[*] 共享本地视频文件

This commit is contained in:
acgist
2023-09-11 09:11:03 +08:00
parent dc2334e8b6
commit 3575cbee4e
2 changed files with 130 additions and 93 deletions

View File

@@ -887,23 +887,19 @@ class Taoyao {
});
producer.observer.on("resume", () => {
console.debug("生产者恢复", producer.id, streamId);
me.push(
protocol.buildMessage("media::producer::resume", {
roomId : roomId,
me.push(protocol.buildMessage("media::producer::resume", {
roomId,
producerId: producer.id
})
);
}));
});
// producer.observer.on("score", fn(score));
producer.on("score", (score) => {
console.debug("生产者评分", producer.id, streamId, score);
me.push(
protocol.buildMessage("media::producer::score", {
roomId : roomId,
me.push(protocol.buildMessage("media::producer::score", {
score,
roomId,
producerId: producer.id,
score : score,
})
);
}));
});
// producer.observer.on("videoorientationchange", fn(videoOrientation));
producer.on("videoorientationchange", (videoOrientation) => {
@@ -926,13 +922,6 @@ class Taoyao {
producerId: producer.id
};
me.push(message);
// me.push(
// protocol.buildMessage("media::producer::score", {
// roomId : roomId,
// producerId: producer.id,
// score : producer.score,
// })
// );
if (producer.kind === "audio") {
// TODO关闭生产者时移除监听
room.audioLevelObserver
@@ -1161,13 +1150,6 @@ class Taoyao {
);
await consumer.resume();
consumer.localPaused = false;
// me.push(
// protocol.buildMessage("media::consumer::score", {
// roomId : roomId,
// consumerId: consumer.id,
// score : consumer.score,
// })
// );
})()
);
}

View File

