Versions Compared

Key

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

...

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

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

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

...

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

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

Flashphoner.init() код code

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

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

Flashphoner.getMediaDevices() код code

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

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

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

getConstraints() код

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

  • камера (sendVideo)
  • микрофон (sendAudio)
  • HTML5 Canvas (sendCanvasStream)

списка доступных медиа-устройств вывода звука

Flashphoner.getMediaDevices() code

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

Code Block
languagejs
themeRDark
    Flashphoner.getMediaDevices(null,  constraints =true, MEDIA_DEVICE_KIND.OUTPUT).then(function (list) {
        audio: $("#sendAudio").is(':checked'),
list.audio.forEach(function (device) {
         video: $("#sendVideo").is(':checked'),   ...
        });
        ...
    }).catch(function (error) {
        customStream: $("#sendCanvasStream#notifyFlash").is(':checked')text("Failed to get media devices");
    });

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

...

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

getConstraints() code

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

  • камера (sendVideo)
  • микрофон (sendAudio)
Code Block
languagejs
themeRDark
    if (constraints.audio)constraints = {
        constraints.audio = {: $("#sendAudio").is(':checked'),
            deviceIdvideo: $('#audioInput'"#sendVideo").valis(':checked'),
    };

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

  • выбор микрофона (deviceId)
  • коррекция ошибок для кодека Opus (fec)
  • режим стерео (stereo)
  • битрейт аудио (bitrate)
Code Block
languagejs
themeRDark
     };if (constraints.audio) {
        if ($("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());
    }

...

Code Block
languagejs
themeRDark
            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.widthdeviceId = {minexact: parseInt($('#sendWidth#videoInput').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());


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

Flashphoner.getMediaAccess() код code

В метод передаются граничные параметры для аудио и видео (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);
        ...
        testStarted = true;
    }).catch(function (error) {
        $("#testBtn").prop('disabled', false);
        testStarted = false;
    });


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

Flashphoner.createSession() код code

Code Block
languagejs
themeRDark
    Flashphoner.createSession({urlServer: url, timeout: tm}).on(SESSION_STATUS.ESTABLISHED, function (session) {
        //session connected, start streamingsetStatus("#connectStatus", session.status());
        startStreamingonConnected(session);
    }).on(SESSION_STATUS.DISCONNECTED, function () {
        setStatus("#connectStatus", SESSION_STATUS.DISCONNECTED);
        onStoppedonDisconnected();
    }).on(SESSION_STATUS.FAILED, function () {
        setStatus("#connectStatus", SESSION_STATUS.FAILED);
        onStoppedonDisconnected();
    });


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

ConnectionStatusEvent ESTABLISHED кодESTABLISHED code

Code Block
languagejs
themeRDark
    Flashphoner.createSession({urlServer: url, timeout: tm}).on(SESSION_STATUS.ESTABLISHED, function (session) {
        //session connected, start streamingsetStatus("#connectStatus", session.status());
        startStreamingonConnected(session);
        }).on(SESSION_STATUS.DISCONNECTED, function () {
        ......
    }).on(SESSION_STATUS.FAILED, function () {
        ...
    });

...

;


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

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

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

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

StreamStatusEvent PUBLISHING код

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

Code Block
languagejs
themeRDark
    publishStream = session.createStream({transport: transportInput,
        namecvoExtension: streamNamecvo,
        displaystripCodecs: localVideo,strippedCodecs
         cacheLocalResources: true,...
    });
    publishStream.publish();


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

StreamStatusEvent PUBLISHING code

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

        //play previewonPublishing(stream);
    }).on(STREAM_STATUS.UNPUBLISHED, function   var constraints = () {
        ...
    audio: $("#playAudio"}).is(':checked'),on(STREAM_STATUS.FAILED, function () {
        ...
    });
   video: $("#playVideo").is(':checked')
 publishStream.publish();


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

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

Code Block
languagejs
themeRDark
    previewStream    };= session.createStream({
        if (constraints.video) {
name: streamName,
        display: remoteVideo,
    constraints.video = {
  constraints: constraints,
        transport: transportOutput,
    width: (!$("#receiveDefaultSize").is(":checked")) ? parseInt($('#receiveWidth').val()) : 0, stripCodecs: strippedCodecs
        ...
    });
    height: (!$("#receiveDefaultSize").is(":checked")) ? parseInt($('#receiveHeight').val()) : 0,
previewStream.play();


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

StreamStatusEvent PLAYING code

Code Block
languagejs
themeRDark
    previewStream = session.createStream({
        ...
    }).on(STREAM_STATUS.PLAYING, function (stream) {
        playConnectionQualityStat.connectionQualityUpdateTimestamp = new Date().valueOf();
        setStatus("#playStatus", stream.status());
        onPlaying(stream);
        document.getElementById(stream.id()).addEventListener('resize', function (event) {
            $("#playResolution").text(event.target.videoWidth + "x" + event.target.videoHeight);
            resizeVideo(event.target);
        });
        //wait for incoming stream
        if (Flashphoner.getMediaProviders()[0] == "WebRTC") {
            setTimeout(function () {
                detectSpeech(stream);
            }, 3000);
        }
        ...
    });
    previewStream.play();


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

stream.stop() code

Code Block
languagejs
themeRDark
    $("#playBtn").text("Stop").off('click').click(function () {
        $(this).prop('disabled', true);
        stream.stop();
    }).prop('disabled', false);


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

StreamStatusEvent STOPPED code

Code Block
languagejs
themeRDark
    previewStream = session.createStream({
        ...
    }).on(STREAM_STATUS.STOPPED, function () {
        setStatus("#playStatus", STREAM_STATUS.STOPPED);
        onStopped();
        ...
    });
    previewStream.play();


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

stream.stop() code

Code Block
languagejs
themeRDark
    $("#publishBtn").text("Stop").off('click').click(function () {
        $(this).prop('disabled', true);
        stream.stop();
    }).prop('disabled', false);


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

StreamStatusEvent UNPUBLISHED code

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


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

code:

Code Block
languagejs
themeRDark
        if ($("#muteAudioToggle").is(":checked")) {
            muteAudio();
        }


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

code:

Code Block
languagejs
themeRDark
        if ($("#muteVideoToggle").is(":checked")) {
            muteVideo();
        }


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

stream.getStats() code:

Code Block
languagejs
themeRDark
        publishStream.getStats(function (stats) {
            if (stats && stats.outboundStream) {
                if (stats.outboundStream.video) {
                    showStat(stats.outboundStream.video, "outVideoStat");
                    let vBitrate = (stats.outboundStream.video.bytesSent - videoBytesSent) * 8;
                    if ($('#outVideoStatBitrate').length == 0) {
                        let html = "<div>Bitrate: " + "<span id='outVideoStatBitrate' style='font-weight: normal'>" + vBitrate + "</span>" + "</div>";
                        $("#outVideoStat").append(html);
                    } else {
                        $('#outVideoStatBitrate').text(vBitrate);
                    }
                    videoBytesSent = stats.outboundStream.video.bytesSent;
                    ...
                }

                if (stats.outboundStream.audio) {
                    showStat(stats.outboundStream.audio, "outAudioStat");
                    let aBitrate = (stats.outboundStream.audio.bytesSent - audioBytesSent) * 8;
                    if ($('#outAudioStatBitrate').length == 0) {
                        let html = "<div>Bitrate: " + "<span id='outAudioStatBitrate' style='font-weight: normal'>" + aBitrate + "</span>" + "</div>";
                        $("#outAudioStat").append(html);
                    } else {
                        $('#outAudioStatBitrate').text(aBitrate);
                    }
                    audioBytesSent = stats.outboundStream.audio.bytesSent;
                }
            }
       bitrate: (!$("#receiveDefaultBitrate").is(":checked")) ? $("#receiveBitrate").val() : 0,...
         });


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

stream.getStats() code:

Code Block
languagejs
themeRDark
       quality: (!$("#receiveDefaultQuality").is(":checked")) ? $('#quality').val() : 0 previewStream.getStats(function (stats) {
            };
if (stats && stats.inboundStream) {
    }
        previewStream = session.createStream({
  if (stats.inboundStream.video) {
        name: streamName,
            display: remoteVideo,
   showStat(stats.inboundStream.video, "inVideoStat");
          constraints: constraints
         let vBitrate = (stats.inboundStream.video.bytesReceived - videoBytesReceived) * 8;
        });
         previewStream.play();
    }).on(STREAM_STATUS.UNPUBLISHED, function (if ($('#inVideoStatBitrate').length == 0) {
        ...
    }).on(STREAM_STATUS.FAILED, function () {
        ...
 let html  });
    publishStream.publish();

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

previewStream.stop() код

Code Block
languagejs
themeRDark
    $("#publishBtn").text("Stop").off('click').click(function () {
= "<div>Bitrate: " + "<span id='inVideoStatBitrate' style='font-weight: normal'>" + vBitrate + "</span>" + "</div>";
                        $(this).prop('disabled', true"#inVideoStat").append(html);
        previewStream.stop();
    }).prop('disabled', false);

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

StreamStatusEvent STOPPED код

Code Block
languagejs
themeRDark
       } previewStream = session.createStream(else {
            name: streamName,
            display: remoteVideo,$('#inVideoStatBitrate').text(vBitrate);
            constraints: constraints
        }).on(STREAM_STATUS.PLAYING, function (previewStream) {
}
               ...
     videoBytesReceived   }).on(STREAM_STATUS.STOPPED, function () {= stats.inboundStream.video.bytesReceived;
            publishStream.stop();
        }).on(STREAM_STATUS.FAILED, function () {
...
                ...}

        });
        if previewStream.play();

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

