From 29942be38e11b297164dcd838e82c96ea152f6ff Mon Sep 17 00:00:00 2001
From: Michael Tokarev <mjt@tls.msk.ru>
Date: Sat, 5 May 2012 19:15:49 +0400
Subject: [PATCH] make celt to be optional
Forwarded: yes
Comment: upstream apparently does not want this patch

With this patch applied, celt051 library isn't required
anymore.  It is still required by default, but there's
a new configure option, --disable-celt051, which makes
the configure code to omit checking/finding the celt
library and makes resulting spice library to not use
celt codec at all.

The changes in the code - there are relatively many -
are located in 3 source files (see diffstat):

 client/playback_channel.cpp
 client/record_channel.cpp
 server/snd_worker.c

and are local/private to the library (client and server),
so no external ABI/API is done.

I found and marked hopefully all places where celt
codec is being touched/referenced.  The patch may
help future development too, indicating all places
where codec-specific code is used (just grep source
for HAVE_CELT051 to see these).

I plan to use this patch in the upcoming Debian
release, codename wheezy, to get rid of celt
codec library there, since we decided celt051 is
not going to be included, but it is obviously not
a good idea to drop spice entirely.

I did some interoperability tests and the thing
appears to work -- unpatched client to patched
server, patched client to unpatched server and
patched client to patched server.  I didn't check
old clients and servers, however.  In all cases,
raw audio stream is being choosen and used.  But
since I don't really know how spice works internally,
maybe I didn't perform correct testing.

Signed-off-By: Michael Tokarev <mjt@tls.msk.ru>
Cc: Ron Lee <ron@debian.org>
Cc: Liang Guo <bluestonechina@gmail.com>
---
 client/audio_channels.h     |    8 +++++
 client/playback_channel.cpp |   25 ++++++++++---
 client/record_channel.cpp   |   21 +++++++++--
 configure.ac                |   16 ++++++---
 server/snd_worker.c         |   82 ++++++++++++++++++++++++++++++++++---------
 5 files changed, 122 insertions(+), 30 deletions(-)

--- a/client/audio_channels.h
+++ b/client/audio_channels.h
@@ -18,7 +18,9 @@
 #ifndef _H_AUDIO_CHANNELS
 #define _H_AUDIO_CHANNELS
 
+#if HAVE_CELT051
 #include <celt051/celt.h>
+#endif
 
 #include "red_channel.h"
 #include "debug.h"
@@ -45,7 +47,9 @@
     void handle_start(RedPeer::InMessage* message);
     void handle_stop(RedPeer::InMessage* message);
     void handle_raw_data(RedPeer::InMessage* message);
+#if HAVE_CELT051
     void handle_celt_data(RedPeer::InMessage* message);
+#endif
     void null_handler(RedPeer::InMessage* message);
     void disable();
 
@@ -57,8 +61,10 @@
     WavePlaybackAbstract* _wave_player;
     uint32_t _mode;
     uint32_t _frame_bytes;
+#if HAVE_CELT051
     CELTMode *_celt_mode;
     CELTDecoder *_celt_decoder;
+#endif
     bool _playing;
     uint32_t _frame_count;
 };
@@ -96,8 +102,10 @@
     Mutex _messages_lock;
     std::list<RecordSamplesMessage *> _messages;
     int _mode;
+#if HAVE_CELT051
     CELTMode *_celt_mode;
     CELTEncoder *_celt_encoder;
+#endif
     uint32_t _frame_bytes;
 
     static int data_mode;
--- a/client/playback_channel.cpp
+++ b/client/playback_channel.cpp
@@ -151,8 +151,10 @@
                  Platform::PRIORITY_HIGH)
     , _wave_player (NULL)
     , _mode (SPICE_AUDIO_DATA_MODE_INVALID)
+#if HAVE_CELT051
     , _celt_mode (NULL)
     , _celt_decoder (NULL)
+#endif
     , _playing (false)
 {
 #ifdef WAVE_CAPTURE
@@ -169,7 +171,9 @@
 
     handler->set_handler(SPICE_MSG_PLAYBACK_MODE, &PlaybackChannel::handle_mode);
 
+#if HAVE_CELT051
     set_capability(SPICE_PLAYBACK_CAP_CELT_0_5_1);
+#endif
 }
 
 void PlaybackChannel::clear()
