[client] audio: change the audio latency graph sample point

This removes the need for locking while also giving a better result in
the graph output. Also when the graph is disabled via the overlay
options it will no longer cause redraws.
This commit is contained in:
Geoffrey McRae 2022-01-28 10:59:12 +11:00
parent a0477466d2
commit 22b968ff53
7 changed files with 25 additions and 56 deletions

View file

@ -116,7 +116,7 @@ typedef const char * (*GraphFormatFn)(const char * name,
GraphHandle app_registerGraph(const char * name, RingBuffer buffer, GraphHandle app_registerGraph(const char * name, RingBuffer buffer,
float min, float max, GraphFormatFn formatFn); float min, float max, GraphFormatFn formatFn);
void app_unregisterGraph(GraphHandle handle); void app_unregisterGraph(GraphHandle handle);
void app_invalidateGraphs(void); void app_invalidateGraph(GraphHandle handle);
void app_overlayConfigRegister(const char * title, void app_overlayConfigRegister(const char * title,
void (*callback)(void * udata, int * id), void * udata); void (*callback)(void * udata, int * id), void * udata);

View file

@ -706,9 +706,9 @@ void app_unregisterGraph(GraphHandle handle)
overlayGraph_unregister(handle); overlayGraph_unregister(handle);
} }
void app_invalidateGraphs(void) void app_invalidateGraph(GraphHandle handle)
{ {
overlayGraph_invalidate(); overlayGraph_invalidate(handle);
} }
void app_registerOverlay(const struct LG_OverlayOps * ops, const void * params) void app_registerOverlay(const struct LG_OverlayOps * ops, const void * params)

View file

