mediasfu-angular 2.0.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +528 -163
- package/dist/README.md +537 -163
- package/dist/fesm2022/mediasfu-angular.mjs +2369 -1797
- package/dist/fesm2022/mediasfu-angular.mjs.map +1 -1
- package/dist/lib/@types/types.d.ts +23 -1
- package/dist/lib/components/mediasfu-components/mediasfu-broadcast.component.d.ts +70 -26
- package/dist/lib/components/mediasfu-components/mediasfu-chat.component.d.ts +71 -23
- package/dist/lib/components/mediasfu-components/mediasfu-conference.component.d.ts +79 -29
- package/dist/lib/components/mediasfu-components/mediasfu-generic.component.d.ts +79 -29
- package/dist/lib/components/mediasfu-components/mediasfu-webinar.component.d.ts +82 -32
- package/dist/lib/components/misc-components/pre-join-page/pre-join-page.component.d.ts +16 -5
- package/dist/lib/consumers/connect-send-transport-audio.service.d.ts +12 -0
- package/dist/lib/consumers/connect-send-transport.service.d.ts +1 -0
- package/dist/lib/consumers/consumer-resume.service.d.ts +6 -1
- package/dist/lib/methods/utils/create-room-on-media-sfu.service.d.ts +5 -3
- package/dist/lib/methods/utils/join-room-on-media-sfu.service.d.ts +19 -5
- package/dist/lib/methods/utils/mini-audio-player/mini-audio-player.component.d.ts +10 -6
- package/dist/lib/producers/producer-emits/join-local-room.service.d.ts +15 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -288,19 +288,21 @@ updateValidated(true);
|
|
|
288
288
|
|
|
289
289
|
See the following code for the PreJoinPage page logic:
|
|
290
290
|
|
|
291
|
-
```
|
|
292
|
-
|
|
291
|
+
```typescript
|
|
292
|
+
import { Component, Inject, Input, OnInit, Optional } from '@angular/core';
|
|
293
293
|
import { FormBuilder, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
|
|
294
294
|
import { CommonModule } from '@angular/common';
|
|
295
295
|
import { Socket } from 'socket.io-client';
|
|
296
296
|
import {
|
|
297
297
|
ConnectSocketType, ShowAlert,
|
|
298
298
|
ConnectLocalSocketType, ResponseLocalConnection,
|
|
299
|
-
ResponseLocalConnectionData, RecordingParams, MeetingRoomParams
|
|
299
|
+
ResponseLocalConnectionData, RecordingParams, MeetingRoomParams,
|
|
300
|
+
CreateMediaSFURoomOptions,JoinMediaSFURoomOptions,
|
|
300
301
|
} from '../../../@types/types';
|
|
301
302
|
import { CheckLimitsAndMakeRequest } from '../../../methods/utils/check-limits-and-make-request.service';
|
|
302
303
|
import { CreateRoomOnMediaSFU } from '../../../methods/utils/create-room-on-media-sfu.service';
|
|
303
|
-
import {
|
|
304
|
+
import { CreateRoomOnMediaSFUType, JoinRoomOnMediaSFUType, JoinRoomOnMediaSFU } from '../../../methods/utils/join-room-on-media-sfu.service';
|
|
305
|
+
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
|
|
304
306
|
|
|
305
307
|
export interface JoinLocalEventRoomParameters {
|
|
306
308
|
eventID: string;
|
|
@@ -370,6 +372,10 @@ export interface PreJoinPageOptions {
|
|
|
370
372
|
connectMediaSFU?: boolean;
|
|
371
373
|
parameters: PreJoinPageParameters;
|
|
372
374
|
credentials?: Credentials;
|
|
375
|
+
returnUI?: boolean;
|
|
376
|
+
noUIPreJoinOptions?: CreateMediaSFURoomOptions | JoinMediaSFURoomOptions;
|
|
377
|
+
createMediaSFURoom?: CreateRoomOnMediaSFUType;
|
|
378
|
+
joinMediaSFURoom?: JoinRoomOnMediaSFUType;
|
|
373
379
|
}
|
|
374
380
|
|
|
375
381
|
export type PreJoinPageType = (options: PreJoinPageOptions) => HTMLElement;
|
|
@@ -454,6 +460,11 @@ export class PreJoinPage implements OnInit {
|
|
|
454
460
|
@Input() credentials: Credentials = { apiUserName: 'yourAPIUSERNAME', apiKey: 'yourAPIKEY' };
|
|
455
461
|
@Input() localLink: string | undefined = "";
|
|
456
462
|
@Input() connectMediaSFU: boolean | undefined = true;
|
|
463
|
+
@Input() returnUI?: boolean;
|
|
464
|
+
@Input() noUIPreJoinOptions?: CreateMediaSFURoomOptions | JoinMediaSFURoomOptions;
|
|
465
|
+
@Input() createMediaSFURoom?: CreateRoomOnMediaSFUType;
|
|
466
|
+
@Input() joinMediaSFURoom?: JoinRoomOnMediaSFUType;
|
|
467
|
+
|
|
457
468
|
|
|
458
469
|
isCreateMode = false;
|
|
459
470
|
preJoinForm: FormGroup;
|
|
@@ -465,15 +476,23 @@ export class PreJoinPage implements OnInit {
|
|
|
465
476
|
localData: ResponseLocalConnectionData | undefined = undefined;
|
|
466
477
|
initSocket: Socket | undefined = undefined;
|
|
467
478
|
|
|
479
|
+
pending = new BehaviorSubject<boolean>(false);
|
|
480
|
+
|
|
468
481
|
constructor(
|
|
469
482
|
private fb: FormBuilder,
|
|
470
483
|
@Optional() @Inject('parameters') injectedParameters: PreJoinPageParameters,
|
|
471
484
|
@Optional() @Inject('credentials') injectedCredentials: Credentials,
|
|
472
485
|
@Optional() @Inject('localLink') injectedLocalLink: string,
|
|
473
486
|
@Optional() @Inject('connectMediaSFU') injectedConnectMediaSFU: boolean,
|
|
487
|
+
@Optional() @Inject('returnUI') injectedReturnUI: boolean,
|
|
488
|
+
@Optional() @Inject('noUIPreJoinOptions') injectedNoUIPreJoinOptions: CreateMediaSFURoomOptions | JoinMediaSFURoomOptions,
|
|
489
|
+
@Optional() @Inject('createMediaSFURoom') injectedCreateMediaSFURoom: CreateRoomOnMediaSFUType,
|
|
490
|
+
@Optional() @Inject('joinMediaSFURoom') injectedJoinMediaSFURoom: JoinRoomOnMediaSFUType,
|
|
491
|
+
|
|
492
|
+
|
|
474
493
|
private checkLimitsService: CheckLimitsAndMakeRequest,
|
|
475
494
|
private createRoomService: CreateRoomOnMediaSFU,
|
|
476
|
-
private joinRoomService:
|
|
495
|
+
private joinRoomService: JoinRoomOnMediaSFU
|
|
477
496
|
) {
|
|
478
497
|
this.preJoinForm = this.fb.group({
|
|
479
498
|
name: ['', Validators.required],
|
|
@@ -486,12 +505,22 @@ export class PreJoinPage implements OnInit {
|
|
|
486
505
|
this.credentials = injectedCredentials || this.credentials;
|
|
487
506
|
this.localLink = injectedLocalLink || this.localLink;
|
|
488
507
|
this.connectMediaSFU = injectedConnectMediaSFU !== undefined ? injectedConnectMediaSFU : this.connectMediaSFU;
|
|
508
|
+
this.returnUI = injectedReturnUI !== undefined ? injectedReturnUI : this.returnUI;
|
|
509
|
+
this.noUIPreJoinOptions = injectedNoUIPreJoinOptions || this.noUIPreJoinOptions;
|
|
510
|
+
this.createMediaSFURoom = injectedCreateMediaSFURoom || this.createMediaSFURoom;
|
|
511
|
+
this.joinMediaSFURoom = injectedJoinMediaSFURoom || this.joinMediaSFURoom;
|
|
489
512
|
|
|
490
513
|
}
|
|
491
514
|
|
|
492
515
|
ngOnInit(): void {
|
|
516
|
+
// If we have a localLink and not connected yet, try to connect
|
|
493
517
|
if (this.localLink && !this.localConnected && !this.initSocket) {
|
|
494
|
-
this.connectLocalSocket()
|
|
518
|
+
this.connectLocalSocket().then(() => {
|
|
519
|
+
this.checkProceed();
|
|
520
|
+
});
|
|
521
|
+
} else {
|
|
522
|
+
// If no localLink or already connected, try to proceed
|
|
523
|
+
this.checkProceed();
|
|
495
524
|
}
|
|
496
525
|
}
|
|
497
526
|
|
|
@@ -512,6 +541,27 @@ export class PreJoinPage implements OnInit {
|
|
|
512
541
|
}
|
|
513
542
|
}
|
|
514
543
|
|
|
544
|
+
private async checkProceed(): Promise<void> {
|
|
545
|
+
// If we do not need to return UI and we have noUIPreJoinOptions, proceed like in the React code
|
|
546
|
+
if (!this.returnUI && this.noUIPreJoinOptions) {
|
|
547
|
+
if ('action' in this.noUIPreJoinOptions && this.noUIPreJoinOptions.action === 'create') {
|
|
548
|
+
const createOptions = this.noUIPreJoinOptions as CreateMediaSFURoomOptions;
|
|
549
|
+
if (!createOptions.userName || !createOptions.duration || !createOptions.eventType || !createOptions.capacity) {
|
|
550
|
+
throw new Error('Please provide all the required parameters: userName, duration, eventType, capacity');
|
|
551
|
+
}
|
|
552
|
+
await this.handleCreateRoom();
|
|
553
|
+
} else if ('action' in this.noUIPreJoinOptions && this.noUIPreJoinOptions.action === 'join') {
|
|
554
|
+
const joinOptions = this.noUIPreJoinOptions as JoinMediaSFURoomOptions;
|
|
555
|
+
if (!joinOptions.userName || !joinOptions.meetingID) {
|
|
556
|
+
throw new Error('Please provide all the required parameters: userName, meetingID');
|
|
557
|
+
}
|
|
558
|
+
await this.handleJoinRoom();
|
|
559
|
+
} else {
|
|
560
|
+
throw new Error('Invalid options provided for creating/joining a room without UI.');
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
515
565
|
toggleMode(): void {
|
|
516
566
|
this.isCreateMode = !this.isCreateMode;
|
|
517
567
|
this.error = '';
|
|
@@ -556,10 +606,14 @@ export class PreJoinPage implements OnInit {
|
|
|
556
606
|
|
|
557
607
|
async roomCreator(options: { payload: any; apiUserName: string; apiKey: string; validate?: boolean }): Promise<any> {
|
|
558
608
|
const { payload, apiUserName, apiKey, validate = true } = options;
|
|
559
|
-
|
|
609
|
+
if (!this.createMediaSFURoom) {
|
|
610
|
+
this.createMediaSFURoom = this.createRoomService.createRoomOnMediaSFU;
|
|
611
|
+
}
|
|
612
|
+
const response = await this.createMediaSFURoom({
|
|
560
613
|
payload,
|
|
561
614
|
apiUserName,
|
|
562
615
|
apiKey,
|
|
616
|
+
localLink: this.localLink,
|
|
563
617
|
});
|
|
564
618
|
|
|
565
619
|
if (response.success && response.data && 'roomName' in response.data) {
|
|
@@ -586,21 +640,37 @@ export class PreJoinPage implements OnInit {
|
|
|
586
640
|
|
|
587
641
|
async handleCreateRoom(): Promise<void> {
|
|
588
642
|
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
if (!name || !duration || !eventType || !capacity) {
|
|
592
|
-
this.error = 'Please fill all the fields.';
|
|
643
|
+
if (this.pending.value) {
|
|
593
644
|
return;
|
|
594
645
|
}
|
|
646
|
+
this.pending.next(true);
|
|
647
|
+
let payload = {} as CreateMediaSFURoomOptions;
|
|
595
648
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
649
|
+
if (this.returnUI) {
|
|
650
|
+
const { name, duration, eventType, capacity } = this.preJoinForm.value;
|
|
651
|
+
|
|
652
|
+
if (!name || !duration || !eventType || !capacity) {
|
|
653
|
+
this.error = 'Please fill all the fields.';
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
payload = {
|
|
658
|
+
action: 'create',
|
|
659
|
+
duration: parseInt(duration),
|
|
660
|
+
capacity: parseInt(capacity),
|
|
661
|
+
eventType,
|
|
662
|
+
userName: name,
|
|
663
|
+
recordOnly: false,
|
|
664
|
+
};
|
|
665
|
+
} else {
|
|
666
|
+
if (this.noUIPreJoinOptions && 'action' in this.noUIPreJoinOptions && this.noUIPreJoinOptions.action === 'create') {
|
|
667
|
+
payload = this.noUIPreJoinOptions as CreateMediaSFURoomOptions;
|
|
668
|
+
} else {
|
|
669
|
+
this.error = 'Invalid options provided for creating a room without UI.';
|
|
670
|
+
this.pending.next(false);
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
604
674
|
|
|
605
675
|
this.parameters.updateIsLoadingModalVisible(true);
|
|
606
676
|
|
|
@@ -614,13 +684,13 @@ export class PreJoinPage implements OnInit {
|
|
|
614
684
|
Math.floor(10 + Math.random() * 99).toString();
|
|
615
685
|
eventID = 'm' + eventID;
|
|
616
686
|
const eventRoomParams = this.localData?.meetingRoomParams_;
|
|
617
|
-
eventRoomParams!.type = eventType as 'chat' | 'broadcast' | 'webinar' | 'conference';
|
|
687
|
+
eventRoomParams!.type = payload.eventType as 'chat' | 'broadcast' | 'webinar' | 'conference';
|
|
618
688
|
|
|
619
689
|
const createData: CreateLocalRoomParameters = {
|
|
620
690
|
eventID: eventID,
|
|
621
|
-
duration:
|
|
622
|
-
capacity:
|
|
623
|
-
userName:
|
|
691
|
+
duration: payload.duration,
|
|
692
|
+
capacity: payload.capacity,
|
|
693
|
+
userName: payload.userName,
|
|
624
694
|
scheduledDate: new Date(),
|
|
625
695
|
secureCode: secureCode,
|
|
626
696
|
waitRoom: false,
|
|
@@ -649,16 +719,18 @@ export class PreJoinPage implements OnInit {
|
|
|
649
719
|
|
|
650
720
|
if (response && response.success && response.data && 'roomName' in response.data) {
|
|
651
721
|
createData.eventID = response.data.roomName;
|
|
652
|
-
createData.secureCode = response.data.
|
|
722
|
+
createData.secureCode = response.data.secureCode;
|
|
653
723
|
createData.mediasfuURL = response.data.publicURL;
|
|
654
724
|
await this.createLocalRoom({ createData: createData, link: response.data.link });
|
|
655
725
|
} else {
|
|
726
|
+
this.pending.next(false);
|
|
656
727
|
this.parameters.updateIsLoadingModalVisible(false);
|
|
657
728
|
this.error = 'Unable to create room on MediaSFU.';
|
|
658
729
|
try {
|
|
659
730
|
this.parameters.updateSocket(this.initSocket!);
|
|
660
731
|
await this.createLocalRoom({ createData: createData });
|
|
661
732
|
} catch (error: any) {
|
|
733
|
+
this.pending.next(false);
|
|
662
734
|
this.parameters.updateIsLoadingModalVisible(false);
|
|
663
735
|
this.error = `Unable to create room. ${error}`;
|
|
664
736
|
}
|
|
@@ -668,6 +740,7 @@ export class PreJoinPage implements OnInit {
|
|
|
668
740
|
this.parameters.updateSocket(this.initSocket!);
|
|
669
741
|
await this.createLocalRoom({ createData: createData });
|
|
670
742
|
} catch (error: any) {
|
|
743
|
+
this.pending.next(false);
|
|
671
744
|
this.parameters.updateIsLoadingModalVisible(false);
|
|
672
745
|
this.error = `Unable to create room. ${error}`;
|
|
673
746
|
}
|
|
@@ -679,32 +752,44 @@ export class PreJoinPage implements OnInit {
|
|
|
679
752
|
apiKey: this.credentials.apiKey,
|
|
680
753
|
validate: true,
|
|
681
754
|
});
|
|
755
|
+
this.pending.next(false);
|
|
682
756
|
}
|
|
683
757
|
}
|
|
684
758
|
|
|
685
759
|
async handleJoinRoom(): Promise<void> {
|
|
686
|
-
if (this.
|
|
687
|
-
this.error = 'Please fill all the fields.';
|
|
760
|
+
if (this.pending.value) {
|
|
688
761
|
return;
|
|
689
762
|
}
|
|
763
|
+
this.pending.next(true);
|
|
764
|
+
let payload = {} as JoinMediaSFURoomOptions;
|
|
690
765
|
|
|
691
|
-
|
|
766
|
+
if (this.returnUI) {
|
|
767
|
+
const { name, eventID } = this.preJoinForm.value;
|
|
692
768
|
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
769
|
+
if (!name || !eventID) {
|
|
770
|
+
this.error = 'Please fill all the fields.';
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
697
773
|
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
774
|
+
payload = {
|
|
775
|
+
action: 'join',
|
|
776
|
+
meetingID: eventID,
|
|
777
|
+
userName: name,
|
|
778
|
+
};
|
|
779
|
+
} else {
|
|
780
|
+
if (this.noUIPreJoinOptions && 'action' in this.noUIPreJoinOptions && this.noUIPreJoinOptions.action === 'join') {
|
|
781
|
+
payload = this.noUIPreJoinOptions as JoinMediaSFURoomOptions;
|
|
782
|
+
} else {
|
|
783
|
+
this.error = 'Invalid options provided for joining a room without UI.';
|
|
784
|
+
this.pending.next(false);
|
|
785
|
+
return;
|
|
786
|
+
}
|
|
787
|
+
}
|
|
703
788
|
|
|
704
789
|
if (this.localLink && !this.localLink.includes('mediasfu.com')) {
|
|
705
|
-
const joinData = {
|
|
706
|
-
eventID:
|
|
707
|
-
userName:
|
|
790
|
+
const joinData: JoinLocalEventRoomParameters = {
|
|
791
|
+
eventID: payload.meetingID,
|
|
792
|
+
userName: payload.userName,
|
|
708
793
|
secureCode: '',
|
|
709
794
|
videoPreference: null,
|
|
710
795
|
audioPreference: null,
|
|
@@ -712,15 +797,20 @@ export class PreJoinPage implements OnInit {
|
|
|
712
797
|
};
|
|
713
798
|
|
|
714
799
|
await this.joinLocalRoom({ joinData: joinData });
|
|
800
|
+
this.pending.next(false);
|
|
715
801
|
return;
|
|
716
802
|
}
|
|
717
803
|
|
|
718
804
|
this.parameters.updateIsLoadingModalVisible(true);
|
|
719
805
|
try {
|
|
720
|
-
|
|
806
|
+
if (!this.joinMediaSFURoom) {
|
|
807
|
+
this.joinMediaSFURoom = this.joinRoomService.joinRoomOnMediaSFU;
|
|
808
|
+
}
|
|
809
|
+
const response = await this.joinMediaSFURoom({
|
|
721
810
|
payload,
|
|
722
811
|
apiUserName: this.credentials.apiUserName,
|
|
723
812
|
apiKey: this.credentials.apiKey,
|
|
813
|
+
localLink: this.localLink,
|
|
724
814
|
});
|
|
725
815
|
|
|
726
816
|
if (response.success && response.data && 'roomName' in response.data) {
|
|
@@ -728,13 +818,15 @@ export class PreJoinPage implements OnInit {
|
|
|
728
818
|
apiUserName: response.data.roomName,
|
|
729
819
|
apiToken: response.data.secret,
|
|
730
820
|
link: response.data.link,
|
|
731
|
-
userName:
|
|
821
|
+
userName: payload.userName,
|
|
732
822
|
parameters: this.parameters,
|
|
733
823
|
validate: true,
|
|
734
824
|
});
|
|
735
825
|
this.error = '';
|
|
826
|
+
this.pending.next(false);
|
|
736
827
|
} else {
|
|
737
828
|
this.parameters.updateIsLoadingModalVisible(false);
|
|
829
|
+
this.pending.next(false);
|
|
738
830
|
this.error = `Unable to connect to room. ${
|
|
739
831
|
response.data ? ('error' in response.data ? response.data.error : '') : ''
|
|
740
832
|
}`;
|
|
@@ -745,7 +837,6 @@ export class PreJoinPage implements OnInit {
|
|
|
745
837
|
}
|
|
746
838
|
}
|
|
747
839
|
}
|
|
748
|
-
|
|
749
840
|
```
|
|
750
841
|
|
|
751
842
|
### IP Blockage Warning And Local UI Development
|
|
@@ -760,8 +851,7 @@ In this mode, the module will operate locally without making requests to MediaSF
|
|
|
760
851
|
|
|
761
852
|
### Example for Generic UI to Render Broadcast Room
|
|
762
853
|
|
|
763
|
-
```
|
|
764
|
-
|
|
854
|
+
```typescript
|
|
765
855
|
import { Component, OnInit } from '@angular/core';
|
|
766
856
|
import {
|
|
767
857
|
MediasfuBroadcast,
|
|
@@ -866,7 +956,7 @@ export class AppComponent implements OnInit {
|
|
|
866
956
|
|
|
867
957
|
### Example for Generic View
|
|
868
958
|
|
|
869
|
-
```
|
|
959
|
+
```typescript
|
|
870
960
|
import { Component, OnInit } from '@angular/core';
|
|
871
961
|
import {
|
|
872
962
|
GenerateRandomParticipants,
|
|
@@ -881,44 +971,41 @@ import {
|
|
|
881
971
|
PreJoinPage,
|
|
882
972
|
} from 'mediasfu-angular';
|
|
883
973
|
|
|
974
|
+
// Assume all missing imports are similar to the previous example
|
|
975
|
+
|
|
884
976
|
|
|
885
977
|
/**
|
|
886
|
-
*
|
|
887
|
-
*
|
|
888
|
-
* This component initializes the necessary configuration and credentials for the MediaSFU application.
|
|
889
|
-
* Users can specify their own Community Edition (CE) server, utilize MediaSFU Cloud by default, or enable MediaSFU Cloud for egress features.
|
|
978
|
+
* AppComponent
|
|
890
979
|
*
|
|
891
|
-
*
|
|
892
|
-
* -
|
|
893
|
-
* -
|
|
894
|
-
* -
|
|
895
|
-
*
|
|
896
|
-
* - **Credentials Requirement**: If not using your own server, provide `apiUserName` and `apiKey`. The same applies when using MediaSFU Cloud for egress.
|
|
897
|
-
* - **Deprecated Feature**: `useLocalUIMode` is deprecated due to updates for strong typing and improved configuration options.
|
|
980
|
+
* This component demonstrates how to:
|
|
981
|
+
* - Configure credentials for MediaSFU Cloud and/or Community Edition (CE).
|
|
982
|
+
* - Use MediaSFU with or without a custom server.
|
|
983
|
+
* - Integrate a pre-join page.
|
|
984
|
+
* - Disable the default MediaSFU UI and manage state through `sourceParameters` for a fully custom frontend.
|
|
898
985
|
*
|
|
899
|
-
*
|
|
900
|
-
*
|
|
901
|
-
*
|
|
902
|
-
*
|
|
903
|
-
*
|
|
904
|
-
*
|
|
905
|
-
* imports: [BrowserModule, MediasfuWebinar],
|
|
906
|
-
* bootstrap: [AppComponent]
|
|
907
|
-
* })
|
|
908
|
-
* export class AppModule { }
|
|
909
|
-
* ```
|
|
986
|
+
* Basic instructions:
|
|
987
|
+
* 1. Set `localLink` to your CE server if you have one, or leave it blank to use MediaSFU Cloud.
|
|
988
|
+
* 2. Set `connectMediaSFU` to determine whether you're connecting to MediaSFU Cloud services.
|
|
989
|
+
* 3. Provide credentials if using MediaSFU Cloud (dummy credentials are acceptable in certain scenarios).
|
|
990
|
+
* 4. If you prefer a custom UI, set `returnUI` to false and handle all interactions via `sourceParameters` and `updateSourceParameters`.
|
|
991
|
+
* 5. For secure production usage, use custom `createMediaSFURoom` and `joinMediaSFURoom` functions to forward requests through your backend.
|
|
910
992
|
*/
|
|
911
993
|
@Component({
|
|
912
994
|
selector: 'app-root',
|
|
913
|
-
imports: [
|
|
995
|
+
imports: [MediasfuGeneric],
|
|
914
996
|
template: `
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
997
|
+
<app-mediasfu-generic
|
|
998
|
+
[PrejoinPage]="PreJoinPage"
|
|
999
|
+
[credentials]="credentials"
|
|
1000
|
+
[localLink]="localLink"
|
|
1001
|
+
[connectMediaSFU]="connectMediaSFU"
|
|
1002
|
+
[returnUI]="returnUI"
|
|
1003
|
+
[noUIPreJoinOptions]="!returnUI ? noUIPreJoinOptions : undefined"
|
|
1004
|
+
[sourceParameters]="!returnUI ? sourceParameters : undefined"
|
|
1005
|
+
[updateSourceParameters]="!returnUI ? updateSourceParameters : undefined"
|
|
1006
|
+
[createMediaSFURoom]="createRoomOnMediaSFU.createRoomOnMediaSFU"
|
|
1007
|
+
[joinMediaSFURoom]="joinRoomOnMediaSFU.joinRoomOnMediaSFU">
|
|
1008
|
+
</app-mediasfu-generic>
|
|
922
1009
|
`,
|
|
923
1010
|
providers: [
|
|
924
1011
|
GenerateRandomParticipants,
|
|
@@ -928,54 +1015,187 @@ import {
|
|
|
928
1015
|
],
|
|
929
1016
|
})
|
|
930
1017
|
export class AppComponent implements OnInit {
|
|
931
|
-
//
|
|
932
|
-
//
|
|
933
|
-
//
|
|
1018
|
+
// =========================================================
|
|
1019
|
+
// API CREDENTIALS CONFIGURATION
|
|
1020
|
+
// =========================================================
|
|
1021
|
+
//
|
|
1022
|
+
// Scenario A: Not using MediaSFU Cloud at all.
|
|
1023
|
+
// - No credentials needed. Just set localLink to your CE server.
|
|
1024
|
+
// Example:
|
|
1025
|
+
/*
|
|
1026
|
+
credentials = {};
|
|
1027
|
+
localLink = 'http://your-ce-server.com'; // e.g., 'http://localhost:3000'
|
|
1028
|
+
connectMediaSFU = localLink.trim() !== '';
|
|
1029
|
+
*/
|
|
934
1030
|
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
*/
|
|
1031
|
+
// Scenario B: Using MediaSFU CE + MediaSFU Cloud for Egress only.
|
|
1032
|
+
// - Use dummy credentials (8 characters for userName, 64 characters for apiKey).
|
|
1033
|
+
// - Your CE backend will forward requests with your real credentials.
|
|
1034
|
+
/*
|
|
940
1035
|
credentials = {
|
|
941
|
-
apiUserName: '
|
|
942
|
-
apiKey: '
|
|
1036
|
+
apiUserName: 'dummyUsr', // 8 characters
|
|
1037
|
+
apiKey: '1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef', // 64 characters
|
|
943
1038
|
};
|
|
1039
|
+
localLink = 'http://your-ce-server.com'; // e.g., 'http://localhost:3000'
|
|
1040
|
+
connectMediaSFU = localLink.trim() !== '';
|
|
1041
|
+
*/
|
|
944
1042
|
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
1043
|
+
// Scenario C: Using MediaSFU Cloud without your own server.
|
|
1044
|
+
// - For development, use your actual or dummy credentials.
|
|
1045
|
+
// - In production, securely handle credentials server-side and use custom room functions.
|
|
1046
|
+
credentials = {
|
|
1047
|
+
apiUserName: 'yourDevUser', // 8 characters recommended for dummy
|
|
1048
|
+
apiKey: 'yourDevApiKey1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef', // 64 characters
|
|
1049
|
+
};
|
|
1050
|
+
localLink = ''; // Leave empty if not using your own server
|
|
1051
|
+
connectMediaSFU = true; // Set to true if using MediaSFU Cloud since localLink is empty
|
|
1052
|
+
|
|
1053
|
+
// =========================================================
|
|
1054
|
+
// UI RENDERING OPTIONS
|
|
1055
|
+
// =========================================================
|
|
1056
|
+
//
|
|
1057
|
+
// If you want a fully custom UI (e.g., a custom layout inspired by WhatsApp):
|
|
1058
|
+
// 1. Set `returnUI = false` to prevent the default MediaSFU UI from rendering.
|
|
1059
|
+
// 2. Provide `noUIPreJoinOptions` to simulate what would have been entered on a pre-join page.
|
|
1060
|
+
// 3. Use `sourceParameters` and `updateSourceParameters` to access and update state/actions.
|
|
1061
|
+
// 4. No need for any of the above if you're using the default MediaSFU UI.
|
|
1062
|
+
//
|
|
1063
|
+
// Example noUIPreJoinOptions for creating a room:
|
|
1064
|
+
noUIPreJoinOptions: CreateMediaSFURoomOptions | JoinMediaSFURoomOptions = {
|
|
1065
|
+
action: 'create',
|
|
1066
|
+
capacity: 10,
|
|
1067
|
+
duration: 15,
|
|
1068
|
+
eventType: 'broadcast',
|
|
1069
|
+
userName: 'Prince',
|
|
1070
|
+
};
|
|
1071
|
+
|
|
1072
|
+
// Example noUIPreJoinOptions for joining a room:
|
|
1073
|
+
// noUIPreJoinOptions: CreateMediaSFURoomOptions | JoinMediaSFURoomOptions = {
|
|
1074
|
+
// action: 'join',
|
|
1075
|
+
// userName: 'Prince',
|
|
1076
|
+
// meetingID: 'yourMeetingID'
|
|
1077
|
+
// };
|
|
1078
|
+
|
|
1079
|
+
returnUI = true; // Set to false for custom UI, true for default MediaSFU UI
|
|
1080
|
+
|
|
1081
|
+
sourceParameters: { [key: string]: any } = {};
|
|
950
1082
|
|
|
951
1083
|
/**
|
|
952
|
-
*
|
|
953
|
-
* indicating the use of MediaSFU Cloud by default.
|
|
1084
|
+
* Function to update sourceParameters state.
|
|
954
1085
|
*
|
|
955
|
-
*
|
|
956
|
-
* - If `localLink` is empty, the application will connect to MediaSFU Cloud by default.
|
|
1086
|
+
* @param data - The data to update sourceParameters with.
|
|
957
1087
|
*/
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
// ====== USE CASES ======
|
|
962
|
-
// ========================
|
|
1088
|
+
updateSourceParameters = (data: { [key: string]: any }) => {
|
|
1089
|
+
this.sourceParameters = data;
|
|
1090
|
+
};
|
|
963
1091
|
|
|
964
|
-
//
|
|
965
|
-
//
|
|
966
|
-
//
|
|
1092
|
+
// =========================================================
|
|
1093
|
+
// CUSTOM ROOM FUNCTIONS (OPTIONAL)
|
|
1094
|
+
// =========================================================
|
|
1095
|
+
//
|
|
1096
|
+
// To securely forward requests to MediaSFU:
|
|
1097
|
+
// - Implement custom `createMediaSFURoom` and `joinMediaSFURoom` functions.
|
|
1098
|
+
// - These functions send requests to your server, which then communicates with MediaSFU Cloud.
|
|
1099
|
+
//
|
|
1100
|
+
// The imported `createRoomOnMediaSFU` and `joinRoomOnMediaSFU` are examples.
|
|
1101
|
+
//
|
|
1102
|
+
// If using MediaSFU CE backend, ensure your server endpoints:
|
|
1103
|
+
// - Validate dummy credentials.
|
|
1104
|
+
// - Forward requests to mediasfu.com with real credentials.
|
|
1105
|
+
|
|
1106
|
+
// =========================================================
|
|
1107
|
+
// COMPONENT SELECTION AND RENDERING
|
|
1108
|
+
// =========================================================
|
|
1109
|
+
//
|
|
1110
|
+
// Multiple components are available depending on your event type:
|
|
1111
|
+
// MediasfuBroadcast, MediasfuChat, MediasfuWebinar, MediasfuConference
|
|
1112
|
+
//
|
|
1113
|
+
// By default, we'll use MediasfuGeneric with custom settings.
|
|
1114
|
+
//
|
|
1115
|
+
// Uncomment the desired component below and comment out the others as needed.
|
|
1116
|
+
//
|
|
1117
|
+
// Example of MediaSFU CE with no MediaSFU Cloud
|
|
1118
|
+
// return (
|
|
1119
|
+
// <app-mediasfu-generic
|
|
1120
|
+
// [PrejoinPage]="PreJoinPage"
|
|
1121
|
+
// [localLink]="localLink">
|
|
1122
|
+
// </app-mediasfu-generic>
|
|
1123
|
+
// );
|
|
1124
|
+
|
|
1125
|
+
// Example of MediaSFU CE + MediaSFU Cloud for Egress only
|
|
1126
|
+
// return (
|
|
1127
|
+
// <app-mediasfu-generic
|
|
1128
|
+
// [PrejoinPage]="PreJoinPage"
|
|
1129
|
+
// [credentials]="credentials"
|
|
1130
|
+
// [localLink]="localLink"
|
|
1131
|
+
// [connectMediaSFU]="connectMediaSFU">
|
|
1132
|
+
// </app-mediasfu-generic>
|
|
1133
|
+
// );
|
|
1134
|
+
|
|
1135
|
+
// Example of MediaSFU Cloud only
|
|
1136
|
+
// return (
|
|
1137
|
+
// <app-mediasfu-generic
|
|
1138
|
+
// [PrejoinPage]="PreJoinPage"
|
|
1139
|
+
// [credentials]="credentials"
|
|
1140
|
+
// [connectMediaSFU]="connectMediaSFU">
|
|
1141
|
+
// </app-mediasfu-generic>
|
|
1142
|
+
// );
|
|
1143
|
+
|
|
1144
|
+
// Example of MediaSFU CE + MediaSFU Cloud for Egress only with custom UI
|
|
1145
|
+
// return (
|
|
1146
|
+
// <app-mediasfu-generic
|
|
1147
|
+
// [PrejoinPage]="PreJoinPage"
|
|
1148
|
+
// [credentials]="credentials"
|
|
1149
|
+
// [localLink]="localLink"
|
|
1150
|
+
// [connectMediaSFU]="connectMediaSFU"
|
|
1151
|
+
// [returnUI]="false"
|
|
1152
|
+
// [noUIPreJoinOptions]="noUIPreJoinOptions"
|
|
1153
|
+
// [sourceParameters]="sourceParameters"
|
|
1154
|
+
// [updateSourceParameters]="updateSourceParameters"
|
|
1155
|
+
// [createMediaSFURoom]="createRoomOnMediaSFU"
|
|
1156
|
+
// [joinMediaSFURoom]="joinRoomOnMediaSFU">
|
|
1157
|
+
// </app-mediasfu-generic>
|
|
1158
|
+
// );
|
|
1159
|
+
|
|
1160
|
+
// Example of MediaSFU Cloud only with custom UI
|
|
1161
|
+
// return (
|
|
1162
|
+
// <app-mediasfu-generic
|
|
1163
|
+
// [PrejoinPage]="PreJoinPage"
|
|
1164
|
+
// [credentials]="credentials"
|
|
1165
|
+
// [connectMediaSFU]="connectMediaSFU"
|
|
1166
|
+
// [returnUI]="false"
|
|
1167
|
+
// [noUIPreJoinOptions]="noUIPreJoinOptions"
|
|
1168
|
+
// [sourceParameters]="sourceParameters"
|
|
1169
|
+
// [updateSourceParameters]="updateSourceParameters"
|
|
1170
|
+
// [createMediaSFURoom]="createRoomOnMediaSFU"
|
|
1171
|
+
// [joinMediaSFURoom]="joinRoomOnMediaSFU">
|
|
1172
|
+
// </app-mediasfu-generic>
|
|
1173
|
+
// );
|
|
1174
|
+
|
|
1175
|
+
// Example of using MediaSFU CE only with custom UI
|
|
1176
|
+
// return (
|
|
1177
|
+
// <app-mediasfu-generic
|
|
1178
|
+
// [PrejoinPage]="PreJoinPage"
|
|
1179
|
+
// [localLink]="localLink"
|
|
1180
|
+
// [connectMediaSFU]="false"
|
|
1181
|
+
// [returnUI]="false"
|
|
1182
|
+
// [noUIPreJoinOptions]="noUIPreJoinOptions"
|
|
1183
|
+
// [sourceParameters]="sourceParameters"
|
|
1184
|
+
// [updateSourceParameters]="updateSourceParameters">
|
|
1185
|
+
// </app-mediasfu-generic>
|
|
1186
|
+
// );
|
|
967
1187
|
|
|
968
1188
|
/**
|
|
969
|
-
*
|
|
970
|
-
* for generating random participants and messages.
|
|
1189
|
+
* Default Rendering: MediasfuGeneric with Updated Configuration
|
|
971
1190
|
*
|
|
972
|
-
*
|
|
1191
|
+
* Renders the MediasfuGeneric component with specified server and cloud connection settings.
|
|
1192
|
+
* Configured for custom UI usage if `returnUI` is set to false.
|
|
973
1193
|
*/
|
|
974
|
-
/*
|
|
975
|
-
useSeed = false;
|
|
976
|
-
seedData: any = {};
|
|
977
|
-
|
|
978
1194
|
ngOnInit(): void {
|
|
1195
|
+
// Deprecated Feature: useSeed and seedData for generating random participants and messages
|
|
1196
|
+
// Uncomment and configure the following section if you intend to use seed data
|
|
1197
|
+
|
|
1198
|
+
/*
|
|
979
1199
|
if (this.useSeed) {
|
|
980
1200
|
const memberName = 'Alice';
|
|
981
1201
|
const hostName = 'Fred';
|
|
@@ -1021,8 +1241,8 @@ export class AppComponent implements OnInit {
|
|
|
1021
1241
|
|
|
1022
1242
|
// Determine whether to use local UI mode
|
|
1023
1243
|
this.useLocalUIMode = this.useSeed;
|
|
1244
|
+
*/
|
|
1024
1245
|
}
|
|
1025
|
-
*/
|
|
1026
1246
|
|
|
1027
1247
|
// ========================
|
|
1028
1248
|
// ====== COMPONENT SELECTION ======
|
|
@@ -1099,7 +1319,6 @@ export class AppComponent implements OnInit {
|
|
|
1099
1319
|
* Renders the MediasfuWebinar component with specified server and cloud connection settings.
|
|
1100
1320
|
* This is the default use case if no specific event type is selected.
|
|
1101
1321
|
*/
|
|
1102
|
-
seedData: any = {}; // Initialize seedData as empty object
|
|
1103
1322
|
|
|
1104
1323
|
// Reference to the PreJoinPage component
|
|
1105
1324
|
PreJoinPage = PreJoinPage;
|
|
@@ -1108,7 +1327,9 @@ export class AppComponent implements OnInit {
|
|
|
1108
1327
|
private generateRandomParticipants: GenerateRandomParticipants,
|
|
1109
1328
|
private generateRandomMessages: GenerateRandomMessages,
|
|
1110
1329
|
private generateRandomRequestList: GenerateRandomRequestList,
|
|
1111
|
-
private generateRandomWaitingRoomList: GenerateRandomWaitingRoomList
|
|
1330
|
+
private generateRandomWaitingRoomList: GenerateRandomWaitingRoomList,
|
|
1331
|
+
public createRoomOnMediaSFU: CreateRoomOnMediaSFU,
|
|
1332
|
+
public joinRoomOnMediaSFU: JoinRoomOnMediaSFU
|
|
1112
1333
|
) { }
|
|
1113
1334
|
|
|
1114
1335
|
// Deprecated Feature: useSeed and seedData for generating random participants and messages
|
|
@@ -1118,59 +1339,203 @@ export class AppComponent implements OnInit {
|
|
|
1118
1339
|
// eventType = 'webinar';
|
|
1119
1340
|
// useLocalUIMode = false;
|
|
1120
1341
|
|
|
1121
|
-
ngOnInit(): void {
|
|
1122
|
-
// If using seed data, generate random participants and messages - DEPRECATED FEATURE
|
|
1123
|
-
// Note: This feature is deprecated and maintained only for legacy purposes.
|
|
1124
|
-
// Uncomment and configure the following section if you intend to use seed data
|
|
1125
|
-
|
|
1126
|
-
// if (this.useSeed) {
|
|
1127
|
-
// const memberName = 'Alice';
|
|
1128
|
-
// const hostName = 'Fred';
|
|
1129
|
-
|
|
1130
|
-
// // Generate random participants
|
|
1131
|
-
// const participants_ = this.generateRandomParticipants.generateRandomParticipants({
|
|
1132
|
-
// member: memberName,
|
|
1133
|
-
// coHost: '',
|
|
1134
|
-
// host: hostName,
|
|
1135
|
-
// forChatBroadcast: this.eventType === 'broadcast' || this.eventType === 'chat',
|
|
1136
|
-
// });
|
|
1137
|
-
|
|
1138
|
-
// // Generate random messages
|
|
1139
|
-
// const messages_ = this.generateRandomMessages.generateRandomMessages({
|
|
1140
|
-
// participants: participants_,
|
|
1141
|
-
// member: memberName,
|
|
1142
|
-
// host: hostName,
|
|
1143
|
-
// forChatBroadcast: this.eventType === 'broadcast' || this.eventType === 'chat',
|
|
1144
|
-
// });
|
|
1145
|
-
|
|
1146
|
-
// // Generate random request list
|
|
1147
|
-
// const requests_ = this.generateRandomRequestList.generateRandomRequestList({
|
|
1148
|
-
// participants: participants_,
|
|
1149
|
-
// hostName: memberName,
|
|
1150
|
-
// coHostName: '',
|
|
1151
|
-
// numberOfRequests: 3,
|
|
1152
|
-
// });
|
|
1153
|
-
|
|
1154
|
-
// // Generate random waiting room list
|
|
1155
|
-
// const waitingList_ = this.generateRandomWaitingRoomList.generateRandomWaitingRoomList();
|
|
1156
|
-
|
|
1157
|
-
// // Assign generated data to seedData
|
|
1158
|
-
// this.seedData = {
|
|
1159
|
-
// participants: participants_,
|
|
1160
|
-
// messages: messages_,
|
|
1161
|
-
// requests: requests_,
|
|
1162
|
-
// waitingList: waitingList_,
|
|
1163
|
-
// member: memberName,
|
|
1164
|
-
// host: hostName,
|
|
1165
|
-
// eventType: this.eventType,
|
|
1166
|
-
// };
|
|
1167
|
-
// }
|
|
1168
|
-
|
|
1169
|
-
// Determine whether to use local UI mode, deprecated feature
|
|
1170
|
-
// this.useLocalUIMode = this.useSeed;
|
|
1171
|
-
}
|
|
1172
1342
|
}
|
|
1173
1343
|
|
|
1344
|
+
export default AppComponent;
|
|
1345
|
+
|
|
1346
|
+
/**
|
|
1347
|
+
* =========================================================
|
|
1348
|
+
* ADDITIONAL NOTES
|
|
1349
|
+
* =========================================================
|
|
1350
|
+
*
|
|
1351
|
+
* Handling Core Methods:
|
|
1352
|
+
* Once `sourceParameters` is populated, you can call core methods like `clickVideo` or `clickAudio` directly:
|
|
1353
|
+
* Example:
|
|
1354
|
+
* sourceParameters.clickVideo({ ...sourceParameters });
|
|
1355
|
+
* sourceParameters.clickAudio({ ...sourceParameters });
|
|
1356
|
+
*
|
|
1357
|
+
* This allows your custom UI to directly interact with MediaSFU functionalities.
|
|
1358
|
+
*
|
|
1359
|
+
* Deprecated Features (Seed Data):
|
|
1360
|
+
* The seed data generation feature is deprecated. Avoid using `useLocalUIMode` or `useSeed` in new implementations.
|
|
1361
|
+
*
|
|
1362
|
+
* Security Considerations:
|
|
1363
|
+
* - **Protect API Credentials:** Ensure that API credentials are not exposed in the frontend. Use environment variables and secure backend services to handle sensitive information.
|
|
1364
|
+
* - **Use HTTPS:** Always use HTTPS to secure data transmission between the client and server.
|
|
1365
|
+
* - **Validate Inputs:** Implement proper validation and error handling on both client and server sides to prevent malicious inputs.
|
|
1366
|
+
*
|
|
1367
|
+
* Example CE Backend Setup:
|
|
1368
|
+
* If using MediaSFU CE + MediaSFU Cloud, your backend might look like this:
|
|
1369
|
+
*
|
|
1370
|
+
* ```javascript
|
|
1371
|
+
* // Endpoint for `createRoom`
|
|
1372
|
+
* app.post("/createRoom", async (req, res) => {
|
|
1373
|
+
* try {
|
|
1374
|
+
* const payload = req.body;
|
|
1375
|
+
* const [apiUserName, apiKey] = req.headers.authorization
|
|
1376
|
+
* .replace("Bearer ", "")
|
|
1377
|
+
* .split(":");
|
|
1378
|
+
*
|
|
1379
|
+
* // Verify temporary credentials
|
|
1380
|
+
* if (!apiUserName || !apiKey || !verifyCredentials(apiUserName, apiKey)) {
|
|
1381
|
+
* return res.status(401).json({ error: "Invalid or expired credentials" });
|
|
1382
|
+
* }
|
|
1383
|
+
*
|
|
1384
|
+
* const response = await fetch("https://mediasfu.com/v1/rooms/", {
|
|
1385
|
+
* method: "POST",
|
|
1386
|
+
* headers: {
|
|
1387
|
+
* "Content-Type": "application/json",
|
|
1388
|
+
* Authorization: `Bearer ${actualApiUserName}:${actualApiKey}`,
|
|
1389
|
+
* },
|
|
1390
|
+
* body: JSON.stringify(payload),
|
|
1391
|
+
* });
|
|
1392
|
+
*
|
|
1393
|
+
* const result = await response.json();
|
|
1394
|
+
* res.status(response.status).json(result);
|
|
1395
|
+
* } catch (error) {
|
|
1396
|
+
* console.error("Error creating room:", error);
|
|
1397
|
+
* res.status(500).json({ error: "Internal server error" });
|
|
1398
|
+
* }
|
|
1399
|
+
* });
|
|
1400
|
+
*
|
|
1401
|
+
* // Endpoint for `joinRoom`
|
|
1402
|
+
* app.post("/joinRoom", async (req, res) => {
|
|
1403
|
+
* try {
|
|
1404
|
+
* const payload = req.body;
|
|
1405
|
+
* const [apiUserName, apiKey] = req.headers.authorization
|
|
1406
|
+
* .replace("Bearer ", "")
|
|
1407
|
+
* .split(":");
|
|
1408
|
+
*
|
|
1409
|
+
* // Verify temporary credentials
|
|
1410
|
+
* if (!apiUserName || !apiKey || !verifyCredentials(apiUserName, apiKey)) {
|
|
1411
|
+
* return res.status(401).json({ error: "Invalid or expired credentials" });
|
|
1412
|
+
* }
|
|
1413
|
+
*
|
|
1414
|
+
* const response = await fetch("https://mediasfu.com/v1/rooms", {
|
|
1415
|
+
* method: "POST",
|
|
1416
|
+
* headers: {
|
|
1417
|
+
* "Content-Type": "application/json",
|
|
1418
|
+
* Authorization: `Bearer ${actualApiUserName}:${actualApiKey}`,
|
|
1419
|
+
* },
|
|
1420
|
+
* body: JSON.stringify(payload),
|
|
1421
|
+
* });
|
|
1422
|
+
*
|
|
1423
|
+
* const result = await response.json();
|
|
1424
|
+
* res.status(response.status).json(result);
|
|
1425
|
+
* } catch (error) {
|
|
1426
|
+
* console.error("Error joining room:", error);
|
|
1427
|
+
* res.status(500).json({ error: "Internal server error" });
|
|
1428
|
+
* }
|
|
1429
|
+
* });
|
|
1430
|
+
* ```
|
|
1431
|
+
*
|
|
1432
|
+
* Custom Room Function Implementation:
|
|
1433
|
+
* Below are examples of how to implement custom functions for creating and joining rooms securely:
|
|
1434
|
+
*
|
|
1435
|
+
* ```typescript
|
|
1436
|
+
* import { CreateJoinRoomError, CreateJoinRoomResponse, CreateJoinRoomType, CreateMediaSFURoomOptions, JoinMediaSFURoomOptions } from '../../@types/types';
|
|
1437
|
+
*
|
|
1438
|
+
*
|
|
1439
|
+
* * Async function to create a room on MediaSFU.
|
|
1440
|
+
* *
|
|
1441
|
+
* * @param {object} options - The options for creating a room.
|
|
1442
|
+
* * @param {CreateMediaSFURoomOptions} options.payload - The payload for the API request.
|
|
1443
|
+
* * @param {string} options.apiUserName - The API username.
|
|
1444
|
+
* * @param {string} options.apiKey - The API key.
|
|
1445
|
+
* * @param {string} options.localLink - The local link.
|
|
1446
|
+
* * @returns {Promise<{ data: CreateJoinRoomResponse | CreateJoinRoomError | null; success: boolean; }>} The response from the API.
|
|
1447
|
+
*
|
|
1448
|
+
* export const createRoomOnMediaSFU: CreateJoinRoomType = async ({
|
|
1449
|
+
* payload,
|
|
1450
|
+
* apiUserName,
|
|
1451
|
+
* apiKey,
|
|
1452
|
+
* localLink = '',
|
|
1453
|
+
* }) => {
|
|
1454
|
+
* try {
|
|
1455
|
+
* let finalLink = 'https://mediasfu.com/v1/rooms/';
|
|
1456
|
+
*
|
|
1457
|
+
* // Update finalLink if using a local server
|
|
1458
|
+
* if (localLink) {
|
|
1459
|
+
* finalLink = `${localLink}/createRoom`;
|
|
1460
|
+
* }
|
|
1461
|
+
*
|
|
1462
|
+
* const response = await fetch(finalLink, {
|
|
1463
|
+
* method: 'POST',
|
|
1464
|
+
* headers: {
|
|
1465
|
+
* 'Content-Type': 'application/json',
|
|
1466
|
+
* Authorization: `Bearer ${apiUserName}:${apiKey}`,
|
|
1467
|
+
* },
|
|
1468
|
+
* body: JSON.stringify(payload),
|
|
1469
|
+
* });
|
|
1470
|
+
*
|
|
1471
|
+
* if (!response.ok) {
|
|
1472
|
+
* throw new Error(`HTTP error! Status: ${response.status}`);
|
|
1473
|
+
* }
|
|
1474
|
+
*
|
|
1475
|
+
* const data: CreateJoinRoomResponse = await response.json();
|
|
1476
|
+
* return { data, success: true };
|
|
1477
|
+
* } catch (error) {
|
|
1478
|
+
* const errorMessage = (error as Error).message || 'unknown error';
|
|
1479
|
+
* return {
|
|
1480
|
+
* data: { error: `Unable to create room, ${errorMessage}` },
|
|
1481
|
+
* success: false,
|
|
1482
|
+
* };
|
|
1483
|
+
* }
|
|
1484
|
+
* };
|
|
1485
|
+
*
|
|
1486
|
+
*
|
|
1487
|
+
* * Async function to join a room on MediaSFU.
|
|
1488
|
+
* *
|
|
1489
|
+
* * @param {object} options - The options for joining a room.
|
|
1490
|
+
* * @param {JoinMediaSFURoomOptions} options.payload - The payload for the API request.
|
|
1491
|
+
* * @param {string} options.apiUserName - The API username.
|
|
1492
|
+
* * @param {string} options.apiKey - The API key.
|
|
1493
|
+
* * @param {string} options.localLink - The local link.
|
|
1494
|
+
* * @returns {Promise<{ data: CreateJoinRoomResponse | CreateJoinRoomError | null; success: boolean; }>} The response from the API.
|
|
1495
|
+
*
|
|
1496
|
+
* export const joinRoomOnMediaSFU: JoinRoomOnMediaSFUType = async ({
|
|
1497
|
+
* payload,
|
|
1498
|
+
* apiUserName,
|
|
1499
|
+
* apiKey,
|
|
1500
|
+
* localLink = '',
|
|
1501
|
+
* }) => {
|
|
1502
|
+
* try {
|
|
1503
|
+
* let finalLink = 'https://mediasfu.com/v1/rooms/join';
|
|
1504
|
+
*
|
|
1505
|
+
* // Update finalLink if using a local server
|
|
1506
|
+
* if (localLink) {
|
|
1507
|
+
* finalLink = `${localLink}/joinRoom`;
|
|
1508
|
+
* }
|
|
1509
|
+
*
|
|
1510
|
+
* const response = await fetch(finalLink, {
|
|
1511
|
+
* method: 'POST',
|
|
1512
|
+
* headers: {
|
|
1513
|
+
* 'Content-Type': 'application/json',
|
|
1514
|
+
* Authorization: `Bearer ${apiUserName}:${apiKey}`,
|
|
1515
|
+
* },
|
|
1516
|
+
* body: JSON.stringify(payload),
|
|
1517
|
+
* });
|
|
1518
|
+
*
|
|
1519
|
+
* if (!response.ok) {
|
|
1520
|
+
* throw new Error(`HTTP error! Status: ${response.status}`);
|
|
1521
|
+
* }
|
|
1522
|
+
*
|
|
1523
|
+
* const data: CreateJoinRoomResponse = await response.json();
|
|
1524
|
+
* return { data, success: true };
|
|
1525
|
+
* } catch (error) {
|
|
1526
|
+
* const errorMessage = (error as Error).message || 'unknown error';
|
|
1527
|
+
* return {
|
|
1528
|
+
* data: { error: `Unable to join room, ${errorMessage}` },
|
|
1529
|
+
* success: false,
|
|
1530
|
+
* };
|
|
1531
|
+
* }
|
|
1532
|
+
* };
|
|
1533
|
+
* ```
|
|
1534
|
+
*
|
|
1535
|
+
* =======================
|
|
1536
|
+
* ====== END OF GUIDE ======
|
|
1537
|
+
* =======================
|
|
1538
|
+
*/
|
|
1174
1539
|
|
|
1175
1540
|
```
|
|
1176
1541
|
|