Package list squeezelite / 11c3a1f
1.4beta1 - merge output branch - native support of dsd playback to dop capable dac or via conversion to pcm and resampling - support dop in flac playback to dop dacs - support of output to stdout - support of resampling only when sample rate is not natively supported - fix problem with libmpg123 playback not playing to end of track - add ablity for player name change to be stored locally in a file (to emulate hardware where name is stored on player) Adrian Smith 7 years ago
26 changed file(s) with 3464 addition(s) and 1668 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
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;
+110
-52
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
5455 #if ALSA
5556 " -p <priority>\t\tSet real time priority of output thread (1-99)\n"
5657 #endif
57 " -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"
5859 #if RESAMPLE
59 " -u [params]\t\tUpsample, params = <recipe>:<flags>:<attenuation>:<precision>:<passband_end>:<stopband_start>:<phase_response>,\n"
60 " \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"
6162 " \t\t\t flags = num in hex,\n"
6263 " \t\t\t attenuation = attenuation in dB to apply (default is -1db if not explicitly set),\n"
6364 " \t\t\t precision = number of bits precision (NB. HQ = 20. VHQ = 28),\n"
6566 " \t\t\t stopband_start = number in percent (Aliasing/imaging control. > passband_end),\n"
6667 " \t\t\t phase_response = 0-100 (0 = minimum / 50 = linear / 100 = maximum)\n"
6768 #endif
69 #if DSD
70 " -D\t\t\tOutput device supports DSD over PCM (DoP)\n"
71 #endif
6872 #if VISEXPORT
6973 " -v \t\t\tVisulizer support\n"
7074 #endif
7377 #endif
7478 " -t \t\t\tLicense terms\n"
7579 "\n"
76 "Build options: "
80 "Build options:"
7781 #if LINUX
78 "LINUX"
82 " LINUX"
7983 #endif
8084 #if WIN
81 "WIN"
85 " WIN"
8286 #endif
8387 #if OSX
84 "OSX"
88 " OSX"
8589 #endif
8690 #if ALSA
8791 " ALSA"
106110 #endif
107111 #if VISEXPORT
108112 " VISEXPORT"
113 #endif
114 #if DSD
115 " DSD"
116 #endif
117 #if LINKALL
118 " LINKALL"
109119 #endif
110120 "\n\n",
111121 argv0);
123133 "GNU General Public License for more details.\n\n"
124134 "You should have received a copy of the GNU General Public License\n"
125135 "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
126140 );
127141 }
128142
143157 u8_t mac[6];
144158 unsigned stream_buf_size = STREAMBUF_SIZE;
145159 unsigned output_buf_size = 0; // set later
146 unsigned max_rate = 0;
147 char *upsample = NULL;
160 unsigned rates[MAX_SUPPORTED_SAMPLERATES] = { 0 };
161 char *resample = NULL;
162 char *output_params = NULL;
148163 #if LINUX
149164 bool daemonize = false;
150165 #endif
151166 #if ALSA
152 unsigned alsa_buffer = ALSA_BUFFER_TIME;
153 unsigned alsa_period = ALSA_PERIOD_COUNT;
154 char *alsa_sample_fmt = NULL;
155 bool alsa_mmap = true;
156167 unsigned rt_priority = OUTPUT_RT_PRIORITY;
157168 #endif
158 #if PORTAUDIO
159 unsigned pa_latency = 0;
160 int pa_osx_playnice = -1;
169 #if DSD
170 bool dop = false;
161171 #endif
162172 #if VISEXPORT
163173 bool visexport = false;
180190 optind += 2;
181191 } else if (strstr("ltz"
182192 #if RESAMPLE
183 "u"
193 "uR"
194 #endif
195 #if DSD
196 "D"
184197 #endif
185198 #if VISEXPORT
186199 "v"
197210 case 'o':
198211 output_device = optarg;
199212 break;
200 case 'a':
201 {
202 #if ALSA
203 char *t = next_param(optarg, ':');
204 char *c = next_param(NULL, ':');
205 char *s = next_param(NULL, ':');
206 char *m = next_param(NULL, ':');
207 if (t) alsa_buffer = atoi(t);
208 if (c) alsa_period = atoi(c);
209 if (s) alsa_sample_fmt = s;
210 if (m) alsa_mmap = atoi(m);
211 #endif
212 #if PORTAUDIO
213 char *l = next_param(optarg, ':');
214 char *p = next_param(NULL, ':');
215 if (l) pa_latency = (unsigned)atoi(l);
216 if (p) pa_osx_playnice = atoi(p);
217 #endif
218 }
213 case 'a':
214 output_params = optarg;
219215 break;
220216 case 'b':
221217 {
262258 }
263259 break;
264260 case 'r':
265 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 <max>-<min> or <max>, extract rates from test rates within this range
282 unsigned ref[] TEST_RATES;
283 char *maxstr = next_param(optarg, '-');
284 char *minstr = next_param(NULL, '-');
285 unsigned max = maxstr ? atoi(maxstr) : ref[0];
286 unsigned min = minstr ? atoi(minstr) : 0;
287 int i, j;
288 rates[0] = max;
289 for (i = 0, j = 1; i < MAX_SUPPORTED_SAMPLERATES; ++i) {
290 if (ref[i] < rates[j-1] && ref[i] >= min) {
291 rates[j++] = ref[i];
292 }
293 }
294 }
266295 break;
267296 case 's':
268297 server = optarg;
288317 break;
289318 #if RESAMPLE
290319 case 'u':
320 case 'R':
291321 if (optind < argc && argv[optind] && argv[optind][0] != '-') {
292 upsample = argv[optind++];
322 resample = argv[optind++];
293323 } else {
294 upsample = "";
295 }
324 resample = "";
325 }
326 break;
327 #endif
328 #if DSD
329 case 'D':
330 dop = true;
296331 break;
297332 #endif
298333 #if VISEXPORT
322357 signal(SIGHUP, sighandler);
323358 #endif
324359
325 // set the output buffer size if not specified on the command line to take account of upsampling
360 // set the output buffer size if not specified on the command line, take account of resampling
326361 if (!output_buf_size) {
327362 output_buf_size = OUTPUTBUF_SIZE;
328 if (upsample) {
329 output_buf_size *= max_rate ? max_rate / 44100 : 8;
363 if (resample) {
364 unsigned scale = 8;
365 if (rates[0]) {
366 scale = rates[0] / 44100;
367 if (scale > 8) scale = 8;
368 if (scale < 1) scale = 1;
369 }
370 output_buf_size *= scale;
330371 }
331372 }
332373
350391
351392 stream_init(log_stream, stream_buf_size);
352393
353 #if ALSA
354 output_init(log_output, output_device, output_buf_size, alsa_buffer, alsa_period, alsa_sample_fmt, alsa_mmap,
355 max_rate, rt_priority);
394 if (!strcmp(output_device, "-")) {
395 output_init_stdout(log_output, output_buf_size, output_params, rates);
396 } else {
397 #if ALSA
398 output_init_alsa(log_output, output_device, output_buf_size, output_params, rates, rt_priority);
356399 #endif
357400 #if PORTAUDIO
358 output_init(log_output, output_device, output_buf_size, pa_latency, pa_osx_playnice, max_rate);
401 output_init_pa(log_output, output_device, output_buf_size, output_params, rates);
402 #endif
403 }
404
405 #if DSD
406 dop_init(dop);
359407 #endif
360408
361409 #if VISEXPORT
362410 if (visexport) {
363 output_vis_init(mac);
411 output_vis_init(log_output, mac);
364412 }
365413 #endif
366414
367415 decode_init(log_decode, codecs);
368416
369417 #if RESAMPLE
370 if (upsample) {
371 process_init(upsample);
418 if (resample) {
419 process_init(resample);
372420 }
373421 #endif
374422
381429
382430 decode_close();
383431 stream_close();
384 output_close();
432
433 if (!strcmp(output_device, "-")) {
434 output_close_stdout();
435 } else {
436 #if ALSA
437 output_close_alsa();
438 #endif
439 #if PORTAUDIO
440 output_close_pa();
441 #endif
442 }
385443
386444 #if WIN
387445 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 <