diff options
Diffstat (limited to 'audio/spiceaudio.c')
-rw-r--r-- | audio/spiceaudio.c | 253 |
1 files changed, 85 insertions, 168 deletions
diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c index 26873c7..9860f9c 100644 --- a/audio/spiceaudio.c +++ b/audio/spiceaudio.c @@ -40,27 +40,21 @@ #define LINE_IN_SAMPLES (256 * 4) #endif -typedef struct SpiceRateCtl { - int64_t start_ticks; - int64_t bytes_sent; -} SpiceRateCtl; - typedef struct SpiceVoiceOut { HWVoiceOut hw; SpicePlaybackInstance sin; - SpiceRateCtl rate; + RateCtl rate; int active; uint32_t *frame; - uint32_t *fpos; + uint32_t fpos; uint32_t fsize; } SpiceVoiceOut; typedef struct SpiceVoiceIn { HWVoiceIn hw; SpiceRecordInstance sin; - SpiceRateCtl rate; + RateCtl rate; int active; - uint32_t samples[LINE_IN_SAMPLES]; } SpiceVoiceIn; static const SpicePlaybackInterface playback_sif = { @@ -90,32 +84,6 @@ static void spice_audio_fini (void *opaque) /* nothing */ } -static void rate_start (SpiceRateCtl *rate) -{ - memset (rate, 0, sizeof (*rate)); - rate->start_ticks = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); -} - -static int rate_get_samples (struct audio_pcm_info *info, SpiceRateCtl *rate) -{ - int64_t now; - int64_t ticks; - int64_t bytes; - int64_t samples; - - now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - ticks = now - rate->start_ticks; - bytes = muldiv64(ticks, info->bytes_per_second, NANOSECONDS_PER_SECOND); - samples = (bytes - rate->bytes_sent) >> info->shift; - if (samples < 0 || samples > 65536) { - error_report("Resetting rate control (%" PRId64 " samples)", samples); - rate_start(rate); - samples = 0; - } - rate->bytes_sent += samples << info->shift; - return samples; -} - /* playback */ static int line_out_init(HWVoiceOut *hw, struct audsettings *as, @@ -152,93 +120,76 @@ static void line_out_fini (HWVoiceOut *hw) spice_server_remove_interface (&out->sin.base); } -static size_t line_out_run (HWVoiceOut *hw, size_t live) +static void *line_out_get_buffer(HWVoiceOut *hw, size_t *size) { - SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw); - size_t rpos, decr; - size_t samples; + SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw); - if (!live) { - return 0; + if (!out->frame) { + spice_server_playback_get_buffer(&out->sin, &out->frame, &out->fsize); + out->fpos = 0; } - decr = rate_get_samples (&hw->info, &out->rate); - decr = MIN (live, decr); + if (out->frame) { + *size = audio_rate_get_bytes( + &hw->info, &out->rate, (out->fsize - out->fpos) << hw->info.shift); + } else { + audio_rate_start(&out->rate); + } + return out->frame + out->fpos; +} - samples = decr; - rpos = hw->rpos; - while (samples) { - int left_till_end_samples = hw->samples - rpos; - int len = MIN (samples, left_till_end_samples); +static size_t line_out_put_buffer(HWVoiceOut *hw, void *buf, size_t size) +{ + SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw); - if (!out->frame) { - spice_server_playback_get_buffer (&out->sin, &out->frame, &out->fsize); - out->fpos = out->frame; - } - if (out->frame) { - len = MIN (len, out->fsize); - hw->clip (out->fpos, hw->mix_buf + rpos, len); - out->fsize -= len; - out->fpos += len; - if (out->fsize == 0) { - spice_server_playback_put_samples (&out->sin, out->frame); - out->frame = out->fpos = NULL; - } - } - rpos = (rpos + len) % hw->samples; - samples -= len; + assert(buf == out->frame + out->fpos && out->fpos <= out->fsize); + out->fpos += size >> 2; + + if (out->fpos == out->fsize) { /* buffer full */ + spice_server_playback_put_samples(&out->sin, out->frame); + out->frame = NULL; } - hw->rpos = rpos; - return decr; + + return size; } -static int line_out_ctl (HWVoiceOut *hw, int cmd, ...) +static void line_out_enable(HWVoiceOut *hw, bool enable) { SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw); - switch (cmd) { - case VOICE_ENABLE: + if (enable) { if (out->active) { - break; + return; } out->active = 1; - rate_start (&out->rate); + audio_rate_start(&out->rate); spice_server_playback_start (&out->sin); - break; - case VOICE_DISABLE: + } else { if (!out->active) { - break; + return; } out->active = 0; if (out->frame) { - memset (out->fpos, 0, out->fsize << 2); + memset(out->frame + out->fpos, 0, (out->fsize - out->fpos) << 2); spice_server_playback_put_samples (&out->sin, out->frame); - out->frame = out->fpos = NULL; + out->frame = NULL; } spice_server_playback_stop (&out->sin); - break; - case VOICE_VOLUME: - { -#if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2)) - SWVoiceOut *sw; - va_list ap; - uint16_t vol[2]; - - va_start (ap, cmd); - sw = va_arg (ap, SWVoiceOut *); - va_end (ap); - - vol[0] = sw->vol.l / ((1ULL << 16) + 1); - vol[1] = sw->vol.r / ((1ULL << 16) + 1); - spice_server_playback_set_volume (&out->sin, 2, vol); - spice_server_playback_set_mute (&out->sin, sw->vol.mute); -#endif - break; - } } +} - return 0; +#if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2)) +static void line_out_volume(HWVoiceOut *hw, struct mixeng_volume *vol) +{ + SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw); + uint16_t svol[2]; + + svol[0] = vol->l / ((1ULL << 16) + 1); + svol[1] = vol->r / ((1ULL << 16) + 1); + spice_server_playback_set_volume(&out->sin, 2, svol); + spice_server_playback_set_mute(&out->sin, vol->mute); } +#endif /* record */ @@ -275,104 +226,73 @@ static void line_in_fini (HWVoiceIn *hw) spice_server_remove_interface (&in->sin.base); } -static size_t line_in_run(HWVoiceIn *hw) +static size_t line_in_read(HWVoiceIn *hw, void *buf, size_t len) { SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw); - size_t num_samples; - int ready; - size_t len[2]; - uint64_t delta_samp; - const uint32_t *samples; - - if (!(num_samples = hw->samples - audio_pcm_hw_get_live_in (hw))) { - return 0; - } + uint64_t to_read = audio_rate_get_bytes(&hw->info, &in->rate, len) >> 2; + size_t ready = spice_server_record_get_samples(&in->sin, buf, to_read); - delta_samp = rate_get_samples (&hw->info, &in->rate); - num_samples = MIN (num_samples, delta_samp); - - ready = spice_server_record_get_samples (&in->sin, in->samples, num_samples); - samples = in->samples; + /* XXX: do we need this? */ if (ready == 0) { - static const uint32_t silence[LINE_IN_SAMPLES]; - samples = silence; - ready = LINE_IN_SAMPLES; - } - - num_samples = MIN (ready, num_samples); - - if (hw->wpos + num_samples > hw->samples) { - len[0] = hw->samples - hw->wpos; - len[1] = num_samples - len[0]; - } else { - len[0] = num_samples; - len[1] = 0; + memset(buf, 0, to_read << 2); + ready = to_read; } - hw->conv (hw->conv_buf + hw->wpos, samples, len[0]); - - if (len[1]) { - hw->conv (hw->conv_buf, samples + len[0], len[1]); - } - - hw->wpos = (hw->wpos + num_samples) % hw->samples; - - return num_samples; + return ready << 2; } -static int line_in_ctl (HWVoiceIn *hw, int cmd, ...) +static void line_in_enable(HWVoiceIn *hw, bool enable) { SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw); - switch (cmd) { - case VOICE_ENABLE: + if (enable) { if (in->active) { - break; + return; } in->active = 1; - rate_start (&in->rate); + audio_rate_start(&in->rate); spice_server_record_start (&in->sin); - break; - case VOICE_DISABLE: + } else { if (!in->active) { - break; + return; } in->active = 0; spice_server_record_stop (&in->sin); - break; - case VOICE_VOLUME: - { -#if ((SPICE_INTERFACE_RECORD_MAJOR >= 2) && (SPICE_INTERFACE_RECORD_MINOR >= 2)) - SWVoiceIn *sw; - va_list ap; - uint16_t vol[2]; - - va_start (ap, cmd); - sw = va_arg (ap, SWVoiceIn *); - va_end (ap); - - vol[0] = sw->vol.l / ((1ULL << 16) + 1); - vol[1] = sw->vol.r / ((1ULL << 16) + 1); - spice_server_record_set_volume (&in->sin, 2, vol); - spice_server_record_set_mute (&in->sin, sw->vol.mute); -#endif - break; - } } +} - return 0; +#if ((SPICE_INTERFACE_RECORD_MAJOR >= 2) && (SPICE_INTERFACE_RECORD_MINOR >= 2)) +static void line_in_volume(HWVoiceIn *hw, struct mixeng_volume *vol) +{ + SpiceVoiceIn *in = container_of(hw, SpiceVoiceIn, hw); + uint16_t svol[2]; + + svol[0] = vol->l / ((1ULL << 16) + 1); + svol[1] = vol->r / ((1ULL << 16) + 1); + spice_server_record_set_volume(&in->sin, 2, svol); + spice_server_record_set_mute(&in->sin, vol->mute); } +#endif static struct audio_pcm_ops audio_callbacks = { .init_out = line_out_init, .fini_out = line_out_fini, - .run_out = line_out_run, - .ctl_out = line_out_ctl, + .write = audio_generic_write, + .get_buffer_out = line_out_get_buffer, + .put_buffer_out = line_out_put_buffer, + .enable_out = line_out_enable, +#if (SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && \ + (SPICE_INTERFACE_PLAYBACK_MINOR >= 2) + .volume_out = line_out_volume, +#endif .init_in = line_in_init, .fini_in = line_in_fini, - .run_in = line_in_run, - .ctl_in = line_in_ctl, + .read = line_in_read, + .enable_in = line_in_enable, +#if ((SPICE_INTERFACE_RECORD_MAJOR >= 2) && (SPICE_INTERFACE_RECORD_MINOR >= 2)) + .volume_in = line_in_volume, +#endif }; static struct audio_driver spice_audio_driver = { @@ -385,9 +305,6 @@ static struct audio_driver spice_audio_driver = { .max_voices_in = 1, .voice_size_out = sizeof (SpiceVoiceOut), .voice_size_in = sizeof (SpiceVoiceIn), -#if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2)) - .ctl_caps = VOICE_VOLUME_CAP -#endif }; void qemu_spice_audio_init (void) |