From 4c7c0ef3a70001b1bc9011ef824d3c6fcccd9ca0 Mon Sep 17 00:00:00 2001 From: Jeremy White Date: Sat, 30 Nov 2013 09:14:44 -0600 Subject: Revise the spice client and server to use the new snd_codec functions in spice-common. This makes celt optional, and paves the way to readily add additional codecs. Signed-off-by: Jeremy White --- README | 1 - client/audio_channels.h | 12 ++- client/playback_channel.cpp | 59 ++++++------- client/record_channel.cpp | 69 ++++++--------- configure.ac | 12 +-- server/Makefile.am | 2 - server/snd_worker.c | 205 ++++++++++++++++++-------------------------- spice-common | 2 +- 8 files changed, 151 insertions(+), 211 deletions(-) diff --git a/README b/README index b344066a..dea43444 100644 --- a/README +++ b/README @@ -28,7 +28,6 @@ The following mandatory dependancies are required in order to build SPICE Spice protocol >= 0.9.0 - Celt >= 0.5.1.1, < 0.6.0 Pixman >= 0.17.7 OpenSSL libjpeg diff --git a/client/audio_channels.h b/client/audio_channels.h index d38a79eb..d7b81e75 100644 --- a/client/audio_channels.h +++ b/client/audio_channels.h @@ -18,7 +18,7 @@ #ifndef _H_AUDIO_CHANNELS #define _H_AUDIO_CHANNELS -#include +#include "common/snd_codec.h" #include "red_channel.h" #include "debug.h" @@ -45,7 +45,7 @@ private: void handle_start(RedPeer::InMessage* message); void handle_stop(RedPeer::InMessage* message); void handle_raw_data(RedPeer::InMessage* message); - void handle_celt_data(RedPeer::InMessage* message); + void handle_compressed_data(RedPeer::InMessage* message); void null_handler(RedPeer::InMessage* message); void disable(); @@ -57,8 +57,7 @@ private: WavePlaybackAbstract* _wave_player; uint32_t _mode; uint32_t _frame_bytes; - CELTMode *_celt_mode; - CELTDecoder *_celt_decoder; + SndCodec _codec; bool _playing; uint32_t _frame_count; }; @@ -96,11 +95,10 @@ private: Mutex _messages_lock; std::list _messages; int _mode; - CELTMode *_celt_mode; - CELTEncoder *_celt_encoder; + SndCodec _codec; uint32_t _frame_bytes; - static int data_mode; + uint8_t compressed_buf[SND_CODEC_MAX_COMPRESSED_BYTES]; friend class RecordSamplesMessage; }; diff --git a/client/playback_channel.cpp b/client/playback_channel.cpp index 802a4d3b..173c94a6 100644 --- a/client/playback_channel.cpp +++ b/client/playback_channel.cpp @@ -151,8 +151,7 @@ PlaybackChannel::PlaybackChannel(RedClient& client, uint32_t id) Platform::PRIORITY_HIGH) , _wave_player (NULL) , _mode (SPICE_AUDIO_DATA_MODE_INVALID) - , _celt_mode (NULL) - , _celt_decoder (NULL) + , _codec(NULL) , _playing (false) { #ifdef WAVE_CAPTURE @@ -169,7 +168,8 @@ PlaybackChannel::PlaybackChannel(RedClient& client, uint32_t id) handler->set_handler(SPICE_MSG_PLAYBACK_MODE, &PlaybackChannel::handle_mode); - set_capability(SPICE_PLAYBACK_CAP_CELT_0_5_1); + if (snd_codec_is_capable(SPICE_AUDIO_DATA_MODE_CELT_0_5_1)) + set_capability(SPICE_PLAYBACK_CAP_CELT_0_5_1); } void PlaybackChannel::clear() @@ -182,15 +182,7 @@ void PlaybackChannel::clear() } _mode = SPICE_AUDIO_DATA_MODE_INVALID; - if (_celt_decoder) { - celt051_decoder_destroy(_celt_decoder); - _celt_decoder = NULL; - } - - if (_celt_mode) { - celt051_mode_destroy(_celt_mode); - _celt_mode = NULL; - } + snd_codec_destroy(&_codec); } void PlaybackChannel::on_disconnect() @@ -214,22 +206,23 @@ 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 (_mode == SPICE_AUDIO_DATA_MODE_CELT_0_5_1) { - handler->set_handler(SPICE_MSG_PLAYBACK_DATA, &PlaybackChannel::handle_celt_data); + } else if (snd_codec_is_capable(_mode)) { + handler->set_handler(SPICE_MSG_PLAYBACK_DATA, &PlaybackChannel::handle_compressed_data); } else { THROW("invalid mode"); } + } void PlaybackChannel::handle_mode(RedPeer::InMessage* message) { - SpiceMsgPlaybackMode* playbacke_mode = (SpiceMsgPlaybackMode*)message->data(); - if (playbacke_mode->mode != SPICE_AUDIO_DATA_MODE_RAW && - playbacke_mode->mode != SPICE_AUDIO_DATA_MODE_CELT_0_5_1) { + SpiceMsgPlaybackMode* playback_mode = (SpiceMsgPlaybackMode*)message->data(); + if (playback_mode->mode != SPICE_AUDIO_DATA_MODE_RAW + && !snd_codec_is_capable(playback_mode->mode) ) { THROW("invalid mode"); } - _mode = playbacke_mode->mode; + _mode = playback_mode->mode; if (_playing) { set_data_handler(); return; @@ -265,15 +258,14 @@ void PlaybackChannel::handle_start(RedPeer::InMessage* message) start_wave(); #endif if (!_wave_player) { - // for now support only one setting - int celt_mode_err; - if (start->format != SPICE_AUDIO_FMT_S16) { THROW("unexpected format"); } + if (start->channels != 2) { + THROW("unexpected number of channels"); + } int bits_per_sample = 16; - int frame_size = 256; - _frame_bytes = frame_size * start->channels * bits_per_sample / 8; + int frame_size = SND_CODEC_MAX_FRAME_SIZE; try { _wave_player = Platform::create_player(start->frequency, bits_per_sample, start->channels); @@ -284,14 +276,13 @@ void PlaybackChannel::handle_start(RedPeer::InMessage* message) return; } - if (!(_celt_mode = celt051_mode_create(start->frequency, start->channels, - frame_size, &celt_mode_err))) { - THROW("create celt mode failed %d", celt_mode_err); + 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); } - if (!(_celt_decoder = celt051_decoder_create(_celt_mode))) { - THROW("create celt decoder"); - } + _frame_bytes = frame_size * start->channels * bits_per_sample / 8; } _playing = true; _frame_count = 0; @@ -333,16 +324,16 @@ void PlaybackChannel::handle_raw_data(RedPeer::InMessage* message) _wave_player->write(data); } -void PlaybackChannel::handle_celt_data(RedPeer::InMessage* message) +void PlaybackChannel::handle_compressed_data(RedPeer::InMessage* message) { SpiceMsgPlaybackPacket* packet = (SpiceMsgPlaybackPacket*)message->data(); uint8_t* data = packet->data; uint32_t size = packet->data_size; - celt_int16_t pcm[256 * 2]; + int pcm_size = _frame_bytes; + uint8_t pcm[_frame_bytes]; - if (celt051_decode(_celt_decoder, data, size, pcm) != CELT_OK) { - THROW("celt decode failed"); - } + if (snd_codec_decode(_codec, data, size, pcm, &pcm_size) != SND_CODEC_OK) + THROW("decode failed"); #ifdef WAVE_CAPTURE put_wave_data(pcm, _frame_bytes); return; diff --git a/client/record_channel.cpp b/client/record_channel.cpp index d9332c6b..2870f62f 100644 --- a/client/record_channel.cpp +++ b/client/record_channel.cpp @@ -60,8 +60,6 @@ void RecordSamplesMessage::release() _channel.release_message(this); } -int RecordChannel::data_mode = SPICE_AUDIO_DATA_MODE_CELT_0_5_1; - class RecordHandler: public MessageHandlerImp { public: RecordHandler(RecordChannel& channel) @@ -72,8 +70,7 @@ RecordChannel::RecordChannel(RedClient& client, uint32_t id) : RedChannel(client, SPICE_CHANNEL_RECORD, id, new RecordHandler(*this)) , _wave_recorder (NULL) , _mode (SPICE_AUDIO_DATA_MODE_INVALID) - , _celt_mode (NULL) - , _celt_encoder (NULL) + , _codec(NULL) { for (int i = 0; i < NUM_SAMPLES_MESSAGES; i++) { _messages.push_front(new RecordSamplesMessage(*this)); @@ -90,7 +87,8 @@ RecordChannel::RecordChannel(RedClient& client, uint32_t id) handler->set_handler(SPICE_MSG_RECORD_START, &RecordChannel::handle_start); - set_capability(SPICE_RECORD_CAP_CELT_0_5_1); + if (snd_codec_is_capable(SPICE_AUDIO_DATA_MODE_CELT_0_5_1)) + set_capability(SPICE_RECORD_CAP_CELT_0_5_1); } RecordChannel::~RecordChannel(void) @@ -114,9 +112,12 @@ void RecordChannel::on_connect() Message* message = new Message(SPICE_MSGC_RECORD_MODE); SpiceMsgcRecordMode mode; mode.time = get_mm_time(); - mode.mode = _mode = - test_capability(SPICE_RECORD_CAP_CELT_0_5_1) ? RecordChannel::data_mode : - SPICE_AUDIO_DATA_MODE_RAW; + if (snd_codec_is_capable(SPICE_AUDIO_DATA_MODE_CELT_0_5_1) && + 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; + mode.mode = _mode; _marshallers->msgc_record_mode(message->marshaller(), &mode); post_message(message); } @@ -142,12 +143,15 @@ void RecordChannel::handle_start(RedPeer::InMessage* message) handler->set_handler(SPICE_MSG_RECORD_START, NULL); handler->set_handler(SPICE_MSG_RECORD_STOP, &RecordChannel::handle_stop); - ASSERT(!_wave_recorder && !_celt_mode && !_celt_encoder); + ASSERT(!_wave_recorder); // for now support only one setting if (start->format != SPICE_AUDIO_FMT_S16) { THROW("unexpected format"); } + if (start->channels != 2) { + THROW("unexpected number of channels"); + } int bits_per_sample = 16; try { @@ -159,17 +163,13 @@ void RecordChannel::handle_start(RedPeer::InMessage* message) return; } - int frame_size = 256; - int celt_mode_err; - _frame_bytes = frame_size * bits_per_sample * start->channels / 8; - if (!(_celt_mode = celt051_mode_create(start->frequency, start->channels, frame_size, - &celt_mode_err))) { - THROW("create celt mode failed %d", celt_mode_err); - } - - if (!(_celt_encoder = celt051_encoder_create(_celt_mode))) { - THROW("create celt encoder failed"); + 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_start_mark(); _wave_recorder->start(); @@ -182,14 +182,7 @@ void RecordChannel::clear() delete _wave_recorder; _wave_recorder = NULL; } - if (_celt_encoder) { - celt051_encoder_destroy(_celt_encoder); - _celt_encoder = NULL; - } - if (_celt_mode) { - celt051_mode_destroy(_celt_mode); - _celt_mode = NULL; - } + snd_codec_destroy(&_codec); } void RecordChannel::handle_stop(RedPeer::InMessage* message) @@ -200,7 +193,6 @@ void RecordChannel::handle_stop(RedPeer::InMessage* message) if (!_wave_recorder) { return; } - ASSERT(_celt_mode && _celt_encoder); clear(); } @@ -242,10 +234,6 @@ void RecordChannel::remove_event_source(EventSources::Trigger& event_source) get_process_loop().remove_trigger(event_source); } -#define FRAME_SIZE 256 -#define CELT_BIT_RATE (64 * 1024) -#define CELT_COMPRESSED_FRAME_BYTES (FRAME_SIZE * CELT_BIT_RATE / 44100 / 8) - void RecordChannel::push_frame(uint8_t *frame) { RecordSamplesMessage *message; @@ -254,19 +242,18 @@ void RecordChannel::push_frame(uint8_t *frame) DBG(0, "blocked"); return; } - uint8_t celt_buf[CELT_COMPRESSED_FRAME_BYTES]; int n; - if (_mode == SPICE_AUDIO_DATA_MODE_CELT_0_5_1) { - n = celt051_encode(_celt_encoder, (celt_int16_t *)frame, NULL, celt_buf, - CELT_COMPRESSED_FRAME_BYTES); - if (n < 0) { - THROW("celt encode failed"); - } - frame = celt_buf; - } else { + + if (_mode == SPICE_AUDIO_DATA_MODE_RAW) { n = _frame_bytes; + } else { + n = sizeof(compressed_buf); + if (snd_codec_encode(_codec, frame, _frame_bytes, compressed_buf, &n) != SND_CODEC_OK) + THROW("encode failed"); + frame = compressed_buf; } + RedPeer::OutMessage& peer_message = message->peer_message(); peer_message.reset(SPICE_MSGC_RECORD_DATA); SpiceMsgcRecordPacket packet; diff --git a/configure.ac b/configure.ac index db4fd891..c897368a 100644 --- a/configure.ac +++ b/configure.ac @@ -230,11 +230,13 @@ AC_SUBST(PIXMAN_CFLAGS) AC_SUBST(PIXMAN_LIBS) SPICE_REQUIRES+=" pixman-1 >= 0.17.7" -PKG_CHECK_MODULES(CELT051, celt051 >= 0.5.1.1) -AC_SUBST(CELT051_CFLAGS) -AC_SUBST(CELT051_LIBS) -AC_SUBST(CELT051_LIBDIR) -SPICE_REQUIRES+=" celt051 >= 0.5.1.1" +AC_ARG_ENABLE(celt051, + [ --disable-celt051 Disable celt051 audio codec (enabled by default)],, + [enable_celt051="yes"]) + +if test "x$enable_celt051" = "xyes"; then + PKG_CHECK_MODULES(CELT051, celt051 >= 0.5.1.1, SPICE_REQUIRES+=" celt051 >= 0.5.1.1") +fi if test ! -e client/generated_marshallers.cpp; then AC_MSG_CHECKING([for pyparsing python module]) diff --git a/server/Makefile.am b/server/Makefile.am index 6dcf2ee6..13c6223b 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -4,7 +4,6 @@ SUBDIRS = . tests AM_CPPFLAGS = \ -DSPICE_SERVER_INTERNAL \ -DRED_STATISTICS \ - $(CELT051_CFLAGS) \ $(COMMON_CFLAGS) \ $(GLIB2_CFLAGS) \ $(PIXMAN_CFLAGS) \ @@ -33,7 +32,6 @@ endif libspice_server_la_LIBADD = \ $(top_builddir)/spice-common/common/libspice-common.la \ $(top_builddir)/spice-common/common/libspice-common-server.la \ - $(CELT051_LIBS) \ $(GL_LIBS) \ $(GLIB2_LIBS) \ $(JPEG_LIBS) \ diff --git a/server/snd_worker.c b/server/snd_worker.c index 9156bf5d..f40fd658 100644 --- a/server/snd_worker.c +++ b/server/snd_worker.c @@ -25,7 +25,6 @@ #include #include #include -#include #include "common/marshaller.h" #include "common/generated_server_marshallers.h" @@ -36,20 +35,14 @@ #include "reds.h" #include "red_dispatcher.h" #include "snd_worker.h" +#include "common/snd_codec.h" #include "demarshallers.h" #ifndef IOV_MAX #define IOV_MAX 1024 #endif -#define SND_RECEIVE_BUF_SIZE (16 * 1024 * 2) - -#define FRAME_SIZE 256 -#define PLAYBACK_BUF_SIZE (FRAME_SIZE * 4) - -#define CELT_BIT_RATE (64 * 1024) -#define CELT_COMPRESSED_FRAME_BYTES (FRAME_SIZE * CELT_BIT_RATE / SPICE_INTERFACE_PLAYBACK_FREQ / 8) - +#define SND_RECEIVE_BUF_SIZE (16 * 1024 * 2) #define RECORD_SAMPLES_SIZE (SND_RECEIVE_BUF_SIZE >> 2) enum PlaybackCommand { @@ -129,7 +122,7 @@ typedef struct PlaybackChannel PlaybackChannel; typedef struct AudioFrame AudioFrame; struct AudioFrame { uint32_t time; - uint32_t samples[FRAME_SIZE]; + uint32_t samples[SND_CODEC_MAX_FRAME_SIZE]; PlaybackChannel *channel; AudioFrame *next; }; @@ -140,13 +133,10 @@ struct PlaybackChannel { AudioFrame *free_frames; AudioFrame *in_progress; AudioFrame *pending_frame; - CELTMode *celt_mode; - CELTEncoder *celt_encoder; uint32_t mode; - struct { - uint8_t celt_buf[CELT_COMPRESSED_FRAME_BYTES]; - } send_data; uint32_t latency; + SndCodec codec; + uint8_t encode_buf[SND_CODEC_MAX_COMPRESSED_BYTES]; }; struct SndWorker { @@ -182,13 +172,12 @@ typedef struct RecordChannel { uint32_t mode; uint32_t mode_time; uint32_t start_time; - CELTDecoder *celt_decoder; - CELTMode *celt_mode; - uint32_t celt_buf[FRAME_SIZE]; + SndCodec codec; + uint8_t decode_buf[SND_CODEC_MAX_FRAME_BYTES]; } RecordChannel; static SndWorker *workers; -static uint32_t playback_compression = SPICE_AUDIO_DATA_MODE_CELT_0_5_1; +static uint32_t playback_compression = TRUE; static void snd_receive(void* data); @@ -321,23 +310,19 @@ static int snd_record_handle_write(RecordChannel *record_channel, size_t size, v } packet = (SpiceMsgcRecordPacket *)message; - size = packet->data_size; - if (record_channel->mode == SPICE_AUDIO_DATA_MODE_CELT_0_5_1) { - int celt_err = celt051_decode(record_channel->celt_decoder, packet->data, size, - (celt_int16_t *)record_channel->celt_buf); - if (celt_err != CELT_OK) { - spice_printerr("celt decode failed (%d)", celt_err); - return FALSE; - } - data = record_channel->celt_buf; - size = FRAME_SIZE; - } else if (record_channel->mode == SPICE_AUDIO_DATA_MODE_RAW) { + if (record_channel->mode == SPICE_AUDIO_DATA_MODE_RAW) { data = (uint32_t *)packet->data; - size = size >> 2; + size = packet->data_size >> 2; size = MIN(size, RECORD_SAMPLES_SIZE); - } else { - return FALSE; + } else { + int decode_size; + decode_size = sizeof(record_channel->decode_buf); + if (snd_codec_decode(record_channel->codec, packet->data, packet->data_size, + record_channel->decode_buf, &decode_size) != SND_CODEC_OK) + return FALSE; + data = (uint32_t *) record_channel->decode_buf; + size = decode_size >> 2; } write_pos = record_channel->write_pos % RECORD_SAMPLES_SIZE; @@ -387,9 +372,9 @@ static int snd_record_handle_message(SndChannel *channel, size_t size, uint32_t SpiceMsgcRecordMode *mode = (SpiceMsgcRecordMode *)message; record_channel->mode = mode->mode; record_channel->mode_time = mode->time; - if (record_channel->mode != SPICE_AUDIO_DATA_MODE_CELT_0_5_1 && - record_channel->mode != SPICE_AUDIO_DATA_MODE_RAW) { - spice_printerr("unsupported mode"); + if (record_channel->mode != SPICE_AUDIO_DATA_MODE_RAW && + ! snd_codec_is_capable(record_channel->mode)) { + spice_printerr("unsupported mode %d", record_channel->mode); } break; } @@ -758,19 +743,19 @@ static int snd_playback_send_write(PlaybackChannel *playback_channel) spice_marshall_msg_playback_data(channel->send_data.marshaller, &msg); - if (playback_channel->mode == SPICE_AUDIO_DATA_MODE_CELT_0_5_1) { - int n = celt051_encode(playback_channel->celt_encoder, (celt_int16_t *)frame->samples, NULL, - playback_channel->send_data.celt_buf, CELT_COMPRESSED_FRAME_BYTES); - if (n < 0) { - spice_printerr("celt encode failed"); + if (playback_channel->mode == SPICE_AUDIO_DATA_MODE_RAW) { + spice_marshaller_add_ref(channel->send_data.marshaller, + (uint8_t *)frame->samples, sizeof(frame->samples)); + } + else { + int n = sizeof(playback_channel->encode_buf); + if (snd_codec_encode(playback_channel->codec, (uint8_t *) frame->samples, sizeof(frame->samples), + playback_channel->encode_buf, &n) != SND_CODEC_OK) { + spice_printerr("encode failed"); snd_disconnect_channel(channel); return FALSE; } - spice_marshaller_add_ref(channel->send_data.marshaller, - playback_channel->send_data.celt_buf, n); - } else { - spice_marshaller_add_ref(channel->send_data.marshaller, - (uint8_t *)frame->samples, sizeof(frame->samples)); + spice_marshaller_add_ref(channel->send_data.marshaller, playback_channel->encode_buf, n); } return snd_begin_send_message(channel); @@ -1090,7 +1075,7 @@ SPICE_GNUC_VISIBLE void spice_server_playback_get_buffer(SpicePlaybackInstance * *frame = playback_channel->free_frames->samples; playback_channel->free_frames = playback_channel->free_frames->next; - *num_samples = FRAME_SIZE; + *num_samples = snd_codec_frame_size(playback_channel->codec); } SPICE_GNUC_VISIBLE void spice_server_playback_put_samples(SpicePlaybackInstance *sin, uint32_t *samples) @@ -1140,6 +1125,18 @@ void snd_set_playback_latency(RedClient *client, uint32_t latency) } } } + +static int snd_desired_audio_mode(int client_can_celt) +{ + if (! playback_compression) + return SPICE_AUDIO_DATA_MODE_RAW; + + if (client_can_celt && snd_codec_is_capable(SPICE_AUDIO_DATA_MODE_CELT_0_5_1)) + return SPICE_AUDIO_DATA_MODE_CELT_0_5_1; + + return SPICE_AUDIO_DATA_MODE_RAW; +} + static void on_new_playback_channel(SndWorker *worker) { PlaybackChannel *playback_channel = @@ -1168,8 +1165,7 @@ static void snd_playback_cleanup(SndChannel *channel) reds_enable_mm_timer(); } - celt051_encoder_destroy(playback_channel->celt_encoder); - celt051_mode_destroy(playback_channel->celt_mode); + snd_codec_destroy(&playback_channel->codec); } static void snd_set_playback_peer(RedChannel *channel, RedClient *client, RedsStream *stream, @@ -1179,25 +1175,9 @@ static void snd_set_playback_peer(RedChannel *channel, RedClient *client, RedsSt SndWorker *worker = channel->data; PlaybackChannel *playback_channel; SpicePlaybackState *st = SPICE_CONTAINEROF(worker, SpicePlaybackState, worker); - CELTEncoder *celt_encoder; - CELTMode *celt_mode; - int celt_error; - RedChannelClient *rcc; snd_disconnect_channel(worker->connection); - if (!(celt_mode = celt051_mode_create(SPICE_INTERFACE_PLAYBACK_FREQ, - SPICE_INTERFACE_PLAYBACK_CHAN, - FRAME_SIZE, &celt_error))) { - spice_printerr("create celt mode failed %d", celt_error); - return; - } - - if (!(celt_encoder = celt051_encoder_create(celt_mode))) { - spice_printerr("create celt encoder failed"); - goto error_1; - } - if (!(playback_channel = (PlaybackChannel *)__new_channel(worker, sizeof(*playback_channel), SPICE_CHANNEL_PLAYBACK, @@ -1210,32 +1190,30 @@ static void snd_set_playback_peer(RedChannel *channel, RedClient *client, RedsSt snd_playback_cleanup, common_caps, num_common_caps, caps, num_caps))) { - goto error_2; + return; } worker->connection = &playback_channel->base; - rcc = playback_channel->base.channel_client; snd_playback_free_frame(playback_channel, &playback_channel->frames[0]); snd_playback_free_frame(playback_channel, &playback_channel->frames[1]); snd_playback_free_frame(playback_channel, &playback_channel->frames[2]); - playback_channel->celt_mode = celt_mode; - playback_channel->celt_encoder = celt_encoder; - playback_channel->mode = red_channel_client_test_remote_cap(rcc, - SPICE_PLAYBACK_CAP_CELT_0_5_1) ? - playback_compression : SPICE_AUDIO_DATA_MODE_RAW; + int client_can_celt = red_channel_client_test_remote_cap(playback_channel->base.channel_client, + SPICE_PLAYBACK_CAP_CELT_0_5_1); + int desired_mode = snd_desired_audio_mode(client_can_celt); + playback_channel->mode = SPICE_AUDIO_DATA_MODE_RAW; + if (desired_mode != SPICE_AUDIO_DATA_MODE_RAW) { + if (snd_codec_create(&playback_channel->codec, desired_mode, SPICE_INTERFACE_PLAYBACK_FREQ, SND_CODEC_ENCODE) == SND_CODEC_OK) { + playback_channel->mode = desired_mode; + } else { + spice_printerr("create encoder failed"); + } + } on_new_playback_channel(worker); if (worker->active) { spice_server_playback_start(st->sin); } snd_playback_send(worker->connection); - return; - -error_2: - celt051_encoder_destroy(celt_encoder); - -error_1: - celt051_mode_destroy(celt_mode); } static void snd_record_migrate_channel_client(RedChannelClient *rcc) @@ -1380,9 +1358,7 @@ static void on_new_record_channel(SndWorker *worker) static void snd_record_cleanup(SndChannel *channel) { RecordChannel *record_channel = SPICE_CONTAINEROF(channel, RecordChannel, base); - - celt051_decoder_destroy(record_channel->celt_decoder); - celt051_mode_destroy(record_channel->celt_mode); + snd_codec_destroy(&record_channel->codec); } static void snd_set_record_peer(RedChannel *channel, RedClient *client, RedsStream *stream, @@ -1392,24 +1368,9 @@ static void snd_set_record_peer(RedChannel *channel, RedClient *client, RedsStre SndWorker *worker = channel->data; RecordChannel *record_channel; SpiceRecordState *st = SPICE_CONTAINEROF(worker, SpiceRecordState, worker); - CELTDecoder *celt_decoder; - CELTMode *celt_mode; - int celt_error; snd_disconnect_channel(worker->connection); - if (!(celt_mode = celt051_mode_create(SPICE_INTERFACE_RECORD_FREQ, - SPICE_INTERFACE_RECORD_CHAN, - FRAME_SIZE, &celt_error))) { - spice_printerr("create celt mode failed %d", celt_error); - return; - } - - if (!(celt_decoder = celt051_decoder_create(celt_mode))) { - spice_printerr("create celt decoder failed"); - goto error_1; - } - if (!(record_channel = (RecordChannel *)__new_channel(worker, sizeof(*record_channel), SPICE_CHANNEL_RECORD, @@ -1422,26 +1383,28 @@ static void snd_set_record_peer(RedChannel *channel, RedClient *client, RedsStre snd_record_cleanup, common_caps, num_common_caps, caps, num_caps))) { - goto error_2; + return; } - worker->connection = &record_channel->base; + int client_can_celt = red_channel_client_test_remote_cap(record_channel->base.channel_client, + SPICE_RECORD_CAP_CELT_0_5_1); + int desired_mode = snd_desired_audio_mode(client_can_celt); + record_channel->mode = SPICE_AUDIO_DATA_MODE_RAW; + if (desired_mode != SPICE_AUDIO_DATA_MODE_RAW) { + if (snd_codec_create(&record_channel->codec, desired_mode, SPICE_INTERFACE_RECORD_FREQ, SND_CODEC_DECODE) == SND_CODEC_OK) { + record_channel->mode = desired_mode; + } else { + spice_printerr("create decoder failed"); + } + } - record_channel->celt_mode = celt_mode; - record_channel->celt_decoder = celt_decoder; + worker->connection = &record_channel->base; on_new_record_channel(worker); if (worker->active) { spice_server_record_start(st->sin); } snd_record_send(worker->connection); - return; - -error_2: - celt051_decoder_destroy(celt_decoder); - -error_1: - celt051_mode_destroy(celt_mode); } static void snd_playback_migrate_channel_client(RedChannelClient *rcc) @@ -1498,7 +1461,10 @@ void snd_attach_playback(SpicePlaybackInstance *sin) client_cbs.migrate = snd_playback_migrate_channel_client; red_channel_register_client_cbs(channel, &client_cbs); red_channel_set_data(channel, playback_worker); - red_channel_set_cap(channel, SPICE_PLAYBACK_CAP_CELT_0_5_1); + + if (snd_codec_is_capable(SPICE_AUDIO_DATA_MODE_CELT_0_5_1)) + red_channel_set_cap(channel, SPICE_PLAYBACK_CAP_CELT_0_5_1); + red_channel_set_cap(channel, SPICE_PLAYBACK_CAP_VOLUME); playback_worker->base_channel = channel; @@ -1525,7 +1491,8 @@ void snd_attach_record(SpiceRecordInstance *sin) client_cbs.migrate = snd_record_migrate_channel_client; red_channel_register_client_cbs(channel, &client_cbs); red_channel_set_data(channel, record_worker); - red_channel_set_cap(channel, SPICE_RECORD_CAP_CELT_0_5_1); + if (snd_codec_is_capable(SPICE_AUDIO_DATA_MODE_CELT_0_5_1)) + red_channel_set_cap(channel, SPICE_RECORD_CAP_CELT_0_5_1); red_channel_set_cap(channel, SPICE_RECORD_CAP_VOLUME); record_worker->base_channel = channel; @@ -1572,18 +1539,16 @@ void snd_set_playback_compression(int on) { SndWorker *now = workers; - playback_compression = on ? SPICE_AUDIO_DATA_MODE_CELT_0_5_1 : SPICE_AUDIO_DATA_MODE_RAW; + playback_compression = !!on; + for (; now; now = now->next) { if (now->base_channel->type == SPICE_CHANNEL_PLAYBACK && now->connection) { - SndChannel* sndchannel = now->connection; PlaybackChannel* playback = (PlaybackChannel*)now->connection; - if (!red_channel_client_test_remote_cap(sndchannel->channel_client, - SPICE_PLAYBACK_CAP_CELT_0_5_1)) { - spice_assert(playback->mode == SPICE_AUDIO_DATA_MODE_RAW); - continue; - } - if (playback->mode != playback_compression) { - playback->mode = playback_compression; + int desired_mode = snd_desired_audio_mode( + red_channel_client_test_remote_cap(now->connection->channel_client, SPICE_PLAYBACK_CAP_CELT_0_5_1) + ); + if (playback->mode != desired_mode) { + playback->mode = desired_mode; snd_set_command(now->connection, SND_PLAYBACK_MODE_MASK); } } @@ -1592,5 +1557,5 @@ void snd_set_playback_compression(int on) int snd_get_playback_compression(void) { - return (playback_compression == SPICE_AUDIO_DATA_MODE_RAW) ? FALSE : TRUE; + return playback_compression; } diff --git a/spice-common b/spice-common index 7e8ba107..c108e4ee 160000 --- a/spice-common +++ b/spice-common @@ -1 +1 @@ -Subproject commit 7e8ba10779a3fb11d587e8a59fe389acd2412dd0 +Subproject commit c108e4ee8cb33218d9a64e25de9e79b63d23a8e7 -- cgit