xref: /btstack/test/sbc/sbc_decoder_test.c (revision 22d3119a2b68d66bb67f51eac9994e0633cfcc27)
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     int enough_data;
71     const OI_BYTE *frameData;
72 } sbc_state_t;
73 static sbc_state_t state;
74 
75 
76 void OI_AssertFail(char* file, int line, char* reason){
77     printf("AssertFail file %s, line %d, reason %s\n", file, line, reason);
78 }
79 
80 static void show_usage(void){
81     printf("Usage: ./sbc_decoder_test input.sbc");
82 }
83 
84 static ssize_t __read(int fd, void *buf, size_t count){
85     ssize_t len, pos = 0;
86 
87     while (count > 0) {
88         len = read(fd, buf + pos, count);
89         if (len <= 0)
90             return pos;
91 
92         count -= len;
93         pos   += len;
94     }
95     return pos;
96 }
97 
98 void little_endian_store_16(uint8_t *buffer, uint16_t pos, uint16_t value){
99     buffer[pos++] = value;
100     buffer[pos++] = value >> 8;
101 }
102 
103 void little_endian_store_32(uint8_t *buffer, uint16_t pos, uint32_t value){
104     buffer[pos++] = value;
105     buffer[pos++] = value >> 8;
106     buffer[pos++] = value >> 16;
107     buffer[pos++] = value >> 24;
108 }
109 
110 void little_endian_fstore_16(FILE *wav_file, uint16_t value){
111     little_endian_store_32(buf, 0, value);
112     fwrite(&buf, 1, 2, wav_file);
113 }
114 
115 void little_endian_fstore_32(FILE *wav_file, uint32_t value){
116     little_endian_store_32(buf, 0, value);
117     fwrite(&buf, 1, 4, wav_file);
118 }
119 
120 
121 static void write_wav_header(FILE * wav_file, OI_CODEC_SBC_DECODER_CONTEXT * decoderContext, int frame_count){
122     unsigned int bytes_per_sample = 2;
123     int num_samples = decoderContext->common.frameInfo.nrof_blocks * decoderContext->common.frameInfo.nrof_subbands;
124     int num_channels = decoderContext->common.frameInfo.nrof_channels;
125     int sample_rate = decoderContext->common.frameInfo.frequency;
126 
127     /* write RIFF header */
128     fwrite("RIFF", 1, 4, wav_file);
129     // num_samples = blocks * subbands
130     uint32_t data_bytes = (uint32_t) (bytes_per_sample * num_samples * frame_count * num_channels);
131     little_endian_fstore_32(wav_file, data_bytes + 36);
132     fwrite("WAVE", 1, 4, wav_file);
133 
134     int byte_rate = sample_rate * num_channels * bytes_per_sample;
135     int bits_per_sample = 8 * bytes_per_sample;
136     int block_align = num_channels * bits_per_sample;
137     int fmt_length = 16;
138     int fmt_format_tag = 1; // PCM
139 
140     /* write fmt chunk */
141     fwrite("fmt ", 1, 4, wav_file);
142     little_endian_fstore_32(wav_file, fmt_length);
143     little_endian_fstore_16(wav_file, fmt_format_tag);
144     little_endian_fstore_16(wav_file, num_channels);
145     little_endian_fstore_32(wav_file, sample_rate);
146     little_endian_fstore_32(wav_file, byte_rate);
147     little_endian_fstore_16(wav_file, block_align);
148     little_endian_fstore_16(wav_file, bits_per_sample);
149 
150     /* write data chunk */
151     fwrite("data", 1, 4, wav_file);
152     little_endian_fstore_32(wav_file, data_bytes);
153 }
154 
155 static void write_wav_data(FILE * wav_file, OI_CODEC_SBC_DECODER_CONTEXT * decoderContext, int16_t * data){
156     int num_samples = decoderContext->common.frameInfo.nrof_blocks * decoderContext->common.frameInfo.nrof_subbands;
157     int num_channels = decoderContext->common.frameInfo.nrof_channels;
158     int i;
159     for (i=0; i < num_samples; i++){
160         little_endian_fstore_16(wav_file, (uint16_t)data[i]);
161         if (num_channels == 2){
162             little_endian_fstore_16(wav_file, (uint16_t)data);
163         }
164     }
165 }
166 
167 
168 
169 static uint8_t read_buffer[200];
170 
171 static int read_next_sbc_chunk(int fd, sbc_state_t * state){
172     // read data into seperate buffer
173     state->bytesRead = __read(fd, data + state->frameBytes, sizeof(data) - state->frameBytes);
174     state->frameBytes += state->bytesRead;
175     state->bytesRead = state->frameBytes;
176     state->frameData = data;
177     state->enough_data = 1;
178     return state->frameBytes != 0;
179 
180     // uint16_t size = __read(fd, read_buffer, sizeof(read_buffer));
181     // return size != 0;
182 }
183 
184 
185 static void handle_received_sbc_data(sbc_state_t * state, uint8_t * read_buffer, int read_buffer_len){
186     int numFreeBytes = sizeof(data) - state->frameBytes;
187 
188     if (numFreeBytes >= read_buffer_len){
189         memcpy(data + state->frameBytes, read_buffer, read_buffer_len);
190         state->bytesRead = read_buffer_len;
191         state->inputBufferBytes = 0;
192     } else {
193         memcpy(data + state->frameBytes, read_buffer, numFreeBytes);
194         state->bytesRead = numFreeBytes;
195         state->inputBufferBytes = read_buffer_len - numFreeBytes;
196     }
197     state->frameBytes += state->bytesRead;
198     state->bytesRead = state->frameBytes;
199     state->frameData = data;
200     state->enough_data = 1;
201 }
202 
203 // {
204 //     while (not done){
205 //         read some data (max size) using __read or even direct read
206 //         handle received sbc data
207 //     }
208 // }
209 
210 static void init_sbc_state(sbc_state_t * state){
211     state->frameBytes = 0;
212     state->bytesRead = 0;
213     state->frame_count = 0;
214     state->enough_data = 0;
215     state->inputBufferBytes = 0;
216     state->frameData = NULL;
217 }
218 
219 int main (int argc, const char * argv[]){
220     if (argc < 2){
221         show_usage();
222         return -1;
223     }
224 
225     const char * sbc_filename = argv[1];
226     const char * wav_filename = argv[2];
227 
228 
229     int fd = open(sbc_filename, O_RDONLY);
230     if (fd < 0) {
231         printf("Can't open file %s", sbc_filename);
232         return -1;
233     }
234     printf("Open sbc file: %s\n", sbc_filename);
235 
236     //OI_STATUS status = OI_CODEC_SBC_DecoderReset(&context, decoderData, sizeof(decoderData), 1, 1, FALSE);
237 
238     OI_STATUS status = OI_CODEC_mSBC_DecoderReset(&context, decoderData, sizeof(decoderData));
239     if (status != 0){
240         printf("Reset decoder error %d\n", status);
241         return -1;
242     }
243 
244     FILE * wav_file = fopen(wav_filename, "wb");
245 
246     init_sbc_state(&state);
247 
248     while (read_next_sbc_chunk(fd, &state)){
249         while (state.frameBytes != 0 && state.enough_data){
250 
251             status = OI_CODEC_SBC_DecodeFrame(&context, &state.frameData, &state.frameBytes, pcmData, &pcmBytes);
252 
253             if (status != 0){
254                 if (status != OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA && status != OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA){
255                     OI_CODEC_SBC_DumpConfig(&(context. common.frameInfo));
256                     printf("Frame decode error %d\n", status);
257                     break;
258                 }
259                 printf("Not enough data, read next %u bytes\n", state.bytesRead-state.frameBytes);
260                 state.enough_data = 0;
261                 memmove(data, data + state.bytesRead - state.frameBytes, state.frameBytes);
262                 continue;
263             }
264 
265             if (state.frame_count == 0){
266                 write_wav_header(wav_file, &context, 0);
267             }
268             write_wav_data(wav_file, &context, pcmData);
269             state.frame_count++;
270         }
271 
272     }
273 
274     rewind(wav_file);
275     write_wav_header(wav_file, &context, state.frame_count);
276 
277     fclose(wav_file);
278     printf("Write %d frames to wav file: %s\n", state.frame_count, wav_filename);
279 
280     close(fd);
281 }
282