How to use WebRTC with Wowza Streaming Engine

Wowza Streaming Engine™ media server software version 4.5.0.02 and later supports WebRTC streaming as a public preview AddOn. The WebRTC Preview AddOn package includes HTML examples of how to use the WebRTC HTML5 browser capability with Wowza Streaming Engine. Session information (SDP data) is exchanged between the browser and Wowza Streaming Engine using a WebSocket connection with JSON-formatted data. The current implementation is very simple. This functionality is only supported by browsers that support the WebRTC API.

Wowza Streaming Engine's WebRTC implementation supports the following codecs:

  • Video: VP8, VP9, H.264
  • Audio: Opus, Vorbis, PCMU, PCMA

Note: Not all browsers support all codecs. We recommend that you use VP8 video with either Opus or Vorbis audio.

Contents


WebRTC Preview AddOn package contents
Requirements
Install the WebRTC Preview AddOn
HTML examples
Hosting example HTML over HTTPS
How to...
Set up a live stream repeater (origin/edge) for use with WebRTC Streaming
Listen for and reject WebRTC session create and destroy commands in a module
Get a WebRTCSession interface to/from RTPSession
Different ways to get WebRTC session information from IApplicationInstance
Forcefully disconnect a WebRTC session
Subclass HTTPWebRTCExchangeSessionInfo to secure WebRTC playback and publishing
Record a live WebRTC stream
Known issues and limitations

WebRTC Preview AddOn package contents


The WebRTC AddOn package includes the following folders and files:

  • html/publish: HTML example of WebRTC publishing
  • html/play: HTML example of playing WebRTC content
  • html/chat: HTML example of WebRTC chat
  • java/HTTPWebRTCExchangeSessionInfo.java: HTTP Provider source code for SDP exchange

Requirements


To access the WebRTC AddOn public preview technology, you must complete the WebRTC preview request form.

The Google Chrome browser requires a secure HTTPS connection to connect to a web camera (getUserMedia) for WebRTC publishing. Because of this requirement, the example webpages must be delivered over HTTPS. Because of cross-domain issues, an SSL certificate is needed to secure the connection between the browser and Wowza Streaming Engine for exchange of the session information (SDP data). A free Wowza StreamLock certificate can be used to secure this connection. The instructions below assume you have configured port 443 with an SSL certificate. Wowza Streaming Engine can also be used to deliver the example webpages over HTTPS using the built-in HTTPProviderSimpleWebServer HTTP Provider and the same StreamLock certificate. 

If you plan to use your own SSL certificate, the following resources may help you convert your SSL certificate to the Java KeyStore (JKS) format that's required by Wowza Streaming Engine:

Install the WebRTC Preview AddOn


