1. AmqpClient - RpcServer New message received
2023-04-26T21:54:22.150 - DEBUG: AmqpClient - RpcServer New message received {
method: 'linkup',
args: [ 'b801af2aac214c09ae0100bdc52b2f0f-1', { video: [Object] } ],
corrID: 67,
replyTo: 'amq.gen-WtoELIbC4gJ1GfdYgkvSFA'
}
2. WebrtcNode.linkup
dist-debug/webrtc_agent/webrtc/index.js
2023-04-26T21:54:22.151 - DEBUG: WebrtcNode - linkup,
connectionId: b801af2aac214c09ae0100bdc52b2f0f-1 from: {
video: {
id: '7c497d10719d48d192fc355cd8a9d38a-1',
ip: '192.168.221.62',
port: 42227
}
}
7c497d10719d48d192fc355cd8a9d38a-1 是 publish的 publicTrackId
b801af2aac214c09ae0100bdc52b2f0f-1 是subscribe的 publicTrackId
// connectionId 就是transportId,或者connectionId
// from.video.id 就是 被订阅的publicTrackId
//
// streamInfo = {id: 'string', ip: 'string', port: 'number'}
// from = {audio: streamInfo, video: streamInfo, data: streamInfo}
that.linkup = function (connectionId, from, callback) {
log.debug('linkup, connectionId:', connectionId, 'from:', from);
router.linkup(connectionId, from).then(onSuccess(callback), onError(callback));
};
3. InternalConnectionRouter.linkup
dist-debug/webrtc_agent/webrtc/internalConnectionRouter.js
2023-04-26T21:54:22.151 - DEBUG: InternalConnectionRouter -
linkup: b801af2aac214c09ae0100bdc52b2f0f-1 {
video: {
id: '7c497d10719d48d192fc355cd8a9d38a-1',
ip: '192.168.221.62',
port: 42227
}
}
/*
* This function linkup localDestination with ID `dstId` with `from`,
* `from` can either be localSource or remoteSource.
* SourceInfo = {id: 'string', ip: 'string', port: 'number'}
* from = {audio: SourceInfo, video: SourceInfo, data: SourceInfo}
*/
// dstId 就是transportId,或者connectionId
linkup(dstId, from) {
log.debug('linkup:', dstId, from);
let audioFrom, videoFrom, dataFrom;
for(let [type, stream] of Object.entries(from)) {
// id 就是 被订阅的publicTrackId
// 就是 publish的 publicTrackId
if (!stream.id) {
continue;
}
// 在 publish的时候把publicTrackId 存放在这里
// ?????
if (!this.connections.getConnection(stream.id)) {
this.getOrCreateRemoteSource(stream, (stat) => {
log.debug('Remote source stat:', stream.id, stat);
if (stat === 'disconnected') {
this.destroyRemoteSource(stream.id);
}
});
if (!this.remoteStreams.has(stream.id)) {
log.warn('Remote stream never added:', stream.id);
return Promise.reject('Invalid remote from:' + type + ', ' + stream.id);
}
// Save destination mapping for remote stream
// TODO: destroy remote streams when needed
this.remoteStreams.get(stream.id).add(dstId);
}
}
if (from.audio) audioFrom = from.audio.id;
if (from.video) videoFrom = from.video.id;
if (from.data) dataFrom = from.data.id;
return this.connections.linkupConnection(
dstId, audioFrom, videoFrom, dataFrom);
}
Connections.getConnection
dist-debug/webrtc_agent/webrtc/connections.js
that.getConnection = function (connectionId) {
return connections[connectionId];
};
4. Connections.linkupConnection
dist-debug/webrtc_agent/webrtc/connections.js
2023-04-26T21:54:22.152 - DEBUG: Connections - linkup,
connectionId: b801af2aac214c09ae0100bdc52b2f0f-1 ,
audioFrom: undefined ,
videoFrom: 7c497d10719d48d192fc355cd8a9d38a-1 ,
dataFrom: undefined
2023-04-26T21:54:22.152 - DEBUG: Connections - linkup,
destname=VideoFramePacketizer
2023-04-26T21:54:22.152 - DEBUG: Connections - linkup complete.
// connectionId, 就是订阅的connectId
that.linkupConnection = function(connectionId, audioFrom, videoFrom, dataFrom) {
log.debug('linkup, connectionId:', connectionId, ', audioFrom:', audioFrom, ', videoFrom:', videoFrom, ', dataFrom: ', dataFrom);
if (!connectionId || !connections[connectionId]) {
log.error('Subscription does not exist:' + connectionId);
return Promise.reject('Subscription does not exist:' + connectionId);
}
// connectionId = publicTackId
/* conn = {type: 'webrtc' | 'avstream' | 'recording' | 'internal',
direction: 'in' | 'out',
audioFrom: ConnectionID | undefined,
videoFrom: ConnectionID | undefined,
connnection: WebRtcConnection | InternalOut | RTSPConnectionOut
}*/
const conn = connections[connectionId];
// map [['audio', audioFrom], ['video', videoFrom], ['data', dataFrom]]
// name : audio/video/date
// from : audioFrom/videoFrom/dataFrom , connectionId
for (const [name, from] of new Map([['audio', audioFrom], ['video', videoFrom], ['data', dataFrom]])) {
if (from && !connections[from]) {
log.error(name + ' stream does not exist:' + from);
return Promise.reject({ type : 'failed', reason : name + ' stream does not exist:' + from });
}
// 这里的from 对应的就是videoFrom
if (from) {
// conn.connection = WrtcStream
// dest = this.videoFramePacker
const dest = conn.connection.receiver(name);
//
if (!dest) {
return Promise.reject({ type : 'failed', reason : 'Destination connection(' + name + ') is not ready' });
}
// TODO: Add a new method isNanAddon to NAN addon objects.
// Names of NAN addons.
//const nanObjects = [ 'QuicTransportStream',
//'WebTransportFrameSource',
//'WebTransportFrameDestination' ];
// 这里应该是isNanObj = false
const isNanObj = nanObjects.includes(dest.constructor.name) ? true : false;
// from 就是publish的connectId,connection 就是VideoFrameSource
// 就是小节5
connections[from].connection.addDestination(name, dest, isNanObj);
// connectionId 是订阅的connectId,
// connections[connectionId] 就是conn
// 对conn属性videoFrom 赋值 = from
// 看下文日志
connections[connectionId][name + 'From'] = from;
}
}
log.debug('linkup complete.');
return Promise.resolve('ok');
};
WrtcStream.receiver
dist-debug/webrtc_agent/webrtc/wrtcConnection.js
receiver(track) {
let dest = null;
if (track === 'audio') {
dest = this.audioFramePacketizer;
} else if (track === 'video') {
dest = this.videoFramePacketizer;
} else {
log.error('receiver error');
}
return dest;
}
log
2023-04-26T21:25:12.855 - DEBUG: AmqpClient - RpcServer New message received {
method: 'linkup',
args: [ '2d64d6603ac5462d93f1fef46056a2d6-0', { audio: [Object] } ],
corrID: 53,
replyTo: 'amq.gen-FP2ga0dFEdfk9AEDnTvueg'
}
2023-04-26T21:25:12.856 - DEBUG: WebrtcNode - linkup, connectionId: 2d64d6603ac5462d93f1fef46056a2d6-0 from: {
audio: {
id: 'fc4121e5ed3e41df904c56544c77242b-0',
ip: '192.168.221.62',
port: 43195
}
}
2023-04-26T21:25:12.856 - DEBUG: InternalConnectionRouter - linkup: 2d64d6603ac5462d93f1fef46056a2d6-0 {
audio: {
id: 'fc4121e5ed3e41df904c56544c77242b-0',
ip: '192.168.221.62',
port: 43195
}
}
2023-04-26T21:25:12.856 - DEBUG: Connections - linkup,
connectionId: 2d64d6603ac5462d93f1fef46056a2d6-0 ,
audioFrom: fc4121e5ed3e41df904c56544c77242b-0 ,
videoFrom: undefined ,
dataFrom: undefined
2023-04-26T21:25:12.856 - DEBUG: Connections - linkup,
destname=AudioFramePacketizer
2023-04-26T21:25:12.857 - DEBUG: Connections - linkup complete.
2023-04-26T21:25:12.857 - DEBUG: AmqpClient - RpcServer New message received {
method: 'linkup',
args: [ '2d64d6603ac5462d93f1fef46056a2d6-1', { video: [Object] } ],
corrID: 54,
replyTo: 'amq.gen-FP2ga0dFEdfk9AEDnTvueg'
}
2023-04-26T21:25:12.857 - DEBUG: WebrtcNode - linkup, connectionId: 2d64d6603ac5462d93f1fef46056a2d6-1 from: {
video: {
id: 'fc4121e5ed3e41df904c56544c77242b-1',
ip: '192.168.221.62',
port: 43195
}
}
2023-04-26T21:25:12.857 - DEBUG: InternalConnectionRouter - linkup: 2d64d6603ac5462d93f1fef46056a2d6-1 {
video: {
id: 'fc4121e5ed3e41df904c56544c77242b-1',
ip: '192.168.221.62',
port: 43195
}
}
2023-04-26T21:25:12.857 - DEBUG: Connections - linkup,
connectionId: 2d64d6603ac5462d93f1fef46056a2d6-1 ,
audioFrom: undefined ,
videoFrom: fc4121e5ed3e41df904c56544c77242b-1 ,
dataFrom: undefined
2023-04-26T21:25:12.857 - DEBUG: Connections - linkup,
destname=VideoFramePacketizer
2023-04-26T21:25:12.857 - DEBUG: Connections - linkup complete.
5. VideoFrameSource.addDestination
dist-debug/webrtc_agent/webrtc/wrtcConnection.js
sender() {
let sender = null;
if (this.videoFrameConstructor) {
sender = this.videoFrameConstructor.source();
sender.parent = this.videoFrameConstructor;
} else {
log.error('sender error');
}
if (sender) {
// 调用的就是这个方法
sender.addDestination = (track, dest) => {
// parent = VideoFameConstructor
sender.parent.addDestination(dest);
};
sender.removeDestination = (track, dest) => {
sender.parent.removeDestination(dest);
};
}
return sender;
}
6. addon.VideoFameConstructor.addDestination
7. NAN_METHOD(VideoFrameConstructor::addDestination)
NAN_METHOD(VideoFrameConstructor::addDestination) {
VideoFrameConstructor* obj = Nan::ObjectWrap::Unwrap<VideoFrameConstructor>(info.Holder());
owt_base::VideoFrameConstructor* me = obj->me;
FrameDestination* param = node::ObjectWrap::Unwrap<FrameDestination>(
Nan::To<v8::Object>(info[0]).ToLocalChecked());
owt_base::FrameDestination* dest = param->dest;
me->addVideoDestination(dest);
}
8. owt_base::FrameSource::addVideoDestination
source/core/owt_base/MediaFramePipeline.cpp
void FrameSource::addVideoDestination(FrameDestination* dest)
{
boost::unique_lock<boost::shared_mutex> lock(m_video_dests_mutex);
m_video_dests.push_back(dest);
lock.unlock();
dest->setVideoSource(this);
}