root / audio / audio_template.h @ 9e56e756
History | View | Annotate | Download (13 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 | 7267c094 | Anthony Liguori | g_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 | 7267c094 | Anthony Liguori | g_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 | 571ec3d6 | bellard | samples = ((int64_t) sw->hw->samples << 32) / sw->ratio;
|
112 | c0fe3827 | bellard | |
113 | 1ea879e5 | malc | sw->buf = audio_calloc (AUDIO_FUNC, samples, sizeof (struct st_sample)); |
114 | 571ec3d6 | bellard | if (!sw->buf) {
|
115 | 571ec3d6 | bellard | dolog ("Could not allocate buffer for `%s' (%d samples)\n",
|
116 | 571ec3d6 | bellard | SW_NAME (sw), samples); |
117 | c0fe3827 | bellard | return -1; |
118 | c0fe3827 | bellard | } |
119 | c0fe3827 | bellard | |
120 | 571ec3d6 | bellard | #ifdef DAC
|
121 | 571ec3d6 | bellard | sw->rate = st_rate_start (sw->info.freq, sw->hw->info.freq); |
122 | 571ec3d6 | bellard | #else
|
123 | 571ec3d6 | bellard | sw->rate = st_rate_start (sw->hw->info.freq, sw->info.freq); |
124 | 571ec3d6 | bellard | #endif
|
125 | 571ec3d6 | bellard | if (!sw->rate) {
|
126 | 7267c094 | Anthony Liguori | g_free (sw->buf); |
127 | 571ec3d6 | bellard | sw->buf = NULL;
|
128 | 571ec3d6 | bellard | return -1; |
129 | 571ec3d6 | bellard | } |
130 | c0fe3827 | bellard | return 0; |
131 | c0fe3827 | bellard | } |
132 | c0fe3827 | bellard | |
133 | 571ec3d6 | bellard | static int glue (audio_pcm_sw_init_, TYPE) ( |
134 | 571ec3d6 | bellard | SW *sw, |
135 | 571ec3d6 | bellard | HW *hw, |
136 | 571ec3d6 | bellard | const char *name, |
137 | 1ea879e5 | malc | struct audsettings *as
|
138 | 571ec3d6 | bellard | ) |
139 | 571ec3d6 | bellard | { |
140 | 571ec3d6 | bellard | int err;
|
141 | 571ec3d6 | bellard | |
142 | d929eba5 | bellard | audio_pcm_init_info (&sw->info, as); |
143 | 571ec3d6 | bellard | sw->hw = hw; |
144 | 571ec3d6 | bellard | sw->active = 0;
|
145 | 571ec3d6 | bellard | #ifdef DAC
|
146 | 571ec3d6 | bellard | sw->ratio = ((int64_t) sw->hw->info.freq << 32) / sw->info.freq;
|
147 | 571ec3d6 | bellard | sw->total_hw_samples_mixed = 0;
|
148 | 571ec3d6 | bellard | sw->empty = 1;
|
149 | 571ec3d6 | bellard | #else
|
150 | 571ec3d6 | bellard | sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq;
|
151 | 571ec3d6 | bellard | #endif
|
152 | 571ec3d6 | bellard | |
153 | 571ec3d6 | bellard | #ifdef DAC
|
154 | 571ec3d6 | bellard | sw->conv = mixeng_conv |
155 | 571ec3d6 | bellard | #else
|
156 | 571ec3d6 | bellard | sw->clip = mixeng_clip |
157 | 571ec3d6 | bellard | #endif
|
158 | 571ec3d6 | bellard | [sw->info.nchannels == 2]
|
159 | 571ec3d6 | bellard | [sw->info.sign] |
160 | d929eba5 | bellard | [sw->info.swap_endianness] |
161 | f941aa25 | ths | [audio_bits_to_index (sw->info.bits)]; |
162 | 571ec3d6 | bellard | |
163 | 7267c094 | Anthony Liguori | sw->name = g_strdup (name); |
164 | 571ec3d6 | bellard | err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw); |
165 | 571ec3d6 | bellard | if (err) {
|
166 | 7267c094 | Anthony Liguori | g_free (sw->name); |
167 | 571ec3d6 | bellard | sw->name = NULL;
|
168 | 571ec3d6 | bellard | } |
169 | 571ec3d6 | bellard | return err;
|
170 | 571ec3d6 | bellard | } |
171 | 571ec3d6 | bellard | |
172 | 1d14ffa9 | bellard | static void glue (audio_pcm_sw_fini_, TYPE) (SW *sw) |
173 | 1d14ffa9 | bellard | { |
174 | 1d14ffa9 | bellard | glue (audio_pcm_sw_free_resources_, TYPE) (sw); |
175 | 1d14ffa9 | bellard | if (sw->name) {
|
176 | 7267c094 | Anthony Liguori | g_free (sw->name); |
177 | 1d14ffa9 | bellard | sw->name = NULL;
|
178 | 1d14ffa9 | bellard | } |
179 | 1d14ffa9 | bellard | } |
180 | 1d14ffa9 | bellard | |
181 | 1d14ffa9 | bellard | static void glue (audio_pcm_hw_add_sw_, TYPE) (HW *hw, SW *sw) |
182 | 1d14ffa9 | bellard | { |
183 | 72cf2d4f | Blue Swirl | QLIST_INSERT_HEAD (&hw->sw_head, sw, entries); |
184 | 1d14ffa9 | bellard | } |
185 | 1d14ffa9 | bellard | |
186 | 1d14ffa9 | bellard | static void glue (audio_pcm_hw_del_sw_, TYPE) (SW *sw) |
187 | 1d14ffa9 | bellard | { |
188 | 72cf2d4f | Blue Swirl | QLIST_REMOVE (sw, entries); |
189 | 1d14ffa9 | bellard | } |
190 | 1d14ffa9 | bellard | |
191 | 1a7dafce | malc | static void glue (audio_pcm_hw_gc_, TYPE) (HW **hwp) |
192 | 1d14ffa9 | bellard | { |
193 | 1a7dafce | malc | AudioState *s = &glob_audio_state; |
194 | c0fe3827 | bellard | HW *hw = *hwp; |
195 | 1d14ffa9 | bellard | |
196 | 1d14ffa9 | bellard | if (!hw->sw_head.lh_first) {
|
197 | 8ead62cf | bellard | #ifdef DAC
|
198 | 8ead62cf | bellard | audio_detach_capture (hw); |
199 | 8ead62cf | bellard | #endif
|
200 | 72cf2d4f | Blue Swirl | QLIST_REMOVE (hw, entries); |
201 | c0fe3827 | bellard | glue (s->nb_hw_voices_, TYPE) += 1;
|
202 | c0fe3827 | bellard | glue (audio_pcm_hw_free_resources_ ,TYPE) (hw); |
203 | c0fe3827 | bellard | glue (hw->pcm_ops->fini_, TYPE) (hw); |
204 | 7267c094 | Anthony Liguori | g_free (hw); |
205 | c0fe3827 | bellard | *hwp = NULL;
|
206 | 1d14ffa9 | bellard | } |
207 | 1d14ffa9 | bellard | } |
208 | 1d14ffa9 | bellard | |
209 | 1a7dafce | malc | static HW *glue (audio_pcm_hw_find_any_, TYPE) (HW *hw)
|
210 | 1d14ffa9 | bellard | { |
211 | 1a7dafce | malc | AudioState *s = &glob_audio_state; |
212 | 1a7dafce | malc | return hw ? hw->entries.le_next : glue (s->hw_head_, TYPE).lh_first;
|
213 | 1d14ffa9 | bellard | } |
214 | 1d14ffa9 | bellard | |
215 | 1a7dafce | malc | static HW *glue (audio_pcm_hw_find_any_enabled_, TYPE) (HW *hw)
|
216 | 1d14ffa9 | bellard | { |
217 | 1a7dafce | malc | while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) {
|
218 | c0fe3827 | bellard | if (hw->enabled) {
|
219 | 1d14ffa9 | bellard | return hw;
|
220 | 1d14ffa9 | bellard | } |
221 | 1d14ffa9 | bellard | } |
222 | 1d14ffa9 | bellard | return NULL; |
223 | 1d14ffa9 | bellard | } |
224 | 1d14ffa9 | bellard | |
225 | 1d14ffa9 | bellard | static HW *glue (audio_pcm_hw_find_specific_, TYPE) (
|
226 | 1d14ffa9 | bellard | HW *hw, |
227 | 1ea879e5 | malc | struct audsettings *as
|
228 | 1d14ffa9 | bellard | ) |
229 | 1d14ffa9 | bellard | { |
230 | 1a7dafce | malc | while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) {
|
231 | c0fe3827 | bellard | if (audio_pcm_info_eq (&hw->info, as)) {
|
232 | 1d14ffa9 | bellard | return hw;
|
233 | 1d14ffa9 | bellard | } |
234 | 1d14ffa9 | bellard | } |
235 | 1d14ffa9 | bellard | return NULL; |
236 | 1d14ffa9 | bellard | } |
237 | 1d14ffa9 | bellard | |
238 | 1a7dafce | malc | static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as) |
239 | 1d14ffa9 | bellard | { |
240 | 1d14ffa9 | bellard | HW *hw; |
241 | 1a7dafce | malc | AudioState *s = &glob_audio_state; |
242 | 571ec3d6 | bellard | struct audio_driver *drv = s->drv;
|
243 | 1d14ffa9 | bellard | |
244 | 571ec3d6 | bellard | if (!glue (s->nb_hw_voices_, TYPE)) {
|
245 | 571ec3d6 | bellard | return NULL; |
246 | 571ec3d6 | bellard | } |
247 | 1d14ffa9 | bellard | |
248 | 571ec3d6 | bellard | if (audio_bug (AUDIO_FUNC, !drv)) {
|
249 | 571ec3d6 | bellard | dolog ("No host audio driver\n");
|
250 | 571ec3d6 | bellard | return NULL; |
251 | 1d14ffa9 | bellard | } |
252 | 1d14ffa9 | bellard | |
253 | 571ec3d6 | bellard | if (audio_bug (AUDIO_FUNC, !drv->pcm_ops)) {
|
254 | 571ec3d6 | bellard | dolog ("Host audio driver without pcm_ops\n");
|
255 | 571ec3d6 | bellard | return NULL; |
256 | 571ec3d6 | bellard | } |
257 | 571ec3d6 | bellard | |
258 | 571ec3d6 | bellard | hw = audio_calloc (AUDIO_FUNC, 1, glue (drv->voice_size_, TYPE));
|
259 | 571ec3d6 | bellard | if (!hw) {
|
260 | 571ec3d6 | bellard | dolog ("Can not allocate voice `%s' size %d\n",
|
261 | 571ec3d6 | bellard | drv->name, glue (drv->voice_size_, TYPE)); |
262 | 571ec3d6 | bellard | return NULL; |
263 | 571ec3d6 | bellard | } |
264 | 571ec3d6 | bellard | |
265 | 571ec3d6 | bellard | hw->pcm_ops = drv->pcm_ops; |
266 | 72cf2d4f | Blue Swirl | QLIST_INIT (&hw->sw_head); |
267 | 8ead62cf | bellard | #ifdef DAC
|
268 | 72cf2d4f | Blue Swirl | QLIST_INIT (&hw->cap_head); |
269 | 8ead62cf | bellard | #endif
|
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 | d929eba5 | bellard | [hw->info.swap_endianness] |
287 | f941aa25 | ths | [audio_bits_to_index (hw->info.bits)]; |
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 | 72cf2d4f | Blue Swirl | QLIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries); |
294 | 571ec3d6 | bellard | glue (s->nb_hw_voices_, TYPE) -= 1;
|
295 | 8ead62cf | bellard | #ifdef DAC
|
296 | 1a7dafce | malc | audio_attach_capture (hw); |
297 | 8ead62cf | bellard | #endif
|
298 | 571ec3d6 | bellard | return hw;
|
299 | 571ec3d6 | bellard | |
300 | 571ec3d6 | bellard | err1:
|
301 | 571ec3d6 | bellard | glue (hw->pcm_ops->fini_, TYPE) (hw); |
302 | 571ec3d6 | bellard | err0:
|
303 | 7267c094 | Anthony Liguori | g_free (hw); |
304 | 1d14ffa9 | bellard | return NULL; |
305 | 1d14ffa9 | bellard | } |
306 | 1d14ffa9 | bellard | |
307 | 1a7dafce | malc | static HW *glue (audio_pcm_hw_add_, TYPE) (struct audsettings *as) |
308 | 1d14ffa9 | bellard | { |
309 | 1d14ffa9 | bellard | HW *hw; |
310 | 1d14ffa9 | bellard | |
311 | c0fe3827 | bellard | if (glue (conf.fixed_, TYPE).enabled && glue (conf.fixed_, TYPE).greedy) {
|
312 | 1a7dafce | malc | hw = glue (audio_pcm_hw_add_new_, TYPE) (as); |
313 | 1d14ffa9 | bellard | if (hw) {
|
314 | 1d14ffa9 | bellard | return hw;
|
315 | 1d14ffa9 | bellard | } |
316 | 1d14ffa9 | bellard | } |
317 | 1d14ffa9 | bellard | |
318 | 1a7dafce | malc | hw = glue (audio_pcm_hw_find_specific_, TYPE) (NULL, as);
|
319 | 1d14ffa9 | bellard | if (hw) {
|
320 | 1d14ffa9 | bellard | return hw;
|
321 | 1d14ffa9 | bellard | } |
322 | 1d14ffa9 | bellard | |
323 | 1a7dafce | malc | hw = glue (audio_pcm_hw_add_new_, TYPE) (as); |
324 | 1d14ffa9 | bellard | if (hw) {
|
325 | 1d14ffa9 | bellard | return hw;
|
326 | 1d14ffa9 | bellard | } |
327 | 1d14ffa9 | bellard | |
328 | 1a7dafce | malc | return glue (audio_pcm_hw_find_any_, TYPE) (NULL); |
329 | 1d14ffa9 | bellard | } |
330 | 1d14ffa9 | bellard | |
331 | 1d14ffa9 | bellard | static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
|
332 | c0fe3827 | bellard | const char *sw_name, |
333 | 1ea879e5 | malc | struct audsettings *as
|
334 | 1d14ffa9 | bellard | ) |
335 | 1d14ffa9 | bellard | { |
336 | 1d14ffa9 | bellard | SW *sw; |
337 | 1d14ffa9 | bellard | HW *hw; |
338 | 1ea879e5 | malc | struct audsettings hw_as;
|
339 | 1d14ffa9 | bellard | |
340 | c0fe3827 | bellard | if (glue (conf.fixed_, TYPE).enabled) {
|
341 | c0fe3827 | bellard | hw_as = glue (conf.fixed_, TYPE).settings; |
342 | c0fe3827 | bellard | } |
343 | c0fe3827 | bellard | else {
|
344 | c0fe3827 | bellard | hw_as = *as; |
345 | 1d14ffa9 | bellard | } |
346 | 1d14ffa9 | bellard | |
347 | c0fe3827 | bellard | sw = audio_calloc (AUDIO_FUNC, 1, sizeof (*sw)); |
348 | 1d14ffa9 | bellard | if (!sw) {
|
349 | e7cad338 | bellard | dolog ("Could not allocate soft voice `%s' (%zu bytes)\n",
|
350 | c0fe3827 | bellard | sw_name ? sw_name : "unknown", sizeof (*sw)); |
351 | 1d14ffa9 | bellard | goto err1;
|
352 | 1d14ffa9 | bellard | } |
353 | 1d14ffa9 | bellard | |
354 | 1a7dafce | malc | hw = glue (audio_pcm_hw_add_, TYPE) (&hw_as); |
355 | 1d14ffa9 | bellard | if (!hw) {
|
356 | 1d14ffa9 | bellard | goto err2;
|
357 | 1d14ffa9 | bellard | } |
358 | 1d14ffa9 | bellard | |
359 | 1d14ffa9 | bellard | glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw); |
360 | 1d14ffa9 | bellard | |
361 | d929eba5 | bellard | if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as)) {
|
362 | 1d14ffa9 | bellard | goto err3;
|
363 | 1d14ffa9 | bellard | } |
364 | 1d14ffa9 | bellard | |
365 | 1d14ffa9 | bellard | return sw;
|
366 | 1d14ffa9 | bellard | |
367 | 1d14ffa9 | bellard | err3:
|
368 | 1d14ffa9 | bellard | glue (audio_pcm_hw_del_sw_, TYPE) (sw); |
369 | 1a7dafce | malc | glue (audio_pcm_hw_gc_, TYPE) (&hw); |
370 | 1d14ffa9 | bellard | err2:
|
371 | 7267c094 | Anthony Liguori | g_free (sw); |
372 | 1d14ffa9 | bellard | err1:
|
373 | 1d14ffa9 | bellard | return NULL; |
374 | 1d14ffa9 | bellard | } |
375 | 1d14ffa9 | bellard | |
376 | 1a7dafce | malc | static void glue (audio_close_, TYPE) (SW *sw) |
377 | c0fe3827 | bellard | { |
378 | c0fe3827 | bellard | glue (audio_pcm_sw_fini_, TYPE) (sw); |
379 | c0fe3827 | bellard | glue (audio_pcm_hw_del_sw_, TYPE) (sw); |
380 | 1a7dafce | malc | glue (audio_pcm_hw_gc_, TYPE) (&sw->hw); |
381 | 7267c094 | Anthony Liguori | g_free (sw); |
382 | c0fe3827 | bellard | } |
383 | 571ec3d6 | bellard | |
384 | c0fe3827 | bellard | void glue (AUD_close_, TYPE) (QEMUSoundCard *card, SW *sw)
|
385 | 1d14ffa9 | bellard | { |
386 | 1d14ffa9 | bellard | if (sw) {
|
387 | 1a7dafce | malc | if (audio_bug (AUDIO_FUNC, !card)) {
|
388 | 1a7dafce | malc | dolog ("card=%p\n", card);
|
389 | c0fe3827 | bellard | return;
|
390 | c0fe3827 | bellard | } |
391 | c0fe3827 | bellard | |
392 | 1a7dafce | malc | glue (audio_close_, TYPE) (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 | cb4f03e8 | malc | audio_callback_fn callback_fn, |
402 | 1ea879e5 | malc | struct audsettings *as
|
403 | 1d14ffa9 | bellard | ) |
404 | 1d14ffa9 | bellard | { |
405 | 1a7dafce | malc | AudioState *s = &glob_audio_state; |
406 | 1d14ffa9 | bellard | #ifdef DAC
|
407 | 1d14ffa9 | bellard | int live = 0; |
408 | 1d14ffa9 | bellard | SW *old_sw = NULL;
|
409 | 1d14ffa9 | bellard | #endif
|
410 | 1d14ffa9 | bellard | |
411 | c0fe3827 | bellard | ldebug ("open %s, freq %d, nchannels %d, fmt %d\n",
|
412 | c0fe3827 | bellard | name, as->freq, as->nchannels, as->fmt); |
413 | c0fe3827 | bellard | |
414 | 1a7dafce | malc | if (audio_bug (AUDIO_FUNC, !card || !name || !callback_fn || !as)) {
|
415 | 1a7dafce | malc | dolog ("card=%p name=%p callback_fn=%p as=%p\n",
|
416 | 1a7dafce | malc | card, name, callback_fn, as); |
417 | 1d14ffa9 | bellard | goto fail;
|
418 | 1d14ffa9 | bellard | } |
419 | 1d14ffa9 | bellard | |
420 | ec36b695 | bellard | if (audio_bug (AUDIO_FUNC, audio_validate_settings (as))) {
|
421 | c0fe3827 | bellard | audio_print_settings (as); |
422 | 1d14ffa9 | bellard | goto fail;
|
423 | 1d14ffa9 | bellard | } |
424 | 1d14ffa9 | bellard | |
425 | c0fe3827 | bellard | if (audio_bug (AUDIO_FUNC, !s->drv)) {
|
426 | c0fe3827 | bellard | dolog ("Can not open `%s' (no host audio driver)\n", name);
|
427 | 1d14ffa9 | bellard | goto fail;
|
428 | 1d14ffa9 | bellard | } |
429 | 1d14ffa9 | bellard | |
430 | c0fe3827 | bellard | if (sw && audio_pcm_info_eq (&sw->info, as)) {
|
431 | 1d14ffa9 | bellard | return sw;
|
432 | 1d14ffa9 | bellard | } |
433 | 1d14ffa9 | bellard | |
434 | 1d14ffa9 | bellard | #ifdef DAC
|
435 | c0fe3827 | bellard | if (conf.plive && sw && (!sw->active && !sw->empty)) {
|
436 | 1d14ffa9 | bellard | live = sw->total_hw_samples_mixed; |
437 | 1d14ffa9 | bellard | |
438 | 1d14ffa9 | bellard | #ifdef DEBUG_PLIVE
|
439 | c0fe3827 | bellard | dolog ("Replacing voice %s with %d live samples\n", SW_NAME (sw), live);
|
440 | 1d14ffa9 | bellard | dolog ("Old %s freq %d, bits %d, channels %d\n",
|
441 | c0fe3827 | bellard | SW_NAME (sw), sw->info.freq, sw->info.bits, sw->info.nchannels); |
442 | 1d14ffa9 | bellard | dolog ("New %s freq %d, bits %d, channels %d\n",
|
443 | c0fe3827 | bellard | name, |
444 | a244eb74 | Juan Quintela | as->freq, |
445 | a244eb74 | Juan Quintela | (as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) ? 16 : 8, |
446 | a244eb74 | Juan Quintela | as->nchannels); |
447 | 1d14ffa9 | bellard | #endif
|
448 | 1d14ffa9 | bellard | |
449 | 1d14ffa9 | bellard | if (live) {
|
450 | 1d14ffa9 | bellard | old_sw = sw; |
451 | 1d14ffa9 | bellard | old_sw->callback.fn = NULL;
|
452 | 1d14ffa9 | bellard | sw = NULL;
|
453 | 1d14ffa9 | bellard | } |
454 | 1d14ffa9 | bellard | } |
455 | 1d14ffa9 | bellard | #endif
|
456 | 1d14ffa9 | bellard | |
457 | c0fe3827 | bellard | if (!glue (conf.fixed_, TYPE).enabled && sw) {
|
458 | c0fe3827 | bellard | glue (AUD_close_, TYPE) (card, sw); |
459 | 1d14ffa9 | bellard | sw = NULL;
|
460 | 1d14ffa9 | bellard | } |
461 | 1d14ffa9 | bellard | |
462 | 1d14ffa9 | bellard | if (sw) {
|
463 | 1d14ffa9 | bellard | HW *hw = sw->hw; |
464 | 1d14ffa9 | bellard | |
465 | 1d14ffa9 | bellard | if (!hw) {
|
466 | c0fe3827 | bellard | dolog ("Internal logic error voice `%s' has no hardware store\n",
|
467 | c0fe3827 | bellard | SW_NAME (sw)); |
468 | 1d14ffa9 | bellard | goto fail;
|
469 | 1d14ffa9 | bellard | } |
470 | 1d14ffa9 | bellard | |
471 | 571ec3d6 | bellard | glue (audio_pcm_sw_fini_, TYPE) (sw); |
472 | d929eba5 | bellard | if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as)) {
|
473 | 1d14ffa9 | bellard | goto fail;
|
474 | 1d14ffa9 | bellard | } |
475 | 1d14ffa9 | bellard | } |
476 | 1d14ffa9 | bellard | else {
|
477 | 1a7dafce | malc | sw = glue (audio_pcm_create_voice_pair_, TYPE) (name, as); |
478 | 1d14ffa9 | bellard | if (!sw) {
|
479 | c0fe3827 | bellard | dolog ("Failed to create voice `%s'\n", name);
|
480 | 571ec3d6 | bellard | return NULL; |
481 | 1d14ffa9 | bellard | } |
482 | 1d14ffa9 | bellard | } |
483 | 1d14ffa9 | bellard | |
484 | 7cbb28ed | malc | sw->card = card; |
485 | 7cbb28ed | malc | sw->vol = nominal_volume; |
486 | 7cbb28ed | malc | sw->callback.fn = callback_fn; |
487 | 7cbb28ed | malc | sw->callback.opaque = callback_opaque; |
488 | 1d14ffa9 | bellard | |
489 | 1d14ffa9 | bellard | #ifdef DAC
|
490 | 7cbb28ed | malc | if (live) {
|
491 | 7cbb28ed | malc | int mixed =
|
492 | 7cbb28ed | malc | (live << old_sw->info.shift) |
493 | 7cbb28ed | malc | * old_sw->info.bytes_per_second |
494 | 7cbb28ed | malc | / sw->info.bytes_per_second; |
495 | 1d14ffa9 | bellard | |
496 | 1d14ffa9 | bellard | #ifdef DEBUG_PLIVE
|
497 | 7cbb28ed | malc | dolog ("Silence will be mixed %d\n", mixed);
|
498 | 1d14ffa9 | bellard | #endif
|
499 | 7cbb28ed | malc | sw->total_hw_samples_mixed += mixed; |
500 | 7cbb28ed | malc | } |
501 | 1d14ffa9 | bellard | #endif
|
502 | 1d14ffa9 | bellard | |
503 | 1d14ffa9 | bellard | #ifdef DEBUG_AUDIO
|
504 | 7cbb28ed | malc | dolog ("%s\n", name);
|
505 | 7cbb28ed | malc | audio_pcm_print_info ("hw", &sw->hw->info);
|
506 | 7cbb28ed | malc | audio_pcm_print_info ("sw", &sw->info);
|
507 | 1d14ffa9 | bellard | #endif
|
508 | 1d14ffa9 | bellard | |
509 | 1d14ffa9 | bellard | return sw;
|
510 | 1d14ffa9 | bellard | |
511 | 1d14ffa9 | bellard | fail:
|
512 | c0fe3827 | bellard | glue (AUD_close_, TYPE) (card, sw); |
513 | 1d14ffa9 | bellard | return NULL; |
514 | 1d14ffa9 | bellard | } |
515 | 1d14ffa9 | bellard | |
516 | 1d14ffa9 | bellard | int glue (AUD_is_active_, TYPE) (SW *sw)
|
517 | 1d14ffa9 | bellard | { |
518 | 1d14ffa9 | bellard | return sw ? sw->active : 0; |
519 | 1d14ffa9 | bellard | } |
520 | 1d14ffa9 | bellard | |
521 | 1d14ffa9 | bellard | void glue (AUD_init_time_stamp_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts)
|
522 | 1d14ffa9 | bellard | { |
523 | 1d14ffa9 | bellard | if (!sw) {
|
524 | 1d14ffa9 | bellard | return;
|
525 | 1d14ffa9 | bellard | } |
526 | 1d14ffa9 | bellard | |
527 | 1d14ffa9 | bellard | ts->old_ts = sw->hw->ts_helper; |
528 | 1d14ffa9 | bellard | } |
529 | 1d14ffa9 | bellard | |
530 | c0fe3827 | bellard | uint64_t glue (AUD_get_elapsed_usec_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts) |
531 | 1d14ffa9 | bellard | { |
532 | 1d14ffa9 | bellard | uint64_t delta, cur_ts, old_ts; |
533 | 1d14ffa9 | bellard | |
534 | 1d14ffa9 | bellard | if (!sw) {
|
535 | 1d14ffa9 | bellard | return 0; |
536 | 1d14ffa9 | bellard | } |
537 | 1d14ffa9 | bellard | |
538 | 1d14ffa9 | bellard | cur_ts = sw->hw->ts_helper; |
539 | 1d14ffa9 | bellard | old_ts = ts->old_ts; |
540 | 0bfcd599 | Blue Swirl | /* dolog ("cur %" PRId64 " old %" PRId64 "\n", cur_ts, old_ts); */
|
541 | 1d14ffa9 | bellard | |
542 | 1d14ffa9 | bellard | if (cur_ts >= old_ts) {
|
543 | 1d14ffa9 | bellard | delta = cur_ts - old_ts; |
544 | 1d14ffa9 | bellard | } |
545 | 1d14ffa9 | bellard | else {
|
546 | 1d14ffa9 | bellard | delta = UINT64_MAX - old_ts + cur_ts; |
547 | 1d14ffa9 | bellard | } |
548 | 1d14ffa9 | bellard | |
549 | 1d14ffa9 | bellard | if (!delta) {
|
550 | 1d14ffa9 | bellard | return 0; |
551 | 1d14ffa9 | bellard | } |
552 | 1d14ffa9 | bellard | |
553 | 4f4cc0ef | malc | return muldiv64 (delta, sw->hw->info.freq, 1000000); |
554 | 1d14ffa9 | bellard | } |
555 | 1d14ffa9 | bellard | |
556 | 1d14ffa9 | bellard | #undef TYPE
|
557 | 1d14ffa9 | bellard | #undef HW
|
558 | 1d14ffa9 | bellard | #undef SW
|
559 | 571ec3d6 | bellard | #undef HWBUF
|
560 | 571ec3d6 | bellard | #undef NAME |