[client] audio: add audio playback latency interface and graph

This commit is contained in:
Geoffrey McRae 2022-01-17 22:13:41 +11:00
parent 5629655f74
commit 689cc53255
5 changed files with 81 additions and 5 deletions

View File

@ -370,6 +370,16 @@ static void pipewire_playbackMute(bool mute)
pw_thread_loop_unlock(pw.thread);
}
static uint64_t pipewire_playbackLatency(void)
{
const int frames = ringbuffer_getCount(pw.playback.buffer);
if (frames == 0)
return 0;
// TODO: we should really include the hw latency here too
return (uint64_t)pw.playback.sampleRate * 1000ULL / frames;
}
static void pipewire_recordStopStream(void)
{
if (!pw.record.stream)
@ -527,11 +537,12 @@ struct LG_AudioDevOps LGAD_PipeWire =
.free = pipewire_free,
.playback =
{
.start = pipewire_playbackStart,
.play = pipewire_playbackPlay,
.stop = pipewire_playbackStop,
.volume = pipewire_playbackVolume,
.mute = pipewire_playbackMute
.start = pipewire_playbackStart,
.play = pipewire_playbackPlay,
.stop = pipewire_playbackStop,
.volume = pipewire_playbackVolume,
.mute = pipewire_playbackMute,
.latency = pipewire_playbackLatency
},
.record =
{

View File

@ -59,6 +59,9 @@ struct LG_AudioDevOps
/* [optional] called to set muting of the output */
void (*mute)(bool mute);
/* return the current total playback latency in microseconds */
uint64_t (*latency)(void);
}
playback;

View File

@ -18,6 +18,7 @@
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "audio.h"
#include "main.h"
#include "common/array.h"
#include "common/util.h"
@ -36,6 +37,10 @@ typedef struct
int volumeChannels;
uint16_t volume[8];
bool mute;
LG_Lock lock;
RingBuffer timings;
GraphHandle graph;
}
playback;
@ -60,6 +65,7 @@ void audio_init(void)
if (LG_AudioDevs[i]->init())
{
audio.audioDev = LG_AudioDevs[i];
LG_LOCK_INIT(audio.playback.lock);
DEBUG_INFO("Using AudioDev: %s", audio.audioDev->name);
return;
}
@ -77,6 +83,7 @@ void audio_free(void)
audio.audioDev->free();
audio.audioDev = NULL;
LG_LOCK_FREE(audio.playback.lock);
}
bool audio_supportsPlayback(void)
@ -84,6 +91,16 @@ bool audio_supportsPlayback(void)
return audio.audioDev && audio.audioDev->playback.start;
}
static const char * audioGraphFormatFn(const char * name,
float min, float max, float avg, float freq, float last)
{
static char title[64];
snprintf(title, sizeof(title),
"%s: min:%4.2f max:%4.2f avg:%4.2f now:%4.2f",
name, min, max, avg, last);
return title;
}
void audio_playbackStart(int channels, int sampleRate, PSAudioFormat format,
uint32_t time)
{
@ -101,6 +118,8 @@ void audio_playbackStart(int channels, int sampleRate, PSAudioFormat format,
return;
}
LG_LOCK(audio.playback.lock);
lastChannels = channels;
lastSampleRate = sampleRate;
audio.playback.started = true;
@ -116,6 +135,16 @@ void audio_playbackStart(int channels, int sampleRate, PSAudioFormat format,
// set the inital mute state
if (audio.audioDev->playback.mute)
audio.audioDev->playback.mute(audio.playback.mute);
// if the audio dev can report it's latency setup a timing graph
if (audio.audioDev->playback.latency)
{
audio.playback.timings = ringbuffer_new(2400, sizeof(float));
audio.playback.graph = app_registerGraph("PLAYBACK",
audio.playback.timings, 0.0f, 100.0f, audioGraphFormatFn);
}
LG_UNLOCK(audio.playback.lock);
}
void audio_playbackStop(void)
@ -123,8 +152,18 @@ void audio_playbackStop(void)
if (!audio.audioDev || !audio.playback.started)
return;
LG_LOCK(audio.playback.lock);
audio.audioDev->playback.stop();
audio.playback.started = false;
if (audio.playback.timings)
{
app_unregisterGraph(audio.playback.graph);
ringbuffer_free(&audio.playback.timings);
}
LG_UNLOCK(audio.playback.lock);
}
void audio_playbackVolume(int channels, const uint16_t volume[])
@ -244,3 +283,19 @@ void audio_recordMute(bool mute)
audio.audioDev->record.mute(mute);
}
void audio_tick(unsigned long long tickCount)
{
LG_LOCK(audio.playback.lock);
if (!audio.playback.timings)
{
LG_UNLOCK(audio.playback.lock);
return;
}
const uint64_t latency = audio.audioDev->playback.latency();
const float flatency = latency > 0 ? (float)latency / 1000.0f : 0.0f;
ringbuffer_push(audio.playback.timings, &flatency);
LG_UNLOCK(audio.playback.lock);
}

View File

@ -18,6 +18,9 @@
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdbool.h>
#include <purespice.h>
void audio_init(void);
void audio_free(void);
@ -34,3 +37,5 @@ void audio_recordStart(int channels, int sampleRate, PSAudioFormat format);
void audio_recordStop(void);
void audio_recordVolume(int channels, const uint16_t volume[]);
void audio_recordMute(bool mute);
void audio_tick(unsigned long long tickCount);

View File

@ -155,6 +155,8 @@ static bool tickTimerFn(void * unused)
if (needsRender)
app_invalidateWindow(false);
audio_tick(tickCount);
++tickCount;
return true;
}