[Spice-devel] [spice opus support 3/6 (take 4b)] Add support for the Opus codec
Christophe Fergeau
cfergeau at redhat.com
Tue Dec 10 10:46:11 PST 2013
On Sat, Nov 30, 2013 at 09:19:21AM -0600, Jeremy White wrote:
>
> Signed-off-by: Jeremy White <jwhite at codeweavers.com>
> ---
> client/audio_channels.h | 3 +-
> client/audio_devices.h | 8 ---
> client/platform.h | 6 ++-
> client/playback_channel.cpp | 23 ++++----
> client/record_channel.cpp | 41 ++++++++++-----
> client/x11/platform.cpp | 10 ++--
> client/x11/playback.cpp | 13 ++---
> client/x11/playback.h | 5 +-
> client/x11/record.cpp | 15 +++---
> client/x11/record.h | 7 ++-
> server/snd_worker.c | 121 +++++++++++++++++++++++++++++++++----------
> server/spice-server.syms | 8 +++
> server/spice.h | 15 ++++--
> 13 files changed, 188 insertions(+), 87 deletions(-)
>
> diff --git a/client/audio_channels.h b/client/audio_channels.h
> index d7b81e7..fdb4dc9 100644
> --- a/client/audio_channels.h
> +++ b/client/audio_channels.h
> @@ -72,7 +72,6 @@ public:
> static ChannelFactory& Factory();
>
> protected:
> - virtual void on_connect();
> virtual void on_disconnect();
>
> private:
> @@ -85,6 +84,8 @@ private:
> virtual void remove_event_source(EventSources::Trigger& event_source);
> virtual void push_frame(uint8_t *frame);
>
> + void set_desired_mode(int frequency);
> + void send_record_mode();
> void send_start_mark();
> void release_message(RecordSamplesMessage *message);
> RecordSamplesMessage * get_message();
> diff --git a/client/audio_devices.h b/client/audio_devices.h
> index a1da1f7..111c366 100644
> --- a/client/audio_devices.h
> +++ b/client/audio_devices.h
> @@ -27,10 +27,6 @@ public:
> virtual bool abort() = 0;
> virtual void stop() = 0;
> virtual uint32_t get_delay_ms() = 0;
> -
> - enum {
> - FRAME_SIZE = 256,
> - };
> };
>
> class WaveRecordAbstract {
> @@ -42,10 +38,6 @@ public:
> virtual void start() = 0;
> virtual void stop() = 0;
> virtual bool abort() = 0;
> -
> - enum {
> - FRAME_SIZE = 256,
> - };
> };
>
> #endif
> diff --git a/client/platform.h b/client/platform.h
> index 913bcde..0a88f06 100644
> --- a/client/platform.h
> +++ b/client/platform.h
> @@ -68,10 +68,12 @@ public:
> static WaveRecordAbstract* create_recorder(RecordClient& client,
> uint32_t sampels_per_sec,
> uint32_t bits_per_sample,
> - uint32_t channels);
> + uint32_t channels,
> + uint32_t frame_size);
> static WavePlaybackAbstract* create_player(uint32_t sampels_per_sec,
> uint32_t bits_per_sample,
> - uint32_t channels);
> + uint32_t channels,
> + uint32_t frame_size);
>
> enum {
> SCROLL_LOCK_MODIFIER_SHIFT,
> diff --git a/client/playback_channel.cpp b/client/playback_channel.cpp
> index 173c94a..9f8c334 100644
> --- a/client/playback_channel.cpp
> +++ b/client/playback_channel.cpp
> @@ -168,8 +168,10 @@ PlaybackChannel::PlaybackChannel(RedClient& client, uint32_t id)
>
> handler->set_handler(SPICE_MSG_PLAYBACK_MODE, &PlaybackChannel::handle_mode);
>
> - if (snd_codec_is_capable(SPICE_AUDIO_DATA_MODE_CELT_0_5_1))
> + if (snd_codec_is_capable(SPICE_AUDIO_DATA_MODE_CELT_0_5_1, SND_CODEC_ANY_FREQUENCY))
> set_capability(SPICE_PLAYBACK_CAP_CELT_0_5_1);
> + if (snd_codec_is_capable(SPICE_AUDIO_DATA_MODE_OPUS, SND_CODEC_ANY_FREQUENCY))
> + set_capability(SPICE_PLAYBACK_CAP_OPUS);
> }
>
> void PlaybackChannel::clear()
> @@ -206,7 +208,7 @@ void PlaybackChannel::set_data_handler()
>
> if (_mode == SPICE_AUDIO_DATA_MODE_RAW) {
> handler->set_handler(SPICE_MSG_PLAYBACK_DATA, &PlaybackChannel::handle_raw_data);
> - } else if (snd_codec_is_capable(_mode)) {
> + } else if (snd_codec_is_capable(_mode, SND_CODEC_ANY_FREQUENCY)) {
> handler->set_handler(SPICE_MSG_PLAYBACK_DATA, &PlaybackChannel::handle_compressed_data);
> } else {
> THROW("invalid mode");
> @@ -218,7 +220,7 @@ void PlaybackChannel::handle_mode(RedPeer::InMessage* message)
> {
> SpiceMsgPlaybackMode* playback_mode = (SpiceMsgPlaybackMode*)message->data();
> if (playback_mode->mode != SPICE_AUDIO_DATA_MODE_RAW
> - && !snd_codec_is_capable(playback_mode->mode) ) {
> + && !snd_codec_is_capable(playback_mode->mode, SND_CODEC_ANY_FREQUENCY) ) {
> THROW("invalid mode");
> }
>
> @@ -266,9 +268,16 @@ void PlaybackChannel::handle_start(RedPeer::InMessage* message)
> }
> int bits_per_sample = 16;
> int frame_size = SND_CODEC_MAX_FRAME_SIZE;
> +
> + if (_mode != SPICE_AUDIO_DATA_MODE_RAW) {
> + if (snd_codec_create(&_codec, _mode, start->frequency, SND_CODEC_DECODE) != SND_CODEC_OK)
> + THROW("create decoder");
> + frame_size = snd_codec_frame_size(_codec);
> + }
> +
> try {
> _wave_player = Platform::create_player(start->frequency, bits_per_sample,
> - start->channels);
> + start->channels, frame_size);
> } catch (...) {
> LOG_WARN("create player failed");
> //todo: support disconnecting single channel
> @@ -276,12 +285,6 @@ void PlaybackChannel::handle_start(RedPeer::InMessage* message)
> return;
> }
>
> - if (_mode != SPICE_AUDIO_DATA_MODE_RAW) {
> - if (snd_codec_create(&_codec, _mode, start->frequency, SND_CODEC_DECODE) != SND_CODEC_OK)
> - THROW("create decoder");
> - frame_size = snd_codec_frame_size(_codec);
> - }
> -
> _frame_bytes = frame_size * start->channels * bits_per_sample / 8;
> }
> _playing = true;
> diff --git a/client/record_channel.cpp b/client/record_channel.cpp
> index 2870f62..047cdd0 100644
> --- a/client/record_channel.cpp
> +++ b/client/record_channel.cpp
> @@ -87,8 +87,10 @@ RecordChannel::RecordChannel(RedClient& client, uint32_t id)
>
> handler->set_handler(SPICE_MSG_RECORD_START, &RecordChannel::handle_start);
>
> - if (snd_codec_is_capable(SPICE_AUDIO_DATA_MODE_CELT_0_5_1))
> + if (snd_codec_is_capable(SPICE_AUDIO_DATA_MODE_CELT_0_5_1, SND_CODEC_ANY_FREQUENCY))
> set_capability(SPICE_RECORD_CAP_CELT_0_5_1);
> + if (snd_codec_is_capable(SPICE_AUDIO_DATA_MODE_OPUS, SND_CODEC_ANY_FREQUENCY))
> + set_capability(SPICE_RECORD_CAP_OPUS);
> }
>
> RecordChannel::~RecordChannel(void)
> @@ -107,16 +109,23 @@ bool RecordChannel::abort(void)
> return (!_wave_recorder || _wave_recorder->abort()) && RedChannel::abort();
> }
>
> -void RecordChannel::on_connect()
> +void RecordChannel::set_desired_mode(int frequency)
> {
> - Message* message = new Message(SPICE_MSGC_RECORD_MODE);
> - SpiceMsgcRecordMode mode;
> - mode.time = get_mm_time();
> - if (snd_codec_is_capable(SPICE_AUDIO_DATA_MODE_CELT_0_5_1) &&
> + if (snd_codec_is_capable(SPICE_AUDIO_DATA_MODE_OPUS, frequency) &&
> + test_capability(SPICE_RECORD_CAP_OPUS))
> + _mode = SPICE_AUDIO_DATA_MODE_OPUS;
> + else if (snd_codec_is_capable(SPICE_AUDIO_DATA_MODE_CELT_0_5_1, frequency) &&
> test_capability(SPICE_RECORD_CAP_CELT_0_5_1))
> _mode = SPICE_AUDIO_DATA_MODE_CELT_0_5_1;
> else
> _mode = SPICE_AUDIO_DATA_MODE_RAW;
> +}
> +
> +void RecordChannel::send_record_mode()
> +{
> + Message* message = new Message(SPICE_MSGC_RECORD_MODE);
> + SpiceMsgcRecordMode mode;
> + mode.time = get_mm_time();
> mode.mode = _mode;
> _marshallers->msgc_record_mode(message->marshaller(), &mode);
> post_message(message);
> @@ -153,24 +162,29 @@ void RecordChannel::handle_start(RedPeer::InMessage* message)
> THROW("unexpected number of channels");
> }
>
> + set_desired_mode(start->frequency);
> +
> + int frame_size = SND_CODEC_MAX_FRAME_SIZE;
> + if (_mode != SPICE_AUDIO_DATA_MODE_RAW) {
> + if (snd_codec_create(&_codec, _mode, start->frequency, SND_CODEC_ENCODE) != SND_CODEC_OK)
> + THROW("create encoder failed");
> + frame_size = snd_codec_frame_size(_codec);
> + }
> +
> int bits_per_sample = 16;
> try {
> _wave_recorder = Platform::create_recorder(*this, start->frequency,
> bits_per_sample,
> - start->channels);
> + start->channels,
> + frame_size);
> } catch (...) {
> LOG_WARN("create recorder failed");
> return;
> }
>
> - int frame_size = SND_CODEC_MAX_FRAME_SIZE;
> - if (_mode != SPICE_AUDIO_DATA_MODE_RAW) {
> - if (snd_codec_create(&_codec, _mode, start->frequency, SND_CODEC_ENCODE) != SND_CODEC_OK)
> - THROW("create encoder failed");
> - frame_size = snd_codec_frame_size(_codec);
> - }
> _frame_bytes = frame_size * bits_per_sample * start->channels / 8;
>
> + send_record_mode();
> send_start_mark();
> _wave_recorder->start();
> }
> @@ -237,7 +251,6 @@ void RecordChannel::remove_event_source(EventSources::Trigger& event_source)
> void RecordChannel::push_frame(uint8_t *frame)
> {
> RecordSamplesMessage *message;
> - ASSERT(_frame_bytes == FRAME_SIZE * 4);
> if (!(message = get_message())) {
> DBG(0, "blocked");
> return;
> diff --git a/client/x11/platform.cpp b/client/x11/platform.cpp
> index b8563b3..bb8704c 100644
> --- a/client/x11/platform.cpp
> +++ b/client/x11/platform.cpp
> @@ -3433,16 +3433,18 @@ void Platform::reset_cursor_pos()
> WaveRecordAbstract* Platform::create_recorder(RecordClient& client,
> uint32_t sampels_per_sec,
> uint32_t bits_per_sample,
> - uint32_t channels)
> + uint32_t channels,
> + uint32_t frame_size)
> {
> - return new WaveRecorder(client, sampels_per_sec, bits_per_sample, channels);
> + return new WaveRecorder(client, sampels_per_sec, bits_per_sample, channels, frame_size);
> }
>
> WavePlaybackAbstract* Platform::create_player(uint32_t sampels_per_sec,
> uint32_t bits_per_sample,
> - uint32_t channels)
> + uint32_t channels,
> + uint32_t frame_size)
> {
> - return new WavePlayer(sampels_per_sec, bits_per_sample, channels);
> + return new WavePlayer(sampels_per_sec, bits_per_sample, channels, frame_size);
> }
>
> void XPlatform::on_focus_in()
> diff --git a/client/x11/playback.cpp b/client/x11/playback.cpp
> index 5fa7e18..035d6de 100644
> --- a/client/x11/playback.cpp
> +++ b/client/x11/playback.cpp
> @@ -24,12 +24,12 @@
>
> #define REING_SIZE_MS 300
>
> -WavePlayer::WavePlayer(uint32_t sampels_per_sec, uint32_t bits_per_sample, uint32_t channels)
> +WavePlayer::WavePlayer(uint32_t sampels_per_sec, uint32_t bits_per_sample, uint32_t channels, uint32_t frame_size)
> : _pcm (NULL)
> , _hw_params (NULL)
> , _sw_params (NULL)
> {
> - if (!init(sampels_per_sec, bits_per_sample, channels)) {
> + if (!init(sampels_per_sec, bits_per_sample, channels, frame_size)) {
> cleanup();
> THROW("failed");
> }
> @@ -57,9 +57,9 @@ WavePlayer::~WavePlayer()
>
> bool WavePlayer::init(uint32_t sampels_per_sec,
> uint32_t bits_per_sample,
> - uint32_t channels)
> + uint32_t channels,
> + uint32_t frame_size)
> {
> - const int frame_size = WavePlaybackAbstract::FRAME_SIZE;
> const char* pcm_device = "default";
> snd_pcm_format_t format;
> int err;
> @@ -75,6 +75,7 @@ bool WavePlayer::init(uint32_t sampels_per_sec,
> return false;
> }
> _sampels_per_ms = sampels_per_sec / 1000;
> + _frame_size = frame_size;
>
> if ((err = snd_pcm_open(&_pcm, pcm_device, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) {
> LOG_ERROR("cannot open audio playback device %s %s", pcm_device, snd_strerror(err));
> @@ -183,14 +184,14 @@ bool WavePlayer::init(uint32_t sampels_per_sec,
>
> bool WavePlayer::write(uint8_t* frame)
> {
> - snd_pcm_sframes_t ret = snd_pcm_writei(_pcm, frame, WavePlaybackAbstract::FRAME_SIZE);
> + snd_pcm_sframes_t ret = snd_pcm_writei(_pcm, frame, _frame_size);
> if (ret < 0) {
> if (ret == -EAGAIN) {
> return false;
> }
> DBG(0, "err %s", snd_strerror(-ret));
> if (snd_pcm_recover(_pcm, ret, 1) == 0) {
> - snd_pcm_writei(_pcm, frame, WavePlaybackAbstract::FRAME_SIZE);
> + snd_pcm_writei(_pcm, frame, _frame_size);
> }
> }
> return true;
> diff --git a/client/x11/playback.h b/client/x11/playback.h
> index 27ef9ed..383f02d 100644
> --- a/client/x11/playback.h
> +++ b/client/x11/playback.h
> @@ -25,7 +25,7 @@
>
> class WavePlayer: public WavePlaybackAbstract {
> public:
> - WavePlayer(uint32_t sampels_per_sec, uint32_t bits_per_sample, uint32_t channels);
> + WavePlayer(uint32_t sampels_per_sec, uint32_t bits_per_sample, uint32_t channels, uint32_t frame_size);
> virtual ~WavePlayer();
>
> virtual bool write(uint8_t* frame);
> @@ -34,7 +34,7 @@ public:
> virtual uint32_t get_delay_ms();
>
> private:
> - bool init(uint32_t sampels_per_sec, uint32_t bits_per_sample, uint32_t channel);
> + bool init(uint32_t sampels_per_sec, uint32_t bits_per_sample, uint32_t channel, uint32_t frame_size);
> void cleanup();
>
> private:
> @@ -42,6 +42,7 @@ private:
> snd_pcm_hw_params_t* _hw_params;
> snd_pcm_sw_params_t* _sw_params;
> uint32_t _sampels_per_ms;
> + uint32_t _frame_size;
> };
>
> #endif
> diff --git a/client/x11/record.cpp b/client/x11/record.cpp
> index 535a8c9..32c0af7 100644
> --- a/client/x11/record.cpp
> +++ b/client/x11/record.cpp
> @@ -48,18 +48,19 @@ void WaveRecorder::EventTrigger::on_event()
> WaveRecorder::WaveRecorder(Platform::RecordClient& client,
> uint32_t sampels_per_sec,
> uint32_t bits_per_sample,
> - uint32_t channels)
> + uint32_t channels,
> + uint32_t frame_size)
> : _client (client)
> , _pcm (NULL)
> , _hw_params (NULL)
> , _sw_params (NULL)
> , _sample_bytes (bits_per_sample * channels / 8)
> - , _frame (new uint8_t[_sample_bytes * WaveRecordAbstract::FRAME_SIZE])
> + , _frame (new uint8_t[_sample_bytes * frame_size])
> , _frame_pos (_frame)
> - , _frame_end (_frame + _sample_bytes * WaveRecordAbstract::FRAME_SIZE)
> + , _frame_end (_frame + _sample_bytes * frame_size)
> , _event_trigger (NULL)
> {
> - if (!init(sampels_per_sec, bits_per_sample, channels)) {
> + if (!init(sampels_per_sec, bits_per_sample, channels, frame_size)) {
> cleanup();
> THROW("failed");
> }
> @@ -93,13 +94,15 @@ void WaveRecorder::cleanup()
>
> bool WaveRecorder::init(uint32_t sampels_per_sec,
> uint32_t bits_per_sample,
> - uint32_t channels)
> + uint32_t channels,
> + uint32_t frame_size)
> {
> - const int frame_size = WaveRecordAbstract::FRAME_SIZE;
> const char* pcm_device = "default";
> snd_pcm_format_t format;
> int err;
>
> + _frame_size = frame_size;
> +
> switch (bits_per_sample) {
> case 8:
> format = SND_PCM_FORMAT_S8;
> diff --git a/client/x11/record.h b/client/x11/record.h
> index 9141096..9470791 100644
> --- a/client/x11/record.h
> +++ b/client/x11/record.h
> @@ -29,7 +29,8 @@ public:
> WaveRecorder(Platform::RecordClient& client,
> uint32_t sampels_per_sec,
> uint32_t bits_per_sample,
> - uint32_t channels);
> + uint32_t channels,
> + uint32_t frame_size);
> virtual ~WaveRecorder();
>
> virtual void start();
> @@ -39,7 +40,8 @@ public:
> private:
> bool init(uint32_t sampels_per_sec,
> uint32_t bits_per_sample,
> - uint32_t channels);
> + uint32_t channels,
> + uint32_t frame_size);
> void cleanup();
> void on_event();
>
> @@ -49,6 +51,7 @@ private:
> snd_pcm_hw_params_t* _hw_params;
> snd_pcm_sw_params_t* _sw_params;
> uint32_t _sample_bytes;
> + uint32_t _frame_size;
> uint8_t* _frame;
> uint8_t* _frame_pos;
> uint8_t* _frame_end;
> diff --git a/server/snd_worker.c b/server/snd_worker.c
> index f40fd65..240f0dd 100644
> --- a/server/snd_worker.c
> +++ b/server/snd_worker.c
> +SPICE_GNUC_VISIBLE uint32_t spice_server_get_best_playback_rate(SpicePlaybackInstance *sin)
> +{
> + int client_can_opus = TRUE;
> + if (sin && sin->st->worker.connection) {
> + SndChannel *channel = sin->st->worker.connection;
> + PlaybackChannel *playback_channel = SPICE_CONTAINEROF(channel, PlaybackChannel, base);
> + client_can_opus = red_channel_client_test_remote_cap(playback_channel->base.channel_client,
> + SPICE_PLAYBACK_CAP_OPUS);
> + }
> +
> + if (client_can_opus && snd_codec_is_capable(SPICE_AUDIO_DATA_MODE_OPUS, SND_CODEC_ANY_FREQUENCY))
> + return SND_CODEC_OPUS_PLAYBACK_FREQ;
> +
> + return SND_CODEC_CELT_PLAYBACK_FREQ;
> +}
> +
> +SPICE_GNUC_VISIBLE void spice_server_set_playback_rate(SpicePlaybackInstance *sin, uint32_t frequency)
> +{
> + RedChannel *channel = sin->st->worker.base_channel;
> + sin->st->frequency = frequency;
> + if (channel && snd_codec_is_capable(SPICE_AUDIO_DATA_MODE_OPUS, frequency))
> + red_channel_set_cap(channel, SPICE_PLAYBACK_CAP_OPUS);
> +}
> +
> +SPICE_GNUC_VISIBLE uint32_t spice_server_get_best_record_rate(SpiceRecordInstance *sin)
> +{
> + int client_can_opus = TRUE;
> + if (sin && sin->st->worker.connection) {
> + SndChannel *channel = sin->st->worker.connection;
> + RecordChannel *record_channel = SPICE_CONTAINEROF(channel, RecordChannel, base);
> + client_can_opus = red_channel_client_test_remote_cap(record_channel->base.channel_client,
> + SPICE_RECORD_CAP_OPUS);
> + }
> +
> + if (client_can_opus && snd_codec_is_capable(SPICE_AUDIO_DATA_MODE_OPUS, SND_CODEC_ANY_FREQUENCY))
> + return SND_CODEC_OPUS_PLAYBACK_FREQ;
> +
> + return SND_CODEC_CELT_PLAYBACK_FREQ;
> +}
> +
> +SPICE_GNUC_VISIBLE void spice_server_set_record_rate(SpiceRecordInstance *sin, uint32_t frequency)
> +{
> + RedChannel *channel = sin->st->worker.base_channel;
> + sin->st->frequency = frequency;
> + if (channel && snd_codec_is_capable(SPICE_AUDIO_DATA_MODE_OPUS, frequency))
> + red_channel_set_cap(channel, SPICE_PLAYBACK_CAP_OPUS);
small c&p issue here, this should be SPICE_RECORD_CAP_OPUS. I'll squash
this in, and finally push the whole series! Thanks a lot for all
the hardwork!
Christophe
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.freedesktop.org/archives/spice-devel/attachments/20131210/5d03cc47/attachment-0001.pgp>
More information about the Spice-devel
mailing list