mirror of
https://github.com/Ryujinx/libsoundio.git
synced 2024-12-22 22:35:28 +00:00
CoreAudio: microphone example works
This commit is contained in:
parent
29d55f59f7
commit
eb7308d992
|
@ -249,8 +249,6 @@ view `coverage/index.html` in a browser.
|
||||||
|
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
0. implement CoreAudio (OSX) backend, get examples working
|
|
||||||
- microphone example
|
|
||||||
0. ALSA backend for microphone example is broken
|
0. ALSA backend for microphone example is broken
|
||||||
0. Add some builtin channel layouts from
|
0. Add some builtin channel layouts from
|
||||||
https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/CoreAudioDataTypesRef/#//apple_ref/doc/constant_group/Audio_Channel_Layout_Tags
|
https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/CoreAudioDataTypesRef/#//apple_ref/doc/constant_group/Audio_Channel_Layout_Tags
|
||||||
|
|
|
@ -189,15 +189,6 @@ static int aim_to_scope(SoundIoDeviceAim aim) {
|
||||||
return (aim == SoundIoDeviceAimInput) ?
|
return (aim == SoundIoDeviceAimInput) ?
|
||||||
kAudioObjectPropertyScopeInput : kAudioObjectPropertyScopeOutput;
|
kAudioObjectPropertyScopeInput : kAudioObjectPropertyScopeOutput;
|
||||||
}
|
}
|
||||||
// TODO
|
|
||||||
/*
|
|
||||||
@constant kAudioDevicePropertyLatency
|
|
||||||
A UInt32 containing the number of frames of latency in the AudioDevice. Note
|
|
||||||
that input and output latency may differ. Further, the AudioDevice's
|
|
||||||
AudioStreams may have additional latency so they should be queried as well.
|
|
||||||
If both the device and the stream say they have latency, then the total
|
|
||||||
latency for the stream is the device latency summed with the stream latency.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static SoundIoChannelId from_channel_descr(const AudioChannelDescription *descr) {
|
static SoundIoChannelId from_channel_descr(const AudioChannelDescription *descr) {
|
||||||
switch (descr->mChannelLabel) {
|
switch (descr->mChannelLabel) {
|
||||||
|
@ -637,12 +628,19 @@ static int refresh_devices(struct SoundIoPrivate *si) {
|
||||||
prop_address.mScope = aim_to_scope(aim);
|
prop_address.mScope = aim_to_scope(aim);
|
||||||
prop_address.mElement = kAudioObjectPropertyElementMaster;
|
prop_address.mElement = kAudioObjectPropertyElementMaster;
|
||||||
io_size = sizeof(double);
|
io_size = sizeof(double);
|
||||||
|
double value;
|
||||||
if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, 0, nullptr,
|
if ((os_err = AudioObjectGetPropertyData(device_id, &prop_address, 0, nullptr,
|
||||||
&io_size, &rd.device->sample_rate_current)))
|
&io_size, &value)))
|
||||||
{
|
{
|
||||||
deinit_refresh_devices(&rd);
|
deinit_refresh_devices(&rd);
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
}
|
}
|
||||||
|
double floored_value = floor(value);
|
||||||
|
if (value != floored_value) {
|
||||||
|
deinit_refresh_devices(&rd);
|
||||||
|
return SoundIoErrorIncompatibleDevice;
|
||||||
|
}
|
||||||
|
rd.device->sample_rate_current = (int)floored_value;
|
||||||
|
|
||||||
prop_address.mSelector = kAudioDevicePropertyAvailableNominalSampleRates;
|
prop_address.mSelector = kAudioDevicePropertyAvailableNominalSampleRates;
|
||||||
prop_address.mScope = aim_to_scope(aim);
|
prop_address.mScope = aim_to_scope(aim);
|
||||||
|
@ -677,6 +675,12 @@ static int refresh_devices(struct SoundIoPrivate *si) {
|
||||||
if (rd.device->sample_rate_max == 0 || max_val > rd.device->sample_rate_max)
|
if (rd.device->sample_rate_max == 0 || max_val > rd.device->sample_rate_max)
|
||||||
rd.device->sample_rate_max = max_val;
|
rd.device->sample_rate_max = max_val;
|
||||||
}
|
}
|
||||||
|
// If you try to open an input stream with anything but the current
|
||||||
|
// nominal sample rate, AudioUnitRender returns an error.
|
||||||
|
if (aim == SoundIoDeviceAimInput) {
|
||||||
|
rd.device->sample_rate_min = rd.device->sample_rate_current;
|
||||||
|
rd.device->sample_rate_max = rd.device->sample_rate_current;
|
||||||
|
}
|
||||||
|
|
||||||
prop_address.mSelector = kAudioDevicePropertyBufferFrameSize;
|
prop_address.mSelector = kAudioDevicePropertyBufferFrameSize;
|
||||||
prop_address.mScope = aim_to_scope(aim);
|
prop_address.mScope = aim_to_scope(aim);
|
||||||
|
@ -1056,6 +1060,8 @@ static void instream_destroy_ca(struct SoundIoPrivate *si, struct SoundIoInStrea
|
||||||
AudioOutputUnitStop(isca->instance);
|
AudioOutputUnitStop(isca->instance);
|
||||||
AudioComponentInstanceDispose(isca->instance);
|
AudioComponentInstanceDispose(isca->instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(isca->buffer_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
static OSStatus read_callback_ca(void *userdata, AudioUnitRenderActionFlags *io_action_flags,
|
static OSStatus read_callback_ca(void *userdata, AudioUnitRenderActionFlags *io_action_flags,
|
||||||
|
@ -1066,11 +1072,38 @@ static OSStatus read_callback_ca(void *userdata, AudioUnitRenderActionFlags *io_
|
||||||
SoundIoInStream *instream = &is->pub;
|
SoundIoInStream *instream = &is->pub;
|
||||||
SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
|
SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
|
||||||
|
|
||||||
isca->io_data = io_data;
|
for (int i = 0; i < isca->buffer_list->mNumberBuffers; i += 1) {
|
||||||
isca->buffer_index = 0;
|
isca->buffer_list->mBuffers[i].mData = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus os_err;
|
||||||
|
if ((os_err = AudioUnitRender(isca->instance, io_action_flags, in_time_stamp,
|
||||||
|
in_bus_number, in_number_frames, isca->buffer_list)))
|
||||||
|
{
|
||||||
|
instream->error_callback(instream, SoundIoErrorStreaming);
|
||||||
|
return noErr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isca->buffer_list->mNumberBuffers == 1) {
|
||||||
|
AudioBuffer *audio_buffer = &isca->buffer_list->mBuffers[0];
|
||||||
|
assert(audio_buffer->mNumberChannels == instream->layout.channel_count);
|
||||||
|
assert(audio_buffer->mDataByteSize == in_number_frames * instream->bytes_per_frame);
|
||||||
|
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
|
||||||
|
isca->areas[ch].ptr = ((char*)audio_buffer->mData) + instream->bytes_per_sample;
|
||||||
|
isca->areas[ch].step = instream->bytes_per_frame;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert(isca->buffer_list->mNumberBuffers == instream->layout.channel_count);
|
||||||
|
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
|
||||||
|
AudioBuffer *audio_buffer = &isca->buffer_list->mBuffers[ch];
|
||||||
|
assert(audio_buffer->mDataByteSize == in_number_frames * instream->bytes_per_sample);
|
||||||
|
isca->areas[ch].ptr = (char*)audio_buffer->mData;
|
||||||
|
isca->areas[ch].step = instream->bytes_per_sample;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
isca->frames_left = in_number_frames;
|
isca->frames_left = in_number_frames;
|
||||||
instream->read_callback(instream, isca->frames_left, isca->frames_left);
|
instream->read_callback(instream, isca->frames_left, isca->frames_left);
|
||||||
isca->io_data = nullptr;
|
|
||||||
|
|
||||||
return noErr;
|
return noErr;
|
||||||
}
|
}
|
||||||
|
@ -1081,6 +1114,8 @@ static int instream_open_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPri
|
||||||
SoundIoDevice *device = instream->device;
|
SoundIoDevice *device = instream->device;
|
||||||
SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device;
|
SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device;
|
||||||
SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio;
|
SoundIoDeviceCoreAudio *dca = &dev->backend_data.coreaudio;
|
||||||
|
UInt32 io_size;
|
||||||
|
OSStatus os_err;
|
||||||
|
|
||||||
if (instream->buffer_duration == 0.0)
|
if (instream->buffer_duration == 0.0)
|
||||||
instream->buffer_duration = device->buffer_duration_current;
|
instream->buffer_duration = device->buffer_duration_current;
|
||||||
|
@ -1090,6 +1125,33 @@ static int instream_open_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPri
|
||||||
instream->buffer_duration,
|
instream->buffer_duration,
|
||||||
device->buffer_duration_max);
|
device->buffer_duration_max);
|
||||||
|
|
||||||
|
|
||||||
|
AudioObjectPropertyAddress prop_address;
|
||||||
|
prop_address.mSelector = kAudioDevicePropertyStreamConfiguration;
|
||||||
|
prop_address.mScope = kAudioObjectPropertyScopeInput;
|
||||||
|
prop_address.mElement = kAudioObjectPropertyElementMaster;
|
||||||
|
io_size = 0;
|
||||||
|
if ((os_err = AudioObjectGetPropertyDataSize(dca->device_id, &prop_address,
|
||||||
|
0, nullptr, &io_size)))
|
||||||
|
{
|
||||||
|
instream_destroy_ca(si, is);
|
||||||
|
return SoundIoErrorOpeningDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
isca->buffer_list = (AudioBufferList*)allocate_nonzero<char>(io_size);
|
||||||
|
if (!isca->buffer_list) {
|
||||||
|
instream_destroy_ca(si, is);
|
||||||
|
return SoundIoErrorNoMem;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((os_err = AudioObjectGetPropertyData(dca->device_id, &prop_address,
|
||||||
|
0, nullptr, &io_size, isca->buffer_list)))
|
||||||
|
{
|
||||||
|
instream_destroy_ca(si, is);
|
||||||
|
return SoundIoErrorOpeningDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
AudioComponentDescription desc = {0};
|
AudioComponentDescription desc = {0};
|
||||||
desc.componentType = kAudioUnitType_Output;
|
desc.componentType = kAudioUnitType_Output;
|
||||||
desc.componentSubType = kAudioUnitSubType_HALOutput;
|
desc.componentSubType = kAudioUnitSubType_HALOutput;
|
||||||
|
@ -1101,7 +1163,6 @@ static int instream_open_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPri
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
OSStatus os_err;
|
|
||||||
if ((os_err = AudioComponentInstanceNew(component, &isca->instance))) {
|
if ((os_err = AudioComponentInstanceNew(component, &isca->instance))) {
|
||||||
instream_destroy_ca(si, is);
|
instream_destroy_ca(si, is);
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
|
@ -1162,11 +1223,9 @@ static int instream_open_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPri
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
AudioObjectPropertyAddress prop_address = {
|
prop_address.mSelector = kAudioDevicePropertyBufferFrameSize;
|
||||||
kAudioDevicePropertyBufferFrameSize,
|
prop_address.mScope = kAudioObjectPropertyScopeOutput;
|
||||||
kAudioObjectPropertyScopeOutput,
|
prop_address.mElement = INPUT_ELEMENT;
|
||||||
INPUT_ELEMENT
|
|
||||||
};
|
|
||||||
UInt32 buffer_frame_size = instream->buffer_duration * instream->sample_rate;
|
UInt32 buffer_frame_size = instream->buffer_duration * instream->sample_rate;
|
||||||
if ((os_err = AudioObjectSetPropertyData(dca->device_id, &prop_address,
|
if ((os_err = AudioObjectSetPropertyData(dca->device_id, &prop_address,
|
||||||
0, nullptr, sizeof(UInt32), &buffer_frame_size)))
|
0, nullptr, sizeof(UInt32), &buffer_frame_size)))
|
||||||
|
@ -1210,11 +1269,20 @@ static int instream_start_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPr
|
||||||
static int instream_begin_read_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is,
|
static int instream_begin_read_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is,
|
||||||
SoundIoChannelArea **out_areas, int *frame_count)
|
SoundIoChannelArea **out_areas, int *frame_count)
|
||||||
{
|
{
|
||||||
soundio_panic("TODO begin read");
|
SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
|
||||||
|
|
||||||
|
if (*frame_count != isca->frames_left)
|
||||||
|
return SoundIoErrorInvalid;
|
||||||
|
|
||||||
|
*out_areas = isca->areas;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_end_read_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
static int instream_end_read_ca(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||||
soundio_panic("TODO end read");
|
SoundIoInStreamCoreAudio *isca = &is->backend_data.coreaudio;
|
||||||
|
isca->frames_left = 0;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -52,9 +52,9 @@ struct SoundIoOutStreamCoreAudio {
|
||||||
|
|
||||||
struct SoundIoInStreamCoreAudio {
|
struct SoundIoInStreamCoreAudio {
|
||||||
AudioComponentInstance instance;
|
AudioComponentInstance instance;
|
||||||
AudioBufferList *io_data;
|
AudioBufferList *buffer_list;
|
||||||
int buffer_index;
|
|
||||||
int frames_left;
|
int frames_left;
|
||||||
|
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue