APPLE CONFIDENTIAL

Abstract

This document describes the process of porting AirPlay Audio to a new platform. It provides an overview of the component breakdown, list of recommended steps, and potential issues you might run into while bringing up AirPlay. This document is intended for Developers who are planning to port the AirPlay Audio Receiver to their platform.


Glossary

Accessory

Receiver-side of an AirPlay session (e.g. Speaker).

ALAC

Apple Lossless Audio Codec. [REF5]

Property List (Plist)

Property lists represents data using name-value pairs.

Binary Plist

Binary format for an Apple Property List. [REF3]

Bonjour

Apple’s zero-configuration network discovery technology. [REF1]

Controller

Initiator device or the sender-side of an AirPlay session (e.g. iPhone).

CoreFoundation

Apple’s API for collections, numbers, strings, preferences, property lists, etc. [REF2]

Curve25519

Elliptic curve Diffie-Hellman key agreement protocol. [REF8]

DACP

Digital Audio Control Protocol. Used by AirPlay for playback control.

mDNSResponder

Open Source Bonjour implementation. [REF1]

MFi

Apple’s Made for iPhone/iPod/iPad licensing program. [REF6]

MFi-SAP

MFi Secure Association Protocol.

PCM

Pulse-code modulation encoding for uncompressed audio.

POSIX

Portable Operating System Interface. [REF9]

Wireless Accessory Configuration

Apple Protocol for configuring AirPlay Accessories.


1. Project Contents

Apple’s AirPlay Audio POSIX Source release contains the POSIX compliant AirPlay software which can be ported onto a new platform by implementing the necessary interfaces detailed in this document. The source code release contains the following:

1.1. Directory Structure Overview

AirPlayAudioPOSIXReceiver
├── Documentation/
│   ├── HeaderDocs/
│   └── index.html
├── External/
│   ├── AppleLossless/
│   ├── Curve25519/
│   ├── GladmanAES/
│   └── WirelessAccesssoryConfiguration/
├── Makefile
├── Platform/
│   ├── Platform_NetBSD_Pi/
│   │   ├── Makefile
│   │   └── Platform.include.mk
│   └── Platform_OSX_Stubs/
│       ├── Makefile
│       └── Platform.include.mk
├── Sources/
└── Support/

1.2. Directory Structure Details

Location Content

Documentation/

Directory containing documentation.

Makefile

AirPlay Makefile.

Sources/

Directory containing the Apple AirPlay source files.

Support/

Directory containing supporting source files for the Apple AirPlay software.

External

Directory containing all Open/Licensed external source code used by Apple AirPlay Software.

Platform/

Directory containing the example platform implementations.

Platform/Platform_OSX_Stubs/

Directory containing an example platform stub implementation that builds and links (but does not run) on Mac OS X 10.8 or later - includes a stubbed out platform implementation.

Platform/Platform_OSX_Stubs/Platform.include.mk

Example platform specific Makefile that is included in the main AirPlay Makefile to build the Mac OS X stubbed out platform implementation.

Platform/Platform_NetBSD_Pi/

Directory containing the platform implementation for NetBSD on Raspberry Pi.

 NOTE:  The developer should only modify source in the Platform directory.


2. Porting Overview

  1. Set up a toolchain for compiling and linking code.

    Set up the compilers, linkers, and any tools needed to compile the source code for the intended target platform.

  2. Port Bonjour.

    AirPlay requires the Bonjour stack to operate. Please refer to https://developer.apple.com/bonjour/ for information on porting Bonjour to your platform.

  3. Create Platform directory.

    Make a copy of the provided example platform Platform/Platform_OSX_Stubs/ directory for the target platform. This will provide a starting point for your target specific platform implementation for AirPlay.

  4. Update Platform Include Makefile.

    Update the Platform.include.mk file in the platform directory to provide information regarding the toolset, include paths etc. Refer to the provided Platform.include.mk file for more details.

  5. Complete the implementation of the platform interfaces required by AirPlay.

    Implement the interfaces required by AirPlay using OS/Platform specific APIs of the target. The stub implementation provided in Platform/Platform_OSX_Stubs/ directory will provide a good starting point for this. Relevant comments, functions and examples have been tagged with PLATFORM_TO_DO keyword.

  6. Build AirPlay and the platform implementation.

    Build AirPlay and the platform implementation for the target platform. AirPlay will be compiled as a library, which then can be linked with the platform executable. See Building AirPlay for more details.


3. Interfaces

AirPlay POSIX Source project depends on some platform implemented interfaces in order to operate. And it provides a few interfaces which Platform implementation should call. This section provides an overview of the various interfaces involved.

Table 1. Called from AirPlay source into developer code
Interface Interface Header Purpose

Preferences

