Moving Off Deprecated HAL APIs
This Technical Note discusses transitioning to the newer AudioDevice and AudioObject APIs available since the release of Mac OS X 10.5.
Introduction
The AudioHardware.h header file contains APIs used to work with the audio HAL. The audio HAL provides the abstraction through which applications can access audio hardware. There are a set of HAL APIs which have been deprecated since the release of Mac OS X 10.5 and should no longer be used.
There are two types of deprecated APIs. The first type are the AudioDeviceIOProc registration calls, these include AudioDeviceAddIOProc and AudioDeviceRemoveIOProc. The second type are the property accessors such as AudioHardwareGetProperty, AudioDeviceSetProperty and related APIs.
Transitioning to the newer APIs is straight forward and recommended for all applications currently using the older deprecated APIs.
IOProc Registration Changes
The AudioDeviceIOProc registration change introduces the AudioDeviceIOProcID type and remaps AudioDeviceAddIOProc and AudioDeviceRemoveIOProc to AudioDeviceCreateIOProcID and AudioDeviceDestroyIOProcID respectively.
An AudioDeviceIOProcID represents both an IOProc and the client data that goes with it. Once created, an AudioDeviceIOProcID can be used everywhere one would use a regular IOProc. The purpose for an AudioDeviceIOProcID is to allow a client to register the same function pointer as an IOProc with a device multiple times (as long as the user client data pointer is different each time).
When using these new registration APIs, you pass the AudioDeviceIOProcID returned from AudioDeviceCreateIOProcID to AudioDeviceStart and AudioDeviceStop rather than the IOProc itself.
Examples
Listing 1 Deprecated - AudioDeviceIOProc Registration.
OSStatus MyIOProc(AudioDeviceID inDevice,
const AudioTimeStamp* inNow,
const AudioBufferList* inInputData,
const AudioTimeStamp* inInputTime,
AudioBufferList* outOutputData,
const AudioTimeStamp* inOutputTime,
void* inClientData)
{
// your IOProc here
...
}
// Deprecated
void DeprecatedFakePlay(AudioObjectID inDevice, void* inClientData)
{
// register the IOProc
OSStatus theError = AudioDeviceAddIOProc(inDevice, MyIOProc, inClientData);
// handle errors
// start IO
theError = AudioDeviceStart(inDevice, MyIOProc);
...
// stop IO
theError = AudioDeviceStop(inDevice, MyIOProc);
// unregister the IOProc
theError = AudioDeviceRemoveIOProc(inDevice, MyIOProc);
} |
Listing 2 New - AudioDeviceIOProc Registration.
OSStatus MyIOProc(AudioDeviceID inDevice,
const AudioTimeStamp* inNow,
const AudioBufferList* inInputData,
const AudioTimeStamp* inInputTime,
AudioBufferList* outOutputData,
const AudioTimeStamp* inOutputTime,
void* inClientData)
{
// your IOProc here
...
}
// New Mac OS X 10.5+
void NewFakePlay(AudioObjectID inDevice, void* inClientData)
{
// register the IOProc
AudioDeviceIOProcID theIOProcID = NULL;
OSStatus theError = AudioDeviceCreateIOProcID(inDevice, MyIOProc, inClientData, &theIOProcID);
// handle errors
// ensure theIOProcID != NULL
// start IO
theError = AudioDeviceStart(inDevice, theIOProcID);
...
// stop IO
theError = AudioDeviceStop(inDevice, theIOProcID);
// unregister the IOProc
theError = AudioDeviceDestroyIOProcID(inDevice, theIOProcID);
} |
Property Accessor Changes
The Property Accessor changes are a little different but can be summed up like this -- All the individual class property access functions have been replaced by a similarly named AudioObject-prefixed function.
The table below illustrates the basic mapping where 'XXX' in the older API name can be replaced by 'Hardware', 'Device' or 'Stream':
Deprecated API | New API |
|---|---|
AudioXXXGetPropertyInfo | AudioObjectHasProperty, AudioObjectIsPropertySettable, AudioObjectGetPropertyDataSize |
AudioXXXGetProperty | AudioObjectGetPropertyData |
AudioXXXSetProperty | AudioObjectSetPropertyData |
AudioXXXAddPropertyListener | AudioObjectAddPropertyListener |
AudioXXXRemovePropertyListener | AudioObjectRemovePropertyListener |
The key difference between the deprecated and new API is the use of the AudioObjectPropertyAddress structure.
struct AudioObjectPropertyAddress
{
AudioObjectPropertySelector mSelector;
AudioObjectPropertyScope mScope;
AudioObjectPropertyElement mElement;
};
typedef struct AudioObjectPropertyAddress AudioObjectPropertyAddress; |
The AudioObjectPropertyAddress structure is used with the new APIs to encapsulate the distinguishing information for a specific property; the selector ID (mSelector), the scope (mScope) and the element (mElement). The HAL uses the terms scope and element in the same way that the AudioUnit API does.
Most objects have only one scope and one element, for example the System Object, Stream Object and Control Object have only one scope, kAudioObjectPropertyScopeGlobal and one element, kAudioObjectPropertyElementMaster.
Device Objects are different and may have three other scopes beside kAudioObjectPropertyScopeGlobal. These are kAudioDevicePropertyScopeInput, kAudioDevicePropertyScopeOutput, and kAudioDevicePropertyScopePlayThrough.
For a Device Object, the element (mElement) of the AudioObjectPropertyAddress structure refers to the channel number on the device.
Examples
Listing 3 Deprecated - Getting the default Input device.
AudioDeviceID DeprecatedGetDefaultInputDevice()
{
AudioDeviceID theAnswer = 0;
UInt32 theSize = sizeof(AudioDeviceID);
OSStatus theError = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice,
&theSize,
&theAnswer);
// handle errors
return theAnswer;
} |
Listing 4 New - Getting the default input device.
AudioDeviceID NewGetDefaultInputDevice()
{
AudioDeviceID theAnswer = 0;
UInt32 theSize = sizeof(AudioDeviceID);
AudioObjectPropertyAddress theAddress = { kAudioHardwarePropertyDefaultInputDevice,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster };
OSStatus theError = AudioObjectGetPropertyData(kAudioObjectSystemObject,
&theAddress,
0,
NULL,
&theSize,
&theAnswer);
// handle errors
return theAnswer;
} |
Listing 5 Deprecated - Getting the current volume scalar.
Float32 DeprecatedGetVolumeScalar(AudioDeviceID inDevice, bool inIsInput, UInt32 inChannel)
{
Float32 theAnswer = 0;
UInt32 theSize = sizeof(Float32);
OSStatus theError = AudioDeviceGetProperty(inDevice,
inChannel,
inIsInput,
kAudioDevicePropertyVolumeScalar,
&theSize,
&theAnswer);
// handle errors
return theAnswer;
} |
Listing 6 New - Getting the current volume scalar.
Float32 NewGetVolumeScalar(AudioDeviceID inDevice, bool inIsInput, UInt32 inChannel)
{
Float32 theAnswer = 0;
UInt32 theSize = sizeof(Float32);
AudioObjectPropertyScope theScope = inIsInput ? kAudioDevicePropertyScopeInput :
kAudioDevicePropertyScopeOutput
AudioObjectPropertyAddress theAddress = { kAudioDevicePropertyVolumeScalar,
theScope,
inChannel };
OSStatus theError = AudioObjectGetPropertyData(inDevice,
&theAddress,
0,
NULL,
&theSize,
&theAnswer);
// handle errors
return theAnswer;
} |
Note the usage of kAudioObjectSystemObject when replacing the old APIs. kAudioObjectSystemObject is an AudioObjectID that always refers to the one and only instance of the Audio System Object.
Reference
See CoreAudio/AudioHardware.h for further details.
Document Revision History
| Date | Notes |
|---|---|
| 2010-04-14 | Editorial |
| 2010-04-08 | Editorial |
| 2010-01-09 | New document that discusses transitioning to the newer AudioDevice and AudioObject APIs available on Mac OS X 10.5+ |
Copyright © 2010 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2010-04-14