音声出力デバイスの一覧を取得する

NSSoundの

- (void)setPlaybackDeviceIdentifier:(NSString *)playbackDeviceIdentifier;

に渡す引数について
とりあえず、出力デバイスの一覧欲しいよねってことで、
やってみます。


さて、playbackDeviceIdentifierをどうやってもってくるものか。。。
ちなみにNSSoundには、選択可能なデバイスを返してくれるようなメソッドは用意されていません。
CoreAudioを使ってデバイスのIDを取得します。
参考URL
http://objective-audio.jp/2008/04/core-audio-4.html
http://objective-audio.jp/2009/09/coreaudio-audioobject.html
macos - AudioObjectGetPropertyData to get a list of input devices - Stack Overflow

/* CoreAudioを使用するフレームワークに追加するのと、インポートするのを忘れずに */
OSStatus err;
AudioDeviceID *deviceIDPtr = NULL;
UInt32 size;
AudioObjectPropertyAddress propAddr;

/*
 * 全てのデバイスを取得
 *   setPlaybackDeviceIdentifier:にインプットデバイスを渡すと落ちてしまうので、
 *   アウトプットデバイスだけの一覧を取得したい
 *   ただ、アウトプットデバイスの一覧を一発で取得する方法がどうも見当たらない
 *   mScopeにkAudioDevicePropertyScopeOutputを入れてやれば、できそうに見えるが、
 *   AudioDeviceIDには指定できないことに注意。
 *   なので、各デバイスが持っているストリームを逐一チェックすることにする
 */
propAddr.mScope    = kAudioObjectPropertyScopeGlobal;
propAddr.mElement  = kAudioObjectPropertyElementMaster;
propAddr.mSelector = kAudioHardwarePropertyDevices;{
    
    err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propAddr, 0, NULL, &size);
    if(err != noErr) goto catchErr;
    
    deviceIDPtr = malloc(size);
    
    err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propAddr, 0, NULL, &size, deviceIDPtr);
    if(err != noErr) goto catchErr;
}

/* 取得したデバイスの数 */
UInt32 count = size / sizeof(AudioDeviceID);

/* 各デバイス */
int i;
for(i=0; i<count; i++){
    
    // デバイスがアウトプットストリームを持っているか確かめる
    propAddr.mSelector = kAudioDevicePropertyStreams;{
        propAddr.mScope    = kAudioDevicePropertyScopeOutput;
        err = AudioObjectGetPropertyDataSize(deviceIDPtr[i], &propAddr, 0, NULL, &size);
        if (err != noErr) {
            goto catchErr;
        }
        
        UInt32 streamCount = size/sizeof(AudioStreamID);
        if (streamCount == 0) {
            continue;
        }
    }
    
    
    propAddr.mScope    = kAudioObjectPropertyScopeGlobal;
    
    
    // デバイスのUIDを取得
    //  こいつを 『setPlaybackDeviceIdentifier:』に渡してやる
    CFStringRef deviceUID;
    propAddr.mSelector = kAudioDevicePropertyDeviceUID;{
        err = AudioObjectGetPropertyDataSize(deviceIDPtr[i], &propAddr, 0, NULL, &size);
        if(err != noErr) goto catchErr;
        
        err = AudioObjectGetPropertyData(deviceIDPtr[i], &propAddr, 0, NULL, &size, &deviceUID);
        if(err != noErr) {
            CFRelease( deviceUID );
            goto catchErr;
        }
    }
    
    // デバイスの名前を取得
    CFStringRef deviceName;
    propAddr.mSelector = kAudioObjectPropertyName;{
        err = AudioObjectGetPropertyDataSize( deviceIDPtr[i], &propAddr, 0, NULL, &size );
        if(err != noErr) goto catchErr;
        
        err = AudioObjectGetPropertyData( deviceIDPtr[i], &propAddr, 0, NULL, &size, &deviceName ); 
        if(err != noErr) {
            CFRelease( deviceName );
            CFRelease( deviceUID );
            goto catchErr;
        }
    }

   /* do something */

   CFRelease( deviceName );
   CFRelease( deviceUID );
}