Support/CFCompat.h

Called by AirPlay for Preference information purposes.

System Info

Support/SystemUtils.h

Called by AirPlay for System information purposes.

MFi SAP

Support/MFiSAP.h

Called by AirPlay for MFi SAP purposes.

Receiver Platform

Sources/AirPlayReceiverPOSIX.h

Called by AirPlay for Airplay Receiver purposes.

Tick

Support/TickUtils.h

Called by AirPlay for high resolution tick related purposes.

Random Bytes

Support/RandomNumberUtils.h

Called by AirPlay for Random Bytes purposes.

Atomic Operations

Support/AtomicUtils.h

Called by AirPlay for atomic operation purposes.
GCC implementation provided

AES

Support/AESUtils.h

Called by AirPlay for AES operation purposes.
openssl compatible

Audio

Support/AudioUtils.h

Called by AirPlay for audio rendering purposes.

Bonjour

Bonjour Library Interface APIs.
Open Source distribution available

POSIX

POSIX compliant APIs called by AirPlay for OS, network & standard library purposes.


Table 2. Called from developer code into AirPlay source
Interface Interface Header Purpose

Initialization

Sources/AirPlayMain.h

Called by developer to kickoff/shutdown AirPlay.

DACP Callback

Sources/AirPlayReceiverServer.h

Called by developer to notify AirPlay about User interaction.

Platform Callback

Sources/AirPlayReceiverServer.h

Called by developer in response to AirPlay Platform calls.
Sample implementation provided

Core Foundation

Core Foundation support API(s) to be used by Developer to implement AirPlay Platform Interface



4. Porting Notes

4.1. Audio Rendering

AirPlay Receiver on the accessory receives the audio stream from the sender device over the network, which is then de-packetized, decrypted, decoded, and buffered according to timing information in the stream. The Platform retrieves the received audio samples by periodically calling into AirPlay’s callback function, and then renders the samples at the rate specified by audio format.

Platform should implement the Audio Interface to receive the samples and render them using the audio hardware.

4.1.1. Platform Audio Thread, Sample Retrieval

Platform should create a separate thread which will call AudioStreamAudioCallback_f() function to retrieve the audio samples from AirPlay, and then render the audio on the audio output path. It is recommended that platform utilize available hardware mechanisms (for ex. low buffer threshold notification) as the trigger to invoke the audio callback function when the audio hardware needs the next chunk of audio.

The periodicity of the audio callback invocation should be chosen based on the following requirements:

  • It should be invoked frequent enough to ensure that there is very little likelihood of the hardware running dry due to thread scheduling delays, which could prevent the audio thread from running in time to provide new samples to the hardware. So it should be based on platform properties like thread scheduling, thread priorities, cpu usage etc.

  • It should not be invoked with too much audio samples already queued in the audio HW buffer, as it could lead to silence samples being returned to the platform if the AirPlay buffer is close to empty. This will lead to audio drops which could have been avoided.

Timing information is important for proper synchronization of audio. When the AudioStreamAudioCallback_f() is invoked by the Platform, it should provide the sample count/number for the first sample to be filled in and a host timestamp in the future for when the first sample will be heard. The host time should be as close as possible to when the sample will really be heard.

4.1.2. Audio Buffers

As mentioned earlier, buffering too much audio samples in the HW buffer can lead to the scenario in which silence samples could be returned in the platform buffer if the airplay buffer is close to empty. So it is recommended that platform buffer only 2 x “low buffer threshold” worth of audio samples in the audio HW buffer. And when the hardware consumes/plays out the audio samples and hits the “low buffer threshold”, the audio callback function should be invoked again. This will ensure that:

  • audio callback function is called with sufficient audio samples in the HW buffer to prevent underflows.

  • too much audio samples is not buffered in the HW buffer when invoking the callback function - this will prevent the potential for unnecessary silence samples being copied to the platform buffer.

Note that the Buffer size provided to the callback function will impact the additional latency for audio to be heard. So the sizing of this should not be too big as to introduce too much latency. So the size of the buffer should depend on the preferred latency, but should be generally around 50ms.

4.1.3. Audio Format Specs

AirPlay conveys the format of the audio samples being provided to the Platform by calling AudioStreamSetFormat(). The platform should use the information specified by that API to setup the audio hardware for audio rendering. The characteristic of audio samples provided by AirPlay currently are:

        Format      : PCM
        Sample Rate : 44100
        Sample Size : 16 bit
        Channels    : 2 (Stereo)
        Sign        : Signed
        Byte Order  : Host Byte Order

Note that AirPlay may support/add more audio formats in the future. The platform implementation should ensure that it does not use a hard-coded setting and instead use the information provided by AudioStreamSetFormat() when setting up the audio hardware.