To install and configure the WebRTC AddOn, do the following:

  1. Enable the preview. To do this, edit [install-dir]/conf/Server.xml  and add the following property to the <Properties> container at the bottom of Server.xml:
    <Property>
      <Name>webrtc76de5tceo3l18xdh9e7ga</Name>
      <Value>true</Value>
      <Type>Boolean</Type>
    </Property>
  2. Edit [install-dir]/conf/VHost.xml and make the following changes:
    • Configure HTTP Provider for SDP exchange: Add the following XML snippet as the second-to-last entry in the list of HTTPProviders for HostPort entry 443 (SSL port). It's important that it be the second-to-last entry.
      <HTTPProvider>
        <BaseClass>com.wowza.wms.webrtc.http.HTTPWebRTCExchangeSessionInfo</BaseClass>
        <RequestFilters>*webrtc-session.json</RequestFilters>
        <AuthenticationMethod>none</AuthenticationMethod>
      </HTTPProvider>
    • Configure WebRTC streaming: Add the following properties to the <Properties> container at the end of the file (see Description, below, for necessary modifications to property values).
      <Property>
        <Name>webrtcKeyStorePath</Name>
        <Value>${com.wowza.wms.context.VHostConfigHome}/conf/[streamlock-filename].jks</Value>
        <Type>String</Type>
      </Property>
      <Property>
        <Name>webrtcKeyStorePassword</Name>
        <Value>[streamlock-password]</Value>
        <Type>String</Type>
      </Property>
      Description
      • webrtcKeyStorePath: Path to StreamLock certificate that will be used for WebRTC DTLS handshake. Replace [streamlock-filename] with your StreamLock certificate filename.
      • webrtcKeyStorePassword: Password for StreamLock certificate that will be used for WebRTC DTLS handshake. Replace [streamlock-password] with your StreamLock certificate password.
  3. Create an application for live streaming named webrtc:
    • Create a WebRTC applications folder ([install-dir]/applications/webrtc) and a WebRTC configuration folder ([install-dir]/conf/webrtc)
    • Copy the [install-dir]/conf/live/Application.xml file to the new [install-dir ]/conf/webrtc folder.
    • Edit the [install-dir]/conf/webrtc/Application.xml file and change the <Application>/<Name> to webrtc:
      <Application>
        <Name>webrtc</Name>

  4. Configure the webrtc live application. Edit [install-dir]/conf/webrtc/Application.xml and add the following properties to the <Properties> container at the end of the file (see Description, below, for necessary modifications to property values).
    <Property>
      <Name>webrtcEnablePublish</Name>
      <Value>true</Value>
      <Type>Boolean</Type>
    </Property>
    <Property>
      <Name>webrtcEnablePlay</Name>
      <Value>true</Value>
      <Type>Boolean</Type>
    </Property>
    <Property>
      <Name>webrtcEnableQuery</Name>
      <Value>true</Value>
      <Type>Boolean</Type>
    </Property>
    <Property>
      <!-- comma separated list of IP addresses and the transport information. For multiple IP's use a pipe character to separate the lists -->
      <Name>webrtcIceCandidateIpAddresses</Name>
      <Value>[wowza-streaming-engine-external-ip-address],udp</Value>
      <Type>String</Type>
    </Property>
    <Property>
      <Name>webrtcUDPBindAddress</Name>
      <Value>0.0.0.0</Value>
      <Type>String</Type>
    </Property>
    <Property>
      <Name>webrtcPreferredCodecsAudio</Name>
      <Value>opus,vorbis,pcmu,pcma</Value>
      <Type>String</Type>
    </Property>
    <Property>
      <Name>webrtcPreferredCodecsVideo</Name>
      <Value>vp8,h264</Value>
      <Type>String</Type>
    </Property>
    <Property>
      <Name>webrtcDebugLog</Name>
      <Value>false</Value>
      <Type>Boolean</Type>
    </Property>

    Description

    • webrtcEnablePublish: Enable WebRTC publishing to this application. Required for the publish and chat example HTML applications.
    • webrtcEnablePlay: Enable WebRTC playback from this application. Required for the play and chat example HTML applications.
    • webrtcEnableQuery: Enable query of published stream names for this application. Required for chat example HTML application.
    • webrtcIceCandidateIpAddresses: IP address, transport, and port used for WebRTC streaming.

      For the transmission control protocol (TCP), the value should be set to [wowza-streaming-engine-external-ip-address],tcp,[port] where [wowza-streaming-engine-external-ip-address] is the external IP address of the Wowza Streaming Engine instance and [port] is one of the non-SSL-protected streaming HostPort entries defined in [install-dir]/conf/VHost.xml. For example, to stream over port 1935, the entry would be  66.175.168.127,tcp,1935.

      For the user datagram protocol (UDP), the value should be set to [wowza-streaming-engine-external-ip-address],udp where [wowza-streaming-engine-external-ip-address] is the external IP address of the Wowza Streaming Engine instance. The port is dynamically assigned for UDP delivery.

      For multiple IP addresses, use a pipe character to separate the lists.

    • webrtcUDPBindAddress: Local IP address of the network card you want to use for WebRTC UDP traffic. (This value is not used if streaming WebRTC over TCP.) For UDP delivery in general, it's OK to leave this property blank. The property is only needed if the server has multiple network interfaces. For some network situations, like running on a cloud instance, a value of 0.0.0.0 would be best instead of the local IP address of the network card to prevent connection problems.
    • webrtcPreferredCodecsAudio: Comma-deliniated list of audio codecs, in order of preference, for stream ingestion. The default is opus,vorbis,pcmu,pcma.
    • webrtcPreferredCodecsVideo: Comma-deliniated list of video codecs, in order of preference for stream ingestion. The default is vp8,h264, but valid values are vp8vp9, and h264. If you want to stream in Chrome using VP9, change the property value to vp9,vp8,h264.
    • webrtcDebugLog: Enable WebRTC debug logging.
  5. Add the following properties to the <RTP>/<Properties> container in the [install-dir]/conf/webrtc/Application.xml file (see Description, below, for necessary modifications to property values):
    <Property>
      <Name>rtpForceH264Constraint</Name>
      <Value>true</Value>
      <Type>Boolean</Type>
    </Property>
    <Property>
      <Name>rtpForceH264ConstraintValue</Name>
      <Value>192</Value>
      <Type>Integer</Type>
    </Property>
    <Property>
      <Name>rtpUseLowestH264Constraint</Name>
      <Value>true</Value>
      <Type>Boolean</Type>
    </Property>
    <Property>
      <Name>rtpUseHighestH264Constraint</Name>
      <Value>false</Value>
      <Type>Boolean</Type>
    </Property>

    Description

    • rtpForceH264Constraint: Set to true to allow the SDP file that is returned to contain different H264 constraints than the stream contains. In most cases, setting rtpForceH264Constraint to true enables WebRTC to play without issue. The default value is false. Note that the Mozilla FireFox and Google Chrome browsers require additional constraint fields to be set.
    • rtpForceH264ConstraintValue: Use to set the constraint fields. The default value, 192, works in most circumstances. Other valid values are 128, 224, and 240.
    • rtpUseLowestH264Constraint: Set to true to compare the initial codec data and the first video unit to the profile data and use the lowest value. Use this (or rtpUseHighestH264Constraint) to aid in playing the stream when an encoder doesn't send consistent codec information for the stream.
    • rtpUseHighestH264Constraint: Set to true to compare the initial codec data and the first video unit to the profile data and use the highest value. Use this (or rtpUseLowestH264Constraint) to aid in playing the stream when an encoder doesn't send consistent codec information for the stream.

      Note: The rtpUseLowestH264Constraint and rtpUseHighestH264Constraint properties can't be used simultaneously. If both are set to true, rtpUseHighestH264Constraint is used.

