pyLiveMusic 0.2__tar.gz → 0.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pyLiveMusic might be problematic. Click here for more details.
- {pylivemusic-0.2 → pylivemusic-0.3}/PKG-INFO +1 -1
- {pylivemusic-0.2 → pylivemusic-0.3}/src/_core/_core_engine/_webrtc/backend.py +2 -8
- {pylivemusic-0.2 → pylivemusic-0.3}/src/_core/_core_engine/_webrtc/peer.py +18 -5
- pylivemusic-0.3/src/_core/_core_engine/_webrtc/signaling.py +109 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/pyLiveMusic/__init__.py +1 -1
- {pylivemusic-0.2 → pylivemusic-0.3}/src/pyLiveMusic.egg-info/PKG-INFO +1 -1
- pylivemusic-0.2/src/_core/_core_engine/_webrtc/signaling.py +0 -91
- {pylivemusic-0.2 → pylivemusic-0.3}/LICENSE +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/README.md +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/pyproject.toml +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/setup.cfg +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/_api/_errors.py +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/_api/_routes.py +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/_api/playback.py +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/_api/queue.py +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/_api/rooms.py +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/_core/_aiohttp/_app.py +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/_core/_aiohttp/_endpoints.py +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/_core/_core_engine/_webrtc/audio.py +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/_core/_core_func/_auth/_auth.py +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/_core/_core_func/_context.py +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/_core/_core_func/_data_config.py +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/_core/_core_func/_state/_data_state.py +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/_core/_database/memory/_repo.py +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/_core/_database/memory/_storage.py +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/_core/_database/mongo/_repo.py +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/_core/_database/mongo/_storage.py +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/_core/_database/redis/_repo.py +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/_core/_database/redis/_storage.py +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/_utils/_settings.py +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/pyLiveMusic/_logger.py +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/pyLiveMusic/_static/audio.html +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/pyLiveMusic/_static/audio.js +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/pyLiveMusic/_static/embed.html +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/pyLiveMusic/core/__init__.py +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/pyLiveMusic/core/client.py +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/pyLiveMusic/player/__init__.py +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/pyLiveMusic/player/playback.py +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/pyLiveMusic/player/queue.py +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/pyLiveMusic/player/room.py +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/pyLiveMusic/storage/__init__.py +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/pyLiveMusic/storage/memory.py +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/pyLiveMusic/storage/mongodb.py +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/pyLiveMusic/storage/redis.py +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/pyLiveMusic.egg-info/SOURCES.txt +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/pyLiveMusic.egg-info/dependency_links.txt +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/pyLiveMusic.egg-info/requires.txt +0 -0
- {pylivemusic-0.2 → pylivemusic-0.3}/src/pyLiveMusic.egg-info/top_level.txt +0 -0
|
@@ -352,27 +352,21 @@ class Room:
|
|
|
352
352
|
|
|
353
353
|
|
|
354
354
|
# WebRTC offer
|
|
355
|
-
|
|
356
355
|
async def offer(self, peer, sdp):
|
|
357
356
|
offer = RTCSessionDescription(
|
|
358
357
|
sdp=sdp,
|
|
359
358
|
type="offer",
|
|
360
359
|
)
|
|
361
360
|
|
|
362
|
-
await peer.connection.setRemoteDescription(
|
|
363
|
-
offer
|
|
364
|
-
)
|
|
361
|
+
await peer.connection.setRemoteDescription(offer)
|
|
365
362
|
|
|
366
363
|
await peer.set_remote_ready()
|
|
367
364
|
|
|
368
365
|
answer = await peer.connection.createAnswer()
|
|
369
366
|
|
|
370
|
-
await peer.connection.setLocalDescription(
|
|
371
|
-
answer
|
|
372
|
-
)
|
|
367
|
+
await peer.connection.setLocalDescription(answer)
|
|
373
368
|
|
|
374
369
|
return peer.connection.localDescription
|
|
375
|
-
|
|
376
370
|
# State
|
|
377
371
|
|
|
378
372
|
def state(self):
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
|
|
1
3
|
from aiortc import RTCPeerConnection
|
|
2
4
|
from aiortc.contrib.media import MediaRelay
|
|
3
|
-
from pyLiveMusic._logger import logs
|
|
4
5
|
|
|
6
|
+
from pyLiveMusic._logger import logs
|
|
5
7
|
from _utils._settings import QUALITY_BITRATES
|
|
6
8
|
|
|
7
9
|
|
|
8
10
|
class Peer:
|
|
9
11
|
def __init__(self, relay, audio_track, quality="high", on_close=None):
|
|
10
|
-
|
|
11
12
|
self.id = None
|
|
12
13
|
self.connection = RTCPeerConnection()
|
|
13
14
|
logs.info("[WEBRTC] Creating peer")
|
|
@@ -22,6 +23,9 @@ class Peer:
|
|
|
22
23
|
self._on_close = on_close
|
|
23
24
|
self._closed = False
|
|
24
25
|
|
|
26
|
+
self._remote_ready = asyncio.Event()
|
|
27
|
+
self._pending_candidates = []
|
|
28
|
+
|
|
25
29
|
@self.connection.on("connectionstatechange")
|
|
26
30
|
async def connection_state():
|
|
27
31
|
logs.info(
|
|
@@ -51,10 +55,20 @@ class Peer:
|
|
|
51
55
|
f"{self.connection.signalingState}"
|
|
52
56
|
)
|
|
53
57
|
|
|
58
|
+
async def add_candidate(self, candidate):
|
|
59
|
+
if not self._remote_ready.is_set():
|
|
60
|
+
self._pending_candidates.append(candidate)
|
|
61
|
+
return
|
|
54
62
|
|
|
55
|
-
async def add_ice_candidate(self, candidate):
|
|
56
63
|
await self.connection.addIceCandidate(candidate)
|
|
57
64
|
|
|
65
|
+
async def set_remote_ready(self):
|
|
66
|
+
self._remote_ready.set()
|
|
67
|
+
|
|
68
|
+
for candidate in self._pending_candidates:
|
|
69
|
+
await self.connection.addIceCandidate(candidate)
|
|
70
|
+
|
|
71
|
+
self._pending_candidates.clear()
|
|
58
72
|
|
|
59
73
|
async def set_quality(self, quality):
|
|
60
74
|
if quality not in QUALITY_BITRATES:
|
|
@@ -70,10 +84,9 @@ class Peer:
|
|
|
70
84
|
|
|
71
85
|
await self.sender.setParameters(parameters)
|
|
72
86
|
|
|
73
|
-
|
|
74
87
|
async def close(self):
|
|
75
88
|
if self._closed:
|
|
76
89
|
return
|
|
77
90
|
|
|
78
91
|
self._closed = True
|
|
79
|
-
await self.connection.close()
|
|
92
|
+
await self.connection.close()
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
from aiohttp import web
|
|
2
|
+
from aiortc.sdp import candidate_from_sdp
|
|
3
|
+
|
|
4
|
+
from pyLiveMusic._logger import logs
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
async def offer(request):
|
|
8
|
+
try:
|
|
9
|
+
room_id = request.match_info["room_id"]
|
|
10
|
+
|
|
11
|
+
room = request.app["state"].rooms.get(room_id)
|
|
12
|
+
|
|
13
|
+
if room is None:
|
|
14
|
+
raise web.HTTPNotFound(text="Room not found")
|
|
15
|
+
|
|
16
|
+
data = await request.json()
|
|
17
|
+
|
|
18
|
+
sdp = data.get("sdp")
|
|
19
|
+
|
|
20
|
+
if not sdp:
|
|
21
|
+
raise web.HTTPBadRequest(text="Missing SDP")
|
|
22
|
+
|
|
23
|
+
peer = await room.add_peer()
|
|
24
|
+
|
|
25
|
+
try:
|
|
26
|
+
answer = await room.offer(peer, sdp)
|
|
27
|
+
|
|
28
|
+
except Exception:
|
|
29
|
+
await room.remove_peer(peer)
|
|
30
|
+
raise
|
|
31
|
+
|
|
32
|
+
return web.json_response({
|
|
33
|
+
"peer_id": peer.id,
|
|
34
|
+
"type": answer.type,
|
|
35
|
+
"sdp": answer.sdp,
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
except web.HTTPException:
|
|
39
|
+
raise
|
|
40
|
+
|
|
41
|
+
except Exception:
|
|
42
|
+
logs.exception("[WEBRTC] Offer error")
|
|
43
|
+
raise
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
async def candidate(request):
|
|
47
|
+
try:
|
|
48
|
+
room_id = request.match_info["room_id"]
|
|
49
|
+
|
|
50
|
+
room = request.app["state"].rooms.get(room_id)
|
|
51
|
+
|
|
52
|
+
if room is None:
|
|
53
|
+
raise web.HTTPNotFound(
|
|
54
|
+
text="Room not found"
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
data = await request.json()
|
|
58
|
+
|
|
59
|
+
peer_id = data.get("peer_id")
|
|
60
|
+
|
|
61
|
+
if not peer_id:
|
|
62
|
+
raise web.HTTPBadRequest(
|
|
63
|
+
text="Missing peer_id"
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
peer = room.get_peer(peer_id)
|
|
67
|
+
|
|
68
|
+
if peer is None:
|
|
69
|
+
raise web.HTTPNotFound(
|
|
70
|
+
text="Peer not found"
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
value = data.get("candidate")
|
|
74
|
+
|
|
75
|
+
if not value:
|
|
76
|
+
return web.json_response({
|
|
77
|
+
"ok": True
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
candidate_sdp = value.get("candidate")
|
|
81
|
+
|
|
82
|
+
if not candidate_sdp:
|
|
83
|
+
return web.json_response({
|
|
84
|
+
"ok": True
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
try:
|
|
88
|
+
ice = candidate_from_sdp(candidate_sdp)
|
|
89
|
+
|
|
90
|
+
except Exception as error:
|
|
91
|
+
raise web.HTTPBadRequest(
|
|
92
|
+
text=f"Invalid ICE candidate: {error}"
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
ice.sdpMid = value.get("sdpMid")
|
|
96
|
+
ice.sdpMLineIndex = value.get("sdpMLineIndex")
|
|
97
|
+
|
|
98
|
+
await peer.add_candidate(ice)
|
|
99
|
+
|
|
100
|
+
return web.json_response({
|
|
101
|
+
"ok": True
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
except web.HTTPException:
|
|
105
|
+
raise
|
|
106
|
+
|
|
107
|
+
except Exception:
|
|
108
|
+
logs.exception("[WEBRTC] Candidate error")
|
|
109
|
+
raise
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
from aiohttp import web
|
|
2
|
-
from aiortc.sdp import candidate_from_sdp
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
async def offer(request):
|
|
6
|
-
room_id = request.match_info["room_id"]
|
|
7
|
-
room = request.app["state"].rooms.get(room_id)
|
|
8
|
-
|
|
9
|
-
if room is None:
|
|
10
|
-
raise web.HTTPNotFound(text="Room not found")
|
|
11
|
-
|
|
12
|
-
data = await request.json()
|
|
13
|
-
|
|
14
|
-
peer = await room.add_peer()
|
|
15
|
-
|
|
16
|
-
try:
|
|
17
|
-
answer = await room.offer(
|
|
18
|
-
peer,
|
|
19
|
-
data["sdp"]
|
|
20
|
-
)
|
|
21
|
-
|
|
22
|
-
except Exception:
|
|
23
|
-
await room.remove_peer(peer)
|
|
24
|
-
raise
|
|
25
|
-
|
|
26
|
-
return web.json_response({
|
|
27
|
-
"peer_id": peer.id,
|
|
28
|
-
"type": answer.type,
|
|
29
|
-
"sdp": answer.sdp,
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
async def candidate(request):
|
|
34
|
-
room_id = request.match_info["room_id"]
|
|
35
|
-
|
|
36
|
-
room = request.app["state"].rooms.get(room_id)
|
|
37
|
-
|
|
38
|
-
if room is None:
|
|
39
|
-
raise web.HTTPNotFound(
|
|
40
|
-
text="Room not found"
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
data = await request.json()
|
|
44
|
-
|
|
45
|
-
peer_id = data.get("peer_id")
|
|
46
|
-
|
|
47
|
-
if not peer_id:
|
|
48
|
-
raise web.HTTPBadRequest(
|
|
49
|
-
text="Missing peer_id"
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
peer = room.get_peer(peer_id)
|
|
53
|
-
|
|
54
|
-
if peer is None:
|
|
55
|
-
raise web.HTTPNotFound(
|
|
56
|
-
text="Peer not found"
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
value = data.get("candidate")
|
|
60
|
-
|
|
61
|
-
if not value:
|
|
62
|
-
return web.json_response({
|
|
63
|
-
"ok": True
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
candidate_sdp = value.get("candidate")
|
|
67
|
-
|
|
68
|
-
if not candidate_sdp:
|
|
69
|
-
return web.json_response({
|
|
70
|
-
"ok": True
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
try:
|
|
74
|
-
ice = candidate_from_sdp(
|
|
75
|
-
candidate_sdp
|
|
76
|
-
)
|
|
77
|
-
except Exception as error:
|
|
78
|
-
raise web.HTTPBadRequest(
|
|
79
|
-
text=f"Invalid ICE candidate: {error}"
|
|
80
|
-
)
|
|
81
|
-
|
|
82
|
-
ice.sdpMid = value.get("sdpMid")
|
|
83
|
-
ice.sdpMLineIndex = value.get(
|
|
84
|
-
"sdpMLineIndex"
|
|
85
|
-
)
|
|
86
|
-
|
|
87
|
-
await peer.add_candidate(ice)
|
|
88
|
-
|
|
89
|
-
return web.json_response({
|
|
90
|
-
"ok": True
|
|
91
|
-
})
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|