4.2. Atomic Operations

AirPlay uses the Atomic Operation Interface for lock-free atomic operations, such as incrementing an integer, compare-and-swap, etc. GCC based implementation of these functions are provided. If the toolset for the target platform is not based on GCC, porting is required, and the following functions need to be implemented in an atomic, and ideally lock-free, manner.

        int32_t atomic_add_and_fetch_32( int32_t *inPtr, int32_t inVal );

        Boolean atomic_bool_compare_and_swap_32( int32_t *inPtr, int32_t inOldValue, int32_t inNewValue );

        int32_t atomic_fetch_and_and_32( int32_t *inPtr, int32_t inVal );

        int32_t atomic_fetch_and_or_32( int32_t *inPtr, int32_t inVal );

        void atomic_read_write_barrier( void );

        int32_t atomic_sub_and_fetch_32( int32_t *inPtr, int32_t inVal );

        int32_t atomic_val_compare_and_swap_32( int32_t *inPtr, int32_t inOldValue, int32_t inNewValue );

        void atomic_yield( void );

4.3. MFi Authentication and Encryption

AirPlay accessories are required to have an Apple authentication Coprocessor so the controller can authenticate and setup encrypted communication with the accessory. The authentication and encryption protocol is provided as portable code that should work on any platform. Access to the Apple authentication Coprocessor is different for each platform. The following functions need to be implemented to provide the required MFi features to AirPlay. For detailed API documentation see MFiSAP.h.

        OSStatus MFiPlatform_Initialize( void );

        void MFiPlatform_Finalize( void );

        OSStatus MFiPlatform_CopyCertificate( uint8_t **outCertificatePtr, size_t *outCertificateLen );

These functions are called when AirPlay needs to interact with the Apple Authentication Coprocessor. Please refer to the relevant version of the "Apple Authentication Coprocessor" document to obtain more details on how to interact with the Authentication Coprocessor. This document can be found on the MFi Portal.

Tips for interacting with the Apple Authentication Coprocessor
It is important to implement a robust error detection and retry scheme when interacting with the Coprocessor over the I2C interface. See the following sections of the Authentication Coprocessor documentation for more information:

  • NACK Responses Replace Clock Stretching

  • Automatic Sleep State Entry and Exit

4.4. Random Bytes

AirPlay uses Random Bytes Interface for cryptographic key exchange and various other purposes. All random bytes go through a single API, RandomBytes(). This API generates N bytes of cryptographic random data. The platform implementation must generate cryptographic random bytes (e.g. can’t use ANSI rand(), POSIX random(), etc.). If there is not enough entropy to satisfy the request, it must block until sufficient entropy is available, and should not return an error in that case). Here’s the API definition

        OSStatus RandomBytes( void *inBuffer, size_t inByteCount );

4.5. System Preferences & Information

AirPlay needs system preferences/information such as device name, manufacturer name etc. for its operation. This section lists the various setting and preferences information AirPlay uses and associated relevant information.

Accessory Name

Accessory name allows the user to identffy the accessory on the sender devices like iPhone, iPad etc. AirPlay will call GetDeviceName() to retrieve the accessory name from the platform implementation. This device name will be used by AirPlay in the Bonjour records and when displaying accessory list to the user on the sender devices.

Accessories that provide a mechanism (for ex. Web UI, setup app, device menu etc.) to allow the user to set/change the accessory name, should call AirPlayReceiverServerPostEvent(kAirPlayEvent_PrefsChanged) to notify AirPlay of the name change.

Model Name

AirPlay sends out the Accessory model name as part of the Bonjour record for the accessory. AirPlay will call GetDeviceModelString() to retieve the model name from the platform implementation.

Play Password

AirPlay supports optionally requiring a password to initiate playback to the accessory. AirPlay will call CFPreferencesCopyAppValue_compat(kAirPlayPrefKey_PlayPassword) during the password verification process to retrieve the password from the platform implementation. If the password is set by the user, AirPlay will confirm the password on the sender device when streaming is initiated to the password protected accessory.

Accessories that provide a mechanism (for ex. Web UI, setup app, device menu etc.) to allow the user to set/change the AirPlay play password, should call AirPlayReceiverServerPostEvent(kAirPlayEvent_PrefsChanged) to notify AirPlay of password change.

Firmware Version

AirPlay sends out the Firmware version as part of the Bonjour record for the accessory. Developer should provide the firmware version number in the Platform.inclue.mk file passed to the AirPlay Makefile when building AirPlay. Refer to Building AirPlay section below for more details.

