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; } }
/* Process the PCM samples in the DSP and send out for mixing */ static enum voice_state voice_buffer_insert(struct voice_thread_data *td) { if (!queue_empty(&voice_queue)) return VOICE_STATE_MESSAGE; char *dest = (char *)voice_buf_get(); if (dest != NULL) { voice_buf_commit(dsp_process(td->dsp, dest, td->src, td->count) * sizeof (int32_t)); return VOICE_STATE_DECODE; } sleep(0); return VOICE_STATE_BUFFER_INSERT; }
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 */
static void ci_pcmbuf_insert(const void *ch1, const void *ch2, int count) { num_output_samples += count; if (use_dsp) { struct dsp_buffer src; src.remcount = count; src.pin[0] = ch1; src.pin[1] = ch2; src.proc_mask = 0; while (1) { int out_count = MAX(count, 512); int16_t buf[2 * out_count]; struct dsp_buffer dst; dst.remcount = 0; dst.p16out = buf; dst.bufcount = out_count; dsp_process(ci.dsp, &src, &dst); if (dst.remcount > 0) { if (mode == MODE_WRITE) write_pcm(buf, dst.remcount); else if (mode == MODE_PLAY) playback_pcm(buf, dst.remcount); } else if (src.remcount <= 0) { break; } } } else { /* Convert to 32-bit interleaved. */ count *= format.channels; int i; int32_t buf[count]; if (format.depth > 16) { if (format.stereo_mode == STEREO_NONINTERLEAVED) { for (i = 0; i < count; i += 2) { buf[i+0] = ((int32_t*)ch1)[i/2]; buf[i+1] = ((int32_t*)ch2)[i/2]; } } else { memcpy(buf, ch1, sizeof(buf)); } } else { if (format.stereo_mode == STEREO_NONINTERLEAVED) { for (i = 0; i < count; i += 2) { buf[i+0] = ((int16_t*)ch1)[i/2]; buf[i+1] = ((int16_t*)ch2)[i/2]; } } else { for (i = 0; i < count; i++) { buf[i] = ((int16_t*)ch1)[i]; } } } if (mode == MODE_WRITE) write_pcm_raw(buf, count); } perform_config(); }
/* 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 */