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_rerouted,
ma_device_notification_type_interruption_began, ma_device_notification_type_interruption_began,
ma_device_notification_type_interruption_ended, 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; } ma_device_notification_type;
typedef struct typedef struct
@ -20216,7 +20218,13 @@ static void ma_device__on_notification(ma_device_notification notification)
{ {
MA_ASSERT(notification.pDevice != NULL); 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) { if (notification.pDevice->onNotification != NULL) {
notification.pDevice->onNotification(&notification); notification.pDevice->onNotification(&notification);
@ -24824,6 +24832,7 @@ static ma_result ma_device_read__wasapi(ma_device* pDevice, void* pFrames, ma_ui
/* Overrun detection. */ /* Overrun detection. */
if ((flags & MA_AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY) != 0) { 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. */ /* 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. */ continue; /* Try again. */
} else if (resultALSA == -EPIPE) { } else if (resultALSA == -EPIPE) {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "EPIPE (read)\n"); 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. */ /* 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); 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. */ continue; /* Try again. */
} else if (resultALSA == -EPIPE) { } else if (resultALSA == -EPIPE) {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "EPIPE (write)\n"); 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. */ /* 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). */ 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_uint8 silence[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
ma_uint64 remaining = framesMapped; ma_uint64 remaining = framesMapped;
ma_uint32 capacity = sizeof(silence) / bpf; 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); ma_silence_pcm_frames(silence, capacity, pDevice->capture.internalFormat, pDevice->capture.internalChannels);
while (remaining > 0 && ma_device_get_state(pDevice) == ma_device_state_started) { while (remaining > 0 && ma_device_get_state(pDevice) == ma_device_state_started) {
ma_uint32 n = (ma_uint32)ma_min(remaining, capacity); 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 #ifdef MA_SUPPORT_PULSEAUDIO
static void audio_diag_pulse_underflow(ma_pa_stream* stream, void* userdata) { static void audio_diag_pulse_underflow(ma_pa_stream* stream, void* userdata) {
(void)stream; (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) { static void audio_diag_pulse_overflow(ma_pa_stream* stream, void* userdata) {
(void)stream; ma_device* device = userdata;
audio_diag_event(userdata, AUDIO_DIAG_BACKEND_OVERFLOW, AUDIO_DIAG_WRITE, 1, 0); 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) { static void audio_diag_pulse_started(ma_pa_stream* stream, void* userdata) {
(void)stream; (void)stream;
@ -67,7 +69,6 @@ static void audio_diag_pulse_init(void* device) {
if (dev->pContext->backend != ma_backend_pulseaudio) return; if (dev->pContext->backend != ma_backend_pulseaudio) return;
audio_diag_pulse_buffer(dev, 1); audio_diag_pulse_buffer(dev, 1);
audio_diag_pulse_buffer(dev, 0); audio_diag_pulse_buffer(dev, 0);
if (!dev->pulse.pStreamPlayback) return;
#ifndef MA_NO_RUNTIME_LINKING #ifndef MA_NO_RUNTIME_LINKING
underflow = (ma_pa_stream_set_suspended_callback_proc)dlsym(dev->pContext->pulse.pulseSO, "pa_stream_set_underflow_callback"); 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"); 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"); audio_diag_log(ma_device_get_log(dev), MA_LOG_LEVEL_WARNING, "PulseAudio xrun/started callbacks unavailable");
return; return;
} }
underflow((ma_pa_stream*)dev->pulse.pStreamPlayback, audio_diag_pulse_underflow, dev); if (dev->pulse.pStreamCapture) overflow((ma_pa_stream*)dev->pulse.pStreamCapture, audio_diag_pulse_overflow, dev);
overflow((ma_pa_stream*)dev->pulse.pStreamPlayback, audio_diag_pulse_overflow, dev); if (dev->pulse.pStreamPlayback) {
started((ma_pa_stream*)dev->pulse.pStreamPlayback, audio_diag_pulse_started, dev); 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"); audio_diag_log(ma_device_get_log(dev), MA_LOG_LEVEL_INFO, "PulseAudio xrun/started observers registered");
#else #else
(void)device; (void)device;

Loading…
Cancel
Save