The firmware version should be specified in the format <AirPlay Firmware Version>.<MCU Firmware Version>.<Vendor Custom> where:

  • <AirPlay Firmware Version> should specify the version of the AirPlay code base. For accessories based on the POSIX source release, this value can be found in the third field of the release number of the POSIX source drop, and is composed of the letter “p” followed by a number. For example, for the POSIX source drop release “AirPlay Audio POSIX Receiver 190.9.p7”, the value of the <AirPlay Firmware Version> field is “p7”. For accessories based on the Microchip DM8XX module, this field value will be provided by the technology provider and is composed of the letter “s” followed by a number.

  • <MCU Firmware Version> should specify the MCU firmware version if the accessory has a separate MCU. If no MCU is used, this field should be set to 0.

  • <Vendor Custom> field can be used to specify whatever other firmware versioning information desired by the deverloper. If no custom data is used, this field should be filled with a 0.

example: fv=p7.0515.0

MAC Address

AirPlay requires the MAC address of the primary network interface on the accessory. Accessories with a wireless WiFi interface should use the MAC address of the WiFi interface as the primary MAC address. AirPlay will call GetPrimaryMACAddressPlatform() to retieve the MAC affress from the platform implementation.


4.6. High Resolution Tick

AirPlay requires high resolution timing support from the platform implementation. This should be based on a simple tick counter, such as the processor cycle counter in many CPUs. The following two functions need to be implemented by the platform.

        uint64_t UpTicks( void )
                Return the current value of the tick counter.

        uint64_t UpTicksPerSecond( void )
                Return the number of ticks in a second.

4.7. Song Metadata Support

AirPlay sender device sends the following information (if available) related to the currently playing song to the accessory, and accessories with display capabilities can display them to the user:

  • Album Name

  • Artist Name

  • Song Title

  • Composer

  • Album Artwork

  • Elapsed Time

  • Total Time

Accessory should specify the Metadata it supports via the platform AirPlayReceiverPlatformGetSupportedMetadata() implementation, and AirPlay will include that information in the Bonjour record broadcast by the accessory.

AirPlay core will call the AirPlayReceiverPlatformSetMetadata() to convey the information related to the currently playing song. The accessory should update the display with the newly received metadata/progree information whenever this function is called. Note that the Metadata text fields (like name, title etc.) is specified in UTF8 and care must be taken to ensure that UTF8 characters are displayed properly to the end user.

4.8. Skew Compensation

AirPlay provides builtin software-based skew compensation support which is used by AirPlay when it detects skew in the audio being played out. Platforms which have high quality skew compensation support can disable AirPlay’s builtin skew compensation and do its own skew compensation for better quality. When Platform’s skew compensation is enabled, AirPlay will periodically notify the Platform about the new sample rate to be used to ensure appropriate compensation.

Platform need to do the following to use its own skew compensation:

Indicate support for Platform skew compensation

Platform should use PLATFORM_SKEW_COMPENSATION_ENABLE in Platform.include.mk file to indicate Platform’s skew compensation support to AirPlay. AirPlay will disable its internal builtin skew compensation logic when Platform specifies this.

AirPlay’s AudioStreamSetVarispeedRate() call to Platform

Platforms which support skew compensation of its own should implement AudioStreamSetVarispeedRate(), which AirPlay will periodically call to communicate the new sample rate Platform to be used to compensate the skew detected by AirPlay.

4.9. Audio Source Switch

AirPlay Accessories can support multiple audio sources, allowing the user to switch audio inputs to play audio from the various supported sources like radio, CD, Dock etc.

Accessory should do the following when switching away from an active AirPlay session, to ensure that the sender device is notified of the audio input switching away from AirPlay.

    AirPlayReceiverServerSendDACPCommand(kDACPCommandStr_SetProperty kDACPProperty_DevicePreventPlayback "=1")
    AirPlayReceiverServerSendDACPCommand(kDACPCommandStr_SetProperty kDACPProperty_DeviceBusy "=1")
    AirPlayReceiverServerSendDACPCommand(kDACPCommandStr_SetProperty kDACPProperty_DevicePreventPlayback "=0")

Accessory should do the following when switching into AirPlay input when AirPlay session is inactive, to ensure that the sender device is notified of the audio input switching to AirPlay.

    AirPlayReceiverServerSendDACPCommand(kDACPCommandStr_SetProperty kDACPProperty_DeviceBusy "=0")

4.10. Volume Control

AirPlay allows end user to control the audio volume of the accessory from both the sender device and the accessory. Volume changes on the sender device will cause AirPlay on the accessory to call AudioStreamSetVolume() to change the volume on the accessory. AirPlay will also call AudioStreamGetVolume() as needed to retrieve the current volume level on the accessory. The volume in these functions is represented on a 0.0 - 1.0 range.

A volume Up/Down initiated by the user on the accessory (via a remote control or panel buttons) should call AirPlay’s AirPlayReceiverServerSendDACPCommand( kDACPCommandStr_VolumeUp or kDACPCommandStr_VolumeDown ) to notify AirPlay of the volume Up/Down request.

