Example of
...
stream capturing from SIP call,
...
RTMP stream pulling from other server, streams mixing and re-publishing to a third party RTMP server
This example demonstrates how to make a call to SIP, receive audio and video traffic from SIP in response, capture RTMP stream from other server, mix audio streams, inject mixer sound to the SIP call and then redirect the SIP stream to a third-party RTMP server for further broadcasting
Image RemovedImage Added
The code of the example
This example is a simple REST client written on JavaScript, available at:
...
where host is WCS server address.
Analyzing the code
To analyze the code get sipget sip-as-rtmp-4.js file js file version with hash c306c1bbf49bfcbd8e24be927ae95f63b7dbaaba hash ecbadc3 that can be found found hereand and is availabe to download in build build 2.0.5.28.2747212.
1.
...
code
...
REST / HTTP queries sending.
code
Sending is done using POST method with ContentType application/json by AJAX query using jQuery framework.
Code Block |
---|
|
function loadPlayer(sendREST(url, data, successHandler, errorHandler) {
detectFlash(console.info("url: " + url);
var attributes = {}console.info("data: " + data);
attributes.id = "player";
$.ajax({
attributes.name = "player";url: url,
attributes.styleclass="center-block";
beforeSend: function var( flashvarsxhr =) {};
var pathToSWF = "../../dependencies/rtmp_player/player.swf";
xhr.overrideMimeType( "text/plain;" );
var elementId = "player"; },
var params = {};
type: 'POST',
params.menu = "true";contentType: 'application/json',
params.swliveconnect = "true";
data: data,
params.allowfullscreen = "true";
params.allowscriptaccess = "always"; success: (successHandler === undefined) ? handleAjaxSuccess : successHandler,
params.bgcolor = "#777777";
error: swfobject.embedSWF(pathToSWF, elementId, "350", "400", "11.2.202", "expressInstall.swf", flashvars, params, attributes(errorHandler === undefined) ? handleAjaxError : errorHandler
});
} |
2. Making outgoing call with REST / HTTP queries sending.
code
...
-request /call/startup
code
Connection and call data (RESTCall) are collected from the boxes on page
Code Block |
---|
|
function sendREST(url, data, successHandler, errorHandler) {
var url = console.infofield("url: restUrl") + url);"/call/startup";
console.info("data: " + datacallId = generateCallID();
$("#sipCallId").ajaxval({callId);
...
var RESTCall url: url,= {};
RESTCall.toStream = field("rtmpStream");
beforeSend: function (RESTCall.hasAudio xhr= ) {field("hasAudio");
RESTCall.hasVideo xhr.overrideMimeType( "text/plain;" = field("hasVideo");
RESTCall.callId = callId;
},
RESTCall.sipLogin = field("sipLogin");
type: 'POST',RESTCall.sipAuthenticationName = field("sipAuthenticationName");
RESTCall.sipPassword = field("sipPassword");
contentType: 'application/json',
RESTCall.sipPort = field("sipPort");
RESTCall.sipDomain data: data,= field("sipDomain");
RESTCall.sipOutboundProxy = field("sipOutboundProxy");
success: (successHandler === undefined) ? handleAjaxSuccess : successHandler, RESTCall.appKey = field("appKey");
RESTCall.sipRegisterRequired = field("sipRegisterRequired");
for (var key in error: (errorHandler === undefined) ? handleAjaxError : errorHandler
});
} |
3. Making outgoing call with REST-request /call/startup
code
Connection and call data (RESTCall) are collected from the boxes on page
RESTCall) {
setCookie(key, RESTCall[key]);
}
RESTCall.callee = field("callee");
var data = JSON.stringify(RESTCall);
sendREST(url, data);
startCheckCallStatus(); |
3. Capturing RTMP stream from other server with /pull/rtmp/pull REST query
code
Code Block |
---|
|
var pullRtmp = function(uri, fn) {
var url = console.log("Pull rtmp " + uri);
send(field("restUrl") + "/pull/callrtmp/startuppull";, {
callId = generateCallID(); uri: uri
$("#sipCallId").val(callId);}).then(
...
var RESTCall = {};fn(STREAM_STATUS.PENDING)
RESTCall.toStream = field("rtmpStream");).catch(function(e){
RESTCall.hasAudio = field("hasAudio"console.error(e);
RESTCall.hasVideo = field("hasVideo"fn(STREAM_STATUS.FAILED);
RESTCall.callId = callId;
RESTCall.sipLogin = field("sipLogin");});
}; |
4. Stop capturing RTMP stream from other server with /pull/rtmp/terminate REST query
code
Code Block |
---|
|
var terminateRtmp = function(uri, fn) {
RESTCall.sipAuthenticationName = field("sipAuthenticationName"console.log("Terminate rtmp " + uri);
RESTCall.sipPassword = send(field("sipPasswordrestUrl");
+ "/pull/rtmp/terminate", {
RESTCall.sipPort = field("sipPort");
RESTCall.sipDomain = field("sipDomain");uri: uri
RESTCall.sipOutboundProxy = field("sipOutboundProxy");
}).then(
RESTCall.appKey = field("appKey");fn(STREAM_STATUS.STOPPED)
RESTCall.sipRegisterRequired = field("sipRegisterRequired");
for (var key in RESTCall).catch(function(e) {
setCookie(key, RESTCall[key]fn(STREAM_STATUS.FAILED);
}
RESTCall.callee = field("callee"console.error(e);
var data = JSON.stringify(RESTCall);
sendREST(url, data);
startCheckCallStatus(); |
...
5. Mixer starting with /mixer/startup REST query
code
Code Block |
---|
|
var pullRtmpstartMixer = function(uri, fnstreamName) {
console.log("PullStart rtmpmixer " + uristreamName);
return send(field("restUrl") + "/pullmixer/rtmp/pullstartup", {
uri: uri
}).then("mixer://" + streamName,
fn(STREAM_STATUS.PENDING)
).catch(function(e){localStreamName: streamName
console.error(e);
fn(STREAM_STATUS.FAILED);
});
}; |
...
6. Mixer stopping with /mixer/terminate REST query
code
Code Block |
---|
|
var terminateRtmpstopMixer = function(uristreamName, fn) {
console.log("TerminateStop rtmpmixer " + uristreamName);
return send(field("restUrl") + "/pull/rtmpmixer/terminate", {
uri: uri
}).then("mixer://" + streamName,
fn(STREAM_STATUS.STOPPED)
).catch(function(e) {localStreamName: streamName
fn(STREAM_STATUS.FAILED);
console.error(e);
})
}; |
...
7. Adding/removing streams to mixer with /mixer/add and /mixer/remove REST queries
code
Code Block |
---|
|
var startMixer = function(streamNameif ($(ctx).is(':checked')) {
console.log("Start mixer " + streamName);
// Add stream to mixer
return send(field("restUrl") + "/mixer/startupadd", {
uri: "mixer://" + streamNamemixerStream,
localStreamName: streamName
mixerStream,
remoteStreamName: stream
});
}; |
7. Mixer stopping with /mixer/terminate REST query
code
Code Block |
---|
|
var stopMixer = function(streamName, fn) {
.then(function(){
console.log("Stop mixer " + streamNameadded");
});
return} else {
// Remove stream from mixer
send(field("restUrl") + "/mixer/terminateremove", {
uri: "mixer://" + streamNamemixerStream,
localStreamName: streamName
mixerStream,
});
}; |
8. Adding/removing streams to mixer with /mixer/add and /mixer/remove REST queries
code
Code Block |
---|
|
if ($(ctx).is(':checked')) { remoteStreamName: stream
// Add stream to mixer
send(field("restUrl") + "/mixer/add", }).then(function(){
uri: "mixer://" + mixerStream,console.log("removed");
localStreamName: mixerStream,});
} |
8. Injecting mixer stream to the SIP call with /call/inject REST query
code
Code Block |
---|
|
function injectStreamBtn(ctx) {
var streamName remoteStreamName: stream= $("#injectStream").val();
if (!streamName) {
}).then(function(){
console.log$("added"#injectStream").parent().addClass('has-error');
return })false;
} else {
var $that = // Remove stream from mixer
send(field$(ctx);
send(field("restUrl") + "/mixercall/removeinject_stream", {
uricallId: "mixer://" + mixerStream$("#sipCallId").val(),
localStreamNamestreamName: mixerStream,streamName
}).then(function(){
remoteStreamName: stream$that.removeClass('btn-success').addClass('btn-danger');
}$that.parents().closest('.input-group').then(function(){children('input').attr('disabled', true);
}).catch(function() {
console.log("removed"$that.removeClass('btn-danger').addClass('btn-success');
});
} |
...
$that.parents().closest('.input-group').children('input').attr('disabled', false);
});
} |
9. Re-publishing the SIP call stream to an RTMP server with /push/startup REST query
code
Code Block |
---|
|
function injectStreamBtnstartRtmpStream(ctx) {
if var streamName = $("#injectStream").val();
(!rtmpStreamStarted) {
if (!streamName) {rtmpStreamStarted = true;
$var url = field("#injectStream").parent().addClass('has-error')restUrl") + "/push/startup";
returnvar false;
RESTObj = {};
var $that = $(ctx);
var send(field("restUrl") + "/call/inject_stream", {options = {};
callId:if ($("#sipCallId#mute").valis(),':checked')) {
streamName: streamName
}).then(function(){options.action = "mute";
$that.removeClass('btn-success').addClass('btn-danger');
} else if ($("#music").is(':checked')) {
$that.parents().closest('.input-group').children('input').attr('disabled', true);
options.action = "sound_on";
options.soundFile = "sample.wav";
}).catch(function() {
$that.removeClass('btn-danger').addClass('btn-success');
RESTObj.streamName = field("rtmpStream");
RESTObj.rtmpUrl = field("rtmpUrl");
RESTObj.options $that.parents().closest('.input-group').children('input').attr('disabled', false= options;
console.log("Start rtmp");
sendREST(url, JSON.stringify(RESTObj), startupRtmpSuccessHandler, startupRtmpErrorHandler);
});
} |
10. Re-publishing the SIP call stream to an RTMP server with /push/startup REST query
sendDataToPlayer();
startCheckTransponderStatus();
}
} |
10. Mute/unmute RTMP stream re-published sound
Mute sound with /push/mute code
Code Block |
---|
|
function startRtmpStreammute() {
if (!rtmpStreamStarted) {
rtmpStreamStarted = true$("#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);
}
} |
Unmute sound /push/unmute code
Code Block |
---|
|
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 options.soundFile url = field("sample.wav";
}
RESTObj.streamName = field("rtmpStream");
restUrl") + "/push/unmute";
sendREST(url, RESTObj.rtmpUrl = field("rtmpUrl"JSON.stringify(RESTObj), muteSuccessHandler, muteErrorHandler);
}
} |
11. Injecting additional sound to RTMP stream re-published.
Injecting sound from file with /push/sound_on code
Code Block |
---|
|
function soundOn() {
RESTObj.options = options; if (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";
}
} |
11. Mute/unmute RTMP stream re-published sound
Mute sound with /push/mute code
Code Block |
---|
|
function mute() { RESTObj.loop = false;
if (rtmpStreamStarted) {
var url = $field("#muterestUrl").prop('disabled', true) + "/push/sound_on";
var RESTObj = {}sendREST(url, JSON.stringify(RESTObj), injectSoundSuccessHandler, injectSoundErrorHandler);
RESTObj.mediaSessionId = rtmpMediaSessionId;
var url = field("restUrl") + "/push/mute";}
} |
Stop injecting sound from file with /push/sound_off code
Code Block |
---|
|
function soundOff() {
if (rtmpStreamStarted) {
sendREST(url, JSON.stringify(RESTObj), muteSuccessHandler, muteErrorHandler);
}
} |
Unmute sound /push/unmute code
Code Block |
---|
|
function unmute() {
if (rtmpStreamStarted) {$("#music").prop('disabled', true);
var RESTObj = {};
RESTObj.mediaSessionId = rtmpMediaSessionId;
$("#mute").prop('disabled', true);
var RESTObj = {};
RESTObj.mediaSessionId = rtmpMediaSessionId;
var url = field("restUrl") + "/push/unmutesound_off";
sendREST(url, JSON.stringify(RESTObj), muteSuccessHandlerinjectSoundSuccessHandler, muteErrorHandlerinjectSoundErrorHandler);
}
} |
12. Injecting additional sound to RTMP stream re-published.
...
Hangup the SIP call with /call/terminate REST query.
code
Code Block |
---|
|
function soundOnhangup() {
var url if= field(rtmpStreamStarted"restUrl") { + "/call/terminate";
var currentCallId = $("#music").prop('disabled', true);
{ callId: callId };
var RESTObjdata = {}JSON.stringify(currentCallId);
RESTObj.mediaSessionId = rtmpMediaSessionId;
RESTObj.soundFile = "sample.wav";sendREST(url, data);
} |
13. RTMP URL displaying on the page to copy to a third party player
code
Code Block |
---|
|
function sendDataToPlayer() {
RESTObj.loopvar host = false;field("rtmpUrl")
var url = field("restUrl") + "/push/sound_on";.replace("localhost", window.location.hostname)
sendREST(url, JSON.stringify(RESTObj), injectSoundSuccessHandler, injectSoundErrorHandler);
}
} |
Stop injecting sound from file with /push/sound_off code
Code Block |
---|
|
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. Hangup the SIP call with /call/terminate REST query.
code
Code Block |
---|
|
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);
} |