@@ -182,6 +186,7 @@
     }
     _mode = SPICE_AUDIO_DATA_MODE_INVALID;
 
+#if HAVE_CELT051
     if (_celt_decoder) {
         celt051_decoder_destroy(_celt_decoder);
         _celt_decoder = NULL;
@@ -191,6 +196,7 @@
         celt051_mode_destroy(_celt_mode);
         _celt_mode = NULL;
     }
+#endif
 }
 
 void PlaybackChannel::on_disconnect()
@@ -214,8 +220,10 @@
 
     if (_mode == SPICE_AUDIO_DATA_MODE_RAW) {
         handler->set_handler(SPICE_MSG_PLAYBACK_DATA, &PlaybackChannel::handle_raw_data);
+#if HAVE_CELT051
     } else if (_mode == SPICE_AUDIO_DATA_MODE_CELT_0_5_1) {
         handler->set_handler(SPICE_MSG_PLAYBACK_DATA, &PlaybackChannel::handle_celt_data);
+#endif
     } else {
         THROW("invalid mode");
     }
@@ -224,8 +232,11 @@
 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) {
+    if (playbacke_mode->mode != SPICE_AUDIO_DATA_MODE_RAW
+#if HAVE_CELT051
+        && playbacke_mode->mode != SPICE_AUDIO_DATA_MODE_CELT_0_5_1
+#endif
+       ) {
         THROW("invalid mode");
     }
 
@@ -265,9 +276,6 @@
     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");
         }
@@ -284,6 +292,10 @@
             return;
         }
 
+#if HAVE_CELT051
+        // for now support only one setting
+        int celt_mode_err;
+
         if (!(_celt_mode = celt051_mode_create(start->frequency, start->channels,
                                                frame_size, &celt_mode_err))) {
             THROW("create celt mode failed %d", celt_mode_err);
@@ -292,6 +304,7 @@
         if (!(_celt_decoder = celt051_decoder_create(_celt_mode))) {
             THROW("create celt decoder");
         }
+#endif
     }
     _playing = true;
     _frame_count = 0;
@@ -333,6 +346,7 @@
     _wave_player->write(data);
 }
 
+#if HAVE_CELT051
 void PlaybackChannel::handle_celt_data(RedPeer::InMessage* message)
 {
     SpiceMsgPlaybackPacket* packet = (SpiceMsgPlaybackPacket*)message->data();
@@ -352,6 +366,7 @@
     }
     _wave_player->write((uint8_t *)pcm);
 }
