summaryrefslogtreecommitdiffstats
path: root/server/snd_worker.c
diff options
context:
space:
mode:
Diffstat (limited to 'server/snd_worker.c')
-rw-r--r--server/snd_worker.c205
1 files changed, 85 insertions, 120 deletions
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 <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;
}