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