The term codec is a portmanteau for encoder and decoder. An encoder is a device or software that encodes a media signal typically compressing it in the process. A decoder performs the opposite operation and decodes the media for playback. Intuitively, a codec can be seen as "the language in which the media is represented". Hence, for a multimedia communication to take place, the parties must support at least one shared codec. There are many audio and video codecs in the market each of which has different properties in terms of required computing resources, compression ratio and fidelity. In this guide, we show how Twilio's Programmable Video Platform enables developers to select the most appropriate codec for two objectives:
The codecs supported by Twilio's client SDKs are platform dependent. In the JavaScript SDK it's up to the browser vendors to provide codec implementations, while on mobile SDKs it depends on the device's capabilities.
Video Codecs Supported by Twilio's Programmable Video SDKs.
SDK or Browser | VP8 | VP9 | H.264 |
---|---|---|---|
Chrome 57+ | Yes | Yes | Yes |
Chrome < 57 | Yes | Yes | No (Enable with internal flag) |
Safari 12.1+ | Yes | Yes [1] | Yes |
Safari < 12.1 | No | No | Yes |
Firefox 55+ | Yes | Yes | Yes |
Video iOS 2.0+ | Yes | Yes | Yes [2] |
Video iOS 1.x | Yes | Yes | No |
Video Android 2.0+ | Yes | Yes | Yes [3] (If hardware supports it) |
Video Android 1.x | Yes | No | No |
Check the browser support per platform table.
Note: Safari introduced webrtc support in version 11. The rest of the document will not refer to any earlier versions as they are not supported
[1]: VP9 support was added in Safari 15.
[2]: Twilio Video for iOS relies on hardware support for H.264. Hardware encode/decode is supported on all iOS devices.
[3]: Twilio Video for Android relies on hardware support for H.264, which depends on devices' capabilities. Reference the following snippets to check if the device supports H.264
Video Android 2.x - 5.x
12boolean isH264Supported = MediaCodecVideoDecoder.isH264HwSupported() &&3MediaCodecVideoEncoder.isH264HwSupported();
Video Android 6.x+
12HardwareVideoEncoderFactory hardwareVideoEncoderFactory =3new HardwareVideoEncoderFactory(null, true, true);4HardwareVideoDecoderFactory hardwareVideoDecoderFactory =5new HardwareVideoDecoderFactory(null);67boolean h264EncoderSupported = false;8for (VideoCodecInfo videoCodecInfo : hardwareVideoEncoderFactory.getSupportedCodecs()) {9if (videoCodecInfo.name.equalsIgnoreCase("h264")) {10h264EncoderSupported = true;11break;12}13}14boolean h264DecoderSupported = false;15for (VideoCodecInfo videoCodecInfo : hardwareVideoDecoderFactory.getSupportedCodecs()) {16if (videoCodecInfo.name.equalsIgnoreCase("h264")) {17h264DecoderSupported = true;18break;19}20}2122boolean isH264Supported = h264EncoderSupported && h264DecoderSupported;23
Furthermore, not all browsers support H.264. Developers can evaluate H.264 browser support usig the following code snippet
1let isH264Supported;23/**4* Test support for H264 codec.5* @returns {Promise<boolean>} true if supported, false if not6*/7function testH264Support() {8if (typeof isH264Supported === 'boolean') {9return Promise.resolve(isH264Supported);10}11if (typeof RTCRtpSender !== undefined12&& typeof RTCRtpSender.getCapabilities === 'function') {13isH264Supported = !!RTCRtpSender.getCapabilities('video').codecs.find(({ mimeType }) => mimeType === 'video/H264');14return Promise.resolve(isH264Supported);15}16if (typeof RTCPeerConnection === 'undefined') {17isH264Supported = false;18return Promise.resolve(isH264Supported);19}2021let offerOptions = {};22const pc = new RTCPeerConnection();23try {24pc.addTransceiver('video');25} catch (e) {26offerOptions.offerToReceiveVideo = true;27}2829return pc.createOffer(offerOptions).then(offer => {30isH264Supported = /^a=rtpmap:.+ H264/m.test(offer.sdp);31pc.close();32return isH264Supported;33});34}3536// Now we can call testH264Support to check if H.264 is supported37testH264Support().then(isSupported => {38console.log(`This browser ${isSupported39? 'supports' : 'does not support'} H264 codec`);40});
Audio Codecs Supported by Twilio's Programmable Video SDKs
SDK or Browser | iSAC | OPUS | PCMU | PCMA | G.722 |
---|---|---|---|---|---|
Chrome 110+ | No | Yes | Yes | Yes | Yes |
Safari | Yes | Yes | Yes | Yes | Yes |
Firefox 55+ | No | Yes | Yes | Yes | Yes |
Video iOS 2.0+ | Yes | Yes | Yes | Yes | Yes |
Video iOS 1.x | Yes | Yes | Yes | Yes | Yes |
Android 2.0+ | Yes | Yes | Yes | Yes | Yes |
Android 1.x | No | Yes | No | No | No |
Before establishing a multimedia communication, the involved parties need to agree on the codecs to be used. Twilio manages this through an automatic codec negotiation that imposes some interoperability restrictions.
In a Video Room, an SFU (Selective Forwarding Unit) mediates among clients. If client A wants to send media to clients B and C, then A sends only one media stream to the SFU that, in turn, forwards it to B and C. Due to this, the codec negotiation takes place based on the following principles:
These have interoperability implications. First because the only codecs allowed are the ones supported by the SFU. The following tables summarize them:
Video Codecs supported in Video Room SFU infrastructure
VP8 | VP9 | H.264 | |
---|---|---|---|
Is Supported? | Yes | No | Yes |
Audio Codecs supported in Video Room SFU infrastructure
iSAC | OPUS | PCMU | PCMA | G.722 | |
---|---|---|---|---|---|
Is Supported? | No | Yes | Yes | No | No |
Second, because the codecs negotiated at some point in a call may limit the interoperability with clients joining later. As a result, a set of clients supporting a common codec does not guarantee that they will be actually able to communicate. To illustrate this, imagine an example scenario in which two participants A and B, using Chrome and Firefox respectively, start communicating using VP8. If later a Safari < 12.1 browser joins (as C) it will not be able to receive A's and B's video tracks because Safari < 12.1 only supports H.264. This is unfortunate because both A and B could communicate H.264 but when they connected to the SFU negotiated their default that is VP8. This example scenario is represented on the following figure:
For guaranteeing video interoperability with Safari < 12.1 we can force all the clients of a Room to publish their videos using H.264. This can be achieved using two alternative mechanisms:
When the Room is created using the Rooms REST API, you can set the following parameter: VideoCodecs=H264
.
You can use the Room Settings menu located at your Twilio Video Console and set H.264 as the Room's video codec, as shown on the following figure:
When doing so, the SFU rejects to accept tracks published in VP8 and forces all the clients to use H.264, which guarantees interoperability with Safari < 12.1. The resulting Room topology in this case is the one shown below:
For further details about using Safari < 12.1 in Rooms see the Working with Safari < 12.1 Guide.
For optimizing applications in media quality or battery life sometimes it is interesting to override codecs defaults at the client side. Due to this, Twilio's APIs have introduced a Codec Preferences capability that is available at the SDKs listed in the table below:
Twilio SDKs supporting Codec Preferences |
---|
JavaScript SDK v1.3+ |
Android SDK v2.0+ |
iOS SDK v2.0+ |
The Codec Preferences based on the following principles:
ConnectOptions
.The following code snippets illustrate how a Participant can connect to a room preferring iSAC as audio codec and H.264 as video codec.
Selecting preferred codecs in JavaScript SDK (required v1.3+)
1// Web Javascript2const room = await connect(token, {3preferredAudioCodecs: ['isac'],4preferredVideoCodecs: ['H264']5});
Selecting preferred codecs in Android SDK (required v2.0+)
Note that checking for H.264 hardware support changed from v5.x to v6.x. See this section to learn how to use the correct syntax.
1// Android Java23// Prefer H264 if it is hardware available for encoding and decoding4VideoCodec videoCodec = isH264Supported ? (new H264Codec()) : (new Vp8Codec());5ConnectOptions connectOptions = new ConnectOptions.Builder(token)6.preferAudioCodecs(Collections.singletonList(new IsacCodec()))7.preferVideoCodecs(Collections.singletonList(videoCodec)8.build();910Room room = Video.connect(context, connectOptions, listener);
Selecting preferred codecs in iOS SDK (required v2.0+)
1// iOS Swift2let options = TVIConnectOptions.init(token: accessToken block: {(builder: TVIConnectOptionsBuilder) -> Void in3builder.preferredAudioCodecs = [ TVIIsacCodec() ]4builder.preferredVideoCodecs = [ TVIH264Codec() ]5}67var room = TwilioVideo.connect(with: options delegate: self)
1// iOS Objective-C2TVIConnectOptions *options = [TVIConnectOptions optionsWithToken:self.accessToken3block:^(TVIConnectOptionsBuilder * _Nonnull builder) {4builder.preferredAudioCodecs = @[ [TVIIsacCodec new] ];5builder.preferredVideoCodecs = @[ [TVIH264Codec new] ];6}];78TVIRoom *room = [TwilioVideo connectWithOptions:options delegate:self];
For further information on how Codec Preferences work, please check the corresponding SDK reference documentation regarding the connect
primitive and its ConnectOptions
parameter.
In Twilio Programmable Video, we say that a room is using Multi-codec capabilities when different participants send their video (or audio) using different codecs. Multi-codecs may be useful for optimizing the battery life of your applications as many vendors provide hardware acceleration support for specific codec suites. For example, all iOS devices have H.264 hardware acceleration while many modern Android devices provide it for both H.264 and VP8. When different devices have different hardware support, it may be interesting to send media using one codec (i.e. the one supported by the local device hardware) while receiving in another (i.e. the one hardware-supported by the remote parties).
This can be achieved using Codec Preferences. For example, imagine three clients A, B and C being respectively Chrome, Firefox and an iOS smartphone. By default (see sections above) these clients negotiate VP8 as the video codec. However, we may prefer to use H.264 in C to optimize the battery life of the iOS smartphone. In this case, we just need to set H.264 as C's preferred codec. The following code snippets illustrate how to it:
Participant A - Codec Preferences
1// We don't really need this: VP8 is Chrome's default preferred video codec2const room = await connect(token, {3preferredVideoCodecs: ['VP8']4});
Participant B - Codec Preferences
1// We don't really need this: VP8 is Firefox's default preferred video codec2const room = await connect(token, {3preferredVideoCodecs: ['VP8']4});
Participant C - Codec Preferences
1// iOS Swift2let options = TVIConnectOptions.init(token: accessToken block: {(builder: TVIConnectOptionsBuilder) -> Void in3builder.preferredVideoCodecs = [ TVIH264Codec() ]4}5var room = TwilioVideo.connect(with: options delegate: self)
If A, B, and C connect to a Room, the topology is the following: