sora-sdk 2025.1.0.dev10__tar.gz → 2025.1.0.dev12__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 sora-sdk might be problematic. Click here for more details.
- {sora_sdk-2025.1.0.dev10/src/sora_sdk.egg-info → sora_sdk-2025.1.0.dev12}/PKG-INFO +1 -1
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/pyproject.toml +1 -1
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/src/sora_sdk/sora_sdk_ext.cpython-311-darwin.so +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12/src/sora_sdk.egg-info}/PKG-INFO +1 -1
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/tests/test_apple_video_toolbox.py +229 -87
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/tests/test_authz_simulcast.py +12 -5
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/tests/test_intel_vpl.py +27 -12
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/tests/test_nvidia_video_codec_sdk.py +133 -54
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/LICENSE +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/MANIFEST.in +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/NOTICE.md +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/README.md +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/buildbase.py +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/pypath.py +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/run.py +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/setup.cfg +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/setup.py +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/src/sora_sdk/__init__.py +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/src/sora_sdk/py.typed +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/src/sora_sdk/sora_sdk_ext.pyi +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/src/sora_sdk.egg-info/SOURCES.txt +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/src/sora_sdk.egg-info/dependency_links.txt +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/src/sora_sdk.egg-info/top_level.txt +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/tests/test_authz.py +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/tests/test_ca_cert.py +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/tests/test_capability.py +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/tests/test_codec_preference.py +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/tests/test_degradation_preference.py +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/tests/test_encoded_transform.py +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/tests/test_messaging.py +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/tests/test_messaging_header.py +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/tests/test_openh264.py +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/tests/test_opus.py +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/tests/test_re_offer_re_answer_sdp.py +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/tests/test_sendonly_recvonly.py +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/tests/test_signaling.py +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/tests/test_signaling_message.py +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/tests/test_signaling_notify.py +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/tests/test_simulcast.py +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/tests/test_sora_disconnect.py +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/tests/test_type_disconnect.py +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/tests/test_type_switched.py +0 -0
- {sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/tests/test_vad.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sora_sdk"
|
|
3
3
|
authors = [{ name = "Shiguredo Inc.", email = "contact+pypi@shiguredo.jp" }]
|
|
4
|
-
version = "2025.1.0.
|
|
4
|
+
version = "2025.1.0.dev12"
|
|
5
5
|
description = "WebRTC SFU Sora Python SDK"
|
|
6
6
|
readme = "README.md"
|
|
7
7
|
license = { file = "LICENSE" }
|
{sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/src/sora_sdk/sora_sdk_ext.cpython-311-darwin.so
RENAMED
|
Binary file
|
|
@@ -1,22 +1,21 @@
|
|
|
1
|
+
import os
|
|
1
2
|
import sys
|
|
2
3
|
import time
|
|
3
4
|
import uuid
|
|
4
5
|
|
|
6
|
+
import jwt
|
|
5
7
|
import pytest
|
|
6
8
|
from client import SoraClient, SoraRole
|
|
7
9
|
|
|
8
|
-
"""
|
|
9
|
-
GitHub Actions で Video Toolbox を送受信で利用しようとするとエラーになるので、
|
|
10
|
-
テストを sendonly のみに絞っている
|
|
11
|
-
"""
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
@pytest.mark.skipif(
|
|
12
|
+
os.environ.get("APPLE_VIDEO_TOOLBOX") is None, reason="Apple Video Toolbox でのみ実行する"
|
|
13
|
+
)
|
|
15
14
|
@pytest.mark.parametrize(
|
|
16
15
|
"video_codec_type",
|
|
17
16
|
["H264", "H265"],
|
|
18
17
|
)
|
|
19
|
-
def
|
|
18
|
+
def test_apple_video_toolbox_sendonly(setup, video_codec_type):
|
|
20
19
|
signaling_urls = setup.get("signaling_urls")
|
|
21
20
|
channel_id_prefix = setup.get("channel_id_prefix")
|
|
22
21
|
metadata = setup.get("metadata")
|
|
@@ -57,7 +56,73 @@ def test_macos_video_hwa_sendonly(setup, video_codec_type):
|
|
|
57
56
|
assert outbound_rtp_stats["packetsSent"] > 0
|
|
58
57
|
|
|
59
58
|
|
|
60
|
-
@pytest.mark.skipif(
|
|
59
|
+
@pytest.mark.skipif(
|
|
60
|
+
os.environ.get("APPLE_VIDEO_TOOLBOX") is None, reason="Apple Video Toolbox でのみ実行する"
|
|
61
|
+
)
|
|
62
|
+
@pytest.mark.parametrize(
|
|
63
|
+
"video_codec_type",
|
|
64
|
+
["H264", "H265"],
|
|
65
|
+
)
|
|
66
|
+
def test_apple_video_toolbox_sendonly_recvonly(setup, video_codec_type):
|
|
67
|
+
signaling_urls = setup.get("signaling_urls")
|
|
68
|
+
channel_id_prefix = setup.get("channel_id_prefix")
|
|
69
|
+
metadata = setup.get("metadata")
|
|
70
|
+
|
|
71
|
+
channel_id = f"{channel_id_prefix}_{__name__}_{sys._getframe().f_code.co_name}_{uuid.uuid4()}"
|
|
72
|
+
|
|
73
|
+
sendonly = SoraClient(
|
|
74
|
+
signaling_urls,
|
|
75
|
+
SoraRole.SENDONLY,
|
|
76
|
+
channel_id,
|
|
77
|
+
audio=False,
|
|
78
|
+
video=True,
|
|
79
|
+
video_codec_type=video_codec_type,
|
|
80
|
+
metadata=metadata,
|
|
81
|
+
)
|
|
82
|
+
sendonly.connect(fake_video=True)
|
|
83
|
+
|
|
84
|
+
recvonly = SoraClient(
|
|
85
|
+
signaling_urls,
|
|
86
|
+
SoraRole.RECVONLY,
|
|
87
|
+
channel_id,
|
|
88
|
+
metadata=metadata,
|
|
89
|
+
)
|
|
90
|
+
recvonly.connect()
|
|
91
|
+
|
|
92
|
+
time.sleep(5)
|
|
93
|
+
|
|
94
|
+
sendonly_stats = sendonly.get_stats()
|
|
95
|
+
recvonly_stats = recvonly.get_stats()
|
|
96
|
+
|
|
97
|
+
sendonly.disconnect()
|
|
98
|
+
recvonly.disconnect()
|
|
99
|
+
|
|
100
|
+
# codec が無かったら StopIteration 例外が上がる
|
|
101
|
+
sendonly_codec_stats = next(s for s in sendonly_stats if s.get("type") == "codec")
|
|
102
|
+
# 指定した video_codec_type が採用されているかどうか確認する
|
|
103
|
+
assert sendonly_codec_stats["mimeType"] == f"video/{video_codec_type}"
|
|
104
|
+
|
|
105
|
+
# outbound-rtp が無かったら StopIteration 例外が上がる
|
|
106
|
+
outbound_rtp_stats = next(s for s in sendonly_stats if s.get("type") == "outbound-rtp")
|
|
107
|
+
assert outbound_rtp_stats["encoderImplementation"] == "VideoToolbox"
|
|
108
|
+
assert outbound_rtp_stats["bytesSent"] > 0
|
|
109
|
+
assert outbound_rtp_stats["packetsSent"] > 0
|
|
110
|
+
|
|
111
|
+
# codec が無かったら StopIteration 例外が上がる
|
|
112
|
+
recvonly_codec_stats = next(s for s in recvonly_stats if s.get("type") == "codec")
|
|
113
|
+
# 指定した video_codec_type が採用されているかどうか確認する
|
|
114
|
+
assert recvonly_codec_stats["mimeType"] == f"video/{video_codec_type}"
|
|
115
|
+
|
|
116
|
+
# outbound-rtp が無かったら StopIteration 例外が上がる
|
|
117
|
+
inbound_rtp_stats = next(s for s in recvonly_stats if s.get("type") == "inbound-rtp")
|
|
118
|
+
assert inbound_rtp_stats["decoderImplementation"] == "VideoToolbox"
|
|
119
|
+
assert inbound_rtp_stats["bytesReceived"] > 0
|
|
120
|
+
assert inbound_rtp_stats["packetsReceived"] > 0
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
@pytest.mark.skipif(
|
|
124
|
+
os.environ.get("APPLE_VIDEO_TOOLBOX") is None, reason="Apple Video Toolbox でのみ実行する"
|
|
125
|
+
)
|
|
61
126
|
@pytest.mark.parametrize(
|
|
62
127
|
(
|
|
63
128
|
"video_codec_type",
|
|
@@ -89,7 +154,7 @@ def test_macos_video_hwa_sendonly(setup, video_codec_type):
|
|
|
89
154
|
("H265", "VideoToolbox", 200, 320, 180, 1),
|
|
90
155
|
],
|
|
91
156
|
)
|
|
92
|
-
def
|
|
157
|
+
def test_apple_video_toolbox_simulcast(
|
|
93
158
|
setup,
|
|
94
159
|
video_codec_type,
|
|
95
160
|
expected_implementation,
|
|
@@ -186,115 +251,192 @@ def test_macos_simulcast(
|
|
|
186
251
|
)
|
|
187
252
|
|
|
188
253
|
|
|
189
|
-
@pytest.mark.
|
|
190
|
-
|
|
254
|
+
@pytest.mark.skipif(
|
|
255
|
+
os.environ.get("APPLE_VIDEO_TOOLBOX") is None, reason="Apple Video Toolbox でのみ実行する"
|
|
256
|
+
)
|
|
257
|
+
@pytest.mark.parametrize(
|
|
258
|
+
(
|
|
259
|
+
"video_codec_type",
|
|
260
|
+
"encoder_implementation",
|
|
261
|
+
"video_bit_rate",
|
|
262
|
+
"video_width",
|
|
263
|
+
"video_height",
|
|
264
|
+
),
|
|
265
|
+
[
|
|
266
|
+
# どうやら scaleResolutionDownTo を指定すると規定されたテーブルのビットレートでは足りない模様
|
|
267
|
+
("H264", "VideoToolbox", 1000, 320, 180),
|
|
268
|
+
("H265", "VideoToolbox", 1000, 320, 180),
|
|
269
|
+
],
|
|
270
|
+
)
|
|
271
|
+
def test_apple_video_toolbox_simulcast_authz_scale_resolution_to(
|
|
272
|
+
setup,
|
|
273
|
+
video_codec_type,
|
|
274
|
+
encoder_implementation,
|
|
275
|
+
video_bit_rate,
|
|
276
|
+
video_width,
|
|
277
|
+
video_height,
|
|
278
|
+
):
|
|
191
279
|
signaling_urls = setup.get("signaling_urls")
|
|
192
280
|
channel_id_prefix = setup.get("channel_id_prefix")
|
|
193
|
-
|
|
281
|
+
secret = setup.get("secret")
|
|
194
282
|
|
|
195
283
|
channel_id = f"{channel_id_prefix}_{__name__}_{sys._getframe().f_code.co_name}_{uuid.uuid4()}"
|
|
196
284
|
|
|
285
|
+
simulcast_encodings = [
|
|
286
|
+
{
|
|
287
|
+
"rid": "r0",
|
|
288
|
+
"active": True,
|
|
289
|
+
"scaleResolutionDownTo": {"maxWidth": 320, "maxHeight": 180},
|
|
290
|
+
"scalabilityMode": "L1T1",
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
"rid": "r1",
|
|
294
|
+
"active": True,
|
|
295
|
+
"scaleResolutionDownTo": {"maxWidth": 320, "maxHeight": 180},
|
|
296
|
+
"scalabilityMode": "L1T1",
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
"rid": "r2",
|
|
300
|
+
"active": True,
|
|
301
|
+
"scaleResolutionDownTo": {"maxWidth": 320, "maxHeight": 180},
|
|
302
|
+
"scalabilityMode": "L1T1",
|
|
303
|
+
},
|
|
304
|
+
]
|
|
305
|
+
|
|
306
|
+
access_token = jwt.encode(
|
|
307
|
+
{
|
|
308
|
+
"channel_id": channel_id,
|
|
309
|
+
"video": True,
|
|
310
|
+
"video_codec_type": video_codec_type,
|
|
311
|
+
"video_bit_rate": video_bit_rate,
|
|
312
|
+
"simulcast": True,
|
|
313
|
+
"simulcast_encodings": simulcast_encodings,
|
|
314
|
+
# 現在時刻 + 300 秒 (5分)
|
|
315
|
+
"exp": int(time.time()) + 300,
|
|
316
|
+
},
|
|
317
|
+
secret,
|
|
318
|
+
algorithm="HS256",
|
|
319
|
+
)
|
|
320
|
+
|
|
197
321
|
sendonly = SoraClient(
|
|
198
322
|
signaling_urls,
|
|
199
323
|
SoraRole.SENDONLY,
|
|
200
324
|
channel_id,
|
|
201
325
|
audio=False,
|
|
202
326
|
video=True,
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
sendonly.connect()
|
|
207
|
-
|
|
208
|
-
recvonly = SoraClient(
|
|
209
|
-
signaling_urls,
|
|
210
|
-
SoraRole.RECVONLY,
|
|
211
|
-
channel_id,
|
|
212
|
-
metadata=metadata,
|
|
327
|
+
metadata={"access_token": access_token},
|
|
328
|
+
video_width=video_width,
|
|
329
|
+
video_height=video_height,
|
|
213
330
|
)
|
|
214
|
-
|
|
331
|
+
sendonly.connect(fake_video=True)
|
|
215
332
|
|
|
216
333
|
time.sleep(5)
|
|
217
334
|
|
|
218
|
-
|
|
219
|
-
|
|
335
|
+
# "type": "offer" の SDP で Simulcast があるかどうか
|
|
336
|
+
assert sendonly.offer_message is not None
|
|
337
|
+
assert sendonly.offer_message["sdp"] is not None
|
|
338
|
+
assert video_codec_type in sendonly.offer_message["sdp"]
|
|
339
|
+
assert "a=simulcast:recv r0;r1;r2" in sendonly.offer_message["sdp"]
|
|
220
340
|
|
|
221
|
-
sendonly.
|
|
222
|
-
|
|
341
|
+
assert "encodings" in sendonly.offer_message
|
|
342
|
+
assert len(sendonly.offer_message["encodings"]) == 3
|
|
223
343
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
assert sendonly_codec_stats["mimeType"] == "video/H264"
|
|
344
|
+
assert sendonly.offer_message["encodings"][0]["rid"] == simulcast_encodings[0]["rid"]
|
|
345
|
+
assert sendonly.offer_message["encodings"][1]["rid"] == simulcast_encodings[1]["rid"]
|
|
346
|
+
assert sendonly.offer_message["encodings"][2]["rid"] == simulcast_encodings[2]["rid"]
|
|
228
347
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
assert
|
|
232
|
-
assert outbound_rtp_stats["bytesSent"] > 0
|
|
233
|
-
assert outbound_rtp_stats["packetsSent"] > 0
|
|
348
|
+
assert sendonly.offer_message["encodings"][0]["active"] == simulcast_encodings[0]["active"]
|
|
349
|
+
assert sendonly.offer_message["encodings"][1]["active"] == simulcast_encodings[1]["active"]
|
|
350
|
+
assert sendonly.offer_message["encodings"][2]["active"] == simulcast_encodings[2]["active"]
|
|
234
351
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
assert
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
@pytest.mark.skip(reason="ローカルでは成功する")
|
|
248
|
-
def test_macos_h265_sendonly_recvonly(setup):
|
|
249
|
-
signaling_urls = setup.get("signaling_urls")
|
|
250
|
-
channel_id_prefix = setup.get("channel_id_prefix")
|
|
251
|
-
metadata = setup.get("metadata")
|
|
352
|
+
assert (
|
|
353
|
+
sendonly.offer_message["encodings"][0]["scaleResolutionDownTo"]["maxWidth"]
|
|
354
|
+
== simulcast_encodings[0]["scaleResolutionDownTo"]["maxWidth"]
|
|
355
|
+
)
|
|
356
|
+
assert (
|
|
357
|
+
sendonly.offer_message["encodings"][1]["scaleResolutionDownTo"]["maxWidth"]
|
|
358
|
+
== simulcast_encodings[1]["scaleResolutionDownTo"]["maxWidth"]
|
|
359
|
+
)
|
|
360
|
+
assert (
|
|
361
|
+
sendonly.offer_message["encodings"][2]["scaleResolutionDownTo"]["maxWidth"]
|
|
362
|
+
== simulcast_encodings[2]["scaleResolutionDownTo"]["maxWidth"]
|
|
363
|
+
)
|
|
252
364
|
|
|
253
|
-
|
|
365
|
+
assert (
|
|
366
|
+
sendonly.offer_message["encodings"][0]["scalabilityMode"]
|
|
367
|
+
== simulcast_encodings[0]["scalabilityMode"]
|
|
368
|
+
)
|
|
254
369
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
channel_id,
|
|
259
|
-
audio=False,
|
|
260
|
-
video=True,
|
|
261
|
-
video_codec_type="H265",
|
|
262
|
-
metadata=metadata,
|
|
370
|
+
assert (
|
|
371
|
+
sendonly.offer_message["encodings"][1]["scalabilityMode"]
|
|
372
|
+
== simulcast_encodings[1]["scalabilityMode"]
|
|
263
373
|
)
|
|
264
|
-
sendonly.connect()
|
|
265
374
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
channel_id,
|
|
270
|
-
metadata=metadata,
|
|
375
|
+
assert (
|
|
376
|
+
sendonly.offer_message["encodings"][2]["scalabilityMode"]
|
|
377
|
+
== simulcast_encodings[2]["scalabilityMode"]
|
|
271
378
|
)
|
|
272
|
-
recvonly.connect()
|
|
273
379
|
|
|
274
|
-
|
|
380
|
+
# "type": "answer" の SDP で Simulcast があるかどうか
|
|
381
|
+
assert sendonly.answer_message is not None
|
|
382
|
+
assert "sdp" in sendonly.answer_message
|
|
383
|
+
assert "a=simulcast:send r0;r1;r2" in sendonly.answer_message["sdp"]
|
|
275
384
|
|
|
276
385
|
sendonly_stats = sendonly.get_stats()
|
|
277
|
-
recvonly_stats = recvonly.get_stats()
|
|
278
|
-
|
|
279
386
|
sendonly.disconnect()
|
|
280
|
-
recvonly.disconnect()
|
|
281
387
|
|
|
282
388
|
# codec が無かったら StopIteration 例外が上がる
|
|
283
389
|
sendonly_codec_stats = next(s for s in sendonly_stats if s.get("type") == "codec")
|
|
284
|
-
assert sendonly_codec_stats["mimeType"] == "video/
|
|
390
|
+
assert sendonly_codec_stats["mimeType"] == f"video/{video_codec_type}"
|
|
285
391
|
|
|
286
|
-
# outbound-rtp
|
|
287
|
-
outbound_rtp_stats =
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
392
|
+
# 複数の outbound-rtp 統計情報を取得
|
|
393
|
+
outbound_rtp_stats = [
|
|
394
|
+
s for s in sendonly_stats if s.get("type") == "outbound-rtp" and s.get("kind") == "video"
|
|
395
|
+
]
|
|
396
|
+
# simulcast_count に関係なく統計情報はかならず 3 本出力される
|
|
397
|
+
# これは SDP で rid で ~r0 とかやる減るはず
|
|
398
|
+
assert len(outbound_rtp_stats) == 3
|
|
291
399
|
|
|
292
|
-
#
|
|
293
|
-
|
|
294
|
-
assert recvonly_codec_stats["mimeType"] == "video/H265"
|
|
400
|
+
# rid でソート
|
|
401
|
+
sorted_stats = sorted(outbound_rtp_stats, key=lambda x: x.get("rid", ""))
|
|
295
402
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
403
|
+
for i, s in enumerate(sorted_stats):
|
|
404
|
+
assert s["rid"] == f"r{i}"
|
|
405
|
+
assert s["kind"] == "video"
|
|
406
|
+
|
|
407
|
+
# VP8 の場合は scaleResolutionDownTo を指定すると SimulcastEncoderAdapter が無くなる
|
|
408
|
+
# TODO: 念のため他の挙動も確認すること
|
|
409
|
+
if video_codec_type == "VP9":
|
|
410
|
+
assert "SimulcastEncoderAdapter" in s["encoderImplementation"]
|
|
411
|
+
assert encoder_implementation in s["encoderImplementation"]
|
|
412
|
+
|
|
413
|
+
assert s["keyFramesEncoded"] > 0
|
|
414
|
+
assert s["bytesSent"] > 500
|
|
415
|
+
assert s["packetsSent"] > 10
|
|
416
|
+
|
|
417
|
+
assert s["frameWidth"] == 320
|
|
418
|
+
assert s["frameHeight"] == 176
|
|
419
|
+
|
|
420
|
+
# FIXME:これは libwebrtc 側の挙動を制御できず L1T2 になってしまう
|
|
421
|
+
scalability_mode = None
|
|
422
|
+
# FIXME: scalabilityMode がない場合がある
|
|
423
|
+
if "scalabilityMode" in s:
|
|
424
|
+
scalability_mode = s["scalabilityMode"]
|
|
425
|
+
assert s["scalabilityMode"] == "L1T2"
|
|
426
|
+
|
|
427
|
+
# targetBitrate が指定したビットレートの 90% 以上、100% 以下に収まることを確認
|
|
428
|
+
expected_bitrate = video_bit_rate * 1000
|
|
429
|
+
print(
|
|
430
|
+
s["rid"],
|
|
431
|
+
video_codec_type,
|
|
432
|
+
s["encoderImplementation"],
|
|
433
|
+
scalability_mode,
|
|
434
|
+
expected_bitrate,
|
|
435
|
+
s["targetBitrate"],
|
|
436
|
+
s["frameWidth"],
|
|
437
|
+
s["frameHeight"],
|
|
438
|
+
s["bytesSent"],
|
|
439
|
+
s["packetsSent"],
|
|
440
|
+
)
|
|
441
|
+
# 期待値の 20% 以上、100% 以下に収まることを確認
|
|
442
|
+
assert expected_bitrate * 0.2 <= s["targetBitrate"] <= expected_bitrate
|
|
@@ -7,6 +7,7 @@ import pytest
|
|
|
7
7
|
from client import SoraClient, SoraRole
|
|
8
8
|
|
|
9
9
|
|
|
10
|
+
@pytest.mark.skipif(sys.platform == "darwin", reason="Apple では SW コーデックは動作させない")
|
|
10
11
|
@pytest.mark.parametrize(
|
|
11
12
|
(
|
|
12
13
|
"video_codec_type",
|
|
@@ -91,7 +92,6 @@ def test_simulcast_authz_scale_resolution_to(
|
|
|
91
92
|
assert sendonly.offer_message["sdp"] is not None
|
|
92
93
|
assert video_codec_type in sendonly.offer_message["sdp"]
|
|
93
94
|
assert "a=simulcast:recv r0;r1;r2" in sendonly.offer_message["sdp"]
|
|
94
|
-
sendonly_stats = sendonly.get_stats()
|
|
95
95
|
|
|
96
96
|
assert "encodings" in sendonly.offer_message
|
|
97
97
|
assert len(sendonly.offer_message["encodings"]) == 3
|
|
@@ -121,22 +121,25 @@ def test_simulcast_authz_scale_resolution_to(
|
|
|
121
121
|
sendonly.offer_message["encodings"][0]["scalabilityMode"]
|
|
122
122
|
== simulcast_encodings[0]["scalabilityMode"]
|
|
123
123
|
)
|
|
124
|
+
|
|
124
125
|
assert (
|
|
125
126
|
sendonly.offer_message["encodings"][1]["scalabilityMode"]
|
|
126
127
|
== simulcast_encodings[1]["scalabilityMode"]
|
|
127
128
|
)
|
|
129
|
+
|
|
128
130
|
assert (
|
|
129
131
|
sendonly.offer_message["encodings"][2]["scalabilityMode"]
|
|
130
132
|
== simulcast_encodings[2]["scalabilityMode"]
|
|
131
133
|
)
|
|
132
134
|
|
|
133
|
-
sendonly.disconnect()
|
|
134
|
-
|
|
135
135
|
# "type": "answer" の SDP で Simulcast があるかどうか
|
|
136
136
|
assert sendonly.answer_message is not None
|
|
137
137
|
assert "sdp" in sendonly.answer_message
|
|
138
138
|
assert "a=simulcast:send r0;r1;r2" in sendonly.answer_message["sdp"]
|
|
139
139
|
|
|
140
|
+
sendonly_stats = sendonly.get_stats()
|
|
141
|
+
sendonly.disconnect()
|
|
142
|
+
|
|
140
143
|
# codec が無かったら StopIteration 例外が上がる
|
|
141
144
|
sendonly_codec_stats = next(s for s in sendonly_stats if s.get("type") == "codec")
|
|
142
145
|
assert sendonly_codec_stats["mimeType"] == f"video/{video_codec_type}"
|
|
@@ -170,7 +173,11 @@ def test_simulcast_authz_scale_resolution_to(
|
|
|
170
173
|
assert s["frameHeight"] == 352
|
|
171
174
|
|
|
172
175
|
# FIXME:これは libwebrtc 側の挙動を制御できず L1T2 になってしまう
|
|
173
|
-
|
|
176
|
+
scalability_mode = None
|
|
177
|
+
# FIXME: scalabilityMode がない場合がある
|
|
178
|
+
if "scalabilityMode" in s:
|
|
179
|
+
scalability_mode = s["scalabilityMode"]
|
|
180
|
+
assert s["scalabilityMode"] == "L1T2"
|
|
174
181
|
|
|
175
182
|
# targetBitrate が指定したビットレートの 90% 以上、100% 以下に収まることを確認
|
|
176
183
|
expected_bitrate = video_bit_rate * 1000
|
|
@@ -178,7 +185,7 @@ def test_simulcast_authz_scale_resolution_to(
|
|
|
178
185
|
s["rid"],
|
|
179
186
|
video_codec_type,
|
|
180
187
|
s["encoderImplementation"],
|
|
181
|
-
|
|
188
|
+
scalability_mode,
|
|
182
189
|
expected_bitrate,
|
|
183
190
|
s["targetBitrate"],
|
|
184
191
|
s["frameWidth"],
|
|
@@ -4,7 +4,12 @@ import time
|
|
|
4
4
|
import uuid
|
|
5
5
|
|
|
6
6
|
import pytest
|
|
7
|
-
from client import
|
|
7
|
+
from client import (
|
|
8
|
+
SoraClient,
|
|
9
|
+
SoraRole,
|
|
10
|
+
codec_type_string_to_codec_type,
|
|
11
|
+
is_codec_supported,
|
|
12
|
+
)
|
|
8
13
|
|
|
9
14
|
from sora_sdk import (
|
|
10
15
|
SoraVideoCodecImplementation,
|
|
@@ -41,8 +46,10 @@ def test_intel_vpl_available(setup):
|
|
|
41
46
|
# Sora Python SDK では VPL VP9 Encoder が正常に動作しないため無効
|
|
42
47
|
assert c.encoder is False
|
|
43
48
|
case SoraVideoCodecType.AV1:
|
|
44
|
-
|
|
45
|
-
assert c.
|
|
49
|
+
# チップによって対応指定ないものがあるので判断しない
|
|
50
|
+
# assert c.decoder is True
|
|
51
|
+
# assert c.encoder is True
|
|
52
|
+
pass
|
|
46
53
|
case SoraVideoCodecType.H264:
|
|
47
54
|
assert c.decoder is True
|
|
48
55
|
assert c.encoder is True
|
|
@@ -76,6 +83,9 @@ def test_intel_vpl_sendonly(
|
|
|
76
83
|
expected_codec_implementation,
|
|
77
84
|
preference_codec_implementation,
|
|
78
85
|
):
|
|
86
|
+
if not is_codec_supported(video_codec_type, SoraVideoCodecImplementation.INTEL_VPL):
|
|
87
|
+
pytest.skip(f"このチップでは {video_codec_type} がサポートされていません")
|
|
88
|
+
|
|
79
89
|
signaling_urls = setup.get("signaling_urls")
|
|
80
90
|
channel_id_prefix = setup.get("channel_id_prefix")
|
|
81
91
|
metadata = setup.get("metadata")
|
|
@@ -184,6 +194,9 @@ def test_intel_vpl_simulcast(
|
|
|
184
194
|
video_height,
|
|
185
195
|
simulcast_count,
|
|
186
196
|
):
|
|
197
|
+
if not is_codec_supported(video_codec_type, SoraVideoCodecImplementation.INTEL_VPL):
|
|
198
|
+
pytest.skip(f"このチップでは {video_codec_type} がサポートされていません")
|
|
199
|
+
|
|
187
200
|
signaling_urls = setup.get("signaling_urls")
|
|
188
201
|
channel_id_prefix = setup.get("channel_id_prefix")
|
|
189
202
|
metadata = setup.get("metadata")
|
|
@@ -205,15 +218,7 @@ def test_intel_vpl_simulcast(
|
|
|
205
218
|
video_codec_preference=SoraVideoCodecPreference(
|
|
206
219
|
codecs=[
|
|
207
220
|
SoraVideoCodecPreference.Codec(
|
|
208
|
-
type=
|
|
209
|
-
encoder=SoraVideoCodecImplementation.INTEL_VPL,
|
|
210
|
-
),
|
|
211
|
-
SoraVideoCodecPreference.Codec(
|
|
212
|
-
type=SoraVideoCodecType.H264,
|
|
213
|
-
encoder=SoraVideoCodecImplementation.INTEL_VPL,
|
|
214
|
-
),
|
|
215
|
-
SoraVideoCodecPreference.Codec(
|
|
216
|
-
type=SoraVideoCodecType.H265,
|
|
221
|
+
type=codec_type_string_to_codec_type(video_codec_type),
|
|
217
222
|
encoder=SoraVideoCodecImplementation.INTEL_VPL,
|
|
218
223
|
),
|
|
219
224
|
]
|
|
@@ -315,6 +320,9 @@ def test_intel_vpl_sendonly_recvonly(
|
|
|
315
320
|
expected_codec_implementation,
|
|
316
321
|
preference_codec_implementation,
|
|
317
322
|
):
|
|
323
|
+
if not is_codec_supported(video_codec_type, SoraVideoCodecImplementation.INTEL_VPL):
|
|
324
|
+
pytest.skip(f"このチップでは {video_codec_type} がサポートされていません")
|
|
325
|
+
|
|
318
326
|
signaling_urls = setup.get("signaling_urls")
|
|
319
327
|
channel_id_prefix = setup.get("channel_id_prefix")
|
|
320
328
|
metadata = setup.get("metadata")
|
|
@@ -579,6 +587,9 @@ def test_intel_vpl_vp9_sendonly_recvonly(setup):
|
|
|
579
587
|
def test_intel_vpl_av1_mini_resolution(
|
|
580
588
|
setup, video_codec_type, expected_implementation, video_bit_rate, video_width, video_height
|
|
581
589
|
):
|
|
590
|
+
if not is_codec_supported(video_codec_type, SoraVideoCodecImplementation.INTEL_VPL):
|
|
591
|
+
pytest.skip(f"このチップでは {video_codec_type} がサポートされていません")
|
|
592
|
+
|
|
582
593
|
signaling_urls = setup.get("signaling_urls")
|
|
583
594
|
channel_id_prefix = setup.get("channel_id_prefix")
|
|
584
595
|
metadata = setup.get("metadata")
|
|
@@ -689,6 +700,10 @@ def test_intel_vpl_sendonly_recvonly_sw_hw(
|
|
|
689
700
|
- 送信はソフトウェアだけど、受信はハードウェアでやる
|
|
690
701
|
- 送信はハードウェアだけど、受信はソフトウェアでやる
|
|
691
702
|
"""
|
|
703
|
+
|
|
704
|
+
if not is_codec_supported(video_codec_type, SoraVideoCodecImplementation.INTEL_VPL):
|
|
705
|
+
pytest.skip(f"このチップでは {video_codec_type} がサポートされていません")
|
|
706
|
+
|
|
692
707
|
signaling_urls = setup.get("signaling_urls")
|
|
693
708
|
channel_id_prefix = setup.get("channel_id_prefix")
|
|
694
709
|
metadata = setup.get("metadata")
|
|
@@ -4,9 +4,18 @@ import time
|
|
|
4
4
|
import uuid
|
|
5
5
|
|
|
6
6
|
import pytest
|
|
7
|
-
from client import
|
|
7
|
+
from client import (
|
|
8
|
+
SoraClient,
|
|
9
|
+
SoraRole,
|
|
10
|
+
codec_type_string_to_codec_type,
|
|
11
|
+
is_codec_supported,
|
|
12
|
+
)
|
|
8
13
|
|
|
9
|
-
from sora_sdk import
|
|
14
|
+
from sora_sdk import (
|
|
15
|
+
SoraVideoCodecImplementation,
|
|
16
|
+
SoraVideoCodecPreference,
|
|
17
|
+
SoraVideoCodecType,
|
|
18
|
+
)
|
|
10
19
|
|
|
11
20
|
|
|
12
21
|
# @pytest.mark.skip()
|
|
@@ -19,13 +28,17 @@ from sora_sdk import SoraVideoCodecImplementation, SoraVideoCodecPreference, Sor
|
|
|
19
28
|
"expected_implementation",
|
|
20
29
|
),
|
|
21
30
|
[
|
|
22
|
-
("VP9", "NvCodec"),
|
|
23
31
|
("AV1", "NvCodec"),
|
|
24
32
|
("H264", "NvCodec"),
|
|
25
33
|
("H265", "NvCodec"),
|
|
26
34
|
],
|
|
27
35
|
)
|
|
28
|
-
def
|
|
36
|
+
def test_nvidia_codec_sdk_sendonly(setup, video_codec_type, expected_implementation):
|
|
37
|
+
if not is_codec_supported(
|
|
38
|
+
video_codec_type, SoraVideoCodecImplementation.NVIDIA_VIDEO_CODEC_SDK
|
|
39
|
+
):
|
|
40
|
+
pytest.skip(f"このチップでは {video_codec_type} がサポートされていません")
|
|
41
|
+
|
|
29
42
|
signaling_urls = setup.get("signaling_urls")
|
|
30
43
|
channel_id_prefix = setup.get("channel_id_prefix")
|
|
31
44
|
metadata = setup.get("metadata")
|
|
@@ -43,15 +56,7 @@ def test_intel_vpl_sendonly(setup, video_codec_type, expected_implementation):
|
|
|
43
56
|
video_codec_preference=SoraVideoCodecPreference(
|
|
44
57
|
codecs=[
|
|
45
58
|
SoraVideoCodecPreference.Codec(
|
|
46
|
-
type=
|
|
47
|
-
encoder=SoraVideoCodecImplementation.NVIDIA_VIDEO_CODEC_SDK,
|
|
48
|
-
),
|
|
49
|
-
SoraVideoCodecPreference.Codec(
|
|
50
|
-
type=SoraVideoCodecType.H264,
|
|
51
|
-
encoder=SoraVideoCodecImplementation.NVIDIA_VIDEO_CODEC_SDK,
|
|
52
|
-
),
|
|
53
|
-
SoraVideoCodecPreference.Codec(
|
|
54
|
-
type=SoraVideoCodecType.H265,
|
|
59
|
+
type=codec_type_string_to_codec_type(video_codec_type),
|
|
55
60
|
encoder=SoraVideoCodecImplementation.NVIDIA_VIDEO_CODEC_SDK,
|
|
56
61
|
),
|
|
57
62
|
]
|
|
@@ -108,34 +113,32 @@ def test_intel_vpl_sendonly(setup, video_codec_type, expected_implementation):
|
|
|
108
113
|
# FIXME: AV1 では、解像度が一定数より低くなる場合、エラーになるのでコメントアウトしている
|
|
109
114
|
[
|
|
110
115
|
# 1080p
|
|
111
|
-
("
|
|
116
|
+
("AV1", "NvCodec", 5000, 1920, 1080, 3),
|
|
112
117
|
("H264", "NvCodec", 5000, 1920, 1080, 3),
|
|
113
118
|
("H265", "NvCodec", 5000, 1920, 1080, 3),
|
|
114
119
|
# 720p
|
|
115
|
-
("
|
|
120
|
+
("AV1", "NvCodec", 2500, 1280, 720, 3),
|
|
116
121
|
("H264", "NvCodec", 2500, 1280, 720, 3),
|
|
117
122
|
("H265", "NvCodec", 2500, 1280, 720, 3),
|
|
118
123
|
# 540p
|
|
119
|
-
("
|
|
124
|
+
("AV1", "NvCodec", 1200, 960, 540, 3),
|
|
120
125
|
("H264", "NvCodec", 1200, 960, 540, 3),
|
|
121
126
|
("H265", "NvCodec", 1200, 960, 540, 3),
|
|
122
127
|
# 360p
|
|
123
|
-
("
|
|
128
|
+
("AV1", "NvCodec", 700, 640, 360, 2),
|
|
124
129
|
("H264", "NvCodec", 700, 640, 360, 2),
|
|
125
130
|
("H265", "NvCodec", 700, 640, 360, 2),
|
|
126
131
|
# 270p
|
|
127
|
-
("
|
|
128
|
-
("
|
|
129
|
-
("H265", "NvCodec", 450, 480, 270, 2),
|
|
132
|
+
# ("H264", "NvCodec", 450, 480, 270, 2),
|
|
133
|
+
# ("H265", "NvCodec", 450, 480, 270, 2),
|
|
130
134
|
# 180p
|
|
131
|
-
("
|
|
132
|
-
("
|
|
133
|
-
("H265", "NvCodec", 142, 320, 180, 1),
|
|
135
|
+
# ("H264", "NvCodec", 200, 320, 180, 1),
|
|
136
|
+
# ("H265", "NvCodec", 142, 320, 180, 1),
|
|
134
137
|
# 135p
|
|
135
|
-
("H265", "NvCodec", 101, 240, 135, 1),
|
|
138
|
+
# ("H265", "NvCodec", 101, 240, 135, 1),
|
|
136
139
|
],
|
|
137
140
|
)
|
|
138
|
-
def
|
|
141
|
+
def test_nvidia_codec_sdk_simulcast(
|
|
139
142
|
setup,
|
|
140
143
|
video_codec_type,
|
|
141
144
|
expected_implementation,
|
|
@@ -144,6 +147,11 @@ def test_intel_vpl_simulcast(
|
|
|
144
147
|
video_height,
|
|
145
148
|
simulcast_count,
|
|
146
149
|
):
|
|
150
|
+
if not is_codec_supported(
|
|
151
|
+
video_codec_type, SoraVideoCodecImplementation.NVIDIA_VIDEO_CODEC_SDK
|
|
152
|
+
):
|
|
153
|
+
pytest.skip(f"このチップでは {video_codec_type} がサポートされていません")
|
|
154
|
+
|
|
147
155
|
signaling_urls = setup.get("signaling_urls")
|
|
148
156
|
channel_id_prefix = setup.get("channel_id_prefix")
|
|
149
157
|
metadata = setup.get("metadata")
|
|
@@ -165,15 +173,7 @@ def test_intel_vpl_simulcast(
|
|
|
165
173
|
video_codec_preference=SoraVideoCodecPreference(
|
|
166
174
|
codecs=[
|
|
167
175
|
SoraVideoCodecPreference.Codec(
|
|
168
|
-
type=
|
|
169
|
-
encoder=SoraVideoCodecImplementation.NVIDIA_VIDEO_CODEC_SDK,
|
|
170
|
-
),
|
|
171
|
-
SoraVideoCodecPreference.Codec(
|
|
172
|
-
type=SoraVideoCodecType.H264,
|
|
173
|
-
encoder=SoraVideoCodecImplementation.NVIDIA_VIDEO_CODEC_SDK,
|
|
174
|
-
),
|
|
175
|
-
SoraVideoCodecPreference.Codec(
|
|
176
|
-
type=SoraVideoCodecType.H265,
|
|
176
|
+
type=codec_type_string_to_codec_type(video_codec_type),
|
|
177
177
|
encoder=SoraVideoCodecImplementation.NVIDIA_VIDEO_CODEC_SDK,
|
|
178
178
|
),
|
|
179
179
|
]
|
|
@@ -258,13 +258,17 @@ def test_intel_vpl_simulcast(
|
|
|
258
258
|
"expected_implementation",
|
|
259
259
|
),
|
|
260
260
|
[
|
|
261
|
-
("VP9", "NvCodec"),
|
|
262
261
|
("AV1", "NvCodec"),
|
|
263
262
|
("H264", "NvCodec"),
|
|
264
263
|
("H265", "NvCodec"),
|
|
265
264
|
],
|
|
266
265
|
)
|
|
267
|
-
def
|
|
266
|
+
def test_nvidia_codec_sdk_sendonly_recvonly(setup, video_codec_type, expected_implementation):
|
|
267
|
+
if not is_codec_supported(
|
|
268
|
+
video_codec_type, SoraVideoCodecImplementation.NVIDIA_VIDEO_CODEC_SDK
|
|
269
|
+
):
|
|
270
|
+
pytest.skip(f"このチップでは {video_codec_type} がサポートされていません")
|
|
271
|
+
|
|
268
272
|
signaling_urls = setup.get("signaling_urls")
|
|
269
273
|
channel_id_prefix = setup.get("channel_id_prefix")
|
|
270
274
|
metadata = setup.get("metadata")
|
|
@@ -282,15 +286,7 @@ def test_intel_vpl_sendonly_recvonly(setup, video_codec_type, expected_implement
|
|
|
282
286
|
video_codec_preference=SoraVideoCodecPreference(
|
|
283
287
|
codecs=[
|
|
284
288
|
SoraVideoCodecPreference.Codec(
|
|
285
|
-
type=
|
|
286
|
-
encoder=SoraVideoCodecImplementation.NVIDIA_VIDEO_CODEC_SDK,
|
|
287
|
-
),
|
|
288
|
-
SoraVideoCodecPreference.Codec(
|
|
289
|
-
type=SoraVideoCodecType.H264,
|
|
290
|
-
encoder=SoraVideoCodecImplementation.NVIDIA_VIDEO_CODEC_SDK,
|
|
291
|
-
),
|
|
292
|
-
SoraVideoCodecPreference.Codec(
|
|
293
|
-
type=SoraVideoCodecType.H265,
|
|
289
|
+
type=codec_type_string_to_codec_type(video_codec_type),
|
|
294
290
|
encoder=SoraVideoCodecImplementation.NVIDIA_VIDEO_CODEC_SDK,
|
|
295
291
|
),
|
|
296
292
|
]
|
|
@@ -306,15 +302,7 @@ def test_intel_vpl_sendonly_recvonly(setup, video_codec_type, expected_implement
|
|
|
306
302
|
video_codec_preference=SoraVideoCodecPreference(
|
|
307
303
|
codecs=[
|
|
308
304
|
SoraVideoCodecPreference.Codec(
|
|
309
|
-
type=
|
|
310
|
-
decoder=SoraVideoCodecImplementation.NVIDIA_VIDEO_CODEC_SDK,
|
|
311
|
-
),
|
|
312
|
-
SoraVideoCodecPreference.Codec(
|
|
313
|
-
type=SoraVideoCodecType.H264,
|
|
314
|
-
decoder=SoraVideoCodecImplementation.NVIDIA_VIDEO_CODEC_SDK,
|
|
315
|
-
),
|
|
316
|
-
SoraVideoCodecPreference.Codec(
|
|
317
|
-
type=SoraVideoCodecType.H265,
|
|
305
|
+
type=codec_type_string_to_codec_type(video_codec_type),
|
|
318
306
|
decoder=SoraVideoCodecImplementation.NVIDIA_VIDEO_CODEC_SDK,
|
|
319
307
|
),
|
|
320
308
|
]
|
|
@@ -361,3 +349,94 @@ def test_intel_vpl_sendonly_recvonly(setup, video_codec_type, expected_implement
|
|
|
361
349
|
assert inbound_rtp_stats["decoderImplementation"] == expected_implementation
|
|
362
350
|
assert inbound_rtp_stats["bytesReceived"] > 0
|
|
363
351
|
assert inbound_rtp_stats["packetsReceived"] > 0
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
@pytest.mark.skipif(
|
|
355
|
+
os.environ.get("NVIDIA_VIDEO_SDK") is None, reason="NVIDIA Video Codec SDK でのみ実行する"
|
|
356
|
+
)
|
|
357
|
+
def test_nvidia_codec_sdk_vp9_hwa_decoder(setup):
|
|
358
|
+
"""
|
|
359
|
+
NVIDIA Video Codec SDK VP9 はデコーダーは利用できるので、そのテスト
|
|
360
|
+
"""
|
|
361
|
+
signaling_urls = setup.get("signaling_urls")
|
|
362
|
+
channel_id_prefix = setup.get("channel_id_prefix")
|
|
363
|
+
metadata = setup.get("metadata")
|
|
364
|
+
|
|
365
|
+
channel_id = f"{channel_id_prefix}_{__name__}_{sys._getframe().f_code.co_name}_{uuid.uuid4()}"
|
|
366
|
+
|
|
367
|
+
sendonly = SoraClient(
|
|
368
|
+
signaling_urls,
|
|
369
|
+
SoraRole.SENDONLY,
|
|
370
|
+
channel_id,
|
|
371
|
+
audio=False,
|
|
372
|
+
video=True,
|
|
373
|
+
video_codec_type="VP9",
|
|
374
|
+
metadata=metadata,
|
|
375
|
+
video_codec_preference=SoraVideoCodecPreference(
|
|
376
|
+
codecs=[
|
|
377
|
+
SoraVideoCodecPreference.Codec(
|
|
378
|
+
type=SoraVideoCodecType.VP9,
|
|
379
|
+
# NVIDIA Video Codec SDK で VP9 Encoder は搭載していないので INTERNAL を指定
|
|
380
|
+
encoder=SoraVideoCodecImplementation.INTERNAL,
|
|
381
|
+
),
|
|
382
|
+
]
|
|
383
|
+
),
|
|
384
|
+
)
|
|
385
|
+
sendonly.connect(fake_video=True)
|
|
386
|
+
|
|
387
|
+
recvonly = SoraClient(
|
|
388
|
+
signaling_urls,
|
|
389
|
+
SoraRole.RECVONLY,
|
|
390
|
+
channel_id,
|
|
391
|
+
metadata=metadata,
|
|
392
|
+
video_codec_preference=SoraVideoCodecPreference(
|
|
393
|
+
codecs=[
|
|
394
|
+
SoraVideoCodecPreference.Codec(
|
|
395
|
+
type=SoraVideoCodecType.VP9,
|
|
396
|
+
# NVIDIA Video Codec SDK で VP9 Decoder は搭載しているので NVIDIA_VIDEO_CODEC_SDK を指定
|
|
397
|
+
decoder=SoraVideoCodecImplementation.NVIDIA_VIDEO_CODEC_SDK,
|
|
398
|
+
),
|
|
399
|
+
]
|
|
400
|
+
),
|
|
401
|
+
)
|
|
402
|
+
recvonly.connect()
|
|
403
|
+
|
|
404
|
+
time.sleep(5)
|
|
405
|
+
|
|
406
|
+
sendonly_stats = sendonly.get_stats()
|
|
407
|
+
recvonly_stats = recvonly.get_stats()
|
|
408
|
+
|
|
409
|
+
sendonly.disconnect()
|
|
410
|
+
recvonly.disconnect()
|
|
411
|
+
|
|
412
|
+
# offer の sdp に video_codec_type が含まれているかどうかを確認している
|
|
413
|
+
assert sendonly.offer_message is not None
|
|
414
|
+
assert "sdp" in sendonly.offer_message
|
|
415
|
+
assert "VP9" in sendonly.offer_message["sdp"]
|
|
416
|
+
|
|
417
|
+
# answer の sdp に video_codec_type が含まれているかどうかを確認している
|
|
418
|
+
assert sendonly.answer_message is not None
|
|
419
|
+
assert "sdp" in sendonly.answer_message
|
|
420
|
+
assert "VP9" in sendonly.answer_message["sdp"]
|
|
421
|
+
|
|
422
|
+
# codec が無かったら StopIteration 例外が上がる
|
|
423
|
+
sendonly_codec_stats = next(s for s in sendonly_stats if s.get("type") == "codec")
|
|
424
|
+
# VP9 が採用されているかどうか確認する
|
|
425
|
+
assert sendonly_codec_stats["mimeType"] == "video/VP9"
|
|
426
|
+
|
|
427
|
+
# outbound-rtp が無かったら StopIteration 例外が上がる
|
|
428
|
+
outbound_rtp_stats = next(s for s in sendonly_stats if s.get("type") == "outbound-rtp")
|
|
429
|
+
assert outbound_rtp_stats["encoderImplementation"] == "libvpx"
|
|
430
|
+
assert outbound_rtp_stats["bytesSent"] > 0
|
|
431
|
+
assert outbound_rtp_stats["packetsSent"] > 0
|
|
432
|
+
|
|
433
|
+
# codec が無かったら StopIteration 例外が上がる
|
|
434
|
+
recvonly_codec_stats = next(s for s in recvonly_stats if s.get("type") == "codec")
|
|
435
|
+
# VP9 が採用されているかどうか確認する
|
|
436
|
+
assert recvonly_codec_stats["mimeType"] == "video/VP9"
|
|
437
|
+
|
|
438
|
+
# inbound-rtp が無かったら StopIteration 例外が上がる
|
|
439
|
+
inbound_rtp_stats = next(s for s in recvonly_stats if s.get("type") == "inbound-rtp")
|
|
440
|
+
assert inbound_rtp_stats["decoderImplementation"] == "NvCodec"
|
|
441
|
+
assert inbound_rtp_stats["bytesReceived"] > 0
|
|
442
|
+
assert inbound_rtp_stats["packetsReceived"] > 0
|
|
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
|
{sora_sdk-2025.1.0.dev10 → sora_sdk-2025.1.0.dev12}/src/sora_sdk.egg-info/dependency_links.txt
RENAMED
|
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
|