Skip to contentSkip to navigationSkip to topbar
On this page

JavaScript WebRTC overrides


(warning)

Public Beta

WebRTC overrides for Video JavaScript SDK is currently in Public Beta. Learn more about beta product support(link takes you to an external page).


Overview

overview page anchor

You can use WebRTC override APIs to replace the core WebRTC APIs with your own implementation. These overrides let the Video JavaScript SDK run in virtual environments, such as Citrix HDX(link takes you to an external page), that use WebRTC redirection.


JavaScript WebRTC overrides

javascript-webrtc-overrides page anchor

getUserMedia

getusermedia page anchor

Overrides the browser's default getUserMedia implementation to control how the media input is captured. Call this method with the media constraints as a parameter. This method returns a promise that resolves with a MediaStream object when the requested media is successfully obtained. This capability is available through the public methods: createLocalTracks, createLocalAudioTrack, createLocalVideoTrack, and connect.

Overrides the browser's default enumerateDevices implementation to obtain the list of available input and output devices on the system. This method doesn't take any parameters and returns a promise that resolves with an array of MediaDeviceInfo objects describing all the available devices. This new capability is available through the public methods: createLocalTracks, createLocalAudioTrack, createLocalVideoTrack, and connect.

Overrides the browser's default MediaStream object used to create streams. For consistency, implement the EventTarget interface (directly or indirectly) on this object to match the browser's native MediaStream API.

(information)

Info

A known issue with Citrix HDX is that stream objects created by their custom implementation don't implement the EventTarget interface. The methods addEventListener, removeEventListener, and dispatchEvent are unavailable. As a workaround, you can shim this functionality on the application side using the following polyfill:

1
function polyfillMediaStreamEventListeners() {
2
const originalCreateMediaStream = window.CitrixWebRTC.createMediaStream;
3
4
window.CitrixWebRTC.createMediaStream = function(tracks) {
5
const mediaStream = originalCreateMediaStream.call(this, tracks);
6
const listeners = {};
7
8
mediaStream.addEventListener = function(eventName, listener) {
9
const methodName = `on${eventName}`;
10
if(!(methodName in this)) {
11
throw new Error(`Unrecognized event: ${eventName}. MediaStream does not support this event.`);
12
}
13
14
// Get or initialize listeners for this event
15
const currentListeners = listeners[eventName] || [];
16
listeners[eventName] = currentListeners.concat(listener);
17
18
this[methodName] = createEventHandler(listeners[eventName]);
19
}
20
21
mediaStream.removeEventListener = function(eventName, listener) {
22
const methodName = `on${eventName}`;
23
const currentListeners = listeners[eventName] || [];
24
listeners[eventName] = currentListeners.filter(l => l !== listener);
25
26
this[methodName] = createEventHandler(listeners[eventName]);
27
}
28
29
return mediaStream;
30
}
31
}

This polyfill is expected to be included post-beta to facilitate the integration of Citrix HDX with Twilio Video. It will be available through the public methods: createLocalTracks, createLocalAudioTrack, createLocalVideoTrack, and connect.

Overrides the browser's RTCPeerConnection implementation to represent a WebRTC connection. For consistency, implement the EventTarget interface (directly or indirectly) on this object to match the browser's native RTCPeerConnection API.

(information)

Info

A known issue with Citrix HDX is that the peerconnection objects created by their custom RTCPeerConnection don't implement the EventTarget interface. As a workaround, you can shim the following polyfill on the application side:

1
function polyfillPeerConnectionEventListeners() {
2
const instanceListeners = new WeakMap();
3
4
window.CitrixWebRTC.CitrixPeerConnection.prototype.addEventListener = function(eventName, listener) {
5
const methodName = `on${eventName}`;
6
if(!(methodName in this)) {
7
throw new Error(`Unrecognized event: ${eventName}. CitrixPeerConnection does not support this event.`);
8
}
9
10
// Get or initialize listeners for this instance
11
let listeners = instanceListeners.get(this);
12
if (!listeners) {
13
listeners = {};
14
instanceListeners.set(this, listeners);
15
}
16
17
// Get or initialize listeners for this event
18
const currentListeners = listeners[eventName] || [];
19
listeners[eventName] = currentListeners.concat(listener);
20
21
this[methodName] = createEventHandler(listeners[eventName]);
22
}
23
24
window.CitrixWebRTC.CitrixPeerConnection.prototype.removeEventListener = function(eventName, listener) {
25
const methodName = `on${eventName}`;
26
const listeners = instanceListeners.get(this);
27
if (!listeners) return;
28
29
const currentListeners = listeners[eventName] || [];
30
listeners[eventName] = currentListeners.filter(l => l !== listener);
31
32
this[methodName] = createEventHandler(listeners[eventName]);
33
}
34
}

