aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--airtunes2.rst169
1 files changed, 124 insertions, 45 deletions
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. <http://www.apple.com/>`_
* `Rogue Amoeba Software, LLC <http://www.rogueamoeba.com/>`_
+
+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