Codebase list squeezelite / 3ebd004
0.9beta4 - implement mp3 decoding with libmpg123 as alternative to libmad (mad has preference at present if available) - fix crash when restarting stream during crossfade Adrian Smith 11 years ago
6 changed file(s) with 229 addition(s) and 10 deletion(s). Raw diff Collapse all Expand all
22 LDFLAGS ?= -lasound -lpthread -ldl -lrt
33 EXECUTABLE ?= squeezelite
44
5 SOURCES = main.c slimproto.c utils.c output.c buffer.c stream.c decode.c flac.c pcm.c mad.c vorbis.c faad.c
5 SOURCES = main.c slimproto.c utils.c output.c buffer.c stream.c decode.c flac.c pcm.c mad.c vorbis.c faad.c mpg.c
66 DEPS = squeezelite.h
77
88 OBJECTS = $(SOURCES:.c=.o)
103103 if (!opt || !strcmp(opt, "ogg")) codecs[i++] = register_vorbis();
104104 if (!opt || !strcmp(opt, "flac")) codecs[i++] = register_flac();
105105 if (!opt || !strcmp(opt, "pcm")) codecs[i++] = register_pcm();
106 if (!opt || !strcmp(opt, "mp3")) codecs[i++] = register_mad();
106
107 // try mad then mpg for mp3 unless command line option passed
108 if ( !opt || !strcmp(opt, "mp3") || !strcmp(opt, "mad")) codecs[i] = register_mad();
109 if ((!opt || !strcmp(opt, "mp3") || !strcmp(opt, "mpg")) && !codecs[i]) codecs[i] = register_mpg();
107110
108111 #if LINUX || OSX
109112 pthread_attr_t attr;
+209
-0
mpg.c less more
0 /*
1 * Squeezelite - lightweight headless squeezebox emulator
2 *
3 * (c) Adrian Smith 2012, 2013, triode1@btinternet.com
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 */
19
20 #include "squeezelite.h"
21
22 #include <mpg123.h>
23
24 #define READ_SIZE 512
25 #define WRITE_SIZE 32 * 1024
26
27 struct mpg {
28 mpg123_handle *h;
29 // mpg symbols to be dynamically loaded
30 int (* mpg123_init)(void);
31 int (* mpg123_feature)(const enum mpg123_feature_set);
32 void (* mpg123_rates)(const long **, size_t *);
33 int (* mpg123_format_none)(mpg123_handle *);
34 int (* mpg123_format)(mpg123_handle *, long, int, int);
35 mpg123_handle *(* mpg123_new)(const char*, int *);
36 void (* mpg123_delete)(mpg123_handle *);
37 int (* mpg123_open_feed)(mpg123_handle *);
38 int (* mpg123_decode)(mpg123_handle *, const unsigned char *, size_t, unsigned char *, size_t, size_t *);
39 int (* mpg123_getformat)(mpg123_handle *, long *, int *, int *);
40 const char* (* mpg123_plain_strerror)(int);
41 };
42
43 static struct mpg *m;
44
45 extern log_level loglevel;
46
47 extern struct buffer *streambuf;
48 extern struct buffer *outputbuf;
49 extern struct streamstate stream;
50 extern struct outputstate output;
51 extern struct decodestate decode;
52
53 #define LOCK_S mutex_lock(streambuf->mutex)
54 #define UNLOCK_S mutex_unlock(streambuf->mutex)
55 #define LOCK_O mutex_lock(outputbuf->mutex)
56 #define UNLOCK_O mutex_unlock(outputbuf->mutex)
57
58 static decode_state mpg_decode(void) {
59 size_t bytes, space, size;
60 int ret;
61
62 LOCK_S;
63 LOCK_O;
64 bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf));
65 space = min(_buf_space(outputbuf), _buf_cont_write(outputbuf));
66 bytes = min(bytes, READ_SIZE);
67 space = min(space, WRITE_SIZE);
68
69 if (stream.state <= DISCONNECT && bytes == 0) {
70 UNLOCK_O;
71 UNLOCK_S;
72 return DECODE_COMPLETE;
73 }
74
75 ret = m->mpg123_decode(m->h, streambuf->readp, bytes, outputbuf->writep, space, &size);
76
77 if (ret == MPG123_NEW_FORMAT) {
78
79 if (decode.new_stream) {
80 long rate;
81 int channels, enc;
82
83 m->mpg123_getformat(m->h, &rate, &channels, &enc);
84
85 LOG_INFO("setting track_start");
86 output.next_sample_rate = rate;
87 output.track_start = outputbuf->writep;
88 if (output.fade_mode) _checkfade(true);
89 decode.new_stream = false;
90
91 } else {
92 LOG_WARN("format change mid stream - not supported");
93 }
94 }
95
96 _buf_inc_readp(streambuf, bytes);
97 _buf_inc_writep(outputbuf, size);
98
99 UNLOCK_O;
100 UNLOCK_S;
101
102 LOG_SDEBUG("write %u frames", size / BYTES_PER_FRAME);
103
104 if (ret == MPG123_DONE) {
105 LOG_INFO("stream complete");
106 return DECODE_COMPLETE;
107 }
108
109 if (ret == MPG123_ERR) {
110 LOG_WARN("Error");
111 return DECODE_COMPLETE;
112 }
113
114 // OK and NEED_MORE keep running
115 return DECODE_RUNNING;
116 }
117
118 static void mpg_open(u8_t size, u8_t rate, u8_t chan, u8_t endianness) {
119 int err;
120 const long *list;
121 size_t count, i;
122
123 if (m->h) {
124 m->mpg123_delete(m->h);
125 }
126
127 m->h = m->mpg123_new(NULL, &err);
128
129 if (m->h == NULL) {
130 LOG_WARN("new error: %s", m->mpg123_plain_strerror(err));
131 }
132
133 // restrict output to 32bit signed 2 channel for all supported sample rates
134 m->mpg123_rates(&list, &count);
135 m->mpg123_format_none(m->h);
136 for (i = 0; i < count; i++) {
137 m->mpg123_format(m->h, list[i], 2, MPG123_ENC_SIGNED_32);
138 }
139
140 err = m->mpg123_open_feed(m->h);
141
142 if (err) {
143 LOG_WARN("open feed error: %s", m->mpg123_plain_strerror(err));
144 }
145 }
146
147 static void mpg_close(void) {
148 m->mpg123_delete(m->h);
149 m->h = NULL;
150 }
151
152 static bool load_mpg() {
153 void *handle = dlopen(LIBMPG, RTLD_NOW);
154 char *err;
155
156 if (!handle) {
157 LOG_INFO("dlerror: %s", dlerror());
158 return false;
159 }
160
161 m = malloc(sizeof(struct mpg));
162
163 m->h = NULL;
164 m->mpg123_init = dlsym(handle, "mpg123_init");
165 m->mpg123_feature = dlsym(handle, "mpg123_feature");
166 m->mpg123_rates = dlsym(handle, "mpg123_rates");
167 m->mpg123_format_none = dlsym(handle, "mpg123_format_none");
168 m->mpg123_format = dlsym(handle, "mpg123_format");
169 m->mpg123_new = dlsym(handle, "mpg123_new");
170 m->mpg123_delete = dlsym(handle, "mpg123_delete");
171 m->mpg123_open_feed = dlsym(handle, "mpg123_open_feed");
172 m->mpg123_decode = dlsym(handle, "mpg123_decode");
173 m->mpg123_getformat = dlsym(handle, "mpg123_getformat");
174 m->mpg123_plain_strerror = dlsym(handle, "mpg123_plain_strerror");
175
176 if ((err = dlerror()) != NULL) {
177 LOG_INFO("dlerror: %s", err);
178 return false;
179 }
180
181 m->mpg123_init();
182
183 if (!m->mpg123_feature(MPG123_FEATURE_OUTPUT_32BIT)) {
184 LOG_WARN("32 bit output not supported - disabled");
185 return false;
186 }
187
188 LOG_INFO("loaded "LIBMPG);
189 return true;
190 }
191
192 struct codec *register_mpg(void) {
193 static struct codec ret = {
194 'm', // id
195 "mp3", // types
196 READ_SIZE, // min read
197 WRITE_SIZE, // min space
198 mpg_open, // open
199 mpg_close, // close
200 mpg_decode, // decode
201 };
202
203 if (!load_mpg()) {
204 return NULL;
205 }
206
207 return &ret;
208 }
773773 } else {
774774 LOG_WARN("unable to skip crossfaded start");
775775 }
776 output.fade = FADE_NONE;
776 output.fade = FADE_INACTIVE;
777777 output.current_replay_gain = output.next_replay_gain;
778778 } else {
779779 LOG_INFO("fade complete");
780 output.fade = FADE_NONE;
780 output.fade = FADE_INACTIVE;
781781 }
782782 }
783783 // if fade in progress set fade gain, ensure cont_frames reduced so we get to end of fade at start of chunk
838838 out_frames = (frames_t)alsa_frames;
839839
840840 // perform crossfade buffer copying here as we do not know the actual out_frames value until here
841 if (output.fade == FADE_ACTIVE && output.fade_dir == FADE_CROSS) {
841 if (output.fade == FADE_ACTIVE && output.fade_dir == FADE_CROSS && cross_ptr) {
842842 s32_t *ptr = (s32_t *)(void *)outputbuf->readp;
843843 frames_t count = out_frames * 2;
844844 while (count--) {
10651065 #endif
10661066 if (!silence) {
10671067
1068 if (output.fade == FADE_ACTIVE && output.fade_dir == FADE_CROSS) {
1068 if (output.fade == FADE_ACTIVE && output.fade_dir == FADE_CROSS && cross_ptr) {
10691069 s32_t *ptr = (s32_t *)(void *)outputbuf->readp;
10701070 frames_t count = out_frames * 2;
10711071 while (count--) {
12841284 void output_flush(void) {
12851285 LOG_INFO("flush output buffer");
12861286 buf_flush(outputbuf);
1287 LOCK;
1288 output.fade = FADE_INACTIVE;
1289 UNLOCK;
12871290 }
12881291
12891292 void output_close(void) {
221221 case 'q':
222222 stream_disconnect();
223223 buf_flush(streambuf);
224 buf_flush(outputbuf);
224 output_flush();
225225 break;
226226 case 'f':
227227 stream_disconnect();
228228 buf_flush(streambuf);
229 buf_flush(outputbuf);
229 output_flush();
230230 break;
231231 case 'p':
232232 {
1717 *
1818 */
1919
20 #define VERSION "v0.9beta3"
20 #define VERSION "v0.9beta4"
2121
2222 // build detection
2323 #if defined(linux)
6464 #if LINUX
6565 #define LIBFLAC "libFLAC.so.8"
6666 #define LIBMAD "libmad.so.0"
67 #define LIBMPG "libmpg123.so.0"
6768 #define LIBVORBIS "libvorbisfile.so.3"
6869 #define LIBTREMOR "libvorbisidec.so.1"
6970 #define LIBFAAD "libfaad.so.2"
7273 #if OSX
7374 #define LIBFLAC "libFLAC.8.dylib"
7475 #define LIBMAD "libmad.0.dylib"
76 #define LIBMPG "libmpg123.0.dylib"
7577 #define LIBVORBIS "libvorbisfile.3.dylib"
7678 #define LIBTREMOR "libvorbisidec.1.dylib"
7779 #define LIBFAAD "libfaad.2.dylib"
8082 #if WIN
8183 #define LIBFLAC "libFLAC.dll"
8284 #define LIBMAD "libmad.dll"
85 #define LIBMPG "libmpg123.dll"
8386 #define LIBVORBIS "libvorbisfile.dll"
8487 #define LIBTREMOR "libvorbisidec.dll"
8588 #define LIBFAAD "libfaad2.dll"
410413 void _pa_open(void);
411414
412415 // codecs
413 #define MAX_CODECS 5
416 #define MAX_CODECS 6
414417
415418 struct codec *register_flac(void);
416419 struct codec *register_pcm(void);
417420 struct codec *register_mad(void);
421 struct codec *register_mpg(void);
418422 struct codec *register_vorbis(void);
419423 struct codec *register_faad(void);