static bool osx_output_enable(struct audio_output *ao, GError **error_r) { struct osx_output *oo = (struct osx_output *)ao; ComponentDescription desc; desc.componentType = kAudioUnitType_Output; desc.componentSubType = oo->component_subtype; desc.componentManufacturer = kAudioUnitManufacturer_Apple; desc.componentFlags = 0; desc.componentFlagsMask = 0; Component comp = FindNextComponent(NULL, &desc); if (comp == 0) { g_set_error(error_r, osx_output_quark(), 0, "Error finding OS X component"); return false; } OSStatus status = OpenAComponent(comp, &oo->au); if (status != noErr) { g_set_error(error_r, osx_output_quark(), status, "Unable to open OS X component: %s", GetMacOSStatusCommentString(status)); return false; } if (!osx_output_set_device(oo, error_r)) { CloseComponent(oo->au); return false; } AURenderCallbackStruct callback; callback.inputProc = osx_render; callback.inputProcRefCon = oo; ComponentResult result = AudioUnitSetProperty(oo->au, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &callback, sizeof(callback)); if (result != noErr) { CloseComponent(oo->au); g_set_error(error_r, osx_output_quark(), result, "unable to set callback for OS X audio unit"); return false; } return true; }
static bool osx_output_open(void *data, struct audio_format *audio_format, GError **error) { struct osx_output *od = data; ComponentDescription desc; Component comp; AURenderCallbackStruct callback; AudioStreamBasicDescription stream_description; OSStatus status; ComponentResult result; desc.componentType = kAudioUnitType_Output; desc.componentSubType = kAudioUnitSubType_DefaultOutput; desc.componentManufacturer = kAudioUnitManufacturer_Apple; desc.componentFlags = 0; desc.componentFlagsMask = 0; comp = FindNextComponent(NULL, &desc); if (comp == 0) { g_set_error(error, osx_output_quark(), 0, "Error finding OS X component"); return false; } status = OpenAComponent(comp, &od->au); if (status != noErr) { g_set_error(error, osx_output_quark(), 0, "Unable to open OS X component: %s", GetMacOSStatusCommentString(status)); return false; } status = AudioUnitInitialize(od->au); if (status != noErr) { CloseComponent(od->au); g_set_error(error, osx_output_quark(), 0, "Unable to initialize OS X audio unit: %s", GetMacOSStatusCommentString(status)); return false; } callback.inputProc = osx_render; callback.inputProcRefCon = od; result = AudioUnitSetProperty(od->au, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &callback, sizeof(callback)); if (result != noErr) { AudioUnitUninitialize(od->au); CloseComponent(od->au); g_set_error(error, osx_output_quark(), 0, "unable to set callback for OS X audio unit"); return false; } stream_description.mSampleRate = audio_format->sample_rate; stream_description.mFormatID = kAudioFormatLinearPCM; stream_description.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; #if G_BYTE_ORDER == G_BIG_ENDIAN stream_description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; #endif stream_description.mBytesPerPacket = audio_format_frame_size(audio_format); stream_description.mFramesPerPacket = 1; stream_description.mBytesPerFrame = stream_description.mBytesPerPacket; stream_description.mChannelsPerFrame = audio_format->channels; switch (audio_format->format) { case SAMPLE_FORMAT_S8: stream_description.mBitsPerChannel = 8; break; case SAMPLE_FORMAT_S16: stream_description.mBitsPerChannel = 16; break; default: audio_format->format = SAMPLE_FORMAT_S16; stream_description.mBitsPerChannel = 16; break; } result = AudioUnitSetProperty(od->au, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &stream_description, sizeof(stream_description)); if (result != noErr) { AudioUnitUninitialize(od->au); CloseComponent(od->au); g_set_error(error, osx_output_quark(), 0, "Unable to set format on OS X device"); return false; } /* create a buffer of 1s */ od->buffer_size = (audio_format->sample_rate) * audio_format_frame_size(audio_format); od->buffer = g_realloc(od->buffer, od->buffer_size); od->pos = 0; od->len = 0; status = AudioOutputUnitStart(od->au); if (status != 0) { g_set_error(error, osx_output_quark(), 0, "unable to start audio output: %s", GetMacOSStatusCommentString(status)); return false; } return true; }
static bool osx_output_open(struct audio_output *ao, struct audio_format *audio_format, GError **error) { struct osx_output *od = (struct osx_output *)ao; AudioStreamBasicDescription stream_description; stream_description.mSampleRate = audio_format->sample_rate; stream_description.mFormatID = kAudioFormatLinearPCM; stream_description.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; switch (audio_format->format) { case SAMPLE_FORMAT_S8: stream_description.mBitsPerChannel = 8; break; case SAMPLE_FORMAT_S16: stream_description.mBitsPerChannel = 16; break; case SAMPLE_FORMAT_S32: stream_description.mBitsPerChannel = 32; break; default: audio_format->format = SAMPLE_FORMAT_S32; stream_description.mBitsPerChannel = 32; break; } #if G_BYTE_ORDER == G_BIG_ENDIAN stream_description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; #endif stream_description.mBytesPerPacket = audio_format_frame_size(audio_format); stream_description.mFramesPerPacket = 1; stream_description.mBytesPerFrame = stream_description.mBytesPerPacket; stream_description.mChannelsPerFrame = audio_format->channels; ComponentResult result = AudioUnitSetProperty(od->au, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &stream_description, sizeof(stream_description)); if (result != noErr) { g_set_error(error, osx_output_quark(), result, "Unable to set format on OS X device"); return false; } OSStatus status = AudioUnitInitialize(od->au); if (status != noErr) { g_set_error(error, osx_output_quark(), status, "Unable to initialize OS X audio unit: %s", GetMacOSStatusCommentString(status)); return false; } /* create a buffer of 1s */ od->buffer = fifo_buffer_new(audio_format->sample_rate * audio_format_frame_size(audio_format)); status = AudioOutputUnitStart(od->au); if (status != 0) { AudioUnitUninitialize(od->au); g_set_error(error, osx_output_quark(), status, "unable to start audio output: %s", GetMacOSStatusCommentString(status)); return false; } return true; }
static bool osx_output_set_device(struct osx_output *oo, GError **error) { bool ret = true; OSStatus status; UInt32 size, numdevices; AudioDeviceID *deviceids = NULL; char name[256]; unsigned int i; if (oo->component_subtype != kAudioUnitSubType_HALOutput) goto done; /* how many audio devices are there? */ status = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size, NULL); if (status != noErr) { g_set_error(error, osx_output_quark(), status, "Unable to determine number of OS X audio devices: %s", GetMacOSStatusCommentString(status)); ret = false; goto done; } /* what are the available audio device IDs? */ numdevices = size / sizeof(AudioDeviceID); deviceids = g_malloc(size); status = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size, deviceids); if (status != noErr) { g_set_error(error, osx_output_quark(), status, "Unable to determine OS X audio device IDs: %s", GetMacOSStatusCommentString(status)); ret = false; goto done; } /* which audio device matches oo->device_name? */ for (i = 0; i < numdevices; i++) { size = sizeof(name); status = AudioDeviceGetProperty(deviceids[i], 0, false, kAudioDevicePropertyDeviceName, &size, name); if (status != noErr) { g_set_error(error, osx_output_quark(), status, "Unable to determine OS X device name " "(device %u): %s", (unsigned int) deviceids[i], GetMacOSStatusCommentString(status)); ret = false; goto done; } if (strcmp(oo->device_name, name) == 0) { g_debug("found matching device: ID=%u, name=%s", (unsigned int) deviceids[i], name); break; } } if (i == numdevices) { g_warning("Found no audio device with name '%s' " "(will use default audio device)", oo->device_name); goto done; } status = AudioUnitSetProperty(oo->au, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &(deviceids[i]), sizeof(AudioDeviceID)); if (status != noErr) { g_set_error(error, osx_output_quark(), status, "Unable to set OS X audio output device: %s", GetMacOSStatusCommentString(status)); ret = false; goto done; } g_debug("set OS X audio output device ID=%u, name=%s", (unsigned int) deviceids[i], name); done: if (deviceids != NULL) g_free(deviceids); return ret; }