2011-01-01 9 views
9

मैं सिस्टम के इनपुट उपकरणों की सूची पुनर्प्राप्त करने के लिए ओएस एक्स में 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 डिवाइस आईडी के माध्यम से पुनरावृत्ति आउटपुट से आदानों सॉर्ट करने के लिए मिल गया है है: यहाँ कुछ कोड मैं परिवर्तित कि काम करना चाहिए (अपरीक्षित हालांकि) है।

इस लूप के अंदर सिर्फ हिस्सा है:

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; 
    } 

मुझे आशा है कि यह किसी और में मदद करता है, मैं यह जानने कि एप्पल xcode में अपने सी +++ एचएएल इंटरफेस के लिए स्रोत प्रदान करता है/अतिरिक्त/CoreAudio/एचएएल/समाप्त हो गया एचपीबेस जो इसे समझने में महत्वपूर्ण था।

4

मैंने सभी इनपुट उपकरणों को संख्या के साथ प्रिंट करने के लिए "sbooth" द्वारा सबमिट किए गए कोड को थोड़ा संशोधित किया है। प्रत्येक डिवाइस के लिए बफर का और नहीं। प्रत्येक बफर के लिए चैनलों का।

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

स्विफ्ट 3.0 Xcode 8 बीटा 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 
} 
संबंधित मुद्दे

 संबंधित मुद्दे