Wowza Media Studio Group Call Host

WebRTC Studio Conferencing for Wowza Media Server. Host.

Layouts

Note: Not a live demo, server configuration is just for example. For live working example try the Dolby.io Publisher and Subscriber example. Or AWS Kinesis Publisher and Subscriber example.

Note: To feature a participant select them first or add their stream name to the api method arguments. Toggle the room view to show the video merger view.

WebRTC Conferencing Studio configuration for Wowza Media Server. Wowza Media Developer and full licence works with WebRTC.

Participants join a lobby area for the host to add / remove the streams to the room.

Support added to feature participants larger fullscreen view by simply clicking the fullscreen icon on and off. Or an api is provided.

Conferencing host with graphics accelerated stream merger broadcasting and recording features. Using the conferencing plugin an api is provided to feature and mute a selected participant.

In both the html and stream merger, the ability to show profile poster images when cameras are enabled is supported.

The stream merger application can be set to preview a video rendering of the output stream using the mergerPreview config.

The secondary Websocket Wowza provider project is required for signalling new room partipants after publishing begins. Subscribed streams of participants will be displayed in the configured container selector.

RTMP and server side streams published to the room server application instance will join the room.

Configured is a custom publish token that is verified with the custom Wowza webrtc provider module using a configured shared secret.

Supplied is a custom example websocket signal server Wowza provider project for one to many and group call features. Security token verification is provided by the same publish token.

Configured is server side recording via the conferencing custom websocket provider module. Configure the stream name to record as the WebGL merger stream name ie C6Lx6ku6FEXgKtt-merger

A token service can be configured to refresh publish and subscribe tokens.

    
  <div class="flex flex-col w-full">
          <div id="wowza-conference-studio-host" class=""></div>

  </div>
  <script type="text/javascript">
  	var player = flowplayer("#wowza-conference-studio-host", {
    "mergerSrc": "C6Lx6ku6FEXgKtt-merger",
    "peakmeter": {},
    "rtc": {
        "applicationName": "webrtc-rooms/room1",
        "autoStartDevice": true,
        "buttons": false,
        "conference": {
            "autoPublish": true,
            "bgImage": "../../images/virtualbg.jpg",
            "container": "#conference-container",
            "enableFocus": true,
            "featuredContainer": "#featured-container",
            "fullscreenFeatured": true,
            "host": true,
            "lobbyContainer": "#conference-participant-container",
            "lobbyPlayerTemplate": "<div id=\"${id}\" class=\"conference-player conference-lobby-player group flex justify-center items-center\"><div id=\"${playerid}\" class=\"no-volume no-toggle\"></div><button class=\"invisible group-hover:visible bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-2 absolute font-semibold bg-gradient-to-tr from-iblue-default hover:from-iblue-light to-iblue-light hover:to-iblue-default text-white focus:shadow-outline focus:outline-none text-sm\" x-data=\"{ staged: ${staged} }\" x-text=\"staged ? 'Remove' : 'Add To Room'\" @click.prevent=\"addToRoom($event);\" data-name=\"${name}\">Add To Room</button></div>",
            "logo": "../../images/wowza-logo.png",
            "mergerApplication": "webrtc-merger/room1",
            "mergerContainer": "#conference-merge-container",
            "mergerOnly": false,
            "mergerPreview": true,
            "playerTemplate": "<div id=\"${id}\" class=\"conference-player\"><div id=\"${playerid}\" class=\"no-volume\"></div></div>",
            "profile": "../../images/wowza-logo.png",
            "roomContainer": "#room-container",
            "studioMode": true
        },
        "meterAutoStart": false,
        "opus": {
            "usedtx": 1
        },
        "publishToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ3ZWJydGMifQ.MjehxjweF5tPPqUJQjHEHdHLz4sjaXkTkJh0dkM8w9_M5PMKoyzUJZPYyYtgT1qn17eDZlUOUeIeyr37z-KhN1u66L2ScVCwvs0dBjf6s2ZSIw0shvKmCdq7u5bd5llWTY0FDbbtFA1l60CkfOsTd0_dQpeyKm3Y94XgIaPyJB_PCCezO8V1xmcyMT1aqPfwr99AmM8s_P_8nuDL6A1HHppImwZL550AnTjuPQaAMRSVSNuzlLrwFXBA1SRaKOa2AVkIzP0tYkqWCYd03Gvn_CpxZ5dhk5s4UYSoYeK2FX4nz4khn_k8loFO-vDu2M-1r7dvFXnt8iNYWGTzDxPNuQ",
        "publisher": true,
        "recording": {
            "codec": "VP9",
            "mimeType": "video/webm",
            "name": "C6Lx6ku6FEXgKtt-merger",
            "server": true
        },
        "seperateScreen": true,
        "server": "wowza-conference",
        "serverURL": "rtc.electroteque.org",
        "tokenService": "tokenService",
        "verticalMeter": false
    },
    "src": [
        {
            "appName": "webrtc",
            "publisher": true,
            "src": "C6Lx6ku6FEXgKtt",
            "type": "application/webrtc"
        }
    ],
    "title": "Host",
    "token": "eyJraWQiOiIyeHRpc0Q5NHZzTjIiLCJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJjIjoie1wiYWNsXCI6NixcImlkXCI6XCIyeHRpc0Q5NHZzTjJcIixcImRvbWFpblwiOltcImVsZWN0cm90ZXF1ZS5vcmdcIl19IiwiaXNzIjoiRmxvd3BsYXllciJ9.WLUkZHpDNoaXWDaFO2V5UfXm7SnDvE1pFAM0e7ppnFovOSyCCZM-b8gQNBSElB5yirTP__x76Qyo8pMWh6lVrw"
});

async function tokenService() {
return new Promise((accept) => {
accept("eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ3ZWJydGMifQ.MjehxjweF5tPPqUJQjHEHdHLz4sjaXkTkJh0dkM8w9_M5PMKoyzUJZPYyYtgT1qn17eDZlUOUeIeyr37z-KhN1u66L2ScVCwvs0dBjf6s2ZSIw0shvKmCdq7u5bd5llWTY0FDbbtFA1l60CkfOsTd0_dQpeyKm3Y94XgIaPyJB_PCCezO8V1xmcyMT1aqPfwr99AmM8s_P_8nuDL6A1HHppImwZL550AnTjuPQaAMRSVSNuzlLrwFXBA1SRaKOa2AVkIzP0tYkqWCYd03Gvn_CpxZ5dhk5s4UYSoYeK2FX4nz4khn_k8loFO-vDu2M-1r7dvFXnt8iNYWGTzDxPNuQ");
});
}
player.on("selectedParticipant", (e, participant) => {
console.log("selected participant", e.data);
}).on("unselectedParticipant", (e, participant) => {
console.log("unselected participant", e.data);
}).on("participantleft", (e, sender) => {
}).on("participantfeatured", (e, sender) => {
}).on("participantunfeatured", (e, sender) => {
}).on("leaveroom", e => {
}).on("roomjoinfailed", e => {
}).on("existingparticipants", (e, sender) => {
}).on("roomPlayer", (e) => {
console.log("Room Player ", e.data);
}).on("participantPlayer", (e) => {
console.log("Lobby Player ", e.data);
}).on("roomConfig", (e) => {
const state = e.data[0], config = e.data[1];
console.log("Room Config ", state, config);
});
  </script>