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
);
211 static int line_in_init (HWVoiceIn
*hw
, struct audsettings
*as
)
213 SpiceVoiceIn
*in
= container_of (hw
, SpiceVoiceIn
, hw
);
214 struct audsettings settings
;
216 settings
.freq
= SPICE_INTERFACE_RECORD_FREQ
;
217 settings
.nchannels
= SPICE_INTERFACE_RECORD_CHAN
;
218 settings
.fmt
= AUD_FMT_S16
;
219 settings
.endianness
= AUDIO_HOST_ENDIANNESS
;
221 audio_pcm_init_info (&hw
->info
, &settings
);
222 hw
->samples
= LINE_IN_SAMPLES
;
225 in
->sin
.base
.sif
= &record_sif
.base
;
226 qemu_spice_add_interface (&in
->sin
.base
);
230 static void line_in_fini (HWVoiceIn
*hw
)
232 SpiceVoiceIn
*in
= container_of (hw
, SpiceVoiceIn
, hw
);
234 spice_server_remove_interface (&in
->sin
.base
);
237 static int line_in_run (HWVoiceIn
*hw
)
239 SpiceVoiceIn
*in
= container_of (hw
, SpiceVoiceIn
, hw
);
244 const uint32_t *samples
;
246 if (!(num_samples
= hw
->samples
- audio_pcm_hw_get_live_in (hw
))) {
250 delta_samp
= rate_get_samples (&hw
->info
, &in
->rate
);
251 num_samples
= audio_MIN (num_samples
, delta_samp
);
253 ready
= spice_server_record_get_samples (&in
->sin
, in
->samples
, num_samples
);
254 samples
= in
->samples
;
256 static const uint32_t silence
[LINE_IN_SAMPLES
];
258 ready
= LINE_IN_SAMPLES
;
261 num_samples
= audio_MIN (ready
, num_samples
);
263 if (hw
->wpos
+ num_samples
> hw
->samples
) {
264 len
[0] = hw
->samples
- hw
->wpos
;
265 len
[1] = num_samples
- len
[0];
267 len
[0] = num_samples
;
271 hw
->conv (hw
->conv_buf
+ hw
->wpos
, samples
, len
[0]);
274 hw
->conv (hw
->conv_buf
, samples
+ len
[0], len
[1]);
277 hw
->wpos
= (hw
->wpos
+ num_samples
) % hw
->samples
;
282 static int line_in_read (SWVoiceIn
*sw
, void *buf
, int size
)
284 return audio_pcm_sw_read (sw
, buf
, size
);
287 static int line_in_ctl (HWVoiceIn
*hw
, int cmd
, ...)
289 SpiceVoiceIn
*in
= container_of (hw
, SpiceVoiceIn
, hw
);
297 rate_start (&in
->rate
);
298 spice_server_record_start (&in
->sin
);
305 spice_server_record_stop (&in
->sin
);
311 static struct audio_option audio_options
[] = {
312 { /* end of list */ },
315 static struct audio_pcm_ops audio_callbacks
= {
316 .init_out
= line_out_init
,
317 .fini_out
= line_out_fini
,
318 .run_out
= line_out_run
,
319 .write
= line_out_write
,
320 .ctl_out
= line_out_ctl
,
322 .init_in
= line_in_init
,
323 .fini_in
= line_in_fini
,
324 .run_in
= line_in_run
,
325 .read
= line_in_read
,
326 .ctl_in
= line_in_ctl
,
329 struct audio_driver spice_audio_driver
= {
331 .descr
= "spice audio driver",
332 .options
= audio_options
,
333 .init
= spice_audio_init
,
334 .fini
= spice_audio_fini
,
335 .pcm_ops
= &audio_callbacks
,
338 .voice_size_out
= sizeof (SpiceVoiceOut
),
339 .voice_size_in
= sizeof (SpiceVoiceIn
),
342 void qemu_spice_audio_init (void)
344 spice_audio_driver
.can_be_default
= 1;