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 loadPlayersendREST() {
    detectFlash();url, data, successHandler, errorHandler) {
    var attributes = {}console.info("url: " + url);
    attributes.id = "player"console.info("data: " + data);
    attributes.name = "player";
$.ajax({
        attributes.styleclass="center-block";
url: url,
        var flashvars = {};
beforeSend: function ( xhr ) {
          var pathToSWF =xhr.overrideMimeType( "../../dependencies/rtmp_player/player.swf"text/plain;" );
    var elementId = "player";
  },
      var params = {};type: 'POST',
    params.menu = "true";
  contentType:  params.swliveconnect = "true";
'application/json',
       params.allowfullscreen = "true";data: data,
    params.allowscriptaccess = "always";
    success:  params.bgcolor = "#777777";
    swfobject.embedSWF(pathToSWF, elementId, "350", "400", "11.2.202", "expressInstall.swf", flashvars, params, attributes(successHandler === undefined) ? handleAjaxSuccess : successHandler,
        error: (errorHandler === undefined) ? handleAjaxError : errorHandler
    });
}

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

код

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

...

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

code

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

Code Block
languagejs
themeRDark
function sendREST(url, data, successHandler, errorHandler)var {
url =   console.infofield("url: restUrl") + url)"/call/startup";
    console.info("data: " + datacallId = generateCallID();
    $("#sipCallId").ajaxval({callId);
    ...
    url: url,
  var RESTCall = {};
    RESTCall.toStream = beforeSend: function ( xhr ) {field("rtmpStream");
    RESTCall.hasAudio = field("hasAudio");
    RESTCall.hasVideo = xhr.overrideMimeTypefield( "text/plain;hasVideo" );
    RESTCall.callId    },= callId;
    RESTCall.sipLogin = field("sipLogin");
  type: 'POST',
    RESTCall.sipAuthenticationName = field("sipAuthenticationName");
    RESTCall.sipPassword contentType: 'application/json',= field("sipPassword");
    RESTCall.sipPort = field("sipPort");
  data: data,
 RESTCall.sipDomain = field("sipDomain");
    RESTCall.sipOutboundProxy success:= (successHandler === undefined) ? handleAjaxSuccess : successHandler,field("sipOutboundProxy");
    RESTCall.appKey = field("appKey");
    RESTCall.sipRegisterRequired = field("sipRegisterRequired");

  error:  for (errorHandler === undefined) ? handleAjaxError : errorHandler
    });
}

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

код

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

Code Block
languagejs
themeRDark
    var urlvar key in RESTCall) {
        setCookie(key, RESTCall[key]);
    }

    RESTCall.callee = field("restUrlcallee");

  + "/call/startup";
    callId  var data = generateCallIDJSON.stringify(RESTCall);

    $("#sipCallId").val(callIdsendREST(url, data);
    ...
    var RESTCall = {};
    RESTCall.toStream = field("rtmpStream");startCheckCallStatus();

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

code

Code Block
languagejs
themeRDark
var pullRtmp = function(uri, fn) {
    RESTCall.hasAudio = field("hasAudio"console.log("Pull rtmp " + uri);
    RESTCall.hasVideo = send(field("hasVideorestUrl");
 + "/pull/rtmp/pull", {
 RESTCall.callId = callId;
    RESTCall.sipLogin = field("sipLogin");uri: uri
    RESTCall.sipAuthenticationName = field("sipAuthenticationName");}).then(
    RESTCall.sipPassword = field("sipPassword");  fn(STREAM_STATUS.PENDING)
    RESTCall.sipPort = field("sipPort");
).catch(function(e){
      RESTCall.sipDomain = field("sipDomain"console.error(e);
      RESTCall.sipOutboundProxy = field("sipOutboundProxy"fn(STREAM_STATUS.FAILED);
    RESTCall.appKey});
};

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

code

Code Block
languagejs
themeRDark
var terminateRtmp = field("appKey");function(uri, fn) {
    RESTCall.sipRegisterRequired = field("sipRegisterRequired");
console.log("Terminate rtmp " + uri);
    for (var key in RESTCall)send(field("restUrl") + "/pull/rtmp/terminate", {
        setCookie(key, RESTCall[key]);uri: uri
    }
).then(
    RESTCall.callee = field("callee");

    var data = JSON.stringify(RESTCall);

    sendREST(url, data  fn(STREAM_STATUS.STOPPED)
    ).catch(function(e) {
        fn(STREAM_STATUS.FAILED);
        console.error(e);
    startCheckCallStatus(})
};

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

кодcode

Code Block
languagejs
themeRDark
var pullRtmpstartMixer = function(uri, fnstreamName) {
    console.log("PullStart rtmpmixer " + uristreamName);
    return send(field("restUrl") + "/pullmixer/rtmp/pullstartup", {
        uri: "mixer: uri
//" + streamName,
     }).then(
   localStreamName: streamName
    fn(STREAM_STATUS.PENDING)
    ).catch(function(e)});
};

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

code

Code Block
languagejs
themeRDark
var stopMixer = function(streamName, fn) {
    console.log("Stop mixer " + console.error(estreamName);
    return    fn(STREAM_STATUS.FAILED);send(field("restUrl") + "/mixer/terminate", {
        uri: "mixer://" + streamName,
        localStreamName: streamName
    });
};

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

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

code

Code Block
languagejs
themeRDark
var terminateRtmp = function(uri, fnif ($(ctx).is(':checked')) {
    console.log("Terminate rtmp " + uri);
 // Add stream to mixer
        send(field("restUrl") + "/pullmixer/rtmp/terminateadd", {
            uri: uri
 "mixer://" + mixerStream,
     }).then(
        fn(STREAM_STATUS.STOPPED)
localStreamName: mixerStream,
     ).catch       remoteStreamName: stream
        }).then(function(e) {
          fn(STREAM_STATUS.FAILED  console.log("added");
        console.error(e});
    })
};

6. Запуск микшера запросом /mixer/startup

код

Code Block
languagejs
themeRDark
var startMixer = function(streamName) {
    console.log("Start mixer " + streamName);
 else {
        // Remove stream from mixer
       return send(field("restUrl") + "/mixer/startupremove", {
            uri: "mixer://"  + streamNamemixerStream,
            localStreamName: streamNamemixerStream,
    });
};

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

код

Code Block
languagejs
themeRDark
var stopMixer = function(streamName, fn) {
    console.log("Stop mixer " + streamName);
remoteStreamName: stream
       return send(field("restUrl") + "/mixer/terminate", {
}).then(function(){
           uri: "mixer://" + streamName,console.log("removed");
        localStreamName: streamName});
    });
};

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

code

Code Block
languagejs
themeRDark
iffunction ($injectStreamBtn(ctx).is(':checked')) {
    var streamName = $("#injectStream").val();
  // Add stream to mixerif (!streamName) {
        send(field$("restUrl") + "/mixer/add", {#injectStream").parent().addClass('has-error');
        return false;
   uri: "mixer://" + mixerStream, }
    var $that = $(ctx);
     localStreamName: mixerStream,send(field("restUrl") + "/call/inject_stream", {
        callId: $("#sipCallId").val(),
   remoteStreamName:  stream
   streamName: streamName
    }).then(function(){
            console.log("added"$that.removeClass('btn-success').addClass('btn-danger');
        })$that.parents().closest('.input-group').children('input').attr('disabled', true);
    } else).catch(function() {
        // Remove stream from mixer
        send(field("restUrl") + "/mixer/remove", {
            uri: "mixer://"  + mixerStream,$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) {
      localStreamName: mixerStream,
 rtmpStreamStarted = true;
         remoteStreamName: stream
var url = field("restUrl") + "/push/startup";
        var }).then(function(){RESTObj = {};
        var options   console.log("removed")= {};
        });
    }

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

код

Code Block
languagejs
themeRDark
function injectStreamBtn(ctxif ($("#mute").is(':checked')) {
         var streamName   options.action = $("#injectStreammute").val();
    if (!streamName) {
  } else if    ($("#injectStream#music").parent().addClassis('has-error:checked');) {
         return false;
  options.action  }= "sound_on";
    var  $that = $(ctx);
    send(field("restUrl") + "/call/inject_stream", {options.soundFile = "sample.wav";
        callId: $("#sipCallId").val(),}
        streamName: RESTObj.streamName
    }).then(function(){= field("rtmpStream");
        $that.removeClass('btn-success').addClass('btn-danger')RESTObj.rtmpUrl = field("rtmpUrl");
        $that.parents().closest('.input-group').children('input').attr('disabled', true)RESTObj.options = options;
    }).catch(function() {    console.log("Start rtmp");
        $that.removeClass('btn-danger').addClass('btn-success'sendREST(url, JSON.stringify(RESTObj), startupRtmpSuccessHandler, startupRtmpErrorHandler);
        sendDataToPlayer();
        $that.parents().closest('.input-group').children('input').attr('disabled', false);
  startCheckTransponderStatus();
    });
}

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

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

Code Block
languagejsxml
themeRDark
function startRtmpStreammute() {
    if (!rtmpStreamStarted) {
        rtmpStreamStarted =$("#mute").prop('disabled', true);
        var urlRESTObj = field("restUrl") + "/push/startup"{};
        var RESTObj.mediaSessionId = {}rtmpMediaSessionId;
        var optionsurl = {} field("restUrl") + "/push/mute";
        if ($("#mute").is(':checked')sendREST(url, JSON.stringify(RESTObj), muteSuccessHandler, muteErrorHandler);
    }
}

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

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

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

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

Code Block
languagejs
themeRDark
function soundOn() {
    if    RESTObj.options = options;(rtmpStreamStarted) {
        console.log$("Start rtmp"#music").prop('disabled', true);
        sendREST(url, JSON.stringify(RESTObj), startupRtmpSuccessHandler, startupRtmpErrorHandler);
var RESTObj = {};
        RESTObj.mediaSessionId = sendDataToPlayer()rtmpMediaSessionId;
         startCheckTransponderStatus()RESTObj.soundFile = "sample.wav";
      }
}

...

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

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

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

Code Block
languagejs
themeRDark
function soundOff() {
    if (rtmpStreamStarted) {
        sendREST(url, JSON.stringify(RESTObj), muteSuccessHandler, muteErrorHandler)$("#music").prop('disabled', true);
    }
}

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

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

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

code

Code Block
languagejs
themeRDark
function soundOnhangup() {
    var ifurl = field(rtmpStreamStarted"restUrl") {
 + "/call/terminate";
    var currentCallId = {  $("#music").prop('disabled', true)callId: callId };
    var data =  var RESTObj = {};
  JSON.stringify(currentCallId);
    sendREST(url, data);
}

13. RTMP URL displaying on the page to copy to a third party player

code

Code Block
languagejs
themeRDark
function sendDataToPlayer() {
    var host RESTObj.mediaSessionId = rtmpMediaSessionId;field("rtmpUrl")
        RESTObj.soundFile = "sample.wav";
        RESTObj.loop = false;.replace("localhost", window.location.hostname)
        var url = field("restUrl") + "/push/sound_on";
        sendREST(url, JSON.stringify(RESTObj), injectSoundSuccessHandler, injectSoundErrorHandler);
    }
}

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

Code Block
languagejs
themeRDark
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
themeRDark
function hangup() {.replace("127.0.0.1", window.location.hostname);

    var urlrtmpStreamPrefix = field("restUrl") + "/call/terminate""rtmp_";
    var currentCallIdurl = {host callId: callId };
    var data = JSON.stringify(currentCallId+ "/" + rtmpStreamPrefix + field("rtmpStream");
    sendREST$("#player").text(url, data);
}