2 * Copyright (C) 2010 Red Hat, Inc.
4 * maintained by Gerd Hoffmann <kraxel@redhat.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 or
9 * (at your option) version 3 of the License.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include "qemu/osdep.h"
22 #include "qemu/host-utils.h"
23 #include "qemu/module.h"
24 #include "qemu/error-report.h"
25 #include "qemu/timer.h"
26 #include "ui/qemu-spice.h"
28 #define AUDIO_CAP "spice"
30 #include "audio_int.h"
32 #if SPICE_INTERFACE_PLAYBACK_MAJOR > 1 || SPICE_INTERFACE_PLAYBACK_MINOR >= 3
33 #define LINE_OUT_SAMPLES (480 * 4)
35 #define LINE_OUT_SAMPLES (256 * 4)
38 #if SPICE_INTERFACE_RECORD_MAJOR > 2 || SPICE_INTERFACE_RECORD_MINOR >= 3
39 #define LINE_IN_SAMPLES (480 * 4)
41 #define LINE_IN_SAMPLES (256 * 4)
44 typedef struct SpiceRateCtl
{
49 typedef struct SpiceVoiceOut
{
51 SpicePlaybackInstance sin
;
59 typedef struct SpiceVoiceIn
{
61 SpiceRecordInstance sin
;
64 uint32_t samples
[LINE_IN_SAMPLES
];
67 static const SpicePlaybackInterface playback_sif
= {
68 .base
.type
= SPICE_INTERFACE_PLAYBACK
,
69 .base
.description
= "playback",
70 .base
.major_version
= SPICE_INTERFACE_PLAYBACK_MAJOR
,
71 .base
.minor_version
= SPICE_INTERFACE_PLAYBACK_MINOR
,
74 static const SpiceRecordInterface record_sif
= {
75 .base
.type
= SPICE_INTERFACE_RECORD
,
76 .base
.description
= "record",
77 .base
.major_version
= SPICE_INTERFACE_RECORD_MAJOR
,
78 .base
.minor_version
= SPICE_INTERFACE_RECORD_MINOR
,
81 static void *spice_audio_init(Audiodev
*dev
)
86 return &spice_audio_init
;
89 static void spice_audio_fini (void *opaque
)
94 static void rate_start (SpiceRateCtl
*rate
)
96 memset (rate
, 0, sizeof (*rate
));
97 rate
->start_ticks
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
100 static int rate_get_samples (struct audio_pcm_info
*info
, SpiceRateCtl
*rate
)
107 now
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
108 ticks
= now
- rate
->start_ticks
;
109 bytes
= muldiv64(ticks
, info
->bytes_per_second
, NANOSECONDS_PER_SECOND
);
110 samples
= (bytes
- rate
->bytes_sent
) >> info
->shift
;
111 if (samples
< 0 || samples
> 65536) {
112 error_report("Resetting rate control (%" PRId64
" samples)", samples
);
116 rate
->bytes_sent
+= samples
<< info
->shift
;
122 static int line_out_init(HWVoiceOut
*hw
, struct audsettings
*as
,
125 SpiceVoiceOut
*out
= container_of (hw
, SpiceVoiceOut
, hw
);
126 struct audsettings settings
;
128 #if SPICE_INTERFACE_PLAYBACK_MAJOR > 1 || SPICE_INTERFACE_PLAYBACK_MINOR >= 3
129 settings
.freq
= spice_server_get_best_playback_rate(NULL
);
131 settings
.freq
= SPICE_INTERFACE_PLAYBACK_FREQ
;
133 settings
.nchannels
= SPICE_INTERFACE_PLAYBACK_CHAN
;
134 settings
.fmt
= AUDIO_FORMAT_S16
;
135 settings
.endianness
= AUDIO_HOST_ENDIANNESS
;
137 audio_pcm_init_info (&hw
->info
, &settings
);
138 hw
->samples
= LINE_OUT_SAMPLES
;
141 out
->sin
.base
.sif
= &playback_sif
.base
;
142 qemu_spice_add_interface (&out
->sin
.base
);
143 #if SPICE_INTERFACE_PLAYBACK_MAJOR > 1 || SPICE_INTERFACE_PLAYBACK_MINOR >= 3
144 spice_server_set_playback_rate(&out
->sin
, settings
.freq
);
149 static void line_out_fini (HWVoiceOut
*hw
)
151 SpiceVoiceOut
*out
= container_of (hw
, SpiceVoiceOut
, hw
);
153 spice_server_remove_interface (&out
->sin
.base
);
156 static int line_out_run (HWVoiceOut
*hw
, int live
)
158 SpiceVoiceOut
*out
= container_of (hw
, SpiceVoiceOut
, hw
);
166 decr
= rate_get_samples (&hw
->info
, &out
->rate
);
167 decr
= audio_MIN (live
, decr
);
172 int left_till_end_samples
= hw
->samples
- rpos
;
173 int len
= audio_MIN (samples
, left_till_end_samples
);
176 spice_server_playback_get_buffer (&out
->sin
, &out
->frame
, &out
->fsize
);
177 out
->fpos
= out
->frame
;
180 len
= audio_MIN (len
, out
->fsize
);
181 hw
->clip (out
->fpos
, hw
->mix_buf
+ rpos
, len
);
184 if (out
->fsize
== 0) {
185 spice_server_playback_put_samples (&out
->sin
, out
->frame
);
186 out
->frame
= out
->fpos
= NULL
;
189 rpos
= (rpos
+ len
) % hw
->samples
;
196 static int line_out_write (SWVoiceOut
*sw
, void *buf
, int len
)
198 return audio_pcm_sw_write (sw
, buf
, len
);
201 static int line_out_ctl (HWVoiceOut
*hw
, int cmd
, ...)
203 SpiceVoiceOut
*out
= container_of (hw
, SpiceVoiceOut
, hw
);
211 rate_start (&out
->rate
);
212 spice_server_playback_start (&out
->sin
);
220 memset (out
->fpos
, 0, out
->fsize
<< 2);
221 spice_server_playback_put_samples (&out
->sin
, out
->frame
);
222 out
->frame
= out
->fpos
= NULL
;
224 spice_server_playback_stop (&out
->sin
);
228 #if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2))
234 sw
= va_arg (ap
, SWVoiceOut
*);
237 vol
[0] = sw
->vol
.l
/ ((1ULL << 16) + 1);
238 vol
[1] = sw
->vol
.r
/ ((1ULL << 16) + 1);
239 spice_server_playback_set_volume (&out
->sin
, 2, vol
);
240 spice_server_playback_set_mute (&out
->sin
, sw
->vol
.mute
);
251 static int line_in_init(HWVoiceIn
*hw
, struct audsettings
*as
, void *drv_opaque
)
253 SpiceVoiceIn
*in
= container_of (hw
, SpiceVoiceIn
, hw
);
254 struct audsettings settings
;
256 #if SPICE_INTERFACE_RECORD_MAJOR > 2 || SPICE_INTERFACE_RECORD_MINOR >= 3
257 settings
.freq
= spice_server_get_best_record_rate(NULL
);
259 settings
.freq
= SPICE_INTERFACE_RECORD_FREQ
;
261 settings
.nchannels
= SPICE_INTERFACE_RECORD_CHAN
;
262 settings
.fmt
= AUDIO_FORMAT_S16
;
263 settings
.endianness
= AUDIO_HOST_ENDIANNESS
;
265 audio_pcm_init_info (&hw
->info
, &settings
);
266 hw
->samples
= LINE_IN_SAMPLES
;
269 in
->sin
.base
.sif
= &record_sif
.base
;
270 qemu_spice_add_interface (&in
->sin
.base
);
271 #if SPICE_INTERFACE_RECORD_MAJOR > 2 || SPICE_INTERFACE_RECORD_MINOR >= 3
272 spice_server_set_record_rate(&in
->sin
, settings
.freq
);
277 static void line_in_fini (HWVoiceIn
*hw
)
279 SpiceVoiceIn
*in
= container_of (hw
, SpiceVoiceIn
, hw
);
281 spice_server_remove_interface (&in
->sin
.base
);
284 static int line_in_run (HWVoiceIn
*hw
)
286 SpiceVoiceIn
*in
= container_of (hw
, SpiceVoiceIn
, hw
);
291 const uint32_t *samples
;
293 if (!(num_samples
= hw
->samples
- audio_pcm_hw_get_live_in (hw
))) {
297 delta_samp
= rate_get_samples (&hw
->info
, &in
->rate
);
298 num_samples
= audio_MIN (num_samples
, delta_samp
);
300 ready
= spice_server_record_get_samples (&in
->sin
, in
->samples
, num_samples
);
301 samples
= in
->samples
;
303 static const uint32_t silence
[LINE_IN_SAMPLES
];
305 ready
= LINE_IN_SAMPLES
;
308 num_samples
= audio_MIN (ready
, num_samples
);
310 if (hw
->wpos
+ num_samples
> hw
->samples
) {
311 len
[0] = hw
->samples
- hw
->wpos
;
312 len
[1] = num_samples
- len
[0];
314 len
[0] = num_samples
;
318 hw
->conv (hw
->conv_buf
+ hw
->wpos
, samples
, len
[0]);
321 hw
->conv (hw
->conv_buf
, samples
+ len
[0], len
[1]);
324 hw
->wpos
= (hw
->wpos
+ num_samples
) % hw
->samples
;
329 static int line_in_read (SWVoiceIn
*sw
, void *buf
, int size
)
331 return audio_pcm_sw_read (sw
, buf
, size
);
334 static int line_in_ctl (HWVoiceIn
*hw
, int cmd
, ...)
336 SpiceVoiceIn
*in
= container_of (hw
, SpiceVoiceIn
, hw
);
344 rate_start (&in
->rate
);
345 spice_server_record_start (&in
->sin
);
352 spice_server_record_stop (&in
->sin
);
356 #if ((SPICE_INTERFACE_RECORD_MAJOR >= 2) && (SPICE_INTERFACE_RECORD_MINOR >= 2))
362 sw
= va_arg (ap
, SWVoiceIn
*);
365 vol
[0] = sw
->vol
.l
/ ((1ULL << 16) + 1);
366 vol
[1] = sw
->vol
.r
/ ((1ULL << 16) + 1);
367 spice_server_record_set_volume (&in
->sin
, 2, vol
);
368 spice_server_record_set_mute (&in
->sin
, sw
->vol
.mute
);
377 static struct audio_pcm_ops audio_callbacks
= {
378 .init_out
= line_out_init
,
379 .fini_out
= line_out_fini
,
380 .run_out
= line_out_run
,
381 .write
= line_out_write
,
382 .ctl_out
= line_out_ctl
,
384 .init_in
= line_in_init
,
385 .fini_in
= line_in_fini
,
386 .run_in
= line_in_run
,
387 .read
= line_in_read
,
388 .ctl_in
= line_in_ctl
,
391 static struct audio_driver spice_audio_driver
= {
393 .descr
= "spice audio driver",
394 .init
= spice_audio_init
,
395 .fini
= spice_audio_fini
,
396 .pcm_ops
= &audio_callbacks
,
399 .voice_size_out
= sizeof (SpiceVoiceOut
),
400 .voice_size_in
= sizeof (SpiceVoiceIn
),
401 #if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2))
402 .ctl_caps
= VOICE_VOLUME_CAP
406 void qemu_spice_audio_init (void)
408 spice_audio_driver
.can_be_default
= 1;
411 static void register_audio_spice(void)
413 audio_driver_register(&spice_audio_driver
);
415 type_init(register_audio_spice
);