mediasfu-angular 2.0.2 → 2.1.1
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 +527 -162
- package/dist/README.md +530 -162
- package/dist/fesm2022/mediasfu-angular.mjs +2373 -1801
- 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 +56 -12
- package/dist/lib/components/mediasfu-components/mediasfu-chat.component.d.ts +57 -9
- package/dist/lib/components/mediasfu-components/mediasfu-conference.component.d.ts +61 -11
- package/dist/lib/components/mediasfu-components/mediasfu-generic.component.d.ts +61 -11
- package/dist/lib/components/mediasfu-components/mediasfu-webinar.component.d.ts +64 -14
- 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 +4 -3
- package/dist/lib/methods/utils/join-room-on-media-sfu.service.d.ts +18 -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/dist/README.md
CHANGED
|
@@ -34,8 +34,11 @@ MediaSFU offers a cutting-edge streaming experience that empowers users to custo
|
|
|
34
34
|
# MediaSFU Angular Module Documentation
|
|
35
35
|
|
|
36
36
|
## Unlock the Power of MediaSFU Community Edition
|
|
37
|
+
|
|
37
38
|
**MediaSFU Community Edition is free and open-source**—perfect for developers who want to run their own media server without upfront costs. With robust features and simple setup, you can launch your media solution in minutes. **Ready to scale?** Upgrade seamlessly to **MediaSFU Cloud** for enterprise-grade performance and global scalability.
|
|
39
|
+
|
|
38
40
|
**[Get started now on GitHub!](https://github.com/MediaSFU/MediaSFUOpen)**
|
|
41
|
+
|
|
39
42
|
---
|
|
40
43
|
|
|
41
44
|
## Table of Contents
|
|
@@ -285,19 +288,21 @@ updateValidated(true);
|
|
|
285
288
|
|
|
286
289
|
See the following code for the PreJoinPage page logic:
|
|
287
290
|
|
|
288
|
-
```
|
|
289
|
-
|
|
291
|
+
```typescript
|
|
292
|
+
import { Component, Inject, Input, OnInit, Optional } from '@angular/core';
|
|
290
293
|
import { FormBuilder, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
|
|
291
294
|
import { CommonModule } from '@angular/common';
|
|
292
295
|
import { Socket } from 'socket.io-client';
|
|
293
296
|
import {
|
|
294
297
|
ConnectSocketType, ShowAlert,
|
|
295
298
|
ConnectLocalSocketType, ResponseLocalConnection,
|
|
296
|
-
ResponseLocalConnectionData, RecordingParams, MeetingRoomParams
|
|
299
|
+
ResponseLocalConnectionData, RecordingParams, MeetingRoomParams,
|
|
300
|
+
CreateMediaSFURoomOptions,JoinMediaSFURoomOptions,
|
|
297
301
|
} from '../../../@types/types';
|
|
298
302
|
import { CheckLimitsAndMakeRequest } from '../../../methods/utils/check-limits-and-make-request.service';
|
|
299
303
|
import { CreateRoomOnMediaSFU } from '../../../methods/utils/create-room-on-media-sfu.service';
|
|
300
|
-
import {
|
|
304
|
+
import { CreateRoomOnMediaSFUType, JoinRoomOnMediaSFUType, JoinRoomOnMediaSFU } from '../../../methods/utils/join-room-on-media-sfu.service';
|
|
305
|
+
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
|
|
301
306
|
|
|
302
307
|
export interface JoinLocalEventRoomParameters {
|
|
303
308
|
eventID: string;
|
|
@@ -367,6 +372,10 @@ export interface PreJoinPageOptions {
|
|
|
367
372
|
connectMediaSFU?: boolean;
|
|
368
373
|
parameters: PreJoinPageParameters;
|
|
369
374
|
credentials?: Credentials;
|
|
375
|
+
returnUI?: boolean;
|
|
376
|
+
noUIPreJoinOptions?: CreateMediaSFURoomOptions | JoinMediaSFURoomOptions;
|
|
377
|
+
createMediaSFURoom?: CreateRoomOnMediaSFUType;
|
|
378
|
+
joinMediaSFURoom?: JoinRoomOnMediaSFUType;
|
|
370
379
|
}
|
|
371
380
|
|
|
372
381
|
export type PreJoinPageType = (options: PreJoinPageOptions) => HTMLElement;
|
|
@@ -451,6 +460,11 @@ export class PreJoinPage implements OnInit {
|
|
|
451
460
|
@Input() credentials: Credentials = { apiUserName: 'yourAPIUSERNAME', apiKey: 'yourAPIKEY' };
|
|
452
461
|
@Input() localLink: string | undefined = "";
|
|
453
462
|
@Input() connectMediaSFU: boolean | undefined = true;
|
|
463
|
+
@Input() returnUI?: boolean;
|
|
464
|
+
@Input() noUIPreJoinOptions?: CreateMediaSFURoomOptions | JoinMediaSFURoomOptions;
|
|
465
|
+
@Input() createMediaSFURoom?: CreateRoomOnMediaSFUType;
|
|
466
|
+
@Input() joinMediaSFURoom?: JoinRoomOnMediaSFUType;
|
|
467
|
+
|
|
454
468
|
|
|
455
469
|
isCreateMode = false;
|
|
456
470
|
preJoinForm: FormGroup;
|
|
@@ -462,15 +476,23 @@ export class PreJoinPage implements OnInit {
|
|
|
462
476
|
localData: ResponseLocalConnectionData | undefined = undefined;
|
|
463
477
|
initSocket: Socket | undefined = undefined;
|
|
464
478
|
|
|
479
|
+
pending = new BehaviorSubject<boolean>(false);
|
|
480
|
+
|
|
465
481
|
constructor(
|
|
466
482
|
private fb: FormBuilder,
|
|
467
483
|
@Optional() @Inject('parameters') injectedParameters: PreJoinPageParameters,
|
|
468
484
|
@Optional() @Inject('credentials') injectedCredentials: Credentials,
|
|
469
485
|
@Optional() @Inject('localLink') injectedLocalLink: string,
|
|
470
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
|
+
|
|
471
493
|
private checkLimitsService: CheckLimitsAndMakeRequest,
|
|
472
494
|
private createRoomService: CreateRoomOnMediaSFU,
|
|
473
|
-
private joinRoomService:
|
|
495
|
+
private joinRoomService: JoinRoomOnMediaSFU
|
|
474
496
|
) {
|
|
475
497
|
this.preJoinForm = this.fb.group({
|
|
476
498
|
name: ['', Validators.required],
|
|
@@ -483,12 +505,22 @@ export class PreJoinPage implements OnInit {
|
|
|
483
505
|
this.credentials = injectedCredentials || this.credentials;
|
|
484
506
|
this.localLink = injectedLocalLink || this.localLink;
|
|
485
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;
|
|
486
512
|
|
|
487
513
|
}
|
|
488
514
|
|
|
489
515
|
ngOnInit(): void {
|
|
516
|
+
// If we have a localLink and not connected yet, try to connect
|
|
490
517
|
if (this.localLink && !this.localConnected && !this.initSocket) {
|
|
491
|
-
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();
|
|
492
524
|
}
|
|
493
525
|
}
|
|
494
526
|
|
|
@@ -509,6 +541,27 @@ export class PreJoinPage implements OnInit {
|
|
|
509
541
|
}
|
|
510
542
|
}
|
|
511
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
|
+
|
|
512
565
|
toggleMode(): void {
|
|
513
566
|
this.isCreateMode = !this.isCreateMode;
|
|
514
567
|
this.error = '';
|
|
@@ -553,10 +606,14 @@ export class PreJoinPage implements OnInit {
|
|
|
553
606
|
|
|
554
607
|
async roomCreator(options: { payload: any; apiUserName: string; apiKey: string; validate?: boolean }): Promise<any> {
|
|
555
608
|
const { payload, apiUserName, apiKey, validate = true } = options;
|
|
556
|
-
|
|
609
|
+
if (!this.createMediaSFURoom) {
|
|
610
|
+
this.createMediaSFURoom = this.createRoomService.createRoomOnMediaSFU;
|
|
611
|
+
}
|
|
612
|
+
const response = await this.createMediaSFURoom({
|
|
557
613
|
payload,
|
|
558
614
|
apiUserName,
|
|
559
615
|
apiKey,
|
|
616
|
+
localLink: this.localLink,
|
|
560
617
|
});
|
|
561
618
|
|
|
562
619
|
if (response.success && response.data && 'roomName' in response.data) {
|
|
@@ -583,21 +640,37 @@ export class PreJoinPage implements OnInit {
|
|
|
583
640
|
|
|
584
641
|
async handleCreateRoom(): Promise<void> {
|
|
585
642
|
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
if (!name || !duration || !eventType || !capacity) {
|
|
589
|
-
this.error = 'Please fill all the fields.';
|
|
643
|
+
if (this.pending.value) {
|
|
590
644
|
return;
|
|
591
645
|
}
|
|
646
|
+
this.pending.next(true);
|
|
647
|
+
let payload = {} as CreateMediaSFURoomOptions;
|
|
592
648
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
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
|
+
}
|
|
601
674
|
|
|
602
675
|
this.parameters.updateIsLoadingModalVisible(true);
|
|
603
676
|
|
|
@@ -611,13 +684,13 @@ export class PreJoinPage implements OnInit {
|
|
|
611
684
|
Math.floor(10 + Math.random() * 99).toString();
|
|
612
685
|
eventID = 'm' + eventID;
|
|
613
686
|
const eventRoomParams = this.localData?.meetingRoomParams_;
|
|
614
|
-
eventRoomParams!.type = eventType as 'chat' | 'broadcast' | 'webinar' | 'conference';
|
|
687
|
+
eventRoomParams!.type = payload.eventType as 'chat' | 'broadcast' | 'webinar' | 'conference';
|
|
615
688
|
|
|
616
689
|
const createData: CreateLocalRoomParameters = {
|
|
617
690
|
eventID: eventID,
|
|
618
|
-
duration:
|
|
619
|
-
capacity:
|
|
620
|
-
userName:
|
|
691
|
+
duration: payload.duration,
|
|
692
|
+
capacity: payload.capacity,
|
|
693
|
+
userName: payload.userName,
|
|
621
694
|
scheduledDate: new Date(),
|
|
622
695
|
secureCode: secureCode,
|
|
623
696
|
waitRoom: false,
|
|
@@ -650,12 +723,14 @@ export class PreJoinPage implements OnInit {
|
|
|
650
723
|
createData.mediasfuURL = response.data.publicURL;
|
|
651
724
|
await this.createLocalRoom({ createData: createData, link: response.data.link });
|
|
652
725
|
} else {
|
|
726
|
+
this.pending.next(false);
|
|
653
727
|
this.parameters.updateIsLoadingModalVisible(false);
|
|
654
728
|
this.error = 'Unable to create room on MediaSFU.';
|
|
655
729
|
try {
|
|
656
730
|
this.parameters.updateSocket(this.initSocket!);
|
|
657
731
|
await this.createLocalRoom({ createData: createData });
|
|
658
732
|
} catch (error: any) {
|
|
733
|
+
this.pending.next(false);
|
|
659
734
|
this.parameters.updateIsLoadingModalVisible(false);
|
|
660
735
|
this.error = `Unable to create room. ${error}`;
|
|
661
736
|
}
|
|
@@ -665,6 +740,7 @@ export class PreJoinPage implements OnInit {
|
|
|
665
740
|
this.parameters.updateSocket(this.initSocket!);
|
|
666
741
|
await this.createLocalRoom({ createData: createData });
|
|
667
742
|
} catch (error: any) {
|
|
743
|
+
this.pending.next(false);
|
|
668
744
|
this.parameters.updateIsLoadingModalVisible(false);
|
|
669
745
|
this.error = `Unable to create room. ${error}`;
|
|
670
746
|
}
|
|
@@ -676,32 +752,44 @@ export class PreJoinPage implements OnInit {
|
|
|
676
752
|
apiKey: this.credentials.apiKey,
|
|
677
753
|
validate: true,
|
|
678
754
|
});
|
|
755
|
+
this.pending.next(false);
|
|
679
756
|
}
|
|
680
757
|
}
|
|
681
758
|
|
|
682
759
|
async handleJoinRoom(): Promise<void> {
|
|
683
|
-
if (this.
|
|
684
|
-
this.error = 'Please fill all the fields.';
|
|
760
|
+
if (this.pending.value) {
|
|
685
761
|
return;
|
|
686
762
|
}
|
|
763
|
+
this.pending.next(true);
|
|
764
|
+
let payload = {} as JoinMediaSFURoomOptions;
|
|
687
765
|
|
|
688
|
-
|
|
766
|
+
if (this.returnUI) {
|
|
767
|
+
const { name, eventID } = this.preJoinForm.value;
|
|
689
768
|
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
769
|
+
if (!name || !eventID) {
|
|
770
|
+
this.error = 'Please fill all the fields.';
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
694
773
|
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
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
|
+
}
|
|
700
788
|
|
|
701
789
|
if (this.localLink && !this.localLink.includes('mediasfu.com')) {
|
|
702
|
-
const joinData = {
|
|
703
|
-
eventID:
|
|
704
|
-
userName:
|
|
790
|
+
const joinData: JoinLocalEventRoomParameters = {
|
|
791
|
+
eventID: payload.meetingID,
|
|
792
|
+
userName: payload.userName,
|
|
705
793
|
secureCode: '',
|
|
706
794
|
videoPreference: null,
|
|
707
795
|
audioPreference: null,
|
|
@@ -709,15 +797,20 @@ export class PreJoinPage implements OnInit {
|
|
|
709
797
|
};
|
|
710
798
|
|
|
711
799
|
await this.joinLocalRoom({ joinData: joinData });
|
|
800
|
+
this.pending.next(false);
|
|
712
801
|
return;
|
|
713
802
|
}
|
|
714
803
|
|
|
715
804
|
this.parameters.updateIsLoadingModalVisible(true);
|
|
716
805
|
try {
|
|
717
|
-
|
|
806
|
+
if (!this.joinMediaSFURoom) {
|
|
807
|
+
this.joinMediaSFURoom = this.joinRoomService.joinRoomOnMediaSFU;
|
|
808
|
+
}
|
|
809
|
+
const response = await this.joinMediaSFURoom({
|
|
718
810
|
payload,
|
|
719
811
|
apiUserName: this.credentials.apiUserName,
|
|
720
812
|
apiKey: this.credentials.apiKey,
|
|
813
|
+
localLink: this.localLink,
|
|
721
814
|
});
|
|
722
815
|
|
|
723
816
|
if (response.success && response.data && 'roomName' in response.data) {
|
|
@@ -725,13 +818,15 @@ export class PreJoinPage implements OnInit {
|
|
|
725
818
|
apiUserName: response.data.roomName,
|
|
726
819
|
apiToken: response.data.secret,
|
|
727
820
|
link: response.data.link,
|
|
728
|
-
userName:
|
|
821
|
+
userName: payload.userName,
|
|
729
822
|
parameters: this.parameters,
|
|
730
823
|
validate: true,
|
|
731
824
|
});
|
|
732
825
|
this.error = '';
|
|
826
|
+
this.pending.next(false);
|
|
733
827
|
} else {
|
|
734
828
|
this.parameters.updateIsLoadingModalVisible(false);
|
|
829
|
+
this.pending.next(false);
|
|
735
830
|
this.error = `Unable to connect to room. ${
|
|
736
831
|
response.data ? ('error' in response.data ? response.data.error : '') : ''
|
|
737
832
|
}`;
|
|
@@ -742,7 +837,6 @@ export class PreJoinPage implements OnInit {
|
|
|
742
837
|
}
|
|
743
838
|
}
|
|
744
839
|
}
|
|
745
|
-
|
|
746
840
|
```
|
|
747
841
|
|
|
748
842
|
### IP Blockage Warning And Local UI Development
|
|
@@ -757,8 +851,7 @@ In this mode, the module will operate locally without making requests to MediaSF
|
|
|
757
851
|
|
|
758
852
|
### Example for Generic UI to Render Broadcast Room
|
|
759
853
|
|
|
760
|
-
```
|
|
761
|
-
|
|
854
|
+
```typescript
|
|
762
855
|
import { Component, OnInit } from '@angular/core';
|
|
763
856
|
import {
|
|
764
857
|
MediasfuBroadcast,
|
|
@@ -863,7 +956,7 @@ export class AppComponent implements OnInit {
|
|
|
863
956
|
|
|
864
957
|
### Example for Generic View
|
|
865
958
|
|
|
866
|
-
```
|
|
959
|
+
```typescript
|
|
867
960
|
import { Component, OnInit } from '@angular/core';
|
|
868
961
|
import {
|
|
869
962
|
GenerateRandomParticipants,
|
|
@@ -878,44 +971,41 @@ import {
|
|
|
878
971
|
PreJoinPage,
|
|
879
972
|
} from 'mediasfu-angular';
|
|
880
973
|
|
|
974
|
+
// Assume all missing imports are similar to the previous example
|
|
975
|
+
|
|
881
976
|
|
|
882
977
|
/**
|
|
883
|
-
*
|
|
884
|
-
*
|
|
885
|
-
* This component initializes the necessary configuration and credentials for the MediaSFU application.
|
|
886
|
-
* Users can specify their own Community Edition (CE) server, utilize MediaSFU Cloud by default, or enable MediaSFU Cloud for egress features.
|
|
978
|
+
* AppComponent
|
|
887
979
|
*
|
|
888
|
-
*
|
|
889
|
-
* -
|
|
890
|
-
* -
|
|
891
|
-
* -
|
|
892
|
-
*
|
|
893
|
-
* - **Credentials Requirement**: If not using your own server, provide `apiUserName` and `apiKey`. The same applies when using MediaSFU Cloud for egress.
|
|
894
|
-
* - **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.
|
|
895
985
|
*
|
|
896
|
-
*
|
|
897
|
-
*
|
|
898
|
-
*
|
|
899
|
-
*
|
|
900
|
-
*
|
|
901
|
-
*
|
|
902
|
-
* imports: [BrowserModule, MediasfuWebinar],
|
|
903
|
-
* bootstrap: [AppComponent]
|
|
904
|
-
* })
|
|
905
|
-
* export class AppModule { }
|
|
906
|
-
* ```
|
|
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.
|
|
907
992
|
*/
|
|
908
993
|
@Component({
|
|
909
994
|
selector: 'app-root',
|
|
910
|
-
imports: [
|
|
995
|
+
imports: [MediasfuGeneric],
|
|
911
996
|
template: `
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
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>
|
|
919
1009
|
`,
|
|
920
1010
|
providers: [
|
|
921
1011
|
GenerateRandomParticipants,
|
|
@@ -925,54 +1015,187 @@ import {
|
|
|
925
1015
|
],
|
|
926
1016
|
})
|
|
927
1017
|
export class AppComponent implements OnInit {
|
|
928
|
-
//
|
|
929
|
-
//
|
|
930
|
-
//
|
|
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
|
+
*/
|
|
931
1030
|
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
*/
|
|
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
|
+
/*
|
|
937
1035
|
credentials = {
|
|
938
|
-
apiUserName: '
|
|
939
|
-
apiKey: '
|
|
1036
|
+
apiUserName: 'dummyUsr', // 8 characters
|
|
1037
|
+
apiKey: '1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef', // 64 characters
|
|
940
1038
|
};
|
|
1039
|
+
localLink = 'http://your-ce-server.com'; // e.g., 'http://localhost:3000'
|
|
1040
|
+
connectMediaSFU = localLink.trim() !== '';
|
|
1041
|
+
*/
|
|
941
1042
|
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
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 } = {};
|
|
947
1082
|
|
|
948
1083
|
/**
|
|
949
|
-
*
|
|
950
|
-
* indicating the use of MediaSFU Cloud by default.
|
|
1084
|
+
* Function to update sourceParameters state.
|
|
951
1085
|
*
|
|
952
|
-
*
|
|
953
|
-
* - If `localLink` is empty, the application will connect to MediaSFU Cloud by default.
|
|
1086
|
+
* @param data - The data to update sourceParameters with.
|
|
954
1087
|
*/
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
// ====== USE CASES ======
|
|
959
|
-
// ========================
|
|
1088
|
+
updateSourceParameters = (data: { [key: string]: any }) => {
|
|
1089
|
+
this.sourceParameters = data;
|
|
1090
|
+
};
|
|
960
1091
|
|
|
961
|
-
//
|
|
962
|
-
//
|
|
963
|
-
//
|
|
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
|
+
// );
|
|
964
1187
|
|
|
965
1188
|
/**
|
|
966
|
-
*
|
|
967
|
-
* for generating random participants and messages.
|
|
1189
|
+
* Default Rendering: MediasfuGeneric with Updated Configuration
|
|
968
1190
|
*
|
|
969
|
-
*
|
|
1191
|
+
* Renders the MediasfuGeneric component with specified server and cloud connection settings.
|
|
1192
|
+
* Configured for custom UI usage if `returnUI` is set to false.
|
|
970
1193
|
*/
|
|
971
|
-
/*
|
|
972
|
-
useSeed = false;
|
|
973
|
-
seedData: any = {};
|
|
974
|
-
|
|
975
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
|
+
/*
|
|
976
1199
|
if (this.useSeed) {
|
|
977
1200
|
const memberName = 'Alice';
|
|
978
1201
|
const hostName = 'Fred';
|
|
@@ -1018,8 +1241,8 @@ export class AppComponent implements OnInit {
|
|
|
1018
1241
|
|
|
1019
1242
|
// Determine whether to use local UI mode
|
|
1020
1243
|
this.useLocalUIMode = this.useSeed;
|
|
1244
|
+
*/
|
|
1021
1245
|
}
|
|
1022
|
-
*/
|
|
1023
1246
|
|
|
1024
1247
|
// ========================
|
|
1025
1248
|
// ====== COMPONENT SELECTION ======
|
|
@@ -1096,7 +1319,6 @@ export class AppComponent implements OnInit {
|
|
|
1096
1319
|
* Renders the MediasfuWebinar component with specified server and cloud connection settings.
|
|
1097
1320
|
* This is the default use case if no specific event type is selected.
|
|
1098
1321
|
*/
|
|
1099
|
-
seedData: any = {}; // Initialize seedData as empty object
|
|
1100
1322
|
|
|
1101
1323
|
// Reference to the PreJoinPage component
|
|
1102
1324
|
PreJoinPage = PreJoinPage;
|
|
@@ -1105,7 +1327,9 @@ export class AppComponent implements OnInit {
|
|
|
1105
1327
|
private generateRandomParticipants: GenerateRandomParticipants,
|
|
1106
1328
|
private generateRandomMessages: GenerateRandomMessages,
|
|
1107
1329
|
private generateRandomRequestList: GenerateRandomRequestList,
|
|
1108
|
-
private generateRandomWaitingRoomList: GenerateRandomWaitingRoomList
|
|
1330
|
+
private generateRandomWaitingRoomList: GenerateRandomWaitingRoomList,
|
|
1331
|
+
public createRoomOnMediaSFU: CreateRoomOnMediaSFU,
|
|
1332
|
+
public joinRoomOnMediaSFU: JoinRoomOnMediaSFU
|
|
1109
1333
|
) { }
|
|
1110
1334
|
|
|
1111
1335
|
// Deprecated Feature: useSeed and seedData for generating random participants and messages
|
|
@@ -1115,59 +1339,203 @@ export class AppComponent implements OnInit {
|
|
|
1115
1339
|
// eventType = 'webinar';
|
|
1116
1340
|
// useLocalUIMode = false;
|
|
1117
1341
|
|
|
1118
|
-
ngOnInit(): void {
|
|
1119
|
-
// If using seed data, generate random participants and messages - DEPRECATED FEATURE
|
|
1120
|
-
// Note: This feature is deprecated and maintained only for legacy purposes.
|
|
1121
|
-
// Uncomment and configure the following section if you intend to use seed data
|
|
1122
|
-
|
|
1123
|
-
// if (this.useSeed) {
|
|
1124
|
-
// const memberName = 'Alice';
|
|
1125
|
-
// const hostName = 'Fred';
|
|
1126
|
-
|
|
1127
|
-
// // Generate random participants
|
|
1128
|
-
// const participants_ = this.generateRandomParticipants.generateRandomParticipants({
|
|
1129
|
-
// member: memberName,
|
|
1130
|
-
// coHost: '',
|
|
1131
|
-
// host: hostName,
|
|
1132
|
-
// forChatBroadcast: this.eventType === 'broadcast' || this.eventType === 'chat',
|
|
1133
|
-
// });
|
|
1134
|
-
|
|
1135
|
-
// // Generate random messages
|
|
1136
|
-
// const messages_ = this.generateRandomMessages.generateRandomMessages({
|
|
1137
|
-
// participants: participants_,
|
|
1138
|
-
// member: memberName,
|
|
1139
|
-
// host: hostName,
|
|
1140
|
-
// forChatBroadcast: this.eventType === 'broadcast' || this.eventType === 'chat',
|
|
1141
|
-
// });
|
|
1142
|
-
|
|
1143
|
-
// // Generate random request list
|
|
1144
|
-
// const requests_ = this.generateRandomRequestList.generateRandomRequestList({
|
|
1145
|
-
// participants: participants_,
|
|
1146
|
-
// hostName: memberName,
|
|
1147
|
-
// coHostName: '',
|
|
1148
|
-
// numberOfRequests: 3,
|
|
1149
|
-
// });
|
|
1150
|
-
|
|
1151
|
-
// // Generate random waiting room list
|
|
1152
|
-
// const waitingList_ = this.generateRandomWaitingRoomList.generateRandomWaitingRoomList();
|
|
1153
|
-
|
|
1154
|
-
// // Assign generated data to seedData
|
|
1155
|
-
// this.seedData = {
|
|
1156
|
-
// participants: participants_,
|
|
1157
|
-
// messages: messages_,
|
|
1158
|
-
// requests: requests_,
|
|
1159
|
-
// waitingList: waitingList_,
|
|
1160
|
-
// member: memberName,
|
|
1161
|
-
// host: hostName,
|
|
1162
|
-
// eventType: this.eventType,
|
|
1163
|
-
// };
|
|
1164
|
-
// }
|
|
1165
|
-
|
|
1166
|
-
// Determine whether to use local UI mode, deprecated feature
|
|
1167
|
-
// this.useLocalUIMode = this.useSeed;
|
|
1168
|
-
}
|
|
1169
1342
|
}
|
|
1170
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
|
+
*/
|
|
1171
1539
|
|
|
1172
1540
|
```
|
|
1173
1541
|
|