Browse Source

Expose WASAPI and Linux audio buffer glitches to device owners

master
evgeny 2 days ago
parent
commit
360d5dddaa
  1. 16
      lib/miniaudio.h
  2. 18
      tools/chatgui/transport/miniaudio_impl.c

16
lib/miniaudio.h

@ -6780,7 +6780,9 @@ typedef enum
ma_device_notification_type_rerouted,
ma_device_notification_type_interruption_began,
ma_device_notification_type_interruption_ended,
ma_device_notification_type_unlocked
ma_device_notification_type_unlocked,
ma_device_notification_type_capture_overrun, /* uTun: подтверждённый backend разрыв входного PCM. */
ma_device_notification_type_playback_underrun /* uTun: backend исчерпал буфер воспроизведения. */
} ma_device_notification_type;
typedef struct
@ -20216,7 +20218,13 @@ static void ma_device__on_notification(ma_device_notification notification)
{
MA_ASSERT(notification.pDevice != NULL);
MA_DIAGNOSTIC_EVENT(notification.pDevice, AUDIO_DIAG_NOTIFY, -1, notification.type, ma_device_get_state(notification.pDevice));
if (notification.type == ma_device_notification_type_capture_overrun) {
MA_DIAGNOSTIC_EVENT(notification.pDevice, AUDIO_DIAG_BACKEND_OVERFLOW, AUDIO_DIAG_READ, 1, 0);
} else if (notification.type == ma_device_notification_type_playback_underrun) {
MA_DIAGNOSTIC_EVENT(notification.pDevice, AUDIO_DIAG_BACKEND_UNDERRUN, AUDIO_DIAG_WRITE, 1, 0);
} else {
MA_DIAGNOSTIC_EVENT(notification.pDevice, AUDIO_DIAG_NOTIFY, -1, notification.type, ma_device_get_state(notification.pDevice));
}
if (notification.pDevice->onNotification != NULL) {
notification.pDevice->onNotification(&notification);
@ -24824,6 +24832,7 @@ static ma_result ma_device_read__wasapi(ma_device* pDevice, void* pFrames, ma_ui
/* Overrun detection. */
if ((flags & MA_AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY) != 0) {
ma_device__on_notification(ma_device_notification_init(pDevice, ma_device_notification_type_capture_overrun));
/* Glitched. Probably due to an overrun. */
/*
@ -29900,6 +29909,7 @@ static ma_result ma_device_read__alsa(ma_device* pDevice, void* pFramesOut, ma_u
continue; /* Try again. */
} else if (resultALSA == -EPIPE) {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "EPIPE (read)\n");
ma_device__on_notification(ma_device_notification_init(pDevice, ma_device_notification_type_capture_overrun));
/* Overrun. Recover and try again. If this fails we need to return an error. */
resultALSA = ((ma_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture, resultALSA, MA_TRUE);
@ -29955,6 +29965,7 @@ static ma_result ma_device_write__alsa(ma_device* pDevice, const void* pFrames,
continue; /* Try again. */
} else if (resultALSA == -EPIPE) {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "EPIPE (write)\n");
ma_device__on_notification(ma_device_notification_init(pDevice, ma_device_notification_type_playback_underrun));
/* Underrun. Recover and try again. If this fails we need to return an error. */
resultALSA = ((ma_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback, resultALSA, MA_TRUE); /* MA_TRUE=silent (don't print anything on error). */
@ -31839,6 +31850,7 @@ static void ma_device_on_read__pulse(ma_pa_stream* pStream, size_t byteCount, vo
ma_uint8 silence[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
ma_uint64 remaining = framesMapped;
ma_uint32 capacity = sizeof(silence) / bpf;
ma_device__on_notification(ma_device_notification_init(pDevice, ma_device_notification_type_capture_overrun));
ma_silence_pcm_frames(silence, capacity, pDevice->capture.internalFormat, pDevice->capture.internalChannels);
while (remaining > 0 && ma_device_get_state(pDevice) == ma_device_state_started) {
ma_uint32 n = (ma_uint32)ma_min(remaining, capacity);

18
tools/chatgui/transport/miniaudio_impl.c

@ -20,11 +20,13 @@ static void audio_capture_hole(uint64_t offset);
#ifdef MA_SUPPORT_PULSEAUDIO
static void audio_diag_pulse_underflow(ma_pa_stream* stream, void* userdata) {
(void)stream;
audio_diag_event(userdata, AUDIO_DIAG_BACKEND_UNDERRUN, AUDIO_DIAG_WRITE, 1, 0);
ma_device__on_notification(ma_device_notification_init(userdata, ma_device_notification_type_playback_underrun));
}
static void audio_diag_pulse_overflow(ma_pa_stream* stream, void* userdata) {
(void)stream;
audio_diag_event(userdata, AUDIO_DIAG_BACKEND_OVERFLOW, AUDIO_DIAG_WRITE, 1, 0);
ma_device* device = userdata;
if (stream == device->pulse.pStreamCapture)
ma_device__on_notification(ma_device_notification_init(device, ma_device_notification_type_capture_overrun));
else audio_diag_event(userdata, AUDIO_DIAG_BACKEND_OVERFLOW, AUDIO_DIAG_WRITE, 1, 0);
}
static void audio_diag_pulse_started(ma_pa_stream* stream, void* userdata) {
(void)stream;
@ -67,7 +69,6 @@ static void audio_diag_pulse_init(void* device) {
if (dev->pContext->backend != ma_backend_pulseaudio) return;
audio_diag_pulse_buffer(dev, 1);
audio_diag_pulse_buffer(dev, 0);
if (!dev->pulse.pStreamPlayback) return;
#ifndef MA_NO_RUNTIME_LINKING
underflow = (ma_pa_stream_set_suspended_callback_proc)dlsym(dev->pContext->pulse.pulseSO, "pa_stream_set_underflow_callback");
overflow = (ma_pa_stream_set_suspended_callback_proc)dlsym(dev->pContext->pulse.pulseSO, "pa_stream_set_overflow_callback");
@ -81,9 +82,12 @@ static void audio_diag_pulse_init(void* device) {
audio_diag_log(ma_device_get_log(dev), MA_LOG_LEVEL_WARNING, "PulseAudio xrun/started callbacks unavailable");
return;
}
underflow((ma_pa_stream*)dev->pulse.pStreamPlayback, audio_diag_pulse_underflow, dev);
overflow((ma_pa_stream*)dev->pulse.pStreamPlayback, audio_diag_pulse_overflow, dev);
started((ma_pa_stream*)dev->pulse.pStreamPlayback, audio_diag_pulse_started, dev);
if (dev->pulse.pStreamCapture) overflow((ma_pa_stream*)dev->pulse.pStreamCapture, audio_diag_pulse_overflow, dev);
if (dev->pulse.pStreamPlayback) {
underflow((ma_pa_stream*)dev->pulse.pStreamPlayback, audio_diag_pulse_underflow, dev);
overflow((ma_pa_stream*)dev->pulse.pStreamPlayback, audio_diag_pulse_overflow, dev);
started((ma_pa_stream*)dev->pulse.pStreamPlayback, audio_diag_pulse_started, dev);
}
audio_diag_log(ma_device_get_log(dev), MA_LOG_LEVEL_INFO, "PulseAudio xrun/started observers registered");
#else
(void)device;

Loading…
Cancel
Save