Search code examples
macoscore-audioiokitkernel-extension

How to set speaker configuration programatically using Core Audio API on Mac OS X?


I have a 7.1 channel audio output device and a custom kext to drive that. My custom application needs to send 7.1 rear channel audio data to the device but the device receives only 2 channel audio data. I checked "Configure Speaker" option in "Audio MIDI setup" application and it's set to stereo. When I set it to "7.1 Rear Surround" everything works fine. In my final product, I don't want the user to have to do all of this manually. So, the question is - Is there any Core Audio API or any other means of doing this programatically?

enter image description here


Solution

  • Ok, after playing around with some Core Audio APIs, finally I could get this done.

    1. Get the AudioDeviceID:

      AudioDeviceID audioDevice = getMyAwesomeDeviceID();
      
    2. Create an AudioObjectPropertyAddress:

      AudioObjectPropertyAddress propertyAddress;
      propertyAddress.mSelector = kAudioDevicePropertyPreferredChannelLayout;
      propertyAddress.mScope = kAudioDevicePropertyScopeOutput;
      propertyAddress.mElement = kAudioObjectPropertyElementMaster;
      
    3. Query if the audio object has this property:

      AudioObjectHasProperty(audioDevice, &propertyAddress)
      
    4. Get the data size of this property and create AudioChannelLayout:

      UInt32 propSize(0);
      AudioObjectGetPropertyDataSize(audioDevice, &propertyAddress, 0, NULL, &propSize);
      AudioChannelLayout* layout = (AudioChannelLayout*)malloc(propSize);
      
    5. Configure your AudioChannelLayout structure (eg: stereo layout):

      AudioChannelLabel labels[2] = {kAudioChannelLabel_Right, kAudioChannelLabel_Left};
      
      layout->mNumberChannelDescriptions = 2;
      for (UInt32 i = 2; i < layout->mNumberChannelDescriptions; i++) {
          layout->mChannelDescriptions[i].mChannelLabel = labels[i];
          layout->mChannelDescriptions[i].mChannelFlags = kAudioChannelFlags_AllOff;
      }
      
    6. Set the AudioObject property data:

      AudioObjectSetPropertyData(audioDevice, &propertyAddress, 0, NULL, propSize, layout);