This patch is quite huge but have some benefits: - reduce dependency (DummyChannel* and some RedChannelClient internals); - reuse RedChannelClient instead of reading from the RedsStream directly. You can see that SndChannelClient has much less field as the code to read/write from/to client is reused from RedChannelClient instead of creating a fake RedChannelClient just to make the system happy. One of the different between the old sound code and all other RedChannelClient objects was that the sound channel don't use a queue while RedChannelClient use RedPipeItem object. This was the main reason why RedChannelClient was not used. To implement the old behaviour a "persistent_pipe_item" is used. This RedPipeItem will be queued to RedChannelClient (only one!) so signal code we have data to send. The {playback,record}_channel_send_item will then send the messages to the client using RedChannelClient functions. For this reason snd_reset_send_data is replaced by a call to red_channel_client_init_send_data and snd_begin_send_message is replaced by red_channel_client_begin_send_message. Signed-off-by: Frediano Ziglio <fziglio@xxxxxxxxxx> --- server/sound.c | 944 +++++++++++++++++++++----------------------------- 1 file changed, 413 insertions(+), 531 deletions(-) diff --git a/server/sound.c b/server/sound.c index 310ff6e..a645b60 100644 --- a/server/sound.c +++ b/server/sound.c @@ -32,14 +32,10 @@ #include "spice.h" #include "red-common.h" -#include "dummy-channel.h" -#include "dummy-channel-client.h" #include "main-channel.h" #include "reds.h" #include "red-qxl.h" #include "red-channel-client.h" -/* FIXME: for now, allow sound channel access to private RedChannelClient data */ -#include "red-channel-client-private.h" #include "red-client.h" #include "sound.h" #include "demarshallers.h" @@ -56,6 +52,7 @@ enum SndCommand { SND_MIGRATE, SND_CTRL, SND_VOLUME, + SND_MUTE, SND_END_COMMAND, }; @@ -68,6 +65,8 @@ enum PlaybackCommand { #define SND_MIGRATE_MASK (1 << SND_MIGRATE) #define SND_CTRL_MASK (1 << SND_CTRL) #define SND_VOLUME_MASK (1 << SND_VOLUME) +#define SND_MUTE_MASK (1 << SND_MUTE) +#define SND_VOLUME_MUTE_MASK (SND_VOLUME_MASK|SND_MUTE_MASK) #define SND_PLAYBACK_MODE_MASK (1 << SND_PLAYBACK_MODE) #define SND_PLAYBACK_PCM_MASK (1 << SND_PLAYBACK_PCM) @@ -82,49 +81,43 @@ typedef struct AudioFrameContainer AudioFrameContainer; typedef struct SpicePlaybackState PlaybackChannel; typedef struct SpiceRecordState RecordChannel; -typedef void (*snd_channel_send_messages_proc)(void *in_channel); -typedef int (*snd_channel_handle_message_proc)(SndChannelClient *client, size_t size, uint32_t type, void *message); typedef void (*snd_channel_on_message_done_proc)(SndChannelClient *client); -typedef void (*snd_channel_cleanup_channel_proc)(SndChannelClient *client); -#define SND_CHANNEL_CLIENT(obj) (&(obj)->base) + +#define TYPE_SND_CHANNEL_CLIENT snd_channel_client_get_type() +#define SND_CHANNEL_CLIENT(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_SND_CHANNEL_CLIENT, SndChannelClient)) +GType snd_channel_client_get_type(void) G_GNUC_CONST; /* Connects an audio client to a Spice client */ struct SndChannelClient { - RedsStream *stream; - SndChannel *channel; - spice_parse_channel_func_t parser; - int refs; - - RedChannelClient *channel_client; + RedChannelClient parent; int active; int client_active; - int blocked; uint32_t command; - struct { - uint64_t serial; - SpiceMarshaller *marshaller; - uint32_t size; - uint32_t pos; - } send_data; - - struct { - uint8_t buf[SND_RECEIVE_BUF_SIZE]; - uint8_t *message_start; - uint8_t *now; - uint8_t *end; - } receive_data; - - snd_channel_send_messages_proc send_messages; - snd_channel_handle_message_proc handle_message; + /* we don't expect very big messages so don't allocate too much + * bytes, data will be cached in RecordChannelClient::samples */ + uint8_t receive_buf[SND_CODEC_MAX_FRAME_BYTES + 64]; + RedPipeItem persistent_pipe_item; + snd_channel_on_message_done_proc on_message_done; - snd_channel_cleanup_channel_proc cleanup; }; -typedef struct AudioFrame AudioFrame; +typedef struct SndChannelClientClass { + RedChannelClientClass parent_class; +} SndChannelClientClass; + +G_DEFINE_TYPE(SndChannelClient, snd_channel_client, RED_TYPE_CHANNEL_CLIENT) + + +enum { + RED_PIPE_ITEM_PERSISTENT = RED_PIPE_ITEM_TYPE_CHANNEL_BASE, +}; + + struct AudioFrame { uint32_t time; uint32_t samples[SND_CODEC_MAX_FRAME_SIZE]; @@ -141,8 +134,13 @@ struct AudioFrameContainer AudioFrame items[NUM_AUDIO_FRAMES]; }; +#define TYPE_PLAYBACK_CHANNEL_CLIENT playback_channel_client_get_type() +#define PLAYBACK_CHANNEL_CLIENT(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_PLAYBACK_CHANNEL_CLIENT, PlaybackChannelClient)) +GType playback_channel_client_get_type(void) G_GNUC_CONST; + struct PlaybackChannelClient { - SndChannelClient base; + SndChannelClient parent; AudioFrameContainer *frames; AudioFrame *free_frames; @@ -154,6 +152,13 @@ struct PlaybackChannelClient { uint8_t encode_buf[SND_CODEC_MAX_COMPRESSED_BYTES]; }; +typedef struct PlaybackChannelClientClass { + SndChannelClientClass parent_class; +} PlaybackChannelClientClass; + +G_DEFINE_TYPE(PlaybackChannelClient, playback_channel_client, TYPE_SND_CHANNEL_CLIENT) + + typedef struct SpiceVolumeState { uint16_t *volume; uint8_t volume_nchannels; @@ -214,8 +219,13 @@ typedef struct RecordChannelClass { G_DEFINE_TYPE(RecordChannel, record_channel, TYPE_SND_CHANNEL) +#define TYPE_RECORD_CHANNEL_CLIENT record_channel_client_get_type() +#define RECORD_CHANNEL_CLIENT(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_RECORD_CHANNEL_CLIENT, RecordChannelClient)) +GType record_channel_client_get_type(void) G_GNUC_CONST; + struct RecordChannelClient { - SndChannelClient base; + SndChannelClient parent; uint32_t samples[RECORD_SAMPLES_SIZE]; uint32_t write_pos; uint32_t read_pos; @@ -226,57 +236,24 @@ struct RecordChannelClient { uint8_t decode_buf[SND_CODEC_MAX_FRAME_BYTES]; }; +typedef struct RecordChannelClientClass { + SndChannelClientClass parent_class; +} RecordChannelClientClass; + +G_DEFINE_TYPE(RecordChannelClient, record_channel_client, TYPE_SND_CHANNEL_CLIENT) + + /* A list of all Spice{Playback,Record}State objects */ static SndChannel *snd_channels; -static void snd_receive(SndChannelClient *client); static void snd_playback_start(SndChannel *channel); static void snd_record_start(SndChannel *channel); -static void snd_playback_alloc_frames(PlaybackChannelClient *playback); - -static SndChannelClient *snd_channel_unref(SndChannelClient *client) -{ - if (!--client->refs) { - spice_printerr("SndChannelClient=%p freed", client); - free(client); - return NULL; - } - return client; -} +static void snd_send(SndChannelClient * client); static RedsState* snd_channel_get_server(SndChannelClient *client) { g_return_val_if_fail(client != NULL, NULL); - return red_channel_get_server(RED_CHANNEL(client->channel)); -} - -static void snd_disconnect_channel(SndChannelClient *client) -{ - SndChannel *channel; - RedsState *reds; - RedChannel *red_channel; - uint32_t type; - - if (!client || !client->stream) { - spice_debug("not connected"); - return; - } - red_channel = red_channel_client_get_channel(client->channel_client); - reds = snd_channel_get_server(client); - g_object_get(red_channel, "channel-type", &type, NULL); - spice_debug("SndChannelClient=%p rcc=%p type=%d", - client, client->channel_client, type); - channel = client->channel; - client->cleanup(client); - red_channel_client_disconnect(channel->connection->channel_client); - channel->connection->channel_client = NULL; - reds_core_watch_remove(reds, client->stream->watch); - client->stream->watch = NULL; - reds_stream_free(client->stream); - client->stream = NULL; - spice_marshaller_destroy(client->send_data.marshaller); - snd_channel_unref(client); - channel->connection = NULL; + return red_channel_get_server(red_channel_client_get_channel(RED_CHANNEL_CLIENT(client))); } static void snd_playback_free_frame(PlaybackChannelClient *playback_client, AudioFrame *frame) @@ -294,69 +271,11 @@ static void snd_playback_on_message_done(SndChannelClient *client) playback_client->in_progress = NULL; if (playback_client->pending_frame) { client->command |= SND_PLAYBACK_PCM_MASK; + snd_send(client); } } } -static void snd_record_on_message_done(SndChannelClient *client) -{ -} - -static int snd_send_data(SndChannelClient *client) -{ - uint32_t n; - - if (!client) { - return FALSE; - } - - if (!(n = client->send_data.size - client->send_data.pos)) { - return TRUE; - } - - RedsState *reds = snd_channel_get_server(client); - for (;;) { - struct iovec vec[IOV_MAX]; - int vec_size; - - if (!n) { - client->on_message_done(client); - - if (client->blocked) { - client->blocked = FALSE; - reds_core_watch_update_mask(reds, client->stream->watch, SPICE_WATCH_EVENT_READ); - } - break; - } - - vec_size = spice_marshaller_fill_iovec(client->send_data.marshaller, - vec, IOV_MAX, client->send_data.pos); - n = reds_stream_writev(client->stream, vec, vec_size); - if (n == -1) { - switch (errno) { - case EAGAIN: - client->blocked = TRUE; - reds_core_watch_update_mask(reds, client->stream->watch, SPICE_WATCH_EVENT_READ | - SPICE_WATCH_EVENT_WRITE); - return FALSE; - case EINTR: - break; - case EPIPE: - snd_disconnect_channel(client); - return FALSE; - default: - spice_printerr("%s", strerror(errno)); - snd_disconnect_channel(client); - return FALSE; - } - } else { - client->send_data.pos += n; - } - n = client->send_data.size - client->send_data.pos; - } - return TRUE; -} - static int snd_record_handle_write(RecordChannelClient *record_client, size_t size, void *message) { SpiceMsgcRecordPacket *packet; @@ -402,35 +321,29 @@ static int snd_record_handle_write(RecordChannelClient *record_client, size_t si return TRUE; } -static int snd_playback_handle_message(SndChannelClient *client, size_t size, uint32_t type, void *message) +static int +playback_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint16_t type, void *message) { - if (!client) { - return FALSE; - } - switch (type) { case SPICE_MSGC_DISCONNECTING: break; default: - spice_printerr("invalid message type %u", type); - return FALSE; + return red_channel_client_handle_message(rcc, size, type, message); } return TRUE; } -static int snd_record_handle_message(SndChannelClient *client, size_t size, uint32_t type, void *message) +static int +record_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint16_t type, void *message) { - RecordChannelClient *record_client = (RecordChannelClient *)client; + RecordChannelClient *record_client = RECORD_CHANNEL_CLIENT(rcc); - if (!client) { - return FALSE; - } switch (type) { case SPICE_MSGC_RECORD_DATA: return snd_record_handle_write(record_client, size, message); case SPICE_MSGC_RECORD_MODE: { SpiceMsgcRecordMode *mode = (SpiceMsgcRecordMode *)message; - SndChannel *channel = client->channel; + SndChannel *channel = SND_CHANNEL(red_channel_client_get_channel(rcc)); record_client->mode_time = mode->time; if (mode->mode != SPICE_AUDIO_DATA_MODE_RAW) { if (snd_codec_is_capable(mode->mode, channel->frequency)) { @@ -460,153 +373,23 @@ static int snd_record_handle_message(SndChannelClient *client, size_t size, uint case SPICE_MSGC_DISCONNECTING: break; default: - spice_printerr("invalid message type %u", type); - return FALSE; + return red_channel_client_handle_message(rcc, size, type, message); } return TRUE; } -static void snd_receive(SndChannelClient *client) -{ - SpiceDataHeaderOpaque *header; - - if (!client) { - return; - } - - header = &client->channel_client->incoming.header; - - for (;;) { - ssize_t n; - n = client->receive_data.end - client->receive_data.now; - spice_warn_if_fail(n > 0); - n = reds_stream_read(client->stream, client->receive_data.now, n); - if (n <= 0) { - if (n == 0) { - snd_disconnect_channel(client); - return; - } - spice_assert(n == -1); - switch (errno) { - case EAGAIN: - return; - case EINTR: - break; - case EPIPE: - snd_disconnect_channel(client); - return; - default: - spice_printerr("%s", strerror(errno)); - snd_disconnect_channel(client); - return; - } - } else { - client->receive_data.now += n; - for (;;) { - uint8_t *msg_start = client->receive_data.message_start; - uint8_t *data = msg_start + header->header_size; - size_t parsed_size; - uint8_t *parsed; - message_destructor_t parsed_free; - - header->data = msg_start; - n = client->receive_data.now - msg_start; - - if (n < header->header_size || - n < header->header_size + header->get_msg_size(header)) { - break; - } - parsed = client->parser((void *)data, data + header->get_msg_size(header), - header->get_msg_type(header), - SPICE_VERSION_MINOR, &parsed_size, &parsed_free); - if (parsed == NULL) { - spice_printerr("failed to parse message type %d", header->get_msg_type(header)); - snd_disconnect_channel(client); - return; - } - if (!client->handle_message(client, parsed_size, - header->get_msg_type(header), parsed)) { - free(parsed); - snd_disconnect_channel(client); - return; - } - parsed_free(parsed); - client->receive_data.message_start = msg_start + header->header_size + - header->get_msg_size(header); - } - if (client->receive_data.now == client->receive_data.message_start) { - client->receive_data.now = client->receive_data.buf; - client->receive_data.message_start = client->receive_data.buf; - } else if (client->receive_data.now == client->receive_data.end) { - memcpy(client->receive_data.buf, client->receive_data.message_start, n); - client->receive_data.now = client->receive_data.buf + n; - client->receive_data.message_start = client->receive_data.buf; - } - } - } -} - -static void snd_event(int fd, int event, void *data) -{ - SndChannelClient *client = data; - - if (event & SPICE_WATCH_EVENT_READ) { - snd_receive(client); - } - if (event & SPICE_WATCH_EVENT_WRITE) { - client->send_messages(client); - } -} - -static inline int snd_reset_send_data(SndChannelClient *client, uint16_t verb) -{ - SpiceDataHeaderOpaque *header; - - if (!client) { - return FALSE; - } - - header = &client->channel_client->priv->send_data.header; - spice_marshaller_reset(client->send_data.marshaller); - header->data = spice_marshaller_reserve_space(client->send_data.marshaller, - header->header_size); - spice_marshaller_set_base(client->send_data.marshaller, - header->header_size); - client->send_data.pos = 0; - header->set_msg_size(header, 0); - header->set_msg_type(header, verb); - client->send_data.serial++; - if (!client->channel_client->priv->is_mini_header) { - header->set_msg_serial(header, client->send_data.serial); - header->set_msg_sub_list(header, 0); - } - - return TRUE; -} - -static int snd_begin_send_message(SndChannelClient *client) -{ - SpiceDataHeaderOpaque *header = &client->channel_client->priv->send_data.header; - - spice_marshaller_flush(client->send_data.marshaller); - client->send_data.size = spice_marshaller_get_total_size(client->send_data.marshaller); - header->set_msg_size(header, client->send_data.size - header->header_size); - return snd_send_data(client); -} - static int snd_channel_send_migrate(SndChannelClient *client) { - SpiceMarshaller *m = client->send_data.marshaller; + RedChannelClient *rcc = RED_CHANNEL_CLIENT(client); + SpiceMarshaller *m = red_channel_client_get_marshaller(rcc); SpiceMsgMigrate migrate; - if (!snd_reset_send_data(client, SPICE_MSG_MIGRATE)) { - return FALSE; - } - spice_debug(NULL); + red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE); migrate.flags = 0; spice_marshall_msg_migrate(m, &migrate); - return snd_begin_send_message(client); + red_channel_client_begin_send_message(rcc); + return FALSE; } static int snd_playback_send_migrate(PlaybackChannelClient *client) @@ -618,25 +401,26 @@ static int snd_send_volume(SndChannelClient *client, uint32_t cap, int msg) { SpiceMsgAudioVolume *vol; uint8_t c; - SpiceVolumeState *st = &client->channel->volume; - SpiceMarshaller *m = client->send_data.marshaller; + RedChannelClient *rcc = RED_CHANNEL_CLIENT(client); + SpiceMarshaller *m = red_channel_client_get_marshaller(rcc); + SndChannel *channel = SND_CHANNEL(red_channel_client_get_channel(rcc)); + SpiceVolumeState *st = &channel->volume; - if (!red_channel_client_test_remote_cap(client->channel_client, cap)) { + if (!red_channel_client_test_remote_cap(rcc, cap)) { return TRUE; } vol = alloca(sizeof (SpiceMsgAudioVolume) + st->volume_nchannels * sizeof (uint16_t)); - if (!snd_reset_send_data(client, msg)) { - return FALSE; - } + red_channel_client_init_send_data(rcc, msg); vol->nchannels = st->volume_nchannels; for (c = 0; c < st->volume_nchannels; ++c) { vol->volume[c] = st->volume[c]; } spice_marshall_SpiceMsgAudioVolume(m, vol); - return snd_begin_send_message(client); + red_channel_client_begin_send_message(rcc); + return FALSE; } static int snd_playback_send_volume(PlaybackChannelClient *playback_client) @@ -648,20 +432,21 @@ static int snd_playback_send_volume(PlaybackChannelClient *playback_client) static int snd_send_mute(SndChannelClient *client, uint32_t cap, int msg) { SpiceMsgAudioMute mute; - SpiceVolumeState *st = &client->channel->volume; - SpiceMarshaller *m = client->send_data.marshaller; + RedChannelClient *rcc = RED_CHANNEL_CLIENT(client); + SpiceMarshaller *m = red_channel_client_get_marshaller(rcc); + SndChannel *channel = SND_CHANNEL(red_channel_client_get_channel(rcc)); + SpiceVolumeState *st = &channel->volume; - if (!red_channel_client_test_remote_cap(client->channel_client, cap)) { + if (!red_channel_client_test_remote_cap(rcc, cap)) { return TRUE; } - if (!snd_reset_send_data(client, msg)) { - return FALSE; - } + red_channel_client_init_send_data(rcc, msg); mute.mute = st->mute; spice_marshall_SpiceMsgAudioMute(m, &mute); - return snd_begin_send_message(client); + red_channel_client_begin_send_message(rcc); + return FALSE; } static int snd_playback_send_mute(PlaybackChannelClient *playback_client) @@ -672,48 +457,45 @@ static int snd_playback_send_mute(PlaybackChannelClient *playback_client) static int snd_playback_send_latency(PlaybackChannelClient *playback_client) { - SndChannelClient *client = SND_CHANNEL_CLIENT(playback_client); - SpiceMarshaller *m = client->send_data.marshaller; + RedChannelClient *rcc = RED_CHANNEL_CLIENT(playback_client); + SpiceMarshaller *m = red_channel_client_get_marshaller(rcc); SpiceMsgPlaybackLatency latency_msg; spice_debug("latency %u", playback_client->latency); - if (!snd_reset_send_data(client, SPICE_MSG_PLAYBACK_LATENCY)) { - return FALSE; - } + red_channel_client_init_send_data(rcc, SPICE_MSG_PLAYBACK_LATENCY); latency_msg.latency_ms = playback_client->latency; spice_marshall_msg_playback_latency(m, &latency_msg); - return snd_begin_send_message(client); + red_channel_client_begin_send_message(rcc); + return FALSE; } + static int snd_playback_send_start(PlaybackChannelClient *playback_client) { - SndChannelClient *client = (SndChannelClient *)playback_client; - SpiceMarshaller *m = client->send_data.marshaller; + RedChannelClient *rcc = RED_CHANNEL_CLIENT(playback_client); + SpiceMarshaller *m = red_channel_client_get_marshaller(rcc); SpiceMsgPlaybackStart start; - if (!snd_reset_send_data(client, SPICE_MSG_PLAYBACK_START)) { - return FALSE; - } - + red_channel_client_init_send_data(rcc, SPICE_MSG_PLAYBACK_START); start.channels = SPICE_INTERFACE_PLAYBACK_CHAN; - start.frequency = client->channel->frequency; + start.frequency = SND_CHANNEL(red_channel_client_get_channel(rcc))->frequency; spice_assert(SPICE_INTERFACE_PLAYBACK_FMT == SPICE_INTERFACE_AUDIO_FMT_S16); start.format = SPICE_AUDIO_FMT_S16; start.time = reds_get_mm_time(); spice_marshall_msg_playback_start(m, &start); - return snd_begin_send_message(client); + red_channel_client_begin_send_message(rcc); + return FALSE; } static int snd_playback_send_stop(PlaybackChannelClient *playback_client) { - SndChannelClient *client = (SndChannelClient *)playback_client; + RedChannelClient *rcc = RED_CHANNEL_CLIENT(playback_client); - if (!snd_reset_send_data(client, SPICE_MSG_PLAYBACK_STOP)) { - return FALSE; - } + red_channel_client_init_send_data(rcc, SPICE_MSG_PLAYBACK_STOP); - return snd_begin_send_message(client); + red_channel_client_begin_send_message(rcc); + return FALSE; } static int snd_playback_send_ctl(PlaybackChannelClient *playback_client) @@ -729,32 +511,30 @@ static int snd_playback_send_ctl(PlaybackChannelClient *playback_client) static int snd_record_send_start(RecordChannelClient *record_client) { - SndChannelClient *client = (SndChannelClient *)record_client; - SpiceMarshaller *m = client->send_data.marshaller; + RedChannelClient *rcc = RED_CHANNEL_CLIENT(record_client); + SpiceMarshaller *m = red_channel_client_get_marshaller(rcc); SpiceMsgRecordStart start; - if (!snd_reset_send_data(client, SPICE_MSG_RECORD_START)) { - return FALSE; - } + red_channel_client_init_send_data(rcc, SPICE_MSG_RECORD_START); start.channels = SPICE_INTERFACE_RECORD_CHAN; - start.frequency = client->channel->frequency; + start.frequency = SND_CHANNEL(red_channel_client_get_channel(rcc))->frequency; spice_assert(SPICE_INTERFACE_RECORD_FMT == SPICE_INTERFACE_AUDIO_FMT_S16); start.format = SPICE_AUDIO_FMT_S16; spice_marshall_msg_record_start(m, &start); - return snd_begin_send_message(client); + red_channel_client_begin_send_message(rcc); + return FALSE; } static int snd_record_send_stop(RecordChannelClient *record_client) { - SndChannelClient *client = (SndChannelClient *)record_client; + RedChannelClient *rcc = RED_CHANNEL_CLIENT(record_client); - if (!snd_reset_send_data(client, SPICE_MSG_RECORD_STOP)) { - return FALSE; - } + red_channel_client_init_send_data(rcc, SPICE_MSG_RECORD_STOP); - return snd_begin_send_message(client); + red_channel_client_begin_send_message(rcc); + return FALSE; } static int snd_record_send_ctl(RecordChannelClient *record_client) @@ -791,14 +571,13 @@ static int snd_record_send_migrate(RecordChannelClient *record_client) static int snd_playback_send_write(PlaybackChannelClient *playback_client) { - SndChannelClient *client = (SndChannelClient *)playback_client; - SpiceMarshaller *m = client->send_data.marshaller; + RedChannelClient *rcc = RED_CHANNEL_CLIENT(playback_client); + SpiceMarshaller *m = red_channel_client_get_marshaller(rcc); AudioFrame *frame; SpiceMsgPlaybackPacket msg; + RedPipeItem *pipe_item = &SND_CHANNEL_CLIENT(playback_client)->persistent_pipe_item; - if (!snd_reset_send_data(client, SPICE_MSG_PLAYBACK_DATA)) { - return FALSE; - } + red_channel_client_init_send_data(rcc, SPICE_MSG_PLAYBACK_DATA); frame = playback_client->in_progress; msg.time = frame->time; @@ -806,9 +585,10 @@ static int snd_playback_send_write(PlaybackChannelClient *playback_client) spice_marshall_msg_playback_data(m, &msg); if (playback_client->mode == SPICE_AUDIO_DATA_MODE_RAW) { - spice_marshaller_add_by_ref(m, (uint8_t *)frame->samples, - snd_codec_frame_size(playback_client->codec) * - sizeof(frame->samples[0])); + spice_marshaller_add_by_ref_full(m, (uint8_t *)frame->samples, + snd_codec_frame_size(playback_client->codec) * + sizeof(frame->samples[0]), + marshaller_unref_pipe_item, pipe_item); } else { int n = sizeof(playback_client->encode_buf); @@ -816,46 +596,71 @@ static int snd_playback_send_write(PlaybackChannelClient *playback_client) snd_codec_frame_size(playback_client->codec) * sizeof(frame->samples[0]), playback_client->encode_buf, &n) != SND_CODEC_OK) { spice_printerr("encode failed"); - snd_disconnect_channel(client); - return FALSE; + red_channel_client_disconnect(rcc); + return TRUE; } - spice_marshaller_add_by_ref(m, playback_client->encode_buf, n); + spice_marshaller_add_by_ref_full(m, playback_client->encode_buf, n, + marshaller_unref_pipe_item, pipe_item); } - return snd_begin_send_message(client); + red_channel_client_begin_send_message(rcc); + return FALSE; } static int playback_send_mode(PlaybackChannelClient *playback_client) { - SndChannelClient *client = (SndChannelClient *)playback_client; - SpiceMarshaller *m = client->send_data.marshaller; + RedChannelClient *rcc = RED_CHANNEL_CLIENT(playback_client); + SpiceMarshaller *m = red_channel_client_get_marshaller(rcc); SpiceMsgPlaybackMode mode; - if (!snd_reset_send_data(client, SPICE_MSG_PLAYBACK_MODE)) { - return FALSE; - } + red_channel_client_init_send_data(rcc, SPICE_MSG_PLAYBACK_MODE); mode.time = reds_get_mm_time(); mode.mode = playback_client->mode; spice_marshall_msg_playback_mode(m, &mode); - return snd_begin_send_message(client); + red_channel_client_begin_send_message(rcc); + return FALSE; } -static void snd_playback_send(void* data) +static void snd_persistent_pipe_item_free(struct RedPipeItem *item) { - PlaybackChannelClient *playback_client = (PlaybackChannelClient*)data; - SndChannelClient *client = SND_CHANNEL_CLIENT(playback_client); + SndChannelClient *client = SPICE_CONTAINEROF(item, SndChannelClient, persistent_pipe_item); + + red_pipe_item_init_full(item, RED_PIPE_ITEM_PERSISTENT, + snd_persistent_pipe_item_free); - if (!playback_client || !snd_send_data(data)) { + if (client->on_message_done) { + client->on_message_done(client); + } +} + +static void snd_send(SndChannelClient * client) +{ + RedChannelClient *rcc = RED_CHANNEL_CLIENT(client); + + if (!client || !red_channel_client_pipe_is_empty(rcc) || !client->command) { return; } + // just append a dummy item and push! + red_pipe_item_init_full(&client->persistent_pipe_item, RED_PIPE_ITEM_PERSISTENT, + snd_persistent_pipe_item_free); + red_channel_client_pipe_add_push(rcc, &client->persistent_pipe_item); +} +static void playback_channel_send_item(RedChannelClient *rcc, RedPipeItem *base) +{ + PlaybackChannelClient *playback_client = PLAYBACK_CHANNEL_CLIENT(rcc); + SndChannelClient *client = SND_CHANNEL_CLIENT(rcc); + + client->command &= SND_PLAYBACK_MODE_MASK|SND_PLAYBACK_PCM_MASK| + SND_CTRL_MASK|SND_VOLUME_MUTE_MASK| + SND_MIGRATE_MASK|SND_PLAYBACK_LATENCY_MASK; while (client->command) { if (client->command & SND_PLAYBACK_MODE_MASK) { + client->command &= ~SND_PLAYBACK_MODE_MASK; if (!playback_send_mode(playback_client)) { - return; + break; } - client->command &= ~SND_PLAYBACK_MODE_MASK; } if (client->command & SND_PLAYBACK_PCM_MASK) { spice_assert(!playback_client->in_progress && playback_client->pending_frame); @@ -863,95 +668,94 @@ static void snd_playback_send(void* data) playback_client->pending_frame = NULL; client->command &= ~SND_PLAYBACK_PCM_MASK; if (!snd_playback_send_write(playback_client)) { - spice_printerr("snd_send_playback_write failed"); - return; + break; } + spice_printerr("snd_send_playback_write failed"); } if (client->command & SND_CTRL_MASK) { + client->command &= ~SND_CTRL_MASK; if (!snd_playback_send_ctl(playback_client)) { - return; + break; } - client->command &= ~SND_CTRL_MASK; } if (client->command & SND_VOLUME_MASK) { - if (!snd_playback_send_volume(playback_client) || - !snd_playback_send_mute(playback_client)) { - return; - } client->command &= ~SND_VOLUME_MASK; + if (!snd_playback_send_volume(playback_client)) { + break; + } + } + if (client->command & SND_MUTE_MASK) { + client->command &= ~SND_MUTE_MASK; + if (!snd_playback_send_mute(playback_client)) { + break; + } } if (client->command & SND_MIGRATE_MASK) { + client->command &= ~SND_MIGRATE_MASK; if (!snd_playback_send_migrate(playback_client)) { - return; + break; } - client->command &= ~SND_MIGRATE_MASK; } if (client->command & SND_PLAYBACK_LATENCY_MASK) { + client->command &= ~SND_PLAYBACK_LATENCY_MASK; if (!snd_playback_send_latency(playback_client)) { - return; + break; } - client->command &= ~SND_PLAYBACK_LATENCY_MASK; } } + snd_send(client); } -static void snd_record_send(void* data) +static void record_channel_send_item(RedChannelClient *rcc, RedPipeItem *base) { - RecordChannelClient *record_client = (RecordChannelClient*)data; - SndChannelClient *client = SND_CHANNEL_CLIENT(record_client); - - if (!record_client || !snd_send_data(data)) { - return; - } + RecordChannelClient *record_client = RECORD_CHANNEL_CLIENT(rcc); + SndChannelClient *client = SND_CHANNEL_CLIENT(rcc); + client->command &= SND_CTRL_MASK|SND_VOLUME_MUTE_MASK|SND_MIGRATE_MASK; while (client->command) { if (client->command & SND_CTRL_MASK) { + client->command &= ~SND_CTRL_MASK; if (!snd_record_send_ctl(record_client)) { - return; + break; } - client->command &= ~SND_CTRL_MASK; } if (client->command & SND_VOLUME_MASK) { - if (!snd_record_send_volume(record_client) || - !snd_record_send_mute(record_client)) { - return; - } client->command &= ~SND_VOLUME_MASK; + if (!snd_record_send_volume(record_client)) { + break; + } + } + if (client->command & SND_MUTE_MASK) { + client->command &= ~SND_MUTE_MASK; + if (!snd_record_send_mute(record_client)) { + break; + } } if (client->command & SND_MIGRATE_MASK) { + client->command &= ~SND_MIGRATE_MASK; if (!snd_record_send_migrate(record_client)) { - return; + break; } - client->command &= ~SND_MIGRATE_MASK; } } + snd_send(client); } -static SndChannelClient *__new_channel(SndChannel *channel, int size, uint32_t channel_id, - RedClient *red_client, - RedsStream *stream, - int migrate, - snd_channel_send_messages_proc send_messages, - snd_channel_handle_message_proc handle_message, - snd_channel_on_message_done_proc on_message_done, - snd_channel_cleanup_channel_proc cleanup, - uint32_t *common_caps, int num_common_caps, - uint32_t *caps, int num_caps) +static int snd_channel_config_socket(RedChannelClient *rcc) { - SndChannelClient *client; int delay_val; int flags; #ifdef SO_PRIORITY int priority; #endif int tos; + RedsStream *stream = red_channel_client_get_stream(rcc); + RedClient *red_client = red_channel_client_get_client(rcc); MainChannelClient *mcc = red_client_get_main(red_client); - RedsState *reds = red_channel_get_server(RED_CHANNEL(channel)); - spice_assert(stream); if ((flags = fcntl(stream->socket, F_GETFL)) == -1) { spice_printerr("accept failed, %s", strerror(errno)); - goto error1; + return FALSE; } #ifdef SO_PRIORITY @@ -980,69 +784,39 @@ static SndChannelClient *__new_channel(SndChannel *channel, int size, uint32_t c if (fcntl(stream->socket, F_SETFL, flags | O_NONBLOCK) == -1) { spice_printerr("accept failed, %s", strerror(errno)); - goto error1; - } - - spice_assert(size >= sizeof(*client)); - client = spice_malloc0(size); - client->refs = 1; - client->parser = spice_get_client_channel_parser(channel_id, NULL); - client->stream = stream; - client->channel = channel; - client->receive_data.message_start = client->receive_data.buf; - client->receive_data.now = client->receive_data.buf; - client->receive_data.end = client->receive_data.buf + sizeof(client->receive_data.buf); - client->send_data.marshaller = spice_marshaller_new(); - - stream->watch = reds_core_watch_add(reds, stream->socket, SPICE_WATCH_EVENT_READ, - snd_event, client); - if (stream->watch == NULL) { - spice_printerr("watch_add failed, %s", strerror(errno)); - goto error2; - } - - client->send_messages = send_messages; - client->handle_message = handle_message; - client->on_message_done = on_message_done; - client->cleanup = cleanup; - - client->channel_client = - dummy_channel_client_create(RED_CHANNEL(channel), red_client, - num_common_caps, common_caps, num_caps, caps); - if (!client->channel_client) { - goto error2; + return FALSE; } - return client; - -error2: - free(client); - -error1: - reds_stream_free(stream); - return NULL; -} -static int snd_channel_config_socket(RedChannelClient *rcc) -{ - g_assert_not_reached(); + return TRUE; } static void snd_channel_on_disconnect(RedChannelClient *rcc) { - g_assert_not_reached(); + SndChannel *channel = SND_CHANNEL(red_channel_client_get_channel(rcc)); + if (channel->connection && rcc == RED_CHANNEL_CLIENT(channel->connection)) { + channel->connection = NULL; + } } static uint8_t* snd_channel_client_alloc_recv_buf(RedChannelClient *rcc, uint16_t type, uint32_t size) { - g_assert_not_reached(); + SndChannelClient *client = SND_CHANNEL_CLIENT(rcc); + // If message is to big allocate one, this should never happen + if (size > sizeof(client->receive_buf)) { + return spice_malloc(size); + } + return client->receive_buf; } static void snd_channel_client_release_recv_buf(RedChannelClient *rcc, uint16_t type, uint32_t size, uint8_t *msg) { - g_assert_not_reached(); + SndChannelClient *client = SND_CHANNEL_CLIENT(rcc); + if (msg != client->receive_buf) { + free(msg); + } } static void snd_disconnect_channel_client(RedChannelClient *rcc) @@ -1057,8 +831,8 @@ static void snd_disconnect_channel_client(RedChannelClient *rcc) spice_debug("channel-type=%d", type); if (channel->connection) { - spice_assert(channel->connection->channel_client == rcc); - snd_disconnect_channel(channel->connection); + spice_assert(RED_CHANNEL_CLIENT(channel->connection) == rcc); + red_channel_client_disconnect(rcc); } } @@ -1076,7 +850,6 @@ SPICE_GNUC_VISIBLE void spice_server_playback_set_volume(SpicePlaybackInstance * { SpiceVolumeState *st = &sin->st->channel.volume; SndChannelClient *client = sin->st->channel.connection; - PlaybackChannelClient *playback_client = SPICE_CONTAINEROF(client, PlaybackChannelClient, base); st->volume_nchannels = nchannels; free(st->volume); @@ -1085,21 +858,22 @@ SPICE_GNUC_VISIBLE void spice_server_playback_set_volume(SpicePlaybackInstance * if (!client || nchannels == 0) return; - snd_playback_send_volume(playback_client); + snd_set_command(client, SND_VOLUME_MUTE_MASK); + snd_send(client); } SPICE_GNUC_VISIBLE void spice_server_playback_set_mute(SpicePlaybackInstance *sin, uint8_t mute) { SpiceVolumeState *st = &sin->st->channel.volume; SndChannelClient *client = sin->st->channel.connection; - PlaybackChannelClient *playback_client = SPICE_CONTAINEROF(client, PlaybackChannelClient, base); st->mute = mute; if (!client) return; - snd_playback_send_mute(playback_client); + snd_set_command(client, SND_VOLUME_MUTE_MASK); + snd_send(client); } static void snd_playback_start(SndChannel *channel) @@ -1114,7 +888,7 @@ static void snd_playback_start(SndChannel *channel) client->active = TRUE; if (!client->client_active) { snd_set_command(client, SND_CTRL_MASK); - snd_playback_send(client); + snd_send(client); } else { client->command &= ~SND_CTRL_MASK; } @@ -1128,17 +902,17 @@ SPICE_GNUC_VISIBLE void spice_server_playback_start(SpicePlaybackInstance *sin) SPICE_GNUC_VISIBLE void spice_server_playback_stop(SpicePlaybackInstance *sin) { SndChannelClient *client = sin->st->channel.connection; - PlaybackChannelClient *playback_client = SPICE_CONTAINEROF(client, PlaybackChannelClient, base); sin->st->channel.active = 0; if (!client) return; + PlaybackChannelClient *playback_client = PLAYBACK_CHANNEL_CLIENT(client); spice_assert(client->active); reds_enable_mm_time(snd_channel_get_server(client)); client->active = FALSE; if (client->client_active) { snd_set_command(client, SND_CTRL_MASK); - snd_playback_send(client); + snd_send(client); } else { client->command &= ~SND_CTRL_MASK; client->command &= ~SND_PLAYBACK_PCM_MASK; @@ -1156,11 +930,14 @@ SPICE_GNUC_VISIBLE void spice_server_playback_get_buffer(SpicePlaybackInstance * uint32_t **frame, uint32_t *num_samples) { SndChannelClient *client = sin->st->channel.connection; - PlaybackChannelClient *playback_client = SPICE_CONTAINEROF(client, PlaybackChannelClient, base); - if (!client || !playback_client->free_frames) { - *frame = NULL; - *num_samples = 0; + *frame = NULL; + *num_samples = 0; + if (!client) { + return; + } + PlaybackChannelClient *playback_client = PLAYBACK_CHANNEL_CLIENT(client); + if (!playback_client->free_frames) { return; } spice_assert(client->active); @@ -1201,7 +978,7 @@ SPICE_GNUC_VISIBLE void spice_server_playback_put_samples(SpicePlaybackInstance frame->time = reds_get_mm_time(); playback_client->pending_frame = frame; snd_set_command(SND_CHANNEL_CLIENT(playback_client), SND_PLAYBACK_PCM_MASK); - snd_playback_send(SND_CHANNEL_CLIENT(playback_client)); + snd_send(SND_CHANNEL_CLIENT(playback_client)); } void snd_set_playback_latency(RedClient *client, uint32_t latency) @@ -1212,15 +989,15 @@ void snd_set_playback_latency(RedClient *client, uint32_t latency) uint32_t type; g_object_get(RED_CHANNEL(now), "channel-type", &type, NULL); if (type == SPICE_CHANNEL_PLAYBACK && now->connection && - red_channel_client_get_client(now->connection->channel_client) == client) { + red_channel_client_get_client(RED_CHANNEL_CLIENT(now->connection)) == client) { - if (red_channel_client_test_remote_cap(now->connection->channel_client, + if (red_channel_client_test_remote_cap(RED_CHANNEL_CLIENT(now->connection), SPICE_PLAYBACK_CAP_LATENCY)) { PlaybackChannelClient* playback = (PlaybackChannelClient*)now->connection; playback->latency = latency; snd_set_command(now->connection, SND_PLAYBACK_LATENCY_MASK); - snd_playback_send(now->connection); + snd_send(now->connection); } else { spice_debug("client doesn't not support SPICE_PLAYBACK_CAP_LATENCY"); } @@ -1255,17 +1032,19 @@ static void on_new_playback_channel(SndChannel *channel, SndChannelClient *snd_c snd_set_command(snd_channel, SND_CTRL_MASK); } if (channel->volume.volume_nchannels) { - snd_set_command(snd_channel, SND_VOLUME_MASK); + snd_set_command(snd_channel, SND_VOLUME_MUTE_MASK); } if (snd_channel->active) { reds_disable_mm_time(reds); } } -static void snd_playback_cleanup(SndChannelClient *client) +static void +playback_channel_client_finalize(GObject *object) { - PlaybackChannelClient *playback_client = SPICE_CONTAINEROF(client, PlaybackChannelClient, base); int i; + PlaybackChannelClient *playback_client = PLAYBACK_CHANNEL_CLIENT(object); + SndChannelClient *client = SND_CHANNEL_CLIENT(playback_client); // free frames, unref them for (i = 0; i < NUM_AUDIO_FRAMES; ++i) { @@ -1280,43 +1059,31 @@ static void snd_playback_cleanup(SndChannelClient *client) } snd_codec_destroy(&playback_client->codec); + + G_OBJECT_CLASS(playback_channel_client_parent_class)->finalize(object); } -static void snd_set_playback_peer(RedChannel *red_channel, RedClient *client, RedsStream *stream, - int migration, int num_common_caps, uint32_t *common_caps, - int num_caps, uint32_t *caps) +static void +playback_channel_client_constructed(GObject *object) { + PlaybackChannelClient *playback_client = PLAYBACK_CHANNEL_CLIENT(object); + RedChannel *red_channel = red_channel_client_get_channel(RED_CHANNEL_CLIENT(playback_client)); + RedClient *client = red_channel_client_get_client(RED_CHANNEL_CLIENT(playback_client)); SndChannel *channel = SND_CHANNEL(red_channel); - PlaybackChannelClient *playback_client; - snd_disconnect_channel(channel->connection); - - if (!(playback_client = (PlaybackChannelClient *)__new_channel(channel, - sizeof(*playback_client), - SPICE_CHANNEL_PLAYBACK, - client, - stream, - migration, - snd_playback_send, - snd_playback_handle_message, - snd_playback_on_message_done, - snd_playback_cleanup, - common_caps, num_common_caps, - caps, num_caps))) { - return; - } + G_OBJECT_CLASS(playback_channel_client_parent_class)->constructed(object); - snd_playback_alloc_frames(playback_client); + SND_CHANNEL_CLIENT(playback_client)->on_message_done = snd_playback_on_message_done; - int client_can_celt = red_channel_client_test_remote_cap(playback_client->base.channel_client, + RedChannelClient *rcc = RED_CHANNEL_CLIENT(playback_client); + int client_can_celt = red_channel_client_test_remote_cap(rcc, SPICE_PLAYBACK_CAP_CELT_0_5_1); - int client_can_opus = red_channel_client_test_remote_cap(playback_client->base.channel_client, + int client_can_opus = red_channel_client_test_remote_cap(rcc, SPICE_PLAYBACK_CAP_OPUS); int playback_compression = reds_config_get_playback_compression(red_channel_get_server(red_channel)); int desired_mode = snd_desired_audio_mode(playback_compression, channel->frequency, client_can_celt, client_can_opus); - playback_client->mode = SPICE_AUDIO_DATA_MODE_RAW; if (desired_mode != SPICE_AUDIO_DATA_MODE_RAW) { if (snd_codec_create(&playback_client->codec, desired_mode, channel->frequency, SND_CODEC_ENCODE) == SND_CODEC_OK) { @@ -1333,7 +1100,46 @@ static void snd_set_playback_peer(RedChannel *red_channel, RedClient *client, Re if (channel->active) { snd_playback_start(channel); } - snd_playback_send(channel->connection); + snd_send(SND_CHANNEL_CLIENT(playback_client)); +} + +static void snd_set_playback_peer(RedChannel *red_channel, RedClient *client, RedsStream *stream, + int migration, int num_common_caps, uint32_t *common_caps, + int num_caps, uint32_t *caps) +{ + SndChannel *channel = SND_CHANNEL(red_channel); + GArray *common_caps_array = NULL, *caps_array = NULL; + + if (channel->connection) { + red_channel_client_disconnect(RED_CHANNEL_CLIENT(channel->connection)); + channel->connection = NULL; + } + + if (common_caps) { + common_caps_array = g_array_sized_new(FALSE, FALSE, sizeof (*common_caps), + num_common_caps); + g_array_append_vals(common_caps_array, common_caps, num_common_caps); + } + if (caps) { + caps_array = g_array_sized_new(FALSE, FALSE, sizeof (*caps), num_caps); + g_array_append_vals(caps_array, caps, num_caps); + } + + g_initable_new(TYPE_PLAYBACK_CHANNEL_CLIENT, + NULL, NULL, + "channel", channel, + "client", client, + "stream", stream, + "caps", caps_array, + "common-caps", common_caps_array, + NULL); + + if (caps_array) { + g_array_unref(caps_array); + } + if (common_caps_array) { + g_array_unref(common_caps_array); + } } static void snd_record_migrate_channel_client(RedChannelClient *rcc) @@ -1345,9 +1151,9 @@ static void snd_record_migrate_channel_client(RedChannelClient *rcc) spice_assert(channel); if (channel->connection) { - spice_assert(channel->connection->channel_client == rcc); + spice_assert(RED_CHANNEL_CLIENT(channel->connection) == rcc); snd_set_command(channel->connection, SND_MIGRATE_MASK); - snd_record_send(channel->connection); + snd_send(channel->connection); } } @@ -1357,7 +1163,6 @@ SPICE_GNUC_VISIBLE void spice_server_record_set_volume(SpiceRecordInstance *sin, { SpiceVolumeState *st = &sin->st->channel.volume; SndChannelClient *client = sin->st->channel.connection; - RecordChannelClient *record_client = SPICE_CONTAINEROF(client, RecordChannelClient, base); st->volume_nchannels = nchannels; free(st->volume); @@ -1366,38 +1171,40 @@ SPICE_GNUC_VISIBLE void spice_server_record_set_volume(SpiceRecordInstance *sin, if (!client || nchannels == 0) return; - snd_record_send_volume(record_client); + snd_set_command(client, SND_VOLUME_MUTE_MASK); + snd_send(client); } SPICE_GNUC_VISIBLE void spice_server_record_set_mute(SpiceRecordInstance *sin, uint8_t mute) { SpiceVolumeState *st = &sin->st->channel.volume; SndChannelClient *client = sin->st->channel.connection; - RecordChannelClient *record_client = SPICE_CONTAINEROF(client, RecordChannelClient, base); st->mute = mute; if (!client) return; - snd_record_send_mute(record_client); + snd_set_command(client, SND_VOLUME_MUTE_MASK); + snd_send(client); } static void snd_record_start(SndChannel *channel) { SndChannelClient *client = channel->connection; - RecordChannelClient *record_client = SPICE_CONTAINEROF(client, RecordChannelClient, base); channel->active = 1; - if (!client) + if (!client) { return; + } + RecordChannelClient *record_client = RECORD_CHANNEL_CLIENT(client); spice_assert(!client->active); record_client->read_pos = record_client->write_pos = 0; //todo: improve by //stream generation client->active = TRUE; if (!client->client_active) { snd_set_command(client, SND_CTRL_MASK); - snd_record_send(client); + snd_send(client); } else { client->command &= ~SND_CTRL_MASK; } @@ -1419,7 +1226,7 @@ SPICE_GNUC_VISIBLE void spice_server_record_stop(SpiceRecordInstance *sin) client->active = FALSE; if (client->client_active) { snd_set_command(client, SND_CTRL_MASK); - snd_record_send(client); + snd_send(client); } else { client->command &= ~SND_CTRL_MASK; } @@ -1429,13 +1236,13 @@ SPICE_GNUC_VISIBLE uint32_t spice_server_record_get_samples(SpiceRecordInstance uint32_t *samples, uint32_t bufsize) { SndChannelClient *client = sin->st->channel.connection; - RecordChannelClient *record_client = SPICE_CONTAINEROF(client, RecordChannelClient, base); uint32_t read_pos; uint32_t now; uint32_t len; if (!client) return 0; + RecordChannelClient *record_client = RECORD_CHANNEL_CLIENT(client); spice_assert(client->active); if (record_client->write_pos < RECORD_SAMPLES_SIZE / 2) { @@ -1444,14 +1251,17 @@ SPICE_GNUC_VISIBLE uint32_t spice_server_record_get_samples(SpiceRecordInstance len = MIN(record_client->write_pos - record_client->read_pos, bufsize); + // TODO why ?? stream already call if got data +#if 0 if (len < bufsize) { - SndChannel *channel = client->channel; + SndChannel *channel = SND_CHANNEL(red_channel_client_get_channel(RED_CHANNEL_CLIENT(client))); snd_receive(client); if (!channel->connection) { return 0; } len = MIN(record_client->write_pos - record_client->read_pos, bufsize); } +#endif read_pos = record_client->read_pos % RECORD_SAMPLES_SIZE; record_client->read_pos += len; @@ -1467,7 +1277,7 @@ static uint32_t snd_get_best_rate(SndChannelClient *client, uint32_t cap_opus) { int client_can_opus = TRUE; if (client) { - client_can_opus = red_channel_client_test_remote_cap(client->channel_client, cap_opus); + client_can_opus = red_channel_client_test_remote_cap(RED_CHANNEL_CLIENT(client), cap_opus); } if (client_can_opus && snd_codec_is_capable(SPICE_AUDIO_DATA_MODE_OPUS, SND_CODEC_ANY_FREQUENCY)) @@ -1509,52 +1319,79 @@ static void on_new_record_channel(SndChannel *channel, SndChannelClient *snd_cha { spice_assert(snd_channel); - channel->connection = snd_channel ; + channel->connection = snd_channel; if (channel->volume.volume_nchannels) { - snd_set_command(snd_channel, SND_VOLUME_MASK); + snd_set_command(snd_channel, SND_VOLUME_MUTE_MASK); } if (snd_channel->active) { snd_set_command(snd_channel, SND_CTRL_MASK); } } -static void snd_record_cleanup(SndChannelClient *client) +static void +record_channel_client_finalize(GObject *object) { - RecordChannelClient *record_client = SPICE_CONTAINEROF(client, RecordChannelClient, base); + RecordChannelClient *record_client = RECORD_CHANNEL_CLIENT(object); + snd_codec_destroy(&record_client->codec); + + G_OBJECT_CLASS(record_channel_client_parent_class)->finalize(object); +} + +static void +record_channel_client_constructed(GObject *object) +{ + RecordChannelClient *record_client = RECORD_CHANNEL_CLIENT(object); + RedChannel *red_channel = red_channel_client_get_channel(RED_CHANNEL_CLIENT(record_client)); + SndChannel *channel = SND_CHANNEL(red_channel); + + G_OBJECT_CLASS(record_channel_client_parent_class)->constructed(object); + + on_new_record_channel(channel, SND_CHANNEL_CLIENT(record_client)); + if (channel->active) { + snd_record_start(channel); + } + snd_send(SND_CHANNEL_CLIENT(record_client)); } + static void snd_set_record_peer(RedChannel *red_channel, RedClient *client, RedsStream *stream, int migration, int num_common_caps, uint32_t *common_caps, int num_caps, uint32_t *caps) { SndChannel *channel = SND_CHANNEL(red_channel); - RecordChannelClient *record_client; - - snd_disconnect_channel(channel->connection); - - if (!(record_client = (RecordChannelClient *)__new_channel(channel, - sizeof(*record_client), - SPICE_CHANNEL_RECORD, - client, - stream, - migration, - snd_record_send, - snd_record_handle_message, - snd_record_on_message_done, - snd_record_cleanup, - common_caps, num_common_caps, - caps, num_caps))) { - return; + GArray *common_caps_array = NULL, *caps_array = NULL; + + if (channel->connection) { + red_channel_client_disconnect(RED_CHANNEL_CLIENT(channel->connection)); + channel->connection = NULL; } - record_client->mode = SPICE_AUDIO_DATA_MODE_RAW; + if (common_caps) { + common_caps_array = g_array_sized_new(FALSE, FALSE, sizeof (*common_caps), + num_common_caps); + g_array_append_vals(common_caps_array, common_caps, num_common_caps); + } + if (caps) { + caps_array = g_array_sized_new(FALSE, FALSE, sizeof (*caps), num_caps); + g_array_append_vals(caps_array, caps, num_caps); + } - on_new_record_channel(channel, SND_CHANNEL_CLIENT(record_client)); - if (channel->active) { - snd_record_start(channel); + g_initable_new(TYPE_RECORD_CHANNEL_CLIENT, + NULL, NULL, + "channel", channel, + "client", client, + "stream", stream, + "caps", caps_array, + "common-caps", common_caps_array, + NULL); + + if (caps_array) { + g_array_unref(caps_array); + } + if (common_caps_array) { + g_array_unref(common_caps_array); } - snd_record_send(channel->connection); } static void snd_playback_migrate_channel_client(RedChannelClient *rcc) @@ -1567,9 +1404,9 @@ static void snd_playback_migrate_channel_client(RedChannelClient *rcc) spice_debug(NULL); if (channel->connection) { - spice_assert(channel->connection->channel_client == rcc); + spice_assert(RED_CHANNEL_CLIENT(channel->connection) == rcc); snd_set_command(channel->connection, SND_MIGRATE_MASK); - snd_playback_send(channel->connection); + snd_send(channel->connection); } } @@ -1641,8 +1478,13 @@ static void playback_channel_class_init(PlaybackChannelClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS(klass); + RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass); object_class->constructed = playback_channel_constructed; + + channel_class->parser = spice_get_client_channel_parser(SPICE_CHANNEL_PLAYBACK, NULL); + channel_class->handle_parsed = playback_channel_handle_parsed; + channel_class->send_item = playback_channel_send_item; } void snd_attach_playback(RedsState *reds, SpicePlaybackInstance *sin) @@ -1687,8 +1529,13 @@ static void record_channel_class_init(RecordChannelClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS(klass); + RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass); object_class->constructed = record_channel_constructed; + + channel_class->parser = spice_get_client_channel_parser(SPICE_CHANNEL_RECORD, NULL); + channel_class->handle_parsed = record_channel_handle_parsed; + channel_class->send_item = record_channel_send_item; } void snd_attach_record(RedsState *reds, SpiceRecordInstance *sin) @@ -1709,7 +1556,6 @@ static void snd_detach_common(SndChannel *channel) RedsState *reds = red_channel_get_server(RED_CHANNEL(channel)); remove_channel(channel); - snd_disconnect_channel(channel->connection); reds_unregister_channel(reds, RED_CHANNEL(channel)); free(channel->volume.volume); channel->volume.volume = NULL; @@ -1735,9 +1581,10 @@ void snd_set_playback_compression(int on) g_object_get(RED_CHANNEL(now), "channel-type", &type, NULL); if (type == SPICE_CHANNEL_PLAYBACK && now->connection) { PlaybackChannelClient* playback = (PlaybackChannelClient*)now->connection; - int client_can_celt = red_channel_client_test_remote_cap(playback->base.channel_client, + RedChannelClient *rcc = RED_CHANNEL_CLIENT(playback); + int client_can_celt = red_channel_client_test_remote_cap(rcc, SPICE_PLAYBACK_CAP_CELT_0_5_1); - int client_can_opus = red_channel_client_test_remote_cap(playback->base.channel_client, + int client_can_opus = red_channel_client_test_remote_cap(rcc, SPICE_PLAYBACK_CAP_OPUS); int desired_mode = snd_desired_audio_mode(on, now->frequency, client_can_opus, client_can_celt); @@ -1749,10 +1596,31 @@ void snd_set_playback_compression(int on) } } -static void snd_playback_alloc_frames(PlaybackChannelClient *playback) +static void +snd_channel_client_class_init(SndChannelClientClass *self) +{ +} + +static void +snd_channel_client_init(SndChannelClient *self) +{ +} + +static void +playback_channel_client_class_init(PlaybackChannelClientClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + object_class->constructed = playback_channel_client_constructed; + object_class->finalize = playback_channel_client_finalize; +} + +static void +playback_channel_client_init(PlaybackChannelClient *playback) { int i; + playback->mode = SPICE_AUDIO_DATA_MODE_RAW; + playback->frames = spice_new0(AudioFrameContainer, 1); playback->frames->refs = 1; for (i = 0; i < NUM_AUDIO_FRAMES; ++i) { @@ -1760,3 +1628,17 @@ static void snd_playback_alloc_frames(PlaybackChannelClient *playback) snd_playback_free_frame(playback, &playback->frames->items[i]); } } + +static void +record_channel_client_class_init(RecordChannelClientClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + object_class->constructed = record_channel_client_constructed; + object_class->finalize = record_channel_client_finalize; +} + +static void +record_channel_client_init(RecordChannelClient *record) +{ + record->mode = SPICE_AUDIO_DATA_MODE_RAW; +} -- git-series 0.9.1 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel