@epicgames-ps/lib-pixelstreamingfrontend-ue5.5 0.1.3 → 0.1.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@epicgames-ps/lib-pixelstreamingfrontend-ue5.5",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Frontend library for Unreal Engine 5.5 Pixel Streaming",
5
5
  "main": "dist/lib-pixelstreamingfrontend.js",
6
6
  "module": "dist/lib-pixelstreamingfrontend.esm.js",
@@ -104,6 +104,7 @@ export class PeerConnectionController {
104
104
  *
105
105
  */
106
106
  async receiveOffer(offer: RTCSessionDescriptionInit, config: Config) {
107
+
107
108
  Logger.Log(Logger.GetStackTrace(), 'Receive Offer', 6);
108
109
 
109
110
  this.peerConnection?.setRemoteDescription(offer).then(() => {
@@ -124,6 +125,9 @@ export class PeerConnectionController {
124
125
  );
125
126
  }
126
127
 
128
+ // Add our list of preferred codecs, in order of preference
129
+ this.config.setOptionSettingOptions(OptionParameters.PreferredCodec, this.fuzzyIntersectUEAndBrowserCodecs(offer));
130
+
127
131
  this.setupTransceiversAsync(useMic).finally(() => {
128
132
  this.peerConnection
129
133
  ?.createAnswer()
@@ -144,33 +148,17 @@ export class PeerConnectionController {
144
148
  });
145
149
  });
146
150
  });
147
-
148
- // Ugly syntax, but this achieves the intersection of the browser supported list and the UE supported list
149
- this.config.setOptionSettingOptions(
150
- OptionParameters.PreferredCodec,
151
- this.parseAvailableCodecs(offer).filter((value) =>
152
- this.config
153
- .getSettingOption(OptionParameters.PreferredCodec)
154
- .options.includes(value)
155
- )
156
- );
157
151
  }
158
152
 
159
- /**
153
+ /**
160
154
  * Set the Remote Descriptor from the signaling server to the RTC Peer Connection
161
155
  * @param answer - RTC Session Descriptor from the Signaling Server
162
156
  */
163
157
  receiveAnswer(answer: RTCSessionDescriptionInit) {
164
158
  this.peerConnection?.setRemoteDescription(answer);
165
- // Ugly syntax, but this achieves the intersection of the browser supported list and the UE supported list
166
- this.config.setOptionSettingOptions(
167
- OptionParameters.PreferredCodec,
168
- this.parseAvailableCodecs(answer).filter((value) =>
169
- this.config
170
- .getSettingOption(OptionParameters.PreferredCodec)
171
- .options.includes(value)
172
- )
173
- );
159
+
160
+ // Add our list of preferred codecs, in order of preference
161
+ this.config.setOptionSettingOptions(OptionParameters.PreferredCodec, this.fuzzyIntersectUEAndBrowserCodecs(answer));
174
162
  }
175
163
 
176
164
  /**
@@ -371,16 +359,55 @@ export class PeerConnectionController {
371
359
  // Default Functionality: Do Nothing
372
360
  }
373
361
 
362
+ /**
363
+ * Find the intersection between UE and browser codecs, with fuzzy matching if some parameters are mismatched.
364
+ * @param sdp The remote sdp
365
+ * @returns The intersection between browser supported codecs and ue supported codecs.
366
+ */
367
+ fuzzyIntersectUEAndBrowserCodecs(sdp: RTCSessionDescriptionInit) : string[] {
368
+ // We want to build an array of all supported codecs on both sides
369
+ const allSupportedCodecs: Array<string> = new Array<string>();
370
+ const allUECodecs: string[] = this.parseAvailableCodecs(sdp);
371
+ const allBrowserCodecs: string[] = this.config.getSettingOption(OptionParameters.PreferredCodec).options;
372
+ for(const ueCodec of allUECodecs) {
373
+ // Check if browser codecs directly matches UE codec (with parameters and everything)
374
+ if(allBrowserCodecs.includes(ueCodec)) {
375
+ allSupportedCodecs.push(ueCodec);
376
+ continue;
377
+ }
378
+ // Otherwise check if browser codec at least contains a match for the UE codec name (without parameters).
379
+ else {
380
+ const ueCodecNameAndParams: string[] = ueCodec.split(" ");
381
+ const ueCodecName = ueCodecNameAndParams[0];
382
+ for(const browserCodec of allBrowserCodecs) {
383
+ if(browserCodec.includes(ueCodecName)) {
384
+ // We pass browser codec here as they option contain extra parameters.
385
+ allSupportedCodecs.push(browserCodec);
386
+ break;
387
+ }
388
+ }
389
+ }
390
+ }
391
+ return allSupportedCodecs;
392
+ }
393
+
374
394
  /**
375
395
  * Setup tracks on the RTC Peer Connection
376
396
  * @param useMic - is mic in use
377
397
  */
