Table of Contents |
---|
Пример стримера c доступом к медиа-устройствам
Данный стример может использоваться для публикации следующих типов потоков с и проигрывания WebRTC потоков на Web Call Server
- WebRTC
- RTMFP
- RTMP
и позволяет выбрать медиа-устройства и параметры для публикуемого видео
...
На скриншоте ниже представлен пример во время публикации потока.
На странице вопроизводятся отображаются два видео элемента:
- 'Local' - видео с камеры
- 'PreviewPlayer' - видео, которое приходит с сервера
Код примера
Код данного примера находится на WCS-сервере по следующему пути:
...
Здесь host - адрес WCS-сервера.
Работа с кодом примера
Для разбора кода возьмем версию файла manager.js с хэшем 66cc393 ecbadc3, которая находится здесь и доступна для скачивания в соответствующей сборке 2.0.5.28.2753.133.212.
1. Инициализация API.
Flashphoner.init() code
Code Block | ||||
---|---|---|---|---|
| ||||
Flashphoner.init({ screenSharingExtensionId: extensionId, flashMediaProviderSwfLocation: '../../../../media-provider.swf', mediaProvidersReadyCallback: function (mediaProviders) { mediaProvidersReadyCallback: functionif (Flashphoner.isUsingTemasys(mediaProviders)) { //hide remote video if current media provider is Flash if (mediaProviders[0] == "Flash") { $("#audioInputForm").hide(); $("#fecForm#videoInputForm").hide(); $("#stereoForm").hide();} } $("#sendAudioBitrateForm").hide(); }) |
2. Получение списка доступных медиа-устройств ввода
Flashphoner.getMediaDevices() code
При получении списка медиа-устройств заполняются выпадающие списки микрофонов и камер на странице клиента.
Code Block | ||||
---|---|---|---|---|
| ||||
Flashphoner.getMediaDevices(null, true).then(function (list) { list.audio.forEach(function (device) { $("#cpuOveruseDetectionForm").hide(); ... }); if (Flashphoner.isUsingTemasys()list.video.forEach(function (device) { ... $("#audioInputForm").hide()}); ... }).catch(function (error) { $("#videoInputForm#notifyFlash").hide(); } } text("Failed to get media devices"); }); |
23. Получение списка доступных медиа-устройств вводавывода звука
Flashphoner.getMediaDevices() code
При получении списка медиа-устройств заполняются выпадающие списки микрофонов и камер выпадающий список устройств вывода звука на странице клиента.
Code Block | ||||
---|---|---|---|---|
| ||||
Flashphoner.getMediaDevices(null, true, MEDIA_DEVICE_KIND.OUTPUT).then(function (list) { list.audio.forEach(function (device) { ... }); list..video.forEach(function (device) { ... }); ... }).catch(function (error) { $("#notifyFlash").text("Failed to get media devices"); }); |
3. Получение списка доступных медиа-устройств вывода звука
Flashphoner.getMediaDevices() code
При получении списка медиа-устройств заполняются выпадающий список устройств вывода звука на странице клиента.4. Получение граничных параметров для публикации аудио и видео со страницы клиента
getConstraints() code
Источники публикации:
- камера (sendVideo)
- микрофон (sendAudio)
Code Block | ||||
---|---|---|---|---|
| ||||
Flashphoner.getMediaDevices(null, true, MEDIA_DEVICE_KIND.OUTPUT).then(function (list) constraints = { list.audio.forEach(function (device) {audio: $("#sendAudio").is(':checked'), video: $("#sendVideo").is(':checked'), ... }; |
Параметры аудио:
- выбор микрофона (deviceId)
- коррекция ошибок для кодека Opus (fec)
- режим стерео (stereo)
- битрейт аудио (bitrate)
Code Block | ||||
---|---|---|---|---|
| ||||
if });(constraints.audio) { constraints... audio = { }).catch(function (error) { deviceId: $("#notifyFlash"'#audioInput').textval("Failed) to get media devices"); }); |
4. Получение граничных параметров для публикации аудио и видео со страницы клиента
getConstraints() code
Источники публикации:
- камера (sendVideo)
- микрофон (sendAudio)
Code Block | ||||
---|---|---|---|---|
| ||||
constraints = { audio:if ($("#sendAudio#fec").is(':checked'),) video: constraints.audio.fec = $("#sendVideo#fec").is(':checked'),; }; |
Параметры аудио:
- выбор микрофона (deviceId)
- коррекция ошибок для кодека Opus (fec)
- режим стерео (stereo)
- битрейт аудио (bitrate)
Code Block | ||||
---|---|---|---|---|
| ||||
if ($("#sendStereoAudio").is(':checked')) if (constraints.audio) { constraints.audio.stereo = { deviceId: $('#audioInput'"#sendStereoAudio").valis() }':checked'); if (parseInt($("#fec"'#sendAudioBitrate').is(':checked')val()) > 0) constraints.audio.fecbitrate = parseInt($("#fec"'#sendAudioBitrate').is(':checked'val()); if ($("#sendStereoAudio").is(':checked')) } |
Параметры видео:
- выбор камеры (deviceId)
- размеры при публикации (width, height)
- минимальный и максимальный битрейт видео (minBitrate, maxBitrate)
- FPS (frameRate)
Code Block | ||||
---|---|---|---|---|
| ||||
constraints.audio.stereovideo = $("#sendStereoAudio").is(':checked'); { deviceId: {exact: $('#videoInput').val()}, ifwidth: (parseInt($('#sendAudioBitrate#sendWidth').val()), > 0) constraints.audio.bitrate = height: parseInt($('#sendAudioBitrate#sendHeight').val()); } |
Параметры видео:
- выбор камеры (deviceId)
- размеры при публикации (width, height)
- минимальный и максимальный битрейт видео (minBitrate, maxBitrate)
- FPS (frameRate)
Code Block | ||||
---|---|---|---|---|
| ||||
; if (Browser.isSafariWebRTC() && Browser.isiOS() && constraints.video =Flashphoner.getMediaProviders()[0] === "WebRTC") { deviceId:constraints.video.deviceId = {exact: $('#videoInput').val()}, ; } width: if (parseInt($('#sendWidth#sendVideoMinBitrate').val()) > 0), height:constraints.video.minBitrate = parseInt($('#sendHeight#sendVideoMinBitrate').val()); if (parseInt($('#sendVideoMaxBitrate').val()) > };0) if (Browser.isSafariWebRTC() && Browser.isiOS() && Flashphoner.getMediaProviders()[0] === "WebRTC") { constraints.video.deviceId = {exact: $('#videoInputconstraints.video.maxBitrate = parseInt($('#sendVideoMaxBitrate').val()}; }); if (parseInt($('#sendVideoMinBitrate#fps').val()) > 0) constraints.video.minBitrateframeRate = parseInt($('#sendVideoMinBitrate#fps').val()); |
5. Получение доступа к медиаустройствам для локального тестирования
Flashphoner.getMediaAccess() code
В метод передаются граничные параметры для аудио и видео (constrains), а также localVideo - div-элемент, в котором будет отображаться видео с выбранной камеры.
Code Block | ||||
---|---|---|---|---|
| ||||
Flashphoner.getMediaAccess(getConstraints(), localVideo).then(function (disp) { if (parseInt($('#sendVideoMaxBitrate$("#testBtn").text("Release").off('click').valclick(function ()) > 0) { constraints.video.maxBitrate = parseInt($('#sendVideoMaxBitrate'this).val())prop('disabled', true); if (parseInt($('#fps').val()) > 0)stopTest(); }).prop('disabled', false); constraints.video.frameRate = parseInt($('#fps').val()); |
...
. |
...
. |
...
В метод передаются граничные параметры для аудио и видео (constrains), а также localVideo - div-элемент, в котором будет отображаться видео с выбранной камеры.
Code Block | ||||
---|---|---|---|---|
| ||||
Flashphoner.getMediaAccess(getConstraints(), localVideo).then(function (disp) { $("#testBtn").text("Release").off('click').click(function () { . testStarted = true; }).catch(function (error) { $(this"#testBtn").prop('disabled', truefalse); testStarted = false; stopTest(); }); |
6. Подключение к серверу.
Flashphoner.createSession() code
Code Block | ||||
---|---|---|---|---|
| ||||
Flashphoner.createSession({urlServer: url, timeout: tm}).prop('disabled', false);on(SESSION_STATUS.ESTABLISHED, function (session) { ... testStarted = true; }).catch(}).on(SESSION_STATUS.DISCONNECTED, function (error) { ... $("#testBtn"}).prop('disabled', false);on(SESSION_STATUS.FAILED, function () { testStarted = false;... }); |
6. Подключение к серверу.
Flashphoner.createSession() 7. Получение от сервера события, подтверждающего успешное соединение.
ConnectionStatusEvent ESTABLISHED code
Code Block | ||||
---|---|---|---|---|
| ||||
Flashphoner.createSession({urlServer: url, timeout: tm}).on(SESSION_STATUS.ESTABLISHED, function (session) { setStatus("#connectStatus", session.status()); onConnected(session)); onConnected(session);... }).on(SESSION_STATUS.DISCONNECTED, function () ; |
8. Публикация видеопотока
session.createStream(), publishStream.publish() code
Code Block | ||||
---|---|---|---|---|
| ||||
publishStream = session.createStream({ setStatus("#connectStatus", SESSION_STATUS.DISCONNECTED); name: streamName, display: localVideo, onDisconnected(); }).on(SESSION_STATUS.FAILED, function () { cacheLocalResources: true, setStatus("#connectStatus", SESSION_STATUS.FAILED); constraints: constraints, onDisconnected(); }); |
7. Получение от сервера события, подтверждающего успешное соединение.
ConnectionStatusEvent ESTABLISHED code
Code Block | ||||
---|---|---|---|---|
| ||||
mediaConnectionConstraints: mediaConnectionConstraints, Flashphoner.createSession({urlServersdpHook: urlrewriteSdp, timeout: tm}).on(SESSION_STATUS.ESTABLISHED, function (session) { transport: transportInput, setStatus("#connectStatus", session.status()); cvoExtension: cvo, onConnected(session); stripCodecs: strippedCodecs, videoContentHint: contentHint ... }); |
8. Публикация видеопотока
...
publishStream.publish(); |
9. Получение от сервера события, подтверждающего успешную публикацию потока
StreamStatusEvent PUBLISHING code
Code Block | ||||
---|---|---|---|---|
| ||||
publishStream = session.createStream({ name: streamName,... display: localVideo, cacheLocalResources: true, constraints: constraints,}).on(STREAM_STATUS.PUBLISHING, function (stream) { mediaConnectionConstraints: mediaConnectionConstraints,$("#testBtn").prop('disabled', true); sdpHook: rewriteSdp, var video = document.getElementById(stream.id()); transport: transportInput, //resize local if resolution cvoExtension: cvo,is available stripCodecs: strippedCodecs ... }); publishStream.publish(); |
9. Получение от сервера события, подтверждающего успешную публикацию потока
StreamStatusEvent PUBLISHING code
Code Block | ||||
---|---|---|---|---|
| ||||
publishStream = session.createStream({if (video.videoWidth > 0 && video.videoHeight > 0) { resizeLocalVideo({target: video}); ...} }).on(STREAM_STATUS.PUBLISHING, function (stream) { enablePublishToggles(true); if ($("#testBtn#muteVideoToggle").prop('disabled', true);is(":checked")) { var video = document.getElementById(stream.id() muteVideo(); //resize local if resolution is available} if (video.videoWidth > 0 && video.videoHeight > 0($("#muteAudioToggle").is(":checked")) { resizeLocalVideo({target: video}muteAudio(); } enablePublishToggles(true); if ($("#muteVideoToggle").is(":checked")) {//remove resize listener in case this video was cached earlier muteVideo(video.removeEventListener('resize', resizeLocalVideo); }video.addEventListener('resize', resizeLocalVideo); if ($("#muteAudioToggle").is(":checked")) {publishStream.setMicrophoneGain(currentGainValue); muteAudio(setStatus("#publishStatus", STREAM_STATUS.PUBLISHING); }onPublishing(stream); }).on(STREAM_STATUS.UNPUBLISHED, function //remove resize listener in case this video was cached earlier () { ... video}).removeEventListener('resize', resizeLocalVideo);on(STREAM_STATUS.FAILED, function () { video.addEventListener('resize', resizeLocalVideo... }); publishStream.publish(); |
10. Воспроизведение потока
session.createStream(), previewStream.play() code
Code Block | ||||
---|---|---|---|---|
| ||||
previewStream = publishStreamsession.setMicrophoneGaincreateStream(currentGainValue);{ setStatus("#publishStatus", STREAM_STATUS.PUBLISHING); name: streamName, onPublishing(stream); display: remoteVideo, }).on(STREAM_STATUS.UNPUBLISHED, function () { constraints: constraints, ...transport: transportOutput, }).on(STREAM_STATUS.FAILED, function () { stripCodecs: strippedCodecs ... }); publishStreampreviewStream.publishplay(); |
10. Воспроизведение потока
session.createStream(), previewStream.play() 11. Получение от сервера события, подтверждающего успешное воспроизведение потока
StreamStatusEvent PLAYING code
Code Block | ||||
---|---|---|---|---|
| ||||
previewStream = session.createStream({ name: streamName,... }).on(STREAM_STATUS.PLAYING, function (stream) { display: remoteVideo, playConnectionQualityStat.connectionQualityUpdateTimestamp = constraints: constraints,new Date().valueOf(); transport: transportOutput, setStatus("#playStatus", stream.status()); stripCodecs: strippedCodecsonPlaying(stream); document.getElementById(stream.. }); previewStream.play(); |
11. Получение от сервера события, подтверждающего успешное воспроизведение потока
StreamStatusEvent PLAYING code
Code Block | ||||
---|---|---|---|---|
| ||||
id()).addEventListener('resize', function (event) { previewStream = session.createStream({ $("#playResolution").text(event.target.videoWidth + "x" + event.target.videoHeight); ... resizeVideo(event.target); }).on(STREAM_STATUS.PLAYING, function (stream) { }); playConnectionQualityStat.connectionQualityUpdateTimestamp = new Date().valueOf();//wait for incoming stream if setStatus("#playStatus", stream.status()); (Flashphoner.getMediaProviders()[0] == "WebRTC") { onPlaying(stream); document.getElementById(stream.id()).addEventListener('resize', setTimeout(function (event) { $("#playResolution").text(event.target.videoWidth + "x" + event.target.videoHeight);if(Browser.isChrome()) { resizeVideo(event.target); }detectSpeechChrome(stream); //wait for incoming stream } else { if (Flashphoner.getMediaProviders()[0] == "WebRTC") { setTimeout(function detectSpeech(stream) {; detectSpeech(stream);} }, 3000); } ... }); previewStream.play(); |
12. Остановка воспроизведения потока.
stream.stop() code
Code Block | ||||
---|---|---|---|---|
| ||||
$("#playBtn").text("Stop").off('click').click(function () { $(this).prop('disabled', true); stream.stop(); }).prop('disabled', false); |
...
StreamStatusEvent STOPPED code
Code Block | ||||
---|---|---|---|---|
| ||||
previewStream = session.createStream({ ... }).on(STREAM_STATUS.STOPPED, function () { setStatus("#playStatus", STREAM_STATUS.STOPPED); onStopped(); ... }); previewStream.play(); |
14. Остановка публикации видеопотока
stream.stop() code
Code Block | ||||
---|---|---|---|---|
| ||||
$("#publishBtn").text("Stop").off('click').click(function () { $(this).prop('disabled', true); stream.stop(); }).prop('disabled', false); |
...
StreamStatusEvent UNPUBLISHED code
Code Block | ||||
---|---|---|---|---|
| ||||
publishStream = session.createStream({ ... }).on(STREAM_STATUS.UNPUBLISHED, function () { setStatus("#publishStatus", STREAM_STATUS.UNPUBLISHED); onUnpublished(); ... }); publishStream.publish(); |
16. Отключение микрофонамикрофона
stream.muteAudio() code:
Code Block | ||||
---|---|---|---|---|
| ||||
function muteAudio() { if ($("#muteAudioToggle").is(":checked"))publishStream) { publishStream.muteAudio(); } } |
17. Отключение камеры
stream.muteVideo() code:
Code Block | ||||
---|---|---|---|---|
| ||||
function muteVideo() { if ($("#muteVideoToggle").is(":checked"))publishStream) { publishStream.muteVideo(); } } |
18. Отображение статистики при публикации потока
...