mirror of
				https://github.com/gnif/LookingGlass.git
				synced 2025-11-03 22:22:08 +00:00 
			
		
		
		
	[client] audio: implement record interface and glue
This commit is contained in:
		@@ -200,7 +200,7 @@ static void pipewire_start(int channels, int sampleRate)
 | 
			
		||||
  pw_thread_loop_unlock(pw.thread);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void pipewire_play(uint8_t * data, int size)
 | 
			
		||||
static void pipewire_play(uint8_t * data, size_t size)
 | 
			
		||||
{
 | 
			
		||||
  if (!pw.stream)
 | 
			
		||||
    return;
 | 
			
		||||
 
 | 
			
		||||
@@ -288,7 +288,7 @@ static void pulseaudio_start(int channels, int sampleRate)
 | 
			
		||||
  pa_threaded_mainloop_unlock(pa.loop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void pulseaudio_play(uint8_t * data, int size)
 | 
			
		||||
static void pulseaudio_play(uint8_t * data, size_t size)
 | 
			
		||||
{
 | 
			
		||||
  if (!pa.sink)
 | 
			
		||||
    return;
 | 
			
		||||
 
 | 
			
		||||
@@ -23,6 +23,7 @@
 | 
			
		||||
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
 | 
			
		||||
struct LG_AudioDevOps
 | 
			
		||||
{
 | 
			
		||||
@@ -48,7 +49,7 @@ struct LG_AudioDevOps
 | 
			
		||||
    /* called for each packet of output audio to play
 | 
			
		||||
     * Note: size is the size of data in bytes, not frames/samples
 | 
			
		||||
     */
 | 
			
		||||
    void (*play)(uint8_t * data, int size);
 | 
			
		||||
    void (*play)(uint8_t * data, size_t size);
 | 
			
		||||
 | 
			
		||||
    /* called when SPICE reports the audio stream has stopped */
 | 
			
		||||
    void (*stop)(void);
 | 
			
		||||
@@ -67,7 +68,7 @@ struct LG_AudioDevOps
 | 
			
		||||
     * Note: currently SPICE only supports S16 samples so always assume so
 | 
			
		||||
     */
 | 
			
		||||
    void (*start)(int channels, int sampleRate,
 | 
			
		||||
        void (*dataFn)(uint8_t * data, int size));
 | 
			
		||||
        void (*dataFn)(uint8_t * data, size_t size));
 | 
			
		||||
 | 
			
		||||
    /* called when SPICE reports the audio stream has stopped */
 | 
			
		||||
    void (*stop)(void);
 | 
			
		||||
 
 | 
			
		||||
@@ -45,6 +45,7 @@ typedef struct
 | 
			
		||||
    int      volumeChannels;
 | 
			
		||||
    uint16_t volume[8];
 | 
			
		||||
    bool     mute;
 | 
			
		||||
    uint32_t time;
 | 
			
		||||
  }
 | 
			
		||||
  record;
 | 
			
		||||
}
 | 
			
		||||
@@ -75,6 +76,11 @@ void audio_free(void)
 | 
			
		||||
  audio.audioDev = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool audio_supportsPlayback(void)
 | 
			
		||||
{
 | 
			
		||||
  return audio.audioDev && audio.audioDev->playback.start;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void audio_playbackStart(int channels, int sampleRate, PSAudioFormat format,
 | 
			
		||||
  uint32_t time)
 | 
			
		||||
{
 | 
			
		||||
@@ -154,3 +160,84 @@ void audio_playbackData(uint8_t * data, size_t size)
 | 
			
		||||
 | 
			
		||||
  audio.audioDev->playback.play(data, size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool audio_supportsRecord(void)
 | 
			
		||||
{
 | 
			
		||||
  return audio.audioDev && audio.audioDev->record.start;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void recordData(uint8_t * data, size_t size)
 | 
			
		||||
{
 | 
			
		||||
  purespice_writeAudio(data, size, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void audio_recordStart(int channels, int sampleRate, PSAudioFormat format)
 | 
			
		||||
{
 | 
			
		||||
  if (!audio.audioDev)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  static int lastChannels   = 0;
 | 
			
		||||
  static int lastSampleRate = 0;
 | 
			
		||||
 | 
			
		||||
  if (audio.record.started)
 | 
			
		||||
  {
 | 
			
		||||
    if (channels != lastChannels || sampleRate != lastSampleRate)
 | 
			
		||||
      audio.audioDev->record.stop();
 | 
			
		||||
    else
 | 
			
		||||
      return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  lastChannels   = channels;
 | 
			
		||||
  lastSampleRate = sampleRate;
 | 
			
		||||
  audio.record.started = true;
 | 
			
		||||
 | 
			
		||||
  DEBUG_INFO("%d channels @ %dHz", channels, sampleRate);
 | 
			
		||||
  audio.audioDev->record.start(channels, sampleRate, recordData);
 | 
			
		||||
 | 
			
		||||
  // if a volume level was stored, set it before we return
 | 
			
		||||
  if (audio.record.volumeChannels)
 | 
			
		||||
    audio.audioDev->record.volume(
 | 
			
		||||
        audio.playback.volumeChannels,
 | 
			
		||||
        audio.playback.volume);
 | 
			
		||||
 | 
			
		||||
  // set the inital mute state
 | 
			
		||||
  audio.audioDev->record.mute(audio.playback.mute);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void audio_recordStop(void)
 | 
			
		||||
{
 | 
			
		||||
  if (!audio.audioDev || !audio.record.started)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  audio.audioDev->record.stop();
 | 
			
		||||
  audio.record.started = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void audio_recordVolume(int channels, const uint16_t volume[])
 | 
			
		||||
{
 | 
			
		||||
  if (!audio.audioDev || !audio.audioDev->record.volume)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  // store the values so we can restore the state if the stream is restarted
 | 
			
		||||
  channels = min(ARRAY_LENGTH(audio.record.volume), channels);
 | 
			
		||||
  memcpy(audio.record.volume, volume, sizeof(uint16_t) * channels);
 | 
			
		||||
  audio.record.volumeChannels = channels;
 | 
			
		||||
 | 
			
		||||
  if (!audio.record.started)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  audio.audioDev->record.volume(channels, volume);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void audio_recordMute(bool mute)
 | 
			
		||||
{
 | 
			
		||||
  if (!audio.audioDev || !audio.audioDev->record.mute)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  // store the value so we can restore it if the stream is restarted
 | 
			
		||||
  audio.record.mute = mute;
 | 
			
		||||
  if (!audio.record.started)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  audio.audioDev->record.mute(mute);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -21,9 +21,16 @@
 | 
			
		||||
void audio_init(void);
 | 
			
		||||
void audio_free(void);
 | 
			
		||||
 | 
			
		||||
bool audio_supportsPlayback(void);
 | 
			
		||||
void audio_playbackStart(int channels, int sampleRate, PSAudioFormat format,
 | 
			
		||||
  uint32_t time);
 | 
			
		||||
void audio_playbackStop(void);
 | 
			
		||||
void audio_playbackVolume(int channels, const uint16_t volume[]);
 | 
			
		||||
void audio_playbackMute(bool mute);
 | 
			
		||||
void audio_playbackData(uint8_t * data, size_t size);
 | 
			
		||||
 | 
			
		||||
bool audio_supportsRecord(void);
 | 
			
		||||
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);
 | 
			
		||||
 
 | 
			
		||||
@@ -783,7 +783,6 @@ void spiceReady(void)
 | 
			
		||||
{
 | 
			
		||||
  // set the intial mouse mode
 | 
			
		||||
  purespice_mouseMode(true);
 | 
			
		||||
  audio_init();
 | 
			
		||||
 | 
			
		||||
  PSServerInfo info;
 | 
			
		||||
  if (!purespice_getServerInfo(&info))
 | 
			
		||||
@@ -807,6 +806,9 @@ void spiceReady(void)
 | 
			
		||||
 | 
			
		||||
int spiceThread(void * arg)
 | 
			
		||||
{
 | 
			
		||||
  if (g_params.useSpiceAudio)
 | 
			
		||||
    audio_init();
 | 
			
		||||
 | 
			
		||||
  const struct PSConfig config =
 | 
			
		||||
  {
 | 
			
		||||
    .host      = g_params.spiceHost,
 | 
			
		||||
@@ -829,12 +831,20 @@ int spiceThread(void * arg)
 | 
			
		||||
    },
 | 
			
		||||
    .playback =
 | 
			
		||||
    {
 | 
			
		||||
      .enable = g_params.useSpiceAudio,
 | 
			
		||||
      .enable = audio_supportsPlayback(),
 | 
			
		||||
      .start  = audio_playbackStart,
 | 
			
		||||
      .volume = audio_playbackVolume,
 | 
			
		||||
      .mute   = audio_playbackMute,
 | 
			
		||||
      .stop   = audio_playbackStop,
 | 
			
		||||
      .data   = audio_playbackData
 | 
			
		||||
    },
 | 
			
		||||
    .record =
 | 
			
		||||
    {
 | 
			
		||||
      .enable = audio_supportsRecord(),
 | 
			
		||||
      .start  = audio_recordStart,
 | 
			
		||||
      .volume = audio_recordVolume,
 | 
			
		||||
      .mute   = audio_recordMute,
 | 
			
		||||
      .stop   = audio_recordStop
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user