mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-23 16:54:03 +02:00
Core Audio: Improvements to sample rate selection on desktop.
This commit is contained in:
+44
-13
@@ -3197,6 +3197,10 @@ typedef struct
|
|||||||
const char* pStreamNamePlayback;
|
const char* pStreamNamePlayback;
|
||||||
const char* pStreamNameCapture;
|
const char* pStreamNameCapture;
|
||||||
} pulse;
|
} pulse;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
ma_bool32 allowNominalSampleRateChange; /* Desktop only. When enabled, allows changing of the sample rate at the operating system level. */
|
||||||
|
} coreaudio;
|
||||||
} ma_device_config;
|
} ma_device_config;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@@ -4601,6 +4605,13 @@ then be set directly on the structure. Below are the members of the `ma_device_c
|
|||||||
pulse.pStreamNameCapture
|
pulse.pStreamNameCapture
|
||||||
PulseAudio only. Sets the stream name for capture.
|
PulseAudio only. Sets the stream name for capture.
|
||||||
|
|
||||||
|
coreaudio.allowNominalSampleRateChange
|
||||||
|
Core Audio only. Desktop only. When enabled, allows the sample rate of the device to be changed at the operating system level. This
|
||||||
|
is disabled by default in order to prevent intrusive changes to the user's system. This is useful if you want to use a sample rate
|
||||||
|
that is known to be natively supported by the hardware thereby avoiding the cost of resampling. When set to true, miniaudio will
|
||||||
|
find the closest match between the sample rate requested in the device config and the sample rates natively supported by the
|
||||||
|
hardware. When set to false, the sample rate currently set by the operating system will always be used.
|
||||||
|
|
||||||
|
|
||||||
Once initialized, the device's config is immutable. If you need to change the config you will need to initialize a new device.
|
Once initialized, the device's config is immutable. If you need to change the config you will need to initialize a new device.
|
||||||
|
|
||||||
@@ -24816,6 +24827,8 @@ static void ma_device_uninit__coreaudio(ma_device* pDevice)
|
|||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
ma_bool32 allowNominalSampleRateChange;
|
||||||
|
|
||||||
/* Input. */
|
/* Input. */
|
||||||
ma_format formatIn;
|
ma_format formatIn;
|
||||||
ma_uint32 channelsIn;
|
ma_uint32 channelsIn;
|
||||||
@@ -24990,16 +25003,6 @@ static ma_result ma_device_init_internal__coreaudio(ma_context* pContext, ma_dev
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Update 2020-10-10:
|
|
||||||
|
|
||||||
I cannot remember where I read this in the documentation and I cannot find it again. For now I'm going to remove this
|
|
||||||
and see what the feedback from the community is like. If this results in issues we can add it back in again. The idea
|
|
||||||
is that the closest sample rate natively supported by the backend to the requested sample rate should be used if possible.
|
|
||||||
|
|
||||||
Update 2020-11-06:
|
|
||||||
|
|
||||||
I have found the documentation that talks about keeping the sample rate consistent:
|
|
||||||
|
|
||||||
Technical Note TN2091: Device input using the HAL Output Audio Unit
|
Technical Note TN2091: Device input using the HAL Output Audio Unit
|
||||||
https://developer.apple.com/library/archive/technotes/tn2091/_index.html
|
https://developer.apple.com/library/archive/technotes/tn2091/_index.html
|
||||||
|
|
||||||
@@ -25016,11 +25019,34 @@ static ma_result ma_device_init_internal__coreaudio(ma_context* pContext, ma_dev
|
|||||||
|
|
||||||
I have tried going against the documentation by setting the sample rate anyway, but this just results in AudioUnitRender()
|
I have tried going against the documentation by setting the sample rate anyway, but this just results in AudioUnitRender()
|
||||||
returning a result code of -10863. I have also tried changing the format directly on the input scope on the input bus, but
|
returning a result code of -10863. I have also tried changing the format directly on the input scope on the input bus, but
|
||||||
this just results in `ca_require: IsStreamFormatWritable(inScope, inElement) NotWritable` when trying to set the format. At
|
this just results in `ca_require: IsStreamFormatWritable(inScope, inElement) NotWritable` when trying to set the format.
|
||||||
this point I'm not sure how to change the sample rate on the device even if the device reports native support for it. If
|
|
||||||
anybody has any suggestions on this please let me know.
|
Something that does seem to work, however, has been setting the nominal sample rate on the deivce object. The problem with
|
||||||
|
this, however, is that it actually changes the sample rate at the operating system level and not just the application. This
|
||||||
|
could be intrusive to the user, however, so I don't think it's wise to make this the default. Instead I'm making this a
|
||||||
|
configuration option. When the `coreaudio.allowNominalSampleRateChange` config option is set to true, changing the sample
|
||||||
|
rate will be allowed. Otherwise it'll be fixed to the current sample rate. To check the system-defined sample rate, run
|
||||||
|
the Audio MIDI Setup program that comes installed on macOS and observe how the sample rate changes as the sample rate is
|
||||||
|
changed by miniaudio.
|
||||||
*/
|
*/
|
||||||
|
if (pData->allowNominalSampleRateChange) {
|
||||||
|
AudioValueRange sampleRateRange;
|
||||||
|
AudioObjectPropertyAddress propAddress;
|
||||||
|
|
||||||
|
sampleRateRange.mMinimum = bestFormat.mSampleRate;
|
||||||
|
sampleRateRange.mMaximum = bestFormat.mSampleRate;
|
||||||
|
|
||||||
|
propAddress.mSelector = kAudioDevicePropertyNominalSampleRate;
|
||||||
|
propAddress.mScope = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput;
|
||||||
|
propAddress.mElement = kAudioObjectPropertyElementMaster;
|
||||||
|
|
||||||
|
status = ((ma_AudioObjectSetPropertyData_proc)pContext->coreaudio.AudioObjectSetPropertyData)(deviceObjectID, &propAddress, 0, NULL, sizeof(sampleRateRange), &sampleRateRange);
|
||||||
|
if (status != noErr) {
|
||||||
bestFormat.mSampleRate = origFormat.mSampleRate;
|
bestFormat.mSampleRate = origFormat.mSampleRate;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bestFormat.mSampleRate = origFormat.mSampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, formatScope, formatElement, &bestFormat, sizeof(bestFormat));
|
status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, formatScope, formatElement, &bestFormat, sizeof(bestFormat));
|
||||||
if (status != noErr) {
|
if (status != noErr) {
|
||||||
@@ -25265,6 +25291,8 @@ static ma_result ma_device_reinit_internal__coreaudio(ma_device* pDevice, ma_dev
|
|||||||
return MA_INVALID_ARGS;
|
return MA_INVALID_ARGS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data.allowNominalSampleRateChange = MA_FALSE; /* Don't change the nominal sample rate when switching devices. */
|
||||||
|
|
||||||
if (deviceType == ma_device_type_capture) {
|
if (deviceType == ma_device_type_capture) {
|
||||||
data.formatIn = pDevice->capture.format;
|
data.formatIn = pDevice->capture.format;
|
||||||
data.channelsIn = pDevice->capture.channels;
|
data.channelsIn = pDevice->capture.channels;
|
||||||
@@ -25368,6 +25396,7 @@ static ma_result ma_device_init__coreaudio(ma_context* pContext, const ma_device
|
|||||||
/* Capture needs to be initialized first. */
|
/* Capture needs to be initialized first. */
|
||||||
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
|
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
|
||||||
ma_device_init_internal_data__coreaudio data;
|
ma_device_init_internal_data__coreaudio data;
|
||||||
|
data.allowNominalSampleRateChange = pConfig->coreaudio.allowNominalSampleRateChange;
|
||||||
data.formatIn = pConfig->capture.format;
|
data.formatIn = pConfig->capture.format;
|
||||||
data.channelsIn = pConfig->capture.channels;
|
data.channelsIn = pConfig->capture.channels;
|
||||||
data.sampleRateIn = pConfig->sampleRate;
|
data.sampleRateIn = pConfig->sampleRate;
|
||||||
@@ -25421,6 +25450,7 @@ static ma_result ma_device_init__coreaudio(ma_context* pContext, const ma_device
|
|||||||
/* Playback. */
|
/* Playback. */
|
||||||
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
|
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
|
||||||
ma_device_init_internal_data__coreaudio data;
|
ma_device_init_internal_data__coreaudio data;
|
||||||
|
data.allowNominalSampleRateChange = pConfig->coreaudio.allowNominalSampleRateChange;
|
||||||
data.formatIn = pConfig->playback.format;
|
data.formatIn = pConfig->playback.format;
|
||||||
data.channelsIn = pConfig->playback.channels;
|
data.channelsIn = pConfig->playback.channels;
|
||||||
data.sampleRateIn = pConfig->sampleRate;
|
data.sampleRateIn = pConfig->sampleRate;
|
||||||
@@ -62960,6 +62990,7 @@ v0.10.22 - TBD
|
|||||||
- Fix some compilation warnings on GCC and Clang relating to the Speex resampler.
|
- Fix some compilation warnings on GCC and Clang relating to the Speex resampler.
|
||||||
- Fix a compilation error for the Linux build when the ALSA and JACK backends are both disabled.
|
- Fix a compilation error for the Linux build when the ALSA and JACK backends are both disabled.
|
||||||
- ALSA: Fix a bug in `ma_context_get_device_info()` where the PCM handle is left open in the event of an error.
|
- ALSA: Fix a bug in `ma_context_get_device_info()` where the PCM handle is left open in the event of an error.
|
||||||
|
- Core Audio: Further improvements to sample rate selection.
|
||||||
- Add support for detecting default devices during device enumeration and with `ma_context_get_device_info()`.
|
- Add support for detecting default devices during device enumeration and with `ma_context_get_device_info()`.
|
||||||
- Add documentation for `MA_NO_RUNTIME_LINKING`.
|
- Add documentation for `MA_NO_RUNTIME_LINKING`.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user