mirror of
				https://github.com/gnif/LookingGlass.git
				synced 2025-11-04 06:31:54 +00:00 
			
		
		
		
	[client] audio: drain buffers on stop instead of just discarding them
This commit is contained in:
		@@ -28,20 +28,31 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  STREAM_STATE_STOP,
 | 
				
			||||||
 | 
					  STREAM_STATE_SETUP,
 | 
				
			||||||
 | 
					  STREAM_STATE_RUN,
 | 
				
			||||||
 | 
					  STREAM_STATE_DRAIN
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					StreamState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define STREAM_ACTIVE(state) \
 | 
				
			||||||
 | 
					  (state == STREAM_STATE_SETUP || state == STREAM_STATE_RUN)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct
 | 
					typedef struct
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  struct LG_AudioDevOps * audioDev;
 | 
					  struct LG_AudioDevOps * audioDev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  struct
 | 
					  struct
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    bool       setup;
 | 
					    StreamState state;
 | 
				
			||||||
    bool       started;
 | 
					    int         volumeChannels;
 | 
				
			||||||
    int        volumeChannels;
 | 
					    uint16_t    volume[8];
 | 
				
			||||||
    uint16_t   volume[8];
 | 
					    bool        mute;
 | 
				
			||||||
    bool       mute;
 | 
					    int         sampleRate;
 | 
				
			||||||
    int        sampleRate;
 | 
					    int         stride;
 | 
				
			||||||
    int        stride;
 | 
					    RingBuffer  buffer;
 | 
				
			||||||
    RingBuffer buffer;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    LG_Lock     lock;
 | 
					    LG_Lock     lock;
 | 
				
			||||||
    RingBuffer  timings;
 | 
					    RingBuffer  timings;
 | 
				
			||||||