A Mute request initiated by the user on the accessory (via a remote control or panel buttons) should call AirPlay’s AirPlayReceiverServerSendDACPCommand( kDACPCommandStr_SetProperty kDACPProperty_DeviceVolume "=-144.0" ) to notify AirPlay of the mute request. Platform is responsible for keeping track of the volume before this mute request so that it can be used later when user does an unmute request. Developer should call AirPlay’s AirPlayReceiverServerSendDACPCommand( kDACPCommandStr_SetProperty kDACPProperty_DeviceVolume "=<previous volume level>" ) to notify AirPlay of the new volume level.

Note that volume level mentioned above is a floating-point dB attenuation value, where 0.0 is full volume and -144.0 is completely muted. The practical volume range utilized for the AirPlay stream has a basis of -30dB to 0dB with a special cased mute level of -144dB (linear volume of 0) in order to avoid infinities. The following equations can be used to convert between a dB value and a linear volume:

linear volume = pow( 10, dB / 20 )
dB value      = 20 * log10( linear volume )

Accessories which support setting volume to a specific level (for ex. presets or sliders) should also call AirPlayReceiverServerSendDACPCommand(kDACPCommandStr_SetProperty kDACPProperty_DeviceVolume "=<value>") to set volume to the specific level.

4.11. Remote Control of AirPlay

The AirPlay Product Definition Specification [REF11] specifies the various remote operations allowed from an AirPlay Audio Accessory.

When the user uses the input device to control AirPlay (for ex. pausing playback, moving to the next song in a playlist, etc.), the developer should use AirPlayReceiverServerSendDACPCommand() to send the appropriate DACP commands, which will then be sent from the accessory to the controller. The developer should pass the DACP command string, which conveys the operation requested, as input parameter to the following interface.

        OSStatus AirPlayReceiverServerSendDACPCommand( AirPlayReceiverServerRef inServer, const char *inDACPCommand );

The table below lists the various operations and the corresponding DACP command string to be passed to AirPlayReceiverServerSendDACPCommand() by the developer:

        Action                  DACP Command String                                     Comment
        ------                  -------------------                                     -------
        Play                    kDACPCommandStr_Play                    Start playback of the current AirPlay session (only for separate play button).
        Stop                    kDACPCommandStr_Stop                    Stop playback of the current AirPlay session.
        Pause                   kDACPCommandStr_Pause                   Pause playback of the current AirPlay session (only for separate pause button).
        Pause Toggle            kDACPCommandStr_PlayPause               Toggle between play and pause of current AirPlay session (only for combined pause/play button).
        Next Item               kDACPCommandStr_NextItem                Go to the next song in the playlist.
        Previous Item           kDACPCommandStr_PrevItem                Go to the previous song in the playlist.
        Repeat Toggle           kDACPCommandStr_RepeatAdvance           Repeat Advance.
        Shuffle Toggle          kDACPCommandStr_ShuffleToggle           Shuffle Toggle.
        Volume Up               kDACPCommandStr_VolumeUp                Raise the volume of the current AirPlay session.
        Volume Down             kDACPCommandStr_VolumeDown              Lower the volume of the current AirPlay session.
        Set Propety             kDACPCommandStr_SetProperty             Set the following properties:
                Volume Level            kDACPProperty_DeviceVolume=<value>      Set the volume of the current AirPlay session to the specified level.

4.12. Multiple Network Interfaces

Accessories with multiple network interfaces (for ex. WiFi and Ethernet) should have only one active network at any time. Accessory should ensure that the end user is allowed to select only one network interface to be active. If the user selects a different interface, the currently active interface should be shut down before activating the newly selected network interface.

Note
Accessories with multiple network interfaces should always use the MAC address of the WiFi interface as the primary MAC address in the implementation of GetPrimaryMACAddressPlatform() (even when the WiFi network is inactive). AirPlay will use this to uniquely identify the device’s bonjour records from multiple networks.

4.13. Building AirPlay

AirPlay provides a Makefile which should be used to build all AirPlay related code.

Make Targets

The following targets are supported when building AirPlay:

airplaylib (default)

Build Airplay Library. This is the default target. AirPlay library libAirPlay.a will be created in the platform specified object directory.

clean

Cleans all Airplay related objects.

help

Prints out help page

Make Options

The following options are supported when building AirPlay. Passing <option>=1 as argument to the make command line would enable the options listed below:

debug

Build airplay in debug mode. This will enable symbol table and avoid optimization and stripping.

openssl

Build airplay to utilise platform provided openssl library. This will force AirPlay to not use the default Gladman AES implementation and use openssl instead.

