Codebase list squeezelite / 975ccee
Merge tag 'upstream/1.4' into master-v1.4 Chris Boot 10 years ago
27 changed file(s) with 3567 addition(s) and 1685 deletion(s). Raw diff Collapse all Expand all
0 Version 1.0 - 15/2/13
1 =====================
2 - initial release
3
4 Version 1.1 - 12/4/13
5 =====================
6
7 Minor changes
8 - add timeout on slimproto connection to detect dead server
9 - fix issue with clipping on windows by disabling portaudio dither
10 - silence alsa error messages on linux alsa builds unless debugging is enabled
11 - hide some additional error messages unless debuging is enabled so usb dacs produce less error messages when turned off and on
12
13 Version 1.2 - 6/7/13
14 ====================
15
16 Features
17 - support of upsampling via libsoxr
18
19 Minor changes
20 - command line option for setting the service address now requires "-s" before the server address
21 - fixes a bug where the channels could become swapped when using S16_LE ALSA output
22 - falls back to polling for a new server if one is not found for more than 30 seconds
23 - fixes play of wav/aiff local files when the LocalPlayer plugin is active
24
25 Version 1.3 - 6/10/13
26 =====================
27
28 Features
29 - support for wma/alac decode via ffmpeg library (requires compilation with -DFFMPEG)
30 - support for export of audio data to jivelite to enable visulizations on linux (requires compilation with -DVISEXPORT)
31
32 Minor changes
33 - support async as well as sync resampling rates
34 - support on/off of audio device with portaudio
35 - improved gapless support for aac/mad when skipping to mid track (based on patches from Wouter Ellenbroek)
36 - various bug fixes
37
38 Version 1.3.1 - 25/11/13
39 ========================
40
41 Minor changes
42 - support of compile time linking for distro packaging, uses -DLINKALL option
43
44 Version 1.4 (beta)
45 ==================
46
47 Features
48 - native support of dsd playback to dop capable dac or via conversion to pcm and resampling
49 - support dop in flac playback to dop dacs
50 - support of output to stdout
51
52 Minor changes
53 - support of resampling only when sample rate is not natively supported
54 - fix problem with libmpg123 playback not playing to end of track
55 - add ablity for player name change to be stored locally in a file (to emulate hardware where name is stored on player)
56
22 LDFLAGS ?= -lasound -lpthread -lm -lrt
33 EXECUTABLE ?= squeezelite
44
5 SOURCES = main.c slimproto.c utils.c output.c buffer.c stream.c decode.c process.c resample.c flac.c pcm.c mad.c vorbis.c faad.c mpg.c ffmpeg.c
6 DEPS = squeezelite.h slimproto.h
5 # passing one or more of these in $(OPTS) enables optional feature inclusion
6 OPT_DSD = -DDSD
7 OPT_FF = -DFFMPEG
8 OPT_LINKALL = -DLINKALL
9 OPT_RESAMPLE= -DRESAMPLE
10 OPT_VIS = -DVISEXPORT
711
8 UNAME = $(shell uname -s)
12 SOURCES = \
13 main.c slimproto.c buffer.c stream.c utils.c \
14 output.c output_alsa.c output_pa.c output_stdout.c output_pack.c decode.c \
15 flac.c pcm.c mad.c vorbis.c faad.c mpg.c
916
10 ifneq (,$(findstring -DLINKALL, $(CFLAGS)))
11 LDFLAGS += -lFLAC -lmad -lvorbisfile -lfaad -lmpg123
12 ifneq (,$(findstring -DFFMPEG, $(CFLAGS)))
13 LDFLAGS += -lavcodec -lavformat -lavutil
17 SOURCES_DSD = dsd.c dop.c dsd2pcm/dsd2pcm.c
18 SOURCES_FF = ffmpeg.c
19 SOURCES_RESAMPLE = process.c resample.c
20 SOURCES_VIS = output_vis.c
21
22 LINK_LINUX = -ldl
23
24 LINKALL = -lFLAC -lmad -lvorbisfile -lfaad -lmpg123
25 LINKALL_FF = -lavcodec -lavformat -lavutil
26 LINKALL_RESAMPLE = -lsoxr
27
28 DEPS = squeezelite.h slimproto.h
29
30 UNAME = $(shell uname -s)
31
32 # add optional sources
33 ifneq (,$(findstring $(OPT_DSD), $(CFLAGS)))
34 SOURCES += $(SOURCES_DSD)
1435 endif
15 ifneq (,$(findstring -DRESAMPLE, $(CFLAGS)))
16 LDFLAGS += -lsoxr
36 ifneq (,$(findstring $(OPT_FF), $(CFLAGS)))
37 SOURCES += $(SOURCES_FF)
38 endif
39 ifneq (,$(findstring $(OPT_RESAMPLE), $(CFLAGS)))
40 SOURCES += $(SOURCES_RESAMPLE)
41 endif
42 ifneq (,$(findstring $(OPT_VIS), $(CFLAGS)))
43 SOURCES += $(SOURCES_VIS)
44 endif
45
46 # add optional link options
47 ifneq (,$(findstring $(OPT_LINKALL), $(CFLAGS)))
48 LDFLAGS += $(LINKALL)
49 ifneq (,$(findstring $(OPT_FF), $(CFLAGS)))
50 LDFLAGS += $(LINKALL_FF)
51 endif
52 ifneq (,$(findstring $(OPT_RESAMPLE), $(CFLAGS)))
53 LDFLAGS += $(LINKALL_RESAMPLE)
1754 endif
1855 else
19 # if not LINKALL and linux add -ldl
56 # if not LINKALL and linux add LINK_LINUX
2057 ifeq ($(UNAME), Linux)
21 LDFLAGS += -ldl
58 LDFLAGS += $(LINK_LINUX)
2259 endif
2360 endif
2461
3269 $(OBJECTS): $(DEPS)
3370
3471 .c.o:
35 $(CC) $(CFLAGS) $< -c -o $@
72 $(CC) $(CFLAGS) $(CPPFLAGS) $< -c -o $@
3673
3774 clean:
3875 rm -f $(OBJECTS) $(EXECUTABLE)
128128 LOG_INFO("init decode");
129129
130130 // register codecs
131 // alc,wma,wmap,wmal,aac,spt,ogg,ogf,flc,aif,pcm,mp3
131 // dsf,dff,alc,wma,wmap,wmal,aac,spt,ogg,ogf,flc,aif,pcm,mp3
132132 i = 0;
133 #if DSD
134 if (!opt || strstr(opt, "dsd")) codecs[i++] = register_dsd();
135 #endif
133136 #if FFMPEG
134137 if (!opt || strstr(opt, "alac")) codecs[i++] = register_ff("alc");
135138 if (!opt || strstr(opt, "wma")) codecs[i++] = register_ff("wma");
190193 UNLOCK_D;
191194 }
192195
193 unsigned decode_newstream(unsigned sample_rate, unsigned max_sample_rate) {
196 unsigned decode_newstream(unsigned sample_rate, unsigned supported_rates[]) {
194197
195198 MAY_PROCESS(
196199 if (decode.process) {
197 return process_newstream(&decode.direct, sample_rate, max_sample_rate);
200 return process_newstream(&decode.direct, sample_rate, supported_rates);
198201 }
199202 );
200203
221224 if (codecs[i] && codecs[i]->id == format) {
222225
223226 if (codec && codec != codecs[i]) {
224 LOG_INFO("closing codec");
227 LOG_INFO("closing codec: '%c'", codec->id);
225228 codec->close();
226229 }
227230
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 // DSP over PCM (DOP) specific functions
21
22 #include "squeezelite.h"
23
24 #if DSD
25
26 extern struct buffer *outputbuf;
27 extern struct outputstate output;
28
29 #define LOCK_O mutex_lock(outputbuf->mutex)
30 #define UNLOCK_O mutex_unlock(outputbuf->mutex)
31
32 // check for 32 dop marker frames to see if this is dop in flac
33 // dop is always encoded in 24 bit samples with marker 0x0005xxxx or 0x00FAxxxx
34 bool is_flac_dop(u32_t *lptr, u32_t *rptr, frames_t frames) {
35 int matched = 0;
36 u32_t next = 0;
37
38 while (frames--) {
39 if (((*lptr & 0x00FF0000) == 0x00050000 && (*rptr & 0x00FF0000) == 0x00050000) ||
40 ((*lptr & 0x00FF0000) == 0x00FA0000 && (*rptr & 0x00FF0000) == 0x00FA0000)) {
41 if (*lptr >> 24 == next) {
42 matched++;
43 next = ( 0x05 + 0xFA ) - next;
44 } else {
45 next = *lptr >> 24;
46 matched = 1;
47 }
48 } else {
49 return false;
50 }
51 if (matched == 32) {
52 return true;
53 }
54
55 ++lptr; ++rptr;
56 }
57 return false;
58 }
59
60 // update the dop marker for frames in the output buffer
61 // performaned on all output including silence to maintain marker phase consitency
62 void update_dop_marker(u32_t *ptr, frames_t frames) {
63 static u32_t marker = 0x05;
64 while (frames--) {
65 u32_t scaled_marker = marker << 24;
66 *ptr = (*ptr & 0x00FFFFFF) | scaled_marker;
67 ++ptr;
68 *ptr = (*ptr & 0x00FFFFFF) | scaled_marker;
69 ++ptr;
70 marker = ( 0x05 + 0xFA ) - marker;
71 }
72 }
73
74 // fill silence buffer with 10101100 which represents dop silence
75 // leave marker zero it will be updated at output, leave lsb zero
76 void dop_silence_frames(u32_t *ptr, frames_t frames) {
77 while (frames--) {
78 *ptr++ = 0x00ACAC00;
79 *ptr++ = 0x00ACAC00;
80 }
81 }
82
83 void dop_init(bool enable) {
84 LOCK_O;
85 output.has_dop = enable;
86 UNLOCK_O;
87 }
88
89 #endif // DSD
+622
-0
dsd.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 // dsd support
21
22 #include "squeezelite.h"
23
24 #if DSD
25
26 // use dsd2pcm from Sebastian Gesemann for conversion to pcm:
27 #include "./dsd2pcm/dsd2pcm.h"
28
29 extern log_level loglevel;
30
31 extern struct buffer *streambuf;
32 extern struct buffer *outputbuf;
33 extern struct streamstate stream;
34 extern struct outputstate output;
35 extern struct decodestate decode;
36 extern struct processstate process;
37
38 #define LOCK_S mutex_lock(streambuf->mutex)
39 #define UNLOCK_S mutex_unlock(streambuf->mutex)
40 #define LOCK_O mutex_lock(outputbuf->mutex)
41 #define UNLOCK_O mutex_unlock(outputbuf->mutex)
42 #if PROCESS
43 #define LOCK_O_direct if (decode.direct) mutex_lock(outputbuf->mutex)
44 #define UNLOCK_O_direct if (decode.direct) mutex_unlock(outputbuf->mutex)
45 #define LOCK_O_not_direct if (!decode.direct) mutex_lock(outputbuf->mutex)
46 #define UNLOCK_O_not_direct if (!decode.direct) mutex_unlock(outputbuf->mutex)
47 #define IF_DIRECT(x) if (decode.direct) { x }
48 #define IF_PROCESS(x) if (!decode.direct) { x }
49 #else
50 #define LOCK_O_direct mutex_lock(outputbuf->mutex)
51 #define UNLOCK_O_direct mutex_unlock(outputbuf->mutex)
52 #define LOCK_O_not_direct
53 #define UNLOCK_O_not_direct
54 #define IF_DIRECT(x) { x }
55 #define IF_PROCESS(x)
56 #endif
57
58 #define BLOCK 4096 // expected size of dsd block
59 #define BLOCK_FRAMES BLOCK * BYTES_PER_FRAME
60 #define WRAP_BUF_SIZE 16
61
62 typedef enum { UNKNOWN=0, DSF, DSDIFF } dsd_type;
63
64 static bool dop = false; // local copy of output.has_dop to avoid holding output lock
65
66 struct dsd {
67 dsd_type type;
68 u32_t consume;
69 u32_t sample_rate;
70 u32_t channels;
71 u64_t sample_bytes;
72 u32_t block_size;
73 bool lsb_first;
74 dsd2pcm_ctx *dsd2pcm_ctx[2];
75 float *transfer[2];
76 };
77
78 static struct dsd *d;
79
80 static u64_t unpack64be(const u8_t *p) {
81 return
82 (u64_t)p[0] << 56 | (u64_t)p[1] << 48 | (u64_t)p[2] << 40 | (u64_t)p[3] << 32 |
83 (u64_t)p[4] << 24 | (u64_t)p[5] << 16 | (u64_t)p[6] << 8 | (u64_t)p[7];
84 }
85
86 static u64_t unpack64le(const u8_t *p) {
87 return
88 (u64_t)p[7] << 56 | (u64_t)p[6] << 48 | (u64_t)p[5] << 40 | (u64_t)p[4] << 32 |
89 (u64_t)p[3] << 24 | (u64_t)p[2] << 16 | (u64_t)p[1] << 8 | (u64_t)p[0];
90 }
91
92 static u32_t unpack32le(const u8_t *p) {
93 return
94 (u32_t)p[3] << 24 | (u32_t)p[2] << 16 | (u32_t)p[1] << 8 | (u32_t)p[0];
95 }
96
97 static int _read_header(void) {
98 unsigned bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf));
99 s32_t consume;
100
101 if (!d->type && bytes >= 4) {
102 if (!memcmp(streambuf->readp, "FRM8", 4)) {
103 d->type = DSDIFF;
104 } else if (!memcmp(streambuf->readp, "DSD ", 4)) {
105 d->type = DSF;
106 } else {
107 LOG_WARN("bad type");
108 return -1;
109 }
110 }
111
112 while (bytes >= 16) {
113 char id[5];
114 u64_t len = d->type == DSDIFF ? unpack64be(streambuf->readp + 4) : unpack64le(streambuf->readp + 4);
115 memcpy(id, streambuf->readp, 4);
116 id[4] = '\0';
117 consume = 0;
118
119 if (d->type == DSDIFF) {
120 if (!strcmp(id, "FRM8")) {
121 if (!memcmp(streambuf->readp + 12, "DSD ", 4)) {
122 consume = 16; // read into
123 } else {
124 LOG_WARN("bad dsdiff FRM8");
125 return -1;
126 }
127 }
128 if (!strcmp(id, "PROP") && !memcmp(streambuf->readp + 12, "SND ", 4)) {
129 consume = 16; // read into
130 }
131 if (!strcmp(id, "FVER")) {
132 LOG_INFO("DSDIFF version: %u.%u.%u.%u", *(streambuf->readp + 12), *(streambuf->readp + 13),
133 *(streambuf->readp + 14), *(streambuf->readp + 15));
134 }
135 if (!strcmp(id, "FS ")) {
136 d->sample_rate = unpackN((void *)(streambuf->readp + 12));
137 LOG_INFO("sample rate: %u", d->sample_rate);
138 }
139 if (!strcmp(id, "CHNL")) {
140 d->channels = unpackn((void *)(streambuf->readp + 12));
141 LOG_INFO("channels: %u", d->channels);
142 }
143 if (!strcmp(id, "DSD ")) {
144 LOG_INFO("found dsd len: " FMT_u64, len);
145 d->sample_bytes = len;
146 _buf_inc_readp(streambuf, 12);
147 bytes -= 12;
148 return 1; // got to the audio
149 }
150 }
151
152 if (d->type == DSF) {
153 if (!strcmp(id, "fmt ")) {
154 if (bytes >= len && bytes >= 52) {
155 u32_t version = unpack32le((void *)(streambuf->readp + 12));
156 u32_t format = unpack32le((void *)(streambuf->readp + 16));
157 LOG_INFO("DSF version: %u format: %u", version, format);
158 if (format != 0) {
159 LOG_WARN("only support DSD raw format");
160 return -1;
161 }
162 d->channels = unpack32le((void *)(streambuf->readp + 24));
163 d->sample_rate = unpack32le((void *)(streambuf->readp + 28));
164 d->lsb_first = (unpack32le((void *)(streambuf->readp + 32)) == 1);
165 d->sample_bytes = unpack64le((void *)(streambuf->readp + 36)) / 8;
166 d->block_size = unpack32le((void *)(streambuf->readp + 44));
167 LOG_INFO("channels: %u", d->channels);
168 LOG_INFO("sample rate: %u", d->sample_rate);
169 LOG_INFO("lsb first: %u", d->lsb_first);
170 LOG_INFO("sample bytes: " FMT_u64, d->sample_bytes);
171 LOG_INFO("block size: %u", d->block_size);
172 } else {
173 consume = -1; // come back later
174 }
175 }
176 if (!strcmp(id, "data")) {
177 LOG_INFO("found dsd len: " FMT_u64, len);
178 _buf_inc_readp(streambuf, 12);
179 bytes -= 12;
180 return 1; // got to the audio
181 }
182 }
183
184 // default to consuming whole chunk
185 if (!consume) {
186 consume = (s32_t)((d->type == DSDIFF) ? len + 12 : len);
187 }
188
189 if (bytes >= consume) {
190 LOG_DEBUG("id: %s len: " FMT_u64 " consume: %d", id, len, consume);
191 _buf_inc_readp(streambuf, consume);
192 bytes -= consume;
193 } else if (consume > 0) {
194 LOG_DEBUG("id: %s len: " FMT_u64 " consume: %d - partial consume: %u", id, len, consume, bytes);
195 _buf_inc_readp(streambuf, bytes);
196 d->consume = consume - bytes;
197 break;
198 } else {
199 break;
200 }
201 }
202
203 return 0;
204 }
205
206 static decode_state _decode_dsf(void) {
207
208 // samples in streambuf are interleaved on block basis
209 // we transfer whole blocks for all channels in one call and so itterate the while loop below to handle wraps
210
211 unsigned bytes = _buf_used(streambuf);
212 unsigned block_left = d->block_size;
213
214 unsigned bytes_per_frame = dop ? 2 : 1;
215
216 if (bytes < d->block_size * d->channels) {
217 LOG_WARN("stream too short");
218 return DECODE_ERROR;
219 }
220
221 IF_PROCESS(
222 process.in_frames = 0;
223 );
224
225 while (block_left) {
226
227 frames_t frames, out, count;
228 unsigned bytes_read;
229
230 u8_t *iptrl = (u8_t *)streambuf->readp;
231 u8_t *iptrr = (u8_t *)streambuf->readp + d->block_size;
232 u32_t *optr;
233
234 if (iptrr >= streambuf->wrap) {
235 iptrr -= streambuf->size;
236 }
237
238 bytes = min(block_left, min(streambuf->wrap - iptrl, streambuf->wrap - iptrr));
239
240 IF_DIRECT(
241 out = min(_buf_space(outputbuf), _buf_cont_write(outputbuf)) / BYTES_PER_FRAME;
242 optr = (u32_t *)outputbuf->writep;
243 );
244 IF_PROCESS(
245 out = process.max_in_frames - process.in_frames;
246 optr = (u32_t *)(process.inbuf + process.in_frames * BYTES_PER_FRAME);
247 );
248
249 frames = min(bytes, d->sample_bytes) / bytes_per_frame;
250 if (frames == 0) {
251 // /2 for dop should never result in 0 as header len is always even
252 LOG_WARN("frames got to zero");
253 return DECODE_ERROR;
254 }
255
256 frames = min(frames, out);
257 frames = min(frames, BLOCK);
258 bytes_read = frames * bytes_per_frame;
259
260 count = frames;
261
262 if (dop) {
263
264 if (d->channels == 1) {
265 if (d->lsb_first) {
266 while (count--) {
267 *(optr++) = dsd2pcm_bitreverse[*(iptrl)] << 16 | dsd2pcm_bitreverse[*(iptrl+1)] << 8;
268 *(optr++) = dsd2pcm_bitreverse[*(iptrl)] << 16 | dsd2pcm_bitreverse[*(iptrl+1)] << 8;
269 iptrl += 2;
270 }
271 } else {
272 while (count--) {
273 *(optr++) = *(iptrl) << 16 | *(iptrl+1) << 8;
274 *(optr++) = *(iptrl) << 16 | *(iptrl+1) << 8;
275 iptrl += 2;
276 }
277 }
278 } else {
279 if (d->lsb_first) {
280 while (count--) {
281 *(optr++) = dsd2pcm_bitreverse[*(iptrl)] << 16 | dsd2pcm_bitreverse[*(iptrl+1)] << 8;
282 *(optr++) = dsd2pcm_bitreverse[*(iptrr)] << 16 | dsd2pcm_bitreverse[*(iptrr+1)] << 8;
283 iptrl += 2;
284 iptrr += 2;
285 }
286 } else {
287 while (count--) {
288 *(optr++) = *(iptrl) << 16 | *(iptrl+1) << 8;
289 *(optr++) = *(iptrr) << 16 | *(iptrr+1) << 8;
290 iptrl += 2;
291 iptrr += 2;
292 }
293 }
294 }
295
296 } else {
297
298 if (d->channels == 1) {
299 float *iptrf = d->transfer[0];
300 dsd2pcm_translate(d->dsd2pcm_ctx[0], frames, iptrl, 1, d->lsb_first, iptrf, 1);
301 while (count--) {
302 double scaled = *iptrf++ * 0x7fffffff;
303 if (scaled > 2147483647.0) scaled = 2147483647.0;
304 if (scaled < -2147483648.0) scaled = -2147483648.0;
305 *optr++ = (s32_t)scaled;
306 *optr++ = (s32_t)scaled;
307 }
308 } else {
309 float *iptrfl = d->transfer[0];
310 float *iptrfr = d->transfer[1];
311 dsd2pcm_translate(d->dsd2pcm_ctx[0], frames, iptrl, 1, d->lsb_first, iptrfl, 1);
312 dsd2pcm_translate(d->dsd2pcm_ctx[1], frames, iptrr, 1, d->lsb_first, iptrfr, 1);
313 while (count--) {
314 double scaledl = *iptrfl++ * 0x7fffffff;
315 double scaledr = *iptrfr++ * 0x7fffffff;
316 if (scaledl > 2147483647.0) scaledl = 2147483647.0;
317 if (scaledl < -2147483648.0) scaledl = -2147483648.0;
318 if (scaledr > 2147483647.0) scaledr = 2147483647.0;
319 if (scaledr < -2147483648.0) scaledr = -2147483648.0;
320 *optr++ = (s32_t)scaledl;
321 *optr++ = (s32_t)scaledr;
322 }
323 }
324
325 }
326
327 _buf_inc_readp(streambuf, bytes_read);
328
329 block_left -= bytes_read;
330
331 if (d->sample_bytes > bytes_read) {
332 d->sample_bytes -= bytes_read;
333 } else {
334 LOG_INFO("end of track samples");
335 block_left = 0;
336 d->sample_bytes = 0;
337 }
338
339 IF_DIRECT(
340 _buf_inc_writep(outputbuf, frames * BYTES_PER_FRAME);
341 );
342 IF_PROCESS(
343 process.in_frames += frames;
344 );
345
346 LOG_SDEBUG("write %u frames", frames);
347 }
348
349 // skip the other channel blocks
350 // the right channel has already been read and is guarenteed to be in streambuf so can be skipped immediately
351 if (d->channels > 1) {
352 _buf_inc_readp(streambuf, d->block_size);
353 }
354 if (d->channels > 2) {
355 d->consume = d->block_size * (d->channels - 2);
356 }
357
358 return DECODE_RUNNING;
359 }
360
361 static decode_state _decode_dsdiff(void) {
362
363 // samples in streambuf are interleaved on byte per channel
364 // we process as little as necessary per call and only need to handle frames wrapping round streambuf
365
366 unsigned bytes_per_frame, bytes_read;
367 frames_t out, frames, count;
368 u8_t *iptr;
369 u32_t *optr;
370 u8_t tmp[WRAP_BUF_SIZE];
371
372 unsigned bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf));
373
374 IF_DIRECT(
375 out = min(_buf_space(outputbuf), _buf_cont_write(outputbuf)) / BYTES_PER_FRAME;
376 );
377 IF_PROCESS(
378 out = process.max_in_frames;
379 );
380
381 if (dop) {
382 bytes_per_frame = d->channels * 2;
383 } else {
384 bytes_per_frame = d->channels;
385 out = min(out, BLOCK);
386 }
387
388 frames = min(min(bytes, d->sample_bytes) / bytes_per_frame, out);
389 bytes_read = frames * bytes_per_frame;
390
391 iptr = (u8_t *)streambuf->readp;
392
393 IF_DIRECT(
394 optr = (u32_t *)outputbuf->writep;
395 );
396 IF_PROCESS(
397 optr = (u32_t *)process.inbuf;
398 );
399
400 // handle wrap around end of streambuf and partial dop frame at end of stream
401 if (!frames && bytes < bytes_per_frame) {
402 memset(tmp, 0x69, WRAP_BUF_SIZE); // 0x69 = dsd silence
403 memcpy(tmp, streambuf->readp, bytes);
404 if (_buf_used(streambuf) > bytes_per_frame) {
405 memcpy(tmp + bytes, streambuf->buf, bytes_per_frame - bytes);
406 bytes_read = bytes_per_frame;
407 } else {
408 bytes_read = bytes;
409 }
410 iptr = tmp;
411 frames = 1;
412 }
413
414 count = frames;
415
416 if (dop) {
417
418 if (d->channels == 1) {
419 while (count--) {
420 *(optr++) = *(iptr) << 16 | *(iptr+1) << 8;
421 *(optr++) = *(iptr) << 16 | *(iptr+1) << 8;
422 iptr += bytes_per_frame;
423 }
424 } else {
425 while (count--) {
426 *(optr++) = *(iptr ) << 16 | *(iptr + d->channels) << 8;
427 *(optr++) = *(iptr+1) << 16 | *(iptr + d->channels + 1) << 8;
428 iptr += bytes_per_frame;
429 }
430 }
431
432 } else {
433
434 if (d->channels == 1) {
435 float *iptrf = d->transfer[0];
436 dsd2pcm_translate(d->dsd2pcm_ctx[0], frames, iptr, 1, 0, iptrf, 1);
437 while (count--) {
438 double scaled = *iptrf++ * 0x7fffffff;
439 if (scaled > 2147483647.0) scaled = 2147483647.0;
440 if (scaled < -2147483648.0) scaled = -2147483648.0;
441 *optr++ = (s32_t)scaled;
442 *optr++ = (s32_t)scaled;
443 }
444 } else {
445 float *iptrfl = d->transfer[0];
446 float *iptrfr = d->transfer[1];
447 dsd2pcm_translate(d->dsd2pcm_ctx[0], frames, iptr, d->channels, 0, iptrfl, 1);
448 dsd2pcm_translate(d->dsd2pcm_ctx[1], frames, iptr + 1, d->channels, 0, iptrfr, 1);
449 while (count--) {
450 double scaledl = *iptrfl++ * 0x7fffffff;
451 double scaledr = *iptrfr++ * 0x7fffffff;
452 if (scaledl > 2147483647.0) scaledl = 2147483647.0;
453 if (scaledl < -2147483648.0) scaledl = -2147483648.0;
454 if (scaledr > 2147483647.0) scaledr = 2147483647.0;
455 if (scaledr < -2147483648.0) scaledr = -2147483648.0;
456 *optr++ = (s32_t)scaledl;
457 *optr++ = (s32_t)scaledr;
458 }
459 }
460
461 }
462
463 _buf_inc_readp(streambuf, bytes_read);
464
465 if (d->sample_bytes > bytes_read) {
466 d->sample_bytes -= bytes_read;
467 } else {
468 LOG_INFO("end of track samples");
469 d->sample_bytes = 0;
470 }
471
472 IF_DIRECT(
473 _buf_inc_writep(outputbuf, frames * BYTES_PER_FRAME);
474 );
475 IF_PROCESS(
476 process.in_frames = frames;
477 );
478
479 LOG_SDEBUG("write %u frames", frames);
480
481 return DECODE_RUNNING;
482 }
483
484
485 static decode_state dsd_decode(void) {
486 decode_state ret;
487
488 LOCK_S;
489
490 if ((stream.state <= DISCONNECT && !_buf_used(streambuf)) || (!decode.new_stream && d->sample_bytes == 0)) {
491 UNLOCK_S;
492 return DECODE_COMPLETE;
493 }
494
495 if (d->consume) {
496 unsigned consume = min(d->consume, min(_buf_used(streambuf), _buf_cont_read(streambuf)));
497 LOG_DEBUG("consume: %u of %u", consume, d->consume);
498 _buf_inc_readp(streambuf, consume);
499 d->consume -= consume;
500 if (d->consume) {
501 UNLOCK_S;
502 return DECODE_RUNNING;
503 }
504 }
505
506 if (decode.new_stream) {
507 int r = _read_header();
508 if (r < 1) {
509 UNLOCK_S;
510 return DECODE_ERROR;
511 }
512 if (r == 0) {
513 UNLOCK_S;
514 return DECODE_RUNNING;
515 }
516 // otherwise got to start of audio
517
518 LOCK_O;
519
520 LOG_INFO("setting track_start");
521 output.track_start = outputbuf->writep;
522
523 dop = output.has_dop;
524
525 if (dop && d->sample_rate / 16 > output.supported_rates[0]) {
526 LOG_INFO("DOP sample rate too high for device - converting to PCM");
527 dop = false;
528 }
529
530 if (dop) {
531 LOG_INFO("DOP output");
532 output.next_dop = true;
533 output.next_sample_rate = d->sample_rate / 16;
534 output.fade = FADE_INACTIVE;
535 } else {
536 LOG_INFO("DSD to PCM output");
537 output.next_dop = false;
538 output.next_sample_rate = decode_newstream(d->sample_rate / 8, output.supported_rates);
539 if (output.fade_mode) _checkfade(true);
540 }
541
542 decode.new_stream = false;
543
544 UNLOCK_O;
545 }
546
547 LOCK_O_direct;
548
549 switch (d->type) {
550 case DSF:
551 ret = _decode_dsf();
552 break;
553 case DSDIFF:
554 ret = _decode_dsdiff();
555 break;
556 default:
557 ret = DECODE_ERROR;
558 }
559
560 UNLOCK_O_direct;
561 UNLOCK_S;
562
563 return ret;
564 }
565
566 static void dsd_open(u8_t size, u8_t rate, u8_t chan, u8_t endianness) {
567 d->type = UNKNOWN;
568
569 if (!d->dsd2pcm_ctx[0]) {
570 d->dsd2pcm_ctx[0] = dsd2pcm_init();
571 d->dsd2pcm_ctx[1] = dsd2pcm_init();
572 } else {
573 dsd2pcm_reset(d->dsd2pcm_ctx[0]);
574 dsd2pcm_reset(d->dsd2pcm_ctx[1]);
575 }
576 if (!d->transfer[1]) {
577 d->transfer[0] = malloc(sizeof(float) * BLOCK);
578 d->transfer[1] = malloc(sizeof(float) * BLOCK);
579 }
580 }
581
582 static void dsd_close(void) {
583 if (d->dsd2pcm_ctx[0]) {
584 dsd2pcm_destroy(d->dsd2pcm_ctx[0]);
585 dsd2pcm_destroy(d->dsd2pcm_ctx[1]);
586 d->dsd2pcm_ctx[0] = NULL;
587 d->dsd2pcm_ctx[1] = NULL;
588 }
589 if (d->transfer[0]) {
590 free(d->transfer[0]);
591 free(d->transfer[1]);
592 d->transfer[0] = NULL;
593 d->transfer[1] = NULL;
594 }
595 }
596
597 struct codec *register_dsd(void) {
598 static struct codec ret = {
599 'd', // id
600 "dsf,dff", // types
601 BLOCK * 2, // min read
602 BLOCK_FRAMES,// min space
603 dsd_open, // open
604 dsd_close, // close
605 dsd_decode, // decode
606 };
607
608 d = malloc(sizeof(struct dsd));
609 if (!d) {
610 return NULL;
611 }
612
613 memset(d, 0, sizeof(struct dsd));
614
615 dsd2pcm_precalc();
616
617 LOG_INFO("using dsd");
618 return &ret;
619 }
620
621 #endif // DSD
0 Copyright 2009, 2011 Sebastian Gesemann. All rights reserved.
1
2 Redistribution and use in source and binary forms, with or without modification, are
3 permitted provided that the following conditions are met:
4
5 1. Redistributions of source code must retain the above copyright notice, this list of
6 conditions and the following disclaimer.
7
8 2. Redistributions in binary form must reproduce the above copyright notice, this list
9 of conditions and the following disclaimer in the documentation and/or other materials
10 provided with the distribution.
11
12 THIS SOFTWARE IS PROVIDED BY SEBASTIAN GESEMANN ''AS IS'' AND ANY EXPRESS OR IMPLIED
13 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
14 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SEBASTIAN GESEMANN OR
15 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
16 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
17 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
18 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
19 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
20 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21
22 The views and conclusions contained in the software and documentation are those of the
23 authors and should not be interpreted as representing official policies, either expressed
24 or implied, of Sebastian Gesemann.
0 /*
1
2 Copyright 2009, 2011 Sebastian Gesemann. All rights reserved.
3
4 Redistribution and use in source and binary forms, with or without modification, are
5 permitted provided that the following conditions are met:
6
7 1. Redistributions of source code must retain the above copyright notice, this list of
8 conditions and the following disclaimer.
9
10 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 of conditions and the following disclaimer in the documentation and/or other materials
12 provided with the distribution.
13
14 THIS SOFTWARE IS PROVIDED BY SEBASTIAN GESEMANN ''AS IS'' AND ANY EXPRESS OR IMPLIED
15 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SEBASTIAN GESEMANN OR
17 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
24 The views and conclusions contained in the software and documentation are those of the
25 authors and should not be interpreted as representing official policies, either expressed
26 or implied, of Sebastian Gesemann.
27
28 ----
29
30 Additions (c) Adrian Smith, 2013 under same licence terms:
31 - expose bitreverse array as dsd2pcm_bitreverse
32 - expose precalc function as dsd2pcm_precalc to allow it to be initalised
33
34 */
35
36 #include <stdlib.h>
37 #include <string.h>
38
39 #include "dsd2pcm.h"
40
41 #define HTAPS 48 /* number of FIR constants */
42 #define FIFOSIZE 16 /* must be a power of two */
43 #define FIFOMASK (FIFOSIZE-1) /* bit mask for FIFO offsets */
44 #define CTABLES ((HTAPS+7)/8) /* number of "8 MACs" lookup tables */
45
46 #if FIFOSIZE*8 < HTAPS*2
47 #error "FIFOSIZE too small"
48 #endif
49
50 /*
51 * Properties of this 96-tap lowpass filter when applied on a signal
52 * with sampling rate of 44100*64 Hz:
53 *
54 * () has a delay of 17 microseconds.
55 *
56 * () flat response up to 48 kHz
57 *
58 * () if you downsample afterwards by a factor of 8, the
59 * spectrum below 70 kHz is practically alias-free.
60 *
61 * () stopband rejection is about 160 dB
62 *
63 * The coefficient tables ("ctables") take only 6 Kibi Bytes and
64 * should fit into a modern processor's fast cache.
65 */
66
67 /*
68 * The 2nd half (48 coeffs) of a 96-tap symmetric lowpass filter
69 */
70 static const double htaps[HTAPS] = {
71 0.09950731974056658,
72 0.09562845727714668,
73 0.08819647126516944,
74 0.07782552527068175,
75 0.06534876523171299,
76 0.05172629311427257,
77 0.0379429484910187,
78 0.02490921351762261,
79 0.0133774746265897,
80 0.003883043418804416,
81 -0.003284703416210726,
82 -0.008080250212687497,
83 -0.01067241812471033,
84 -0.01139427235000863,
85 -0.0106813877974587,
86 -0.009007905078766049,
87 -0.006828859761015335,
88 -0.004535184322001496,
89 -0.002425035959059578,
90 -0.0006922187080790708,
91 0.0005700762133516592,
92 0.001353838005269448,
93 0.001713709169690937,
94 0.001742046839472948,
95 0.001545601648013235,
96 0.001226696225277855,
97 0.0008704322683580222,
98 0.0005381636200535649,
99 0.000266446345425276,
100 7.002968738383528e-05,
101 -5.279407053811266e-05,
102 -0.0001140625650874684,
103 -0.0001304796361231895,
104 -0.0001189970287491285,
105 -9.396247155265073e-05,
106 -6.577634378272832e-05,
107 -4.07492895872535e-05,
108 -2.17407957554587e-05,
109 -9.163058931391722e-06,
110 -2.017460145032201e-06,
111 1.249721855219005e-06,
112 2.166655190537392e-06,
113 1.930520892991082e-06,
114 1.319400334374195e-06,
115 7.410039764949091e-07,
116 3.423230509967409e-07,
117 1.244182214744588e-07,
118 3.130441005359396e-08
119 };
120
121 static float ctables[CTABLES][256];
122 unsigned char dsd2pcm_bitreverse[256];
123 static int precalculated = 0;
124
125 void dsd2pcm_precalc(void)
126 {
127 int t, e, m, k;
128 double acc;
129 if (precalculated) return;
130 for (t=0, e=0; t<256; ++t) {
131 dsd2pcm_bitreverse[t] = e;
132 for (m=128; m && !((e^=m)&m); m>>=1)
133 ;
134 }
135 for (t=0; t<CTABLES; ++t) {
136 k = HTAPS - t*8;
137 if (k>8) k=8;
138 for (e=0; e<256; ++e) {
139 acc = 0.0;
140 for (m=0; m<k; ++m) {
141 acc += (((e >> (7-m)) & 1)*2-1) * htaps[t*8+m];
142 }
143 ctables[CTABLES-1-t][e] = (float)acc;
144 }
145 }
146 precalculated = 1;
147 }
148
149 struct dsd2pcm_ctx_s
150 {
151 unsigned char fifo[FIFOSIZE];
152 unsigned fifopos;
153 };
154
155 extern dsd2pcm_ctx* dsd2pcm_init()
156 {
157 dsd2pcm_ctx* ptr;
158 if (!precalculated) dsd2pcm_precalc();
159 ptr = (dsd2pcm_ctx*) malloc(sizeof(dsd2pcm_ctx));
160 if (ptr) dsd2pcm_reset(ptr);
161 return ptr;
162 }
163
164 extern void dsd2pcm_destroy(dsd2pcm_ctx* ptr)
165 {
166 free(ptr);
167 }
168
169 extern dsd2pcm_ctx* dsd2pcm_clone(dsd2pcm_ctx* ptr)
170 {
171 dsd2pcm_ctx* p2;
172 p2 = (dsd2pcm_ctx*) malloc(sizeof(dsd2pcm_ctx));
173 if (p2) {
174 memcpy(p2,ptr,sizeof(dsd2pcm_ctx));
175 }
176 return p2;
177 }
178
179 extern void dsd2pcm_reset(dsd2pcm_ctx* ptr)
180 {
181 int i;
182 for (i=0; i<FIFOSIZE; ++i)
183 ptr->fifo[i] = 0x69; /* my favorite silence pattern */
184 ptr->fifopos = 0;
185 /* 0x69 = 01101001
186 * This pattern "on repeat" makes a low energy 352.8 kHz tone
187 * and a high energy 1.0584 MHz tone which should be filtered
188 * out completely by any playback system --> silence
189 */
190 }
191
192 extern void dsd2pcm_translate(
193 dsd2pcm_ctx* ptr,
194 size_t samples,
195 const unsigned char *src, ptrdiff_t src_stride,
196 int lsbf,
197 float *dst, ptrdiff_t dst_stride)
198 {
199 unsigned ffp;
200 unsigned i;
201 unsigned bite1, bite2;
202 unsigned char* p;
203 double acc;
204 ffp = ptr->fifopos;
205 lsbf = lsbf ? 1 : 0;
206 while (samples-- > 0) {
207 bite1 = *src & 0xFFu;
208 if (lsbf) bite1 = dsd2pcm_bitreverse[bite1];
209 ptr->fifo[ffp] = bite1; src += src_stride;
210 p = ptr->fifo + ((ffp-CTABLES) & FIFOMASK);
211 *p = dsd2pcm_bitreverse[*p & 0xFF];
212 acc = 0;
213 for (i=0; i<CTABLES; ++i) {
214 bite1 = ptr->fifo[(ffp -i) & FIFOMASK] & 0xFF;
215 bite2 = ptr->fifo[(ffp-(CTABLES*2-1)+i) & FIFOMASK] & 0xFF;
216 acc += ctables[i][bite1] + ctables[i][bite2];
217 }
218 *dst = (float)acc; dst += dst_stride;
219 ffp = (ffp + 1) & FIFOMASK;
220 }
221 ptr->fifopos = ffp;
222 }
223
0 /*
1
2 Copyright 2009, 2011 Sebastian Gesemann. All rights reserved.
3
4 Redistribution and use in source and binary forms, with or without modification, are
5 permitted provided that the following conditions are met:
6
7 1. Redistributions of source code must retain the above copyright notice, this list of
8 conditions and the following disclaimer.
9
10 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 of conditions and the following disclaimer in the documentation and/or other materials
12 provided with the distribution.
13
14 THIS SOFTWARE IS PROVIDED BY SEBASTIAN GESEMANN ''AS IS'' AND ANY EXPRESS OR IMPLIED
15 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SEBASTIAN GESEMANN OR
17 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
24 The views and conclusions contained in the software and documentation are those of the
25 authors and should not be interpreted as representing official policies, either expressed
26 or implied, of Sebastian Gesemann.
27
28 ----
29
30 Marked additions (c) Adrian Smith, 2013 under same licence terms
31
32 */
33
34 #ifndef DSD2PCM_H_INCLUDED
35 #define DSD2PCM_H_INCLUDED
36
37 #include <stddef.h>
38 #include <string.h>
39
40 #ifdef __cplusplus
41 extern "C" {
42 #endif
43
44 struct dsd2pcm_ctx_s;
45
46 typedef struct dsd2pcm_ctx_s dsd2pcm_ctx;
47
48 /**
49 * initializes a "dsd2pcm engine" for one channel
50 * (precomputes tables and allocates memory)
51 *
52 * This is the only function that is not thread-safe in terms of the
53 * POSIX thread-safety definition because it modifies global state
54 * (lookup tables are computed during the first call)
55 */
56 extern dsd2pcm_ctx* dsd2pcm_init(void);
57
58 /**
59 * deinitializes a "dsd2pcm engine"
60 * (releases memory, don't forget!)
61 */
62 extern void dsd2pcm_destroy(dsd2pcm_ctx *ctx);
63
64 /**
65 * clones the context and returns a pointer to the
66 * newly allocated copy
67 */
68 extern dsd2pcm_ctx* dsd2pcm_clone(dsd2pcm_ctx *ctx);
69
70 /**
71 * resets the internal state for a fresh new stream
72 */
73 extern void dsd2pcm_reset(dsd2pcm_ctx *ctx);
74
75 /**
76 * "translates" a stream of octets to a stream of floats
77 * (8:1 decimation)
78 * @param ctx -- pointer to abstract context (buffers)
79 * @param samples -- number of octets/samples to "translate"
80 * @param src -- pointer to first octet (input)
81 * @param src_stride -- src pointer increment
82 * @param lsbitfirst -- bitorder, 0=msb first, 1=lsbfirst
83 * @param dst -- pointer to first float (output)
84 * @param dst_stride -- dst pointer increment
85 */
86 extern void dsd2pcm_translate(dsd2pcm_ctx *ctx,
87 size_t samples,
88 const unsigned char *src, ptrdiff_t src_stride,
89 int lsbitfirst,
90 float *dst, ptrdiff_t dst_stride);
91
92 /**
93 * Additions by Adrian Smith (c) 2013 for Squeezelite
94 */
95 extern unsigned char dsd2pcm_bitreverse[];
96
97 extern void dsd2pcm_precalc(void);
98 /**
99 * End of addition
100 */
101
102 #ifdef __cplusplus
103 } /* extern "C" */
104 #endif
105
106 #endif /* include guard DSD2PCM_H_INCLUDED */
107
374374
375375 LOCK_O;
376376 LOG_INFO("setting track_start");
377 output.next_sample_rate = decode_newstream(samplerate, output.max_sample_rate);
377 output.next_sample_rate = decode_newstream(samplerate, output.supported_rates);
378 IF_DSD( output.next_dop = false; )
378379 output.track_start = outputbuf->writep;
379380 if (output.fade_mode) _checkfade(true);
380381 decode.new_stream = false;
337337
338338 LOCK_O;
339339 LOG_INFO("setting track_start");
340 output.next_sample_rate = decode_newstream(ff->codecC->sample_rate, output.max_sample_rate);
340 output.next_sample_rate = decode_newstream(ff->codecC->sample_rate, output.supported_rates);
341 IF_DSD( output.next_dop = false; )
341342 output.track_start = outputbuf->writep;
342343 if (output.fade_mode) _checkfade(true);
343344 decode.new_stream = false;
113113 if (decode.new_stream) {
114114 LOCK_O;
115115 LOG_INFO("setting track_start");
116 output.next_sample_rate = decode_newstream(frame->header.sample_rate, output.max_sample_rate);
117116 output.track_start = outputbuf->writep;
117 decode.new_stream = false;
118
119 #if DSD
120 if (output.has_dop && bits_per_sample == 24 && is_flac_dop((u32_t *)lptr, (u32_t *)rptr, frames)) {
121 LOG_INFO("file contains DOP");
122 output.next_dop = true;
123 output.next_sample_rate = frame->header.sample_rate;
124 output.fade = FADE_INACTIVE;
125 } else {
126 output.next_sample_rate = decode_newstream(frame->header.sample_rate, output.supported_rates);
127 output.next_dop = false;
128 if (output.fade_mode) _checkfade(true);
129 }
130 #else
131 output.next_sample_rate = decode_newstream(frame->header.sample_rate, output.supported_rates);
118132 if (output.fade_mode) _checkfade(true);
119 decode.new_stream = false;
133 #endif
134
120135 UNLOCK_O;
121136 }
122137
208208 if (decode.new_stream) {
209209 LOCK_O;
210210 LOG_INFO("setting track_start");
211 output.next_sample_rate = decode_newstream(m->synth.pcm.samplerate, output.max_sample_rate);
211 output.next_sample_rate = decode_newstream(m->synth.pcm.samplerate, output.supported_rates);
212 IF_DSD( output.next_dop = false; )
212213 output.track_start = outputbuf->writep;
213214 if (output.fade_mode) _checkfade(true);
214215 decode.new_stream = false;
+127
-57
main.c less more
2727 printf(TITLE " See -t for license terms\n"
2828 "Usage: %s [options]\n"
2929 " -s <server>[:<port>]\tConnect to specified server, otherwise uses autodiscovery to find server\n"
30 " -o <output device>\tSpecify output device, default \"default\"\n"
30 " -o <output device>\tSpecify output device, default \"default\", - = output to stdout\n"
3131 " -l \t\t\tList output devices\n"
3232 #if ALSA
3333 " -a <b>:<p>:<f>:<m>\tSpecify ALSA params to open output device, b = buffer time in ms or size in bytes, p = period count or size in bytes, f sample format (16|24|24_3|32), m = use mmap (0|1)\n"
3939 " -a <l>\t\tSpecify Portaudio params to open output device, l = target latency in ms\n"
4040 #endif
4141 #endif
42 " -a <f>\t\tSpecify sample format (16|24|32) of output file when using -o - to output samples to stdout (interleaved little endian only)\n"
4243 " -b <stream>:<output>\tSpecify internal Stream and Output buffer sizes in Kbytes\n"
4344 " -c <codec1>,<codec2>\tRestrict codecs to those specified, otherwise load all available codecs; known codecs: "
4445 #if FFMPEG
5051 " -f <logfile>\t\tWrite debug to logfile\n"
5152 " -m <mac addr>\t\tSet mac address, format: ab:cd:ef:12:34:56\n"
5253 " -n <name>\t\tSet the player name\n"
54 " -N <filename>\t\tStore player name in filename to allow server defined name changes to be shared between servers (not suppored with -n)\n"
5355 #if ALSA
5456 " -p <priority>\t\tSet real time priority of output thread (1-99)\n"
5557 #endif
56 " -r <rate>\t\tMax sample rate for output device, enables output device to be off when squeezelite is started\n"
58 " -r <rates>\t\tSpecify sample rates supported by device, enables output device to be off when squeezelite is started; rates = <maxrate> | <minrate>-<maxrate> | <rate1>,<rate2>,<rate3>\n"
5759 #if RESAMPLE
58 " -u [params]\t\tUpsample, params = <recipe>:<flags>:<attenuation>:<precision>:<passband_end>:<stopband_start>:<phase_response>,\n"
59 " \t\t\t recipe = (v|h|m|l|q)(|L|I|M)(|s), (|X) = async - resample to max rate for device, otherwise resample to max sync rate\n"
60 " -R -u [params]\tResample, params = <recipe>:<flags>:<attenuation>:<precision>:<passband_end>:<stopband_start>:<phase_response>,\n"
61 " \t\t\t recipe = (v|h|m|l|q)(L|I|M)(s) [E|X], E = exception - resample only if native rate not supported, X = async - resample to max rate for device, otherwise to max sync rate\n"
6062 " \t\t\t flags = num in hex,\n"
6163 " \t\t\t attenuation = attenuation in dB to apply (default is -1db if not explicitly set),\n"
6264 " \t\t\t precision = number of bits precision (NB. HQ = 20. VHQ = 28),\n"
6466 " \t\t\t stopband_start = number in percent (Aliasing/imaging control. > passband_end),\n"
6567 " \t\t\t phase_response = 0-100 (0 = minimum / 50 = linear / 100 = maximum)\n"
6668 #endif
69 #if DSD
70 " -D\t\t\tOutput device supports DSD over PCM (DoP)\n"
71 #endif
6772 #if VISEXPORT
6873 " -v \t\t\tVisulizer support\n"
6974 #endif
7277 #endif
7378 " -t \t\t\tLicense terms\n"
7479 "\n"
75 "Build options: "
80 "Build options:"
7681 #if LINUX
77 "LINUX"
82 " LINUX"
7883 #endif
7984 #if WIN
80 "WIN"
85 " WIN"
8186 #endif
8287 #if OSX
83 "OSX"
88 " OSX"
8489 #endif
8590 #if ALSA
8691 " ALSA"
105110 #endif
106111 #if VISEXPORT
107112 " VISEXPORT"
113 #endif
114 #if DSD
115 " DSD"
116 #endif
117 #if LINKALL
118 " LINKALL"
108119 #endif
109120 "\n\n",
110121 argv0);
122133 "GNU General Public License for more details.\n\n"
123134 "You should have received a copy of the GNU General Public License\n"
124135 "along with this program. If not, see <http://www.gnu.org/licenses/>.\n\n"
136 #if DSD
137 "Contains dsd2pcm library Copyright 2009, 2011 Sebastian Gesemann which\n"
138 "is subject to its own license.\n\n"
139 #endif
125140 );
126141 }
127142
137152 char *output_device = "default";
138153 char *codecs = NULL;
139154 char *name = NULL;
155 char *namefile = NULL;
140156 char *logfile = NULL;
141157 u8_t mac[6];
142158 unsigned stream_buf_size = STREAMBUF_SIZE;
143159 unsigned output_buf_size = 0; // set later
144 unsigned max_rate = 0;
145 char *upsample = NULL;
160 unsigned rates[MAX_SUPPORTED_SAMPLERATES] = { 0 };
161 char *resample = NULL;
162 char *output_params = NULL;
146163 #if LINUX
147164 bool daemonize = false;
148165 #endif
149166 #if ALSA
150 unsigned alsa_buffer = ALSA_BUFFER_TIME;
151 unsigned alsa_period = ALSA_PERIOD_COUNT;
152 char *alsa_sample_fmt = NULL;
153 bool alsa_mmap = true;
154167 unsigned rt_priority = OUTPUT_RT_PRIORITY;
155168 #endif
156 #if PORTAUDIO
157 unsigned pa_latency = 0;
158 int pa_osx_playnice = -1;
169 #if DSD
170 bool dop = false;
159171 #endif
160172 #if VISEXPORT
161173 bool visexport = false;
173185
174186 while (optind < argc && strlen(argv[optind]) >= 2 && argv[optind][0] == '-') {
175187 char *opt = argv[optind] + 1;
176 if (strstr("oabcdfmnprs", opt) && optind < argc - 1) {
188 if (strstr("oabcdfmnNprs", opt) && optind < argc - 1) {
177189 optarg = argv[optind + 1];
178190 optind += 2;
179191 } else if (strstr("ltz"
180192 #if RESAMPLE
181 "u"
193 "uR"
194 #endif
195 #if DSD
196 "D"
182197 #endif
183198 #if VISEXPORT
184199 "v"
195210 case 'o':
196211 output_device = optarg;
197212 break;
198 case 'a':
199 {
200 #if ALSA
201 char *t = next_param(optarg, ':');
202 char *c = next_param(NULL, ':');
203 char *s = next_param(NULL, ':');
204 char *m = next_param(NULL, ':');
205 if (t) alsa_buffer = atoi(t);
206 if (c) alsa_period = atoi(c);
207 if (s) alsa_sample_fmt = s;
208 if (m) alsa_mmap = atoi(m);
209 #endif
210 #if PORTAUDIO
211 char *l = next_param(optarg, ':');
212 char *p = next_param(NULL, ':');
213 if (l) pa_latency = (unsigned)atoi(l);
214 if (p) pa_osx_playnice = atoi(p);
215 #endif
216 }
213 case 'a':
214 output_params = optarg;
217215 break;
218216 case 'b':
219217 {
260258 }
261259 break;
262260 case 'r':
263 max_rate = atoi(optarg);
261 if (strstr(optarg,",")) {
262 // parse sample rates and sort them
263 char *r = next_param(optarg, ',');
264 unsigned tmp[MAX_SUPPORTED_SAMPLERATES] = { 0 };
265 int i, j;
266 int last = 999999;
267 for (i = 0; r && i < MAX_SUPPORTED_SAMPLERATES; ++i) {
268 tmp[i] = atoi(r);
269 r = next_param(NULL, ',');
270 }
271 for (i = 0; i < MAX_SUPPORTED_SAMPLERATES; ++i) {
272 int largest = 0;
273 for (j = 0; j < MAX_SUPPORTED_SAMPLERATES; ++j) {
274 if (tmp[j] > largest && tmp[j] < last) {
275 largest = tmp[j];
276 }
277 }
278 rates[i] = last = largest;
279 }
280 } else {
281 // optstr is <min>-<max> or <max>, extract rates from test rates within this range
282 unsigned ref[] TEST_RATES;
283 char *str1 = next_param(optarg, '-');
284 char *str2 = next_param(NULL, '-');
285 unsigned max = str2 ? atoi(str2) : (str1 ? atoi(str1) : ref[0]);
286 unsigned min = str1 && str2 ? atoi(str1) : 0;
287 unsigned tmp;
288 int i, j;
289 if (max < min) { tmp = max; max = min; min = tmp; }
290 rates[0] = max;
291 for (i = 0, j = 1; i < MAX_SUPPORTED_SAMPLERATES; ++i) {
292 if (ref[i] < rates[j-1] && ref[i] >= min) {
293 rates[j++] = ref[i];
294 }
295 }
296 }
264297 break;
265298 case 's':
266299 server = optarg;
267300 break;
268301 case 'n':
269302 name = optarg;
303 break;
304 case 'N':
305 namefile = optarg;
270306 break;
271307 #if ALSA
272308 case 'p':
283319 break;
284320 #if RESAMPLE
285321 case 'u':
322 case 'R':
286323 if (optind < argc && argv[optind] && argv[optind][0] != '-') {
287 upsample = argv[optind++];
324 resample = argv[optind++];
288325 } else {
289 upsample = "";
290 }
326 resample = "";
327 }
328 break;
329 #endif
330 #if DSD
331 case 'D':
332 dop = true;
291333 break;
292334 #endif
293335 #if VISEXPORT
317359 signal(SIGHUP, sighandler);
318360 #endif
319361
320 // set the output buffer size if not specified on the command line to take account of upsampling
362 // set the output buffer size if not specified on the command line, take account of resampling
321363 if (!output_buf_size) {
322364 output_buf_size = OUTPUTBUF_SIZE;
323 if (upsample) {
324 output_buf_size *= max_rate ? max_rate / 44100 : 8;
365 if (resample) {
366 unsigned scale = 8;
367 if (rates[0]) {
368 scale = rates[0] / 44100;
369 if (scale > 8) scale = 8;
370 if (scale < 1) scale = 1;
371 }
372 output_buf_size *= scale;
325373 }
326374 }
327375
345393
346394 stream_init(log_stream, stream_buf_size);
347395
348 #if ALSA
349 output_init(log_output, output_device, output_buf_size, alsa_buffer, alsa_period, alsa_sample_fmt, alsa_mmap,
350 max_rate, rt_priority);
396 if (!strcmp(output_device, "-")) {
397 output_init_stdout(log_output, output_buf_size, output_params, rates);
398 } else {
399 #if ALSA
400 output_init_alsa(log_output, output_device, output_buf_size, output_params, rates, rt_priority);
351401 #endif
352402 #if PORTAUDIO
353 output_init(log_output, output_device, output_buf_size, pa_latency, pa_osx_playnice, max_rate);
403 output_init_pa(log_output, output_device, output_buf_size, output_params, rates);
404 #endif
405 }
406
407 #if DSD
408 dop_init(dop);
354409 #endif
355410
356411 #if VISEXPORT
357412 if (visexport) {
358 output_vis_init(mac);
413 output_vis_init(log_output, mac);
359414 }
360415 #endif
361416
362417 decode_init(log_decode, codecs);
363418
364419 #if RESAMPLE
365 if (upsample) {
366 process_init(upsample);
367 }
368 #endif
369
370 slimproto(log_slimproto, server, mac, name);
420 if (resample) {
421 process_init(resample);
422 }
423 #endif
424
425 if (name && namefile) {
426 printf("-n and -N option should not be used at same time\n");
427 exit(0);
428 }
429
430 slimproto(log_slimproto, server, mac, name, namefile);
371431
372432 decode_close();
373433 stream_close();
374 output_close();
434
435 if (!strcmp(output_device, "-")) {
436 output_close_stdout();
437 } else {
438 #if ALSA
439 output_close_alsa();
440 #endif
441 #if PORTAUDIO
442 output_close_pa();
443 #endif
444 }
375445
376446 #if WIN
377447 winsock_close();
101101 bytes = min(bytes, READ_SIZE);
102102 space = min(space, WRITE_SIZE);
103103
104 if (stream.state <= DISCONNECT && bytes == 0) {
105 UNLOCK_O_direct;
106 UNLOCK_S;
107 return DECODE_COMPLETE;
108 }
109
110104 if (m->use16bit) {
111105 space = (space / BYTES_PER_FRAME) * 4;
112106 }
128122
129123 LOG_INFO("setting track_start");
130124 LOCK_O_not_direct;
131 output.next_sample_rate = decode_newstream(rate, output.max_sample_rate);
125 output.next_sample_rate = decode_newstream(rate, output.supported_rates);
126 IF_DSD( output.next_dop = false; )
132127 output.track_start = outputbuf->writep;
133128 if (output.fade_mode) _checkfade(true);
134129 decode.new_stream = false;
162157 );
163158
164159 UNLOCK_O_direct;
165 UNLOCK_S;
166160
167161 LOG_SDEBUG("write %u frames", size / BYTES_PER_FRAME);
168162
169 if (ret == MPG123_DONE) {
163 if (ret == MPG123_DONE || (bytes == 0 && size == 0 && stream.state <= DISCONNECT)) {
164 UNLOCK_S;
170165 LOG_INFO("stream complete");
171166 return DECODE_COMPLETE;
172167 }
168
169 UNLOCK_S;
173170
174171 if (ret == MPG123_ERR) {
175172 LOG_WARN("Error");
+262
-1537
output.c less more
1717 *
1818 */
1919
20 // Output using Alsa or Portaudio:
21 // - ALSA output is the preferred output for linux as it allows direct hardware access
22 // - PortAudio is the output output supported on other platforms and also builds on linux for test purposes
20 // Common output function
2321
2422 #include "squeezelite.h"
25 #if ALSA
26 #include <alsa/asoundlib.h>
27 #include <sys/mman.h>
28 #include <malloc.h>
23
24 static log_level loglevel;
25
26 struct outputstate output;
27
28 static struct buffer buf;
29
30 struct buffer *outputbuf = &buf;
31
32 u8_t *silencebuf;
33 #if DSD
34 u8_t *silencebuf_dop;
2935 #endif
30 #if PORTAUDIO
31 #include <portaudio.h>
32 #if OSX
33 #include <pa_mac_core.h>
34 #endif
35 #endif
36 #if VISEXPORT && !ALSA
37 #include <sys/mman.h>
38 #include <fcntl.h>
39 #endif
40
41 #if ALSA
42
43 #define MAX_SILENCE_FRAMES 1024
44 #define MAX_DEVICE_LEN 128
45
46 static snd_pcm_format_t fmts[] = { SND_PCM_FORMAT_S32_LE, SND_PCM_FORMAT_S24_LE, SND_PCM_FORMAT_S24_3LE, SND_PCM_FORMAT_S16_LE,
47 SND_PCM_FORMAT_UNKNOWN };
48 #if SL_LITTLE_ENDIAN
49 #define NATIVE_FORMAT SND_PCM_FORMAT_S32_LE
50 #else
51 #define NATIVE_FORMAT SND_PCM_FORMAT_S32_BE
52 #endif
53
54 // ouput device
55 static struct {
56 char device[MAX_DEVICE_LEN + 1];
57 snd_pcm_format_t format;
58 snd_pcm_uframes_t buffer_size;
59 snd_pcm_uframes_t period_size;
60 unsigned rate;
61 bool mmap;
62 u8_t *write_buf;
63 } alsa;
64
65 static u8_t silencebuf[MAX_SILENCE_FRAMES * BYTES_PER_FRAME];
66
67 #endif // ALSA
68
69 #if PORTAUDIO
70
71 #define MAX_SILENCE_FRAMES 102400 // silencebuf not used in pa case so set large
72
73 // ouput device
74 static struct {
75 unsigned rate;
76 PaStream *stream;
77 } pa;
78
79 #endif // PORTAUDIO
80
81 #if VISEXPORT
82
83 #define VIS_BUF_SIZE 16384
84 #define VIS_LOCK_NS 1000000 // ns to wait for vis wrlock
85
86 static struct vis_t {
87 pthread_rwlock_t rwlock;
88 u32_t buf_size;
89 u32_t buf_index;
90 bool running;
91 u32_t rate;
92 time_t updated;
93 s16_t buffer[VIS_BUF_SIZE];
94 } *vis_mmap = NULL;
95
96 static char vis_shm_path[40];
97 static int vis_fd = -1;
98
99 #endif // VISEXPORT
100
101 static log_level loglevel;
102
103 struct outputstate output;
104
105 static struct buffer buf;
106
107 struct buffer *outputbuf = &buf;
108
109 static bool running = true;
11036
11137 #define LOCK mutex_lock(outputbuf->mutex)
11238 #define UNLOCK mutex_unlock(outputbuf->mutex)
11339
114 #define MAX_SCALESAMPLE 0x7fffffffffffLL
115 #define MIN_SCALESAMPLE -MAX_SCALESAMPLE
116
117 static inline s32_t gain(s32_t gain, s32_t sample) {
118 s64_t res = (s64_t)gain * (s64_t)sample;
119 if (res > MAX_SCALESAMPLE) res = MAX_SCALESAMPLE;
120 if (res < MIN_SCALESAMPLE) res = MIN_SCALESAMPLE;
121 return (s32_t) (res >> 16);
122 }
123
124 static inline s32_t to_gain(float f) {
125 return (s32_t)(f * 65536.0F);
126 }
127
128 #if ALSA
129
130 void list_devices(void) {
131 void **hints, **n;
132 if (snd_device_name_hint(-1, "pcm", &hints) >= 0) {
133 n = hints;
134 printf("Output devices:\n");
135 while (*n) {
136 char *name = snd_device_name_get_hint(*n, "NAME");
137 char *desc = snd_device_name_get_hint(*n, "DESC");
138 if (name) printf(" %-30s", name);
139 if (desc) {
140 char *s1 = strtok(desc, "\n");
141 char *s2 = strtok(NULL, "\n");
142 if (s1) printf(" - %s", s1);
143 if (s2) printf(" - %s", s2);
144 }
145 printf("\n");
146 if (name) free(name);
147 if (desc) free(desc);
148 n++;
149 }
150 snd_device_name_free_hint(hints);
151 }
152 printf("\n");
153 }
154
155 static void *alsa_error_handler(const char *file, int line, const char *function, int err, const char *fmt, ...) {
156 va_list args;
157 if ((loglevel >= lINFO && err == 0) || loglevel >= lDEBUG) {
158 fprintf(stderr, "%s ALSA %s:%d ", logtime(), function, line);
159 va_start(args, fmt);
160 vfprintf(stderr, fmt, args);
161 fprintf(stderr, "\n");
162 fflush(stderr);
163 }
164 return NULL;
165 }
166
167 static void alsa_close(snd_pcm_t *pcmp) {
168 int err;
169 if ((err = snd_pcm_close(pcmp)) < 0) {
170 LOG_INFO("snd_pcm_close error: %s", snd_strerror(err));
171 }
172 }
173
174 static bool test_open(const char *device, u32_t *max_rate) {
175 int err;
176 snd_pcm_t *pcm;
177 snd_pcm_hw_params_t *hw_params;
178 hw_params = (snd_pcm_hw_params_t *) alloca(snd_pcm_hw_params_sizeof());
179 memset(hw_params, 0, snd_pcm_hw_params_sizeof());
180
181 // open device
182 if ((err = snd_pcm_open(&pcm, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
183 LOG_ERROR("playback open error: %s", snd_strerror(err));
184 return false;
185 }
186
187 // get max params
188 if ((err = snd_pcm_hw_params_any(pcm, hw_params)) < 0) {
189 LOG_ERROR("hwparam init error: %s", snd_strerror(err));
190 return false;
191 }
192
193 // get max rate
194 if ((err = snd_pcm_hw_params_get_rate_max(hw_params, max_rate, 0)) < 0) {
195 LOG_ERROR("unable to get max sample rate: %s", snd_strerror(err));
196 return false;
197 }
198
199 if (*max_rate > 384000) {
200 *max_rate = 384000;
201 }
202
203 if ((err = snd_pcm_close(pcm)) < 0) {
204 LOG_ERROR("snd_pcm_close error: %s", snd_strerror(err));
205 return false;
206 }
207
208 return true;
209 }
210
211 static bool pcm_probe(const char *device) {
212 int err;
213 snd_pcm_t *pcm;
214
215 if ((err = snd_pcm_open(&pcm, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
216 return false;
217 }
218
219 if ((err = snd_pcm_close(pcm)) < 0) {
220 LOG_ERROR("snd_pcm_close error: %s", snd_strerror(err));
221 }
222
223 return true;
224 }
225
226 static int alsa_open(snd_pcm_t **pcmp, const char *device, unsigned sample_rate, unsigned alsa_buffer, unsigned alsa_period) {
227 int err;
228 snd_pcm_hw_params_t *hw_params;
229 snd_pcm_hw_params_alloca(&hw_params);
230
231 // close if already open
232 if (*pcmp) alsa_close(*pcmp);
233
234 // reset params
235 alsa.rate = 0;
236 alsa.period_size = 0;
237 strcpy(alsa.device, device);
238
239 if (strlen(device) > MAX_DEVICE_LEN - 4 - 1) {
240 LOG_ERROR("device name too long: %s", device);
241 return -1;
242 }
243
244 bool retry;
245 do {
246 // open device
247 if ((err = snd_pcm_open(pcmp, alsa.device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
248 LOG_ERROR("playback open error: %s", snd_strerror(err));
249 return err;
250 }
251
252 // init params
253 memset(hw_params, 0, snd_pcm_hw_params_sizeof());
254 if ((err = snd_pcm_hw_params_any(*pcmp, hw_params)) < 0) {
255 LOG_ERROR("hwparam init error: %s", snd_strerror(err));
256 return err;
257 }
258
259 // open hw: devices without resampling, if sample rate fails try plughw: with resampling
260 bool hw = !strncmp(alsa.device, "hw:", 3);
261 retry = false;
262
263 if ((err = snd_pcm_hw_params_set_rate_resample(*pcmp, hw_params, !hw)) < 0) {
264 LOG_ERROR("resampling setup failed: %s", snd_strerror(err));
265 return err;
266 }
267
268 if ((err = snd_pcm_hw_params_set_rate(*pcmp, hw_params, sample_rate, 0)) < 0) {
269 if (hw) {
270 strcpy(alsa.device + 4, device);
271 memcpy(alsa.device, "plug", 4);
272 LOG_INFO("reopening device %s in plug mode as %s for resampling", device, alsa.device);
273 snd_pcm_close(*pcmp);
274 retry = true;
275 }
276 }
277
278 } while (retry);
279
280 // set access
281 if (!alsa.mmap || snd_pcm_hw_params_set_access(*pcmp, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) {
282 if ((err = snd_pcm_hw_params_set_access(*pcmp, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
283 LOG_ERROR("access type not available: %s", snd_strerror(err));
284 return err;
285 }
286 alsa.mmap = false;
287 }
288
289 // set the sample format
290 snd_pcm_format_t *fmt = alsa.format ? &alsa.format : (snd_pcm_format_t *)fmts;
291 do {
292 if (snd_pcm_hw_params_set_format(*pcmp, hw_params, *fmt) >= 0) {
293 LOG_INFO("opened device %s using format: %s sample rate: %u mmap: %u", alsa.device, snd_pcm_format_name(*fmt), sample_rate, alsa.mmap);
294 alsa.format = *fmt;
295 break;
296 }
297 if (alsa.format) {
298 LOG_ERROR("unable to open audio device requested format: %s", snd_pcm_format_name(alsa.format));
299 return -1;
300 }
301 ++fmt;
302 if (*fmt == SND_PCM_FORMAT_UNKNOWN) {
303 LOG_ERROR("unable to open audio device with any supported format");
304 return -1;
305 }
306 } while (*fmt != SND_PCM_FORMAT_UNKNOWN);
307
308 // set channels
309 if ((err = snd_pcm_hw_params_set_channels (*pcmp, hw_params, 2)) < 0) {
310 LOG_ERROR("channel count not available: %s", snd_strerror(err));
311 return err;
312 }
313
314 // set period size - value of < 50 treated as period count, otherwise size in bytes
315 if (alsa_period < 50) {
316 unsigned count = alsa_period;
317 if ((err = snd_pcm_hw_params_set_periods_near(*pcmp, hw_params, &count, 0)) < 0) {
318 LOG_ERROR("unable to set period count %s", snd_strerror(err));
319 return err;
320 }
321 } else {
322 snd_pcm_uframes_t size = alsa_period;
323 int dir = 0;
324 if ((err = snd_pcm_hw_params_set_period_size_near(*pcmp, hw_params, &size, &dir)) < 0) {
325 LOG_ERROR("unable to set period size %s", snd_strerror(err));
326 return err;
327 }
328 }
329
330 // set buffer size - value of < 500 treated as buffer time in ms, otherwise size in bytes
331 if (alsa_buffer < 500) {
332 unsigned time = alsa_buffer * 1000;
333 int dir = 0;
334 if ((err = snd_pcm_hw_params_set_buffer_time_near(*pcmp, hw_params, &time, &dir)) < 0) {
335 LOG_ERROR("unable to set buffer time %s", snd_strerror(err));
336 return err;
337 }
338 } else {
339 snd_pcm_uframes_t size = alsa_buffer;
340 if ((err = snd_pcm_hw_params_set_buffer_size_near(*pcmp, hw_params, &size)) < 0) {
341 LOG_ERROR("unable to set buffer size %s", snd_strerror(err));
342 return err;
343 }
344 }
345
346 // get period_size
347 if ((err = snd_pcm_hw_params_get_period_size(hw_params, &alsa.period_size, 0)) < 0) {
348 LOG_ERROR("unable to get period size: %s", snd_strerror(err));
349 return err;
350 }
351
352 // get buffer_size
353 if ((err = snd_pcm_hw_params_get_buffer_size(hw_params, &alsa.buffer_size)) < 0) {
354 LOG_ERROR("unable to get buffer size: %s", snd_strerror(err));
355 return err;
356 }
357
358 LOG_INFO("buffer: %u period: %u -> buffer size: %u period size: %u", alsa_buffer, alsa_period, alsa.buffer_size, alsa.period_size);
359
360 // create an intermediate buffer for non mmap case for all but NATIVE_FORMAT
361 // this is used to pack samples into the output format before calling writei
362 if (!alsa.mmap && !alsa.write_buf && alsa.format != NATIVE_FORMAT) {
363 alsa.write_buf = malloc(alsa.period_size * BYTES_PER_FRAME);
364 if (!alsa.write_buf) {
365 LOG_ERROR("unable to malloc write_buf");
366 return -1;
367 }
368 }
369
370 // set params
371 if ((err = snd_pcm_hw_params(*pcmp, hw_params)) < 0) {
372 LOG_ERROR("unable to set hw params: %s", snd_strerror(err));
373 return err;
374 }
375
376 // dump info
377 if (loglevel == lSDEBUG) {
378 static snd_output_t *debug_output;
379 snd_output_stdio_attach(&debug_output, stderr, 0);
380 snd_pcm_dump(*pcmp, debug_output);
381 }
382
383 // this indicates we have opened the device ok
384 alsa.rate = sample_rate;
385
386 return 0;
387 }
388
389 #endif // ALSA
390
391 #if PORTAUDIO
392
393 void list_devices(void) {
394 PaError err;
395 int i;
396
397 if ((err = Pa_Initialize()) != paNoError) {
398 LOG_WARN("error initialising port audio: %s", Pa_GetErrorText(err));
399 return;
400 }
401
402 printf("Output devices:\n");
403 for (i = 0; i < Pa_GetDeviceCount(); ++i) {
404 printf(" %i - %s [%s]\n", i, Pa_GetDeviceInfo(i)->name, Pa_GetHostApiInfo(Pa_GetDeviceInfo(i)->hostApi)->name);
405 }
406 printf("\n");
407
408 if ((err = Pa_Terminate()) != paNoError) {
409 LOG_WARN("error closing port audio: %s", Pa_GetErrorText(err));
410 }
411 }
412
413 static int pa_device_id(const char *device) {
414 int len = strlen(device);
415 int i;
416
417 if (!strncmp(device, "default", 7)) {
418 return Pa_GetDefaultOutputDevice();
419 }
420 if (len >= 1 && len <= 2 && device[0] >= '0' && device[0] <= '9') {
421 return atoi(device);
422 }
423
424 for (i = 0; i < Pa_GetDeviceCount(); ++i) {
425 if (!strncmp(Pa_GetDeviceInfo(i)->name, device, len)) {
426 return i;
427 }
428 }
429
430 return -1;
431 }
432
433 static int pa_callback(const void *pa_input, void *pa_output, unsigned long pa_frames_wanted,
434 const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData);
435
436 static bool test_open(const char *device, u32_t *max_rate) {
437 PaStreamParameters outputParameters;
438 PaError err;
439 u32_t rates[] = { 384000, 352800, 192000, 176400, 96000, 88200, 48000, 44100, 0 };
440 int device_id, i;
441
442 if ((device_id = pa_device_id(device)) == -1) {
443 LOG_INFO("device %s not found", device);
444 return false;
445 }
446
447 outputParameters.device = device_id;
448 outputParameters.channelCount = 2;
449 outputParameters.sampleFormat = paInt32;
450 outputParameters.suggestedLatency =
451 output.latency ? (double)output.latency/(double)1000 : Pa_GetDeviceInfo(outputParameters.device)->defaultHighOutputLatency;
452 outputParameters.hostApiSpecificStreamInfo = NULL;
453
454 // check supported sample rates
455 // Note use Pa_OpenStream as it appears more reliable than Pa_OpenStream on some windows apis
456 for (i = 0; rates[i]; ++i) {
457 err = Pa_OpenStream(&pa.stream, NULL, &outputParameters, (double)rates[i], paFramesPerBufferUnspecified, paNoFlag,
458 pa_callback, NULL);
459 if (err == paNoError) {
460 Pa_CloseStream(pa.stream);
461 *max_rate = rates[i];
462 break;
463 }
464 }
465
466 if (!rates[i]) {
467 LOG_WARN("no available rate found");
468 return false;
469 }
470
471 if ((err = Pa_OpenStream(&pa.stream, NULL, &outputParameters, (double)*max_rate, paFramesPerBufferUnspecified,
472 paNoFlag, pa_callback, NULL)) != paNoError) {
473 LOG_WARN("error opening stream: %s", Pa_GetErrorText(err));
474 return false;
475 }
476
477 if ((err = Pa_CloseStream(pa.stream)) != paNoError) {
478 LOG_WARN("error closing stream: %s", Pa_GetErrorText(err));
479 return false;
480 }
481
482 pa.stream = NULL;
483
484 return true;
485 }
486
487 static void pa_stream_finished(void *userdata) {
488 if (running) {
489 LOG_INFO("stream finished");
490 LOCK;
491 output.pa_reopen = true;
40 // functions starting _* are called with mutex locked
41
42 frames_t _output_frames(frames_t avail) {
43
44 frames_t frames, size;
45 bool silence;
46
47 s32_t cross_gain_in = 0, cross_gain_out = 0; s32_t *cross_ptr = NULL;
48
49 s32_t gainL = output.current_replay_gain ? gain(output.gainL, output.current_replay_gain) : output.gainL;
50 s32_t gainR = output.current_replay_gain ? gain(output.gainR, output.current_replay_gain) : output.gainR;
51
52 frames = _buf_used(outputbuf) / BYTES_PER_FRAME;
53 silence = false;
54
55 // start when threshold met
56 if (output.state == OUTPUT_BUFFER && frames > output.threshold * output.next_sample_rate / 100 && frames > output.start_frames) {
57 output.state = OUTPUT_RUNNING;
58 LOG_INFO("start buffer frames: %u", frames);
49259 wake_controller();
493 UNLOCK;
494 }
495 }
496
497 static thread_type monitor_thread;
498 bool monitor_thread_running = false;
499
500 static void *pa_monitor() {
501 bool output_off;
502
503 LOCK;
504
505 if (monitor_thread_running) {
506 LOG_DEBUG("monitor thread already running");
507 UNLOCK;
508 return 0;
509 }
510
511 LOG_DEBUG("start monitor thread");
512
513 monitor_thread_running = true;
514 output_off = (output.state == OUTPUT_OFF);
515
516 while (monitor_thread_running) {
517 if (output_off) {
518 if (output.state != OUTPUT_OFF) {
519 LOG_INFO("output on");
520 break;
521 }
60 }
61
62 // skip ahead - consume outputbuf but play nothing
63 if (output.state == OUTPUT_SKIP_FRAMES) {
64 if (frames > 0) {
65 frames_t skip = min(frames, output.skip_frames);
66 LOG_INFO("skip %u of %u frames", skip, output.skip_frames);
67 frames -= skip;
68 output.frames_played += skip;
69 while (skip > 0) {
70 frames_t cont_frames = min(skip, _buf_cont_read(outputbuf) / BYTES_PER_FRAME);
71 skip -= cont_frames;
72 _buf_inc_readp(outputbuf, cont_frames * BYTES_PER_FRAME);
73 }
74 }
75 output.state = OUTPUT_RUNNING;
76 }
77
78 // pause frames - play silence for required frames
79 if (output.state == OUTPUT_PAUSE_FRAMES) {
80 LOG_INFO("pause %u frames", output.pause_frames);
81 if (output.pause_frames == 0) {
82 output.state = OUTPUT_RUNNING;
52283 } else {
523 // this is a hack to partially support hot plugging of devices
524 // we rely on terminating and reinitalising PA to get an updated list of devices and use name for output.device
525 LOG_INFO("probing device %s", output.device);
526 Pa_Terminate();
527 Pa_Initialize();
528 pa.stream = NULL;
529 if (pa_device_id(output.device) != -1) {
530 LOG_INFO("device reopen");
531 break;
532 }
533 }
534
535 UNLOCK;
536 sleep(output_off ? 1 : 5);
537 LOCK;
538 }
539
540 LOG_DEBUG("end monitor thread");
541
542 monitor_thread_running = false;
543 pa.stream = NULL;
544
545 _pa_open();
546
547 UNLOCK;
548
549 return 0;
550 }
551
552 void _pa_open(void) {
553 PaStreamParameters outputParameters;
554 PaError err = paNoError;
555 int device_id;
556
557 if (pa.stream) {
558 if ((err = Pa_CloseStream(pa.stream)) != paNoError) {
559 LOG_WARN("error closing stream: %s", Pa_GetErrorText(err));
560 }
561 }
562
563 if (output.state == OUTPUT_OFF) {
564 // we get called when transitioning to OUTPUT_OFF to create the probe thread
565 // set err to avoid opening device and logging messages
566 err = 1;
567
568 } else if ((device_id = pa_device_id(output.device)) == -1) {
569 LOG_INFO("device %s not found", output.device);
570 err = 1;
571
572 } else {
573
574 outputParameters.device = device_id;
575 outputParameters.channelCount = 2;
576 outputParameters.sampleFormat = paInt32;
577 outputParameters.suggestedLatency =
578 output.latency ? (double)output.latency/(double)1000 : Pa_GetDeviceInfo(outputParameters.device)->defaultHighOutputLatency;
579 outputParameters.hostApiSpecificStreamInfo = NULL;
84 silence = true;
85 frames = min(avail, output.pause_frames);
86 frames = min(frames, MAX_SILENCE_FRAMES);
87 output.pause_frames -= frames;
88 }
89 }
90
91 // start at - play silence until jiffies reached
92 if (output.state == OUTPUT_START_AT) {
93 u32_t now = gettime_ms();
94 if (now >= output.start_at || output.start_at > now + 10000) {
95 output.state = OUTPUT_RUNNING;
96 } else {
97 u32_t delta_frames = (output.start_at - now) * output.current_sample_rate / 1000;
98 silence = true;
99 frames = min(avail, delta_frames);
100 frames = min(frames, MAX_SILENCE_FRAMES);
101 }
102 }
103
104 // play silence if buffering or no frames
105 if (output.state <= OUTPUT_BUFFER || frames == 0) {
106 silence = true;
107 frames = min(avail, MAX_SILENCE_FRAMES);
108 }
109
110 LOG_SDEBUG("avail: %d frames: %d silence: %d", avail, frames, silence);
111 frames = min(frames, avail);
112 size = frames;
113
114 while (size > 0) {
115 frames_t out_frames;
116 frames_t cont_frames = _buf_cont_read(outputbuf) / BYTES_PER_FRAME;
117 int wrote;
580118
581 #if OSX
582 // enable pro mode which aims to avoid resampling if possible
583 // see http://code.google.com/p/squeezelite/issues/detail?id=11 & http://code.google.com/p/squeezelite/issues/detail?id=37
584 // command line controls osx_playnice which is -1 if not specified, 0 or 1 - choose playnice if -1 or 1
585 PaMacCoreStreamInfo macInfo;
586 unsigned long streamInfoFlags;
587 if (output.osx_playnice) {
588 LOG_INFO("opening device in PlayNice mode");
589 streamInfoFlags = paMacCorePlayNice;
590 } else {
591 LOG_INFO("opening device in Pro mode");
592 streamInfoFlags = paMacCorePro;
593 }
594 PaMacCore_SetupStreamInfo(&macInfo, streamInfoFlags);
595 outputParameters.hostApiSpecificStreamInfo = &macInfo;
596 #endif
597 }
598
599 if (!err &&
600 (err = Pa_OpenStream(&pa.stream, NULL, &outputParameters, (double)output.current_sample_rate, paFramesPerBufferUnspecified,
601 paPrimeOutputBuffersUsingStreamCallback | paDitherOff, pa_callback, NULL)) != paNoError) {
602 LOG_WARN("error opening device %i - %s : %s", outputParameters.device, Pa_GetDeviceInfo(outputParameters.device)->name,
603 Pa_GetErrorText(err));
604 }
605
606 if (!err) {
607 LOG_INFO("opened device %i - %s at %u latency %u ms", outputParameters.device, Pa_GetDeviceInfo(outputParameters.device)->name,
608 (unsigned int)Pa_GetStreamInfo(pa.stream)->sampleRate, (unsigned int)(Pa_GetStreamInfo(pa.stream)->outputLatency * 1000));
609
610 pa.rate = output.current_sample_rate;
611
612 if ((err = Pa_SetStreamFinishedCallback(pa.stream, pa_stream_finished)) != paNoError) {
613 LOG_WARN("error setting finish callback: %s", Pa_GetErrorText(err));
614 }
615
616 if ((err = Pa_StartStream(pa.stream)) != paNoError) {
617 LOG_WARN("error starting stream: %s", Pa_GetErrorText(err));
618 }
619 }
620
621 if (err && !monitor_thread_running) {
622 // create a thread to check for output state change or device return
623 #if LINUX || OSX
624 pthread_create(&monitor_thread, NULL, pa_monitor, NULL);
625 #endif
626 #if WIN
627 monitor_thread = CreateThread(NULL, OUTPUT_THREAD_STACK_SIZE, (LPTHREAD_START_ROUTINE)&pa_monitor, NULL, 0, NULL);
628 #endif
629 }
630 }
631
632 #endif // PORTAUDIO
633
634
635 #if ALSA
636
637 // output thread for Alsa
638
639 static void *output_thread(void *arg) {
640 snd_pcm_t *pcmp = NULL;
641 bool start = true;
642 bool output_off = false, probe_device = (arg != NULL);
643 int err;
644
645 while (running) {
646
647 // disabled output - player is off
648 while (output_off) {
649 usleep(100000);
650 LOCK;
651 output_off = (output.state == OUTPUT_OFF);
652 UNLOCK;
653 if (!running) return 0;
654 }
655
656 // wait until device returns - to allow usb audio devices to be turned off
657 if (probe_device) {
658 while (!pcm_probe(output.device)) {
659 LOG_DEBUG("waiting for device %s to return", output.device);
660 sleep(5);
661 }
662 probe_device = false;
663 }
664
665 if (!pcmp || alsa.rate != output.current_sample_rate) {
666 LOG_INFO("open output device: %s", output.device);
667 if (!!alsa_open(&pcmp, output.device, output.current_sample_rate, output.buffer, output.period)) {
668 sleep(5);
119 if (output.track_start && !silence) {
120 if (output.track_start == outputbuf->readp) {
121 LOG_INFO("track start sample rate: %u replay_gain: %u", output.next_sample_rate, output.next_replay_gain);
122 output.frames_played = 0;
123 output.track_started = true;
124 output.current_sample_rate = output.next_sample_rate;
125 IF_DSD( output.dop = output.next_dop; )
126 if (!output.fade == FADE_ACTIVE || !output.fade_mode == FADE_CROSSFADE) {
127 output.current_replay_gain = output.next_replay_gain;
128 }
129 output.track_start = NULL;
669130 continue;
670 }
671 start = true;
672 }
673
674 snd_pcm_state_t state = snd_pcm_state(pcmp);
675
676 if (state == SND_PCM_STATE_XRUN) {
677 LOG_INFO("XRUN");
678 if ((err = snd_pcm_recover(pcmp, -EPIPE, 1)) < 0) {
679 LOG_INFO("XRUN recover failed: %s", snd_strerror(err));
680 }
681 start = true;
682 continue;
683 } else if (state == SND_PCM_STATE_SUSPENDED) {
684 if ((err = snd_pcm_recover(pcmp, -ESTRPIPE, 1)) < 0) {
685 LOG_INFO("SUSPEND recover failed: %s", snd_strerror(err));
686 }
687 } else if (state == SND_PCM_STATE_DISCONNECTED) {
688 LOG_INFO("Device %s no longer available", output.device);
689 alsa_close(pcmp);
690 pcmp = NULL;
691 probe_device = true;
692 continue;
693 }
694
695 if (start && alsa.mmap) {
696 if ((err = snd_pcm_start(pcmp)) < 0) {
697 if ((err = snd_pcm_recover(pcmp, err, 1)) < 0) {
698 if (err == -ENODEV) {
699 LOG_INFO("Device %s no longer available", output.device);
700 alsa_close(pcmp);
701 pcmp = NULL;
702 probe_device = true;
703 continue;
704 }
705 LOG_INFO("start error: %s", snd_strerror(err));
131 } else if (output.track_start > outputbuf->readp) {
132 // reduce cont_frames so we find the next track start at beginning of next chunk
133 cont_frames = min(cont_frames, (output.track_start - outputbuf->readp) / BYTES_PER_FRAME);
134 }
135 }
136
137 IF_DSD(
138 if (output.dop) {
139 gainL = gainR = FIXED_ONE;
140 }
141 )
142
143 if (output.fade && !silence) {
144 if (output.fade == FADE_DUE) {
145 if (output.fade_start == outputbuf->readp) {
146 LOG_INFO("fade start reached");
147 output.fade = FADE_ACTIVE;
148 } else if (output.fade_start > outputbuf->readp) {
149 cont_frames = min(cont_frames, (output.fade_start - outputbuf->readp) / BYTES_PER_FRAME);
706150 }
707 } else {
708 start = false;
709 }
710 }
711
712 snd_pcm_sframes_t avail = snd_pcm_avail_update(pcmp);
713
714 if (avail < 0) {
715 if ((err = snd_pcm_recover(pcmp, avail, 1)) < 0) {
716 if (err == -ENODEV) {
717 LOG_INFO("Device %s no longer available", output.device);
718 alsa_close(pcmp);
719 pcmp = NULL;
720 probe_device = true;
721 continue;
722 }
723 LOG_WARN("recover failed: %s", snd_strerror(err));
724 }
725 start = true;
726 continue;
727 }
728
729 if (avail < alsa.period_size) {
730 if ((err = snd_pcm_wait(pcmp, 1000)) < 0) {
731 if ((err = snd_pcm_recover(pcmp, err, 1)) < 0) {
732 LOG_INFO("pcm wait error: %s", snd_strerror(err));
733 }
734 start = true;
735 continue;
736 }
737 avail = snd_pcm_avail_update(pcmp);
738 }
739
740 // restrict avail in writei mode as write_buf is restricted to period_size
741 if (!alsa.mmap) {
742 avail = min(avail, alsa.period_size);
743 }
744
745 // avoid spinning in cases where wait returns but no bytes available (seen with pulse audio)
746 if (avail == 0) {
747 LOG_SDEBUG("avail 0 - sleeping");
748 usleep(10000);
749 continue;
750 }
751
752 LOCK;
753
754 // turn off if requested
755 if (output.state == OUTPUT_OFF) {
756 UNLOCK;
757 alsa_close(pcmp);
758 pcmp = NULL;
759 output_off = true;
760 LOG_INFO("disabling output");
761 #if VISEXPORT
762 if (vis_mmap) {
763 pthread_rwlock_wrlock(&vis_mmap->rwlock);
764 vis_mmap->running = false;
765 pthread_rwlock_unlock(&vis_mmap->rwlock);
766 }
767 #endif
768 continue;
769 }
770
771 #endif // ALSA
772
773 #if PORTAUDIO
774 static int pa_callback(const void *pa_input, void *pa_output, unsigned long pa_frames_wanted,
775 const PaStreamCallbackTimeInfo *time_info, PaStreamCallbackFlags statusFlags, void *userData) {
776
777 u8_t *optr = (u8_t *)pa_output;
778 frames_t avail = pa_frames_wanted;
779 #endif
780 frames_t frames, size;
781 bool silence;
782
783 s32_t cross_gain_in = 0, cross_gain_out = 0; s32_t *cross_ptr = NULL;
784
785 #if PORTAUDIO
786 LOCK;
787 #endif
788
789 frames = _buf_used(outputbuf) / BYTES_PER_FRAME;
790 silence = false;
791
792 // start when threshold met, note: avail * 4 may need tuning
793 if (output.state == OUTPUT_BUFFER && frames > output.threshold * output.next_sample_rate / 100 &&
794 #if ALSA
795 frames > alsa.buffer_size * 2
796 #endif
797 #if PORTAUDIO
798 frames > avail * 4
799 #endif
800 ) {
801 output.state = OUTPUT_RUNNING;
802 wake_controller();
803 }
804
805 // skip ahead - consume outputbuf but play nothing
806 if (output.state == OUTPUT_SKIP_FRAMES) {
807 if (frames > 0) {
808 frames_t skip = min(frames, output.skip_frames);
809 LOG_INFO("skip %u of %u frames", skip, output.skip_frames);
810 frames -= skip;
811 output.frames_played += skip;
812 while (skip > 0) {
813 frames_t cont_frames = min(skip, _buf_cont_read(outputbuf) / BYTES_PER_FRAME);
814 skip -= cont_frames;
815 _buf_inc_readp(outputbuf, cont_frames * BYTES_PER_FRAME);
816 }
817 }
818 output.state = OUTPUT_RUNNING;
819 }
820
821 // pause frames - play silence for required frames
822 if (output.state == OUTPUT_PAUSE_FRAMES) {
823 LOG_INFO("pause %u frames", output.pause_frames);
824 if (output.pause_frames == 0) {
825 output.state = OUTPUT_RUNNING;
826 } else {
827 silence = true;
828 frames = min(avail, output.pause_frames);
829 frames = min(frames, MAX_SILENCE_FRAMES);
830 output.pause_frames -= frames;
831 }
832 }
833
834 // start at - play slience until jiffies reached
835 if (output.state == OUTPUT_START_AT) {
836 u32_t now = gettime_ms();
837 if (now >= output.start_at || output.start_at > now + 10000) {
838 output.state = OUTPUT_RUNNING;
839 } else {
840 u32_t delta_frames = (output.start_at - now) * output.current_sample_rate / 1000;
841 silence = true;
842 frames = min(avail, delta_frames);
843 frames = min(frames, MAX_SILENCE_FRAMES);
844 }
845 }
846
847 // play slience if buffering or no frames
848 if (output.state <= OUTPUT_BUFFER || frames == 0) {
849 silence = true;
850 frames = min(avail, MAX_SILENCE_FRAMES);
851 }
852
853 LOG_SDEBUG("avail: %d frames: %d silence: %d", avail, frames, silence);
854 frames = min(frames, avail);
855 size = frames;
856
857 #if ALSA
858 snd_pcm_sframes_t delay;
859 snd_pcm_delay(pcmp, &delay);
860 if (delay >= 0) {
861 output.device_frames = delay;
862 } else {
863 LOG_WARN("snd_pcm_delay returns: %d", delay);
864 if (delay == -EPIPE) {
865 // EPIPE indicates underrun - attempt to recover
866 UNLOCK;
867 continue;
868 }
869 }
870 #endif
871 #if PORTAUDIO
872 output.device_frames = (unsigned)((time_info->outputBufferDacTime - Pa_GetStreamTime(pa.stream)) * output.current_sample_rate);
873 #endif
874 output.updated = gettime_ms();
875
876 while (size > 0) {
877 frames_t out_frames;
878
879 frames_t cont_frames = _buf_cont_read(outputbuf) / BYTES_PER_FRAME;
880
881 s32_t gainL = output.current_replay_gain ? gain(output.gainL, output.current_replay_gain) : output.gainL;
882 s32_t gainR = output.current_replay_gain ? gain(output.gainR, output.current_replay_gain) : output.gainR;
883
884 if (output.track_start && !silence) {
885 if (output.track_start == outputbuf->readp) {
886 LOG_INFO("track start sample rate: %u replay_gain: %u", output.next_sample_rate, output.next_replay_gain);
887 output.frames_played = 0;
888 output.track_started = true;
889 output.current_sample_rate = output.next_sample_rate;
890 if (!output.fade == FADE_ACTIVE || !output.fade_mode == FADE_CROSSFADE) {
151 }
152 if (output.fade == FADE_ACTIVE) {
153 // find position within fade
154 frames_t cur_f = outputbuf->readp >= output.fade_start ? (outputbuf->readp - output.fade_start) / BYTES_PER_FRAME :
155 (outputbuf->readp + outputbuf->size - output.fade_start) / BYTES_PER_FRAME;
156 frames_t dur_f = output.fade_end >= output.fade_start ? (output.fade_end - output.fade_start) / BYTES_PER_FRAME :
157 (output.fade_end + outputbuf->size - output.fade_start) / BYTES_PER_FRAME;
158 if (cur_f >= dur_f) {
159 if (output.fade_mode == FADE_INOUT && output.fade_dir == FADE_DOWN) {
160 LOG_INFO("fade down complete, starting fade up");
161 output.fade_dir = FADE_UP;
162 output.fade_start = outputbuf->readp;
163 output.fade_end = outputbuf->readp + dur_f * BYTES_PER_FRAME;
164 if (output.fade_end >= outputbuf->wrap) {
165 output.fade_end -= outputbuf->size;
166 }
167 cur_f = 0;
168 } else if (output.fade_mode == FADE_CROSSFADE) {
169 LOG_INFO("crossfade complete");
170 if (_buf_used(outputbuf) >= dur_f * BYTES_PER_FRAME) {
171 _buf_inc_readp(outputbuf, dur_f * BYTES_PER_FRAME);
172 LOG_INFO("skipped crossfaded start");
173 } else {
174 LOG_WARN("unable to skip crossfaded start");
175 }
176 output.fade = FADE_INACTIVE;
891177 output.current_replay_gain = output.next_replay_gain;
892 }
893 output.track_start = NULL;
894 if (output.current_sample_rate != output.next_sample_rate) {
895 output.current_sample_rate = output.next_sample_rate;
896 break;
897 }
898 continue;
899 } else if (output.track_start > outputbuf->readp) {
900 // reduce cont_frames so we find the next track start at beginning of next chunk
901 cont_frames = min(cont_frames, (output.track_start - outputbuf->readp) / BYTES_PER_FRAME);
902 }
903 }
904
905 if (output.fade && !silence) {
906 if (output.fade == FADE_DUE) {
907 if (output.fade_start == outputbuf->readp) {
908 LOG_INFO("fade start reached");
909 output.fade = FADE_ACTIVE;
910 } else if (output.fade_start > outputbuf->readp) {
911 cont_frames = min(cont_frames, (output.fade_start - outputbuf->readp) / BYTES_PER_FRAME);
178 } else {
179 LOG_INFO("fade complete");
180 output.fade = FADE_INACTIVE;
912181 }
913182 }
914 if (output.fade == FADE_ACTIVE) {
915 // find position within fade
916 frames_t cur_f = outputbuf->readp >= output.fade_start ? (outputbuf->readp - output.fade_start) / BYTES_PER_FRAME :
917 (outputbuf->readp + outputbuf->size - output.fade_start) / BYTES_PER_FRAME;
918 frames_t dur_f = output.fade_end >= output.fade_start ? (output.fade_end - output.fade_start) / BYTES_PER_FRAME :
919 (output.fade_end + outputbuf->size - output.fade_start) / BYTES_PER_FRAME;
920 if (cur_f >= dur_f) {
921 if (output.fade_mode == FADE_INOUT && output.fade_dir == FADE_DOWN) {
922 LOG_INFO("fade down complete, starting fade up");
923 output.fade_dir = FADE_UP;
924 output.fade_start = outputbuf->readp;
925 output.fade_end = outputbuf->readp + dur_f * BYTES_PER_FRAME;
926 if (output.fade_end >= outputbuf->wrap) {
927 output.fade_end -= outputbuf->size;
183 // if fade in progress set fade gain, ensure cont_frames reduced so we get to end of fade at start of chunk
184 if (output.fade) {
185 if (output.fade_end > outputbuf->readp) {
186 cont_frames = min(cont_frames, (output.fade_end - outputbuf->readp) / BYTES_PER_FRAME);
187 }
188 if (output.fade_dir == FADE_UP || output.fade_dir == FADE_DOWN) {
189 // fade in, in-out, out handled via altering standard gain
190 s32_t fade_gain;
191 if (output.fade_dir == FADE_DOWN) {
192 cur_f = dur_f - cur_f;
193 }
194 fade_gain = to_gain((float)cur_f / (float)dur_f);
195 gainL = gain(gainL, fade_gain);
196 gainR = gain(gainR, fade_gain);
197 }
198 if (output.fade_dir == FADE_CROSS) {
199 // cross fade requires special treatment - performed later based on these values
200 // support different replay gain for old and new track by retaining old value until crossfade completes
201 if (_buf_used(outputbuf) / BYTES_PER_FRAME > dur_f + size) {
202 cross_gain_in = to_gain((float)cur_f / (float)dur_f);
203 cross_gain_out = FIXED_ONE - cross_gain_in;
204 if (output.current_replay_gain) {
205 cross_gain_out = gain(cross_gain_out, output.current_replay_gain);
928206 }
929 cur_f = 0;
930 } else if (output.fade_mode == FADE_CROSSFADE) {
931 LOG_INFO("crossfade complete");
932 if (_buf_used(outputbuf) >= dur_f * BYTES_PER_FRAME) {
933 _buf_inc_readp(outputbuf, dur_f * BYTES_PER_FRAME);
934 LOG_INFO("skipped crossfaded start");
935 } else {
936 LOG_WARN("unable to skip crossfaded start");
207 if (output.next_replay_gain) {
208 cross_gain_in = gain(cross_gain_in, output.next_replay_gain);
937209 }
938 output.fade = FADE_INACTIVE;
939 output.current_replay_gain = output.next_replay_gain;
210 gainL = output.gainL;
211 gainR = output.gainR;
212 cross_ptr = (s32_t *)(output.fade_end + cur_f * BYTES_PER_FRAME);
940213 } else {
941 LOG_INFO("fade complete");
214 LOG_INFO("unable to continue crossfade - too few samples");
942215 output.fade = FADE_INACTIVE;
943216 }
944217 }
945 // if fade in progress set fade gain, ensure cont_frames reduced so we get to end of fade at start of chunk
946 if (output.fade) {
947 if (output.fade_end > outputbuf->readp) {
948 cont_frames = min(cont_frames, (output.fade_end - outputbuf->readp) / BYTES_PER_FRAME);
949 }
950 if (output.fade_dir == FADE_UP || output.fade_dir == FADE_DOWN) {
951 // fade in, in-out, out handled via altering standard gain
952 s32_t fade_gain;
953 if (output.fade_dir == FADE_DOWN) {
954 cur_f = dur_f - cur_f;
955 }
956 fade_gain = to_gain((float)cur_f / (float)dur_f);
957 gainL = gain(gainL, fade_gain);
958 gainR = gain(gainR, fade_gain);
959 }
960 if (output.fade_dir == FADE_CROSS) {
961 // cross fade requires special treatment - performed later based on these values
962 // support different replay gain for old and new track by retaining old value until crossfade completes
963 if (_buf_used(outputbuf) / BYTES_PER_FRAME > dur_f + size) {
964 cross_gain_in = to_gain((float)cur_f / (float)dur_f);
965 cross_gain_out = FIXED_ONE - cross_gain_in;
966 if (output.current_replay_gain) {
967 cross_gain_out = gain(cross_gain_out, output.current_replay_gain);
968 }
969 if (output.next_replay_gain) {
970 cross_gain_in = gain(cross_gain_in, output.next_replay_gain);
971 }
972 gainL = output.gainL;
973 gainR = output.gainR;
974 cross_ptr = (s32_t *)(output.fade_end + cur_f * BYTES_PER_FRAME);
975 } else {
976 LOG_INFO("unable to continue crossfade - too few samples");
977 output.fade = FADE_INACTIVE;
978 }
979 }
980 }
981218 }
982219 }
983
984 out_frames = !silence ? min(size, cont_frames) : size;
985
986 #if ALSA
987 if (alsa.mmap || alsa.format != NATIVE_FORMAT) {
988
989 // in all alsa cases except NATIVE_FORMAT non mmap we take this path:
990 // - mmap: scale and pack to output format, write direct into mmap region
991 // - non mmap: scale and pack into alsa.write_buf, which is the used with writei to send to alsa
992 const snd_pcm_channel_area_t *areas;
993 snd_pcm_uframes_t offset;
994 snd_pcm_uframes_t alsa_frames = (snd_pcm_uframes_t)out_frames;
995
996 if (alsa.mmap) {
997
998 snd_pcm_avail_update(pcmp);
999
1000 if ((err = snd_pcm_mmap_begin(pcmp, &areas, &offset, &alsa_frames)) < 0) {
1001 LOG_WARN("error from mmap_begin: %s", snd_strerror(err));
1002 break;
1003 }
1004
1005 out_frames = (frames_t)alsa_frames;
1006
1007 // temp for debugging mmap issues
1008 if ((areas[0].first + offset * areas[0].step) % 8 != 0) {
1009 LOG_ERROR("Error: mmap offset not multiple of 8!");
1010 }
1011 }
1012
1013 // perform crossfade buffer copying here as we do not know the actual out_frames value until here
1014 if (output.fade == FADE_ACTIVE && output.fade_dir == FADE_CROSS && cross_ptr) {
1015 s32_t *ptr = (s32_t *)(void *)outputbuf->readp;
1016 frames_t count = out_frames * 2;
1017 while (count--) {
1018 if (cross_ptr > (s32_t *)outputbuf->wrap) {
1019 cross_ptr -= outputbuf->size / BYTES_PER_FRAME * 2;
1020 }
1021 *ptr = gain(cross_gain_out, *ptr) + gain(cross_gain_in, *cross_ptr);
1022 ptr++; cross_ptr++;
1023 }
1024 }
1025
1026 void *outputptr = alsa.mmap ? (areas[0].addr + (areas[0].first + offset * areas[0].step) / 8) : alsa.write_buf;
1027 s32_t *inputptr = (s32_t *) (silence ? silencebuf : outputbuf->readp);
1028 frames_t cnt = out_frames;
1029
1030 switch(alsa.format) {
1031 case SND_PCM_FORMAT_S16_LE:
1032 {
1033 u32_t *optr = (u32_t *)(void *)outputptr;
1034 #if SL_LITTLE_ENDIAN
1035 if (gainL == FIXED_ONE && gainR == FIXED_ONE) {
1036 while (cnt--) {
1037 *(optr++) = (*(inputptr) >> 16 & 0x0000ffff) | (*(inputptr + 1) & 0xffff0000);
1038 inputptr += 2;
1039 }
1040 } else {
1041 while (cnt--) {
1042 *(optr++) = (gain(gainL, *(inputptr)) >> 16 & 0x0000ffff) | (gain(gainR, *(inputptr+1)) & 0xffff0000);
1043 inputptr += 2;
1044 }
1045 }
1046 #else
1047 if (gainL == FIXED_ONE && gainR == FIXED_ONE) {
1048 while (cnt--) {
1049 s32_t lsample = *(inputptr++);
1050 s32_t rsample = *(inputptr++);
1051 *(optr++) =
1052 (lsample & 0x00ff0000) << 8 | (lsample & 0xff000000) >> 8 |
1053 (rsample & 0x00ff0000) >> 8 | (rsample & 0xff000000) >> 24;
1054 }
1055 } else {
1056 while (cnt--) {
1057 s32_t lsample = gain(gainL, *(inputptr++));
1058 s32_t rsample = gain(gainR, *(inputptr++));
1059 *(optr++) =
1060 (lsample & 0x00ff0000) << 8 | (lsample & 0xff000000) >> 8 |
1061 (rsample & 0x00ff0000) >> 8 | (rsample & 0xff000000) >> 24;
1062 }
1063 }
1064 #endif
1065 }
1066 break;
1067 case SND_PCM_FORMAT_S24_LE:
1068 {
1069 u32_t *optr = (u32_t *)(void *)outputptr;
1070 #if SL_LITTLE_ENDIAN
1071 if (gainL == FIXED_ONE && gainR == FIXED_ONE) {
1072 while (cnt--) {
1073 *(optr++) = *(inputptr++) >> 8;
1074 *(optr++) = *(inputptr++) >> 8;
1075 }
1076 } else {
1077 while (cnt--) {
1078 *(optr++) = gain(gainL, *(inputptr++)) >> 8;
1079 *(optr++) = gain(gainR, *(inputptr++)) >> 8;
1080 }
1081 }
1082 #else
1083 if (gainL == FIXED_ONE && gainR == FIXED_ONE) {
1084 while (cnt--) {
1085 s32_t lsample = *(inputptr++);
1086 s32_t rsample = *(inputptr++);
1087 *(optr++) =
1088 (lsample & 0xff000000) >> 16 | (lsample & 0x00ff0000) | (lsample & 0x0000ff00 << 16);
1089 *(optr++) =
1090 (rsample & 0xff000000) >> 16 | (rsample & 0x00ff0000) | (rsample & 0x0000ff00 << 16);
1091 }
1092 } else {
1093 while (cnt--) {
1094 s32_t lsample = gain(gainL, *(inputptr++));
1095 s32_t rsample = gain(gainR, *(inputptr++));
1096 *(optr++) =
1097 (lsample & 0xff000000) >> 16 | (lsample & 0x00ff0000) | (lsample & 0x0000ff00 << 16);
1098 *(optr++) =
1099 (rsample & 0xff000000) >> 16 | (rsample & 0x00ff0000) | (rsample & 0x0000ff00 << 16);
1100 }
1101 }
1102 #endif
1103 }
1104 break;
1105 case SND_PCM_FORMAT_S24_3LE:
1106 {
1107 u8_t *optr = (u8_t *)(void *)outputptr;
1108 if (gainL == FIXED_ONE && gainR == FIXED_ONE) {
1109 while (cnt) {
1110 // attempt to do 32 bit memory accesses - move 2 frames at once: 16 bytes -> 12 bytes
1111 // falls through to exception case when not aligned or if less than 2 frames to move
1112 if (((uintptr_t)optr & 0x3) == 0 && cnt >= 2) {
1113 u32_t *o_ptr = (u32_t *)(void *)optr;
1114 while (cnt >= 2) {
1115 s32_t l1 = *(inputptr++); s32_t r1 = *(inputptr++);
1116 s32_t l2 = *(inputptr++); s32_t r2 = *(inputptr++);
1117 #if SL_LITTLE_ENDIAN
1118 *(o_ptr++) = (l1 & 0xffffff00) >> 8 | (r1 & 0x0000ff00) << 16;
1119 *(o_ptr++) = (r1 & 0xffff0000) >> 16 | (l2 & 0x00ffff00) << 8;
1120 *(o_ptr++) = (l2 & 0xff000000) >> 24 | (r2 & 0xffffff00);
1121 #else
1122 *(o_ptr++) = (l1 & 0x0000ff00) << 16 | (l1 & 0x00ff0000) | (l1 & 0xff000000) >> 16 |
1123 (r1 & 0x0000ff00) >> 8;
1124 *(o_ptr++) = (r1 & 0x00ff0000) << 8 | (r1 & 0xff000000) >> 8 | (l2 & 0x0000ff00) |
1125 (l2 & 0x00ff0000) >> 16;
1126 *(o_ptr++) = (l2 & 0xff000000) | (r2 & 0x0000ff00) << 8 | (r2 & 0x00ff0000) >> 8 |
1127 (r2 & 0xff000000) >> 24;
1128 #endif
1129 optr += 12;
1130 cnt -= 2;
1131 }
1132 } else {
1133 s32_t lsample = *(inputptr++);
1134 s32_t rsample = *(inputptr++);
1135 *(optr++) = (lsample & 0x0000ff00) >> 8;
1136 *(optr++) = (lsample & 0x00ff0000) >> 16;
1137 *(optr++) = (lsample & 0xff000000) >> 24;
1138 *(optr++) = (rsample & 0x0000ff00) >> 8;
1139 *(optr++) = (rsample & 0x00ff0000) >> 16;
1140 *(optr++) = (rsample & 0xff000000) >> 24;
1141 cnt--;
1142 }
1143 }
1144 } else {
1145 while (cnt) {
1146 // attempt to do 32 bit memory accesses - move 2 frames at once: 16 bytes -> 12 bytes
1147 // falls through to exception case when not aligned or if less than 2 frames to move
1148 if (((uintptr_t)optr & 0x3) == 0 && cnt >= 2) {
1149 u32_t *o_ptr = (u32_t *)(void *)optr;
1150 while (cnt >= 2) {
1151 s32_t l1 = gain(gainL, *(inputptr++)); s32_t r1 = gain(gainR, *(inputptr++));
1152 s32_t l2 = gain(gainL, *(inputptr++)); s32_t r2 = gain(gainR, *(inputptr++));
1153 #if SL_LITTLE_ENDIAN
1154 *(o_ptr++) = (l1 & 0xffffff00) >> 8 | (r1 & 0x0000ff00) << 16;
1155 *(o_ptr++) = (r1 & 0xffff0000) >> 16 | (l2 & 0x00ffff00) << 8;
1156 *(o_ptr++) = (l2 & 0xff000000) >> 24 | (r2 & 0xffffff00);
1157 #else
1158 *(o_ptr++) = (l1 & 0x0000ff00) << 16 | (l1 & 0x00ff0000) | (l1 & 0xff000000) >> 16 |
1159 (r1 & 0x0000ff00) >> 8;
1160 *(o_ptr++) = (r1 & 0x00ff0000) << 8 | (r1 & 0xff000000) >> 8 | (l2 & 0x0000ff00) |
1161 (l2 & 0x00ff0000) >> 16;
1162 *(o_ptr++) = (l2 & 0xff000000) | (r2 & 0x0000ff00) << 8 | (r2 & 0x00ff0000) >> 8 |
1163 (r2 & 0xff000000) >> 24;
1164 #endif
1165 optr += 12;
1166 cnt -= 2;
1167 }
1168 } else {
1169 s32_t lsample = gain(gainL, *(inputptr++));
1170 s32_t rsample = gain(gainR, *(inputptr++));
1171 *(optr++) = (lsample & 0x0000ff00) >> 8;
1172 *(optr++) = (lsample & 0x00ff0000) >> 16;
1173 *(optr++) = (lsample & 0xff000000) >> 24;
1174 *(optr++) = (rsample & 0x0000ff00) >> 8;
1175 *(optr++) = (rsample & 0x00ff0000) >> 16;
1176 *(optr++) = (rsample & 0xff000000) >> 24;
1177 cnt--;
1178 }
1179 }
1180 }
1181 }
1182 break;
1183 case SND_PCM_FORMAT_S32_LE:
1184 {
1185 u32_t *optr = (u32_t *)(void *)outputptr;
1186 #if SL_LITTLE_ENDIAN
1187 if (gainL == FIXED_ONE && gainR == FIXED_ONE) {
1188 memcpy(outputptr, inputptr, cnt * BYTES_PER_FRAME);
1189 } else {
1190 while (cnt--) {
1191 *(optr++) = gain(gainL, *(inputptr++));
1192 *(optr++) = gain(gainR, *(inputptr++));
1193 }
1194 }
1195 #else
1196 if (gainL == FIXED_ONE && gainR == FIXED_ONE) {
1197 while (cnt--) {
1198 s32_t lsample = *(inputptr++);
1199 s32_t rsample = *(inputptr++);
1200 *(optr++) =
1201 (lsample & 0xff000000) >> 24 | (lsample & 0x00ff0000) >> 8 |
1202 (lsample & 0x0000ff00) << 8 | (lsample & 0x000000ff) << 24;
1203 *(optr++) =
1204 (rsample & 0xff000000) >> 24 | (rsample & 0x00ff0000) >> 8 |
1205 (rsample & 0x0000ff00) << 8 | (rsample & 0x000000ff) << 24;
1206 }
1207 } else {
1208 while (cnt--) {
1209 s32_t lsample = gain(gainL, *(inputptr++));
1210 s32_t rsample = gain(gainR, *(inputptr++));
1211 *(optr++) =
1212 (lsample & 0xff000000) >> 24 | (lsample & 0x00ff0000) >> 8 |
1213 (lsample & 0x0000ff00) << 8 | (lsample & 0x000000ff) << 24;
1214 *(optr++) =
1215 (rsample & 0xff000000) >> 24 | (rsample & 0x00ff0000) >> 8 |
1216 (rsample & 0x0000ff00) << 8 | (rsample & 0x000000ff) << 24;
1217 }
1218 }
1219 #endif
1220 }
1221 break;
1222 default:
1223 break;
1224 }
1225
1226 if (alsa.mmap) {
1227 snd_pcm_sframes_t w = snd_pcm_mmap_commit(pcmp, offset, out_frames);
1228 if (w < 0 || w != out_frames) {
1229 LOG_WARN("mmap_commit error");
1230 break;
1231 }
1232 } else {
1233 snd_pcm_sframes_t w = snd_pcm_writei(pcmp, alsa.write_buf, out_frames);
1234 if (w < 0) {
1235 if (w != -EAGAIN && ((err = snd_pcm_recover(pcmp, w, 1)) < 0)) {
1236 static unsigned recover_count = 0;
1237 LOG_WARN("recover failed: %s [%u]", snd_strerror(err), ++recover_count);
1238 if (recover_count >= 10) {
1239 recover_count = 0;
1240 alsa_close(pcmp);
1241 pcmp = NULL;
1242 }
1243 }
1244 break;
1245 } else {
1246 if (w != out_frames) {
1247 LOG_WARN("writei only wrote %u of %u", w, out_frames);
1248 }
1249 out_frames = w;
1250 }
1251 }
1252
1253 } else {
1254
1255 #endif // ALSA
1256
1257 #if PORTAUDIO
1258 if (1) {
1259 #endif
1260 if (!silence) {
1261
1262 if (output.fade == FADE_ACTIVE && output.fade_dir == FADE_CROSS && cross_ptr) {
1263 s32_t *ptr = (s32_t *)(void *)outputbuf->readp;
1264 frames_t count = out_frames * 2;
1265 while (count--) {
1266 if (cross_ptr > (s32_t *)outputbuf->wrap) {
1267 cross_ptr -= outputbuf->size / BYTES_PER_FRAME * 2;
1268 }
1269 *ptr = gain(cross_gain_out, *ptr) + gain(cross_gain_in, *cross_ptr);
1270 ptr++; cross_ptr++;
1271 }
1272 }
1273
1274 if (gainL != FIXED_ONE || gainR!= FIXED_ONE) {
1275 unsigned count = out_frames;
1276 s32_t *ptrL = (s32_t *)(void *)outputbuf->readp;
1277 s32_t *ptrR = (s32_t *)(void *)outputbuf->readp + 1;
1278 while (count--) {
1279 *ptrL = gain(gainL, *ptrL);
1280 *ptrR = gain(gainR, *ptrR);
1281 ptrL += 2;
1282 ptrR += 2;
1283 }
1284 }
1285 }
1286 #if ALSA
1287 // only used in S32_LE non mmap LE case, write the 32 samples straight with writei, no need for intermediate buffer
1288 snd_pcm_sframes_t w = snd_pcm_writei(pcmp, silence ? silencebuf : outputbuf->readp, out_frames);
1289 if (w < 0) {
1290 if (w != -EAGAIN && ((err = snd_pcm_recover(pcmp, w, 1)) < 0)) {
1291 static unsigned recover_count = 0;
1292 LOG_WARN("recover failed: %s [%u]", snd_strerror(err), ++recover_count);
1293 if (recover_count >= 10) {
1294 recover_count = 0;
1295 alsa_close(pcmp);
1296 pcmp = NULL;
1297 }
1298 }
1299 break;
1300 } else {
1301 if (w != out_frames) {
1302 LOG_WARN("writei only wrote %u of %u", w, out_frames);
1303 }
1304 out_frames = w;
1305 }
1306 #endif
1307 #if PORTAUDIO
1308 if (!silence) {
1309 memcpy(optr, outputbuf->readp, out_frames * BYTES_PER_FRAME);
1310 } else {
1311 memset(optr, 0, out_frames * BYTES_PER_FRAME);
1312 }
1313
1314 optr += out_frames * BYTES_PER_FRAME;
1315 #endif
1316 }
1317
1318 size -= out_frames;
1319
1320 #if VISEXPORT
1321 // attempt to write audio to vis_mmap but do not wait more than VIS_LOCK_NS to get wrlock
1322 // this can result in missing audio export to the mmap region, but this is preferable dropping audio
1323 if (vis_mmap) {
1324 int err;
1325 err = pthread_rwlock_trywrlock(&vis_mmap->rwlock);
1326 if (err) {
1327 struct timespec ts;
1328 clock_gettime(CLOCK_REALTIME, &ts);
1329 ts.tv_nsec += VIS_LOCK_NS;
1330 if (ts.tv_nsec > 1000000000) {
1331 ts.tv_sec += 1;
1332 ts.tv_nsec -= 1000000000;
1333 }
1334 err = pthread_rwlock_timedwrlock(&vis_mmap->rwlock, &ts);
1335 }
1336
1337 if (err) {
1338 LOG_DEBUG("failed to get wrlock - skipping visulizer export");
1339
1340 } else {
1341
1342 if (silence) {
1343 vis_mmap->running = false;
1344 } else {
1345 frames_t vis_cnt = out_frames;
1346 s32_t *ptr = (s32_t *) outputbuf->readp;
1347 unsigned i = vis_mmap->buf_index;
1348
1349 if (!output.current_replay_gain) {
1350 while (vis_cnt--) {
1351 vis_mmap->buffer[i++] = *(ptr++) >> 16;
1352 vis_mmap->buffer[i++] = *(ptr++) >> 16;
1353 if (i == VIS_BUF_SIZE) i = 0;
1354 }
1355 } else {
1356 while (vis_cnt--) {
1357 vis_mmap->buffer[i++] = gain(*(ptr++), output.current_replay_gain) >> 16;
1358 vis_mmap->buffer[i++] = gain(*(ptr++), output.current_replay_gain) >> 16;
1359 if (i == VIS_BUF_SIZE) i = 0;
1360 }
1361 }
1362
1363 vis_mmap->updated = time(NULL);
1364 vis_mmap->running = true;
1365 vis_mmap->buf_index = i;
1366 vis_mmap->rate = output.current_sample_rate;
1367 }
1368
1369 pthread_rwlock_unlock(&vis_mmap->rwlock);
1370 }
1371 }
1372 #endif
220 }
221
222 out_frames = !silence ? min(size, cont_frames) : size;
223
224 wrote = output.write_cb(out_frames, silence, gainL, gainR, cross_gain_in, cross_gain_out, &cross_ptr);
225
226 if (wrote < 0) {
227 LOG_WARN("error in write cb");
228 frames -= out_frames;
229 break;
230 } else {
231 out_frames = (frames_t)wrote;
232 }
233
234 size -= out_frames;
235
236 _vis_export(outputbuf, &output, out_frames, silence);
237
238 if (!silence) {
239 _buf_inc_readp(outputbuf, out_frames * BYTES_PER_FRAME);
240 output.frames_played += out_frames;
241 }
242 }
1373243
1374 if (!silence) {
1375 _buf_inc_readp(outputbuf, out_frames * BYTES_PER_FRAME);
1376 output.frames_played += out_frames;
1377 }
1378 }
1379
1380 LOG_SDEBUG("wrote %u frames", frames);
1381
1382 #if ALSA
1383 UNLOCK;
1384 }
1385
1386 return 0;
244 LOG_SDEBUG("wrote %u frames", frames);
245
246 return frames;
1387247 }
1388 #endif
1389
1390 #if PORTAUDIO
1391 if (frames < pa_frames_wanted) {
1392 LOG_SDEBUG("pad with silence");
1393 memset(optr, 0, (pa_frames_wanted - frames) * BYTES_PER_FRAME);
1394 }
1395
1396 if (output.state == OUTPUT_OFF) {
1397 LOG_INFO("output off");
1398 UNLOCK;
1399 return paComplete;
1400 } else if (pa.rate != output.current_sample_rate) {
1401 UNLOCK;
1402 return paComplete;
1403 } else {
1404 UNLOCK;
1405 return paContinue;
1406 }
1407 }
1408 #endif
1409248
1410249 void _checkfade(bool start) {
1411250 frames_t bytes;
1469308 }
1470309 }
1471310
1472 #if ALSA
1473 static pthread_t thread;
1474 void output_init(log_level level, const char *device, unsigned output_buf_size, unsigned alsa_buffer, unsigned alsa_period,
1475 const char *alsa_sample_fmt, bool mmap, unsigned max_rate, unsigned rt_priority) {
1476 #endif
1477 #if PORTAUDIO
1478 void output_init(log_level level, const char *device, unsigned output_buf_size, unsigned latency, int osx_playnice, unsigned max_rate) {
1479 PaError err;
1480 #endif
311 void output_init_common(log_level level, const char *device, unsigned output_buf_size, unsigned rates[]) {
312 unsigned i;
313
1481314 loglevel = level;
1482
1483 LOG_INFO("init output");
1484315
1485316 output_buf_size = output_buf_size - (output_buf_size % BYTES_PER_FRAME);
1486317 LOG_DEBUG("outputbuf size: %u", output_buf_size);
1487318
1488319 buf_init(outputbuf, output_buf_size);
1489320 if (!outputbuf->buf) {
1490 LOG_ERROR("unable to malloc buffer");
321 LOG_ERROR("unable to malloc output buffer");
1491322 exit(0);
1492323 }
1493324
1494 LOCK;
325 silencebuf = malloc(MAX_SILENCE_FRAMES * BYTES_PER_FRAME);
326 if (!silencebuf) {
327 LOG_ERROR("unable to malloc silence buffer");
328 exit(0);
329 }
330 memset(silencebuf, 0, MAX_SILENCE_FRAMES * BYTES_PER_FRAME);
331
332 IF_DSD(
333 silencebuf_dop = malloc(MAX_SILENCE_FRAMES * BYTES_PER_FRAME);
334 if (!silencebuf_dop) {
335 LOG_ERROR("unable to malloc silence dop buffer");
336 exit(0);
337 }
338 dop_silence_frames((u32_t *)silencebuf_dop, MAX_SILENCE_FRAMES);
339 )
1495340
1496341 output.state = OUTPUT_STOPPED;
1497 output.current_sample_rate = 44100;
1498342 output.device = device;
1499343 output.fade = FADE_INACTIVE;
1500
1501 #if ALSA
1502 alsa.mmap = mmap;
1503 alsa.write_buf = NULL;
1504 alsa.format = 0;
1505 output.buffer = alsa_buffer;
1506 output.period = alsa_period;
1507
1508 memset(silencebuf, 0, sizeof(silencebuf));
1509
1510 if (alsa_sample_fmt) {
1511 if (!strcmp(alsa_sample_fmt, "32")) alsa.format = SND_PCM_FORMAT_S32_LE;
1512 if (!strcmp(alsa_sample_fmt, "24")) alsa.format = SND_PCM_FORMAT_S24_LE;
1513 if (!strcmp(alsa_sample_fmt, "24_3")) alsa.format = SND_PCM_FORMAT_S24_3LE;
1514 if (!strcmp(alsa_sample_fmt, "16")) alsa.format = SND_PCM_FORMAT_S16_LE;
1515 }
1516
1517 LOG_INFO("requested alsa_buffer: %u alsa_period: %u format: %s mmap: %u", output.buffer, output.period,
1518 alsa_sample_fmt ? alsa_sample_fmt : "any", alsa.mmap);
1519
1520 snd_lib_error_set_handler((snd_lib_error_handler_t)alsa_error_handler);
1521 #endif
1522
1523 #if PORTAUDIO
1524 output.latency = latency;
1525 output.osx_playnice = osx_playnice;
1526 pa.stream = NULL;
1527
1528 LOG_INFO("requested latency: %u", output.latency);
1529
1530 if ((err = Pa_Initialize()) != paNoError) {
1531 LOG_WARN("error initialising port audio: %s", Pa_GetErrorText(err));
1532 UNLOCK;
1533 exit(0);
1534 }
1535 #endif
1536
1537 if (!max_rate) {
1538 if (!test_open(output.device, &output.max_sample_rate)) {
344 output.error_opening = false;
345
346 if (!rates[0]) {
347 if (!test_open(output.device, output.supported_rates)) {
1539348 LOG_ERROR("unable to open output device");
1540 UNLOCK;
1541349 exit(0);
1542350 }
1543351 } else {
1544 output.max_sample_rate = max_rate;
1545 }
1546
1547 LOG_INFO("output: %s maxrate: %u", output.device, output.max_sample_rate);
1548
1549 #if ALSA
1550
1551 #if LINUX
1552 // RT linux - aim to avoid pagefaults by locking memory:
1553 // https://rt.wiki.kernel.org/index.php/Threaded_RT-application_with_memory_locking_and_stack_handling_example
1554 if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
1555 LOG_INFO("unable to lock memory: %s", strerror(errno));
1556 } else {
1557 LOG_INFO("memory locked");
1558 }
1559
1560 mallopt(M_TRIM_THRESHOLD, -1);
1561 mallopt(M_MMAP_MAX, 0);
1562
1563 touch_memory(silencebuf, MAX_SILENCE_FRAMES * BYTES_PER_FRAME);
1564 touch_memory(outputbuf->buf, outputbuf->size);
1565 #endif
1566
1567 // start output thread
1568 pthread_attr_t attr;
1569 pthread_attr_init(&attr);
1570 pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN + OUTPUT_THREAD_STACK_SIZE);
1571 pthread_create(&thread, &attr, output_thread, max_rate ? "probe" : NULL);
1572 pthread_attr_destroy(&attr);
1573
1574 // try to set this thread to real-time scheduler class, only works as root or if user has permission
1575 struct sched_param param;
1576 param.sched_priority = rt_priority;
1577 if (pthread_setschedparam(thread, SCHED_FIFO, &param) != 0) {
1578 LOG_DEBUG("unable to set output sched fifo: %s", strerror(errno));
1579 } else {
1580 LOG_DEBUG("set output sched fifo rt: %u", param.sched_priority);
1581 }
1582 #endif
1583
1584 #if PORTAUDIO
1585 _pa_open();
1586 #endif
1587
1588 UNLOCK;
352 for (i = 0; i < MAX_SUPPORTED_SAMPLERATES; ++i) {
353 output.supported_rates[i] = rates[i];
354 }
355 }
356
357 // set initial sample rate, preferring 44100
358 for (i = 0; i < MAX_SUPPORTED_SAMPLERATES; ++i) {
359 if (output.supported_rates[i] == 44100) {
360 output.default_sample_rate = 44100;
361 break;
362 }
363 }
364 if (!output.default_sample_rate) {
365 output.default_sample_rate = rates[0];
366 }
367
368 output.current_sample_rate = output.default_sample_rate;
369
370 if (loglevel >= lINFO) {
371 char rates_buf[10 * MAX_SUPPORTED_SAMPLERATES] = "";
372 for (i = 0; output.supported_rates[i]; ++i) {
373 char s[10];
374 sprintf(s, "%d ", output.supported_rates[i]);
375 strcat(rates_buf, s);
376 }
377 LOG_INFO("supported rates: %s", rates_buf);
378 }
1589379 }
1590380
1591 #if VISEXPORT
1592 void output_vis_init(u8_t *mac) {
1593 sprintf(vis_shm_path, "/squeezelite-%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
1594
1595 LOCK;
1596 vis_fd = shm_open(vis_shm_path, O_CREAT | O_RDWR, 0666);
1597 if (vis_fd != -1) {
1598 if (ftruncate(vis_fd, sizeof(struct vis_t)) == 0) {
1599 vis_mmap = (struct vis_t *)mmap(NULL, sizeof(struct vis_t), PROT_READ | PROT_WRITE, MAP_SHARED, vis_fd, 0);
1600 }
1601 }
1602
1603 if (vis_mmap > 0) {
1604 pthread_rwlockattr_t attr;
1605 pthread_rwlockattr_init(&attr);
1606 pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
1607 pthread_rwlock_init(&vis_mmap->rwlock, &attr);
1608 vis_mmap->buf_size = VIS_BUF_SIZE;
1609 vis_mmap->running = false;
1610 vis_mmap->rate = output.current_sample_rate;
1611 pthread_rwlockattr_destroy(&attr);
1612 LOG_INFO("opened visulizer shared memory as %s", vis_shm_path);
1613 } else {
1614 LOG_WARN("unable to open visualizer shared memory");
1615 vis_mmap = NULL;
1616 }
1617 UNLOCK;
381 void output_close_common(void) {
382 buf_destroy(outputbuf);
383 free(silencebuf);
384 IF_DSD(
385 free(silencebuf_dop);
386 )
1618387 }
1619 #endif
1620388
1621389 void output_flush(void) {
1622390 LOG_INFO("flush output buffer");
1625393 output.fade = FADE_INACTIVE;
1626394 if (output.state != OUTPUT_OFF) {
1627395 output.state = OUTPUT_STOPPED;
396 if (output.error_opening) {
397 output.current_sample_rate = output.default_sample_rate;
398 }
1628399 }
1629400 output.frames_played = 0;
1630401 UNLOCK;
1631402 }
1632
1633 void output_close(void) {
1634 #if PORTAUDIO
1635 PaError err;
1636 #endif
1637
1638 LOG_INFO("close output");
1639
1640 LOCK;
1641
1642 running = false;
1643
1644 #if ALSA
1645 UNLOCK;
1646 pthread_join(thread, NULL);
1647 if (alsa.write_buf) free(alsa.write_buf);
1648 #endif
1649
1650 #if PORTAUDIO
1651 monitor_thread_running = false;
1652
1653 if (pa.stream) {
1654 if ((err = Pa_AbortStream(pa.stream)) != paNoError) {
1655 LOG_WARN("error closing stream: %s", Pa_GetErrorText(err));
1656 }
1657 }
1658 if ((err = Pa_Terminate()) != paNoError) {
1659 LOG_WARN("error closing port audio: %s", Pa_GetErrorText(err));
1660 }
1661 UNLOCK;
1662 #endif
1663
1664 #if VISEXPORT
1665 if (vis_mmap) {
1666 pthread_rwlock_destroy(&vis_mmap->rwlock);
1667 munmap(vis_mmap, sizeof(struct vis_t));
1668 }
1669
1670 if (vis_fd != -1) {
1671 shm_unlink(vis_shm_path);
1672 close(vis_fd);
1673 }
1674 #endif
1675
1676 buf_destroy(outputbuf);
1677 }
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 // Output using Alsa
21
22 #include "squeezelite.h"
23
24 #if ALSA
25
26 #include <alsa/asoundlib.h>
27 #include <sys/mman.h>
28 #include <malloc.h>
29
30 #define MAX_DEVICE_LEN 128
31
32 static snd_pcm_format_t fmts[] = { SND_PCM_FORMAT_S32_LE, SND_PCM_FORMAT_S24_LE, SND_PCM_FORMAT_S24_3LE, SND_PCM_FORMAT_S16_LE,
33 SND_PCM_FORMAT_UNKNOWN };
34
35 #if SL_LITTLE_ENDIAN
36 #define NATIVE_FORMAT SND_PCM_FORMAT_S32_LE
37 #else
38 #define NATIVE_FORMAT SND_PCM_FORMAT_S32_BE
39 #endif
40
41 // ouput device
42 static struct {
43 char device[MAX_DEVICE_LEN + 1];
44 snd_pcm_format_t format;
45 snd_pcm_uframes_t buffer_size;
46 snd_pcm_uframes_t period_size;
47 unsigned rate;
48 bool mmap;
49 bool reopen;
50 u8_t *write_buf;
51 } alsa;
52
53 static snd_pcm_t *pcmp = NULL;
54
55 extern u8_t *silencebuf;
56 #if DSD
57 extern u8_t *silencebuf_dop;
58 #endif
59
60 static log_level loglevel;
61
62 static bool running = true;
63
64 extern struct outputstate output;
65 extern struct buffer *outputbuf;
66
67 #define LOCK mutex_lock(outputbuf->mutex)
68 #define UNLOCK mutex_unlock(outputbuf->mutex)
69
70 void list_devices(void) {
71 void **hints, **n;
72 if (snd_device_name_hint(-1, "pcm", &hints) >= 0) {
73 n = hints;
74 printf("Output devices:\n");
75 while (*n) {
76 char *name = snd_device_name_get_hint(*n, "NAME");
77 char *desc = snd_device_name_get_hint(*n, "DESC");
78 if (name) printf(" %-30s", name);
79 if (desc) {
80 char *s1 = strtok(desc, "\n");
81 char *s2 = strtok(NULL, "\n");
82 if (s1) printf(" - %s", s1);
83 if (s2) printf(" - %s", s2);
84 }
85 printf("\n");
86 if (name) free(name);
87 if (desc) free(desc);
88 n++;
89 }
90 snd_device_name_free_hint(hints);
91 }
92 printf("\n");
93 }
94
95 static void *alsa_error_handler(const char *file, int line, const char *function, int err, const char *fmt, ...) {
96 va_list args;
97 if ((loglevel >= lINFO && err == 0) || loglevel >= lDEBUG) {
98 fprintf(stderr, "%s ALSA %s:%d ", logtime(), function, line);
99 va_start(args, fmt);
100 vfprintf(stderr, fmt, args);
101 fprintf(stderr, "\n");
102 fflush(stderr);
103 }
104 return NULL;
105 }
106
107 static void alsa_close(void) {
108 int err;
109 if ((err = snd_pcm_close(pcmp)) < 0) {
110 LOG_INFO("snd_pcm_close error: %s", snd_strerror(err));
111 }
112 }
113
114 bool test_open(const char *device, unsigned rates[]) {
115 int err;
116 snd_pcm_t *pcm;
117 snd_pcm_hw_params_t *hw_params;
118 hw_params = (snd_pcm_hw_params_t *) alloca(snd_pcm_hw_params_sizeof());
119 memset(hw_params, 0, snd_pcm_hw_params_sizeof());
120
121 // open device
122 if ((err = snd_pcm_open(&pcm, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
123 LOG_ERROR("playback open error: %s", snd_strerror(err));
124 return false;
125 }
126
127 // get max params
128 if ((err = snd_pcm_hw_params_any(pcm, hw_params)) < 0) {
129 LOG_ERROR("hwparam init error: %s", snd_strerror(err));
130 return false;
131 }
132
133 // find supported sample rates to enable client side resampling of non supported rates
134 unsigned i, ind;
135 unsigned ref[] TEST_RATES;
136
137 for (i = 0, ind = 0; ref[i]; ++i) {
138 if (snd_pcm_hw_params_test_rate(pcm, hw_params, ref[i], 0) == 0) {
139 rates[ind++] = ref[i];
140 }
141 }
142
143 if ((err = snd_pcm_close(pcm)) < 0) {
144 LOG_ERROR("snd_pcm_close error: %s", snd_strerror(err));
145 return false;
146 }
147
148 return true;
149 }
150
151 static bool pcm_probe(const char *device) {
152 int err;
153 snd_pcm_t *pcm;
154
155 if ((err = snd_pcm_open(&pcm, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
156 return false;
157 }
158
159 if ((err = snd_pcm_close(pcm)) < 0) {
160 LOG_ERROR("snd_pcm_close error: %s", snd_strerror(err));
161 }
162
163 return true;
164 }
165
166 static int alsa_open(const char *device, unsigned sample_rate, unsigned alsa_buffer, unsigned alsa_period) {
167 int err;
168 snd_pcm_hw_params_t *hw_params;
169 snd_pcm_hw_params_alloca(&hw_params);
170
171 // close if already open
172 if (pcmp) alsa_close();
173
174 // reset params
175 alsa.rate = 0;
176 alsa.period_size = 0;
177 strcpy(alsa.device, device);
178
179 if (strlen(device) > MAX_DEVICE_LEN - 4 - 1) {
180 LOG_ERROR("device name too long: %s", device);
181 return -1;
182 }
183
184 bool retry;
185 do {
186 // open device
187 if ((err = snd_pcm_open(&pcmp, alsa.device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
188 LOG_ERROR("playback open error: %s", snd_strerror(err));
189 return err;
190 }
191
192 // init params
193 memset(hw_params, 0, snd_pcm_hw_params_sizeof());
194 if ((err = snd_pcm_hw_params_any(pcmp, hw_params)) < 0) {
195 LOG_ERROR("hwparam init error: %s", snd_strerror(err));
196 return err;
197 }
198
199 // open hw: devices without resampling, if sample rate fails try plughw: with resampling
200 bool hw = !strncmp(alsa.device, "hw:", 3);
201 retry = false;
202
203 if ((err = snd_pcm_hw_params_set_rate_resample(pcmp, hw_params, !hw)) < 0) {
204 LOG_ERROR("resampling setup failed: %s", snd_strerror(err));
205 return err;
206 }
207
208 if ((err = snd_pcm_hw_params_set_rate(pcmp, hw_params, sample_rate, 0)) < 0) {
209 if (hw) {
210 strcpy(alsa.device + 4, device);
211 memcpy(alsa.device, "plug", 4);
212 LOG_INFO("reopening device %s in plug mode as %s for resampling", device, alsa.device);
213 snd_pcm_close(pcmp);
214 retry = true;
215 }
216 }
217
218 } while (retry);
219
220 // set access
221 if (!alsa.mmap || snd_pcm_hw_params_set_access(pcmp, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) {
222 if ((err = snd_pcm_hw_params_set_access(pcmp, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
223 LOG_ERROR("access type not available: %s", snd_strerror(err));
224 return err;
225 }
226 alsa.mmap = false;
227 }
228
229 // set the sample format
230 snd_pcm_format_t *fmt = alsa.format ? &alsa.format : (snd_pcm_format_t *)fmts;
231 do {
232 if (snd_pcm_hw_params_set_format(pcmp, hw_params, *fmt) >= 0) {
233 LOG_INFO("opened device %s using format: %s sample rate: %u mmap: %u", alsa.device, snd_pcm_format_name(*fmt), sample_rate, alsa.mmap);
234 alsa.format = *fmt;
235 break;
236 }
237 if (alsa.format) {
238 LOG_ERROR("unable to open audio device requested format: %s", snd_pcm_format_name(alsa.format));
239 return -1;
240 }
241 ++fmt;
242 if (*fmt == SND_PCM_FORMAT_UNKNOWN) {
243 LOG_ERROR("unable to open audio device with any supported format");
244 return -1;
245 }
246 } while (*fmt != SND_PCM_FORMAT_UNKNOWN);
247
248 // set the output format to be used by _scale_and_pack
249 switch(alsa.format) {
250 case SND_PCM_FORMAT_S32_LE:
251 output.format = S32_LE; break;
252 case SND_PCM_FORMAT_S24_LE:
253 output.format = S24_LE; break;
254 case SND_PCM_FORMAT_S24_3LE:
255 output.format = S24_3LE; break;
256 case SND_PCM_FORMAT_S16_LE:
257 output.format = S16_LE; break;
258 default:
259 break;
260 }
261
262 // set channels
263 if ((err = snd_pcm_hw_params_set_channels (pcmp, hw_params, 2)) < 0) {
264 LOG_ERROR("channel count not available: %s", snd_strerror(err));
265 return err;
266 }
267
268 // set period size - value of < 50 treated as period count, otherwise size in bytes
269 if (alsa_period < 50) {
270 unsigned count = alsa_period;
271 if ((err = snd_pcm_hw_params_set_periods_near(pcmp, hw_params, &count, 0)) < 0) {
272 LOG_ERROR("unable to set period count %s", snd_strerror(err));
273 return err;
274 }
275 } else {
276 snd_pcm_uframes_t size = alsa_period;
277 int dir = 0;
278 if ((err = snd_pcm_hw_params_set_period_size_near(pcmp, hw_params, &size, &dir)) < 0) {
279 LOG_ERROR("unable to set period size %s", snd_strerror(err));
280 return err;
281 }
282 }
283
284 // set buffer size - value of < 500 treated as buffer time in ms, otherwise size in bytes
285 if (alsa_buffer < 500) {
286 unsigned time = alsa_buffer * 1000;
287 int dir = 0;
288 if ((err = snd_pcm_hw_params_set_buffer_time_near(pcmp, hw_params, &time, &dir)) < 0) {
289 LOG_ERROR("unable to set buffer time %s", snd_strerror(err));
290 return err;
291 }
292 } else {
293 snd_pcm_uframes_t size = alsa_buffer;
294 if ((err = snd_pcm_hw_params_set_buffer_size_near(pcmp, hw_params, &size)) < 0) {
295 LOG_ERROR("unable to set buffer size %s", snd_strerror(err));
296 return err;
297 }
298 }
299
300 // get period_size
301 if ((err = snd_pcm_hw_params_get_period_size(hw_params, &alsa.period_size, 0)) < 0) {
302 LOG_ERROR("unable to get period size: %s", snd_strerror(err));
303 return err;
304 }
305
306 // get buffer_size
307 if ((err = snd_pcm_hw_params_get_buffer_size(hw_params, &alsa.buffer_size)) < 0) {
308 LOG_ERROR("unable to get buffer size: %s", snd_strerror(err));
309 return err;
310 }
311
312 LOG_INFO("buffer: %u period: %u -> buffer size: %u period size: %u", alsa_buffer, alsa_period, alsa.buffer_size, alsa.period_size);
313
314 // ensure we have two buffer sizes of samples before starting output
315 output.start_frames = alsa.buffer_size * 2;
316
317 // create an intermediate buffer for non mmap case for all but NATIVE_FORMAT
318 // this is used to pack samples into the output format before calling writei
319 if (!alsa.mmap && !alsa.write_buf && alsa.format != NATIVE_FORMAT) {
320 alsa.write_buf = malloc(alsa.buffer_size * BYTES_PER_FRAME);
321 if (!alsa.write_buf) {
322 LOG_ERROR("unable to malloc write_buf");
323 return -1;
324 }
325 }
326
327 // set params
328 if ((err = snd_pcm_hw_params(pcmp, hw_params)) < 0) {
329 LOG_ERROR("unable to set hw params: %s", snd_strerror(err));
330 return err;
331 }
332
333 // dump info
334 if (loglevel == lSDEBUG) {
335 static snd_output_t *debug_output;
336 snd_output_stdio_attach(&debug_output, stderr, 0);
337 snd_pcm_dump(pcmp, debug_output);
338 }
339
340 // this indicates we have opened the device ok
341 alsa.rate = sample_rate;
342
343 return 0;
344 }
345
346 static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR,
347 s32_t cross_gain_in, s32_t cross_gain_out, s32_t **cross_ptr) {
348
349 const snd_pcm_channel_area_t *areas;
350 snd_pcm_uframes_t offset;
351 void *outputptr;
352 s32_t *inputptr;
353 int err;
354
355 if (alsa.mmap) {
356 snd_pcm_uframes_t alsa_frames = (snd_pcm_uframes_t)out_frames;
357
358 snd_pcm_avail_update(pcmp);
359
360 if ((err = snd_pcm_mmap_begin(pcmp, &areas, &offset, &alsa_frames)) < 0) {
361 LOG_WARN("error from mmap_begin: %s", snd_strerror(err));
362 return -1;
363 }
364
365 out_frames = (frames_t)alsa_frames;
366 }
367
368 if (!silence) {
369 // applying cross fade is delayed until this point as mmap_begin can change out_frames
370 if (output.fade == FADE_ACTIVE && output.fade_dir == FADE_CROSS && *cross_ptr) {
371 _apply_cross(outputbuf, out_frames, cross_gain_in, cross_gain_out, cross_ptr);
372 }
373 }
374
375 inputptr = (s32_t *) (silence ? silencebuf : outputbuf->readp);
376
377 IF_DSD(
378 if (output.dop) {
379 if (silence) {
380 inputptr = (s32_t *) silencebuf_dop;
381 }
382 update_dop_marker((u32_t *) inputptr, out_frames);
383 }
384 )
385
386 if (alsa.mmap || alsa.format != NATIVE_FORMAT) {
387
388 outputptr = alsa.mmap ? (areas[0].addr + (areas[0].first + offset * areas[0].step) / 8) : alsa.write_buf;
389
390 _scale_and_pack_frames(outputptr, inputptr, out_frames, gainL, gainR, output.format);
391
392 } else {
393
394 outputptr = (void *)inputptr;
395
396 if (!silence) {
397
398 if (gainL != FIXED_ONE || gainR!= FIXED_ONE) {
399 _apply_gain(outputbuf, out_frames, gainL, gainR);
400 }
401 }
402 }
403
404 if (alsa.mmap) {
405
406 snd_pcm_sframes_t w = snd_pcm_mmap_commit(pcmp, offset, out_frames);
407 if (w < 0 || w != out_frames) {
408 LOG_WARN("mmap_commit error");
409 return -1;
410 }
411
412 } else {
413
414 snd_pcm_sframes_t w = snd_pcm_writei(pcmp, outputptr, out_frames);
415 if (w < 0) {
416 //if (w != -EAGAIN && ((err = snd_pcm_recover(pcmp, w, 1)) < 0)) {
417 if (((err = snd_pcm_recover(pcmp, w, 1)) < 0)) {
418 static unsigned recover_count = 0;
419 LOG_WARN("recover failed: %s [%u]", snd_strerror(err), ++recover_count);
420 if (recover_count >= 10) {
421 recover_count = 0;
422 alsa_close();
423 pcmp = NULL;
424 }
425 }
426 return -1;
427 } else {
428 if (w != out_frames) {
429 LOG_WARN("writei only wrote %u of %u", w, out_frames);
430 }
431 out_frames = w;
432 }
433 }
434
435 return (int)out_frames;
436 }
437
438 static void *output_thread(void *arg) {
439 bool start = true;
440 bool output_off = false, probe_device = (arg != NULL);
441 int err;
442
443 while (running) {
444
445 // disabled output - player is off
446 while (output_off) {
447 usleep(100000);
448 LOCK;
449 output_off = (output.state == OUTPUT_OFF);
450 UNLOCK;
451 if (!running) return 0;
452 }
453
454 // wait until device returns - to allow usb audio devices to be turned off
455 if (probe_device) {
456 while (!pcm_probe(output.device)) {
457 LOG_DEBUG("waiting for device %s to return", output.device);
458 sleep(5);
459 }
460 probe_device = false;
461 }
462
463 if (!pcmp || alsa.rate != output.current_sample_rate) {
464 LOG_INFO("open output device: %s", output.device);
465 LOCK;
466
467 // FIXME - some alsa hardware requires opening twice for a new sample rate to work
468 // this is a workaround which should be removed
469 if (alsa.reopen) {
470 alsa_open(output.device, output.current_sample_rate, output.buffer, output.period);
471 }
472
473 if (!!alsa_open(output.device, output.current_sample_rate, output.buffer, output.period)) {
474 output.error_opening = true;
475 UNLOCK;
476 sleep(5);
477 continue;
478 }
479 output.error_opening = false;
480 start = true;
481 UNLOCK;
482 }
483
484 snd_pcm_state_t state = snd_pcm_state(pcmp);
485
486 if (state == SND_PCM_STATE_XRUN) {
487 LOG_INFO("XRUN");
488 if ((err = snd_pcm_recover(pcmp, -EPIPE, 1)) < 0) {
489 LOG_INFO("XRUN recover failed: %s", snd_strerror(err));
490 }
491 start = true;
492 continue;
493 } else if (state == SND_PCM_STATE_SUSPENDED) {
494 if ((err = snd_pcm_recover(pcmp, -ESTRPIPE, 1)) < 0) {
495 LOG_INFO("SUSPEND recover failed: %s", snd_strerror(err));
496 }
497 } else if (state == SND_PCM_STATE_DISCONNECTED) {
498 LOG_INFO("Device %s no longer available", output.device);
499 alsa_close();
500 pcmp = NULL;
501 probe_device = true;
502 continue;
503 }
504
505 snd_pcm_sframes_t avail = snd_pcm_avail_update(pcmp);
506
507 if (avail < 0) {
508 if ((err = snd_pcm_recover(pcmp, avail, 1)) < 0) {
509 if (err == -ENODEV) {
510 LOG_INFO("Device %s no longer available", output.device);
511 alsa_close();
512 pcmp = NULL;
513 probe_device = true;
514 continue;
515 }
516 LOG_WARN("recover failed: %s", snd_strerror(err));
517 }
518 start = true;
519 continue;
520 }
521
522 if (avail < alsa.period_size) {
523 if (start) {
524 if (alsa.mmap && ((err = snd_pcm_start(pcmp)) < 0)) {
525 if ((err = snd_pcm_recover(pcmp, err, 1)) < 0) {
526 if (err == -ENODEV) {
527 LOG_INFO("Device %s no longer available", output.device);
528 alsa_close();
529 pcmp = NULL;
530 probe_device = true;
531 continue;
532 }
533 LOG_INFO("start error: %s", snd_strerror(err));
534 }
535 } else {
536 start = false;
537 }
538 } else {
539 if ((err = snd_pcm_wait(pcmp, 1000)) < 0) {
540 if ((err = snd_pcm_recover(pcmp, err, 1)) < 0) {
541 LOG_INFO("pcm wait error: %s", snd_strerror(err));
542 }
543 start = true;
544 }
545 }
546 continue;
547 }
548
549 // restrict avail in writei mode as write_buf is restricted to period_size
550 if (!alsa.mmap) {
551 avail = min(avail, alsa.period_size);
552 }
553
554 // avoid spinning in cases where wait returns but no bytes available (seen with pulse audio)
555 if (avail == 0) {
556 LOG_SDEBUG("avail 0 - sleeping");
557 usleep(10000);
558 continue;
559 }
560
561 LOCK;
562
563 // turn off if requested
564 if (output.state == OUTPUT_OFF) {
565 UNLOCK;
566 LOG_INFO("disabling output");
567 alsa_close();
568 pcmp = NULL;
569 output_off = true;
570 vis_stop();
571 continue;
572 }
573
574 // measure output delay
575 snd_pcm_sframes_t delay;
576 if ((err = snd_pcm_delay(pcmp, &delay)) < 0) {
577 if (err == -EPIPE) {
578 // EPIPE indicates underrun - attempt to recover
579 UNLOCK;
580 continue;
581 } else {
582 LOG_DEBUG("snd_pcm_delay returns: %d", err);
583 }
584 } else {
585 output.device_frames = delay;
586 output.updated = gettime_ms();
587 }
588
589 // process frames
590 _output_frames(avail);
591
592 UNLOCK;
593 }
594
595 return 0;
596 }
597
598 static pthread_t thread;
599
600 void output_init_alsa(log_level level, const char *device, unsigned output_buf_size, char *params, unsigned rates[], unsigned rt_priority) {
601
602 unsigned alsa_buffer = ALSA_BUFFER_TIME;
603 unsigned alsa_period = ALSA_PERIOD_COUNT;
604 char *alsa_sample_fmt = NULL;
605 bool alsa_mmap = true;
606 bool alsa_reopen = false;
607
608 char *t = next_param(params, ':');
609 char *c = next_param(NULL, ':');
610 char *s = next_param(NULL, ':');
611 char *m = next_param(NULL, ':');
612 char *r = next_param(NULL, ':');
613
614 if (t) alsa_buffer = atoi(t);
615 if (c) alsa_period = atoi(c);
616 if (s) alsa_sample_fmt = s;
617 if (m) alsa_mmap = atoi(m);
618 if (r) alsa_reopen = atoi(r);
619
620 loglevel = level;
621
622 LOG_INFO("init output");
623
624 memset(&output, 0, sizeof(output));
625
626 alsa.mmap = alsa_mmap;
627 alsa.write_buf = NULL;
628 alsa.format = 0;
629 alsa.reopen = alsa_reopen;
630 output.format = 0;
631 output.buffer = alsa_buffer;
632 output.period = alsa_period;
633 output.start_frames = 0;
634 output.write_cb = &_write_frames;
635
636 if (alsa_sample_fmt) {
637 if (!strcmp(alsa_sample_fmt, "32")) alsa.format = SND_PCM_FORMAT_S32_LE;
638 if (!strcmp(alsa_sample_fmt, "24")) alsa.format = SND_PCM_FORMAT_S24_LE;
639 if (!strcmp(alsa_sample_fmt, "24_3")) alsa.format = SND_PCM_FORMAT_S24_3LE;
640 if (!strcmp(alsa_sample_fmt, "16")) alsa.format = SND_PCM_FORMAT_S16_LE;
641 }
642
643 LOG_INFO("requested alsa_buffer: %u alsa_period: %u format: %s mmap: %u", output.buffer, output.period,
644 alsa_sample_fmt ? alsa_sample_fmt : "any", alsa.mmap);
645
646 snd_lib_error_set_handler((snd_lib_error_handler_t)alsa_error_handler);
647
648 output_init_common(level, device, output_buf_size, rates);
649
650 #if LINUX
651 // RT linux - aim to avoid pagefaults by locking memory:
652 // https://rt.wiki.kernel.org/index.php/Threaded_RT-application_with_memory_locking_and_stack_handling_example
653 if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
654 LOG_INFO("unable to lock memory: %s", strerror(errno));
655 } else {
656 LOG_INFO("memory locked");
657 }
658
659 mallopt(M_TRIM_THRESHOLD, -1);
660 mallopt(M_MMAP_MAX, 0);
661
662 touch_memory(silencebuf, MAX_SILENCE_FRAMES * BYTES_PER_FRAME);
663 touch_memory(outputbuf->buf, outputbuf->size);
664 #endif
665
666 // start output thread
667 pthread_attr_t attr;
668 pthread_attr_init(&attr);
669 pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN + OUTPUT_THREAD_STACK_SIZE);
670 pthread_create(&thread, &attr, output_thread, rates[0] ? "probe" : NULL);
671 pthread_attr_destroy(&attr);
672
673 // try to set this thread to real-time scheduler class, only works as root or if user has permission
674 struct sched_param param;
675 param.sched_priority = rt_priority;
676 if (pthread_setschedparam(thread, SCHED_FIFO, &param) != 0) {
677 LOG_DEBUG("unable to set output sched fifo: %s", strerror(errno));
678 } else {
679 LOG_DEBUG("set output sched fifo rt: %u", param.sched_priority);
680 }
681 }
682
683 void output_close_alsa(void) {
684 LOG_INFO("close output");
685
686 LOCK;
687 running = false;
688 UNLOCK;
689
690 pthread_join(thread, NULL);
691
692 if (alsa.write_buf) free(alsa.write_buf);
693
694 output_close_common();
695 }
696
697 #endif // ALSA
698
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 // Portaudio output
21
22 #include "squeezelite.h"
23
24 #if PORTAUDIO
25
26 #include <portaudio.h>
27 #if OSX
28 #include <pa_mac_core.h>
29 #endif
30
31 // ouput device
32 static struct {
33 unsigned rate;
34 PaStream *stream;
35 } pa;
36
37 static log_level loglevel;
38
39 static bool running = true;
40
41 extern struct outputstate output;
42 extern struct buffer *outputbuf;
43
44 #define LOCK mutex_lock(outputbuf->mutex)
45 #define UNLOCK mutex_unlock(outputbuf->mutex)
46
47 extern u8_t *silencebuf;
48 #if DSD
49 extern u8_t *silencebuf_dop;
50 #endif
51
52 void list_devices(void) {
53 PaError err;
54 int i;
55
56 if ((err = Pa_Initialize()) != paNoError) {
57 LOG_WARN("error initialising port audio: %s", Pa_GetErrorText(err));
58 return;
59 }
60
61 printf("Output devices:\n");
62 for (i = 0; i < Pa_GetDeviceCount(); ++i) {
63 printf(" %i - %s [%s]\n", i, Pa_GetDeviceInfo(i)->name, Pa_GetHostApiInfo(Pa_GetDeviceInfo(i)->hostApi)->name);
64 }
65 printf("\n");
66
67 if ((err = Pa_Terminate()) != paNoError) {
68 LOG_WARN("error closing port audio: %s", Pa_GetErrorText(err));
69 }
70 }
71
72 static int pa_device_id(const char *device) {
73 int len = strlen(device);
74 int i;
75
76 if (!strncmp(device, "default", 7)) {
77 return Pa_GetDefaultOutputDevice();
78 }
79 if (len >= 1 && len <= 2 && device[0] >= '0' && device[0] <= '9') {
80 return atoi(device);
81 }
82
83 #define DEVICE_ID_MAXLEN 256
84 for (i = 0; i < Pa_GetDeviceCount(); ++i) {
85 char tmp[DEVICE_ID_MAXLEN];
86 snprintf(tmp, DEVICE_ID_MAXLEN, "%s [%s]", Pa_GetDeviceInfo(i)->name, Pa_GetHostApiInfo(Pa_GetDeviceInfo(i)->hostApi)->name);
87 if (!strncmp(tmp, device, len)) {
88 return i;
89 }
90 }
91
92 return -1;
93 }
94
95 static int pa_callback(const void *pa_input, void *pa_output, unsigned long pa_frames_wanted,
96 const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData);
97
98 bool test_open(const char *device, unsigned rates[]) {
99 PaStreamParameters outputParameters;
100 PaError err;
101 unsigned ref[] TEST_RATES;
102 int device_id, i, ind;
103
104 if ((device_id = pa_device_id(device)) == -1) {
105 LOG_INFO("device %s not found", device);
106 return false;
107 }
108
109 outputParameters.device = device_id;
110 outputParameters.channelCount = 2;
111 outputParameters.sampleFormat = paInt32;
112 outputParameters.suggestedLatency =
113 output.latency ? (double)output.latency/(double)1000 : Pa_GetDeviceInfo(outputParameters.device)->defaultHighOutputLatency;
114 outputParameters.hostApiSpecificStreamInfo = NULL;
115
116 // check supported sample rates
117 // Note use Pa_OpenStream as it appears more reliable than Pa_IsFormatSupported on some windows apis
118 for (i = 0, ind = 0; ref[i]; ++i) {
119 err = Pa_OpenStream(&pa.stream, NULL, &outputParameters, (double)ref[i], paFramesPerBufferUnspecified, paNoFlag,
120 pa_callback, NULL);
121 if (err == paNoError) {
122 Pa_CloseStream(pa.stream);
123 rates[ind++] = ref[i];
124 }
125 }
126
127 if (!rates[0]) {
128 LOG_WARN("no available rate found");
129 return false;
130 }
131
132 pa.stream = NULL;
133 return true;
134 }
135
136 static void pa_stream_finished(void *userdata) {
137 if (running) {
138 LOG_INFO("stream finished");
139 LOCK;
140 output.pa_reopen = true;
141 wake_controller();
142 UNLOCK;
143 }
144 }
145
146 static thread_type monitor_thread;
147 bool monitor_thread_running = false;
148
149 static void *pa_monitor() {
150 bool output_off;
151
152 LOCK;
153
154 if (monitor_thread_running) {
155 LOG_DEBUG("monitor thread already running");
156 UNLOCK;
157 return 0;
158 }
159
160 LOG_DEBUG("start monitor thread");
161
162 monitor_thread_running = true;
163 output_off = (output.state == OUTPUT_OFF);
164
165 while (monitor_thread_running) {
166 if (output_off) {
167 if (output.state != OUTPUT_OFF) {
168 LOG_INFO("output on");
169 break;
170 }
171 } else {
172 // this is a hack to partially support hot plugging of devices
173 // we rely on terminating and reinitalising PA to get an updated list of devices and use name for output.device
174 LOG_INFO("probing device %s", output.device);
175 Pa_Terminate();
176 Pa_Initialize();
177 pa.stream = NULL;
178 if (pa_device_id(output.device) != -1) {
179 LOG_INFO("device reopen");
180 break;
181 }
182 }
183
184 UNLOCK;
185 sleep(output_off ? 1 : 5);
186 LOCK;
187 }
188
189 LOG_DEBUG("end monitor thread");
190
191 monitor_thread_running = false;
192 pa.stream = NULL;
193
194 _pa_open();
195
196 UNLOCK;
197
198 return 0;
199 }
200
201 void _pa_open(void) {
202 PaStreamParameters outputParameters;
203 PaError err = paNoError;
204 int device_id;
205
206 if (pa.stream) {
207 if ((err = Pa_CloseStream(pa.stream)) != paNoError) {
208 LOG_WARN("error closing stream: %s", Pa_GetErrorText(err));
209 }
210 }
211
212 if (output.state == OUTPUT_OFF) {
213 // we get called when transitioning to OUTPUT_OFF to create the probe thread
214 // set err to avoid opening device and logging messages
215 err = 1;
216
217 } else if ((device_id = pa_device_id(output.device)) == -1) {
218 LOG_INFO("device %s not found", output.device);
219 err = 1;
220
221 } else {
222
223 outputParameters.device = device_id;
224 outputParameters.channelCount = 2;
225 outputParameters.sampleFormat = paInt32;
226 outputParameters.suggestedLatency =
227 output.latency ? (double)output.latency/(double)1000 : Pa_GetDeviceInfo(outputParameters.device)->defaultHighOutputLatency;
228 outputParameters.hostApiSpecificStreamInfo = NULL;
229
230 #if OSX
231 // enable pro mode which aims to avoid resampling if possible
232 // see http://code.google.com/p/squeezelite/issues/detail?id=11 & http://code.google.com/p/squeezelite/issues/detail?id=37
233 // command line controls osx_playnice which is -1 if not specified, 0 or 1 - choose playnice if -1 or 1
234 PaMacCoreStreamInfo macInfo;
235 unsigned long streamInfoFlags;
236 if (output.osx_playnice) {
237 LOG_INFO("opening device in PlayNice mode");
238 streamInfoFlags = paMacCorePlayNice;
239 } else {
240 LOG_INFO("opening device in Pro mode");
241 streamInfoFlags = paMacCorePro;
242 }
243 PaMacCore_SetupStreamInfo(&macInfo, streamInfoFlags);
244 outputParameters.hostApiSpecificStreamInfo = &macInfo;
245 #endif
246 }
247
248 if (!err &&
249 (err = Pa_OpenStream(&pa.stream, NULL, &outputParameters, (double)output.current_sample_rate, paFramesPerBufferUnspecified,
250 paPrimeOutputBuffersUsingStreamCallback | paDitherOff, pa_callback, NULL)) != paNoError) {
251 LOG_WARN("error opening device %i - %s : %s", outputParameters.device, Pa_GetDeviceInfo(outputParameters.device)->name,
252 Pa_GetErrorText(err));
253 }
254
255 if (!err) {
256 LOG_INFO("opened device %i - %s at %u latency %u ms", outputParameters.device, Pa_GetDeviceInfo(outputParameters.device)->name,
257 (unsigned int)Pa_GetStreamInfo(pa.stream)->sampleRate, (unsigned int)(Pa_GetStreamInfo(pa.stream)->outputLatency * 1000));
258
259 pa.rate = output.current_sample_rate;
260
261 if ((err = Pa_SetStreamFinishedCallback(pa.stream, pa_stream_finished)) != paNoError) {
262 LOG_WARN("error setting finish callback: %s", Pa_GetErrorText(err));
263 }
264
265 if ((err = Pa_StartStream(pa.stream)) != paNoError) {
266 LOG_WARN("error starting stream: %s", Pa_GetErrorText(err));
267 }
268 }
269
270 if (err && !monitor_thread_running) {
271 vis_stop();
272
273 // create a thread to check for output state change or device return
274 #if LINUX || OSX
275 pthread_create(&monitor_thread, NULL, pa_monitor, NULL);
276 #endif
277 #if WIN
278 monitor_thread = CreateThread(NULL, OUTPUT_THREAD_STACK_SIZE, (LPTHREAD_START_ROUTINE)&pa_monitor, NULL, 0, NULL);
279 #endif
280 }
281
282 output.error_opening = !err;
283 }
284
285 static u8_t *optr;
286
287 static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR,
288 s32_t cross_gain_in, s32_t cross_gain_out, s32_t **cross_ptr) {
289
290 if (!silence) {
291
292 if (output.fade == FADE_ACTIVE && output.fade_dir == FADE_CROSS && *cross_ptr) {
293 _apply_cross(outputbuf, out_frames, cross_gain_in, cross_gain_out, cross_ptr);
294 }
295
296 if (gainL != FIXED_ONE || gainR!= FIXED_ONE) {
297 _apply_gain(outputbuf, out_frames, gainL, gainR);
298 }
299
300 IF_DSD(
301 if (output.dop) {
302 update_dop_marker((u32_t *) outputbuf->readp, out_frames);
303 }
304 )
305
306 memcpy(optr, outputbuf->readp, out_frames * BYTES_PER_FRAME);
307
308 } else {
309
310 u8_t *buf = silencebuf;
311
312 IF_DSD(
313 if (output.dop) {
314 buf = silencebuf_dop;
315 update_dop_marker((u32_t *) buf, out_frames);
316 }
317 )
318
319 memcpy(optr, buf, out_frames * BYTES_PER_FRAME);
320 }
321
322 optr += out_frames * BYTES_PER_FRAME;
323
324 return (int)out_frames;
325 }
326
327 static int pa_callback(const void *pa_input, void *pa_output, unsigned long pa_frames_wanted,
328 const PaStreamCallbackTimeInfo *time_info, PaStreamCallbackFlags statusFlags, void *userData) {
329 int ret;
330 frames_t frames;
331
332 optr = (u8_t *)pa_output;
333
334 LOCK;
335
336 output.device_frames = (unsigned)((time_info->outputBufferDacTime - Pa_GetStreamTime(pa.stream)) * output.current_sample_rate);
337 output.updated = gettime_ms();
338
339 frames = _output_frames(pa_frames_wanted);
340
341 if (frames < pa_frames_wanted) {
342 LOG_SDEBUG("pad with silence");
343 memset(optr, 0, (pa_frames_wanted - frames) * BYTES_PER_FRAME);
344 }
345
346 if (output.state == OUTPUT_OFF) {
347 LOG_INFO("output off");
348 ret = paComplete;
349 } else if (pa.rate != output.current_sample_rate) {
350 ret = paComplete;
351 } else {
352 ret = paContinue;
353 }
354
355 UNLOCK;
356
357 return ret;
358 }
359
360 void output_init_pa(log_level level, const char *device, unsigned output_buf_size, char *params, unsigned rates[]) {
361 PaError err;
362 unsigned latency = 0;
363 int osx_playnice = -1;
364
365 char *l = next_param(params, ':');
366 char *p = next_param(NULL, ':');
367
368 if (l) latency = (unsigned)atoi(l);
369 if (p) osx_playnice = atoi(p);
370
371 loglevel = level;
372
373 LOG_INFO("init output");
374
375 memset(&output, 0, sizeof(output));
376
377 output.latency = latency;
378 output.osx_playnice = osx_playnice;
379 output.format = 0;
380 output.start_frames = 0;
381 output.write_cb = &_write_frames;
382 pa.stream = NULL;
383
384 LOG_INFO("requested latency: %u", output.latency);
385
386 if ((err = Pa_Initialize()) != paNoError) {
387 LOG_WARN("error initialising port audio: %s", Pa_GetErrorText(err));
388 exit(0);
389 }
390
391 output_init_common(level, device, output_buf_size, rates);
392
393 LOCK;
394
395 _pa_open();
396
397 UNLOCK;
398 }
399
400 void output_close_pa(void) {
401 PaError err;
402
403 LOG_INFO("close output");
404
405 LOCK;
406
407 running = false;
408 monitor_thread_running = false;
409
410 if (pa.stream) {
411 if ((err = Pa_AbortStream(pa.stream)) != paNoError) {
412 LOG_WARN("error closing stream: %s", Pa_GetErrorText(err));
413 }
414 }
415
416 if ((err = Pa_Terminate()) != paNoError) {
417 LOG_WARN("error closing port audio: %s", Pa_GetErrorText(err));
418 }
419
420 UNLOCK;
421
422 output_close_common();
423 }
424
425 #endif // PORTAUDIO
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 // Scale and pack functions
21
22 #include "squeezelite.h"
23
24 #define MAX_SCALESAMPLE 0x7fffffffffffLL
25 #define MIN_SCALESAMPLE -MAX_SCALESAMPLE
26
27 // inlining these on windows prevents them being linkable...
28 #if !WIN
29 inline
30 #endif
31 s32_t gain(s32_t gain, s32_t sample) {
32 s64_t res = (s64_t)gain * (s64_t)sample;
33 if (res > MAX_SCALESAMPLE) res = MAX_SCALESAMPLE;
34 if (res < MIN_SCALESAMPLE) res = MIN_SCALESAMPLE;
35 return (s32_t) (res >> 16);
36 }
37 #if !WIN
38 inline
39 #endif
40 s32_t to_gain(float f) {
41 return (s32_t)(f * 65536.0F);
42 }
43
44 void _scale_and_pack_frames(void *outputptr, s32_t *inputptr, frames_t cnt, s32_t gainL, s32_t gainR, output_format format) {
45 switch(format) {
46 case S16_LE:
47 {
48 u32_t *optr = (u32_t *)(void *)outputptr;
49 #if SL_LITTLE_ENDIAN
50 if (gainL == FIXED_ONE && gainR == FIXED_ONE) {
51 while (cnt--) {
52 *(optr++) = (*(inputptr) >> 16 & 0x0000ffff) | (*(inputptr + 1) & 0xffff0000);
53 inputptr += 2;
54 }
55 } else {
56 while (cnt--) {
57 *(optr++) = (gain(gainL, *(inputptr)) >> 16 & 0x0000ffff) | (gain(gainR, *(inputptr+1)) & 0xffff0000);
58 inputptr += 2;
59 }
60 }
61 #else
62 if (gainL == FIXED_ONE && gainR == FIXED_ONE) {
63 while (cnt--) {
64 s32_t lsample = *(inputptr++);
65 s32_t rsample = *(inputptr++);
66 *(optr++) =
67 (lsample & 0x00ff0000) << 8 | (lsample & 0xff000000) >> 8 |
68 (rsample & 0x00ff0000) >> 8 | (rsample & 0xff000000) >> 24;
69 }
70 } else {
71 while (cnt--) {
72 s32_t lsample = gain(gainL, *(inputptr++));
73 s32_t rsample = gain(gainR, *(inputptr++));
74 *(optr++) =
75 (lsample & 0x00ff0000) << 8 | (lsample & 0xff000000) >> 8 |
76 (rsample & 0x00ff0000) >> 8 | (rsample & 0xff000000) >> 24;
77 }
78 }
79 #endif
80 }
81 break;
82 case S24_LE:
83 {
84 u32_t *optr = (u32_t *)(void *)outputptr;
85 #if SL_LITTLE_ENDIAN
86 if (gainL == FIXED_ONE && gainR == FIXED_ONE) {
87 while (cnt--) {
88 *(optr++) = *(inputptr++) >> 8;
89 *(optr++) = *(inputptr++) >> 8;
90 }
91 } else {
92 while (cnt--) {
93 *(optr++) = gain(gainL, *(inputptr++)) >> 8;
94 *(optr++) = gain(gainR, *(inputptr++)) >> 8;
95 }
96 }
97 #else
98 if (gainL == FIXED_ONE && gainR == FIXED_ONE) {
99 while (cnt--) {
100 s32_t lsample = *(inputptr++);
101 s32_t rsample = *(inputptr++);
102 *(optr++) =
103 (lsample & 0xff000000) >> 16 | (lsample & 0x00ff0000) | (lsample & 0x0000ff00 << 16);
104 *(optr++) =
105 (rsample & 0xff000000) >> 16 | (rsample & 0x00ff0000) | (rsample & 0x0000ff00 << 16);
106 }
107 } else {
108 while (cnt--) {
109 s32_t lsample = gain(gainL, *(inputptr++));
110 s32_t rsample = gain(gainR, *(inputptr++));
111 *(optr++) =
112 (lsample & 0xff000000) >> 16 | (lsample & 0x00ff0000) | (lsample & 0x0000ff00 << 16);
113 *(optr++) =
114 (rsample & 0xff000000) >> 16 | (rsample & 0x00ff0000) | (rsample & 0x0000ff00 << 16);
115 }
116 }
117 #endif
118 }
119 break;
120 case S24_3LE:
121 {
122 u8_t *optr = (u8_t *)(void *)outputptr;
123 if (gainL == FIXED_ONE && gainR == FIXED_ONE) {
124 while (cnt) {
125 // attempt to do 32 bit memory accesses - move 2 frames at once: 16 bytes -> 12 bytes
126 // falls through to exception case when not aligned or if less than 2 frames to move
127 if (((uintptr_t)optr & 0x3) == 0 && cnt >= 2) {
128 u32_t *o_ptr = (u32_t *)(void *)optr;
129 while (cnt >= 2) {
130 s32_t l1 = *(inputptr++); s32_t r1 = *(inputptr++);
131 s32_t l2 = *(inputptr++); s32_t r2 = *(inputptr++);
132 #if SL_LITTLE_ENDIAN
133 *(o_ptr++) = (l1 & 0xffffff00) >> 8 | (r1 & 0x0000ff00) << 16;
134 *(o_ptr++) = (r1 & 0xffff0000) >> 16 | (l2 & 0x00ffff00) << 8;
135 *(o_ptr++) = (l2 & 0xff000000) >> 24 | (r2 & 0xffffff00);
136 #else
137 *(o_ptr++) = (l1 & 0x0000ff00) << 16 | (l1 & 0x00ff0000) | (l1 & 0xff000000) >> 16 |
138 (r1 & 0x0000ff00) >> 8;
139 *(o_ptr++) = (r1 & 0x00ff0000) << 8 | (r1 & 0xff000000) >> 8 | (l2 & 0x0000ff00) |
140 (l2 & 0x00ff0000) >> 16;
141 *(o_ptr++) = (l2 & 0xff000000) | (r2 & 0x0000ff00) << 8 | (r2 & 0x00ff0000) >> 8 |
142 (r2 & 0xff000000) >> 24;
143 #endif
144 optr += 12;
145 cnt -= 2;
146 }
147 } else {
148 s32_t lsample = *(inputptr++);
149 s32_t rsample = *(inputptr++);
150 *(optr++) = (lsample & 0x0000ff00) >> 8;
151 *(optr++) = (lsample & 0x00ff0000) >> 16;
152 *(optr++) = (lsample & 0xff000000) >> 24;
153 *(optr++) = (rsample & 0x0000ff00) >> 8;
154 *(optr++) = (rsample & 0x00ff0000) >> 16;
155 *(optr++) = (rsample & 0xff000000) >> 24;
156 cnt--;
157 }
158 }
159 } else {
160 while (cnt) {
161 // attempt to do 32 bit memory accesses - move 2 frames at once: 16 bytes -> 12 bytes
162 // falls through to exception case when not aligned or if less than 2 frames to move
163 if (((uintptr_t)optr & 0x3) == 0 && cnt >= 2) {
164 u32_t *o_ptr = (u32_t *)(void *)optr;
165 while (cnt >= 2) {
166 s32_t l1 = gain(gainL, *(inputptr++)); s32_t r1 = gain(gainR, *(inputptr++));
167 s32_t l2 = gain(gainL, *(inputptr++)); s32_t r2 = gain(gainR, *(inputptr++));
168 #if SL_LITTLE_ENDIAN
169 *(o_ptr++) = (l1 & 0xffffff00) >> 8 | (r1 & 0x0000ff00) << 16;
170 *(o_ptr++) = (r1 & 0xffff0000) >> 16 | (l2 & 0x00ffff00) << 8;
171 *(o_ptr++) = (l2 & 0xff000000) >> 24 | (r2 & 0xffffff00);
172 #else
173 *(o_ptr++) = (l1 & 0x0000ff00) << 16 | (l1 & 0x00ff0000) | (l1 & 0xff000000) >> 16 |
174 (r1 & 0x0000ff00) >> 8;
175 *(o_ptr++) = (r1 & 0x00ff0000) << 8 | (r1 & 0xff000000) >> 8 | (l2 & 0x0000ff00) |
176 (l2 & 0x00ff0000) >> 16;
177 *(o_ptr++) = (l2 & 0xff000000) | (r2 & 0x0000ff00) << 8 | (r2 & 0x00ff0000) >> 8 |
178 (r2 & 0xff000000) >> 24;
179 #endif
180 optr += 12;
181 cnt -= 2;
182 }
183 } else {
184 s32_t lsample = gain(gainL, *(inputptr++));
185 s32_t rsample = gain(gainR, *(inputptr++));
186 *(optr++) = (lsample & 0x0000ff00) >> 8;
187 *(optr++) = (lsample & 0x00ff0000) >> 16;
188 *(optr++) = (lsample & 0xff000000) >> 24;
189 *(optr++) = (rsample & 0x0000ff00) >> 8;
190 *(optr++) = (rsample & 0x00ff0000) >> 16;
191 *(optr++) = (rsample & 0xff000000) >> 24;
192 cnt--;
193 }
194 }
195 }
196 }
197 break;
198 case S32_LE:
199 {
200 u32_t *optr = (u32_t *)(void *)outputptr;
201 #if SL_LITTLE_ENDIAN
202 if (gainL == FIXED_ONE && gainR == FIXED_ONE) {
203 memcpy(outputptr, inputptr, cnt * BYTES_PER_FRAME);
204 } else {
205 while (cnt--) {
206 *(optr++) = gain(gainL, *(inputptr++));
207 *(optr++) = gain(gainR, *(inputptr++));
208 }
209 }
210 #else
211 if (gainL == FIXED_ONE && gainR == FIXED_ONE) {
212 while (cnt--) {
213 s32_t lsample = *(inputptr++);
214 s32_t rsample = *(inputptr++);
215 *(optr++) =
216 (lsample & 0xff000000) >> 24 | (lsample & 0x00ff0000) >> 8 |
217 (lsample & 0x0000ff00) << 8 | (lsample & 0x000000ff) << 24;
218 *(optr++) =
219 (rsample & 0xff000000) >> 24 | (rsample & 0x00ff0000) >> 8 |
220 (rsample & 0x0000ff00) << 8 | (rsample & 0x000000ff) << 24;
221 }
222 } else {
223 while (cnt--) {
224 s32_t lsample = gain(gainL, *(inputptr++));
225 s32_t rsample = gain(gainR, *(inputptr++));
226 *(optr++) =
227 (lsample & 0xff000000) >> 24 | (lsample & 0x00ff0000) >> 8 |
228 (lsample & 0x0000ff00) << 8 | (lsample & 0x000000ff) << 24;
229 *(optr++) =
230 (rsample & 0xff000000) >> 24 | (rsample & 0x00ff0000) >> 8 |
231 (rsample & 0x0000ff00) << 8 | (rsample & 0x000000ff) << 24;
232 }
233 }
234 #endif
235 }
236 break;
237 default:
238 break;
239 }
240 }
241
242 #if !WIN
243 inline
244 #endif
245 void _apply_cross(struct buffer *outputbuf, frames_t out_frames, s32_t cross_gain_in, s32_t cross_gain_out, s32_t **cross_ptr) {
246 s32_t *ptr = (s32_t *)(void *)outputbuf->readp;
247 frames_t count = out_frames * 2;
248 while (count--) {
249 if (*cross_ptr > (s32_t *)outputbuf->wrap) {
250 *cross_ptr -= outputbuf->size / BYTES_PER_FRAME * 2;
251 }
252 *ptr = gain(cross_gain_out, *ptr) + gain(cross_gain_in, **cross_ptr);
253 ptr++; (*cross_ptr)++;
254 }
255 }
256
257 #if !WIN
258 inline
259 #endif
260 void _apply_gain(struct buffer *outputbuf, frames_t count, s32_t gainL, s32_t gainR) {
261 s32_t *ptrL = (s32_t *)(void *)outputbuf->readp;
262 s32_t *ptrR = (s32_t *)(void *)outputbuf->readp + 1;
263 while (count--) {
264 *ptrL = gain(gainL, *ptrL);
265 *ptrR = gain(gainR, *ptrR);
266 ptrL += 2;
267 ptrR += 2;
268 }
269 }
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 // Stdout output
21
22 #include "squeezelite.h"
23
24 #define FRAME_BLOCK MAX_SILENCE_FRAMES
25
26 static log_level loglevel;
27
28 static bool running = true;
29
30 extern struct outputstate output;
31 extern struct buffer *outputbuf;
32
33 #define LOCK mutex_lock(outputbuf->mutex)
34 #define UNLOCK mutex_unlock(outputbuf->mutex)
35
36 extern u8_t *silencebuf;
37 #if DSD
38 extern u8_t *silencebuf_dop;
39 #endif
40
41 // buffer to hold output data so we can block on writing outside of output lock, allocated on init
42 static u8_t *buf;
43 static unsigned buffill;
44 static int bytes_per_frame;
45
46 static int _stdout_write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR,
47 s32_t cross_gain_in, s32_t cross_gain_out, s32_t **cross_ptr) {
48
49 u8_t *obuf;
50
51 if (!silence) {
52
53 if (output.fade == FADE_ACTIVE && output.fade_dir == FADE_CROSS && *cross_ptr) {
54 _apply_cross(outputbuf, out_frames, cross_gain_in, cross_gain_out, cross_ptr);
55 }
56
57 obuf = outputbuf->readp;
58
59 } else {
60
61 obuf = silencebuf;
62 }
63
64 IF_DSD(
65 if (output.dop) {
66 if (silence) {
67 obuf = silencebuf_dop;
68 }
69 update_dop_marker((u32_t *)obuf, out_frames);
70 }
71 )
72
73 _scale_and_pack_frames(buf + buffill * bytes_per_frame, (s32_t *)(void *)obuf, out_frames, gainL, gainR, output.format);
74
75 buffill += out_frames;
76
77 return (int)out_frames;
78 }
79
80 static void *output_thread() {
81
82 LOCK;
83
84 switch (output.format) {
85 case S32_LE:
86 bytes_per_frame = 4 * 2; break;
87 case S24_3LE:
88 bytes_per_frame = 3 * 2; break;
89 case S16_LE:
90 bytes_per_frame = 2 * 2; break;
91 default:
92 bytes_per_frame = 4 * 2; break;
93 break;
94 }
95
96 UNLOCK;
97
98 while (running) {
99
100 LOCK;
101
102 output.device_frames = 0;
103 output.updated = gettime_ms();
104
105 _output_frames(FRAME_BLOCK);
106
107 UNLOCK;
108
109 if (buffill) {
110 fwrite(buf, bytes_per_frame, buffill, stdout);
111 buffill = 0;
112 }
113
114 }
115
116 return 0;
117 }
118
119 static thread_type thread;
120
121 void output_init_stdout(log_level level, unsigned output_buf_size, char *params, unsigned rates[]) {
122 loglevel = level;
123
124 LOG_INFO("init output stdout");
125
126 buf = malloc(FRAME_BLOCK * BYTES_PER_FRAME);
127 if (!buf) {
128 LOG_ERROR("unable to malloc buf");
129 return;
130 }
131 buffill = 0;
132
133 memset(&output, 0, sizeof(output));
134
135 output.format = S32_LE;
136 output.start_frames = FRAME_BLOCK * 2;
137 output.write_cb = &_stdout_write_frames;
138
139 if (params) {
140 if (!strcmp(params, "32")) output.format = S32_LE;
141 if (!strcmp(params, "24")) output.format = S24_3LE;
142 if (!strcmp(params, "16")) output.format = S16_LE;
143 }
144
145 // ensure output rate is specified to avoid test open
146 if (!rates[0]) {
147 rates[0] = 44100;
148 }
149
150 output_init_common(level, "-", output_buf_size, rates);
151
152 #if LINUX || OSX
153 pthread_attr_t attr;
154 pthread_attr_init(&attr);
155 pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN + OUTPUT_THREAD_STACK_SIZE);
156 pthread_create(&thread, &attr, output_thread, NULL);
157 pthread_attr_destroy(&attr);
158 #endif
159 #if WIN
160 thread = CreateThread(NULL, OUTPUT_THREAD_STACK_SIZE, (LPTHREAD_START_ROUTINE)&output_thread, NULL, 0, NULL);
161 #endif
162 }
163
164 void output_close_stdout(void) {
165 LOG_INFO("close output");
166
167 LOCK;
168 running = false;
169 UNLOCK;
170
171 free(buf);
172
173 output_close_common();
174 }
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 // Export audio samples for visualiser process (16 bit only best endevours)
21
22 #include "squeezelite.h"
23
24 #if VISEXPORT
25
26 #include <sys/mman.h>
27 #include <fcntl.h>
28
29 #define VIS_BUF_SIZE 16384
30 #define VIS_LOCK_NS 1000000 // ns to wait for vis wrlock
31
32 static struct vis_t {
33 pthread_rwlock_t rwlock;
34 u32_t buf_size;
35 u32_t buf_index;
36 bool running;
37 u32_t rate;
38 time_t updated;
39 s16_t buffer[VIS_BUF_SIZE];
40 } *vis_mmap = NULL;
41
42 static char vis_shm_path[40];
43 static int vis_fd = -1;
44
45 static log_level loglevel;
46
47 // attempt to write audio to vis_mmap but do not wait more than VIS_LOCK_NS to get wrlock
48 // this can result in missing audio export to the mmap region, but this is preferable dropping audio
49 void _vis_export(struct buffer *outputbuf, struct outputstate *output, frames_t out_frames, bool silence) {
50 if (vis_mmap) {
51 int err;
52
53 err = pthread_rwlock_trywrlock(&vis_mmap->rwlock);
54 if (err) {
55 struct timespec ts;
56 clock_gettime(CLOCK_REALTIME, &ts);
57 ts.tv_nsec += VIS_LOCK_NS;
58 if (ts.tv_nsec > 1000000000) {
59 ts.tv_sec += 1;
60 ts.tv_nsec -= 1000000000;
61 }
62 err = pthread_rwlock_timedwrlock(&vis_mmap->rwlock, &ts);
63 }
64
65 if (err) {
66 LOG_DEBUG("failed to get wrlock - skipping visulizer export");
67
68 } else {
69
70 if (silence) {
71 vis_mmap->running = false;
72 } else {
73 frames_t vis_cnt = out_frames;
74 s32_t *ptr = (s32_t *) outputbuf->readp;
75 unsigned i = vis_mmap->buf_index;
76
77 if (!output->current_replay_gain) {
78 while (vis_cnt--) {
79 vis_mmap->buffer[i++] = *(ptr++) >> 16;
80 vis_mmap->buffer[i++] = *(ptr++) >> 16;
81 if (i == VIS_BUF_SIZE) i = 0;
82 }
83 } else {
84 while (vis_cnt--) {
85 vis_mmap->buffer[i++] = gain(*(ptr++), output->current_replay_gain) >> 16;
86 vis_mmap->buffer[i++] = gain(*(ptr++), output->current_replay_gain) >> 16;
87 if (i == VIS_BUF_SIZE) i = 0;
88 }
89 }
90
91 vis_mmap->updated = time(NULL);
92 vis_mmap->running = true;
93 vis_mmap->buf_index = i;
94 vis_mmap->rate = output->current_sample_rate;
95 }
96
97 pthread_rwlock_unlock(&vis_mmap->rwlock);
98 }
99 }
100 }
101
102 void vis_stop(void) {
103 if (vis_mmap) {
104 pthread_rwlock_wrlock(&vis_mmap->rwlock);
105 vis_mmap->running = false;
106 pthread_rwlock_unlock(&vis_mmap->rwlock);
107 }
108 }
109
110 void output_vis_init(log_level level, u8_t *mac) {
111 loglevel = level;
112
113 sprintf(vis_shm_path, "/squeezelite-%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
114
115 vis_fd = shm_open(vis_shm_path, O_CREAT | O_RDWR, 0666);
116 if (vis_fd != -1) {
117 if (ftruncate(vis_fd, sizeof(struct vis_t)) == 0) {
118 vis_mmap = (struct vis_t *)mmap(NULL, sizeof(struct vis_t), PROT_READ | PROT_WRITE, MAP_SHARED, vis_fd, 0);
119 }
120 }
121
122 if (vis_mmap > 0) {
123 pthread_rwlockattr_t attr;
124 pthread_rwlockattr_init(&attr);
125 pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
126 pthread_rwlock_init(&vis_mmap->rwlock, &attr);
127 vis_mmap->buf_size = VIS_BUF_SIZE;
128 vis_mmap->running = false;
129 vis_mmap->rate = 44100;
130 pthread_rwlockattr_destroy(&attr);
131 LOG_INFO("opened visulizer shared memory as %s", vis_shm_path);
132 } else {
133 LOG_WARN("unable to open visualizer shared memory");
134 vis_mmap = NULL;
135 }
136 }
137
138 #endif // VISEXPORT
+44
-14
pcm.c less more
5858 static u32_t sample_size;
5959 static u32_t channels;
6060 static bool bigendian;
61 static bool limit;
62 static u32_t audio_left;
63 static u32_t bytes_per_frame;
6164
6265 typedef enum { UNKNOWN = 0, WAVE, AIFF } header_format;
6366
64 void _check_header(void) {
67 static void _check_header(void) {
6568 u8_t *ptr = streambuf->readp;
6669 unsigned bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf));
6770 header_format format = UNKNOWN;
99102 if (format == WAVE && !memcmp(ptr, "data", 4)) {
100103 ptr += 8;
101104 _buf_inc_readp(streambuf, ptr - streambuf->readp);
105 audio_left = len;
106 limit = true;
102107 return;
103108 }
104109
107112 // following 4 bytes is blocksize - ignored
108113 ptr += 8 + 8;
109114 _buf_inc_readp(streambuf, ptr + offset - streambuf->readp);
115 audio_left = len;
116 limit = true;
110117 return;
111118 }
112119
149156 }
150157
151158 static decode_state pcm_decode(void) {
152 size_t in, out;
159 unsigned bytes, in, out;
153160 frames_t frames, count;
154161 u32_t *optr;
155162 u8_t *iptr;
163 u8_t tmp[16];
156164
157165 LOCK_S;
158166
162170
163171 LOCK_O_direct;
164172
165 in = min(_buf_used(streambuf), _buf_cont_read(streambuf)) / (channels * sample_size);
173 bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf));
166174
167175 IF_DIRECT(
168176 out = min(_buf_space(outputbuf), _buf_cont_write(outputbuf)) / BYTES_PER_FRAME;
171179 out = process.max_in_frames;
172180 );
173181
174 if (stream.state <= DISCONNECT && in == 0) {
182 if ((stream.state <= DISCONNECT && bytes == 0) || (limit && audio_left == 0)) {
175183 UNLOCK_O_direct;
176184 UNLOCK_S;
177185 return DECODE_COMPLETE;
180188 if (decode.new_stream) {
181189 LOG_INFO("setting track_start");
182190 LOCK_O_not_direct;
183 output.next_sample_rate = decode_newstream(sample_rate, output.max_sample_rate);
191 output.next_sample_rate = decode_newstream(sample_rate, output.supported_rates);
184192 output.track_start = outputbuf->writep;
193 IF_DSD( output.next_dop = false; )
185194 if (output.fade_mode) _checkfade(true);
186195 decode.new_stream = false;
187196 UNLOCK_O_not_direct;
188197 IF_PROCESS(
189198 out = process.max_in_frames;
190199 );
200 bytes_per_frame = channels * sample_size;
201 }
202
203 IF_DIRECT(
204 optr = (u32_t *)outputbuf->writep;
205 );
206 IF_PROCESS(
207 optr = (u32_t *)process.inbuf;
208 );
209 iptr = (u8_t *)streambuf->readp;
210
211 in = bytes / bytes_per_frame;
212
213 // handle frame wrapping round end of streambuf
214 // - only need if resizing of streambuf does not avoid this, could occur in localfile case
215 if (in == 0 && bytes > 0 && _buf_used(streambuf) >= bytes_per_frame) {
216 memcpy(tmp, iptr, bytes);
217 memcpy(tmp + bytes, streambuf->buf, bytes_per_frame - bytes);
218 iptr = tmp;
219 in = 1;
191220 }
192221
193222 frames = min(in, out);
194223 frames = min(frames, MAX_DECODE_FRAMES);
195224
196 IF_DIRECT(
197 optr = (u32_t *)outputbuf->writep;
198 );
199 IF_PROCESS(
200 optr = (u32_t *)process.inbuf;
201 );
202
203 iptr = (u8_t *)streambuf->readp;
225 if (limit && frames * bytes_per_frame > audio_left) {
226 LOG_INFO("reached end of audio");
227 frames = audio_left / bytes_per_frame;
228 }
204229
205230 count = frames * channels;
206231
308333
309334 LOG_SDEBUG("decoded %u frames", frames);
310335
311 _buf_inc_readp(streambuf, frames * channels * sample_size);
336 _buf_inc_readp(streambuf, frames * bytes_per_frame);
337
338 if (limit) {
339 audio_left -= frames * bytes_per_frame;
340 }
312341
313342 IF_DIRECT(
314343 _buf_inc_writep(outputbuf, frames * BYTES_PER_FRAME);
328357 sample_rate = sample_rates[rate - '0'];
329358 channels = chan - '0';
330359 bigendian = (endianness == '0');
360 limit = false;
331361
332362 LOG_INFO("pcm size: %u rate: %u chan: %u bigendian: %u", sample_size, sample_rate, channels, bigendian);
333363 buf_adjust(streambuf, sample_size * channels);
115115 }
116116
117117 // new stream - called with decode mutex set
118 unsigned process_newstream(bool *direct, unsigned raw_sample_rate, unsigned max_sample_rate) {
118 unsigned process_newstream(bool *direct, unsigned raw_sample_rate, unsigned supported_rates[]) {
119119
120 bool active = NEWSTREAM_FUNC(&process, raw_sample_rate, max_sample_rate);
120 bool active = NEWSTREAM_FUNC(&process, raw_sample_rate, supported_rates);
121121
122122 LOG_INFO("processing: %s", active ? "active" : "inactive");
123123
3939 double q_stopband_begin; /* Aliasing/imaging control; > passband_end 1 */
4040 double scale;
4141 bool max_rate;
42 bool exception;
4243 #if !LINKALL
4344 // soxr symbols to be dynamically loaded
4445 soxr_io_spec_t (* soxr_io_spec)(soxr_datatype_t itype, soxr_datatype_t otype);
121122 }
122123 }
123124
124 bool resample_newstream(struct processstate *process, unsigned raw_sample_rate, unsigned max_sample_rate) {
125 unsigned outrate;
126
127 if (r->max_rate) {
128 outrate = max_sample_rate;
129 } else {
130 outrate = raw_sample_rate;
131 while (outrate <= max_sample_rate) outrate <<= 1;
132 outrate >>= 1;
125 bool resample_newstream(struct processstate *process, unsigned raw_sample_rate, unsigned supported_rates[]) {
126 unsigned outrate = 0;
127 int i;
128
129 if (r->exception) {
130 // find direct match - avoid resampling
131 for (i = 0; supported_rates[i]; i++) {
132 if (raw_sample_rate == supported_rates[i]) {
133 outrate = raw_sample_rate;
134 break;
135 }
136 }
137 // else find next highest sync sample rate
138 while (!outrate && i >= 0) {
139 if (supported_rates[i] > raw_sample_rate && supported_rates[i] % raw_sample_rate == 0) {
140 outrate = supported_rates[i];
141 break;
142 }
143 i--;
144 }
145 }
146
147 if (!outrate) {
148 if (r->max_rate) {
149 // resample to max rate for device
150 outrate = supported_rates[0];
151 } else {
152 // resample to max sync sample rate
153 for (i = 0; supported_rates[i]; i++) {
154 if (supported_rates[i] % raw_sample_rate == 0 || raw_sample_rate % supported_rates[i] == 0) {
155 outrate = supported_rates[i];
156 break;
157 }
158 }
159 }
160 if (!outrate) {
161 outrate = supported_rates[0];
162 }
133163 }
134164
135165 process->in_sample_rate = raw_sample_rate;
234264 r->resampler = NULL;
235265 r->old_clips = 0;
236266 r->max_rate = false;
267 r->exception = false;
237268
238269 if (!load_soxr()) {
239270 LOG_WARN("resampling disabled");
273304 if (strchr(recipe, 's')) r->q_recipe |= SOXR_STEEP_FILTER;
274305 // X = async resampling to max_rate
275306 if (strchr(recipe, 'X')) r->max_rate = true;
307 // E = exception, only resample if native rate is not supported
308 if (strchr(recipe, 'E')) r->exception = true;
276309 }
277310
278311 if (flags) {
7474 bool sentSTMu, sentSTMo, sentSTMl;
7575 u32_t new_server;
7676 char *new_server_cap;
77 #define PLAYER_NAME_LEN 64
78 char player_name[PLAYER_NAME_LEN + 1] = "";
79 const char *name_file = NULL;
7780
7881 void send_packet(u8_t *packet, size_t len) {
7982 u8_t *ptr = packet;
381384 UNLOCK_O;
382385 }
383386
387 static void process_setd(u8_t *pkt, int len) {
388 struct setd_packet *setd = (struct setd_packet *)pkt;
389
390 // handle player name query and change
391 if (setd->id == 0) {
392 if (len == 5) {
393 if (strlen(player_name)) {
394 sendSETDName(player_name);
395 }
396 } else if (len > 5) {
397 strncpy(player_name, setd->data, PLAYER_NAME_LEN);
398 player_name[PLAYER_NAME_LEN] = '\0';
399 LOG_INFO("set name: %s", setd->data);
400 // confirm change to server
401 sendSETDName(setd->data);
402 // write name to name_file if -N option set
403 if (name_file) {
404 FILE *fp = fopen(name_file, "w");
405 if (fp) {
406 LOG_INFO("storing name in %s", name_file);
407 fputs(player_name, fp);
408 fclose(fp);
409 } else {
410 LOG_WARN("unable to store new name in %s", name_file);
411 }
412 }
413 }
414 }
415 }
416
384417 #define SYNC_CAP ",SyncgroupID="
385418 #define SYNC_CAP_LEN 13
386419
417450 { "codc", process_codc },
418451 { "aude", process_aude },
419452 { "audg", process_audg },
453 { "setd", process_setd },
420454 { "serv", process_serv },
421455 { "", NULL },
422456 };
677711 return s.sin_addr.s_addr;
678712 }
679713
680 void slimproto(log_level level, char *server, u8_t mac[6], const char *name) {
714 void slimproto(log_level level, char *server, u8_t mac[6], const char *name, const char *namefile) {
681715 struct sockaddr_in serv_addr;
682716 static char fixed_cap[128], var_cap[128] = "";
683717 bool reconnect = false;
702736 slimproto_port = PORT;
703737 }
704738
739 if (name) {
740 strncpy(player_name, name, PLAYER_NAME_LEN);
741 player_name[PLAYER_NAME_LEN] = '\0';
742 }
743
744 if (namefile) {
745 FILE *fp;
746 name_file = namefile;
747 fp = fopen(namefile, "r");
748 if (fp) {
749 if (!fgets(player_name, PLAYER_NAME_LEN, fp)) {
750 player_name[PLAYER_NAME_LEN] = '\0';
751 } else {
752 LOG_INFO("retrived name %s from %s", player_name, name_file);
753 }
754 fclose(fp);
755 }
756 }
757
705758 if (!running) return;
706759
707760 LOCK_O;
708 sprintf(fixed_cap, ",MaxSampleRate=%u", output.max_sample_rate);
761 sprintf(fixed_cap, ",MaxSampleRate=%u", output.supported_rates[0]);
709762
710763 for (i = 0; i < MAX_CODECS; i++) {
711764 if (codecs[i] && codecs[i]->id && strlen(fixed_cap) < 128 - 10) {
780833
781834 sendHELO(reconnect, fixed_cap, var_cap, mac);
782835
783 if (name) {
784 sendSETDName(name);
785 }
786
787836 slimproto_run();
788837
789838 if (!reconnect) {
144144 // possible sync group
145145 };
146146
147 // S:P:Squeezebox2
148 struct setd_packet {
149 char opcode[4];
150 u8_t id;
151 char data[];
152 };
153
147154 // codec open - this is an extension to slimproto to allow the server to read the header and then return decode params
148155 struct codc_packet {
149156 char opcode[4];
1717 *
1818 */
1919
20 // make may define: PORTAUDIO, SELFPIPE or RESAMPLE to influence build
21
22 #define VERSION "v1.3.1"
20 // make may define: PORTAUDIO, SELFPIPE, RESAMPLE, VISEXPORT, DSD, LINKALL to influence build
21
22 #define VERSION "v1.4"
2323
2424 // build detection
2525 #if defined(linux)
8585 #define VISEXPORT 0
8686 #endif
8787
88 #if defined(DSD)
89 #undef DSD
90 #define DSD 1
91 #define IF_DSD(x) { x }
92 #else
93 #undef DSD
94 #define DSD 0
95 #define IF_DSD(x)
96 #endif
97
8898 #if defined(LINKALL)
8999 #undef LINKALL
90100 #define LINKALL 1 // link all libraries at build time - requires all to be available at run time
96106 #if !LINKALL
97107
98108 // dynamically loaded libraries at run time
109
99110 #if LINUX
100111 #define LIBFLAC "libFLAC.so.8"
101112 #define LIBMAD "libmad.so.0"
236247 #define ERROR_WOULDBLOCK WSAEWOULDBLOCK
237248 #define open _open
238249 #define read _read
250 #define snprintf _snprintf
239251
240252 #define in_addr_t u32_t
241253 #define socklen_t int
292304 #else
293305 #error can not support u64_t
294306 #endif
307
308 #define MAX_SILENCE_FRAMES 2048
295309
296310 #define FIXED_ONE 0x10000
297311
368382 void buf_destroy(struct buffer *buf);
369383
370384 // slimproto.c
371 void slimproto(log_level level, char *server, u8_t mac[6], const char *name);
385 void slimproto(log_level level, char *server, u8_t mac[6], const char *name, const char *namefile);
372386 void slimproto_stop(void);
373387 void wake_controller(void);
374388
434448 void decode_init(log_level level, const char *opt);
435449 void decode_close(void);
436450 void decode_flush(void);
437 unsigned decode_newstream(unsigned sample_rate, unsigned max_sample_rate);
451 unsigned decode_newstream(unsigned sample_rate, unsigned supported_rates[]);
438452 void codec_open(u8_t format, u8_t sample_size, u8_t sample_rate, u8_t channels, u8_t endianness);
439453
440454 #if PROCESS
442456 void process_samples(void);
443457 void process_drain(void);
444458 void process_flush(void);
445 unsigned process_newstream(bool *direct, unsigned raw_sample_rate, unsigned max_sample_rate);
459 unsigned process_newstream(bool *direct, unsigned raw_sample_rate, unsigned supported_rates[]);
446460 void process_init(char *opt);
447461 #endif
448462
450464 // resample.c
451465 void resample_samples(struct processstate *process);
452466 bool resample_drain(struct processstate *process);
453 bool resample_newstream(struct processstate *process, unsigned raw_sample_rate, unsigned max_sample_rate);
467 bool resample_newstream(struct processstate *process, unsigned raw_sample_rate, unsigned supported_rates[]);
454468 void resample_flush(void);
455469 bool resample_init(char *opt);
456470 #endif
457471
458 // output.c
472 // output.c output_alsa.c output_pa.c output_pack.c
459473 typedef enum { OUTPUT_OFF = -1, OUTPUT_STOPPED = 0, OUTPUT_BUFFER, OUTPUT_RUNNING,
460474 OUTPUT_PAUSE_FRAMES, OUTPUT_SKIP_FRAMES, OUTPUT_START_AT } output_state;
475
476 typedef enum { S32_LE, S24_LE, S24_3LE, S16_LE } output_format;
461477
462478 typedef enum { FADE_INACTIVE = 0, FADE_DUE, FADE_ACTIVE } fade_state;
463479 typedef enum { FADE_UP = 1, FADE_DOWN, FADE_CROSS } fade_dir;
464480 typedef enum { FADE_NONE = 0, FADE_CROSSFADE, FADE_IN, FADE_OUT, FADE_INOUT } fade_mode;
465481
482 #define MAX_SUPPORTED_SAMPLERATES 16
483 #define TEST_RATES = { 384000, 352800, 192000, 176400, 96000, 88200, 48000, 44100, 32000, 24000, 22500, 16000, 12000, 11025, 8000, 0 }
484
466485 struct outputstate {
467486 output_state state;
487 output_format format;
468488 const char *device;
469489 #if ALSA
470490 unsigned buffer;
476496 unsigned latency;
477497 int osx_playnice;
478498 #endif
499 int (* write_cb)(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR, s32_t cross_gain_in, s32_t cross_gain_out, s32_t **cross_ptr);
500 unsigned start_frames;
479501 unsigned frames_played;
480502 unsigned current_sample_rate;
481 unsigned max_sample_rate;
503 unsigned supported_rates[MAX_SUPPORTED_SAMPLERATES]; // ordered largest first so [0] is max_rate
504 unsigned default_sample_rate;
505 bool error_opening;
482506 unsigned device_frames;
483507 u32_t updated;
484508 u32_t current_replay_gain;
499523 fade_dir fade_dir;
500524 fade_mode fade_mode; // set by slimproto
501525 unsigned fade_secs; // set by slimproto
502 };
503
526 #if DSD
527 bool next_dop; // set in decode thread
528 bool dop;
529 bool has_dop; // set in dop_init - output device supports dop
530 #endif
531 };
532
533 void output_init_common(log_level level, const char *device, unsigned output_buf_size, unsigned rates[]);
534 void output_close_common(void);
535 void output_flush(void);
536 // _* called with mutex locked
537 frames_t _output_frames(frames_t avail);
538 void _checkfade(bool);
539
540 // output_alsa.c
541 #if ALSA
504542 void list_devices(void);
505 #if ALSA
506 void output_init(log_level level, const char *device, unsigned output_buf_size, unsigned alsa_buffer, unsigned alsa_period, const char *alsa_sample_fmt, bool mmap, unsigned max_rate, unsigned rt_priority);
507 #endif
543 bool test_open(const char *device, unsigned rates[]);
544 void output_init_alsa(log_level level, const char *device, unsigned output_buf_size, char *params, unsigned rates[], unsigned rt_priority);
545 void output_close_alsa(void);
546 #endif
547
548 // output_pa.c
508549 #if PORTAUDIO
509 void output_init(log_level level, const char *device, unsigned output_buf_size, unsigned latency, int osx_playnice, unsigned max_rate);
510 #endif
550 void list_devices(void);
551 bool test_open(const char *device, unsigned rates[]);
552 void output_init_pa(log_level level, const char *device, unsigned output_buf_size, char *params, unsigned rates[]);
553 void output_close_pa(void);
554 void _pa_open(void);
555 #endif
556
557 // output_stdout.c
558 void output_init_stdout(log_level level, unsigned output_buf_size, char *params, unsigned rates[]);
559 void output_close_stdout(void);
560
561 // output_pack.c
562 void _scale_and_pack_frames(void *outputptr, s32_t *inputptr, frames_t cnt, s32_t gainL, s32_t gainR, output_format format);
563 void _apply_cross(struct buffer *outputbuf, frames_t out_frames, s32_t cross_gain_in, s32_t cross_gain_out, s32_t **cross_ptr);
564 void _apply_gain(struct buffer *outputbuf, frames_t count, s32_t gainL, s32_t gainR);
565 s32_t gain(s32_t gain, s32_t sample);
566 s32_t to_gain(float f);
567
568 // output_vis.c
511569 #if VISEXPORT
512 void output_vis_init(u8_t *mac);
513 #endif
514 void output_flush(void);
515 void output_close(void);
516 // _* called with mutex locked
517 void _checkfade(bool);
518 void _pa_open(void);
570 void _vis_export(struct buffer *outputbuf, struct outputstate *output, frames_t out_frames, bool silence);
571 void output_vis_init(log_level level, u8_t *mac);
572 void vis_stop(void);
573 #else
574 #define _vis_export(...)
575 #define vis_stop()
576 #endif
577
578 // dop.c
579 #if DSD
580 bool is_flac_dop(u32_t *lptr, u32_t *rptr, frames_t frames);
581 void update_dop_marker(u32_t *ptr, frames_t frames);
582 void dop_silence_frames(u32_t *ptr, frames_t frames);
583 void dop_init(bool enable);
584 #endif
519585
520586 // codecs
521 #define MAX_CODECS 8
587 #define MAX_CODECS 9
522588
523589 struct codec *register_flac(void);
524590 struct codec *register_pcm(void);
526592 struct codec *register_mpg(void);
527593 struct codec *register_vorbis(void);
528594 struct codec *register_faad(void);
595 struct codec *register_dsd(void);
529596 struct codec *register_ff(const char *codec);
3030
3131 struct vorbis {
3232 OggVorbis_File *vf;
33 bool opened;
3334 #if !LINKALL
3435 // vorbis symbols to be dynamically loaded - from either vorbisfile or vorbisidec (tremor) version of library
3536 vorbis_info *(* ov_info)(OggVorbis_File *vf, int link);
141142 UNLOCK_S;
142143 return DECODE_COMPLETE;
143144 }
145 v->opened = true;
144146
145147 info = OV(v, info, v->vf, -1);
146148
147149 LOG_INFO("setting track_start");
148150 LOCK_O_not_direct;
149 output.next_sample_rate = decode_newstream(info->rate, output.max_sample_rate);
151 output.next_sample_rate = decode_newstream(info->rate, output.supported_rates);
152 IF_DSD( output.next_dop = false; )
150153 output.track_start = outputbuf->writep;
151154 if (output.fade_mode) _checkfade(true);
152155 decode.new_stream = false;
243246 static void vorbis_open(u8_t size, u8_t rate, u8_t chan, u8_t endianness) {
244247 if (!v->vf) {
245248 v->vf = malloc(sizeof(OggVorbis_File) + 128); // add some padding as struct size may be larger
249 memset(v->vf, 0, sizeof(OggVorbis_File) + 128);
246250 } else {
251 if (v->opened) {
252 OV(v, clear, v->vf);
253 v->opened = false;
254 }
255 }
256 }
257
258 static void vorbis_close(void) {
259 if (v->opened) {
247260 OV(v, clear, v->vf);
248 }
249 }
250
251 static void vorbis_close(void) {
252 OV(v, clear, v->vf);
261 v->opened = false;
262 }
253263 free(v->vf);
254264 v->vf = NULL;
255265 }
304314 }
305315
306316 v->vf = NULL;
317 v->opened = false;
307318
308319 if (!load_vorbis()) {
309320 return NULL;