1 /* 2 * Copyright (C) 2014 BlueKitchen GmbH 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the copyright holders nor the names of 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 4. Any redistribution, use, or modification is done solely for 17 * personal benefit and not for any commercial purpose or for 18 * monetary gain. 19 * 20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24 * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * Please inquire about commercial licensing options at 34 * [email protected] 35 * 36 */ 37 38 // ***************************************************************************** 39 // 40 // SBC decoder tests 41 // 42 // ***************************************************************************** 43 44 #include "btstack_config.h" 45 46 #include <stdint.h> 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <string.h> 50 #include <fcntl.h> 51 #include <unistd.h> 52 #include "oi_codec_sbc.h" 53 #include "oi_assert.h" 54 55 56 static uint8_t data[10000]; 57 static OI_INT16 pcmData[1000]; 58 static OI_UINT32 pcmBytes = sizeof(pcmData); 59 60 static uint8_t buf[4]; 61 62 static OI_UINT32 decoderData[10000]; 63 static OI_CODEC_SBC_DECODER_CONTEXT context; 64 65 typedef struct { 66 OI_UINT32 bytesRead; 67 OI_UINT32 frameBytes; 68 OI_UINT32 inputBufferBytes; 69 int frame_count; 70 const OI_BYTE *frameData; 71 } sbc_state_t; 72 static sbc_state_t state; 73 74 75 void OI_AssertFail(char* file, int line, char* reason){ 76 printf("AssertFail file %s, line %d, reason %s\n", file, line, reason); 77 } 78 79 static void show_usage(void){ 80 printf("Usage: ./sbc_decoder_test input.sbc"); 81 } 82 83 static ssize_t __read(int fd, void *buf, size_t count){ 84 ssize_t len, pos = 0; 85 86 while (count > 0) { 87 len = read(fd, buf + pos, count); 88 if (len <= 0) 89 return pos; 90 91 count -= len; 92 pos += len; 93 } 94 return pos; 95 } 96 97 void little_endian_store_16(uint8_t *buffer, uint16_t pos, uint16_t value){ 98 buffer[pos++] = value; 99 buffer[pos++] = value >> 8; 100 } 101 102 void little_endian_store_32(uint8_t *buffer, uint16_t pos, uint32_t value){ 103 buffer[pos++] = value; 104 buffer[pos++] = value >> 8; 105 buffer[pos++] = value >> 16; 106 buffer[pos++] = value >> 24; 107 } 108 109 void little_endian_fstore_16(FILE *wav_file, uint16_t value){ 110 little_endian_store_32(buf, 0, value); 111 fwrite(&buf, 1, 2, wav_file); 112 } 113 114 void little_endian_fstore_32(FILE *wav_file, uint32_t value){ 115 little_endian_store_32(buf, 0, value); 116 fwrite(&buf, 1, 4, wav_file); 117 } 118 119 120 static void write_wav_header(FILE * wav_file, OI_CODEC_SBC_DECODER_CONTEXT * decoderContext, int frame_count){ 121 unsigned int bytes_per_sample = 2; 122 int num_samples = decoderContext->common.frameInfo.nrof_blocks * decoderContext->common.frameInfo.nrof_subbands; 123 int num_channels = decoderContext->common.frameInfo.nrof_channels; 124 int sample_rate = decoderContext->common.frameInfo.frequency; 125 126 /* write RIFF header */ 127 fwrite("RIFF", 1, 4, wav_file); 128 // num_samples = blocks * subbands 129 uint32_t data_bytes = (uint32_t) (bytes_per_sample * num_samples * frame_count * num_channels); 130 little_endian_fstore_32(wav_file, data_bytes + 36); 131 fwrite("WAVE", 1, 4, wav_file); 132 133 int byte_rate = sample_rate * num_channels * bytes_per_sample; 134 int bits_per_sample = 8 * bytes_per_sample; 135 int block_align = num_channels * bits_per_sample; 136 int fmt_length = 16; 137 int fmt_format_tag = 1; // PCM 138 139 /* write fmt chunk */ 140 fwrite("fmt ", 1, 4, wav_file); 141 little_endian_fstore_32(wav_file, fmt_length); 142 little_endian_fstore_16(wav_file, fmt_format_tag); 143 little_endian_fstore_16(wav_file, num_channels); 144 little_endian_fstore_32(wav_file, sample_rate); 145 little_endian_fstore_32(wav_file, byte_rate); 146 little_endian_fstore_16(wav_file, block_align); 147 little_endian_fstore_16(wav_file, bits_per_sample); 148 149 /* write data chunk */ 150 fwrite("data", 1, 4, wav_file); 151 little_endian_fstore_32(wav_file, data_bytes); 152 } 153 154 static void write_wav_data(FILE * wav_file, OI_CODEC_SBC_DECODER_CONTEXT * decoderContext, int16_t * data){ 155 int num_samples = decoderContext->common.frameInfo.nrof_blocks * decoderContext->common.frameInfo.nrof_subbands; 156 int num_channels = decoderContext->common.frameInfo.nrof_channels; 157 int i; 158 for (i=0; i < num_samples; i++){ 159 little_endian_fstore_16(wav_file, (uint16_t)data[i]); 160 if (num_channels == 2){ 161 little_endian_fstore_16(wav_file, (uint16_t)data); 162 } 163 } 164 } 165 166 167 168 static uint8_t read_buffer[200]; 169 170 static void init_sbc_state(sbc_state_t * state){ 171 state->frameBytes = 0; 172 state->bytesRead = 0; 173 state->frame_count = 0; 174 state->inputBufferBytes = 0; 175 state->frameData = NULL; 176 } 177 178 static void append_received_sbc_data(sbc_state_t * state, uint8_t * buffer, int size){ 179 int numFreeBytes = sizeof(data) - state->frameBytes; 180 181 if (size > numFreeBytes){ 182 printf("sbc data: more bytes read %u than free bytes in buffer %u", size, numFreeBytes); 183 exit(10); 184 } 185 186 memcpy(data + state->frameBytes, buffer, size); 187 state->frameBytes += size; 188 state->bytesRead = state->frameBytes; 189 state->frameData = data; 190 } 191 192 193 194 int main (int argc, const char * argv[]){ 195 if (argc < 2){ 196 show_usage(); 197 return -1; 198 } 199 200 const char * sbc_filename = argv[1]; 201 const char * wav_filename = argv[2]; 202 203 204 int fd = open(sbc_filename, O_RDONLY); 205 if (fd < 0) { 206 printf("Can't open file %s", sbc_filename); 207 return -1; 208 } 209 printf("Open sbc file: %s\n", sbc_filename); 210 211 //OI_STATUS status = OI_CODEC_SBC_DecoderReset(&context, decoderData, sizeof(decoderData), 1, 1, FALSE); 212 213 OI_STATUS status = OI_CODEC_mSBC_DecoderReset(&context, decoderData, sizeof(decoderData)); 214 if (status != 0){ 215 printf("Reset decoder error %d\n", status); 216 return -1; 217 } 218 219 FILE * wav_file = fopen(wav_filename, "wb"); 220 221 init_sbc_state(&state); 222 223 while (1){ 224 225 int bytes_read = __read(fd, read_buffer, sizeof(read_buffer)); 226 if (0 >= bytes_read) break; 227 228 append_received_sbc_data(&state, read_buffer, bytes_read); 229 230 while (1){ 231 232 status = OI_CODEC_SBC_DecodeFrame(&context, &state.frameData, &state.frameBytes, pcmData, &pcmBytes); 233 234 if (status != 0){ 235 if (status != OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA && status != OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA){ 236 OI_CODEC_SBC_DumpConfig(&(context. common.frameInfo)); 237 printf("Frame decode error %d\n", status); 238 break; 239 } 240 241 printf("Not enough data, read next %u bytes, move %d bytes\n", state.bytesRead-state.frameBytes, state.frameBytes); 242 memmove(data, data + state.bytesRead - state.frameBytes, state.frameBytes); 243 break; 244 } 245 246 if (state.frame_count == 0){ 247 write_wav_header(wav_file, &context, 0); 248 } 249 write_wav_data(wav_file, &context, pcmData); 250 state.frame_count++; 251 } 252 253 } 254 255 rewind(wav_file); 256 write_wav_header(wav_file, &context, state.frame_count); 257 258 fclose(wav_file); 259 printf("Write %d frames to wav file: %s\n", state.frame_count, wav_filename); 260 261 close(fd); 262 } 263