This polyfill is expected to be included post-beta to facilitate the integration of Citrix HDX with Twilio Video. This new option will be available through the ConnectOptions received by the public connect method.

mapMediaElement (Experimental)

mapmediaelement-experimental page anchor

This override is only needed on Citrix HDX environments where the MediaStream implementation can't be attached to media elements directly without passing those media elements through a mapping process. Citrix HDX exposes this mapping process through the window.CitrixWebRTC.mapVideoElement and window.CitrixWebRTC.mapAudioElement methods. You should call the method based on the element type. This function will receive the element as a parameter and expect the application code to handle it according to your use case.

Note: The disposeMediaElement override is experimental and subject to change.

disposeMediaElement (Experimental)

disposemediaelement-experimental page anchor

This override is only needed on Citrix HDX environments where the media elements need special treatment for disposal. This method receives the media element to be cleaned up and the application should handle the element using window.CitrixWebRTC.mapVideoElement or window.CitrixWebRTC.mapAudioElement, depending on its type.

Note: The disposeMediaElement override is experimental and subject to change.


Create local audio and video tracks using the WebRTC overrides

create-local-audio-and-video-tracks-using-the-webrtc-overrides page anchor
1
// Creating both tracks at the same time
2
const localTracks = Video.createLocalTracks({
3
audio: true,
4
video: true,
5
MediaStream: (streamTracks = []) => CitrixWebRTC.createMediaStream(streamTracks),
6
getUserMedia: (...args) => CitrixWebRTC.getUserMedia(...args),
7
enumerateDevices: CitrixWebRTC.enumerateDevices.bind(CitrixWebRTC),
8
mapMediaElement: (element) => attachMediaElement(element), // Application-specific function
9
disposeMediaElement: (element) => detachMediaElement(element), // Application-specific function
10
});
11
12
// Creating only an audio track
13
const localAudioTrack = Video.createLocalAudioTrack({
14
MediaStream: (streamTracks = []) => CitrixWebRTC.createMediaStream(streamTracks),
15
getUserMedia: (...args) => CitrixWebRTC.getUserMedia(...args),
16
enumerateDevices: CitrixWebRTC.enumerateDevices.bind(CitrixWebRTC),
17
mapMediaElement: (element) => attachMediaElement(element), // Application-specific function
18
disposeMediaElement: (element) => detachMediaElement(element), // Application-specific function
19
});
20
21
// Creating only a video track
22
const localVideoTrack = Video.createLocalVideoTrack({
23
MediaStream: (streamTracks = []) => CitrixWebRTC.createMediaStream(streamTracks),
24
getUserMedia: (...args) => CitrixWebRTC.getUserMedia(...args),
25
enumerateDevices: CitrixWebRTC.enumerateDevices.bind(CitrixWebRTC),
26
mapMediaElement: (element) => attachMediaElement(element), // Application-specific function
27
disposeMediaElement: (element) => detachMediaElement(element), // Application-specific function
28
});
29

Connect to a Video Room using preacquired tracks

connect-to-a-video-room-using-preacquired-tracks page anchor
1
const room = Video.connect('$TOKEN', {
2
tracks: localTracks,
3
MediaStream: (streamTracks = []) => CitrixWebRTC.createMediaStream(streamTracks),
4
getUserMedia: (...args) => CitrixWebRTC.getUserMedia(...args),
5
enumerateDevices: CitrixWebRTC.enumerateDevices.bind(CitrixWebRTC),
6
RTCPeerConnection: CitrixWebRTC.RTCPeerConnection.bind(CitrixWebRTC),
7
mapMediaElement: (element) => attachMediaElement(element), // Application-specific function
8
disposeMediaElement: (element) => detachMediaElement(element), // Application-specific function
9
});
10

Connect to a Video Room without providing tracks

connect-to-a-video-room-without-providing-tracks page anchor
1
const room = Video.connect('$TOKEN', {
2
MediaStream: (streamTracks = []) => CitrixWebRTC.createMediaStream(streamTracks),
3
getUserMedia: (...args) => CitrixWebRTC.getUserMedia(...args),
4
enumerateDevices: CitrixWebRTC.enumerateDevices.bind(CitrixWebRTC),
5
RTCPeerConnection: CitrixWebRTC.RTCPeerConnection.bind(CitrixWebRTC),
6
mapMediaElement: (element) => attachMediaElement(element), // Application-specific function
7
disposeMediaElement: (element) => detachMediaElement(element), // Application-specific function
8
});
9

  • WebRTC overrides aren't supported in the Citrix browser. Only the Citrix desktop application is supported.