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/>.
21 #include "qemu/timer.h"
22 #include "ui/qemu-spice.h"
24 #define AUDIO_CAP "spice"
26 #include "audio_int.h"
28 #define LINE_IN_SAMPLES 1024
29 #define LINE_OUT_SAMPLES 1024
31 typedef struct SpiceRateCtl
{
36 typedef struct SpiceVoiceOut
{
38 SpicePlaybackInstance sin
;
46 typedef struct SpiceVoiceIn
{
48 SpiceRecordInstance sin
;
51 uint32_t samples
[LINE_IN_SAMPLES
];
54 static const SpicePlaybackInterface playback_sif
= {
55 .base
.type
= SPICE_INTERFACE_PLAYBACK
,
56 .base
.description
= "playback",
57 .base
.major_version
= SPICE_INTERFACE_PLAYBACK_MAJOR
,
58 .base
.minor_version
= SPICE_INTERFACE_PLAYBACK_MINOR
,
61 static const SpiceRecordInterface record_sif
= {
62 .base
.type
= SPICE_INTERFACE_RECORD
,
63 .base
.description
= "record",
64 .base
.major_version
= SPICE_INTERFACE_RECORD_MAJOR
,
65 .base
.minor_version
= SPICE_INTERFACE_RECORD_MINOR
,
68 static void *spice_audio_init (void)
73 return &spice_audio_init
;
76 static void spice_audio_fini (void *opaque
)
81 static void rate_start (SpiceRateCtl
*rate
)
83 memset (rate
, 0, sizeof (*rate
));
84 rate
->start_ticks
= qemu_get_clock_ns (vm_clock
);
87 static int rate_get_samples (struct audio_pcm_info
*info
, SpiceRateCtl
*rate
)
94 now
= qemu_get_clock_ns (vm_clock
);
95 ticks
= now
- rate
->start_ticks
;
96 bytes
= muldiv64 (ticks
, info
->bytes_per_second
, get_ticks_per_sec ());
97 samples
= (bytes
- rate
->bytes_sent
) >> info
->shift
;
98 if (samples
< 0 || samples
> 65536) {
99 fprintf (stderr
, "Resetting rate control (%" PRId64
" samples)\n", samples
);
103 rate
->bytes_sent
+= samples
<< info
->shift
;
109 static int line_out_init (HWVoiceOut
*hw
, struct audsettings
*as
)
111 SpiceVoiceOut
*out
= container_of (hw
, SpiceVoiceOut
, hw
);
112 struct audsettings settings
;
114 settings
.freq
= SPICE_INTERFACE_PLAYBACK_FREQ
;
115 settings
.nchannels
= SPICE_INTERFACE_PLAYBACK_CHAN
;
116 settings
.fmt
= AUD_FMT_S16
;
117 settings
.endianness
= AUDIO_HOST_ENDIANNESS
;
119 audio_pcm_init_info (&hw
->info
, &settings
);
120 hw
->samples
= LINE_OUT_SAMPLES
;
123 out
->sin
.base
.sif
= &playback_sif
.base
;
124 qemu_spice_add_interface (&out
->sin
.base
);
128 static void line_out_fini (HWVoiceOut
*hw
)
130 SpiceVoiceOut
*out
= container_of (hw
, SpiceVoiceOut
, hw
);
132 spice_server_remove_interface (&out
->sin
.base
);
135 static int line_out_run (HWVoiceOut
*hw
, int live
)
137 SpiceVoiceOut
*out
= container_of (hw
, SpiceVoiceOut
, hw
);
145 decr
= rate_get_samples (&hw
->info
, &out
->rate
);
146 decr
= audio_MIN (live
, decr
);
151 int left_till_end_samples
= hw
->samples
- rpos
;
152 int len
= audio_MIN (samples
, left_till_end_samples
);
155 spice_server_playback_get_buffer (&out
->sin
, &out
->frame
, &out
->fsize
);
156 out
->fpos
= out
->frame
;
159 len
= audio_MIN (len
, out
->fsize
);
160 hw
->clip (out
->fpos
, hw
->mix_buf
+ rpos
, len
);
163 if (out
->fsize
== 0) {
164 spice_server_playback_put_samples (&out
->sin
, out
->frame
);
165 out
->frame
= out
->fpos
= NULL
;
168 rpos
= (rpos
+ len
) % hw
->samples
;
175 static int line_out_write (SWVoiceOut
*sw
, void *buf
, int len
)
177 return audio_pcm_sw_write (sw
, buf
, len
);
180 static int line_out_ctl (HWVoiceOut
*hw
, int cmd
, ...)
182 SpiceVoiceOut
*out
= container_of (hw
, SpiceVoiceOut
, hw
);
190 rate_start (&out
->rate
);
191 spice_server_playback_start (&out
->sin
);
199 memset (out
->fpos
, 0, out
->fsize
<< 2);
200 spice_server_playback_put_samples (&out
->sin
, out
->frame
);
201 out
->frame
= out
->fpos
= NULL
;
203 spice_server_playback_stop (&out
->sin
);
207 #if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2))
213 sw
= va_arg (ap
, SWVoiceOut
*);
216 vol
[0] = sw
->vol
.l
/ ((1ULL << 16) + 1);
217 vol
[1] = sw
->vol
.r
/ ((1ULL << 16) + 1);
218 spice_server_playback_set_volume (&out
->sin
, 2, vol
);
219 spice_server_playback_set_mute (&out
->sin
, sw
->vol
.mute
);
230 static int line_in_init (HWVoiceIn
*hw
, struct audsettings
*as
)
232 SpiceVoiceIn
*in
= container_of (hw
, SpiceVoiceIn
, hw
);
233 struct audsettings settings
;
235 settings
.freq
= SPICE_INTERFACE_RECORD_FREQ
;
236 settings
.nchannels
= SPICE_INTERFACE_RECORD_CHAN
;
237 settings
.fmt
= AUD_FMT_S16
;
238 settings
.endianness
= AUDIO_HOST_ENDIANNESS
;
240 audio_pcm_init_info (&hw
->info
, &settings
);
241 hw
->samples
= LINE_IN_SAMPLES
;
244 in
->sin
.base
.sif
= &record_sif
.base
;
245 qemu_spice_add_interface (&in
->sin
.base
);
249 static void line_in_fini (HWVoiceIn
*hw
)
251 SpiceVoiceIn
*in
= container_of (hw
, SpiceVoiceIn
, hw
);
253 spice_server_remove_interface (&in
->sin
.base
);
256 static int line_in_run (HWVoiceIn
*hw
)
258 SpiceVoiceIn
*in
= container_of (hw
, SpiceVoiceIn
, hw
);
263 const uint32_t *samples
;
265 if (!(num_samples
= hw
->samples
- audio_pcm_hw_get_live_in (hw
))) {
269 delta_samp
= rate_get_samples (&hw
->info
, &in
->rate
);
270 num_samples
= audio_MIN (num_samples
, delta_samp
);
272 ready
= spice_server_record_get_samples (&in
->sin
, in
->samples
, num_samples
);
273 samples
= in
->samples
;
275 static const uint32_t silence
[LINE_IN_SAMPLES
];
277 ready
= LINE_IN_SAMPLES
;
280 num_samples
= audio_MIN (ready
, num_samples
);
282 if (hw
->wpos
+ num_samples
> hw
->samples
) {
283 len
[0] = hw
->samples
- hw
->wpos
;
284 len
[1] = num_samples
- len
[0];
286 len
[0] = num_samples
;
290 hw
->conv (hw
->conv_buf
+ hw
->wpos
, samples
, len
[0]);
293 hw
->conv (hw
->conv_buf
, samples
+ len
[0], len
[1]);
296 hw
->wpos
= (hw
->wpos
+ num_samples
) % hw
->samples
;
301 static int line_in_read (SWVoiceIn
*sw
, void *buf
, int size
)
303 return audio_pcm_sw_read (sw
, buf
, size
);
306 static int line_in_ctl (HWVoiceIn
*hw
, int cmd
, ...)
308 SpiceVoiceIn
*in
= container_of (hw
, SpiceVoiceIn
, hw
);
316 rate_start (&in
->rate
);
317 spice_server_record_start (&in
->sin
);
324 spice_server_record_stop (&in
->sin
);
328 #if ((SPICE_INTERFACE_RECORD_MAJOR >= 2) && (SPICE_INTERFACE_RECORD_MINOR >= 2))
334 sw
= va_arg (ap
, SWVoiceIn
*);
337 vol
[0] = sw
->vol
.l
/ ((1ULL << 16) + 1);
338 vol
[1] = sw
->vol
.r
/ ((1ULL << 16) + 1);
339 spice_server_record_set_volume (&in
->sin
, 2, vol
);
340 spice_server_record_set_mute (&in
->sin
, sw
->vol
.mute
);
349 static struct audio_option audio_options
[] = {
350 { /* end of list */ },
353 static struct audio_pcm_ops audio_callbacks
= {
354 .init_out
= line_out_init
,
355 .fini_out
= line_out_fini
,
356 .run_out
= line_out_run
,
357 .write
= line_out_write
,
358 .ctl_out
= line_out_ctl
,
360 .init_in
= line_in_init
,
361 .fini_in
= line_in_fini
,
362 .run_in
= line_in_run
,
363 .read
= line_in_read
,
364 .ctl_in
= line_in_ctl
,
367 struct audio_driver spice_audio_driver
= {
369 .descr
= "spice audio driver",
370 .options
= audio_options
,
371 .init
= spice_audio_init
,
372 .fini
= spice_audio_fini
,
373 .pcm_ops
= &audio_callbacks
,
376 .voice_size_out
= sizeof (SpiceVoiceOut
),
377 .voice_size_in
= sizeof (SpiceVoiceIn
),
378 #if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2))
379 .ctl_caps
= VOICE_VOLUME_CAP
383 void qemu_spice_audio_init (void)
385 spice_audio_driver
.can_be_default
= 1;