导入数据库表和音视频demo
This commit is contained in:
147
media-server-demo-node/lib/broadcast.js
Normal file
147
media-server-demo-node/lib/broadcast.js
Normal file
@@ -0,0 +1,147 @@
|
||||
//Get the Medooze Media Server interface
|
||||
const MediaServer = require("medooze-media-server");
|
||||
|
||||
//Get Semantic SDP objects
|
||||
const SemanticSDP = require("semantic-sdp");
|
||||
const SDPInfo = SemanticSDP.SDPInfo;
|
||||
const MediaInfo = SemanticSDP.MediaInfo;
|
||||
const CandidateInfo = SemanticSDP.CandidateInfo;
|
||||
const DTLSInfo = SemanticSDP.DTLSInfo;
|
||||
const ICEInfo = SemanticSDP.ICEInfo;
|
||||
const StreamInfo = SemanticSDP.StreamInfo;
|
||||
const TrackInfo = SemanticSDP.TrackInfo;
|
||||
const Direction = SemanticSDP.Direction;
|
||||
const CodecInfo = SemanticSDP.CodecInfo;
|
||||
|
||||
|
||||
//Create new streamer
|
||||
const streamer = MediaServer.createStreamer();
|
||||
|
||||
//Create new video session codecs
|
||||
const video = new MediaInfo("video","video");
|
||||
|
||||
//Add h264 codec
|
||||
video.addCodec(new CodecInfo("h264",96));
|
||||
|
||||
//Create session for video
|
||||
const session = streamer.createSession(video,{
|
||||
local : {
|
||||
port: 5004
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = function(request,protocol,endpoint)
|
||||
{
|
||||
const connection = request.accept(protocol);
|
||||
|
||||
connection.on('message', (frame) =>
|
||||
{
|
||||
//Get cmd
|
||||
var msg = JSON.parse(frame.utf8Data);
|
||||
|
||||
|
||||
//Get cmd
|
||||
if (msg.cmd==="OFFER")
|
||||
{
|
||||
|
||||
//Process the sdp
|
||||
var offer = SDPInfo.process(msg.offer);
|
||||
|
||||
//Create an DTLS ICE transport in that enpoint
|
||||
const transport = endpoint.createTransport({
|
||||
dtls : offer.getDTLS(),
|
||||
ice : offer.getICE()
|
||||
});
|
||||
|
||||
//Set RTP remote properties
|
||||
transport.setRemoteProperties({
|
||||
audio : offer.getMedia("audio"),
|
||||
video : offer.getMedia("video")
|
||||
});
|
||||
|
||||
//Get local DTLS and ICE info
|
||||
const dtls = transport.getLocalDTLSInfo();
|
||||
const ice = transport.getLocalICEInfo();
|
||||
|
||||
//Get local candidates
|
||||
const candidates = endpoint.getLocalCandidates();
|
||||
|
||||
//Create local SDP info
|
||||
let answer = new SDPInfo();
|
||||
|
||||
//Add ice and dtls info
|
||||
answer.setDTLS(dtls);
|
||||
answer.setICE(ice);
|
||||
//For each local candidate
|
||||
for (let i=0;i<candidates.length;++i)
|
||||
//Add candidate to media info
|
||||
answer.addCandidate(candidates[i]);
|
||||
|
||||
//Get remote video m-line info
|
||||
let audioOffer = offer.getMedia("audio");
|
||||
|
||||
//If offer had video
|
||||
if (audioOffer)
|
||||
{
|
||||
//Create video media
|
||||
let audio = new MediaInfo(audioOffer.getId(), "audio");
|
||||
//Set recv only
|
||||
audio.setDirection(Direction.INACTIVE);
|
||||
//Add it to answer
|
||||
answer.addMedia(audio);
|
||||
}
|
||||
|
||||
//Get remote video m-line info
|
||||
let videoOffer = offer.getMedia("video");
|
||||
|
||||
//If offer had video
|
||||
if (videoOffer)
|
||||
{
|
||||
//Create video media
|
||||
let video = new MediaInfo(videoOffer.getId(), "video");
|
||||
|
||||
//Get codec types
|
||||
let h264 = videoOffer.getCodec("h264");
|
||||
//Add video codecs
|
||||
video.addCodec(h264);
|
||||
//Set recv only
|
||||
video.setDirection(Direction.RECVONLY);
|
||||
//Add it to answer
|
||||
answer.addMedia(video);
|
||||
}
|
||||
|
||||
//Set RTP local properties
|
||||
transport.setLocalProperties({
|
||||
audio : answer.getMedia("audio"),
|
||||
video : answer.getMedia("video")
|
||||
});
|
||||
|
||||
|
||||
//Create new local stream with only video
|
||||
const outgoingStream = transport.createOutgoingStream({
|
||||
audio: false,
|
||||
video: true
|
||||
});
|
||||
|
||||
//Copy incoming data from the broadcast stream to the local one
|
||||
outgoingStream.getVideoTracks()[0].attachTo(session.getIncomingStreamTrack());
|
||||
|
||||
//Get local stream info
|
||||
const info = outgoingStream.getStreamInfo();
|
||||
|
||||
//Add local stream info it to the answer
|
||||
answer.addStream(info);
|
||||
|
||||
//Send response
|
||||
connection.sendUTF(JSON.stringify({
|
||||
answer : answer.toString()
|
||||
}));
|
||||
|
||||
//Close on disconnect
|
||||
connection.on("close",() => {
|
||||
//Stop
|
||||
transport.stop();
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
74
media-server-demo-node/lib/datachannels.js
Normal file
74
media-server-demo-node/lib/datachannels.js
Normal file
@@ -0,0 +1,74 @@
|
||||
//Get the Medooze Media Server interface
|
||||
const MediaServer = require("medooze-media-server");
|
||||
|
||||
//Get Semantic SDP objects
|
||||
const SemanticSDP = require("semantic-sdp");
|
||||
const SDPInfo = SemanticSDP.SDPInfo;
|
||||
const MediaInfo = SemanticSDP.MediaInfo;
|
||||
const CandidateInfo = SemanticSDP.CandidateInfo;
|
||||
const DTLSInfo = SemanticSDP.DTLSInfo;
|
||||
const ICEInfo = SemanticSDP.ICEInfo;
|
||||
const StreamInfo = SemanticSDP.StreamInfo;
|
||||
const TrackInfo = SemanticSDP.TrackInfo;
|
||||
const Direction = SemanticSDP.Direction;
|
||||
const CodecInfo = SemanticSDP.CodecInfo;
|
||||
|
||||
const Capabilities = {
|
||||
data : {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = function(request,protocol,endpoint)
|
||||
{
|
||||
const connection = request.accept(protocol);
|
||||
|
||||
connection.on('message', (frame) =>
|
||||
{
|
||||
//Get cmd
|
||||
var msg = JSON.parse(frame.utf8Data);
|
||||
|
||||
//Get cmd
|
||||
if (msg.cmd==="OFFER")
|
||||
{
|
||||
//Process the sdp
|
||||
var offer = SDPInfo.process(msg.offer);
|
||||
|
||||
//Create an DTLS ICE transport in that enpoint
|
||||
const transport = endpoint.createTransport(offer);
|
||||
|
||||
//transport.dump("/tmp/svc.pcap");
|
||||
|
||||
//Set RTP remote properties
|
||||
transport.setRemoteProperties({
|
||||
audio : offer.getMedia("audio"),
|
||||
video : offer.getMedia("video")
|
||||
});
|
||||
|
||||
//Create local SDP info
|
||||
const answer = offer.answer({
|
||||
dtls : transport.getLocalDTLSInfo(),
|
||||
ice : transport.getLocalICEInfo(),
|
||||
candidates : endpoint.getLocalCandidates(),
|
||||
capabilities : Capabilities
|
||||
});
|
||||
|
||||
//Set RTP local properties
|
||||
transport.setLocalProperties({
|
||||
video : answer.getMedia("video")
|
||||
});
|
||||
|
||||
//Get offered stream info
|
||||
//Send response
|
||||
connection.sendUTF(JSON.stringify({
|
||||
answer : answer.toString()
|
||||
}));
|
||||
|
||||
//Close on disconnect
|
||||
connection.on("close",() => {
|
||||
//Stop
|
||||
transport.stop();
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
134
media-server-demo-node/lib/playback.js
Normal file
134
media-server-demo-node/lib/playback.js
Normal file
@@ -0,0 +1,134 @@
|
||||
//Get the Medooze Media Server interface
|
||||
const MediaServer = require("medooze-media-server");
|
||||
const FileSystem = require("fs");
|
||||
const Path = require("path");
|
||||
//Get Semantic SDP objects
|
||||
const SemanticSDP = require("semantic-sdp");
|
||||
const SDPInfo = SemanticSDP.SDPInfo;
|
||||
const MediaInfo = SemanticSDP.MediaInfo;
|
||||
const CandidateInfo = SemanticSDP.CandidateInfo;
|
||||
const DTLSInfo = SemanticSDP.DTLSInfo;
|
||||
const ICEInfo = SemanticSDP.ICEInfo;
|
||||
const StreamInfo = SemanticSDP.StreamInfo;
|
||||
const TrackInfo = SemanticSDP.TrackInfo;
|
||||
const Direction = SemanticSDP.Direction;
|
||||
const CodecInfo = SemanticSDP.CodecInfo;
|
||||
|
||||
const Capabilities = {
|
||||
audio : {
|
||||
codecs : ["opus"],
|
||||
extensions : [ "urn:ietf:params:rtp-hdrext:ssrc-audio-level", "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01"]
|
||||
},
|
||||
video : {
|
||||
codecs : ["vp9","vp8","h264;packetization-mode=1"],
|
||||
rtx : true,
|
||||
rtcpfbs : [
|
||||
{ "id": "transport-cc"},
|
||||
{ "id": "ccm", "params": ["fir"]},
|
||||
{ "id": "nack"},
|
||||
{ "id": "nack", "params": ["pli"]}
|
||||
],
|
||||
extensions : [ "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01"]
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = function(request,protocol,endpoint)
|
||||
{
|
||||
const connection = request.accept(protocol);
|
||||
let player;
|
||||
|
||||
connection.on('message', (frame) =>
|
||||
{
|
||||
//Get cmd
|
||||
var msg = JSON.parse(frame.utf8Data);
|
||||
|
||||
//Get cmd
|
||||
if (msg.cmd==="OFFER")
|
||||
{
|
||||
let mp4;
|
||||
|
||||
//Get all files in recording dir
|
||||
const files = FileSystem.readdirSync('recordings');
|
||||
for(let i in files)
|
||||
{
|
||||
if (Path.extname(files[i])===".mp4")
|
||||
{
|
||||
//got ir
|
||||
mp4 = files[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Check
|
||||
if (!mp4)
|
||||
{
|
||||
console.error("no mp4 found");
|
||||
return connection.close();
|
||||
}
|
||||
|
||||
//Create player
|
||||
player = MediaServer.createPlayer(Path.join("recordings",mp4));
|
||||
|
||||
//Process the sdp
|
||||
var offer = SDPInfo.process(msg.offer);
|
||||
|
||||
//Create an DTLS ICE transport in that enpoint
|
||||
const transport = endpoint.createTransport(offer);
|
||||
|
||||
//Set RTP remote properties
|
||||
transport.setRemoteProperties(offer);
|
||||
|
||||
transport.dump("recordings/play-"+ Date.now()+".pcap",{
|
||||
outgoing : true,
|
||||
rtcp : true
|
||||
});
|
||||
|
||||
//Set RTP remote properties
|
||||
transport.setRemoteProperties(offer);
|
||||
|
||||
//Create local SDP info
|
||||
const answer = offer.answer({
|
||||
dtls : transport.getLocalDTLSInfo(),
|
||||
ice : transport.getLocalICEInfo(),
|
||||
candidates : endpoint.getLocalCandidates(),
|
||||
capabilities : Capabilities
|
||||
});
|
||||
|
||||
//Set RTP local properties
|
||||
transport.setLocalProperties(answer);
|
||||
|
||||
//Create new local stream with only video
|
||||
const outgoingStream = transport.createOutgoingStream({
|
||||
audio: true,
|
||||
video: true
|
||||
});
|
||||
|
||||
//Copy incoming data from the broadcast stream to the local one
|
||||
outgoingStream.attachTo(player);
|
||||
|
||||
//Get local stream info
|
||||
const info = outgoingStream.getStreamInfo();
|
||||
|
||||
//Add local stream info it to the answer
|
||||
answer.addStream(info);
|
||||
|
||||
//Send response
|
||||
connection.sendUTF(JSON.stringify({
|
||||
answer : answer.toString()
|
||||
}));
|
||||
|
||||
|
||||
//Close on disconnect
|
||||
connection.on("close",() => {
|
||||
//Stop
|
||||
transport.stop();
|
||||
//Stop playback too
|
||||
player.stop();
|
||||
});
|
||||
} else if (msg.cmd==="PLAY") {
|
||||
player.play({
|
||||
repeat : true
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
134
media-server-demo-node/lib/playback_1.js
Normal file
134
media-server-demo-node/lib/playback_1.js
Normal file
@@ -0,0 +1,134 @@
|
||||
//Get the Medooze Media Server interface
|
||||
const MediaServer = require("medooze-media-server");
|
||||
const FileSystem = require("fs");
|
||||
const Path = require("path");
|
||||
//Get Semantic SDP objects
|
||||
const SemanticSDP = require("semantic-sdp");
|
||||
const SDPInfo = SemanticSDP.SDPInfo;
|
||||
const MediaInfo = SemanticSDP.MediaInfo;
|
||||
const CandidateInfo = SemanticSDP.CandidateInfo;
|
||||
const DTLSInfo = SemanticSDP.DTLSInfo;
|
||||
const ICEInfo = SemanticSDP.ICEInfo;
|
||||
const StreamInfo = SemanticSDP.StreamInfo;
|
||||
const TrackInfo = SemanticSDP.TrackInfo;
|
||||
const Direction = SemanticSDP.Direction;
|
||||
const CodecInfo = SemanticSDP.CodecInfo;
|
||||
|
||||
const Capabilities = {
|
||||
audio : {
|
||||
codecs : ["opus"],
|
||||
extensions : [ "urn:ietf:params:rtp-hdrext:ssrc-audio-level", "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01"]
|
||||
},
|
||||
video : {
|
||||
codecs : ["vp9","vp8","h264;packetization-mode=1"],
|
||||
rtx : true,
|
||||
rtcpfbs : [
|
||||
{ "id": "transport-cc"},
|
||||
{ "id": "ccm", "params": ["fir"]},
|
||||
{ "id": "nack"},
|
||||
{ "id": "nack", "params": ["pli"]}
|
||||
],
|
||||
extensions : [ "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01"]
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = function(request,protocol,endpoint)
|
||||
{
|
||||
const connection = request.accept(protocol);
|
||||
let player;
|
||||
|
||||
connection.on('message', (frame) =>
|
||||
{
|
||||
//Get cmd
|
||||
var msg = JSON.parse(frame.utf8Data);
|
||||
|
||||
//Get cmd
|
||||
if (msg.cmd==="OFFER")
|
||||
{
|
||||
let mp4;
|
||||
|
||||
//Get all files in recording dir
|
||||
const files = FileSystem.readdirSync('recordings');
|
||||
for(let i in files)
|
||||
{
|
||||
if (Path.extname(files[i])===".mp4")
|
||||
{
|
||||
//got ir
|
||||
mp4 = files[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Check
|
||||
if (!mp4)
|
||||
{
|
||||
console.error("no mp4 found");
|
||||
return connection.close();
|
||||
}
|
||||
|
||||
//Create player
|
||||
player = MediaServer.createPlayer(Path.join("recordings",mp4));
|
||||
|
||||
//Process the sdp
|
||||
var offer = SDPInfo.process(msg.offer);
|
||||
|
||||
//Create an DTLS ICE transport in that enpoint
|
||||
const transport = endpoint.createTransport(offer);
|
||||
|
||||
//Set RTP remote properties
|
||||
transport.setRemoteProperties(offer);
|
||||
|
||||
transport.dump("recordings/play-"+ Date.now()+".pcap",{
|
||||
outgoing : true,
|
||||
rtcp : true
|
||||
});
|
||||
|
||||
//Set RTP remote properties
|
||||
transport.setRemoteProperties(offer);
|
||||
|
||||
//Create local SDP info
|
||||
const answer = offer.answer({
|
||||
dtls : transport.getLocalDTLSInfo(),
|
||||
ice : transport.getLocalICEInfo(),
|
||||
candidates : endpoint.getLocalCandidates(),
|
||||
capabilities : Capabilities
|
||||
});
|
||||
|
||||
//Set RTP local properties
|
||||
transport.setLocalProperties(answer);
|
||||
|
||||
//Create new local stream with only video
|
||||
const outgoingStream = transport.createOutgoingStream({
|
||||
audio: true,
|
||||
video: true
|
||||
});
|
||||
|
||||
//Copy incoming data from the broadcast stream to the local one
|
||||
outgoingStream.attachTo(player);
|
||||
|
||||
//Get local stream info
|
||||
const info = outgoingStream.getStreamInfo();
|
||||
|
||||
//Add local stream info it to the answer
|
||||
answer.addStream(info);
|
||||
|
||||
//Send response
|
||||
connection.sendUTF(JSON.stringify({
|
||||
answer : answer.toString()
|
||||
}));
|
||||
|
||||
|
||||
//Close on disconnect
|
||||
connection.on("close",() => {
|
||||
//Stop
|
||||
transport.stop();
|
||||
//Stop playback too
|
||||
player.stop();
|
||||
});
|
||||
} else if (msg.cmd==="PLAY") {
|
||||
player.play({
|
||||
repeat : true
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
121
media-server-demo-node/lib/recording.js
Normal file
121
media-server-demo-node/lib/recording.js
Normal file
@@ -0,0 +1,121 @@
|
||||
//Get the Medooze Media Server interface
|
||||
const MediaServer = require("medooze-media-server");
|
||||
|
||||
//Get Semantic SDP objects
|
||||
const SemanticSDP = require("semantic-sdp");
|
||||
const SDPInfo = SemanticSDP.SDPInfo;
|
||||
const MediaInfo = SemanticSDP.MediaInfo;
|
||||
const CandidateInfo = SemanticSDP.CandidateInfo;
|
||||
const DTLSInfo = SemanticSDP.DTLSInfo;
|
||||
const ICEInfo = SemanticSDP.ICEInfo;
|
||||
const StreamInfo = SemanticSDP.StreamInfo;
|
||||
const TrackInfo = SemanticSDP.TrackInfo;
|
||||
const Direction = SemanticSDP.Direction;
|
||||
const CodecInfo = SemanticSDP.CodecInfo;
|
||||
|
||||
const Capabilities = {
|
||||
audio : {
|
||||
codecs : ["opus"],
|
||||
extensions : [ "urn:ietf:params:rtp-hdrext:ssrc-audio-level"]
|
||||
},
|
||||
video : {
|
||||
codecs : ["h264;packetization-mode=1"],
|
||||
rtx : true,
|
||||
rtcpfbs : [
|
||||
{ "id": "transport-cc"},
|
||||
{ "id": "ccm", "params": ["fir"]},
|
||||
{ "id": "nack"},
|
||||
{ "id": "nack", "params": ["pli"]}
|
||||
],
|
||||
extensions : [ "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01"]
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = function(request,protocol,endpoint)
|
||||
{
|
||||
const connection = request.accept(protocol);
|
||||
|
||||
connection.on('message', (frame) =>
|
||||
{
|
||||
//Get cmd
|
||||
var msg = JSON.parse(frame.utf8Data);
|
||||
|
||||
//Get cmd
|
||||
if (msg.cmd==="OFFER")
|
||||
{
|
||||
console.log(msg.offer);
|
||||
//Process the sdp
|
||||
var offer = SDPInfo.process(msg.offer);
|
||||
|
||||
//Create recoreder
|
||||
const recorder = MediaServer.createRecorder ("recordings/"+ Date.now() +".mp4",{
|
||||
// refresh : 15000,
|
||||
// timeShift : 60000,
|
||||
disableHints : true,
|
||||
});
|
||||
|
||||
//Create an DTLS ICE transport in that enpoint
|
||||
const transport = endpoint.createTransport(offer);
|
||||
transport.setBandwidthProbing(true);
|
||||
transport.setMaxProbingBitrate(1024000);
|
||||
transport.on("targetbitrate", bitrate=>console.log("targetbitrate " + bitrate));
|
||||
transport.on("dtlsstate", state=>console.log("dtlsstate:"+state));
|
||||
|
||||
transport.dump("recordings/rec-"+ Date.now()+".pcap");
|
||||
|
||||
//Set RTP remote properties
|
||||
transport.setRemoteProperties(offer);
|
||||
|
||||
//Create local SDP info
|
||||
const answer = offer.answer({
|
||||
dtls : transport.getLocalDTLSInfo(),
|
||||
ice : transport.getLocalICEInfo(),
|
||||
candidates : endpoint.getLocalCandidates(),
|
||||
capabilities : Capabilities
|
||||
});
|
||||
|
||||
//Set RTP local properties
|
||||
transport.setLocalProperties(answer);
|
||||
|
||||
//For each stream offered
|
||||
for (let offered of offer.getStreams().values())
|
||||
{
|
||||
//Create the remote stream into the transport
|
||||
const incomingStream = transport.createIncomingStream(offered);
|
||||
|
||||
//Create new local stream with only audio
|
||||
const outgoingStream = transport.createOutgoingStream({
|
||||
audio: false,
|
||||
video: true
|
||||
});
|
||||
|
||||
//Get local stream info
|
||||
const info = outgoingStream.getStreamInfo();
|
||||
|
||||
//Copy incoming data from the remote stream to the local one
|
||||
outgoingStream.attachTo(incomingStream);
|
||||
|
||||
//Add local stream info it to the answer
|
||||
answer.addStream(info);
|
||||
|
||||
//Record it
|
||||
recorder.record(incomingStream);
|
||||
}
|
||||
|
||||
//setTimeout(()=>recorder.flush(),60000);
|
||||
|
||||
//Send response
|
||||
connection.sendUTF(JSON.stringify({
|
||||
answer : answer.toString()
|
||||
}));
|
||||
|
||||
//Close on disconnect
|
||||
connection.on("close",() => {
|
||||
console.log("close");
|
||||
//Stop
|
||||
recorder.stop();
|
||||
transport && transport.stop();
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
141
media-server-demo-node/lib/simulcast.js
Normal file
141
media-server-demo-node/lib/simulcast.js
Normal file
@@ -0,0 +1,141 @@
|
||||
//Get the Medooze Media Server interface
|
||||
const MediaServer = require("medooze-media-server");
|
||||
|
||||
//Get Semantic SDP objects
|
||||
const SemanticSDP = require("semantic-sdp");
|
||||
const SDPInfo = SemanticSDP.SDPInfo;
|
||||
const MediaInfo = SemanticSDP.MediaInfo;
|
||||
const CandidateInfo = SemanticSDP.CandidateInfo;
|
||||
const DTLSInfo = SemanticSDP.DTLSInfo;
|
||||
const ICEInfo = SemanticSDP.ICEInfo;
|
||||
const StreamInfo = SemanticSDP.StreamInfo;
|
||||
const TrackInfo = SemanticSDP.TrackInfo;
|
||||
const Direction = SemanticSDP.Direction;
|
||||
const CodecInfo = SemanticSDP.CodecInfo;
|
||||
|
||||
|
||||
const Capabilities = {
|
||||
video : {
|
||||
codecs : ["h264;packetization-mode=1"],
|
||||
rtx : true,
|
||||
rtcpfbs : [
|
||||
{ "id": "goog-remb"},
|
||||
{ "id": "transport-cc"},
|
||||
{ "id": "ccm", "params": ["fir"]},
|
||||
{ "id": "nack"},
|
||||
{ "id": "nack", "params": ["pli"]}
|
||||
],
|
||||
extensions : [
|
||||
"urn:3gpp:video-orientation",
|
||||
"http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01",
|
||||
"urn:ietf:params:rtp-hdrext:sdes:mid",
|
||||
"urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id",
|
||||
"urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id",
|
||||
"http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time"
|
||||
],
|
||||
simulcast : true
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = function(request,protocol,endpoint)
|
||||
{
|
||||
const connection = request.accept(protocol);
|
||||
|
||||
connection.on('message', (frame) =>
|
||||
{
|
||||
//Get cmd
|
||||
var msg = JSON.parse(frame.utf8Data);
|
||||
|
||||
|
||||
//Get cmd
|
||||
if (msg.cmd==="OFFER")
|
||||
{
|
||||
|
||||
//Process the sdp
|
||||
var offer = SDPInfo.process(msg.offer);
|
||||
|
||||
//Create an DTLS ICE transport in that enpoint
|
||||
const transport = endpoint.createTransport(offer);
|
||||
|
||||
//Set RTP remote properties
|
||||
transport.setRemoteProperties(offer);
|
||||
|
||||
//Enable bandwidth probing
|
||||
transport.setBandwidthProbing(true);
|
||||
transport.setMaxProbingBitrate(300*1000);
|
||||
|
||||
//Create local SDP info
|
||||
const answer = offer.answer({
|
||||
dtls : transport.getLocalDTLSInfo(),
|
||||
ice : transport.getLocalICEInfo(),
|
||||
candidates : endpoint.getLocalCandidates(),
|
||||
capabilities : Capabilities
|
||||
});
|
||||
|
||||
//Set RTP local properties
|
||||
transport.setLocalProperties({
|
||||
video : answer.getMedia("video")
|
||||
});
|
||||
|
||||
//Get timestamp
|
||||
const ts = Date.now();
|
||||
|
||||
//Dump contents
|
||||
transport.dump("recordings/simulcast-"+ts+".pcap");
|
||||
|
||||
//Create recoreder
|
||||
//const recorder = MediaServer.createRecorder ("recordings/simulcast"+ts +".mp4");
|
||||
|
||||
//For each stream offered
|
||||
for (let offered of offer.getStreams().values())
|
||||
{
|
||||
|
||||
//Create the remote stream into the transport
|
||||
const incomingStream = transport.createIncomingStream(offered);
|
||||
|
||||
//Create new local stream
|
||||
const outgoingStream = transport.createOutgoingStream({
|
||||
audio: false,
|
||||
video: true
|
||||
});
|
||||
|
||||
//Get local stream info
|
||||
const info = outgoingStream.getStreamInfo();
|
||||
|
||||
//Copy incoming data from the remote stream to the local one
|
||||
connection.transporder = outgoingStream.attachTo(incomingStream)[0];
|
||||
|
||||
//Add local stream info it to the answer
|
||||
answer.addStream(info);
|
||||
|
||||
setInterval(()=>{
|
||||
//console.dir(incomingStream.getStats(),{depth:null});
|
||||
//console.log(outgoingStream.getStats());
|
||||
},1000);
|
||||
//Record it
|
||||
//recorder.record(incomingStream);
|
||||
}
|
||||
|
||||
//Send response
|
||||
connection.sendUTF(JSON.stringify({
|
||||
answer : answer.toString().replace("h264","H264")
|
||||
}));
|
||||
|
||||
console.log("OFFER");
|
||||
console.log(msg.offer);
|
||||
console.log("ANSWER");
|
||||
console.log(answer.toString().replace("h264","H264"));
|
||||
//Close on disconnect
|
||||
connection.on("close",() => {
|
||||
//Stop transport an recorded
|
||||
transport.stop();
|
||||
//recorder.stop();
|
||||
});
|
||||
} else {
|
||||
connection.transporder.selectEncoding(msg.rid);
|
||||
//Select layer
|
||||
connection.transporder.selectLayer(parseInt(msg.spatialLayerId),parseInt(msg.temporalLayerId));
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
153
media-server-demo-node/lib/svc.js
Normal file
153
media-server-demo-node/lib/svc.js
Normal file
@@ -0,0 +1,153 @@
|
||||
//Get the Medooze Media Server interface
|
||||
const MediaServer = require("medooze-media-server");
|
||||
|
||||
//Get Semantic SDP objects
|
||||
const SemanticSDP = require("semantic-sdp");
|
||||
const SDPInfo = SemanticSDP.SDPInfo;
|
||||
const MediaInfo = SemanticSDP.MediaInfo;
|
||||
const CandidateInfo = SemanticSDP.CandidateInfo;
|
||||
const DTLSInfo = SemanticSDP.DTLSInfo;
|
||||
const ICEInfo = SemanticSDP.ICEInfo;
|
||||
const StreamInfo = SemanticSDP.StreamInfo;
|
||||
const TrackInfo = SemanticSDP.TrackInfo;
|
||||
const Direction = SemanticSDP.Direction;
|
||||
const CodecInfo = SemanticSDP.CodecInfo;
|
||||
|
||||
const Capabilities = {
|
||||
video : {
|
||||
codecs : ["vp9"],
|
||||
rtx : true,
|
||||
rtcpfbs : [
|
||||
{ "id": "transport-cc"},
|
||||
{ "id": "ccm", "params": ["fir"]},
|
||||
{ "id": "nack"},
|
||||
{ "id": "nack", "params": ["pli"]}
|
||||
],
|
||||
extensions : [ "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01"]
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = function(request,protocol,endpoint)
|
||||
{
|
||||
const connection = request.accept(protocol);
|
||||
|
||||
connection.on('message', (frame) =>
|
||||
{
|
||||
//Get cmd
|
||||
var msg = JSON.parse(frame.utf8Data);
|
||||
|
||||
//Get cmd
|
||||
if (msg.cmd==="OFFER")
|
||||
{
|
||||
const streams = {};
|
||||
|
||||
//Process the sdp
|
||||
var offer = SDPInfo.process(msg.offer);
|
||||
|
||||
//Create an DTLS ICE transport in that enpoint
|
||||
const transport = endpoint.createTransport(offer);
|
||||
|
||||
//Enable probing
|
||||
transport.setBandwidthProbing(true);
|
||||
transport.setMaxProbingBitrate(512000);
|
||||
|
||||
//DUMP
|
||||
//transport.dump("recordings/svc-"+ts+".pcap",{incoming:true,rtcp:true,rtpHeadersOnly:true,bwe:true});
|
||||
|
||||
//Set RTP remote properties
|
||||
transport.setRemoteProperties({
|
||||
audio : offer.getMedia("audio"),
|
||||
video : offer.getMedia("video")
|
||||
});
|
||||
|
||||
//Create local SDP info
|
||||
const answer = offer.answer({
|
||||
dtls : transport.getLocalDTLSInfo(),
|
||||
ice : transport.getLocalICEInfo(),
|
||||
candidates : endpoint.getLocalCandidates(),
|
||||
capabilities : Capabilities
|
||||
});
|
||||
|
||||
//Set RTP local properties
|
||||
transport.setLocalProperties({
|
||||
video : answer.getMedia("video")
|
||||
});
|
||||
|
||||
//Get offered stream info
|
||||
const offered = offer.getFirstStream();
|
||||
|
||||
//Create the remote stream into the transports
|
||||
const incomingStream = transport.createIncomingStream(offered);
|
||||
|
||||
//Create new local stream
|
||||
const outgoingStream = transport.createOutgoingStream({
|
||||
audio: false,
|
||||
video: true
|
||||
});
|
||||
|
||||
//Get local stream info
|
||||
const info = outgoingStream.getStreamInfo();
|
||||
|
||||
//Copy incoming data from the remote stream to the local one
|
||||
const transponder = connection.transporder = outgoingStream.attachTo(incomingStream)[0];
|
||||
|
||||
//Start on low
|
||||
transponder.selectLayer(0,0);
|
||||
|
||||
//Listen for bwe events
|
||||
transport.on("targetbitrate", bitrate=>{
|
||||
//Get previous layer ids
|
||||
const sid = transponder.getSelectedSpatialLayerId();
|
||||
const tid = transponder.getSelectedTemporalLayerId();
|
||||
//Select stream layer from bitrate
|
||||
const rate = transponder.setTargetBitrate(bitrate);
|
||||
//Get next layer
|
||||
const next = rate.layers[rate.layerIndex-1];
|
||||
//Probing
|
||||
let probing = false;
|
||||
//If the jump is lower
|
||||
if (next)
|
||||
{
|
||||
//Set probing bitrate
|
||||
probing = next.bitrate-rate;
|
||||
//Set it on transport
|
||||
transport.setMaxProbingBitrate(next.bitrate-rate);
|
||||
//Enable
|
||||
transport.setBandwidthProbing(true);
|
||||
} else
|
||||
//Disable
|
||||
transport.setBandwidthProbing(false);
|
||||
|
||||
//Log
|
||||
console.log("targetbitrate :" + bitrate + " probing:" + probing +" sid:" + transponder.getSelectedSpatialLayerId() + " tid:" +transponder.getSelectedTemporalLayerId());
|
||||
//If changed
|
||||
if (sid!=transponder.getSelectedSpatialLayerId() || tid!=transponder.getSelectedTemporalLayerId())
|
||||
//Send response
|
||||
connection.sendUTF(JSON.stringify({
|
||||
sid : transponder.getSelectedSpatialLayerId(),
|
||||
tid : transponder.getSelectedTemporalLayerId()
|
||||
}));
|
||||
});
|
||||
|
||||
//Add local stream info it to the answer
|
||||
answer.addStream(info);
|
||||
|
||||
//Add to streams
|
||||
streams[incomingStream.getId()] = incomingStream;
|
||||
|
||||
//Send response
|
||||
connection.sendUTF(JSON.stringify({
|
||||
answer : answer.toString()
|
||||
}));
|
||||
|
||||
//Close on disconnect
|
||||
connection.on("close",() => {
|
||||
//Stop
|
||||
transport.stop();
|
||||
});
|
||||
} else {
|
||||
//Select layer
|
||||
connection.transporder.selectLayer(parseInt(msg.spatialLayerId),parseInt(msg.temporalLayerId));
|
||||
}
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user