OSDN Git Service

5ac02b44e1355eac0541b2c4b413eae2c9783111
[android-x86/external-bluetooth-bluez.git] / utils / sbc / sbcdec.c
1 /*
2  *
3  *  Bluetooth low-complexity, subband codec (SBC) decoder
4  *
5  *  Copyright (C) 2004-2008  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 <string.h>
34 #include <getopt.h>
35 #include <sys/stat.h>
36 #include <sys/ioctl.h>
37 #include <sys/soundcard.h>
38
39 #include "sbc.h"
40
41 #define BUF_SIZE 8192
42
43 static void decode(char *filename, char *output, int tofile)
44 {
45         unsigned char buf[BUF_SIZE], *stream;
46         struct stat st;
47         off_t filesize;
48         sbc_t sbc;
49         int fd, ad, pos, streamlen, framelen, count, written, len;
50         int format = AFMT_S16_BE, frequency, channels;
51
52         if (stat(filename, &st) < 0) {
53                 fprintf(stderr, "Can't get size of file %s: %s\n",
54                                                 filename, strerror(errno));
55                 return;
56         }
57
58         filesize = st.st_size;
59         stream = malloc(st.st_size);
60
61         if (!stream) {
62                 fprintf(stderr, "Can't allocate memory for %s: %s\n",
63                                                 filename, strerror(errno));
64                 return;
65         }
66
67         fd = open(filename, O_RDONLY);
68         if (fd < 0) {
69                 fprintf(stderr, "Can't open file %s: %s\n",
70                                                 filename, strerror(errno));
71                 goto free;
72         }
73
74         if (read(fd, stream, st.st_size) != st.st_size) {
75                 fprintf(stderr, "Can't read content of %s: %s\n",
76                                                 filename, strerror(errno));
77                 close(fd);
78                 goto free;
79         }
80
81         close(fd);
82
83         pos = 0;
84         streamlen = st.st_size;
85
86         if (tofile)
87                 ad = open(output, O_WRONLY | O_CREAT | O_TRUNC, 0644);
88         else
89                 ad = open(output, O_WRONLY, 0);
90
91         if (ad < 0) {
92                 fprintf(stderr, "Can't open output %s: %s\n",
93                                                 output, strerror(errno));
94                 goto free;
95         }
96
97         sbc_init(&sbc, 0L);
98         sbc.endian = SBC_BE;
99
100         framelen = sbc_decode(&sbc, stream, streamlen, buf, sizeof(buf), &len);
101         channels = sbc.mode == SBC_MODE_MONO ? 1 : 2;
102         switch (sbc.frequency) {
103         case SBC_FREQ_16000:
104                 frequency = 16000;
105                 break;
106
107         case SBC_FREQ_32000:
108                 frequency = 32000;
109                 break;
110
111         case SBC_FREQ_44100:
112                 frequency = 44100;
113                 break;
114
115         case SBC_FREQ_48000:
116                 frequency = 48000;
117                 break;
118         default:
119                 frequency = 0;
120         }
121
122         printf("%d Hz, %d channels\n", frequency, channels);
123         if (!tofile) {
124                 if (ioctl(ad, SNDCTL_DSP_SETFMT, &format) < 0) {
125                         fprintf(stderr, "Can't set audio format on %s: %s\n",
126                                         output, strerror(errno));
127                         goto close;
128                 }
129                 if (ioctl(ad, SNDCTL_DSP_CHANNELS, &channels) < 0) {
130                         fprintf(stderr,
131                                 "Can't set number of channels on %s: %s\n",
132                                 output, strerror(errno));
133                         goto close;
134                 }
135
136                 if (ioctl(ad, SNDCTL_DSP_SPEED, &frequency) < 0) {
137                         fprintf(stderr, "Can't set audio rate on %s: %s\n",
138                                         output, strerror(errno));
139                         goto close;
140                 }
141         }
142
143         count = 0;
144         while (framelen > 0) {
145                 /* we have completed an sbc_decode at this point sbc.len is the
146                  * length of the frame we just decoded count is the number of
147                  * decoded bytes yet to be written */
148
149                 if (count + len >= BUF_SIZE) {
150                         /* buffer is too full to stuff decoded audio in so it
151                          * must be written to the device */
152                         written = write(ad, buf, count);
153                         if (written > 0)
154                                 count -= written;
155                 }
156
157                 /* sanity check */
158                 if (count + len >= BUF_SIZE) {
159                         fprintf(stderr,
160                                 "buffer size of %d is too small for decoded"
161                                 " data (%d)\n", BUF_SIZE, len + count);
162                         exit(1);
163                 }
164
165                 /* increase the count */
166                 count += len;
167
168                 /* push the pointer in the file forward to the next bit to be
169                  * decoded tell the decoder to decode up to the remaining
170                  * length of the file (!) */
171                 pos += framelen;
172                 framelen = sbc_decode(&sbc, stream + pos, streamlen - pos,
173                                         buf + count, sizeof(buf) - count,
174                                         &len);
175         }
176
177         if (count > 0) {
178                 written = write(ad, buf, count);
179                 if (written > 0)
180                         count -= written;
181         }
182
183 close:
184         sbc_finish(&sbc);
185
186         close(ad);
187
188 free:
189         free(stream);
190 }
191
192 static void usage(void)
193 {
194         printf("SBC decoder utility ver %s\n", VERSION);
195         printf("Copyright (c) 2004-2008  Marcel Holtmann\n\n");
196
197         printf("Usage:\n"
198                 "\tsbcdec [options] file(s)\n"
199                 "\n");
200
201         printf("Options:\n"
202                 "\t-h, --help           Display help\n"
203                 "\t-v, --verbose        Verbose mode\n"
204                 "\t-d, --device <dsp>   Sound device\n"
205                 "\t-f, --file <file>    Decode to a file\n"
206                 "\n");
207 }
208
209 static struct option main_options[] = {
210         { "help",       0, 0, 'h' },
211         { "device",     1, 0, 'd' },
212         { "verbose",    0, 0, 'v' },
213         { "file",       1, 0, 'f' },
214         { 0, 0, 0, 0 }
215 };
216
217 int main(int argc, char *argv[])
218 {
219         char *output = NULL;
220         int i, opt, verbose = 0, tofile = 0;
221
222         while ((opt = getopt_long(argc, argv, "+hvd:f:", main_options, NULL)) != -1) {
223                 switch(opt) {
224                 case 'h':
225                         usage();
226                         exit(0);
227
228                 case 'v':
229                         verbose = 1;
230                         break;
231
232                 case 'd':
233                         if (output)
234                                 free(output);
235                         output = strdup(optarg);
236                         tofile = 0;
237                         break;
238
239                 case 'f' :
240                         if (output)
241                                 free(output);
242                         output = strdup(optarg);
243                         tofile = 1;
244                         break;
245
246                 default:
247                         exit(1);
248                 }
249         }
250
251         argc -= optind;
252         argv += optind;
253         optind = 0;
254
255         if (argc < 1) {
256                 usage();
257                 exit(1);
258         }
259
260         for (i = 0; i < argc; i++)
261                 decode(argv[i], output ? output : "/dev/dsp", tofile);
262
263         if (output)
264                 free(output);
265
266         return 0;
267 }