• 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, mode, 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 	mode = hdr.channel_mode;
203 	method = hdr.allocation_method;
204 
205 	count = calc_frame_len(&hdr);
206 
207 	bitpool[0] = hdr.bitpool;
208 	frame_len[0] = count + 4;
209 
210 	for (n = 1; n < SIZE; n++) {
211 		bitpool[n] = 0;
212 		frame_len[n] = 0;
213 	}
214 
215 	if (lseek(fd, 0, SEEK_SET) < 0) {
216 		num = 1;
217 		rate = calc_bit_rate(&hdr);
218 		while (count) {
219 			size = count > sizeof(buf) ? sizeof(buf) : count;
220 			len = __read(fd, buf, size);
221 			if (len < 0)
222 				break;
223 			count -= len;
224 		}
225 	} else {
226 		num = 0;
227 		rate = 0;
228 	}
229 
230 	while (1) {
231 		len = __read(fd, &hdr, sizeof(hdr));
232 		if (len < 0) {
233 			fprintf(stderr, "Unable to read frame header"
234 					" (error %d)\n", errno);
235 			break;
236 		}
237 
238 		if (len == 0)
239 			break;
240 
241 		if ((size_t) len < sizeof(hdr) || hdr.syncword != 0x9c) {
242 			fprintf(stderr, "Corrupted SBC stream "
243 					"(len %zd syncword 0x%02x)\n",
244 					len, hdr.syncword);
245 			break;
246 		}
247 
248 		count = calc_frame_len(&hdr);
249 		len = count + 4;
250 
251 		p1 = -1;
252 		p2 = -1;
253 		for (n = 0; n < SIZE; n++) {
254 			if (p1 < 0 && (bitpool[n] == 0 || bitpool[n] == hdr.bitpool))
255 				p1 = n;
256 			if (p2 < 0 && (frame_len[n] == 0 || frame_len[n] == len))
257 				p2 = n;
258 		}
259 		if (p1 >= 0)
260 			bitpool[p1] = hdr.bitpool;
261 		if (p2 >= 0)
262 			frame_len[p2] = len;
263 
264 		while (count) {
265 			size = count > sizeof(buf) ? sizeof(buf) : count;
266 
267 			len = __read(fd, buf, size);
268 			if (len != size) {
269 				fprintf(stderr, "Unable to read frame data "
270 						"(error %d)\n", errno);
271 				break;
272 			}
273 
274 			count -= len;
275 		}
276 
277 		rate += calc_bit_rate(&hdr);
278 		num++;
279 	}
280 
281 	printf("Subbands\t\t%d\n", subbands);
282 	printf("Block length\t\t%d\n", blocks);
283 	printf("Sampling frequency\t%s\n", freq2str(freq));
284 	printf("Channel mode\t\t%s\n", mode2str(hdr.channel_mode));
285 	printf("Allocation method\t%s\n", method ? "SNR" : "Loudness");
286 	printf("Bitpool\t\t\t%d", bitpool[0]);
287 	for (n = 1; n < SIZE; n++)
288 		if (bitpool[n] > 0)
289 			printf(", %d", bitpool[n]);
290 	printf("\n");
291 	printf("Number of frames\t%d\n", num);
292 	printf("Frame length\t\t%d", frame_len[0]);
293 	for (n = 1; n < SIZE; n++)
294 		if (frame_len[n] > 0)
295 			printf(", %d", frame_len[n]);
296 	printf(" Bytes\n");
297 	if (num > 0)
298 		printf("Bit rate\t\t%.3f kbps\n", rate / num);
299 
300 	if (fd > fileno(stderr))
301 		close(fd);
302 
303 	printf("\n");
304 
305 	return 0;
306 }
307 
main(int argc,char * argv[])308 int main(int argc, char *argv[])
309 {
310 	int i;
311 
312 	if (argc < 2) {
313 		fprintf(stderr, "Usage: sbcinfo <file>\n");
314 		exit(1);
315 	}
316 
317 	for (i = 0; i < argc - 1; i++)
318 		if (analyze_file(argv[i + 1]) < 0)
319 			exit(1);
320 
321 	return 0;
322 }
323