Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

raop: Fix broken audio streaming #2496

Merged
merged 1 commit into from
Sep 6, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions pyatv/protocols/raop/protocols/airplayv2.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from pyatv.protocols.airplay.auth import verify_connection
from pyatv.protocols.airplay.channels import EventChannel
from pyatv.protocols.raop.protocols import StreamContext, StreamProtocol
from pyatv.support.chacha20 import Chacha20Cipher
from pyatv.support.chacha20 import Chacha20Cipher, Chacha20Cipher8byteNonce
from pyatv.support.http import decode_bplist_from_body
from pyatv.support.rtsp import RtspSession

Expand Down Expand Up @@ -153,7 +153,7 @@
self.context.control_port = stream["controlPort"]
self.context.server_port = stream["dataPort"]

self._cipher = Chacha20Cipher(shared_secret, shared_secret)
self._cipher = Chacha20Cipher8byteNonce(shared_secret, shared_secret)

Check warning on line 156 in pyatv/protocols/raop/protocols/airplayv2.py

View check run for this annotation

Codecov / codecov/patch

pyatv/protocols/raop/protocols/airplayv2.py#L156

Added line #L156 was not covered by tests

def teardown(self) -> None:
"""Teardown resources allocated by setup efter streaming finished."""
Expand Down Expand Up @@ -186,12 +186,22 @@
"""Send audio packet to receiver."""
# TODO: This part is extremely sub-optimized. Should at least use a memoryview
# and do in-place operations to avoid copying memory left and right.
nonce = b""

Check warning on line 189 in pyatv/protocols/raop/protocols/airplayv2.py

View check run for this annotation

Codecov / codecov/patch

pyatv/protocols/raop/protocols/airplayv2.py#L189

Added line #L189 was not covered by tests
if self._cipher:
# Save the nonce that will be used by the next encrypt call as it is
# included in the audio packet.
nonce = self._cipher.out_nonce
aad = rtp_header[4:12]
audio = self._cipher.encrypt(audio, nonce=nonce, aad=aad)

packet = rtp_header + audio + nonce
# Do _not_ pass nonce=nonce here as that not increase the internal counter
# of outgoing messages. We would just send zero as nonce. We did that in
# the past and Apple doesn't seem to care, but other vendors might do.
audio = self._cipher.encrypt(audio, aad=aad)

Check warning on line 199 in pyatv/protocols/raop/protocols/airplayv2.py

View check run for this annotation

Codecov / codecov/patch

pyatv/protocols/raop/protocols/airplayv2.py#L199

Added line #L199 was not covered by tests

# Build the audio packet. Make sure to drop the "upper four" bytes of the nonce
# as only eight byte nonces are used for encryption (the Chacha20
# implementation however returns twelve bytes according to specification).
packet = rtp_header + audio + nonce[-8:]

Check warning on line 204 in pyatv/protocols/raop/protocols/airplayv2.py

View check run for this annotation

Codecov / codecov/patch

pyatv/protocols/raop/protocols/airplayv2.py#L204

Added line #L204 was not covered by tests

transport.sendto(packet)

Expand Down
Loading