1 /* 2 * QEMU ESD audio driver 3 * 4 * Copyright (c) 2008-2009 The Android Open Source Project 5 * Copyright (c) 2006 Frederick Reeve (brushed up by malc) 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a copy 8 * of this software and associated documentation files (the "Software"), to deal 9 * in the Software without restriction, including without limitation the rights 10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 * copies of the Software, and to permit persons to whom the Software is 12 * furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included in 15 * all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 * THE SOFTWARE. 24 */ 25 #include <esd.h> 26 #include "qemu-common.h" 27 #include "audio.h" 28 #include <signal.h> 29 30 #define AUDIO_CAP "esd" 31 #include "audio_int.h" 32 #include <dlfcn.h> 33 34 #include "qemu_debug.h" 35 36 #define DEBUG 1 37 38 #if DEBUG 39 # include <stdio.h> 40 # define D(...) VERBOSE_PRINT(audio,__VA_ARGS__) 41 # define D_ACTIVE VERBOSE_CHECK(audio) 42 # define O(...) VERBOSE_PRINT(audioout,__VA_ARGS__) 43 # define I(...) VERBOSE_PRINT(audioin,__VA_ARGS__) 44 #else 45 # define D(...) ((void)0) 46 # define D_ACTIVE 0 47 # define O(...) ((void)0) 48 # define I(...) ((void)0) 49 #endif 50 51 #define STRINGIFY_(x) #x 52 #define STRINGIFY(x) STRINGIFY_(x) 53 54 typedef struct { 55 HWVoiceOut hw; 56 int done; 57 int live; 58 int decr; 59 int rpos; 60 void *pcm_buf; 61 int fd; 62 } ESDVoiceOut; 63 64 typedef struct { 65 HWVoiceIn hw; 66 int done; 67 int dead; 68 int incr; 69 int wpos; 70 void *pcm_buf; 71 int fd; 72 } ESDVoiceIn; 73 74 static struct { 75 int samples; 76 int divisor; 77 char *dac_host; 78 char *adc_host; 79 } conf = { 80 1024, 81 2, 82 NULL, 83 NULL 84 }; 85 86 /* link dynamically to the libesd.so */ 87 88 #define DYNLINK_FUNCTIONS \ 89 DYNLINK_FUNC(int,esd_play_stream,(esd_format_t,int,const char*,const char*)) \ 90 DYNLINK_FUNC(int,esd_record_stream,(esd_format_t,int,const char*,const char*)) \ 91 DYNLINK_FUNC(int,esd_open_sound,( const char *host )) \ 92 DYNLINK_FUNC(int,esd_close,(int)) \ 93 94 #define DYNLINK_FUNCTIONS_INIT \ 95 esd_dynlink_init 96 97 #include "dynlink.h" 98 99 static void* esd_lib; 100 101 static void GCC_FMT_ATTR (2, 3) qesd_logerr (int err, const char *fmt, ...) 102 { 103 va_list ap; 104 105 va_start (ap, fmt); 106 AUD_vlog (AUDIO_CAP, fmt, ap); 107 va_end (ap); 108 109 AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err)); 110 } 111 112 static int qesd_run_out (HWVoiceOut *hw) 113 { 114 ESDVoiceOut *esd = (ESDVoiceOut *) hw; 115 int liveSamples, totalSamples; 116 int rpos, nwrite, writeSamples, writeBytes; 117 118 liveSamples = audio_pcm_hw_get_live_out (hw); 119 rpos = hw->rpos; 120 totalSamples = 0; 121 122 while (liveSamples > 0) { 123 int chunkSamples = audio_MIN (liveSamples, hw->samples - rpos); 124 int chunkBytes = chunkSamples << hw->info.shift; 125 struct st_sample *src = hw->mix_buf + rpos; 126 127 hw->clip (esd->pcm_buf, src, chunkSamples); 128 129 AGAIN: 130 nwrite = write (esd->fd, esd->pcm_buf, chunkBytes); 131 if (nwrite == -1) { 132 if (errno == EINTR) 133 goto AGAIN; 134 if (errno == EAGAIN || errno == EWOULDBLOCK) 135 break; 136 qesd_logerr (errno, "write failed: %s\n", strerror(errno)); 137 O("EsounD output thread write error: %s", strerror(errno)); 138 break; 139 } 140 if (nwrite == 0) 141 break; 142 143 writeSamples = nwrite >> hw->info.shift; 144 writeBytes = writeSamples << hw->info.shift; 145 if (writeBytes != nwrite) { 146 dolog ("warning: Misaligned write %d (requested %d), " 147 "alignment %d\n", 148 nwrite, writeBytes, hw->info.align + 1); 149 } 150 rpos = (rpos + writeSamples) % hw->samples; 151 totalSamples += writeSamples; 152 liveSamples -= writeSamples; 153 } 154 hw->rpos = rpos; 155 return totalSamples; 156 } 157 158 static int qesd_write (SWVoiceOut *sw, void *buf, int len) 159 { 160 return audio_pcm_sw_write (sw, buf, len); 161 } 162 163 static int qesd_init_out (HWVoiceOut *hw, struct audsettings *as) 164 { 165 ESDVoiceOut *esd = (ESDVoiceOut *) hw; 166 struct audsettings obt_as = *as; 167 int esdfmt = ESD_STREAM | ESD_PLAY; 168 int result = -1; 169 170 /* shut down verbose debug spew */ 171 if (!D_ACTIVE) 172 stdio_disable(); 173 174 O("initializing EsoundD audio output"); 175 esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO; 176 switch (as->fmt) { 177 case AUD_FMT_S8: 178 case AUD_FMT_U8: 179 esdfmt |= ESD_BITS8; 180 obt_as.fmt = AUD_FMT_U8; 181 break; 182 #if 0 183 case AUD_FMT_S32: 184 case AUD_FMT_U32: 185 dolog ("Will use 16 instead of 32 bit samples\n"); 186 #endif 187 case AUD_FMT_S16: 188 case AUD_FMT_U16: 189 deffmt: 190 esdfmt |= ESD_BITS16; 191 obt_as.fmt = AUD_FMT_S16; 192 break; 193 194 default: 195 dolog ("Internal logic error: Bad audio format %d\n", as->fmt); 196 goto deffmt; 197 198 } 199 obt_as.endianness = AUDIO_HOST_ENDIANNESS; 200 201 audio_pcm_init_info (&hw->info, &obt_as); 202 203 hw->samples = conf.samples; 204 esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); 205 if (!esd->pcm_buf) { 206 dolog ("Could not allocate buffer (%d bytes)\n", 207 hw->samples << hw->info.shift); 208 goto exit; 209 } 210 211 esd->fd = FF(esd_play_stream) (esdfmt, as->freq, conf.dac_host, NULL); 212 if (esd->fd < 0) { 213 if (conf.dac_host == NULL) { 214 esd->fd = FF(esd_play_stream) (esdfmt, as->freq, "localhost", NULL); 215 } 216 if (esd->fd < 0) { 217 qesd_logerr (errno, "esd_play_stream failed\n"); 218 goto fail2; 219 } 220 } 221 222 { 223 int flags; 224 flags = fcntl(esd->fd, F_GETFL); 225 fcntl(esd->fd, F_SETFL, flags | O_NONBLOCK); 226 } 227 228 result = 0; /* success */ 229 goto exit; 230 231 fail2: 232 qemu_free (esd->pcm_buf); 233 esd->pcm_buf = NULL; 234 235 exit: 236 if (!D_ACTIVE) 237 stdio_enable(); 238 239 return result; 240 } 241 242 static void qesd_fini_out (HWVoiceOut *hw) 243 { 244 ESDVoiceOut *esd = (ESDVoiceOut *) hw; 245 246 if (esd->fd >= 0) { 247 if (close (esd->fd)) { 248 qesd_logerr (errno, "failed to close esd socket\n"); 249 } 250 esd->fd = -1; 251 } 252 qemu_free (esd->pcm_buf); 253 esd->pcm_buf = NULL; 254 } 255 256 static int qesd_ctl_out (HWVoiceOut *hw, int cmd, ...) 257 { 258 (void) hw; 259 (void) cmd; 260 return 0; 261 } 262 263 /* capture */ 264 static int qesd_run_in (HWVoiceIn *hw) 265 { 266 int wpos, liveSamples, totalSamples; 267 int grabSamples; 268 ESDVoiceIn *esd = (ESDVoiceIn *) hw; 269 270 wpos = hw->wpos; 271 liveSamples = audio_pcm_hw_get_live_in (hw); 272 grabSamples = hw->samples - liveSamples; 273 totalSamples = 0; 274 275 while (grabSamples > 0) { 276 ssize_t nread; 277 int chunkSamples = audio_MIN (grabSamples, hw->samples - wpos); 278 int chunkBytes = chunkSamples << hw->info.shift; 279 int readSamples, readBytes; 280 void* buf = advance (esd->pcm_buf, wpos); 281 282 AGAIN: 283 nread = read (esd->fd, buf, chunkBytes); 284 if (nread == -1) { 285 if (errno == EINTR) 286 goto AGAIN; 287 if (errno == EAGAIN || errno == EWOULDBLOCK) 288 break; 289 290 qesd_logerr (errno, "read failed: %s\n", strerror(errno)); 291 break; 292 } 293 if (nread == 0) 294 break; 295 296 readSamples = nread >> hw->info.shift; 297 readBytes = readSamples << hw->info.shift; 298 299 if (readBytes != nread) { 300 dolog ("warning: Misaligned read %d (requested %d), " 301 "alignment %d\n", 302 nread, readBytes, hw->info.align + 1); 303 } 304 305 hw->conv (hw->conv_buf + wpos, buf, readSamples, 306 &nominal_volume); 307 308 wpos = (wpos + readSamples) % hw->samples; 309 grabSamples -= readSamples; 310 totalSamples += readSamples; 311 } 312 hw->wpos = wpos; 313 return totalSamples; 314 } 315 316 static int qesd_read (SWVoiceIn *sw, void *buf, int len) 317 { 318 return audio_pcm_sw_read (sw, buf, len); 319 } 320 321 static int qesd_init_in (HWVoiceIn *hw, struct audsettings *as) 322 { 323 ESDVoiceIn *esd = (ESDVoiceIn *) hw; 324 struct audsettings obt_as = *as; 325 int esdfmt = ESD_STREAM | ESD_RECORD; 326 int result = -1; 327 328 /* shut down verbose debug spew */ 329 if (!D_ACTIVE) 330 stdio_disable(); 331 332 esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO; 333 switch (as->fmt) { 334 case AUD_FMT_S8: 335 case AUD_FMT_U8: 336 esdfmt |= ESD_BITS8; 337 obt_as.fmt = AUD_FMT_U8; 338 break; 339 340 case AUD_FMT_S16: 341 case AUD_FMT_U16: 342 esdfmt |= ESD_BITS16; 343 obt_as.fmt = AUD_FMT_S16; 344 break; 345 346 case AUD_FMT_S32: 347 case AUD_FMT_U32: 348 dolog ("Will use 16 instead of 32 bit samples\n"); 349 esdfmt |= ESD_BITS16; 350 obt_as.fmt = AUD_FMT_S16; 351 break; 352 } 353 obt_as.endianness = AUDIO_HOST_ENDIANNESS; 354 355 audio_pcm_init_info (&hw->info, &obt_as); 356 357 hw->samples = conf.samples; 358 esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); 359 if (!esd->pcm_buf) { 360 dolog ("Could not allocate buffer (%d bytes)\n", 361 hw->samples << hw->info.shift); 362 goto exit; 363 } 364 365 esd->fd = FF(esd_record_stream) (esdfmt, as->freq, conf.adc_host, NULL); 366 if (esd->fd < 0) { 367 if (conf.adc_host == NULL) { 368 esd->fd = FF(esd_record_stream) (esdfmt, as->freq, "localhost", NULL); 369 } 370 if (esd->fd < 0) { 371 qesd_logerr (errno, "esd_record_stream failed\n"); 372 goto fail2; 373 } 374 } 375 376 { 377 int flags; 378 flags = fcntl(esd->fd, F_GETFL); 379 fcntl(esd->fd, F_SETFL, flags | O_NONBLOCK); 380 } 381 382 result = 0; /* success */ 383 goto exit; 384 385 fail2: 386 qemu_free (esd->pcm_buf); 387 esd->pcm_buf = NULL; 388 389 exit: 390 if (!D_ACTIVE) 391 stdio_enable(); 392 393 return result; 394 } 395 396 static void qesd_fini_in (HWVoiceIn *hw) 397 { 398 ESDVoiceIn *esd = (ESDVoiceIn *) hw; 399 400 if (esd->fd >= 0) { 401 if (close (esd->fd)) { 402 qesd_logerr (errno, "failed to close esd socket\n"); 403 } 404 esd->fd = -1; 405 } 406 qemu_free (esd->pcm_buf); 407 esd->pcm_buf = NULL; 408 } 409 410 static int qesd_ctl_in (HWVoiceIn *hw, int cmd, ...) 411 { 412 (void) hw; 413 (void) cmd; 414 return 0; 415 } 416 417 /* common */ 418 static void *qesd_audio_init (void) 419 { 420 void* result = NULL; 421 422 D("%s: entering", __FUNCTION__); 423 424 if (esd_lib == NULL) { 425 int fd; 426 427 esd_lib = dlopen( "libesd.so", RTLD_NOW ); 428 if (esd_lib == NULL) 429 esd_lib = dlopen( "libesd.so.0", RTLD_NOW ); 430 431 if (esd_lib == NULL) { 432 D("could not find libesd on this system"); 433 goto Exit; 434 } 435 436 if (esd_dynlink_init(esd_lib) < 0) 437 goto Fail; 438 439 fd = FF(esd_open_sound)(conf.dac_host); 440 if (fd < 0) { 441 D("%s: could not open direct sound server connection, trying localhost", 442 __FUNCTION__); 443 fd = FF(esd_open_sound)("localhost"); 444 if (fd < 0) { 445 D("%s: could not open localhost sound server connection", __FUNCTION__); 446 goto Fail; 447 } 448 } 449 450 D("%s: EsounD server connection succeeded", __FUNCTION__); 451 /* FF(esd_close)(fd); */ 452 } 453 result = &conf; 454 goto Exit; 455 456 Fail: 457 D("%s: failed to open library", __FUNCTION__); 458 dlclose(esd_lib); 459 esd_lib = NULL; 460 461 Exit: 462 return result; 463 } 464 465 static void qesd_audio_fini (void *opaque) 466 { 467 (void) opaque; 468 if (esd_lib != NULL) { 469 dlclose(esd_lib); 470 esd_lib = NULL; 471 } 472 ldebug ("esd_fini"); 473 } 474 475 struct audio_option qesd_options[] = { 476 {"SAMPLES", AUD_OPT_INT, &conf.samples, 477 "buffer size in samples", NULL, 0}, 478 479 {"DIVISOR", AUD_OPT_INT, &conf.divisor, 480 "threshold divisor", NULL, 0}, 481 482 {"DAC_HOST", AUD_OPT_STR, &conf.dac_host, 483 "playback host", NULL, 0}, 484 485 {"ADC_HOST", AUD_OPT_STR, &conf.adc_host, 486 "capture host", NULL, 0}, 487 488 {NULL, 0, NULL, NULL, NULL, 0} 489 }; 490 491 static struct audio_pcm_ops qesd_pcm_ops = { 492 qesd_init_out, 493 qesd_fini_out, 494 qesd_run_out, 495 qesd_write, 496 qesd_ctl_out, 497 498 qesd_init_in, 499 qesd_fini_in, 500 qesd_run_in, 501 qesd_read, 502 qesd_ctl_in, 503 }; 504 505 struct audio_driver esd_audio_driver = { 506 INIT_FIELD (name = ) "esd", 507 INIT_FIELD (descr = ) 508 "EsounD audio (en.wikipedia.org/wiki/Esound)", 509 INIT_FIELD (options = ) qesd_options, 510 INIT_FIELD (init = ) qesd_audio_init, 511 INIT_FIELD (fini = ) qesd_audio_fini, 512 INIT_FIELD (pcm_ops = ) &qesd_pcm_ops, 513 INIT_FIELD (can_be_default = ) 1, 514 INIT_FIELD (max_voices_out = ) INT_MAX, 515 INIT_FIELD (max_voices_in = ) 1, 516 INIT_FIELD (voice_size_out = ) sizeof (ESDVoiceOut), 517 INIT_FIELD (voice_size_in = ) sizeof (ESDVoiceIn) 518 }; 519