@antmedia/web_player 2.8.2 → 2.8.3-ALPHA-29-03-2024

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.
@@ -22,7 +22,8 @@ jobs:
22
22
  - run: npm install --include=dev
23
23
  - run: npm run compile
24
24
  - run: npm test
25
- - run: npm version SNAPSHOT"-`date +"%Y-%b-%d-%I-%M"`" --no-git-tag-version
25
+ #Fix this versioning for the snapshots
26
+ - run: npm version 2.8.3-SNAPSHOT"-`date +"%Y-%b-%d-%I-%M"`" --no-git-tag-version
26
27
  - run: npm publish --tag SNAPSHOT
27
28
  env:
28
29
  NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
package/README.md CHANGED
@@ -20,59 +20,71 @@ Install the Web Player package using npm:
20
20
  npm i @antmedia/web_player
21
21
  ```
22
22
 
23
- ## Configuration Parameters
24
-
25
- The player accepts several configuration parameters, either through the URL or directly in the code:
26
-
27
- 1. `id` (String): The stream ID to play. This parameter is mandatory.
28
- 2. `token` (String): The token for stream access. It's mandatory if token security is enabled on the server side.
29
- 3. `autoplay` (Boolean): Autoplay the stream if available. Optional. Default value is `true`.
30
- 4. `mute` (Boolean): Start playing in mute mode if the stream is available. Optional. Default value is `true`.
31
- 5. `playOrder` (String): The order of technologies used for playing. Optional. Default value is `"webrtc,hls"`. Possible values include `"hls,webrtc"`, `"webrtc"`, `"hls"`, `"vod"`, `"dash"`.
32
- 6. `playType` (String): The order of play types used for playing. Optional. Default value is `"mp4,webm"`. Possible values include `"webm,mp4"`, `"mp4"`, `"webm"`, `"mov"`.
33
- 7. `targetLatency` (Number): The target latency for the DASH player. Optional. Default value is `3`.
34
- 8. `is360` (Boolean): Enable playback in 360 mode. Optional. Default value is `false`.
35
-
36
23
  ## Usage
37
24
 
38
25
  ### Basic Usage
39
26
 
40
- Import the `WebPlayer` and initialize it with the desired configuration:
27
+ To use the Web Player, import it and initialize it with the parameters received from the URL. Refer to the Configuration Parameters section below for more details.
41
28
 
42
- ```javascript
43
- import { WebPlayer } from "@antmedia/web_player";
29
+ 1. In your web application, create a div with the id video_container. This will serve as the container for the player.
44
30
 
45
- var embeddedPlayer = new WebPlayer(window, document.getElementById("video_container"), document.getElementById("video_info"));
31
+ ```
32
+ <div id="video_container" ></div>
33
+ ````
34
+
35
+ 2. Initialize the player as follows:
36
+ ```javascript
37
+ import { WebPlayer } from "@antmedia/web_player";
46
38
 
