188a9940aSMilanka Ringwald /* 288a9940aSMilanka Ringwald * Copyright (C) 2014 BlueKitchen GmbH 388a9940aSMilanka Ringwald * 488a9940aSMilanka Ringwald * Redistribution and use in source and binary forms, with or without 588a9940aSMilanka Ringwald * modification, are permitted provided that the following conditions 688a9940aSMilanka Ringwald * are met: 788a9940aSMilanka Ringwald * 888a9940aSMilanka Ringwald * 1. Redistributions of source code must retain the above copyright 988a9940aSMilanka Ringwald * notice, this list of conditions and the following disclaimer. 1088a9940aSMilanka Ringwald * 2. Redistributions in binary form must reproduce the above copyright 1188a9940aSMilanka Ringwald * notice, this list of conditions and the following disclaimer in the 1288a9940aSMilanka Ringwald * documentation and/or other materials provided with the distribution. 1388a9940aSMilanka Ringwald * 3. Neither the name of the copyright holders nor the names of 1488a9940aSMilanka Ringwald * contributors may be used to endorse or promote products derived 1588a9940aSMilanka Ringwald * from this software without specific prior written permission. 1688a9940aSMilanka Ringwald * 4. Any redistribution, use, or modification is done solely for 1788a9940aSMilanka Ringwald * personal benefit and not for any commercial purpose or for 1888a9940aSMilanka Ringwald * monetary gain. 1988a9940aSMilanka Ringwald * 2088a9940aSMilanka Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 2188a9940aSMilanka Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2288a9940aSMilanka Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 2388a9940aSMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 2488a9940aSMilanka Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 2588a9940aSMilanka Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 2688a9940aSMilanka Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 2788a9940aSMilanka Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 2888a9940aSMilanka Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2988a9940aSMilanka Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 3088a9940aSMilanka Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3188a9940aSMilanka Ringwald * SUCH DAMAGE. 3288a9940aSMilanka Ringwald * 3388a9940aSMilanka Ringwald * Please inquire about commercial licensing options at 3488a9940aSMilanka Ringwald * [email protected] 3588a9940aSMilanka Ringwald * 3688a9940aSMilanka Ringwald */ 3788a9940aSMilanka Ringwald 3888a9940aSMilanka Ringwald // ***************************************************************************** 3988a9940aSMilanka Ringwald // 4088a9940aSMilanka Ringwald // SBC decoder tests 4188a9940aSMilanka Ringwald // 4288a9940aSMilanka Ringwald // ***************************************************************************** 4388a9940aSMilanka Ringwald 4488a9940aSMilanka Ringwald #include "btstack_config.h" 4588a9940aSMilanka Ringwald 4688a9940aSMilanka Ringwald #include <stdint.h> 4788a9940aSMilanka Ringwald #include <stdio.h> 4888a9940aSMilanka Ringwald #include <stdlib.h> 4988a9940aSMilanka Ringwald #include <string.h> 5088a9940aSMilanka Ringwald #include <fcntl.h> 5188a9940aSMilanka Ringwald #include <unistd.h> 5288a9940aSMilanka Ringwald #include "oi_codec_sbc.h" 5388a9940aSMilanka Ringwald #include "oi_assert.h" 5488a9940aSMilanka Ringwald 55091c1bfdSMilanka Ringwald static uint8_t read_buffer[6000]; 56091c1bfdSMilanka Ringwald static uint8_t frame_buffer[5000]; 57*dc2354f3SMilanka Ringwald static OI_INT16 pcm_data[1000]; 58*dc2354f3SMilanka Ringwald static OI_UINT32 pcm_bytes = sizeof(pcm_data); 5922d3119aSMilanka Ringwald 6088a9940aSMilanka Ringwald static uint8_t buf[4]; 6188a9940aSMilanka Ringwald 62*dc2354f3SMilanka Ringwald static OI_UINT32 decoder_data[10000]; 63*dc2354f3SMilanka Ringwald static OI_CODEC_SBC_DECODER_CONTEXT decoder_context; 6488a9940aSMilanka Ringwald 65082d19a8SMilanka Ringwald typedef struct wav_writer_state { 66082d19a8SMilanka Ringwald FILE * wav_file; 67082d19a8SMilanka Ringwald int sample_rate; 68082d19a8SMilanka Ringwald int total_num_samples; 69082d19a8SMilanka Ringwald } wav_writer_state_t; 70082d19a8SMilanka Ringwald 7122d3119aSMilanka Ringwald typedef struct { 72*dc2354f3SMilanka Ringwald OI_UINT32 bytes_read; 73*dc2354f3SMilanka Ringwald OI_UINT32 bytes_in_frame; 74*dc2354f3SMilanka Ringwald const OI_BYTE *frame_data; 75082d19a8SMilanka Ringwald void * context; 76082d19a8SMilanka Ringwald void (*handle_pcm_data)(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context); 7722d3119aSMilanka Ringwald } sbc_state_t; 7822d3119aSMilanka Ringwald static sbc_state_t state; 7922d3119aSMilanka Ringwald 8022d3119aSMilanka Ringwald 8188a9940aSMilanka Ringwald static void show_usage(void){ 8288a9940aSMilanka Ringwald printf("Usage: ./sbc_decoder_test input.sbc"); 8388a9940aSMilanka Ringwald } 8488a9940aSMilanka Ringwald 8588a9940aSMilanka Ringwald static ssize_t __read(int fd, void *buf, size_t count){ 8688a9940aSMilanka Ringwald ssize_t len, pos = 0; 8788a9940aSMilanka Ringwald 8888a9940aSMilanka Ringwald while (count > 0) { 8988a9940aSMilanka Ringwald len = read(fd, buf + pos, count); 9088a9940aSMilanka Ringwald if (len <= 0) 9188a9940aSMilanka Ringwald return pos; 9288a9940aSMilanka Ringwald 9388a9940aSMilanka Ringwald count -= len; 9488a9940aSMilanka Ringwald pos += len; 9588a9940aSMilanka Ringwald } 9688a9940aSMilanka Ringwald return pos; 9788a9940aSMilanka Ringwald } 9888a9940aSMilanka Ringwald 9988a9940aSMilanka Ringwald void little_endian_store_16(uint8_t *buffer, uint16_t pos, uint16_t value){ 10088a9940aSMilanka Ringwald buffer[pos++] = value; 10188a9940aSMilanka Ringwald buffer[pos++] = value >> 8; 10288a9940aSMilanka Ringwald } 10388a9940aSMilanka Ringwald 10488a9940aSMilanka Ringwald void little_endian_store_32(uint8_t *buffer, uint16_t pos, uint32_t value){ 10588a9940aSMilanka Ringwald buffer[pos++] = value; 10688a9940aSMilanka Ringwald buffer[pos++] = value >> 8; 10788a9940aSMilanka Ringwald buffer[pos++] = value >> 16; 10888a9940aSMilanka Ringwald buffer[pos++] = value >> 24; 10988a9940aSMilanka Ringwald } 11088a9940aSMilanka Ringwald 11188a9940aSMilanka Ringwald void little_endian_fstore_16(FILE *wav_file, uint16_t value){ 11288a9940aSMilanka Ringwald little_endian_store_32(buf, 0, value); 11388a9940aSMilanka Ringwald fwrite(&buf, 1, 2, wav_file); 11488a9940aSMilanka Ringwald } 11588a9940aSMilanka Ringwald 11688a9940aSMilanka Ringwald void little_endian_fstore_32(FILE *wav_file, uint32_t value){ 11788a9940aSMilanka Ringwald little_endian_store_32(buf, 0, value); 11888a9940aSMilanka Ringwald fwrite(&buf, 1, 4, wav_file); 11988a9940aSMilanka Ringwald } 12088a9940aSMilanka Ringwald 121435e3c4eSMilanka Ringwald 122082d19a8SMilanka Ringwald static void write_wav_header(FILE * wav_file, int total_num_samples, int num_channels, int sample_rate){ 12388a9940aSMilanka Ringwald unsigned int bytes_per_sample = 2; 12488a9940aSMilanka Ringwald /* write RIFF header */ 12588a9940aSMilanka Ringwald fwrite("RIFF", 1, 4, wav_file); 12688a9940aSMilanka Ringwald // num_samples = blocks * subbands 127082d19a8SMilanka Ringwald uint32_t data_bytes = (uint32_t) (bytes_per_sample * total_num_samples * num_channels); 12888a9940aSMilanka Ringwald little_endian_fstore_32(wav_file, data_bytes + 36); 12988a9940aSMilanka Ringwald fwrite("WAVE", 1, 4, wav_file); 13088a9940aSMilanka Ringwald 13188a9940aSMilanka Ringwald int byte_rate = sample_rate * num_channels * bytes_per_sample; 13288a9940aSMilanka Ringwald int bits_per_sample = 8 * bytes_per_sample; 13388a9940aSMilanka Ringwald int block_align = num_channels * bits_per_sample; 13488a9940aSMilanka Ringwald int fmt_length = 16; 13588a9940aSMilanka Ringwald int fmt_format_tag = 1; // PCM 13688a9940aSMilanka Ringwald 13788a9940aSMilanka Ringwald /* write fmt chunk */ 13888a9940aSMilanka Ringwald fwrite("fmt ", 1, 4, wav_file); 13988a9940aSMilanka Ringwald little_endian_fstore_32(wav_file, fmt_length); 14088a9940aSMilanka Ringwald little_endian_fstore_16(wav_file, fmt_format_tag); 14188a9940aSMilanka Ringwald little_endian_fstore_16(wav_file, num_channels); 14288a9940aSMilanka Ringwald little_endian_fstore_32(wav_file, sample_rate); 14388a9940aSMilanka Ringwald little_endian_fstore_32(wav_file, byte_rate); 14488a9940aSMilanka Ringwald little_endian_fstore_16(wav_file, block_align); 14588a9940aSMilanka Ringwald little_endian_fstore_16(wav_file, bits_per_sample); 14688a9940aSMilanka Ringwald 14788a9940aSMilanka Ringwald /* write data chunk */ 14888a9940aSMilanka Ringwald fwrite("data", 1, 4, wav_file); 14988a9940aSMilanka Ringwald little_endian_fstore_32(wav_file, data_bytes); 15088a9940aSMilanka Ringwald } 15188a9940aSMilanka Ringwald 152082d19a8SMilanka Ringwald static void write_wav_data(FILE * wav_file, int num_samples, int num_channels, int16_t * data){ 15388a9940aSMilanka Ringwald int i; 15488a9940aSMilanka Ringwald for (i=0; i < num_samples; i++){ 15588a9940aSMilanka Ringwald little_endian_fstore_16(wav_file, (uint16_t)data[i]); 15688a9940aSMilanka Ringwald if (num_channels == 2){ 15788a9940aSMilanka Ringwald little_endian_fstore_16(wav_file, (uint16_t)data); 15888a9940aSMilanka Ringwald } 15988a9940aSMilanka Ringwald } 16088a9940aSMilanka Ringwald } 16188a9940aSMilanka Ringwald 162082d19a8SMilanka Ringwald static void handle_pcm_data(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context){ 163082d19a8SMilanka Ringwald wav_writer_state_t * wav_writer_state = (wav_writer_state_t*) context; 164082d19a8SMilanka Ringwald write_wav_data(wav_writer_state->wav_file, num_samples, num_channels, data); 165082d19a8SMilanka Ringwald wav_writer_state->total_num_samples+=num_samples; 166082d19a8SMilanka Ringwald } 167082d19a8SMilanka Ringwald 1687a2baf07SMilanka Ringwald static void append_received_sbc_data(sbc_state_t * state, uint8_t * buffer, int size){ 169*dc2354f3SMilanka Ringwald int numFreeBytes = sizeof(frame_buffer) - state->bytes_in_frame; 1707a2baf07SMilanka Ringwald 1717a2baf07SMilanka Ringwald if (size > numFreeBytes){ 1727a2baf07SMilanka Ringwald printf("sbc data: more bytes read %u than free bytes in buffer %u", size, numFreeBytes); 1737a2baf07SMilanka Ringwald exit(10); 1747a2baf07SMilanka Ringwald } 1757a2baf07SMilanka Ringwald 176*dc2354f3SMilanka Ringwald memcpy(frame_buffer + state->bytes_in_frame, buffer, size); 177*dc2354f3SMilanka Ringwald state->bytes_in_frame += size; 178*dc2354f3SMilanka Ringwald state->bytes_read = state->bytes_in_frame; 179*dc2354f3SMilanka Ringwald state->frame_data = frame_buffer; 1807a2baf07SMilanka Ringwald } 1817a2baf07SMilanka Ringwald 182*dc2354f3SMilanka Ringwald static inline int num_samples(OI_CODEC_SBC_DECODER_CONTEXT * context){ 183*dc2354f3SMilanka Ringwald return context->common.frameInfo.nrof_blocks * context->common.frameInfo.nrof_subbands; 184*dc2354f3SMilanka Ringwald } 185091c1bfdSMilanka Ringwald 186*dc2354f3SMilanka Ringwald static inline int num_channels(OI_CODEC_SBC_DECODER_CONTEXT * context){ 187*dc2354f3SMilanka Ringwald return context->common.frameInfo.nrof_channels; 188*dc2354f3SMilanka Ringwald } 189*dc2354f3SMilanka Ringwald 190*dc2354f3SMilanka Ringwald static inline int sample_rate(OI_CODEC_SBC_DECODER_CONTEXT * context){ 191*dc2354f3SMilanka Ringwald return context->common.frameInfo.frequency; 192*dc2354f3SMilanka Ringwald } 193*dc2354f3SMilanka Ringwald 194*dc2354f3SMilanka Ringwald 195*dc2354f3SMilanka Ringwald void OI_AssertFail(char* file, int line, char* reason){ 196*dc2354f3SMilanka Ringwald printf("AssertFail file %s, line %d, reason %s\n", file, line, reason); 197*dc2354f3SMilanka Ringwald } 198*dc2354f3SMilanka Ringwald 199*dc2354f3SMilanka Ringwald void init_sbc_state(sbc_state_t * state, void (*callback)(int16_t * data, int num_samples, int num_channels, int sample_rate, void * context), void * context){ 200*dc2354f3SMilanka Ringwald state->bytes_in_frame = 0; 201*dc2354f3SMilanka Ringwald state->bytes_read = 0; 202*dc2354f3SMilanka Ringwald state->frame_data = NULL; 203*dc2354f3SMilanka Ringwald state->handle_pcm_data = callback; 204*dc2354f3SMilanka Ringwald state->context = context; 205*dc2354f3SMilanka Ringwald } 206*dc2354f3SMilanka Ringwald 207*dc2354f3SMilanka Ringwald void handle_received_sbc_chunk(sbc_state_t * state, uint8_t * buffer, int size){ 208*dc2354f3SMilanka Ringwald int bytes_read = size; 209*dc2354f3SMilanka Ringwald while (bytes_read > 0){ 210*dc2354f3SMilanka Ringwald int space_in_frame_buffer = sizeof(frame_buffer) - state->bytes_in_frame; 211*dc2354f3SMilanka Ringwald int bytes_to_append = space_in_frame_buffer > bytes_read ? bytes_read : space_in_frame_buffer; 212*dc2354f3SMilanka Ringwald append_received_sbc_data(state, buffer, bytes_to_append); 213*dc2354f3SMilanka Ringwald 214*dc2354f3SMilanka Ringwald while (1){ 215*dc2354f3SMilanka Ringwald OI_STATUS status = OI_CODEC_SBC_DecodeFrame(&decoder_context, &(state->frame_data), &(state->bytes_in_frame), pcm_data, &pcm_bytes); 216091c1bfdSMilanka Ringwald 217091c1bfdSMilanka Ringwald if (status != 0){ 218091c1bfdSMilanka Ringwald if (status != OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA && status != OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA){ 219*dc2354f3SMilanka Ringwald OI_CODEC_SBC_DumpConfig(&(decoder_context.common.frameInfo)); 220091c1bfdSMilanka Ringwald printf("Frame decode error %d\n", status); 221091c1bfdSMilanka Ringwald break; 222091c1bfdSMilanka Ringwald } 223*dc2354f3SMilanka Ringwald // printf("Not enough data, read next %u bytes, move %d bytes\n", state->bytes_read-state->bytes_in_frame, state->bytes_in_frame); 224*dc2354f3SMilanka Ringwald memmove(frame_buffer, frame_buffer + state->bytes_read - state->bytes_in_frame, state->bytes_in_frame); 225091c1bfdSMilanka Ringwald break; 226091c1bfdSMilanka Ringwald } 227*dc2354f3SMilanka Ringwald state->handle_pcm_data(pcm_data, num_samples(&decoder_context), num_channels(&decoder_context), sample_rate(&decoder_context), state->context); 228*dc2354f3SMilanka Ringwald } 229091c1bfdSMilanka Ringwald 230*dc2354f3SMilanka Ringwald memmove(buffer, buffer + bytes_to_append, size - bytes_to_append); 231*dc2354f3SMilanka Ringwald bytes_read -= bytes_to_append; 232091c1bfdSMilanka Ringwald } 233091c1bfdSMilanka Ringwald } 2347a2baf07SMilanka Ringwald 2357a2baf07SMilanka Ringwald 23688a9940aSMilanka Ringwald int main (int argc, const char * argv[]){ 23788a9940aSMilanka Ringwald if (argc < 2){ 23888a9940aSMilanka Ringwald show_usage(); 23988a9940aSMilanka Ringwald return -1; 24088a9940aSMilanka Ringwald } 24188a9940aSMilanka Ringwald 24288a9940aSMilanka Ringwald const char * sbc_filename = argv[1]; 24388a9940aSMilanka Ringwald const char * wav_filename = argv[2]; 24488a9940aSMilanka Ringwald 24588a9940aSMilanka Ringwald 24688a9940aSMilanka Ringwald int fd = open(sbc_filename, O_RDONLY); 24788a9940aSMilanka Ringwald if (fd < 0) { 24888a9940aSMilanka Ringwald printf("Can't open file %s", sbc_filename); 24988a9940aSMilanka Ringwald return -1; 25088a9940aSMilanka Ringwald } 25188a9940aSMilanka Ringwald printf("Open sbc file: %s\n", sbc_filename); 25288a9940aSMilanka Ringwald 253*dc2354f3SMilanka Ringwald //OI_STATUS status = OI_CODEC_SBC_DecoderReset(&context, decoder_data, sizeof(decoder_data), 1, 1, FALSE); 25488a9940aSMilanka Ringwald 255*dc2354f3SMilanka Ringwald OI_STATUS status = OI_CODEC_mSBC_DecoderReset(&decoder_context, decoder_data, sizeof(decoder_data)); 25688a9940aSMilanka Ringwald if (status != 0){ 25788a9940aSMilanka Ringwald printf("Reset decoder error %d\n", status); 25888a9940aSMilanka Ringwald return -1; 25988a9940aSMilanka Ringwald } 26022d3119aSMilanka Ringwald 26188a9940aSMilanka Ringwald FILE * wav_file = fopen(wav_filename, "wb"); 262082d19a8SMilanka Ringwald wav_writer_state_t wav_writer_state; 263082d19a8SMilanka Ringwald wav_writer_state.wav_file = wav_file; 264082d19a8SMilanka Ringwald init_sbc_state(&state, &handle_pcm_data, (void*)&wav_writer_state); 265082d19a8SMilanka Ringwald write_wav_header(wav_writer_state.wav_file, 0, 0, 0); 26622d3119aSMilanka Ringwald 2677a2baf07SMilanka Ringwald while (1){ 268*dc2354f3SMilanka Ringwald // get next chunk 2697a2baf07SMilanka Ringwald int bytes_read = __read(fd, read_buffer, sizeof(read_buffer)); 2707a2baf07SMilanka Ringwald if (0 >= bytes_read) break; 271*dc2354f3SMilanka Ringwald // process chunk 272*dc2354f3SMilanka Ringwald handle_received_sbc_chunk(&state, read_buffer, bytes_read); 27388a9940aSMilanka Ringwald } 27422d3119aSMilanka Ringwald 27588a9940aSMilanka Ringwald rewind(wav_file); 276*dc2354f3SMilanka Ringwald write_wav_header(wav_writer_state.wav_file, wav_writer_state.total_num_samples, num_channels(&decoder_context), sample_rate(&decoder_context)); 27788a9940aSMilanka Ringwald 27888a9940aSMilanka Ringwald fclose(wav_file); 27988a9940aSMilanka Ringwald close(fd); 280082d19a8SMilanka Ringwald 281*dc2354f3SMilanka Ringwald int frame_count = wav_writer_state.total_num_samples/num_samples(&decoder_context); 282082d19a8SMilanka Ringwald printf("Write %d frames to wav file: %s\n", frame_count, wav_filename); 283082d19a8SMilanka Ringwald 28488a9940aSMilanka Ringwald } 285