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 29#define AUDIO_CAP "esd" 30#include "audio_int.h" 31#include "audio_pt_int.h" 32 33#include "qemu_debug.h" 34 35#define DEBUG 1 36 37#if DEBUG 38# include <stdio.h> 39# define D(...) VERBOSE_PRINT(audio,__VA_ARGS__) 40# define D_ACTIVE VERBOSE_CHECK(audio) 41# define O(...) VERBOSE_PRINT(audioout,__VA_ARGS__) 42# define I(...) VERBOSE_PRINT(audioin,__VA_ARGS__) 43#else 44# define D(...) ((void)0) 45# define D_ACTIVE 0 46# define O(...) ((void)0) 47# define I(...) ((void)0) 48#endif 49 50#define STRINGIFY_(x) #x 51#define STRINGIFY(x) STRINGIFY_(x) 52 53#include <dlfcn.h> 54/* link dynamically to the libesd.so */ 55 56#define DYNLINK_FUNCTIONS \ 57 DYNLINK_FUNC(int,esd_play_stream,(esd_format_t,int,const char*,const char*)) \ 58 DYNLINK_FUNC(int,esd_record_stream,(esd_format_t,int,const char*,const char*)) \ 59 DYNLINK_FUNC(int,esd_open_sound,( const char *host )) \ 60 DYNLINK_FUNC(int,esd_close,(int)) \ 61 62#define DYNLINK_FUNCTIONS_INIT \ 63 esd_dynlink_init 64 65#include "dynlink.h" 66 67static void* esd_lib; 68 69 70typedef struct { 71 HWVoiceOut hw; 72 int done; 73 int live; 74 int decr; 75 int rpos; 76 void *pcm_buf; 77 int fd; 78 struct audio_pt pt; 79} ESDVoiceOut; 80 81typedef struct { 82 HWVoiceIn hw; 83 int done; 84 int dead; 85 int incr; 86 int wpos; 87 void *pcm_buf; 88 int fd; 89 struct audio_pt pt; 90} ESDVoiceIn; 91 92static struct { 93 int samples; 94 int divisor; 95 char *dac_host; 96 char *adc_host; 97} conf = { 98 .samples = 1024, 99 .divisor = 2, 100}; 101 102static void GCC_FMT_ATTR (2, 3) qesd_logerr (int err, const char *fmt, ...) 103{ 104 va_list ap; 105 106 va_start (ap, fmt); 107 AUD_vlog (AUDIO_CAP, fmt, ap); 108 va_end (ap); 109 110 AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err)); 111} 112 113/* playback */ 114static void *qesd_thread_out (void *arg) 115{ 116 ESDVoiceOut *esd = arg; 117 HWVoiceOut *hw = &esd->hw; 118 int threshold; 119 120 threshold = conf.divisor ? hw->samples / conf.divisor : 0; 121 122 if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) { 123 return NULL; 124 } 125 126 for (;;) { 127 int decr, to_mix, rpos; 128 129 for (;;) { 130 if (esd->done) { 131 goto exit; 132 } 133 134 if (esd->live > threshold) { 135 break; 136 } 137 138 if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) { 139 goto exit; 140 } 141 } 142 143 decr = to_mix = esd->live; 144 rpos = hw->rpos; 145 146 if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) { 147 return NULL; 148 } 149 150 while (to_mix) { 151 ssize_t written; 152 int chunk = audio_MIN (to_mix, hw->samples - rpos); 153 struct st_sample *src = hw->mix_buf + rpos; 154 155 hw->clip (esd->pcm_buf, src, chunk); 156 157 again: 158 written = write (esd->fd, esd->pcm_buf, chunk << hw->info.shift); 159 if (written == -1) { 160 if (errno == EINTR || errno == EAGAIN) { 161 goto again; 162 } 163 qesd_logerr (errno, "write failed\n"); 164 return NULL; 165 } 166 167 if (written != chunk << hw->info.shift) { 168 int wsamples = written >> hw->info.shift; 169 int wbytes = wsamples << hw->info.shift; 170 if (wbytes != written) { 171 dolog ("warning: Misaligned write %d (requested %zd), " 172 "alignment %d\n", 173 wbytes, written, hw->info.align + 1); 174 } 175 to_mix -= wsamples; 176 rpos = (rpos + wsamples) % hw->samples; 177 break; 178 } 179 180 rpos = (rpos + chunk) % hw->samples; 181 to_mix -= chunk; 182 } 183 184 if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) { 185 return NULL; 186 } 187 188 esd->rpos = rpos; 189 esd->live -= decr; 190 esd->decr += decr; 191 } 192 193 exit: 194 audio_pt_unlock (&esd->pt, AUDIO_FUNC); 195 return NULL; 196} 197 198static int qesd_run_out (HWVoiceOut *hw, int live) 199{ 200 int decr; 201 ESDVoiceOut *esd = (ESDVoiceOut *) hw; 202 203 if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) { 204 return 0; 205 } 206 207 decr = audio_MIN (live, esd->decr); 208 esd->decr -= decr; 209 esd->live = live - decr; 210 hw->rpos = esd->rpos; 211 if (esd->live > 0) { 212 audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC); 213 } 214 else { 215 audio_pt_unlock (&esd->pt, AUDIO_FUNC); 216 } 217 return decr; 218} 219 220static int qesd_write (SWVoiceOut *sw, void *buf, int len) 221{ 222 return audio_pcm_sw_write (sw, buf, len); 223} 224 225static int qesd_init_out (HWVoiceOut *hw, struct audsettings *as) 226{ 227 ESDVoiceOut *esd = (ESDVoiceOut *) hw; 228 struct audsettings obt_as = *as; 229 int esdfmt = ESD_STREAM | ESD_PLAY; 230 231 esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO; 232 switch (as->fmt) { 233 case AUD_FMT_S8: 234 case AUD_FMT_U8: 235 esdfmt |= ESD_BITS8; 236 obt_as.fmt = AUD_FMT_U8; 237 break; 238 239 case AUD_FMT_S32: 240 case AUD_FMT_U32: 241 dolog ("Will use 16 instead of 32 bit samples\n"); 242 243 case AUD_FMT_S16: 244 case AUD_FMT_U16: 245 deffmt: 246 esdfmt |= ESD_BITS16; 247 obt_as.fmt = AUD_FMT_S16; 248 break; 249 250 default: 251 dolog ("Internal logic error: Bad audio format %d\n", as->fmt); 252 goto deffmt; 253 254 } 255 obt_as.endianness = AUDIO_HOST_ENDIANNESS; 256 257 audio_pcm_init_info (&hw->info, &obt_as); 258 259 hw->samples = conf.samples; 260 esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); 261 if (!esd->pcm_buf) { 262 dolog ("Could not allocate buffer (%d bytes)\n", 263 hw->samples << hw->info.shift); 264 return -1; 265 } 266 267 esd->fd = FF(esd_play_stream) (esdfmt, as->freq, conf.dac_host, NULL); 268 if (esd->fd < 0) { 269 qesd_logerr (errno, "esd_play_stream failed\n"); 270 goto fail1; 271 } 272 273 if (audio_pt_init (&esd->pt, qesd_thread_out, esd, AUDIO_CAP, AUDIO_FUNC)) { 274 goto fail2; 275 } 276 277 return 0; 278 279 fail2: 280 if (close (esd->fd)) { 281 qesd_logerr (errno, "%s: close on esd socket(%d) failed\n", 282 AUDIO_FUNC, esd->fd); 283 } 284 esd->fd = -1; 285 286 fail1: 287 qemu_free (esd->pcm_buf); 288 esd->pcm_buf = NULL; 289 return -1; 290} 291 292static void qesd_fini_out (HWVoiceOut *hw) 293{ 294 void *ret; 295 ESDVoiceOut *esd = (ESDVoiceOut *) hw; 296 297 audio_pt_lock (&esd->pt, AUDIO_FUNC); 298 esd->done = 1; 299 audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC); 300 audio_pt_join (&esd->pt, &ret, AUDIO_FUNC); 301 302 if (esd->fd >= 0) { 303 if (close (esd->fd)) { 304 qesd_logerr (errno, "failed to close esd socket\n"); 305 } 306 esd->fd = -1; 307 } 308 309 audio_pt_fini (&esd->pt, AUDIO_FUNC); 310 311 qemu_free (esd->pcm_buf); 312 esd->pcm_buf = NULL; 313} 314 315static int qesd_ctl_out (HWVoiceOut *hw, int cmd, ...) 316{ 317 (void) hw; 318 (void) cmd; 319 return 0; 320} 321 322/* capture */ 323static void *qesd_thread_in (void *arg) 324{ 325 ESDVoiceIn *esd = arg; 326 HWVoiceIn *hw = &esd->hw; 327 int threshold; 328 329 threshold = conf.divisor ? hw->samples / conf.divisor : 0; 330 331 if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) { 332 return NULL; 333 } 334 335 for (;;) { 336 int incr, to_grab, wpos; 337 338 for (;;) { 339 if (esd->done) { 340 goto exit; 341 } 342 343 if (esd->dead > threshold) { 344 break; 345 } 346 347 if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) { 348 goto exit; 349 } 350 } 351 352 incr = to_grab = esd->dead; 353 wpos = hw->wpos; 354 355 if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) { 356 return NULL; 357 } 358 359 while (to_grab) { 360 ssize_t nread; 361 int chunk = audio_MIN (to_grab, hw->samples - wpos); 362 void *buf = advance (esd->pcm_buf, wpos); 363 364 again: 365 nread = read (esd->fd, buf, chunk << hw->info.shift); 366 if (nread == -1) { 367 if (errno == EINTR || errno == EAGAIN) { 368 goto again; 369 } 370 qesd_logerr (errno, "read failed\n"); 371 return NULL; 372 } 373 374 if (nread != chunk << hw->info.shift) { 375 int rsamples = nread >> hw->info.shift; 376 int rbytes = rsamples << hw->info.shift; 377 if (rbytes != nread) { 378 dolog ("warning: Misaligned write %d (requested %zd), " 379 "alignment %d\n", 380 rbytes, nread, hw->info.align + 1); 381 } 382 to_grab -= rsamples; 383 wpos = (wpos + rsamples) % hw->samples; 384 break; 385 } 386 387 hw->conv (hw->conv_buf + wpos, buf, nread >> hw->info.shift, 388 &nominal_volume); 389 wpos = (wpos + chunk) % hw->samples; 390 to_grab -= chunk; 391 } 392 393 if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) { 394 return NULL; 395 } 396 397 esd->wpos = wpos; 398 esd->dead -= incr; 399 esd->incr += incr; 400 } 401 402 exit: 403 audio_pt_unlock (&esd->pt, AUDIO_FUNC); 404 return NULL; 405} 406 407static int qesd_run_in (HWVoiceIn *hw) 408{ 409 int live, incr, dead; 410 ESDVoiceIn *esd = (ESDVoiceIn *) hw; 411 412 if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) { 413 return 0; 414 } 415 416 live = audio_pcm_hw_get_live_in (hw); 417 dead = hw->samples - live; 418 incr = audio_MIN (dead, esd->incr); 419 esd->incr -= incr; 420 esd->dead = dead - incr; 421 hw->wpos = esd->wpos; 422 if (esd->dead > 0) { 423 audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC); 424 } 425 else { 426 audio_pt_unlock (&esd->pt, AUDIO_FUNC); 427 } 428 return incr; 429} 430 431static int qesd_read (SWVoiceIn *sw, void *buf, int len) 432{ 433 return audio_pcm_sw_read (sw, buf, len); 434} 435 436static int qesd_init_in (HWVoiceIn *hw, struct audsettings *as) 437{ 438 ESDVoiceIn *esd = (ESDVoiceIn *) hw; 439 struct audsettings obt_as = *as; 440 int esdfmt = ESD_STREAM | ESD_RECORD; 441 442 esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO; 443 switch (as->fmt) { 444 case AUD_FMT_S8: 445 case AUD_FMT_U8: 446 esdfmt |= ESD_BITS8; 447 obt_as.fmt = AUD_FMT_U8; 448 break; 449 450 case AUD_FMT_S16: 451 case AUD_FMT_U16: 452 esdfmt |= ESD_BITS16; 453 obt_as.fmt = AUD_FMT_S16; 454 break; 455 456 case AUD_FMT_S32: 457 case AUD_FMT_U32: 458 dolog ("Will use 16 instead of 32 bit samples\n"); 459 esdfmt |= ESD_BITS16; 460 obt_as.fmt = AUD_FMT_S16; 461 break; 462 } 463 obt_as.endianness = AUDIO_HOST_ENDIANNESS; 464 465 audio_pcm_init_info (&hw->info, &obt_as); 466 467 hw->samples = conf.samples; 468 esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); 469 if (!esd->pcm_buf) { 470 dolog ("Could not allocate buffer (%d bytes)\n", 471 hw->samples << hw->info.shift); 472 return -1; 473 } 474 475 esd->fd = FF(esd_record_stream) (esdfmt, as->freq, conf.adc_host, NULL); 476 if (esd->fd < 0) { 477 qesd_logerr (errno, "esd_record_stream failed\n"); 478 goto fail1; 479 } 480 481 if (audio_pt_init (&esd->pt, qesd_thread_in, esd, AUDIO_CAP, AUDIO_FUNC)) { 482 goto fail2; 483 } 484 485 return 0; 486 487 fail2: 488 if (close (esd->fd)) { 489 qesd_logerr (errno, "%s: close on esd socket(%d) failed\n", 490 AUDIO_FUNC, esd->fd); 491 } 492 esd->fd = -1; 493 494 fail1: 495 qemu_free (esd->pcm_buf); 496 esd->pcm_buf = NULL; 497 return -1; 498} 499 500static void qesd_fini_in (HWVoiceIn *hw) 501{ 502 void *ret; 503 ESDVoiceIn *esd = (ESDVoiceIn *) hw; 504 505 audio_pt_lock (&esd->pt, AUDIO_FUNC); 506 esd->done = 1; 507 audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC); 508 audio_pt_join (&esd->pt, &ret, AUDIO_FUNC); 509 510 if (esd->fd >= 0) { 511 if (close (esd->fd)) { 512 qesd_logerr (errno, "failed to close esd socket\n"); 513 } 514 esd->fd = -1; 515 } 516 517 audio_pt_fini (&esd->pt, AUDIO_FUNC); 518 519 qemu_free (esd->pcm_buf); 520 esd->pcm_buf = NULL; 521} 522 523static int qesd_ctl_in (HWVoiceIn *hw, int cmd, ...) 524{ 525 (void) hw; 526 (void) cmd; 527 return 0; 528} 529 530/* common */ 531static void *qesd_audio_init (void) 532{ 533 void* result = NULL; 534 535 D("%s: entering", __FUNCTION__); 536 537 if (esd_lib == NULL) { 538 int fd; 539 540 esd_lib = dlopen( "libesd.so", RTLD_NOW ); 541 if (esd_lib == NULL) 542 esd_lib = dlopen( "libesd.so.0", RTLD_NOW ); 543 544 if (esd_lib == NULL) { 545 D("could not find libesd on this system"); 546 goto Exit; 547 } 548 549 if (esd_dynlink_init(esd_lib) < 0) 550 goto Fail; 551 552 fd = FF(esd_open_sound)(conf.dac_host); 553 if (fd < 0) { 554 D("%s: could not open direct sound server connection, trying localhost", 555 __FUNCTION__); 556 fd = FF(esd_open_sound)("localhost"); 557 if (fd < 0) { 558 D("%s: could not open localhost sound server connection", __FUNCTION__); 559 goto Fail; 560 } 561 } 562 563 D("%s: EsounD server connection succeeded", __FUNCTION__); 564 /* FF(esd_close)(fd); */ 565 } 566 result = &conf; 567 goto Exit; 568 569Fail: 570 D("%s: failed to open library", __FUNCTION__); 571 dlclose(esd_lib); 572 esd_lib = NULL; 573 574Exit: 575 return result; 576} 577 578static void qesd_audio_fini (void *opaque) 579{ 580 (void) opaque; 581 if (esd_lib != NULL) { 582 dlclose(esd_lib); 583 esd_lib = NULL; 584 } 585 ldebug ("esd_fini"); 586} 587 588struct audio_option qesd_options[] = { 589 { 590 .name = "SAMPLES", 591 .tag = AUD_OPT_INT, 592 .valp = &conf.samples, 593 .descr = "buffer size in samples" 594 }, 595 { 596 .name = "DIVISOR", 597 .tag = AUD_OPT_INT, 598 .valp = &conf.divisor, 599 .descr = "threshold divisor" 600 }, 601 { 602 .name = "DAC_HOST", 603 .tag = AUD_OPT_STR, 604 .valp = &conf.dac_host, 605 .descr = "playback host" 606 }, 607 { 608 .name = "ADC_HOST", 609 .tag = AUD_OPT_STR, 610 .valp = &conf.adc_host, 611 .descr = "capture host" 612 }, 613 { /* End of list */ } 614}; 615 616static struct audio_pcm_ops qesd_pcm_ops = { 617 .init_out = qesd_init_out, 618 .fini_out = qesd_fini_out, 619 .run_out = qesd_run_out, 620 .write = qesd_write, 621 .ctl_out = qesd_ctl_out, 622 623 .init_in = qesd_init_in, 624 .fini_in = qesd_fini_in, 625 .run_in = qesd_run_in, 626 .read = qesd_read, 627 .ctl_in = qesd_ctl_in, 628}; 629 630struct audio_driver esd_audio_driver = { 631 .name = "esd", 632 .descr = "http://en.wikipedia.org/wiki/Esound", 633 .options = qesd_options, 634 .init = qesd_audio_init, 635 .fini = qesd_audio_fini, 636 .pcm_ops = &qesd_pcm_ops, 637 .can_be_default = 0, 638 .max_voices_out = INT_MAX, 639 .max_voices_in = INT_MAX, 640 .voice_size_out = sizeof (ESDVoiceOut), 641 .voice_size_in = sizeof (ESDVoiceIn) 642}; 643