Skip to content

Instantly share code, notes, and snippets.

@ChunMinChang
Last active June 5, 2020 09:52
Show Gist options
  • Save ChunMinChang/ea74c8228745449873716e1d98ba956e to your computer and use it in GitHub Desktop.
Save ChunMinChang/ea74c8228745449873716e1d98ba956e to your computer and use it in GitHub Desktop.
CoreAudio Playground #coreaudio #multichannel_audio
CXX = g++
CFLAGS=-Wall -std=c++14
LIBRARIES = -framework AudioUnit -framework CoreAudio
all:
$(CC) $(CFLAGS) $(LIBRARIES) PreferredChannelLayout.cpp -o PreferredChannelLayout
clean:
rm PreferredChannelLayout
#include <cassert>
#include <iostream>
#include <AudioUnit/AudioUnit.h>
#include <CoreAudio/CoreAudio.h>
#define AU_OUT_BUS 0
#define AU_IN_BUS 1
#define DEBUG true // Set true to log the debugging messages.
#define LOG(...) DEBUG && fprintf(stdout, __VA_ARGS__)
// OSStatus
// get_number_of_supported_channels()
// {
// AudioUnit au = nullptr;
// AudioComponentDescription desc;
// AudioComponent comp;
//
// UInt32 size = 0;
// OSStatus rv = noErr;
// Boolean writable;
//
// desc.componentType = kAudioUnitType_Output;
// // desc.componentSubType = kAudioUnitSubType_DefaultOutput;
// desc.componentSubType = kAudioUnitSubType_HALOutput;
// desc.componentManufacturer = kAudioUnitManufacturer_Apple;
// desc.componentFlags = 0;
// desc.componentFlagsMask = 0;
//
// comp = AudioComponentFindNext(NULL, &desc);
// if (comp == NULL) {
// LOG("%d: Could not find default audio output hardware.\n", rv);
// return rv;
// }
//
// rv = AudioComponentInstanceNew(comp, &au);
// if (rv != noErr) {
// LOG("%d: Could not link default audio output hardware to the audio unit.\n", rv);
// return rv;
// }
//
// rv = AudioUnitGetPropertyInfo(au,
// kAudioUnitProperty_SupportedNumChannels,
// kAudioUnitScope_Global,
// AU_OUT_BUS,
// &size,
// &writable);
// if (rv != noErr) {
// LOG("%d: Could not get size of kAudioUnitProperty_SupportedNumChannels.\n", rv);
// return rv;
// }
// assert(size > 0 && writable);
//
// AUChannelInfo* info = (AUChannelInfo*) malloc(size);
// rv = AudioUnitGetProperty(au,
// kAudioUnitProperty_SupportedNumChannels,
// kAudioUnitScope_Global,
// AU_OUT_BUS,
// info,
// &size);
// if (rv != noErr) {
// LOG("%d: Could not get kAudioUnitProperty_SupportedNumChannels.\n", rv);
// return rv;
// }
// LOG("input channels: %d, output channels: %d\n", info->inChannels, info->outChannels);
// free(info);
//
// return rv;
// }
OSStatus
get_channel_layout(bool preferred)
{
AudioUnit outputUnit;
AudioComponentDescription desc;
AudioComponent comp;
AudioDeviceID deviceId = 0;
UInt32 size;
OSStatus rv = noErr;
Boolean writable;
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_DefaultOutput;
// desc.componentSubType = kAudioUnitSubType_HALOutput;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
comp = AudioComponentFindNext(NULL, &desc);
if (comp == NULL) {
LOG("%d: Could not find default audio output hardware.\n", rv);
return rv;
}
rv = AudioComponentInstanceNew(comp, &outputUnit);
if (rv != noErr) {
LOG("%d: Could not link default audio output hardware to the audio unit.\n", rv);
return rv;
}
// Check if we have IO
UInt32 hasIO = 0;
size = sizeof(hasIO);
rv = AudioUnitGetProperty(outputUnit,
kAudioOutputUnitProperty_HasIO,
kAudioUnitScope_Output,
AU_OUT_BUS,
&hasIO,
&size);
if (!hasIO) {
LOG("%d: No audio output for this audio unit.\n", rv);
return rv;
}
// Get the current device
size = sizeof(deviceId);
rv = AudioUnitGetProperty(outputUnit,
kAudioOutputUnitProperty_CurrentDevice,
kAudioUnitScope_Output,
AU_OUT_BUS,
&deviceId,
&size);
if (rv != noErr) {
LOG("%d: Could not get current audio output device.\n", rv);
return rv;
}
LOG("device id: %d\n", deviceId);
// Get the current format
AudioStreamBasicDescription format;
size = sizeof(format);
rv = AudioUnitGetProperty(outputUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
AU_OUT_BUS,
&format,
&size);
if (rv != noErr) {
LOG("%d: Could not get current audio output format.\n", rv);
}
LOG("Output device sampling rate: %.2f with %d channels.\n", format.mSampleRate, format.mChannelsPerFrame);
// Get the default channel layout
size = 0;
rv = AudioUnitGetPropertyInfo(outputUnit,
(preferred) ? kAudioDevicePropertyPreferredChannelLayout : kAudioUnitProperty_AudioChannelLayout,
kAudioUnitScope_Output,
AU_OUT_BUS,
&size,
&writable);
if (rv != noErr) {
LOG("%d: Could not get size of %s.\n", rv, (preferred) ? "kAudioDevicePropertyPreferredChannelLayout" : "kAudioUnitProperty_AudioChannelLayout");
return rv;
}
assert(size > 0);
AudioChannelLayout* layout = (AudioChannelLayout*) malloc(size);
rv = AudioUnitGetProperty(outputUnit,
(preferred) ? kAudioDevicePropertyPreferredChannelLayout : kAudioUnitProperty_AudioChannelLayout,
kAudioUnitScope_Output,
AU_OUT_BUS,
layout,
&size);
if (rv != noErr) {
LOG("%d: Could not get %s.\n", rv, (preferred) ? "kAudioDevicePropertyPreferredChannelLayout" : "kAudioUnitProperty_AudioChannelLayout");
return rv;
}
if (layout->mChannelLayoutTag != kAudioChannelLayoutTag_UseChannelDescriptions) {
// kAudioChannelLayoutTag_UseChannelBitmap
// kAudioChannelLayoutTag_Mono
// kAudioChannelLayoutTag_Stereo
// ....
LOG("%d: We only handle UseChannelDescriptions for now.\n", rv);
return rv;
}
LOG("%schannel layout:\n", (preferred) ? "preferred " : "");
for (UInt32 i = 0; i < layout->mNumberChannelDescriptions; ++i) {
LOG("[%d] %d(0x%x)\n", i, layout->mChannelDescriptions[i].mChannelLabel, layout->mChannelDescriptions[i].mChannelLabel);
}
return rv;
}
int main()
{
get_channel_layout(false);
get_channel_layout(true);
// get_number_of_supported_channels();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment