mirror of
https://github.com/Ryujinx/libsoundio.git
synced 2025-01-03 17:15:47 +00:00
CoreAudio: obtain most device information
This commit is contained in:
parent
6d185de82c
commit
f77663399f
|
@ -242,6 +242,11 @@ view `coverage/index.html` in a browser.
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
0. implement CoreAudio (OSX) backend, get examples working
|
0. implement CoreAudio (OSX) backend, get examples working
|
||||||
|
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
|
||||||
|
0. Add more PulseAudio channel ids
|
||||||
|
0. Make sure PulseAudio can handle refresh devices crashing before
|
||||||
|
block_until_have_devices
|
||||||
0. implement WASAPI (Windows) backend, get examples working
|
0. implement WASAPI (Windows) backend, get examples working
|
||||||
0. implement ASIO (Windows) backend, get examples working
|
0. implement ASIO (Windows) backend, get examples working
|
||||||
0. Integrate into libgroove and test with Groove Basin
|
0. Integrate into libgroove and test with Groove Basin
|
||||||
|
@ -268,6 +273,7 @@ view `coverage/index.html` in a browser.
|
||||||
0. -fvisibility=hidden and then explicitly export stuff, or
|
0. -fvisibility=hidden and then explicitly export stuff, or
|
||||||
explicitly make the unexported stuff private
|
explicitly make the unexported stuff private
|
||||||
0. add len arguments to APIs that have char *
|
0. add len arguments to APIs that have char *
|
||||||
|
- replace strdup with soundio_str_dupe
|
||||||
0. Support PulseAudio proplist properties for main context and streams
|
0. Support PulseAudio proplist properties for main context and streams
|
||||||
0. Expose JACK options in `jack_client_open`
|
0. Expose JACK options in `jack_client_open`
|
||||||
0. custom allocator support
|
0. custom allocator support
|
||||||
|
|
|
@ -147,6 +147,7 @@ int main(int argc, char **argv) {
|
||||||
soundio_wait_events(soundio);
|
soundio_wait_events(soundio);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
soundio_flush_events(soundio);
|
||||||
int err = list_devices(soundio);
|
int err = list_devices(soundio);
|
||||||
soundio_destroy(soundio);
|
soundio_destroy(soundio);
|
||||||
return err;
|
return err;
|
||||||
|
|
|
@ -193,6 +193,7 @@ int main(int argc, char **argv) {
|
||||||
if (err)
|
if (err)
|
||||||
panic("error connecting: %s", soundio_strerror(err));
|
panic("error connecting: %s", soundio_strerror(err));
|
||||||
|
|
||||||
|
soundio_flush_events(soundio);
|
||||||
|
|
||||||
int default_out_device_index = soundio_default_output_device_index(soundio);
|
int default_out_device_index = soundio_default_output_device_index(soundio);
|
||||||
if (default_out_device_index < 0)
|
if (default_out_device_index < 0)
|
||||||
|
|
|
@ -105,6 +105,8 @@ int main(int argc, char **argv) {
|
||||||
if (err)
|
if (err)
|
||||||
panic("error connecting: %s", soundio_strerror(err));
|
panic("error connecting: %s", soundio_strerror(err));
|
||||||
|
|
||||||
|
soundio_flush_events(soundio);
|
||||||
|
|
||||||
int default_out_device_index = soundio_default_output_device_index(soundio);
|
int default_out_device_index = soundio_default_output_device_index(soundio);
|
||||||
if (default_out_device_index < 0)
|
if (default_out_device_index < 0)
|
||||||
panic("no output device found");
|
panic("no output device found");
|
||||||
|
|
|
@ -70,9 +70,52 @@ enum SoundIoChannelId {
|
||||||
SoundIoChannelIdTopSideRight,
|
SoundIoChannelIdTopSideRight,
|
||||||
SoundIoChannelIdLeftLfe,
|
SoundIoChannelIdLeftLfe,
|
||||||
SoundIoChannelIdRightLfe,
|
SoundIoChannelIdRightLfe,
|
||||||
|
SoundIoChannelIdLfe2,
|
||||||
SoundIoChannelIdBottomCenter,
|
SoundIoChannelIdBottomCenter,
|
||||||
SoundIoChannelIdBottomLeftCenter,
|
SoundIoChannelIdBottomLeftCenter,
|
||||||
SoundIoChannelIdBottomRightCenter,
|
SoundIoChannelIdBottomRightCenter,
|
||||||
|
|
||||||
|
// Mid/side recording
|
||||||
|
SoundIoChannelIdMsMid,
|
||||||
|
SoundIoChannelIdMsSide,
|
||||||
|
|
||||||
|
// first order ambisonic channels
|
||||||
|
SoundIoChannelIdAmbisonicW,
|
||||||
|
SoundIoChannelIdAmbisonicX,
|
||||||
|
SoundIoChannelIdAmbisonicY,
|
||||||
|
SoundIoChannelIdAmbisonicZ,
|
||||||
|
|
||||||
|
// X-Y Recording
|
||||||
|
SoundIoChannelIdXyX,
|
||||||
|
SoundIoChannelIdXyY,
|
||||||
|
|
||||||
|
// Other
|
||||||
|
SoundIoChannelIdHeadphonesLeft,
|
||||||
|
SoundIoChannelIdHeadphonesRight,
|
||||||
|
SoundIoChannelIdClickTrack,
|
||||||
|
SoundIoChannelIdForeignLanguage,
|
||||||
|
SoundIoChannelIdHearingImpaired,
|
||||||
|
SoundIoChannelIdNarration,
|
||||||
|
SoundIoChannelIdHaptic,
|
||||||
|
SoundIoChannelIdDialogCentricMix,
|
||||||
|
|
||||||
|
SoundIoChannelIdAux,
|
||||||
|
SoundIoChannelIdAux0,
|
||||||
|
SoundIoChannelIdAux1,
|
||||||
|
SoundIoChannelIdAux2,
|
||||||
|
SoundIoChannelIdAux3,
|
||||||
|
SoundIoChannelIdAux4,
|
||||||
|
SoundIoChannelIdAux5,
|
||||||
|
SoundIoChannelIdAux6,
|
||||||
|
SoundIoChannelIdAux7,
|
||||||
|
SoundIoChannelIdAux8,
|
||||||
|
SoundIoChannelIdAux9,
|
||||||
|
SoundIoChannelIdAux10,
|
||||||
|
SoundIoChannelIdAux11,
|
||||||
|
SoundIoChannelIdAux12,
|
||||||
|
SoundIoChannelIdAux13,
|
||||||
|
SoundIoChannelIdAux14,
|
||||||
|
SoundIoChannelIdAux15,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum SoundIoChannelLayoutId {
|
enum SoundIoChannelLayoutId {
|
||||||
|
@ -214,7 +257,9 @@ struct SoundIo {
|
||||||
// when the JACK server shuts down. When this happens, listing devices
|
// when the JACK server shuts down. When this happens, listing devices
|
||||||
// and opening streams will always fail with
|
// and opening streams will always fail with
|
||||||
// SoundIoErrorBackendDisconnected. This callback is only called during a
|
// SoundIoErrorBackendDisconnected. This callback is only called during a
|
||||||
// call to soundio_flush_events or soundio_wait_events.
|
// call to `soundio_flush_events` or `soundio_wait_events`.
|
||||||
|
// If you do not supply a callback, the default will crash your program
|
||||||
|
// with an error message.
|
||||||
void (*on_backend_disconnect)(struct SoundIo *, int err);
|
void (*on_backend_disconnect)(struct SoundIo *, int err);
|
||||||
// Optional callback. Called from an unknown thread that you should not use
|
// Optional callback. Called from an unknown thread that you should not use
|
||||||
// to call any soundio functions. You may use this to signal a condition
|
// to call any soundio functions. You may use this to signal a condition
|
||||||
|
@ -592,22 +637,37 @@ const char * soundio_format_string(enum SoundIoFormat format);
|
||||||
|
|
||||||
// Devices
|
// Devices
|
||||||
|
|
||||||
|
// When you call `soundio_flush_events`, a snapshot of all device state is
|
||||||
|
// saved and these functions merely access the snapshot data. When you want
|
||||||
|
// to check for new devices, call `soundio_flush_events`. Or you can call
|
||||||
|
// `soundio_wait_events` to block until devices change. If an error occurs
|
||||||
|
// scanning devices in a background thread, `on_backend_disconnect` is called
|
||||||
|
// with the error code.
|
||||||
|
|
||||||
|
// Get the number of input devices.
|
||||||
|
// Returns -1 if you never called `soundio_flush_events`.
|
||||||
int soundio_input_device_count(struct SoundIo *soundio);
|
int soundio_input_device_count(struct SoundIo *soundio);
|
||||||
|
// Get the number of output devices.
|
||||||
|
// Returns -1 if you never called `soundio_flush_events`.
|
||||||
int soundio_output_device_count(struct SoundIo *soundio);
|
int soundio_output_device_count(struct SoundIo *soundio);
|
||||||
|
|
||||||
// Always returns a device. Call soundio_device_unref when done.
|
// Always returns a device. Call soundio_device_unref when done.
|
||||||
// `index` must be 0 <= index < soundio_input_device_count
|
// `index` must be 0 <= index < soundio_input_device_count
|
||||||
|
// Returns NULL if you never called `soundio_flush_events`.
|
||||||
struct SoundIoDevice *soundio_get_input_device(struct SoundIo *soundio, int index);
|
struct SoundIoDevice *soundio_get_input_device(struct SoundIo *soundio, int index);
|
||||||
// Always returns a device. Call soundio_device_unref when done.
|
// Always returns a device. Call soundio_device_unref when done.
|
||||||
// `index` must be 0 <= index < soundio_output_device_count
|
// `index` must be 0 <= index < soundio_output_device_count
|
||||||
|
// Returns NULL if you never called `soundio_flush_events`.
|
||||||
struct SoundIoDevice *soundio_get_output_device(struct SoundIo *soundio, int index);
|
struct SoundIoDevice *soundio_get_output_device(struct SoundIo *soundio, int index);
|
||||||
|
|
||||||
// returns the index of the default input device
|
// returns the index of the default input device
|
||||||
// returns -1 if there are no devices.
|
// returns -1 if there are no devices or if you never called
|
||||||
|
// `soundio_flush_events`.
|
||||||
int soundio_default_input_device_index(struct SoundIo *soundio);
|
int soundio_default_input_device_index(struct SoundIo *soundio);
|
||||||
|
|
||||||
// returns the index of the default output device
|
// returns the index of the default output device
|
||||||
// returns -1 if there are no devices.
|
// returns -1 if there are no devices or if you never called
|
||||||
|
// `soundio_flush_events`.
|
||||||
int soundio_default_output_device_index(struct SoundIo *soundio);
|
int soundio_default_output_device_index(struct SoundIo *soundio);
|
||||||
|
|
||||||
void soundio_device_ref(struct SoundIoDevice *device);
|
void soundio_device_ref(struct SoundIoDevice *device);
|
||||||
|
|
|
@ -805,10 +805,13 @@ static void device_thread_run(void *arg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (got_rescan_event) {
|
if (got_rescan_event) {
|
||||||
if ((err = refresh_devices(si))) {
|
err = refresh_devices(si);
|
||||||
|
if (err)
|
||||||
shutdown_backend(si, err);
|
shutdown_backend(si, err);
|
||||||
|
if (!sia->have_devices_flag.exchange(true))
|
||||||
|
soundio_os_cond_signal(sica->have_devices_cond, nullptr);
|
||||||
|
if (err)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ static OSStatus on_devices_changed(AudioObjectID in_object_id, UInt32 in_number_
|
||||||
SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
|
SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
|
||||||
|
|
||||||
sica->device_scan_queued.store(true);
|
sica->device_scan_queued.store(true);
|
||||||
soundio_os_cond_signal(sica->cond, nullptr);
|
soundio_os_cond_signal(sica->scan_devices_cond, nullptr);
|
||||||
|
|
||||||
return noErr;
|
return noErr;
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ static OSStatus on_service_restarted(AudioObjectID in_object_id, UInt32 in_numbe
|
||||||
SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
|
SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
|
||||||
|
|
||||||
sica->service_restarted.store(true);
|
sica->service_restarted.store(true);
|
||||||
soundio_os_cond_signal(sica->cond, nullptr);
|
soundio_os_cond_signal(sica->scan_devices_cond, nullptr);
|
||||||
|
|
||||||
return noErr;
|
return noErr;
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ static void destroy_ca(struct SoundIoPrivate *si) {
|
||||||
|
|
||||||
if (sica->thread) {
|
if (sica->thread) {
|
||||||
sica->abort_flag.clear();
|
sica->abort_flag.clear();
|
||||||
soundio_os_cond_signal(sica->cond, nullptr);
|
soundio_os_cond_signal(sica->scan_devices_cond, nullptr);
|
||||||
soundio_os_thread_destroy(sica->thread);
|
soundio_os_thread_destroy(sica->thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,6 +62,9 @@ static void destroy_ca(struct SoundIoPrivate *si) {
|
||||||
if (sica->have_devices_cond)
|
if (sica->have_devices_cond)
|
||||||
soundio_os_cond_destroy(sica->have_devices_cond);
|
soundio_os_cond_destroy(sica->have_devices_cond);
|
||||||
|
|
||||||
|
if (sica->scan_devices_cond)
|
||||||
|
soundio_os_cond_destroy(sica->scan_devices_cond);
|
||||||
|
|
||||||
if (sica->mutex)
|
if (sica->mutex)
|
||||||
soundio_os_mutex_destroy(sica->mutex);
|
soundio_os_mutex_destroy(sica->mutex);
|
||||||
|
|
||||||
|
@ -95,12 +98,6 @@ static int aim_to_scope(SoundIoDeviceAim aim) {
|
||||||
kAudioObjectPropertyScopeInput : kAudioObjectPropertyScopeOutput;
|
kAudioObjectPropertyScopeInput : kAudioObjectPropertyScopeOutput;
|
||||||
}
|
}
|
||||||
// TODO
|
// TODO
|
||||||
/*
|
|
||||||
@constant kAudioHardwarePropertyDefaultInputDevice
|
|
||||||
The AudioObjectID of the default input AudioDevice.
|
|
||||||
@constant kAudioHardwarePropertyDefaultOutputDevice
|
|
||||||
The AudioObjectID of the default output AudioDevice.
|
|
||||||
*/
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
@constant kAudioDevicePropertyDeviceHasChanged
|
@constant kAudioDevicePropertyDeviceHasChanged
|
||||||
|
@ -110,31 +107,265 @@ static int aim_to_scope(SoundIoDeviceAim aim) {
|
||||||
be conveyed through other notifications. In response to this notification,
|
be conveyed through other notifications. In response to this notification,
|
||||||
clients should re-evaluate everything they need to know about the device,
|
clients should re-evaluate everything they need to know about the device,
|
||||||
particularly the layout and values of the controls.
|
particularly the layout and values of the controls.
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
@constant kAudioDevicePropertyBufferFrameSize
|
@constant kAudioDevicePropertyBufferFrameSize
|
||||||
A UInt32 whose value indicates the number of frames in the IO buffers.
|
A UInt32 whose value indicates the number of frames in the IO buffers.
|
||||||
@constant kAudioDevicePropertyBufferFrameSizeRange
|
@constant kAudioDevicePropertyBufferFrameSizeRange
|
||||||
An AudioValueRange indicating the minimum and maximum values, inclusive, for
|
An AudioValueRange indicating the minimum and maximum values, inclusive, for
|
||||||
kAudioDevicePropertyBufferFrameSize.
|
kAudioDevicePropertyBufferFrameSize.
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
@constant kAudioDevicePropertyStreamConfiguration
|
@constant kAudioDevicePropertyLatency
|
||||||
This property returns the stream configuration of the device in an
|
A UInt32 containing the number of frames of latency in the AudioDevice. Note
|
||||||
AudioBufferList (with the buffer pointers set to NULL) which describes the
|
that input and output latency may differ. Further, the AudioDevice's
|
||||||
list of streams and the number of channels in each stream. This corresponds
|
AudioStreams may have additional latency so they should be queried as well.
|
||||||
to what will be passed into the IOProc.
|
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.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
@constant kAudioDevicePropertyNominalSampleRate
|
||||||
|
A Float64 that indicates the current nominal sample rate of the AudioDevice.
|
||||||
|
@constant kAudioDevicePropertyAvailableNominalSampleRates
|
||||||
|
An array of AudioValueRange structs that indicates the valid ranges for the
|
||||||
|
nominal sample rate of the AudioDevice.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
@constant kAudioDevicePropertyIcon
|
||||||
|
A CFURLRef that indicates an image file that can be used to represent the
|
||||||
|
device visually. The caller is responsible for releasing the returned
|
||||||
|
CFObject.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
@constant kAudioDevicePropertyPreferredChannelsForStereo
|
||||||
|
An array of two UInt32s, the first for the left channel, the second for the
|
||||||
|
right channel, that indicate the channel numbers to use for stereo IO on the
|
||||||
|
device. The value of this property can be different for input and output and
|
||||||
|
there are no restrictions on the channel numbers that can be used.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static SoundIoChannelId from_channel_descr(const AudioChannelDescription *descr) {
|
||||||
|
switch (descr->mChannelLabel) {
|
||||||
|
default: return SoundIoChannelIdInvalid;
|
||||||
|
case kAudioChannelLabel_Left: return SoundIoChannelIdFrontLeft;
|
||||||
|
case kAudioChannelLabel_Right: return SoundIoChannelIdFrontRight;
|
||||||
|
case kAudioChannelLabel_Center: return SoundIoChannelIdFrontCenter;
|
||||||
|
case kAudioChannelLabel_LFEScreen: return SoundIoChannelIdLfe;
|
||||||
|
case kAudioChannelLabel_LeftSurround: return SoundIoChannelIdSideLeft;
|
||||||
|
case kAudioChannelLabel_RightSurround: return SoundIoChannelIdSideRight;
|
||||||
|
case kAudioChannelLabel_LeftCenter: return SoundIoChannelIdSideLeft;
|
||||||
|
case kAudioChannelLabel_RightCenter: return SoundIoChannelIdSideRight;
|
||||||
|
case kAudioChannelLabel_CenterSurround: return SoundIoChannelIdBackCenter;
|
||||||
|
case kAudioChannelLabel_LeftSurroundDirect: return SoundIoChannelIdSideLeft;
|
||||||
|
case kAudioChannelLabel_RightSurroundDirect: return SoundIoChannelIdSideRight;
|
||||||
|
case kAudioChannelLabel_TopCenterSurround: return SoundIoChannelIdTopCenter;
|
||||||
|
case kAudioChannelLabel_VerticalHeightLeft: return SoundIoChannelIdTopSideLeft;
|
||||||
|
case kAudioChannelLabel_VerticalHeightCenter: return SoundIoChannelIdTopCenter;
|
||||||
|
case kAudioChannelLabel_VerticalHeightRight: return SoundIoChannelIdTopSideRight;
|
||||||
|
case kAudioChannelLabel_TopBackLeft: return SoundIoChannelIdTopBackLeft;
|
||||||
|
case kAudioChannelLabel_TopBackCenter: return SoundIoChannelIdTopBackCenter;
|
||||||
|
case kAudioChannelLabel_TopBackRight: return SoundIoChannelIdTopBackRight;
|
||||||
|
case kAudioChannelLabel_RearSurroundLeft: return SoundIoChannelIdBackLeft;
|
||||||
|
case kAudioChannelLabel_RearSurroundRight: return SoundIoChannelIdBackRight;
|
||||||
|
case kAudioChannelLabel_LeftWide: return SoundIoChannelIdFrontLeftWide;
|
||||||
|
case kAudioChannelLabel_RightWide: return SoundIoChannelIdFrontRightWide;
|
||||||
|
case kAudioChannelLabel_LFE2: return SoundIoChannelIdLfe2;
|
||||||
|
case kAudioChannelLabel_LeftTotal: return SoundIoChannelIdFrontLeft;
|
||||||
|
case kAudioChannelLabel_RightTotal: return SoundIoChannelIdFrontRight;
|
||||||
|
case kAudioChannelLabel_HearingImpaired: return SoundIoChannelIdHearingImpaired;
|
||||||
|
case kAudioChannelLabel_Narration: return SoundIoChannelIdNarration;
|
||||||
|
case kAudioChannelLabel_Mono: return SoundIoChannelIdFrontCenter;
|
||||||
|
case kAudioChannelLabel_DialogCentricMix: return SoundIoChannelIdDialogCentricMix;
|
||||||
|
case kAudioChannelLabel_CenterSurroundDirect: return SoundIoChannelIdBackCenter;
|
||||||
|
case kAudioChannelLabel_Haptic: return SoundIoChannelIdHaptic;
|
||||||
|
|
||||||
|
case kAudioChannelLabel_Ambisonic_W: return SoundIoChannelIdAmbisonicW;
|
||||||
|
case kAudioChannelLabel_Ambisonic_X: return SoundIoChannelIdAmbisonicX;
|
||||||
|
case kAudioChannelLabel_Ambisonic_Y: return SoundIoChannelIdAmbisonicY;
|
||||||
|
case kAudioChannelLabel_Ambisonic_Z: return SoundIoChannelIdAmbisonicZ;
|
||||||
|
|
||||||
|
case kAudioChannelLabel_MS_Mid: return SoundIoChannelIdMsMid;
|
||||||
|
case kAudioChannelLabel_MS_Side: return SoundIoChannelIdMsSide;
|
||||||
|
|
||||||
|
case kAudioChannelLabel_XY_X: return SoundIoChannelIdXyX;
|
||||||
|
case kAudioChannelLabel_XY_Y: return SoundIoChannelIdXyY;
|
||||||
|
|
||||||
|
case kAudioChannelLabel_HeadphonesLeft: return SoundIoChannelIdHeadphonesLeft;
|
||||||
|
case kAudioChannelLabel_HeadphonesRight: return SoundIoChannelIdHeadphonesRight;
|
||||||
|
case kAudioChannelLabel_ClickTrack: return SoundIoChannelIdClickTrack;
|
||||||
|
case kAudioChannelLabel_ForeignLanguage: return SoundIoChannelIdForeignLanguage;
|
||||||
|
|
||||||
|
case kAudioChannelLabel_Discrete: return SoundIoChannelIdAux;
|
||||||
|
|
||||||
|
case kAudioChannelLabel_Discrete_0: return SoundIoChannelIdAux0;
|
||||||
|
case kAudioChannelLabel_Discrete_1: return SoundIoChannelIdAux1;
|
||||||
|
case kAudioChannelLabel_Discrete_2: return SoundIoChannelIdAux2;
|
||||||
|
case kAudioChannelLabel_Discrete_3: return SoundIoChannelIdAux3;
|
||||||
|
case kAudioChannelLabel_Discrete_4: return SoundIoChannelIdAux4;
|
||||||
|
case kAudioChannelLabel_Discrete_5: return SoundIoChannelIdAux5;
|
||||||
|
case kAudioChannelLabel_Discrete_6: return SoundIoChannelIdAux6;
|
||||||
|
case kAudioChannelLabel_Discrete_7: return SoundIoChannelIdAux7;
|
||||||
|
case kAudioChannelLabel_Discrete_8: return SoundIoChannelIdAux8;
|
||||||
|
case kAudioChannelLabel_Discrete_9: return SoundIoChannelIdAux9;
|
||||||
|
case kAudioChannelLabel_Discrete_10: return SoundIoChannelIdAux10;
|
||||||
|
case kAudioChannelLabel_Discrete_11: return SoundIoChannelIdAux11;
|
||||||
|
case kAudioChannelLabel_Discrete_12: return SoundIoChannelIdAux12;
|
||||||
|
case kAudioChannelLabel_Discrete_13: return SoundIoChannelIdAux13;
|
||||||
|
case kAudioChannelLabel_Discrete_14: return SoundIoChannelIdAux14;
|
||||||
|
case kAudioChannelLabel_Discrete_15: return SoundIoChannelIdAux15;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// See https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/CoreAudioDataTypesRef/#//apple_ref/doc/constant_group/Audio_Channel_Layout_Tags
|
||||||
|
// Possible Errors:
|
||||||
|
// * SoundIoErrorIncompatibleDevice
|
||||||
|
static int from_coreaudio_layout(const AudioChannelLayout *ca_layout, SoundIoChannelLayout *layout) {
|
||||||
|
switch (ca_layout->mChannelLayoutTag) {
|
||||||
|
case kAudioChannelLayoutTag_UseChannelDescriptions:
|
||||||
|
{
|
||||||
|
layout->channel_count = ca_layout->mNumberChannelDescriptions;
|
||||||
|
for (int i = 0; i < layout->channel_count; i += 1) {
|
||||||
|
layout->channels[i] = from_channel_descr(&ca_layout->mChannelDescriptions[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case kAudioChannelLayoutTag_UseChannelBitmap:
|
||||||
|
soundio_panic("TODO how the f to parse this");
|
||||||
|
return SoundIoErrorIncompatibleDevice;
|
||||||
|
case kAudioChannelLayoutTag_Mono:
|
||||||
|
layout->channel_count = 1;
|
||||||
|
layout->channels[0] = SoundIoChannelIdFrontCenter;
|
||||||
|
break;
|
||||||
|
case kAudioChannelLayoutTag_Stereo:
|
||||||
|
case kAudioChannelLayoutTag_StereoHeadphones:
|
||||||
|
case kAudioChannelLayoutTag_MatrixStereo:
|
||||||
|
layout->channel_count = 2;
|
||||||
|
layout->channels[0] = SoundIoChannelIdFrontLeft;
|
||||||
|
layout->channels[1] = SoundIoChannelIdFrontRight;
|
||||||
|
break;
|
||||||
|
case kAudioChannelLayoutTag_XY:
|
||||||
|
layout->channel_count = 2;
|
||||||
|
layout->channels[0] = SoundIoChannelIdXyX;
|
||||||
|
layout->channels[1] = SoundIoChannelIdXyY;
|
||||||
|
break;
|
||||||
|
case kAudioChannelLayoutTag_Binaural:
|
||||||
|
layout->channel_count = 2;
|
||||||
|
layout->channels[0] = SoundIoChannelIdFrontLeft;
|
||||||
|
layout->channels[1] = SoundIoChannelIdFrontRight;
|
||||||
|
break;
|
||||||
|
case kAudioChannelLayoutTag_MidSide:
|
||||||
|
layout->channel_count = 2;
|
||||||
|
layout->channels[0] = SoundIoChannelIdMsMid;
|
||||||
|
layout->channels[1] = SoundIoChannelIdMsSide;
|
||||||
|
break;
|
||||||
|
case kAudioChannelLayoutTag_Ambisonic_B_Format:
|
||||||
|
layout->channel_count = 4;
|
||||||
|
layout->channels[0] = SoundIoChannelIdAmbisonicW;
|
||||||
|
layout->channels[1] = SoundIoChannelIdAmbisonicX;
|
||||||
|
layout->channels[2] = SoundIoChannelIdAmbisonicY;
|
||||||
|
layout->channels[3] = SoundIoChannelIdAmbisonicZ;
|
||||||
|
break;
|
||||||
|
case kAudioChannelLayoutTag_Quadraphonic:
|
||||||
|
layout->channel_count = 4;
|
||||||
|
layout->channels[0] = SoundIoChannelIdFrontLeft;
|
||||||
|
layout->channels[1] = SoundIoChannelIdFrontRight;
|
||||||
|
layout->channels[2] = SoundIoChannelIdBackLeft;
|
||||||
|
layout->channels[3] = SoundIoChannelIdBackRight;
|
||||||
|
break;
|
||||||
|
case kAudioChannelLayoutTag_Pentagonal:
|
||||||
|
layout->channel_count = 5;
|
||||||
|
layout->channels[0] = SoundIoChannelIdSideLeft;
|
||||||
|
layout->channels[1] = SoundIoChannelIdSideRight;
|
||||||
|
layout->channels[2] = SoundIoChannelIdBackLeft;
|
||||||
|
layout->channels[3] = SoundIoChannelIdBackRight;
|
||||||
|
layout->channels[4] = SoundIoChannelIdFrontCenter;
|
||||||
|
break;
|
||||||
|
case kAudioChannelLayoutTag_Hexagonal:
|
||||||
|
layout->channel_count = 6;
|
||||||
|
layout->channels[0] = SoundIoChannelIdFrontLeft;
|
||||||
|
layout->channels[1] = SoundIoChannelIdFrontRight;
|
||||||
|
layout->channels[2] = SoundIoChannelIdBackLeft;
|
||||||
|
layout->channels[3] = SoundIoChannelIdBackRight;
|
||||||
|
layout->channels[4] = SoundIoChannelIdFrontCenter;
|
||||||
|
layout->channels[5] = SoundIoChannelIdBackCenter;
|
||||||
|
break;
|
||||||
|
case kAudioChannelLayoutTag_Octagonal:
|
||||||
|
layout->channel_count = 8;
|
||||||
|
layout->channels[0] = SoundIoChannelIdFrontLeft;
|
||||||
|
layout->channels[1] = SoundIoChannelIdFrontRight;
|
||||||
|
layout->channels[2] = SoundIoChannelIdBackLeft;
|
||||||
|
layout->channels[3] = SoundIoChannelIdBackRight;
|
||||||
|
layout->channels[4] = SoundIoChannelIdFrontCenter;
|
||||||
|
layout->channels[5] = SoundIoChannelIdBackCenter;
|
||||||
|
layout->channels[6] = SoundIoChannelIdSideLeft;
|
||||||
|
layout->channels[7] = SoundIoChannelIdSideRight;
|
||||||
|
break;
|
||||||
|
case kAudioChannelLayoutTag_Cube:
|
||||||
|
layout->channel_count = 8;
|
||||||
|
layout->channels[0] = SoundIoChannelIdFrontLeft;
|
||||||
|
layout->channels[1] = SoundIoChannelIdFrontRight;
|
||||||
|
layout->channels[2] = SoundIoChannelIdBackLeft;
|
||||||
|
layout->channels[3] = SoundIoChannelIdBackRight;
|
||||||
|
layout->channels[4] = SoundIoChannelIdTopFrontLeft;
|
||||||
|
layout->channels[5] = SoundIoChannelIdTopFrontRight;
|
||||||
|
layout->channels[6] = SoundIoChannelIdTopBackLeft;
|
||||||
|
layout->channels[7] = SoundIoChannelIdTopBackRight;
|
||||||
|
break;
|
||||||
|
// TODO more hardcoded channel layouts
|
||||||
|
default:
|
||||||
|
return SoundIoErrorIncompatibleDevice;
|
||||||
|
}
|
||||||
|
soundio_channel_layout_detect_builtin(layout);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool all_channels_invalid(const struct SoundIoChannelLayout *layout) {
|
||||||
|
for (int i = 0; i < layout->channel_count; i += 1) {
|
||||||
|
if (layout->channels[i] != SoundIoChannelIdInvalid)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RefreshDevices {
|
||||||
|
SoundIoDevicesInfo *devices_info;
|
||||||
|
int devices_size;
|
||||||
|
AudioObjectID *devices;
|
||||||
|
CFStringRef string_ref;
|
||||||
|
char *device_name;
|
||||||
|
int device_name_len;
|
||||||
|
AudioBufferList *buffer_list;
|
||||||
|
SoundIoDevice *device;
|
||||||
|
AudioChannelLayout *audio_channel_layout;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void deinit_refresh_devices(RefreshDevices *rd) {
|
||||||
|
destroy(rd->devices_info);
|
||||||
|
deallocate((char*)rd->devices, rd->devices_size);
|
||||||
|
if (rd->string_ref)
|
||||||
|
CFRelease(rd->string_ref);
|
||||||
|
free(rd->device_name);
|
||||||
|
free(rd->buffer_list);
|
||||||
|
soundio_device_unref(rd->device);
|
||||||
|
free(rd->audio_channel_layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO get the device UID which persists between unplug/plug
|
||||||
// TODO go through here and make sure all allocations are freed
|
// TODO go through here and make sure all allocations are freed
|
||||||
static int refresh_devices(struct SoundIoPrivate *si) {
|
static int refresh_devices(struct SoundIoPrivate *si) {
|
||||||
SoundIo *soundio = &si->pub;
|
SoundIo *soundio = &si->pub;
|
||||||
SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
|
SoundIoCoreAudio *sica = &si->backend_data.coreaudio;
|
||||||
|
|
||||||
SoundIoDevicesInfo *devices_info = create<SoundIoDevicesInfo>();
|
UInt32 io_size;
|
||||||
if (!devices_info) {
|
OSStatus os_err;
|
||||||
soundio_panic("out of mem");
|
int err;
|
||||||
|
|
||||||
|
RefreshDevices rd;
|
||||||
|
memset(&rd, 0, sizeof(RefreshDevices));
|
||||||
|
|
||||||
|
if (!(rd.devices_info = create<SoundIoDevicesInfo>())) {
|
||||||
|
deinit_refresh_devices(&rd);
|
||||||
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioObjectPropertyAddress prop_address = {
|
AudioObjectPropertyAddress prop_address = {
|
||||||
|
@ -143,54 +374,76 @@ static int refresh_devices(struct SoundIoPrivate *si) {
|
||||||
kAudioObjectPropertyElementMaster
|
kAudioObjectPropertyElementMaster
|
||||||
};
|
};
|
||||||
|
|
||||||
UInt32 the_data_size = 0;
|
if ((os_err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject,
|
||||||
OSStatus err;
|
&prop_address, 0, nullptr, &io_size)))
|
||||||
if ((err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject,
|
|
||||||
&prop_address, 0, nullptr, &the_data_size)))
|
|
||||||
{
|
{
|
||||||
soundio_panic("get prop data size");
|
deinit_refresh_devices(&rd);
|
||||||
|
return SoundIoErrorOpeningDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
int devices_available = the_data_size / (UInt32)sizeof(AudioObjectID);
|
AudioObjectID default_input_id;
|
||||||
|
AudioObjectID default_output_id;
|
||||||
|
|
||||||
if (devices_available < 1) {
|
int device_count = io_size / (UInt32)sizeof(AudioObjectID);
|
||||||
soundio_panic("no devices");
|
if (device_count >= 1) {
|
||||||
|
rd.devices_size = io_size;
|
||||||
|
rd.devices = (AudioObjectID *)allocate<char>(rd.devices_size);
|
||||||
|
if (!rd.devices) {
|
||||||
|
deinit_refresh_devices(&rd);
|
||||||
|
return SoundIoErrorNoMem;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((os_err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop_address, 0, nullptr,
|
||||||
|
&io_size, rd.devices)))
|
||||||
|
{
|
||||||
|
deinit_refresh_devices(&rd);
|
||||||
|
return SoundIoErrorOpeningDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
io_size = sizeof(AudioObjectID);
|
||||||
|
prop_address.mSelector = kAudioHardwarePropertyDefaultInputDevice;
|
||||||
|
if ((os_err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop_address,
|
||||||
|
0, nullptr, &io_size, &default_input_id)))
|
||||||
|
{
|
||||||
|
deinit_refresh_devices(&rd);
|
||||||
|
return SoundIoErrorOpeningDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
io_size = sizeof(AudioObjectID);
|
||||||
|
prop_address.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
|
||||||
|
if ((os_err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop_address,
|
||||||
|
0, nullptr, &io_size, &default_output_id)))
|
||||||
|
{
|
||||||
|
deinit_refresh_devices(&rd);
|
||||||
|
return SoundIoErrorOpeningDevice;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioObjectID *devices = (AudioObjectID *)allocate<char>(the_data_size);
|
for (int i = 0; i < device_count; i += 1) {
|
||||||
if (!devices) {
|
AudioObjectID deviceID = rd.devices[i];
|
||||||
soundio_panic("out of mem");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop_address, 0, nullptr,
|
|
||||||
&the_data_size, devices)))
|
|
||||||
{
|
|
||||||
soundio_panic("get property data");
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr, "device count: %d\n", devices_available);
|
|
||||||
|
|
||||||
for (int i = 0; i < devices_available; i += 1) {
|
|
||||||
AudioObjectID deviceID = devices[i];
|
|
||||||
|
|
||||||
prop_address.mSelector = kAudioObjectPropertyName;
|
prop_address.mSelector = kAudioObjectPropertyName;
|
||||||
CFStringRef temp_string_ref = nullptr;
|
prop_address.mScope = kAudioObjectPropertyScopeGlobal;
|
||||||
UInt32 io_size = sizeof(CFStringRef);
|
prop_address.mElement = kAudioObjectPropertyElementMaster;
|
||||||
if ((err = AudioObjectGetPropertyData(deviceID, &prop_address,
|
io_size = sizeof(CFStringRef);
|
||||||
0, nullptr, &io_size, &temp_string_ref)))
|
if (rd.string_ref) {
|
||||||
|
CFRelease(rd.string_ref);
|
||||||
|
rd.string_ref = nullptr;
|
||||||
|
}
|
||||||
|
if ((os_err = AudioObjectGetPropertyData(deviceID, &prop_address,
|
||||||
|
0, nullptr, &io_size, &rd.string_ref)))
|
||||||
{
|
{
|
||||||
soundio_panic("error getting name");
|
deinit_refresh_devices(&rd);
|
||||||
|
return SoundIoErrorOpeningDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *device_name;
|
free(rd.device_name);
|
||||||
int device_name_len;
|
rd.device_name = nullptr;
|
||||||
if ((err = from_cf_string(temp_string_ref, &device_name, &device_name_len))) {
|
if ((err = from_cf_string(rd.string_ref, &rd.device_name, &rd.device_name_len))) {
|
||||||
soundio_panic("error decoding");
|
deinit_refresh_devices(&rd);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
fprintf(stderr, "device name: %s\n", device_name);
|
|
||||||
|
|
||||||
CFRelease(temp_string_ref);
|
|
||||||
temp_string_ref = nullptr;
|
|
||||||
|
|
||||||
|
|
||||||
for (int aim_i = 0; aim_i < array_length(aims); aim_i += 1) {
|
for (int aim_i = 0; aim_i < array_length(aims); aim_i += 1) {
|
||||||
|
@ -199,42 +452,119 @@ static int refresh_devices(struct SoundIoPrivate *si) {
|
||||||
io_size = 0;
|
io_size = 0;
|
||||||
prop_address.mSelector = kAudioDevicePropertyStreamConfiguration;
|
prop_address.mSelector = kAudioDevicePropertyStreamConfiguration;
|
||||||
prop_address.mScope = aim_to_scope(aim);
|
prop_address.mScope = aim_to_scope(aim);
|
||||||
prop_address.mElement = 0;
|
prop_address.mElement = kAudioObjectPropertyElementMaster;
|
||||||
if ((err = AudioObjectGetPropertyDataSize(deviceID, &prop_address, 0, nullptr, &io_size))) {
|
if ((os_err = AudioObjectGetPropertyDataSize(deviceID, &prop_address, 0, nullptr, &io_size))) {
|
||||||
soundio_panic("input channel get prop data size");
|
deinit_refresh_devices(&rd);
|
||||||
|
return SoundIoErrorOpeningDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioBufferList *buffer_list = (AudioBufferList*)allocate<char>(io_size);
|
free(rd.buffer_list);
|
||||||
if (!buffer_list) {
|
rd.buffer_list = (AudioBufferList*)allocate_nonzero<char>(io_size);
|
||||||
soundio_panic("out of mem");
|
if (!rd.buffer_list) {
|
||||||
|
deinit_refresh_devices(&rd);
|
||||||
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((err = AudioObjectGetPropertyData(deviceID, &prop_address, 0, nullptr,
|
if ((os_err = AudioObjectGetPropertyData(deviceID, &prop_address, 0, nullptr,
|
||||||
&io_size, buffer_list)))
|
&io_size, rd.buffer_list)))
|
||||||
{
|
{
|
||||||
soundio_panic("get input channel data");
|
deinit_refresh_devices(&rd);
|
||||||
|
return SoundIoErrorOpeningDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
int channel_count = 0;
|
int channel_count = 0;
|
||||||
for (int i = 0; i < buffer_list->mNumberBuffers; i += 1) {
|
for (int i = 0; i < rd.buffer_list->mNumberBuffers; i += 1) {
|
||||||
channel_count += buffer_list->mBuffers[i].mNumberChannels;
|
channel_count += rd.buffer_list->mBuffers[i].mNumberChannels;
|
||||||
}
|
}
|
||||||
deallocate((char*)buffer_list, io_size);
|
|
||||||
|
|
||||||
fprintf(stderr, "%d channel count: %d\n", aim_i, channel_count);
|
if (channel_count <= 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
SoundIoDevicePrivate *dev = create<SoundIoDevicePrivate>();
|
||||||
|
if (!dev) {
|
||||||
|
deinit_refresh_devices(&rd);
|
||||||
|
return SoundIoErrorNoMem;
|
||||||
|
}
|
||||||
|
assert(!rd.device);
|
||||||
|
rd.device = &dev->pub;
|
||||||
|
rd.device->ref_count = 1;
|
||||||
|
rd.device->soundio = soundio;
|
||||||
|
rd.device->is_raw = false; // TODO
|
||||||
|
rd.device->aim = aim;
|
||||||
|
rd.device->id = soundio_alloc_sprintf(nullptr, "%ld", (long)deviceID);
|
||||||
|
rd.device->name = soundio_str_dupe(rd.device_name, rd.device_name_len);
|
||||||
|
rd.device->layout_count = 1;
|
||||||
|
rd.device->layouts = create<SoundIoChannelLayout>();
|
||||||
|
rd.device->format_count = 1;
|
||||||
|
rd.device->formats = create<SoundIoFormat>();
|
||||||
|
// TODO more props
|
||||||
|
|
||||||
|
if (!rd.device->id || !rd.device->name || !rd.device->layouts || !rd.device->formats) {
|
||||||
|
deinit_refresh_devices(&rd);
|
||||||
|
return SoundIoErrorNoMem;
|
||||||
|
}
|
||||||
|
|
||||||
|
prop_address.mSelector = kAudioDevicePropertyPreferredChannelLayout;
|
||||||
|
prop_address.mScope = aim_to_scope(aim);
|
||||||
|
prop_address.mElement = kAudioObjectPropertyElementMaster;
|
||||||
|
if (!(os_err = AudioObjectGetPropertyDataSize(deviceID, &prop_address,
|
||||||
|
0, nullptr, &io_size)))
|
||||||
|
{
|
||||||
|
rd.audio_channel_layout = (AudioChannelLayout *)allocate<char>(io_size);
|
||||||
|
if (!rd.audio_channel_layout) {
|
||||||
|
deinit_refresh_devices(&rd);
|
||||||
|
return SoundIoErrorNoMem;
|
||||||
|
}
|
||||||
|
if ((os_err = AudioObjectGetPropertyData(deviceID, &prop_address, 0, nullptr,
|
||||||
|
&io_size, rd.audio_channel_layout)))
|
||||||
|
{
|
||||||
|
deinit_refresh_devices(&rd);
|
||||||
|
return SoundIoErrorOpeningDevice;
|
||||||
|
}
|
||||||
|
if ((err = from_coreaudio_layout(rd.audio_channel_layout, &rd.device->current_layout))) {
|
||||||
|
rd.device->current_layout.channel_count = channel_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (all_channels_invalid(&rd.device->current_layout)) {
|
||||||
|
const struct SoundIoChannelLayout *guessed_layout =
|
||||||
|
soundio_channel_layout_get_default(channel_count);
|
||||||
|
if (guessed_layout)
|
||||||
|
rd.device->current_layout = *guessed_layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
rd.device->layouts[0] = rd.device->current_layout;
|
||||||
|
// in CoreAudio, format is always 32-bit native endian float
|
||||||
|
rd.device->formats[0] = SoundIoFormatFloat32NE;
|
||||||
|
|
||||||
|
SoundIoList<SoundIoDevice *> *device_list;
|
||||||
|
if (rd.device->aim == SoundIoDeviceAimOutput) {
|
||||||
|
device_list = &rd.devices_info->output_devices;
|
||||||
|
if (deviceID == default_output_id)
|
||||||
|
rd.devices_info->default_output_index = device_list->length;
|
||||||
|
} else {
|
||||||
|
assert(rd.device->aim == SoundIoDeviceAimInput);
|
||||||
|
device_list = &rd.devices_info->input_devices;
|
||||||
|
if (deviceID == default_input_id)
|
||||||
|
rd.devices_info->default_input_index = device_list->length;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((err = device_list->append(rd.device))) {
|
||||||
|
deinit_refresh_devices(&rd);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
rd.device = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
soundio_os_mutex_lock(sica->mutex);
|
soundio_os_mutex_lock(sica->mutex);
|
||||||
soundio_destroy_devices_info(sica->ready_devices_info);
|
soundio_destroy_devices_info(sica->ready_devices_info);
|
||||||
sica->ready_devices_info = devices_info;
|
sica->ready_devices_info = rd.devices_info;
|
||||||
soundio->on_events_signal(soundio);
|
soundio->on_events_signal(soundio);
|
||||||
soundio_os_mutex_unlock(sica->mutex);
|
soundio_os_mutex_unlock(sica->mutex);
|
||||||
if (!sica->have_devices_flag.exchange(true))
|
|
||||||
soundio_os_cond_signal(sica->have_devices_cond, nullptr);
|
|
||||||
|
|
||||||
|
rd.devices_info = nullptr;
|
||||||
|
deinit_refresh_devices(&rd);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -310,12 +640,16 @@ static void device_thread_run(void *arg) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (sica->device_scan_queued.exchange(false)) {
|
if (sica->device_scan_queued.exchange(false)) {
|
||||||
if ((err = refresh_devices(si))) {
|
err = refresh_devices(si);
|
||||||
|
if (err)
|
||||||
shutdown_backend(si, err);
|
shutdown_backend(si, err);
|
||||||
|
if (!sica->have_devices_flag.exchange(true))
|
||||||
|
soundio_os_cond_signal(sica->have_devices_cond, nullptr);
|
||||||
|
if (err)
|
||||||
return;
|
return;
|
||||||
}
|
soundio_os_cond_signal(sica->cond, nullptr);
|
||||||
}
|
}
|
||||||
soundio_os_cond_wait(sica->cond, nullptr);
|
soundio_os_cond_wait(sica->scan_devices_cond, nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -409,6 +743,12 @@ int soundio_coreaudio_init(SoundIoPrivate *si) {
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sica->scan_devices_cond = soundio_os_cond_create();
|
||||||
|
if (!sica->scan_devices_cond) {
|
||||||
|
destroy_ca(si);
|
||||||
|
return SoundIoErrorNoMem;
|
||||||
|
}
|
||||||
|
|
||||||
AudioObjectPropertyAddress prop_address = {
|
AudioObjectPropertyAddress prop_address = {
|
||||||
kAudioHardwarePropertyDevices,
|
kAudioHardwarePropertyDevices,
|
||||||
kAudioObjectPropertyScopeGlobal,
|
kAudioObjectPropertyScopeGlobal,
|
||||||
|
|
|
@ -28,6 +28,7 @@ struct SoundIoCoreAudio {
|
||||||
struct SoundIoDevicesInfo *ready_devices_info;
|
struct SoundIoDevicesInfo *ready_devices_info;
|
||||||
atomic_bool have_devices_flag;
|
atomic_bool have_devices_flag;
|
||||||
SoundIoOsCond *have_devices_cond;
|
SoundIoOsCond *have_devices_cond;
|
||||||
|
SoundIoOsCond *scan_devices_cond;
|
||||||
|
|
||||||
atomic_bool device_scan_queued;
|
atomic_bool device_scan_queued;
|
||||||
atomic_bool service_restarted;
|
atomic_bool service_restarted;
|
||||||
|
|
13
src/jack.cpp
13
src/jack.cpp
|
@ -70,15 +70,6 @@ static SoundIoJackClient *find_or_create_client(SoundIoList<SoundIoJackClient> *
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *dupe_str(const char *str, int str_len) {
|
|
||||||
char *out = allocate_nonzero<char>(str_len + 1);
|
|
||||||
if (!out)
|
|
||||||
return nullptr;
|
|
||||||
memcpy(out, str, str_len);
|
|
||||||
out[str_len] = 0;
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void destruct_device(SoundIoDevicePrivate *dp) {
|
static void destruct_device(SoundIoDevicePrivate *dp) {
|
||||||
SoundIoDeviceJack *dj = &dp->backend_data.jack;
|
SoundIoDeviceJack *dj = &dp->backend_data.jack;
|
||||||
for (int i = 0; i < dj->port_count; i += 1) {
|
for (int i = 0; i < dj->port_count; i += 1) {
|
||||||
|
@ -194,7 +185,7 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
|
||||||
device->soundio = soundio;
|
device->soundio = soundio;
|
||||||
device->is_raw = false;
|
device->is_raw = false;
|
||||||
device->aim = client->aim;
|
device->aim = client->aim;
|
||||||
device->id = dupe_str(client->name, client->name_len);
|
device->id = soundio_str_dupe(client->name, client->name_len);
|
||||||
device->name = allocate<char>(description_len);
|
device->name = allocate<char>(description_len);
|
||||||
device->layout_count = 1;
|
device->layout_count = 1;
|
||||||
device->layouts = create<SoundIoChannelLayout>();
|
device->layouts = create<SoundIoChannelLayout>();
|
||||||
|
@ -223,7 +214,7 @@ static int refresh_devices_bare(SoundIoPrivate *si) {
|
||||||
for (int port_index = 0; port_index < client->port_count; port_index += 1) {
|
for (int port_index = 0; port_index < client->port_count; port_index += 1) {
|
||||||
SoundIoJackPort *port = &client->ports[port_index];
|
SoundIoJackPort *port = &client->ports[port_index];
|
||||||
SoundIoDeviceJackPort *djp = &dj->ports[port_index];
|
SoundIoDeviceJackPort *djp = &dj->ports[port_index];
|
||||||
djp->full_name = dupe_str(port->full_name, port->full_name_len);
|
djp->full_name = soundio_str_dupe(port->full_name, port->full_name_len);
|
||||||
djp->full_name_len = port->full_name_len;
|
djp->full_name_len = port->full_name_len;
|
||||||
djp->channel_id = port->channel_id;
|
djp->channel_id = port->channel_id;
|
||||||
|
|
||||||
|
|
|
@ -425,6 +425,8 @@ void soundio_os_cond_signal(struct SoundIoOsCond *cond,
|
||||||
if (kevent(cond->kq_id, &kev, 1, NULL, 0, &timeout) == -1) {
|
if (kevent(cond->kq_id, &kev, 1, NULL, 0, &timeout) == -1) {
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
return;
|
return;
|
||||||
|
if (errno == ENOENT)
|
||||||
|
return;
|
||||||
assert(0); // kevent signal error
|
assert(0); // kevent signal error
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -152,10 +152,13 @@ void soundio_destroy(struct SoundIo *soundio) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_nothing_cb(struct SoundIo *) { }
|
static void do_nothing_cb(struct SoundIo *) { }
|
||||||
static void do_nothing_backend_disconnect_cb(struct SoundIo *, int err) { }
|
|
||||||
static void default_msg_callback(const char *msg) { }
|
static void default_msg_callback(const char *msg) { }
|
||||||
|
|
||||||
struct SoundIo * soundio_create(void) {
|
static void default_backend_disconnect_cb(struct SoundIo *, int err) {
|
||||||
|
soundio_panic("libsoundio: backend disconnected: %s", soundio_strerror(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SoundIo *soundio_create(void) {
|
||||||
int err;
|
int err;
|
||||||
if ((err = soundio_os_init()))
|
if ((err = soundio_os_init()))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -164,7 +167,7 @@ struct SoundIo * soundio_create(void) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
SoundIo *soundio = &si->pub;
|
SoundIo *soundio = &si->pub;
|
||||||
soundio->on_devices_change = do_nothing_cb;
|
soundio->on_devices_change = do_nothing_cb;
|
||||||
soundio->on_backend_disconnect = do_nothing_backend_disconnect_cb;
|
soundio->on_backend_disconnect = default_backend_disconnect_cb;
|
||||||
soundio->on_events_signal = do_nothing_cb;
|
soundio->on_events_signal = do_nothing_cb;
|
||||||
soundio->app_name = "SoundIo";
|
soundio->app_name = "SoundIo";
|
||||||
soundio->jack_info_callback = default_msg_callback;
|
soundio->jack_info_callback = default_msg_callback;
|
||||||
|
@ -207,6 +210,7 @@ int soundio_connect_backend(SoundIo *soundio, SoundIoBackend backend) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
soundio->current_backend = backend;
|
soundio->current_backend = backend;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,8 +256,7 @@ int soundio_input_device_count(struct SoundIo *soundio) {
|
||||||
assert(soundio->current_backend != SoundIoBackendNone);
|
assert(soundio->current_backend != SoundIoBackendNone);
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
||||||
if (!si->safe_devices_info)
|
if (!si->safe_devices_info)
|
||||||
soundio_flush_events(soundio);
|
return -1;
|
||||||
assert(si->safe_devices_info);
|
|
||||||
return si->safe_devices_info->input_devices.length;
|
return si->safe_devices_info->input_devices.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,8 +264,7 @@ int soundio_output_device_count(struct SoundIo *soundio) {
|
||||||
assert(soundio->current_backend != SoundIoBackendNone);
|
assert(soundio->current_backend != SoundIoBackendNone);
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
||||||
if (!si->safe_devices_info)
|
if (!si->safe_devices_info)
|
||||||
soundio_flush_events(soundio);
|
return -1;
|
||||||
assert(si->safe_devices_info);
|
|
||||||
return si->safe_devices_info->output_devices.length;
|
return si->safe_devices_info->output_devices.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,8 +272,7 @@ int soundio_default_input_device_index(struct SoundIo *soundio) {
|
||||||
assert(soundio->current_backend != SoundIoBackendNone);
|
assert(soundio->current_backend != SoundIoBackendNone);
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
||||||
if (!si->safe_devices_info)
|
if (!si->safe_devices_info)
|
||||||
soundio_flush_events(soundio);
|
return -1;
|
||||||
assert(si->safe_devices_info);
|
|
||||||
return si->safe_devices_info->default_input_index;
|
return si->safe_devices_info->default_input_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,28 +280,31 @@ int soundio_default_output_device_index(struct SoundIo *soundio) {
|
||||||
assert(soundio->current_backend != SoundIoBackendNone);
|
assert(soundio->current_backend != SoundIoBackendNone);
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
||||||
if (!si->safe_devices_info)
|
if (!si->safe_devices_info)
|
||||||
soundio_flush_events(soundio);
|
return -1;
|
||||||
assert(si->safe_devices_info);
|
|
||||||
return si->safe_devices_info->default_output_index;
|
return si->safe_devices_info->default_output_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SoundIoDevice *soundio_get_input_device(struct SoundIo *soundio, int index) {
|
struct SoundIoDevice *soundio_get_input_device(struct SoundIo *soundio, int index) {
|
||||||
assert(soundio->current_backend != SoundIoBackendNone);
|
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
||||||
assert(si->safe_devices_info);
|
assert(soundio->current_backend != SoundIoBackendNone);
|
||||||
assert(index >= 0);
|
assert(index >= 0);
|
||||||
assert(index < si->safe_devices_info->input_devices.length);
|
assert(index < si->safe_devices_info->input_devices.length);
|
||||||
|
if (!si->safe_devices_info)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
SoundIoDevice *device = si->safe_devices_info->input_devices.at(index);
|
SoundIoDevice *device = si->safe_devices_info->input_devices.at(index);
|
||||||
soundio_device_ref(device);
|
soundio_device_ref(device);
|
||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SoundIoDevice *soundio_get_output_device(struct SoundIo *soundio, int index) {
|
struct SoundIoDevice *soundio_get_output_device(struct SoundIo *soundio, int index) {
|
||||||
assert(soundio->current_backend != SoundIoBackendNone);
|
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
||||||
assert(si->safe_devices_info);
|
assert(soundio->current_backend != SoundIoBackendNone);
|
||||||
assert(index >= 0);
|
assert(index >= 0);
|
||||||
assert(index < si->safe_devices_info->output_devices.length);
|
assert(index < si->safe_devices_info->output_devices.length);
|
||||||
|
if (!si->safe_devices_info)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
SoundIoDevice *device = si->safe_devices_info->output_devices.at(index);
|
SoundIoDevice *device = si->safe_devices_info->output_devices.at(index);
|
||||||
soundio_device_ref(device);
|
soundio_device_ref(device);
|
||||||
return device;
|
return device;
|
||||||
|
|
|
@ -88,6 +88,15 @@ void soundio_panic(const char *format, ...)
|
||||||
char *soundio_alloc_sprintf(int *len, const char *format, ...)
|
char *soundio_alloc_sprintf(int *len, const char *format, ...)
|
||||||
__attribute__ ((format (printf, 2, 3)));
|
__attribute__ ((format (printf, 2, 3)));
|
||||||
|
|
||||||
|
static inline char *soundio_str_dupe(const char *str, int str_len) {
|
||||||
|
char *out = allocate_nonzero<char>(str_len + 1);
|
||||||
|
if (!out)
|
||||||
|
return nullptr;
|
||||||
|
memcpy(out, str, str_len);
|
||||||
|
out[str_len] = 0;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool soundio_streql(const char *str1, int str1_len, const char *str2, int str2_len) {
|
static inline bool soundio_streql(const char *str1, int str1_len, const char *str2, int str2_len) {
|
||||||
if (str1_len != str2_len)
|
if (str1_len != str2_len)
|
||||||
return false;
|
return false;
|
||||||
|
|
Loading…
Reference in a new issue