378
398
  async setupTransceiversAsync(useMic: boolean) {
379
- const hasTransceivers =
380
- this.peerConnection?.getTransceivers().length > 0;
381
399
 
382
- // Setup a transceiver for getting UE video
383
- this.peerConnection?.addTransceiver('video', { direction: 'recvonly' });
400
+ // Setup a transceiver for receiving video (if we need to)
401
+ let hasVideoReceiver = false;
402
+ for (const transceiver of this.peerConnection?.getTransceivers() ?? []) {
403
+ if (transceiver && transceiver.receiver && transceiver.receiver.track && transceiver.receiver.track.kind === 'video') {
404
+ hasVideoReceiver = true;
405
+ break;
406
+ }
407
+ }
408
+ if(!hasVideoReceiver) {
409
+ this.peerConnection?.addTransceiver('video', { direction: 'recvonly' });
410
+ }
384
411
 
385
412
  // We can only set preferred codec on Chrome
386
413
  if (RTCRtpReceiver.getCapabilities && this.preferredCodec != '') {
@@ -390,7 +417,6 @@ export class PeerConnectionController {
390
417
  transceiver.receiver &&
391
418
  transceiver.receiver.track &&
392
419
  transceiver.receiver.track.kind === 'video' &&
393
- // As of 06/2023, FireFox has added RTCRtpReceiver.getCapabilities, but hasn't added the ability to set codec preferences
394
420
  transceiver.setCodecPreferences
395
421
  ) {
396
422
  const preferredRTPCodec = this.preferredCodec.split(' ');
@@ -435,11 +461,21 @@ export class PeerConnectionController {
435
461
  }
436
462
  }
437
463
 
464
+ let hasAudioReceiver = false;
465
+ for (const transceiver of this.peerConnection?.getTransceivers() ?? []) {
466
+ if (transceiver && transceiver.receiver && transceiver.receiver.track && transceiver.receiver.track.kind === 'audio') {
467
+ hasAudioReceiver = true;
468
+ break;
469
+ }
470
+ }
471
+
438
472
  // Setup a transceiver for sending mic audio to UE and receiving audio from UE
439
473
  if (!useMic) {
440
- this.peerConnection?.addTransceiver('audio', {
441
- direction: 'recvonly'
442
- });
474
+ if(!hasAudioReceiver) {
475
+ this.peerConnection?.addTransceiver('audio', {
476
+ direction: 'recvonly'
477
+ });
478
+ }
443
479
  } else {
444
480
  // set the audio options based on mic usage
445
481
  const audioOptions = {
@@ -464,7 +500,7 @@ export class PeerConnectionController {
464
500
  mediaSendOptions
465
501
  );
466
502
  if (stream) {
467
- if (hasTransceivers) {
503
+ if (hasAudioReceiver) {
468
504
  for (const transceiver of this.peerConnection?.getTransceivers() ?? []) {
469
505
  if (RTCUtils.canTransceiverReceiveAudio(transceiver)) {
470
506
  for (const track of stream.getTracks()) {
@@ -485,9 +521,11 @@ export class PeerConnectionController {
485
521
  }
486
522
  }
487
523
  } else {
488
- this.peerConnection?.addTransceiver('audio', {
489
- direction: 'recvonly'
490
- });
524
+ if(!hasAudioReceiver) {
525
+ this.peerConnection?.addTransceiver('audio', {
526
+ direction: 'recvonly'
527
+ });
528
+ }
491
529
  }
492
530
  }
493
531
  }
@@ -102,6 +102,12 @@ export declare class PeerConnectionController {
102
102
  * @param datachannelEvent - The peer's data channel
103
103
  */
104
104
  onDataChannel(datachannelEvent: RTCDataChannelEvent): void;
105
+ /**
106
+ * Find the intersection between UE and browser codecs, with fuzzy matching if some parameters are mismatched.
107
+ * @param sdp The remote sdp
108
+ * @returns The intersection between browser supported codecs and ue supported codecs.
109
+ */
110
+ fuzzyIntersectUEAndBrowserCodecs(sdp: RTCSessionDescriptionInit): string[];
105
111
  /**
106
112
  * Setup tracks on the RTC Peer Connection
107
113
  * @param useMic - is mic in use