2011-01-01 11 views
9

OS XでAudioObjectGetPropertyDataを使用してシステムの入力デバイスのリストを取得するにはどうすればよいですか?デバイスは、あなたがチェックし、それが任意の入力チャンネルを持っているかどうかを確認する必要がある入力デバイスであるかどうかを確認するにはAudioObjectGetPropertyDataを使用して入力デバイスのリストを取得する

AudioDeviceID devices[12]; 
UInt32 arraySize = sizeof(devices); 

AudioObjectPropertyAddress thePropertyAddress = { kAudioHardwarePropertyDevices, 
                kAudioObjectPropertyScopeGlobal, 
                kAudioObjectPropertyElementMaster }; 

AudioObjectGetPropertyData(kAudioObjectSystemObject, 
          &thePropertyAddress, 
          0, 
          NULL, 
          &arraySize, 
          &devices); 

答えて

22

:私は現在、デバイスのグローバルリストを取得するため、次のダミーのコードを持っています。ここで私はそれが動作するはず変換いくつかのコード(未テストけれども)は次のとおりです。

CFArrayRef CreateInputDeviceArray() 
{ 
    AudioObjectPropertyAddress propertyAddress = { 
     kAudioHardwarePropertyDevices, 
     kAudioObjectPropertyScopeGlobal, 
     kAudioObjectPropertyElementMaster 
    }; 

    UInt32 dataSize = 0; 
    OSStatus status = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &dataSize); 
    if(kAudioHardwareNoError != status) { 
     fprintf(stderr, "AudioObjectGetPropertyDataSize (kAudioHardwarePropertyDevices) failed: %i\n", status); 
     return NULL; 
    } 

    UInt32 deviceCount = static_cast<UInt32>(dataSize/sizeof(AudioDeviceID)); 

    AudioDeviceID *audioDevices = static_cast<AudioDeviceID *>(malloc(dataSize)); 
    if(NULL == audioDevices) { 
     fputs("Unable to allocate memory", stderr); 
     return NULL; 
    } 

    status = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &dataSize, audioDevices); 
    if(kAudioHardwareNoError != status) { 
     fprintf(stderr, "AudioObjectGetPropertyData (kAudioHardwarePropertyDevices) failed: %i\n", status); 
     free(audioDevices), audioDevices = NULL; 
     return NULL; 
    } 

    CFMutableArrayRef inputDeviceArray = CFArrayCreateMutable(kCFAllocatorDefault, deviceCount, &kCFTypeArrayCallBacks); 
    if(NULL == inputDeviceArray) { 
     fputs("CFArrayCreateMutable failed", stderr); 
     free(audioDevices), audioDevices = NULL; 
     return NULL; 
    } 

    // Iterate through all the devices and determine which are input-capable 
    propertyAddress.mScope = kAudioDevicePropertyScopeInput; 
    for(UInt32 i = 0; i < deviceCount; ++i) { 
     // Query device UID 
     CFStringRef deviceUID = NULL; 
     dataSize = sizeof(deviceUID); 
     propertyAddress.mSelector = kAudioDevicePropertyDeviceUID; 
     status = AudioObjectGetPropertyData(audioDevices[i], &propertyAddress, 0, NULL, &dataSize, &deviceUID); 
     if(kAudioHardwareNoError != status) { 
      fprintf(stderr, "AudioObjectGetPropertyData (kAudioDevicePropertyDeviceUID) failed: %i\n", status); 
      continue; 
     } 

     // Query device name 
     CFStringRef deviceName = NULL; 
     dataSize = sizeof(deviceName); 
     propertyAddress.mSelector = kAudioDevicePropertyDeviceNameCFString; 
     status = AudioObjectGetPropertyData(audioDevices[i], &propertyAddress, 0, NULL, &dataSize, &deviceName); 
     if(kAudioHardwareNoError != status) { 
      fprintf(stderr, "AudioObjectGetPropertyData (kAudioDevicePropertyDeviceNameCFString) failed: %i\n", status); 
      continue; 
     } 

     // Query device manufacturer 
     CFStringRef deviceManufacturer = NULL; 
     dataSize = sizeof(deviceManufacturer); 
     propertyAddress.mSelector = kAudioDevicePropertyDeviceManufacturerCFString; 
     status = AudioObjectGetPropertyData(audioDevices[i], &propertyAddress, 0, NULL, &dataSize, &deviceManufacturer); 
     if(kAudioHardwareNoError != status) { 
      fprintf(stderr, "AudioObjectGetPropertyData (kAudioDevicePropertyDeviceManufacturerCFString) failed: %i\n", status); 
      continue; 
     } 

     // Determine if the device is an input device (it is an input device if it has input channels) 
     dataSize = 0; 
     propertyAddress.mSelector = kAudioDevicePropertyStreamConfiguration; 
     status = AudioObjectGetPropertyDataSize(audioDevices[i], &propertyAddress, 0, NULL, &dataSize); 
     if(kAudioHardwareNoError != status) { 
      fprintf(stderr, "AudioObjectGetPropertyDataSize (kAudioDevicePropertyStreamConfiguration) failed: %i\n", status); 
      continue; 
     } 

     AudioBufferList *bufferList = static_cast<AudioBufferList *>(malloc(dataSize)); 
     if(NULL == bufferList) { 
      fputs("Unable to allocate memory", stderr); 
      break; 
     } 

     status = AudioObjectGetPropertyData(audioDevices[i], &propertyAddress, 0, NULL, &dataSize, bufferList); 
     if(kAudioHardwareNoError != status || 0 == bufferList->mNumberBuffers) { 
      if(kAudioHardwareNoError != status) 
       fprintf(stderr, "AudioObjectGetPropertyData (kAudioDevicePropertyStreamConfiguration) failed: %i\n", status); 
      free(bufferList), bufferList = NULL; 
      continue;   
     } 

     free(bufferList), bufferList = NULL; 

     // Add a dictionary for this device to the array of input devices 
     CFStringRef keys [] = { CFSTR("deviceUID"),  CFSTR("deviceName"), CFSTR("deviceManufacturer") }; 
     CFStringRef values [] = { deviceUID,    deviceName,    deviceManufacturer }; 

     CFDictionaryRef deviceDictionary = CFDictionaryCreate(kCFAllocatorDefault, 
                   reinterpret_cast<const void **>(keys), 
                   reinterpret_cast<const void **>(values), 
                   3, 
                   &kCFTypeDictionaryKeyCallBacks, 
                   &kCFTypeDictionaryValueCallBacks); 


     CFArrayAppendValue(inputDeviceArray, deviceDictionary); 

     CFRelease(deviceDictionary), deviceDictionary = NULL; 
    } 

    free(audioDevices), audioDevices = NULL; 

    // Return a non-mutable copy of the array 
    CFArrayRef copy = CFArrayCreateCopy(kCFAllocatorDefault, inputDeviceArray); 
    CFRelease(inputDeviceArray), inputDeviceArray = NULL; 

    return copy; 
} 
+0

