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
38struct 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
49struct 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
63static 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
91static 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
120static 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
136static 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
152static 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
170static 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
307int 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