mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice
synced 2025-12-31 20:04:09 +00:00
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 <jwhite@codeweavers.com>
This commit is contained in:
parent
4fc9ba5f27
commit
4c7c0ef3a7
1
README
1
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
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
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;
|
||||
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");
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
12
configure.ac
12
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])
|
||||
|
||||
@ -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) \
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
worker->connection = &record_channel->base;
|
||||
|
||||
record_channel->celt_mode = celt_mode;
|
||||
record_channel->celt_decoder = celt_decoder;
|
||||
|
||||
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 +1 @@
|
||||
Subproject commit 7e8ba10779a3fb11d587e8a59fe389acd2412dd0
|
||||
Subproject commit c108e4ee8cb33218d9a64e25de9e79b63d23a8e7
|
||||
Loading…
Reference in New Issue
Block a user