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