From f962e5b510f954360c7b3263b5758d2719a04a36 Mon Sep 17 00:00:00 2001 From: Anonymous Contributor <> Date: Mon, 28 Sep 2009 22:47:00 +0100 Subject: Many updates --- airtunes2.rst | 169 ++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 124 insertions(+), 45 deletions(-) (limited to 'airtunes2.rst') diff --git a/airtunes2.rst b/airtunes2.rst index 2bcbded..c06db62 100644 --- a/airtunes2.rst +++ b/airtunes2.rst @@ -18,6 +18,23 @@ Credits * `Apple Inc. `_ * `Rogue Amoeba Software, LLC `_ + +Streaming audio to an AirTunes 2 compatible device +-------------------------------------------------- + +If encryption is necessary, a random key and IV (initialization vector) for AES +encryption, 16 bytes each, should be generated. + +Every stream has a timestamp (uint64; initially set to ``INITIAL_TIMESTAMP``, +see Constants_) and sequence number (int16; initially set to 0) attached to it. +Both are updated when sending audio packets. + +Up to ``PACKET_BACKLOG`` audio packets should be kept around to resend them if +necessary. After sending a audio packet, the sender should check if a sync +packet should also be sent (basically every ``TIMESYNC_INTERVAL`` frames and +just after connecting). + + Preferred TCP/UDP ports ----------------------- @@ -39,6 +56,7 @@ Timing request 0x52 Timing response 0x53 Sync 0x54 Range resend 0x55 +Audio data 0x60 =============== ==== Data types @@ -131,6 +149,22 @@ ResendPacket } +Constants +--------- + +===================== ========================= ========================== +Name Value Description +===================== ========================= ========================== +FRAMES_PER_PACKET 352 Audio frames per packet +SHORTS_PER_PACKET 2 * FRAMES_PER_PACKET Shorts per packet +TIMESTAMPS_PER_SECOND 44100 Timestamps per second +TIMESYNC_INTERVAL 44100 Once per second +TIME_PER_PACKET FRAMES_PER_PACKET / 44100 Milliseconds +PACKET_BACKLOG 1000 Packet resend buffer size +INITIAL_TIMESTAMP 0x10000000 +===================== ========================= ========================== + + RTSP ---- @@ -148,7 +182,7 @@ CSeq | Request sequence number. Can either be counted RTP-Info ``rtptime={RTP timestamp}`` Session Server session ID (after SETUP) User-Agent | ``iTunes/{Version} (Windows; N;)`` - (e.g. Version=``7.6.2``) + (e.g. Version=``iTunes/7.6.2 (Windows; N;)``) ================ ================================================= @@ -157,7 +191,7 @@ Request URI Unless specified otherwise, ``rtsp://{Local IP address}/{Client session ID}`` must be used as the request URI. The client session ID is a random number -between 0 and 2^32. +between 0 and 2^32 generated once per connection. ANNOUNCE @@ -310,40 +344,38 @@ If ``Apple-Response``, ``Server`` or ``Audio-Latency`` in response: :: - metadata_type() { - if (Apple-Response in response) { - lowercase_password = False; - audio_format = EncryptedALAC; - wants_album_art = False; - wants_metadata = False; - wants_progress = False; - has_bad_latency_header = False; - } + if (Apple-Response in response) { + lowercase_password = False; + audio_format = EncryptedALAC; + wants_album_art = False; + wants_metadata = False; + wants_progress = False; + has_bad_latency_header = False; + } - if (Server in response) { - lowercase_password = True; - has_bad_latency_header = True; - - if (not Apple-Response in response) { - audio_format = UnencryptedALAC; - wants_album_art = DAAP; - wants_metadata = DAAP; - wants_progress = True; - } + if (Server in response) { + lowercase_password = True; + has_bad_latency_header = True; + + if (not Apple-Response in response) { + audio_format = UnencryptedALAC; + wants_album_art = DAAP; + wants_metadata = DAAP; + wants_progress = True; } - - if (Audio-Latency in response) { - if (not has_bad_latency_header) { - audio_latency = Audio-Latency; - } else { - if (Audio-Latency == 322 or - Audio-Latency == 15049) { - audio_latency = 11025; - } - - /* Why always 11025? */ + } + + if (Audio-Latency in response) { + if (not has_bad_latency_header) { + audio_latency = Audio-Latency; + } else { + if (Audio-Latency == 322 or + Audio-Latency == 15049) { audio_latency = 11025; } + + /* Why always 11025? */ + audio_latency = 11025; } } @@ -375,6 +407,8 @@ Sync Sync packets are sent once per second or when adding a speaker. +TODO: More details such as timing adjustments. + Sending sync packet ~~~~~~~~~~~~~~~~~~~ @@ -396,6 +430,63 @@ Sending sync packet } +Audio +----- + +Audio packet +~~~~~~~~~~~~ + +Header:: + + /* The first 4 bytes are an RtpHeader */ + { 0x80, 0x60, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x62, 0x74, 0x05, 0xb9 } + + +Audio codec +~~~~~~~~~~~ + +=============== ===================== +Codec Apple Lossless (ALAC) +Sample size 16 Bit +Channels 2 +Sample rate 44100 +=============== ===================== + + +Packetizing audio +~~~~~~~~~~~~~~~~~ + +#. Collect ``FRAMES_PER_PACKET`` frames from input data (each frame is + 2 bytes) +#. Encode input frames using ALAC codec +#. Encode packet data + + - Raw L16 + + #. Convert raw input data to big endian (it's an array of uint16) + #. Copy audio header and converted audio data into one buffer + #. Set 2nd byte of buffer to 0xa + + - Unencrypted ALAC + + #. Copy audio header to buffer + #. Append ALAC encoded audio data to buffer + + - Encrypted ALAC + + #. Encrypt ALAC encoded audio data (only complete 16 byte blocks, + the rest stays unencrypted) + #. Copy audio header to buffer + #. Append encrypted audio data to buffer + +#. Set bytes 2-4 to sequence number in big endian +#. Set bytes 4-8 to timestamp in big endian +#. Increase sequence number by one for next packet +#. Increase timestamp by number of frames in this packet + + Metadata -------- @@ -444,17 +535,5 @@ Field Description rast ``afs`` if Airfoil speaker ramach ``{Platform name}.{OS major version}`` raver Library version -raAudioFormats TODO +raAudioFormats ``ALAC`` or ``L16`` ============== ======================================= - - -Other numbers -------------- - -======================== ======================= -Audio frames per packet 352 -Shorts per packet (TODO) 704 -Timestamps per second 44100 -Time sync interval 44100 (once per second) -Recovery buffer size 1000 packets -======================== ======================= \ No newline at end of file -- cgit v1.2.3-59-g8ed1b