A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 615 lines 18 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2007 Michael Sevakis 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation; either version 2 15 * of the License, or (at your option) any later version. 16 * 17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 * KIND, either express or implied. 19 * 20 ****************************************************************************/ 21 22#include "config.h" 23#include "system.h" 24#include "kernel.h" 25#include "core_alloc.h" 26#include "thread.h" 27#include "appevents.h" 28#include "voice_thread.h" 29#include "talk.h" 30#include "dsp_core.h" 31#include "pcm.h" 32#include "pcm_mixer.h" 33#include "codecs/libspeex/speex/speex.h" 34#include "settings.h" 35 36/* Default number of PCM frames to queue - adjust as necessary per-target */ 37#define VOICE_FRAMES 4 38 39/* Define any of these as "1" and uncomment the LOGF_ENABLE line to log 40 regular and/or timeout messages */ 41#define VOICE_LOGQUEUES 0 42#define VOICE_LOGQUEUES_SYS_TIMEOUT 0 43 44/*#define LOGF_ENABLE*/ 45#include "logf.h" 46 47#if VOICE_LOGQUEUES 48#define LOGFQUEUE logf 49#else 50#define LOGFQUEUE(...) 51#endif 52 53#if VOICE_LOGQUEUES_SYS_TIMEOUT 54#define LOGFQUEUE_SYS_TIMEOUT logf 55#else 56#define LOGFQUEUE_SYS_TIMEOUT(...) 57#endif 58 59#ifndef IBSS_ATTR_VOICE_STACK 60#define IBSS_ATTR_VOICE_STACK IBSS_ATTR 61#endif 62 63/* Minimum priority needs to be a bit elevated since voice has fairly low 64 latency */ 65#define PRIORITY_VOICE (PRIORITY_PLAYBACK-4) 66 67/* A speex frame generally consists of 20ms of audio 68 * (http://www.speex.org/docs/manual/speex-manual/node10.html) 69 * for wideband mode this results in 320 samples of decoded PCM. 70 */ 71#define VOICE_FRAME_COUNT 320 /* Samples / frame */ 72#define VOICE_SAMPLE_RATE 16000 /* Sample rate in HZ */ 73#define VOICE_SAMPLE_DEPTH 16 /* Sample depth in bits */ 74/* The max. wideband bitrate is 42.4 kbps 75 * (http://www.speex.org/docs/manual/speex-manual/node11.html). For 20ms 76 * this gives a maximum of 106 bytes for an encoded speex frame */ 77#define VOICE_MAX_ENCODED_FRAME_SIZE 106 78 79/* Voice thread variables */ 80static unsigned int voice_thread_id = 0; 81#if defined(CPU_MIPS) 82/* MIPS is stack-hungry */ 83#define VOICE_STACK_EXTRA 0x500 84#elif defined(CPU_COLDFIRE) 85/* ISR uses any available stack - need a bit more room */ 86#define VOICE_STACK_EXTRA 0x400 87#elif (CONFIG_PLATFORM & PLATFORM_HOSTED) 88/* Needed at least on the Sony NWZ hosted targets, but probably a good idea on all of them */ 89#define VOICE_STACK_EXTRA 0x500 90#else 91#define VOICE_STACK_EXTRA 0x3c0 92#endif 93static long voice_stack[(DEFAULT_STACK_SIZE + VOICE_STACK_EXTRA)/sizeof(long)] 94 IBSS_ATTR_VOICE_STACK; 95static const char voice_thread_name[] = "voice"; 96 97/* Voice thread synchronization objects */ 98static struct event_queue voice_queue SHAREDBSS_ATTR; 99static struct queue_sender_list voice_queue_sender_list SHAREDBSS_ATTR; 100static int quiet_counter SHAREDDATA_ATTR = 0; 101static bool voice_playing = false; 102 103#define VOICE_PCM_FRAME_COUNT ((PLAY_SAMPR_MAX*VOICE_FRAME_COUNT + \ 104 VOICE_SAMPLE_RATE) / VOICE_SAMPLE_RATE) 105#define VOICE_PCM_FRAME_SIZE (VOICE_PCM_FRAME_COUNT*2*sizeof (int16_t)) 106 107/* Voice processing states */ 108enum voice_state 109{ 110 VOICE_STATE_MESSAGE = 0, 111 VOICE_STATE_DECODE, 112 VOICE_STATE_BUFFER_INSERT, 113 VOICE_STATE_QUIT, 114}; 115 116/* A delay to not bring audio back to normal level too soon */ 117#define QUIET_COUNT 3 118 119enum voice_thread_messages 120{ 121 Q_VOICE_PLAY = 0, /* Play a clip */ 122 Q_VOICE_STOP, /* Stop current clip */ 123 Q_VOICE_KILL, /* Kill voice thread till restart*/ 124}; 125 126/* Structure to store clip data callback info */ 127struct voice_info 128{ 129 /* Callback to get more clips */ 130 voice_play_callback_t get_more; 131 /* Start of clip */ 132 const void *start; 133 /* Size of clip */ 134 size_t size; 135}; 136 137/* Private thread data for its current state that must be passed to its 138 * internal functions */ 139struct voice_thread_data 140{ 141 struct queue_event ev; /* Last queue event pulled from queue */ 142 void *st; /* Decoder instance */ 143 SpeexBits bits; /* Bit cursor */ 144 struct dsp_config *dsp; /* DSP used for voice output */ 145 struct voice_info vi; /* Copy of clip data */ 146 int lookahead; /* Number of samples to drop at start of clip */ 147 struct dsp_buffer src; /* Speex output buffer/input to DSP */ 148 struct dsp_buffer *dst; /* Pointer to DSP output buffer for PCM */ 149}; 150 151/* Functions called in their repective state that return the next state to 152 state machine loop - compiler may inline them at its discretion */ 153static enum voice_state voice_message(struct voice_thread_data *td); 154static enum voice_state voice_decode(struct voice_thread_data *td); 155static enum voice_state voice_buffer_insert(struct voice_thread_data *td); 156 157/* Might have lookahead and be skipping samples, so size is needed */ 158static struct voice_buf 159{ 160 /* Buffer for decoded samples */ 161 spx_int16_t spx_outbuf[VOICE_FRAME_COUNT]; 162 /* Queue frame indexes */ 163 unsigned int volatile frame_in; 164 unsigned int volatile frame_out; 165 /* For PCM pointer adjustment */ 166 struct voice_thread_data *td; 167 /* Buffers for mixing voice */ 168 struct voice_pcm_frame 169 { 170 size_t size; 171 int16_t pcm[2*VOICE_PCM_FRAME_COUNT]; 172 } frames[VOICE_FRAMES]; 173} *voice_buf = NULL; 174 175static int voice_buf_hid = 0; 176 177static int move_callback(int handle, void *current, void *new) 178{ 179 /* Have to adjust the pointers that point into things in voice_buf */ 180 off_t diff = new - current; 181 struct voice_thread_data *td = voice_buf->td; 182 183 if (td != NULL) 184 { 185 td->src.p32[0] = SKIPBYTES(td->src.p32[0], diff); 186 td->src.p32[1] = SKIPBYTES(td->src.p32[1], diff); 187 188 if (td->dst != NULL) /* Only when calling dsp_process */ 189 td->dst->p16out = SKIPBYTES(td->dst->p16out, diff); 190 191 mixer_adjust_channel_address(PCM_MIXER_CHAN_VOICE, diff); 192 } 193 194 voice_buf = new; 195 196 return BUFLIB_CB_OK; 197 (void)handle; 198}; 199 200static void sync_callback(int handle, bool sync_on) 201{ 202 /* A move must not allow PCM to access the channel */ 203 if (sync_on) 204 pcm_play_lock(); 205 else 206 pcm_play_unlock(); 207 208 (void)handle; 209} 210 211static struct buflib_callbacks ops = 212{ 213 .move_callback = move_callback, 214 .sync_callback = sync_callback, 215}; 216 217/* Number of frames in queue */ 218static unsigned int voice_unplayed_frames(void) 219{ 220 return voice_buf->frame_in - voice_buf->frame_out; 221} 222 223/* Mixer channel callback */ 224static void voice_pcm_callback(const void **start, size_t *size) 225{ 226 unsigned int frame_out = ++voice_buf->frame_out; 227 228 if (voice_unplayed_frames() == 0) 229 return; /* Done! */ 230 231 struct voice_pcm_frame *frame = 232 &voice_buf->frames[frame_out % VOICE_FRAMES]; 233 234 *start = frame->pcm; 235 *size = frame->size; 236} 237 238/* Start playback of voice channel if not already playing */ 239static void voice_start_playback(void) 240{ 241 if (mixer_channel_status(PCM_MIXER_CHAN_VOICE) != CHANNEL_STOPPED || 242 voice_unplayed_frames() == 0) 243 return; 244 245 struct voice_pcm_frame *frame = 246 &voice_buf->frames[voice_buf->frame_out % VOICE_FRAMES]; 247 248 mixer_channel_play_data(PCM_MIXER_CHAN_VOICE, voice_pcm_callback, 249 frame->pcm, frame->size); 250} 251 252/* Stop the voice channel */ 253static void voice_stop_playback(void) 254{ 255 mixer_channel_stop(PCM_MIXER_CHAN_VOICE); 256 voice_buf->frame_in = voice_buf->frame_out = 0; 257} 258 259/* Grab a free PCM frame */ 260static int16_t * voice_buf_get(void) 261{ 262 if (voice_unplayed_frames() >= VOICE_FRAMES) 263 { 264 /* Full */ 265 voice_start_playback(); 266 return NULL; 267 } 268 269 return voice_buf->frames[voice_buf->frame_in % VOICE_FRAMES].pcm; 270} 271 272/* Commit a frame returned by voice_buf_get and set the actual size */ 273static void voice_buf_commit(int count) 274{ 275 if (count > 0) 276 { 277 unsigned int frame_in = voice_buf->frame_in; 278 voice_buf->frames[frame_in % VOICE_FRAMES].size = 279 count * 2 * sizeof (int16_t); 280 voice_buf->frame_in = frame_in + 1; 281 } 282} 283 284/* Stop any current clip and start playing a new one */ 285void voice_play_data(const void *start, size_t size, 286 voice_play_callback_t get_more) 287{ 288 if (voice_thread_id && start && size && get_more) 289 { 290 struct voice_info voice_clip = 291 { 292 .get_more = get_more, 293 .start = start, 294 .size = size, 295 }; 296 297 LOGFQUEUE("mp3 >| voice Q_VOICE_PLAY"); 298 queue_send(&voice_queue, Q_VOICE_PLAY, (intptr_t)&voice_clip); 299 } 300} 301 302/* Stop current voice clip from playing */ 303void voice_play_stop(void) 304{ 305 if (voice_thread_id != 0) 306 { 307 LOGFQUEUE("mp3 >| voice Q_VOICE_STOP"); 308 queue_send(&voice_queue, Q_VOICE_STOP, 0); 309 } 310} 311 312/* This function is meant to be used by the buffer request functions to 313 ensure the codec is no longer active */ 314void voice_stop(void) 315{ 316 /* Unqueue all future clips */ 317 talk_force_shutup(); 318} 319 320/* Wait for voice to finish speaking. */ 321void voice_wait(void) 322{ 323 /* NOTE: One problem here is that we can't tell if another thread started a 324 * new clip by the time we wait. This should be resolvable if conditions 325 * ever require knowing the very clip you requested has finished. */ 326 327 while (voice_playing) 328 sleep(1); 329} 330 331void voice_set_mixer_level(int percent) 332{ 333 percent *= MIX_AMP_UNITY; 334 percent /= 100; 335 mixer_channel_set_amplitude(PCM_MIXER_CHAN_VOICE, percent); 336} 337 338/* Initialize voice thread data that must be valid upon starting and the 339 * setup the DSP parameters */ 340static void voice_data_init(struct voice_thread_data *td) 341{ 342 td->dsp = dsp_get_config(CODEC_IDX_VOICE); 343 dsp_configure(td->dsp, DSP_RESET, 0); 344 dsp_configure(td->dsp, DSP_SET_FREQUENCY, VOICE_SAMPLE_RATE); 345 dsp_configure(td->dsp, DSP_SET_SAMPLE_DEPTH, VOICE_SAMPLE_DEPTH); 346 dsp_configure(td->dsp, DSP_SET_STEREO_MODE, STEREO_MONO); 347 348 voice_set_mixer_level(global_settings.talk_mixer_amp); 349 350 voice_buf->td = td; 351 td->dst = NULL; 352} 353 354/* Voice thread message processing */ 355static enum voice_state voice_message(struct voice_thread_data *td) 356{ 357 queue_wait_w_tmo(&voice_queue, &td->ev, 358 quiet_counter > 0 ? HZ/10 : TIMEOUT_BLOCK); 359 360 switch (td->ev.id) 361 { 362 case Q_VOICE_PLAY: 363 LOGFQUEUE("voice < Q_VOICE_PLAY"); 364 365 /* Boost CPU now */ 366 trigger_cpu_boost(); 367 368 if (quiet_counter != 0) 369 { 370 /* Stop any clip still playing */ 371 voice_stop_playback(); 372 dsp_configure(td->dsp, DSP_FLUSH, 0); 373 } 374 375 if (quiet_counter <= 0) 376 { 377 voice_playing = true; 378 dsp_configure(td->dsp, DSP_SET_OUT_FREQUENCY, mixer_get_frequency()); 379 send_event(VOICE_EVENT_IS_PLAYING, &voice_playing); 380 } 381 382 quiet_counter = QUIET_COUNT; 383 384 /* Copy the clip info */ 385 td->vi = *(struct voice_info *)td->ev.data; 386 387 /* We need nothing more from the sending thread - let it run */ 388 queue_reply(&voice_queue, 1); 389 390 /* Clean-start the decoder */ 391 td->st = speex_decoder_init(&speex_wb_mode); 392 393 /* Make bit buffer use our own buffer */ 394 speex_bits_set_bit_buffer(&td->bits, (void *)td->vi.start, 395 td->vi.size); 396 speex_decoder_ctl(td->st, SPEEX_GET_LOOKAHEAD, &td->lookahead); 397 398 return VOICE_STATE_DECODE; 399 case Q_VOICE_KILL: 400 queue_delete(&voice_queue); 401 return VOICE_STATE_QUIT; 402 case SYS_TIMEOUT: 403 if (voice_unplayed_frames()) 404 { 405 /* Waiting for PCM to finish */ 406 break; 407 } 408 409 /* Drop through and stop the first time after clip runs out */ 410 if (quiet_counter-- != QUIET_COUNT) 411 { 412 if (quiet_counter <= 0) 413 { 414 voice_playing = false; 415 send_event(VOICE_EVENT_IS_PLAYING, &voice_playing); 416 } 417 break; 418 } 419 420 /* Fall-through */ 421 case Q_VOICE_STOP: 422 LOGFQUEUE("voice < Q_VOICE_STOP"); 423 cancel_cpu_boost(); 424 voice_stop_playback(); 425 break; 426 427 /* No default: no other message ids are sent */ 428 } 429 430 return VOICE_STATE_MESSAGE; 431} 432 433/* Decode frames or stop if all have completed */ 434static enum voice_state voice_decode(struct voice_thread_data *td) 435{ 436 if (!queue_empty(&voice_queue)) 437 return VOICE_STATE_MESSAGE; 438 439 /* Decode the data */ 440 if (speex_decode_int(td->st, &td->bits, voice_buf->spx_outbuf) < 0) 441 { 442 /* End of stream or error - get next clip */ 443 td->vi.size = 0; 444 445 if (td->vi.get_more != NULL) 446 td->vi.get_more(&td->vi.start, &td->vi.size); 447 448 if (td->vi.start != NULL && td->vi.size > 0) 449 { 450 /* Make bit buffer use our own buffer */ 451 speex_bits_set_bit_buffer(&td->bits, (void *)td->vi.start, 452 td->vi.size); 453 /* Don't skip any samples when we're stringing clips together */ 454 td->lookahead = 0; 455 } 456 else 457 { 458 /* If all clips are done and not playing, force pcm playback. */ 459 if (voice_unplayed_frames() > 0) 460 voice_start_playback(); 461 return VOICE_STATE_MESSAGE; 462 } 463 } 464 else 465 { 466 if (td->vi.size > VOICE_MAX_ENCODED_FRAME_SIZE 467 && td->bits.charPtr > (int)(td->vi.size - VOICE_MAX_ENCODED_FRAME_SIZE) 468 && td->vi.get_more != NULL) 469 { 470 /* request more data _before_ running out of data (requesting 471 * more after the fact prevents speex from successful decoding) 472 * place a hint telling the callback how much of the 473 * previous buffer we have consumed such that it can rewind 474 * as necessary */ 475 int bitPtr = td->bits.bitPtr; 476 td->vi.size = td->bits.charPtr; 477 td->vi.get_more(&td->vi.start, &td->vi.size); 478 speex_bits_set_bit_buffer(&td->bits, (void *)td->vi.start, 479 td->vi.size); 480 td->bits.bitPtr = bitPtr; 481 } 482 483 yield(); 484 485 /* Output the decoded frame */ 486 td->src.remcount = VOICE_FRAME_COUNT - td->lookahead; 487 td->src.pin[0] = &voice_buf->spx_outbuf[td->lookahead]; 488 td->src.pin[1] = NULL; 489 td->src.proc_mask = 0; 490 491 td->lookahead -= MIN(VOICE_FRAME_COUNT, td->lookahead); 492 493 if (td->src.remcount > 0) 494 return VOICE_STATE_BUFFER_INSERT; 495 } 496 497 return VOICE_STATE_DECODE; 498} 499 500/* Process the PCM samples in the DSP and send out for mixing */ 501static enum voice_state voice_buffer_insert(struct voice_thread_data *td) 502{ 503 if (!queue_empty(&voice_queue)) 504 return VOICE_STATE_MESSAGE; 505 506 struct dsp_buffer dst; 507 508 if ((dst.p16out = voice_buf_get()) != NULL) 509 { 510 dst.remcount = 0; 511 dst.bufcount = VOICE_PCM_FRAME_COUNT; 512 513 td->dst = &dst; 514 dsp_process(td->dsp, &td->src, &dst, true); 515 td->dst = NULL; 516 517 voice_buf_commit(dst.remcount); 518 519 /* Unless other effects are introduced to voice that have delays, 520 all output should have been purged to dst in one call */ 521 return td->src.remcount > 0 ? 522 VOICE_STATE_BUFFER_INSERT : VOICE_STATE_DECODE; 523 } 524 525 sleep(0); 526 return VOICE_STATE_BUFFER_INSERT; 527} 528 529/* Voice thread entrypoint */ 530static void voice_thread(void) 531{ 532 struct voice_thread_data td; 533 enum voice_state state = VOICE_STATE_MESSAGE; 534 535 voice_data_init(&td); 536 537 while (1) 538 { 539 switch (state) 540 { 541 case VOICE_STATE_MESSAGE: 542 state = voice_message(&td); 543 break; 544 case VOICE_STATE_DECODE: 545 state = voice_decode(&td); 546 break; 547 case VOICE_STATE_BUFFER_INSERT: 548 state = voice_buffer_insert(&td); 549 break; 550 case VOICE_STATE_QUIT: 551 logf("Exiting voice thread"); 552 core_free(voice_buf_hid); 553 voice_buf_hid = 0; 554 return; 555 } 556 } 557 return; 558} 559 560/* kill voice thread and dont allow re-init*/ 561void voice_thread_kill(void) 562{ 563 queue_send(&voice_queue, Q_VOICE_KILL, 0); 564} 565 566/* Initialize buffers, all synchronization objects and create the thread */ 567void voice_thread_init(void) 568{ 569 if (voice_thread_id != 0) 570 return; /* Already did an init and succeeded at it */ 571 572 voice_buf_hid = core_alloc_ex(sizeof (*voice_buf), &ops); 573 574 if (voice_buf_hid <= 0) 575 { 576 logf("voice: core_alloc_ex failed"); 577 return; 578 } 579 580 voice_buf = core_get_data(voice_buf_hid); 581 582 if (voice_buf == NULL) 583 { 584 logf("voice: core_get_data failed"); 585 core_free(voice_buf_hid); 586 voice_buf_hid = 0; 587 return; 588 } 589 590 memset(voice_buf, 0, sizeof (*voice_buf)); 591 592 logf("Starting voice thread"); 593 queue_init(&voice_queue, false); 594 595 voice_thread_id = create_thread(voice_thread, voice_stack, 596 sizeof(voice_stack), 0, voice_thread_name 597 IF_PRIO(, PRIORITY_VOICE) IF_COP(, CPU)); 598 599 queue_enable_queue_send(&voice_queue, &voice_queue_sender_list, 600 voice_thread_id); 601} 602 603#ifdef HAVE_PRIORITY_SCHEDULING 604/* Set the voice thread priority */ 605void voice_thread_set_priority(int priority) 606{ 607 if (voice_thread_id == 0) 608 return; 609 610 if (priority > PRIORITY_VOICE) 611 priority = PRIORITY_VOICE; 612 613 thread_set_priority(voice_thread_id, priority); 614} 615#endif