#include "msbc_decoder_port.h" static struct sbc_decoder_state sbc_internal_decoder_state = {0}; static void msbc_append_received_data(struct sbc_decoder_state * state, uint8_t * buffer, int size) { int numFreeBytes = sizeof(state->frame_buffer) - state->bytes_in_frame_buffer; if (size > numFreeBytes) { printf("SBC data: more bytes read %u than free bytes in buffer %u", size, numFreeBytes); } (void)memcpy(state->frame_buffer + state->bytes_in_frame_buffer, buffer, size); state->bytes_in_frame_buffer += size; } // returns position of mSBC sync word static int msbc_find_h2_sync(const uint8_t *frame_data, OI_UINT32 frame_bytes, int * sync_word_nr) { int syncword = mSBC_SYNCWORD; uint8_t h2_first_byte = 0; uint8_t h2_second_byte = 0; unsigned int i; for (i=0; i> 4; if ( ((hn>>1) & 0x05) == (hn & 0x05) ) { *sync_word_nr = ((hn & 0x04) >> 1) | (hn & 0x01); return i; } } } } h2_first_byte = h2_second_byte; h2_second_byte = frame_data[i]; } return -1; } static int msbc_find_sequence_of_zeros(const uint8_t *frame_data, OI_UINT32 frame_bytes, int seq_length) { int zero_seq_count = 0; unsigned int i; for (i=0; i= seq_length) return zero_seq_count; } else { zero_seq_count = 0; } } return 0; } static void msbc_decoder_drop_processed_bytes(struct sbc_decoder_state * decoder_state, uint16_t bytes_processed) { memmove(decoder_state->frame_buffer, decoder_state->frame_buffer + bytes_processed, decoder_state->bytes_in_frame_buffer-bytes_processed); decoder_state->bytes_in_frame_buffer -= bytes_processed; } static int16_t msbc_crop_sample(float val){ float croped_val = val; if (croped_val > 32767.0) croped_val= 32767.0; if (croped_val < -32768.0) croped_val=-32768.0; return (int16_t) croped_val; } void msbc_plc_good_frame(struct sbc_plc_state *plc_state, int16_t *in, int16_t *out){ float val; int i = 0; plc_state->good_frames_nr++; plc_state->frame_count++; #ifdef OCTAVE_OUTPUT FILE * oct_file = NULL; if (plc_state->nbf>0){ oct_file = open_octave_file(plc_state, OCTAVE_FRAME_TYPE_GOOD); if (oct_file){ octave_fprintf_plot_history_frame(plc_state, oct_file, plc_state->frame_count); } } #endif if (plc_state->nbf>0) { for (i=0;ihist[SBC_LHIST+i]; } for (i = SBC_RT;i<(SBC_RT+SBC_OLAL);i++) { float left = plc_state->hist[SBC_LHIST+i]; float right = in[i]; val = (left*rcos[i-SBC_RT]) + (right*rcos[SBC_OLAL+SBC_RT-1-i]); out[i] = msbc_crop_sample(val); } } for (;ihist[SBC_LHIST+i] = out[i]; } // shift the history buffer for (i=0;ihist[i] = plc_state->hist[i+SBC_FS]; } #ifdef OCTAVE_OUTPUT if (oct_file){ octave_fprintf_plot_output(plc_state, oct_file); fclose(oct_file); } #endif plc_state->nbf=0; } static int msbc_decoder_get_num_samples_per_frame(struct sbc_decoder_state * state) { return state->decoder_context.common.frameInfo.nrof_blocks * state->decoder_context.common.frameInfo.nrof_subbands; } static int msbc_decoder_get_num_channels(struct sbc_decoder_state * state) { return state->decoder_context.common.frameInfo.nrof_channels; } static int msbc_decoder_get_sample_rate(struct sbc_decoder_state * state) { return state->decoder_context.common.frameInfo.frequency; } void msbc_decoder_process_msbc_data(int packet_status_flag, uint8_t * buffer, int size) { int h2_syncword = 0,h2_sync_pos = 0,zero_seq_found = 0,bytes_missing = 0,bytes_to_append = 0; int input_bytes = size; int bad_frame = 0; uint16_t undecoding_bytes = 0,bytes_processed = 0; const uint8_t *frame_data; const unsigned int MSBC_FRAME_SIZE = 60; struct sbc_decoder_state * decoder_state = &sbc_internal_decoder_state; while (input_bytes > 0) { bytes_missing = MSBC_FRAME_SIZE - decoder_state->bytes_in_frame_buffer; bytes_to_append = (input_bytes < bytes_missing ? input_bytes : bytes_missing); if (bytes_to_append) { msbc_append_received_data(decoder_state, buffer, bytes_to_append); buffer += bytes_to_append; input_bytes -= bytes_to_append; } if (decoder_state->bytes_in_frame_buffer < MSBC_FRAME_SIZE) break; undecoding_bytes = decoder_state->bytes_in_frame_buffer; frame_data = decoder_state->frame_buffer; // testing only - corrupt frame periodically //btstack_sbc_decoder_bluedroid_simulate_error(frame_data); // assert frame looks like this: 01 x8 AD [rest of frame 56 bytes] 00 h2_sync_pos = msbc_find_h2_sync(frame_data, decoder_state->bytes_in_frame_buffer, &h2_syncword); if (h2_sync_pos < 0) { // no sync found, discard all but last 2 bytes bytes_processed = decoder_state->bytes_in_frame_buffer - 2; msbc_decoder_drop_processed_bytes(decoder_state, bytes_processed); // don't try PLC without at least a single good frame if (decoder_state->first_good_frame_found){ decoder_state->msbc_bad_bytes += bytes_processed; } continue; } zero_seq_found = msbc_find_sequence_of_zeros(frame_data, decoder_state->bytes_in_frame_buffer, 20); // after first valid frame, zero sequences count as bad frames if (decoder_state->first_good_frame_found) { bad_frame = zero_seq_found || packet_status_flag; } if (bad_frame) { // stats if (zero_seq_found) { decoder_state->zero_frames_nr++; } else { decoder_state->bad_frames_nr++; } #ifdef LOG_FRAME_STATUS if (zero_seq_found) { printf("%d : ZERO FRAME\n", decoder_state->h2_sequence_nr); } else { printf("%d : BAD FRAME\n", decoder_state->h2_sequence_nr); } #endif // retry after dropping 3 byte sync bytes_processed = 3; msbc_decoder_drop_processed_bytes(decoder_state, bytes_processed); decoder_state->msbc_bad_bytes += bytes_processed; // log_info("Trace bad frame"); continue; } //ready to decode frame OI_STATUS status = OI_CODEC_SBC_DecodeFrame(&(decoder_state->decoder_context), &frame_data, &(decoder_state->bytes_in_frame_buffer), decoder_state->pcm_plc_data, &(decoder_state->pcm_bytes)); bytes_processed = undecoding_bytes - decoder_state->bytes_in_frame_buffer; // log_info("Trace decode status %u, processed %u (bad bytes %u), bytes in buffer %u", (int) status, bytes_processed, decoder_state->msbc_bad_bytes, decoder_state->bytes_in_frame_buffer); switch(status) { case 0: // synced decoder_state->first_good_frame_found = 1; // get rid of padding byte, not processed by SBC decoder decoder_state->bytes_in_frame_buffer = 0; // restart counting bad bytes decoder_state->msbc_bad_bytes = 0; // feed good frame into PLC history msbc_plc_good_frame(&decoder_state->plc_state, decoder_state->pcm_plc_data, decoder_state->pcm_data); // deliver PCM data decoder_state->handle_pcm_data(decoder_state->pcm_data, msbc_decoder_get_num_samples_per_frame(decoder_state), msbc_decoder_get_num_channels(decoder_state), msbc_decoder_get_sample_rate(decoder_state), decoder_state->context); // stats decoder_state->good_frames_nr++; continue; case OI_CODEC_SBC_CHECKSUM_MISMATCH: // The next frame is somehow corrupt. printf("OI_CODEC_SBC_CHECKSUM_MISMATCH"); // Did the codec consume any bytes? if (bytes_processed > 0){ // Good. Nothing to do. } else { // Skip the bogus frame by skipping the header. bytes_processed = 1; } break; case OI_STATUS_INVALID_PARAMETERS: // This caused by corrupt frames. // The codec apparently does not recover from this. // Re-initialize the codec. printf("SBC decode: invalid parameters: resetting codec"); if (OI_CODEC_mSBC_DecoderReset(&(decoder_state->decoder_context), decoder_state->decoder_data, sizeof(decoder_state->decoder_data)) != OI_STATUS_SUCCESS) { printf("SBC decode: resetting codec failed"); } break; default: printf("Frame decode error: %d", status); break; } // on success, while loop was restarted, so all processed bytes have been "bad" decoder_state->msbc_bad_bytes += bytes_processed; // drop processed bytes from frame buffer msbc_decoder_drop_processed_bytes(decoder_state, bytes_processed); } } int msbc_decoder_init(msbc_decoder_data_cb cb) { struct sbc_decoder_state * decoder_state = &sbc_internal_decoder_state; OI_STATUS status = OI_STATUS_SUCCESS; status = OI_CODEC_mSBC_DecoderReset(&(decoder_state->decoder_context), decoder_state->decoder_data, sizeof(decoder_state->decoder_data)); decoder_state->bytes_in_frame_buffer = 0; decoder_state->pcm_bytes = sizeof(decoder_state->pcm_data); decoder_state->h2_sequence_nr = -1; decoder_state->first_good_frame_found = 0; decoder_state->handle_pcm_data = cb; decoder_state->context = NULL; decoder_state->plc_state.nbf = 0; decoder_state->plc_state.bestlag = 0; memset(decoder_state->plc_state.hist,0,sizeof(decoder_state->plc_state.hist)); return (int)status; }