Makefile Variables

AirPlay Makefile does not contain any information regarding the target platform’s toolset and build environment. The AirPlay Makefile expects the developer to provide information related to the build environment and toolset when executing the Makefile. The developer should provide a platform include makefile, containing the necessary build environment information, as a parameter to make command. The command line to be used for this is:

make platform_makefile=<path_to_Platform.Include.mk> ...

Note
Refer to the sample platform include makefile Platform.include.mk for more details regarding the makefile variables to be provided by the developer.
Make Examples
  • Build debug mode AirPlay library
    make platform_makefile=<path_to_Platform.Include.mk> debug=1

  • Build non-debug mode AirPlay library
    make platform_makefile=<path_to_Platform.Include.mk>

  • Build openssl based debug mode AirPlay library
    make platform_makefile=<path_to_Platform.Include.mk> debug=1 openssl=1

  • Clean AirPlay
    make platform_makefile=<path_to_Platform.Include.mk> clean

  • Get help about building AirPlay
    make platform_makefile=<path_to_Platform.Include.mk> help

4.14. Running AirPlay

The developer should determine, based on the accessory platform characteristics, which platform process to run AirPlay in. The AirPlay Makefile allows the Developer to build AirPlay library as detailed in Building AirPlay section above. which then should be linked to a platform executable as needed.

  • Make AirPlay Makefile defaul target to create the AirPlay library.

  • AirPlay library libAirPlay.a will be created in the object directory

  • Build the platform implementation and link to the AirPlay library to create the platform executable.

  • The developer should start the AirPlay executable during platform boot-up.

  • The developer should start mDNSResponder (Bonjour) daemon before kicking off AirPlay Daemon.

4.15. External Source

The following Open/Licensed source projects are used by the AirPlay source release. Source code for some of the below is included with the AirPlay POSIX source release (External/). Any modifications to the original source are also described in the following sections.

Bonjour [REF1]:

Bonjour is Apple’s zero-configuration networking which enables automatic discovery of devices and services on a local network using industry standard IP protocols. AirPlay uses Bonjour for its accessory discovery purposes and links to the libdns library.

The developer should port mDNSResponder (Apple’s bonjour implementation), which is available as Open Source, to the accessory platform. Refer to https://developer.apple.com/bonjour/ for more details on porting mDNSResponder.


Apple Lossless Audio Codec (ALAC) [REF5]:

The Apple Lossless Audio Codec (ALAC) is an audio Codec developed by Apple and supported on iPhone, iPad, most iPods, Mac and iTunes. ALAC is a data compression method which reduces the size of audio files with no loss of information. A decoded ALAC stream is bit-for-bit identical to the original uncompressed audio file.

AirPlay uses ALAC decoder on the accessory side for streaming purposes. The AirPlay Source Release includes the ALAC source code (External/AppleLossless/) as needed for accessory features. Refer to http://alac.macosforge.org for more details on ALAC and its Open Source release.


Apple Wireless Accessory Configuration (WAC):

Wireless Accessory Configuration (WAC) is an Apple proprietary configuration protocol which allows a controlling device, such as an iPhone, to send configuration information to the accessory. This includes joining a network, the accessory name etc.



Developers must use WAC on their AirPlay Accessories to provide an enhanced user experience when interacting with the accessory. Apple provides developers access to WAC as a Licensed Source Release as part of the MFi Program [REF6]. Refer to Developer MFi Portal for more details on porting WAC to the accessory platform.



Note: AirPlay does not interact with WAC directly.


GladmanAES [REF7]:

The AirPlay Source Release uses/contains a modified version (External/GladmanAES/) of GladmanAES Open Source release for encryption/decryption.

The following modifications have been made to the Open Source release of GladmanAES to better suit AirPlay’s needs:

  • Added support for in-place encrypt/decrypt.

  • Added support for working without ACE support.

  • Fixes for endian detection.

  • Fixes for compiling on different compilers, 64-bit, etc.

  • Fixes for warnings.


Curve25519 [REF8]:

The AirPlay Source Release contains a modified version (External/Curve25519/) of Curve25519 Open Source release for its Public Key purposes.

The following modifications have been made to the Open Source release of Curve25519 to better suit AirPlay needs:

  • Added default basepoint.

  • Fixes for misaligned access.

  • Fixes for compiling on different compilers, 64-bit, etc.

  • Fixes for warnings.


4.16. POSIX Interface

AirPlay uses POSIX compliant APIs for various purposes like:

  • OS functionalities

    • Threads

    • Memory

    • Mutex

    • Semaphores

    • Conditional Variable

    • File descriptor

  • Network Operations

    • Socket

    • Bind/Connect/Accept

