osxaudio: Attempt to configure the segment size in CoreAudio

Set the BufferFrame size in CoreAudio so it will deliver data
in ringbuffer segment units when recording. Otherwise, CoreAudio
will provide data in whatever granularity it wants, with no
relationship to the requested latency-time.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5140>
This commit is contained in:
Jan Schmidt 2023-07-26 00:21:18 +10:00 committed by GStreamer Marge Bot
parent 2df9283d3f
commit f5d2ea76b4
4 changed files with 33 additions and 7 deletions

View file

@ -174,7 +174,8 @@ gst_osx_audio_ring_buffer_acquire (GstAudioRingBuffer * buf,
{ {
gboolean ret = FALSE, is_passthrough = FALSE; gboolean ret = FALSE, is_passthrough = FALSE;
GstOsxAudioRingBuffer *osxbuf; GstOsxAudioRingBuffer *osxbuf;
AudioStreamBasicDescription format; AudioStreamBasicDescription format = { 0 };
guint32 frames_per_packet = 0;
osxbuf = GST_OSX_AUDIO_RING_BUFFER (buf); osxbuf = GST_OSX_AUDIO_RING_BUFFER (buf);
@ -225,6 +226,8 @@ gst_osx_audio_ring_buffer_acquire (GstAudioRingBuffer * buf,
(spec->latency_time * GST_AUDIO_INFO_RATE (&spec->info) / (spec->latency_time * GST_AUDIO_INFO_RATE (&spec->info) /
G_USEC_PER_SEC) * GST_AUDIO_INFO_BPF (&spec->info); G_USEC_PER_SEC) * GST_AUDIO_INFO_BPF (&spec->info);
spec->segtotal = spec->buffer_time / spec->latency_time; spec->segtotal = spec->buffer_time / spec->latency_time;
frames_per_packet = spec->segsize / GST_AUDIO_INFO_BPF (&spec->info);
is_passthrough = FALSE; is_passthrough = FALSE;
} }
@ -239,7 +242,7 @@ gst_osx_audio_ring_buffer_acquire (GstAudioRingBuffer * buf,
buf->memory = g_malloc0 (buf->size); buf->memory = g_malloc0 (buf->size);
ret = gst_core_audio_initialize (osxbuf->core_audio, format, spec->caps, ret = gst_core_audio_initialize (osxbuf->core_audio, format, spec->caps,
is_passthrough); frames_per_packet, is_passthrough);
if (!ret) { if (!ret) {
g_free (buf->memory); g_free (buf->memory);

View file

@ -208,22 +208,26 @@ gst_core_audio_get_samples_and_latency (GstCoreAudio * core_audio,
gboolean gboolean
gst_core_audio_initialize (GstCoreAudio * core_audio, gst_core_audio_initialize (GstCoreAudio * core_audio,
AudioStreamBasicDescription format, GstCaps * caps, gboolean is_passthrough) AudioStreamBasicDescription format, GstCaps * caps,
guint32 frames_per_packet, gboolean is_passthrough)
{ {
guint32 frame_size;
GST_DEBUG_OBJECT (core_audio, GST_DEBUG_OBJECT (core_audio,
"Initializing: passthrough:%d caps:%" GST_PTR_FORMAT, is_passthrough, "Initializing: passthrough:%d caps:%" GST_PTR_FORMAT, is_passthrough,
caps); caps);
if (!gst_core_audio_initialize_impl (core_audio, format, caps, if (!gst_core_audio_initialize_impl (core_audio, format, caps,
is_passthrough, &frame_size)) { is_passthrough, &frames_per_packet)) {
return FALSE; return FALSE;
} }
if (core_audio->is_src) { if (core_audio->is_src) {
/* create AudioBufferList needed for recording */ /* create AudioBufferList needed for recording */
core_audio->recBufferSize = frame_size * format.mBytesPerFrame; core_audio->recBufferSize = frames_per_packet * format.mBytesPerFrame;
GST_DEBUG_OBJECT (core_audio,
"Allocating record buffers %u bytes %u frames",
core_audio->recBufferSize, frames_per_packet);
core_audio->recBufferList = core_audio->recBufferList =
buffer_list_alloc (format.mChannelsPerFrame, core_audio->recBufferSize, buffer_list_alloc (format.mChannelsPerFrame, core_audio->recBufferSize,
/* Currently always TRUE (i.e. interleaved) */ /* Currently always TRUE (i.e. interleaved) */

View file

@ -127,6 +127,7 @@ gboolean gst_core_audio_close (GstCoreAudio *core
gboolean gst_core_audio_initialize (GstCoreAudio *core_audio, gboolean gst_core_audio_initialize (GstCoreAudio *core_audio,
AudioStreamBasicDescription format, AudioStreamBasicDescription format,
GstCaps *caps, GstCaps *caps,
guint32 frames_per_packet,
gboolean is_passthrough); gboolean is_passthrough);
void gst_core_audio_uninitialize (GstCoreAudio *core_audio); void gst_core_audio_uninitialize (GstCoreAudio *core_audio);

View file

@ -1174,6 +1174,24 @@ gst_core_audio_initialize_impl (GstCoreAudio * core_audio,
if (core_audio->is_src) { if (core_audio->is_src) {
propertySize = sizeof (*frame_size); propertySize = sizeof (*frame_size);
// Attempt to configure the requested frame size if smaller than the device's
// This will apparently modify the size for all audio devices in the current process so should
// be done conservatively
if (frame_size != 0) {
guint32 cur_frame_size;
status = AudioUnitGetProperty (core_audio->audiounit, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, 0, /* N/A for global */
&cur_frame_size, &propertySize);
if (!status && *frame_size < cur_frame_size) {
status = AudioUnitSetProperty (core_audio->audiounit, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, 0, /* N/A for global */
frame_size, propertySize);
if (status) {
GST_WARNING_OBJECT (core_audio->osxbuf,
"Failed to set desired frame size of %u: %d", *frame_size,
(int) status);
}
}
}
status = AudioUnitGetProperty (core_audio->audiounit, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, 0, /* N/A for global */ status = AudioUnitGetProperty (core_audio->audiounit, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, 0, /* N/A for global */
frame_size, &propertySize); frame_size, &propertySize);