[*] 日常优化
This commit is contained in:
@@ -801,30 +801,6 @@ class Taoyao {
|
|||||||
me.push(message);
|
me.push(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 重启ICE信令
|
|
||||||
*
|
|
||||||
* @param {*} message 消息
|
|
||||||
* @param {*} body 消息主体
|
|
||||||
*/
|
|
||||||
async mediaIceRestart(message, body) {
|
|
||||||
const me = this;
|
|
||||||
const {
|
|
||||||
roomId,
|
|
||||||
transportId
|
|
||||||
} = body;
|
|
||||||
const room = me.rooms.get(roomId);
|
|
||||||
const transport = room?.transports.get(transportId);
|
|
||||||
if(transport) {
|
|
||||||
console.debug("重启ICE", transportId);
|
|
||||||
const iceParameters = await transport.restartIce();
|
|
||||||
message.body.iceParameters = iceParameters;
|
|
||||||
me.push(message);
|
|
||||||
} else {
|
|
||||||
console.warn("重启ICE(无效)", transportId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 消费媒体信令
|
* 消费媒体信令
|
||||||
*
|
*
|
||||||
@@ -1376,6 +1352,31 @@ class Taoyao {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重启ICE信令
|
||||||
|
*
|
||||||
|
* @param {*} message 信令消息
|
||||||
|
* @param {*} body 消息主体
|
||||||
|
*/
|
||||||
|
async mediaIceRestart(message, body) {
|
||||||
|
const {
|
||||||
|
roomId,
|
||||||
|
transportId
|
||||||
|
} = body;
|
||||||
|
const room = this.rooms.get(roomId);
|
||||||
|
const transport = room?.transports.get(transportId);
|
||||||
|
if(!transport) {
|
||||||
|
console.warn("重启ICE(无效通道)", transportId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.debug("重启ICE", transportId);
|
||||||
|
message.body = {
|
||||||
|
...body,
|
||||||
|
iceParameters: await transport.restartIce()
|
||||||
|
};
|
||||||
|
this.push(message);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生产媒体信令
|
* 生产媒体信令
|
||||||
*
|
*
|
||||||
@@ -1594,10 +1595,11 @@ class Taoyao {
|
|||||||
const {
|
const {
|
||||||
roomId
|
roomId
|
||||||
} = body;
|
} = body;
|
||||||
const room = this.rooms.get(roomId);
|
const room = this.rooms.get(roomId);
|
||||||
|
const rtpCapabilities = room?.mediasoupRouter.rtpCapabilities;
|
||||||
message.body = {
|
message.body = {
|
||||||
...message.body,
|
...body,
|
||||||
rtpCapabilities: room?.mediasoupRouter.rtpCapabilities
|
rtpCapabilities
|
||||||
};
|
};
|
||||||
this.push(message);
|
this.push(message);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1800,29 +1800,6 @@ class Taoyao extends RemoteClient {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 重启ICE信令
|
|
||||||
*/
|
|
||||||
async mediaIceRestart() {
|
|
||||||
const me = this;
|
|
||||||
if (me.sendTransport) {
|
|
||||||
const response = await me.request(protocol.buildMessage("media::ice::restart", {
|
|
||||||
roomId : me.roomId,
|
|
||||||
transportId: me.sendTransport.id
|
|
||||||
}));
|
|
||||||
const { iceParameters } = response.body;
|
|
||||||
await me.sendTransport.restartIce({ iceParameters });
|
|
||||||
}
|
|
||||||
if (me.recvTransport) {
|
|
||||||
const response = await me.request(protocol.buildMessage("media::ice::restart", {
|
|
||||||
roomId : me.roomId,
|
|
||||||
transportId: me.recvTransport.id
|
|
||||||
}));
|
|
||||||
const { iceParameters } = response.body;
|
|
||||||
await me.recvTransport.restartIce({ iceParameters });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 消费媒体信令
|
* 消费媒体信令
|
||||||
*
|
*
|
||||||
@@ -2024,233 +2001,6 @@ class Taoyao extends RemoteClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 媒体回调
|
|
||||||
*
|
|
||||||
* @param {*} clientId 终端ID
|
|
||||||
* @param {*} track 媒体轨道
|
|
||||||
*/
|
|
||||||
callbackTrack(clientId, track) {
|
|
||||||
const me = this;
|
|
||||||
const callbackMessage = protocol.buildMessage("media::track", {
|
|
||||||
clientId,
|
|
||||||
track,
|
|
||||||
});
|
|
||||||
callbackMessage.code = SUCCESS_CODE;
|
|
||||||
callbackMessage.message = SUCCESS_MESSAGE;
|
|
||||||
me.callback(callbackMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生产媒体
|
|
||||||
*
|
|
||||||
* 如果需要加密:producer.rtpSender
|
|
||||||
* const senderStreams = sender.createEncodedStreams();
|
|
||||||
* const readableStream = senderStreams.readable || senderStreams.readableStream;
|
|
||||||
* const writableStream = senderStreams.writable || senderStreams.writableStream;
|
|
||||||
*
|
|
||||||
* @returns 所有生产者
|
|
||||||
*/
|
|
||||||
async mediaProduce(audioTrack, videoTrack) {
|
|
||||||
const me = this;
|
|
||||||
if(!audioTrack || !videoTrack) {
|
|
||||||
await me.checkDevice();
|
|
||||||
}
|
|
||||||
await me.createSendTransport();
|
|
||||||
await me.createRecvTransport();
|
|
||||||
await me.produceAudio(audioTrack);
|
|
||||||
await me.produceVideo(videoTrack);
|
|
||||||
await me.produceData();
|
|
||||||
return {
|
|
||||||
dataProducer : me.dataProducer,
|
|
||||||
audioProducer: me.audioProducer,
|
|
||||||
videoProducer: me.videoProducer,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生产音频
|
|
||||||
*
|
|
||||||
* @param {*} audioTrack 音频轨道(可以为空自动)
|
|
||||||
*/
|
|
||||||
async produceAudio(audioTrack) {
|
|
||||||
const me = this;
|
|
||||||
if (me.audioProducer) {
|
|
||||||
console.debug("已经存在音频生产者");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
!me.audioProduce ||
|
|
||||||
!me.mediasoupDevice.canProduce("audio")
|
|
||||||
) {
|
|
||||||
console.debug("不能生产音频数媒");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const track = audioTrack || await me.getAudioTrack();
|
|
||||||
const codecOptions = {
|
|
||||||
opusDtx : true,
|
|
||||||
opusFec : true,
|
|
||||||
opusNack : true,
|
|
||||||
opusStereo : true,
|
|
||||||
};
|
|
||||||
me.audioTrack = track;
|
|
||||||
me.audioProducer = await me.sendTransport.produce({
|
|
||||||
track,
|
|
||||||
codecOptions,
|
|
||||||
appData: {
|
|
||||||
videoSource: me.videoSource
|
|
||||||
},
|
|
||||||
});
|
|
||||||
me.callbackTrack(me.clientId, track);
|
|
||||||
if (me.proxy && me.proxy.media) {
|
|
||||||
me.proxy.media(track, me.audioProducer);
|
|
||||||
} else {
|
|
||||||
console.warn("终端没有实现服务代理");
|
|
||||||
}
|
|
||||||
me.audioProducer.on("transportclose", () => {
|
|
||||||
console.debug("关闭音频生产者(通道关闭)", me.audioProducer.id);
|
|
||||||
me.audioProducer.close();
|
|
||||||
});
|
|
||||||
me.audioProducer.on("trackended", () => {
|
|
||||||
console.debug("关闭音频生产者(媒体结束)", me.audioProducer.id);
|
|
||||||
me.audioProducer.close();
|
|
||||||
});
|
|
||||||
me.audioProducer.observer.on("close", () => {
|
|
||||||
console.debug("关闭音频生产者", me.audioProducer.id);
|
|
||||||
me.audioProducer = null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 关闭音频生产者
|
|
||||||
*/
|
|
||||||
async closeAudioProducer() {
|
|
||||||
this.mediaProducerClose(this.audioProducer?.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 暂停音频生产者
|
|
||||||
*/
|
|
||||||
async pauseAudioProducer() {
|
|
||||||
this.mediaProducerPause(this.audioProducer?.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 恢复音频生产者
|
|
||||||
*/
|
|
||||||
async resumeAudioProducer() {
|
|
||||||
this.mediaProducerResume(this.audioProducer?.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生产视频
|
|
||||||
*
|
|
||||||
* @param {*} videoTrack 音频轨道(可以为空自动)
|
|
||||||
*/
|
|
||||||
async produceVideo(videoTrack) {
|
|
||||||
const me = this;
|
|
||||||
if (me.videoProducer) {
|
|
||||||
console.debug("已经存在视频生产者");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
!me.videoProduce ||
|
|
||||||
!me.mediasoupDevice.canProduce("video")
|
|
||||||
) {
|
|
||||||
console.debug("不能生产视频媒体");
|
|
||||||
}
|
|
||||||
const track = videoTrack || await me.getVideoTrack();
|
|
||||||
const codecOptions = {
|
|
||||||
videoGoogleStartBitrate: 400,
|
|
||||||
videoGoogleMinBitrate : 800,
|
|
||||||
videoGoogleMaxBitrate : 1600,
|
|
||||||
};
|
|
||||||
let codec;
|
|
||||||
if(me.forceVP8) {
|
|
||||||
codec = me.mediasoupDevice.rtpCapabilities.codecs.find((c) => c.mimeType.toLowerCase() === "video/vp8");
|
|
||||||
if (codec) {
|
|
||||||
console.debug("强制使用VP8视频编码");
|
|
||||||
} else {
|
|
||||||
console.debug("不支持VP8视频编码");
|
|
||||||
}
|
|
||||||
} else if (me.forceVP9) {
|
|
||||||
codec = me.mediasoupDevice.rtpCapabilities.codecs.find((c) => c.mimeType.toLowerCase() === "video/vp9");
|
|
||||||
if (codec) {
|
|
||||||
console.debug("强制使用VP9视频编码");
|
|
||||||
} else {
|
|
||||||
console.debug("不支持VP9视频编码");
|
|
||||||
}
|
|
||||||
} else if (me.forceH264) {
|
|
||||||
codec = me.mediasoupDevice.rtpCapabilities.codecs.find((c) => c.mimeType.toLowerCase() === "video/h264");
|
|
||||||
if (codec) {
|
|
||||||
console.debug("强制使用H264视频编码");
|
|
||||||
} else {
|
|
||||||
console.debug("不支持H264视频编码");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let encodings;
|
|
||||||
if (me.useLayers) {
|
|
||||||
const priorityVideoCodec = me.mediasoupDevice.rtpCapabilities.codecs.find((c) => c.kind === "video");
|
|
||||||
if (
|
|
||||||
(me.forceVP9 && codec) ||
|
|
||||||
priorityVideoCodec.mimeType.toLowerCase() === "video/vp9"
|
|
||||||
) {
|
|
||||||
encodings = defaultSvcEncodings;
|
|
||||||
} else {
|
|
||||||
encodings = defaultSimulcastEncodings;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
me.videoTrack = track;
|
|
||||||
me.videoProducer = await me.sendTransport.produce({
|
|
||||||
codec,
|
|
||||||
track,
|
|
||||||
encodings,
|
|
||||||
codecOptions,
|
|
||||||
appData: {
|
|
||||||
videoSource: me.videoSource
|
|
||||||
},
|
|
||||||
});
|
|
||||||
me.callbackTrack(me.clientId, track);
|
|
||||||
if (me.proxy && me.proxy.media) {
|
|
||||||
me.proxy.media(track, me.videoProducer);
|
|
||||||
} else {
|
|
||||||
console.warn("终端没有实现服务代理");
|
|
||||||
}
|
|
||||||
me.videoProducer.on("transportclose", () => {
|
|
||||||
console.debug("关闭视频生产者(通道关闭)", me.videoProducer.id);
|
|
||||||
me.videoProducer.close();
|
|
||||||
});
|
|
||||||
me.videoProducer.on("trackended", () => {
|
|
||||||
console.debug("关闭视频生产者(媒体结束)", me.videoProducer.id);
|
|
||||||
me.videoProducer.close();
|
|
||||||
});
|
|
||||||
me.videoProducer.observer.on("close", () => {
|
|
||||||
console.debug("关闭视频生产者", me.videoProducer.id);
|
|
||||||
me.videoProducer = null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 关闭视频生产者
|
|
||||||
*/
|
|
||||||
async closeVideoProducer() {
|
|
||||||
this.mediaProducerClose(this.videoProducer?.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 暂停视频生产者
|
|
||||||
*/
|
|
||||||
async pauseVideoProducer() {
|
|
||||||
this.mediaProducerPause(this.videoProducer?.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 恢复视频生产者
|
|
||||||
*/
|
|
||||||
async resumeVideoProducer() {
|
|
||||||
this.mediaProducerResume(this.videoProducer?.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生产数据
|
* 生产数据
|
||||||
*/
|
*/
|
||||||
@@ -2290,13 +2040,6 @@ class Taoyao extends RemoteClient {
|
|||||||
// me.dataProducer.on("sctpsendbufferfull", fn());
|
// me.dataProducer.on("sctpsendbufferfull", fn());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 关闭数据生产者
|
|
||||||
*/
|
|
||||||
async closeDataProducer() {
|
|
||||||
this.mediaDataProducerClose(this.dataProducer?.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过数据生产者发送数据
|
* 通过数据生产者发送数据
|
||||||
*
|
*
|
||||||
@@ -2306,29 +2049,276 @@ class Taoyao extends RemoteClient {
|
|||||||
this.dataProducer?.send(data);
|
this.dataProducer?.send(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭数据生产者
|
||||||
|
*/
|
||||||
|
async closeDataProducer() {
|
||||||
|
this.mediaDataProducerClose(this.dataProducer?.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重启ICE信令
|
||||||
|
*/
|
||||||
|
async mediaIceRestart() {
|
||||||
|
if (this.sendTransport) {
|
||||||
|
const response = await this.request(protocol.buildMessage("media::ice::restart", {
|
||||||
|
roomId : this.roomId,
|
||||||
|
transportId: this.sendTransport.id
|
||||||
|
}));
|
||||||
|
const {
|
||||||
|
iceParameters
|
||||||
|
} = response.body;
|
||||||
|
await this.sendTransport.restartIce({
|
||||||
|
iceParameters
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (this.recvTransport) {
|
||||||
|
const response = await this.request(protocol.buildMessage("media::ice::restart", {
|
||||||
|
roomId : this.roomId,
|
||||||
|
transportId: this.recvTransport.id
|
||||||
|
}));
|
||||||
|
const {
|
||||||
|
iceParameters
|
||||||
|
} = response.body;
|
||||||
|
await this.recvTransport.restartIce({
|
||||||
|
iceParameters
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生产媒体
|
||||||
|
*
|
||||||
|
* 如果需要加密:producer.rtpSender
|
||||||
|
* const senderStreams = sender.createEncodedStreams();
|
||||||
|
* const readableStream = senderStreams.readable || senderStreams.readableStream;
|
||||||
|
* const writableStream = senderStreams.writable || senderStreams.writableStream;
|
||||||
|
*
|
||||||
|
* @returns 所有生产者
|
||||||
|
*/
|
||||||
|
async mediaProduce(audioTrack, videoTrack) {
|
||||||
|
if(!audioTrack || !videoTrack) {
|
||||||
|
await this.checkDevice();
|
||||||
|
}
|
||||||
|
if(!this.sendTransport) {
|
||||||
|
await this.createSendTransport();
|
||||||
|
}
|
||||||
|
if(!this.recvTransport) {
|
||||||
|
await this.createRecvTransport();
|
||||||
|
}
|
||||||
|
await this.produceAudio(audioTrack);
|
||||||
|
await this.produceVideo(videoTrack);
|
||||||
|
await this.produceData();
|
||||||
|
return {
|
||||||
|
dataProducer : this.dataProducer,
|
||||||
|
audioProducer: this.audioProducer,
|
||||||
|
videoProducer: this.videoProducer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生产音频
|
||||||
|
*
|
||||||
|
* @param {*} audioTrack 音频轨道(可以为空自动)
|
||||||
|
*/
|
||||||
|
async produceAudio(audioTrack) {
|
||||||
|
if (this.audioProducer) {
|
||||||
|
console.debug("已经存在音频生产者");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
!this.audioProduce ||
|
||||||
|
!this.mediasoupDevice.canProduce("audio")
|
||||||
|
) {
|
||||||
|
console.debug("不能生产音频数媒");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const codecOptions = {
|
||||||
|
opusDtx : true,
|
||||||
|
opusFec : true,
|
||||||
|
opusNack : true,
|
||||||
|
opusStereo : true,
|
||||||
|
};
|
||||||
|
const track = audioTrack || await this.getAudioTrack();
|
||||||
|
this.audioTrack = track;
|
||||||
|
this.audioProducer = await this.sendTransport.produce({
|
||||||
|
track,
|
||||||
|
codecOptions,
|
||||||
|
appData: {
|
||||||
|
videoSource: this.videoSource
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.callbackTrack(this.clientId, track);
|
||||||
|
if (this.proxy && this.proxy.media) {
|
||||||
|
this.proxy.media(track, this.audioProducer);
|
||||||
|
} else {
|
||||||
|
console.warn("终端没有实现服务代理");
|
||||||
|
}
|
||||||
|
this.audioProducer.on("transportclose", () => {
|
||||||
|
console.debug("关闭音频生产者(通道关闭)", this.audioProducer.id);
|
||||||
|
this.audioProducer.close();
|
||||||
|
});
|
||||||
|
this.audioProducer.on("trackended", () => {
|
||||||
|
console.debug("关闭音频生产者(媒体结束)", this.audioProducer.id);
|
||||||
|
this.audioProducer.close();
|
||||||
|
});
|
||||||
|
this.audioProducer.observer.on("close", () => {
|
||||||
|
console.debug("关闭音频生产者", this.audioProducer.id);
|
||||||
|
this.audioProducer = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭音频生产者
|
||||||
|
*/
|
||||||
|
async closeAudioProducer() {
|
||||||
|
this.mediaProducerClose(this.audioProducer?.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 暂停音频生产者
|
||||||
|
*/
|
||||||
|
async pauseAudioProducer() {
|
||||||
|
this.mediaProducerPause(this.audioProducer?.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 恢复音频生产者
|
||||||
|
*/
|
||||||
|
async resumeAudioProducer() {
|
||||||
|
this.mediaProducerResume(this.audioProducer?.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生产视频
|
||||||
|
*
|
||||||
|
* @param {*} videoTrack 音频轨道(可以为空自动)
|
||||||
|
*/
|
||||||
|
async produceVideo(videoTrack) {
|
||||||
|
if (this.videoProducer) {
|
||||||
|
console.debug("已经存在视频生产者");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
!this.videoProduce ||
|
||||||
|
!this.mediasoupDevice.canProduce("video")
|
||||||
|
) {
|
||||||
|
console.debug("不能生产视频媒体");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const codecOptions = {
|
||||||
|
videoGoogleStartBitrate: 400,
|
||||||
|
videoGoogleMinBitrate : 800,
|
||||||
|
videoGoogleMaxBitrate : 1600,
|
||||||
|
};
|
||||||
|
let codec;
|
||||||
|
if(this.forceVP8) {
|
||||||
|
codec = this.mediasoupDevice.rtpCapabilities.codecs.find((c) => c.mimeType.toLowerCase() === "video/vp8");
|
||||||
|
if (codec) {
|
||||||
|
console.debug("强制使用VP8视频编码");
|
||||||
|
} else {
|
||||||
|
console.debug("不支持VP8视频编码");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.forceVP9) {
|
||||||
|
codec = this.mediasoupDevice.rtpCapabilities.codecs.find((c) => c.mimeType.toLowerCase() === "video/vp9");
|
||||||
|
if (codec) {
|
||||||
|
console.debug("强制使用VP9视频编码");
|
||||||
|
} else {
|
||||||
|
console.debug("不支持VP9视频编码");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.forceH264) {
|
||||||
|
codec = this.mediasoupDevice.rtpCapabilities.codecs.find((c) => c.mimeType.toLowerCase() === "video/h264");
|
||||||
|
if (codec) {
|
||||||
|
console.debug("强制使用H264视频编码");
|
||||||
|
} else {
|
||||||
|
console.debug("不支持H264视频编码");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let encodings;
|
||||||
|
if (this.useLayers) {
|
||||||
|
const priorityVideoCodec = this.mediasoupDevice.rtpCapabilities.codecs.find((c) => c.kind === "video");
|
||||||
|
if ((this.forceVP9 && codec) || priorityVideoCodec.mimeType.toLowerCase() === "video/vp9") {
|
||||||
|
encodings = defaultSvcEncodings;
|
||||||
|
} else {
|
||||||
|
encodings = defaultSimulcastEncodings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const track = videoTrack || await this.getVideoTrack();
|
||||||
|
this.videoTrack = track;
|
||||||
|
this.videoProducer = await this.sendTransport.produce({
|
||||||
|
codec,
|
||||||
|
track,
|
||||||
|
encodings,
|
||||||
|
codecOptions,
|
||||||
|
appData: {
|
||||||
|
videoSource: this.videoSource
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.callbackTrack(this.clientId, track);
|
||||||
|
if (this.proxy && this.proxy.media) {
|
||||||
|
this.proxy.media(track, this.videoProducer);
|
||||||
|
} else {
|
||||||
|
console.warn("终端没有实现服务代理");
|
||||||
|
}
|
||||||
|
this.videoProducer.on("transportclose", () => {
|
||||||
|
console.debug("关闭视频生产者(通道关闭)", this.videoProducer.id);
|
||||||
|
this.videoProducer.close();
|
||||||
|
});
|
||||||
|
this.videoProducer.on("trackended", () => {
|
||||||
|
console.debug("关闭视频生产者(媒体结束)", this.videoProducer.id);
|
||||||
|
this.videoProducer.close();
|
||||||
|
});
|
||||||
|
this.videoProducer.observer.on("close", () => {
|
||||||
|
console.debug("关闭视频生产者", this.videoProducer.id);
|
||||||
|
this.videoProducer = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭视频生产者
|
||||||
|
*/
|
||||||
|
async closeVideoProducer() {
|
||||||
|
this.mediaProducerClose(this.videoProducer?.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 暂停视频生产者
|
||||||
|
*/
|
||||||
|
async pauseVideoProducer() {
|
||||||
|
this.mediaProducerPause(this.videoProducer?.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 恢复视频生产者
|
||||||
|
*/
|
||||||
|
async resumeVideoProducer() {
|
||||||
|
this.mediaProducerResume(this.videoProducer?.id);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 切换视频来源
|
* 切换视频来源
|
||||||
*
|
*
|
||||||
* @param {*} videoSource 视频来源(可以为空)
|
* @param {*} videoSource 视频来源(可以为空)
|
||||||
*/
|
*/
|
||||||
async exchangeVideoSource(videoSource) {
|
async exchangeVideoSource(videoSource) {
|
||||||
const me = this;
|
console.debug("切换视频来源", videoSource, this.videoSource);
|
||||||
console.debug("切换视频来源", videoSource, me.videoSource);
|
|
||||||
const old = this.videoSource;
|
const old = this.videoSource;
|
||||||
if(videoSource) {
|
if(videoSource) {
|
||||||
me.videoSource = videoSource;
|
this.videoSource = videoSource;
|
||||||
} else {
|
} else {
|
||||||
if(me.videoSource === "file") {
|
if(this.videoSource === "file") {
|
||||||
me.videoSource = "camera";
|
this.videoSource = "camera";
|
||||||
} else if(me.videoSource === "camera") {
|
} else if(this.videoSource === "camera") {
|
||||||
me.videoSource = "screen";
|
this.videoSource = "screen";
|
||||||
} else if(me.videoSource === "screen") {
|
} else if(this.videoSource === "screen") {
|
||||||
me.videoSource = "file";
|
this.videoSource = "file";
|
||||||
} else {
|
} else {
|
||||||
me.videoSource = "camera";
|
this.videoSource = "camera";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await me.updateVideoProducer();
|
await this.updateVideoProducer();
|
||||||
if(old === "file") {
|
if(old === "file") {
|
||||||
this.closeFileVideo();
|
this.closeFileVideo();
|
||||||
}
|
}
|
||||||
@@ -2340,20 +2330,22 @@ class Taoyao extends RemoteClient {
|
|||||||
* @param {*} 更新视频轨道
|
* @param {*} 更新视频轨道
|
||||||
*/
|
*/
|
||||||
async updateVideoProducer(videoTrack) {
|
async updateVideoProducer(videoTrack) {
|
||||||
const me = this;
|
const track = videoTrack || await this.getVideoTrack();
|
||||||
const track = videoTrack || await me.getVideoTrack();
|
await this.videoProducer.replaceTrack({
|
||||||
await me.videoProducer.replaceTrack({
|
|
||||||
track
|
track
|
||||||
});
|
});
|
||||||
me.callbackTrack(me.clientId, track);
|
this.callbackTrack(this.clientId, track);
|
||||||
me.proxy.media(track, me.videoProducer);
|
if (this.proxy && this.proxy.media) {
|
||||||
|
this.proxy.media(track, this.videoProducer);
|
||||||
|
} else {
|
||||||
|
console.warn("终端没有实现服务代理");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 验证设备
|
* 验证设备
|
||||||
*/
|
*/
|
||||||
async checkDevice() {
|
async checkDevice() {
|
||||||
const me = this;
|
|
||||||
if (
|
if (
|
||||||
navigator.mediaDevices &&
|
navigator.mediaDevices &&
|
||||||
navigator.mediaDevices.getUserMedia &&
|
navigator.mediaDevices.getUserMedia &&
|
||||||
@@ -2375,18 +2367,18 @@ class Taoyao extends RemoteClient {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (!audioEnabled && me.audioProduce) {
|
if (!audioEnabled && this.audioProduce) {
|
||||||
me.platformError("没有音频媒体设备");
|
this.platformError("没有音频媒体设备");
|
||||||
// 强制修改
|
// 强制修改
|
||||||
me.audioProduce = false;
|
this.audioProduce = false;
|
||||||
}
|
}
|
||||||
if (!videoEnabled && me.videoProduce) {
|
if (!videoEnabled && this.videoProduce) {
|
||||||
me.platformError("没有视频媒体设备");
|
this.platformError("没有视频媒体设备");
|
||||||
// 强制修改
|
// 强制修改
|
||||||
me.videoProduce = false;
|
this.videoProduce = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
me.platformError("没有媒体权限");
|
this.platformError("没有媒体权限");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3601,6 +3593,22 @@ class Taoyao extends RemoteClient {
|
|||||||
await track.applyConstraints(Object.assign(track.getSettings(), setting));
|
await track.applyConstraints(Object.assign(track.getSettings(), setting));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 媒体回调
|
||||||
|
*
|
||||||
|
* @param {*} clientId 终端ID
|
||||||
|
* @param {*} track 媒体轨道
|
||||||
|
*/
|
||||||
|
callbackTrack(clientId, track) {
|
||||||
|
const callbackMessage = protocol.buildMessage("media::track", {
|
||||||
|
track,
|
||||||
|
clientId,
|
||||||
|
});
|
||||||
|
callbackMessage.code = SUCCESS_CODE;
|
||||||
|
callbackMessage.message = SUCCESS_MESSAGE;
|
||||||
|
this.callback(callbackMessage);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 统计设备信息
|
* 统计设备信息
|
||||||
*
|
*
|
||||||
@@ -3609,15 +3617,14 @@ class Taoyao extends RemoteClient {
|
|||||||
* @returns 设备信息统计
|
* @returns 设备信息统计
|
||||||
*/
|
*/
|
||||||
async getClientStats(clientId) {
|
async getClientStats(clientId) {
|
||||||
const me = this;
|
|
||||||
const stats = {};
|
const stats = {};
|
||||||
if(clientId === me.clientId) {
|
if(clientId === this.clientId) {
|
||||||
stats.sendTransport = await me.sendTransport.getStats();
|
stats.sendTransport = await this.sendTransport.getStats();
|
||||||
stats.recvTransport = await me.recvTransport.getStats();
|
stats.recvTransport = await this.recvTransport.getStats();
|
||||||
stats.audioProducer = await me.audioProducer.getStats();
|
stats.audioProducer = await this.audioProducer.getStats();
|
||||||
stats.videoProducer = await me.videoProducer.getStats();
|
stats.videoProducer = await this.videoProducer.getStats();
|
||||||
} else {
|
} else {
|
||||||
const consumers = Array.from(me.consumers.values());
|
const consumers = Array.from(this.consumers.values());
|
||||||
for(const consumer of consumers) {
|
for(const consumer of consumers) {
|
||||||
if(clientId === consumer.sourceId) {
|
if(clientId === consumer.sourceId) {
|
||||||
stats[consumer.kind] = await consumer.getStats();
|
stats[consumer.kind] = await consumer.getStats();
|
||||||
@@ -3663,42 +3670,44 @@ class Taoyao extends RemoteClient {
|
|||||||
*/
|
*/
|
||||||
async closeRoomMedia() {
|
async closeRoomMedia() {
|
||||||
console.debug("关闭视频房间媒体");
|
console.debug("关闭视频房间媒体");
|
||||||
const me = this;
|
this.roomId = null;
|
||||||
me.roomId = null;
|
await this.close();
|
||||||
await me.close();
|
this.consumers.forEach(async (consumer, consumerId) => {
|
||||||
if (me.sendTransport) {
|
|
||||||
await me.sendTransport.close();
|
|
||||||
me.sendTransport = null;
|
|
||||||
}
|
|
||||||
if (me.recvTransport) {
|
|
||||||
await me.recvTransport.close();
|
|
||||||
me.recvTransport = null;
|
|
||||||
}
|
|
||||||
if(me.dataProducer) {
|
|
||||||
await me.dataProducer.close();
|
|
||||||
me.dataProducer = null;
|
|
||||||
}
|
|
||||||
if(me.audioProducer) {
|
|
||||||
await me.audioProducer.close();
|
|
||||||
me.audioProducer = null;
|
|
||||||
}
|
|
||||||
if(me.videoProducer) {
|
|
||||||
await me.videoProducer.close();
|
|
||||||
me.videoProducer = null;
|
|
||||||
}
|
|
||||||
me.consumers.forEach(async (consumer, consumerId) => {
|
|
||||||
await consumer.close();
|
await consumer.close();
|
||||||
});
|
});
|
||||||
me.consumers.clear();
|
this.consumers.clear();
|
||||||
me.dataConsumers.forEach(async (dataConsumer, consumerId) => {
|
this.dataConsumers.forEach(async (dataConsumer, consumerId) => {
|
||||||
await dataConsumer.close();
|
await dataConsumer.close();
|
||||||
});
|
});
|
||||||
me.dataConsumers.clear();
|
this.dataConsumers.clear();
|
||||||
me.remoteClients.forEach(async (client, clientId) => {
|
this.remoteClients.forEach(async (remoteClient, clientId) => {
|
||||||
await client.close();
|
await remoteClient.close();
|
||||||
});
|
});
|
||||||
me.remoteClients.clear();
|
this.remoteClients.clear();
|
||||||
me.closeFileVideo();
|
if(this.audioProducer) {
|
||||||
|
await this.audioProducer.close();
|
||||||
|
this.audioProducer = null;
|
||||||
|
}
|
||||||
|
if(this.videoProducer) {
|
||||||
|
await this.videoProducer.close();
|
||||||
|
this.videoProducer = null;
|
||||||
|
}
|
||||||
|
if(this.dataProducer) {
|
||||||
|
await this.dataProducer.close();
|
||||||
|
this.dataProducer = null;
|
||||||
|
}
|
||||||
|
if (this.sendTransport) {
|
||||||
|
await this.sendTransport.close();
|
||||||
|
this.sendTransport = null;
|
||||||
|
}
|
||||||
|
if (this.recvTransport) {
|
||||||
|
await this.recvTransport.close();
|
||||||
|
this.recvTransport = null;
|
||||||
|
}
|
||||||
|
if(this.mediasoupDevice) {
|
||||||
|
this.mediasoupDevice = null;
|
||||||
|
}
|
||||||
|
this.closeFileVideo();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -3706,26 +3715,24 @@ class Taoyao extends RemoteClient {
|
|||||||
*/
|
*/
|
||||||
closeSessionMedia() {
|
closeSessionMedia() {
|
||||||
console.debug("关闭视频会话媒体");
|
console.debug("关闭视频会话媒体");
|
||||||
const me = this;
|
this.sessionClients.forEach((session, sessionId) => {
|
||||||
me.sessionClients.forEach((session, sessionId) => {
|
|
||||||
session.close();
|
session.close();
|
||||||
console.debug("关闭会话", sessionId);
|
console.debug("关闭会话", sessionId);
|
||||||
});
|
});
|
||||||
me.sessionClients.clear();
|
this.sessionClients.clear();
|
||||||
me.closeFileVideo();
|
this.closeFileVideo();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 关闭资源
|
* 关闭资源
|
||||||
*/
|
*/
|
||||||
closeAll() {
|
closeAll() {
|
||||||
const me = this;
|
if(this.closed) {
|
||||||
if(me.closed) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
me.closed = true;
|
this.closed = true;
|
||||||
me.closeRoomMedia();
|
this.closeRoomMedia();
|
||||||
me.closeSessionMedia();
|
this.closeSessionMedia();
|
||||||
signalChannel.close();
|
signalChannel.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user