xref: /openbmc/qemu/audio/dsound_template.h (revision 1fd6bb44)
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 NAME2
289 #undef TYPE
290 #undef IFACE
291 #undef BUFPTR
292 #undef FIELD
293 #undef FIELD2
294