publishStream.stop() код

Code Block
languagejs
themeRDark
(stats.inboundStream.audio) {
                   previewStream = session.createStream({ showStat(stats.inboundStream.audio, "inAudioStat");
            name:  streamName,
      let aBitrate = (stats.inboundStream.audio.bytesReceived - audioBytesReceived) display: remoteVideo,* 8;
            constraints: constraints
        }).on(STREAM_STATUS.PLAYING, function (previewStreamif ($('#inAudioStatBitrate').length == 0) {
            ...
        }).on(STREAM_STATUS.STOPPED, function () {
          let  publishStream.stop();
        }).on(STREAM_STATUS.FAILED, function () {
    html = "<div style='font-weight: bold'>Bitrate: " + "<span id='inAudioStatBitrate' style='font-weight: normal'>" + aBitrate + "</span>" + "</div>";
        ...
        });
        previewStream.play();

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

StreamStatusEvent UNPUBLISHED код

Code Block
languagejs
themeRDark
    publishStream = session.createStream({
$("#inAudioStat").append(html);
            name: streamName,
       } display:else localVideo,
{
              cacheLocalResources: true,
        constraints: constraints, $('#inAudioStatBitrate').text(aBitrate);
        mediaConnectionConstraints: mediaConnectionConstraints
    }).on(STREAM_STATUS.PUBLISHING, function (publishStream) {
    }
    ...
    }).on(STREAM_STATUS.UNPUBLISHED, function () {
            audioBytesReceived  setStatus(STREAM_STATUS.UNPUBLISHED)= stats.inboundStream.audio.bytesReceived;
        //enable start button
      }
  onStopped();
    }).on(STREAM_STATUS.FAILED, function () {
        ...
    });
        }
     publishStream.publish(   });