+#endif
 
 class PlaybackFactory: public ChannelFactory {
 public:
--- a/client/record_channel.cpp
+++ b/client/record_channel.cpp
@@ -72,8 +72,10 @@
     : RedChannel(client, SPICE_CHANNEL_RECORD, id, new RecordHandler(*this))
     , _wave_recorder (NULL)
     , _mode (SPICE_AUDIO_DATA_MODE_INVALID)
+#if HAVE_CELT051
     , _celt_mode (NULL)
     , _celt_encoder (NULL)
+#endif
 {
     for (int i = 0; i < NUM_SAMPLES_MESSAGES; i++) {
         _messages.push_front(new RecordSamplesMessage(*this));
@@ -89,8 +91,9 @@
     handler->set_handler(SPICE_MSG_NOTIFY, &RecordChannel::handle_notify);
 
     handler->set_handler(SPICE_MSG_RECORD_START, &RecordChannel::handle_start);
-
+#if HAVE_CELT051
     set_capability(SPICE_RECORD_CAP_CELT_0_5_1);
+#endif
 }
 
 RecordChannel::~RecordChannel(void)
@@ -115,7 +118,9 @@
     SpiceMsgcRecordMode mode;
     mode.time = get_mm_time();
     mode.mode = _mode =
+#if HAVE_CELT051
       test_capability(SPICE_RECORD_CAP_CELT_0_5_1) ? RecordChannel::data_mode :
+#endif
                                                                       SPICE_AUDIO_DATA_MODE_RAW;
     _marshallers->msgc_record_mode(message->marshaller(), &mode);
     post_message(message);
@@ -142,7 +147,11 @@
 
     handler->set_handler(SPICE_MSG_RECORD_START, NULL);
     handler->set_handler(SPICE_MSG_RECORD_STOP, &RecordChannel::handle_stop);
+#if HAVE_CELT051
     ASSERT(!_wave_recorder && !_celt_mode && !_celt_encoder);
+#else
+    ASSERT(!_wave_recorder);
+#endif
 
     // for now support only one setting
     if (start->format != SPICE_AUDIO_FMT_S16) {
@@ -160,8 +169,9 @@
     }
 
     int frame_size = 256;
-    int celt_mode_err;
     _frame_bytes = frame_size * bits_per_sample * start->channels / 8;
+#if HAVE_CELT051
+    int celt_mode_err;
     if (!(_celt_mode = celt051_mode_create(start->frequency, start->channels, frame_size,
                                            &celt_mode_err))) {
         THROW("create celt mode failed %d", celt_mode_err);
@@ -170,6 +180,7 @@
     if (!(_celt_encoder = celt051_encoder_create(_celt_mode))) {
         THROW("create celt encoder failed");
     }
+#endif
 
     send_start_mark();
     _wave_recorder->start();
@@ -182,6 +193,7 @@
         delete _wave_recorder;
         _wave_recorder = NULL;
     }
+#if HAVE_CELT051
     if (_celt_encoder) {
         celt051_encoder_destroy(_celt_encoder);
         _celt_encoder = NULL;
@@ -190,6 +202,7 @@
         celt051_mode_destroy(_celt_mode);
         _celt_mode = NULL;
     }
+#endif
 }
 
 void RecordChannel::handle_stop(RedPeer::InMessage* message)
@@ -200,7 +213,9 @@
     if (!_wave_recorder) {
         return;
     }
+#if HAVE_CELT051
     ASSERT(_celt_mode && _celt_encoder);
+#endif
     clear();
 }
 
@@ -254,8 +269,9 @@
         DBG(0, "blocked");
         return;
     }
-    uint8_t celt_buf[CELT_COMPRESSED_FRAME_BYTES];
     int n;
+#if HAVE_CELT051
+    uint8_t celt_buf[CELT_COMPRESSED_FRAME_BYTES];
 
     if (_mode == SPICE_AUDIO_DATA_MODE_CELT_0_5_1) {
         n = celt051_encode(_celt_encoder, (celt_int16_t *)frame, NULL, celt_buf,
@@ -264,7 +280,9 @@
             THROW("celt encode failed");
         }
         frame = celt_buf;
-    } else {
+    } else
+#endif
+    {
         n = _frame_bytes;
     }
     RedPeer::OutMessage& peer_message = message->peer_message();
--- a/configure.ac
+++ b/configure.ac
@@ -147,6 +147,9 @@
 if test "x$enable_smartcard" = "xyes"; then
    AC_DEFINE([USE_SMARTCARD], [1], [Define if supporting smartcard proxying])
 fi
+AC_ARG_ENABLE(celt051,
+[  --disable-celt051       Disable celt051 audio codec (enabled by default)],,
+[enable_celt051="yes"])
 
 AC_ARG_ENABLE(client,
 [  --enable-client         Enable spice client],,
@@ -246,11 +249,14 @@
 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"
+if test "x$enable_celt051" = "xyes"; then
+    PKG_CHECK_MODULES(CELT051, celt051 >= 0.5.1.1)
+    SPICE_REQUIRES+=" celt051 >= 0.5.1.1"
+    AC_DEFINE([HAVE_CELT051], 1, [Define if we have celt051 codec])
+    AC_SUBST(CELT051_CFLAGS)
+    AC_SUBST(CELT051_LIBS)
+    AC_SUBST(CELT051_LIBDIR)
+fi
 
 if test ! -e client/generated_marshallers.cpp; then
 AC_MSG_CHECKING([for pyparsing python module])
--- a/server/snd_worker.c
+++ b/server/snd_worker.c
@@ -25,7 +25,9 @@
 #include <sys/socket.h>
 #include <netinet/ip.h>
 #include <netinet/tcp.h>
+#if HAVE_CELT051
 #include <celt051/celt.h>
+#endif
 
 #include "common/marshaller.h"
 #include "common/generated_server_marshallers.h"
@@ -140,12 +142,16 @@
     AudioFrame *free_frames;
     AudioFrame *in_progress;
     AudioFrame *pending_frame;
+#if HAVE_CELT051
     CELTMode *celt_mode;
     CELTEncoder *celt_encoder;
+#endif
     uint32_t mode;
+#if HAVE_CELT051
     struct {
         uint8_t celt_buf[CELT_COMPRESSED_FRAME_BYTES];
     } send_data;
+#endif
     uint32_t latency;
 };
 
