Привет.
Моя задача - получить с клиента видеопоток с вебки, проанализировать его и вернуть результат в виде строки. Читая документацию aiortc и смотря их примеры на
гите, смог сделать лишь такой вариант:
async def offer(request):
params = await request.json()
offer = RTCSessionDescription(sdp=params["sdp"], type=params["type"])
pc = RTCPeerConnection()
pcs.add(pc)
await server(pc, offer)
return web.Response(
content_type="application/json",
text=json.dumps(
{"sdp": pc.localDescription.sdp, "type": pc.localDescription.type}
),
)
pcs = set()
async def server(pc, offer):
@pc.on("connectionstatechange")
async def on_connectionstatechange():
print("Connection state is %s" % pc.connectionState)
if pc.connectionState == "failed":
await pc.close()
pcs.discard(pc)
@pc.on("track")
def on_track(track):
print("======= received track: ", track)
if track.kind == "video":
global new_video_track
new_video_track = Sign(track)
pc.addTrack(new_video_track)
@pc.on("datachannel")
def on_datachannel(channel):
global new_video_track
new_video_track.channel = channel
print("mounted channel")
@channel.on("message")
async def on_message(message):
if isinstance(message, str):
data = message.encode("utf-8")
else:
data = message
print("receive data: ", data)
await pc.setRemoteDescription(offer)
answer = await pc.createAnswer()
await pc.setLocalDescription(answer)
async def on_shutdown(app):
# close peer connections
coros = [pc.close() for pc in pcs]
await asyncio.gather(*coros)
pcs.clear()
class Sign(VideoStreamTrack):
kind = "video"
def __init__(self, track):
super().__init__()
self.track = track
self.channel = None
async def recv(self):
frame = await self.track.recv()
# получаю необходимый результат
if self.channel and self.sentence:
self.channel.send(json.dumps({'word': self.sentence}))
return frame
но такой результат не устраивает, так как обратно нужно вернуть кадр. Как сделать так чтобы возвращалось только моё слово.
Вот клиент
var pc = null;
var localVideo = document.querySelector("video#localVideo");
var serverVideo = document.querySelector("video#serverVideo");
navigator.mediaDevices.getUserMedia({
video: {
height: 1080,
width: 1920,
frameRate: {
max: 10
}
}
}).then(stream => {
localVideo.srcObject = stream;
localVideo.addEventListener('loadedmetadata', () => {
localVideo.play();
});
});
function negotiate () {
return pc.createOffer().then(function (offer) {
return pc.setLocalDescription(offer);
}).then(function () {
// wait for ICE gathering to complete
return new Promise(function (resolve) {
if (pc.iceGatheringState === 'complete') {
resolve();
} else {
function checkState () {
if (pc.iceGatheringState === 'complete') {
pc.removeEventListener('icegatheringstatechange', checkState);
resolve();
}
}
pc.addEventListener('icegatheringstatechange', checkState);
}
});
}).then(function () {
var offer = pc.localDescription;
return fetch('/offer', {
body: JSON.stringify({
sdp: offer.sdp,
type: offer.type,
}),
headers: {
'Content-Type': 'application/json'
},
method: 'POST'
});
}).then(function (response) {
return response.json();
}).then(function (answer) {
return pc.setRemoteDescription(answer);
}).catch(function (e) {
alert(e);
});
}
function start () {
var config = {
sdpSemantics: 'unified-plan',
iceServers: [{ urls: ['stun:stun.l.google.com:19302'] }]
};
pc = new RTCPeerConnection(config);
localVideo.srcObject.getVideoTracks().forEach(track => {
pc.addTrack(track);
});
pc.addEventListener('track', function (evt) {
console.log("receive server video");
if (evt.track.kind == 'video') {
serverVideo.srcObject = evt.streams[0];
}
});
ch = pc.createDataChannel("chat", {
ordered: false,
maxRetransmits: 0,
});
ch.addEventListener("message", function (evt) {
console.log(Date.now() - JSON.parse(evt.data).now);
});
document.getElementById('start').style.display = 'none';
negotiate();
document.getElementById('stop').style.display = 'inline-block';
}
function stop () {
document.getElementById('stop').style.display = 'none';
setTimeout(function () {
pc.close();
}, 500);
}
Заранее спасибо и простите за большие куски кода.