HTML examples


The WebRTC Preview package includes the following HTML examples:

Publish example: The publish example shows how to publish a media stream to Wowza Streaming Engine using WebRTC. Change the SDP URL to reflect the domain name of your StreamLock or SSL certificate. This URL is used to exchange SDP information. You can also change the video and audio bitrate in addition to the frame rate. The frame rate option only works for VP9 and H.264 video codecs when using Chrome version 55.0.1 or later.

Play example: The play example shows how to playback a media stream from Wowza Streaming Engine using WebRTC. Change the SDP URL to reflect the domain name of your StreamLock or SSL certificate. This URL is used to exchange SDP information.

Chat example: The chat example shows how to set up a multi-person chat session. The example is quite simple and is intended to be an example of what it possible rather than a finished work. Change the SDP URL to reflect the domain name of your StreamLock or SSL certificate. This URL is used to exchange SDP information.

Hosting example HTML over HTTPS

There are several options for HTTPS hosting of the HTML examples:

  • The examples are hosted on www.wowza.com: WebRTC Preview HTML Examples. This is a great option if you don't need to modify the HTML or JavaScript code.
  • Host the HTML examples on your own web server that's secured using HTTPS. To install, copy the contents of the html folder to your web server.
  • Host the HTML examples on Wowza Streaming Engine using the built-in HTTPProviderSimpleWebServer HTTP Provider by doing the following:
    1. Edit [install-dir]/conf/VHost.xml and add the following HostPort entry to the HostPortList (replace [streamlock-filename] and [streamlock-password] with your StreamLock filename and password):
      <HostPort>
        <Name>Admin WebRTC</Name>
        <Type>Admin</Type>
        <ProcessorCount>${com.wowza.wms.TuningAuto}</ProcessorCount>
        <IpAddress>*</IpAddress>
        <Port>9443</Port>
        <HTTPIdent2Response></HTTPIdent2Response>
        <SSLConfig>
          <KeyStorePath>${com.wowza.wms.context.VHostConfigHome}/conf/[streamlock-filename].jks</KeyStorePath>
          <KeyStorePassword>[streamlock-password]</KeyStorePassword>
          <KeyStoreType>JKS</KeyStoreType>
          <DomainToKeyStoreMapPath></DomainToKeyStoreMapPath>
          <SSLProtocol>TLS</SSLProtocol>
          <Algorithm>SunX509</Algorithm>
          <CipherSuites></CipherSuites>
          <Protocols></Protocols>
        </SSLConfig>
        <SocketConfiguration>
          <ReuseAddress>true</ReuseAddress>
          <ReceiveBufferSize>16000</ReceiveBufferSize>
          <ReadBufferSize>16000</ReadBufferSize>
          <SendBufferSize>16000</SendBufferSize>
          <KeepAlive>true</KeepAlive>
          <AcceptorBackLog>100</AcceptorBackLog>
        </SocketConfiguration>
        <HTTPStreamerAdapterIDs></HTTPStreamerAdapterIDs>
        <HTTPProviders>
          <HTTPProvider>
            <BaseClass>com.wowza.wms.http.HTTPProviderSimpleWebServer</BaseClass>
            <RequestFilters>webrtc*</RequestFilters>
            <AuthenticationMethod>none</AuthenticationMethod>
          </HTTPProvider>
        </HTTPProviders>
      </HostPort>
    2. Create the folder [install-dir]/htdocs/webrtc and copy the contents of the html folder into this folder.

