on_track
1. track-added
dist/webrtc_agent/webrtc/wrtcConnection.js
const setupTransport = function (mid) {
...
if (rids) {
...
} else {
// 走这里的代码
// No simulcast
if (!trackMap.has(mid)) {
// 1. Connection wrtc
trackMap.set(mid, new WrtcStream(mid, wrtc, direction, trackSettings));
...
// 3. Notify new track
// on_track, wrtcConnection 就是在创建的时候,传入的参数
on_track({
type: 'track-added',
track: trackMap.get(mid),
operationId: opSettings.operationId,
mid: mid
});
} else {
log.warn(`Conflict trackId ${mid} for ${wrtcId}`);
}
}
return opSettings.operationId;
};
trackMap 属性——存放了WrtcStream
// composedId => WrtcStream
var trackMap = new Map();
composeId
const composeId = function (mid, rid) {
return mid + ':' + rid;
};
1.1 on_track
dist/webrtc_agent/webrtc/wrtcConnection.js
module.exports = function (spec, on_status, on_track) {
...
}
1.2 on_track= function onTrack(trackInfo)
dist/webrtc_agent/webrtc/index.js
var connection = new WrtcConnection({
connectionId: transportId,
threadPool: threadPool,
ioThreadPool: ioThreadPool,
network_interfaces: global.config.webrtc.network_interfaces,
owner,
}, function onTransportStatus(status) {
notifyTransportStatus(controller, transportId, status);
}, function onTrack(trackInfo) {
handleTrackInfo(transportId, trackInfo, controller);
});
2. ======WebrtcNode.handleTrackInfo
dist/webrtc_agent/webrtc/index.js
// trackInfo 就是on__track 回调回来
var handleTrackInfo = function (transportId, trackInfo, controller) {
var publicTrackId;
var updateInfo;
if (trackInfo.type === 'track-added') {
// Generate public track ID
const track = trackInfo.track; // track是WrtcStream
// track.id 就是mid
publicTrackId = transportId + '-' + track.id;
if (mediaTracks.has(publicTrackId)) {
log.error('Conflict public track id:', publicTrackId, transportId, track.id);
return;
}
mediaTracks.set(publicTrackId, track);
mappingPublicId.get(transportId).set(track.id, publicTrackId);
if (track.direction === 'in') {
...
} else {
// 2. add track
router.addLocalDestination(publicTrackId, 'webrtc', track)
.catch(e => log.warn('Unexpected error during track add:', e));
}
// 3. Bind media-update handler
track.on('media-update', (jsonUpdate) => {
log.debug('notifyMediaUpdate:', publicTrackId, jsonUpdate);
notifyMediaUpdate(controller, publicTrackId, track.direction, JSON.parse(jsonUpdate));
});
// 4. Notify controller
const mediaType = track.format('audio') ? 'audio' : 'video';
updateInfo = {
type: 'track-added',
trackId: publicTrackId,
mediaType: track.format('audio') ? 'audio' : 'video',
mediaFormat: track.format(mediaType),
direction: track.direction,
operationId: trackInfo.operationId,
mid: trackInfo.mid,
rid: trackInfo.rid,
active: true,
};
log.debug('notifyTrackUpdate', controller, publicTrackId, updateInfo);
notifyTrackUpdate(controller, transportId, updateInfo);
} else if (trackInfo.type === 'track-removed') {
...
} else if (trackInfo.type === 'tracks-complete') {
updateInfo = {
type: 'tracks-complete',
operationId: trackInfo.operationId
};
notifyTrackUpdate(controller, transportId, updateInfo);
}
};
track==WrtcStream
publicTrackId = transportId + ‘-’ + track.id;
track.id, (rids不空,composedId=mid:rids)
track.id, (rids为空,composedId=mid)
mediaTracks——{ publicTrackId => WrtcTrack }
// Map { publicTrackId => WrtcTrack }
var mediaTracks = new Map();
mediaTracks.set(publicTrackId, track);
mappingPublicId——{ transportId => Map { trackId => publicTrackId } }
// Map { transportId => Map { trackId => publicTrackId } }
var mappingPublicId = new Map();
mappingPublicId.get(transportId).set(track.id, publicTrackId);
var router = new InternalConnectionRouter(global.config.internal);
2.1 xxxxx
2.2 InternalConnectionRouter.addLocalDestination
dist-debug/webrtc_agent/webrtc/internalConnectionRouter.js
2023-04-26T21:54:19.802 - DEBUG: InternalConnectionRouter - addLocalDestination: b149e44bb10d4e91bd162a8c6806ae7b-1 webrtc
/*
* @param {string} id ID for destination connection (subscription)
* @param {string} type Type description for connection
* @param {FrameSource} source Wrapper class for FrameDestination
*/
// id = publicTrackId = transportId + '-' + track.id;
// type = 'webrtc',
// dest 就是2 创建的WrtcStream
addLocalDestination(id, type, dest) {
log.debug('addLocalDestination:', id, type);
// 1. Connections connnections
return this.connections.addConnection(id, type, '', dest, 'out');
}
2.2.1 internalServer 赋值const {InternalServer, InternalClient} = internalIO;
dist-debug/webrtc_agent/webrtc/internalConnectionRouter.js
source/agent/addons/internalIO/InternalServerWrapper.h
source/agent/addons/internalIO/InternalClientWrapper.h
????? InternalServer::onSessionData
source/core/owt_base/internal/InternalServer.cpp
2.3.4 Connections.addConnection
dist-debug/webrtc_agent/webrtc/connections.js
// addConnection(id, type, '', source, 'in');
// connectionId = id = publicTrackId
// connectionType = type = 'webrtc'
// connectionController = ''
// conn = WrtcStream
// direction = 'in'
that.addConnection = function (connectionId, connectionType, connectionController, conn, direction) {
log.debug('Add connection:', connectionId, connectionType, connectionController);
if (connections[connectionId]) {
log.error('Connection already exists:'+connectionId);
return Promise.reject({type: 'failed', reason: 'Connection already exists:'+connectionId});
}
connections[connectionId] = {
type: connectionType,
direction: direction,
audioFrom: undefined,
videoFrom: undefined,
connection: conn,
controller: connectionController
};
return Promise.resolve('ok');
};
这里存放在connections的数据包括WrtcStream,在linkupConnection 的时候调用
connections
/*{ConnectionID: {type: 'webrtc' | 'avstream' | 'recording' | 'internal',
direction: 'in' | 'out',
audioFrom: ConnectionID | undefined,
videoFrom: ConnectionID | undefined,
connnection: WebRtcConnection | InternalOut | RTSPConnectionOut
}
}
*/
connections = {};
log
2023-04-26T21:54:19.803 - DEBUG: Connections -
Add connection: b149e44bb10d4e91bd162a8c6806ae7b-1
webrtc
log——conn
2023-04-26T21:54:19.798 - DEBUG: Connections - WrtcStream {
_events: [Object: null prototype] {},
_eventsCount: 0,
_maxListeners: undefined,
id: '0',
wrtc: Connection {
_events: [Object: null prototype] { status_event: [Function (anonymous)] },
_eventsCount: 1,
_maxListeners: undefined,
id: 'b149e44bb10d4e91bd162a8c6806ae7b',
threadPool: ThreadPool {},
ioThreadPool: IOThreadPool {},
mediaConfiguration: 'default',
mediaStreams: Map(1) { '0' => [MediaStream] },
initialized: true,
options: { ipAddresses: [] },
ipAddresses: [],
trickleIce: false,
metadata: {},
isProcessingRemoteSdp: false,
ready: false,
wrtc: WebRtcConnection {},
callBase: CallBase {},
sessionVersion: 0,
[Symbol(kCapture)]: false
},
direction: 'out',
audioFormat: { codec: 'opus', sampleRate: 48000, channelNum: 2 },
videoFormat: null,
audio: {
mid: '0',
midExtId: 4,
format: { codec: 'opus', sampleRate: 48000, channelNum: 2 }
},
video: undefined,
audioFrameConstructor: null,
audioFramePacketizer: AudioFramePacketizer {},
videoFrameConstructor: null,
videoFramePacketizer: null,
closed: false,
owner: 'xG6DXLHdXwky_E8eAAAD',
[Symbol(kCapture)]: false
}
===============
2023-04-26T21:54:19.803 - DEBUG: Connections - WrtcStream {
_events: [Object: null prototype] {},
_eventsCount: 0,
_maxListeners: undefined,
id: '1',
wrtc: Connection {
_events: [Object: null prototype] { status_event: [Function (anonymous)] },
_eventsCount: 1,
_maxListeners: undefined,
id: 'b149e44bb10d4e91bd162a8c6806ae7b',
threadPool: ThreadPool {},
ioThreadPool: IOThreadPool {},
mediaConfiguration: 'default',
mediaStreams: Map(2) { '0' => [MediaStream], '1' => [MediaStream] },
initialized: true,
options: { ipAddresses: [] },
ipAddresses: [],
trickleIce: false,
metadata: {},
isProcessingRemoteSdp: false,
ready: false,
wrtc: WebRtcConnection {},
callBase: CallBase {},
sessionVersion: 0,
[Symbol(kCapture)]: false
},
direction: 'out',
audioFormat: null,
videoFormat: { codec: 'av1' },
audio: undefined,
video: { transportcc: 3, mid: '1', midExtId: 4, format: { codec: 'av1' } },
audioFrameConstructor: null,
audioFramePacketizer: null,
videoFrameConstructor: null,
videoFramePacketizer: VideoFramePacketizer {},
closed: false,
owner: 'xG6DXLHdXwky_E8eAAAD',
[Symbol(kCapture)]: false
}
2.3 xxxxxxx WebrtcNode.notifyMediaUpdate
subscribe 的流程不会触发
2.4 WebrtcNode.notifyTrackUpdate
dist/webrtc_agent/webrtc/index.js
/* updateInfo = {
* event: ('track-added' | 'track-removed' | 'track-updated'),
* trackId, mediaType, mediaFormat, active }
*/
// controller 就是WebrtcNode.publish的时候options传递的controller
var notifyTrackUpdate = function (controller, transportId, updateInfo) {
// 广播消息
rpcClient.remoteCast(controller, 'onTrackUpdate', [transportId, updateInfo]);
...
};
log
2023-04-26T21:54:19.798 - DEBUG: WebrtcNode - notifyTrackUpdate conference-aed26ef945c09ddf89b3@192.168.221.62_0 b149e44bb10d4e91bd162a8c6806ae7b-0 {
type: 'track-added',
trackId: 'b149e44bb10d4e91bd162a8c6806ae7b-0',
mediaType: 'audio',
mediaFormat: { codec: 'opus', sampleRate: 48000, channelNum: 2 },
direction: 'out',
operationId: 'b149e44bb10d4e91bd162a8c6806ae7b',
mid: '0',
rid: undefined,
active: true
}
2023-04-26T21:54:19.803 - DEBUG: WebrtcNode - notifyTrackUpdate conference-aed26ef945c09ddf89b3@192.168.221.62_0 b149e44bb10d4e91bd162a8c6806ae7b-1 {
type: 'track-added',
trackId: 'b149e44bb10d4e91bd162a8c6806ae7b-1',
mediaType: 'video',
mediaFormat: { codec: 'av1' },
direction: 'out',
operationId: 'b149e44bb10d4e91bd162a8c6806ae7b',
mid: '1',
rid: undefined,
active: true
}
RpcClient.remoteCast
dist/webrtc_agent/amqpClient.js
remoteCast(to, method, args) {
const channel = this.bus.channel;
if (this.ready && channel) {
const content = JSON.stringify({
method,
args,
});
try {
channel.publish(RPC_EXC.name, to, Buffer.from(content));
} catch (e) {
log.warn('Failed to publish:', e);
}
} else {
this.ready = false;
}
}