この回答とコードスニペットをいただきありがとうございます。これは非常に便利です! – iKenndac

+0

あなたは大歓迎です! – sbooth

+0

これは素晴らしい動作です!答えとしてマークする必要があります。 – rocky

7

ここで私はCoreAudio対応デバイスIDを反復処理する際の出力から入力をソートするために発見した最良の方法です。私は、これは私はAppleが/エクストラ/ CoreAudio対応/ HAL/Xcodeで自分のC+++ HALインタフェースのソースを提供することを見つける終了し、他の誰かに役立ちます願ってい

BOOL isMic = NO; 
    BOOL isSpeaker = NO; 

    AudioDeviceID device  = audioDevices[i]; 

    // Determine direction of the device by asking for the number of input or 
    // output streams. 
    propertyAddress.mSelector = kAudioDevicePropertyStreams; 
    propertyAddress.mScope  = kAudioDevicePropertyScopeInput; 

    UInt32 dataSize    = 0; 
    OSStatus status    = AudioObjectGetPropertyDataSize(device, 
                   &propertyAddress, 
                   0, 
                   NULL, 
                   &dataSize);   
    UInt32 streamCount   = dataSize/sizeof(AudioStreamID); 

    if (streamCount > 0) 
    { 
     isMic = YES; 
    } 

    propertyAddress.mScope = kAudioDevicePropertyScopeOutput;  
    dataSize    = 0; 
    status     = AudioObjectGetPropertyDataSize(device, 
                  &propertyAddress, 
                  0, 
                  NULL, 
                  &dataSize);   
    streamCount    = dataSize/sizeof(AudioStreamID); 

    if (streamCount > 0) 
    { 
     isSpeaker = YES; 
    } 