When using Wowza Streaming Engine to host the example files, use the following URL to access them: https://[streamlock-domain-name]:9443/webrtc/[path-to-example-file].

For example, if the StreamLock domain name is 123456.streamlock.net, the URL for the publish HTML example would be: https://123456.streamloack.net:9443/webrtc/publish/index.html.

How to...


Set up a live stream repeater (origin/edge) for use with WebRTC Streaming

For detailed information about how to set up a live repeater edge application, see Wowza edge. Make sure to enable the RTSP/RTP playback type.

Each edge server and the edge application must be configured for WebRTC streaming per the above instructions. Currently, we don't have explicit instructions on how to do load balancing between the edge servers. It should be possible to enhance the provided play code example to first make a request to a third-party load balancer to get the address of the least loaded edge server and then alter the WebSocket URL to point to that server dynamically. We hope to add support for load balancing WebRTC connections in a future version of our dynamic load balancing solution.

WebRTC edge streams will function like other origin/edge streams. The edge server will fetch the stream dynamically from the origin upon the first request for it. The stream will be dropped from the edge server a few seconds after the last viewer stops watching it.

Listen for and reject WebRTC session create and destroy commands in a module

import com.wowza.wms.module.*;
import com.wowza.wms.rtp.model.*;

public class ModuleListenWebRTCSession extends ModuleBase
{
  public void onRTPSessionCreate(RTPSession rtpSession)
  {
    if (rtpSession.isWebRTC())
    {
      getLogger().info("ModuleListenWebRTCSession.onRTPSessionCreate["+rtpSession.getSessionId()+"]");

      // If a query parameter is added to the stream name it should be shown here
      // An example would be
      //
      // Stream Name: myStream?param1=value1
      //
      // should output
      //
      // ModuleListenWebRTCSession.RTPStream.QueryParameter[param1=value]
      getLogger().info("ModuleListenWebRTCSession.RTPStream.QueryParameter["+rtpSession.getRTSPStream().getStreamQueryStr()+"]");

      // Call rejectSession to stop the session immediately
      //rtpSession.rejectSession();
    }
  }

  public void onRTPSessionDestroy(RTPSession rtpSession)
  {
    if (rtpSession.isWebRTC())
    {
      getLogger().info("ModuleListenWebRTCSession.onRTPSessionDestroy["+rtpSession.getSessionId()+"]");
    }
  }
}