@@ -550,6 +550,8 @@ class Taoyao extends RemoteClient {
mediasoupDevice;
// 文件共享
fileVideo;
// 文件共享地址
fileVideoObjectURL;
// 视频来源file|camera|screen
videoSource;
// 强制使用TCP
@@ -608,7 +610,6 @@ class Taoyao extends RemoteClient {
dataProduce = true,
audioProduce = true,
videoProduce = true,
fileVideo = null,
videoSource = "camera",
forceTcp = false,
forceVP8 = false,
@@ -631,7 +632,6 @@ class Taoyao extends RemoteClient {
this.dataProduce = dataProduce;
this.audioProduce = audioProduce;
this.videoProduce = videoProduce;
this.fileVideo = fileVideo;
this.videoSource = videoSource;
this.forceTcp = forceTcp;
this.forceVP8 = forceVP8;
@@ -930,6 +930,52 @@ class Taoyao extends RemoteClient {
}
}
/**
* 选择视频文件
*/
async getFileVideo() {
const input = document.createElement("input");
input.type = "file";
const select = new Promise((resolve, reject) => {
input.onchange = (e) => {
resolve(input.value);
}
input.oncancel = (e) => {
resolve(null);
};
});
input.click();
const file = await select;
input.remove();
if(!file) {
console.debug("没有选择共享文件");
return;
}
console.debug("选择文件", file);
this.fileVideo = document.createElement("video");
this.fileVideo.loop = true;
this.fileVideo.muted = true;
this.fileVideo.controls = true;
this.fileVideo.src = URL.createObjectURL(input.files[0]);
this.fileVideo.style = "position:fixed;top:1rem;left:1rem;width:128px;border:2px solid #FFF;";
// this.fileVideo.style.display = "none";
document.body.appendChild(this.fileVideo);
// 开始播放不然不能采集
await this.fileVideo.play();
}
/**
* 释放视频文件
*/
async closeFileVideo() {
if(this.fileVideo) {
this.fileVideo.remove();
}
if(this.fileVideoObjectURL) {
URL.revokeObjectURL(this.fileVideoObjectURL);
}
}
/**
* @returns 媒体
*/
@@ -937,6 +983,7 @@ class Taoyao extends RemoteClient {
const me = this;
let stream;
if (me.videoSource === "file") {
await this.getFileVideo();
stream = me.fileVideo.captureStream();
} else if (me.videoSource === "camera") {
console.debug("媒体配置", me.audioConfig, me.videoConfig);
@@ -1016,6 +1063,7 @@ class Taoyao extends RemoteClient {
let stream;
const me = this;
if (me.videoSource === "file") {
await this.getFileVideo();
stream = me.fileVideo.captureStream();
} else if (me.videoSource === "camera") {
stream = await navigator.mediaDevices.getUserMedia({
@@ -1854,57 +1902,6 @@ class Taoyao extends RemoteClient {
}
}
/**
* 恢复生产者信令
*
* @param {*} producerId 生产者ID
*/
mediaProducerResume(producerId) {
const me = this;
const producer = me.getProducer(producerId);
if(producer) {
if(!producer.paused) {
return;
}
console.debug("恢复生产者", producerId);
me.push(protocol.buildMessage("media::producer::resume", {
roomId : me.roomId,
producerId: producerId,
}));
} else {
console.debug("恢复生产者无效", producerId);
}
}
/**
* 恢复生产者信令
*
* @param {*} message 信令消息
*/
async defaultMediaProducerResume(message) {
const me = this;
const {
roomId,
producerId
} = message.body;
const producer = me.getProducer(producerId);
if (producer) {
console.debug("恢复生产者", producerId);
producer.resume();
} else {
console.debug("恢复生产者无效", producerId);
}
}
/**
* 媒体生产者评分信令
*
* @param {*} message 信令消息
*/
defaultMediaProducerScore(message) {
console.debug("生产者评分", message);
}
/**
* 消费媒体信令
*
@@ -2396,6 +2393,7 @@ class Taoyao extends RemoteClient {
async exchangeVideoSource(videoSource) {
const me = this;
console.debug("切换视频来源", videoSource, me.videoSource);
const old = this.videoSource;
if(videoSource) {
me.videoSource = videoSource;
} else {
@@ -2410,6 +2408,9 @@ class Taoyao extends RemoteClient {
}
}
await me.updateVideoProducer();
if(old === "file") {
this.closeFileVideo();
}
}
/**
@@ -2468,6 +2469,59 @@ class Taoyao extends RemoteClient {
}
}
/**
* 恢复生产者信令
*
* @param {*} producerId 生产者ID
*/
mediaProducerResume(producerId) {
const producer = this.getProducer(producerId);
if(!producer) {
console.debug("恢复生产者(生产者无效)", producerId);
return;
}
if(!producer.paused) {
console.debug("恢复生产者(生产者已经恢复)", producerId);
return;
}
console.debug("恢复生产者", producerId);
this.push(protocol.buildMessage("media::producer::resume", {
producerId,
roomId: this.roomId,
}));
}
/**
* 恢复生产者信令
*
* @param {*} message 信令消息
*/
async defaultMediaProducerResume(message) {
const {
producerId
} = message.body;
const producer = this.getProducer(producerId);
if (!producer) {
console.debug("恢复生产者(生产者无效)", producerId);
return;
}
if(!producer.paused) {
console.debug("恢复生产者(生产者已经恢复)", producerId);
return;
}
console.debug("恢复生产者", producerId);
producer.resume();
}
/**
* 媒体生产者评分信令
*
* @param {*} message 信令消息
*/
defaultMediaProducerScore(message) {
console.debug("生产者评分", message);
}
/**
* 查询生产者状态信令
*
@@ -3417,19 +3471,20 @@ class Taoyao extends RemoteClient {
* @param {*} video 视频
*/
localPhotograph(video) {
const me = this;
const canvas = document.createElement('canvas');
const canvas = document.createElement("canvas");
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
const context = canvas.getContext('2d');
const context = canvas.getContext("2d");
context.drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
const dataURL = canvas.toDataURL('images/png');
const download = document.createElement('a');
const dataURL = canvas.toDataURL("images/png");
const download = document.createElement("a");
download.href = dataURL;
download.download = 'taoyao.png';
download.style.display = 'none';
document.body.appendChild(download);
download.download = "taoyao.png";
// download.style.display = "none";
// document.body.appendChild(download);
download.click();
// 释放资源
canvas.remove();
download.remove();
}
@@ -3485,11 +3540,11 @@ class Taoyao extends RemoteClient {
me.mediaRecorder.onstop = (e) => {
const blob = new Blob(me.mediaRecorderChunks);
const objectURL = URL.createObjectURL(blob);
const download = document.createElement('a');
const download = document.createElement("a");
download.href = objectURL;
download.download = 'taoyao.mp4';
download.style.display = 'none';
document.body.appendChild(download);
download.download = "taoyao.mp4";
// download.style.display = "none";
// document.body.appendChild(download);
download.click();
download.remove();
URL.revokeObjectURL(objectURL);