xref: /openbmc/qemu/audio/dsound_template.h (revision dfbd2768)
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     dsound *s
72     )
73 {
74     HRESULT hr;
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     hr = glue(IFACE, _Lock)(buf, pos, len, &p1, &blen1, &p2, &blen2, flag);
85 
86     if (FAILED (hr)) {
87 #ifndef DSBTYPE_IN
88         if (hr == DSERR_BUFFERLOST) {
89             if (glue (dsound_restore_, TYPE) (buf, s)) {
90                 dsound_logerr (hr, "Could not lock " NAME "\n");
91             }
92             goto fail;
93         }
94 #endif
95         dsound_logerr (hr, "Could not lock " NAME "\n");
96         goto fail;
97     }
98 
99     if ((p1 && (blen1 & info->align)) || (p2 && (blen2 & info->align))) {
100         dolog ("DirectSound returned misaligned buffer %ld %ld\n",
101                blen1, blen2);
102         glue (dsound_unlock_, TYPE) (buf, p1, p2, blen1, blen2);
103         goto fail;
104     }
105 
106     if (!p1 && blen1) {
107         dolog ("warning: !p1 && blen1=%ld\n", blen1);
108         blen1 = 0;
109     }
110 
111     if (!p2 && blen2) {
112         dolog ("warning: !p2 && blen2=%ld\n", blen2);
113         blen2 = 0;
114     }
115 
116     *p1p = p1;
117     *p2p = p2;
118     *blen1p = blen1;
119     *blen2p = blen2;
120     return 0;
121 
122  fail:
123     *p1p = NULL - 1;
124     *p2p = NULL - 1;
125     *blen1p = -1;
126     *blen2p = -1;
127     return -1;
128 }
129 
130 #ifdef DSBTYPE_IN
131 static void dsound_fini_in (HWVoiceIn *hw)
132 #else
133 static void dsound_fini_out (HWVoiceOut *hw)
134 #endif
135 {
136     HRESULT hr;
137 #ifdef DSBTYPE_IN
138     DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
139 #else
140     DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
141 #endif
142 
143     if (ds->FIELD) {
144         hr = glue (IFACE, _Stop) (ds->FIELD);
145         if (FAILED (hr)) {
146             dsound_logerr (hr, "Could not stop " NAME "\n");
147         }
148 
149         hr = glue (IFACE, _Release) (ds->FIELD);
150         if (FAILED (hr)) {
151             dsound_logerr (hr, "Could not release " NAME "\n");
152         }
153         ds->FIELD = NULL;
154     }
155 }
156 
157 #ifdef DSBTYPE_IN
158 static int dsound_init_in(HWVoiceIn *hw, struct audsettings *as,
159                           void *drv_opaque)
160 #else
161 static int dsound_init_out(HWVoiceOut *hw, struct audsettings *as,
162                            void *drv_opaque)
163 #endif
164 {
165     int err;
166     HRESULT hr;
167     dsound *s = drv_opaque;
168     WAVEFORMATEX wfx;
169     struct audsettings obt_as;
170     DSoundConf *conf = &s->conf;
171 #ifdef DSBTYPE_IN
172     const char *typ = "ADC";
173     DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
174     DSCBUFFERDESC bd;
175     DSCBCAPS bc;
176 #else
177     const char *typ = "DAC";
178     DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
179     DSBUFFERDESC bd;
180     DSBCAPS bc;
181 #endif
182 
183     if (!s->FIELD2) {
184         dolog ("Attempt to initialize voice without " NAME2 " object\n");
185         return -1;
186     }
187 
188     err = waveformat_from_audio_settings (&wfx, as);
189     if (err) {
190         return -1;
191     }
192 
193     memset (&bd, 0, sizeof (bd));
194     bd.dwSize = sizeof (bd);
195     bd.lpwfxFormat = &wfx;
196 #ifdef DSBTYPE_IN
197     bd.dwBufferBytes = conf->bufsize_in;
198     hr = IDirectSoundCapture_CreateCaptureBuffer (
199         s->dsound_capture,
200         &bd,
201         &ds->dsound_capture_buffer,
202         NULL
203         );
204 #else
205     bd.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2;
206     bd.dwBufferBytes = conf->bufsize_out;
207     hr = IDirectSound_CreateSoundBuffer (
208         s->dsound,
209         &bd,
210         &ds->dsound_buffer,
211         NULL
212         );
213 #endif
214 
215     if (FAILED (hr)) {
216         dsound_logerr2 (hr, typ, "Could not create " NAME "\n");
217         return -1;
218     }
219 
220     hr = glue (IFACE, _GetFormat) (ds->FIELD, &wfx, sizeof (wfx), NULL);
221     if (FAILED (hr)) {
222         dsound_logerr2 (hr, typ, "Could not get " NAME " format\n");
223         goto fail0;
224     }
225 
226 #ifdef DEBUG_DSOUND
227     dolog (NAME "\n");
228     print_wave_format (&wfx);
229 #endif
230 
231     memset (&bc, 0, sizeof (bc));
232     bc.dwSize = sizeof (bc);
233 
234     hr = glue (IFACE, _GetCaps) (ds->FIELD, &bc);
235     if (FAILED (hr)) {
236         dsound_logerr2 (hr, typ, "Could not get " NAME " format\n");
237         goto fail0;
238     }
239 
240     err = waveformat_to_audio_settings (&wfx, &obt_as);
241     if (err) {
242         goto fail0;
243     }
244 
245     ds->first_time = 1;
246     obt_as.endianness = 0;
247     audio_pcm_init_info (&hw->info, &obt_as);
248 
249     if (bc.dwBufferBytes & hw->info.align) {
250         dolog (
251             "GetCaps returned misaligned buffer size %ld, alignment %d\n",
252             bc.dwBufferBytes, hw->info.align + 1
253             );
254     }
255     hw->samples = bc.dwBufferBytes >> hw->info.shift;
256     ds->s = s;
257 
258 #ifdef DEBUG_DSOUND
259     dolog ("caps %ld, desc %ld\n",
260            bc.dwBufferBytes, bd.dwBufferBytes);
261 
262     dolog ("bufsize %d, freq %d, chan %d, fmt %d\n",
263            hw->bufsize, settings.freq, settings.nchannels, settings.fmt);
264 #endif
265     return 0;
266 
267  fail0:
268     glue (dsound_fini_, TYPE) (hw);
269     return -1;
270 }
271 
272 #undef NAME
273 #undef NAME2
274 #undef TYPE
275 #undef IFACE
276 #undef BUFPTR
277 #undef FIELD
278 #undef FIELD2
279