static void codec_pcmbuf_insert_callback( const void *ch1, const void *ch2, int count) { const char *src[2] = { ch1, ch2 }; while (count > 0) { int out_count = dsp_output_count(ci.dsp, count); int inp_count; char *dest; while (1) { if ((dest = pcmbuf_request_buffer(&out_count)) != NULL) break; cancel_cpu_boost(); /* It will be awhile before space is available but we want "instant" response to any message */ queue_wait_w_tmo(&codec_queue, NULL, HZ/20); if (!queue_empty(&codec_queue) && codec_check_queue__have_msg() < 0) return; } /* Get the real input_size for output_size bytes, guarding * against resampling buffer overflows. */ inp_count = dsp_input_count(ci.dsp, out_count); if (inp_count <= 0) return; /* Input size has grown, no error, just don't write more than length */ if (inp_count > count) inp_count = count; out_count = dsp_process(ci.dsp, dest, src, inp_count); if (out_count <= 0) return; pcmbuf_write_complete(out_count); count -= inp_count; } }
static void codec_pcmbuf_insert_callback( const void *ch1, const void *ch2, int count) { const char *src[2] = { ch1, ch2 }; while (count > 0) { int out_count = dsp_output_count(ci.dsp, count); int inp_count; char *dest; /* Prevent audio from a previous track from playing */ if (ci.new_track || ci.stop_codec) return; while ((dest = pcmbuf_request_buffer(&out_count)) == NULL) { cancel_cpu_boost(); sleep(1); if (ci.seek_time || ci.new_track || ci.stop_codec) return; } /* Get the real input_size for output_size bytes, guarding * against resampling buffer overflows. */ inp_count = dsp_input_count(ci.dsp, out_count); if (inp_count <= 0) return; /* Input size has grown, no error, just don't write more than length */ if (inp_count > count) inp_count = count; out_count = dsp_process(ci.dsp, dest, src, inp_count); if (out_count <= 0) return; pcmbuf_write_complete(out_count); count -= inp_count; } } /* codec_pcmbuf_insert_callback */
/* Voice thread entrypoint */ static void voice_thread(void) { struct voice_thread_data td; voice_data_init(&td); /* audio thread will only set this once after it finished the final * audio hardware init so this little construct is safe - even * cross-core. */ while (!audio_is_thread_ready()) sleep(0); goto message_wait; while (1) { td.state = TSTATE_DECODE; if (!queue_empty(&voice_queue)) { message_wait: queue_wait(&voice_queue, &td.ev); message_process: voice_message(&td); /* Branch to initial start point or branch back to previous * operation if interrupted by a message */ switch (td.state) { case TSTATE_DECODE: goto voice_decode; case TSTATE_BUFFER_INSERT: goto buffer_insert; default: goto message_wait; } } voice_decode: /* Decode the data */ if (speex_decode_int(td.st, &td.bits, voice_output_buf) < 0) { /* End of stream or error - get next clip */ td.vi.size = 0; if (td.vi.get_more != NULL) td.vi.get_more(&td.vi.start, &td.vi.size); if (td.vi.start != NULL && (ssize_t)td.vi.size > 0) { /* Make bit buffer use our own buffer */ speex_bits_set_bit_buffer(&td.bits, td.vi.start, td.vi.size); /* Don't skip any samples when we're stringing clips together */ td.lookahead = 0; /* Paranoid check - be sure never to somehow get stuck in a * loop without listening to the queue */ yield(); if (!queue_empty(&voice_queue)) goto message_wait; else goto voice_decode; } /* If all clips are done and not playing, force pcm playback. */ if (!pcm_is_playing()) pcmbuf_play_start(); /* Synthesize a stop request */ /* NOTE: We have no way to know when the pcm data placed in the * buffer is actually consumed and playback has reached the end * so until the info is available or inferred somehow, this will * not be accurate and the stopped signal will come too soon. * ie. You may not hear the "Shutting Down" splash even though * it waits for voice to stop. */ td.ev.id = Q_VOICE_STOP; td.ev.data = 0; /* Let PCM drain by itself */ yield(); goto message_process; } yield(); /* Output the decoded frame */ td.count = VOICE_FRAME_SIZE - td.lookahead; td.src[0] = (const char *)&voice_output_buf[td.lookahead]; td.src[1] = NULL; td.lookahead -= MIN(VOICE_FRAME_SIZE, td.lookahead); buffer_insert: /* Process the PCM samples in the DSP and send out for mixing */ td.state = TSTATE_BUFFER_INSERT; while (td.count > 0) { int out_count = dsp_output_count(td.dsp, td.count); int inp_count; char *dest; while (1) { if (!queue_empty(&voice_queue)) goto message_wait; if ((dest = pcmbuf_request_voice_buffer(&out_count)) != NULL) break; yield(); } /* Get the real input_size for output_size bytes, guarding * against resampling buffer overflows. */ inp_count = dsp_input_count(td.dsp, out_count); if (inp_count <= 0) break; /* Input size has grown, no error, just don't write more than * length */ if (inp_count > td.count) inp_count = td.count; out_count = dsp_process(td.dsp, dest, td.src, inp_count); if (out_count <= 0) break; pcmbuf_write_voice_complete(out_count); td.count -= inp_count; } yield(); } /* end while */ } /* voice_thread */