merged 15a_aqemu.patch audio patch (malc)
[qemu] / audio / dsound_template.h
1 /*
2  * QEMU DirectSound audio driver header
3  *
4  * Copyright (c) 2005 Vassili Karpov (malc)
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 #ifdef DSBTYPE_IN
25 #define NAME "capture buffer"
26 #define TYPE in
27 #define IFACE IDirectSoundCaptureBuffer
28 #define BUFPTR LPDIRECTSOUNDCAPTUREBUFFER
29 #define FIELD dsound_capture_buffer
30 #else
31 #define NAME "playback buffer"
32 #define TYPE out
33 #define IFACE IDirectSoundBuffer
34 #define BUFPTR LPDIRECTSOUNDBUFFER
35 #define FIELD dsound_buffer
36 #endif
37
38 static int glue (dsound_unlock_, TYPE) (
39     BUFPTR buf,
40     LPVOID p1,
41     LPVOID p2,
42     DWORD blen1,
43     DWORD blen2
44     )
45 {
46     HRESULT hr;
47
48     hr = glue (IFACE, _Unlock) (buf, p1, blen1, p2, blen2);
49     if (FAILED (hr)) {
50         dsound_logerr (hr, "Can not unlock " NAME "\n");
51         return -1;
52     }
53
54     return 0;
55 }
56
57 static int glue (dsound_lock_, TYPE) (
58     BUFPTR buf,
59     struct audio_pcm_info *info,
60     DWORD pos,
61     DWORD len,
62     LPVOID *p1p,
63     LPVOID *p2p,
64     DWORD *blen1p,
65     DWORD *blen2p,
66     int entire
67     )
68 {
69     HRESULT hr;
70     int i;
71     LPVOID p1 = NULL, p2 = NULL;
72     DWORD blen1 = 0, blen2 = 0;
73
74     for (i = 0; i < conf.lock_retries; ++i) {
75         hr = glue (IFACE, _Lock) (
76             buf,
77             pos,
78             len,
79             &p1,
80             &blen1,
81             &p2,
82             &blen2,
83             (entire
84 #ifdef DSBTYPE_IN
85              ? DSCBLOCK_ENTIREBUFFER
86 #else
87              ? DSBLOCK_ENTIREBUFFER
88 #endif
89              : 0)
90             );
91
92         if (FAILED (hr)) {
93 #ifndef DSBTYPE_IN
94             if (hr == DSERR_BUFFERLOST) {
95                 if (glue (dsound_restore_, TYPE) (buf)) {
96                     dsound_logerr (hr, "Can not lock " NAME "\n");
97                     goto fail;
98                 }
99                 continue;
100             }
101 #endif
102             dsound_logerr (hr, "Can not lock " NAME "\n");
103             goto fail;
104         }
105
106         break;
107     }
108
109     if (i == conf.lock_retries) {
110         dolog ("%d attempts to lock " NAME " failed\n", i);
111         goto fail;
112     }
113
114     if ((p1 && (blen1 & info->align)) || (p2 && (blen2 & info->align))) {
115         dolog ("DirectSound returned misaligned buffer %ld %ld\n",
116                blen1, blen2);
117         glue (dsound_unlock_, TYPE) (buf, p1, p2, blen1, blen2);
118         goto fail;
119     }
120
121     if (!p1 && blen1) {
122         dolog ("warning: !p1 && blen1=%ld\n", blen1);
123         blen1 = 0;
124     }
125
126     if (!p2 && blen2) {
127         dolog ("warning: !p2 && blen2=%ld\n", blen2);
128         blen2 = 0;
129     }
130
131     *p1p = p1;
132     *p2p = p2;
133     *blen1p = blen1;
134     *blen2p = blen2;
135     return 0;
136
137  fail:
138     *p1p = NULL - 1;
139     *p2p = NULL - 1;
140     *blen1p = -1;
141     *blen2p = -1;
142     return -1;
143 }
144
145 #ifdef DSBTYPE_IN
146 static void dsound_fini_in (HWVoiceIn *hw)
147 #else
148 static void dsound_fini_out (HWVoiceOut *hw)
149 #endif
150 {
151     HRESULT hr;
152 #ifdef DSBTYPE_IN
153     DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
154 #else
155     DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
156 #endif
157
158     if (ds->FIELD) {
159         hr = glue (IFACE, _Stop) (ds->FIELD);
160         if (FAILED (hr)) {
161             dsound_logerr (hr, "Can not stop " NAME "\n");
162         }
163
164         hr = glue (IFACE, _Release) (ds->FIELD);
165         if (FAILED (hr)) {
166             dsound_logerr (hr, "Can not release " NAME "\n");
167         }
168         ds->FIELD = NULL;
169     }
170 }
171
172 #ifdef DSBTYPE_IN
173 static int dsound_init_in (
174     HWVoiceIn *hw,
175     int freq,
176     int nchannels,
177     audfmt_e fmt
178     )
179 #else
180 static int dsound_init_out (
181     HWVoiceOut *hw,
182     int freq,
183     int nchannels,
184     audfmt_e fmt
185     )
186 #endif
187 {
188     int err;
189     HRESULT hr;
190     dsound *s = &glob_dsound;
191     WAVEFORMATEX wfx;
192     struct full_fmt full_fmt;
193 #ifdef DSBTYPE_IN
194     const char *typ = "ADC";
195     DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
196     DSCBUFFERDESC bd;
197     DSCBCAPS bc;
198 #else
199     const char *typ = "DAC";
200     DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
201     DSBUFFERDESC bd;
202     DSBCAPS bc;
203 #endif
204
205     full_fmt.freq = freq;
206     full_fmt.nchannels = nchannels;
207     full_fmt.fmt = fmt;
208     err = waveformat_from_full_fmt (&wfx, &full_fmt);
209     if (err) {
210         return -1;
211     }
212
213     memset (&bd, 0, sizeof (bd));
214     bd.dwSize = sizeof (bd);
215     bd.lpwfxFormat = &wfx;
216 #ifdef DSBTYPE_IN
217     bd.dwBufferBytes = conf.bufsize_in;
218     hr = IDirectSoundCapture_CreateCaptureBuffer (
219         s->dsound_capture,
220         &bd,
221         &ds->dsound_capture_buffer,
222         NULL
223         );
224 #else
225     bd.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2;
226     bd.dwBufferBytes = conf.bufsize_out;
227     hr = IDirectSound_CreateSoundBuffer (
228         s->dsound,
229         &bd,
230         &ds->dsound_buffer,
231         NULL
232         );
233 #endif
234
235     if (FAILED (hr)) {
236         dsound_logerr2 (hr, typ, "Can not create " NAME "\n");
237         return -1;
238     }
239
240     hr = glue (IFACE, _GetFormat) (
241         ds->FIELD,
242         &wfx,
243         sizeof (wfx),
244         NULL
245         );
246     if (FAILED (hr)) {
247         dsound_logerr2 (hr, typ, "Can not get " NAME " format\n");
248         goto fail0;
249     }
250
251 #ifdef DEBUG_DSOUND
252     dolog (NAME "\n");
253     print_wave_format (&wfx);
254 #endif
255
256     memset (&bc, 0, sizeof (bc));
257     bc.dwSize = sizeof (bc);
258
259     hr = glue (IFACE, _GetCaps) (ds->FIELD, &bc);
260     if (FAILED (hr)) {
261         dsound_logerr2 (hr, typ, "Can not get " NAME " format\n");
262         goto fail0;
263     }
264
265     err = waveformat_to_full_fmt (&wfx, &full_fmt);
266     if (err) {
267         goto fail0;
268     }
269
270     ds->first_time = 1;
271     hw->bufsize = bc.dwBufferBytes;
272     audio_pcm_init_info (
273         &hw->info,
274         full_fmt.freq,
275         full_fmt.nchannels,
276         full_fmt.fmt,
277         audio_need_to_swap_endian (0)
278         );
279
280 #ifdef DEBUG_DSOUND
281     dolog ("caps %ld, desc %ld\n",
282            bc.dwBufferBytes, bd.dwBufferBytes);
283
284     dolog ("bufsize %d, freq %d, chan %d, fmt %d\n",
285            hw->bufsize, full_fmt.freq, full_fmt.nchannels, full_fmt.fmt);
286 #endif
287     return 0;
288
289  fail0:
290     glue (dsound_fini_, TYPE) (hw);
291     return -1;
292 }
293
294 #undef NAME
295 #undef TYPE
296 #undef IFACE
297 #undef BUFPTR
298 #undef FIELD