root / audio / audio_template.h @ 1b2b0af5
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 | 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 | 571ec3d6 | bellard | audsettings_t *as, |
144 | 571ec3d6 | bellard | int endian
|
145 | 571ec3d6 | bellard | ) |
146 | 571ec3d6 | bellard | { |
147 | 571ec3d6 | bellard | int err;
|
148 | 571ec3d6 | bellard | |
149 | 571ec3d6 | bellard | audio_pcm_init_info (&sw->info, as, audio_need_to_swap_endian (endian)); |
150 | 571ec3d6 | bellard | sw->hw = hw; |
151 | 571ec3d6 | bellard | sw->active = 0;
|
152 | 571ec3d6 | bellard | #ifdef DAC
|
153 | 571ec3d6 | bellard | sw->ratio = ((int64_t) sw->hw->info.freq << 32) / sw->info.freq;
|
154 | 571ec3d6 | bellard | sw->total_hw_samples_mixed = 0;
|
155 | 571ec3d6 | bellard | sw->empty = 1;
|
156 | 571ec3d6 | bellard | #else
|
157 | 571ec3d6 | bellard | sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq;
|
158 | 571ec3d6 | bellard | #endif
|
159 | 571ec3d6 | bellard | |
160 | 571ec3d6 | bellard | #ifdef DAC
|
161 | 571ec3d6 | bellard | sw->conv = mixeng_conv |
162 | 571ec3d6 | bellard | #else
|
163 | 571ec3d6 | bellard | sw->clip = mixeng_clip |
164 | 571ec3d6 | bellard | #endif
|
165 | 571ec3d6 | bellard | [sw->info.nchannels == 2]
|
166 | 571ec3d6 | bellard | [sw->info.sign] |
167 | 571ec3d6 | bellard | [sw->info.swap_endian] |
168 | 571ec3d6 | bellard | [sw->info.bits == 16];
|
169 | 571ec3d6 | bellard | |
170 | 571ec3d6 | bellard | sw->name = qemu_strdup (name); |
171 | 571ec3d6 | bellard | err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw); |
172 | 571ec3d6 | bellard | if (err) {
|
173 | 571ec3d6 | bellard | qemu_free (sw->name); |
174 | 571ec3d6 | bellard | sw->name = NULL;
|
175 | 571ec3d6 | bellard | } |
176 | 571ec3d6 | bellard | return err;
|
177 | 571ec3d6 | bellard | } |
178 | 571ec3d6 | bellard | |
179 | 1d14ffa9 | bellard | static void glue (audio_pcm_sw_fini_, TYPE) (SW *sw) |
180 | 1d14ffa9 | bellard | { |
181 | 1d14ffa9 | bellard | glue (audio_pcm_sw_free_resources_, TYPE) (sw); |
182 | 1d14ffa9 | bellard | if (sw->name) {
|
183 | 1d14ffa9 | bellard | qemu_free (sw->name); |
184 | 1d14ffa9 | bellard | sw->name = NULL;
|
185 | 1d14ffa9 | bellard | } |
186 | 1d14ffa9 | bellard | } |
187 | 1d14ffa9 | bellard | |
188 | 1d14ffa9 | bellard | static void glue (audio_pcm_hw_add_sw_, TYPE) (HW *hw, SW *sw) |
189 | 1d14ffa9 | bellard | { |
190 | 1d14ffa9 | bellard | LIST_INSERT_HEAD (&hw->sw_head, sw, entries); |
191 | 1d14ffa9 | bellard | } |
192 | 1d14ffa9 | bellard | |
193 | 1d14ffa9 | bellard | static void glue (audio_pcm_hw_del_sw_, TYPE) (SW *sw) |
194 | 1d14ffa9 | bellard | { |
195 | 1d14ffa9 | bellard | LIST_REMOVE (sw, entries); |
196 | 1d14ffa9 | bellard | } |
197 | 1d14ffa9 | bellard | |
198 | c0fe3827 | bellard | static void glue (audio_pcm_hw_gc_, TYPE) (AudioState *s, HW **hwp) |
199 | 1d14ffa9 | bellard | { |
200 | c0fe3827 | bellard | HW *hw = *hwp; |
201 | 1d14ffa9 | bellard | |
202 | 1d14ffa9 | bellard | if (!hw->sw_head.lh_first) {
|
203 | c0fe3827 | bellard | LIST_REMOVE (hw, entries); |
204 | c0fe3827 | bellard | glue (s->nb_hw_voices_, TYPE) += 1;
|
205 | c0fe3827 | bellard | glue (audio_pcm_hw_free_resources_ ,TYPE) (hw); |
206 | c0fe3827 | bellard | glue (hw->pcm_ops->fini_, TYPE) (hw); |
207 | c0fe3827 | bellard | qemu_free (hw); |
208 | c0fe3827 | bellard | *hwp = NULL;
|
209 | 1d14ffa9 | bellard | } |
210 | 1d14ffa9 | bellard | } |
211 | 1d14ffa9 | bellard | |
212 | c0fe3827 | bellard | static HW *glue (audio_pcm_hw_find_any_, TYPE) (AudioState *s, HW *hw)
|
213 | 1d14ffa9 | bellard | { |
214 | c0fe3827 | bellard | return hw ? hw->entries.le_next : s->glue (hw_head_, TYPE).lh_first;
|
215 | 1d14ffa9 | bellard | } |
216 | 1d14ffa9 | bellard | |
217 | c0fe3827 | bellard | static HW *glue (audio_pcm_hw_find_any_enabled_, TYPE) (AudioState *s, HW *hw)
|
218 | 1d14ffa9 | bellard | { |
219 | c0fe3827 | bellard | while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (s, hw))) {
|
220 | c0fe3827 | bellard | if (hw->enabled) {
|
221 | 1d14ffa9 | bellard | return hw;
|
222 | 1d14ffa9 | bellard | } |
223 | 1d14ffa9 | bellard | } |
224 | 1d14ffa9 | bellard | return NULL; |
225 | 1d14ffa9 | bellard | } |
226 | 1d14ffa9 | bellard | |
227 | 1d14ffa9 | bellard | static HW *glue (audio_pcm_hw_find_specific_, TYPE) (
|
228 | c0fe3827 | bellard | AudioState *s, |
229 | 1d14ffa9 | bellard | HW *hw, |
230 | c0fe3827 | bellard | audsettings_t *as |
231 | 1d14ffa9 | bellard | ) |
232 | 1d14ffa9 | bellard | { |
233 | c0fe3827 | bellard | while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (s, hw))) {
|
234 | c0fe3827 | bellard | if (audio_pcm_info_eq (&hw->info, as)) {
|
235 | 1d14ffa9 | bellard | return hw;
|
236 | 1d14ffa9 | bellard | } |
237 | 1d14ffa9 | bellard | } |
238 | 1d14ffa9 | bellard | return NULL; |
239 | 1d14ffa9 | bellard | } |
240 | 1d14ffa9 | bellard | |
241 | c0fe3827 | bellard | static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as)
|
242 | 1d14ffa9 | bellard | { |
243 | 1d14ffa9 | bellard | HW *hw; |
244 | 571ec3d6 | bellard | struct audio_driver *drv = s->drv;
|
245 | 1d14ffa9 | bellard | |
246 | 571ec3d6 | bellard | if (!glue (s->nb_hw_voices_, TYPE)) {
|
247 | 571ec3d6 | bellard | return NULL; |
248 | 571ec3d6 | bellard | } |
249 | 1d14ffa9 | bellard | |
250 | 571ec3d6 | bellard | if (audio_bug (AUDIO_FUNC, !drv)) {
|
251 | 571ec3d6 | bellard | dolog ("No host audio driver\n");
|
252 | 571ec3d6 | bellard | return NULL; |
253 | 1d14ffa9 | bellard | } |
254 | 1d14ffa9 | bellard | |
255 | 571ec3d6 | bellard | if (audio_bug (AUDIO_FUNC, !drv->pcm_ops)) {
|
256 | 571ec3d6 | bellard | dolog ("Host audio driver without pcm_ops\n");
|
257 | 571ec3d6 | bellard | return NULL; |
258 | 571ec3d6 | bellard | } |
259 | 571ec3d6 | bellard | |
260 | 571ec3d6 | bellard | hw = audio_calloc (AUDIO_FUNC, 1, glue (drv->voice_size_, TYPE));
|
261 | 571ec3d6 | bellard | if (!hw) {
|
262 | 571ec3d6 | bellard | dolog ("Can not allocate voice `%s' size %d\n",
|
263 | 571ec3d6 | bellard | drv->name, glue (drv->voice_size_, TYPE)); |
264 | 571ec3d6 | bellard | return NULL; |
265 | 571ec3d6 | bellard | } |
266 | 571ec3d6 | bellard | |
267 | 571ec3d6 | bellard | hw->pcm_ops = drv->pcm_ops; |
268 | 571ec3d6 | bellard | LIST_INIT (&hw->sw_head); |
269 | 571ec3d6 | bellard | |
270 | 571ec3d6 | bellard | if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) {
|
271 | 571ec3d6 | bellard | goto err0;
|
272 | 571ec3d6 | bellard | } |
273 | 571ec3d6 | bellard | |
274 | 571ec3d6 | bellard | if (audio_bug (AUDIO_FUNC, hw->samples <= 0)) { |
275 | 571ec3d6 | bellard | dolog ("hw->samples=%d\n", hw->samples);
|
276 | 571ec3d6 | bellard | goto err1;
|
277 | 571ec3d6 | bellard | } |
278 | 571ec3d6 | bellard | |
279 | 571ec3d6 | bellard | #ifdef DAC
|
280 | 571ec3d6 | bellard | hw->clip = mixeng_clip |
281 | 571ec3d6 | bellard | #else
|
282 | 571ec3d6 | bellard | hw->conv = mixeng_conv |
283 | 571ec3d6 | bellard | #endif
|
284 | 571ec3d6 | bellard | [hw->info.nchannels == 2]
|
285 | 571ec3d6 | bellard | [hw->info.sign] |
286 | 571ec3d6 | bellard | [hw->info.swap_endian] |
287 | 571ec3d6 | bellard | [hw->info.bits == 16];
|
288 | 571ec3d6 | bellard | |
289 | 571ec3d6 | bellard | if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) {
|
290 | 571ec3d6 | bellard | goto err1;
|
291 | 571ec3d6 | bellard | } |
292 | 571ec3d6 | bellard | |
293 | 571ec3d6 | bellard | LIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries); |
294 | 571ec3d6 | bellard | glue (s->nb_hw_voices_, TYPE) -= 1;
|
295 | 571ec3d6 | bellard | return hw;
|
296 | 571ec3d6 | bellard | |
297 | 571ec3d6 | bellard | err1:
|
298 | 571ec3d6 | bellard | glue (hw->pcm_ops->fini_, TYPE) (hw); |
299 | 571ec3d6 | bellard | err0:
|
300 | 571ec3d6 | bellard | qemu_free (hw); |
301 | 1d14ffa9 | bellard | return NULL; |
302 | 1d14ffa9 | bellard | } |
303 | 1d14ffa9 | bellard | |
304 | c0fe3827 | bellard | static HW *glue (audio_pcm_hw_add_, TYPE) (AudioState *s, audsettings_t *as)
|
305 | 1d14ffa9 | bellard | { |
306 | 1d14ffa9 | bellard | HW *hw; |
307 | 1d14ffa9 | bellard | |
308 | c0fe3827 | bellard | if (glue (conf.fixed_, TYPE).enabled && glue (conf.fixed_, TYPE).greedy) {
|
309 | c0fe3827 | bellard | hw = glue (audio_pcm_hw_add_new_, TYPE) (s, as); |
310 | 1d14ffa9 | bellard | if (hw) {
|
311 | 1d14ffa9 | bellard | return hw;
|
312 | 1d14ffa9 | bellard | } |
313 | 1d14ffa9 | bellard | } |
314 | 1d14ffa9 | bellard | |
315 | c0fe3827 | bellard | hw = glue (audio_pcm_hw_find_specific_, TYPE) (s, NULL, as);
|
316 | 1d14ffa9 | bellard | if (hw) {
|
317 | 1d14ffa9 | bellard | return hw;
|
318 | 1d14ffa9 | bellard | } |
319 | 1d14ffa9 | bellard | |
320 | c0fe3827 | bellard | hw = glue (audio_pcm_hw_add_new_, TYPE) (s, as); |
321 | 1d14ffa9 | bellard | if (hw) {
|
322 | 1d14ffa9 | bellard | return hw;
|
323 | 1d14ffa9 | bellard | } |
324 | 1d14ffa9 | bellard | |
325 | c0fe3827 | bellard | return glue (audio_pcm_hw_find_any_, TYPE) (s, NULL); |
326 | 1d14ffa9 | bellard | } |
327 | 1d14ffa9 | bellard | |
328 | 1d14ffa9 | bellard | static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
|
329 | c0fe3827 | bellard | AudioState *s, |
330 | c0fe3827 | bellard | const char *sw_name, |
331 | 571ec3d6 | bellard | audsettings_t *as, |
332 | 571ec3d6 | bellard | int sw_endian
|
333 | 1d14ffa9 | bellard | ) |
334 | 1d14ffa9 | bellard | { |
335 | 1d14ffa9 | bellard | SW *sw; |
336 | 1d14ffa9 | bellard | HW *hw; |
337 | c0fe3827 | bellard | audsettings_t hw_as; |
338 | 1d14ffa9 | bellard | |
339 | c0fe3827 | bellard | if (glue (conf.fixed_, TYPE).enabled) {
|
340 | c0fe3827 | bellard | hw_as = glue (conf.fixed_, TYPE).settings; |
341 | c0fe3827 | bellard | } |
342 | c0fe3827 | bellard | else {
|
343 | c0fe3827 | bellard | hw_as = *as; |
344 | 1d14ffa9 | bellard | } |
345 | 1d14ffa9 | bellard | |
346 | c0fe3827 | bellard | sw = audio_calloc (AUDIO_FUNC, 1, sizeof (*sw)); |
347 | 1d14ffa9 | bellard | if (!sw) {
|
348 | e7cad338 | bellard | dolog ("Could not allocate soft voice `%s' (%zu bytes)\n",
|
349 | c0fe3827 | bellard | sw_name ? sw_name : "unknown", sizeof (*sw)); |
350 | 1d14ffa9 | bellard | goto err1;
|
351 | 1d14ffa9 | bellard | } |
352 | 1d14ffa9 | bellard | |
353 | c0fe3827 | bellard | hw = glue (audio_pcm_hw_add_, TYPE) (s, &hw_as); |
354 | 1d14ffa9 | bellard | if (!hw) {
|
355 | 1d14ffa9 | bellard | goto err2;
|
356 | 1d14ffa9 | bellard | } |
357 | 1d14ffa9 | bellard | |
358 | 1d14ffa9 | bellard | glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw); |
359 | 1d14ffa9 | bellard | |
360 | 571ec3d6 | bellard | if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as, sw_endian)) {
|
361 | 1d14ffa9 | bellard | goto err3;
|
362 | 1d14ffa9 | bellard | } |
363 | 1d14ffa9 | bellard | |
364 | 1d14ffa9 | bellard | return sw;
|
365 | 1d14ffa9 | bellard | |
366 | 1d14ffa9 | bellard | err3:
|
367 | 1d14ffa9 | bellard | glue (audio_pcm_hw_del_sw_, TYPE) (sw); |
368 | c0fe3827 | bellard | glue (audio_pcm_hw_gc_, TYPE) (s, &hw); |
369 | 1d14ffa9 | bellard | err2:
|
370 | 1d14ffa9 | bellard | qemu_free (sw); |
371 | 1d14ffa9 | bellard | err1:
|
372 | 1d14ffa9 | bellard | return NULL; |
373 | 1d14ffa9 | bellard | } |
374 | 1d14ffa9 | bellard | |
375 | c0fe3827 | bellard | static void glue (audio_close_, TYPE) (AudioState *s, SW *sw) |
376 | c0fe3827 | bellard | { |
377 | c0fe3827 | bellard | glue (audio_pcm_sw_fini_, TYPE) (sw); |
378 | c0fe3827 | bellard | glue (audio_pcm_hw_del_sw_, TYPE) (sw); |
379 | c0fe3827 | bellard | glue (audio_pcm_hw_gc_, TYPE) (s, &sw->hw); |
380 | c0fe3827 | bellard | qemu_free (sw); |
381 | c0fe3827 | bellard | } |
382 | 571ec3d6 | bellard | |
383 | c0fe3827 | bellard | void glue (AUD_close_, TYPE) (QEMUSoundCard *card, SW *sw)
|
384 | 1d14ffa9 | bellard | { |
385 | 1d14ffa9 | bellard | if (sw) {
|
386 | c0fe3827 | bellard | if (audio_bug (AUDIO_FUNC, !card || !card->audio)) {
|
387 | c0fe3827 | bellard | dolog ("card=%p card->audio=%p\n",
|
388 | c0fe3827 | bellard | card, card ? card->audio : NULL);
|
389 | c0fe3827 | bellard | return;
|
390 | c0fe3827 | bellard | } |
391 | c0fe3827 | bellard | |
392 | c0fe3827 | bellard | glue (audio_close_, TYPE) (card->audio, sw); |
393 | 1d14ffa9 | bellard | } |
394 | 1d14ffa9 | bellard | } |
395 | 1d14ffa9 | bellard | |
396 | 1d14ffa9 | bellard | SW *glue (AUD_open_, TYPE) ( |
397 | c0fe3827 | bellard | QEMUSoundCard *card, |
398 | 1d14ffa9 | bellard | SW *sw, |
399 | 1d14ffa9 | bellard | const char *name, |
400 | 1d14ffa9 | bellard | void *callback_opaque ,
|
401 | 1d14ffa9 | bellard | audio_callback_fn_t callback_fn, |
402 | 571ec3d6 | bellard | audsettings_t *as, |
403 | 571ec3d6 | bellard | int sw_endian
|
404 | 1d14ffa9 | bellard | ) |
405 | 1d14ffa9 | bellard | { |
406 | c0fe3827 | bellard | AudioState *s; |
407 | 1d14ffa9 | bellard | #ifdef DAC
|
408 | 1d14ffa9 | bellard | int live = 0; |
409 | 1d14ffa9 | bellard | SW *old_sw = NULL;
|
410 | 1d14ffa9 | bellard | #endif
|
411 | 1d14ffa9 | bellard | |
412 | c0fe3827 | bellard | ldebug ("open %s, freq %d, nchannels %d, fmt %d\n",
|
413 | c0fe3827 | bellard | name, as->freq, as->nchannels, as->fmt); |
414 | c0fe3827 | bellard | |
415 | c0fe3827 | bellard | if (audio_bug (AUDIO_FUNC,
|
416 | c0fe3827 | bellard | !card || !card->audio || !name || !callback_fn || !as)) { |
417 | c0fe3827 | bellard | dolog ("card=%p card->audio=%p name=%p callback_fn=%p as=%p\n",
|
418 | c0fe3827 | bellard | card, card ? card->audio : NULL, name, callback_fn, as);
|
419 | 1d14ffa9 | bellard | goto fail;
|
420 | 1d14ffa9 | bellard | } |
421 | 1d14ffa9 | bellard | |
422 | c0fe3827 | bellard | s = card->audio; |
423 | c0fe3827 | bellard | |
424 | c0fe3827 | bellard | if (audio_bug (AUDIO_FUNC, audio_validate_settigs (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 | 571ec3d6 | bellard | if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as, sw_endian)) {
|
477 | 1d14ffa9 | bellard | goto fail;
|
478 | 1d14ffa9 | bellard | } |
479 | 1d14ffa9 | bellard | } |
480 | 1d14ffa9 | bellard | else {
|
481 | 571ec3d6 | bellard | sw = glue (audio_pcm_create_voice_pair_, TYPE) (s, name, as, sw_endian); |
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 | 1d14ffa9 | bellard | sw->vol = nominal_volume; |
490 | 1d14ffa9 | bellard | sw->callback.fn = callback_fn; |
491 | 1d14ffa9 | bellard | sw->callback.opaque = callback_opaque; |
492 | 1d14ffa9 | bellard | |
493 | 1d14ffa9 | bellard | #ifdef DAC
|
494 | 1d14ffa9 | bellard | if (live) {
|
495 | 1d14ffa9 | bellard | int mixed =
|
496 | 1d14ffa9 | bellard | (live << old_sw->info.shift) |
497 | 1d14ffa9 | bellard | * old_sw->info.bytes_per_second |
498 | 1d14ffa9 | bellard | / sw->info.bytes_per_second; |
499 | 1d14ffa9 | bellard | |
500 | 1d14ffa9 | bellard | #ifdef DEBUG_PLIVE
|
501 | 1d14ffa9 | bellard | dolog ("Silence will be mixed %d\n", mixed);
|
502 | 1d14ffa9 | bellard | #endif
|
503 | 1d14ffa9 | bellard | sw->total_hw_samples_mixed += mixed; |
504 | 1d14ffa9 | bellard | } |
505 | 1d14ffa9 | bellard | #endif
|
506 | 1d14ffa9 | bellard | |
507 | 1d14ffa9 | bellard | #ifdef DEBUG_AUDIO
|
508 | 1d14ffa9 | bellard | dolog ("%s\n", name);
|
509 | 1d14ffa9 | bellard | audio_pcm_print_info ("hw", &sw->hw->info);
|
510 | 1d14ffa9 | bellard | audio_pcm_print_info ("sw", &sw->info);
|
511 | 1d14ffa9 | bellard | #endif
|
512 | 1d14ffa9 | bellard | } |
513 | 1d14ffa9 | bellard | |
514 | 1d14ffa9 | bellard | return sw;
|
515 | 1d14ffa9 | bellard | |
516 | 1d14ffa9 | bellard | fail:
|
517 | c0fe3827 | bellard | glue (AUD_close_, TYPE) (card, sw); |
518 | 1d14ffa9 | bellard | return NULL; |
519 | 1d14ffa9 | bellard | } |
520 | 1d14ffa9 | bellard | |
521 | 1d14ffa9 | bellard | int glue (AUD_is_active_, TYPE) (SW *sw)
|
522 | 1d14ffa9 | bellard | { |
523 | 1d14ffa9 | bellard | return sw ? sw->active : 0; |
524 | 1d14ffa9 | bellard | } |
525 | 1d14ffa9 | bellard | |
526 | 1d14ffa9 | bellard | void glue (AUD_init_time_stamp_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts)
|
527 | 1d14ffa9 | bellard | { |
528 | 1d14ffa9 | bellard | if (!sw) {
|
529 | 1d14ffa9 | bellard | return;
|
530 | 1d14ffa9 | bellard | } |
531 | 1d14ffa9 | bellard | |
532 | 1d14ffa9 | bellard | ts->old_ts = sw->hw->ts_helper; |
533 | 1d14ffa9 | bellard | } |
534 | 1d14ffa9 | bellard | |
535 | c0fe3827 | bellard | uint64_t glue (AUD_get_elapsed_usec_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts) |
536 | 1d14ffa9 | bellard | { |
537 | 1d14ffa9 | bellard | uint64_t delta, cur_ts, old_ts; |
538 | 1d14ffa9 | bellard | |
539 | 1d14ffa9 | bellard | if (!sw) {
|
540 | 1d14ffa9 | bellard | return 0; |
541 | 1d14ffa9 | bellard | } |
542 | 1d14ffa9 | bellard | |
543 | 1d14ffa9 | bellard | cur_ts = sw->hw->ts_helper; |
544 | 1d14ffa9 | bellard | old_ts = ts->old_ts; |
545 | 1d14ffa9 | bellard | /* dolog ("cur %lld old %lld\n", cur_ts, old_ts); */
|
546 | 1d14ffa9 | bellard | |
547 | 1d14ffa9 | bellard | if (cur_ts >= old_ts) {
|
548 | 1d14ffa9 | bellard | delta = cur_ts - old_ts; |
549 | 1d14ffa9 | bellard | } |
550 | 1d14ffa9 | bellard | else {
|
551 | 1d14ffa9 | bellard | delta = UINT64_MAX - old_ts + cur_ts; |
552 | 1d14ffa9 | bellard | } |
553 | 1d14ffa9 | bellard | |
554 | 1d14ffa9 | bellard | if (!delta) {
|
555 | 1d14ffa9 | bellard | return 0; |
556 | 1d14ffa9 | bellard | } |
557 | 1d14ffa9 | bellard | |
558 | 1d14ffa9 | bellard | return (delta * sw->hw->info.freq) / 1000000; |
559 | 1d14ffa9 | bellard | } |
560 | 1d14ffa9 | bellard | |
561 | 1d14ffa9 | bellard | #undef TYPE
|
562 | 1d14ffa9 | bellard | #undef HW
|
563 | 1d14ffa9 | bellard | #undef SW
|
564 | 571ec3d6 | bellard | #undef HWBUF
|
565 | 571ec3d6 | bellard | #undef NAME |