[Janus example] Can't setLocalDescription when request 'subscriber' to Janus server
See original GitHub issueI try to get media this janus example, but it fail when i set answer to local description.
Log
Sdp send:
v=0
o=- 3768613065 3768613065 IN IP4 0.0.0.0
s=-
t=0 0
a=group:BUNDLE 0
a=msid-semantic:WMS *
m=video 50342 UDP/TLS/RTP/SAVPF 97 98 99 100 101 102
c=IN IP4 192.168.1.106
a=sendrecv
a=extmap:1 urn:ietf:params:rtp-hdrext:sdes:mid
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=mid:0
a=msid:96b6d97a-0ada-4f90-9d75-ae3c7cbc14d0 bd6a1f9b-008a-4316-a9de-3f1a32e3269d
a=rtcp:9 IN IP4 0.0.0.0
a=rtcp-mux
a=ssrc-group:FID 2105842630 265384714
a=ssrc:2105842630 cname:{f52d8811-2b40-4e5d-818f-65525f6a05d2}
a=ssrc:265384714 cname:{f52d8811-2b40-4e5d-818f-65525f6a05d2}
a=rtpmap:97 VP8/90000
a=rtcp-fb:97 nack
a=rtcp-fb:97 nack pli
a=rtcp-fb:97 goog-remb
a=rtpmap:98 rtx/90000
a=fmtp:98 apt=97
a=rtpmap:99 H264/90000
a=rtcp-fb:99 nack
a=rtcp-fb:99 nack pli
a=rtcp-fb:99 goog-remb
a=fmtp:99 packetization-mode=1;level-asymmetry-allowed=1;profile-level-id=42001f
a=rtpmap:100 rtx/90000
a=fmtp:100 apt=99
a=rtpmap:101 H264/90000
a=rtcp-fb:101 nack
a=rtcp-fb:101 nack pli
a=rtcp-fb:101 goog-remb
a=fmtp:101 packetization-mode=1;level-asymmetry-allowed=1;profile-level-id=42e01f
a=rtpmap:102 rtx/90000
a=fmtp:102 apt=101
a=candidate:d4bad81fb3c6405654f15a07a2301334 1 udp 2130706431 192.168.1.106 50342 typ host
a=candidate:e14221d1d547f61a5dfb3ba5ecb25c41 1 udp 1694498815 118.69.55.211 50342 typ srflx raddr 192.168.1.106 rport 50342
a=end-of-candidates
a=ice-ufrag:v7e4
a=ice-pwd:hlvgnGDIncSavgWZvpbgGI
a=fingerprint:sha-256 A2:59:BC:78:A1:AC:CA:D8:10:64:BE:39:56:EF:08:CF:A0:40:3F:12:51:9A:E8:FA:AB:BB:F4:A9:18:B2:A4:11
a=setup:actpass
Apply answer:
v=0
o=- 3768613065 3768613065 IN IP4 192.168.1.101
s=VideoRoom 1234
t=0 0
a=group:BUNDLE 0
a=msid-semantic: WMS janus
m=video 9 UDP/TLS/RTP/SAVPF 97
c=IN IP4 192.168.1.101
a=recvonly
a=mid:0
a=rtcp-mux
a=ice-ufrag:TkXI
a=ice-pwd:RGGUPol4QHtXf0mJmLrjCJ
a=ice-options:trickle
a=fingerprint:sha-256 AC:70:3C:28:19:F2:EE:87:46:EE:46:BC:80:8A:56:7B:FE:AF:75:80:FC:9C:D3:11:6D:61:AD:D9:48:5A:8A:4D
a=setup:active
a=rtpmap:97 VP8/90000
a=rtcp-fb:97 ccm fir
a=rtcp-fb:97 nack
a=rtcp-fb:97 nack pli
a=rtcp-fb:97 goog-remb
a=rtcp-fb:97 transport-cc
a=extmap:1 urn:ietf:params:rtp-hdrext:sdes:mid
a=candidate:1 1 udp 2013266431 192.168.1.101 39814 typ host
a=end-of-candidates
Subscribe:
v=0
o=- 1559622640473327 1 IN IP4 192.168.1.101
s=VideoRoom 1234
t=0 0
a=group:BUNDLE audio video
a=msid-semantic: WMS janus
m=audio 9 UDP/TLS/RTP/SAVPF 111
c=IN IP4 192.168.1.101
a=sendonly
a=mid:audio
a=rtcp-mux
a=ice-ufrag:XbSE
a=ice-pwd:UQk34IkY61TDmw0rRjLERd
a=ice-options:trickle
a=fingerprint:sha-256 AC:70:3C:28:19:F2:EE:87:46:EE:46:BC:80:8A:56:7B:FE:AF:75:80:FC:9C:D3:11:6D:61:AD:D9:48:5A:8A:4D
a=setup:actpass
a=rtpmap:111 opus/48000/2
a=ssrc:3748566445 cname:janus
a=ssrc:3748566445 msid:janus janusa0
a=ssrc:3748566445 mslabel:janus
a=ssrc:3748566445 label:janusa0
a=candidate:1 1 udp 2013266431 192.168.1.101 58954 typ host
a=end-of-candidates
m=video 9 UDP/TLS/RTP/SAVPF 96
c=IN IP4 192.168.1.101
a=sendonly
a=mid:video
a=rtcp-mux
a=ice-ufrag:XbSE
a=ice-pwd:UQk34IkY61TDmw0rRjLERd
a=ice-options:trickle
a=fingerprint:sha-256 AC:70:3C:28:19:F2:EE:87:46:EE:46:BC:80:8A:56:7B:FE:AF:75:80:FC:9C:D3:11:6D:61:AD:D9:48:5A:8A:4D
a=setup:actpass
a=rtpmap:96 VP8/90000
a=rtcp-fb:96 ccm fir
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtcp-fb:96 goog-remb
a=ssrc:333201977 cname:janus
a=ssrc:333201977 msid:janus janusv0
a=ssrc:333201977 mslabel:janus
a=ssrc:333201977 label:janusv0
a=candidate:1 1 udp 2013266431 192.168.1.101 58954 typ host
a=end-of-candidates
Create Answer:
v=0
o=- 3768613065 3768613065 IN IP4 0.0.0.0
s=-
t=0 0
a=group:BUNDLE audio video
a=msid-semantic:WMS *
m=audio 9 UDP/TLS/RTP/SAVPF 111
c=IN IP4 0.0.0.0
a=recvonly
a=mid:audio
a=msid:96b6d97a-0ada-4f90-9d75-ae3c7cbc14d0 b2382091-46c3-4ca4-9de2-4c424a1f32c0
a=rtcp:9 IN IP4 0.0.0.0
a=rtcp-mux
a=ssrc:2457074259 cname:{f52d8811-2b40-4e5d-818f-65525f6a05d2}
a=rtpmap:111 opus/48000/2
a=ice-ufrag:ED1v
a=ice-pwd:ErbuIgtrv8g8vYgREXFjJp
a=fingerprint:sha-256 A2:59:BC:78:A1:AC:CA:D8:10:64:BE:39:56:EF:08:CF:A0:40:3F:12:51:9A:E8:FA:AB:BB:F4:A9:18:B2:A4:11
a=setup:active
m=video 9 UDP/TLS/RTP/SAVPF 96
c=IN IP4 0.0.0.0
a=recvonly
a=mid:video
a=msid:96b6d97a-0ada-4f90-9d75-ae3c7cbc14d0 bd9344e7-c1b2-4c17-941e-c7859853305f
a=rtcp:9 IN IP4 0.0.0.0
a=rtcp-mux
a=ssrc:3592921475 cname:{f52d8811-2b40-4e5d-818f-65525f6a05d2}
a=rtpmap:96 VP8/90000
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtcp-fb:96 goog-remb
a=ice-ufrag:ED1v
a=ice-pwd:ErbuIgtrv8g8vYgREXFjJp
a=fingerprint:sha-256 A2:59:BC:78:A1:AC:CA:D8:10:64:BE:39:56:EF:08:CF:A0:40:3F:12:51:9A:E8:FA:AB:BB:F4:A9:18:B2:A4:11
a=setup:active
Track audio received
Track video received
Traceback (most recent call last):
File ".\janus.py", line 264, in <module>
run(pc=pc, player=player, recorder=recorder, room=args.room, session=session)
File "C:\Python37\lib\asyncio\base_events.py", line 573, in run_until_complete
return future.result()
File ".\janus.py", line 215, in run
await subscribe(i["id"])
File ".\janus.py", line 199, in subscribe
await pc.setLocalDescription(answer)
File "C:\Users\LAPTOP MSI\Documents\.env37\lib\site-packages\aiortc\rtcpeerconnection.py", line 618, in setLocalDescription
t._currentDirection = and_direction(t.direction, t._offerDirection)
File "C:\Users\LAPTOP MSI\Documents\.env37\lib\site-packages\aiortc\rtcpeerconnection.py", line 207, in and_direction
return sdp.DIRECTIONS[sdp.DIRECTIONS.index(a) & sdp.DIRECTIONS.index(b)]
ValueError: None is not in list
Task was destroyed but it is pending!
task: <Task pending coro=<MediaRecorder.__run_track() running at C:\Users\LAPTOP MSI\Documents\.env37\lib\site-packages\aiortc\contrib\media.py:361> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x000002C189788738>()]>>
Code
I just change run
function and add recorder = MediaRecorder(args.record_to)
to main
import os
import sys
# Fix not found ffmpeg dll
_ffmpeg = os.path.join(sys.prefix, 'share', 'ffpyplayer', 'ffmpeg', 'bin')
os.environ["PATH"] += os.pathsep + _ffmpeg
import argparse
import asyncio
import logging
import random
import string
import time
import aiohttp
from aiortc import RTCPeerConnection, RTCSessionDescription, VideoStreamTrack
from aiortc.contrib.media import MediaPlayer, MediaRecorder
def transaction_id():
return "".join(random.choice(string.ascii_letters) for x in range(12))
class JanusPlugin:
def __init__(self, session, url):
self._queue = asyncio.Queue()
self._session = session
self._url = url
async def send(self, payload):
message = {"janus": "message", "transaction": transaction_id()}
message.update(payload)
async with self._session._http.post(self._url, json=message) as response:
data = await response.json()
if data["janus"] == "success":
return data
elif data["janus"] == "error":
return data
elif data["janus"] == "ack":
pass
response = await self._queue.get()
self.has_request = False
assert response["transaction"] == message["transaction"]
return response
class JanusSession:
def __init__(self, url):
self._http = None
self._poll_task = None
self._plugins = {}
self._root_url = url
self._session_url = None
async def attach(self, plugin):
message = {"janus": "attach", "plugin": plugin, "transaction": transaction_id()}
async with self._http.post(self._session_url, json=message) as response:
data = await response.json()
assert data["janus"] == "success"
plugin_id = data["data"]["id"]
plugin = JanusPlugin(self, self._session_url + "/" + str(plugin_id))
self._plugins[plugin_id] = plugin
return plugin
async def create(self):
self._http = aiohttp.ClientSession()
message = {"janus": "create", "transaction": transaction_id()}
async with self._http.post(self._root_url, json=message) as response:
data = await response.json()
assert data["janus"] == "success"
session_id = data["data"]["id"]
self._session_url = self._root_url + "/" + str(session_id)
self._poll_task = asyncio.ensure_future(self._poll())
async def destroy(self):
if self._poll_task:
self._poll_task.cancel()
self._poll_task = None
if self._session_url:
message = {"janus": "destroy", "transaction": transaction_id()}
async with self._http.post(self._session_url, json=message) as response:
data = await response.json()
assert data["janus"] == "success"
self._session_url = None
if self._http:
await self._http.close()
self._http = None
async def _poll(self):
while True:
params = {"maxev": 1, "rid": int(time.time() * 1000)}
async with self._http.get(self._session_url, params=params) as response:
data = await response.json()
if data["janus"] == "event":
plugin = self._plugins.get(data["sender"], None)
if plugin:
await plugin._queue.put(data)
else:
print(data)
async def run(pc, player, recorder, room, session):
await session.create()
@pc.on("track")
async def on_track(track):
print("Track %s received" % track.kind)
if track.kind == 'video':
recorder.addTrack(track)
await recorder.start()
# configure media
media = {
"audio": False,
"video": True,
"videocodec": "vp8"
}
# if player and player.audio:
# pc.addTrack(player.audio)
# media["audio"] = True
pc.addTrack(player.video)
plugin = await session.attach("janus.plugin.videoroom")
response = await plugin.send({
"body": {
"request" : "listparticipants",
'room': room
},
})
publishers = response['plugindata']['data']['participants']
# join video room
response = await plugin.send(
{
"body": {
"display": "aiortc",
"ptype": "publisher",
"request": "join",
"room": room,
}
}
)
# send offer
await pc.setLocalDescription(await pc.createOffer())
request = {"request": "configure"}
request.update(media)
response = await plugin.send(
{
"body": request,
"jsep": {
"sdp": pc.localDescription.sdp,
"trickle": False,
"type": pc.localDescription.type,
},
}
)
print('Sdp send:')
print(pc.localDescription.sdp)
# apply answer
answer = RTCSessionDescription(
sdp=response["jsep"]["sdp"], type=response["jsep"]["type"]
)
await pc.setRemoteDescription(answer)
print('Apply answer:')
print(response["jsep"]["sdp"])
async def subscribe(sub_id):
plugin = await session.attach("janus.plugin.videoroom")
request = {
"request" : "join",
"ptype" : "subscriber",
"room" : room,
"feed" : sub_id,
# "private_id" : ''
}
response = await plugin.send(
{
"body": request,
}
)
await pc.setRemoteDescription(RTCSessionDescription(
sdp=response["jsep"]["sdp"], type=response["jsep"]["type"]
))
print('Subscribe:')
print(response["jsep"]["sdp"])
answer = await pc.createAnswer()
print('Create Answer:')
print(answer.sdp)
await pc.setLocalDescription(answer)
response = await plugin.send(
{
"body": {"request" : "start"},
"jsep": {
"sdp": pc.localDescription.sdp,
"trickle": False,
"type": pc.localDescription.type,
}
}
)
print(response)
if publishers != []:
for i in publishers:
await subscribe(i["id"])
print('Start call')
i = 0
while True:
await asyncio.sleep(1)
print('Leave call')
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Janus")
parser.add_argument("url", help="Janus root URL, e.g. http://localhost:8088/janus")
parser.add_argument(
"--room",
type=int,
default=1234,
help="The video room ID to join (default: 1234).",
),
parser.add_argument("--play-from", help="Read the media from a file and sent it."),
parser.add_argument("--verbose", "-v", action="count")
args = parser.parse_args()
if args.verbose:
logging.basicConfig(level=logging.DEBUG)
# create signaling and peer connection
session = JanusSession(args.url)
pc = RTCPeerConnection()
# create media source
if args.play_from:
player = MediaPlayer(args.play_from)
else:
player = None
recorder = MediaRecorder('test.mkv')
loop = asyncio.get_event_loop()
try:
loop.run_until_complete(
run(pc=pc, player=player, recorder=recorder, room=args.room, session=session)
)
except KeyboardInterrupt:
pass
finally:
loop.run_until_complete(pc.close())
loop.run_until_complete(session.destroy())
Issue Analytics
- State:
- Created 4 years ago
- Reactions:1
- Comments:10
Top Results From Across the Web
Janus Demos are not working: WebRtc Connection is stuck in ...
When I tried to add Janus gateway websocket URI in echo test, it returns an error that;. Error connecting to the Janus WebSockets...
Read more >RTCPeerConnection.setLocalDescription() - Web APIs | MDN
The RTCPeerConnection method setLocalDescription() changes the local description associated with the connection. This description specifies ...
Read more >Deploying Janus - Janus WebRTC Server
When you're going to deploy Janus (e.g., to try the demos we made available out-of-the-box), ... var server = "http://www.example.com:8088/janus";.
Read more >webRTC with Janus iOS swift - Stack Overflow
does webRTC handles the playing of audio streams? or we need to handle manually? your code seems to different comparing mine.. so not...
Read more >Janus: The Server-side WebRTC Jack of All Trades - YouTube
Speaker: Lorenzo Miniero, MeetechoWhile WebRTC was conceived as peer-to-peer, it's actually quite common to have one of the peers in the ...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
you can set debug level is DEBUG to show all log.
aoirtc
doesn’t create a same tag to track it (like aoirtc.sub_module). But you can find all of them by https://github.com/aiortc/aiortc/search?q=logging.getLogger&unscoped_q=logging.getLoggeryou are welcome