summaryrefslogtreecommitdiffstats
path: root/server/snd_worker.c
diff options
context:
space:
mode:
Diffstat (limited to 'server/snd_worker.c')
-rw-r--r--server/snd_worker.c172
1 files changed, 170 insertions, 2 deletions
diff --git a/server/snd_worker.c b/server/snd_worker.c
index 8da11e1a..182eb3c2 100644
--- a/server/snd_worker.c
+++ b/server/snd_worker.c
@@ -52,20 +52,24 @@ enum PlaybackeCommand {
SND_PLAYBACK_MODE,
SND_PLAYBACK_CTRL,
SND_PLAYBACK_PCM,
+ SND_PLAYBACK_VOLUME,
};
enum RecordCommand {
SND_RECORD_MIGRATE,
SND_RECORD_CTRL,
+ SND_RECORD_VOLUME,
};
#define SND_PLAYBACK_MIGRATE_MASK (1 << SND_PLAYBACK_MIGRATE)
#define SND_PLAYBACK_MODE_MASK (1 << SND_PLAYBACK_MODE)
#define SND_PLAYBACK_CTRL_MASK (1 << SND_PLAYBACK_CTRL)
#define SND_PLAYBACK_PCM_MASK (1 << SND_PLAYBACK_PCM)
+#define SND_PLAYBACK_VOLUME_MASK (1 << SND_PLAYBACK_VOLUME)
#define SND_RECORD_MIGRATE_MASK (1 << SND_RECORD_MIGRATE)
#define SND_RECORD_CTRL_MASK (1 << SND_RECORD_CTRL)
+#define SND_RECORD_VOLUME_MASK (1 << SND_RECORD_VOLUME)
typedef struct SndChannel SndChannel;
typedef void (*send_messages_proc)(void *in_channel);
@@ -141,14 +145,22 @@ struct SndWorker {
int active;
};
+typedef struct SpiceVolumeState {
+ uint8_t volume_nchannels;
+ uint16_t *volume;
+ int mute;
+} SpiceVolumeState;
+
struct SpicePlaybackState {
struct SndWorker worker;
SpicePlaybackInstance *sin;
+ SpiceVolumeState volume;
};
struct SpiceRecordState {
struct SndWorker worker;
SpiceRecordInstance *sin;
+ SpiceVolumeState volume;
};
#define RECORD_MIG_VERSION 1
@@ -508,6 +520,54 @@ static int snd_playback_send_migrate(PlaybackChannel *channel)
return snd_begin_send_message((SndChannel *)channel);
}
+static int snd_send_volume(SndChannel *channel, SpiceVolumeState *st, int msg)
+{
+ SpiceMsgAudioVolume *vol;
+ uint8_t c;
+
+ vol = alloca(sizeof (SpiceMsgAudioVolume) +
+ st->volume_nchannels * sizeof (uint16_t));
+ if (!snd_reset_send_data(channel, msg)) {
+ return FALSE;
+ }
+ vol->nchannels = st->volume_nchannels;
+ for (c = 0; c < st->volume_nchannels; ++c) {
+ vol->volume[c] = st->volume[c];
+ }
+ spice_marshall_SpiceMsgAudioVolume(channel->send_data.marshaller, vol);
+
+ return snd_begin_send_message(channel);
+}
+
+static int snd_playback_send_volume(PlaybackChannel *playback_channel)
+{
+ SndChannel *channel = &playback_channel->base;
+ SpicePlaybackState *st = SPICE_CONTAINEROF(channel->worker, SpicePlaybackState, worker);
+
+ return snd_send_volume(channel, &st->volume, SPICE_MSG_PLAYBACK_VOLUME);
+}
+
+static int snd_send_mute(SndChannel *channel, SpiceVolumeState *st, int msg)
+{
+ SpiceMsgAudioMute mute;
+
+ if (!snd_reset_send_data(channel, msg)) {
+ return FALSE;
+ }
+ mute.mute = st->mute;
+ spice_marshall_SpiceMsgAudioMute(channel->send_data.marshaller, &mute);
+
+ return snd_begin_send_message(channel);
+}
+
+static int snd_playback_send_mute(PlaybackChannel *playback_channel)
+{
+ SndChannel *channel = &playback_channel->base;
+ SpicePlaybackState *st = SPICE_CONTAINEROF(channel->worker, SpicePlaybackState, worker);
+
+ return snd_send_mute(channel, &st->volume, SPICE_MSG_PLAYBACK_MUTE);
+}
+
static int snd_playback_send_start(PlaybackChannel *playback_channel)
{
SndChannel *channel = (SndChannel *)playback_channel;
@@ -589,6 +649,22 @@ static int snd_record_send_ctl(RecordChannel *record_channel)
}
}
+static int snd_record_send_volume(RecordChannel *record_channel)
+{
+ SndChannel *channel = &record_channel->base;
+ SpiceRecordState *st = SPICE_CONTAINEROF(channel->worker, SpiceRecordState, worker);
+
+ return snd_send_volume(channel, &st->volume, SPICE_MSG_RECORD_VOLUME);
+}
+
+static int snd_record_send_mute(RecordChannel *record_channel)
+{
+ SndChannel *channel = &record_channel->base;
+ SpiceRecordState *st = SPICE_CONTAINEROF(channel->worker, SpiceRecordState, worker);
+
+ return snd_send_mute(channel, &st->volume, SPICE_MSG_RECORD_MUTE);
+}
+
static int snd_record_send_migrate(RecordChannel *record_channel)
{
SndChannel *channel = (SndChannel *)record_channel;
@@ -704,6 +780,13 @@ static void snd_playback_send(void* data)
}
channel->command &= ~SND_PLAYBACK_CTRL_MASK;
}
+ if (channel->command & SND_PLAYBACK_VOLUME_MASK) {
+ if (!snd_playback_send_volume(playback_channel) ||
+ !snd_playback_send_mute(playback_channel)) {
+ return;
+ }
+ channel->command &= ~SND_PLAYBACK_VOLUME_MASK;
+ }
if (channel->command & SND_PLAYBACK_MIGRATE_MASK) {
if (!snd_playback_send_migrate(playback_channel)) {
return;
@@ -729,6 +812,13 @@ static void snd_record_send(void* data)
}
channel->command &= ~SND_RECORD_CTRL_MASK;
}
+ if (channel->command & SND_RECORD_VOLUME_MASK) {
+ if (!snd_record_send_volume(record_channel) ||
+ !snd_record_send_mute(record_channel)) {
+ return;
+ }
+ channel->command &= ~SND_RECORD_VOLUME_MASK;
+ }
if (channel->command & SND_RECORD_MIGRATE_MASK) {
if (!snd_record_send_migrate(record_channel)) {
return;
@@ -823,6 +913,38 @@ static void snd_set_command(SndChannel *channel, uint32_t command)
channel->command |= command;
}
+__visible__ void spice_server_playback_set_volume(SpicePlaybackInstance *sin,
+ uint8_t nchannels,
+ uint16_t *volume)
+{
+ SpiceVolumeState *st = &sin->st->volume;
+ SndChannel *channel = sin->st->worker.connection;
+ PlaybackChannel *playback_channel = SPICE_CONTAINEROF(channel, PlaybackChannel, base);
+
+ st->volume_nchannels = nchannels;
+ free(st->volume);
+ st->volume = spice_memdup(volume, sizeof(uint16_t) * nchannels);
+
+ if (!channel)
+ return;
+
+ snd_playback_send_volume(playback_channel);
+}
+
+__visible__ void spice_server_playback_set_mute(SpicePlaybackInstance *sin, uint8_t mute)
+{
+ SpiceVolumeState *st = &sin->st->volume;
+ SndChannel *channel = sin->st->worker.connection;
+ PlaybackChannel *playback_channel = SPICE_CONTAINEROF(channel, PlaybackChannel, base);
+
+ st->mute = mute;
+
+ if (!channel)
+ return;
+
+ snd_playback_send_mute(playback_channel);
+}
+
__visible__ void spice_server_playback_start(SpicePlaybackInstance *sin)
{
SndChannel *channel = sin->st->worker.connection;
@@ -919,6 +1041,7 @@ static void on_new_playback_channel(SndWorker *worker)
if (!playback_channel->base.migrate && playback_channel->base.active) {
snd_set_command((SndChannel *)playback_channel, SND_PLAYBACK_CTRL_MASK);
}
+ snd_set_command((SndChannel *)playback_channel, SND_PLAYBACK_VOLUME_MASK);
if (playback_channel->base.active) {
reds_disable_mm_timer();
}
@@ -1006,6 +1129,38 @@ static void snd_record_migrate(Channel *channel)
}
}
+__visible__ void spice_server_record_set_volume(SpiceRecordInstance *sin,
+ uint8_t nchannels,
+ uint16_t *volume)
+{
+ SpiceVolumeState *st = &sin->st->volume;
+ SndChannel *channel = sin->st->worker.connection;
+ RecordChannel *record_channel = SPICE_CONTAINEROF(channel, RecordChannel, base);
+
+ st->volume_nchannels = nchannels;
+ free(st->volume);
+ st->volume = spice_memdup(volume, sizeof(uint16_t) * nchannels);
+
+ if (!channel)
+ return;
+
+ snd_record_send_volume(record_channel);
+}
+
+__visible__ void spice_server_record_set_mute(SpiceRecordInstance *sin, uint8_t mute)
+{
+ SpiceVolumeState *st = &sin->st->volume;
+ SndChannel *channel = sin->st->worker.connection;
+ RecordChannel *record_channel = SPICE_CONTAINEROF(channel, RecordChannel, base);
+
+ st->mute = mute;
+
+ if (!channel)
+ return;
+
+ snd_record_send_mute(record_channel);
+}
+
__visible__ void spice_server_record_start(SpiceRecordInstance *sin)
{
SndChannel *channel = sin->st->worker.connection;
@@ -1087,6 +1242,7 @@ static void on_new_record_channel(SndWorker *worker)
RecordChannel *record_channel = (RecordChannel *)worker->connection;
ASSERT(record_channel);
+ snd_set_command((SndChannel *)record_channel, SND_RECORD_VOLUME_MASK);
if (!record_channel->base.migrate) {
if (record_channel->base.active) {
snd_set_command((SndChannel *)record_channel, SND_RECORD_CTRL_MASK);
@@ -1242,16 +1398,28 @@ static void snd_detach_common(SndWorker *worker)
reds_channel_dispose(&worker->base);
}
+static void spice_playback_state_free(SpicePlaybackState *st)
+{
+ free(st->volume.volume);
+ free(st);
+}
+
void snd_detach_playback(SpicePlaybackInstance *sin)
{
snd_detach_common(&sin->st->worker);
- free(sin->st);
+ spice_playback_state_free(sin->st);
+}
+
+static void spice_record_state_free(SpiceRecordState *st)
+{
+ free(st->volume.volume);
+ free(st);
}
void snd_detach_record(SpiceRecordInstance *sin)
{
snd_detach_common(&sin->st->worker);
- free(sin->st);
+ spice_record_state_free(sin->st);
}
void snd_set_playback_compression(int on)