mplay.flac.c (15933B)
1#include "mplay.h" 2 3#include <FLAC/format.h> 4#include <FLAC/stream_decoder.h> 5#include <pulse/sample.h> 6#include <pulse/introspect.h> 7#include <pulse/operation.h> 8#include <pulse/stream.h> 9#include <pulse/thread-mainloop.h> 10#include <pulse/volume.h> 11#include <pulse/pulseaudio.h> 12#include <pulse/def.h> 13 14#include <sys/mman.h> 15#include <sys/stat.h> 16#include <pthread.h> 17#include <fcntl.h> 18#include <termios.h> 19#include <unistd.h> 20 21#include <stdarg.h> 22#include <stdint.h> 23#include <stdbool.h> 24#include <string.h> 25#include <stdio.h> 26#include <stdlib.h> 27 28struct decoder { 29 FLAC__StreamDecoder *flac; 30 uint8_t *samples; 31 size_t sample_cnt; 32 size_t sample_cap; 33 size_t sample_size; 34 size_t sample_max; 35 36 size_t sample_next; 37 38 bool seek; 39 40 uint32_t rate; 41 uint8_t channels; 42 pa_sample_format_t format; 43 44 bool init; 45 bool pause; 46 bool done; 47 bool end; 48}; 49 50static pa_buffer_attr pa_buf = { 51 .fragsize = UINT32_MAX, 52 .maxlength = UINT32_MAX, 53 .tlength = UINT32_MAX, 54 .prebuf = UINT32_MAX, 55 .minreq = UINT32_MAX, 56}; 57 58static pa_stream_flags_t pa_stream_flags = PA_STREAM_START_CORKED 59 | PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_ADJUST_LATENCY; 60 61static pa_threaded_mainloop *pa_mloop; 62static pa_context *pa_ctx; 63static pa_stream *pa_strm; 64static pa_sink_input_info pa_strm_sink; 65static bool pa_strm_sink_update; 66 67static struct decoder decoder; 68 69static pthread_t input_worker_thread; 70static bool input_worker_alive = false; 71 72static struct termios term_old; 73static struct termios term_new; 74static bool term_set = false; 75 76static bool headless = false; 77static bool verbose = false; 78static bool istty = false; 79 80static void 81__attribute__((noreturn)) 82__attribute__((format(printf, 1, 2))) 83die(const char *fmt, ...) 84{ 85 va_list ap; 86 87 fputs("mplay.flac: ", stderr); 88 va_start(ap, fmt); 89 vfprintf(stderr, fmt, ap); 90 va_end(ap); 91 if (*fmt && fmt[strlen(fmt)-1] == ':') { 92 perror(NULL); 93 } else { 94 fputc('\n', stderr); 95 } 96 97 exit(1); 98} 99 100static void 101term_set_canonical(void) 102{ 103 term_new.c_lflag |= ICANON; 104 term_new.c_lflag |= ECHO; 105 if (tcsetattr(0, TCSANOW, &term_new)) 106 die("tcsetattr:"); 107} 108 109static void 110term_set_raw(void) 111{ 112 term_new.c_lflag &= ~(0U | ICANON); 113 term_new.c_lflag &= ~(0U | ECHO); 114 if (tcsetattr(0, TCSANOW, &term_new)) 115 die("tcsetattr:"); 116} 117 118static void 119get_line(char *buf, int size) 120{ 121 char *c; 122 123 if (istty) putc('>', stderr); 124 if (istty) term_set_canonical(); 125 fgets(buf, size, stdin); 126 if ((c = strchr(buf, '\n'))) *c = '\0'; 127 if (istty) term_set_raw(); 128} 129 130static FLAC__StreamDecoderWriteStatus 131decoder_write_callback(const FLAC__StreamDecoder *flac, 132 const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *user) 133{ 134 uint32_t si, ch; 135 136 assert(decoder.sample_next == decoder.sample_cnt); 137 138 if (decoder.sample_cnt + frame->header.blocksize > decoder.sample_cap) { 139 decoder.sample_cap = MAX(decoder.sample_cap * 2, 140 decoder.sample_cnt + frame->header.blocksize); 141 decoder.samples = realloc(decoder.samples, decoder.sample_cap 142 * decoder.channels * decoder.sample_size); 143 if (!decoder.samples) die("realloc:"); 144 } 145 146 if (decoder.format == PA_SAMPLE_S16LE) { 147 uint16_t *sample = (uint16_t *)decoder.samples 148 + decoder.sample_cnt * decoder.channels; 149 for (si = 0; si < frame->header.blocksize; si++) { 150 for (ch = 0; ch < frame->header.channels; ch++) { 151 *sample++ = (uint16_t)htole32((uint32_t)buffer[ch][si]); 152 } 153 } 154 } else if (decoder.format == PA_SAMPLE_S32LE) { 155 uint32_t *sample = (uint32_t *)decoder.samples 156 + decoder.sample_cnt * decoder.channels; 157 for (si = 0; si < frame->header.blocksize; si++) { 158 for (ch = 0; ch < frame->header.channels; ch++) { 159 *sample++ = htole32((uint32_t)buffer[ch][si]); 160 } 161 } 162 } 163 164 decoder.sample_cnt += frame->header.blocksize; 165 decoder.sample_max = MAX(decoder.sample_max, decoder.sample_cnt); 166 167 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; 168} 169 170static void 171decoder_metadata_callback(const FLAC__StreamDecoder *flac, 172 const FLAC__StreamMetadata *metadata, void *user) 173{ 174 if (!decoder.init && metadata->type == FLAC__METADATA_TYPE_STREAMINFO) { 175 decoder.sample_cnt = 0; 176 decoder.rate = metadata->data.stream_info.sample_rate; 177 decoder.channels = (uint8_t) metadata->data.stream_info.channels; 178 decoder.sample_size = metadata->data.stream_info.bits_per_sample / 8; 179 decoder.sample_max = metadata->data.stream_info.total_samples; 180 if (decoder.sample_size == 2) { 181 decoder.format = PA_SAMPLE_S16LE; 182 } else if (decoder.sample_size == 4) { 183 decoder.format = PA_SAMPLE_S32LE; 184 } else { 185 die("unsupported sample size"); 186 } 187 decoder.init = true; 188 } 189} 190 191static void 192decoder_error_callback(const FLAC__StreamDecoder *flac, 193 FLAC__StreamDecoderErrorStatus status, void *user) 194{ 195 die("flac decoding error: %s", FLAC__StreamDecoderErrorStatusString[status]); 196} 197 198static void 199decoder_flac_decode_next(void) 200{ 201 bool ok; 202 203 ok = FLAC__stream_decoder_process_single(decoder.flac); 204 FLAC__StreamDecoderState state = 205 FLAC__stream_decoder_get_state(decoder.flac); 206 if (!ok) { 207 die("decode process failed: %s", 208 FLAC__StreamDecoderStateString[state]); 209 } 210 decoder.done = state == FLAC__STREAM_DECODER_END_OF_STREAM; 211} 212 213static uint8_t * 214decoder_process_frame(size_t *cnt) 215{ 216 size_t _cnt; 217 218 if (decoder.sample_next < decoder.sample_cnt) { 219 _cnt = decoder.sample_cnt - decoder.sample_next; 220 } else { 221 if (decoder.done) { 222 decoder.end = true; 223 _cnt = 0; 224 } else { 225 decoder_flac_decode_next(); 226 _cnt = decoder.sample_cnt - decoder.sample_next; 227 } 228 } 229 230 if (cnt) *cnt = _cnt; 231 232 return decoder.samples + decoder.sample_next \ 233 * decoder.channels * decoder.sample_size; 234} 235 236static void 237decoder_init(const char *file) 238{ 239 FLAC__StreamDecoderInitStatus init_status; 240 241 decoder.sample_cnt = 0; 242 decoder.sample_next = 0; 243 decoder.sample_cap = 0; 244 decoder.sample_size = 0; 245 decoder.samples = NULL; 246 247 decoder.seek = false; 248 decoder.pause = false; 249 decoder.done = false; 250 decoder.end = false; 251 252 decoder.flac = FLAC__stream_decoder_new(); 253 init_status = FLAC__stream_decoder_init_file(decoder.flac, file, 254 decoder_write_callback, decoder_metadata_callback, 255 decoder_error_callback, NULL); 256 if (init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) { 257 die("flac decoder init failed: %s", 258 FLAC__StreamDecoderInitStatusString[init_status]); 259 } 260 261 /* decode channel specs */ 262 decoder.init = false; 263 decoder_process_frame(NULL); 264 assert(decoder.init); 265} 266 267static void 268decoder_seek(size_t sample_pos) 269{ 270 size_t cnt; 271 272 while (decoder.sample_next < sample_pos) { 273 decoder_process_frame(&cnt); 274 if (decoder.end) { 275 mplay_status(MPLAY_INFO_EXIT, "from seek"); 276 exit(0); 277 } 278 decoder.sample_next += cnt; 279 } 280 decoder.sample_next = sample_pos; 281} 282 283 284static void 285pa_stream_drain_callback(pa_stream *stream, int success, void *data) 286{ 287 mplay_status(MPLAY_INFO_EXIT, NULL); 288 exit(0); 289} 290 291static void 292pa_stream_write_callback(pa_stream *stream, size_t requested, void *data) 293{ 294 uint8_t *samples; 295 pa_operation *op; 296 ssize_t remaining; 297 size_t cnt, size; 298 299 remaining = (ssize_t) requested; 300 while (remaining > 0) { 301 samples = decoder_process_frame(&cnt); 302 if (decoder.end) { 303 op = pa_stream_drain(pa_strm, 304 pa_stream_drain_callback, NULL); 305 pa_operation_unref(op); 306 return; 307 } 308 if (!cnt) continue; 309 310 cnt = MIN(cnt, (size_t) remaining); 311 size = cnt * decoder.channels * decoder.sample_size; 312 pa_stream_write(stream, samples, size, NULL, 0, 313 decoder.seek ? PA_SEEK_RELATIVE_ON_READ : PA_SEEK_RELATIVE); 314 decoder.sample_next += cnt; 315 316 decoder.seek = false; 317 remaining -= (ssize_t) size; 318 } 319} 320 321static void 322pa_stream_underflow_callback(struct pa_stream *stream, void *data) 323{ 324 fprintf(stderr, "pulseaudio underflow!\n"); 325} 326 327static void 328pa_stream_overflow_callback(struct pa_stream *stream, void *data) 329{ 330 fprintf(stderr, "pulseaudio overflow!\n"); 331} 332 333static void 334update_sink_input_info_callback(struct pa_context *ctx, 335 const pa_sink_input_info *info, int eol, void *data) 336{ 337 if (eol) return; 338 memcpy(&pa_strm_sink, info, sizeof(pa_sink_input_info)); 339 pa_strm_sink_update = true; 340 pa_threaded_mainloop_signal(pa_mloop, true); 341} 342 343static void 344update_sink_input_info(void) 345{ 346 pa_operation *op; 347 348 pa_strm_sink_update = false; 349 op = pa_context_get_sink_input_info(pa_ctx, 350 pa_stream_get_index(pa_strm), 351 update_sink_input_info_callback, NULL); 352 if (!op) die("pa_context_get_sink_input_info failed"); 353 354 while (!pa_strm_sink_update) { 355 pa_threaded_mainloop_unlock(pa_mloop); 356 pa_threaded_mainloop_wait(pa_mloop); 357 pa_threaded_mainloop_lock(pa_mloop); 358 } 359 360 pa_threaded_mainloop_accept(pa_mloop); 361 362 pa_operation_unref(op); 363} 364 365static size_t 366stream_samples_buffered(void) 367{ 368 static size_t last_read_index = 0, last_write_index = 0; 369 const pa_timing_info *info; 370 size_t buffered; 371 372 info = pa_stream_get_timing_info(pa_strm); 373 if (!info || info->write_index_corrupt || info->read_index_corrupt) 374 return 0; 375 376 if (info->read_index != last_read_index) 377 last_write_index = (size_t) MAX(0, info->write_index); 378 379 buffered = (last_write_index - last_read_index) 380 / (decoder.sample_size * decoder.channels); 381 382 last_read_index = (size_t) MAX(0, info->read_index); 383 384 return buffered; 385} 386 387static double 388user_vol(void) 389{ 390 pa_volume_t vol; 391 392 update_sink_input_info(); 393 if (!pa_strm_sink.has_volume) 394 return -1; 395 396 vol = pa_cvolume_avg(&pa_strm_sink.volume); 397 398 return (double) vol * 100.F / (double) PA_VOLUME_NORM; 399} 400 401static double 402user_pos(void) 403{ 404 size_t sample_pos; 405 406 sample_pos = (size_t) MAX(0, 407 (ssize_t) decoder.sample_next - (ssize_t) stream_samples_buffered()); 408 409 return (double) sample_pos * 1.F / (double) decoder.rate; 410} 411 412static double 413user_end(void) 414{ 415 return (double) decoder.sample_max * 1.F / (double) decoder.rate; 416} 417 418static void 419cmd_setvol(double vol, double delta) 420{ 421 pa_operation *op; 422 423 pa_threaded_mainloop_lock(pa_mloop); 424 425 if (delta != 0) { 426 vol = user_vol() + delta; 427 } 428 429 update_sink_input_info(); 430 pa_cvolume_set(&pa_strm_sink.volume, 2, 431 (pa_volume_t) (vol * PA_VOLUME_NORM / 100.F)); 432 if (pa_cvolume_avg(&pa_strm_sink.volume) > 2 * PA_VOLUME_NORM) 433 pa_cvolume_set(&pa_strm_sink.volume, 2, 2 * PA_VOLUME_NORM); 434 435 op = pa_context_set_sink_input_volume(pa_ctx, 436 pa_stream_get_index(pa_strm), 437 &pa_strm_sink.volume, NULL, NULL); 438 pa_operation_unref(op); 439 440 mplay_status(MPLAY_INFO_VOLUME, "%02.2f", (double) pa_cvolume_avg(&pa_strm_sink.volume) 441 * 100.f / (double) PA_VOLUME_NORM); 442 443 pa_threaded_mainloop_unlock(pa_mloop); 444} 445 446static void 447cmd_seek(double time_sec, double delta) 448{ 449 size_t sample_pos; 450 pa_operation *op; 451 452 pa_threaded_mainloop_lock(pa_mloop); 453 454 if (delta != 0) { 455 time_sec = user_pos() + delta; 456 } 457 458 if (time_sec < 0) time_sec = 0; 459 sample_pos = (size_t) (time_sec * decoder.rate); 460 decoder_seek(sample_pos); 461 462 op = pa_stream_flush(pa_strm, NULL, NULL); 463 pa_operation_unref(op); 464 decoder.seek = true; 465 466 mplay_status(MPLAY_INFO_SEEK, "%02.2f", user_pos()); 467 468 pa_threaded_mainloop_unlock(pa_mloop); 469} 470 471static void 472cmd_playpause(void) 473{ 474 pa_operation *op; 475 476 pa_threaded_mainloop_lock(pa_mloop); 477 478 decoder.pause ^= 1; 479 op = pa_stream_cork(pa_strm, decoder.pause, NULL, NULL); 480 pa_operation_unref(op); 481 482 mplay_status(MPLAY_INFO_PAUSE, "%i", decoder.pause); 483 484 pa_threaded_mainloop_unlock(pa_mloop); 485} 486 487static void 488cmd_status(void) 489{ 490 pa_threaded_mainloop_lock(pa_mloop); 491 492 update_sink_input_info(); 493 494 mplay_status(MPLAY_INFO_STATUS, 495 "volume=%02.2f,pos=%02.2f,end=%02.2f,pause=%i", 496 user_vol(), user_pos(), user_end(), decoder.pause); 497 498 pa_threaded_mainloop_unlock(pa_mloop); 499} 500 501static bool 502key_input(void) 503{ 504 char linebuf[16], *end; 505 float fval; 506 int key; 507 508 while ((key = mplay_getkey()) == MPLAY_KEY_INV); 509 510 if (key == MPLAY_KEY_EOF) return false; 511 512 switch (mplay_action(key)) { 513 case MPLAY_ACTION_VOLUME: 514 get_line(linebuf, sizeof(linebuf)); 515 fval = strtof(linebuf, &end); 516 if (!end || *end) { 517 mplay_status(MPLAY_INFO_VOLUME, "fail:bad float"); 518 break; 519 } 520 cmd_setvol(fval, 0); 521 break; 522 case MPLAY_ACTION_VOLUME_UP: 523 cmd_setvol(0, 5); 524 break; 525 case MPLAY_ACTION_VOLUME_DOWN: 526 cmd_setvol(0, -5); 527 break; 528 case MPLAY_ACTION_SEEK: 529 get_line(linebuf, sizeof(linebuf)); 530 fval = strtof(linebuf, &end); 531 if (!end || *end) { 532 mplay_status(MPLAY_INFO_SEEK, "fail:bad float"); 533 break; 534 } 535 cmd_seek(fval, 0); 536 break; 537 case MPLAY_ACTION_SEEK_BWD: 538 cmd_seek(0, -5); 539 break; 540 case MPLAY_ACTION_SEEK_FWD: 541 cmd_seek(0, 5); 542 break; 543 case MPLAY_ACTION_PAUSE: 544 cmd_playpause(); 545 break; 546 case MPLAY_ACTION_STATUS: 547 cmd_status(); 548 break; 549 default: 550 mplay_status(MPLAY_INFO_INPUT, "fail"); 551 break; 552 } 553 554 return true; 555} 556 557static void * 558input_worker(void *arg) 559{ 560 input_worker_alive = true; 561 562 setvbuf(stdin, NULL, _IONBF, 0); 563 setvbuf(stdout, NULL, _IONBF, 0); 564 setvbuf(stderr, NULL, _IONBF, 0); 565 566 if (istty) { 567 if (tcgetattr(0, &term_old)) 568 die("tcgetattr:"); 569 term_new = term_old; 570 term_new.c_iflag |= BRKINT; 571 term_new.c_iflag &= ~(0U | IGNBRK); 572 term_set = true; 573 574 term_set_raw(); 575 } 576 577 mplay_status(MPLAY_INFO_READY, NULL); 578 579 while (key_input()); 580 581 return NULL; 582} 583 584static void 585pulse_context_init(void) 586{ 587 pa_mainloop_api *pa_mloop_api; 588 int ret; 589 590 pa_mloop_api = pa_threaded_mainloop_get_api(pa_mloop); 591 if (!pa_mloop_api) die("pa_threaded_mainloop_get_api"); 592 593 pa_ctx = pa_context_new(pa_mloop_api, "mplay.flac"); 594 if (!pa_ctx) die("pa_context_new"); 595 596 ret = pa_context_connect(pa_ctx, NULL, 0, NULL); 597 if (ret) die("pa_context_connect: %s", 598 pa_strerror(pa_context_errno(pa_ctx))); 599 600 while (pa_context_get_state(pa_ctx) != PA_CONTEXT_READY) { 601 pa_threaded_mainloop_unlock(pa_mloop); 602 pa_threaded_mainloop_wait(pa_mloop); 603 pa_threaded_mainloop_lock(pa_mloop); 604 } 605} 606 607static void 608pulse_stream_init(void) 609{ 610 struct pa_sample_spec pa_spec; 611 pa_channel_map pa_chmap; 612 int ret; 613 614 pa_channel_map_init_stereo(&pa_chmap); 615 616 pa_spec.channels = decoder.channels; 617 pa_spec.rate = decoder.rate; 618 pa_spec.format = decoder.format; 619 620 pa_strm = pa_stream_new(pa_ctx, "mplay.flac", &pa_spec, &pa_chmap); 621 if (!pa_strm) die("pa_stream_new: %s", 622 pa_strerror(pa_context_errno(pa_ctx))); 623 624 pa_stream_set_write_callback(pa_strm, pa_stream_write_callback, NULL); 625 626 if (verbose) { 627 pa_stream_set_underflow_callback(pa_strm, 628 pa_stream_underflow_callback, NULL); 629 pa_stream_set_overflow_callback(pa_strm, 630 pa_stream_overflow_callback, NULL); 631 } 632 633 ret = pa_stream_connect_playback(pa_strm, NULL, 634 &pa_buf, pa_stream_flags, NULL, NULL); 635 if (ret) die("pa_stream_connect_playback failed"); 636 637 while (pa_stream_get_state(pa_strm) != PA_STREAM_READY) { 638 pa_threaded_mainloop_unlock(pa_mloop); 639 pa_threaded_mainloop_wait(pa_mloop); 640 pa_threaded_mainloop_lock(pa_mloop); 641 } 642} 643 644static void 645sigint_handler(int sig) 646{ 647 exit(0); 648} 649 650static void 651cleanup(void) 652{ 653 if (term_set) tcsetattr(0, TCSANOW, &term_old); 654 655 pa_stream_disconnect(pa_strm); 656 pa_stream_unref(pa_strm); 657 658 pa_context_disconnect(pa_ctx); 659 pa_context_unref(pa_ctx); 660 661 if (input_worker_alive) 662 pthread_kill(input_worker_thread, SIGINT); 663} 664 665static void 666usage(void) 667{ 668 fprintf(stderr, "Usage: mplay.flac [-v] [" MPLAY_FLAG_HEADLESS "] FILE\n"); 669 exit(1); 670} 671 672int 673main(int argc, const char **argv) 674{ 675 pthread_mutex_t lock; 676 const char **arg; 677 const char *file; 678 679 file = NULL; 680 for (arg = argv + 1; *arg; arg++) { 681 if (!strcmp(*arg, MPLAY_FLAG_HEADLESS)) { 682 headless = true; 683 } else if (!strcmp(*arg, "-v")) { 684 verbose = true; 685 } else { 686 if (file) usage(); 687 file = *arg; 688 } 689 } 690 if (!file) usage(); 691 692 istty = isatty(0); 693 694 decoder_init(file); 695 696 pa_mloop = pa_threaded_mainloop_new(); 697 if (!pa_mloop) die("pa_threaded_mainloop_new"); 698 699 pa_threaded_mainloop_start(pa_mloop); 700 701 pa_threaded_mainloop_lock(pa_mloop); 702 pulse_context_init(); 703 pulse_stream_init(); 704 pa_stream_cork(pa_strm, 0, NULL, NULL); 705 pa_threaded_mainloop_unlock(pa_mloop); 706 707 atexit(cleanup); 708 signal(SIGINT, sigint_handler); 709 710 if (!headless) { 711 if (pthread_create(&input_worker_thread, NULL, input_worker, NULL)) 712 die("pthread_create"); 713 pthread_join(input_worker_thread, NULL); 714 } else { 715 pthread_mutex_init(&lock, NULL); 716 pthread_mutex_lock(&lock); 717 pthread_mutex_lock(&lock); 718 } 719 720 return 0; 721}