1/* 2 * Copyright (C) 2010 Julien BLACHE <jb@jblache.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 */ 18 19#ifdef HAVE_CONFIG_H 20# include <config.h> 21#endif 22 23#include <stdio.h> 24#include <stdlib.h> 25#include <unistd.h> 26#include <string.h> 27#include <errno.h> 28#include <stdint.h> 29#include <inttypes.h> 30 31#include <alsa/asoundlib.h> 32 33#include "conffile.h" 34#include "logger.h" 35#include "player.h" 36#include "laudio.h" 37 38 39struct pcm_packet 40{ 41 uint8_t samples[STOB(AIRTUNES_V2_PACKET_SAMPLES)]; 42 43 uint64_t rtptime; 44 45 size_t offset; 46 47 struct pcm_packet *next; 48}; 49 50static uint64_t pcm_pos; 51static uint64_t pcm_start_pos; 52static int pcm_last_error; 53static int pcm_recovery; 54static int pcm_buf_threshold; 55 56static struct pcm_packet *pcm_pkt_head; 57static struct pcm_packet *pcm_pkt_tail; 58 59static char *card_name; 60static char *mixer_name; 61static snd_pcm_t *hdl; 62static snd_mixer_t *mixer_hdl; 63static snd_mixer_elem_t *vol_elem; 64static long vol_min; 65static long vol_max; 66 67static enum laudio_state pcm_status; 68static laudio_status_cb status_cb; 69 70 71static void 72update_status(enum laudio_state status) 73{ 74 pcm_status = status; 75 status_cb(status); 76} 77 78static int 79laudio_xrun_recover(int err) 80{ 81 int ret; 82 83 if (err != 0) 84 pcm_last_error = err; 85 86 /* Buffer underrun */ 87 if (err == -EPIPE) 88 { 89 pcm_last_error = 0; 90 91 ret = snd_pcm_prepare(hdl); 92 if (ret < 0) 93 { 94 DPRINTF(E_WARN, L_LAUDIO, "Couldn't recover from underrun: %s\n", snd_strerror(ret)); 95 return 1; 96 } 97 98 return 0; 99 } 100 /* Device suspended */ 101 else if (pcm_last_error == -ESTRPIPE) 102 { 103 ret = snd_pcm_resume(hdl); 104 if (ret == -EAGAIN) 105 { 106 pcm_recovery++; 107 108 return 2; 109 } 110 else if (ret < 0) 111 { 112 pcm_recovery = 0; 113 114 ret = snd_pcm_prepare(hdl); 115 if (ret < 0) 116 { 117 DPRINTF(E_WARN, L_LAUDIO, "Couldn't recover from suspend: %s\n", snd_strerror(ret)); 118 return 1; 119 } 120 } 121 122 pcm_recovery = 0; 123 return 0; 124 } 125 126 return err; 127} 128 129static int 130laudio_set_start_threshold(snd_pcm_uframes_t threshold) 131{ 132 snd_pcm_sw_params_t *sw_params; 133 int ret; 134 135 ret = snd_pcm_sw_params_malloc(&sw_params); 136 if (ret < 0) 137 { 138 DPRINTF(E_LOG, L_LAUDIO, "Could not allocate sw params: %s\n", snd_strerror(ret)); 139 140 goto out_fail; 141 } 142 143 ret = snd_pcm_sw_params_current(hdl, sw_params); 144 if (ret < 0) 145 { 146 DPRINTF(E_LOG, L_LAUDIO, "Could not retrieve current sw params: %s\n", snd_strerror(ret)); 147 148 goto out_fail; 149 } 150 151 ret = snd_pcm_sw_params_set_start_threshold(hdl, sw_params, threshold); 152 if (ret < 0) 153 { 154 DPRINTF(E_LOG, L_LAUDIO, "Could not set start threshold: %s\n", snd_strerror(ret)); 155 156 goto out_fail; 157 } 158 159 ret = snd_pcm_sw_params(hdl, sw_params); 160 if (ret < 0) 161 { 162 DPRINTF(E_LOG, L_LAUDIO, "Could not set sw params: %s\n", snd_strerror(ret)); 163 164 goto out_fail; 165 } 166 167 return 0; 168 169 out_fail: 170 snd_pcm_sw_params_free(sw_params); 171 172 return -1; 173} 174 175void 176laudio_write(uint8_t *buf, uint64_t rtptime) 177{ 178 struct pcm_packet *pkt; 179 snd_pcm_sframes_t nsamp; 180 int ret; 181 182 pkt = (struct pcm_packet *)malloc(sizeof(struct pcm_packet)); 183 if (!pkt) 184 { 185 DPRINTF(E_LOG, L_LAUDIO, "Out of memory for PCM pkt\n"); 186 187 update_status(LAUDIO_FAILED); 188 return; 189 } 190 191 memcpy(pkt->samples, buf, sizeof(pkt->samples)); 192 193 pkt->rtptime = rtptime; 194 pkt->offset = 0; 195 pkt->next = NULL; 196 197 if (pcm_pkt_tail) 198 { 199 pcm_pkt_tail->next = pkt; 200 pcm_pkt_tail = pkt; 201 } 202 else 203 { 204 pcm_pkt_head = pkt; 205 pcm_pkt_tail = pkt; 206 } 207 208 if (pcm_pos < pcm_pkt_head->rtptime) 209 { 210 pcm_pos += AIRTUNES_V2_PACKET_SAMPLES; 211 212 return; 213 } 214 else if ((pcm_status != LAUDIO_RUNNING) && (pcm_pos >= pcm_start_pos)) 215 { 216 /* Kill threshold */ 217 ret = laudio_set_start_threshold(0); 218 if (ret < 0) 219 DPRINTF(E_WARN, L_LAUDIO, "Couldn't set PCM start threshold to 0 for output start\n"); 220 221 update_status(LAUDIO_RUNNING); 222 } 223 224 pkt = pcm_pkt_head; 225 226 while (pkt) 227 { 228 if (pcm_recovery) 229 { 230 ret = laudio_xrun_recover(0); 231 if ((ret == 2) && (pcm_recovery < 10)) 232 return; 233 else 234 { 235 if (ret == 2) 236 DPRINTF(E_LOG, L_LAUDIO, "Couldn't recover PCM device after 10 tries, aborting\n"); 237 238 update_status(LAUDIO_FAILED); 239 return; 240 } 241 } 242 243 nsamp = snd_pcm_writei(hdl, pkt->samples + pkt->offset, BTOS(sizeof(pkt->samples) - pkt->offset)); 244 if ((nsamp == -EPIPE) || (nsamp == -ESTRPIPE)) 245 { 246 ret = laudio_xrun_recover(nsamp); 247 if ((ret < 0) || (ret == 1)) 248 { 249 if (ret < 0) 250 DPRINTF(E_LOG, L_LAUDIO, "PCM write error: %s\n", snd_strerror(ret)); 251 252 update_status(LAUDIO_FAILED); 253 return; 254 } 255 else if (ret != 0) 256 return; 257 258 continue; 259 } 260 else if (nsamp < 0) 261 { 262 DPRINTF(E_LOG, L_LAUDIO, "PCM write error: %s\n", snd_strerror(nsamp)); 263 264 update_status(LAUDIO_FAILED); 265 return; 266 } 267 268 pcm_pos += nsamp; 269 270 pkt->offset += STOB(nsamp); 271 if (pkt->offset == sizeof(pkt->samples)) 272 { 273 pcm_pkt_head = pkt->next; 274 275 if (pkt == pcm_pkt_tail) 276 pcm_pkt_tail = NULL; 277 278 free(pkt); 279 280 pkt = pcm_pkt_head; 281 } 282 283 /* Don't let ALSA fill up the buffer too much */ 284 if (nsamp == AIRTUNES_V2_PACKET_SAMPLES) 285 return; 286 } 287} 288 289uint64_t 290laudio_get_pos(void) 291{ 292 snd_pcm_sframes_t delay; 293 int ret; 294 295 if (pcm_pos == 0) 296 return 0; 297 298 ret = snd_pcm_delay(hdl, &delay); 299 if (ret < 0) 300 { 301 DPRINTF(E_WARN, L_LAUDIO, "Could not obtain PCM delay: %s\n", snd_strerror(ret)); 302 303 return pcm_pos; 304 } 305 306 return pcm_pos - delay; 307} 308 309void 310laudio_set_volume(int vol) 311{ 312 int pcm_vol; 313 314 if (!mixer_hdl || !vol_elem) 315 return; 316 317 snd_mixer_handle_events(mixer_hdl); 318 319 if (!snd_mixer_selem_is_active(vol_elem)) 320 return; 321 322 switch (vol) 323 { 324 case 0: 325 pcm_vol = vol_min; 326 break; 327 328 case 100: 329 pcm_vol = vol_max; 330 break; 331 332 default: 333 pcm_vol = vol_min + (vol * (vol_max - vol_min)) / 100; 334 break; 335 } 336 337 DPRINTF(E_DBG, L_LAUDIO, "Setting PCM volume to %d (%d)\n", pcm_vol, vol); 338 339 snd_mixer_selem_set_playback_volume_all(vol_elem, pcm_vol); 340} 341 342int 343laudio_start(uint64_t cur_pos, uint64_t next_pkt) 344{ 345 int ret; 346 347 ret = snd_pcm_prepare(hdl); 348 if (ret < 0) 349 { 350 DPRINTF(E_LOG, L_LAUDIO, "Could not prepare PCM device: %s\n", snd_strerror(ret)); 351 352 return -1; 353 } 354 355 DPRINTF(E_DBG, L_LAUDIO, "PCM will start after %d samples (%d packets)\n", pcm_buf_threshold, pcm_buf_threshold / AIRTUNES_V2_PACKET_SAMPLES); 356 357 /* Make pcm_pos the rtptime of the packet containing cur_pos */ 358 pcm_pos = next_pkt; 359 while (pcm_pos > cur_pos) 360 pcm_pos -= AIRTUNES_V2_PACKET_SAMPLES; 361 362 pcm_start_pos = next_pkt + pcm_buf_threshold; 363 364 /* Compensate threshold, as it's taken into account by snd_pcm_delay() */ 365 pcm_pos += pcm_buf_threshold; 366 367 DPRINTF(E_DBG, L_LAUDIO, "PCM pos %" PRIu64 ", start pos %" PRIu64 "\n", pcm_pos, pcm_start_pos); 368 369 pcm_pkt_head = NULL; 370 pcm_pkt_tail = NULL; 371 372 pcm_last_error = 0; 373 pcm_recovery = 0; 374 375 ret = laudio_set_start_threshold(pcm_buf_threshold); 376 if (ret < 0) 377 { 378 DPRINTF(E_LOG, L_LAUDIO, "Could not set PCM start threshold for local audio start\n"); 379 380 return -1; 381 } 382 383 update_status(LAUDIO_STARTED); 384 385 return 0; 386} 387 388void 389laudio_stop(void) 390{ 391 struct pcm_packet *pkt; 392 393 update_status(LAUDIO_STOPPING); 394 395 snd_pcm_drop(hdl); 396 397 for (pkt = pcm_pkt_head; pcm_pkt_head; pkt = pcm_pkt_head) 398 { 399 pcm_pkt_head = pkt->next; 400 401 free(pkt); 402 } 403 404 pcm_pkt_head = NULL; 405 pcm_pkt_tail = NULL; 406 407 update_status(LAUDIO_OPEN); 408} 409 410static int 411mixer_open(void) 412{ 413 snd_mixer_elem_t *elem; 414 snd_mixer_elem_t *master; 415 snd_mixer_elem_t *pcm; 416 snd_mixer_elem_t *custom; 417 snd_mixer_selem_id_t *sid; 418 int ret; 419 420 ret = snd_mixer_open(&mixer_hdl, 0); 421 if (ret < 0) 422 { 423 DPRINTF(E_LOG, L_LAUDIO, "Failed to open mixer: %s\n", snd_strerror(ret)); 424 425 mixer_hdl = NULL; 426 return -1; 427 } 428 429 ret = snd_mixer_attach(mixer_hdl, card_name); 430 if (ret < 0) 431 { 432 DPRINTF(E_LOG, L_LAUDIO, "Failed to attach mixer: %s\n", snd_strerror(ret)); 433 434 goto out_close; 435 } 436 437 ret = snd_mixer_selem_register(mixer_hdl, NULL, NULL); 438 if (ret < 0) 439 { 440 DPRINTF(E_LOG, L_LAUDIO, "Failed to register mixer: %s\n", snd_strerror(ret)); 441 442 goto out_detach; 443 } 444 445 ret = snd_mixer_load(mixer_hdl); 446 if (ret < 0) 447 { 448 DPRINTF(E_LOG, L_LAUDIO, "Failed to load mixer: %s\n", snd_strerror(ret)); 449 450 goto out_detach; 451 } 452 453 /* Grab interesting elements */ 454 snd_mixer_selem_id_alloca(&sid); 455 456 pcm = NULL; 457 master = NULL; 458 custom = NULL; 459 for (elem = snd_mixer_first_elem(mixer_hdl); elem; elem = snd_mixer_elem_next(elem)) 460 { 461 snd_mixer_selem_get_id(elem, sid); 462 463 if (mixer_name && (strcmp(snd_mixer_selem_id_get_name(sid), mixer_name) == 0)) 464 { 465 custom = elem; 466 break; 467 } 468 else if (strcmp(snd_mixer_selem_id_get_name(sid), "PCM") == 0) 469 pcm = elem; 470 else if (strcmp(snd_mixer_selem_id_get_name(sid), "Master") == 0) 471 master = elem; 472 } 473 474 if (mixer_name) 475 { 476 if (custom) 477 vol_elem = custom; 478 else 479 { 480 DPRINTF(E_LOG, L_LAUDIO, "Failed to open configured mixer element '%s'\n", mixer_name); 481 482 goto out_detach; 483 } 484 } 485 else if (pcm) 486 vol_elem = pcm; 487 else if (master) 488 vol_elem = master; 489 else 490 { 491 DPRINTF(E_LOG, L_LAUDIO, "Failed to open PCM or Master mixer element\n"); 492 493 goto out_detach; 494 } 495 496 /* Get min & max volume */ 497 snd_mixer_selem_get_playback_volume_range(vol_elem, &vol_min, &vol_max); 498 499 return 0; 500 501 out_detach: 502 snd_mixer_detach(mixer_hdl, card_name); 503 out_close: 504 snd_mixer_close(mixer_hdl); 505 mixer_hdl = NULL; 506 vol_elem = NULL; 507 508 return -1; 509} 510 511int 512laudio_open(void) 513{ 514 snd_pcm_hw_params_t *hw_params; 515 snd_pcm_uframes_t bufsize; 516 int ret; 517 518 hw_params = NULL; 519 520 ret = snd_pcm_open(&hdl, card_name, SND_PCM_STREAM_PLAYBACK, 0); 521 if (ret < 0) 522 { 523 DPRINTF(E_LOG, L_LAUDIO, "Could not open playback device: %s\n", snd_strerror(ret)); 524 525 return -1; 526 } 527 528 /* HW params */ 529 ret = snd_pcm_hw_params_malloc(&hw_params); 530 if (ret < 0) 531 { 532 DPRINTF(E_LOG, L_LAUDIO, "Could not allocate hw params: %s\n", snd_strerror(ret)); 533 534 goto out_fail; 535 } 536 537 ret = snd_pcm_hw_params_any(hdl, hw_params); 538 if (ret < 0) 539 { 540 DPRINTF(E_LOG, L_LAUDIO, "Could not retrieve hw params: %s\n", snd_strerror(ret)); 541 542 goto out_fail; 543 } 544 545 ret = snd_pcm_hw_params_set_access(hdl, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); 546 if (ret < 0) 547 { 548 DPRINTF(E_LOG, L_LAUDIO, "Could not set access method: %s\n", snd_strerror(ret)); 549 550 goto out_fail; 551 } 552 553 ret = snd_pcm_hw_params_set_format(hdl, hw_params, SND_PCM_FORMAT_S16_LE); 554 if (ret < 0) 555 { 556 DPRINTF(E_LOG, L_LAUDIO, "Could not set S16LE format: %s\n", snd_strerror(ret)); 557 558 goto out_fail; 559 } 560 561 ret = snd_pcm_hw_params_set_channels(hdl, hw_params, 2); 562 if (ret < 0) 563 { 564 DPRINTF(E_LOG, L_LAUDIO, "Could not set stereo output: %s\n", snd_strerror(ret)); 565 566 goto out_fail; 567 } 568 569 ret = snd_pcm_hw_params_set_rate(hdl, hw_params, 44100, 0); 570 if (ret < 0) 571 { 572 DPRINTF(E_LOG, L_LAUDIO, "Hardware doesn't support 44.1 kHz: %s\n", snd_strerror(ret)); 573 574 goto out_fail; 575 } 576 577 ret = snd_pcm_hw_params_get_buffer_size_max(hw_params, &bufsize); 578 if (ret < 0) 579 { 580 DPRINTF(E_LOG, L_LAUDIO, "Could not get max buffer size: %s\n", snd_strerror(ret)); 581 582 goto out_fail; 583 } 584 585 DPRINTF(E_DBG, L_LAUDIO, "Max buffer size is %lu samples\n", bufsize); 586 587 ret = snd_pcm_hw_params_set_buffer_size_max(hdl, hw_params, &bufsize); 588 if (ret < 0) 589 { 590 DPRINTF(E_LOG, L_LAUDIO, "Could not set buffer size to max: %s\n", snd_strerror(ret)); 591 592 goto out_fail; 593 } 594 595 DPRINTF(E_DBG, L_LAUDIO, "Buffer size is %lu samples\n", bufsize); 596 597 ret = snd_pcm_hw_params(hdl, hw_params); 598 if (ret < 0) 599 { 600 DPRINTF(E_LOG, L_LAUDIO, "Could not set hw params: %s\n", snd_strerror(ret)); 601 602 goto out_fail; 603 } 604 605 snd_pcm_hw_params_free(hw_params); 606 hw_params = NULL; 607 608 pcm_pos = 0; 609 pcm_last_error = 0; 610 pcm_recovery = 0; 611 pcm_buf_threshold = (bufsize / AIRTUNES_V2_PACKET_SAMPLES) * AIRTUNES_V2_PACKET_SAMPLES; 612 613 ret = mixer_open(); 614 if (ret < 0) 615 { 616 DPRINTF(E_LOG, L_LAUDIO, "Could not open mixer\n"); 617 618 goto out_fail; 619 } 620 621 update_status(LAUDIO_OPEN); 622 623 return 0; 624 625 out_fail: 626 if (hw_params) 627 snd_pcm_hw_params_free(hw_params); 628 629 snd_pcm_close(hdl); 630 hdl = NULL; 631 632 return -1; 633} 634 635void 636laudio_close(void) 637{ 638 struct pcm_packet *pkt; 639 640 snd_pcm_close(hdl); 641 hdl = NULL; 642 643 if (mixer_hdl) 644 { 645 snd_mixer_detach(mixer_hdl, card_name); 646 snd_mixer_close(mixer_hdl); 647 648 mixer_hdl = NULL; 649 vol_elem = NULL; 650 } 651 652 for (pkt = pcm_pkt_head; pcm_pkt_head; pkt = pcm_pkt_head) 653 { 654 pcm_pkt_head = pkt->next; 655 656 free(pkt); 657 } 658 659 pcm_pkt_head = NULL; 660 pcm_pkt_tail = NULL; 661 662 update_status(LAUDIO_CLOSED); 663} 664 665 666int 667laudio_init(laudio_status_cb cb) 668{ 669 snd_lib_error_set_handler(logger_alsa); 670 671 status_cb = cb; 672 673 card_name = cfg_getstr(cfg_getsec(cfg, "audio"), "card"); 674 mixer_name = cfg_getstr(cfg_getsec(cfg, "audio"), "mixer"); 675 676 hdl = NULL; 677 mixer_hdl = NULL; 678 vol_elem = NULL; 679 680 return 0; 681} 682 683void 684laudio_deinit(void) 685{ 686 snd_lib_error_set_handler(NULL); 687} 688