diff options
Diffstat (limited to 'server/snd_worker.c')
-rw-r--r-- | server/snd_worker.c | 205 |
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; } |