|
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 NAME2 "DirectSoundCapture" |
|
27 #define TYPE in |
|
28 #define IFACE IDirectSoundCaptureBuffer |
|
29 #define BUFPTR LPDIRECTSOUNDCAPTUREBUFFER |
|
30 #define FIELD dsound_capture_buffer |
|
31 #define FIELD2 dsound_capture |
|
32 #else |
|
33 #define NAME "playback buffer" |
|
34 #define NAME2 "DirectSound" |
|
35 #define TYPE out |
|
36 #define IFACE IDirectSoundBuffer |
|
37 #define BUFPTR LPDIRECTSOUNDBUFFER |
|
38 #define FIELD dsound_buffer |
|
39 #define FIELD2 dsound |
|
40 #endif |
|
41 |
|
42 static int glue (dsound_unlock_, TYPE) ( |
|
43 BUFPTR buf, |
|
44 LPVOID p1, |
|
45 LPVOID p2, |
|
46 DWORD blen1, |
|
47 DWORD blen2 |
|
48 ) |
|
49 { |
|
50 HRESULT hr; |
|
51 |
|
52 hr = glue (IFACE, _Unlock) (buf, p1, blen1, p2, blen2); |
|
53 if (FAILED (hr)) { |
|
54 dsound_logerr (hr, "Could not unlock " NAME "\n"); |
|
55 return -1; |
|
56 } |
|
57 |
|
58 return 0; |
|
59 } |
|
60 |
|
61 static int glue (dsound_lock_, TYPE) ( |
|
62 BUFPTR buf, |
|
63 struct audio_pcm_info *info, |
|
64 DWORD pos, |
|
65 DWORD len, |
|
66 LPVOID *p1p, |
|
67 LPVOID *p2p, |
|
68 DWORD *blen1p, |
|
69 DWORD *blen2p, |
|
70 int entire |
|
71 ) |
|
72 { |
|
73 HRESULT hr; |
|
74 int i; |
|
75 LPVOID p1 = NULL, p2 = NULL; |
|
76 DWORD blen1 = 0, blen2 = 0; |
|
77 DWORD flag; |
|
78 |
|
79 #ifdef DSBTYPE_IN |
|
80 flag = entire ? DSCBLOCK_ENTIREBUFFER : 0; |
|
81 #else |
|
82 flag = entire ? DSBLOCK_ENTIREBUFFER : 0; |
|
83 #endif |
|
84 for (i = 0; i < conf.lock_retries; ++i) { |
|
85 hr = glue (IFACE, _Lock) ( |
|
86 buf, |
|
87 pos, |
|
88 len, |
|
89 &p1, |
|
90 &blen1, |
|
91 &p2, |
|
92 &blen2, |
|
93 flag |
|
94 ); |
|
95 |
|
96 if (FAILED (hr)) { |
|
97 #ifndef DSBTYPE_IN |
|
98 if (hr == DSERR_BUFFERLOST) { |
|
99 if (glue (dsound_restore_, TYPE) (buf)) { |
|
100 dsound_logerr (hr, "Could not lock " NAME "\n"); |
|
101 goto fail; |
|
102 } |
|
103 continue; |
|
104 } |
|
105 #endif |
|
106 dsound_logerr (hr, "Could not lock " NAME "\n"); |
|
107 goto fail; |
|
108 } |
|
109 |
|
110 break; |
|
111 } |
|
112 |
|
113 if (i == conf.lock_retries) { |
|
114 dolog ("%d attempts to lock " NAME " failed\n", i); |
|
115 goto fail; |
|
116 } |
|
117 |
|
118 if ((p1 && (blen1 & info->align)) || (p2 && (blen2 & info->align))) { |
|
119 dolog ("DirectSound returned misaligned buffer %ld %ld\n", |
|
120 blen1, blen2); |
|
121 glue (dsound_unlock_, TYPE) (buf, p1, p2, blen1, blen2); |
|
122 goto fail; |
|
123 } |
|
124 |
|
125 if (!p1 && blen1) { |
|
126 dolog ("warning: !p1 && blen1=%ld\n", blen1); |
|
127 blen1 = 0; |
|
128 } |
|
129 |
|
130 if (!p2 && blen2) { |
|
131 dolog ("warning: !p2 && blen2=%ld\n", blen2); |
|
132 blen2 = 0; |
|
133 } |
|
134 |
|
135 *p1p = p1; |
|
136 *p2p = p2; |
|
137 *blen1p = blen1; |
|
138 *blen2p = blen2; |
|
139 return 0; |
|
140 |
|
141 fail: |
|
142 *p1p = NULL - 1; |
|
143 *p2p = NULL - 1; |
|
144 *blen1p = -1; |
|
145 *blen2p = -1; |
|
146 return -1; |
|
147 } |
|
148 |
|
149 #ifdef DSBTYPE_IN |
|
150 static void dsound_fini_in (HWVoiceIn *hw) |
|
151 #else |
|
152 static void dsound_fini_out (HWVoiceOut *hw) |
|
153 #endif |
|
154 { |
|
155 HRESULT hr; |
|
156 #ifdef DSBTYPE_IN |
|
157 DSoundVoiceIn *ds = (DSoundVoiceIn *) hw; |
|
158 #else |
|
159 DSoundVoiceOut *ds = (DSoundVoiceOut *) hw; |
|
160 #endif |
|
161 |
|
162 if (ds->FIELD) { |
|
163 hr = glue (IFACE, _Stop) (ds->FIELD); |
|
164 if (FAILED (hr)) { |
|
165 dsound_logerr (hr, "Could not stop " NAME "\n"); |
|
166 } |
|
167 |
|
168 hr = glue (IFACE, _Release) (ds->FIELD); |
|
169 if (FAILED (hr)) { |
|
170 dsound_logerr (hr, "Could not release " NAME "\n"); |
|
171 } |
|
172 ds->FIELD = NULL; |
|
173 } |
|
174 } |
|
175 |
|
176 #ifdef DSBTYPE_IN |
|
177 static int dsound_init_in (HWVoiceIn *hw, struct audsettings *as) |
|
178 #else |
|
179 static int dsound_init_out (HWVoiceOut *hw, struct audsettings *as) |
|
180 #endif |
|
181 { |
|
182 int err; |
|
183 HRESULT hr; |
|
184 dsound *s = &glob_dsound; |
|
185 WAVEFORMATEX wfx; |
|
186 struct audsettings obt_as; |
|
187 #ifdef DSBTYPE_IN |
|
188 const char *typ = "ADC"; |
|
189 DSoundVoiceIn *ds = (DSoundVoiceIn *) hw; |
|
190 DSCBUFFERDESC bd; |
|
191 DSCBCAPS bc; |
|
192 #else |
|
193 const char *typ = "DAC"; |
|
194 DSoundVoiceOut *ds = (DSoundVoiceOut *) hw; |
|
195 DSBUFFERDESC bd; |
|
196 DSBCAPS bc; |
|
197 #endif |
|
198 |
|
199 if (!s->FIELD2) { |
|
200 dolog ("Attempt to initialize voice without " NAME2 " object\n"); |
|
201 return -1; |
|
202 } |
|
203 |
|
204 err = waveformat_from_audio_settings (&wfx, as); |
|
205 if (err) { |
|
206 return -1; |
|
207 } |
|
208 |
|
209 memset (&bd, 0, sizeof (bd)); |
|
210 bd.dwSize = sizeof (bd); |
|
211 bd.lpwfxFormat = &wfx; |
|
212 #ifdef DSBTYPE_IN |
|
213 bd.dwBufferBytes = conf.bufsize_in; |
|
214 hr = IDirectSoundCapture_CreateCaptureBuffer ( |
|
215 s->dsound_capture, |
|
216 &bd, |
|
217 &ds->dsound_capture_buffer, |
|
218 NULL |
|
219 ); |
|
220 #else |
|
221 bd.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2; |
|
222 bd.dwBufferBytes = conf.bufsize_out; |
|
223 hr = IDirectSound_CreateSoundBuffer ( |
|
224 s->dsound, |
|
225 &bd, |
|
226 &ds->dsound_buffer, |
|
227 NULL |
|
228 ); |
|
229 #endif |
|
230 |
|
231 if (FAILED (hr)) { |
|
232 dsound_logerr2 (hr, typ, "Could not create " NAME "\n"); |
|
233 return -1; |
|
234 } |
|
235 |
|
236 hr = glue (IFACE, _GetFormat) (ds->FIELD, &wfx, sizeof (wfx), NULL); |
|
237 if (FAILED (hr)) { |
|
238 dsound_logerr2 (hr, typ, "Could not get " NAME " format\n"); |
|
239 goto fail0; |
|
240 } |
|
241 |
|
242 #ifdef DEBUG_DSOUND |
|
243 dolog (NAME "\n"); |
|
244 print_wave_format (&wfx); |
|
245 #endif |
|
246 |
|
247 memset (&bc, 0, sizeof (bc)); |
|
248 bc.dwSize = sizeof (bc); |
|
249 |
|
250 hr = glue (IFACE, _GetCaps) (ds->FIELD, &bc); |
|
251 if (FAILED (hr)) { |
|
252 dsound_logerr2 (hr, typ, "Could not get " NAME " format\n"); |
|
253 goto fail0; |
|
254 } |
|
255 |
|
256 err = waveformat_to_audio_settings (&wfx, &obt_as); |
|
257 if (err) { |
|
258 goto fail0; |
|
259 } |
|
260 |
|
261 ds->first_time = 1; |
|
262 obt_as.endianness = 0; |
|
263 audio_pcm_init_info (&hw->info, &obt_as); |
|
264 |
|
265 if (bc.dwBufferBytes & hw->info.align) { |
|
266 dolog ( |
|
267 "GetCaps returned misaligned buffer size %ld, alignment %d\n", |
|
268 bc.dwBufferBytes, hw->info.align + 1 |
|
269 ); |
|
270 } |
|
271 hw->samples = bc.dwBufferBytes >> hw->info.shift; |
|
272 |
|
273 #ifdef DEBUG_DSOUND |
|
274 dolog ("caps %ld, desc %ld\n", |
|
275 bc.dwBufferBytes, bd.dwBufferBytes); |
|
276 |
|
277 dolog ("bufsize %d, freq %d, chan %d, fmt %d\n", |
|
278 hw->bufsize, settings.freq, settings.nchannels, settings.fmt); |
|
279 #endif |
|
280 return 0; |
|
281 |
|
282 fail0: |
|
283 glue (dsound_fini_, TYPE) (hw); |
|
284 return -1; |
|
285 } |
|
286 |
|
287 #undef NAME |
|
288 #undef TYPE |
|
289 #undef IFACE |
|
290 #undef BUFPTR |
|
291 #undef FIELD |