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 |
|---|---|
Directory containing documentation. |
|
AirPlay Makefile. |
|
Directory containing the Apple AirPlay source files. |
|
Directory containing supporting source files for the Apple AirPlay software. |
|
Directory containing all Open/Licensed external source code used by Apple AirPlay Software. |
|
Directory containing the example platform implementations. |
|
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. |
|
Example platform specific Makefile that is included in the main AirPlay Makefile to build the Mac OS X stubbed out platform implementation. |
|
Directory containing the platform implementation for NetBSD on Raspberry Pi. |
|
NOTE: The developer should only modify source in the Platform directory. |
|
2. Porting Overview
-
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.
-
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.
-
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.
-
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.
-
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.
-
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.
| Interface | Interface Header | Purpose |
|---|---|---|
Called by AirPlay for Preference information purposes. |
||
Called by AirPlay for System information purposes. |
||
Called by AirPlay for MFi SAP purposes. |
||
Called by AirPlay for Airplay Receiver purposes. |
||
Called by AirPlay for high resolution tick related purposes. |
||
Called by AirPlay for Random Bytes purposes. |
||
Called by AirPlay for atomic operation purposes. GCC implementation provided |
||
Called by AirPlay for AES operation purposes. openssl compatible |
||
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. |
| Interface | Interface Header | Purpose |
|---|---|---|
Called by developer to kickoff/shutdown AirPlay. |
||
Called by developer to notify AirPlay about User interaction. |
||
Called by developer in response to AirPlay Platform calls. Sample implementation provided |
||
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.
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 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.
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.
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.
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
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:
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.
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.
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
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.
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. |
-
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 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.
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.
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.
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.
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
|
Note
|
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
|
Note
|
6.4. Receiver Platform Interface
#include "AirPlayReceiverPOSIX.h"
APIs called by AirPlay for AirPlay Receiver purposes
|
Note
|
|
6.5. Tick Interface
#include "TickUtils.h"
APIs called by AirPlay for timer tick related purposes.
|
Note
|
6.6. Random Bytes Interface
#include "RandomNumberUtils.h"
APIs called by AirPlay for random bytes purposes.
|
Note
|
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.
|
Note
|
6.9. Audio Interface
#include "AudioUtils.h"
APIs called by AirPlay related to Audio rendering on the accessory.
|
Note
|
6.10. Bonjour Interface
Bonjour Library Interface APIs
|
Note
|
|
6.11. POSIX Interface
POSIX compliant APIs called by AirPlay for basic Operating System, network and standard library purposes.
|
Note
|
|
6.12. InitiaizationInterface
#include "AirPlayMain.h"
To be called by Developer to start and shut down AirPlay.
|
Note
|
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.
|
Note
|
6.14. Platform Callback Interface
#include "AirPlayReceiverServer.h"
To be called by Developer in response to AirPlay Platform Interface calls
|
Note
|
6.15. Core Foundation Interface
Core Foundation support APIs to be called by Developer to implement AirPlay Platform Interface
7. References
-
[REF1] mDNSResponder open source releases,
http://www.opensource.apple.com/tarballs/mDNSResponder/ -
[REF2] Core Foundation API,
http://en.wikipedia.org/wiki/Core_Foundation -
[REF3] Apple Property Lists,
http://en.wikipedia.org/wiki/Property_list -
[REF4] CFPreferences,
https://developer.apple.com/library/mac/#documentation/CoreFoundation/Reference/CFPreferencesUtils/Reference/reference.html -
[REF5] Apple Lossless Audio Codec (ALAC),
http://alac.macosforge.org -
[REF6] Apple’s Made for iPhone/iPod/iPad licensing program,
https://developer.apple.com/programs/mfi/ -
[REF7] GladmanAES,
http://gladman.plushost.co.uk/oldsite/AES/ -
[REF8] Curve25519-donna,
https://code.google.com/p/curve25519-donna/ -
[REF9] POSIX - Portable Operating System Interface,
http://en.wikipedia.org/wiki/POSIX -
[REF10] Advanced Encryption Standard,
http://en.wikipedia.org/wiki/Advanced_Encryption_Standard -
[REF11] AirPlay Product Definition Specification - Audio Streaming Devices,
Available to Developer under MFi Licensing.
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