A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 1440 lines 40 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2005 by Miika Pekkarinen 11 * Copyright (C) 2011 by Michael Sevakis 12 * 13 * This program is free software; you can redistribute it and/or 14 * modify it under the terms of the GNU General Public License 15 * as published by the Free Software Foundation; either version 2 16 * of the License, or (at your option) any later version. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 ****************************************************************************/ 22#include <stdio.h> 23#include "config.h" 24#include "system.h" 25#include "debug.h" 26#include <kernel.h> 27#include "pcm.h" 28#include "pcm_mixer.h" 29#include "pcmbuf.h" 30#include "dsp-util.h" 31#include "playback.h" 32#include "codec_thread.h" 33 34/* Define LOGF_ENABLE to enable logf output in this file */ 35/*#define LOGF_ENABLE*/ 36#include "logf.h" 37#if (CONFIG_PLATFORM & PLATFORM_NATIVE) 38#include "cpu.h" 39#endif 40#include "settings.h" 41#include "audio.h" 42#include "voice_thread.h" 43 44/* 2 channels * 2 bytes/sample, interleaved */ 45#define PCMBUF_SAMPLE_SIZE (2 * 2) 46 47/* This is the target fill size of chunks on the pcm buffer 48 Can be any number of samples but power of two sizes make for faster and 49 smaller math - must be < 65536 bytes */ 50#define PCMBUF_CHUNK_SIZE 8192u 51 52/* Small guard buf to give decent space near end */ 53#define PCMBUF_GUARD_SIZE (PCMBUF_CHUNK_SIZE / 8) 54 55/* Mnemonics for common data commit thresholds */ 56#define COMMIT_CHUNKS PCMBUF_CHUNK_SIZE 57#define COMMIT_ALL_DATA 1u 58 59/* Size of the crossfade buffer where codec data is written to be faded 60 on commit */ 61#define CROSSFADE_BUFSIZE PCMBUF_CHUNK_SIZE 62 63/* Maximum contiguous space that PCM buffer will allow (to avoid excessive 64 draining between inserts and observe low-latency mode) */ 65#define PCMBUF_MAX_BUFFER (PCMBUF_CHUNK_SIZE * 4) 66 67/* Forced buffer insert constraint can thus be from 1KB to 32KB using 8KB 68 chunks */ 69 70/* Return data level in 1/4-second increments */ 71#define DATA_LEVEL(quarter_secs) (pcmbuf_sampr * (quarter_secs)) 72 73/* Number of bytes played per second */ 74#define BYTERATE (pcmbuf_sampr * PCMBUF_SAMPLE_SIZE) 75 76#if MEMORYSIZE > 2 77/* Keep watermark high for large memory target - at least (2s) */ 78#define PCMBUF_WATERMARK (BYTERATE * 2) 79#define MIN_BUFFER_SIZE (BYTERATE * 3) 80/* 1 seconds of buffer is low data */ 81#define LOW_DATA DATA_LEVEL(4) 82#else 83#define PCMBUF_WATERMARK (BYTERATE / 4) /* 0.25 seconds */ 84#define MIN_BUFFER_SIZE (BYTERATE * 1) 85/* under watermark is low data */ 86#define LOW_DATA pcmbuf_watermark 87#endif 88 89/* Describes each audio packet - keep it small since there are many of them */ 90struct chunkdesc 91{ 92 uint16_t size; /* Actual size (0 < size <= PCMBUF_CHUNK_SIZE) */ 93 uint16_t pos_key; /* Who put the position info in 94 (undefined: 0, valid: 1..POSITION_KEY_MAX) */ 95 unsigned long elapsed; /* Elapsed time to use */ 96 off_t offset; /* Offset to use */ 97}; 98 99#define POSITION_KEY_MAX UINT16_MAX 100 101 102/* General PCM buffer data */ 103#define INVALID_BUF_INDEX ((size_t)0 - (size_t)1) 104 105static void *pcmbuf_buffer; 106static void *pcmbuf_guardbuf; 107static size_t pcmbuf_size; 108static struct chunkdesc *pcmbuf_descriptors; 109static unsigned int pcmbuf_desc_count; 110static unsigned int position_key = 1; 111static unsigned int pcmbuf_sampr = 0; 112 113static size_t chunk_ridx; 114static size_t chunk_widx; 115 116static size_t pcmbuf_bytes_waiting; 117static struct chunkdesc *current_desc; 118static size_t chunk_transidx; 119 120static size_t pcmbuf_watermark = 0; 121 122static bool low_latency_mode = false; 123 124static bool pcmbuf_sync_position = false; 125 126/* Fade effect */ 127static unsigned int fade_vol = MIX_AMP_UNITY; 128static enum 129{ 130 PCM_NOT_FADING = 0, 131 PCM_FADING_IN, 132 PCM_FADING_OUT, 133} fade_state = PCM_NOT_FADING; 134static bool fade_out_complete = false; 135 136/* Voice */ 137static bool soft_mode = false; 138 139#ifdef HAVE_CROSSFADE 140/* Crossfade related state */ 141 142static int crossfade_setting; 143static int crossfade_enable_request; 144 145static enum 146{ 147 CROSSFADE_INACTIVE = 0, /* Crossfade is OFF */ 148 CROSSFADE_ACTIVE, /* Crossfade is fading in */ 149 CROSSFADE_START, /* New crossfade is starting */ 150 CROSSFADE_CONTINUE, /* Next track continues fade */ 151} crossfade_status = CROSSFADE_INACTIVE; 152 153static bool crossfade_mixmode; 154static bool crossfade_auto_skip; 155static size_t crossfade_widx; 156static size_t crossfade_bufidx; 157 158struct mixfader 159{ 160 int32_t factor; /* Current volume factor to use */ 161 int32_t endfac; /* Saturating end factor */ 162 int32_t nsamp2; /* Twice the number of samples */ 163 int32_t dfact2; /* Twice the range of factors */ 164 int32_t ferr; /* Current error accumulator */ 165 int32_t dfquo; /* Quotient of fade range / sample range */ 166 int32_t dfrem; /* Remainder of fade range / sample range */ 167 int32_t dfinc; /* Base increment (-1 or +1) */ 168 bool alloc; /* Allocate blocks if needed else abort at EOB */ 169} crossfade_infader; 170 171/* Defines for operations on position info when mixing/fading - 172 passed in offset parameter */ 173enum 174{ 175 MIXFADE_KEEP_POS = -1, /* Keep position info in chunk */ 176 MIXFADE_NULLIFY_POS = -2, /* Ignore position info in chunk */ 177 /* Positive values cause stamping/restamping */ 178}; 179 180#define MIXFADE_UNITY_BITS 16 181#define MIXFADE_UNITY (1 << MIXFADE_UNITY_BITS) 182 183static void crossfade_cancel(void); 184static void crossfade_start(void); 185static void write_to_crossfade(size_t size, unsigned long elapsed, 186 off_t offset); 187static void pcmbuf_finish_crossfade_enable(void); 188#else 189#define crossfade_cancel() do {} while(0) 190#endif /* HAVE_CROSSFADE */ 191 192/* Thread */ 193#ifdef HAVE_PRIORITY_SCHEDULING 194static int codec_thread_priority = PRIORITY_PLAYBACK; 195#endif 196 197/* Callbacks into playback.c */ 198extern void audio_pcmbuf_position_callback(unsigned long elapsed, 199 off_t offset, unsigned int key); 200extern void audio_pcmbuf_track_change(bool pcmbuf); 201extern bool audio_pcmbuf_may_play(void); 202extern void audio_pcmbuf_sync_position(void); 203 204 205/**************************************/ 206 207/* start PCM if callback says it's alright */ 208static void start_audio_playback(void) 209{ 210 if (audio_pcmbuf_may_play()) 211 pcmbuf_play_start(); 212} 213 214/* Return number of commited bytes in buffer (committed chunks count as 215 a full chunk even if only partially filled) */ 216static size_t pcmbuf_unplayed_bytes(void) 217{ 218 size_t ridx = chunk_ridx; 219 size_t widx = chunk_widx; 220 221 if (ridx > widx) 222 widx += pcmbuf_size; 223 224 return widx - ridx; 225} 226 227/* Returns TRUE if amount of data is under the target fill size */ 228static bool pcmbuf_data_critical(void) 229{ 230 return pcmbuf_unplayed_bytes() < LOW_DATA; 231} 232 233/* Return the next PCM chunk in the PCM buffer given a byte index into it */ 234static size_t index_next(size_t index) 235{ 236 index = ALIGN_DOWN(index + PCMBUF_CHUNK_SIZE, PCMBUF_CHUNK_SIZE); 237 238 if (index >= pcmbuf_size) 239 index -= pcmbuf_size; 240 241 return index; 242} 243 244/* Convert a byte offset in the PCM buffer into a pointer in the buffer */ 245static FORCE_INLINE void * index_buffer(size_t index) 246{ 247 return pcmbuf_buffer + index; 248} 249 250/* Convert a pointer in the buffer into an index offset */ 251static FORCE_INLINE size_t buffer_index(void *p) 252{ 253 return (uintptr_t)p - (uintptr_t)pcmbuf_buffer; 254} 255 256/* Return a chunk descriptor for a byte index in the buffer */ 257static struct chunkdesc * index_chunkdesc(size_t index) 258{ 259 return &pcmbuf_descriptors[index / PCMBUF_CHUNK_SIZE]; 260} 261 262/* Return the first byte of a chunk for a byte index in the buffer, offset by 'offset' 263 chunks */ 264static size_t index_chunk_offs(size_t index, int offset) 265{ 266 int i = index / PCMBUF_CHUNK_SIZE; 267 268 if (offset != 0) 269 { 270 i = (i + offset) % (int)pcmbuf_desc_count; 271 272 /* remainder => modulus */ 273 if (i < 0) 274 i += pcmbuf_desc_count; 275 } 276 277 return i * PCMBUF_CHUNK_SIZE; 278} 279 280/* Test if a buffer index lies within the committed data region */ 281static bool index_committed(size_t index) 282{ 283 if (index == INVALID_BUF_INDEX) 284 return false; 285 286 size_t ridx = chunk_ridx; 287 size_t widx = chunk_widx; 288 289 if (widx < ridx) 290 { 291 widx += pcmbuf_size; 292 293 if (index < ridx) 294 index += pcmbuf_size; 295 } 296 297 return index >= ridx && index < widx; 298} 299 300/* Snip the tail of buffer at chunk of specified index plus chunk offset */ 301void snip_buffer_tail(size_t index, int offset) 302{ 303 /* Call with PCM lockout */ 304 if (index == INVALID_BUF_INDEX) 305 return; 306 307 index = index_chunk_offs(index, offset); 308 309 if (!index_committed(index) && index != chunk_widx) 310 return; 311 312 chunk_widx = index; 313 pcmbuf_bytes_waiting = 0; 314 index_chunkdesc(index)->pos_key = 0; 315 316#ifdef HAVE_CROSSFADE 317 /* Kill crossfade if it would now be operating in the void */ 318 if (crossfade_status != CROSSFADE_INACTIVE && 319 !index_committed(crossfade_widx) && crossfade_widx != chunk_widx) 320 { 321 crossfade_cancel(); 322 } 323#endif /* HAVE_CROSSFADE */ 324} 325 326 327/** Accept new PCM data */ 328 329/* Split the uncommitted data as needed into chunks, stopping when uncommitted 330 data is below the threshold */ 331static void commit_chunks(size_t threshold) 332{ 333 size_t index = chunk_widx; 334 size_t end_index = index + pcmbuf_bytes_waiting; 335 336 /* Copy to the beginning of the buffer all data that must wrap */ 337 if (end_index > pcmbuf_size) 338 memcpy(pcmbuf_buffer, pcmbuf_guardbuf, end_index - pcmbuf_size); 339 340 struct chunkdesc *desc = index_chunkdesc(index); 341 342 do 343 { 344 size_t size = MIN(pcmbuf_bytes_waiting, PCMBUF_CHUNK_SIZE); 345 pcmbuf_bytes_waiting -= size; 346 347 /* Fill in the values in the new buffer chunk */ 348 desc->size = (uint16_t)size; 349 350 /* Advance the current write chunk and make it available to the 351 PCM callback */ 352 chunk_widx = index = index_next(index); 353 desc = index_chunkdesc(index); 354 355 /* Reset it before using it */ 356 desc->pos_key = 0; 357 } 358 while (pcmbuf_bytes_waiting >= threshold); 359} 360 361/* If uncommitted data count is above or equal to the threshold, commit it */ 362static FORCE_INLINE void commit_if_needed(size_t threshold) 363{ 364 if (pcmbuf_bytes_waiting >= threshold) 365 commit_chunks(threshold); 366} 367 368/* Place positioning information in the chunk */ 369static void stamp_chunk(struct chunkdesc *desc, unsigned long elapsed, 370 off_t offset) 371{ 372 /* One-time stamping of a given chunk by the same track - new track may 373 overwrite */ 374 unsigned int key = position_key; 375 376 if (desc->pos_key != key) 377 { 378 desc->pos_key = key; 379 desc->elapsed = elapsed; 380 desc->offset = offset; 381 } 382} 383 384/* Set priority of the codec thread */ 385#ifdef HAVE_PRIORITY_SCHEDULING 386/* 387 * expects pcm_fill_state in tenth-% units (e.g. full pcm buffer is 10) */ 388static void boost_codec_thread(int pcm_fill_state) 389{ 390 static const int8_t prios[11] = 391 { 392 PRIORITY_PLAYBACK_MAX, /* 0 - 10% */ 393 PRIORITY_PLAYBACK_MAX+1, /* 10 - 20% */ 394 PRIORITY_PLAYBACK_MAX+3, /* 20 - 30% */ 395 PRIORITY_PLAYBACK_MAX+5, /* 30 - 40% */ 396 PRIORITY_PLAYBACK_MAX+7, /* 40 - 50% */ 397 PRIORITY_PLAYBACK_MAX+8, /* 50 - 60% */ 398 PRIORITY_PLAYBACK_MAX+9, /* 60 - 70% */ 399 /* raising priority above 70% shouldn't be needed */ 400 PRIORITY_PLAYBACK, /* 70 - 80% */ 401 PRIORITY_PLAYBACK, /* 80 - 90% */ 402 PRIORITY_PLAYBACK, /* 90 -100% */ 403 PRIORITY_PLAYBACK, /* 100% */ 404 }; 405 406 int new_prio = prios[pcm_fill_state]; 407 408 /* Keep voice and codec threads at the same priority or else voice 409 * will starve if the codec thread's priority is boosted. */ 410 if (new_prio != codec_thread_priority) 411 { 412 codec_thread_set_priority(new_prio); 413 voice_thread_set_priority(new_prio); 414 codec_thread_priority = new_prio; 415 } 416} 417#else 418#define boost_codec_thread(pcm_fill_state) do{}while(0) 419#endif /* HAVE_PRIORITY_SCHEDULING */ 420 421/* Get the next available buffer and size - assumes adequate space exists */ 422static void * get_write_buffer(size_t *size) 423{ 424 /* Obtain current chunk fill address */ 425 size_t index = chunk_widx + pcmbuf_bytes_waiting; 426 size_t index_end = pcmbuf_size + PCMBUF_GUARD_SIZE; 427 428 /* Get count to the end of the buffer where a wrap will happen + 429 the guard */ 430 size_t endsize = index_end - index; 431 432 /* Return available unwrapped space */ 433 *size = MIN(*size, endsize); 434 435 return index_buffer(index); 436} 437 438/* Commit outstanding data leaving less than a chunk size remaining */ 439static void commit_write_buffer(size_t size) 440{ 441 /* Add this data and commit if one or more chunks are ready */ 442 pcmbuf_bytes_waiting += size; 443 commit_if_needed(COMMIT_CHUNKS); 444} 445 446/* Request space in the buffer for writing output samples */ 447void * pcmbuf_request_buffer(int *count) 448{ 449 size_t size = *count * PCMBUF_SAMPLE_SIZE; 450 451#ifdef HAVE_CROSSFADE 452 /* We're going to crossfade to a new track, which is now on its way */ 453 if (crossfade_status > CROSSFADE_ACTIVE) 454 crossfade_start(); 455 456 /* If crossfade has begun, put the new track samples in the crossfade 457 buffer area */ 458 if (crossfade_status != CROSSFADE_INACTIVE && size > CROSSFADE_BUFSIZE) 459 size = CROSSFADE_BUFSIZE; 460 else 461#endif /* HAVE_CROSSFADE */ 462 if (size > PCMBUF_MAX_BUFFER) 463 size = PCMBUF_MAX_BUFFER; /* constrain request */ 464 465 enum channel_status status = mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK); 466 size_t remaining = pcmbuf_unplayed_bytes(); 467 468 /* Need to have length bytes to prevent wrapping overwriting - leave one 469 descriptor free to guard so that 0 != full in ring buffer */ 470 size_t freespace = pcmbuf_free(); 471 472 if (pcmbuf_sync_position) 473 audio_pcmbuf_sync_position(); 474 475 if (freespace < size + PCMBUF_CHUNK_SIZE) 476 return NULL; 477 478 /* Maintain the buffer level above the watermark */ 479 if (status != CHANNEL_STOPPED) 480 { 481 if (low_latency_mode) 482 { 483 /* 1/4s latency. */ 484 if (remaining > DATA_LEVEL(1)) 485 return NULL; 486 } 487 488 /* Boost CPU if necessary */ 489 size_t realrem = pcmbuf_size - freespace; 490 491 if (realrem < pcmbuf_watermark) 492 trigger_cpu_boost(); 493 494 boost_codec_thread(realrem*10 / pcmbuf_size); 495 } 496 else /* !playing */ 497 { 498 /* Boost CPU for pre-buffer */ 499 trigger_cpu_boost(); 500 501 /* If pre-buffered to the watermark, start playback */ 502 if (!pcmbuf_data_critical()) 503 start_audio_playback(); 504 } 505 506 void *buf; 507 508#ifdef HAVE_CROSSFADE 509 if (crossfade_status != CROSSFADE_INACTIVE) 510 { 511 crossfade_bufidx = index_chunk_offs(chunk_ridx, -1); 512 buf = index_buffer(crossfade_bufidx); /* always CROSSFADE_BUFSIZE */ 513 } 514 else 515#endif 516 { 517 /* Give the maximum amount available if there's more */ 518 if (size + PCMBUF_CHUNK_SIZE < freespace) 519 size = freespace - PCMBUF_CHUNK_SIZE; 520 521 buf = get_write_buffer(&size); 522 } 523 524 *count = size / PCMBUF_SAMPLE_SIZE; 525 return buf; 526} 527 528/* Handle new samples to the buffer */ 529void pcmbuf_write_complete(int count, unsigned long elapsed, off_t offset) 530{ 531 size_t size = count * PCMBUF_SAMPLE_SIZE; 532 533#ifdef HAVE_CROSSFADE 534 if (crossfade_status != CROSSFADE_INACTIVE) 535 { 536 write_to_crossfade(size, elapsed, offset); 537 } 538 else 539#endif 540 { 541 stamp_chunk(index_chunkdesc(chunk_widx), elapsed, offset); 542 commit_write_buffer(size); 543 } 544 545 /* Revert to position updates by PCM */ 546 pcmbuf_sync_position = false; 547} 548 549 550/** Init */ 551static unsigned int get_next_required_pcmbuf_chunks(void) 552{ 553 size_t size = MIN_BUFFER_SIZE; 554 555#ifdef HAVE_CROSSFADE 556 if (crossfade_enable_request != CROSSFADE_ENABLE_OFF) 557 { 558 size_t seconds = global_settings.crossfade_fade_out_delay + 559 global_settings.crossfade_fade_out_duration; 560 size += seconds * BYTERATE; 561 } 562#endif 563 564 logf("pcmbuf len: %lu", (unsigned long)(size / BYTERATE)); 565 return size / PCMBUF_CHUNK_SIZE; 566} 567 568/* Initialize the ringbuffer state */ 569static void init_buffer_state(void) 570{ 571 /* Reset counters */ 572 chunk_ridx = chunk_widx = 0; 573 pcmbuf_bytes_waiting = 0; 574 575 /* Reset first descriptor */ 576 if (pcmbuf_descriptors) 577 pcmbuf_descriptors->pos_key = 0; 578 579 /* Clear change notification */ 580 chunk_transidx = INVALID_BUF_INDEX; 581} 582 583/* call prior to init to get bytes required */ 584size_t pcmbuf_size_reqd(void) 585{ 586 return get_next_required_pcmbuf_chunks() * PCMBUF_CHUNK_SIZE; 587} 588 589/* Initialize the PCM buffer. The structure looks like this: 590 * ...|---------PCMBUF---------|GUARDBUF|DESCS| */ 591size_t pcmbuf_init(void *bufend) 592{ 593 void *bufstart; 594 595 /* Set up the buffers */ 596 pcmbuf_desc_count = get_next_required_pcmbuf_chunks(); 597 pcmbuf_size = pcmbuf_desc_count * PCMBUF_CHUNK_SIZE; 598 pcmbuf_descriptors = (struct chunkdesc *)bufend - pcmbuf_desc_count; 599 600 pcmbuf_buffer = (void *)pcmbuf_descriptors - 601 pcmbuf_size - PCMBUF_GUARD_SIZE; 602 603 /* Mem-align buffer chunks for more efficient handling in lower layers */ 604 pcmbuf_buffer = ALIGN_DOWN(pcmbuf_buffer, (uintptr_t)MEM_ALIGN_SIZE); 605 606 pcmbuf_guardbuf = pcmbuf_buffer + pcmbuf_size; 607 bufstart = pcmbuf_buffer; 608 609#ifdef HAVE_CROSSFADE 610 pcmbuf_finish_crossfade_enable(); 611#else 612 pcmbuf_watermark = PCMBUF_WATERMARK; 613#endif /* HAVE_CROSSFADE */ 614 615 init_buffer_state(); 616 617 pcmbuf_soft_mode(false); 618 619 return bufend - bufstart; 620} 621 622 623/** Track change */ 624 625/* Place a track change notification in a specific descriptor or post it 626 immediately if the buffer is empty or the index is invalid */ 627static void pcmbuf_monitor_track_change_ex(size_t index) 628{ 629 /* Call with PCM lockout */ 630 if (chunk_ridx != chunk_widx && index != INVALID_BUF_INDEX) 631 { 632 /* If monitoring, set flag for one previous to specified chunk */ 633 index = index_chunk_offs(index, -1); 634 635 /* Ensure PCM playback hasn't already played this out */ 636 if (index_committed(index)) 637 { 638 chunk_transidx = index; 639 return; 640 } 641 } 642 643 /* Post now if buffer is no longer coming up */ 644 chunk_transidx = INVALID_BUF_INDEX; 645 audio_pcmbuf_track_change(false); 646} 647 648/* Clear end of track and optionally the positioning info for all data */ 649static void pcmbuf_cancel_track_change(bool position) 650{ 651 /* Call with PCM lockout */ 652 snip_buffer_tail(chunk_transidx, 1); 653 654 chunk_transidx = INVALID_BUF_INDEX; 655 656 if (!position) 657 return; 658 659 size_t index = chunk_ridx; 660 661 while (1) 662 { 663 index_chunkdesc(index)->pos_key = 0; 664 665 if (index == chunk_widx) 666 break; 667 668 index = index_next(index); 669 } 670} 671 672/* Place a track change notification at the end of the buffer or post it 673 immediately if the buffer is empty */ 674void pcmbuf_monitor_track_change(bool monitor) 675{ 676 pcm_play_lock(); 677 678 if (monitor) 679 pcmbuf_monitor_track_change_ex(chunk_widx); 680 else 681 pcmbuf_cancel_track_change(false); 682 683 pcm_play_unlock(); 684} 685 686void pcmbuf_start_track_change(enum pcm_track_change_type type) 687{ 688 /* Commit all outstanding data before starting next track - tracks don't 689 comingle inside a single buffer chunk */ 690 commit_if_needed(COMMIT_ALL_DATA); 691 692 if (type == TRACK_CHANGE_AUTO_PILEUP) 693 { 694 /* Fill might not have been above watermark */ 695 start_audio_playback(); 696 return; 697 } 698 699#ifdef HAVE_CROSSFADE 700 bool crossfade = false; 701#endif 702 bool auto_skip = type != TRACK_CHANGE_MANUAL; 703 704 /* Update position key so that: 705 1) Positions are keyed to the track to which they belong for sync 706 purposes 707 708 2) Buffers stamped with the outgoing track's positions are restamped 709 to the incoming track's positions when crossfading 710 */ 711 if (++position_key > POSITION_KEY_MAX) 712 position_key = 1; 713 714 if (type == TRACK_CHANGE_END_OF_DATA) 715 { 716 crossfade_cancel(); 717 718 /* Fill might not have been above watermark */ 719 start_audio_playback(); 720 } 721#ifdef HAVE_CROSSFADE 722 /* Determine whether this track change needs to crossfaded and how */ 723 else if (crossfade_setting != CROSSFADE_ENABLE_OFF) 724 { 725 if (crossfade_status == CROSSFADE_INACTIVE && 726 pcmbuf_unplayed_bytes() >= DATA_LEVEL(2) && 727 !low_latency_mode) 728 { 729 switch (crossfade_setting) 730 { 731 case CROSSFADE_ENABLE_AUTOSKIP: 732 crossfade = auto_skip; 733 break; 734 case CROSSFADE_ENABLE_MANSKIP: 735 crossfade = !auto_skip; 736 break; 737 case CROSSFADE_ENABLE_SHUFFLE: 738 crossfade = global_settings.playlist_shuffle; 739 break; 740 case CROSSFADE_ENABLE_SHUFFLE_OR_MANSKIP: 741 crossfade = global_settings.playlist_shuffle || !auto_skip; 742 break; 743 case CROSSFADE_ENABLE_ALWAYS: 744 crossfade = true; 745 break; 746 } 747 } 748 } 749 750 if (crossfade) 751 { 752 logf("crossfade track change"); 753 754 /* Don't enable mix mode when skipping tracks manually */ 755 crossfade_mixmode = auto_skip && 756 global_settings.crossfade_fade_out_mixmode; 757 758 crossfade_auto_skip = auto_skip; 759 760 crossfade_status = CROSSFADE_START; 761 762 pcmbuf_monitor_track_change(auto_skip); 763 764 trigger_cpu_boost(); 765 } 766 else 767#endif /* HAVE_CROSSFADE */ 768 if (auto_skip) 769 { 770 /* The codec is moving on to the next track, but the current track will 771 * continue to play, so mark the last write chunk as the last one in 772 * the track */ 773 logf("gapless track change"); 774 775#ifdef HAVE_CROSSFADE 776 if (crossfade_status == CROSSFADE_ACTIVE) 777 crossfade_status = CROSSFADE_CONTINUE; 778#endif 779 780 pcmbuf_monitor_track_change(true); 781 } 782 else 783 { 784 /* Discard old data; caller needs no transition notification */ 785 logf("manual track change"); 786 pcmbuf_play_stop(); 787 } 788} 789 790 791/** Playback */ 792 793/* PCM driver callback */ 794static void pcmbuf_pcm_callback(const void **start, size_t *size) 795{ 796 /*- Process the chunk that just finished -*/ 797 size_t index = chunk_ridx; 798 struct chunkdesc *desc = current_desc; 799 800 if (desc) 801 { 802 /* If last chunk in the track, notify of track change */ 803 if (index == chunk_transidx) 804 { 805 chunk_transidx = INVALID_BUF_INDEX; 806 audio_pcmbuf_track_change(true); 807 } 808 809 /* Free it for reuse */ 810 chunk_ridx = index = index_next(index); 811 } 812 813 /*- Process the new one -*/ 814 if (index != chunk_widx && !fade_out_complete) 815 { 816 current_desc = desc = index_chunkdesc(index); 817 818 *start = index_buffer(index); 819 *size = desc->size; 820 821 if (desc->pos_key != 0) 822 { 823 /* Positioning chunk - notify playback */ 824 audio_pcmbuf_position_callback(desc->elapsed, desc->offset, 825 desc->pos_key); 826 } 827 } 828} 829 830/* Force playback */ 831void pcmbuf_play_start(void) 832{ 833 logf("pcmbuf_play_start"); 834 835 if (mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK) == CHANNEL_STOPPED && 836 chunk_widx != chunk_ridx) 837 { 838 current_desc = NULL; 839 mixer_channel_play_data(PCM_MIXER_CHAN_PLAYBACK, pcmbuf_pcm_callback, 840 NULL, 0); 841 } 842} 843 844/* Stop channel, empty and reset buffer */ 845void pcmbuf_play_stop(void) 846{ 847 logf("pcmbuf_play_stop"); 848 849 /* Reset channel */ 850 mixer_channel_stop(PCM_MIXER_CHAN_PLAYBACK); 851 852 /* Reset buffer */ 853 init_buffer_state(); 854 855 /* Revert to position updates by PCM */ 856 pcmbuf_sync_position = false; 857 858 /* Fader OFF */ 859 crossfade_cancel(); 860 861 /* Can unboost the codec thread here no matter who's calling, 862 * pretend full pcm buffer to unboost */ 863 boost_codec_thread(10); 864} 865 866void pcmbuf_pause(bool pause) 867{ 868 logf("pcmbuf_pause: %s", pause?"pause":"play"); 869 870 if (mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK) != CHANNEL_STOPPED) 871 mixer_channel_play_pause(PCM_MIXER_CHAN_PLAYBACK, !pause); 872 else if (!pause) 873 pcmbuf_play_start(); 874} 875 876 877/** Crossfade */ 878 879#ifdef HAVE_CROSSFADE 880 881/* Initialize a fader */ 882static void mixfader_init(struct mixfader *faderp, int32_t start_factor, 883 int32_t end_factor, size_t size, bool alloc) 884{ 885 /* Linear fade */ 886 faderp->endfac = end_factor; 887 faderp->nsamp2 = size / PCMBUF_SAMPLE_SIZE * 2; 888 faderp->alloc = alloc; 889 890 if (faderp->nsamp2 == 0) 891 { 892 /* No data; set up as if fader finished the fade */ 893 faderp->factor = end_factor; 894 return; 895 } 896 897 int32_t dfact2 = 2*abs(end_factor - start_factor); 898 faderp->factor = start_factor; 899 faderp->ferr = dfact2 / 2; 900 faderp->dfquo = dfact2 / faderp->nsamp2; 901 faderp->dfrem = dfact2 - faderp->dfquo*faderp->nsamp2; 902 faderp->dfinc = end_factor < start_factor ? -1 : +1; 903 faderp->dfquo *= faderp->dfinc; 904} 905 906/* Query if the fader has finished its envelope */ 907static inline bool mixfader_finished(const struct mixfader *faderp) 908{ 909 return faderp->factor == faderp->endfac; 910} 911 912/* Step fader by one sample */ 913static inline void mixfader_step(struct mixfader *faderp) 914{ 915 if (mixfader_finished(faderp)) 916 return; 917 918 faderp->factor += faderp->dfquo; 919 faderp->ferr += faderp->dfrem; 920 921 if (faderp->ferr >= faderp->nsamp2) 922 { 923 faderp->factor += faderp->dfinc; 924 faderp->ferr -= faderp->nsamp2; 925 } 926} 927 928static FORCE_INLINE int32_t mixfade_sample(const struct mixfader *faderp, int32_t s) 929{ 930 return (faderp->factor * s + MIXFADE_UNITY/2) >> MIXFADE_UNITY_BITS; 931} 932 933/* Cancel crossfade operation */ 934static void crossfade_cancel(void) 935{ 936 crossfade_status = CROSSFADE_INACTIVE; 937 crossfade_widx = INVALID_BUF_INDEX; 938} 939 940/* Find the buffer index that's 'size' bytes away from 'index' */ 941static size_t crossfade_find_index(size_t index, size_t size) 942{ 943 if (index != INVALID_BUF_INDEX) 944 { 945 size_t i = index_chunk_offs(index, 0); 946 size += index - i; 947 948 while (i != chunk_widx) 949 { 950 size_t desc_size = index_chunkdesc(i)->size; 951 952 if (size < desc_size) 953 { 954 index = i + size; 955 break; 956 } 957 958 size -= desc_size; 959 i = index_next(i); 960 } 961 } 962 963 return index; 964} 965 966/* Align the needed buffer area up to the end of existing data */ 967static size_t crossfade_find_buftail(bool auto_skip, size_t buffer_rem, 968 size_t buffer_need, size_t *buffer_rem_outp) 969{ 970 size_t index = chunk_ridx; 971 972 if (buffer_rem > buffer_need) 973 { 974 size_t distance; 975 976 if (auto_skip) 977 { 978 /* Automatic track changes only modify the last part of the buffer, 979 * so find the right chunk and sample to start the crossfade */ 980 distance = buffer_rem - buffer_need; 981 buffer_rem = buffer_need; 982 } 983 else 984 { 985 /* Manual skips occur immediately, but give 1/5s to process */ 986 distance = MIN(BYTERATE / 5, buffer_rem); 987 buffer_rem -= distance; 988 } 989 990 index = crossfade_find_index(index, distance); 991 } 992 993 if (buffer_rem_outp) 994 *buffer_rem_outp = buffer_rem; 995 996 return index; 997} 998 999/* Run a fader on some buffers */ 1000static void crossfade_mix_fade(struct mixfader *faderp, size_t size, 1001 void *input_buf, size_t *out_index, 1002 unsigned long elapsed, off_t offset) 1003{ 1004 if (size == 0) 1005 return; 1006 1007 size_t index = *out_index; 1008 1009 if (index == INVALID_BUF_INDEX) 1010 return; 1011 1012 int16_t *inbuf = input_buf; 1013 1014 bool alloced = inbuf && faderp->alloc && 1015 index_chunk_offs(index, 0) == chunk_widx; 1016 1017 while (size) 1018 { 1019 struct chunkdesc *desc = index_chunkdesc(index); 1020 int16_t *outbuf = index_buffer(index); 1021 1022 switch (offset) 1023 { 1024 case MIXFADE_NULLIFY_POS: 1025 /* Stop position updates for the chunk */ 1026 desc->pos_key = 0; 1027 break; 1028 case MIXFADE_KEEP_POS: 1029 /* Keep position info as it is */ 1030 break; 1031 default: 1032 /* Replace position info */ 1033 stamp_chunk(desc, elapsed, offset); 1034 } 1035 1036 size_t amount = (alloced ? PCMBUF_CHUNK_SIZE : desc->size) 1037 - (index % PCMBUF_CHUNK_SIZE); 1038 int16_t *chunkend = SKIPBYTES(outbuf, amount); 1039 1040 if (size < amount) 1041 amount = size; 1042 1043 size -= amount; 1044 1045 if (alloced) 1046 { 1047 /* Fade the input buffer into the new destination chunk */ 1048 for (size_t s = amount; s != 0; s -= PCMBUF_SAMPLE_SIZE) 1049 { 1050 *outbuf++ = mixfade_sample(faderp, *inbuf++); 1051 *outbuf++ = mixfade_sample(faderp, *inbuf++); 1052 mixfader_step(faderp); 1053 } 1054 1055 commit_write_buffer(amount); 1056 } 1057 else if (inbuf) 1058 { 1059 /* Fade the input buffer and mix into the destination chunk */ 1060 for (size_t s = amount; s != 0; s -= PCMBUF_SAMPLE_SIZE) 1061 { 1062 int32_t left = outbuf[0]; 1063 int32_t right = outbuf[1]; 1064 left += mixfade_sample(faderp, *inbuf++); 1065 right += mixfade_sample(faderp, *inbuf++); 1066 *outbuf++ = clip_sample_16(left); 1067 *outbuf++ = clip_sample_16(right); 1068 mixfader_step(faderp); 1069 } 1070 } 1071 else 1072 { 1073 /* Fade the chunk in place */ 1074 for (size_t s = amount; s != 0; s -= PCMBUF_SAMPLE_SIZE) 1075 { 1076 int32_t left = outbuf[0]; 1077 int32_t right = outbuf[1]; 1078 *outbuf++ = mixfade_sample(faderp, left); 1079 *outbuf++ = mixfade_sample(faderp, right); 1080 mixfader_step(faderp); 1081 } 1082 } 1083 1084 if (outbuf < chunkend) 1085 { 1086 index += amount; 1087 continue; 1088 } 1089 1090 /* Move destination to next chunk as needed */ 1091 index = index_next(index); 1092 1093 if (index == chunk_widx) 1094 { 1095 /* End of existing data */ 1096 if (!inbuf || !faderp->alloc) 1097 { 1098 index = INVALID_BUF_INDEX; 1099 break; 1100 } 1101 1102 alloced = true; 1103 } 1104 } 1105 1106 *out_index = index; 1107} 1108 1109/* Initializes crossfader, calculates all necessary parameters and performs 1110 * fade-out with the PCM buffer. */ 1111static void crossfade_start(void) 1112{ 1113 logf("crossfade_start"); 1114 1115 pcm_play_lock(); 1116 1117 if (crossfade_status == CROSSFADE_CONTINUE) 1118 { 1119 logf("fade-in continuing"); 1120 1121 crossfade_status = CROSSFADE_ACTIVE; 1122 1123 if (crossfade_auto_skip) 1124 pcmbuf_monitor_track_change_ex(crossfade_widx); 1125 1126 pcm_play_unlock(); 1127 return; 1128 } 1129 1130 /* Initialize the crossfade buffer size to all of the buffered data that 1131 * has not yet been sent to the DMA */ 1132 size_t unplayed = pcmbuf_unplayed_bytes(); 1133 1134 /* Reject crossfade if less than .5s of data */ 1135 if (unplayed < DATA_LEVEL(2)) 1136 { 1137 logf("crossfade rejected"); 1138 crossfade_cancel(); 1139 pcm_play_unlock(); 1140 return; 1141 } 1142 1143 /* Fading will happen */ 1144 crossfade_status = CROSSFADE_ACTIVE; 1145 1146 /* Get fade info from settings. */ 1147 size_t fade_out_delay = global_settings.crossfade_fade_out_delay * BYTERATE; 1148 size_t fade_out_rem = global_settings.crossfade_fade_out_duration * BYTERATE; 1149 size_t fade_in_delay = global_settings.crossfade_fade_in_delay * BYTERATE; 1150 size_t fade_in_duration = global_settings.crossfade_fade_in_duration * BYTERATE; 1151 1152 if (!crossfade_auto_skip) 1153 { 1154 /* Forego fade-in delay on manual skip - do the best to preserve auto skip 1155 relationship */ 1156 fade_out_delay -= MIN(fade_out_delay, fade_in_delay); 1157 fade_in_delay = 0; 1158 } 1159 1160 size_t fade_out_need = fade_out_delay + fade_out_rem; 1161 1162 if (!crossfade_mixmode) 1163 { 1164 /* Completely process the crossfade fade-out effect with current PCM buffer */ 1165 size_t buffer_rem; 1166 size_t index = crossfade_find_buftail(crossfade_auto_skip, unplayed, 1167 fade_out_need, &buffer_rem); 1168 1169 pcm_play_unlock(); 1170 1171 if (buffer_rem < fade_out_need) 1172 { 1173 /* Existing buffers are short */ 1174 size_t fade_out_short = fade_out_need - buffer_rem; 1175 1176 if (fade_out_delay >= fade_out_short) 1177 { 1178 /* Truncate fade-out delay */ 1179 fade_out_delay -= fade_out_short; 1180 } 1181 else 1182 { 1183 /* Truncate fade-out and eliminate fade-out delay */ 1184 fade_out_rem = buffer_rem; 1185 fade_out_delay = 0; 1186 } 1187 1188 fade_out_need = fade_out_delay + fade_out_rem; 1189 } 1190 1191 /* Find the right chunk and sample to start fading out */ 1192 index = crossfade_find_index(index, fade_out_delay); 1193 1194 /* Fade out the specified amount of the already processed audio */ 1195 struct mixfader outfader; 1196 1197 mixfader_init(&outfader, MIXFADE_UNITY, 0, fade_out_rem, false); 1198 crossfade_mix_fade(&outfader, fade_out_rem, NULL, &index, 0, 1199 MIXFADE_KEEP_POS); 1200 1201 /* Zero-out the rest of the buffer */ 1202 crossfade_mix_fade(&outfader, pcmbuf_size, NULL, &index, 0, 1203 MIXFADE_NULLIFY_POS); 1204 1205 pcm_play_lock(); 1206 } 1207 1208 /* Initialize fade-in counters */ 1209 mixfader_init(&crossfade_infader, 0, MIXFADE_UNITY, fade_in_duration, true); 1210 1211 /* Find the right chunk and sample to start fading in - redo from read 1212 chunk in case original position were/was overrun in callback - the 1213 track change event _must not_ ever fail to happen */ 1214 unplayed = pcmbuf_unplayed_bytes() + fade_in_delay; 1215 1216 crossfade_widx = crossfade_find_buftail(crossfade_auto_skip, unplayed, 1217 fade_out_need, NULL); 1218 1219 /* Move track transistion to chunk before the first one of incoming track */ 1220 if (crossfade_auto_skip) 1221 pcmbuf_monitor_track_change_ex(crossfade_widx); 1222 1223 pcm_play_unlock(); 1224 1225 logf("crossfade_start done!"); 1226} 1227 1228/* Perform fade-in of new track */ 1229static void write_to_crossfade(size_t size, unsigned long elapsed, off_t offset) 1230{ 1231 /* Mix the data */ 1232 crossfade_mix_fade(&crossfade_infader, size, index_buffer(crossfade_bufidx), 1233 &crossfade_widx, elapsed, offset); 1234 1235 /* If no more fading-in to do, stop the crossfade */ 1236 if (mixfader_finished(&crossfade_infader) && 1237 index_chunk_offs(crossfade_widx, 0) == chunk_widx) 1238 { 1239 crossfade_cancel(); 1240 } 1241} 1242 1243static void pcmbuf_finish_crossfade_enable(void) 1244{ 1245 /* Copy the pending setting over now */ 1246 crossfade_setting = crossfade_enable_request; 1247 1248 pcmbuf_watermark = (crossfade_setting != CROSSFADE_ENABLE_OFF && pcmbuf_size) ? 1249 /* If crossfading, try to keep the buffer full other than 1 second */ 1250 (pcmbuf_size - BYTERATE) : 1251 /* Otherwise, just use the default */ 1252 PCMBUF_WATERMARK; 1253} 1254 1255void pcmbuf_request_crossfade_enable(int setting) 1256{ 1257 /* Next setting to be used, not applied now */ 1258 crossfade_enable_request = setting; 1259} 1260 1261bool pcmbuf_is_same_size(void) 1262{ 1263 /* if pcmbuf_buffer is NULL, then not set up yet even once so always */ 1264 bool same_size = pcmbuf_buffer ? 1265 (get_next_required_pcmbuf_chunks() == pcmbuf_desc_count) : true; 1266 1267 /* no buffer change needed, so finish crossfade setup now */ 1268 if (same_size) 1269 pcmbuf_finish_crossfade_enable(); 1270 1271 return same_size; 1272} 1273#endif /* HAVE_CROSSFADE */ 1274 1275 1276/** Debug menu, other metrics */ 1277 1278/* Amount of bytes left in the buffer, accounting for uncommitted bytes */ 1279size_t pcmbuf_free(void) 1280{ 1281 return pcmbuf_size - pcmbuf_unplayed_bytes() - pcmbuf_bytes_waiting; 1282} 1283 1284/* Data bytes allocated for buffer */ 1285size_t pcmbuf_get_bufsize(void) 1286{ 1287 return pcmbuf_size; 1288} 1289 1290/* Number of committed descriptors */ 1291int pcmbuf_used_descs(void) 1292{ 1293 return pcmbuf_unplayed_bytes() / PCMBUF_CHUNK_SIZE; 1294} 1295 1296/* Total number of descriptors allocated */ 1297int pcmbuf_descs(void) 1298{ 1299 return pcmbuf_desc_count; 1300} 1301 1302 1303/** Fading and channel volume control */ 1304 1305/* Sync the channel amplitude to all states */ 1306static void pcmbuf_update_volume(void) 1307{ 1308 unsigned int vol = fade_vol; 1309 1310 if (soft_mode) 1311 vol >>= 2; 1312 1313 mixer_channel_set_amplitude(PCM_MIXER_CHAN_PLAYBACK, vol); 1314} 1315 1316/* Tick that does the fade for the playback channel */ 1317static void pcmbuf_fade_tick(void) 1318{ 1319 /* ~1/3 second for full range fade */ 1320 const unsigned int fade_step = MIX_AMP_UNITY / (HZ / 3); 1321 1322 if (fade_state == PCM_FADING_IN) 1323 fade_vol += MIN(fade_step, MIX_AMP_UNITY - fade_vol); 1324 else if (fade_state == PCM_FADING_OUT) 1325 fade_vol -= MIN(fade_step, fade_vol - MIX_AMP_MUTE); 1326 1327 pcmbuf_update_volume(); 1328 1329 if (fade_vol == MIX_AMP_MUTE || fade_vol == MIX_AMP_UNITY) 1330 { 1331 /* Fade is complete */ 1332 tick_remove_task(pcmbuf_fade_tick); 1333 if (fade_state == PCM_FADING_OUT) 1334 { 1335 /* Tell PCM to stop at its earliest convenience */ 1336 fade_out_complete = true; 1337 } 1338 1339 fade_state = PCM_NOT_FADING; 1340 } 1341} 1342 1343/* Fade channel in or out in the background */ 1344void pcmbuf_fade(bool fade, bool in) 1345{ 1346 /* Must pause any active fade */ 1347 pcm_play_lock(); 1348 1349 if (fade_state != PCM_NOT_FADING) 1350 tick_remove_task(pcmbuf_fade_tick); 1351 1352 fade_out_complete = false; 1353 1354 pcm_play_unlock(); 1355 1356 if (!fade) 1357 { 1358 /* Simply set the level */ 1359 fade_state = PCM_NOT_FADING; 1360 fade_vol = in ? MIX_AMP_UNITY : MIX_AMP_MUTE; 1361 pcmbuf_update_volume(); 1362 } 1363 else 1364 { 1365 /* Set direction and resume fade from current point */ 1366 fade_state = in ? PCM_FADING_IN : PCM_FADING_OUT; 1367 tick_add_task(pcmbuf_fade_tick); 1368 } 1369} 1370 1371/* Return 'true' if fade is in progress */ 1372bool pcmbuf_fading(void) 1373{ 1374 return fade_state != PCM_NOT_FADING; 1375} 1376 1377/* Quiet-down the channel if 'shhh' is true or else play at normal level */ 1378void pcmbuf_soft_mode(bool shhh) 1379{ 1380 /* Have to block the tick or improper order could leave volume in soft 1381 mode if fading reads the old value first but updates after us. */ 1382 int res = fade_state != PCM_NOT_FADING ? 1383 tick_remove_task(pcmbuf_fade_tick) : -1; 1384 1385 soft_mode = shhh; 1386 pcmbuf_update_volume(); 1387 1388 if (res == 0) 1389 tick_add_task(pcmbuf_fade_tick); 1390} 1391 1392 1393/** Time and position */ 1394 1395/* Return the current position key value */ 1396unsigned int pcmbuf_get_position_key(void) 1397{ 1398 return position_key; 1399} 1400 1401/* Set position updates to be synchronous and immediate in addition to during 1402 PCM frames - cancelled upon first codec insert or upon stopping */ 1403void pcmbuf_sync_position_update(void) 1404{ 1405 pcmbuf_sync_position = true; 1406} 1407 1408 1409 1410/** Misc */ 1411 1412bool pcmbuf_is_lowdata(void) 1413{ 1414 enum channel_status status = mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK); 1415 1416 if (status != CHANNEL_PLAYING) 1417 return false; 1418 1419#ifdef HAVE_CROSSFADE 1420 if (crossfade_status != CROSSFADE_INACTIVE) 1421 return false; 1422#endif 1423 1424 return pcmbuf_data_critical(); 1425} 1426 1427void pcmbuf_set_low_latency(bool state) 1428{ 1429 low_latency_mode = state; 1430} 1431 1432void pcmbuf_update_frequency(void) 1433{ 1434 pcmbuf_sampr = mixer_get_frequency(); 1435} 1436 1437unsigned int pcmbuf_get_frequency(void) 1438{ 1439 return pcmbuf_sampr; 1440}