static void gst_speex_dec_reset (GstSpeexDec * dec) { dec->packetno = 0; dec->frame_size = 0; dec->frame_duration = 0; dec->mode = NULL; free (dec->header); dec->header = NULL; speex_bits_destroy (&dec->bits); speex_bits_set_bit_buffer (&dec->bits, NULL, 0); gst_buffer_replace (&dec->streamheader, NULL); gst_buffer_replace (&dec->vorbiscomment, NULL); if (dec->stereo) { speex_stereo_state_destroy (dec->stereo); dec->stereo = NULL; } if (dec->state) { speex_decoder_destroy (dec->state); dec->state = NULL; } }
int universal_speex_get_packet_samples(void *handle, const uint8_t *pPacketData, unsigned packetSize, unsigned *pNumSamples, const struct RtpHeader* pRtpHeader) { SpeexBits bits; int num_frames; struct speex_codec_data_decoder *pSpeexDec = (struct speex_codec_data_decoder *)handle; assert(handle != NULL); /* Wrap data to speex_bits struct */ speex_bits_set_bit_buffer(&bits, (void*)pPacketData, packetSize); /* Get number of frames */ num_frames = speex_bits_get_num_frames(&bits); if (num_frames < 0) { return RPLG_CORRUPTED_DATA; } /* Return number of samples */ *pNumSamples = num_frames * pSpeexDec->mNumSamplesPerFrame; return RPLG_SUCCESS; }
/* Decode frames or stop if all have completed */ static enum voice_state voice_decode(struct voice_thread_data *td) { if (!queue_empty(&voice_queue)) return VOICE_STATE_MESSAGE; /* 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; } else { /* If all clips are done and not playing, force pcm playback. */ voice_start_playback(); return VOICE_STATE_MESSAGE; } } else { 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); if (td->count > 0) return VOICE_STATE_BUFFER_INSERT; } return VOICE_STATE_DECODE; }
static gboolean gst_speex_enc_stop (GstAudioEncoder * benc) { GstSpeexEnc *enc = GST_SPEEX_ENC (benc); GST_DEBUG_OBJECT (enc, "stop"); enc->header_sent = FALSE; if (enc->state) { speex_encoder_destroy (enc->state); enc->state = NULL; } speex_bits_destroy (&enc->bits); speex_bits_set_bit_buffer (&enc->bits, NULL, 0); gst_tag_list_unref (enc->tags); enc->tags = NULL; gst_tag_setter_reset_tags (GST_TAG_SETTER (enc)); return TRUE; }
/* this is called for each file to process */ enum codec_status codec_run(void) { int error = CODEC_ERROR; SpeexBits bits; int eof = 0; spx_ogg_sync_state oy; spx_ogg_page og; spx_ogg_packet op; spx_ogg_stream_state os; spx_int64_t page_granule = 0; spx_int64_t cur_granule = 0; int enh_enabled = 1; int nframes = 2; int eos = 0; SpeexStereoState *stereo; int channels = -1; int samplerate = ci->id3->frequency; int extra_headers = 0; int stream_init = 0; /* rockbox: comment 'set but unused' variables int page_nb_packets; */ int frame_size; int packet_count = 0; int lookahead; int headerssize = 0; unsigned long strtoffset = ci->id3->offset; void *st = NULL; int j = 0; intptr_t param; memset(&bits, 0, sizeof(bits)); memset(&oy, 0, sizeof(oy)); /* Ogg handling still uses mallocs, so reset the malloc buffer per track */ if (codec_init()) { goto exit; } ci->seek_buffer(0); ci->set_elapsed(0); stereo = speex_stereo_state_init(); spx_ogg_sync_init(&oy); spx_ogg_alloc_buffer(&oy,2*CHUNKSIZE); codec_set_replaygain(ci->id3); eof = 0; while (!eof) { enum codec_command_action action = ci->get_command(¶m); if (action == CODEC_ACTION_HALT) break; /*seek (seeks to the page before the position) */ if (action == CODEC_ACTION_SEEK_TIME) { if(samplerate!=0&&packet_count>1){ LOGF("Speex seek page:%lld,%lld,%ld,%lld,%d\n", ((spx_int64_t)param/1000) * (spx_int64_t)samplerate, page_granule, param, (page_granule/samplerate)*1000, samplerate); speex_seek_page_granule(((spx_int64_t)param/1000) * (spx_int64_t)samplerate, page_granule, &oy, headerssize); } ci->set_elapsed(param); ci->seek_complete(); } next_page: /*Get the ogg buffer for writing*/ if(get_more_data(&oy)<1){/*read error*/ goto done; } /* Loop for all complete pages we got (most likely only one) */ while (spx_ogg_sync_pageout(&oy, &og) == 1) { int packet_no; if (stream_init == 0) { spx_ogg_stream_init(&os, spx_ogg_page_serialno(&og)); stream_init = 1; } /* Add page to the bitstream */ spx_ogg_stream_pagein(&os, &og); page_granule = spx_ogg_page_granulepos(&og); /* page_nb_packets = spx_ogg_page_packets(&og); */ cur_granule = page_granule; /* Extract all available packets */ packet_no=0; while (!eos && spx_ogg_stream_packetout(&os, &op)==1){ /* If first packet, process as Speex header */ if (packet_count==0){ st = process_header(&op, enh_enabled, &frame_size, &samplerate, &nframes, &channels, stereo, &extra_headers); speex_decoder_ctl(st, SPEEX_GET_LOOKAHEAD, &lookahead); if (!nframes) nframes=1; if (!st){ goto done; } ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency); ci->configure(DSP_SET_SAMPLE_DEPTH, 16); if (channels == 2) { ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED); } else if (channels == 1) { ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); } /* Speex header in its own page, add the whole page headersize */ headerssize += og.header_len+og.body_len; } else if (packet_count<=1+extra_headers){ /* add packet to headersize */ headerssize += op.bytes; /* Ignore extra headers */ } else { if (packet_count <= 2+extra_headers) { if (strtoffset) { ci->seek_buffer(strtoffset); spx_ogg_sync_reset(&oy); packet_count++; goto next_page; } } packet_no++; if (op.e_o_s) /* End of stream condition */ eos=1; /* Set Speex bitstream to point to Ogg packet */ speex_bits_set_bit_buffer(&bits, (char *)op.packet, op.bytes); for (j = 0; j != nframes; j++){ int ret; /* Decode frame */ ret = speex_decode_int(st, &bits, output); if (ret == -1) break; if (ret == -2) break; if (speex_bits_remaining(&bits) < 0) break; if (channels == 2) speex_decode_stereo_int(output, frame_size, stereo); if (frame_size > 0) { spx_int16_t *frame_start = output + lookahead; if (channels == 2) frame_start += lookahead; ci->pcmbuf_insert(frame_start, NULL, frame_size - lookahead); lookahead = 0; /* 2 bytes/sample */ cur_granule += frame_size / 2; ci->set_offset((long) ci->curpos); ci->set_elapsed((samplerate == 0) ? 0 : cur_granule * 1000 / samplerate); } } } packet_count++; } } } error = CODEC_OK; done: /* Clean things up for the next track */ speex_bits_destroy(&bits); if (st) speex_decoder_destroy(st); if (stream_init) spx_ogg_stream_destroy(&os); spx_ogg_sync_destroy(&oy); exit: return error; }
/* Voice thread message processing */ static enum voice_state voice_message(struct voice_thread_data *td) { if (quiet_counter > 0) queue_wait_w_tmo(&voice_queue, &td->ev, HZ/10); else queue_wait(&voice_queue, &td->ev); switch (td->ev.id) { case Q_VOICE_PLAY: LOGFQUEUE("voice < Q_VOICE_PLAY"); if (quiet_counter == 0) { /* Boost CPU now */ trigger_cpu_boost(); } else { /* Stop any clip still playing */ voice_stop_playback(); } quiet_counter = QUIET_COUNT; /* Copy the clip info */ td->vi = *(struct voice_info *)td->ev.data; /* Be sure audio buffer is initialized */ audio_restore_playback(AUDIO_WANT_VOICE); /* We need nothing more from the sending thread - let it run */ queue_reply(&voice_queue, 1); /* Make audio play more softly and set delay to return to normal playback level */ pcmbuf_soft_mode(true); /* Clean-start the decoder */ td->st = speex_decoder_init(&speex_wb_mode); /* Make bit buffer use our own buffer */ speex_bits_set_bit_buffer(&td->bits, td->vi.start, td->vi.size); speex_decoder_ctl(td->st, SPEEX_GET_LOOKAHEAD, &td->lookahead); return VOICE_STATE_DECODE; case SYS_TIMEOUT: if (voice_unplayed_frames()) { /* Waiting for PCM to finish */ break; } /* Drop through and stop the first time after clip runs out */ if (quiet_counter-- != QUIET_COUNT) { if (quiet_counter <= 0) pcmbuf_soft_mode(false); break; } /* Fall-through */ case Q_VOICE_STOP: LOGFQUEUE("voice < Q_VOICE_STOP"); cancel_cpu_boost(); voice_stop_playback(); break; /* No default: no other message ids are sent */ } return VOICE_STATE_MESSAGE; }
/* 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 */
/* Voice thread message processing */ static void voice_message(struct voice_thread_data *td) { while (1) { switch (td->ev.id) { case Q_VOICE_PLAY: LOGFQUEUE("voice < Q_VOICE_PLAY"); /* Put up a block for completion signal */ voice_done = false; /* Copy the clip info */ td->vi = *(struct voice_info *)td->ev.data; /* Be sure audio buffer is initialized */ audio_restore_playback(AUDIO_WANT_VOICE); /* We need nothing more from the sending thread - let it run */ queue_reply(&voice_queue, 1); if (td->state == TSTATE_STOPPED) { /* Boost CPU now */ trigger_cpu_boost(); } else if (!playback_is_playing()) { /* Just voice, stop any clip still playing */ pcmbuf_play_stop(); } /* Clean-start the decoder */ td->st = speex_decoder_init(&speex_wb_mode); /* Make bit buffer use our own buffer */ speex_bits_set_bit_buffer(&td->bits, td->vi.start, td->vi.size); speex_decoder_ctl(td->st, SPEEX_GET_LOOKAHEAD, &td->lookahead); td->state = TSTATE_DECODE; return; case Q_VOICE_STOP: LOGFQUEUE("voice < Q_VOICE_STOP: %ld", td->ev.data); if (td->ev.data != 0 && !playback_is_playing()) { /* If not playing, it's just voice so stop pcm playback */ pcmbuf_play_stop(); } /* Cancel boost */ cancel_cpu_boost(); td->state = TSTATE_STOPPED; voice_done = true; break; case Q_VOICE_STATE: LOGFQUEUE("voice < Q_VOICE_STATE"); queue_reply(&voice_queue, td->state); if (td->state == TSTATE_STOPPED) break; /* Not in a playback state */ return; default: /* Default messages get a reply and thread continues with no * state transition */ LOGFQUEUE("voice < default"); if (td->state == TSTATE_STOPPED) break; /* Not in playback state */ queue_reply(&voice_queue, 0); return; } queue_wait(&voice_queue, &td->ev); } }
int universal_speex_decode(void* handle, const void* pCodedData, unsigned cbCodedPacketSize, void* pAudioBuffer, unsigned cbBufferSize, unsigned *pcbDecodedSize, const struct RtpHeader* pRtpHeader) { SpeexBits bits; struct speex_codec_data_decoder *mpSpeexDec = (struct speex_codec_data_decoder *)handle; assert(handle != NULL); if (mpSpeexDec->mNumSamplesPerFrame > cbBufferSize) { return RPLG_INVALID_ARGUMENT; } /* Reset number of decoded samples */ *pcbDecodedSize = 0; /* Decode incoming packet if present. Do PLC if no packet. */ if (pCodedData) { /* Prepare data for Speex decoder */ speex_bits_set_bit_buffer(&bits,(char*)pCodedData, cbCodedPacketSize); /* Decode while there are something to decode and enough space * for decoded data. */ while (cbBufferSize >= mpSpeexDec->mNumSamplesPerFrame && (speex_bits_remaining(&bits) > 0)) { int res; /* Decode frame */ res = speex_decode_int(mpSpeexDec->mpDecoderState, &bits, ((spx_int16_t*)pAudioBuffer)+(*pcbDecodedSize)); if (res == 0) { /* Update number of decoded and available samples on success */ *pcbDecodedSize += mpSpeexDec->mNumSamplesPerFrame; cbBufferSize -= mpSpeexDec->mNumSamplesPerFrame; } else { /* If it's the end of the stream or corrupted stream just return */ break; } } } else { int res; /* Do PLC */ res = speex_decode_int(mpSpeexDec->mpDecoderState, NULL, ((spx_int16_t*)pAudioBuffer)+(*pcbDecodedSize)); if (res == 0) { /* Update number of decoded and available samples on success */ *pcbDecodedSize += mpSpeexDec->mNumSamplesPerFrame; } else { /* This mustn't happen for lost packet, but who knows... */ return RPLG_FAILED; } } return RPLG_SUCCESS; }