The developer is responsible for providing the suitable libraries for the POSIX compliant implementation on the accessory platform. Refer to the POSIX Dependencies section for details on POSIX interfaces required by AirPlay.

4.16.1. List of POSIX Dependencies

AirPlayReceiverPlatformGetSupportedMetadata( )
AirPlayReceiverPlatformSetMetadata( )
AudioStreamCreate( )
AudioStreamGetLatency( )
AudioStreamGetVolume( )
AudioStreamPrepare( )
AudioStreamSetAudioCallback( )
AudioStreamSetFormat( )
AudioStreamSetPreferredLatency( )
AudioStreamSetThreadName( )
AudioStreamSetThreadPriority( )
AudioStreamSetVarispeedRate( )
AudioStreamSetVolume( )
AudioStreamStart( )
AudioStreamStop( )
DNSServiceGetAddrInfo( )
DNSServiceProcessResult( )
DNSServiceQueryRecord( )
DNSServiceRefDeallocate( )
DNSServiceRefSockFD( )
DNSServiceRegister( )
DNSServiceResolve( )
DNSServiceUpdateRecord( )
GetDeviceModelString( )
GetDeviceName( )
GetInterfaceMACAddress( )
GetPlatformMaxSocketBufferSize( )
GetPrimaryMACAddressPlatform( )
RandomBytes( )
TXTRecordCreate( )
TXTRecordDeallocate( )
TXTRecordGetBytesPtr( )
TXTRecordGetLength( )
TXTRecordSetValue( )
UpTicks( )
UpTicksPerSecond( )
accept( )
bind( )
bsearch( )
calloc( )
chmod( )
close( )
connect( )
difftime( )
environ( )
fclose( )
fcntl( )
fflush( )
fileno( )
fopen( )
fprintf( )
fputs( )
fread( )
free( )
freeaddrinfo( )
freeifaddrs( )
fseeko( )
fstat$INODE64( )
ftello( )
ftruncate( )
fwrite( )
getaddrinfo( )
getenv( )
gethostname( )
getifaddrs( )
getpeername( )
getpid( )
getpwnam( )
getsockname( )
getsockopt( )
gettimeofday( )
getuid( )
gmtime( )
ioctl( )
listen( )
localtime( )
log10( )
lseek( )
malloc( )
memchr( )
memcmp( )
memcpy( )
memmove( )
memset( )
mkdir( )
mkstemp( )
mktime( )
mmap( )
munmap( )
nanosleep( )
nftw$INODE64( )
open( )
pause( )
pclose( )
pipe( )
popen( )
printf( )
qsort( )
random( )
read( )
realloc( )
recv( )
recvfrom( )
recvmsg( )
remove( )
rename( )
select$1050( )
send( )
sendto( )
setsockopt( )
setvbuf( )
shutdown( )
signal( )
sin( )
sleep( )
socket( )
sscanf( )
stat$INODE64( )
strcasecmp( )
strchr( )
strcmp( )
strcspn( )
strdup( )
strerror( )
strftime( )
strlen( )
strncasecmp( )
strncmp( )
strncpy( )
strrchr( )
strspn( )
strstr( )
strtod( )
strtol( )
strtoul( )
sysconf( )
syslog( )
time( )
unlink( )
usleep( )
waitpid( )
write( )
writev( )


5. Sample Implementations

Sample implementations of the Platform Interfaces have been provided to give the developer a good starting point.

5.1. Platform_OSX_Stubs

This sample implementation will compile the AirPlay files and link to the sample stub implementations, of the functions the platform developer needs to implement, on the Mac OS X 10.8 (or later) platform. The sample implementation in this directory has been annotated with PLATFORM_TO_DO with relevant information, to assist the porting effort. This directory also contains a Platform Makefile which demonstrates building Airplay library and linking it as part of platform exectuable from a platform makefile.

Targets supported by this sample Platform Makefile: daemon library clean.

Note
The sample platform contain stubs and are provided for reference purposes only - it does not run/work as a full fledged airplay stack.
Note
nostubs=1 Make option can be used to get a list of Apple specified AirPlay Platform interfaces.
Note
Developer should use Open Source mDNSResponder source and library built for OSX when building on a Mac. Building AirPlay will fail if this platform is built using the Mac standard DNS-SD headers/library.
To make this example
  • cd Platform/Platform_OSX_Stubs

  • make daemon : Build AirPlay executable.

  • make debug=1 library : Build debug mode AirPlay executable.

  • make clean : Clean build.

  • make nostubs=1 : list of Apple specified AirPlay Platform interfaces.

5.2. Platform_NetBSD_Pi

This implementation provides a working AirPlay Platform for NetBSD running on Raspberry Pi. This has been tested and works on Raspberry Pi Model B and Model B+. Developer requires the following to make use of this platform implementation:

  • Raspberry Pi Model B or Model B+

  • SD Card with NetBSD Pi image

  • Apple Authentication Coprocessor

  • NetBSD development toolchain

