Skip to content

Commit 1d87832

Browse files
committed
simulcast を追加
1 parent 1bfff68 commit 1d87832

File tree

2 files changed

+157
-1
lines changed

2 files changed

+157
-1
lines changed

.github/workflows/e2e-test-amd-amf.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ jobs:
5151
uv python pin ${{ matrix.python_version }}
5252
uv sync
5353
uv run python run.py ubuntu-24.04_x86_64
54-
uv run pytest tests/test_amd_amf.py -s
54+
uv run pytest tests/test_amd_amf.py -v
5555
5656
# slack_notify_succeeded:
5757
# needs: [e2e_test_ubuntu, e2e_test_macos, e2e_test_windows]

tests/test_amd_amf.py

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ def test_amd_amf_available(setup):
4444
assert c.decoder is True
4545
assert c.encoder is False
4646
case SoraVideoCodecType.AV1:
47+
# TODO: AV1 decoder は True だが色々課題あり
4748
assert c.decoder is True
4849
assert c.encoder is True
4950
case SoraVideoCodecType.H264:
@@ -152,3 +153,158 @@ def test_amd_amf_sendonly_recvonly(setup, video_codec_type):
152153
assert inbound_rtp_stats["decoderImplementation"] == "AMF"
153154
assert inbound_rtp_stats["bytesReceived"] > 0
154155
assert inbound_rtp_stats["packetsReceived"] > 0
156+
157+
158+
@pytest.mark.skipif(os.environ.get("AMD_AMF") is None, reason="AMD AMF でのみ実行する")
159+
@pytest.mark.parametrize(
160+
(
161+
"video_codec_type",
162+
"expected_implementation",
163+
"video_bit_rate",
164+
"video_width",
165+
"video_height",
166+
"simulcast_count",
167+
),
168+
# FIXME: H.265 では、本数が 2 本 や 1 本の場合、エラーになるのでコメントアウトしている
169+
# FIXME: AV1 では、解像度が一定数より低くなる場合、エラーになるのでコメントアウトしている
170+
[
171+
# 1080p
172+
("AV1", "AMF", 5000, 1920, 1080, 3),
173+
("H264", "AMF", 5000, 1920, 1080, 3),
174+
("H265", "AMF", 5000, 1920, 1080, 3),
175+
# 720p
176+
("AV1", "AMF", 2500, 1280, 720, 3),
177+
("H264", "AMF", 2500, 1280, 720, 3),
178+
("H265", "AMF", 2500, 1280, 720, 3),
179+
# 540p
180+
("AV1", "AMF", 1200, 960, 540, 3),
181+
("H264", "AMF", 1200, 960, 540, 3),
182+
("H265", "AMF", 1200, 960, 540, 3),
183+
# 360p
184+
# ("AV1", "AMF", 700, 640, 360, 2),
185+
("H264", "AMF", 700, 640, 360, 2),
186+
# ("H265", "AMF", 700, 640, 360, 2),
187+
# 270p
188+
# ("AV1", "AMF", 450, 480, 270, 2),
189+
("H264", "AMF", 450, 480, 270, 2),
190+
# ("H265", "AMF", 257, 480, 270, 2),
191+
# 180p
192+
# ("AV1", "AMF", 200, 320, 180, 1),
193+
("H264", "AMF", 200, 320, 180, 1),
194+
# ("H265", "AMF", 142, 320, 180, 1),
195+
# 135p
196+
# ("H265", "AMF", 101, 240, 135, 1),
197+
],
198+
)
199+
def test_amd_amf_simulcast(
200+
setup,
201+
video_codec_type,
202+
expected_implementation,
203+
video_bit_rate,
204+
video_width,
205+
video_height,
206+
simulcast_count,
207+
):
208+
if not is_codec_supported(video_codec_type, SoraVideoCodecImplementation.AMD_AMF):
209+
pytest.skip(f"このチップでは {video_codec_type} のエンコードがサポートされていません")
210+
211+
signaling_urls = setup.get("signaling_urls")
212+
channel_id_prefix = setup.get("channel_id_prefix")
213+
metadata = setup.get("metadata")
214+
215+
channel_id = f"{channel_id_prefix}_{__name__}_{sys._getframe().f_code.co_name}_{uuid.uuid4()}"
216+
217+
sendonly = SoraClient(
218+
signaling_urls,
219+
SoraRole.SENDONLY,
220+
channel_id,
221+
simulcast=True,
222+
audio=False,
223+
video=True,
224+
video_codec_type=video_codec_type,
225+
video_bit_rate=video_bit_rate,
226+
metadata=metadata,
227+
video_width=video_width,
228+
video_height=video_height,
229+
video_codec_preference=SoraVideoCodecPreference(
230+
codecs=[
231+
SoraVideoCodecPreference.Codec(
232+
type=codec_type_string_to_codec_type(video_codec_type),
233+
encoder=SoraVideoCodecImplementation.AMD_AMF,
234+
),
235+
]
236+
),
237+
)
238+
sendonly.connect(fake_video=True)
239+
240+
time.sleep(5)
241+
242+
sendonly_stats = sendonly.get_stats()
243+
244+
sendonly.disconnect()
245+
246+
# "type": "answer" の SDP で Simulcast があるかどうか
247+
assert sendonly.answer_message is not None
248+
assert "sdp" in sendonly.answer_message
249+
assert "a=simulcast:send r0;r1;r2" in sendonly.answer_message["sdp"]
250+
251+
# codec が無かったら StopIteration 例外が上がる
252+
sendonly_codec_stats = next(s for s in sendonly_stats if s.get("type") == "codec")
253+
assert sendonly_codec_stats["mimeType"] == f"video/{video_codec_type}"
254+
255+
# 複数の outbound-rtp 統計情報を取得
256+
outbound_rtp_stats = [
257+
s for s in sendonly_stats if s.get("type") == "outbound-rtp" and s.get("kind") == "video"
258+
]
259+
# simulcast_count に関係なく統計情報はかならず 3 本出力される
260+
# これは SDP で rid で ~r0 とかやる減るはず
261+
assert len(outbound_rtp_stats) == 3
262+
263+
# rid でソート
264+
sorted_stats = sorted(outbound_rtp_stats, key=lambda x: x.get("rid", ""))
265+
266+
for i, s in enumerate(sorted_stats):
267+
assert s["rid"] == f"r{i}"
268+
# simulcast_count が 2 の場合、rid r2 の bytesSent/packetsSent は 0 or 1 になる
269+
# simulcast_count が 1 の場合、rid r2 と r1 の bytesSent/packetsSent は 0 or 1 になる
270+
if i < simulcast_count:
271+
# 1 本になると simulcastEncodingAdapter がなくなる
272+
# if simulcast_count > 1:
273+
# assert "SimulcastEncoderAdapter" in s["encoderImplementation"]
274+
275+
# targetBitrate が指定したビットレートの 90% 以上、100% 以下に収まることを確認
276+
expected_bitrate = video_bit_rate * 1000
277+
278+
# パケットが一切送られてこない場合は frame_width/frame_height が含まれないので None になる
279+
frame_width = s.get("frameWidth")
280+
frame_height = s.get("frameHeight")
281+
encoder_implementation = s.get("encoderImplementation")
282+
283+
print(
284+
s["rid"],
285+
video_codec_type,
286+
expected_bitrate,
287+
s["targetBitrate"],
288+
expected_implementation,
289+
encoder_implementation,
290+
frame_width,
291+
frame_height,
292+
s["bytesSent"],
293+
s["packetsSent"],
294+
)
295+
assert s["bytesSent"] > 1000
296+
assert s["packetsSent"] > 5
297+
# 期待値の 20% 以上、100% 以下に収まることを確認
298+
assert expected_bitrate * 0.2 <= s["targetBitrate"] <= expected_bitrate
299+
else:
300+
# 本来は 0 なのだが、simulcast_count が 1 の場合、
301+
# packetSent が 0 ではなく 1 や 2 になる場合がある
302+
# byteSent は 0
303+
print(
304+
s["rid"],
305+
video_codec_type,
306+
s["bytesSent"],
307+
s["packetsSent"],
308+
)
309+
assert s["bytesSent"] == 0
310+
assert s["packetsSent"] <= 2

0 commit comments

Comments
 (0)