@@ -107,15 +118,34 @@ static const char * audioGraphFormatFn(const char * name,
 | 
				
			|||||||
  return title;
 | 
					  return title;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void playbackStopNL(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  audio.playback.state = STREAM_STATE_STOP;
 | 
				
			||||||
 | 
					  audio.audioDev->playback.stop();
 | 
				
			||||||
 | 
					  ringbuffer_free(&audio.playback.buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (audio.playback.timings)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    app_unregisterGraph(audio.playback.graph);
 | 
				
			||||||
 | 
					    ringbuffer_free(&audio.playback.timings);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  audio.playback.state = STREAM_STATE_STOP;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int playbackPullFrames(uint8_t ** data, int frames)
 | 
					static int playbackPullFrames(uint8_t ** data, int frames)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  LG_LOCK(audio.playback.lock);
 | 
					  LG_LOCK(audio.playback.lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (audio.playback.buffer)
 | 
					  if (audio.playback.buffer)
 | 
				
			||||||
    *data = ringbuffer_consume(audio.playback.buffer, &frames);
 | 
					    *data = ringbuffer_consume(audio.playback.buffer, &frames);
 | 
				
			||||||
  else
 | 
					  else
 | 
				
			||||||
    frames = 0;
 | 
					    frames = 0;
 | 
				
			||||||
  LG_UNLOCK(audio.playback.lock);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (audio.playback.state == STREAM_STATE_DRAIN && frames == 0)
 | 
				
			||||||
 | 
					    playbackStopNL();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  LG_UNLOCK(audio.playback.lock);
 | 
				
			||||||
  return frames;
 | 
					  return frames;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -125,18 +155,18 @@ void audio_playbackStart(int channels, int sampleRate, PSAudioFormat format,
 | 
				
			|||||||
  if (!audio.audioDev)
 | 
					  if (!audio.audioDev)
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  LG_LOCK(audio.playback.lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static int lastChannels   = 0;
 | 
					  static int lastChannels   = 0;
 | 
				
			||||||
  static int lastSampleRate = 0;
 | 
					  static int lastSampleRate = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (audio.playback.setup)
 | 
					  if (STREAM_ACTIVE(audio.playback.state))
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    if (channels != lastChannels || sampleRate != lastSampleRate)
 | 
					    if (channels == lastChannels && sampleRate == lastSampleRate)
 | 
				
			||||||
      audio.audioDev->playback.stop();
 | 
					      goto no_change;
 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
      return;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  LG_LOCK(audio.playback.lock);
 | 
					    playbackStopNL();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const int bufferFrames = sampleRate / 10;
 | 
					  const int bufferFrames = sampleRate / 10;
 | 
				
			||||||
  audio.playback.buffer = ringbuffer_new(bufferFrames,
 | 
					  audio.playback.buffer = ringbuffer_new(bufferFrames,
 | 
				
			||||||
@@ -147,7 +177,7 @@ void audio_playbackStart(int channels, int sampleRate, PSAudioFormat format,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  audio.playback.sampleRate = sampleRate;
 | 
					  audio.playback.sampleRate = sampleRate;
 | 
				
			||||||
  audio.playback.stride     = channels * sizeof(uint16_t);
 | 
					  audio.playback.stride     = channels * sizeof(uint16_t);
 | 
				
			||||||
  audio.playback.setup      = true;
 | 
					  audio.playback.state      = STREAM_STATE_SETUP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  audio.audioDev->playback.setup(channels, sampleRate, playbackPullFrames);
 | 
					  audio.audioDev->playback.setup(channels, sampleRate, playbackPullFrames);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -166,28 +196,19 @@ void audio_playbackStart(int channels, int sampleRate, PSAudioFormat format,
 | 
				
			|||||||
  audio.playback.graph   = app_registerGraph("PLAYBACK",
 | 
					  audio.playback.graph   = app_registerGraph("PLAYBACK",
 | 
				
			||||||
      audio.playback.timings, 0.0f, 100.0f, audioGraphFormatFn);
 | 
					      audio.playback.timings, 0.0f, 100.0f, audioGraphFormatFn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  audio.playback.state = STREAM_STATE_SETUP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					no_change:
 | 
				
			||||||
  LG_UNLOCK(audio.playback.lock);
 | 
					  LG_UNLOCK(audio.playback.lock);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void audio_playbackStop(void)
 | 
					void audio_playbackStop(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  if (!audio.audioDev || !audio.playback.started)
 | 
					  if (!audio.audioDev || audio.playback.state == STREAM_STATE_STOP)
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  LG_LOCK(audio.playback.lock);
 | 
					  audio.playback.state = STREAM_STATE_DRAIN;
 | 
				
			||||||
 | 
					  return;
 | 
				
			||||||
  audio.audioDev->playback.stop();
 | 
					 | 
				
			||||||
  audio.playback.setup   = false;
 | 
					 | 
				
			||||||
  audio.playback.started = false;
 | 
					 | 
				
			||||||
  ringbuffer_free(&audio.playback.buffer);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  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[])
 | 
				
			||||||
@@ -200,7 +221,7 @@ void audio_playbackVolume(int channels, const uint16_t volume[])
 | 
				
			|||||||
  memcpy(audio.playback.volume, volume, sizeof(uint16_t) * channels);
 | 
					  memcpy(audio.playback.volume, volume, sizeof(uint16_t) * channels);
 | 
				
			||||||
  audio.playback.volumeChannels = channels;
 | 
					  audio.playback.volumeChannels = channels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!audio.playback.setup)
 | 
					  if (!STREAM_ACTIVE(audio.playback.state))
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  audio.audioDev->playback.volume(channels, volume);
 | 
					  audio.audioDev->playback.volume(channels, volume);
 | 
				
			||||||
@@ -213,7 +234,7 @@ void audio_playbackMute(bool mute)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  // store the value so we can restore it if the stream is restarted
 | 
					  // store the value so we can restore it if the stream is restarted
 | 
				
			||||||
  audio.playback.mute = mute;
 | 
					  audio.playback.mute = mute;
 | 
				
			||||||
  if (!audio.playback.setup)
 | 
					  if (!STREAM_ACTIVE(audio.playback.state))
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  audio.audioDev->playback.mute(mute);
 | 
					  audio.audioDev->playback.mute(mute);
 | 
				
			||||||
@@ -221,7 +242,10 @@ void audio_playbackMute(bool mute)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void audio_playbackData(uint8_t * data, size_t size)
 | 
					void audio_playbackData(uint8_t * data, size_t size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  if (!audio.audioDev || !audio.playback.setup)
 | 
					  if (!audio.audioDev)
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!STREAM_ACTIVE(audio.playback.state))
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const int frames = size / audio.playback.stride;
 | 
					  const int frames = size / audio.playback.stride;
 | 
				
			||||||
@@ -229,10 +253,11 @@ void audio_playbackData(uint8_t * data, size_t size)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  // don't start playback until the buffer is sifficiently full to avoid
 | 
					  // don't start playback until the buffer is sifficiently full to avoid
 | 
				
			||||||
  // glitches
 | 
					  // glitches
 | 
				
			||||||
  if (!audio.playback.started && ringbuffer_getCount(audio.playback.buffer) >=
 | 
					  if (audio.playback.state == STREAM_STATE_SETUP &&
 | 
				
			||||||
 | 
					      ringbuffer_getCount(audio.playback.buffer) >=
 | 
				
			||||||
      ringbuffer_getLength(audio.playback.buffer) / 4)
 | 
					      ringbuffer_getLength(audio.playback.buffer) / 4)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    audio.playback.started = true;
 | 
					    audio.playback.state = STREAM_STATE_RUN;
 | 
				
			||||||
    audio.audioDev->playback.start();
 | 
					    audio.audioDev->playback.start();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user