我正在整理一个原型,它使用WebRTC通过aiortc将视频从一个Python脚本流到另一个脚本。
我正在翻阅Python存储库中的网络摄像头示例(使用--play--从视频文件到流而不是摄像头),并尝试将client.js脚本移植到Python。我主要是在那里,但ICE连接从未(成功)完成,并从IN_PROGRESS
到FAILED
后,大约30岁。我接收并可以订阅客户端脚本中的跟踪,但从未开始从webcam.py脚本接收流。
webcam.py脚本保持不变,这是我的client.py脚本:
import asyncio
import json
import requests
import time
from aiortc import (
MediaStreamTrack,
RTCConfiguration,
RTCIceServer,
RTCPeerConnection,
RTCSessionDescription,
)
from aiortc.contrib.media import MediaPlayer, MediaRelay
from loguru import logger
relay = MediaRelay()
class VideoTransformTrack(MediaStreamTrack):
"""
A video stream track that transforms frames from an another track.
"""
kind = "video"
def __init__(self, track):
if track.kind != "video":
raise Exception("Unsupported kind: %s" % (track.kind))
super().__init__() # don't forget this!
logger.info("track kind: %s" % track.kind)
self.track = track
async def recv(self):
logger.info("Attempt to receive frame ...")
frame = await self.track.recv()
logger.info("Received frame: %s" % (frame))
async def run():
# config = RTCConfiguration(
# iceServers=[
# RTCIceServer(
# urls=[
# "stun:stun.l.google.com:19302",
# "stun:stun1.l.google.com:19302",
# "stun:stun2.l.google.com:19302",
# "stun:stun3.l.google.com:19302",
# "stun:stun4.l.google.com:19302",
# ]
# ),
# ]
# )
pc = RTCPeerConnection()
pc.addTransceiver("video", direction="recvonly")
@pc.on("track")
def on_track(track):
"""
Track has been received from client.
"""
logger.info("Track %s received" % track)
pc.addTrack(
VideoTransformTrack(
relay.subscribe(track),
)
)
@track.on("ended")
async def on_ended():
logger.info("Track ended: %s" % track)
offer = await pc.createOffer()
await pc.setLocalDescription(offer)
while True:
logger.info("icegatheringstate: %s" % pc.iceGatheringState)
if pc.iceGatheringState == "complete":
break
offer2 = pc.localDescription
data = {
"sdp": offer2.sdp,
"type": offer2.type,
}
response = requests.post(
"http://localhost:8080/offer",
headers={"Content-Type": "application/json"},
json=data,
)
response_data = response.json()
await pc.setRemoteDescription(
RTCSessionDescription(sdp=response_data["sdp"], type=response_data["type"])
)
while True:
time.sleep(2)
logger.info("pc.iceGatheringState: %s" % pc.iceGatheringState)
logger.info("pc.connectionState : %s" % pc.connectionState)
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(run())
示例存储库中(功能齐全的) client.js脚本的相关部分:
var config = {
sdpSemantics: 'unified-plan'
};
pc = new RTCPeerConnection(config);
negotiate();
function negotiate() {
pc.addTransceiver('video', {direction: 'recvonly'});
pc.addTransceiver('audio', {direction: 'recvonly'});
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);
});
}
我是在翻译中遗漏了一些显而易见的东西,还是需要采取一些额外的步骤来满足方程的aiortc方面?此外,人们如何调试这类问题?我并没有经常使用它,但到目前为止,WebRTC给我的印象是有点像个黑匣子。
注意:我已经尝试在双方显式配置STUN服务器,但这似乎没有任何效果,我的理解是,在默认情况下,aiortc使用Google服务器。
环境:
更新:通过比较使用client.js的Chrome和使用client.py的Python生成的产品,我可能已经在调试这方面取得了一些进展。sdp的内容似乎有一些细微的差异: client.js引用了我的ISP提供的IP和client.py引用0.0.0.0。在所有情况下,我都尝试过使用显式IP,这似乎破坏了一切。这可能是一种“红鲱鱼”,但这里的错误配置可能是根本问题,这似乎是有道理的。
发布于 2022-08-07 12:47:00
异步time.sleep
例程中的run
阻塞主线程并冻结事件循环。
您应该使用await asyncio.sleep(2)
代替。
测试
使用示例代码进行快速测试:然后打印client.py
代码:
2022-08-07 14:39:42.291 | INFO | __main__:run:105 - pc.iceGatheringState: complete
2022-08-07 14:39:42.291 | INFO | __main__:run:106 - pc.connectionState : connected
同样,webcam.py
然后打印到调试控制台:
INFO:aioice.ice:connection(0) ICE completed
Connection state is connected
https://stackoverflow.com/questions/73226685
复制相似问题