これは、ループ内ほんの一部でありますこれを理解する上で重要だったHPBase。

4

"sbooth"が提出したコードを少し修正して、すべての入力デバイスをnoと一緒に印刷しました。各デバイスのバッファの数。各バッファのチャネルの数。良いしばらくの間、これで苦労3.0 Xcodeの8ベータ5

CFArrayRef CreateInputDeviceArray() 
{ 
    AudioObjectPropertyAddress propertyAddress = { 
     kAudioHardwarePropertyDevices, 
     kAudioObjectPropertyScopeGlobal, 
     kAudioObjectPropertyElementMaster 
    }; 

    UInt32 dataSize = 0; 
    OSStatus status = AudioHardwareServiceGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &dataSize); 
    if(kAudioHardwareNoError != status) { 
     fprintf(stderr, "AudioObjectGetPropertyDataSize (kAudioHardwarePropertyDevices) failed: %i\n", status); 
     return NULL; 
    } 

    UInt32 deviceCount = (UInt32)(dataSize/sizeof(AudioDeviceID)); 

    AudioDeviceID *audioDevices = (AudioDeviceID *)(malloc(dataSize)); 
    if(NULL == audioDevices) { 
     fputs("Unable to allocate memory", stderr); 
     return NULL; 
    } 

    status = AudioHardwareServiceGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &dataSize, audioDevices); 
    if(kAudioHardwareNoError != status) { 
     fprintf(stderr, "AudioObjectGetPropertyData (kAudioHardwarePropertyDevices) failed: %i\n", status); 
     free(audioDevices), audioDevices = NULL; 
     return NULL; 
    } 

    CFMutableArrayRef inputDeviceArray = CFArrayCreateMutable(kCFAllocatorDefault, deviceCount, &kCFTypeArrayCallBacks); 
    if(NULL == inputDeviceArray) { 
     fputs("CFArrayCreateMutable failed", stderr); 
     free(audioDevices), audioDevices = NULL; 
     return NULL; 
    } 

    // Iterate through all the devices and determine which are input-capable 
    propertyAddress.mScope = kAudioDevicePropertyScopeInput; 
    for(UInt32 i = 0; i < deviceCount; ++i) { 
     // Query device UID 
     CFStringRef deviceUID = NULL; 
     dataSize = sizeof(deviceUID); 
     propertyAddress.mSelector = kAudioDevicePropertyDeviceUID; 
     status = AudioHardwareServiceGetPropertyData(audioDevices[i], &propertyAddress, 0, NULL, &dataSize, &deviceUID); 
     if(kAudioHardwareNoError != status) { 
      fprintf(stderr, "AudioObjectGetPropertyData (kAudioDevicePropertyDeviceUID) failed: %i\n", status); 
      continue; 
     } 

     // Query device name 
     CFStringRef deviceName = NULL; 
     dataSize = sizeof(deviceName); 
     propertyAddress.mSelector = kAudioDevicePropertyDeviceNameCFString; 
     status = AudioHardwareServiceGetPropertyData(audioDevices[i], &propertyAddress, 0, NULL, &dataSize, &deviceName); 
     if(kAudioHardwareNoError != status) { 
      fprintf(stderr, "AudioObjectGetPropertyData (kAudioDevicePropertyDeviceNameCFString) failed: %i\n", status); 
      continue; 
     } 

     // Query device manufacturer 
     CFStringRef deviceManufacturer = NULL; 
     dataSize = sizeof(deviceManufacturer); 
     propertyAddress.mSelector = kAudioDevicePropertyDeviceManufacturerCFString; 
     status = AudioHardwareServiceGetPropertyData(audioDevices[i], &propertyAddress, 0, NULL, &dataSize, &deviceManufacturer); 
     if(kAudioHardwareNoError != status) { 
      fprintf(stderr, "AudioObjectGetPropertyData (kAudioDevicePropertyDeviceManufacturerCFString) failed: %i\n", status); 
      continue; 
     } 

     // Determine if the device is an input device (it is an input device if it has input channels) 
     dataSize = 0; 
     propertyAddress.mSelector = kAudioDevicePropertyStreamConfiguration; 
     status = AudioHardwareServiceGetPropertyDataSize(audioDevices[i], &propertyAddress, 0, NULL, &dataSize); 
     if(kAudioHardwareNoError != status) { 
      fprintf(stderr, "AudioObjectGetPropertyDataSize (kAudioDevicePropertyStreamConfiguration) failed: %i\n", status); 
      continue; 
     } 

     AudioBufferList *bufferList = (AudioBufferList *)(malloc(dataSize)); 
     if(NULL == bufferList) { 
      fputs("Unable to allocate memory", stderr); 
      break; 
     } 

     status = AudioHardwareServiceGetPropertyData(audioDevices[i], &propertyAddress, 0, NULL, &dataSize, bufferList); 
     if(kAudioHardwareNoError != status || 0 == bufferList->mNumberBuffers) { 
      if(kAudioHardwareNoError != status) 
       fprintf(stderr, "AudioObjectGetPropertyData (kAudioDevicePropertyStreamConfiguration) failed: %i\n", status); 
      free(bufferList), bufferList = NULL; 
      continue; 
     } 
     UInt32 numBuffers = bufferList->mNumberBuffers; 

     printf("\n\ndeviceUID:%s \tdeviceName: %s\ndeviceManufacturer: %s\t#Buffers:%d", \ 
       CFStringGetCStringPtr(deviceUID, kCFStringEncodingMacRoman),\ 
       CFStringGetCStringPtr(deviceName, kCFStringEncodingMacRoman), \ 
       CFStringGetCStringPtr(deviceManufacturer, kCFStringEncodingMacRoman), \ 
       numBuffers 
       ); 
     for (UInt8 j = 0; j < numBuffers; j++) { 
      AudioBuffer ab = bufferList->mBuffers[j]; 
      printf("\n#Channels: %d DataByteSize: %d", ab.mNumberChannels, ab.mDataByteSize); 
     } 

     free(bufferList), bufferList = NULL; 

     // Add a dictionary for this device to the array of input devices 
     CFStringRef keys [] = { CFSTR("deviceUID"),  CFSTR("deviceName"), CFSTR("deviceManufacturer") }; 
     CFStringRef values [] = { deviceUID,    deviceName,    deviceManufacturer }; 



     CFDictionaryRef deviceDictionary = CFDictionaryCreate(kCFAllocatorDefault, 
                   (const void **)(keys), 
                   (const void **)(values), 
                   3, 
                   &kCFTypeDictionaryKeyCallBacks, 
                   &kCFTypeDictionaryValueCallBacks); 


     CFArrayAppendValue(inputDeviceArray, deviceDictionary); 

     CFRelease(deviceDictionary), deviceDictionary = NULL; 
    } 

    free(audioDevices), audioDevices = NULL; 

    // Return a non-mutable copy of the array 
    CFArrayRef copy = CFArrayCreateCopy(kCFAllocatorDefault, inputDeviceArray); 
    CFRelease(inputDeviceArray), inputDeviceArray = NULL; 

    return copy; 
} 
+0

