Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Table of Contents

Пример стримера c доступом к медиа-устройствам

Данный стример может использоваться для публикации следующих типов потоков с и проигрывания WebRTC потоков на Web Call Server

  • WebRTC
  • RTMFP
  • RTMP

и позволяет выбрать медиа-устройства и параметры для публикуемого видео

...

На скриншоте ниже представлен пример во время публикации потока.

Image RemovedImage Added


На странице вопроизводятся отображаются два видео элемента:

  • 'Local' - видео с камеры
  • 'PreviewPlayer' - видео, которое приходит с сервера

Код примера

Код данного примера находится на WCS-сервере по следующему пути:

...

Тестировать данный пример можно по следующему адресу:

https://host:8888/client2/examples/demo/streaming/media_devices_manager/media_device_manager.html

Здесь host - адрес WCS-сервера.

Работа с кодом примера

Для разбора кода возьмем версию файла manager.js с хэшем ecbadc3, которая находится здесь и доступна для скачивания в соответствующей сборке 2.0.5.28.2747212.

1. Инициализация API.

Flashphoner.init() код code

Code Block
languagejs
themeRDark
        Flashphoner.init({
            flashMediaProviderSwfLocationscreenSharingExtensionId: '../../../../media-provider.swf'extensionId,
            mediaProvidersReadyCallback: function (mediaProviders) {
                //hide remote video if current media provider is Flash
(Flashphoner.isUsingTemasys()) {
                   if (mediaProviders[0] == "Flash") {
                    $("#fecForm$("#audioInputForm").hide();
                    $("#stereoForm#videoInputForm").hide();
                    $("#sendAudioBitrateForm").hide();}
            }
          $("#cpuOveruseDetectionForm").hide();
             })

2. Получение списка доступных медиа-устройств ввода

Flashphoner.getMediaDevices() code

При получении списка медиа-устройств заполняются выпадающие списки микрофонов и камер на странице клиента.

Code Block
languagejs
themeRDark
    Flashphoner.getMediaDevices(null, true).then(function (list) {
     }
   list.audio.forEach(function (device) {
           if (Flashphoner.isUsingTemasys()) {...
        });
            $("#audioInputForm").hide();list.video.forEach(function (device) {
            ...
        $("#videoInputForm").hide(});
        ...
    }).catch(function    }(error) {
        $("#notifyFlash").text("Failed to get media }
    devices");
    });

23. Получение списка доступных медиа-устройств . кодвывода звука

Flashphoner.getMediaDevices() код code

При получении списка медиа-устройств заполняются выпадающие списки выпадающий список устройств вывода звука на странице клиента.

Code Block
languagejs
themeRDark
    Flashphoner.getMediaDevices(null, true, MEDIA_DEVICE_KIND.OUTPUT).then(function (list) {
        list.audio.forEach(function (device) {
            ...
     var audio = document.getElementById("audioInput" });
        ...
    var i;
 }).catch(function (error) {
        $("#notifyFlash").text("Failed to get media devices");
 var deviceInList = false;
});

4. Получение граничных параметров для публикации аудио и видео со страницы клиента

getConstraints() code

Источники публикации:

  • камера (sendVideo)
  • микрофон (sendAudio)
Code Block
languagejs
themeRDark
    constraints = {
      for (i = 0; i < audio.options.length; i++) {audio: $("#sendAudio").is(':checked'),
                if (audio.options[i].value == device.id) {video: $("#sendVideo").is(':checked'),
                    deviceInList = true;
                    break;
                }
            }
            if (!deviceInList) {
                var option = document.createElement("option");
                option.text = device.label || device.id;
                option.value = device.id;
                audio.appendChild(option);
            }
        });
        list.video.forEach(function (device) {
            console.log(device);
            var video = document.getElementById("videoInput");
            var i;
            var deviceInList = false;
            for (i = 0; i < video.options.length; i++) {
                if (video.options[i].value == device.id) {
                    deviceInList = true;
                    break;
                }
            }
            if (!deviceInList) {
                var option = document.createElement("option");
                option.text = device.label || device.id;
                option.value = device.id;
                if (option.text.toLowerCase().indexOf("back") >= 0 && video.children.length > 0) {
                    video.insertBefore(option, video.children[0]);
                } else {
                    video.appendChild(option);
                }
            }
        });


        $("#url").val(setURL() + "/" + createUUID(8));

        //set initial button callback
        onStopped();

        if (list.audio.length === 0) {
            $("#sendAudio").prop('checked', false).prop('disabled', true);
        }
        if (list.video.length === 0) {
            $("#sendVideo").prop('checked', false).prop('disabled', true);
        }
    }).catch(function (error) {
        $("#notifyFlash").text("Failed to get media devices");
    });

3. Получение граничных параметров для аудио и видео со страницы клиента

getConstraints() код

Code Block
languagejs
themeRDark
function getConstraints() {
    constraints = {
        audio: $("#sendAudio").is(':checked'),
        video: $("#sendVideo").is(':checked'),
        customStream: $("#sendCanvasStream").is(':checked')
    };

    if (constraints.audio) {
        constraints.audio = {
            deviceId: $('#audioInput').val()
        };
        if ($("#fec").is(':checked'))
            constraints.audio.fec = $("#fec").is(':checked');
        if ($("#sendStereoAudio").is(':checked'))
            constraints.audio.stereo = $("#sendStereoAudio").is(':checked');
        if (parseInt($('#sendAudioBitrate').val()) > 0)
            constraints.audio.bitrate = parseInt($('#sendAudioBitrate').val());
    }

    if (constraints.video) {
        if (constraints.customStream) {
            constraints.customStream = canvas.captureStream(30);
            constraints.video = false;
        } else {
            constraints.video = {
                deviceId: {exact: $('#videoInput').val()},
                width: parseInt($('#sendWidth').val()),
                height: parseInt($('#sendHeight').val())
            };
            if (Browser.isSafariWebRTC() && Browser.isiOS() && Flashphoner.getMediaProviders()[0] === "WebRTC") {
                constraints.video.width = {min: parseInt($('#sendWidth').val()), max: 640};
                constraints.video.height = {min: parseInt($('#sendHeight').val()), max: 480};
            }
            if (parseInt($('#sendVideoMinBitrate').val()) > 0)
                constraints.video.minBitrate = parseInt($('#sendVideoMinBitrate').val());
            if (parseInt($('#sendVideoMaxBitrate').val()) > 0)
                constraints.video.maxBitrate = parseInt($('#sendVideoMaxBitrate').val());
            if (parseInt($('#fps').val()) > 0)
                constraints.video.frameRate = parseInt($('#fps').val());
        }
    }

    return constraints;
}

4. Получение доступа к медиаустройствам для локального тестирования

Flashphoner.getMediaAccess() код

В метод передаются граничные параметры для аудио и видео (constrains), а также localVideo - div-элемент, в котором будет отображаться видео с выбранной камеры.

Code Block
languagejs
themeRDark
Flashphoner.getMediaAccess(getConstraints(), localVideo).then(function (disp) {
        $("#testBtn").text("Release").off('click').click(function () {
            $(this).prop('disabled', true);
            stopTest();
        }).prop('disabled', false);

        window.AudioContext = window.AudioContext || window.webkitAudioContext;
        if (Flashphoner.getMediaProviders()[0] == "WebRTC" && window.AudioContext) {
            for (i = 0; i < localVideo.children.length; i++) {
                if (localVideo.children[i] && localVideo.children[i].id.indexOf("-LOCAL_CACHED_VIDEO") != -1) {
                    var stream = localVideo.children[i].srcObject;
                    audioContextForTest = new AudioContext();
                    var microphone = audioContextForTest.createMediaStreamSource(stream);
                    var javascriptNode = audioContextForTest.createScriptProcessor(1024, 1, 1);
                    microphone.connect(javascriptNode);
                    javascriptNode.connect(audioContextForTest.destination);
                    javascriptNode.onaudioprocess = function (event) {
                        var inpt_L = event.inputBuffer.getChannelData(0);
                        var sum_L = 0.0;
                        for (var i = 0; i < inpt_L.length; ++i) {
                            sum_L += inpt_L[i] * inpt_L[i];
                        }
                        $("#micLevel").text(Math.floor(Math.sqrt(sum_L / inpt_L.length) * 100));
                    }
                }
            }
        } else if (Flashphoner.getMediaProviders()[0] == "Flash") {
            micLevelInterval = setInterval(function () {
                $("#micLevel").text(disp.children[0].getMicrophoneLevel());
            }, 500);
        }
        testStarted = true;
    }).catch(function (error) {
        $("#testBtn").prop('disabled', false);
        testStarted = false;
    });

5. Подключение к серверу.

Flashphoner.createSession() код

Code Block
languagejs
themeRDark
 Flashphoner.createSession({urlServer: url}).on(SESSION_STATUS.ESTABLISHED, function (session) {
        //session connected, start streaming
        startStreaming(session);
    }).on(SESSION_STATUS.DISCONNECTED, function () {
        setStatus(SESSION_STATUS.DISCONNECTED);
        onStopped();
    }).on(SESSION_STATUS.FAILED, function () {
        setStatus(SESSION_STATUS.FAILED);
        onStopped();
    });

6. Получение от сервера события, подтверждающего успешное соединение.

ConnectionStatusEvent ESTABLISHED код

Code Block
languagejs
themeRDark
 Flashphoner.createSession({urlServer: url}).on(SESSION_STATUS.ESTABLISHED, function (session) {
        //session connected, start streaming
        startStreaming(session);
    }).on(SESSION_STATUS.DISCONNECTED, function () {
        setStatus(SESSION_STATUS.DISCONNECTED);
        onStopped();
    }).on(SESSION_STATUS.FAILED, function () {
        setStatus(SESSION_STATUS.FAILED);
        onStopped();
    });

7. Публикация видеопотока

session.createStream(), publishStream.publish() код

Code Block
languagejs
themeRDark
  publishStream = session.createStream({
        name: streamName,
        display: localVideo,
        cacheLocalResources: true,
        constraints: constraints,};

Параметры аудио:

  • выбор микрофона (deviceId)
  • коррекция ошибок для кодека Opus (fec)
  • режим стерео (stereo)
  • битрейт аудио (bitrate)
Code Block
languagejs
themeRDark
    if (constraints.audio) {
        mediaConnectionConstraints: mediaConnectionConstraints constraints.audio = {
    }).on(STREAM_STATUS.PUBLISHING, function (publishStream) {
       deviceId: $("#testBtn").prop('disabled#audioInput', true);
        var video = document.getElementById(publishStream.id());
     .val()
   //resize local if resolution is available};
        if (video.videoWidth > 0 && video.videoHeight > 0) {
   ($("#fec").is(':checked'))
            constraints.audio.fec = $("#fec").is(':checked');
         resizeLocalVideo({target: video});if ($("#sendStereoAudio").is(':checked'))
        }
    constraints.audio.stereo    enableMuteToggles(true= $("#sendStereoAudio").is(':checked');
        if (parseInt($("#muteVideoToggle"'#sendAudioBitrate').isval(":checked")) > {0)
            constraints.audio.bitrate  muteVideo(= parseInt($('#sendAudioBitrate').val());
    }

Параметры видео:

  • выбор камеры (deviceId)
  • размеры при публикации (width, height)
  • минимальный и максимальный битрейт видео (minBitrate, maxBitrate)
  • FPS (frameRate)
Code Block
languagejs
themeRDark
      }
        if ($("#muteAudioToggle").is(":checked"))constraints.video = {
            muteAudio();
    deviceId:    }
    {exact: $('#videoInput').val()},
    //remove resize listener in case this video was cached earlier
        video.removeEventListenerwidth: parseInt($('resize#sendWidth', resizeLocalVideo);
        video.addEventListener('resize', resizeLocalVideo);.val()),
        setStatus(STREAM_STATUS.PUBLISHING);

        //play previewheight: parseInt($('#sendHeight').val())
        var  constraints = {};
            audio:if $("#playAudio").is(':checked'),
            video: $("#playVideo").is(':checked')
 Browser.isSafariWebRTC() && Browser.isiOS() && Flashphoner.getMediaProviders()[0] === "WebRTC") {
       };
        if (constraints.video).deviceId = {exact: $('#videoInput').val()};
            constraints.video = {}
                width: (!$("#receiveDefaultSize").is(":checked")) ? if (parseInt($('#receiveWidth#sendVideoMinBitrate').val()) :> 0,)
                height: (!$("#receiveDefaultSize").is(":checked")) ?constraints.video.minBitrate = parseInt($('#receiveHeight#sendVideoMinBitrate').val()) : 0,;
                bitrate: (!$("#receiveDefaultBitrate").is(":checked")) ? $("#receiveBitrate"if (parseInt($('#sendVideoMaxBitrate').val()) :> 0,)
                quality: (!$("#receiveDefaultQuality").is(":checked")) ? constraints.video.maxBitrate = parseInt($('#quality#sendVideoMaxBitrate').val() : 0
            };
));
          }
  if (parseInt($('#fps').val()) > 0)
   previewStream = session.createStream({
            name: streamName,
            display: remoteVideo,
            constraints: constraints
        }).on(STREAM_STATUS.PLAYING, function (previewStreamconstraints.video.frameRate = parseInt($('#fps').val());


5. Получение доступа к медиаустройствам для локального тестирования

Flashphoner.getMediaAccess() code

В метод передаются граничные параметры для аудио и видео (constrains), а также localVideo - div-элемент, в котором будет отображаться видео с выбранной камеры.

Code Block
languagejs
themeRDark
    Flashphoner.getMediaAccess(getConstraints(), localVideo).then(function (disp) {
            document.getElementById(previewStream.id()).addEventListener('resize', function (event$("#testBtn").text("Release").off('click').click(function () {
                $("#playResolution"this).text(event.target.videoWidth + "x" + event.target.videoHeight);
prop('disabled', true);
            stopTest();
        resizeVideo(event.target}).prop('disabled', false);
            });...
        testStarted = true;
  //enable stop button
   }).catch(function (error) {
          onStarted(publishStream, previewStream$("#testBtn").prop('disabled', false);
        testStarted    //wait for incoming stream= false;
    });

6. Подключение к серверу.

Flashphoner.createSession() code

Code Block
languagejs
themeRDark
    Flashphoner.createSession({urlServer: url,   if (Flashphoner.getMediaProviders()[0] == "WebRTC"timeout: tm}).on(SESSION_STATUS.ESTABLISHED, function (session) {
        ...
        setTimeout(}).on(SESSION_STATUS.DISCONNECTED, function () {
        ...
            detectSpeech(previewStream);}).on(SESSION_STATUS.FAILED, function () {
            ...
    }, 3000);
   );

7. Получение от сервера события, подтверждающего успешное соединение.

ConnectionStatusEvent ESTABLISHED code

Code Block
languagejs
themeRDark
    Flashphoner.createSession({urlServer: url, timeout:   }

   tm}).on(SESSION_STATUS.ESTABLISHED, function (session) {
         drawSquare(setStatus("#connectStatus", session.status());
        }).on(STREAM_STATUS.STOPPED, function () {onConnected(session);
        ...
    });

8. Публикация видеопотока

session.createStream(), publishStream.

...

publish()

...

code

Code Block
languagejs
themeRDark
    publishStream =   }).on(STREAM_STATUS.FAILED, function () session.createStream({
            //preview failed, stop publishStream
name: streamName,
        display: localVideo,
     if (publishStream.status() == STREAM_STATUS.PUBLISHING) { cacheLocalResources: true,
        constraints:  constraints,
      setStatus(STREAM_STATUS.FAILED);
   mediaConnectionConstraints: mediaConnectionConstraints,
        sdpHook: rewriteSdp,
   publishStream.stop();
     transport: transportInput,
        cvoExtension: }cvo,
         });
stripCodecs: strippedCodecs,
         previewStream.play();
    }).on(STREAM_STATUS.UNPUBLISHED, function () {videoContentHint: contentHint
        ...
    });
    setStatus(STREAM_STATUS.UNPUBLISHED);
  publishStream.publish();

9. Получение от сервера события, подтверждающего успешную публикацию потока

StreamStatusEvent PUBLISHING code

Code Block
languagejs
themeRDark
    publishStream  //enable start button= session.createStream({
        onStopped();...
    }).on(STREAM_STATUS.FAILEDPUBLISHING, function (stream) {
        $("#testBtn").prop('disabled', true);
        var video = setStatus(STREAM_STATUS.FAILEDdocument.getElementById(stream.id());
        //enable start button
resize local if resolution is available
        if onStopped();
    });
    publishStream.publish();

8. Получение от сервера события, подтверждающего успешную публикацию потока

StreamStatusEvent PUBLISHING код

При получении данного события создается превью-видеопоток при помощи createStream() и вызывается play() для его воспроизведения.

Code Block
languagejs
themeRDark
publishStream = session.createStream({
(video.videoWidth > 0 && video.videoHeight > 0) {
            nameresizeLocalVideo({target: streamName,video});
        display: localVideo,}
        cacheLocalResources: true,enablePublishToggles(true);
        constraints: constraints,
 if ($("#muteVideoToggle").is(":checked")) {
           mediaConnectionConstraints: mediaConnectionConstraints
 muteVideo();
     }).on(STREAM_STATUS.PUBLISHING, function (publishStream) {}
        if ($("#testBtn#muteAudioToggle").prop('disabled', true);
is(":checked")) {
         var video = document.getElementById(publishStream.id());muteAudio();
        }
        //remove resize local if resolution is available
  listener in case this video was cached earlier
       if (video.videoWidth > 0 && video.videoHeight > 0) {
    removeEventListener('resize', resizeLocalVideo);
        video.addEventListener('resize', resizeLocalVideo);
        resizeLocalVideo({target: video}publishStream.setMicrophoneGain(currentGainValue);
        } setStatus("#publishStatus", STREAM_STATUS.PUBLISHING);
        enableMuteTogglesonPublishing(truestream);
   
     if ($("#muteVideoToggle").is(":checked")}).on(STREAM_STATUS.UNPUBLISHED, function () {
        ...
    }).on(STREAM_STATUS.FAILED, function muteVideo(); {
        }...
    });
    if ($("#muteAudioToggle").is(":checked")) {
publishStream.publish();

10. Воспроизведение потока

session.createStream(), previewStream.play() code

Code Block
languagejs
themeRDark
    previewStream        muteAudio();
= session.createStream({
        name: }streamName,
         //remove resize listener in case this video was cached earlierdisplay: remoteVideo,
        constraints: constraints,
        video.removeEventListener('resize', resizeLocalVideo); transport: transportOutput,
        video.addEventListener('resize', resizeLocalVideo);stripCodecs: strippedCodecs
        setStatus(STREAM_STATUS.PUBLISHING);

     ...
   //play preview });
    previewStream.play();

11. Получение от сервера события, подтверждающего успешное воспроизведение потока

StreamStatusEvent PLAYING code

Code Block
languagejs
themeRDark
    var constraintspreviewStream = session.createStream({
        ...
    audio: $("#playAudio"}).is(':checked'),
  on(STREAM_STATUS.PLAYING, function (stream) {
        playConnectionQualityStat.connectionQualityUpdateTimestamp = video:new $Date("#playVideo").isvalueOf(':checked');
         }setStatus("#playStatus", stream.status());
        if (constraints.video) {onPlaying(stream);
        document.getElementById(stream.id()).addEventListener('resize',    constraints.video =function (event) {
                width: (!$("#receiveDefaultSize#playResolution").is(":checked")) ? parseInt($('#receiveWidth').val()) : 0,
text(event.target.videoWidth + "x" + event.target.videoHeight);
            resizeVideo(event.target);
       height: (!$("#receiveDefaultSize").is(":checked")) ? parseInt($('#receiveHeight').val()) : 0,
 });
        //wait for incoming stream
        bitrate:if (!$("#receiveDefaultBitrate").is(":checked")) ? $("#receiveBitrate").val() : 0,Flashphoner.getMediaProviders()[0] == "WebRTC") {
            setTimeout(function () {
                quality: (!$("#receiveDefaultQuality").is(":checked")) ? $('#quality').val() : 0
if(Browser.isChrome()) {
                    }detectSpeechChrome(stream);
        }
        previewStream} =else session.createStream({
                   name: streamName,
 detectSpeech(stream);
               display: remoteVideo,}
            constraints: constraints}, 3000);
        }).on(STREAM_STATUS.PLAYING, function (previewStream) {
        ...
    });
    previewStream.play();

12. Остановка воспроизведения потока.

stream.stop() code

Code Block
languagejs
themeRDark
    document.getElementById(previewStream.id()).addEventListener('resize', function (event) {
        $("#playBtn").text("Stop").off('click').click(function () {
        $("#playResolution"this).text(event.target.videoWidth + "x" + event.target.videoHeight);
prop('disabled', true);
        stream.stop();
    }).prop('disabled', false);

13. Получение от сервера события, подтверждающего остановку воспроизведения

StreamStatusEvent STOPPED code

Code Block
languagejs
themeRDark
    previewStream = resizeVideo(event.target);session.createStream({
        ...
    });
   .on(STREAM_STATUS.STOPPED, function () {
         //enable stop buttonsetStatus("#playStatus", STREAM_STATUS.STOPPED);
            onStarted(publishStream, previewStreamonStopped();
        ...
    //wait for incoming stream});
     previewStream.play();

14. Остановка публикации видеопотока

stream.stop() code

Code Block
languagejs
themeRDark
       if (Flashphoner.getMediaProviders()[0] == "WebRTC"$("#publishBtn").text("Stop").off('click').click(function () {
        $(this).prop('disabled', true);
       setTimeout(function stream.stop() {;
    }).prop('disabled', false);

15. Получение от сервера события, подтверждающего успешную остановку публикации

StreamStatusEvent UNPUBLISHED code

Code Block
languagejs
themeRDark
    publishStream           detectSpeech(previewStream);= session.createStream({
           ...
     }, 3000);
            }
}).on(STREAM_STATUS.UNPUBLISHED, function () {
            drawSquare(setStatus("#publishStatus", STREAM_STATUS.UNPUBLISHED);
        }).on(STREAM_STATUS.STOPPED, function onUnpublished() {;
        ...
    publishStream.stop(});
    publishStream.publish();

16. Отключение микрофона

stream.muteAudio() code:

Code Block
languagejs
themeRDark
function muteAudio() {
   }).on(STREAM_STATUS.FAILED, function if (publishStream) {
        publishStream.muteAudio();
    //preview failed, stop publishStream
        }
}

17. Отключение камеры

stream.muteVideo() code:

Code Block
languagejs
themeRDark
function muteVideo() {
    if (publishStream.status() == STREAM_STATUS.PUBLISHING) {
                setStatus(STREAM_STATUS.FAILEDpublishStream.muteVideo();
        }
}

18. Отображение статистики при публикации потока

stream.getStats() code:

Code Block
languagejs
themeRDark
        publishStream.stopgetStats(function (stats); {
            if }
(stats && stats.outboundStream) {
     });
        previewStream.play();
   if }).on(STREAM_STATUS.UNPUBLISHED, function ((stats.outboundStream.video) {
           setStatus(STREAM_STATUS.UNPUBLISHED);
        //enable start button showStat(stats.outboundStream.video, "outVideoStat");
        onStopped();
    }).on(STREAM_STATUS.FAILED, function () {
     let vBitrate = setStatus(STREAM_STATUS.FAILED);
        //enable start button
(stats.outboundStream.video.bytesSent - videoBytesSent) * 8;
             onStopped();
    });
    publishStream.publish();

9. Остановка воспроизведения превью-видеопотока.

previewStream.stop() код

Code Block
languagejs
themeRDark
 $("#publishBtn").text("Stop").off('click').click(function () {
if ($('#outVideoStatBitrate').length == 0) {
                   $(this).prop('disabled', true);
    let html =  previewStream.stop();
    }).prop('disabled', false);

10. Получение от сервера события, подтверждающего остановку воспроизведения

StreamStatusEvent STOPPED код

Code Block
languagejs
themeRDark
previewStream = session.createStream({
"<div>Bitrate: " + "<span id='outVideoStatBitrate' style='font-weight: normal'>" + vBitrate + "</span>" + "</div>";
                  name:  streamName,
    $("#outVideoStat").append(html);
        display: remoteVideo,
           } constraints:else constraints{
        }).on(STREAM_STATUS.PLAYING, function (previewStream) {
                document.getElementById(previewStream.id()).addEventListener$('resize', function (event) {#outVideoStatBitrate').text(vBitrate);
                $("#playResolution").text(event.target.videoWidth + "x" + event.target.videoHeight);
 }
                    videoBytesSent  resizeVideo(event.target);
= stats.outboundStream.video.bytesSent;
                    });
...
              //enable stop button}

            onStarted(publishStream, previewStream);
    if   (stats.outboundStream.audio) {
     //wait for incoming stream
            if (Flashphoner.getMediaProviders()[0] == "WebRTC") {
showStat(stats.outboundStream.audio, "outAudioStat");
                    let aBitrate = setTimeout(function () {(stats.outboundStream.audio.bytesSent - audioBytesSent) * 8;
                    if detectSpeech(previewStream);
  ($('#outAudioStatBitrate').length == 0) {
              }, 3000);
         let html  }

            drawSquare()= "<div>Bitrate: " + "<span id='outAudioStatBitrate' style='font-weight: normal'>" + aBitrate + "</span>" + "</div>";
        }).on(STREAM_STATUS.STOPPED, function () {
                publishStream.stop();
        }).on(STREAM_STATUS.FAILED, function () {
 $("#outAudioStat").append(html);
           //preview failed, stop publishStream
      } else {
    if (publishStream.status() == STREAM_STATUS.PUBLISHING) {
                setStatus(STREAM_STATUS.FAILED$('#outAudioStatBitrate').text(aBitrate);
                publishStream.stop();
      }
      }
        });
      audioBytesSent = previewStream.play();

11. Остановка публикации видеопотока после остановки воспроизведения превью-потока.

publishStream.stop() код

Code Block
languagejs
themeRDark
 previewStream = session.createStream({
stats.outboundStream.audio.bytesSent;
               name: streamName,}
            display: remoteVideo,}
            constraints: constraints...
        }).on(STREAM_STATUS.PLAYING, function (previewStream) {
;

19. Отображение статистики при воспроизведении потока

stream.getStats() code:

Code Block
languagejs
themeRDark
        previewStream.getStats(function (stats) {
            if (stats && stats.inboundStream) {
                if document.getElementById(previewStream.id()).addEventListener('resize', function (eventstats.inboundStream.video) {
                    $("#playResolution").text(event.target.videoWidth + "x" + event.target.videoHeight);
showStat(stats.inboundStream.video, "inVideoStat");
                    let vBitrate = resizeVideo(event.target);
   stats.inboundStream.video.bytesReceived - videoBytesReceived) * 8;
         });
           if  //enable stop button
($('#inVideoStatBitrate').length == 0) {
              onStarted(publishStream, previewStream);
         let html  //wait for incoming stream
            if (Flashphoner.getMediaProviders()[0] == "WebRTC") {
= "<div>Bitrate: " + "<span id='inVideoStatBitrate' style='font-weight: normal'>" + vBitrate + "</span>" + "</div>";
                        setTimeout(function () {
$("#inVideoStat").append(html);
                    } else detectSpeech(previewStream);
{
                       }, 3000 $('#inVideoStatBitrate').text(vBitrate);
                    }

              drawSquare();
      videoBytesReceived = }).on(STREAM_STATUS.STOPPED, function () {stats.inboundStream.video.bytesReceived;
            publishStream.stop();
        }).on(STREAM_STATUS.FAILED, function () {
...
                }

 //preview failed, stop publishStream
            if (publishStream.status() == STREAM_STATUS.PUBLISHINGstats.inboundStream.audio) {
                    setStatus(STREAM_STATUS.FAILEDshowStat(stats.inboundStream.audio, "inAudioStat");
                   publishStream.stop();
 let aBitrate = (stats.inboundStream.audio.bytesReceived - audioBytesReceived) * 8;
    }
        });
        if previewStream.play();

12. Получение от сервера события, подтверждающего успешную остановку публикации

StreamStatusEvent UNPUBLISHED код

Code Block
languagejs
themeRDark
publishStream = session.createStream({
($('#inAudioStatBitrate').length == 0) {
               name:  streamName,
       let display: localVideo,
        cacheLocalResources: true,
        constraints: constraints,html = "<div style='font-weight: bold'>Bitrate: " + "<span id='inAudioStatBitrate' style='font-weight: normal'>" + aBitrate + "</span>" + "</div>";
        mediaConnectionConstraints: mediaConnectionConstraints
    }).on(STREAM_STATUS.PUBLISHING, function (publishStream) {
        $("#testBtn#inAudioStat").prop('disabled', trueappend(html);
        var video = document.getElementById(publishStream.id());
        //resize local if resolution} iselse available{
        if (video.videoWidth > 0 && video.videoHeight > 0) {
            resizeLocalVideo({target: video}$('#inAudioStatBitrate').text(aBitrate);
            }
        enableMuteToggles(true);}
        if ($("#muteVideoToggle").is(":checked")) {
          audioBytesReceived  muteVideo()= stats.inboundStream.audio.bytesReceived;
         }
       }
 if ($("#muteAudioToggle").is(":checked")) {
               muteAudio();
...
            }
        });

20. Определение речи при помощи интерфейса ScriptProcessor (любой браузер, кроме Chrome)

audioContext.createMediaStreamSource(), audioContext.createScriptProcessor() code


Code Block
languagejs
themeRDark
function detectSpeech(stream, level,  //remove resize listener in case this video was cached earlierlatency) {
    var mediaStream = document.getElementById(stream.id()).srcObject;
    var source =  videoaudioContext.removeEventListener('resize', resizeLocalVideocreateMediaStreamSource(mediaStream);
    var processor =  videoaudioContext.addEventListener('resize', resizeLocalVideocreateScriptProcessor(512);
    processor.onaudioprocess = handleAudio;
    setStatus(STREAM_STATUS.PUBLISHINGprocessor.connect(audioContext.destination);

       processor.clipping = false;
     //play previewprocessor.lastClip = 0;
    // threshold
   var constraintsprocessor.threshold = { level || 0.10;
    processor.latency = latency || 750;

    audio: $("#playAudio").is(':checked'),processor.isSpeech =
            video: $("#playVideo").is(':checked')
    function () {
    };
        if (constraints!this.videoclipping) return {false;
            if constraints((this.videolastClip = {
      + this.latency) < window.performance.now()) this.clipping = false;
          width: (!$("#receiveDefaultSize").is(":checked")) ? parseInt($('#receiveWidth').val()) : 0, return this.clipping;
        };

    source.connect(processor);

    height: (!$("#receiveDefaultSize").is(":checked")) ? parseInt($('#receiveHeight').val()) : 0,// Check speech every 500 ms
    speechIntervalID = setInterval(function () {
        bitrate:if (!$("#receiveDefaultBitrate").is(":checked")) ? $("#receiveBitrate").val() : 0,
     processor.isSpeech()) {
           quality: (!$("#receiveDefaultQuality#talking").is(":checked")) ? $('#quality').val() : 0
css('background-color', 'green');
        } else {
             }$("#talking").css('background-color', 'red');
        }
    }, 500);
}

Обработка аудиоданных code

Code Block
languagejs
themeRDark
function handleAudio(event) {
    var previewStreambuf = sessionevent.inputBuffer.createStreamgetChannelData({0);
    var bufLength = buf.length;
     name: streamName,var x;
    for (var i = 0; i <  display: remoteVideo,bufLength; i++) {
        x    constraints: constraints
= buf[i];
        if })(Math.on(STREAM_STATUS.PLAYING, function (previewStreamabs(x) >= this.threshold) {
            document.getElementById(previewStream.id()).addEventListener('resize', function (event) {
     this.clipping = true;
           $("#playResolution").text(event.target.videoWidth + "x" + event.target.videoHeight this.lastClip = window.performance.now();
        }
    }
}

21. Определение речи по WebRTC статистике входящего аудио потока в браузере Chrome

stream.getStats() code

Code Block
languagejs
themeRDark
function detectSpeechChrome(stream, level, latency) {
    resizeVideo(event.target);
    statSpeechDetector.threshold = level || 0.010;
    statSpeechDetector.latency = latency || })750;
    statSpeechDetector.clipping = false;
    statSpeechDetector.lastClip = 0;
 //enable stop button
 speechIntervalID = setInterval(function() {
        onStarted(publishStream, previewStream);stream.getStats(function(stat) {
            //waitlet foraudioStats incoming stream= stat.inboundStream.audio;
            if (Flashphoner.getMediaProviders()[0] == "WebRTC"(!audioStats) {
                setTimeout(function () {
        return;
            detectSpeech(previewStream);}
            // Using audioLevel WebRTC }, 3000);stats parameter
            }

    if (audioStats.audioLevel >= statSpeechDetector.threshold) {
        drawSquare();
        }).on(STREAM_STATUS.STOPPED, function () {
 statSpeechDetector.clipping = true;
           publishStream.stop();
     statSpeechDetector.lastClip =  }).on(STREAM_STATUS.FAILED, function () {
   window.performance.now();
         //preview failed, stop publishStream}
            if (publishStream.status() == STREAM_STATUS.PUBLISHING((statSpeechDetector.lastClip + statSpeechDetector.latency) < window.performance.now()) {
                setStatus(STREAM_STATUS.FAILED)statSpeechDetector.clipping = false;
             }
   publishStream.stop();
          if (statSpeechDetector.clipping) }{
        });
        previewStream.play();
    }).on(STREAM_STATUS.UNPUBLISHED, function () {$("#talking").css('background-color', 'green');
        setStatus(STREAM_STATUS.UNPUBLISHED);
    } else {
  //enable start button
        onStopped();
    }$("#talking").on(STREAM_STATUS.FAILED, function () {
   css('background-color', 'red');
     setStatus(STREAM_STATUS.FAILED);
        //enable start button}
        onStopped(});
    },500);
    publishStream.publish();}