• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  *  Bluetooth low-complexity, subband codec (SBC) library
4  *
5  *  Copyright (C) 2008-2010  Nokia Corporation
6  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
7  *
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, write to the Free Software
21  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22  *
23  */
24 
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28 
29 #include <stdio.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34 #include <stdint.h>
35 #include <string.h>
36 #include <libgen.h>
37 
38 #if __BYTE_ORDER == __LITTLE_ENDIAN
39 struct sbc_frame_hdr {
40 	uint8_t syncword:8;		/* Sync word */
41 	uint8_t subbands:1;		/* Subbands */
42 	uint8_t allocation_method:1;	/* Allocation method */
43 	uint8_t channel_mode:2;		/* Channel mode */
44 	uint8_t blocks:2;		/* Blocks */
45 	uint8_t sampling_frequency:2;	/* Sampling frequency */
46 	uint8_t bitpool:8;		/* Bitpool */
47 	uint8_t crc_check:8;		/* CRC check */
48 } __attribute__ ((packed));
49 #elif __BYTE_ORDER == __BIG_ENDIAN
50 struct sbc_frame_hdr {
51 	uint8_t syncword:8;		/* Sync word */
52 	uint8_t sampling_frequency:2;	/* Sampling frequency */
53 	uint8_t blocks:2;		/* Blocks */
54 	uint8_t channel_mode:2;		/* Channel mode */
55 	uint8_t allocation_method:1;	/* Allocation method */
56 	uint8_t subbands:1;		/* Subbands */
57 	uint8_t bitpool:8;		/* Bitpool */
58 	uint8_t crc_check:8;		/* CRC check */
59 } __attribute__ ((packed));
60 #else
61 #error "Unknown byte order"
62 #endif
63 
calc_frame_len(struct sbc_frame_hdr * hdr)64 static int calc_frame_len(struct sbc_frame_hdr *hdr)
65 {
66 	int tmp, nrof_subbands, nrof_blocks;
67 
68 	nrof_subbands = (hdr->subbands + 1) * 4;
69 	nrof_blocks = (hdr->blocks + 1) * 4;
70 
71 	switch (hdr->channel_mode) {
72 	case 0x00:
73 		nrof_subbands /= 2;
74 		tmp = nrof_blocks * hdr->bitpool;
75 		break;
76 	case 0x01:
77 		tmp = nrof_blocks * hdr->bitpool * 2;
78 		break;
79 	case 0x02:
80 		tmp = nrof_blocks * hdr->bitpool;
81 		break;
82 	case 0x03:
83 		tmp = nrof_blocks * hdr->bitpool + nrof_subbands;
84 		break;
85 	default:
86 		return 0;
87 	}
88 
89 	return (nrof_subbands + ((tmp + 7) / 8));
90 }
91 
calc_bit_rate(struct sbc_frame_hdr * hdr)92 static double calc_bit_rate(struct sbc_frame_hdr *hdr)
93 {
94 	int nrof_subbands, nrof_blocks;
95 	double f;
96 
97 	nrof_subbands = (hdr->subbands + 1) * 4;
98 	nrof_blocks = (hdr->blocks + 1) * 4;
99 
100 	switch (hdr->sampling_frequency) {
101 	case 0:
102 		f = 16;
103 		break;
104 	case 1:
105 		f = 32;
106 		break;
107 	case 2:
108 		f = 44.1;
109 		break;
110 	case 3:
111 		f = 48;
112 		break;
113 	default:
114 		return 0;
115 	}
116 
117 	return ((8 * (calc_frame_len(hdr) + 4) * f) /
118 			(nrof_subbands * nrof_blocks));
119 }
120 
freq2str(uint8_t freq)121 static char *freq2str(uint8_t freq)
122 {
123 	switch (freq) {
124 	case 0:
125 		return "16 kHz";
126 	case 1:
127 		return "32 kHz";
128 	case 2:
129 		return "44.1 kHz";
130 	case 3:
131 		return "48 kHz";
132 	default:
133 		return "Unknown";
134 	}
135 }
136 
mode2str(uint8_t mode)137 static char *mode2str(uint8_t mode)
138 {
139 	switch (mode) {
140 	case 0:
141 		return "Mono";
142 	case 1:
143 		return "Dual Channel";
144 	case 2:
145 		return "Stereo";
146 	case 3:
147 		return "Joint Stereo";
148 	default:
149 		return "Unknown";
150 	}
151 }
152 
__read(int fd,void * buf,size_t count)153 static ssize_t __read(int fd, void *buf, size_t count)
154 {
155 	ssize_t len, pos = 0;
156 
157 	while (count > 0) {
158 		len = read(fd, buf + pos, count);
159 		if (len <= 0)
160 			return len;
161 
162 		count -= len;
163 		pos   += len;
164 	}
165 
166 	return pos;
167 }
168 
169 #define SIZE 32
170 
analyze_file(char * filename)171 static int analyze_file(char *filename)
172 {
173 	struct sbc_frame_hdr hdr;
174 	unsigned char buf[64];
175 	double rate;
176 	int bitpool[SIZE], frame_len[SIZE];
177 	int subbands, blocks, freq, method;
178 	int n, p1, p2, fd, size, num;
179 	ssize_t len;
180 	unsigned int count;
181 
182 	if (strcmp(filename, "-")) {
183 		printf("Filename\t\t%s\n", basename(filename));
184 
185 		fd = open(filename, O_RDONLY);
186 		if (fd < 0) {
187 			perror("Can't open file");
188 			return -1;
189 		}
190 	} else
191 		fd = fileno(stdin);
192 
193 	len = __read(fd, &hdr, sizeof(hdr));
194 	if (len != sizeof(hdr) || hdr.syncword != 0x9c) {
195 		fprintf(stderr, "Not a SBC audio file\n");
196 		return -1;
197 	}
198 
199 	subbands = (hdr.subbands + 1) * 4;
200 	blocks = (hdr.blocks + 1) * 4;
201 	freq = hdr.sampling_frequency;
202 	method = hdr.allocation_method;
203 
204 	count = calc_frame_len(&hdr);
205 
206 	bitpool[0] = hdr.bitpool;
207 	frame_len[0] = count + 4;
208 
209 	for (n = 1; n < SIZE; n++) {
210 		bitpool[n] = 0;
211 		frame_len[n] = 0;
212 	}
213 
214 	if (lseek(fd, 0, SEEK_SET) < 0) {
215 		num = 1;
216 		rate = calc_bit_rate(&hdr);
217 		while (count) {
218 			size = count > sizeof(buf) ? sizeof(buf) : count;
219 			len = __read(fd, buf, size);
220 			if (len < 0)
221 				break;
222 			count -= len;
223 		}
224 	} else {
225 		num = 0;
226 		rate = 0;
227 	}
228 
229 	while (1) {
230 		len = __read(fd, &hdr, sizeof(hdr));
231 		if (len < 0) {
232 			fprintf(stderr, "Unable to read frame header"
233 					" (error %d)\n", errno);
234 			break;
235 		}
236 
237 		if (len == 0)
238 			break;
239 
240 		if ((size_t) len < sizeof(hdr) || hdr.syncword != 0x9c) {
241 			fprintf(stderr, "Corrupted SBC stream "
242 					"(len %zd syncword 0x%02x)\n",
243 					len, hdr.syncword);
244 			break;
245 		}
246 
247 		count = calc_frame_len(&hdr);
248 		len = count + 4;
249 
250 		p1 = -1;
251 		p2 = -1;
252 		for (n = 0; n < SIZE; n++) {
253 			if (p1 < 0 && (bitpool[n] == 0 || bitpool[n] == hdr.bitpool))
254 				p1 = n;
255 			if (p2 < 0 && (frame_len[n] == 0 || frame_len[n] == len))
256 				p2 = n;
257 		}
258 		if (p1 >= 0)
259 			bitpool[p1] = hdr.bitpool;
260 		if (p2 >= 0)
261 			frame_len[p2] = len;
262 
263 		while (count) {
264 			size = count > sizeof(buf) ? sizeof(buf) : count;
265 
266 			len = __read(fd, buf, size);
267 			if (len != size) {
268 				fprintf(stderr, "Unable to read frame data "
269 						"(error %d)\n", errno);
270 				break;
271 			}
272 
273 			count -= len;
274 		}
275 
276 		rate += calc_bit_rate(&hdr);
277 		num++;
278 	}
279 
280 	printf("Subbands\t\t%d\n", subbands);
281 	printf("Block length\t\t%d\n", blocks);
282 	printf("Sampling frequency\t%s\n", freq2str(freq));
283 	printf("Channel mode\t\t%s\n", mode2str(hdr.channel_mode));
284 	printf("Allocation method\t%s\n", method ? "SNR" : "Loudness");
285 	printf("Bitpool\t\t\t%d", bitpool[0]);
286 	for (n = 1; n < SIZE; n++)
287 		if (bitpool[n] > 0)
288 			printf(", %d", bitpool[n]);
289 	printf("\n");
290 	printf("Number of frames\t%d\n", num);
291 	printf("Frame length\t\t%d", frame_len[0]);
292 	for (n = 1; n < SIZE; n++)
293 		if (frame_len[n] > 0)
294 			printf(", %d", frame_len[n]);
295 	printf(" Bytes\n");
296 	if (num > 0)
297 		printf("Bit rate\t\t%.3f kbps\n", rate / num);
298 
299 	if (fd > fileno(stderr))
300 		close(fd);
301 
302 	printf("\n");
303 
304 	return 0;
305 }
306 
main(int argc,char * argv[])307 int main(int argc, char *argv[])
308 {
309 	int i;
310 
311 	if (argc < 2) {
312 		fprintf(stderr, "Usage: sbcinfo <file>\n");
313 		exit(1);
314 	}
315 
316 	for (i = 0; i < argc - 1; i++)
317 		if (analyze_file(argv[i + 1]) < 0)
318 			exit(1);
319 
320 	return 0;
321 }
322