スウィフトではどうやってこれをやりますか? – Boggartfly

5

スウィフトが、これは今のところ正常に動作するようです。

func handle(_ errorCode: OSStatus) throws { 
    if errorCode != kAudioHardwareNoError { 
     let error = NSError(domain: NSOSStatusErrorDomain, code: Int(errorCode), userInfo: [NSLocalizedDescriptionKey : "CAError: \(errorCode)" ]) 
     NSApplication.shared().presentError(error) 
     throw error 
    } 
} 

func getInputDevices() throws -> [AudioDeviceID] { 

    var inputDevices: [AudioDeviceID] = [] 

    // Construct the address of the property which holds all available devices 
    var devicesPropertyAddress = AudioObjectPropertyAddress(mSelector: kAudioHardwarePropertyDevices, mScope: kAudioObjectPropertyScopeGlobal, mElement: kAudioObjectPropertyElementMaster) 
    var propertySize = UInt32(0) 

    // Get the size of the property in the kAudioObjectSystemObject so we can make space to store it 
    try handle(AudioObjectGetPropertyDataSize(AudioObjectID(kAudioObjectSystemObject), &devicesPropertyAddress, 0, nil, &propertySize)) 

    // Get the number of devices by dividing the property address by the size of AudioDeviceIDs 
    let numberOfDevices = Int(propertySize)/sizeof(AudioDeviceID.self) 

    // Create space to store the values 
    var deviceIDs: [AudioDeviceID] = [] 
    for _ in 0 ..< numberOfDevices { 
     deviceIDs.append(AudioDeviceID()) 
    } 

    // Get the available devices 
    try handle(AudioObjectGetPropertyData(AudioObjectID(kAudioObjectSystemObject), &devicesPropertyAddress, 0, nil, &propertySize, &deviceIDs)) 

    // Iterate 
    for id in deviceIDs { 

     // Get the device name for fun 
     var name: CFString = "" 
     var propertySize = UInt32(sizeof(CFString.self)) 
     var deviceNamePropertyAddress = AudioObjectPropertyAddress(mSelector: kAudioDevicePropertyDeviceNameCFString, mScope: kAudioObjectPropertyScopeGlobal, mElement: kAudioObjectPropertyElementMaster) 
     try handle(AudioObjectGetPropertyData(id, &deviceNamePropertyAddress, 0, nil, &propertySize, &name)) 

     // Check the input scope of the device for any channels. That would mean it's an input device 

     // Get the stream configuration of the device. It's a list of audio buffers. 
     var streamConfigAddress = AudioObjectPropertyAddress(mSelector: kAudioDevicePropertyStreamConfiguration, mScope: kAudioDevicePropertyScopeInput, mElement: 0) 

     // Get the size so we can make room again 
     try handle(AudioObjectGetPropertyDataSize(id, &streamConfigAddress, 0, nil, &propertySize)) 

     // Create a buffer list with the property size we just got and let core audio fill it 
     let audioBufferList = AudioBufferList.allocate(maximumBuffers: Int(propertySize)) 
     try handle(AudioObjectGetPropertyData(id, &streamConfigAddress, 0, nil, &propertySize, audioBufferList.unsafeMutablePointer)) 

     // Get the number of channels in all the audio buffers in the audio buffer list 
     var channelCount = 0 
     for i in 0 ..< Int(audioBufferList.unsafeMutablePointer.pointee.mNumberBuffers) { 
      channelCount = channelCount + Int(audioBufferList[i].mNumberChannels) 
     } 

     free(audioBufferList.unsafeMutablePointer) 

     // If there are channels, it's an input device 
     if channelCount > 0 { 
      Swift.print("Found input device '\(name)' with \(channelCount) channels") 
      inputDevices.append(id) 
     } 
    } 

    return inputDevices 
} 
関連する問題