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/dist/README.md
CHANGED
|
@@ -23,13 +23,22 @@
|
|
|
23
23
|
|
|
24
24
|
MediaSFU offers a cutting-edge streaming experience that empowers users to customize their recordings and engage their audience with high-quality streams. Whether you're a content creator, educator, or business professional, MediaSFU provides the tools you need to elevate your streaming game.
|
|
25
25
|
|
|
26
|
+
<div style="text-align: center;">
|
|
27
|
+
|
|
28
|
+
<img src="https://mediasfu.com/images/header_1.jpg" alt="Preview Page" title="Preview Page" style="max-height: 600px;">
|
|
29
|
+
|
|
30
|
+
</div>
|
|
31
|
+
|
|
26
32
|
---
|
|
27
33
|
|
|
28
34
|
# MediaSFU Angular Module Documentation
|
|
29
35
|
|
|
30
36
|
## Unlock the Power of MediaSFU Community Edition
|
|
37
|
+
|
|
31
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
|
+
|
|
32
40
|
**[Get started now on GitHub!](https://github.com/MediaSFU/MediaSFUOpen)**
|
|
41
|
+
|
|
33
42
|
---
|
|
34
43
|
|
|
35
44
|
## Table of Contents
|
|
@@ -279,19 +288,21 @@ updateValidated(true);
|
|
|
279
288
|
|
|
280
289
|
See the following code for the PreJoinPage page logic:
|
|
281
290
|
|
|
282
|
-
```
|
|
283
|
-
|
|
291
|
+
```typescript
|
|
292
|
+
import { Component, Inject, Input, OnInit, Optional } from '@angular/core';
|
|
284
293
|
import { FormBuilder, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
|
|
285
294
|
import { CommonModule } from '@angular/common';
|
|
286
295
|
import { Socket } from 'socket.io-client';
|
|
287
296
|
import {
|
|
288
297
|
ConnectSocketType, ShowAlert,
|
|
289
298
|
ConnectLocalSocketType, ResponseLocalConnection,
|
|
290
|
-
ResponseLocalConnectionData, RecordingParams, MeetingRoomParams
|
|
299
|
+
ResponseLocalConnectionData, RecordingParams, MeetingRoomParams,
|
|
300
|
+
CreateMediaSFURoomOptions,JoinMediaSFURoomOptions,
|
|
291
301
|
} from '../../../@types/types';
|
|
292
302
|
import { CheckLimitsAndMakeRequest } from '../../../methods/utils/check-limits-and-make-request.service';
|
|
293
303
|
import { CreateRoomOnMediaSFU } from '../../../methods/utils/create-room-on-media-sfu.service';
|
|
294
|
-
import {
|
|
304
|
+
import { CreateRoomOnMediaSFUType, JoinRoomOnMediaSFUType, JoinRoomOnMediaSFU } from '../../../methods/utils/join-room-on-media-sfu.service';
|
|
305
|
+
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
|
|
295
306
|
|
|
296
307
|
export interface JoinLocalEventRoomParameters {
|
|
297
308
|
eventID: string;
|
|
@@ -361,6 +372,10 @@ export interface PreJoinPageOptions {
|
|
|
361
372
|
connectMediaSFU?: boolean;
|
|
362
373
|
parameters: PreJoinPageParameters;
|
|
363
374
|
credentials?: Credentials;
|
|
375
|
+
returnUI?: boolean;
|
|
376
|
+
noUIPreJoinOptions?: CreateMediaSFURoomOptions | JoinMediaSFURoomOptions;
|
|
377
|
+
createMediaSFURoom?: CreateRoomOnMediaSFUType;
|
|
378
|
+
joinMediaSFURoom?: JoinRoomOnMediaSFUType;
|
|
364
379
|
}
|
|
365
380
|
|
|
366
381
|
export type PreJoinPageType = (options: PreJoinPageOptions) => HTMLElement;
|
|
@@ -445,6 +460,11 @@ export class PreJoinPage implements OnInit {
|
|
|
445
460
|
@Input() credentials: Credentials = { apiUserName: 'yourAPIUSERNAME', apiKey: 'yourAPIKEY' };
|
|
446
461
|
@Input() localLink: string | undefined = "";
|
|
447
462
|
@Input() connectMediaSFU: boolean | undefined = true;
|
|
463
|
+
@Input() returnUI?: boolean;
|
|
464
|
+
@Input() noUIPreJoinOptions?: CreateMediaSFURoomOptions | JoinMediaSFURoomOptions;
|
|
465
|
+
@Input() createMediaSFURoom?: CreateRoomOnMediaSFUType;
|
|
466
|
+
@Input() joinMediaSFURoom?: JoinRoomOnMediaSFUType;
|
|
467
|
+
|
|
448
468
|
|
|
449
469
|
isCreateMode = false;
|
|
450
470
|
preJoinForm: FormGroup;
|
|
@@ -456,15 +476,23 @@ export class PreJoinPage implements OnInit {
|
|
|
456
476
|
localData: ResponseLocalConnectionData | undefined = undefined;
|
|
457
477
|
initSocket: Socket | undefined = undefined;
|
|
458
478
|
|
|
479
|
+
pending = new BehaviorSubject<boolean>(false);
|
|
480
|
+
|
|
459
481
|
constructor(
|
|
460
482
|
private fb: FormBuilder,
|
|
461
483
|
@Optional() @Inject('parameters') injectedParameters: PreJoinPageParameters,
|
|
462
484
|
@Optional() @Inject('credentials') injectedCredentials: Credentials,
|
|
463
485
|
@Optional() @Inject('localLink') injectedLocalLink: string,
|
|
464
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
|
+
|
|
465
493
|
private checkLimitsService: CheckLimitsAndMakeRequest,
|
|
466
494
|
private createRoomService: CreateRoomOnMediaSFU,
|
|
467
|
-
private joinRoomService:
|
|
495
|
+
private joinRoomService: JoinRoomOnMediaSFU
|
|
468
496
|
) {
|
|
469
497
|
this.preJoinForm = this.fb.group({
|
|
470
498
|
name: ['', Validators.required],
|
|
@@ -477,12 +505,22 @@ export class PreJoinPage implements OnInit {
|
|
|
477
505
|
this.credentials = injectedCredentials || this.credentials;
|
|
478
506
|
this.localLink = injectedLocalLink || this.localLink;
|
|
479
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;
|
|
480
512
|
|
|
481
513
|
}
|
|
482
514
|
|
|
483
515
|
ngOnInit(): void {
|
|
516
|
+
// If we have a localLink and not connected yet, try to connect
|
|
484
517
|
if (this.localLink && !this.localConnected && !this.initSocket) {
|
|
485
|
-
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();
|
|
486
524
|
}
|
|
487
525
|
}
|
|
488
526
|
|
|
@@ -503,6 +541,27 @@ export class PreJoinPage implements OnInit {
|
|
|
503
541
|
}
|
|
504
542
|
}
|
|
505
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
|
+
|
|
506
565
|
toggleMode(): void {
|
|
507
566
|
this.isCreateMode = !this.isCreateMode;
|
|
508
567
|
this.error = '';
|
|
@@ -547,10 +606,14 @@ export class PreJoinPage implements OnInit {
|
|
|
547
606
|
|
|
548
607
|
async roomCreator(options: { payload: any; apiUserName: string; apiKey: string; validate?: boolean }): Promise<any> {
|
|
549
608
|
const { payload, apiUserName, apiKey, validate = true } = options;
|
|
550
|
-
|
|
609
|
+
if (!this.createMediaSFURoom) {
|
|
610
|
+
this.createMediaSFURoom = this.createRoomService.createRoomOnMediaSFU;
|
|
611
|
+
}
|
|
612
|
+
const response = await this.createMediaSFURoom({
|
|
551
613
|
payload,
|
|
552
614
|
apiUserName,
|
|
553
615
|
apiKey,
|
|
616
|
+
localLink: this.localLink,
|
|
554
617
|
});
|
|
555
618
|
|
|
556
619
|
if (response.success && response.data && 'roomName' in response.data) {
|
|
@@ -577,21 +640,37 @@ export class PreJoinPage implements OnInit {
|
|
|
577
640
|
|
|
578
641
|
async handleCreateRoom(): Promise<void> {
|
|
579
642
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
if (!name || !duration || !eventType || !capacity) {
|
|
583
|
-
this.error = 'Please fill all the fields.';
|
|
643
|
+
if (this.pending.value) {
|
|
584
644
|
return;
|
|
585
645
|
}
|
|
646
|
+
this.pending.next(true);
|
|
647
|
+
let payload = {} as CreateMediaSFURoomOptions;
|
|
586
648
|
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
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
|
+
}
|
|
595
674
|
|
|
596
675
|
this.parameters.updateIsLoadingModalVisible(true);
|
|
597
676
|
|
|
@@ -605,13 +684,13 @@ export class PreJoinPage implements OnInit {
|
|
|
605
684
|
Math.floor(10 + Math.random() * 99).toString();
|
|
606
685
|
eventID = 'm' + eventID;
|
|
607
686
|
const eventRoomParams = this.localData?.meetingRoomParams_;
|
|
608
|
-
eventRoomParams!.type = eventType as 'chat' | 'broadcast' | 'webinar' | 'conference';
|
|
687
|
+
eventRoomParams!.type = payload.eventType as 'chat' | 'broadcast' | 'webinar' | 'conference';
|
|
609
688
|
|
|
610
689
|
const createData: CreateLocalRoomParameters = {
|
|
611
690
|
eventID: eventID,
|
|
612
|
-
duration:
|
|
613
|
-
capacity:
|
|
614
|
-
userName:
|
|
691
|
+
duration: payload.duration,
|
|
692
|
+
capacity: payload.capacity,
|
|
693
|
+
userName: payload.userName,
|
|
615
694
|
scheduledDate: new Date(),
|
|
616
695
|
secureCode: secureCode,
|
|
617
696
|
waitRoom: false,
|
|
@@ -640,16 +719,18 @@ export class PreJoinPage implements OnInit {
|
|
|
640
719
|
|
|
641
720
|
if (response && response.success && response.data && 'roomName' in response.data) {
|
|
642
721
|
createData.eventID = response.data.roomName;
|
|
643
|
-
createData.secureCode = response.data.
|
|
722
|
+
createData.secureCode = response.data.secureCode;
|
|
644
723
|
createData.mediasfuURL = response.data.publicURL;
|
|
645
724
|
await this.createLocalRoom({ createData: createData, link: response.data.link });
|
|
646
725
|
} else {
|
|
726
|
+
this.pending.next(false);
|
|
647
727
|
this.parameters.updateIsLoadingModalVisible(false);
|
|
648
728
|
this.error = 'Unable to create room on MediaSFU.';
|
|
649
729
|
try {
|
|
650
730
|
this.parameters.updateSocket(this.initSocket!);
|
|
651
731
|
await this.createLocalRoom({ createData: createData });
|
|
652
732
|
} catch (error: any) {
|
|
733
|
+
this.pending.next(false);
|
|
653
734
|
this.parameters.updateIsLoadingModalVisible(false);
|
|
654
735
|
this.error = `Unable to create room. ${error}`;
|
|
655
736
|
}
|
|
@@ -659,6 +740,7 @@ export class PreJoinPage implements OnInit {
|
|
|
659
740
|
this.parameters.updateSocket(this.initSocket!);
|
|
660
741
|
await this.createLocalRoom({ createData: createData });
|
|
661
742
|
} catch (error: any) {
|
|
743
|
+
this.pending.next(false);
|
|
662
744
|
this.parameters.updateIsLoadingModalVisible(false);
|
|
663
745
|
this.error = `Unable to create room. ${error}`;
|
|
664
746
|
}
|
|
@@ -670,32 +752,44 @@ export class PreJoinPage implements OnInit {
|
|
|
670
752
|
apiKey: this.credentials.apiKey,
|
|
671
753
|
validate: true,
|
|
672
754
|
});
|
|
755
|
+
this.pending.next(false);
|
|
673
756
|
}
|
|
674
757
|
}
|
|
675
758
|
|
|
676
759
|
async handleJoinRoom(): Promise<void> {
|
|
677
|
-
if (this.
|
|
678
|
-
this.error = 'Please fill all the fields.';
|
|
760
|
+
if (this.pending.value) {
|
|
679
761
|
return;
|
|
680
762
|
}
|
|
763
|
+
this.pending.next(true);
|
|
764
|
+
let payload = {} as JoinMediaSFURoomOptions;
|
|
681
765
|
|
|
682
|
-
|
|
766
|
+
if (this.returnUI) {
|
|
767
|
+
const { name, eventID } = this.preJoinForm.value;
|
|
683
768
|
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
769
|
+
if (!name || !eventID) {
|
|
770
|
+
this.error = 'Please fill all the fields.';
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
688
773
|
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
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
|
+
}
|
|
694
788
|
|
|
695
789
|
if (this.localLink && !this.localLink.includes('mediasfu.com')) {
|
|
696
|
-
const joinData = {
|
|
697
|
-
eventID:
|
|
698
|
-
userName:
|
|
790
|
+
const joinData: JoinLocalEventRoomParameters = {
|
|
791
|
+
eventID: payload.meetingID,
|
|
792
|
+
userName: payload.userName,
|
|
699
793
|
secureCode: '',
|
|
700
794
|
videoPreference: null,
|
|
701
795
|
audioPreference: null,
|
|
@@ -703,15 +797,20 @@ export class PreJoinPage implements OnInit {
|
|
|
703
797
|
};
|
|
704
798
|
|
|
705
799
|
await this.joinLocalRoom({ joinData: joinData });
|
|
800
|
+
this.pending.next(false);
|
|
706
801
|
return;
|
|
707
802
|
}
|
|
708
803
|
|
|
709
804
|
this.parameters.updateIsLoadingModalVisible(true);
|
|
710
805
|
try {
|
|
711
|
-
|
|
806
|
+
if (!this.joinMediaSFURoom) {
|
|
807
|
+
this.joinMediaSFURoom = this.joinRoomService.joinRoomOnMediaSFU;
|
|
808
|
+
}
|
|
809
|
+
const response = await this.joinMediaSFURoom({
|
|
712
810
|
payload,
|
|
713
811
|
apiUserName: this.credentials.apiUserName,
|
|
714
812
|
apiKey: this.credentials.apiKey,
|
|
813
|
+
localLink: this.localLink,
|
|
715
814
|
});
|
|
716
815
|
|
|
717
816
|
if (response.success && response.data && 'roomName' in response.data) {
|
|
@@ -719,13 +818,15 @@ export class PreJoinPage implements OnInit {
|
|
|
719
818
|
apiUserName: response.data.roomName,
|
|
720
819
|
apiToken: response.data.secret,
|
|
721
820
|
link: response.data.link,
|
|
722
|
-
userName:
|
|
821
|
+
userName: payload.userName,
|
|
723
822
|
parameters: this.parameters,
|
|
724
823
|
validate: true,
|
|
725
824
|
});
|
|
726
825
|
this.error = '';
|
|
826
|
+
this.pending.next(false);
|
|
727
827
|
} else {
|
|
728
828
|
this.parameters.updateIsLoadingModalVisible(false);
|
|
829
|
+
this.pending.next(false);
|
|
729
830
|
this.error = `Unable to connect to room. ${
|
|
730
831
|
response.data ? ('error' in response.data ? response.data.error : '') : ''
|
|
731
832
|
}`;
|
|
@@ -736,7 +837,6 @@ export class PreJoinPage implements OnInit {
|
|
|
736
837
|
}
|
|
737
838
|
}
|
|
738
839
|
}
|
|
739
|
-
|
|
740
840
|
```
|
|
741
841
|
|
|
742
842
|
### IP Blockage Warning And Local UI Development
|
|
@@ -751,8 +851,7 @@ In this mode, the module will operate locally without making requests to MediaSF
|
|
|
751
851
|
|
|
752
852
|
### Example for Generic UI to Render Broadcast Room
|
|
753
853
|
|
|
754
|
-
```
|
|
755
|
-
|
|
854
|
+
```typescript
|
|
756
855
|
import { Component, OnInit } from '@angular/core';
|
|
757
856
|
import {
|
|
758
857
|
MediasfuBroadcast,
|
|
@@ -857,7 +956,7 @@ export class AppComponent implements OnInit {
|
|
|
857
956
|
|
|
858
957
|
### Example for Generic View
|
|
859
958
|
|
|
860
|
-
```
|
|
959
|
+
```typescript
|
|
861
960
|
import { Component, OnInit } from '@angular/core';
|
|
862
961
|
import {
|
|
863
962
|
GenerateRandomParticipants,
|
|
@@ -872,44 +971,41 @@ import {
|
|
|
872
971
|
PreJoinPage,
|
|
873
972
|
} from 'mediasfu-angular';
|
|
874
973
|
|
|
974
|
+
// Assume all missing imports are similar to the previous example
|
|
975
|
+
|
|
875
976
|
|
|
876
977
|
/**
|
|
877
|
-
*
|
|
978
|
+
* AppComponent
|
|
878
979
|
*
|
|
879
|
-
* This component
|
|
880
|
-
*
|
|
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.
|
|
881
985
|
*
|
|
882
|
-
*
|
|
883
|
-
*
|
|
884
|
-
*
|
|
885
|
-
*
|
|
886
|
-
*
|
|
887
|
-
*
|
|
888
|
-
* - **Deprecated Feature**: `useLocalUIMode` is deprecated due to updates for strong typing and improved configuration options.
|
|
889
|
-
*
|
|
890
|
-
* @component
|
|
891
|
-
* @example
|
|
892
|
-
* ```typescript
|
|
893
|
-
* // Example usage of the AppComponent
|
|
894
|
-
* @NgModule({
|
|
895
|
-
* declarations: [AppComponent],
|
|
896
|
-
* imports: [BrowserModule, MediasfuWebinar],
|
|
897
|
-
* bootstrap: [AppComponent]
|
|
898
|
-
* })
|
|
899
|
-
* export class AppModule { }
|
|
900
|
-
* ```
|
|
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.
|
|
901
992
|
*/
|
|
902
993
|
@Component({
|
|
903
994
|
selector: 'app-root',
|
|
904
|
-
imports: [
|
|
995
|
+
imports: [MediasfuGeneric],
|
|
905
996
|
template: `
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
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>
|
|
913
1009
|
`,
|
|
914
1010
|
providers: [
|
|
915
1011
|
GenerateRandomParticipants,
|
|
@@ -919,54 +1015,187 @@ import {
|
|
|
919
1015
|
],
|
|
920
1016
|
})
|
|
921
1017
|
export class AppComponent implements OnInit {
|
|
922
|
-
//
|
|
923
|
-
//
|
|
924
|
-
//
|
|
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
|
+
*/
|
|
925
1030
|
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
*/
|
|
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
|
+
/*
|
|
931
1035
|
credentials = {
|
|
932
|
-
apiUserName: '
|
|
933
|
-
apiKey: '
|
|
1036
|
+
apiUserName: 'dummyUsr', // 8 characters
|
|
1037
|
+
apiKey: '1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef', // 64 characters
|
|
934
1038
|
};
|
|
1039
|
+
localLink = 'http://your-ce-server.com'; // e.g., 'http://localhost:3000'
|
|
1040
|
+
connectMediaSFU = localLink.trim() !== '';
|
|
1041
|
+
*/
|
|
935
1042
|
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
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 } = {};
|
|
941
1082
|
|
|
942
1083
|
/**
|
|
943
|
-
*
|
|
944
|
-
* indicating the use of MediaSFU Cloud by default.
|
|
1084
|
+
* Function to update sourceParameters state.
|
|
945
1085
|
*
|
|
946
|
-
*
|
|
947
|
-
* - If `localLink` is empty, the application will connect to MediaSFU Cloud by default.
|
|
1086
|
+
* @param data - The data to update sourceParameters with.
|
|
948
1087
|
*/
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
// ====== USE CASES ======
|
|
953
|
-
// ========================
|
|
1088
|
+
updateSourceParameters = (data: { [key: string]: any }) => {
|
|
1089
|
+
this.sourceParameters = data;
|
|
1090
|
+
};
|
|
954
1091
|
|
|
955
|
-
//
|
|
956
|
-
//
|
|
957
|
-
//
|
|
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
|
+
// );
|
|
958
1187
|
|
|
959
1188
|
/**
|
|
960
|
-
*
|
|
961
|
-
* for generating random participants and messages.
|
|
1189
|
+
* Default Rendering: MediasfuGeneric with Updated Configuration
|
|
962
1190
|
*
|
|
963
|
-
*
|
|
1191
|
+
* Renders the MediasfuGeneric component with specified server and cloud connection settings.
|
|
1192
|
+
* Configured for custom UI usage if `returnUI` is set to false.
|
|
964
1193
|
*/
|
|
965
|
-
/*
|
|
966
|
-
useSeed = false;
|
|
967
|
-
seedData: any = {};
|
|
968
|
-
|
|
969
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
|
+
/*
|
|
970
1199
|
if (this.useSeed) {
|
|
971
1200
|
const memberName = 'Alice';
|
|
972
1201
|
const hostName = 'Fred';
|
|
@@ -1012,8 +1241,8 @@ export class AppComponent implements OnInit {
|
|
|
1012
1241
|
|
|
1013
1242
|
// Determine whether to use local UI mode
|
|
1014
1243
|
this.useLocalUIMode = this.useSeed;
|
|
1244
|
+
*/
|
|
1015
1245
|
}
|
|
1016
|
-
*/
|
|
1017
1246
|
|
|
1018
1247
|
// ========================
|
|
1019
1248
|
// ====== COMPONENT SELECTION ======
|
|
@@ -1090,7 +1319,6 @@ export class AppComponent implements OnInit {
|
|
|
1090
1319
|
* Renders the MediasfuWebinar component with specified server and cloud connection settings.
|
|
1091
1320
|
* This is the default use case if no specific event type is selected.
|
|
1092
1321
|
*/
|
|
1093
|
-
seedData: any = {}; // Initialize seedData as empty object
|
|
1094
1322
|
|
|
1095
1323
|
// Reference to the PreJoinPage component
|
|
1096
1324
|
PreJoinPage = PreJoinPage;
|
|
@@ -1099,7 +1327,9 @@ export class AppComponent implements OnInit {
|
|
|
1099
1327
|
private generateRandomParticipants: GenerateRandomParticipants,
|
|
1100
1328
|
private generateRandomMessages: GenerateRandomMessages,
|
|
1101
1329
|
private generateRandomRequestList: GenerateRandomRequestList,
|
|
1102
|
-
private generateRandomWaitingRoomList: GenerateRandomWaitingRoomList
|
|
1330
|
+
private generateRandomWaitingRoomList: GenerateRandomWaitingRoomList,
|
|
1331
|
+
public createRoomOnMediaSFU: CreateRoomOnMediaSFU,
|
|
1332
|
+
public joinRoomOnMediaSFU: JoinRoomOnMediaSFU
|
|
1103
1333
|
) { }
|
|
1104
1334
|
|
|
1105
1335
|
// Deprecated Feature: useSeed and seedData for generating random participants and messages
|
|
@@ -1109,59 +1339,203 @@ export class AppComponent implements OnInit {
|
|
|
1109
1339
|
// eventType = 'webinar';
|
|
1110
1340
|
// useLocalUIMode = false;
|
|
1111
1341
|
|
|
1112
|
-
ngOnInit(): void {
|
|
1113
|
-
// If using seed data, generate random participants and messages - DEPRECATED FEATURE
|
|
1114
|
-
// Note: This feature is deprecated and maintained only for legacy purposes.
|
|
1115
|
-
// Uncomment and configure the following section if you intend to use seed data
|
|
1116
|
-
|
|
1117
|
-
// if (this.useSeed) {
|
|
1118
|
-
// const memberName = 'Alice';
|
|
1119
|
-
// const hostName = 'Fred';
|
|
1120
|
-
|
|
1121
|
-
// // Generate random participants
|
|
1122
|
-
// const participants_ = this.generateRandomParticipants.generateRandomParticipants({
|
|
1123
|
-
// member: memberName,
|
|
1124
|
-
// coHost: '',
|
|
1125
|
-
// host: hostName,
|
|
1126
|
-
// forChatBroadcast: this.eventType === 'broadcast' || this.eventType === 'chat',
|
|
1127
|
-
// });
|
|
1128
|
-
|
|
1129
|
-
// // Generate random messages
|
|
1130
|
-
// const messages_ = this.generateRandomMessages.generateRandomMessages({
|
|
1131
|
-
// participants: participants_,
|
|
1132
|
-
// member: memberName,
|
|
1133
|
-
// host: hostName,
|
|
1134
|
-
// forChatBroadcast: this.eventType === 'broadcast' || this.eventType === 'chat',
|
|
1135
|
-
// });
|
|
1136
|
-
|
|
1137
|
-
// // Generate random request list
|
|
1138
|
-
// const requests_ = this.generateRandomRequestList.generateRandomRequestList({
|
|
1139
|
-
// participants: participants_,
|
|
1140
|
-
// hostName: memberName,
|
|
1141
|
-
// coHostName: '',
|
|
1142
|
-
// numberOfRequests: 3,
|
|
1143
|
-
// });
|
|
1144
|
-
|
|
1145
|
-
// // Generate random waiting room list
|
|
1146
|
-
// const waitingList_ = this.generateRandomWaitingRoomList.generateRandomWaitingRoomList();
|
|
1147
|
-
|
|
1148
|
-
// // Assign generated data to seedData
|
|
1149
|
-
// this.seedData = {
|
|
1150
|
-
// participants: participants_,
|
|
1151
|
-
// messages: messages_,
|
|
1152
|
-
// requests: requests_,
|
|
1153
|
-
// waitingList: waitingList_,
|
|
1154
|
-
// member: memberName,
|
|
1155
|
-
// host: hostName,
|
|
1156
|
-
// eventType: this.eventType,
|
|
1157
|
-
// };
|
|
1158
|
-
// }
|
|
1159
|
-
|
|
1160
|
-
// Determine whether to use local UI mode, deprecated feature
|
|
1161
|
-
// this.useLocalUIMode = this.useSeed;
|
|
1162
|
-
}
|
|
1163
1342
|
}
|
|
1164
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
|
+
*/
|
|
1165
1539
|
|
|
1166
1540
|
```
|
|
1167
1541
|
|