[Spice-devel] [spice sound rework 2/4 (take 6)] Revise the spice client and server to use the new snd_codec functions in spice-common.

Jeremy White jwhite at codeweavers.com
Wed Nov 27 11:31:43 PST 2013


This makes celt optional, and paves the way to readily add additional codecs.

Signed-off-by: Jeremy White <jwhite at codeweavers.com>
---
  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 ++++++++++++++++++-------------------------
  7 files changed, 150 insertions(+), 210 deletions(-)

diff --git a/README b/README
index b344066..dea4344 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 d38a79e..d7b81e7 100644
--- a/client/audio_channels.h
+++ b/client/audio_channels.h
@@ -18,7 +18,7 @@
  #ifndef _H_AUDIO_CHANNELS
  #define _H_AUDIO_CHANNELS
  
-#include <celt051/celt.h>
+#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<RecordSamplesMessage *> _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 802a4d3..173c94a 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 d9332c6..2870f62 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<RecordChannel, SPICE_CHANNEL_RECORD> {
  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 882bf1b..b7f6140 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 807fbfb..b98385c 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 9156bf5..f40fd65 100644
--- a/server/snd_worker.c
+++ b/server/snd_worker.c
@@ -25,7 +25,6 @@
  #include <sys/socket.h>
  #include <netinet/ip.h>
  #include <netinet/tcp.h>
-#include <celt051/celt.h>
  
  #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;
  }
-- 
1.7.10.4



More information about the Spice-devel mailing list