0.8.0-alt1
[qemu] / 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, "Could 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, "Could not lock " NAME "\n");
97                     goto fail;
98                 }
99                 continue;
100             }
101 #endif
102             dsound_logerr (hr, "Could 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, "Could not stop " NAME "\n");
162         }
163
164         hr = glue (IFACE, _Release) (ds->FIELD);
165         if (FAILED (hr)) {
166             dsound_logerr (hr, "Could not release " NAME "\n");
167         }
168         ds->FIELD = NULL;
169     }
170 }
171
172 #ifdef DSBTYPE_IN
173 static int dsound_init_in (HWVoiceIn *hw, audsettings_t *as)
174 #else
175 static int dsound_init_out (HWVoiceOut *hw, audsettings_t *as)
176 #endif
177 {
178     int err;
179     HRESULT hr;
180     dsound *s = &glob_dsound;
181     WAVEFORMATEX wfx;
182     audsettings_t obt_as;
183 #ifdef DSBTYPE_IN
184     const char *typ = "ADC";
185     DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
186     DSCBUFFERDESC bd;
187     DSCBCAPS bc;
188 #else
189     const char *typ = "DAC";
190     DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
191     DSBUFFERDESC bd;
192     DSBCAPS bc;
193 #endif
194
195     err = waveformat_from_audio_settings (&wfx, as);
196     if (err) {
197         return -1;
198     }
199
200     memset (&bd, 0, sizeof (bd));
201     bd.dwSize = sizeof (bd);
202     bd.lpwfxFormat = &wfx;
203 #ifdef DSBTYPE_IN
204     bd.dwBufferBytes = conf.bufsize_in;
205     hr = IDirectSoundCapture_CreateCaptureBuffer (
206         s->dsound_capture,
207         &bd,
208         &ds->dsound_capture_buffer,
209         NULL
210         );
211 #else
212     bd.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2;
213     bd.dwBufferBytes = conf.bufsize_out;
214     hr = IDirectSound_CreateSoundBuffer (
215         s->dsound,
216         &bd,
217         &ds->dsound_buffer,
218         NULL
219         );
220 #endif
221
222     if (FAILED (hr)) {
223         dsound_logerr2 (hr, typ, "Could not create " NAME "\n");
224         return -1;
225     }
226
227     hr = glue (IFACE, _GetFormat) (ds->FIELD, &wfx, sizeof (wfx), NULL);
228     if (FAILED (hr)) {
229         dsound_logerr2 (hr, typ, "Could not get " NAME " format\n");
230         goto fail0;
231     }
232
233 #ifdef DEBUG_DSOUND
234     dolog (NAME "\n");
235     print_wave_format (&wfx);
236 #endif
237
238     memset (&bc, 0, sizeof (bc));
239     bc.dwSize = sizeof (bc);
240
241     hr = glue (IFACE, _GetCaps) (ds->FIELD, &bc);
242     if (FAILED (hr)) {
243         dsound_logerr2 (hr, typ, "Could not get " NAME " format\n");
244         goto fail0;
245     }
246
247     err = waveformat_to_audio_settings (&wfx, &obt_as);
248     if (err) {
249         goto fail0;
250     }
251
252     ds->first_time = 1;
253
254     audio_pcm_init_info (&hw->info, &obt_as, audio_need_to_swap_endian (0));
255
256     if (bc.dwBufferBytes & hw->info.align) {
257         dolog (
258             "GetCaps returned misaligned buffer size %ld, alignment %d\n",
259             bc.dwBufferBytes, hw->info.align + 1
260             );
261     }
262     hw->samples = bc.dwBufferBytes >> hw->info.shift;
263
264 #ifdef DEBUG_DSOUND
265     dolog ("caps %ld, desc %ld\n",
266            bc.dwBufferBytes, bd.dwBufferBytes);
267
268     dolog ("bufsize %d, freq %d, chan %d, fmt %d\n",
269            hw->bufsize, settings.freq, settings.nchannels, settings.fmt);
270 #endif
271     return 0;
272
273  fail0:
274     glue (dsound_fini_, TYPE) (hw);
275     return -1;
276 }
277
278 #undef NAME
279 #undef TYPE
280 #undef IFACE
281 #undef BUFPTR
282 #undef FIELD