Determine if an RTPSession is a WebRTC session

boolean RTPSession.isWebRTC();

Get a WebRTCSession interface to/from RTPSession

WebRTCSession rtpSession.getWebRTCSession();
RTPSession WebrtcSession.getRTPSession();

Different ways to get WebRTC session information from IApplicationInstance

List<RTPSession> getWebRTCSessions()
List<RTPSession> getWebRTCSessions(String streamName)
int getWebRTCSessionCount()
int getWebRTCSessionCount(String streamName)
Map<String, Integer> getWebRTCSessionCountsByName()

Forcefully disconnect a WebRTC session

vhost.getWebRTCContext().shutdownSession(webRTCSession.getSessionId());

Subclass HTTPWebRTCExchangeSessionInfo to secure WebRTC playback and publishing

The following code is an incomplete example that demonstrates how to subclass the WebRTC HTTPProvider HTTPWebRTCExchangeSessionInfo and override several methods to secure WebRTC publishing and playback. The path to your new class must replace the class path for the HTTP Provider configured above. You can pass security information from HTML/JavaScript to Wowza Streaming Engine either through query parameters or through the JSON data that's passed over the WebSocket. A userData object, as part of the example JavaScript, can be enhanced to hold this data. You can control publishing, playback, and query through the commented-out commandControl.canPlaycommandControl.canPublish, and commandControl.canQuery variables.

import java.util.*;

import com.wowza.util.*;
import com.wowza.wms.application.*;
import com.wowza.wms.logging.*;
import com.wowza.wms.webrtc.http.*;
import com.wowza.wms.websocket.model.*;

public class HTTPWebRTCExchangeSessionInfoCustom extends HTTPWebRTCExchangeSessionInfo
{
    private static final Class<HTTPWebRTCExchangeSessionInfoCustom> CLASS = HTTPWebRTCExchangeSessionInfoCustom.class;
  private static final String CLASSNAME = "HTTPWebRTCExchangeSessionInfoCustom";

  @Override
  protected void websocketSessionCreate(IWebSocketSession webSocketSession)
  {
    super.websocketSessionCreate(webSocketSession);
    WMSLoggerFactory.getLogger(CLASS).info(CLASSNAME+".websocketSessionCreate: "+webSocketSession.getSessionId());
  }

  @Override
  protected void websocketSessionDestroy(IWebSocketSession webSocketSession)
  {
    super.websocketSessionDestroy(webSocketSession);
    WMSLoggerFactory.getLogger(CLASS).info(CLASSNAME+".websocketSessionDestroy: "+webSocketSession.getSessionId());
  }

  @Override
  protected void authenticateRequest(CommandContext commandContext, CommandControl commandControl)
  {
    super.authenticateRequest(commandContext, commandControl);

    WMSLoggerFactory.getLogger(CLASS).info(CLASSNAME+".authenticateRequest: reqURI:"+commandContext.reqURI);

    int qloc = commandContext.reqURI.indexOf("?");
    if (qloc >= 0)
    {
      String queryStr = commandContext.reqURI.substring(qloc+1).trim();
      if (queryStr.length() > 0)
      {
        Map<String, String> queryMap = HTTPUtils.splitQueryStr(queryStr);
        for(Map.Entry<String, String> entry : queryMap.entrySet())
        {
          WMSLoggerFactory.getLogger(CLASS).info(CLASSNAME+".authenticateRequest: queryMap["+entry.getKey()+"]: "+entry.getValue());
        }
      }
    }

    IApplicationInstance appInstance = commandContext.commandRequest.getApplicationInstance(commandContext.vhost);
    if (appInstance != null)
    {
      WMSLoggerFactory.getLogger(CLASS).info(CLASSNAME+".authenticateRequest: application: "+appInstance.getContextStr());

      // application level properties
      WMSProperties prop = appInstance.getProperties();
    }

    Map<String, Object> jsonEntries = commandContext.commandRequest.getJSONEntries();
    if (jsonEntries != null)
    {
      Map<String, Object> userData = (Map<String, Object>)jsonEntries.get("userData");
      if (userData != null)
      {
        for(Map.Entry<String, Object> entry : userData.entrySet())
        {
          WMSLoggerFactory.getLogger(CLASS).info(CLASSNAME+".authenticateRequest: userData["+entry.getKey()+"]: "+entry.getValue());
        }
      }
    }

    // Perform authentication here and set

    // commandControl.canPlay
    // commandControl.canPublish
    // commandControl.canQuery
  }
}

