mirror of
https://github.com/gnif/LookingGlass.git
synced 2025-04-29 01:56:27 +00:00
[client] audio: add audio playback latency interface and graph
This commit is contained in:
parent
5629655f74
commit
689cc53255
@ -370,6 +370,16 @@ static void pipewire_playbackMute(bool mute)
|
|||||||
pw_thread_loop_unlock(pw.thread);
|
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)
|
static void pipewire_recordStopStream(void)
|
||||||
{
|
{
|
||||||
if (!pw.record.stream)
|
if (!pw.record.stream)
|
||||||
@ -527,11 +537,12 @@ struct LG_AudioDevOps LGAD_PipeWire =
|
|||||||
.free = pipewire_free,
|
.free = pipewire_free,
|
||||||
.playback =
|
.playback =
|
||||||
{
|
{
|
||||||
.start = pipewire_playbackStart,
|
.start = pipewire_playbackStart,
|
||||||
.play = pipewire_playbackPlay,
|
.play = pipewire_playbackPlay,
|
||||||
.stop = pipewire_playbackStop,
|
.stop = pipewire_playbackStop,
|
||||||
.volume = pipewire_playbackVolume,
|
.volume = pipewire_playbackVolume,
|
||||||
.mute = pipewire_playbackMute
|
.mute = pipewire_playbackMute,
|
||||||
|
.latency = pipewire_playbackLatency
|
||||||
},
|
},
|
||||||
.record =
|
.record =
|
||||||
{
|
{
|
||||||
|
@ -59,6 +59,9 @@ struct LG_AudioDevOps
|
|||||||
|
|
||||||
/* [optional] called to set muting of the output */
|
/* [optional] called to set muting of the output */
|
||||||
void (*mute)(bool mute);
|
void (*mute)(bool mute);
|
||||||
|
|
||||||
|
/* return the current total playback latency in microseconds */
|
||||||
|
uint64_t (*latency)(void);
|
||||||
}
|
}
|
||||||
playback;
|
playback;
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "audio.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "common/array.h"
|
#include "common/array.h"
|
||||||
#include "common/util.h"
|
#include "common/util.h"
|
||||||
@ -36,6 +37,10 @@ typedef struct
|
|||||||
int volumeChannels;
|
int volumeChannels;
|
||||||
uint16_t volume[8];
|
uint16_t volume[8];
|
||||||
bool mute;
|
bool mute;
|
||||||
|
|
||||||
|
LG_Lock lock;
|
||||||
|
RingBuffer timings;
|
||||||
|
GraphHandle graph;
|
||||||
}
|
}
|
||||||
playback;
|
playback;
|
||||||
|
|
||||||
@ -60,6 +65,7 @@ void audio_init(void)
|
|||||||
if (LG_AudioDevs[i]->init())
|
if (LG_AudioDevs[i]->init())
|
||||||
{
|
{
|
||||||
audio.audioDev = LG_AudioDevs[i];
|
audio.audioDev = LG_AudioDevs[i];
|
||||||
|
LG_LOCK_INIT(audio.playback.lock);
|
||||||
DEBUG_INFO("Using AudioDev: %s", audio.audioDev->name);
|
DEBUG_INFO("Using AudioDev: %s", audio.audioDev->name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -77,6 +83,7 @@ void audio_free(void)
|
|||||||
|
|
||||||
audio.audioDev->free();
|
audio.audioDev->free();
|
||||||
audio.audioDev = NULL;
|
audio.audioDev = NULL;
|
||||||
|
LG_LOCK_FREE(audio.playback.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool audio_supportsPlayback(void)
|
bool audio_supportsPlayback(void)
|
||||||
@ -84,6 +91,16 @@ bool audio_supportsPlayback(void)
|
|||||||
return audio.audioDev && audio.audioDev->playback.start;
|
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,
|
void audio_playbackStart(int channels, int sampleRate, PSAudioFormat format,
|
||||||
uint32_t time)
|
uint32_t time)
|
||||||
{
|
{
|
||||||
@ -101,6 +118,8 @@ void audio_playbackStart(int channels, int sampleRate, PSAudioFormat format,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LG_LOCK(audio.playback.lock);
|
||||||
|
|
||||||
lastChannels = channels;
|
lastChannels = channels;
|
||||||
lastSampleRate = sampleRate;
|
lastSampleRate = sampleRate;
|
||||||
audio.playback.started = true;
|
audio.playback.started = true;
|
||||||
@ -116,6 +135,16 @@ void audio_playbackStart(int channels, int sampleRate, PSAudioFormat format,
|
|||||||
// set the inital mute state
|
// set the inital mute state
|
||||||
if (audio.audioDev->playback.mute)
|
if (audio.audioDev->playback.mute)
|
||||||
audio.audioDev->playback.mute(audio.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)
|
void audio_playbackStop(void)
|
||||||
@ -123,8 +152,18 @@ void audio_playbackStop(void)
|
|||||||
if (!audio.audioDev || !audio.playback.started)
|
if (!audio.audioDev || !audio.playback.started)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
LG_LOCK(audio.playback.lock);
|
||||||
|
|
||||||
audio.audioDev->playback.stop();
|
audio.audioDev->playback.stop();
|
||||||
audio.playback.started = false;
|
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[])
|
void audio_playbackVolume(int channels, const uint16_t volume[])
|
||||||
@ -244,3 +283,19 @@ void audio_recordMute(bool mute)
|
|||||||
|
|
||||||
audio.audioDev->record.mute(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);
|
||||||
|
}
|
||||||
|
@ -18,6 +18,9 @@
|
|||||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <purespice.h>
|
||||||
|
|
||||||
void audio_init(void);
|
void audio_init(void);
|
||||||
void audio_free(void);
|
void audio_free(void);
|
||||||
|
|
||||||
@ -34,3 +37,5 @@ void audio_recordStart(int channels, int sampleRate, PSAudioFormat format);
|
|||||||
void audio_recordStop(void);
|
void audio_recordStop(void);
|
||||||
void audio_recordVolume(int channels, const uint16_t volume[]);
|
void audio_recordVolume(int channels, const uint16_t volume[]);
|
||||||
void audio_recordMute(bool mute);
|
void audio_recordMute(bool mute);
|
||||||
|
|
||||||
|
void audio_tick(unsigned long long tickCount);
|
||||||
|
@ -155,6 +155,8 @@ static bool tickTimerFn(void * unused)
|
|||||||
if (needsRender)
|
if (needsRender)
|
||||||
app_invalidateWindow(false);
|
app_invalidateWindow(false);
|
||||||
|
|
||||||
|
audio_tick(tickCount);
|
||||||
|
|
||||||
++tickCount;
|
++tickCount;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user