• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  *  Bluetooth low-complexity, subband codec (SBC) library
4  *
5  *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
6  *
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 #include <stdio.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <stdlib.h>
33 #include <stdint.h>
34 #include <string.h>
35 #include <libgen.h>
36 
37 #if __BYTE_ORDER == __LITTLE_ENDIAN
38 struct sbc_frame_hdr {
39 	uint8_t syncword:8;		/* Sync word */
40 	uint8_t subbands:1;		/* Subbands */
41 	uint8_t allocation_method:1;	/* Allocation method */
42 	uint8_t channel_mode:2;		/* Channel mode */
43 	uint8_t blocks:2;		/* Blocks */
44 	uint8_t sampling_frequency:2;	/* Sampling frequency */
45 	uint8_t bitpool:8;		/* Bitpool */
46 	uint8_t crc_check:8;		/* CRC check */
47 } __attribute__ ((packed));
48 #elif __BYTE_ORDER == __BIG_ENDIAN
49 struct sbc_frame_hdr {
50 	uint8_t syncword:8;		/* Sync word */
51 	uint8_t sampling_frequency:2;	/* Sampling frequency */
52 	uint8_t blocks:2;		/* Blocks */
53 	uint8_t channel_mode:2;		/* Channel mode */
54 	uint8_t allocation_method:1;	/* Allocation method */
55 	uint8_t subbands:1;		/* Subbands */
56 	uint8_t bitpool:8;		/* Bitpool */
57 	uint8_t crc_check:8;		/* CRC check */
58 } __attribute__ ((packed));
59 #else
60 #error "Unknown byte order"
61 #endif
62 
calc_frame_len(struct sbc_frame_hdr * hdr)63 static int calc_frame_len(struct sbc_frame_hdr *hdr)
64 {
65 	int tmp, nrof_subbands, nrof_blocks;
66 
67 	nrof_subbands = (hdr->subbands + 1) * 4;
68 	nrof_blocks = (hdr->blocks + 1) * 4;
69 
70 	switch (hdr->channel_mode) {
71 	case 0x00:
72 		nrof_subbands /= 2;
73 		tmp = nrof_blocks * hdr->bitpool;
74 		break;
75 	case 0x01:
76 		tmp = nrof_blocks * hdr->bitpool * 2;
77 		break;
78 	case 0x02:
79 		tmp = nrof_blocks * hdr->bitpool;
80 		break;
81 	case 0x03:
82 		tmp = nrof_blocks * hdr->bitpool + nrof_subbands;
83 		break;
84 	default:
85 		return 0;
86 	}
87 
88 	return (nrof_subbands + ((tmp + 7) / 8));
89 }
90 
calc_bit_rate(struct sbc_frame_hdr * hdr)91 static double calc_bit_rate(struct sbc_frame_hdr *hdr)
92 {
93 	int nrof_subbands, nrof_blocks;
94 	double f;
95 
96 	nrof_subbands = (hdr->subbands + 1) * 4;
97 	nrof_blocks = (hdr->blocks + 1) * 4;
98 
99 	switch (hdr->sampling_frequency) {
100 	case 0:
101 		f = 16;
102 		break;
103 	case 1:
104 		f = 32;
105 		break;
106 	case 2:
107 		f = 44.1;
108 		break;
109 	case 3:
110 		f = 48;
111 		break;
112 	default:
113 		return 0;
114 	}
115 
116 	return ((8 * (calc_frame_len(hdr) + 4) * f) /
117 			(nrof_subbands * nrof_blocks));
118 }
119 
freq2str(uint8_t freq)120 static char *freq2str(uint8_t freq)
121 {
122 	switch (freq) {
123 	case 0:
124 		return "16 kHz";
125 	case 1:
126 		return "32 kHz";
127 	case 2:
128 		return "44.1 kHz";
129 	case 3:
130 		return "48 kHz";
131 	default:
132 		return "Unknown";
133 	}
134 }
135 
mode2str(uint8_t mode)136 static char *mode2str(uint8_t mode)
137 {
138 	switch (mode) {
139 	case 0:
140 		return "Mono";
141 	case 1:
142 		return "Dual Channel";
143 	case 2:
144 		return "Stereo";
145 	case 3:
146 		return "Joint Stereo";
147 	default:
148 		return "Unknown";
149 	}
150 }
151 
__read(int fd,void * buf,size_t count)152 static ssize_t __read(int fd, void *buf, size_t count)
153 {
154 	ssize_t len, pos = 0;
155 
156 	while (count > 0) {
157 		len = read(fd, buf + pos, count);
158 		if (len <= 0)
159 			return len;
160 
161 		count -= len;
162 		pos   += len;
163 	}
164 
165 	return pos;
166 }
167 
168 #define SIZE 32
169 
analyze_file(char * filename)170 static int analyze_file(char *filename)
171 {
172 	struct sbc_frame_hdr hdr;
173 	unsigned char buf[64];
174 	double rate;
175 	int bitpool[SIZE], frame_len[SIZE];
176 	int subbands, blocks, freq, mode, method;
177 	int n, p1, p2, fd, size, num;
178 	ssize_t len;
179 	unsigned int count;
180 
181 	if (strcmp(filename, "-")) {
182 		printf("Filename\t\t%s\n", basename(filename));
183 
184 		fd = open(filename, O_RDONLY);
185 		if (fd < 0) {
186 			perror("Can't open file");
187 			return -1;
188 		}
189 	} else
190 		fd = fileno(stdin);
191 
192 	len = __read(fd, &hdr, sizeof(hdr));
193 	if (len != sizeof(hdr) || hdr.syncword != 0x9c) {
194 		fprintf(stderr, "Not a SBC audio file\n");
195 		return -1;
196 	}
197 
198 	subbands = (hdr.subbands + 1) * 4;
199 	blocks = (hdr.blocks + 1) * 4;
200 	freq = hdr.sampling_frequency;
201 	mode = hdr.channel_mode;
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