@ -100,7 +100,6 @@ typedef struct
RingBuffer buffer; RingBuffer buffer;
RingBuffer deviceTiming; RingBuffer deviceTiming;
LG_Lock lock;
RingBuffer timings; RingBuffer timings;
GraphHandle graph; GraphHandle graph;
@ -134,7 +133,7 @@ typedef struct
} }
PlaybackDeviceTick; PlaybackDeviceTick;
static void playbackStopNL(void); static void playbackStop(void);
void audio_init(void) void audio_init(void)
{ {
@ -143,7 +142,6 @@ 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;
} }
@ -157,15 +155,11 @@ void audio_free(void)
return; return;
// immediate stop of the stream, do not wait for drain // immediate stop of the stream, do not wait for drain
LG_LOCK(audio.playback.lock); playbackStop();
playbackStopNL();
LG_UNLOCK(audio.playback.lock);
audio_recordStop(); audio_recordStop();
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)
@ -183,7 +177,7 @@ static const char * audioGraphFormatFn(const char * name,
return title; return title;
} }
static void playbackStopNL(void) static void playbackStop(void)
{ {
if (audio.playback.state == STREAM_STATE_STOP) if (audio.playback.state == STREAM_STATE_STOP)
return; return;
@ -274,11 +268,8 @@ static int playbackPullFrames(uint8_t * dst, int frames)
if (audio.playback.state == STREAM_STATE_DRAIN && if (audio.playback.state == STREAM_STATE_DRAIN &&
ringbuffer_getCount(audio.playback.buffer) <= 0) ringbuffer_getCount(audio.playback.buffer) <= 0)
{ playbackStop();
LG_LOCK(audio.playback.lock);
playbackStopNL();
LG_UNLOCK(audio.playback.lock);
}
return frames; return frames;
} }
@ -288,13 +279,11 @@ void audio_playbackStart(int channels, int sampleRate, PSAudioFormat format,
if (!audio.audioDev) if (!audio.audioDev)
return; return;
LG_LOCK(audio.playback.lock);
if (audio.playback.state != STREAM_STATE_STOP) if (audio.playback.state != STREAM_STATE_STOP)
{ {
// Stop the current playback immediately. Even if the format is compatible, // Stop the current playback immediately. Even if the format is compatible,
// we may not have enough data left in the buffers to avoid underrunning // we may not have enough data left in the buffers to avoid underrunning
playbackStopNL(); playbackStop();
} }
int srcError; int srcError;
@ -303,7 +292,7 @@ void audio_playbackStart(int channels, int sampleRate, PSAudioFormat format,
if (!audio.playback.spiceData.src) if (!audio.playback.spiceData.src)
{ {
DEBUG_ERROR("Failed to create resampler: %s", src_strerror(srcError)); DEBUG_ERROR("Failed to create resampler: %s", src_strerror(srcError));
goto done; return;
} }
const int bufferFrames = sampleRate; const int bufferFrames = sampleRate;
@ -346,9 +335,6 @@ void audio_playbackStart(int channels, int sampleRate, PSAudioFormat format,
audio.playback.timings, 0.0f, 100.0f, audioGraphFormatFn); audio.playback.timings, 0.0f, 100.0f, audioGraphFormatFn);
audio.playback.state = STREAM_STATE_SETUP; audio.playback.state = STREAM_STATE_SETUP;
done:
LG_UNLOCK(audio.playback.lock);
} }
void audio_playbackStop(void) void audio_playbackStop(void)
@ -418,7 +404,7 @@ void audio_playbackData(uint8_t * data, size_t size)
if (!spiceData->framesIn) if (!spiceData->framesIn)
{ {
DEBUG_ERROR("Failed to malloc framesIn"); DEBUG_ERROR("Failed to malloc framesIn");
playbackStopNL(); playbackStop();
return; return;
} }
@ -428,7 +414,7 @@ void audio_playbackData(uint8_t * data, size_t size)
if (!spiceData->framesOut) if (!spiceData->framesOut)
{ {
DEBUG_ERROR("Failed to malloc framesOut"); DEBUG_ERROR("Failed to malloc framesOut");
playbackStopNL(); playbackStop();
return; return;
} }
} }
@ -571,6 +557,15 @@ void audio_playbackData(uint8_t * data, size_t size)
if (audio.audioDev->playback.start(frames)) if (audio.audioDev->playback.start(frames))
audio.playback.state = STREAM_STATE_RUN; audio.playback.state = STREAM_STATE_RUN;
} }
int latencyFrames = ringbuffer_getCount(audio.playback.buffer);
if (audio.audioDev->playback.latency)
latencyFrames += audio.audioDev->playback.latency();
const float latency = latencyFrames /
(float)(audio.playback.sampleRate / 1000);
ringbuffer_push(audio.playback.timings, &latency);
app_invalidateGraph(audio.playback.graph);
} }
bool audio_supportsRecord(void) bool audio_supportsRecord(void)
@ -655,26 +650,4 @@ 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.buffer)
{
LG_UNLOCK(audio.playback.lock);
return;
}
int frames = ringbuffer_getCount(audio.playback.buffer);
if (audio.audioDev->playback.latency)
frames += audio.audioDev->playback.latency();
const float latency = frames / (float)(audio.playback.sampleRate / 1000);
ringbuffer_push(audio.playback.timings, &latency);
LG_UNLOCK(audio.playback.lock);
app_invalidateGraphs();
}
#endif #endif

View file

@ -40,12 +40,9 @@ 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);
#else #else
static inline void audio_init(void) {} static inline void audio_init(void) {}
static inline void audio_free(void) {} static inline void audio_free(void) {}
static inline void audio_tick(unsigned long long tickCount) {}
#endif #endif

View file

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

View file

@ -245,10 +245,11 @@ void overlayGraph_iterate(void (*callback)(GraphHandle handle, const char * name
ll_unlock(gs.graphs); ll_unlock(gs.graphs);
} }
void overlayGraph_invalidate(void) void overlayGraph_invalidate(GraphHandle handle)
{ {
if (!gs.show) if (!gs.show)
return; return;
app_invalidateWindow(false); if (handle->enabled)
app_invalidateWindow(false);
} }

View file

@ -47,7 +47,7 @@ GraphHandle overlayGraph_register(const char * name, RingBuffer buffer,
void overlayGraph_unregister(); void overlayGraph_unregister();
void overlayGraph_iterate(void (*callback)(GraphHandle handle, const char * name, void overlayGraph_iterate(void (*callback)(GraphHandle handle, const char * name,
bool * enabled, void * udata), void * udata); bool * enabled, void * udata), void * udata);
void overlayGraph_invalidate(void); void overlayGraph_invalidate(GraphHandle handle);
void overlayConfig_register(const char * title, void overlayConfig_register(const char * title,
void (*callback)(void * udata, int * id), void * udata); void (*callback)(void * udata, int * id), void * udata);