root / audio / audio_template.h @ e784ba70
History | View | Annotate | Download (13.3 kB)
1 | 1d14ffa9 | bellard | /*
|
---|---|---|---|
2 | 1d14ffa9 | bellard | * QEMU Audio subsystem header
|
3 | 1d14ffa9 | bellard | *
|
4 | 1d14ffa9 | bellard | * Copyright (c) 2005 Vassili Karpov (malc)
|
5 | 1d14ffa9 | bellard | *
|
6 | 1d14ffa9 | bellard | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
7 | 1d14ffa9 | bellard | * of this software and associated documentation files (the "Software"), to deal
|
8 | 1d14ffa9 | bellard | * in the Software without restriction, including without limitation the rights
|
9 | 1d14ffa9 | bellard | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10 | 1d14ffa9 | bellard | * copies of the Software, and to permit persons to whom the Software is
|
11 | 1d14ffa9 | bellard | * furnished to do so, subject to the following conditions:
|
12 | 1d14ffa9 | bellard | *
|
13 | 1d14ffa9 | bellard | * The above copyright notice and this permission notice shall be included in
|
14 | 1d14ffa9 | bellard | * all copies or substantial portions of the Software.
|
15 | 1d14ffa9 | bellard | *
|
16 | 1d14ffa9 | bellard | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17 | 1d14ffa9 | bellard | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18 | 1d14ffa9 | bellard | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
19 | 1d14ffa9 | bellard | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20 | 1d14ffa9 | bellard | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21 | 1d14ffa9 | bellard | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22 | 1d14ffa9 | bellard | * THE SOFTWARE.
|
23 | 1d14ffa9 | bellard | */
|
24 | 1d14ffa9 | bellard | |
25 | 1d14ffa9 | bellard | #ifdef DAC
|
26 | 571ec3d6 | bellard | #define NAME "playback" |
27 | 571ec3d6 | bellard | #define HWBUF hw->mix_buf
|
28 | 1d14ffa9 | bellard | #define TYPE out
|
29 | 571ec3d6 | bellard | #define HW HWVoiceOut
|
30 | 571ec3d6 | bellard | #define SW SWVoiceOut
|
31 | 1d14ffa9 | bellard | #else
|
32 | 571ec3d6 | bellard | #define NAME "capture" |
33 | 1d14ffa9 | bellard | #define TYPE in
|
34 | 571ec3d6 | bellard | #define HW HWVoiceIn
|
35 | 571ec3d6 | bellard | #define SW SWVoiceIn
|
36 | 571ec3d6 | bellard | #define HWBUF hw->conv_buf
|
37 | 1d14ffa9 | bellard | #endif
|
38 | 1d14ffa9 | bellard | |
39 | 571ec3d6 | bellard | static void glue (audio_init_nb_voices_, TYPE) ( |
40 | 571ec3d6 | bellard | AudioState *s, |
41 | 571ec3d6 | bellard | struct audio_driver *drv
|
42 | c0fe3827 | bellard | ) |
43 | c0fe3827 | bellard | { |
44 | 571ec3d6 | bellard | int max_voices = glue (drv->max_voices_, TYPE);
|
45 | 571ec3d6 | bellard | int voice_size = glue (drv->voice_size_, TYPE);
|
46 | c0fe3827 | bellard | |
47 | 571ec3d6 | bellard | if (glue (s->nb_hw_voices_, TYPE) > max_voices) {
|
48 | 571ec3d6 | bellard | if (!max_voices) {
|
49 | 571ec3d6 | bellard | #ifdef DAC
|
50 | 571ec3d6 | bellard | dolog ("Driver `%s' does not support " NAME "\n", drv->name); |
51 | 571ec3d6 | bellard | #endif
|
52 | 571ec3d6 | bellard | } |
53 | 571ec3d6 | bellard | else {
|
54 | 571ec3d6 | bellard | dolog ("Driver `%s' does not support %d " NAME " voices, max %d\n", |
55 | 571ec3d6 | bellard | drv->name, |
56 | 571ec3d6 | bellard | glue (s->nb_hw_voices_, TYPE), |
57 | 571ec3d6 | bellard | max_voices); |
58 | 571ec3d6 | bellard | } |
59 | 571ec3d6 | bellard | glue (s->nb_hw_voices_, TYPE) = max_voices; |
60 | c0fe3827 | bellard | } |
61 | c0fe3827 | bellard | |
62 | 571ec3d6 | bellard | if (audio_bug (AUDIO_FUNC, !voice_size && max_voices)) {
|
63 | 571ec3d6 | bellard | dolog ("drv=`%s' voice_size=0 max_voices=%d\n",
|
64 | 571ec3d6 | bellard | drv->name, max_voices); |
65 | 571ec3d6 | bellard | glue (s->nb_hw_voices_, TYPE) = 0;
|
66 | 571ec3d6 | bellard | } |
67 | 571ec3d6 | bellard | |
68 | 571ec3d6 | bellard | if (audio_bug (AUDIO_FUNC, voice_size && !max_voices)) {
|
69 | 571ec3d6 | bellard | dolog ("drv=`%s' voice_size=%d max_voices=0\n",
|
70 | 571ec3d6 | bellard | drv->name, voice_size); |
71 | 571ec3d6 | bellard | } |
72 | 571ec3d6 | bellard | } |
73 | 571ec3d6 | bellard | |
74 | 571ec3d6 | bellard | static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw) |
75 | 571ec3d6 | bellard | { |
76 | 571ec3d6 | bellard | if (HWBUF) {
|
77 | 571ec3d6 | bellard | qemu_free (HWBUF); |
78 | 571ec3d6 | bellard | } |
79 | 571ec3d6 | bellard | |
80 | 571ec3d6 | bellard | HWBUF = NULL;
|
81 | 571ec3d6 | bellard | } |
82 | 571ec3d6 | bellard | |
83 | 571ec3d6 | bellard | static int glue (audio_pcm_hw_alloc_resources_, TYPE) (HW *hw) |
84 | 571ec3d6 | bellard | { |
85 | 571ec3d6 | bellard | HWBUF = audio_calloc (AUDIO_FUNC, hw->samples, sizeof (st_sample_t));
|
86 | 571ec3d6 | bellard | if (!HWBUF) {
|
87 | 571ec3d6 | bellard | dolog ("Could not allocate " NAME " buffer (%d samples)\n", |
88 | 571ec3d6 | bellard | hw->samples); |
89 | c0fe3827 | bellard | return -1; |
90 | c0fe3827 | bellard | } |
91 | c0fe3827 | bellard | |
92 | 571ec3d6 | bellard | return 0; |
93 | 571ec3d6 | bellard | } |
94 | 571ec3d6 | bellard | |
95 | 571ec3d6 | bellard | static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw) |
96 | 571ec3d6 | bellard | { |
97 | 571ec3d6 | bellard | if (sw->buf) {
|
98 | 571ec3d6 | bellard | qemu_free (sw->buf); |
99 | 571ec3d6 | bellard | } |
100 | 571ec3d6 | bellard | |
101 | 571ec3d6 | bellard | if (sw->rate) {
|
102 | 571ec3d6 | bellard | st_rate_stop (sw->rate); |
103 | 571ec3d6 | bellard | } |
104 | 571ec3d6 | bellard | |
105 | 571ec3d6 | bellard | sw->buf = NULL;
|
106 | 571ec3d6 | bellard | sw->rate = NULL;
|
107 | 571ec3d6 | bellard | } |
108 | 571ec3d6 | bellard | |
109 | 571ec3d6 | bellard | static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw) |
110 | 571ec3d6 | bellard | { |
111 | 571ec3d6 | bellard | int samples;
|
112 | 571ec3d6 | bellard | |
113 | c0fe3827 | bellard | #ifdef DAC
|
114 | 571ec3d6 | bellard | samples = sw->hw->samples; |
115 | c0fe3827 | bellard | #else
|
116 | 571ec3d6 | bellard | samples = ((int64_t) sw->hw->samples << 32) / sw->ratio;
|
117 | c0fe3827 | bellard | #endif
|
118 | c0fe3827 | bellard | |
119 | 571ec3d6 | bellard | sw->buf = audio_calloc (AUDIO_FUNC, samples, sizeof (st_sample_t));
|
120 | 571ec3d6 | bellard | if (!sw->buf) {
|
121 | 571ec3d6 | bellard | dolog ("Could not allocate buffer for `%s' (%d samples)\n",
|
122 | 571ec3d6 | bellard | SW_NAME (sw), samples); |
123 | c0fe3827 | bellard | return -1; |
124 | c0fe3827 | bellard | } |
125 | c0fe3827 | bellard | |
126 | 571ec3d6 | bellard | #ifdef DAC
|
127 | 571ec3d6 | bellard | sw->rate = st_rate_start (sw->info.freq, sw->hw->info.freq); |
128 | 571ec3d6 | bellard | #else
|
129 | 571ec3d6 | bellard | sw->rate = st_rate_start (sw->hw->info.freq, sw->info.freq); |
130 | 571ec3d6 | bellard | #endif
|
131 | 571ec3d6 | bellard | if (!sw->rate) {
|
132 | 571ec3d6 | bellard | qemu_free (sw->buf); |
133 | 571ec3d6 | bellard | sw->buf = NULL;
|
134 | 571ec3d6 | bellard | return -1; |
135 | 571ec3d6 | bellard | } |
136 | c0fe3827 | bellard | return 0; |
137 | c0fe3827 | bellard | } |
138 | c0fe3827 | bellard | |
139 | 571ec3d6 | bellard | static int glue (audio_pcm_sw_init_, TYPE) ( |
140 | 571ec3d6 | bellard | SW *sw, |
141 | 571ec3d6 | bellard | HW *hw, |
142 | 571ec3d6 | bellard | const char *name, |
143 | d929eba5 | bellard | audsettings_t *as |
144 | 571ec3d6 | bellard | ) |
145 | 571ec3d6 | bellard | { |
146 | 571ec3d6 | bellard | int err;
|
147 | 571ec3d6 | bellard | |
148 | d929eba5 | bellard | audio_pcm_init_info (&sw->info, as); |
149 | 571ec3d6 | bellard | sw->hw = hw; |
150 | 571ec3d6 | bellard | sw->active = 0;
|
151 | 571ec3d6 | bellard | #ifdef DAC
|
152 | 571ec3d6 | bellard | sw->ratio = ((int64_t) sw->hw->info.freq << 32) / sw->info.freq;
|
153 | 571ec3d6 | bellard | sw->total_hw_samples_mixed = 0;
|
154 | 571ec3d6 | bellard | sw->empty = 1;
|
155 | 571ec3d6 | bellard | #else
|
156 | 571ec3d6 | bellard | sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq;
|
157 | 571ec3d6 | bellard | #endif
|
158 | 571ec3d6 | bellard | |
159 | 571ec3d6 | bellard | #ifdef DAC
|
160 | 571ec3d6 | bellard | sw->conv = mixeng_conv |
161 | 571ec3d6 | bellard | #else
|
162 | 571ec3d6 | bellard | sw->clip = mixeng_clip |
163 | 571ec3d6 | bellard | #endif
|
164 | 571ec3d6 | bellard | [sw->info.nchannels == 2]
|
165 | 571ec3d6 | bellard | [sw->info.sign] |
166 | d929eba5 | bellard | [sw->info.swap_endianness] |
167 | f941aa25 | ths | [audio_bits_to_index (sw->info.bits)]; |
168 | 571ec3d6 | bellard | |
169 | 571ec3d6 | bellard | sw->name = qemu_strdup (name); |
170 | 571ec3d6 | bellard | err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw); |
171 | 571ec3d6 | bellard | if (err) {
|
172 | 571ec3d6 | bellard | qemu_free (sw->name); |
173 | 571ec3d6 | bellard | sw->name = NULL;
|
174 | 571ec3d6 | bellard | } |
175 | 571ec3d6 | bellard | return err;
|
176 | 571ec3d6 | bellard | } |
177 | 571ec3d6 | bellard | |
178 | 1d14ffa9 | bellard | static void glue (audio_pcm_sw_fini_, TYPE) (SW *sw) |
179 | 1d14ffa9 | bellard | { |
180 | 1d14ffa9 | bellard | glue (audio_pcm_sw_free_resources_, TYPE) (sw); |
181 | 1d14ffa9 | bellard | if (sw->name) {
|
182 | 1d14ffa9 | bellard | qemu_free (sw->name); |
183 | 1d14ffa9 | bellard | sw->name = NULL;
|
184 | 1d14ffa9 | bellard | } |
185 | 1d14ffa9 | bellard | } |
186 | 1d14ffa9 | bellard | |
187 | 1d14ffa9 | bellard | static void glue (audio_pcm_hw_add_sw_, TYPE) (HW *hw, SW *sw) |
188 | 1d14ffa9 | bellard | { |
189 | 1d14ffa9 | bellard | LIST_INSERT_HEAD (&hw->sw_head, sw, entries); |
190 | 1d14ffa9 | bellard | } |
191 | 1d14ffa9 | bellard | |
192 | 1d14ffa9 | bellard | static void glue (audio_pcm_hw_del_sw_, TYPE) (SW *sw) |
193 | 1d14ffa9 | bellard | { |
194 | 1d14ffa9 | bellard | LIST_REMOVE (sw, entries); |
195 | 1d14ffa9 | bellard | } |
196 | 1d14ffa9 | bellard | |
197 | c0fe3827 | bellard | static void glue (audio_pcm_hw_gc_, TYPE) (AudioState *s, HW **hwp) |
198 | 1d14ffa9 | bellard | { |
199 | c0fe3827 | bellard | HW *hw = *hwp; |
200 | 1d14ffa9 | bellard | |
201 | 1d14ffa9 | bellard | if (!hw->sw_head.lh_first) {
|
202 | 8ead62cf | bellard | #ifdef DAC
|
203 | 8ead62cf | bellard | audio_detach_capture (hw); |
204 | 8ead62cf | bellard | #endif
|
205 | c0fe3827 | bellard | LIST_REMOVE (hw, entries); |
206 | c0fe3827 | bellard | glue (s->nb_hw_voices_, TYPE) += 1;
|
207 | c0fe3827 | bellard | glue (audio_pcm_hw_free_resources_ ,TYPE) (hw); |
208 | c0fe3827 | bellard | glue (hw->pcm_ops->fini_, TYPE) (hw); |
209 | c0fe3827 | bellard | qemu_free (hw); |
210 | c0fe3827 | bellard | *hwp = NULL;
|
211 | 1d14ffa9 | bellard | } |
212 | 1d14ffa9 | bellard | } |
213 | 1d14ffa9 | bellard | |
214 | c0fe3827 | bellard | static HW *glue (audio_pcm_hw_find_any_, TYPE) (AudioState *s, HW *hw)
|
215 | 1d14ffa9 | bellard | { |
216 | c0fe3827 | bellard | return hw ? hw->entries.le_next : s->glue (hw_head_, TYPE).lh_first;
|
217 | 1d14ffa9 | bellard | } |
218 | 1d14ffa9 | bellard | |
219 | c0fe3827 | bellard | static HW *glue (audio_pcm_hw_find_any_enabled_, TYPE) (AudioState *s, HW *hw)
|
220 | 1d14ffa9 | bellard | { |
221 | c0fe3827 | bellard | while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (s, hw))) {
|
222 | c0fe3827 | bellard | if (hw->enabled) {
|
223 | 1d14ffa9 | bellard | return hw;
|
224 | 1d14ffa9 | bellard | } |
225 | 1d14ffa9 | bellard | } |
226 | 1d14ffa9 | bellard | return NULL; |
227 | 1d14ffa9 | bellard | } |
228 | 1d14ffa9 | bellard | |
229 | 1d14ffa9 | bellard | static HW *glue (audio_pcm_hw_find_specific_, TYPE) (
|
230 | c0fe3827 | bellard | AudioState *s, |
231 | 1d14ffa9 | bellard | HW *hw, |
232 | c0fe3827 | bellard | audsettings_t *as |
233 | 1d14ffa9 | bellard | ) |
234 | 1d14ffa9 | bellard | { |
235 | c0fe3827 | bellard | while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (s, hw))) {
|
236 | c0fe3827 | bellard | if (audio_pcm_info_eq (&hw->info, as)) {
|
237 | 1d14ffa9 | bellard | return hw;
|
238 | 1d14ffa9 | bellard | } |
239 | 1d14ffa9 | bellard | } |
240 | 1d14ffa9 | bellard | return NULL; |
241 | 1d14ffa9 | bellard | } |
242 | 1d14ffa9 | bellard | |
243 | c0fe3827 | bellard | static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as)
|
244 | 1d14ffa9 | bellard | { |
245 | 1d14ffa9 | bellard | HW *hw; |
246 | 571ec3d6 | bellard | struct audio_driver *drv = s->drv;
|
247 | 1d14ffa9 | bellard | |
248 | 571ec3d6 | bellard | if (!glue (s->nb_hw_voices_, TYPE)) {
|
249 | 571ec3d6 | bellard | return NULL; |
250 | 571ec3d6 | bellard | } |
251 | 1d14ffa9 | bellard | |
252 | 571ec3d6 | bellard | if (audio_bug (AUDIO_FUNC, !drv)) {
|
253 | 571ec3d6 | bellard | dolog ("No host audio driver\n");
|
254 | 571ec3d6 | bellard | return NULL; |
255 | 1d14ffa9 | bellard | } |
256 | 1d14ffa9 | bellard | |
257 | 571ec3d6 | bellard | if (audio_bug (AUDIO_FUNC, !drv->pcm_ops)) {
|
258 | 571ec3d6 | bellard | dolog ("Host audio driver without pcm_ops\n");
|
259 | 571ec3d6 | bellard | return NULL; |
260 | 571ec3d6 | bellard | } |
261 | 571ec3d6 | bellard | |
262 | 571ec3d6 | bellard | hw = audio_calloc (AUDIO_FUNC, 1, glue (drv->voice_size_, TYPE));
|
263 | 571ec3d6 | bellard | if (!hw) {
|
264 | 571ec3d6 | bellard | dolog ("Can not allocate voice `%s' size %d\n",
|
265 | 571ec3d6 | bellard | drv->name, glue (drv->voice_size_, TYPE)); |
266 | 571ec3d6 | bellard | return NULL; |
267 | 571ec3d6 | bellard | } |
268 | 571ec3d6 | bellard | |
269 | 571ec3d6 | bellard | hw->pcm_ops = drv->pcm_ops; |
270 | 571ec3d6 | bellard | LIST_INIT (&hw->sw_head); |
271 | 8ead62cf | bellard | #ifdef DAC
|
272 | ec36b695 | bellard | LIST_INIT (&hw->cap_head); |
273 | 8ead62cf | bellard | #endif
|
274 | 571ec3d6 | bellard | if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) {
|
275 | 571ec3d6 | bellard | goto err0;
|
276 | 571ec3d6 | bellard | } |
277 | 571ec3d6 | bellard | |
278 | 571ec3d6 | bellard | if (audio_bug (AUDIO_FUNC, hw->samples <= 0)) { |
279 | 571ec3d6 | bellard | dolog ("hw->samples=%d\n", hw->samples);
|
280 | 571ec3d6 | bellard | goto err1;
|
281 | 571ec3d6 | bellard | } |
282 | 571ec3d6 | bellard | |
283 | 571ec3d6 | bellard | #ifdef DAC
|
284 | 571ec3d6 | bellard | hw->clip = mixeng_clip |
285 | 571ec3d6 | bellard | #else
|
286 | 571ec3d6 | bellard | hw->conv = mixeng_conv |
287 | 571ec3d6 | bellard | #endif
|
288 | 571ec3d6 | bellard | [hw->info.nchannels == 2]
|
289 | 571ec3d6 | bellard | [hw->info.sign] |
290 | d929eba5 | bellard | [hw->info.swap_endianness] |
291 | f941aa25 | ths | [audio_bits_to_index (hw->info.bits)]; |
292 | 571ec3d6 | bellard | |
293 | 571ec3d6 | bellard | if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) {
|
294 | 571ec3d6 | bellard | goto err1;
|
295 | 571ec3d6 | bellard | } |
296 | 571ec3d6 | bellard | |
297 | 571ec3d6 | bellard | LIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries); |
298 | 571ec3d6 | bellard | glue (s->nb_hw_voices_, TYPE) -= 1;
|
299 | 8ead62cf | bellard | #ifdef DAC
|
300 | 8ead62cf | bellard | audio_attach_capture (s, hw); |
301 | 8ead62cf | bellard | #endif
|
302 | 571ec3d6 | bellard | return hw;
|
303 | 571ec3d6 | bellard | |
304 | 571ec3d6 | bellard | err1:
|
305 | 571ec3d6 | bellard | glue (hw->pcm_ops->fini_, TYPE) (hw); |
306 | 571ec3d6 | bellard | err0:
|
307 | 571ec3d6 | bellard | qemu_free (hw); |
308 | 1d14ffa9 | bellard | return NULL; |
309 | 1d14ffa9 | bellard | } |
310 | 1d14ffa9 | bellard | |
311 | c0fe3827 | bellard | static HW *glue (audio_pcm_hw_add_, TYPE) (AudioState *s, audsettings_t *as)
|
312 | 1d14ffa9 | bellard | { |
313 | 1d14ffa9 | bellard | HW *hw; |
314 | 1d14ffa9 | bellard | |
315 | c0fe3827 | bellard | if (glue (conf.fixed_, TYPE).enabled && glue (conf.fixed_, TYPE).greedy) {
|
316 | c0fe3827 | bellard | hw = glue (audio_pcm_hw_add_new_, TYPE) (s, as); |
317 | 1d14ffa9 | bellard | if (hw) {
|
318 | 1d14ffa9 | bellard | return hw;
|
319 | 1d14ffa9 | bellard | } |
320 | 1d14ffa9 | bellard | } |
321 | 1d14ffa9 | bellard | |
322 | c0fe3827 | bellard | hw = glue (audio_pcm_hw_find_specific_, TYPE) (s, NULL, as);
|
323 | 1d14ffa9 | bellard | if (hw) {
|
324 | 1d14ffa9 | bellard | return hw;
|
325 | 1d14ffa9 | bellard | } |
326 | 1d14ffa9 | bellard | |
327 | c0fe3827 | bellard | hw = glue (audio_pcm_hw_add_new_, TYPE) (s, as); |
328 | 1d14ffa9 | bellard | if (hw) {
|
329 | 1d14ffa9 | bellard | return hw;
|
330 | 1d14ffa9 | bellard | } |
331 | 1d14ffa9 | bellard | |
332 | c0fe3827 | bellard | return glue (audio_pcm_hw_find_any_, TYPE) (s, NULL); |
333 | 1d14ffa9 | bellard | } |
334 | 1d14ffa9 | bellard | |
335 | 1d14ffa9 | bellard | static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
|
336 | c0fe3827 | bellard | AudioState *s, |
337 | c0fe3827 | bellard | const char *sw_name, |
338 | d929eba5 | bellard | audsettings_t *as |
339 | 1d14ffa9 | bellard | ) |
340 | 1d14ffa9 | bellard | { |
341 | 1d14ffa9 | bellard | SW *sw; |
342 | 1d14ffa9 | bellard | HW *hw; |
343 | c0fe3827 | bellard | audsettings_t hw_as; |
344 | 1d14ffa9 | bellard | |
345 | c0fe3827 | bellard | if (glue (conf.fixed_, TYPE).enabled) {
|
346 | c0fe3827 | bellard | hw_as = glue (conf.fixed_, TYPE).settings; |
347 | c0fe3827 | bellard | } |
348 | c0fe3827 | bellard | else {
|
349 | c0fe3827 | bellard | hw_as = *as; |
350 | 1d14ffa9 | bellard | } |
351 | 1d14ffa9 | bellard | |
352 | c0fe3827 | bellard | sw = audio_calloc (AUDIO_FUNC, 1, sizeof (*sw)); |
353 | 1d14ffa9 | bellard | if (!sw) {
|
354 | e7cad338 | bellard | dolog ("Could not allocate soft voice `%s' (%zu bytes)\n",
|
355 | c0fe3827 | bellard | sw_name ? sw_name : "unknown", sizeof (*sw)); |
356 | 1d14ffa9 | bellard | goto err1;
|
357 | 1d14ffa9 | bellard | } |
358 | 1d14ffa9 | bellard | |
359 | c0fe3827 | bellard | hw = glue (audio_pcm_hw_add_, TYPE) (s, &hw_as); |
360 | 1d14ffa9 | bellard | if (!hw) {
|
361 | 1d14ffa9 | bellard | goto err2;
|
362 | 1d14ffa9 | bellard | } |
363 | 1d14ffa9 | bellard | |
364 | 1d14ffa9 | bellard | glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw); |
365 | 1d14ffa9 | bellard | |
366 | d929eba5 | bellard | if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as)) {
|
367 | 1d14ffa9 | bellard | goto err3;
|
368 | 1d14ffa9 | bellard | } |
369 | 1d14ffa9 | bellard | |
370 | 1d14ffa9 | bellard | return sw;
|
371 | 1d14ffa9 | bellard | |
372 | 1d14ffa9 | bellard | err3:
|
373 | 1d14ffa9 | bellard | glue (audio_pcm_hw_del_sw_, TYPE) (sw); |
374 | c0fe3827 | bellard | glue (audio_pcm_hw_gc_, TYPE) (s, &hw); |
375 | 1d14ffa9 | bellard | err2:
|
376 | 1d14ffa9 | bellard | qemu_free (sw); |
377 | 1d14ffa9 | bellard | err1:
|
378 | 1d14ffa9 | bellard | return NULL; |
379 | 1d14ffa9 | bellard | } |
380 | 1d14ffa9 | bellard | |
381 | c0fe3827 | bellard | static void glue (audio_close_, TYPE) (AudioState *s, SW *sw) |
382 | c0fe3827 | bellard | { |
383 | c0fe3827 | bellard | glue (audio_pcm_sw_fini_, TYPE) (sw); |
384 | c0fe3827 | bellard | glue (audio_pcm_hw_del_sw_, TYPE) (sw); |
385 | c0fe3827 | bellard | glue (audio_pcm_hw_gc_, TYPE) (s, &sw->hw); |
386 | c0fe3827 | bellard | qemu_free (sw); |
387 | c0fe3827 | bellard | } |
388 | 571ec3d6 | bellard | |
389 | c0fe3827 | bellard | void glue (AUD_close_, TYPE) (QEMUSoundCard *card, SW *sw)
|
390 | 1d14ffa9 | bellard | { |
391 | 1d14ffa9 | bellard | if (sw) {
|
392 | c0fe3827 | bellard | if (audio_bug (AUDIO_FUNC, !card || !card->audio)) {
|
393 | c0fe3827 | bellard | dolog ("card=%p card->audio=%p\n",
|
394 | c0fe3827 | bellard | card, card ? card->audio : NULL);
|
395 | c0fe3827 | bellard | return;
|
396 | c0fe3827 | bellard | } |
397 | c0fe3827 | bellard | |
398 | c0fe3827 | bellard | glue (audio_close_, TYPE) (card->audio, sw); |
399 | 1d14ffa9 | bellard | } |
400 | 1d14ffa9 | bellard | } |
401 | 1d14ffa9 | bellard | |
402 | 1d14ffa9 | bellard | SW *glue (AUD_open_, TYPE) ( |
403 | c0fe3827 | bellard | QEMUSoundCard *card, |
404 | 1d14ffa9 | bellard | SW *sw, |
405 | 1d14ffa9 | bellard | const char *name, |
406 | 1d14ffa9 | bellard | void *callback_opaque ,
|
407 | 1d14ffa9 | bellard | audio_callback_fn_t callback_fn, |
408 | d929eba5 | bellard | audsettings_t *as |
409 | 1d14ffa9 | bellard | ) |
410 | 1d14ffa9 | bellard | { |
411 | c0fe3827 | bellard | AudioState *s; |
412 | 1d14ffa9 | bellard | #ifdef DAC
|
413 | 1d14ffa9 | bellard | int live = 0; |
414 | 1d14ffa9 | bellard | SW *old_sw = NULL;
|
415 | 1d14ffa9 | bellard | #endif
|
416 | 1d14ffa9 | bellard | |
417 | c0fe3827 | bellard | ldebug ("open %s, freq %d, nchannels %d, fmt %d\n",
|
418 | c0fe3827 | bellard | name, as->freq, as->nchannels, as->fmt); |
419 | c0fe3827 | bellard | |
420 | c0fe3827 | bellard | if (audio_bug (AUDIO_FUNC,
|
421 | c0fe3827 | bellard | !card || !card->audio || !name || !callback_fn || !as)) { |
422 | c0fe3827 | bellard | dolog ("card=%p card->audio=%p name=%p callback_fn=%p as=%p\n",
|
423 | c0fe3827 | bellard | card, card ? card->audio : NULL, name, callback_fn, as);
|
424 | 1d14ffa9 | bellard | goto fail;
|
425 | 1d14ffa9 | bellard | } |
426 | 1d14ffa9 | bellard | |
427 | c0fe3827 | bellard | s = card->audio; |
428 | c0fe3827 | bellard | |
429 | ec36b695 | bellard | if (audio_bug (AUDIO_FUNC, audio_validate_settings (as))) {
|
430 | c0fe3827 | bellard | audio_print_settings (as); |
431 | 1d14ffa9 | bellard | goto fail;
|
432 | 1d14ffa9 | bellard | } |
433 | 1d14ffa9 | bellard | |
434 | c0fe3827 | bellard | if (audio_bug (AUDIO_FUNC, !s->drv)) {
|
435 | c0fe3827 | bellard | dolog ("Can not open `%s' (no host audio driver)\n", name);
|
436 | 1d14ffa9 | bellard | goto fail;
|
437 | 1d14ffa9 | bellard | } |
438 | 1d14ffa9 | bellard | |
439 | c0fe3827 | bellard | if (sw && audio_pcm_info_eq (&sw->info, as)) {
|
440 | 1d14ffa9 | bellard | return sw;
|
441 | 1d14ffa9 | bellard | } |
442 | 1d14ffa9 | bellard | |
443 | 1d14ffa9 | bellard | #ifdef DAC
|
444 | c0fe3827 | bellard | if (conf.plive && sw && (!sw->active && !sw->empty)) {
|
445 | 1d14ffa9 | bellard | live = sw->total_hw_samples_mixed; |
446 | 1d14ffa9 | bellard | |
447 | 1d14ffa9 | bellard | #ifdef DEBUG_PLIVE
|
448 | c0fe3827 | bellard | dolog ("Replacing voice %s with %d live samples\n", SW_NAME (sw), live);
|
449 | 1d14ffa9 | bellard | dolog ("Old %s freq %d, bits %d, channels %d\n",
|
450 | c0fe3827 | bellard | SW_NAME (sw), sw->info.freq, sw->info.bits, sw->info.nchannels); |
451 | 1d14ffa9 | bellard | dolog ("New %s freq %d, bits %d, channels %d\n",
|
452 | c0fe3827 | bellard | name, |
453 | c0fe3827 | bellard | freq, |
454 | c0fe3827 | bellard | (fmt == AUD_FMT_S16 || fmt == AUD_FMT_U16) ? 16 : 8, |
455 | 1d14ffa9 | bellard | nchannels); |
456 | 1d14ffa9 | bellard | #endif
|
457 | 1d14ffa9 | bellard | |
458 | 1d14ffa9 | bellard | if (live) {
|
459 | 1d14ffa9 | bellard | old_sw = sw; |
460 | 1d14ffa9 | bellard | old_sw->callback.fn = NULL;
|
461 | 1d14ffa9 | bellard | sw = NULL;
|
462 | 1d14ffa9 | bellard | } |
463 | 1d14ffa9 | bellard | } |
464 | 1d14ffa9 | bellard | #endif
|
465 | 1d14ffa9 | bellard | |
466 | c0fe3827 | bellard | if (!glue (conf.fixed_, TYPE).enabled && sw) {
|
467 | c0fe3827 | bellard | glue (AUD_close_, TYPE) (card, sw); |
468 | 1d14ffa9 | bellard | sw = NULL;
|
469 | 1d14ffa9 | bellard | } |
470 | 1d14ffa9 | bellard | |
471 | 1d14ffa9 | bellard | if (sw) {
|
472 | 1d14ffa9 | bellard | HW *hw = sw->hw; |
473 | 1d14ffa9 | bellard | |
474 | 1d14ffa9 | bellard | if (!hw) {
|
475 | c0fe3827 | bellard | dolog ("Internal logic error voice `%s' has no hardware store\n",
|
476 | c0fe3827 | bellard | SW_NAME (sw)); |
477 | 1d14ffa9 | bellard | goto fail;
|
478 | 1d14ffa9 | bellard | } |
479 | 1d14ffa9 | bellard | |
480 | 571ec3d6 | bellard | glue (audio_pcm_sw_fini_, TYPE) (sw); |
481 | d929eba5 | bellard | if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as)) {
|
482 | 1d14ffa9 | bellard | goto fail;
|
483 | 1d14ffa9 | bellard | } |
484 | 1d14ffa9 | bellard | } |
485 | 1d14ffa9 | bellard | else {
|
486 | d929eba5 | bellard | sw = glue (audio_pcm_create_voice_pair_, TYPE) (s, name, as); |
487 | 1d14ffa9 | bellard | if (!sw) {
|
488 | c0fe3827 | bellard | dolog ("Failed to create voice `%s'\n", name);
|
489 | 571ec3d6 | bellard | return NULL; |
490 | 1d14ffa9 | bellard | } |
491 | 1d14ffa9 | bellard | } |
492 | 1d14ffa9 | bellard | |
493 | 1d14ffa9 | bellard | if (sw) {
|
494 | 1d14ffa9 | bellard | sw->vol = nominal_volume; |
495 | 1d14ffa9 | bellard | sw->callback.fn = callback_fn; |
496 | 1d14ffa9 | bellard | sw->callback.opaque = callback_opaque; |
497 | 1d14ffa9 | bellard | |
498 | 1d14ffa9 | bellard | #ifdef DAC
|
499 | 1d14ffa9 | bellard | if (live) {
|
500 | 1d14ffa9 | bellard | int mixed =
|
501 | 1d14ffa9 | bellard | (live << old_sw->info.shift) |
502 | 1d14ffa9 | bellard | * old_sw->info.bytes_per_second |
503 | 1d14ffa9 | bellard | / sw->info.bytes_per_second; |
504 | 1d14ffa9 | bellard | |
505 | 1d14ffa9 | bellard | #ifdef DEBUG_PLIVE
|
506 | 1d14ffa9 | bellard | dolog ("Silence will be mixed %d\n", mixed);
|
507 | 1d14ffa9 | bellard | #endif
|
508 | 1d14ffa9 | bellard | sw->total_hw_samples_mixed += mixed; |
509 | 1d14ffa9 | bellard | } |
510 | 1d14ffa9 | bellard | #endif
|
511 | 1d14ffa9 | bellard | |
512 | 1d14ffa9 | bellard | #ifdef DEBUG_AUDIO
|
513 | 1d14ffa9 | bellard | dolog ("%s\n", name);
|
514 | 1d14ffa9 | bellard | audio_pcm_print_info ("hw", &sw->hw->info);
|
515 | 1d14ffa9 | bellard | audio_pcm_print_info ("sw", &sw->info);
|
516 | 1d14ffa9 | bellard | #endif
|
517 | 1d14ffa9 | bellard | } |
518 | 1d14ffa9 | bellard | |
519 | 1d14ffa9 | bellard | return sw;
|
520 | 1d14ffa9 | bellard | |
521 | 1d14ffa9 | bellard | fail:
|
522 | c0fe3827 | bellard | glue (AUD_close_, TYPE) (card, sw); |
523 | 1d14ffa9 | bellard | return NULL; |
524 | 1d14ffa9 | bellard | } |
525 | 1d14ffa9 | bellard | |
526 | 1d14ffa9 | bellard | int glue (AUD_is_active_, TYPE) (SW *sw)
|
527 | 1d14ffa9 | bellard | { |
528 | 1d14ffa9 | bellard | return sw ? sw->active : 0; |
529 | 1d14ffa9 | bellard | } |
530 | 1d14ffa9 | bellard | |
531 | 1d14ffa9 | bellard | void glue (AUD_init_time_stamp_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts)
|
532 | 1d14ffa9 | bellard | { |
533 | 1d14ffa9 | bellard | if (!sw) {
|
534 | 1d14ffa9 | bellard | return;
|
535 | 1d14ffa9 | bellard | } |
536 | 1d14ffa9 | bellard | |
537 | 1d14ffa9 | bellard | ts->old_ts = sw->hw->ts_helper; |
538 | 1d14ffa9 | bellard | } |
539 | 1d14ffa9 | bellard | |
540 | c0fe3827 | bellard | uint64_t glue (AUD_get_elapsed_usec_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts) |
541 | 1d14ffa9 | bellard | { |
542 | 1d14ffa9 | bellard | uint64_t delta, cur_ts, old_ts; |
543 | 1d14ffa9 | bellard | |
544 | 1d14ffa9 | bellard | if (!sw) {
|
545 | 1d14ffa9 | bellard | return 0; |
546 | 1d14ffa9 | bellard | } |
547 | 1d14ffa9 | bellard | |
548 | 1d14ffa9 | bellard | cur_ts = sw->hw->ts_helper; |
549 | 1d14ffa9 | bellard | old_ts = ts->old_ts; |
550 | 8ead62cf | bellard | /* dolog ("cur %lld old %lld\n", cur_ts, old_ts); */
|
551 | 1d14ffa9 | bellard | |
552 | 1d14ffa9 | bellard | if (cur_ts >= old_ts) {
|
553 | 1d14ffa9 | bellard | delta = cur_ts - old_ts; |
554 | 1d14ffa9 | bellard | } |
555 | 1d14ffa9 | bellard | else {
|
556 | 1d14ffa9 | bellard | delta = UINT64_MAX - old_ts + cur_ts; |
557 | 1d14ffa9 | bellard | } |
558 | 1d14ffa9 | bellard | |
559 | 1d14ffa9 | bellard | if (!delta) {
|
560 | 1d14ffa9 | bellard | return 0; |
561 | 1d14ffa9 | bellard | } |
562 | 1d14ffa9 | bellard | |
563 | 1d14ffa9 | bellard | return (delta * sw->hw->info.freq) / 1000000; |
564 | 1d14ffa9 | bellard | } |
565 | 1d14ffa9 | bellard | |
566 | 1d14ffa9 | bellard | #undef TYPE
|
567 | 1d14ffa9 | bellard | #undef HW
|
568 | 1d14ffa9 | bellard | #undef SW
|
569 | 571ec3d6 | bellard | #undef HWBUF
|
570 | 571ec3d6 | bellard | #undef NAME |