root / audio / spiceaudio.c @ c09015dd
History | View | Annotate | Download (9 kB)
1 | cf2c1839 | Gerd Hoffmann | /*
|
---|---|---|---|
2 | cf2c1839 | Gerd Hoffmann | * Copyright (C) 2010 Red Hat, Inc.
|
3 | cf2c1839 | Gerd Hoffmann | *
|
4 | cf2c1839 | Gerd Hoffmann | * maintained by Gerd Hoffmann <kraxel@redhat.com>
|
5 | cf2c1839 | Gerd Hoffmann | *
|
6 | cf2c1839 | Gerd Hoffmann | * This program is free software; you can redistribute it and/or
|
7 | cf2c1839 | Gerd Hoffmann | * modify it under the terms of the GNU General Public License as
|
8 | cf2c1839 | Gerd Hoffmann | * published by the Free Software Foundation; either version 2 or
|
9 | cf2c1839 | Gerd Hoffmann | * (at your option) version 3 of the License.
|
10 | cf2c1839 | Gerd Hoffmann | *
|
11 | cf2c1839 | Gerd Hoffmann | * This program is distributed in the hope that it will be useful,
|
12 | cf2c1839 | Gerd Hoffmann | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 | cf2c1839 | Gerd Hoffmann | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 | cf2c1839 | Gerd Hoffmann | * GNU General Public License for more details.
|
15 | cf2c1839 | Gerd Hoffmann | *
|
16 | cf2c1839 | Gerd Hoffmann | * You should have received a copy of the GNU General Public License
|
17 | cf2c1839 | Gerd Hoffmann | * along with this program; if not, see <http://www.gnu.org/licenses/>.
|
18 | cf2c1839 | Gerd Hoffmann | */
|
19 | cf2c1839 | Gerd Hoffmann | |
20 | 3e313753 | Gerd Hoffmann | #include "hw/hw.h" |
21 | 3e313753 | Gerd Hoffmann | #include "qemu-timer.h" |
22 | 3e313753 | Gerd Hoffmann | #include "ui/qemu-spice.h" |
23 | 3e313753 | Gerd Hoffmann | |
24 | 3e313753 | Gerd Hoffmann | #define AUDIO_CAP "spice" |
25 | 3e313753 | Gerd Hoffmann | #include "audio.h" |
26 | 3e313753 | Gerd Hoffmann | #include "audio_int.h" |
27 | 3e313753 | Gerd Hoffmann | |
28 | 3e313753 | Gerd Hoffmann | #define LINE_IN_SAMPLES 1024 |
29 | 3e313753 | Gerd Hoffmann | #define LINE_OUT_SAMPLES 1024 |
30 | 3e313753 | Gerd Hoffmann | |
31 | 3e313753 | Gerd Hoffmann | typedef struct SpiceRateCtl { |
32 | 3e313753 | Gerd Hoffmann | int64_t start_ticks; |
33 | 3e313753 | Gerd Hoffmann | int64_t bytes_sent; |
34 | 3e313753 | Gerd Hoffmann | } SpiceRateCtl; |
35 | 3e313753 | Gerd Hoffmann | |
36 | 3e313753 | Gerd Hoffmann | typedef struct SpiceVoiceOut { |
37 | 3e313753 | Gerd Hoffmann | HWVoiceOut hw; |
38 | 3e313753 | Gerd Hoffmann | SpicePlaybackInstance sin; |
39 | 3e313753 | Gerd Hoffmann | SpiceRateCtl rate; |
40 | 3e313753 | Gerd Hoffmann | int active;
|
41 | 3e313753 | Gerd Hoffmann | uint32_t *frame; |
42 | 3e313753 | Gerd Hoffmann | uint32_t *fpos; |
43 | 3e313753 | Gerd Hoffmann | uint32_t fsize; |
44 | 3e313753 | Gerd Hoffmann | } SpiceVoiceOut; |
45 | 3e313753 | Gerd Hoffmann | |
46 | 3e313753 | Gerd Hoffmann | typedef struct SpiceVoiceIn { |
47 | 3e313753 | Gerd Hoffmann | HWVoiceIn hw; |
48 | 3e313753 | Gerd Hoffmann | SpiceRecordInstance sin; |
49 | 3e313753 | Gerd Hoffmann | SpiceRateCtl rate; |
50 | 3e313753 | Gerd Hoffmann | int active;
|
51 | 3e313753 | Gerd Hoffmann | uint32_t samples[LINE_IN_SAMPLES]; |
52 | 3e313753 | Gerd Hoffmann | } SpiceVoiceIn; |
53 | 3e313753 | Gerd Hoffmann | |
54 | 3e313753 | Gerd Hoffmann | static const SpicePlaybackInterface playback_sif = { |
55 | 3e313753 | Gerd Hoffmann | .base.type = SPICE_INTERFACE_PLAYBACK, |
56 | 3e313753 | Gerd Hoffmann | .base.description = "playback",
|
57 | 3e313753 | Gerd Hoffmann | .base.major_version = SPICE_INTERFACE_PLAYBACK_MAJOR, |
58 | 3e313753 | Gerd Hoffmann | .base.minor_version = SPICE_INTERFACE_PLAYBACK_MINOR, |
59 | 3e313753 | Gerd Hoffmann | }; |
60 | 3e313753 | Gerd Hoffmann | |
61 | 3e313753 | Gerd Hoffmann | static const SpiceRecordInterface record_sif = { |
62 | 3e313753 | Gerd Hoffmann | .base.type = SPICE_INTERFACE_RECORD, |
63 | 3e313753 | Gerd Hoffmann | .base.description = "record",
|
64 | 3e313753 | Gerd Hoffmann | .base.major_version = SPICE_INTERFACE_RECORD_MAJOR, |
65 | 3e313753 | Gerd Hoffmann | .base.minor_version = SPICE_INTERFACE_RECORD_MINOR, |
66 | 3e313753 | Gerd Hoffmann | }; |
67 | 3e313753 | Gerd Hoffmann | |
68 | 3e313753 | Gerd Hoffmann | static void *spice_audio_init (void) |
69 | 3e313753 | Gerd Hoffmann | { |
70 | 3e313753 | Gerd Hoffmann | if (!using_spice) {
|
71 | 3e313753 | Gerd Hoffmann | return NULL; |
72 | 3e313753 | Gerd Hoffmann | } |
73 | 3e313753 | Gerd Hoffmann | return &spice_audio_init;
|
74 | 3e313753 | Gerd Hoffmann | } |
75 | 3e313753 | Gerd Hoffmann | |
76 | 3e313753 | Gerd Hoffmann | static void spice_audio_fini (void *opaque) |
77 | 3e313753 | Gerd Hoffmann | { |
78 | 3e313753 | Gerd Hoffmann | /* nothing */
|
79 | 3e313753 | Gerd Hoffmann | } |
80 | 3e313753 | Gerd Hoffmann | |
81 | 3e313753 | Gerd Hoffmann | static void rate_start (SpiceRateCtl *rate) |
82 | 3e313753 | Gerd Hoffmann | { |
83 | 3e313753 | Gerd Hoffmann | memset (rate, 0, sizeof (*rate)); |
84 | 74475455 | Paolo Bonzini | rate->start_ticks = qemu_get_clock_ns (vm_clock); |
85 | 3e313753 | Gerd Hoffmann | } |
86 | 3e313753 | Gerd Hoffmann | |
87 | 3e313753 | Gerd Hoffmann | static int rate_get_samples (struct audio_pcm_info *info, SpiceRateCtl *rate) |
88 | 3e313753 | Gerd Hoffmann | { |
89 | 3e313753 | Gerd Hoffmann | int64_t now; |
90 | 3e313753 | Gerd Hoffmann | int64_t ticks; |
91 | 3e313753 | Gerd Hoffmann | int64_t bytes; |
92 | 3e313753 | Gerd Hoffmann | int64_t samples; |
93 | 3e313753 | Gerd Hoffmann | |
94 | 74475455 | Paolo Bonzini | now = qemu_get_clock_ns (vm_clock); |
95 | 3e313753 | Gerd Hoffmann | ticks = now - rate->start_ticks; |
96 | 3e313753 | Gerd Hoffmann | bytes = muldiv64 (ticks, info->bytes_per_second, get_ticks_per_sec ()); |
97 | 3e313753 | Gerd Hoffmann | samples = (bytes - rate->bytes_sent) >> info->shift; |
98 | 3e313753 | Gerd Hoffmann | if (samples < 0 || samples > 65536) { |
99 | 3e313753 | Gerd Hoffmann | fprintf (stderr, "Resetting rate control (%" PRId64 " samples)\n", samples); |
100 | 3e313753 | Gerd Hoffmann | rate_start (rate); |
101 | 3e313753 | Gerd Hoffmann | samples = 0;
|
102 | 3e313753 | Gerd Hoffmann | } |
103 | 3e313753 | Gerd Hoffmann | rate->bytes_sent += samples << info->shift; |
104 | 3e313753 | Gerd Hoffmann | return samples;
|
105 | 3e313753 | Gerd Hoffmann | } |
106 | 3e313753 | Gerd Hoffmann | |
107 | 3e313753 | Gerd Hoffmann | /* playback */
|
108 | 3e313753 | Gerd Hoffmann | |
109 | 3e313753 | Gerd Hoffmann | static int line_out_init (HWVoiceOut *hw, struct audsettings *as) |
110 | 3e313753 | Gerd Hoffmann | { |
111 | 3e313753 | Gerd Hoffmann | SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw); |
112 | 3e313753 | Gerd Hoffmann | struct audsettings settings;
|
113 | 3e313753 | Gerd Hoffmann | |
114 | 3e313753 | Gerd Hoffmann | settings.freq = SPICE_INTERFACE_PLAYBACK_FREQ; |
115 | 3e313753 | Gerd Hoffmann | settings.nchannels = SPICE_INTERFACE_PLAYBACK_CHAN; |
116 | 3e313753 | Gerd Hoffmann | settings.fmt = AUD_FMT_S16; |
117 | 3e313753 | Gerd Hoffmann | settings.endianness = AUDIO_HOST_ENDIANNESS; |
118 | 3e313753 | Gerd Hoffmann | |
119 | 3e313753 | Gerd Hoffmann | audio_pcm_init_info (&hw->info, &settings); |
120 | 3e313753 | Gerd Hoffmann | hw->samples = LINE_OUT_SAMPLES; |
121 | 3e313753 | Gerd Hoffmann | out->active = 0;
|
122 | 3e313753 | Gerd Hoffmann | |
123 | 3e313753 | Gerd Hoffmann | out->sin.base.sif = &playback_sif.base; |
124 | 3e313753 | Gerd Hoffmann | qemu_spice_add_interface (&out->sin.base); |
125 | 3e313753 | Gerd Hoffmann | return 0; |
126 | 3e313753 | Gerd Hoffmann | } |
127 | 3e313753 | Gerd Hoffmann | |
128 | 3e313753 | Gerd Hoffmann | static void line_out_fini (HWVoiceOut *hw) |
129 | 3e313753 | Gerd Hoffmann | { |
130 | 3e313753 | Gerd Hoffmann | SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw); |
131 | 3e313753 | Gerd Hoffmann | |
132 | 3e313753 | Gerd Hoffmann | spice_server_remove_interface (&out->sin.base); |
133 | 3e313753 | Gerd Hoffmann | } |
134 | 3e313753 | Gerd Hoffmann | |
135 | 3e313753 | Gerd Hoffmann | static int line_out_run (HWVoiceOut *hw, int live) |
136 | 3e313753 | Gerd Hoffmann | { |
137 | 3e313753 | Gerd Hoffmann | SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw); |
138 | 3e313753 | Gerd Hoffmann | int rpos, decr;
|
139 | 3e313753 | Gerd Hoffmann | int samples;
|
140 | 3e313753 | Gerd Hoffmann | |
141 | 3e313753 | Gerd Hoffmann | if (!live) {
|
142 | 3e313753 | Gerd Hoffmann | return 0; |
143 | 3e313753 | Gerd Hoffmann | } |
144 | 3e313753 | Gerd Hoffmann | |
145 | 3e313753 | Gerd Hoffmann | decr = rate_get_samples (&hw->info, &out->rate); |
146 | 3e313753 | Gerd Hoffmann | decr = audio_MIN (live, decr); |
147 | 3e313753 | Gerd Hoffmann | |
148 | 3e313753 | Gerd Hoffmann | samples = decr; |
149 | 3e313753 | Gerd Hoffmann | rpos = hw->rpos; |
150 | 3e313753 | Gerd Hoffmann | while (samples) {
|
151 | 3e313753 | Gerd Hoffmann | int left_till_end_samples = hw->samples - rpos;
|
152 | 3e313753 | Gerd Hoffmann | int len = audio_MIN (samples, left_till_end_samples);
|
153 | 3e313753 | Gerd Hoffmann | |
154 | 3e313753 | Gerd Hoffmann | if (!out->frame) {
|
155 | 3e313753 | Gerd Hoffmann | spice_server_playback_get_buffer (&out->sin, &out->frame, &out->fsize); |
156 | 3e313753 | Gerd Hoffmann | out->fpos = out->frame; |
157 | 3e313753 | Gerd Hoffmann | } |
158 | 3e313753 | Gerd Hoffmann | if (out->frame) {
|
159 | 3e313753 | Gerd Hoffmann | len = audio_MIN (len, out->fsize); |
160 | 3e313753 | Gerd Hoffmann | hw->clip (out->fpos, hw->mix_buf + rpos, len); |
161 | 3e313753 | Gerd Hoffmann | out->fsize -= len; |
162 | 3e313753 | Gerd Hoffmann | out->fpos += len; |
163 | 3e313753 | Gerd Hoffmann | if (out->fsize == 0) { |
164 | 3e313753 | Gerd Hoffmann | spice_server_playback_put_samples (&out->sin, out->frame); |
165 | 3e313753 | Gerd Hoffmann | out->frame = out->fpos = NULL;
|
166 | 3e313753 | Gerd Hoffmann | } |
167 | 3e313753 | Gerd Hoffmann | } |
168 | 3e313753 | Gerd Hoffmann | rpos = (rpos + len) % hw->samples; |
169 | 3e313753 | Gerd Hoffmann | samples -= len; |
170 | 3e313753 | Gerd Hoffmann | } |
171 | 3e313753 | Gerd Hoffmann | hw->rpos = rpos; |
172 | 3e313753 | Gerd Hoffmann | return decr;
|
173 | 3e313753 | Gerd Hoffmann | } |
174 | 3e313753 | Gerd Hoffmann | |
175 | 3e313753 | Gerd Hoffmann | static int line_out_write (SWVoiceOut *sw, void *buf, int len) |
176 | 3e313753 | Gerd Hoffmann | { |
177 | 3e313753 | Gerd Hoffmann | return audio_pcm_sw_write (sw, buf, len);
|
178 | 3e313753 | Gerd Hoffmann | } |
179 | 3e313753 | Gerd Hoffmann | |
180 | 3e313753 | Gerd Hoffmann | static int line_out_ctl (HWVoiceOut *hw, int cmd, ...) |
181 | 3e313753 | Gerd Hoffmann | { |
182 | 3e313753 | Gerd Hoffmann | SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw); |
183 | 3e313753 | Gerd Hoffmann | |
184 | 3e313753 | Gerd Hoffmann | switch (cmd) {
|
185 | 3e313753 | Gerd Hoffmann | case VOICE_ENABLE:
|
186 | 3e313753 | Gerd Hoffmann | if (out->active) {
|
187 | 3e313753 | Gerd Hoffmann | break;
|
188 | 3e313753 | Gerd Hoffmann | } |
189 | 3e313753 | Gerd Hoffmann | out->active = 1;
|
190 | 3e313753 | Gerd Hoffmann | rate_start (&out->rate); |
191 | 3e313753 | Gerd Hoffmann | spice_server_playback_start (&out->sin); |
192 | 3e313753 | Gerd Hoffmann | break;
|
193 | 3e313753 | Gerd Hoffmann | case VOICE_DISABLE:
|
194 | 3e313753 | Gerd Hoffmann | if (!out->active) {
|
195 | 3e313753 | Gerd Hoffmann | break;
|
196 | 3e313753 | Gerd Hoffmann | } |
197 | 3e313753 | Gerd Hoffmann | out->active = 0;
|
198 | 3e313753 | Gerd Hoffmann | if (out->frame) {
|
199 | 3e313753 | Gerd Hoffmann | memset (out->fpos, 0, out->fsize << 2); |
200 | 3e313753 | Gerd Hoffmann | spice_server_playback_put_samples (&out->sin, out->frame); |
201 | 3e313753 | Gerd Hoffmann | out->frame = out->fpos = NULL;
|
202 | 3e313753 | Gerd Hoffmann | } |
203 | 3e313753 | Gerd Hoffmann | spice_server_playback_stop (&out->sin); |
204 | 3e313753 | Gerd Hoffmann | break;
|
205 | 3e313753 | Gerd Hoffmann | } |
206 | 3e313753 | Gerd Hoffmann | return 0; |
207 | 3e313753 | Gerd Hoffmann | } |
208 | 3e313753 | Gerd Hoffmann | |
209 | 3e313753 | Gerd Hoffmann | /* record */
|
210 | 3e313753 | Gerd Hoffmann | |
211 | 3e313753 | Gerd Hoffmann | static int line_in_init (HWVoiceIn *hw, struct audsettings *as) |
212 | 3e313753 | Gerd Hoffmann | { |
213 | 3e313753 | Gerd Hoffmann | SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw); |
214 | 3e313753 | Gerd Hoffmann | struct audsettings settings;
|
215 | 3e313753 | Gerd Hoffmann | |
216 | 3e313753 | Gerd Hoffmann | settings.freq = SPICE_INTERFACE_RECORD_FREQ; |
217 | 3e313753 | Gerd Hoffmann | settings.nchannels = SPICE_INTERFACE_RECORD_CHAN; |
218 | 3e313753 | Gerd Hoffmann | settings.fmt = AUD_FMT_S16; |
219 | 3e313753 | Gerd Hoffmann | settings.endianness = AUDIO_HOST_ENDIANNESS; |
220 | 3e313753 | Gerd Hoffmann | |
221 | 3e313753 | Gerd Hoffmann | audio_pcm_init_info (&hw->info, &settings); |
222 | 3e313753 | Gerd Hoffmann | hw->samples = LINE_IN_SAMPLES; |
223 | 3e313753 | Gerd Hoffmann | in->active = 0;
|
224 | 3e313753 | Gerd Hoffmann | |
225 | 3e313753 | Gerd Hoffmann | in->sin.base.sif = &record_sif.base; |
226 | 3e313753 | Gerd Hoffmann | qemu_spice_add_interface (&in->sin.base); |
227 | 3e313753 | Gerd Hoffmann | return 0; |
228 | 3e313753 | Gerd Hoffmann | } |
229 | 3e313753 | Gerd Hoffmann | |
230 | 3e313753 | Gerd Hoffmann | static void line_in_fini (HWVoiceIn *hw) |
231 | 3e313753 | Gerd Hoffmann | { |
232 | 3e313753 | Gerd Hoffmann | SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw); |
233 | 3e313753 | Gerd Hoffmann | |
234 | 3e313753 | Gerd Hoffmann | spice_server_remove_interface (&in->sin.base); |
235 | 3e313753 | Gerd Hoffmann | } |
236 | 3e313753 | Gerd Hoffmann | |
237 | 3e313753 | Gerd Hoffmann | static int line_in_run (HWVoiceIn *hw) |
238 | 3e313753 | Gerd Hoffmann | { |
239 | 3e313753 | Gerd Hoffmann | SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw); |
240 | 3e313753 | Gerd Hoffmann | int num_samples;
|
241 | 3e313753 | Gerd Hoffmann | int ready;
|
242 | 3e313753 | Gerd Hoffmann | int len[2]; |
243 | 3e313753 | Gerd Hoffmann | uint64_t delta_samp; |
244 | 3e313753 | Gerd Hoffmann | const uint32_t *samples;
|
245 | 3e313753 | Gerd Hoffmann | |
246 | 3e313753 | Gerd Hoffmann | if (!(num_samples = hw->samples - audio_pcm_hw_get_live_in (hw))) {
|
247 | 3e313753 | Gerd Hoffmann | return 0; |
248 | 3e313753 | Gerd Hoffmann | } |
249 | 3e313753 | Gerd Hoffmann | |
250 | 3e313753 | Gerd Hoffmann | delta_samp = rate_get_samples (&hw->info, &in->rate); |
251 | 3e313753 | Gerd Hoffmann | num_samples = audio_MIN (num_samples, delta_samp); |
252 | 3e313753 | Gerd Hoffmann | |
253 | 3e313753 | Gerd Hoffmann | ready = spice_server_record_get_samples (&in->sin, in->samples, num_samples); |
254 | 3e313753 | Gerd Hoffmann | samples = in->samples; |
255 | 3e313753 | Gerd Hoffmann | if (ready == 0) { |
256 | 3e313753 | Gerd Hoffmann | static const uint32_t silence[LINE_IN_SAMPLES]; |
257 | 3e313753 | Gerd Hoffmann | samples = silence; |
258 | 3e313753 | Gerd Hoffmann | ready = LINE_IN_SAMPLES; |
259 | 3e313753 | Gerd Hoffmann | } |
260 | 3e313753 | Gerd Hoffmann | |
261 | 3e313753 | Gerd Hoffmann | num_samples = audio_MIN (ready, num_samples); |
262 | 3e313753 | Gerd Hoffmann | |
263 | 3e313753 | Gerd Hoffmann | if (hw->wpos + num_samples > hw->samples) {
|
264 | 3e313753 | Gerd Hoffmann | len[0] = hw->samples - hw->wpos;
|
265 | 3e313753 | Gerd Hoffmann | len[1] = num_samples - len[0]; |
266 | 3e313753 | Gerd Hoffmann | } else {
|
267 | 3e313753 | Gerd Hoffmann | len[0] = num_samples;
|
268 | 3e313753 | Gerd Hoffmann | len[1] = 0; |
269 | 3e313753 | Gerd Hoffmann | } |
270 | 3e313753 | Gerd Hoffmann | |
271 | 00e07679 | Michael Walle | hw->conv (hw->conv_buf + hw->wpos, samples, len[0]);
|
272 | 3e313753 | Gerd Hoffmann | |
273 | 3e313753 | Gerd Hoffmann | if (len[1]) { |
274 | 00e07679 | Michael Walle | hw->conv (hw->conv_buf, samples + len[0], len[1]); |
275 | 3e313753 | Gerd Hoffmann | } |
276 | 3e313753 | Gerd Hoffmann | |
277 | 3e313753 | Gerd Hoffmann | hw->wpos = (hw->wpos + num_samples) % hw->samples; |
278 | 3e313753 | Gerd Hoffmann | |
279 | 3e313753 | Gerd Hoffmann | return num_samples;
|
280 | 3e313753 | Gerd Hoffmann | } |
281 | 3e313753 | Gerd Hoffmann | |
282 | 3e313753 | Gerd Hoffmann | static int line_in_read (SWVoiceIn *sw, void *buf, int size) |
283 | 3e313753 | Gerd Hoffmann | { |
284 | 3e313753 | Gerd Hoffmann | return audio_pcm_sw_read (sw, buf, size);
|
285 | 3e313753 | Gerd Hoffmann | } |
286 | 3e313753 | Gerd Hoffmann | |
287 | 3e313753 | Gerd Hoffmann | static int line_in_ctl (HWVoiceIn *hw, int cmd, ...) |
288 | 3e313753 | Gerd Hoffmann | { |
289 | 3e313753 | Gerd Hoffmann | SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw); |
290 | 3e313753 | Gerd Hoffmann | |
291 | 3e313753 | Gerd Hoffmann | switch (cmd) {
|
292 | 3e313753 | Gerd Hoffmann | case VOICE_ENABLE:
|
293 | 3e313753 | Gerd Hoffmann | if (in->active) {
|
294 | 3e313753 | Gerd Hoffmann | break;
|
295 | 3e313753 | Gerd Hoffmann | } |
296 | 3e313753 | Gerd Hoffmann | in->active = 1;
|
297 | 3e313753 | Gerd Hoffmann | rate_start (&in->rate); |
298 | 3e313753 | Gerd Hoffmann | spice_server_record_start (&in->sin); |
299 | 3e313753 | Gerd Hoffmann | break;
|
300 | 3e313753 | Gerd Hoffmann | case VOICE_DISABLE:
|
301 | 3e313753 | Gerd Hoffmann | if (!in->active) {
|
302 | 3e313753 | Gerd Hoffmann | break;
|
303 | 3e313753 | Gerd Hoffmann | } |
304 | 3e313753 | Gerd Hoffmann | in->active = 0;
|
305 | 3e313753 | Gerd Hoffmann | spice_server_record_stop (&in->sin); |
306 | 3e313753 | Gerd Hoffmann | break;
|
307 | 3e313753 | Gerd Hoffmann | } |
308 | 3e313753 | Gerd Hoffmann | return 0; |
309 | 3e313753 | Gerd Hoffmann | } |
310 | 3e313753 | Gerd Hoffmann | |
311 | 3e313753 | Gerd Hoffmann | static struct audio_option audio_options[] = { |
312 | 3e313753 | Gerd Hoffmann | { /* end of list */ },
|
313 | 3e313753 | Gerd Hoffmann | }; |
314 | 3e313753 | Gerd Hoffmann | |
315 | 3e313753 | Gerd Hoffmann | static struct audio_pcm_ops audio_callbacks = { |
316 | 3e313753 | Gerd Hoffmann | .init_out = line_out_init, |
317 | 3e313753 | Gerd Hoffmann | .fini_out = line_out_fini, |
318 | 3e313753 | Gerd Hoffmann | .run_out = line_out_run, |
319 | 3e313753 | Gerd Hoffmann | .write = line_out_write, |
320 | 3e313753 | Gerd Hoffmann | .ctl_out = line_out_ctl, |
321 | 3e313753 | Gerd Hoffmann | |
322 | 3e313753 | Gerd Hoffmann | .init_in = line_in_init, |
323 | 3e313753 | Gerd Hoffmann | .fini_in = line_in_fini, |
324 | 3e313753 | Gerd Hoffmann | .run_in = line_in_run, |
325 | 3e313753 | Gerd Hoffmann | .read = line_in_read, |
326 | 3e313753 | Gerd Hoffmann | .ctl_in = line_in_ctl, |
327 | 3e313753 | Gerd Hoffmann | }; |
328 | 3e313753 | Gerd Hoffmann | |
329 | 3e313753 | Gerd Hoffmann | struct audio_driver spice_audio_driver = {
|
330 | 3e313753 | Gerd Hoffmann | .name = "spice",
|
331 | 3e313753 | Gerd Hoffmann | .descr = "spice audio driver",
|
332 | 3e313753 | Gerd Hoffmann | .options = audio_options, |
333 | 3e313753 | Gerd Hoffmann | .init = spice_audio_init, |
334 | 3e313753 | Gerd Hoffmann | .fini = spice_audio_fini, |
335 | 3e313753 | Gerd Hoffmann | .pcm_ops = &audio_callbacks, |
336 | 3e313753 | Gerd Hoffmann | .max_voices_out = 1,
|
337 | 3e313753 | Gerd Hoffmann | .max_voices_in = 1,
|
338 | 3e313753 | Gerd Hoffmann | .voice_size_out = sizeof (SpiceVoiceOut),
|
339 | 3e313753 | Gerd Hoffmann | .voice_size_in = sizeof (SpiceVoiceIn),
|
340 | 3e313753 | Gerd Hoffmann | }; |
341 | 3e313753 | Gerd Hoffmann | |
342 | 3e313753 | Gerd Hoffmann | void qemu_spice_audio_init (void) |
343 | 3e313753 | Gerd Hoffmann | { |
344 | 3e313753 | Gerd Hoffmann | spice_audio_driver.can_be_default = 1;
|
345 | 3e313753 | Gerd Hoffmann | } |