xref: /openbmc/qemu/audio/dsound_template.h (revision 2a886794)
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 "\n");
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     dsound *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 "\n");
93             }
94             goto fail;
95         }
96 #endif
97         dsound_logerr (hr, "Could not lock " NAME "\n");
98         goto fail;
99     }
100 
101     if ((p1p && *p1p && (*blen1p % info->bytes_per_frame)) ||
102         (p2p && *p2p && (*blen2p % info->bytes_per_frame))) {
103         dolog("DirectSound returned misaligned buffer %ld %ld\n",
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         dolog("warning: !p1 && blen1=%ld\n", *blen1p);
112         *blen1p = 0;
113     }
114 
115     if (p2p && !*p2p && *blen2p) {
116         dolog("warning: !p2 && blen2=%ld\n", *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 "\n");
149         }
150 
151         hr = glue (IFACE, _Release) (ds->FIELD);
152         if (FAILED (hr)) {
153             dsound_logerr (hr, "Could not release " NAME "\n");
154         }
155         ds->FIELD = NULL;
156     }
157 }
158 
159 #ifdef DSBTYPE_IN
160 static int dsound_init_in(HWVoiceIn *hw, struct audsettings *as,
161                           void *drv_opaque)
162 #else
163 static int dsound_init_out(HWVoiceOut *hw, struct audsettings *as,
164                            void *drv_opaque)
165 #endif
166 {
167     int err;
168     HRESULT hr;
169     dsound *s = drv_opaque;
170     WAVEFORMATEX wfx;
171     struct audsettings obt_as;
172 #ifdef DSBTYPE_IN
173     const char *typ = "ADC";
174     DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
175     DSCBUFFERDESC bd;
176     DSCBCAPS bc;
177     AudiodevPerDirectionOptions *pdo = s->dev->u.dsound.in;
178 #else
179     const char *typ = "DAC";
180     DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
181     DSBUFFERDESC bd;
182     DSBCAPS bc;
183     AudiodevPerDirectionOptions *pdo = s->dev->u.dsound.out;
184 #endif
185 
186     if (!s->FIELD2) {
187         dolog ("Attempt to initialize voice without " NAME2 " object\n");
188         return -1;
189     }
190 
191     err = waveformat_from_audio_settings (&wfx, as);
192     if (err) {
193         return -1;
194     }
195 
196     memset (&bd, 0, sizeof (bd));
197     bd.dwSize = sizeof (bd);
198     bd.lpwfxFormat = &wfx;
199     bd.dwBufferBytes = audio_buffer_bytes(pdo, as, 92880);
200 #ifdef DSBTYPE_IN
201     hr = IDirectSoundCapture_CreateCaptureBuffer (
202         s->dsound_capture,
203         &bd,
204         &ds->dsound_capture_buffer,
205         NULL
206         );
207 #else
208     bd.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2;
209     hr = IDirectSound_CreateSoundBuffer (
210         s->dsound,
211         &bd,
212         &ds->dsound_buffer,
213         NULL
214         );
215 #endif
216 
217     if (FAILED (hr)) {
218         dsound_logerr2 (hr, typ, "Could not create " NAME "\n");
219         return -1;
220     }
221 
222     hr = glue (IFACE, _GetFormat) (ds->FIELD, &wfx, sizeof (wfx), NULL);
223     if (FAILED (hr)) {
224         dsound_logerr2 (hr, typ, "Could not get " NAME " format\n");
225         goto fail0;
226     }
227 
228 #ifdef DEBUG_DSOUND
229     dolog (NAME "\n");
230     print_wave_format (&wfx);
231 #endif
232 
233     memset (&bc, 0, sizeof (bc));
234     bc.dwSize = sizeof (bc);
235 
236     hr = glue (IFACE, _GetCaps) (ds->FIELD, &bc);
237     if (FAILED (hr)) {
238         dsound_logerr2 (hr, typ, "Could not get " NAME " format\n");
239         goto fail0;
240     }
241 
242     err = waveformat_to_audio_settings (&wfx, &obt_as);
243     if (err) {
244         goto fail0;
245     }
246 
247     obt_as.endianness = 0;
248     audio_pcm_init_info (&hw->info, &obt_as);
249 
250     if (bc.dwBufferBytes % hw->info.bytes_per_frame) {
251         dolog (
252             "GetCaps returned misaligned buffer size %ld, alignment %d\n",
253             bc.dwBufferBytes, hw->info.bytes_per_frame
254             );
255     }
256     hw->size_emul = bc.dwBufferBytes;
257     hw->samples = bc.dwBufferBytes / hw->info.bytes_per_frame;
258     ds->s = s;
259 
260 #ifdef DEBUG_DSOUND
261     dolog ("caps %ld, desc %ld\n",
262            bc.dwBufferBytes, bd.dwBufferBytes);
263 #endif
264     return 0;
265 
266  fail0:
267     glue (dsound_fini_, TYPE) (hw);
268     return -1;
269 }
270 
271 #undef NAME
272 #undef NAME2
273 #undef TYPE
274 #undef IFACE
275 #undef BUFPTR
276 #undef FIELD
277 #undef FIELD2
278 #undef HWVOICE
279 #undef DSOUNDVOICE
280