root / audio / audio_template.h @ 4f4cc0ef
History | View | Annotate | Download (13.2 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 | 1a7dafce | malc | static void glue (audio_init_nb_voices_, TYPE) (struct audio_driver *drv) |
40 | c0fe3827 | bellard | { |
41 | 1a7dafce | malc | AudioState *s = &glob_audio_state; |
42 | 571ec3d6 | bellard | int max_voices = glue (drv->max_voices_, TYPE);
|
43 | 571ec3d6 | bellard | int voice_size = glue (drv->voice_size_, TYPE);
|
44 | c0fe3827 | bellard | |
45 | 571ec3d6 | bellard | if (glue (s->nb_hw_voices_, TYPE) > max_voices) {
|
46 | 571ec3d6 | bellard | if (!max_voices) {
|
47 | 571ec3d6 | bellard | #ifdef DAC
|
48 | 571ec3d6 | bellard | dolog ("Driver `%s' does not support " NAME "\n", drv->name); |
49 | 571ec3d6 | bellard | #endif
|
50 | 571ec3d6 | bellard | } |
51 | 571ec3d6 | bellard | else {
|
52 | 571ec3d6 | bellard | dolog ("Driver `%s' does not support %d " NAME " voices, max %d\n", |
53 | 571ec3d6 | bellard | drv->name, |
54 | 571ec3d6 | bellard | glue (s->nb_hw_voices_, TYPE), |
55 | 571ec3d6 | bellard | max_voices); |
56 | 571ec3d6 | bellard | } |
57 | 571ec3d6 | bellard | glue (s->nb_hw_voices_, TYPE) = max_voices; |
58 | c0fe3827 | bellard | } |
59 | c0fe3827 | bellard | |
60 | 571ec3d6 | bellard | if (audio_bug (AUDIO_FUNC, !voice_size && max_voices)) {
|
61 | 571ec3d6 | bellard | dolog ("drv=`%s' voice_size=0 max_voices=%d\n",
|
62 | 571ec3d6 | bellard | drv->name, max_voices); |
63 | 571ec3d6 | bellard | glue (s->nb_hw_voices_, TYPE) = 0;
|
64 | 571ec3d6 | bellard | } |
65 | 571ec3d6 | bellard | |
66 | 571ec3d6 | bellard | if (audio_bug (AUDIO_FUNC, voice_size && !max_voices)) {
|
67 | 571ec3d6 | bellard | dolog ("drv=`%s' voice_size=%d max_voices=0\n",
|
68 | 571ec3d6 | bellard | drv->name, voice_size); |
69 | 571ec3d6 | bellard | } |
70 | 571ec3d6 | bellard | } |
71 | 571ec3d6 | bellard | |
72 | 571ec3d6 | bellard | static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw) |
73 | 571ec3d6 | bellard | { |
74 | 571ec3d6 | bellard | if (HWBUF) {
|
75 | 571ec3d6 | bellard | qemu_free (HWBUF); |
76 | 571ec3d6 | bellard | } |
77 | 571ec3d6 | bellard | |
78 | 571ec3d6 | bellard | HWBUF = NULL;
|
79 | 571ec3d6 | bellard | } |
80 | 571ec3d6 | bellard | |
81 | 571ec3d6 | bellard | static int glue (audio_pcm_hw_alloc_resources_, TYPE) (HW *hw) |
82 | 571ec3d6 | bellard | { |
83 | 1ea879e5 | malc | HWBUF = audio_calloc (AUDIO_FUNC, hw->samples, sizeof (struct st_sample)); |
84 | 571ec3d6 | bellard | if (!HWBUF) {
|
85 | 571ec3d6 | bellard | dolog ("Could not allocate " NAME " buffer (%d samples)\n", |
86 | 571ec3d6 | bellard | hw->samples); |
87 | c0fe3827 | bellard | return -1; |
88 | c0fe3827 | bellard | } |
89 | c0fe3827 | bellard | |
90 | 571ec3d6 | bellard | return 0; |
91 | 571ec3d6 | bellard | } |
92 | 571ec3d6 | bellard | |
93 | 571ec3d6 | bellard | static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw) |
94 | 571ec3d6 | bellard | { |
95 | 571ec3d6 | bellard | if (sw->buf) {
|
96 | 571ec3d6 | bellard | qemu_free (sw->buf); |
97 | 571ec3d6 | bellard | } |
98 | 571ec3d6 | bellard | |
99 | 571ec3d6 | bellard | if (sw->rate) {
|
100 | 571ec3d6 | bellard | st_rate_stop (sw->rate); |
101 | 571ec3d6 | bellard | } |
102 | 571ec3d6 | bellard | |
103 | 571ec3d6 | bellard | sw->buf = NULL;
|
104 | 571ec3d6 | bellard | sw->rate = NULL;
|
105 | 571ec3d6 | bellard | } |
106 | 571ec3d6 | bellard | |
107 | 571ec3d6 | bellard | static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw) |
108 | 571ec3d6 | bellard | { |
109 | 571ec3d6 | bellard | int samples;
|
110 | 571ec3d6 | bellard | |
111 | c0fe3827 | bellard | #ifdef DAC
|
112 | 571ec3d6 | bellard | samples = sw->hw->samples; |
113 | c0fe3827 | bellard | #else
|
114 | 571ec3d6 | bellard | samples = ((int64_t) sw->hw->samples << 32) / sw->ratio;
|
115 | c0fe3827 | bellard | #endif
|
116 | c0fe3827 | bellard | |
117 | 1ea879e5 | malc | sw->buf = audio_calloc (AUDIO_FUNC, samples, sizeof (struct st_sample)); |
118 | 571ec3d6 | bellard | if (!sw->buf) {
|
119 | 571ec3d6 | bellard | dolog ("Could not allocate buffer for `%s' (%d samples)\n",
|
120 | 571ec3d6 | bellard | SW_NAME (sw), samples); |
121 | c0fe3827 | bellard | return -1; |
122 | c0fe3827 | bellard | } |
123 | c0fe3827 | bellard | |
124 | 571ec3d6 | bellard | #ifdef DAC
|
125 | 571ec3d6 | bellard | sw->rate = st_rate_start (sw->info.freq, sw->hw->info.freq); |
126 | 571ec3d6 | bellard | #else
|
127 | 571ec3d6 | bellard | sw->rate = st_rate_start (sw->hw->info.freq, sw->info.freq); |
128 | 571ec3d6 | bellard | #endif
|
129 | 571ec3d6 | bellard | if (!sw->rate) {
|
130 | 571ec3d6 | bellard | qemu_free (sw->buf); |
131 | 571ec3d6 | bellard | sw->buf = NULL;
|
132 | 571ec3d6 | bellard | return -1; |
133 | 571ec3d6 | bellard | } |
134 | c0fe3827 | bellard | return 0; |
135 | c0fe3827 | bellard | } |
136 | c0fe3827 | bellard | |
137 | 571ec3d6 | bellard | static int glue (audio_pcm_sw_init_, TYPE) ( |
138 | 571ec3d6 | bellard | SW *sw, |
139 | 571ec3d6 | bellard | HW *hw, |
140 | 571ec3d6 | bellard | const char *name, |
141 | 1ea879e5 | malc | struct audsettings *as
|
142 | 571ec3d6 | bellard | ) |
143 | 571ec3d6 | bellard | { |
144 | 571ec3d6 | bellard | int err;
|
145 | 571ec3d6 | bellard | |
146 | d929eba5 | bellard | audio_pcm_init_info (&sw->info, as); |
147 | 571ec3d6 | bellard | sw->hw = hw; |
148 | 571ec3d6 | bellard | sw->active = 0;
|
149 | 571ec3d6 | bellard | #ifdef DAC
|
150 | 571ec3d6 | bellard | sw->ratio = ((int64_t) sw->hw->info.freq << 32) / sw->info.freq;
|
151 | 571ec3d6 | bellard | sw->total_hw_samples_mixed = 0;
|
152 | 571ec3d6 | bellard | sw->empty = 1;
|
153 | 571ec3d6 | bellard | #else
|
154 | 571ec3d6 | bellard | sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq;
|
155 | 571ec3d6 | bellard | #endif
|
156 | 571ec3d6 | bellard | |
157 | 571ec3d6 | bellard | #ifdef DAC
|
158 | 571ec3d6 | bellard | sw->conv = mixeng_conv |
159 | 571ec3d6 | bellard | #else
|
160 | 571ec3d6 | bellard | sw->clip = mixeng_clip |
161 | 571ec3d6 | bellard | #endif
|
162 | 571ec3d6 | bellard | [sw->info.nchannels == 2]
|
163 | 571ec3d6 | bellard | [sw->info.sign] |
164 | d929eba5 | bellard | [sw->info.swap_endianness] |
165 | f941aa25 | ths | [audio_bits_to_index (sw->info.bits)]; |
166 | 571ec3d6 | bellard | |
167 | 571ec3d6 | bellard | sw->name = qemu_strdup (name); |
168 | 571ec3d6 | bellard | err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw); |
169 | 571ec3d6 | bellard | if (err) {
|
170 | 571ec3d6 | bellard | qemu_free (sw->name); |
171 | 571ec3d6 | bellard | sw->name = NULL;
|
172 | 571ec3d6 | bellard | } |
173 | 571ec3d6 | bellard | return err;
|
174 | 571ec3d6 | bellard | } |
175 | 571ec3d6 | bellard | |
176 | 1d14ffa9 | bellard | static void glue (audio_pcm_sw_fini_, TYPE) (SW *sw) |
177 | 1d14ffa9 | bellard | { |
178 | 1d14ffa9 | bellard | glue (audio_pcm_sw_free_resources_, TYPE) (sw); |
179 | 1d14ffa9 | bellard | if (sw->name) {
|
180 | 1d14ffa9 | bellard | qemu_free (sw->name); |
181 | 1d14ffa9 | bellard | sw->name = NULL;
|
182 | 1d14ffa9 | bellard | } |
183 | 1d14ffa9 | bellard | } |
184 | 1d14ffa9 | bellard | |
185 | 1d14ffa9 | bellard | static void glue (audio_pcm_hw_add_sw_, TYPE) (HW *hw, SW *sw) |
186 | 1d14ffa9 | bellard | { |
187 | 72cf2d4f | Blue Swirl | QLIST_INSERT_HEAD (&hw->sw_head, sw, entries); |
188 | 1d14ffa9 | bellard | } |
189 | 1d14ffa9 | bellard | |
190 | 1d14ffa9 | bellard | static void glue (audio_pcm_hw_del_sw_, TYPE) (SW *sw) |
191 | 1d14ffa9 | bellard | { |
192 | 72cf2d4f | Blue Swirl | QLIST_REMOVE (sw, entries); |
193 | 1d14ffa9 | bellard | } |
194 | 1d14ffa9 | bellard | |
195 | 1a7dafce | malc | static void glue (audio_pcm_hw_gc_, TYPE) (HW **hwp) |
196 | 1d14ffa9 | bellard | { |
197 | 1a7dafce | malc | AudioState *s = &glob_audio_state; |
198 | c0fe3827 | bellard | HW *hw = *hwp; |
199 | 1d14ffa9 | bellard | |
200 | 1d14ffa9 | bellard | if (!hw->sw_head.lh_first) {
|
201 | 8ead62cf | bellard | #ifdef DAC
|
202 | 8ead62cf | bellard | audio_detach_capture (hw); |
203 | 8ead62cf | bellard | #endif
|
204 | 72cf2d4f | Blue Swirl | QLIST_REMOVE (hw, entries); |
205 | c0fe3827 | bellard | glue (s->nb_hw_voices_, TYPE) += 1;
|
206 | c0fe3827 | bellard | glue (audio_pcm_hw_free_resources_ ,TYPE) (hw); |
207 | c0fe3827 | bellard | glue (hw->pcm_ops->fini_, TYPE) (hw); |
208 | c0fe3827 | bellard | qemu_free (hw); |
209 | c0fe3827 | bellard | *hwp = NULL;
|
210 | 1d14ffa9 | bellard | } |
211 | 1d14ffa9 | bellard | } |
212 | 1d14ffa9 | bellard | |
213 | 1a7dafce | malc | static HW *glue (audio_pcm_hw_find_any_, TYPE) (HW *hw)
|
214 | 1d14ffa9 | bellard | { |
215 | 1a7dafce | malc | AudioState *s = &glob_audio_state; |
216 | 1a7dafce | malc | return hw ? hw->entries.le_next : glue (s->hw_head_, TYPE).lh_first;
|
217 | 1d14ffa9 | bellard | } |
218 | 1d14ffa9 | bellard | |
219 | 1a7dafce | malc | static HW *glue (audio_pcm_hw_find_any_enabled_, TYPE) (HW *hw)
|
220 | 1d14ffa9 | bellard | { |
221 | 1a7dafce | malc | while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (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 | 1d14ffa9 | bellard | HW *hw, |
231 | 1ea879e5 | malc | struct audsettings *as
|
232 | 1d14ffa9 | bellard | ) |
233 | 1d14ffa9 | bellard | { |
234 | 1a7dafce | malc | while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) {
|
235 | c0fe3827 | bellard | if (audio_pcm_info_eq (&hw->info, as)) {
|
236 | 1d14ffa9 | bellard | return hw;
|
237 | 1d14ffa9 | bellard | } |
238 | 1d14ffa9 | bellard | } |
239 | 1d14ffa9 | bellard | return NULL; |
240 | 1d14ffa9 | bellard | } |
241 | 1d14ffa9 | bellard | |
242 | 1a7dafce | malc | static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as) |
243 | 1d14ffa9 | bellard | { |
244 | 1d14ffa9 | bellard | HW *hw; |
245 | 1a7dafce | malc | AudioState *s = &glob_audio_state; |
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 | 72cf2d4f | Blue Swirl | QLIST_INIT (&hw->sw_head); |
271 | 8ead62cf | bellard | #ifdef DAC
|
272 | 72cf2d4f | Blue Swirl | QLIST_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 | 72cf2d4f | Blue Swirl | QLIST_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 | 1a7dafce | malc | audio_attach_capture (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 | 1a7dafce | malc | static HW *glue (audio_pcm_hw_add_, TYPE) (struct audsettings *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 | 1a7dafce | malc | hw = glue (audio_pcm_hw_add_new_, TYPE) (as); |
317 | 1d14ffa9 | bellard | if (hw) {
|
318 | 1d14ffa9 | bellard | return hw;
|
319 | 1d14ffa9 | bellard | } |
320 | 1d14ffa9 | bellard | } |
321 | 1d14ffa9 | bellard | |
322 | 1a7dafce | malc | hw = glue (audio_pcm_hw_find_specific_, TYPE) (NULL, as);
|
323 | 1d14ffa9 | bellard | if (hw) {
|
324 | 1d14ffa9 | bellard | return hw;
|
325 | 1d14ffa9 | bellard | } |
326 | 1d14ffa9 | bellard | |
327 | 1a7dafce | malc | hw = glue (audio_pcm_hw_add_new_, TYPE) (as); |
328 | 1d14ffa9 | bellard | if (hw) {
|
329 | 1d14ffa9 | bellard | return hw;
|
330 | 1d14ffa9 | bellard | } |
331 | 1d14ffa9 | bellard | |
332 | 1a7dafce | malc | return glue (audio_pcm_hw_find_any_, TYPE) (NULL); |
333 | 1d14ffa9 | bellard | } |
334 | 1d14ffa9 | bellard | |
335 | 1d14ffa9 | bellard | static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
|
336 | c0fe3827 | bellard | const char *sw_name, |
337 | 1ea879e5 | malc | struct audsettings *as
|
338 | 1d14ffa9 | bellard | ) |
339 | 1d14ffa9 | bellard | { |
340 | 1d14ffa9 | bellard | SW *sw; |
341 | 1d14ffa9 | bellard | HW *hw; |
342 | 1ea879e5 | malc | struct audsettings hw_as;
|
343 | 1d14ffa9 | bellard | |
344 | c0fe3827 | bellard | if (glue (conf.fixed_, TYPE).enabled) {
|
345 | c0fe3827 | bellard | hw_as = glue (conf.fixed_, TYPE).settings; |
346 | c0fe3827 | bellard | } |
347 | c0fe3827 | bellard | else {
|
348 | c0fe3827 | bellard | hw_as = *as; |
349 | 1d14ffa9 | bellard | } |
350 | 1d14ffa9 | bellard | |
351 | c0fe3827 | bellard | sw = audio_calloc (AUDIO_FUNC, 1, sizeof (*sw)); |
352 | 1d14ffa9 | bellard | if (!sw) {
|
353 | e7cad338 | bellard | dolog ("Could not allocate soft voice `%s' (%zu bytes)\n",
|
354 | c0fe3827 | bellard | sw_name ? sw_name : "unknown", sizeof (*sw)); |
355 | 1d14ffa9 | bellard | goto err1;
|
356 | 1d14ffa9 | bellard | } |
357 | 1d14ffa9 | bellard | |
358 | 1a7dafce | malc | hw = glue (audio_pcm_hw_add_, TYPE) (&hw_as); |
359 | 1d14ffa9 | bellard | if (!hw) {
|
360 | 1d14ffa9 | bellard | goto err2;
|
361 | 1d14ffa9 | bellard | } |
362 | 1d14ffa9 | bellard | |
363 | 1d14ffa9 | bellard | glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw); |
364 | 1d14ffa9 | bellard | |
365 | d929eba5 | bellard | if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as)) {
|
366 | 1d14ffa9 | bellard | goto err3;
|
367 | 1d14ffa9 | bellard | } |
368 | 1d14ffa9 | bellard | |
369 | 1d14ffa9 | bellard | return sw;
|
370 | 1d14ffa9 | bellard | |
371 | 1d14ffa9 | bellard | err3:
|
372 | 1d14ffa9 | bellard | glue (audio_pcm_hw_del_sw_, TYPE) (sw); |
373 | 1a7dafce | malc | glue (audio_pcm_hw_gc_, TYPE) (&hw); |
374 | 1d14ffa9 | bellard | err2:
|
375 | 1d14ffa9 | bellard | qemu_free (sw); |
376 | 1d14ffa9 | bellard | err1:
|
377 | 1d14ffa9 | bellard | return NULL; |
378 | 1d14ffa9 | bellard | } |
379 | 1d14ffa9 | bellard | |
380 | 1a7dafce | malc | static void glue (audio_close_, TYPE) (SW *sw) |
381 | c0fe3827 | bellard | { |
382 | c0fe3827 | bellard | glue (audio_pcm_sw_fini_, TYPE) (sw); |
383 | c0fe3827 | bellard | glue (audio_pcm_hw_del_sw_, TYPE) (sw); |
384 | 1a7dafce | malc | glue (audio_pcm_hw_gc_, TYPE) (&sw->hw); |
385 | c0fe3827 | bellard | qemu_free (sw); |
386 | c0fe3827 | bellard | } |
387 | 571ec3d6 | bellard | |
388 | c0fe3827 | bellard | void glue (AUD_close_, TYPE) (QEMUSoundCard *card, SW *sw)
|
389 | 1d14ffa9 | bellard | { |
390 | 1d14ffa9 | bellard | if (sw) {
|
391 | 1a7dafce | malc | if (audio_bug (AUDIO_FUNC, !card)) {
|
392 | 1a7dafce | malc | dolog ("card=%p\n", card);
|
393 | c0fe3827 | bellard | return;
|
394 | c0fe3827 | bellard | } |
395 | c0fe3827 | bellard | |
396 | 1a7dafce | malc | glue (audio_close_, TYPE) (sw); |
397 | 1d14ffa9 | bellard | } |
398 | 1d14ffa9 | bellard | } |
399 | 1d14ffa9 | bellard | |
400 | 1d14ffa9 | bellard | SW *glue (AUD_open_, TYPE) ( |
401 | c0fe3827 | bellard | QEMUSoundCard *card, |
402 | 1d14ffa9 | bellard | SW *sw, |
403 | 1d14ffa9 | bellard | const char *name, |
404 | 1d14ffa9 | bellard | void *callback_opaque ,
|
405 | 1d14ffa9 | bellard | audio_callback_fn_t callback_fn, |
406 | 1ea879e5 | malc | struct audsettings *as
|
407 | 1d14ffa9 | bellard | ) |
408 | 1d14ffa9 | bellard | { |
409 | 1a7dafce | malc | AudioState *s = &glob_audio_state; |
410 | 1d14ffa9 | bellard | #ifdef DAC
|
411 | 1d14ffa9 | bellard | int live = 0; |
412 | 1d14ffa9 | bellard | SW *old_sw = NULL;
|
413 | 1d14ffa9 | bellard | #endif
|
414 | 1d14ffa9 | bellard | |
415 | c0fe3827 | bellard | ldebug ("open %s, freq %d, nchannels %d, fmt %d\n",
|
416 | c0fe3827 | bellard | name, as->freq, as->nchannels, as->fmt); |
417 | c0fe3827 | bellard | |
418 | 1a7dafce | malc | if (audio_bug (AUDIO_FUNC, !card || !name || !callback_fn || !as)) {
|
419 | 1a7dafce | malc | dolog ("card=%p name=%p callback_fn=%p as=%p\n",
|
420 | 1a7dafce | malc | card, name, callback_fn, as); |
421 | 1d14ffa9 | bellard | goto fail;
|
422 | 1d14ffa9 | bellard | } |
423 | 1d14ffa9 | bellard | |
424 | ec36b695 | bellard | if (audio_bug (AUDIO_FUNC, audio_validate_settings (as))) {
|
425 | c0fe3827 | bellard | audio_print_settings (as); |
426 | 1d14ffa9 | bellard | goto fail;
|
427 | 1d14ffa9 | bellard | } |
428 | 1d14ffa9 | bellard | |
429 | c0fe3827 | bellard | if (audio_bug (AUDIO_FUNC, !s->drv)) {
|
430 | c0fe3827 | bellard | dolog ("Can not open `%s' (no host audio driver)\n", name);
|
431 | 1d14ffa9 | bellard | goto fail;
|
432 | 1d14ffa9 | bellard | } |
433 | 1d14ffa9 | bellard | |
434 | c0fe3827 | bellard | if (sw && audio_pcm_info_eq (&sw->info, as)) {
|
435 | 1d14ffa9 | bellard | return sw;
|
436 | 1d14ffa9 | bellard | } |
437 | 1d14ffa9 | bellard | |
438 | 1d14ffa9 | bellard | #ifdef DAC
|
439 | c0fe3827 | bellard | if (conf.plive && sw && (!sw->active && !sw->empty)) {
|
440 | 1d14ffa9 | bellard | live = sw->total_hw_samples_mixed; |
441 | 1d14ffa9 | bellard | |
442 | 1d14ffa9 | bellard | #ifdef DEBUG_PLIVE
|
443 | c0fe3827 | bellard | dolog ("Replacing voice %s with %d live samples\n", SW_NAME (sw), live);
|
444 | 1d14ffa9 | bellard | dolog ("Old %s freq %d, bits %d, channels %d\n",
|
445 | c0fe3827 | bellard | SW_NAME (sw), sw->info.freq, sw->info.bits, sw->info.nchannels); |
446 | 1d14ffa9 | bellard | dolog ("New %s freq %d, bits %d, channels %d\n",
|
447 | c0fe3827 | bellard | name, |
448 | c0fe3827 | bellard | freq, |
449 | c0fe3827 | bellard | (fmt == AUD_FMT_S16 || fmt == AUD_FMT_U16) ? 16 : 8, |
450 | 1d14ffa9 | bellard | nchannels); |
451 | 1d14ffa9 | bellard | #endif
|
452 | 1d14ffa9 | bellard | |
453 | 1d14ffa9 | bellard | if (live) {
|
454 | 1d14ffa9 | bellard | old_sw = sw; |
455 | 1d14ffa9 | bellard | old_sw->callback.fn = NULL;
|
456 | 1d14ffa9 | bellard | sw = NULL;
|
457 | 1d14ffa9 | bellard | } |
458 | 1d14ffa9 | bellard | } |
459 | 1d14ffa9 | bellard | #endif
|
460 | 1d14ffa9 | bellard | |
461 | c0fe3827 | bellard | if (!glue (conf.fixed_, TYPE).enabled && sw) {
|
462 | c0fe3827 | bellard | glue (AUD_close_, TYPE) (card, sw); |
463 | 1d14ffa9 | bellard | sw = NULL;
|
464 | 1d14ffa9 | bellard | } |
465 | 1d14ffa9 | bellard | |
466 | 1d14ffa9 | bellard | if (sw) {
|
467 | 1d14ffa9 | bellard | HW *hw = sw->hw; |
468 | 1d14ffa9 | bellard | |
469 | 1d14ffa9 | bellard | if (!hw) {
|
470 | c0fe3827 | bellard | dolog ("Internal logic error voice `%s' has no hardware store\n",
|
471 | c0fe3827 | bellard | SW_NAME (sw)); |
472 | 1d14ffa9 | bellard | goto fail;
|
473 | 1d14ffa9 | bellard | } |
474 | 1d14ffa9 | bellard | |
475 | 571ec3d6 | bellard | glue (audio_pcm_sw_fini_, TYPE) (sw); |
476 | d929eba5 | bellard | if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as)) {
|
477 | 1d14ffa9 | bellard | goto fail;
|
478 | 1d14ffa9 | bellard | } |
479 | 1d14ffa9 | bellard | } |
480 | 1d14ffa9 | bellard | else {
|
481 | 1a7dafce | malc | sw = glue (audio_pcm_create_voice_pair_, TYPE) (name, as); |
482 | 1d14ffa9 | bellard | if (!sw) {
|
483 | c0fe3827 | bellard | dolog ("Failed to create voice `%s'\n", name);
|
484 | 571ec3d6 | bellard | return NULL; |
485 | 1d14ffa9 | bellard | } |
486 | 1d14ffa9 | bellard | } |
487 | 1d14ffa9 | bellard | |
488 | 1d14ffa9 | bellard | if (sw) {
|
489 | 1a7dafce | malc | sw->card = card; |
490 | 1d14ffa9 | bellard | sw->vol = nominal_volume; |
491 | 1d14ffa9 | bellard | sw->callback.fn = callback_fn; |
492 | 1d14ffa9 | bellard | sw->callback.opaque = callback_opaque; |
493 | 1d14ffa9 | bellard | |
494 | 1d14ffa9 | bellard | #ifdef DAC
|
495 | 1d14ffa9 | bellard | if (live) {
|
496 | 1d14ffa9 | bellard | int mixed =
|
497 | 1d14ffa9 | bellard | (live << old_sw->info.shift) |
498 | 1d14ffa9 | bellard | * old_sw->info.bytes_per_second |
499 | 1d14ffa9 | bellard | / sw->info.bytes_per_second; |
500 | 1d14ffa9 | bellard | |
501 | 1d14ffa9 | bellard | #ifdef DEBUG_PLIVE
|
502 | 1d14ffa9 | bellard | dolog ("Silence will be mixed %d\n", mixed);
|
503 | 1d14ffa9 | bellard | #endif
|
504 | 1d14ffa9 | bellard | sw->total_hw_samples_mixed += mixed; |
505 | 1d14ffa9 | bellard | } |
506 | 1d14ffa9 | bellard | #endif
|
507 | 1d14ffa9 | bellard | |
508 | 1d14ffa9 | bellard | #ifdef DEBUG_AUDIO
|
509 | 1d14ffa9 | bellard | dolog ("%s\n", name);
|
510 | 1d14ffa9 | bellard | audio_pcm_print_info ("hw", &sw->hw->info);
|
511 | 1d14ffa9 | bellard | audio_pcm_print_info ("sw", &sw->info);
|
512 | 1d14ffa9 | bellard | #endif
|
513 | 1d14ffa9 | bellard | } |
514 | 1d14ffa9 | bellard | |
515 | 1d14ffa9 | bellard | return sw;
|
516 | 1d14ffa9 | bellard | |
517 | 1d14ffa9 | bellard | fail:
|
518 | c0fe3827 | bellard | glue (AUD_close_, TYPE) (card, sw); |
519 | 1d14ffa9 | bellard | return NULL; |
520 | 1d14ffa9 | bellard | } |
521 | 1d14ffa9 | bellard | |
522 | 1d14ffa9 | bellard | int glue (AUD_is_active_, TYPE) (SW *sw)
|
523 | 1d14ffa9 | bellard | { |
524 | 1d14ffa9 | bellard | return sw ? sw->active : 0; |
525 | 1d14ffa9 | bellard | } |
526 | 1d14ffa9 | bellard | |
527 | 1d14ffa9 | bellard | void glue (AUD_init_time_stamp_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts)
|
528 | 1d14ffa9 | bellard | { |
529 | 1d14ffa9 | bellard | if (!sw) {
|
530 | 1d14ffa9 | bellard | return;
|
531 | 1d14ffa9 | bellard | } |
532 | 1d14ffa9 | bellard | |
533 | 1d14ffa9 | bellard | ts->old_ts = sw->hw->ts_helper; |
534 | 1d14ffa9 | bellard | } |
535 | 1d14ffa9 | bellard | |
536 | c0fe3827 | bellard | uint64_t glue (AUD_get_elapsed_usec_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts) |
537 | 1d14ffa9 | bellard | { |
538 | 1d14ffa9 | bellard | uint64_t delta, cur_ts, old_ts; |
539 | 1d14ffa9 | bellard | |
540 | 1d14ffa9 | bellard | if (!sw) {
|
541 | 1d14ffa9 | bellard | return 0; |
542 | 1d14ffa9 | bellard | } |
543 | 1d14ffa9 | bellard | |
544 | 1d14ffa9 | bellard | cur_ts = sw->hw->ts_helper; |
545 | 1d14ffa9 | bellard | old_ts = ts->old_ts; |
546 | 8ead62cf | bellard | /* dolog ("cur %lld old %lld\n", cur_ts, old_ts); */
|
547 | 1d14ffa9 | bellard | |
548 | 1d14ffa9 | bellard | if (cur_ts >= old_ts) {
|
549 | 1d14ffa9 | bellard | delta = cur_ts - old_ts; |
550 | 1d14ffa9 | bellard | } |
551 | 1d14ffa9 | bellard | else {
|
552 | 1d14ffa9 | bellard | delta = UINT64_MAX - old_ts + cur_ts; |
553 | 1d14ffa9 | bellard | } |
554 | 1d14ffa9 | bellard | |
555 | 1d14ffa9 | bellard | if (!delta) {
|
556 | 1d14ffa9 | bellard | return 0; |
557 | 1d14ffa9 | bellard | } |
558 | 1d14ffa9 | bellard | |
559 | 4f4cc0ef | malc | return muldiv64 (delta, sw->hw->info.freq, 1000000); |
560 | 1d14ffa9 | bellard | } |
561 | 1d14ffa9 | bellard | |
562 | 1d14ffa9 | bellard | #undef TYPE
|
563 | 1d14ffa9 | bellard | #undef HW
|
564 | 1d14ffa9 | bellard | #undef SW
|
565 | 571ec3d6 | bellard | #undef HWBUF
|
566 | 571ec3d6 | bellard | #undef NAME |