Versions Compared

Key

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

Table of Contents

Пример захвата потока с SIP, захвата RTMP-потока с другого сервера, микширования потоков и ретрансляции результата на RTMP-сервер

Данный пример показывает, как можно сделать вызов на SIP, получить от SIP стороны аудио и видео трафик, захватить RTMP-поток с другого сервера, смикшировать аудиопотоки, добавить их к звонку и затем перенаправить полученный поток на RTMP-сервер

Image RemovedImage Added

Код примера

Пример представляет собой REST-клиента, написанного на JavaScript и находится по следующему пути:

...

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

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

Для разбора кода возьмем версию файла sip-as-rtmp-4.js с хешем c306c1bbf49bfcbd8e24be927ae95f63b7dbaaba ecbadc3, которая находится здесь и доступна для
скачивания в соответствующей сборке 2.0.5.28.2747.212

1. Загрузка тестового RTMP-плеера на страницу для дальнейшего тестирования воспроизведения RTMP потока.кодОтправка REST / HTTP - запросов.

code

Отправка происходит методом POST с ContentType application/json AJAX запросом с использованием фреймворка jquery.

Code Block
languagejs
themeRDark
function loadPlayer(sendREST(url, data, successHandler, errorHandler) {
detectFlash(    console.info("url: " + url);
var  attributes = {};
attributes.id = "player";
attributes.name = "player";
attributes.styleclass="center-block";
var flashvars = {};
var pathToSWF = "../../dependencies/rtmp_player/player.swf";
var elementId = "player";
var params = {};
params.menu = "true";
params.swliveconnect = "true";
params.allowfullscreen = "true";
params.allowscriptaccess = "always";
params.bgcolor = "#777777";
swfobject.embedSWF(pathToSWF, elementId, "350", "400", "11.2.202", "expressInstall.swf", flashvars, params, attributes);
}

2. Отправка REST / HTTP - запросов.

код

Отправка происходит методом POST с ContentType application/json AJAX запросом с использованием фреймворка jquery.

Code Block
languagejs
function sendREST(url, data, successHandler, errorHandler) {
console.info("url: " + url);
console.info("data: " + data);
$.ajax({
url: url,
beforeSend: function ( xhr ) {
xhr.overrideMimeType( "text/plain;" );
},
type: 'POST',
contentType: 'application/json',
data: data,
console.info("data: " + data);
    $.ajax({
        url: url,
        beforeSend: function ( xhr ) {
            xhr.overrideMimeType( "text/plain;" );
        },
        type: 'POST',
        contentType: 'application/json',
        data: data,
        success: (successHandler === undefined) ? handleAjaxSuccess : successHandler,
        error: (errorHandler === undefined) ? handleAjaxError : errorHandler
    });
}

32. Создание исходящего звонка при помощи REST-запроса /call/startup

кодcode

Из текстовых форм собираются данные для установки соединения и звонка (RESTCall)

Code Block
languagejs
themeRDark
    var url = field("restUrl") + "/call/startup";
    callId = generateCallID();
    $("#sipCallId").val(callId);
    ...
    var connectionRESTCall = {};
connection.sipLogin    RESTCall.toStream = field("sipLoginrtmpStream");
connection.sipAuthenticationName    RESTCall.hasAudio = field("sipAuthenticationNamehasAudio");
connection.sipPassword    RESTCall.hasVideo = field("sipPasswordhasVideo");
connection.sipPort    RESTCall.callId = field("sipPort")callId;
connection.sipDomain    RESTCall.sipLogin = field("sipDomainsipLogin");
connection.sipOutboundProxy    RESTCall.sipAuthenticationName = field("sipOutboundProxysipAuthenticationName");
connection.appKey    RESTCall.sipPassword = field("appKeysipPassword");
connection.sipRegisterRequired    RESTCall.sipPort = field("sipRegisterRequiredsipPort");

for (var  key in connection) {
setCookie(key, connection[key]);
}

var RESTCall = {};
RESTCall.toStreamRESTCall.sipDomain = field("sipDomain");
    RESTCall.sipOutboundProxy = field("rtmpStreamsipOutboundProxy");
    RESTCall.hasAudioappKey = field("hasAudioappKey");
    RESTCall.hasVideosipRegisterRequired = field("hasVideosipRegisterRequired");
RESTCall.callId = callId;
RESTCall.sipLogin = field("sipLogin");
RESTCall.sipAuthenticationName
    for (var key in RESTCall) {
        setCookie(key, RESTCall[key]);
    }

    RESTCall.callee = field("sipAuthenticationNamecallee");
RESTCall.sipPassword
    var data = field("sipPassword"JSON.stringify(RESTCall);
RESTCall.sipPort = field("sipPort"
    sendREST(url, data);
RESTCall.sipDomain = field("sipDomain");
RESTCall.sipOutboundProxy = fieldstartCheckCallStatus("sipOutboundProxy");
RESTCall.appKey

3. Захват RTMP-потока с другого сервера запросом /pull/rtmp/pull

code

Code Block
languagejs
themeRDark
var pullRtmp = field("appKey");
RESTCall.sipRegisterRequired = field("sipRegisterRequired");

for (var key in RESTCall) {
setCookie(key, RESTCall[key]);
}

RESTCall.callee = field("callee");

var data = JSON.stringify(RESTCall);

sendREST(url, data);
startCheckCallStatus();

...

function(uri, fn) {
    console.log("Pull rtmp " + uri);
    send(field("restUrl") + "/pull/rtmp/pull", {
        uri: uri
    }).then(
        fn(STREAM_STATUS.PENDING)
    ).catch(function(e){
        console.error(e);
        fn(STREAM_STATUS.FAILED);
    });
};

4. Остановка захвата RTMP-потока с другого сервера запросом /pull/rtmp/pullterminate

кодcode

Code Block
languagejs
themeRDark
var pullRtmpterminateRtmp = function(uri, fn) {
    console.log("PullTerminate rtmp " + uri);
    send(field("restUrl") + "/pull/rtmp/pullterminate", {
        uri: uri
    }).then(
        fn(STREAM_STATUS.PENDINGSTOPPED)
    ).catch(function(e) {
console.error(e);
        fn(STREAM_STATUS.FAILED);
        console.error(e);
    });
};

5. Остановка захвата RTMP-потока с другого сервера Запуск микшера запросом /pullmixer/rtmp/terminatestartup

кодcode

Code Block
languagejs
themeRDark
var terminateRtmpstartMixer = function(uri, fnstreamName) {
console    console.log("TerminateStart rtmpmixer " + uristreamName);
    return send(field("restUrl") + "/pullmixer/rtmp/terminatestartup", {
        uri: "mixer: uri
}).then(
fn(STREAM_STATUS.STOPPED)
).catch(function(e) {
fn(STREAM_STATUS.FAILED);
console.error(e);
})
};

...

//" + streamName,
        localStreamName: streamName
    });
};

6. Остановка микшера запросом /mixer/startupterminate

кодcode

Code Block
languagejs
themeRDark
var startMixerstopMixer = function(streamName, fn) {
    console.log("StartStop mixer " + streamName);
    return send(field("restUrl") + "/mixer/startupterminate", {
        uri: "mixer://" + streamName,
        localStreamName: streamName
    });
};

7. Остановка микшера запросом Добавление/удаление потоков в микшер запросами /mixer/add и /mixer/terminateremove

кодcode

Code Block
languagejs
themeRDark
var stopMixer = function(streamName, fn) {
console.log("Stop mixer " + streamName);
returnif ($(ctx).is(':checked')) {
        // Add stream to mixer
        send(field("restUrl") + "/mixer/terminateadd", {
uri:             uri: "mixer://" + streamNamemixerStream,
            localStreamName: mixerStream,
            remoteStreamName: streamName
});
};

8. Добавление/удаление потоков в микшер запросами /mixer/add и /mixer/remove

код

Code Block
languagejs
if ($(ctx).is(':checked')) {
// Add stream to mixer
send(field("restUrl") + "/mixer/add", {
uri: "mixer://" + mixerStream,
localStreamName: mixerStream,
remoteStreamName: stream
}).then(function(){
console.log("added");
});
} else {
// Remove stream from mixer
send(field("restUrl") + "/mixer/remove", {
uri: "mixer://" + mixerStream,
localStreamName: mixerStream,
remoteStreamName: stream
}).then(function(){
console.log("removed");
});
}

9. Добавление выходного потока микшера в звонок запросом /call/inject

код

Code Block
languagejs
function injectStreamBtn(ctx) {
var streamName = $("#injectStream").val();
if (!streamName) {
$("#injectStream").parent().addClass('has-error');
return false;
}
var $that = $(ctx);
send(field("restUrl") + "/call/inject_stream", {
callId: $("#sipCallId").val(),
streamName: streamName
}).then(function(){
$that.removeClass('btn-success').addClass('btn-danger');
$that.parents().closest('.input-group').children('input').attr('disabled', true);
}).catch(function() {
$that.removeClass('btn-danger').addClass('btn-success');
$that.parents().closest('.input-group').children('input').attr('disabled', false);
});
}

...

код

Code Block
languagejs
function startRtmpStream() {
if (!rtmpStreamStarted) {
rtmpStreamStarted = true;
stream
        }).then(function(){
            console.log("added");
        });
    } else {
        // Remove stream from mixer
        send(field("restUrl") + "/mixer/remove", {
            uri: "mixer://"  + mixerStream,
            localStreamName: mixerStream,
            remoteStreamName: stream
        }).then(function(){
            console.log("removed");
        });
    }

8. Добавление выходного потока микшера в звонок запросом /call/inject

code

Code Block
languagejs
themeRDark
function injectStreamBtn(ctx) {
    var streamName = $("#injectStream").val();
    if (!streamName) {
        $("#injectStream").parent().addClass('has-error');
        return false;
    }
    var $that = $(ctx);
    send(field("restUrl") + "/call/inject_stream", {
        callId: $("#sipCallId").val(),
        streamName: streamName
    }).then(function(){
        $that.removeClass('btn-success').addClass('btn-danger');
        $that.parents().closest('.input-group').children('input').attr('disabled', true);
    }).catch(function() {
        $that.removeClass('btn-danger').addClass('btn-success');
        $that.parents().closest('.input-group').children('input').attr('disabled', false);
    });
}

9. Ретрансляция звонка на RTMP-сервер в поток запросом /push/startup

code

Code Block
languagejs
themeRDark
function startRtmpStream() {
    if (!rtmpStreamStarted) {
        rtmpStreamStarted = true;
        var url = field("restUrl") + "/push/startup";
        var RESTObj = {};
        var options = {};
        if ($("#mute").is(':checked')) {
            options.action = "mute";
        } else if ($("#music").is(':checked')) {
            options.action = "sound_on";
            options.soundFile = "sample.wav";
        }
        RESTObj.streamName = field("rtmpStream");
        RESTObj.rtmpUrl = field("rtmpUrl");
        RESTObj.options = options;
        console.log("Start rtmp");
        sendREST(url, JSON.stringify(RESTObj), startupRtmpSuccessHandler, startupRtmpErrorHandler);
        sendDataToPlayer();
        startCheckTransponderStatus();
    }
}

10. Включение/отключение звука ретранслируемого RTMP-потока.

Отключение звука /push/mute code

Code Block
languagexml
themeRDark
function mute() {
    if (rtmpStreamStarted) {
        $("#mute").prop('disabled', true);
        var RESTObj = {};
        RESTObj.mediaSessionId = rtmpMediaSessionId;
        var url = field("restUrl") + "/push/mute";
        sendREST(url, JSON.stringify(RESTObj), muteSuccessHandler, muteErrorHandler);
    }
}

Включение звука /push/unmute code

Code Block
languagejs
themeRDark
function unmute() {
    if (rtmpStreamStarted) {
        $("#mute").prop('disabled', true);
        var RESTObj = {};
        RESTObj.mediaSessionId = rtmpMediaSessionId;
        var url = field("restUrl") + "/push/startupunmute";
var RESTObj = {};
var options = {};
if ($("#mute").is(':checked')) {
options.action = "mute";
} else if (        sendREST(url, JSON.stringify(RESTObj), muteSuccessHandler, muteErrorHandler);
    }
}

11. Включение/отключение дополнительной звуковой дорожки из файла в ретранслируемом RTMP-потоке.

Включение звуковой дорожки из файла /push/sound_on code

Code Block
languagejs
themeRDark
function soundOn() {
    if (rtmpStreamStarted) {
        $("#music").isprop(':checkeddisabled')) {
options.action = "sound_on";
options, true);
        var RESTObj = {};
        RESTObj.mediaSessionId = rtmpMediaSessionId;
        RESTObj.soundFile = "sample.wav";
}
RESTObj.streamName        RESTObj.loop = false;
        var url = field("rtmpStreamrestUrl");
RESTObj.rtmpUrl =+ field("rtmpUrl");
RESTObj.options = options;
console.log("Start rtmp");
"/push/sound_on";
        sendREST(url, JSON.stringify(RESTObj), startupRtmpSuccessHandler, startupRtmpErrorHandler);
sendDataToPlayer();
startCheckTransponderStatus((RESTObj), injectSoundSuccessHandler, injectSoundErrorHandler);
    }
}

11. Включение/отключение звука ретранслируемого RTMP-потока.Отключение звука Отключение звуковой дорожки /push/mute кодsound_off code

Code Block
languagexmljs
themeRDark
function mutesoundOff() {
    if (rtmpStreamStarted) {
        $("#mute#music").prop('disabled', true);
        var RESTObj = {};
        RESTObj.mediaSessionId = rtmpMediaSessionId;
        var url = field("restUrl") + "/push/mutesound_off";
        sendREST(url, JSON.stringify(RESTObj), muteSuccessHandlerinjectSoundSuccessHandler, muteErrorHandlerinjectSoundErrorHandler);
    }
}

Включение звука /push/unmute код12. Завершение звонка запросом /call/terminate.

code

Code Block
languagejs
themeRDark
function unmutehangup() {
if (rtmpStreamStarted) {
$("#mute").prop('disabled', true);
var RESTObj = {};
RESTObj.mediaSessionId = rtmpMediaSessionId;
var url = field("restUrl") + "/push/unmute";
sendREST(url, JSON.stringify(RESTObj), muteSuccessHandler, muteErrorHandler);
}
}

12. Включение/отключение дополнительной звуковой дорожки из файла в ретранслируемом RTMP-потоке.

...

    var url = field("restUrl") + "/call/terminate";
    var currentCallId = { callId: callId };
    var data = JSON.stringify(currentCallId);
    sendREST(url, data);
}

13. Отображение RTMP URL на странице для копирования в сторонний плеер

code

function soundOn() { if (rtmpStreamStarted) { $("#music").prop('disabled', true); var RESTObj = {}; RESTObj.mediaSessionId = rtmpMediaSessionId; RESTObj.soundFile = "sample.wav"; RESTObj.loop = false; var url
Code Block
languagejs
themeRDark
function sendDataToPlayer() {
    var host = field("restUrl") + "/push/sound_on";
sendREST(url, JSON.stringify(RESTObj), injectSoundSuccessHandler, injectSoundErrorHandler);
}
}

Отключение звуковой дорожки /push/sound_off код

Code Block
languagejs
function soundOff() {
if (rtmpStreamStarted) {
$("#music").prop('disabled', true);
var RESTObj = {};
RESTObj.mediaSessionId = rtmpMediaSessionId;
var url = field("restUrl") + "/push/sound_off";
sendREST(url, JSON.stringify(RESTObj), injectSoundSuccessHandler, injectSoundErrorHandler);
}
}

13. Завершение звонка запросом /call/terminate.

код

Code Block
languagejs
function hangup() {
var url = field("restUrl") + "/call/terminate";
var currentCallId = { callId: callId };
var data = JSON.stringify(currentCallId);
sendREST(url, datartmpUrl")
        .replace("localhost", window.location.hostname)
        .replace("127.0.0.1", window.location.hostname);

    var rtmpStreamPrefix = "rtmp_";
    var url = host + "/" + rtmpStreamPrefix + field("rtmpStream");
    $("#player").text(url);
}