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
glue(dsound_unlock_,TYPE)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
glue(dsound_lock_,TYPE)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
dsound_fini_in(HWVoiceIn * hw)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
dsound_init_in(HWVoiceIn * hw,audsettings_t * as)177 static int dsound_init_in (HWVoiceIn *hw, audsettings_t *as)
178 #else
179 static int dsound_init_out (HWVoiceOut *hw, audsettings_t *as)
180 #endif
181 {
182 int err;
183 HRESULT hr;
184 dsound *s = &glob_dsound;
185 WAVEFORMATEX wfx;
186 audsettings_t 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
292