Note
Refer to README.txt file for more details on Raspberry Pi, NetBSD port & outstanding issues.

Targets supported by this sample Platform Makefile: daemon library clean.

To make this example
  • cd Platform/Platform_NetBSD_Pi

  • make daemon : Build AirPlay executable.

  • make debug=1 library : Build debug mode AirPlay executable.

  • make clean : Clean build.


6. API Documentation

6.1. Preferences Interface

#include "CFCompat.h"

APIs called by AirPlay for Preference information purposes

6.2. System Info Interface

#include "SystemUtils.h" #include "NetUtils.h"

APIs called by AirPlay for system information purposes

6.3. MFi SAP Interface

    #include "MFiSAP.h"

APIs called by AirPlay for MFi Authentication purposes

6.4. Receiver Platform Interface

#include "AirPlayReceiverPOSIX.h"

APIs called by AirPlay for AirPlay Receiver purposes

Note
  • API Details

  • Header

  • NOTE: This interface replaces Server Platform Interface and Session Platform Interface.

6.5. Tick Interface

#include "TickUtils.h"

APIs called by AirPlay for timer tick related purposes.

6.6. Random Bytes Interface

#include "RandomNumberUtils.h"

APIs called by AirPlay for random bytes purposes.

6.7. Atomic Operation Interface

#include "AtomicsUtils.h"

APIs called by AirPlay for atomic operation purposes.

Note

6.8. AES Interface

#include "AESUtils.h"

APIs called by AirPlay for AES encryption/decryption purposes.

6.9. Audio Interface

#include "AudioUtils.h"

APIs called by AirPlay related to Audio rendering on the accessory.

6.10. Bonjour Interface

Bonjour Library Interface APIs

Note
  • Open Source distribution available.

6.11. POSIX Interface

POSIX compliant APIs called by AirPlay for basic Operating System, network and standard library purposes.

Note
  • POSIX compliant.

6.12. InitiaizationInterface

#include "AirPlayMain.h"

To be called by Developer to start and shut down AirPlay.

6.13. DACP Callback Interface

#include "DACPCommon.h" #include "AirPlayReceiverServer.h"

To be called by Developer to notify AirPlay about User interaction with the accessory via input devices like remote control.

6.14. Platform Callback Interface

#include "AirPlayReceiverServer.h"

To be called by Developer in response to AirPlay Platform Interface calls

6.15. Core Foundation Interface

Core Foundation support APIs to be called by Developer to implement AirPlay Platform Interface


7. References


8. Release Notes

8.1. AirPlay Audio POSIX Receiver 211.1.p8

  • Updated documentation :

    • Document revision 1.5

    • Added section to clarify platform provided skew compensation support.

    • Replaced Receiver Server/Session Platform interfaces with the new Reciever Platform interface.

    • Added section to document the new NetBSD Pi platform implementation.

    • Added clarification about value to be used for firmware version field.

  • Simplified AirPlay Receiver Platform interfaces :

    • Replaced Server Platform Interface and Session Platform Interface with a simpler new Receiver Platform Interface.

    • Existing Platform implementations of Server Platform Interface and Session Platform Interface should continue to work if needed. It is recommended to switch to the new Receiver Platform Interface.

  • Added NeBSD platform implementation for Raspberry Pi.

  • Added ability for platform to replace AirPlay’s internal skew compensation with a platform provided skew compensation.

  • Added section to clarify behavior on accessories with multiple network interfaces.

  • Fixed incorrect linear translation of incoming dB volume level.

  • Code cleanup.

8.2. AirPlay Audio POSIX Receiver 190.9.p7

  • Updated documentation :

    • Document revision 1.4

    • Clarifications for audio retieval mechanism, callback usage, audio thread/buffer.

    • Clarifications about limitations of sample platform stub implementation.

    • Clarifation that accessories with WiFi should return WiFi MAC address as the primary MAC address.

    • Clarification that platform should specify the DSP dealys via the AudioStreamGetLatency() function.

    • Clarify that accessory should send "playpause" DACP command for combined pause/play remote button

  • Updated AirPlay Makefile to create just a library. Linking should be done by platform.

  • Fixed problem where AirPlay core was hardcoding the Metadata support flags to indicate that all metadat types were supported by the accessory.

  • Fixed failure to compile OSX Platforms on OSX Mavericks.

  • Updates to Platform.include.mk

    • Removed unnecesaary info (linking related info like libraries, patform source files etc) now that AirPlay Makefile creates just a library.

    • Slight change in how platform specifies the endianness of the accessory.

  • Code cleanup