Mercurial > sdl-ios-xcode
comparison src/audio/qsa/SDL_qsa_audio.c @ 3139:7f684f249ec9
indent
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Sat, 23 May 2009 22:41:08 +0000 |
parents | 60301ed80050 |
children | f7b03b6838cb |
comparison
equal
deleted
inserted
replaced
3125:d71d8ceda8b3 | 3139:7f684f249ec9 |
---|---|
57 #define QSA_NO_WORKAROUNDS 0x00000000 | 57 #define QSA_NO_WORKAROUNDS 0x00000000 |
58 #define QSA_MMAP_WORKAROUND 0x00000001 | 58 #define QSA_MMAP_WORKAROUND 0x00000001 |
59 | 59 |
60 struct BuggyCards | 60 struct BuggyCards |
61 { | 61 { |
62 char* cardname; | 62 char *cardname; |
63 unsigned long bugtype; | 63 unsigned long bugtype; |
64 }; | 64 }; |
65 | 65 |
66 #define QSA_WA_CARDS 3 | 66 #define QSA_WA_CARDS 3 |
67 #define QSA_MAX_CARD_NAME_LENGTH 33 | 67 #define QSA_MAX_CARD_NAME_LENGTH 33 |
68 | 68 |
69 struct BuggyCards buggycards[QSA_WA_CARDS]= | 69 struct BuggyCards buggycards[QSA_WA_CARDS] = { |
70 { | 70 {"Sound Blaster Live!", QSA_MMAP_WORKAROUND}, |
71 {"Sound Blaster Live!", QSA_MMAP_WORKAROUND}, | 71 {"Vortex 8820", QSA_MMAP_WORKAROUND}, |
72 {"Vortex 8820", QSA_MMAP_WORKAROUND}, | 72 {"Vortex 8830", QSA_MMAP_WORKAROUND}, |
73 {"Vortex 8830", QSA_MMAP_WORKAROUND}, | |
74 }; | 73 }; |
75 | 74 |
76 /* List of found devices */ | 75 /* List of found devices */ |
77 #define QSA_MAX_DEVICES 32 | 76 #define QSA_MAX_DEVICES 32 |
78 #define QSA_MAX_NAME_LENGTH 81+16 /* Hardcoded in QSA, can't be changed */ | 77 #define QSA_MAX_NAME_LENGTH 81+16 /* Hardcoded in QSA, can't be changed */ |
79 | 78 |
80 typedef struct _QSA_Device | 79 typedef struct _QSA_Device |
81 { | 80 { |
82 char name[QSA_MAX_NAME_LENGTH]; /* Long audio device name for SDL */ | 81 char name[QSA_MAX_NAME_LENGTH]; /* Long audio device name for SDL */ |
83 int cardno; | 82 int cardno; |
84 int deviceno; | 83 int deviceno; |
85 } QSA_Device; | 84 } QSA_Device; |
86 | 85 |
87 QSA_Device qsa_playback_device[QSA_MAX_DEVICES]; | 86 QSA_Device qsa_playback_device[QSA_MAX_DEVICES]; |
88 uint32_t qsa_playback_devices; | 87 uint32_t qsa_playback_devices; |
89 | 88 |
90 QSA_Device qsa_capture_device[QSA_MAX_DEVICES]; | 89 QSA_Device qsa_capture_device[QSA_MAX_DEVICES]; |
91 uint32_t qsa_capture_devices; | 90 uint32_t qsa_capture_devices; |
92 | 91 |
93 static inline void QSA_SetError(const char* fn, int status) | 92 static inline void |
94 { | 93 QSA_SetError(const char *fn, int status) |
95 SDL_SetError("QSA: %s() failed: %s", fn, snd_strerror(status)); | 94 { |
95 SDL_SetError("QSA: %s() failed: %s", fn, snd_strerror(status)); | |
96 } | 96 } |
97 | 97 |
98 /* card names check to apply the workarounds */ | 98 /* card names check to apply the workarounds */ |
99 static int QSA_CheckBuggyCards(_THIS, unsigned long checkfor) | 99 static int |
100 { | 100 QSA_CheckBuggyCards(_THIS, unsigned long checkfor) |
101 char scardname[QSA_MAX_CARD_NAME_LENGTH]; | 101 { |
102 int it; | 102 char scardname[QSA_MAX_CARD_NAME_LENGTH]; |
103 | 103 int it; |
104 if (snd_card_get_name(this->hidden->cardno, scardname, QSA_MAX_CARD_NAME_LENGTH-1)<0) | 104 |
105 { | 105 if (snd_card_get_name |
106 return 0; | 106 (this->hidden->cardno, scardname, QSA_MAX_CARD_NAME_LENGTH - 1) < 0) { |
107 } | 107 return 0; |
108 | 108 } |
109 for (it=0; it<QSA_WA_CARDS; it++) | 109 |
110 { | 110 for (it = 0; it < QSA_WA_CARDS; it++) { |
111 if (SDL_strcmp(buggycards[it].cardname, scardname)==0) | 111 if (SDL_strcmp(buggycards[it].cardname, scardname) == 0) { |
112 { | 112 if (buggycards[it].bugtype == checkfor) { |
113 if (buggycards[it].bugtype==checkfor) | 113 return 1; |
114 { | 114 } |
115 return 1; | 115 } |
116 } | 116 } |
117 } | 117 |
118 } | 118 return 0; |
119 | 119 } |
120 return 0; | 120 |
121 } | 121 static void |
122 | 122 QSA_ThreadInit(_THIS) |
123 static void QSA_ThreadInit(_THIS) | 123 { |
124 { | 124 struct sched_param param; |
125 struct sched_param param; | 125 int status; |
126 int status; | 126 |
127 | 127 /* Increase default 10 priority to 25 to avoid jerky sound */ |
128 /* Increase default 10 priority to 25 to avoid jerky sound */ | 128 status = SchedGet(0, 0, ¶m); |
129 status=SchedGet(0, 0, ¶m); | 129 param.sched_priority = param.sched_curpriority + 15; |
130 param.sched_priority=param.sched_curpriority + 15; | 130 status = SchedSet(0, 0, SCHED_NOCHANGE, ¶m); |
131 status=SchedSet(0, 0, SCHED_NOCHANGE, ¶m); | |
132 } | 131 } |
133 | 132 |
134 /* PCM channel parameters initialize function */ | 133 /* PCM channel parameters initialize function */ |
135 static void QSA_InitAudioParams(snd_pcm_channel_params_t* cpars) | 134 static void |
136 { | 135 QSA_InitAudioParams(snd_pcm_channel_params_t * cpars) |
137 SDL_memset(cpars, 0, sizeof(snd_pcm_channel_params_t)); | 136 { |
138 | 137 SDL_memset(cpars, 0, sizeof(snd_pcm_channel_params_t)); |
139 cpars->channel=SND_PCM_CHANNEL_PLAYBACK; | 138 |
140 cpars->mode=SND_PCM_MODE_BLOCK; | 139 cpars->channel = SND_PCM_CHANNEL_PLAYBACK; |
141 cpars->start_mode=SND_PCM_START_DATA; | 140 cpars->mode = SND_PCM_MODE_BLOCK; |
142 cpars->stop_mode=SND_PCM_STOP_STOP; | 141 cpars->start_mode = SND_PCM_START_DATA; |
143 cpars->format.format=SND_PCM_SFMT_S16_LE; | 142 cpars->stop_mode = SND_PCM_STOP_STOP; |
144 cpars->format.interleave=1; | 143 cpars->format.format = SND_PCM_SFMT_S16_LE; |
145 cpars->format.rate=DEFAULT_CPARAMS_RATE; | 144 cpars->format.interleave = 1; |
146 cpars->format.voices=DEFAULT_CPARAMS_VOICES; | 145 cpars->format.rate = DEFAULT_CPARAMS_RATE; |
147 cpars->buf.block.frag_size=DEFAULT_CPARAMS_FRAG_SIZE; | 146 cpars->format.voices = DEFAULT_CPARAMS_VOICES; |
148 cpars->buf.block.frags_min=DEFAULT_CPARAMS_FRAGS_MIN; | 147 cpars->buf.block.frag_size = DEFAULT_CPARAMS_FRAG_SIZE; |
149 cpars->buf.block.frags_max=DEFAULT_CPARAMS_FRAGS_MAX; | 148 cpars->buf.block.frags_min = DEFAULT_CPARAMS_FRAGS_MIN; |
149 cpars->buf.block.frags_max = DEFAULT_CPARAMS_FRAGS_MAX; | |
150 } | 150 } |
151 | 151 |
152 /* This function waits until it is possible to write a full sound buffer */ | 152 /* This function waits until it is possible to write a full sound buffer */ |
153 static void QSA_WaitDevice(_THIS) | 153 static void |
154 { | 154 QSA_WaitDevice(_THIS) |
155 fd_set wfds; | 155 { |
156 fd_set rfds; | 156 fd_set wfds; |
157 int selectret; | 157 fd_set rfds; |
158 struct timeval timeout; | 158 int selectret; |
159 | 159 struct timeval timeout; |
160 if (!this->hidden->iscapture) | 160 |
161 { | 161 if (!this->hidden->iscapture) { |
162 FD_ZERO(&wfds); | 162 FD_ZERO(&wfds); |
163 FD_SET(this->hidden->audio_fd, &wfds); | 163 FD_SET(this->hidden->audio_fd, &wfds); |
164 } | 164 } else { |
165 else | 165 FD_ZERO(&rfds); |
166 { | 166 FD_SET(this->hidden->audio_fd, &rfds); |
167 FD_ZERO(&rfds); | 167 } |
168 FD_SET(this->hidden->audio_fd, &rfds); | 168 |
169 } | 169 do { |
170 | 170 /* Setup timeout for playing one fragment equal to 2 seconds */ |
171 do { | 171 /* If timeout occured than something wrong with hardware or driver */ |
172 /* Setup timeout for playing one fragment equal to 2 seconds */ | 172 /* For example, Vortex 8820 audio driver stucks on second DAC because */ |
173 /* If timeout occured than something wrong with hardware or driver */ | 173 /* it doesn't exist ! */ |
174 /* For example, Vortex 8820 audio driver stucks on second DAC because */ | 174 timeout.tv_sec = 2; |
175 /* it doesn't exist ! */ | 175 timeout.tv_usec = 0; |
176 timeout.tv_sec=2; | 176 this->hidden->timeout_on_wait = 0; |
177 timeout.tv_usec=0; | 177 |
178 this->hidden->timeout_on_wait=0; | 178 if (!this->hidden->iscapture) { |
179 | 179 selectret = |
180 if (!this->hidden->iscapture) | 180 select(this->hidden->audio_fd + 1, NULL, &wfds, NULL, |
181 { | 181 &timeout); |
182 selectret=select(this->hidden->audio_fd+1, NULL, &wfds, NULL, &timeout); | 182 } else { |
183 } | 183 selectret = |
184 else | 184 select(this->hidden->audio_fd + 1, &rfds, NULL, NULL, |
185 { | 185 &timeout); |
186 selectret=select(this->hidden->audio_fd+1, &rfds, NULL, NULL, &timeout); | 186 } |
187 } | 187 |
188 | 188 switch (selectret) { |
189 switch(selectret) | 189 case -1: |
190 { | 190 { |
191 case -1: | 191 SDL_SetError("QSA: select() failed: %s\n", strerror(errno)); |
192 { | 192 return; |
193 SDL_SetError("QSA: select() failed: %s\n", strerror(errno)); | 193 } |
194 return; | 194 break; |
195 } | 195 case 0: |
196 break; | 196 { |
197 case 0: | 197 SDL_SetError("QSA: timeout on buffer waiting occured\n"); |
198 { | 198 this->hidden->timeout_on_wait = 1; |
199 SDL_SetError("QSA: timeout on buffer waiting occured\n"); | 199 return; |
200 this->hidden->timeout_on_wait=1; | 200 } |
201 return; | 201 break; |
202 } | 202 default: |
203 break; | 203 { |
204 default: | 204 if (!this->hidden->iscapture) { |
205 { | 205 if (FD_ISSET(this->hidden->audio_fd, &wfds)) { |
206 if (!this->hidden->iscapture) | 206 return; |
207 { | |
208 if (FD_ISSET(this->hidden->audio_fd, &wfds)) | |
209 { | |
210 return; | |
211 } | 207 } |
212 } | 208 } else { |
213 else | 209 if (FD_ISSET(this->hidden->audio_fd, &rfds)) { |
214 { | 210 return; |
215 if (FD_ISSET(this->hidden->audio_fd, &rfds)) | |
216 { | |
217 return; | |
218 } | 211 } |
219 } | 212 } |
220 } | 213 } |
221 break; | 214 break; |
222 } | 215 } |
223 } while (1); | 216 } while (1); |
224 } | 217 } |
225 | 218 |
226 static void QSA_PlayDevice(_THIS) | 219 static void |
227 { | 220 QSA_PlayDevice(_THIS) |
228 snd_pcm_channel_status_t cstatus; | 221 { |
229 int written; | 222 snd_pcm_channel_status_t cstatus; |
230 int status; | 223 int written; |
231 int towrite; | 224 int status; |
232 void* pcmbuffer; | 225 int towrite; |
233 | 226 void *pcmbuffer; |
234 if ((!this->enabled) || (!this->hidden)) | 227 |
235 { | 228 if ((!this->enabled) || (!this->hidden)) { |
236 return; | 229 return; |
237 } | 230 } |
238 | 231 |
239 towrite = this->spec.size; | 232 towrite = this->spec.size; |
240 pcmbuffer = this->hidden->pcm_buf; | 233 pcmbuffer = this->hidden->pcm_buf; |
241 | 234 |
242 /* Write the audio data, checking for EAGAIN (buffer full) and underrun */ | 235 /* Write the audio data, checking for EAGAIN (buffer full) and underrun */ |
243 do { | 236 do { |
244 written=snd_pcm_plugin_write(this->hidden->audio_handle, pcmbuffer, towrite); | 237 written = |
245 if (written!=towrite) | 238 snd_pcm_plugin_write(this->hidden->audio_handle, pcmbuffer, |
246 { | 239 towrite); |
247 /* Check if samples playback got stuck somewhere in hardware or in */ | 240 if (written != towrite) { |
248 /* the audio device driver */ | 241 /* Check if samples playback got stuck somewhere in hardware or in */ |
249 if ((errno==EAGAIN) && (written==0)) | 242 /* the audio device driver */ |
250 { | 243 if ((errno == EAGAIN) && (written == 0)) { |
251 if (this->hidden->timeout_on_wait!=0) | 244 if (this->hidden->timeout_on_wait != 0) { |
252 { | 245 SDL_SetError("QSA: buffer playback timeout\n"); |
253 SDL_SetError("QSA: buffer playback timeout\n"); | 246 return; |
254 return; | 247 } |
255 } | 248 } |
256 } | 249 |
257 | 250 /* Check for errors or conditions */ |
258 /* Check for errors or conditions */ | 251 if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { |
259 if ((errno==EAGAIN)||(errno==EWOULDBLOCK)) | 252 /* Let a little CPU time go by and try to write again */ |
260 { | 253 SDL_Delay(1); |
261 /* Let a little CPU time go by and try to write again */ | 254 |
262 SDL_Delay(1); | 255 /* if we wrote some data */ |
263 | 256 towrite -= written; |
264 /* if we wrote some data */ | 257 pcmbuffer += written * this->spec.channels; |
265 towrite-=written; | 258 continue; |
266 pcmbuffer+=written*this->spec.channels; | 259 } else { |
267 continue; | 260 if ((errno == EINVAL) || (errno == EIO)) { |
268 } | 261 SDL_memset(&cstatus, 0, sizeof(cstatus)); |
269 else | 262 if (!this->hidden->iscapture) { |
270 { | 263 cstatus.channel = SND_PCM_CHANNEL_PLAYBACK; |
271 if ((errno==EINVAL)||(errno==EIO)) | 264 } else { |
272 { | 265 cstatus.channel = SND_PCM_CHANNEL_CAPTURE; |
273 SDL_memset(&cstatus, 0, sizeof(cstatus)); | 266 } |
274 if (!this->hidden->iscapture) | 267 |
275 { | 268 status = |
276 cstatus.channel=SND_PCM_CHANNEL_PLAYBACK; | 269 snd_pcm_plugin_status(this->hidden->audio_handle, |
277 } | 270 &cstatus); |
278 else | 271 if (status < 0) { |
279 { | 272 QSA_SetError("snd_pcm_plugin_status", status); |
280 cstatus.channel=SND_PCM_CHANNEL_CAPTURE; | 273 return; |
281 } | 274 } |
282 | 275 |
283 status=snd_pcm_plugin_status(this->hidden->audio_handle, &cstatus); | 276 if ((cstatus.status == SND_PCM_STATUS_UNDERRUN) || |
284 if (status<0) | 277 (cstatus.status == SND_PCM_STATUS_READY)) { |
285 { | 278 if (!this->hidden->iscapture) { |
286 QSA_SetError("snd_pcm_plugin_status", status); | 279 status = |
287 return; | 280 snd_pcm_plugin_prepare(this->hidden-> |
288 } | 281 audio_handle, |
289 | 282 SND_PCM_CHANNEL_PLAYBACK); |
290 if ((cstatus.status==SND_PCM_STATUS_UNDERRUN) || | 283 } else { |
291 (cstatus.status==SND_PCM_STATUS_READY)) | 284 status = |
292 { | 285 snd_pcm_plugin_prepare(this->hidden-> |
293 if (!this->hidden->iscapture) | 286 audio_handle, |
294 { | 287 SND_PCM_CHANNEL_CAPTURE); |
295 status=snd_pcm_plugin_prepare(this->hidden->audio_handle, | 288 } |
296 SND_PCM_CHANNEL_PLAYBACK); | 289 if (status < 0) { |
297 } | 290 QSA_SetError("snd_pcm_plugin_prepare", status); |
298 else | 291 return; |
299 { | 292 } |
300 status=snd_pcm_plugin_prepare(this->hidden->audio_handle, | 293 } |
301 SND_PCM_CHANNEL_CAPTURE); | 294 continue; |
302 } | 295 } else { |
303 if (status<0) | 296 return; |
304 { | 297 } |
305 QSA_SetError("snd_pcm_plugin_prepare", status); | 298 } |
306 return; | 299 } else { |
307 } | 300 /* we wrote all remaining data */ |
308 } | 301 towrite -= written; |
309 continue; | 302 pcmbuffer += written * this->spec.channels; |
310 } | 303 } |
311 else | 304 } while ((towrite > 0) && (this->enabled)); |
312 { | 305 |
313 return; | 306 /* If we couldn't write, assume fatal error for now */ |
314 } | 307 if (towrite != 0) { |
315 } | 308 this->enabled = 0; |
316 } | 309 } |
317 else | 310 } |
318 { | 311 |
319 /* we wrote all remaining data */ | 312 static Uint8 * |
320 towrite -= written; | 313 QSA_GetDeviceBuf(_THIS) |
321 pcmbuffer += written * this->spec.channels; | 314 { |
322 } | 315 return this->hidden->pcm_buf; |
323 } while ((towrite>0) && (this->enabled)); | 316 } |
324 | 317 |
325 /* If we couldn't write, assume fatal error for now */ | 318 static void |
326 if (towrite!=0) | 319 QSA_CloseDevice(_THIS) |
327 { | 320 { |
328 this->enabled=0; | 321 if (this->hidden != NULL) { |
329 } | 322 if (this->hidden->audio_handle != NULL) { |
330 } | 323 if (!this->hidden->iscapture) { |
331 | 324 /* Finish playing available samples */ |
332 static Uint8* QSA_GetDeviceBuf(_THIS) | 325 snd_pcm_plugin_flush(this->hidden->audio_handle, |
333 { | 326 SND_PCM_CHANNEL_PLAYBACK); |
334 return this->hidden->pcm_buf; | 327 } else { |
335 } | 328 /* Cancel unread samples during capture */ |
336 | 329 snd_pcm_plugin_flush(this->hidden->audio_handle, |
337 static void QSA_CloseDevice(_THIS) | 330 SND_PCM_CHANNEL_CAPTURE); |
338 { | 331 } |
339 if (this->hidden!=NULL) | 332 snd_pcm_close(this->hidden->audio_handle); |
340 { | 333 this->hidden->audio_handle = NULL; |
341 if (this->hidden->audio_handle!=NULL) | 334 } |
342 { | 335 |
343 if (!this->hidden->iscapture) | 336 if (this->hidden->pcm_buf != NULL) { |
344 { | 337 SDL_FreeAudioMem(this->hidden->pcm_buf); |
345 /* Finish playing available samples */ | 338 this->hidden->pcm_buf = NULL; |
346 snd_pcm_plugin_flush(this->hidden->audio_handle, SND_PCM_CHANNEL_PLAYBACK); | 339 } |
347 } | 340 |
348 else | 341 SDL_free(this->hidden); |
349 { | 342 this->hidden = NULL; |
350 /* Cancel unread samples during capture */ | 343 } |
351 snd_pcm_plugin_flush(this->hidden->audio_handle, SND_PCM_CHANNEL_CAPTURE); | 344 } |
352 } | 345 |
353 snd_pcm_close(this->hidden->audio_handle); | 346 static int |
354 this->hidden->audio_handle=NULL; | 347 QSA_OpenDevice(_THIS, const char *devname, int iscapture) |
355 } | 348 { |
356 | 349 int status = 0; |
357 if (this->hidden->pcm_buf!=NULL) | 350 int format = 0; |
358 { | 351 SDL_AudioFormat test_format = 0; |
359 SDL_FreeAudioMem(this->hidden->pcm_buf); | 352 int found = 0; |
360 this->hidden->pcm_buf=NULL; | 353 snd_pcm_channel_setup_t csetup; |
361 } | 354 snd_pcm_channel_params_t cparams; |
362 | 355 |
363 SDL_free(this->hidden); | 356 /* Initialize all variables that we clean on shutdown */ |
364 this->hidden=NULL; | 357 this->hidden = |
365 } | 358 (struct SDL_PrivateAudioData *) SDL_calloc(1, |
366 } | 359 (sizeof |
367 | 360 (struct |
368 static int QSA_OpenDevice(_THIS, const char* devname, int iscapture) | 361 SDL_PrivateAudioData))); |
369 { | 362 if (this->hidden == NULL) { |
370 int status=0; | 363 SDL_OutOfMemory(); |
371 int format=0; | 364 return 0; |
372 SDL_AudioFormat test_format=0; | 365 } |
373 int found=0; | 366 SDL_memset(this->hidden, 0, sizeof(struct SDL_PrivateAudioData)); |
374 snd_pcm_channel_setup_t csetup; | 367 |
375 snd_pcm_channel_params_t cparams; | 368 /* Initialize channel transfer parameters to default */ |
376 | 369 QSA_InitAudioParams(&cparams); |
377 /* Initialize all variables that we clean on shutdown */ | 370 |
378 this->hidden=(struct SDL_PrivateAudioData*)SDL_calloc(1, (sizeof(struct SDL_PrivateAudioData))); | 371 /* Initialize channel direction: capture or playback */ |
379 if (this->hidden==NULL) | 372 this->hidden->iscapture = iscapture; |
380 { | 373 |
381 SDL_OutOfMemory(); | 374 /* Find deviceid and cardid by device name for playback */ |
382 return 0; | 375 if ((!this->hidden->iscapture) && (devname != NULL)) { |
383 } | 376 uint32_t device; |
384 SDL_memset(this->hidden, 0, sizeof(struct SDL_PrivateAudioData)); | 377 int32_t status; |
385 | 378 |
386 /* Initialize channel transfer parameters to default */ | 379 /* Search in the playback devices */ |
387 QSA_InitAudioParams(&cparams); | 380 device = 0; |
388 | 381 do { |
389 /* Initialize channel direction: capture or playback */ | 382 status = SDL_strcmp(qsa_playback_device[device].name, devname); |
390 this->hidden->iscapture=iscapture; | 383 if (status == 0) { |
391 | 384 /* Found requested device */ |
392 /* Find deviceid and cardid by device name for playback */ | 385 this->hidden->deviceno = qsa_playback_device[device].deviceno; |
393 if ((!this->hidden->iscapture) && (devname!=NULL)) | 386 this->hidden->cardno = qsa_playback_device[device].cardno; |
394 { | 387 break; |
395 uint32_t device; | 388 } |
396 int32_t status; | 389 device++; |
397 | 390 if (device >= qsa_playback_devices) { |
398 /* Search in the playback devices */ | 391 QSA_CloseDevice(this); |
399 device=0; | 392 SDL_SetError("No such playback device"); |
400 do { | 393 return 0; |
401 status=SDL_strcmp(qsa_playback_device[device].name, devname); | 394 } |
402 if (status==0) | 395 } while (1); |
403 { | 396 } |
404 /* Found requested device */ | 397 |
405 this->hidden->deviceno=qsa_playback_device[device].deviceno; | 398 /* Find deviceid and cardid by device name for capture */ |
406 this->hidden->cardno=qsa_playback_device[device].cardno; | 399 if ((this->hidden->iscapture) && (devname != NULL)) { |
407 break; | 400 /* Search in the capture devices */ |
408 } | 401 uint32_t device; |
409 device++; | 402 int32_t status; |
410 if (device>=qsa_playback_devices) | 403 |
411 { | 404 /* Searching in the playback devices */ |
405 device = 0; | |
406 do { | |
407 status = SDL_strcmp(qsa_capture_device[device].name, devname); | |
408 if (status == 0) { | |
409 /* Found requested device */ | |
410 this->hidden->deviceno = qsa_capture_device[device].deviceno; | |
411 this->hidden->cardno = qsa_capture_device[device].cardno; | |
412 break; | |
413 } | |
414 device++; | |
415 if (device >= qsa_capture_devices) { | |
416 QSA_CloseDevice(this); | |
417 SDL_SetError("No such capture device"); | |
418 return 0; | |
419 } | |
420 } while (1); | |
421 } | |
422 | |
423 /* Check if SDL requested default audio device */ | |
424 if (devname == NULL) { | |
425 /* Open system default audio device */ | |
426 if (!this->hidden->iscapture) { | |
427 status = snd_pcm_open_preferred(&this->hidden->audio_handle, | |
428 &this->hidden->cardno, | |
429 &this->hidden->deviceno, | |
430 SND_PCM_OPEN_PLAYBACK); | |
431 } else { | |
432 status = snd_pcm_open_preferred(&this->hidden->audio_handle, | |
433 &this->hidden->cardno, | |
434 &this->hidden->deviceno, | |
435 SND_PCM_OPEN_CAPTURE); | |
436 } | |
437 } else { | |
438 /* Open requested audio device */ | |
439 if (!this->hidden->iscapture) { | |
440 status = | |
441 snd_pcm_open(&this->hidden->audio_handle, | |
442 this->hidden->cardno, this->hidden->deviceno, | |
443 SND_PCM_OPEN_PLAYBACK); | |
444 } else { | |
445 status = | |
446 snd_pcm_open(&this->hidden->audio_handle, | |
447 this->hidden->cardno, this->hidden->deviceno, | |
448 SND_PCM_OPEN_CAPTURE); | |
449 } | |
450 } | |
451 | |
452 /* Check if requested device is opened */ | |
453 if (status < 0) { | |
454 this->hidden->audio_handle = NULL; | |
455 QSA_CloseDevice(this); | |
456 QSA_SetError("snd_pcm_open", status); | |
457 return 0; | |
458 } | |
459 | |
460 if (!QSA_CheckBuggyCards(this, QSA_MMAP_WORKAROUND)) { | |
461 /* Disable QSA MMAP plugin for buggy audio drivers */ | |
462 status = | |
463 snd_pcm_plugin_set_disable(this->hidden->audio_handle, | |
464 PLUGIN_DISABLE_MMAP); | |
465 if (status < 0) { | |
412 QSA_CloseDevice(this); | 466 QSA_CloseDevice(this); |
413 SDL_SetError("No such playback device"); | 467 QSA_SetError("snd_pcm_plugin_set_disable", status); |
414 return 0; | 468 return 0; |
415 } | 469 } |
416 } while(1); | 470 } |
417 } | 471 |
418 | 472 /* Try for a closest match on audio format */ |
419 /* Find deviceid and cardid by device name for capture */ | 473 format = 0; |
420 if ((this->hidden->iscapture) && (devname!=NULL)) | 474 /* can't use format as SND_PCM_SFMT_U8 = 0 in qsa */ |
421 { | 475 found = 0; |
422 /* Search in the capture devices */ | 476 |
423 uint32_t device; | 477 for (test_format = SDL_FirstAudioFormat(this->spec.format); !found;) { |
424 int32_t status; | 478 /* if match found set format to equivalent QSA format */ |
425 | 479 switch (test_format) { |
426 /* Searching in the playback devices */ | 480 case AUDIO_U8: |
427 device=0; | 481 { |
428 do { | 482 format = SND_PCM_SFMT_U8; |
429 status=SDL_strcmp(qsa_capture_device[device].name, devname); | 483 found = 1; |
430 if (status==0) | 484 } |
431 { | 485 break; |
432 /* Found requested device */ | 486 case AUDIO_S8: |
433 this->hidden->deviceno=qsa_capture_device[device].deviceno; | 487 { |
434 this->hidden->cardno=qsa_capture_device[device].cardno; | 488 format = SND_PCM_SFMT_S8; |
435 break; | 489 found = 1; |
436 } | 490 } |
437 device++; | 491 break; |
438 if (device>=qsa_capture_devices) | 492 case AUDIO_S16LSB: |
439 { | 493 { |
440 QSA_CloseDevice(this); | 494 format = SND_PCM_SFMT_S16_LE; |
441 SDL_SetError("No such capture device"); | 495 found = 1; |
442 return 0; | 496 } |
443 } | 497 break; |
444 } while(1); | 498 case AUDIO_S16MSB: |
445 } | 499 { |
446 | 500 format = SND_PCM_SFMT_S16_BE; |
447 /* Check if SDL requested default audio device */ | 501 found = 1; |
448 if (devname==NULL) | 502 } |
449 { | 503 break; |
450 /* Open system default audio device */ | 504 case AUDIO_U16LSB: |
451 if (!this->hidden->iscapture) | 505 { |
452 { | 506 format = SND_PCM_SFMT_U16_LE; |
453 status=snd_pcm_open_preferred(&this->hidden->audio_handle, | 507 found = 1; |
454 &this->hidden->cardno, | 508 } |
455 &this->hidden->deviceno, SND_PCM_OPEN_PLAYBACK); | 509 break; |
456 } | 510 case AUDIO_U16MSB: |
457 else | 511 { |
458 { | 512 format = SND_PCM_SFMT_U16_BE; |
459 status=snd_pcm_open_preferred(&this->hidden->audio_handle, | 513 found = 1; |
460 &this->hidden->cardno, | 514 } |
461 &this->hidden->deviceno, SND_PCM_OPEN_CAPTURE); | 515 break; |
462 } | 516 case AUDIO_S32LSB: |
463 } | 517 { |
464 else | 518 format = SND_PCM_SFMT_S32_LE; |
465 { | 519 found = 1; |
466 /* Open requested audio device */ | 520 } |
467 if (!this->hidden->iscapture) | 521 break; |
468 { | 522 case AUDIO_S32MSB: |
469 status=snd_pcm_open(&this->hidden->audio_handle, this->hidden->cardno, | 523 { |
470 this->hidden->deviceno, SND_PCM_OPEN_PLAYBACK); | 524 format = SND_PCM_SFMT_S32_BE; |
471 } | 525 found = 1; |
472 else | 526 } |
473 { | 527 break; |
474 status=snd_pcm_open(&this->hidden->audio_handle, this->hidden->cardno, | 528 case AUDIO_F32LSB: |
475 this->hidden->deviceno, SND_PCM_OPEN_CAPTURE); | 529 { |
476 } | 530 format = SND_PCM_SFMT_FLOAT_LE; |
477 } | 531 found = 1; |
478 | 532 } |
479 /* Check if requested device is opened */ | 533 break; |
480 if (status<0) | 534 case AUDIO_F32MSB: |
481 { | 535 { |
482 this->hidden->audio_handle=NULL; | 536 format = SND_PCM_SFMT_FLOAT_BE; |
483 QSA_CloseDevice(this); | 537 found = 1; |
484 QSA_SetError("snd_pcm_open", status); | 538 } |
485 return 0; | 539 break; |
486 } | 540 default: |
487 | 541 { |
488 if (!QSA_CheckBuggyCards(this, QSA_MMAP_WORKAROUND)) | 542 break; |
489 { | 543 } |
490 /* Disable QSA MMAP plugin for buggy audio drivers */ | 544 } |
491 status=snd_pcm_plugin_set_disable(this->hidden->audio_handle, PLUGIN_DISABLE_MMAP); | 545 |
492 if (status<0) | 546 if (!found) { |
493 { | 547 test_format = SDL_NextAudioFormat(); |
494 QSA_CloseDevice(this); | 548 } |
495 QSA_SetError("snd_pcm_plugin_set_disable", status); | 549 } |
496 return 0; | 550 |
497 } | 551 /* assumes test_format not 0 on success */ |
498 } | 552 if (test_format == 0) { |
499 | 553 QSA_CloseDevice(this); |
500 /* Try for a closest match on audio format */ | 554 SDL_SetError("QSA: Couldn't find any hardware audio formats"); |
501 format = 0; | 555 return 0; |
502 /* can't use format as SND_PCM_SFMT_U8 = 0 in qsa */ | 556 } |
503 found = 0; | 557 |
504 | 558 this->spec.format = test_format; |
505 for (test_format = SDL_FirstAudioFormat(this->spec.format); !found;) | 559 |
506 { | 560 /* Set the audio format */ |
507 /* if match found set format to equivalent QSA format */ | 561 cparams.format.format = format; |
508 switch (test_format) | 562 |
509 { | 563 /* Set mono/stereo/4ch/6ch/8ch audio */ |
510 case AUDIO_U8: | 564 cparams.format.voices = this->spec.channels; |
511 { | 565 |
512 format=SND_PCM_SFMT_U8; | 566 /* Set rate */ |
513 found=1; | 567 cparams.format.rate = this->spec.freq; |
514 } | 568 |
515 break; | 569 /* Setup the transfer parameters according to cparams */ |
516 case AUDIO_S8: | 570 status = snd_pcm_plugin_params(this->hidden->audio_handle, &cparams); |
517 { | 571 if (status < 0) { |
518 format=SND_PCM_SFMT_S8; | 572 QSA_CloseDevice(this); |
519 found=1; | 573 QSA_SetError("snd_pcm_channel_params", status); |
520 } | 574 return 0; |
521 break; | 575 } |
522 case AUDIO_S16LSB: | 576 |
523 { | 577 /* Make sure channel is setup right one last time */ |
524 format=SND_PCM_SFMT_S16_LE; | 578 SDL_memset(&csetup, '\0', sizeof(csetup)); |
525 found=1; | 579 if (!this->hidden->iscapture) { |
526 } | 580 csetup.channel = SND_PCM_CHANNEL_PLAYBACK; |
527 break; | 581 } else { |
528 case AUDIO_S16MSB: | 582 csetup.channel = SND_PCM_CHANNEL_CAPTURE; |
529 { | 583 } |
530 format=SND_PCM_SFMT_S16_BE; | 584 |
531 found=1; | 585 /* Setup an audio channel */ |
532 } | 586 if (snd_pcm_plugin_setup(this->hidden->audio_handle, &csetup) < 0) { |
533 break; | 587 QSA_CloseDevice(this); |
534 case AUDIO_U16LSB: | 588 SDL_SetError("QSA: Unable to setup channel\n"); |
535 { | 589 return 0; |
536 format=SND_PCM_SFMT_U16_LE; | 590 } |
537 found=1; | 591 |
538 } | 592 /* Calculate the final parameters for this audio specification */ |
539 break; | 593 SDL_CalculateAudioSpec(&this->spec); |
540 case AUDIO_U16MSB: | 594 |
541 { | 595 this->hidden->pcm_len = this->spec.size; |
542 format=SND_PCM_SFMT_U16_BE; | 596 |
543 found=1; | 597 if (this->hidden->pcm_len == 0) { |
544 } | 598 this->hidden->pcm_len = |
545 break; | 599 csetup.buf.block.frag_size * this->spec.channels * |
546 case AUDIO_S32LSB: | 600 (snd_pcm_format_width(format) / 8); |
547 { | 601 } |
548 format=SND_PCM_SFMT_S32_LE; | 602 |
549 found=1; | 603 /* |
550 } | 604 * Allocate memory to the audio buffer and initialize with silence |
551 break; | 605 * (Note that buffer size must be a multiple of fragment size, so find |
552 case AUDIO_S32MSB: | 606 * closest multiple) |
553 { | 607 */ |
554 format=SND_PCM_SFMT_S32_BE; | 608 this->hidden->pcm_buf = |
555 found=1; | 609 (Uint8 *) SDL_AllocAudioMem(this->hidden->pcm_len); |
556 } | 610 if (this->hidden->pcm_buf == NULL) { |
557 break; | 611 QSA_CloseDevice(this); |
558 case AUDIO_F32LSB: | 612 SDL_OutOfMemory(); |
559 { | 613 return 0; |
560 format=SND_PCM_SFMT_FLOAT_LE; | 614 } |
561 found=1; | 615 SDL_memset(this->hidden->pcm_buf, this->spec.silence, |
562 } | 616 this->hidden->pcm_len); |
563 break; | 617 |
564 case AUDIO_F32MSB: | 618 /* get the file descriptor */ |
565 { | 619 if (!this->hidden->iscapture) { |
566 format=SND_PCM_SFMT_FLOAT_BE; | 620 this->hidden->audio_fd = |
567 found=1; | 621 snd_pcm_file_descriptor(this->hidden->audio_handle, |
568 } | 622 SND_PCM_CHANNEL_PLAYBACK); |
569 break; | 623 } else { |
570 default: | 624 this->hidden->audio_fd = |
571 { | 625 snd_pcm_file_descriptor(this->hidden->audio_handle, |
572 break; | 626 SND_PCM_CHANNEL_CAPTURE); |
573 } | 627 } |
574 } | 628 |
575 | 629 if (this->hidden->audio_fd < 0) { |
576 if (!found) | 630 QSA_CloseDevice(this); |
577 { | 631 QSA_SetError("snd_pcm_file_descriptor", status); |
578 test_format = SDL_NextAudioFormat(); | 632 return 0; |
579 } | 633 } |
580 } | 634 |
581 | 635 /* Prepare an audio channel */ |
582 /* assumes test_format not 0 on success */ | 636 if (!this->hidden->iscapture) { |
583 if (test_format==0) | 637 /* Prepare audio playback */ |
584 { | 638 status = |
585 QSA_CloseDevice(this); | 639 snd_pcm_plugin_prepare(this->hidden->audio_handle, |
586 SDL_SetError("QSA: Couldn't find any hardware audio formats"); | 640 SND_PCM_CHANNEL_PLAYBACK); |
587 return 0; | 641 } else { |
588 } | 642 /* Prepare audio capture */ |
589 | 643 status = |
590 this->spec.format=test_format; | 644 snd_pcm_plugin_prepare(this->hidden->audio_handle, |
591 | 645 SND_PCM_CHANNEL_CAPTURE); |
592 /* Set the audio format */ | 646 } |
593 cparams.format.format=format; | 647 |
594 | 648 if (status < 0) { |
595 /* Set mono/stereo/4ch/6ch/8ch audio */ | 649 QSA_CloseDevice(this); |
596 cparams.format.voices=this->spec.channels; | 650 QSA_SetError("snd_pcm_plugin_prepare", status); |
597 | 651 return 0; |
598 /* Set rate */ | 652 } |
599 cparams.format.rate=this->spec.freq; | 653 |
600 | 654 /* We're really ready to rock and roll. :-) */ |
601 /* Setup the transfer parameters according to cparams */ | 655 return 1; |
602 status=snd_pcm_plugin_params(this->hidden->audio_handle, &cparams); | 656 } |
603 if (status<0) | 657 |
604 { | 658 int |
605 QSA_CloseDevice(this); | 659 QSA_DetectDevices(int iscapture) |
606 QSA_SetError("snd_pcm_channel_params", status); | 660 { |
607 return 0; | 661 uint32_t it; |
608 } | 662 uint32_t cards; |
609 | 663 uint32_t devices; |
610 /* Make sure channel is setup right one last time */ | 664 int32_t status; |
611 SDL_memset(&csetup, '\0', sizeof(csetup)); | 665 |
612 if (!this->hidden->iscapture) | 666 /* Detect amount of available devices */ |
613 { | 667 /* this value can be changed in the runtime */ |
614 csetup.channel=SND_PCM_CHANNEL_PLAYBACK; | 668 cards = snd_cards(); |
615 } | 669 |
616 else | 670 /* If io-audio manager is not running we will get 0 as number */ |
617 { | 671 /* of available audio devices */ |
618 csetup.channel=SND_PCM_CHANNEL_CAPTURE; | 672 if (cards == 0) { |
619 } | 673 /* We have no any available audio devices */ |
620 | 674 return 0; |
621 /* Setup an audio channel */ | 675 } |
622 if (snd_pcm_plugin_setup(this->hidden->audio_handle, &csetup) < 0) | 676 |
623 { | 677 /* Find requested devices by type */ |
624 QSA_CloseDevice(this); | 678 if (!iscapture) { |
625 SDL_SetError("QSA: Unable to setup channel\n"); | 679 /* Playback devices enumeration requested */ |
626 return 0; | 680 for (it = 0; it < cards; it++) { |
627 } | 681 devices = 0; |
628 | 682 do { |
629 /* Calculate the final parameters for this audio specification */ | 683 status = |
630 SDL_CalculateAudioSpec(&this->spec); | 684 snd_card_get_longname(it, |
631 | 685 qsa_playback_device |
632 this->hidden->pcm_len = this->spec.size; | 686 [qsa_playback_devices].name, |
633 | 687 QSA_MAX_NAME_LENGTH); |
634 if (this->hidden->pcm_len==0) | 688 if (status == EOK) { |
635 { | 689 snd_pcm_t *handle; |
636 this->hidden->pcm_len=csetup.buf.block.frag_size * this->spec.channels * | 690 |
637 (snd_pcm_format_width(format) / 8); | 691 /* Add device number to device name */ |
638 } | 692 sprintf(qsa_playback_device[qsa_playback_devices].name + |
639 | 693 SDL_strlen(qsa_playback_device |
640 /* | 694 [qsa_playback_devices].name), " d%d", |
641 * Allocate memory to the audio buffer and initialize with silence | 695 devices); |
642 * (Note that buffer size must be a multiple of fragment size, so find | 696 |
643 * closest multiple) | 697 /* Store associated card number id */ |
644 */ | 698 qsa_playback_device[qsa_playback_devices].cardno = it; |
645 this->hidden->pcm_buf=(Uint8*)SDL_AllocAudioMem(this->hidden->pcm_len); | 699 |
646 if (this->hidden->pcm_buf==NULL) | 700 /* Check if this device id could play anything */ |
647 { | 701 status = |
648 QSA_CloseDevice(this); | 702 snd_pcm_open(&handle, it, devices, |
649 SDL_OutOfMemory(); | 703 SND_PCM_OPEN_PLAYBACK); |
650 return 0; | 704 if (status == EOK) { |
651 } | 705 qsa_playback_device[qsa_playback_devices].deviceno = |
652 SDL_memset(this->hidden->pcm_buf, this->spec.silence, this->hidden->pcm_len); | 706 devices; |
653 | 707 status = snd_pcm_close(handle); |
654 /* get the file descriptor */ | 708 if (status == EOK) { |
655 if (!this->hidden->iscapture) | 709 qsa_playback_devices++; |
656 { | 710 } |
657 this->hidden->audio_fd=snd_pcm_file_descriptor(this->hidden->audio_handle, | 711 } else { |
658 SND_PCM_CHANNEL_PLAYBACK); | 712 /* Check if we got end of devices list */ |
659 } | 713 if (status == -ENOENT) { |
660 else | 714 break; |
661 { | 715 } |
662 this->hidden->audio_fd=snd_pcm_file_descriptor(this->hidden->audio_handle, | 716 } |
663 SND_PCM_CHANNEL_CAPTURE); | 717 } else { |
664 } | 718 break; |
665 | 719 } |
666 if (this->hidden->audio_fd<0) | 720 |
667 { | 721 /* Check if we reached maximum devices count */ |
668 QSA_CloseDevice(this); | 722 if (qsa_playback_devices >= QSA_MAX_DEVICES) { |
669 QSA_SetError("snd_pcm_file_descriptor", status); | 723 break; |
670 return 0; | 724 } |
671 } | 725 devices++; |
672 | 726 } while (1); |
673 /* Prepare an audio channel */ | |
674 if (!this->hidden->iscapture) | |
675 { | |
676 /* Prepare audio playback */ | |
677 status=snd_pcm_plugin_prepare(this->hidden->audio_handle, SND_PCM_CHANNEL_PLAYBACK); | |
678 } | |
679 else | |
680 { | |
681 /* Prepare audio capture */ | |
682 status=snd_pcm_plugin_prepare(this->hidden->audio_handle, SND_PCM_CHANNEL_CAPTURE); | |
683 } | |
684 | |
685 if (status<0) | |
686 { | |
687 QSA_CloseDevice(this); | |
688 QSA_SetError("snd_pcm_plugin_prepare", status); | |
689 return 0; | |
690 } | |
691 | |
692 /* We're really ready to rock and roll. :-) */ | |
693 return 1; | |
694 } | |
695 | |
696 int QSA_DetectDevices(int iscapture) | |
697 { | |
698 uint32_t it; | |
699 uint32_t cards; | |
700 uint32_t devices; | |
701 int32_t status; | |
702 | |
703 /* Detect amount of available devices */ | |
704 /* this value can be changed in the runtime */ | |
705 cards=snd_cards(); | |
706 | |
707 /* If io-audio manager is not running we will get 0 as number */ | |
708 /* of available audio devices */ | |
709 if (cards==0) | |
710 { | |
711 /* We have no any available audio devices */ | |
712 return 0; | |
713 } | |
714 | |
715 /* Find requested devices by type */ | |
716 if (!iscapture) | |
717 { | |
718 /* Playback devices enumeration requested */ | |
719 for(it=0; it<cards; it++) | |
720 { | |
721 devices=0; | |
722 do { | |
723 status=snd_card_get_longname(it, qsa_playback_device[qsa_playback_devices].name, QSA_MAX_NAME_LENGTH); | |
724 if (status==EOK) | |
725 { | |
726 snd_pcm_t* handle; | |
727 | |
728 /* Add device number to device name */ | |
729 sprintf(qsa_playback_device[qsa_playback_devices].name + SDL_strlen(qsa_playback_device[qsa_playback_devices].name), " d%d", devices); | |
730 | |
731 /* Store associated card number id */ | |
732 qsa_playback_device[qsa_playback_devices].cardno=it; | |
733 | |
734 /* Check if this device id could play anything */ | |
735 status=snd_pcm_open(&handle, it, devices, SND_PCM_OPEN_PLAYBACK); | |
736 if (status==EOK) | |
737 { | |
738 qsa_playback_device[qsa_playback_devices].deviceno=devices; | |
739 status=snd_pcm_close(handle); | |
740 if (status==EOK) | |
741 { | |
742 qsa_playback_devices++; | |
743 } | |
744 } | |
745 else | |
746 { | |
747 /* Check if we got end of devices list */ | |
748 if (status==-ENOENT) | |
749 { | |
750 break; | |
751 } | |
752 } | |
753 } | |
754 else | |
755 { | |
756 break; | |
757 } | |
758 | 727 |
759 /* Check if we reached maximum devices count */ | 728 /* Check if we reached maximum devices count */ |
760 if (qsa_playback_devices>=QSA_MAX_DEVICES) | 729 if (qsa_playback_devices >= QSA_MAX_DEVICES) { |
761 { | 730 break; |
762 break; | 731 } |
763 } | 732 } |
764 devices++; | 733 } else { |
765 } while(1); | 734 /* Capture devices enumeration requested */ |
766 | 735 for (it = 0; it < cards; it++) { |
767 /* Check if we reached maximum devices count */ | 736 devices = 0; |
768 if (qsa_playback_devices>=QSA_MAX_DEVICES) | 737 do { |
769 { | 738 status = |
770 break; | 739 snd_card_get_longname(it, |
771 } | 740 qsa_capture_device |
772 } | 741 [qsa_capture_devices].name, |
773 } | 742 QSA_MAX_NAME_LENGTH); |
774 else | 743 if (status == EOK) { |
775 { | 744 snd_pcm_t *handle; |
776 /* Capture devices enumeration requested */ | 745 |
777 for(it=0; it<cards; it++) | 746 /* Add device number to device name */ |
778 { | 747 sprintf(qsa_capture_device[qsa_capture_devices].name + |
779 devices=0; | 748 SDL_strlen(qsa_capture_device |
780 do { | 749 [qsa_capture_devices].name), " d%d", |
781 status=snd_card_get_longname(it, qsa_capture_device[qsa_capture_devices].name, QSA_MAX_NAME_LENGTH); | 750 devices); |
782 if (status==EOK) | 751 |
783 { | 752 /* Store associated card number id */ |
784 snd_pcm_t* handle; | 753 qsa_capture_device[qsa_capture_devices].cardno = it; |
785 | 754 |
786 /* Add device number to device name */ | 755 /* Check if this device id could play anything */ |
787 sprintf(qsa_capture_device[qsa_capture_devices].name + SDL_strlen(qsa_capture_device[qsa_capture_devices].name), " d%d", devices); | 756 status = |
788 | 757 snd_pcm_open(&handle, it, devices, |
789 /* Store associated card number id */ | 758 SND_PCM_OPEN_CAPTURE); |
790 qsa_capture_device[qsa_capture_devices].cardno=it; | 759 if (status == EOK) { |
791 | 760 qsa_capture_device[qsa_capture_devices].deviceno = |
792 /* Check if this device id could play anything */ | 761 devices; |
793 status=snd_pcm_open(&handle, it, devices, SND_PCM_OPEN_CAPTURE); | 762 status = snd_pcm_close(handle); |
794 if (status==EOK) | 763 if (status == EOK) { |
795 { | 764 qsa_capture_devices++; |
796 qsa_capture_device[qsa_capture_devices].deviceno=devices; | 765 } |
797 status=snd_pcm_close(handle); | 766 } else { |
798 if (status==EOK) | 767 /* Check if we got end of devices list */ |
799 { | 768 if (status == -ENOENT) { |
800 qsa_capture_devices++; | 769 break; |
801 } | 770 } |
802 } | 771 } |
803 else | 772 |
804 { | 773 /* Check if we reached maximum devices count */ |
805 /* Check if we got end of devices list */ | 774 if (qsa_capture_devices >= QSA_MAX_DEVICES) { |
806 if (status==-ENOENT) | 775 break; |
807 { | 776 } |
808 break; | 777 } else { |
809 } | 778 break; |
810 } | 779 } |
811 | 780 devices++; |
812 /* Check if we reached maximum devices count */ | 781 } while (1); |
813 if (qsa_capture_devices>=QSA_MAX_DEVICES) | 782 |
814 { | 783 /* Check if we reached maximum devices count */ |
815 break; | 784 if (qsa_capture_devices >= QSA_MAX_DEVICES) { |
816 } | 785 break; |
817 } | 786 } |
818 else | 787 } |
819 { | 788 } |
820 break; | 789 |
821 } | 790 /* Return amount of available playback or capture devices */ |
822 devices++; | 791 if (!iscapture) { |
823 } while(1); | 792 return qsa_playback_devices; |
824 | 793 } else { |
825 /* Check if we reached maximum devices count */ | 794 return qsa_capture_devices; |
826 if (qsa_capture_devices>=QSA_MAX_DEVICES) | 795 } |
827 { | 796 } |
828 break; | 797 |
829 } | 798 const char * |
830 } | 799 QSA_GetDeviceName(int index, int iscapture) |
831 } | 800 { |
832 | 801 if (!iscapture) { |
833 /* Return amount of available playback or capture devices */ | 802 if (index >= qsa_playback_devices) { |
834 if (!iscapture) | 803 return "No such playback device"; |
835 { | 804 } |
836 return qsa_playback_devices; | 805 |
837 } | 806 return qsa_playback_device[index].name; |
838 else | 807 } else { |
839 { | 808 if (index >= qsa_capture_devices) { |
840 return qsa_capture_devices; | 809 return "No such capture device"; |
841 } | 810 } |
842 } | 811 |
843 | 812 return qsa_capture_device[index].name; |
844 const char* QSA_GetDeviceName(int index, int iscapture) | 813 } |
845 { | 814 } |
846 if (!iscapture) | 815 |
847 { | 816 void |
848 if (index>=qsa_playback_devices) | 817 QSA_WaitDone(_THIS) |
849 { | 818 { |
850 return "No such playback device"; | 819 if (!this->hidden->iscapture) { |
851 } | 820 if (this->hidden->audio_handle != NULL) { |
852 | 821 /* Wait till last fragment is played and stop channel */ |
853 return qsa_playback_device[index].name; | 822 snd_pcm_plugin_flush(this->hidden->audio_handle, |
854 } | 823 SND_PCM_CHANNEL_PLAYBACK); |
855 else | 824 } |
856 { | 825 } else { |
857 if (index>=qsa_capture_devices) | 826 if (this->hidden->audio_handle != NULL) { |
858 { | 827 /* Discard all unread data and stop channel */ |
859 return "No such capture device"; | 828 snd_pcm_plugin_flush(this->hidden->audio_handle, |
860 } | 829 SND_PCM_CHANNEL_CAPTURE); |
861 | 830 } |
862 return qsa_capture_device[index].name; | 831 } |
863 } | 832 } |
864 } | 833 |
865 | 834 void |
866 void QSA_WaitDone(_THIS) | 835 QSA_Deinitialize(void) |
867 { | 836 { |
868 if (!this->hidden->iscapture) | 837 /* Clear devices array on shutdown */ |
869 { | 838 SDL_memset(qsa_playback_device, 0x00, |
870 if (this->hidden->audio_handle!=NULL) | 839 sizeof(QSA_Device) * QSA_MAX_DEVICES); |
871 { | 840 SDL_memset(qsa_capture_device, 0x00, |
872 /* Wait till last fragment is played and stop channel */ | 841 sizeof(QSA_Device) * QSA_MAX_DEVICES); |
873 snd_pcm_plugin_flush(this->hidden->audio_handle, SND_PCM_CHANNEL_PLAYBACK); | 842 qsa_playback_devices = 0; |
874 } | 843 qsa_capture_devices = 0; |
875 } | 844 } |
876 else | 845 |
877 { | 846 static int |
878 if (this->hidden->audio_handle!=NULL) | 847 QSA_Init(SDL_AudioDriverImpl * impl) |
879 { | 848 { |
880 /* Discard all unread data and stop channel */ | 849 snd_pcm_t *handle = NULL; |
881 snd_pcm_plugin_flush(this->hidden->audio_handle, SND_PCM_CHANNEL_CAPTURE); | 850 int32_t status = 0; |
882 } | 851 |
883 } | 852 /* Clear devices array */ |
884 } | 853 SDL_memset(qsa_playback_device, 0x00, |
885 | 854 sizeof(QSA_Device) * QSA_MAX_DEVICES); |
886 void QSA_Deinitialize(void) | 855 SDL_memset(qsa_capture_device, 0x00, |
887 { | 856 sizeof(QSA_Device) * QSA_MAX_DEVICES); |
888 /* Clear devices array on shutdown */ | 857 qsa_playback_devices = 0; |
889 SDL_memset(qsa_playback_device, 0x00, sizeof(QSA_Device)*QSA_MAX_DEVICES); | 858 qsa_capture_devices = 0; |
890 SDL_memset(qsa_capture_device, 0x00, sizeof(QSA_Device)*QSA_MAX_DEVICES); | 859 |
891 qsa_playback_devices=0; | 860 /* Set function pointers */ |
892 qsa_capture_devices=0; | 861 /* DeviceLock and DeviceUnlock functions are used default, */ |
893 } | 862 /* provided by SDL, which uses pthread_mutex for lock/unlock */ |
894 | 863 impl->DetectDevices = QSA_DetectDevices; |
895 static int QSA_Init(SDL_AudioDriverImpl* impl) | 864 impl->GetDeviceName = QSA_GetDeviceName; |
896 { | 865 impl->OpenDevice = QSA_OpenDevice; |
897 snd_pcm_t* handle=NULL; | 866 impl->ThreadInit = QSA_ThreadInit; |
898 int32_t status=0; | 867 impl->WaitDevice = QSA_WaitDevice; |
899 | 868 impl->PlayDevice = QSA_PlayDevice; |
900 /* Clear devices array */ | 869 impl->GetDeviceBuf = QSA_GetDeviceBuf; |
901 SDL_memset(qsa_playback_device, 0x00, sizeof(QSA_Device)*QSA_MAX_DEVICES); | 870 impl->CloseDevice = QSA_CloseDevice; |
902 SDL_memset(qsa_capture_device, 0x00, sizeof(QSA_Device)*QSA_MAX_DEVICES); | 871 impl->WaitDone = QSA_WaitDone; |
903 qsa_playback_devices=0; | 872 impl->Deinitialize = QSA_Deinitialize; |
904 qsa_capture_devices=0; | 873 impl->LockDevice = NULL; |
905 | 874 impl->UnlockDevice = NULL; |
906 /* Set function pointers */ | 875 |
907 /* DeviceLock and DeviceUnlock functions are used default, */ | 876 impl->OnlyHasDefaultOutputDevice = 0; |
908 /* provided by SDL, which uses pthread_mutex for lock/unlock */ | 877 impl->ProvidesOwnCallbackThread = 0; |
909 impl->DetectDevices=QSA_DetectDevices; | 878 impl->SkipMixerLock = 0; |
910 impl->GetDeviceName=QSA_GetDeviceName; | 879 impl->HasCaptureSupport = 1; |
911 impl->OpenDevice=QSA_OpenDevice; | 880 impl->OnlyHasDefaultOutputDevice = 0; |
912 impl->ThreadInit=QSA_ThreadInit; | 881 impl->OnlyHasDefaultInputDevice = 0; |
913 impl->WaitDevice=QSA_WaitDevice; | 882 |
914 impl->PlayDevice=QSA_PlayDevice; | 883 /* Check if io-audio manager is running or not */ |
915 impl->GetDeviceBuf=QSA_GetDeviceBuf; | 884 status = snd_cards(); |
916 impl->CloseDevice=QSA_CloseDevice; | 885 if (status == 0) { |
917 impl->WaitDone=QSA_WaitDone; | 886 /* if no, return immediately */ |
918 impl->Deinitialize=QSA_Deinitialize; | 887 return 1; |
919 impl->LockDevice=NULL; | 888 } |
920 impl->UnlockDevice=NULL; | 889 |
921 | 890 /* At this point we are definitely has an audio device */ |
922 impl->OnlyHasDefaultOutputDevice=0; | 891 return 2; |
923 impl->ProvidesOwnCallbackThread=0; | 892 } |
924 impl->SkipMixerLock=0; | 893 |
925 impl->HasCaptureSupport=1; | 894 AudioBootStrap QSAAUDIO_bootstrap = { |
926 impl->OnlyHasDefaultOutputDevice=0; | 895 DRIVER_NAME, "QNX QSA Audio", QSA_Init, 0 |
927 impl->OnlyHasDefaultInputDevice=0; | |
928 | |
929 /* Check if io-audio manager is running or not */ | |
930 status=snd_cards(); | |
931 if (status==0) | |
932 { | |
933 /* if no, return immediately */ | |
934 return 1; | |
935 } | |
936 | |
937 /* At this point we are definitely has an audio device */ | |
938 return 2; | |
939 } | |
940 | |
941 AudioBootStrap QSAAUDIO_bootstrap= | |
942 { | |
943 DRIVER_NAME, "QNX QSA Audio", QSA_Init, 0 | |
944 }; | 896 }; |
945 | 897 |
946 /* vi: set ts=4 sw=4 expandtab: */ | 898 /* vi: set ts=4 sw=4 expandtab: */ |