@@ -182,13 +188,21 @@
     uint32_t mode;
     uint32_t mode_time;
     uint32_t start_time;
+#if HAVE_CELT051
     CELTDecoder *celt_decoder;
     CELTMode *celt_mode;
     uint32_t celt_buf[FRAME_SIZE];
+#endif
 } RecordChannel;
 
 static SndWorker *workers;
-static uint32_t playback_compression = SPICE_AUDIO_DATA_MODE_CELT_0_5_1;
+static uint32_t playback_compression =
+#if HAVE_CELT051
+    SPICE_AUDIO_DATA_MODE_CELT_0_5_1
+#else
+    SPICE_AUDIO_DATA_MODE_RAW
+#endif
+    ;
 
 static void snd_receive(void* data);
 
@@ -323,6 +337,7 @@
     packet = (SpiceMsgcRecordPacket *)message;
     size = packet->data_size;
 
+#if HAVE_CELT051
     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);
@@ -332,7 +347,9 @@
         }
         data = record_channel->celt_buf;
         size = FRAME_SIZE;
-    } else if (record_channel->mode == SPICE_AUDIO_DATA_MODE_RAW) {
+    } else
+#endif
+    if (record_channel->mode == SPICE_AUDIO_DATA_MODE_RAW) {
         data = (uint32_t *)packet->data;
         size = size >> 2;
         size = MIN(size, RECORD_SAMPLES_SIZE);
@@ -387,8 +404,11 @@
         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) {
+        if (record_channel->mode != SPICE_AUDIO_DATA_MODE_RAW
+#if HAVE_CELT051
+            && record_channel->mode != SPICE_AUDIO_DATA_MODE_CELT_0_5_1
+#endif
+            ) {
             spice_printerr("unsupported mode");
         }
         break;
@@ -758,6 +778,7 @@
 
     spice_marshall_msg_playback_data(channel->send_data.marshaller, &msg);
 
+#if HAVE_CELT051
     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);
@@ -768,7 +789,9 @@
         }
         spice_marshaller_add_ref(channel->send_data.marshaller,
                                  playback_channel->send_data.celt_buf, n);
-    } else {
+    } else
+#endif
+    {
         spice_marshaller_add_ref(channel->send_data.marshaller,
                                  (uint8_t *)frame->samples, sizeof(frame->samples));
     }
@@ -1168,8 +1191,10 @@
         reds_enable_mm_timer();
     }
 
+#if HAVE_CELT051
     celt051_encoder_destroy(playback_channel->celt_encoder);
     celt051_mode_destroy(playback_channel->celt_mode);