Record a live WebRTC stream

To record a live WebRTC stream, do the following:

  1. Install the LiveStreamRepeater module. For more information, see How to record live streams (Wowza Streaming Engine).
  2. Configure your WebRTC live application. Open [install-dir]/conf/webrtc/Application.xml in a text editor, and make the following changes:
    •  Set the webrtcPreferredCodecsVideo property's <Value> to h264 only: 
      <Property>
        <Name>webrtcPreferredCodecsVideo</Name>
        <Value>h264</Value>
        <Type>String</Type>
      </Property>

    • Add the liveStreamRecorderDefaultAudioSearchPosition and liveStreamRecorderSkipKeyFrameUntilAudioTimeout properties to the end of the last <Properties> section in the Application.xml file: 
      <Property>
          <Name>streamRecorderDefaultAudioSearchPosition</Name>
          <Type>Boolean</Type>
          <Value>false</Value>
      </Property>
      <Property>
          <Name>streamRecorderSkipKeyFrameUntilAudioTimeout</Name>
          <Type>Integer</Type>
          <Value>10000</Value>
      </Property>

      Where:

      • streamRecorderDefaultAudioSearchPosition, when set to false, causes the LiveStreamRecorder module to search the packets and identify the nearest audio packet to a keyframe. This keeps the audio and video synchronized in the recording. If set to true, the LiveStreamRecorder module assumes the incoming audio and video are interweaved and no actions are taken to ensure synchronization.
      • streamRecorderSkipKeyFrameUntilAudioTimeout is the maximum length of time, in milliseconds, that you want to allow the LiveStreamRecorder to search for audio packets before you start recording. The recording will start as soon as an audio packet is found or when the liveStreamRecorderSkipKeyFrameUntilAudioTimeout value is reached. The default value, 10000, starts recording after 10 seconds. Your recording may not include the first few seconds on the stream.
        Note: The streamRecorderDefaultAudioSearchPosition and streamRecorderSkipKeyFrameUntilAudioTimeout properties should always be used together. Don't configure one without configuring the other, too.
  3. In Wowza Streaming Engine Manager, enable the Transcoder feature and configure the Transrate (Default) template Encoding preset to passthrough the incoming video and convert the incoming audio to AAC. For more information, see How to set up and run Wowza Transcoder for live streaming.
  4. Both your source stream and your transcoded stream with AAC audio will be recorded, but only the transcoded stream will be usable. 

Known issues and limitations


  • Google Chrome, Microsoft Edge, and Mozilla Firefox don't support AAC audio over WebRTC. Streams with AAC audio are played as video-only.
  • Chrome and Firefox (version 49 and greater) support setting the published audio and video bitrate.
  • Limitations of Mozilla Firefox:
    • Firefox has not implemented WebRTC over TCP. Additionally, UDP transport doesn't work in public IP environments.
    • H.264-encoded video published to Wowza Streaming Engine may have missing frames, but playback of H.264-encoded video isn't affected. Additionally, H.264 High Profile is not supported in Firefox. We recommend VP8 for video encoding.
    • If you're using IP network address translation (NAT) boundaries and the Wowza Streaming Engine instance has a private address but a public address is used for access, WebRTC may not work when using the public IP address.
  • WebRTC over TCP has a bitrate limit of 400Kbps.
  • Full session transversal utilities for NAT (STUN) negotiation isn't supported. A single STUN transport configuration (TCP or UDP) must be supplied using the webrtcIceCandidateIpAddresses property.
  • Wowza Streaming Engine doesn't support NON-BUNDLE in the SDP exchange. The second stream will be ignored.
  • Wowza Streaming Engine doesn't support session initiation protocol (SIP).

If you're having problems or want to discuss this article, post in our forum.