47
- embeddedPlayer.initialize().then(() => {
39
+ var embeddedPlayer = new WebPlayer(window, document.getElementById("video_container"), null);
40
+
41
+ embeddedPlayer.initialize().then(() => {
48
42
  embeddedPlayer.play();
49
- });
50
- ```
43
+ });
44
+ ```
51
45
 
52
46
  The sample for this usage is available in [play.html in StreamApp](https://github.com/ant-media/StreamApp/blob/master/src/main/webapp/play.html)
53
47
 
54
48
  ### Advanced Usage
55
- You can also pass the parameters as an object to the WebPlayer constructor:
56
-
57
- ```javascript
58
- var player = new WebPlayer({
59
- streamId: streamId,
60
- httpBaseURL: "http://example.antmedia.io:5080/WebRTCAppEE",
61
- token: tokenId,
62
- playOrder: ["webrtc", "hls", "dash"],
63
- videoHTMLContent: '<video id="video-player" class="video-js vjs-default-skin vjs-big-play-centered" controls playsinline style="width:100%;height:100%"></video>',
64
- }, document.getElementById("video_container"), null);
65
-
66
- player.initialize().then(() => {
49
+ Alternatively, you can pass the parameters as an object to the WebPlayer constructor.
50
+
51
+
52
+ 1. In your web application, create a div with the id video_container. This will serve as the container for the player.
53
+ ```
54
+ <div id="video_container" ></div>
55
+ ````
56
+
57
+ 2. Initialize the player as follows
58
+ ```javascript
59
+ var player = new WebPlayer({
60
+ streamId: "myStreamId",
61
+ httpBaseURL: "http://example.antmedia.io:5080/WebRTCAppEE/", //Remember to add trailing slash(/)
62
+ }, document.getElementById("video_container"), null);
63
+
64
+ player.initialize().then(() => {
67
65
  player.play();
68
- }).catch((error) => {
66
+ }).catch((error) => {
69
67
  console.error("Error while initializing embedded player: " + error);
70
- });
71
- ```
68
+ });
69
+ ```
72
70
 
73
71
  The sample for this usage is available in [app.page.component.ts in Ant-Media-Management-Console](https://github.com/ant-media/Ant-Media-Management-Console/blob/master/src/app/app.page/app.page.component.ts)
74
72
 
75
73
 
74
+ ## Configuration Parameters
75
+
76
+ The player accepts several configuration parameters, either through the URL or directly in the code:
77
+
78
+ 1. `id` (String): The stream ID to play. This parameter is mandatory.
79
+ 2. `token` (String): The token for stream access. It's mandatory if token security is enabled on the server side.
80
+ 3. `autoplay` (Boolean): Autoplay the stream if available. Optional. Default value is `true`.
81
+ 4. `mute` (Boolean): Start playing in mute mode if the stream is available. Optional. Default value is `true`.
82
+ 5. `playOrder` (String): The order of technologies used for playing. Optional. Default value is `"webrtc,hls"`. Possible values include `"hls,webrtc"`, `"webrtc"`, `"hls"`, `"vod"`, `"dash"`.
83
+ 6. `playType` (String): The order of play types used for playing. Optional. Default value is `"mp4,webm"`. Possible values include `"webm,mp4"`, `"mp4"`, `"webm"`, `"mov"`.
84
+ 7. `targetLatency` (Number): The target latency for the DASH player. Optional. Default value is `3`.
85
+ 8. `is360` (Boolean): Enable playback in 360 mode. Optional. Default value is `false`.
86
+
87
+
76
88
  ## Support
77
89
  For support and further inquiries, please visit [Ant Media Server's community](https://github.com/orgs/ant-media/discussions). If you are an enterprise user, you can receive support by sending an email to support@antmedia.io.
78
90
 
@@ -112,11 +112,14 @@
112
112
  */
113
113
  _defineProperty(this, "autoPlay", true);
114
114
  /**
115
- * mute: if true, player will be started muted. Optional. Default value is true.
116
- * default value is true because of browser's autoplay policy.
115
+ * mute: if false the player will try to auto play the stream with audio if it fails player will mute the audio and try again to autoplay it.
117
116
  * It will be taken from url parameter "mute".
118
117
  */
119
- _defineProperty(this, "mute", true);
118
+ _defineProperty(this, "mute", false);
119
+ /**
120
+ * Force the Player to play with audio Auto Play might not work.
121
+ */
122
+ _defineProperty(this, "forcePlayWithAudio", false);
120
123
  /**
121
124
  * targetLatency: target latency in seconds. Optional. Default value is 3.
122
125
  * It will be taken from url parameter "targetLatency".
@@ -293,7 +296,7 @@
293
296
  this.playType = WebPlayer.DEFAULT_PLAY_TYPE;
294
297
  this.token = null;
295
298
  this.autoPlay = true;
296
- this.mute = true;
299
+ this.mute = false;
297
300
  this.targetLatency = 3;
298
301
  this.subscriberId = null;
299
302
  this.subscriberCode = null;
@@ -317,6 +320,7 @@
317
320
  this.dashjsLoaded = false;
318
321
  this.containerElementInitialDisplay = "block";
319
322
  this.placeHolderElementInitialDisplay = "block";
323
+ this.forcePlayWithAudio = false;
320
324
  }
321
325
  initializeFromUrlParams() {
322
326
  var _getUrlParameter;
@@ -342,7 +346,9 @@
342
346
  var muteLocal = fetch_stream.getUrlParameter("mute", this.window.location.search);
343
347
  if (muteLocal === "false") {
344
348
  this.mute = false;
345
- } else {
349
+ //user specifically asks to play with audio so if it fails in auto play, it will not try to play without audio
350
+ this.forcePlayWithAudio = true;
351
+ } else if (muteLocal === "true") {
346
352
  this.mute = true;
347
353
  }
348
354
  var localTargetLatency = fetch_stream.getUrlParameter("targetLatency", this.window.location.search);
@@ -514,7 +520,7 @@
514
520
  autoplay: this.autoPlay
515
521
  });
516
522
  this.videojsPlayer.on('error', e => {
517
- loglevel_min.Logger.warn("There is an error in playback: " + e);
523
+ loglevel_min.Logger.warn("There is an error in playback: ", e);
518
524
  // We need to add this kind of check. If we don't add this kind of checkpoint, it will create an infinite loop
519
525
  if (!this.errorCalled) {
520
526
  this.errorCalled = true;
@@ -559,15 +565,21 @@
559
565
  //hls specific calls
560
566
  if (extension == "m3u8") {
561
567
  videojs.Vhs.xhr.beforeRequest = options => {
562
- var securityParams = this.getSecurityQueryParams();
563
- if (!options.uri.includes(securityParams)) {
564
- if (!options.uri.endsWith("?")) {
565
- options.uri = options.uri + "?";
566
- }
567
- options.uri += securityParams;
568
+ var queryParams = [];
569
+ if (!options.uri.includes("subscriberId") && this.subscriberId != null) {
570
+ queryParams.push("subscriberId=".concat(this.subscriberId));
571
+ }
572
+ if (!options.uri.includes("subscriberCode") && this.subscriberCode != null) {
573
+ queryParams.push("subscriberCode=".concat(this.subscriberCode));
574
+ }
575
+ if (!options.uri.includes("token") && this.token != null) {
576
+ queryParams.push("token=".concat(this.token));
577
+ }
578
+ if (queryParams.length > 0) {
579
+ var queryString = queryParams.join("&");
580
+ options.uri += options.uri.includes("?") ? "&".concat(queryString) : "?".concat(queryString);
568
581
  }
569
582
  loglevel_min.Logger.debug("hls request: " + options.uri);
570
- return options;
571
583
  };
572
584
  this.videojsPlayer.ready(() => {
573
585
  // If it's already added to player, no need to add again
@@ -654,7 +666,16 @@
654
666
  reconnect: false //webrtc adaptor has auto reconnect scenario, just disable it, we manage it here
655
667
  });
656
668
  if (this.autoPlay) {
669
+ //try to play directly
657
670
  this.videojsPlayer.play().catch(e => {
671
+ //if it's not allowed error and default value are being used, try to play it muted
672
+ //if this.forcePlayWithAudio is true, it means user specifically ask to do.
673
+ // If it's false, it's default value so that we can proceed to try to play with muted
674
+ //This implementation is added because of auto play policy of the browsers
675
+ if (e.name === "NotAllowedError" && !this.forcePlayWithAudio) {
676
+ this.videojsPlayer.muted(true);
677
+ this.videojsPlayer.play();
678
+ }
658
679
  loglevel_min.Logger.warn("Problem in playback. The error is " + e);
659
680
  });
660
681
  }
@@ -814,11 +835,26 @@
814
835
  }
815
836
  });
816
837
  this.dashPlayer.on(dashjs.MediaPlayer.events.PLAYBACK_ERROR, event => {
838
+ loglevel_min.Logger.warn("dash playback error: " + event);
817
839
  this.tryNextTech();
818
840
  });
819
841
  this.dashPlayer.on(dashjs.MediaPlayer.events.ERROR, event => {
842
+ loglevel_min.Logger.warn("error: " + event);
820
843
  this.tryNextTech();
821
844
  });
845
+ this.dashPlayer.on(dashjs.MediaPlayer.events.PLAYBACK_NOT_ALLOWED, event => {
846
+ loglevel_min.Logger.warn("dash playback not allowed: " + event);
847
+ this.handleDashPlayBackNotAllowed();
848
+ });
849
+ }
850
+ handleDashPlayBackNotAllowed() {
851
+ if (!this.forcePlayWithAudio) {
852
+ loglevel_min.Logger.info("Try to play with muted audio");
853
+ this.dashPlayer.setMute(true);
854
+ this.dashPlayer.play();
855
+ } else {
856
+ this.tryNextTech();
857
+ }
822
858
  }
823
859
  makeDashPlayerVisibleWhenInitialized() {
824
860
  this.dashPlayer.on(dashjs.MediaPlayer.events.STREAM_INITIALIZED, event => {
@@ -55,11 +55,14 @@ export declare class WebPlayer {
55
55
  */
56
56
  autoPlay: boolean;
57
57
  /**
58
- * mute: if true, player will be started muted. Optional. Default value is true.
59
- * default value is true because of browser's autoplay policy.
58
+ * mute: if false the player will try to auto play the stream with audio if it fails player will mute the audio and try again to autoplay it.
60
59
  * It will be taken from url parameter "mute".
61
60
  */
62
61
  mute: boolean;
62
+ /**
63
+ * Force the Player to play with audio Auto Play might not work.
64
+ */
65
+ forcePlayWithAudio: boolean;
63
66
  /**
64
67
  * targetLatency: target latency in seconds. Optional. Default value is 3.
65
68
  * It will be taken from url parameter "targetLatency".
@@ -176,6 +179,7 @@ export declare class WebPlayer {
176
179
  */
177
180
  playViaDash(streamUrl: any): void;
178
181
  dashLatencyTimer: NodeJS.Timeout | undefined;
182
+ handleDashPlayBackNotAllowed(): void;
179
183
  makeDashPlayerVisibleWhenInitialized(): void;
180
184
  /**
181
185
  * destroy the dash player
@@ -400,11 +400,14 @@ class WebPlayer {
400
400
  */
401
401
  _defineProperty(this, "autoPlay", true);
402
402
  /**
403
- * mute: if true, player will be started muted. Optional. Default value is true.
404
- * default value is true because of browser's autoplay policy.
403
+ * mute: if false the player will try to auto play the stream with audio if it fails player will mute the audio and try again to autoplay it.
405
404
  * It will be taken from url parameter "mute".
406
405
  */
407
- _defineProperty(this, "mute", true);
406
+ _defineProperty(this, "mute", false);
407
+ /**
408
+ * Force the Player to play with audio Auto Play might not work.
409
+ */
410
+ _defineProperty(this, "forcePlayWithAudio", false);
408
411
  /**
409
412
  * targetLatency: target latency in seconds. Optional. Default value is 3.
410
413
  * It will be taken from url parameter "targetLatency".
@@ -581,7 +584,7 @@ class WebPlayer {
581
584
  this.playType = WebPlayer.DEFAULT_PLAY_TYPE;
582
585
  this.token = null;
583
586
  this.autoPlay = true;
584
- this.mute = true;
587
+ this.mute = false;
585
588
  this.targetLatency = 3;
586
589
  this.subscriberId = null;
587
590
  this.subscriberCode = null;
@@ -605,6 +608,7 @@ class WebPlayer {
605
608
  this.dashjsLoaded = false;
606
609
  this.containerElementInitialDisplay = "block";
607
610
  this.placeHolderElementInitialDisplay = "block";
611
+ this.forcePlayWithAudio = false;
608
612
  }
609
613
  initializeFromUrlParams() {
610
614
  var _getUrlParameter;
@@ -630,7 +634,9 @@ class WebPlayer {
630
634
  var muteLocal = getUrlParameter_1("mute", this.window.location.search);
631
635
  if (muteLocal === "false") {
632
636
  this.mute = false;
633
- } else {
637
+ //user specifically asks to play with audio so if it fails in auto play, it will not try to play without audio
638
+ this.forcePlayWithAudio = true;
639
+ } else if (muteLocal === "true") {
634
640
  this.mute = true;
635
641
  }
636
642
  var localTargetLatency = getUrlParameter_1("targetLatency", this.window.location.search);
@@ -802,7 +808,7 @@ class WebPlayer {
802
808
  autoplay: this.autoPlay
803
809
  });
804
810
  this.videojsPlayer.on('error', e => {
805
- Logger_1.warn("There is an error in playback: " + e);
811
+ Logger_1.warn("There is an error in playback: ", e);
806
812
  // We need to add this kind of check. If we don't add this kind of checkpoint, it will create an infinite loop
807
813
  if (!this.errorCalled) {
808
814
  this.errorCalled = true;
@@ -847,15 +853,21 @@ class WebPlayer {
847
853
  //hls specific calls
848
854
  if (extension == "m3u8") {
849
855
  videojs.Vhs.xhr.beforeRequest = options => {
850
- var securityParams = this.getSecurityQueryParams();
851
- if (!options.uri.includes(securityParams)) {
852
- if (!options.uri.endsWith("?")) {
853
- options.uri = options.uri + "?";
854
- }
855
- options.uri += securityParams;
856
+ var queryParams = [];
857
+ if (!options.uri.includes("subscriberId") && this.subscriberId != null) {
858
+ queryParams.push("subscriberId=".concat(this.subscriberId));
859
+ }
860
+ if (!options.uri.includes("subscriberCode") && this.subscriberCode != null) {
861
+ queryParams.push("subscriberCode=".concat(this.subscriberCode));
862
+ }
863
+ if (!options.uri.includes("token") && this.token != null) {
864
+ queryParams.push("token=".concat(this.token));
865
+ }
866
+ if (queryParams.length > 0) {
867
+ var queryString = queryParams.join("&");
868
+ options.uri += options.uri.includes("?") ? "&".concat(queryString) : "?".concat(queryString);
856
869
  }
857
870
  Logger_1.debug("hls request: " + options.uri);
858
- return options;
859
871
  };
860
872
  this.videojsPlayer.ready(() => {
861
873
  // If it's already added to player, no need to add again
@@ -942,7 +954,16 @@ class WebPlayer {
942
954
  reconnect: false //webrtc adaptor has auto reconnect scenario, just disable it, we manage it here
943
955
  });
944
956
  if (this.autoPlay) {
957
+ //try to play directly
945
958
  this.videojsPlayer.play().catch(e => {
959
+ //if it's not allowed error and default value are being used, try to play it muted
960
+ //if this.forcePlayWithAudio is true, it means user specifically ask to do.
961
+ // If it's false, it's default value so that we can proceed to try to play with muted
962
+ //This implementation is added because of auto play policy of the browsers
963
+ if (e.name === "NotAllowedError" && !this.forcePlayWithAudio) {
964
+ this.videojsPlayer.muted(true);
965
+ this.videojsPlayer.play();
966
+ }
946
967
  Logger_1.warn("Problem in playback. The error is " + e);
947
968
  });
948
969
  }
@@ -1102,11 +1123,26 @@ class WebPlayer {
1102
1123
  }
1103
1124
  });
1104
1125
  this.dashPlayer.on(dashjs.MediaPlayer.events.PLAYBACK_ERROR, event => {
1126
+ Logger_1.warn("dash playback error: " + event);
1105
1127
  this.tryNextTech();
1106
1128
  });
1107
1129
  this.dashPlayer.on(dashjs.MediaPlayer.events.ERROR, event => {
1130
+ Logger_1.warn("error: " + event);
1108
1131
  this.tryNextTech();
1109
1132
  });
1133
+ this.dashPlayer.on(dashjs.MediaPlayer.events.PLAYBACK_NOT_ALLOWED, event => {
1134
+ Logger_1.warn("dash playback not allowed: " + event);
1135
+ this.handleDashPlayBackNotAllowed();
1136
+ });
1137
+ }
1138
+ handleDashPlayBackNotAllowed() {
1139
+ if (!this.forcePlayWithAudio) {
1140
+ Logger_1.info("Try to play with muted audio");
1141
+ this.dashPlayer.setMute(true);
1142
+ this.dashPlayer.play();
1143
+ } else {
1144
+ this.tryNextTech();
1145
+ }
1110
1146
  }
1111
1147
  makeDashPlayerVisibleWhenInitialized() {
1112
1148
  this.dashPlayer.on(dashjs.MediaPlayer.events.STREAM_INITIALIZED, event => {
package/dist/index.d.ts CHANGED
@@ -55,11 +55,14 @@ export declare class WebPlayer {
55
55
  */
56
56
  autoPlay: boolean;
57
57
  /**
58
- * mute: if true, player will be started muted. Optional. Default value is true.
59
- * default value is true because of browser's autoplay policy.
58
+ * mute: if false the player will try to auto play the stream with audio if it fails player will mute the audio and try again to autoplay it.
60
59
  * It will be taken from url parameter "mute".
61
60
  */
62
61
  mute: boolean;
62
+ /**
63
+ * Force the Player to play with audio Auto Play might not work.
64
+ */
65
+ forcePlayWithAudio: boolean;
63
66
  /**
64
67
  * targetLatency: target latency in seconds. Optional. Default value is 3.
65
68
  * It will be taken from url parameter "targetLatency".
@@ -122,8 +125,10 @@ export declare class WebPlayer {
122
125
  * Field to keep if tryNextMethod is already called
123
126
  */
124
127
  tryNextTechTimer: any;
125
- websocketURL: any;
128
+ containerElementInitialDisplay: any;
129
+ placeHolderElementInitialDisplay: any;
126
130
  httpBaseURL: string;
131
+ websocketURL: any;
127
132
  dom: any;
128
133
  isWindow(configOrWindow: any): any;
129
134
  initialize(): Promise<any>;
@@ -174,6 +179,7 @@ export declare class WebPlayer {
174
179
  */
175
180
  playViaDash(streamUrl: any): void;
176
181
  dashLatencyTimer: NodeJS.Timeout | undefined;
182
+ handleDashPlayBackNotAllowed(): void;
177
183
  makeDashPlayerVisibleWhenInitialized(): void;
178
184
  /**
179
185
  * destroy the dash player
@@ -402,11 +402,14 @@ class WebPlayer {
402
402
  */
403
403
  _defineProperty(this, "autoPlay", true);
404
404
  /**
405
- * mute: if true, player will be started muted. Optional. Default value is true.
406
- * default value is true because of browser's autoplay policy.
405
+ * mute: if false the player will try to auto play the stream with audio if it fails player will mute the audio and try again to autoplay it.
407
406
  * It will be taken from url parameter "mute".
408
407
  */
409
- _defineProperty(this, "mute", true);
408
+ _defineProperty(this, "mute", false);
409
+ /**
410
+ * Force the Player to play with audio Auto Play might not work.
411
+ */
412
+ _defineProperty(this, "forcePlayWithAudio", false);
410
413
  /**
411
414
  * targetLatency: target latency in seconds. Optional. Default value is 3.
412
415
  * It will be taken from url parameter "targetLatency".
@@ -583,7 +586,7 @@ class WebPlayer {
583
586
  this.playType = WebPlayer.DEFAULT_PLAY_TYPE;
584
587
  this.token = null;
585
588
  this.autoPlay = true;
586
- this.mute = true;
589
+ this.mute = false;
587
590
  this.targetLatency = 3;
588
591
  this.subscriberId = null;
589
592
  this.subscriberCode = null;
@@ -607,6 +610,7 @@ class WebPlayer {
607
610
  this.dashjsLoaded = false;
608
611
  this.containerElementInitialDisplay = "block";
609
612
  this.placeHolderElementInitialDisplay = "block";
613
+ this.forcePlayWithAudio = false;
610
614
  }
611
615
  initializeFromUrlParams() {
612
616
  var _getUrlParameter;
@@ -632,7 +636,9 @@ class WebPlayer {
632
636
  var muteLocal = getUrlParameter_1("mute", this.window.location.search);
633
637
  if (muteLocal === "false") {
634
638
  this.mute = false;
635
- } else {
639
+ //user specifically asks to play with audio so if it fails in auto play, it will not try to play without audio
640
+ this.forcePlayWithAudio = true;
641
+ } else if (muteLocal === "true") {
636
642
  this.mute = true;
637
643
  }
638
644
  var localTargetLatency = getUrlParameter_1("targetLatency", this.window.location.search);
@@ -804,7 +810,7 @@ class WebPlayer {
804
810
  autoplay: this.autoPlay
805
811
  });
806
812
  this.videojsPlayer.on('error', e => {
807
- Logger_1.warn("There is an error in playback: " + e);
813
+ Logger_1.warn("There is an error in playback: ", e);
808
814
  // We need to add this kind of check. If we don't add this kind of checkpoint, it will create an infinite loop
809
815
  if (!this.errorCalled) {
810
816
  this.errorCalled = true;
@@ -849,15 +855,21 @@ class WebPlayer {
849
855
  //hls specific calls
850
856
  if (extension == "m3u8") {
851
857
  videojs.Vhs.xhr.beforeRequest = options => {
852
- var securityParams = this.getSecurityQueryParams();
853
- if (!options.uri.includes(securityParams)) {
854
- if (!options.uri.endsWith("?")) {
855
- options.uri = options.uri + "?";
856
- }
857
- options.uri += securityParams;
858
+ var queryParams = [];
859
+ if (!options.uri.includes("subscriberId") && this.subscriberId != null) {
860
+ queryParams.push("subscriberId=".concat(this.subscriberId));
861
+ }
862
+ if (!options.uri.includes("subscriberCode") && this.subscriberCode != null) {
863
+ queryParams.push("subscriberCode=".concat(this.subscriberCode));
864
+ }
865
+ if (!options.uri.includes("token") && this.token != null) {
866
+ queryParams.push("token=".concat(this.token));
867
+ }
868
+ if (queryParams.length > 0) {
869
+ var queryString = queryParams.join("&");
870
+ options.uri += options.uri.includes("?") ? "&".concat(queryString) : "?".concat(queryString);
858
871
  }
859
872
  Logger_1.debug("hls request: " + options.uri);
860
- return options;
861
873
  };
862
874
  this.videojsPlayer.ready(() => {
863
875
  // If it's already added to player, no need to add again
@@ -944,7 +956,16 @@ class WebPlayer {
944
956
  reconnect: false //webrtc adaptor has auto reconnect scenario, just disable it, we manage it here
945
957
  });
946
958
  if (this.autoPlay) {
959
+ //try to play directly
947
960
  this.videojsPlayer.play().catch(e => {
961
+ //if it's not allowed error and default value are being used, try to play it muted
962
+ //if this.forcePlayWithAudio is true, it means user specifically ask to do.
963
+ // If it's false, it's default value so that we can proceed to try to play with muted
964
+ //This implementation is added because of auto play policy of the browsers
965
+ if (e.name === "NotAllowedError" && !this.forcePlayWithAudio) {
966
+ this.videojsPlayer.muted(true);
967
+ this.videojsPlayer.play();
968
+ }
948
969
  Logger_1.warn("Problem in playback. The error is " + e);
949
970
  });
950
971
  }
@@ -1104,11 +1125,26 @@ class WebPlayer {
1104
1125
  }
1105
1126
  });
1106
1127
  this.dashPlayer.on(dashjs.MediaPlayer.events.PLAYBACK_ERROR, event => {
1128
+ Logger_1.warn("dash playback error: " + event);
1107
1129
  this.tryNextTech();
1108
1130
  });
1109
1131
  this.dashPlayer.on(dashjs.MediaPlayer.events.ERROR, event => {
1132
+ Logger_1.warn("error: " + event);
1110
1133
  this.tryNextTech();
1111
1134
  });
1135
+ this.dashPlayer.on(dashjs.MediaPlayer.events.PLAYBACK_NOT_ALLOWED, event => {
1136
+ Logger_1.warn("dash playback not allowed: " + event);
1137
+ this.handleDashPlayBackNotAllowed();
1138
+ });
1139
+ }
1140
+ handleDashPlayBackNotAllowed() {
1141
+ if (!this.forcePlayWithAudio) {
1142
+ Logger_1.info("Try to play with muted audio");
1143
+ this.dashPlayer.setMute(true);
1144
+ this.dashPlayer.play();
1145
+ } else {
1146
+ this.tryNextTech();
1147
+ }
1112
1148
  }
1113
1149
  makeDashPlayerVisibleWhenInitialized() {
1114
1150
  this.dashPlayer.on(dashjs.MediaPlayer.events.STREAM_INITIALIZED, event => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antmedia/web_player",
3
- "version": "2.8.2",
3
+ "version": "2.8.3-ALPHA-29-03-2024",
4
4
  "description": "Ant Media Server Player that can play WebRTC, HLS, DASH",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/es/index.js",
package/src/web_player.js CHANGED
@@ -78,17 +78,22 @@ export class WebPlayer {
78
78
  autoPlay = true;
79
79
 
80
80
  /**
81
- * mute: if true, player will be started muted. Optional. Default value is true.
82
- * default value is true because of browser's autoplay policy.
81
+ * mute: if false the player will try to auto play the stream with audio if it fails player will mute the audio and try again to autoplay it.
83
82
  * It will be taken from url parameter "mute".
84
83
  */
85
- mute = true;
84
+ mute = false;
85
+
86
+ /**
87
+ * Force the Player to play with audio Auto Play might not work.
88
+ */
89
+ forcePlayWithAudio = false;
86
90
 
87
91
  /**
88
92
  * targetLatency: target latency in seconds. Optional. Default value is 3.
89
93
  * It will be taken from url parameter "targetLatency".
90
94
  * It's used for dash(cmaf) playback.
91
95
  */
96
+
92
97
  targetLatency = 3;
93
98
 
94
99
  /**
@@ -161,6 +166,7 @@ export class WebPlayer {
161
166
  */
162
167
  tryNextTechTimer;
163
168
 
169
+
164
170
  constructor(configOrWindow, containerElement, placeHolderElement) {
165
171
 
166
172
  WebPlayer.DEFAULT_PLAY_ORDER = ["webrtc", "hls"];;
@@ -312,7 +318,7 @@ export class WebPlayer {
312
318
  this.playType = WebPlayer.DEFAULT_PLAY_TYPE;
313
319
  this.token = null;
314
320
  this.autoPlay = true;
315
- this.mute = true;
321
+ this.mute = false;
316
322
  this.targetLatency = 3;
317
323
  this.subscriberId = null;
318
324
  this.subscriberCode = null;
@@ -336,6 +342,7 @@ export class WebPlayer {
336
342
  this.dashjsLoaded = false;
337
343
  this.containerElementInitialDisplay = "block";
338
344
  this.placeHolderElementInitialDisplay = "block";
345
+ this.forcePlayWithAudio = false;
339
346
  }
340
347
 
341
348
  initializeFromUrlParams() {
@@ -365,11 +372,13 @@ export class WebPlayer {
365
372
 
366
373
  let muteLocal = getUrlParameter("mute", this.window.location.search);
367
374
  if (muteLocal === "false") {
368
- this.mute = false;
369
- }
370
- else {
371
- this.mute = true;
372
- }
375
+ this.mute = false;
376
+ //user specifically asks to play with audio so if it fails in auto play, it will not try to play without audio
377
+ this.forcePlayWithAudio = true;
378
+ }else if(muteLocal === "true"){
379
+ this.mute = true;
380
+ }
381
+
373
382
 
374
383
  let localTargetLatency = getUrlParameter("targetLatency", this.window.location.search);
375
384
  if (localTargetLatency != null) {
@@ -571,7 +580,7 @@ export class WebPlayer {
571
580
  });
572
581
 
573
582
  this.videojsPlayer.on('error', (e) => {
574
- Logger.warn("There is an error in playback: " + e);
583
+ Logger.warn("There is an error in playback: ", e);
575
584
  // We need to add this kind of check. If we don't add this kind of checkpoint, it will create an infinite loop
576
585
  if (!this.errorCalled) {
577
586
  this.errorCalled = true;
@@ -627,19 +636,26 @@ export class WebPlayer {
627
636
  //hls specific calls
628
637
  if (extension == "m3u8") {
629
638
  videojs.Vhs.xhr.beforeRequest = (options) => {
639
+ const queryParams = [];
630
640
 
631
- let securityParams = this.getSecurityQueryParams();
632
- if (!options.uri.includes(securityParams))
633
- {
634
- if (!options.uri.endsWith("?"))
635
- {
636
- options.uri = options.uri + "?";
637
- }
638
- options.uri += securityParams;
641
+ if (!options.uri.includes("subscriberId") && this.subscriberId != null) {
642
+ queryParams.push(`subscriberId=${this.subscriberId}`);
639
643
  }
640
644
 
645
+ if (!options.uri.includes("subscriberCode") && this.subscriberCode != null) {
646
+ queryParams.push(`subscriberCode=${this.subscriberCode}`);
647
+ }
648
+
649
+ if (!options.uri.includes("token") && this.token != null) {
650
+ queryParams.push(`token=${this.token}`);
651
+ }
652
+
653
+ if (queryParams.length > 0) {
654
+ const queryString = queryParams.join("&");
655
+ options.uri += options.uri.includes("?") ? `&${queryString}` : `?${queryString}`;
656
+ }
641
657
  Logger.debug("hls request: " + options.uri);
642
- return options;
658
+
643
659
  };
644
660
 
645
661
 
@@ -739,9 +755,19 @@ export class WebPlayer {
739
755
  });
740
756
 
741
757
  if (this.autoPlay) {
758
+ //try to play directly
742
759
  this.videojsPlayer.play().catch((e) => {
743
- Logger.warn("Problem in playback. The error is " + e);
744
- });
760
+
761
+ //if it's not allowed error and default value are being used, try to play it muted
762
+ //if this.forcePlayWithAudio is true, it means user specifically ask to do.
763
+ // If it's false, it's default value so that we can proceed to try to play with muted
764
+ //This implementation is added because of auto play policy of the browsers
765
+ if (e.name === "NotAllowedError" && !this.forcePlayWithAudio) {
766
+ this.videojsPlayer.muted(true);
767
+ this.videojsPlayer.play();
768
+ }
769
+ Logger.warn("Problem in playback. The error is " + e);
770
+ });
745
771
  }
746
772
  }
747
773
 
@@ -926,11 +952,29 @@ export class WebPlayer {
926
952
  }
927
953
  });
928
954
  this.dashPlayer.on(dashjs.MediaPlayer.events.PLAYBACK_ERROR, (event) => {
955
+ Logger.warn("dash playback error: " + event);
929
956
  this.tryNextTech();
930
957
  });
931
958
  this.dashPlayer.on(dashjs.MediaPlayer.events.ERROR, (event) => {
959
+ Logger.warn("error: " + event);
932
960
  this.tryNextTech();
933
961
  });
962
+
963
+ this.dashPlayer.on(dashjs.MediaPlayer.events.PLAYBACK_NOT_ALLOWED, (event) => {
964
+ Logger.warn("dash playback not allowed: " + event);
965
+ this.handleDashPlayBackNotAllowed();
966
+ });
967
+ }
968
+
969
+ handleDashPlayBackNotAllowed() {
970
+ if (!this.forcePlayWithAudio) {
971
+ Logger.info("Try to play with muted audio");
972
+ this.dashPlayer.setMute(true);
973
+ this.dashPlayer.play();
974
+ }
975
+ else {
976
+ this.tryNextTech();
977
+ }
934
978
  }
935
979
 
936
980
  makeDashPlayerVisibleWhenInitialized() {
@@ -45,8 +45,8 @@ describe("WebPlayer", function() {
45
45
  //the following is a test autoPlay is still true in mobile. We just try to play the stream if mobile browser can play or not
46
46
  //in autoPlay mode
47
47
  expect(player.autoPlay).to.true;
48
- expect(player.mute).to.true;
49
- expect(player.isMuted()).to.be.true;
48
+ expect(player.mute).to.false;
49
+ expect(player.isMuted()).to.be.false;
50
50
  expect(player.targetLatency).to.equal(3);
51
51
  expect(player.subscriberId).to.be.null;
52
52
  expect(player.subscriberCode).to.be.null;
@@ -164,8 +164,8 @@ describe("WebPlayer", function() {
164
164
  //the following is a test autoPlay is still true in mobile. We just try to play the stream if mobile browser can play or not
165
165
  //in autoPlay mode
166
166
  expect(player.autoPlay).to.true;
167
- expect(player.mute).to.true;
168
- expect(player.isMuted()).to.be.true;
167
+ expect(player.mute).to.false;
168
+ expect(player.isMuted()).to.be.false;
169
169
  expect(player.targetLatency).to.equal(3);
170
170
  expect(player.subscriberId).to.be.null;
171
171
  expect(player.subscriberCode).to.be.null;
@@ -786,6 +786,70 @@ describe("WebPlayer", function() {
786
786
 
787
787
 
788
788
  });
789
+
790
+ it("testAutoPlay",async function(){
791
+ var videoContainer = document.createElement("video_container");
792
+
793
+ var placeHolder = document.createElement("place_holder");
794
+
795
+ var locationComponent = { href: 'http://example.com?id=stream123.mp4', search: "?id=stream123.mp4", pathname: "/", protocol: "http:" };
796
+ var windowComponent = { location : locationComponent,
797
+ document: document,
798
+ addEventListener: window.addEventListener};
799
+
800
+ var player = new WebPlayer(windowComponent, videoContainer, placeHolder);
801
+ let vjsMock = videojs(WebPlayer.VIDEO_PLAYER_ID, {
802
+ poster: "test",
803
+ liveui:true ,
804
+ liveTracker: {
805
+ trackingThreshold: 0
806
+ },
807
+ html5: {
808
+ vhs: {
809
+ limitRenditionByPlayerDimensions: false
810
+ }
811
+ },
812
+ controls: true,
813
+ class: 'video-js vjs-default-skin vjs-big-play-centered',
814
+ muted: false,
815
+ preload: "auto",
816
+ autoplay: true
817
+ });
818
+
819
+ const mockVideoJS = sinon.stub(window, 'videojs').callsFake(()=>{return vjsMock});
820
+ var muted = sinon.replace(vjsMock, "muted", sinon.fake());
821
+ let play = sinon.stub(vjsMock, 'play').callsFake(()=>{
822
+ return Promise.resolve();
823
+ });
824
+ await player.playIfExists("webrtc"); // autoplay worked with audio
825
+ expect(play.calledOnce).to.be.true;
826
+ expect(muted.notCalled).to.be.true;
827
+
828
+ play.restore();
829
+
830
+ play = sinon.stub(vjsMock, 'play').callsFake(()=>{
831
+ return Promise.reject(new DOMException("NotAllowedError","NotAllowedError"));
832
+ });
833
+ player.forcePlayWithAudio = true;
834
+
835
+ await player.playIfExists("webrtc"); // autoplay failed force play with audio
836
+ expect(play.calledOnce).to.be.true;
837
+ expect(muted.notCalled).to.be.true;
838
+
839
+ play.restore();
840
+
841
+
842
+ play = sinon.stub(vjsMock, 'play').callsFake(()=>{
843
+ return Promise.reject(new DOMException("NotAllowedError","NotAllowedError"));
844
+ });
845
+ player.forcePlayWithAudio = false;
846
+ await player.playIfExists("webrtc"); // autoplay failed try to play without audio
847
+
848
+ expect(play.calledTwice).to.be.true;
849
+ expect(muted.calledWithMatch(true)).to.be.true;
850
+
851
+ sinon.restore();
852
+ })
789
853
 
790
854
 
791
855
  it("webrtc-info-event", async function() {
@@ -885,9 +949,52 @@ describe("WebPlayer", function() {
885
949
  result = player.sendWebRTCData("data");
886
950
  expect(result).to.be.false;
887
951
  expect(sendDataViaWebRTC.callCount).to.be.equal(1);
952
+ });
953
+
954
+
955
+ it("handleDashPlayBackNotAllowed", async function(){
956
+
957
+ this.timeout(10000);
958
+ var videoContainer = document.createElement("video_container");
959
+
960
+
961
+
962
+ var player = new WebPlayer({
963
+ streamId:"streamConfig",
964
+ }, videoContainer, null);
965
+
966
+
967
+ {
968
+ player.playOrder = ["dash"];
969
+ await player.initialize().then(()=> {
970
+
971
+ }).catch((err) => {
972
+ expect.fail("it should not fail because we skip videojs and dash is already loaded");
973
+ });
974
+ }
975
+
976
+ player.dashPlayer = window.dashjs.MediaPlayer().create();
977
+
978
+ var setMute = sinon.replace(player.dashPlayer, "setMute", sinon.fake());
979
+ var play = sinon.replace(player.dashPlayer, "play", sinon.fake());
980
+ var nextTech = sinon.replace(player, "tryNextTech", sinon.fake());
981
+
982
+ expect(player.forcePlayWithAudio).to.be.false;
983
+ player.handleDashPlayBackNotAllowed();
984
+ expect(setMute.calledOnce).to.be.true;
985
+ expect(play.calledOnce).to.be.true;
986
+ expect(nextTech.notCalled).to.be.true;
987
+
988
+ expect(setMute.calledWithExactly(true)).to.be.true;
989
+
990
+
991
+ player.forcePlayWithAudio = true;
992
+ player.handleDashPlayBackNotAllowed();
993
+ expect(setMute.calledOnce).to.be.true;
994
+ expect(play.calledOnce).to.be.true;
995
+ expect(nextTech.calledOnce).to.be.true;
996
+
888
997
 
889
-
890
-
891
998
 
892
999
  });
893
1000
 
package/.project DELETED
@@ -1,17 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <projectDescription>
3
- <name>Embedded-Player</name>
4
- <comment></comment>
5
- <projects>
6
- </projects>
7
- <buildSpec>
8
- <buildCommand>
9
- <name>org.eclipse.wst.validation.validationbuilder</name>
10
- <arguments>
11
- </arguments>
12
- </buildCommand>
13
- </buildSpec>
14
- <natures>
15
- <nature>org.eclipse.wst.jsdt.core.jsNature</nature>
16
- </natures>
17
- </projectDescription>
@@ -1,7 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <classpath>
3
- <classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.JRE_CONTAINER"/>
4
- <classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.baseBrowserLibrary"/>
5
- <classpathentry kind="src" path=""/>
6
- <classpathentry kind="output" path=""/>
7
- </classpath>
@@ -1 +0,0 @@
1
- org.eclipse.wst.jsdt.launching.JRE_CONTAINER