+#endif
 }
 
 static void snd_set_playback_peer(RedChannel *channel, RedClient *client, RedsStream *stream,
@@ -1179,13 +1204,13 @@
     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 HAVE_CELT051
+    CELTEncoder *celt_encoder;
+    CELTMode *celt_mode;
+    int celt_error;
     if (!(celt_mode = celt051_mode_create(SPICE_INTERFACE_PLAYBACK_FREQ,
                                           SPICE_INTERFACE_PLAYBACK_CHAN,
                                           FRAME_SIZE, &celt_error))) {
@@ -1197,6 +1222,7 @@
         spice_printerr("create celt encoder failed");
         goto error_1;
     }
+#endif
 
     if (!(playback_channel = (PlaybackChannel *)__new_channel(worker,
                                                               sizeof(*playback_channel),
@@ -1213,16 +1239,20 @@
         goto error_2;
     }
     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]);
 
+#if HAVE_CELT051
     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_channel->mode =
+       red_channel_client_test_remote_cap(playback_channel->base.channel_client,
+                                          SPICE_PLAYBACK_CAP_CELT_0_5_1) ?
         playback_compression : SPICE_AUDIO_DATA_MODE_RAW;
+#else
+    playback_channel->mode = SPICE_AUDIO_DATA_MODE_RAW;
+#endif
 
     on_new_playback_channel(worker);
     if (worker->active) {
@@ -1232,10 +1262,13 @@
     return;
 
 error_2:
+#if HAVE_CELT051
     celt051_encoder_destroy(celt_encoder);
 
 error_1:
     celt051_mode_destroy(celt_mode);
+#endif
+    return;
 }
 
 static void snd_record_migrate_channel_client(RedChannelClient *rcc)
@@ -1379,10 +1412,12 @@
 
 static void snd_record_cleanup(SndChannel *channel)
 {
+#if HAVE_CELT051
     RecordChannel *record_channel = SPICE_CONTAINEROF(channel, RecordChannel, base);
 
     celt051_decoder_destroy(record_channel->celt_decoder);
     celt051_mode_destroy(record_channel->celt_mode);
+#endif
 }
 
 static void snd_set_record_peer(RedChannel *channel, RedClient *client, RedsStream *stream,
@@ -1392,12 +1427,13 @@
     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 HAVE_CELT051
+    CELTDecoder *celt_decoder;
+    CELTMode *celt_mode;
+    int celt_error;
     if (!(celt_mode = celt051_mode_create(SPICE_INTERFACE_RECORD_FREQ,
                                           SPICE_INTERFACE_RECORD_CHAN,
                                           FRAME_SIZE, &celt_error))) {
@@ -1409,6 +1445,7 @@
         spice_printerr("create celt decoder failed");
         goto error_1;
     }
+#endif
 
     if (!(record_channel = (RecordChannel *)__new_channel(worker,
                                                           sizeof(*record_channel),
@@ -1427,8 +1464,10 @@
 
     worker->connection = &record_channel->base;
 
+#if HAVE_CELT051
     record_channel->celt_mode = celt_mode;
     record_channel->celt_decoder = celt_decoder;
+#endif
 
     on_new_record_channel(worker);
     if (worker->active) {
@@ -1438,10 +1477,13 @@
     return;
 
 error_2:
+#if HAVE_CELT051
     celt051_decoder_destroy(celt_decoder);
 
 error_1:
     celt051_mode_destroy(celt_mode);
+#endif
+    return;
 }
 
 static void snd_playback_migrate_channel_client(RedChannelClient *rcc)
@@ -1498,7 +1540,9 @@
     client_cbs.migrate = snd_playback_migrate_channel_client;
     red_channel_register_client_cbs(channel, &client_cbs);
     red_channel_set_data(channel, playback_worker);
+#if HAVE_CELT051
     red_channel_set_cap(channel, SPICE_PLAYBACK_CAP_CELT_0_5_1);
+#endif
     red_channel_set_cap(channel, SPICE_PLAYBACK_CAP_VOLUME);
 
     playback_worker->base_channel = channel;
@@ -1525,7 +1569,9 @@
     client_cbs.migrate = snd_record_migrate_channel_client;
     red_channel_register_client_cbs(channel, &client_cbs);
     red_channel_set_data(channel, record_worker);
+#if HAVE_CELT051
     red_channel_set_cap(channel, SPICE_RECORD_CAP_CELT_0_5_1);
+#endif
     red_channel_set_cap(channel, SPICE_RECORD_CAP_VOLUME);
 
     record_worker->base_channel = channel;
@@ -1572,7 +1618,11 @@
 {
     SndWorker *now = workers;
 
-    playback_compression = on ? SPICE_AUDIO_DATA_MODE_CELT_0_5_1 : SPICE_AUDIO_DATA_MODE_RAW;
+    playback_compression =
+#if HAVE_CELT051
+       on ? SPICE_AUDIO_DATA_MODE_CELT_0_5_1 :
+#endif
+       SPICE_AUDIO_DATA_MODE_RAW;
     for (; now; now = now->next) {
         if (now->base_channel->type == SPICE_CHANNEL_PLAYBACK && now->connection) {
             SndChannel* sndchannel = now->connection;
