Codebase list squeezelite / f4bd3ce
New upstream version 1.9+git20201216.e02fa87 tony mancill 2 years ago
78 changed file(s) with 8428 addition(s) and 685 deletion(s). Raw diff Collapse all Expand all
0 .vscode/
1 *.o
2 squeezelite
3 squeezelite-pulse
4 tools/alsacap
5 tools/find_servers
+0
-137
ChangeLog.txt less more
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 28/12/13
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
57 Version 1.5 12/1/14
58 ===================
59
60 Minor changes
61 - add configurable delay for switch between pcm and dop
62 - allow visexport to work with jivelite running as any user
63 - bug fixes for dsf playback, for status progress on windows using wdm-ks output, and to avoid 100% cpu
64 - change some logging levels for slimproto to aid readability
65
66 Version 1.6 23/3/14
67 ===================
68
69 Minor changes
70 - add support for direct file playback on windows
71 - add configurable delay for switch between pcm sample rates
72 - support build on freebsd
73 - fix gapless playback on portaudio builds
74 - fix gapless playback for mp3 localfile case with tags at start of file
75
76 Version 1.6.1 22/4/14
77 =====================
78
79 Minor changes
80 - fix bug with PA version changing sample rate between tracks
81 - fix crash when skipping in ogg while resampling
82 - fix typo
83
84 Version 1.6.2 26/5/14
85 =====================
86
87 Minor changes
88 - fix XRUN on track change when resampling on low power cpus
89 - log command line to logfile when debugging enabled
90 - option to exclude codecs (-e)
91 - support parallel execution of libsoxr
92
93 Version 1.6.3 14/6/14
94 =====================
95
96 Minor changes
97 - reduce time to start track when playing local files
98 - disable use of OPENMP when RESAMPLE build option defined, add new option RESAMPLE_MP to enable it
99
100 Version 1.6.4 7/7/14
101 ====================
102
103 Minor changes
104 - improve synchronisation feedback accuracy
105
106 Version 1.6.5 21/11/14
107 ======================
108
109 Minor changes
110 - fix problem opening ALSA device if 44100 is not supported
111 - trap setting of hw player mac address
112
113 Version 1.7 1/1/15
114 ==================
115
116 Minor changes
117 - allow player modelname to be set at compile or run time
118 - workaround alsa drivers reporting very large number of available frames
119 - fix clicks on localfile playback of AIFF files
120 - add -P option to store process id in a file
121 - improve error messages for command line parsing
122
123 Version 1.7.1 10/1/15
124 =====================
125
126 Minor changes
127 - fix crash which could occur when resampling
128
129 Version 1.8 1/2/15
130 ==================
131
132 Features
133 - support for closing output device when idle with -C option
134 - support for basic IR input using LIRC on Linux
135 - support for volume adjustment or unmuting of alsa mixer
136 - support for inverting output polarity via LMS setting (requires recent 7.9 server)
00 Squeezelite - lightweight headless squeezebox emulator
11
22 (c) Adrian Smith 2012-2015, triode1@btinternet.com
3 Ralph Irving 2015-2017, ralph_irving@hotmail.com
34
45 Released under GPLv3 license:
56
0 # Cross compile support - create a Makefile which defines these three variables and then includes this Makefile...
1 CFLAGS ?= -Wall -fPIC -O2 $(OPTS)
2 LDFLAGS ?= -lasound -lpthread -lm -lrt
0 #Cross compile support - create a Makefile which defines these three variables and then includes this Makefile...
1 CFLAGS ?= -Wall -fPIC -O2
2 CFLAGS += -fcommon
3 LDADD ?= -lpthread -lm -lrt
34 EXECUTABLE ?= squeezelite
45
56 # passing one or more of these in $(OPTS) enables optional feature inclusion
67 OPT_DSD = -DDSD
78 OPT_FF = -DFFMPEG
9 OPT_ALAC = -DALAC
810 OPT_LINKALL = -DLINKALL
911 OPT_RESAMPLE= -DRESAMPLE
1012 OPT_VIS = -DVISEXPORT
1113 OPT_IR = -DIR
14 OPT_GPIO = -DGPIO
15 OPT_RPI = -DRPI
16 OPT_NO_FAAD = -DNO_FAAD
17 OPT_SSL = -DUSE_SSL
18 OPT_NOSSLSYM= -DNO_SSLSYM
19 OPT_OPUS = -DOPUS
20 OPT_PORTAUDIO = -DPORTAUDIO
21 OPT_PULSEAUDIO = -DPULSEAUDIO
1222
1323 SOURCES = \
1424 main.c slimproto.c buffer.c stream.c utils.c \
15 output.c output_alsa.c output_pa.c output_stdout.c output_pack.c decode.c \
16 flac.c pcm.c mad.c vorbis.c faad.c mpg.c
25 output.c output_alsa.c output_pa.c output_stdout.c output_pack.c output_pulse.c decode.c \
26 flac.c pcm.c mad.c vorbis.c mpg.c
1727
1828 SOURCES_DSD = dsd.c dop.c dsd2pcm/dsd2pcm.c
1929 SOURCES_FF = ffmpeg.c
30 SOURCES_ALAC = alac.c alac_wrapper.cpp
2031 SOURCES_RESAMPLE = process.c resample.c
2132 SOURCES_VIS = output_vis.c
2233 SOURCES_IR = ir.c
34 SOURCES_GPIO = gpio.c
35 SOURCES_RPI = minimal_gpio.c
36 SOURCES_FAAD = faad.c
37 SOURCES_SSL = sslsym.c
38 SOURCES_OPUS = opus.c
2339
2440 LINK_LINUX = -ldl
41 LINK_ALSA = -lasound
42 LINK_PORTAUDIO = -lportaudio
43 LINK_PULSEAUDIO = -lpulse
44 LINK_SSL = -lssl -lcrypto
45 LINK_ALAC = -lalac
2546
26 LINKALL = -lFLAC -lmad -lvorbisfile -lfaad -lmpg123
27 LINKALL_FF = -lavcodec -lavformat -lavutil
47 LINKALL = -lmad -lmpg123 -lFLAC -lvorbisfile -lvorbis -logg
48 LINKALL_FF = -lavformat -lavcodec -lavutil
2849 LINKALL_RESAMPLE = -lsoxr
2950 LINKALL_IR = -llirc_client
51 LINKALL_FAAD = -lfaad
52 LINKALL_OPUS = -lopusfile -lopus
3053
3154 DEPS = squeezelite.h slimproto.h
3255
3356 UNAME = $(shell uname -s)
3457
3558 # add optional sources
36 ifneq (,$(findstring $(OPT_DSD), $(CFLAGS)))
59 ifneq (,$(findstring $(OPT_DSD), $(OPTS)))
3760 SOURCES += $(SOURCES_DSD)
3861 endif
39 ifneq (,$(findstring $(OPT_FF), $(CFLAGS)))
62 ifneq (,$(findstring $(OPT_FF), $(OPTS)))
4063 SOURCES += $(SOURCES_FF)
4164 endif
42 ifneq (,$(findstring $(OPT_RESAMPLE), $(CFLAGS)))
65 ifneq (,$(findstring $(OPT_ALAC), $(OPTS)))
66 SOURCES += $(SOURCES_ALAC)
67 DEPS += alac_wrapper.h
68 endif
69 ifneq (,$(findstring $(OPT_OPUS), $(OPTS)))
70 SOURCES += $(SOURCES_OPUS)
71 endif
72 ifneq (,$(findstring $(OPT_RESAMPLE), $(OPTS)))
4373 SOURCES += $(SOURCES_RESAMPLE)
4474 endif
45 ifneq (,$(findstring $(OPT_VIS), $(CFLAGS)))
75 ifneq (,$(findstring $(OPT_VIS), $(OPTS)))
4676 SOURCES += $(SOURCES_VIS)
4777 endif
48 ifneq (,$(findstring $(OPT_IR), $(CFLAGS)))
78 ifneq (,$(findstring $(OPT_IR), $(OPTS)))
4979 SOURCES += $(SOURCES_IR)
80 endif
81 ifneq (,$(findstring $(OPT_GPIO), $(OPTS)))
82 SOURCES += $(SOURCES_GPIO)
83 endif
84 ifneq (,$(findstring $(OPT_RPI), $(OPTS)))
85 SOURCES += $(SOURCES_RPI)
86 endif
87 # ensure GPIO is enabled with RPI
88 ifneq (,$(findstring $(OPT_RPI), $(OPTS)))
89 ifeq (,$(findstring $(SOURCES_GPIO), $(SOURCES)))
90 CFLAGS += $(OPT_GPIO)
91 SOURCES += $(SOURCES_GPIO)
92 endif
93 endif
94 ifeq (,$(findstring $(OPT_NO_FAAD), $(OPTS)))
95 SOURCES += $(SOURCES_FAAD)
96 endif
97 ifneq (,$(findstring $(OPT_SSL), $(OPTS)))
98 SOURCES += $(SOURCES_SSL)
5099 endif
51100
52101 # add optional link options
53 ifneq (,$(findstring $(OPT_LINKALL), $(CFLAGS)))
54 LDFLAGS += $(LINKALL)
55 ifneq (,$(findstring $(OPT_FF), $(CFLAGS)))
56 LDFLAGS += $(LINKALL_FF)
102 ifneq (,$(findstring $(OPT_LINKALL), $(OPTS)))
103 LDADD += $(LINKALL)
104 ifneq (,$(findstring $(OPT_FF), $(OPTS)))
105 LDADD += $(LINKALL_FF)
57106 endif
58 ifneq (,$(findstring $(OPT_RESAMPLE), $(CFLAGS)))
59 LDFLAGS += $(LINKALL_RESAMPLE)
107 ifneq (,$(findstring $(OPT_OPUS), $(OPTS)))
108 LDADD += $(LINKALL_OPUS)
60109 endif
61 ifneq (,$(findstring $(OPT_IR), $(CFLAGS)))
62 LDFLAGS += $(LINKALL_IR)
110 ifneq (,$(findstring $(OPT_RESAMPLE), $(OPTS)))
111 LDADD += $(LINKALL_RESAMPLE)
112 endif
113 ifneq (,$(findstring $(OPT_IR), $(OPTS)))
114 LDADD += $(LINKALL_IR)
115 endif
116 ifeq (,$(findstring $(OPT_NO_FAAD), $(OPTS)))
117 LDADD += $(LINKALL_FAAD)
118 endif
119 ifneq (,$(findstring $(OPT_SSL), $(OPTS)))
120 LDADD += $(LINK_SSL)
63121 endif
64122 else
65123 # if not LINKALL and linux add LINK_LINUX
66124 ifeq ($(UNAME), Linux)
67 LDFLAGS += $(LINK_LINUX)
125 LDADD += $(LINK_LINUX)
126 endif
127 ifneq (,$(findstring $(OPT_NOSSLSYM), $(OPTS)))
128 LDADD += $(LINK_SSL)
68129 endif
69130 endif
70131
71 OBJECTS = $(SOURCES:.c=.o)
132 ifneq (,$(findstring $(OPT_PULSEAUDIO), $(OPTS)))
133 LDADD += $(LINK_PULSEAUDIO)
134 else ifneq (,$(findstring $(OPT_PORTAUDIO), $(OPTS)))
135 LDADD += $(LINK_PORTAUDIO)
136 else
137 LDADD += $(LINK_ALSA)
138 endif
139
140 ifneq (,$(findstring $(OPT_ALAC), $(OPTS)))
141 LDADD += $(LINK_ALAC)
142 endif
143
144 OBJECTS = $(addsuffix .o,$(basename $(SOURCES)))
72145
73146 all: $(EXECUTABLE)
74147
75148 $(EXECUTABLE): $(OBJECTS)
76 $(CC) $(OBJECTS) $(LDFLAGS) -o $@
149 ifneq (,$(findstring $(OPT_ALAC), $(OPTS)))
150 $(CXX) $(OBJECTS) $(LDFLAGS) $(LDADD) -o $@
151 else
152 $(CC) $(OBJECTS) $(LDFLAGS) $(LDADD) -o $@
153 endif
77154
78155 $(OBJECTS): $(DEPS)
79156
157 .cpp.o:
158 $(CXX) $(CXXFLAGS) $(CFLAGS) $(CPPFLAGS) $(OPTS) -Wno-multichar $< -c -o $@
159
80160 .c.o:
81 $(CC) $(CFLAGS) $(CPPFLAGS) $< -c -o $@
161 $(CC) $(CFLAGS) $(CPPFLAGS) $(OPTS) $< -c -o $@
82162
83163 clean:
84164 rm -f $(OBJECTS) $(EXECUTABLE)
165
166 print-%:
167 @echo $* = $($*)
0 # Makefile armel
1 OPTS = -DRESAMPLE -DFFMPEG -DVISEXPORT -DDSD -DIR -DGPIO -I/usr/local/include
2 CFLAGS ?= -s -Wall -fPIC -O3 -march=armv5te $(OPTS)
3 LDFLAGS ?= -s -lasound -lpthread -ldl -lrt -Wl,-rpath,/usr/local/lib
4 EXECUTABLE ?= squeezelite
5
6 SOURCES = main.c slimproto.c utils.c buffer.c stream.c decode.c flac.c pcm.c mad.c vorbis.c output_alsa.c output.c output_pa.c output_pack.c output_stdout.c output_vis.c dop.c dsd.c dsd2pcm/dsd2pcm.c faad.c mpg.c resample.c process.c ffmpeg.c ir.c gpio.c
7
8 DEPS = squeezelite.h slimproto.h dsd2pcm/dsd2pcm.h
9
10 OBJECTS = $(SOURCES:.c=.o)
11
12 all: $(EXECUTABLE)
13
14 $(EXECUTABLE): $(OBJECTS)
15 $(CC) $(OBJECTS) $(LDFLAGS) -o $@
16
17 $(OBJECTS): $(DEPS)
18
19 .c.o:
20 $(CC) $(CFLAGS) $< -c -o $@
21
22 clean:
23 rm -f $(OBJECTS) $(EXECUTABLE)
0 OPTS = -DFFMPEG -DRESAMPLE -DGPIO -DUSE_SSL
01 CPPFLAGS = -I/usr/local/include -I/usr/local/include/portaudio2
1 LDFLAGS = -L/usr/local/lib -L/usr/local/lib/portaudio2 -lportaudio -lpthread -lm
2 LDFLAGS = -L/usr/local/lib /usr/local/lib/libportaudio.a -lm
23
34 include Makefile
0 # OSX 10.5 Intel 32-bit
1 OPTS = -DPORTAUDIO -DALAC -DOPUS -DRESAMPLE -DGPIO -DLINKALL -DVISEXPORT -DDSD -DUSE_SSL -I./include -I./include/opus -I./include/alac -O2 -I./include -isysroot /Developer/SDKs/MacOSX10.5.sdk -arch i386
2
3 LDFLAGS = -Wl,-syslibroot,/Developer/SDKs/MacOSX10.5.sdk -arch i386 -mmacosx-version-min=10.5 -L./lib
4
5 LDADD = -lportaudio -lpthread -ldl -lm -framework CoreVideo -framework CoreAudio -framework AudioToolbox -framework AudioUnit -framework Carbon
6
7 EXECUTABLE = squeezelite-i386
8
9 include Makefile
0 # Cross compile support - create a Makefile which defines these three variables and then includes this Makefile...
1 CFLAGS ?= -Wall -DPORTAUDIO -DPA18API -fPIC -O3 -I`pwd`/include $(OPTS)
2 LDFLAGS ?= -lpthread -lm -ldl -lrt -L`pwd`/lib -lportaudio
3 EXECUTABLE ?= squeezelite-oss
4
5 SOURCES = main.c slimproto.c buffer.c stream.c utils.c output.c output_alsa.c output_pa.c output_stdout.c output_pack.c output_vis.c decode.c flac.c pcm.c mad.c vorbis.c faad.c mpg.c dsd.c dop.c dsd2pcm/dsd2pcm.c ffmpeg.c process.c resample.c ir.c
6 DEPS = squeezelite.h slimproto.h
7
8 OBJECTS = $(SOURCES:.c=.o)
9
10 all: $(EXECUTABLE)
11
12 $(EXECUTABLE): $(OBJECTS)
13 $(CC) $(OBJECTS) $(LDFLAGS) -o $@
14
15 $(OBJECTS): $(DEPS)
16
17 .c.o:
18 $(CC) $(CFLAGS) $< -c -o $@
19
20 clean:
21 rm -f $(OBJECTS) $(EXECUTABLE)
0 # OSX 10.4 PPC 32-bit
1 CC=powerpc-apple-darwin10-gcc
2 CXX=powerpc-apple-darwin10-gcc
3 CFLAGS ?= -s -Wall -fPIC -DOSXPPC -DLINKALL -O2 -I./include -isysroot /Developer/SDKs/MacOSX10.4u.sdk -mcpu=G3 -arch ppc
4 LDFLAGS ?= -Wl,-syslibroot,/Developer/SDKs/MacOSX10.4u.sdk -arch ppc -mmacosx-version-min=10.3 -L./lib -lFLAC -lvorbisfile -lvorbis -logg -lmad -lfaad -lmpg123 -lpthread -ldl -lm -lportaudio -framework CoreAudio -framework AudioToolbox -framework AudioUnit -framework Carbon
5 EXECUTABLE ?= squeezelite-ppc
6
7 SOURCES = main.c slimproto.c buffer.c stream.c utils.c output.c output_alsa.c output_pa.c output_stdout.c output_pack.c decode.c flac.c pcm.c mad.c vorbis.c faad.c mpg.c
8
9 DEPS = squeezelite.h slimproto.h
10
11 OBJECTS = $(SOURCES:.c=.o)
12
13 all: $(EXECUTABLE)
14
15 $(EXECUTABLE): $(OBJECTS)
16 $(CC) $(OBJECTS) $(LDFLAGS) -o $@
17
18 $(OBJECTS): $(DEPS)
19
20 .c.o:
21 $(CC) $(CFLAGS) $< -c -o $@
22
23 clean:
24 rm -f $(OBJECTS) $(EXECUTABLE)
0 # OSX 10.3 PPC 64-bit
1 CC=powerpc-apple-darwin10-gcc
2 CXX=powerpc-apple-darwin10-gcc
3 CFLAGS ?= -s -Wall -fPIC -DOSXPPC -DLINKALL -O2 -I./include64 -isysroot /Developer/SDKs/MacOSX10.5.sdk -m64 -arch ppc64 -mmacosx-version-min=10.3
4 LDFLAGS ?= -m64 -Wl,-syslibroot,/Developer/SDKs/MacOSX10.5.sdk -arch ppc64 -mmacosx-version-min=10.3 -L./lib64 -lFLAC -lvorbisfile -lvorbis -logg -lmad -lfaad -lmpg123 -lpthread -ldl -lm -lportaudio -framework CoreAudio -framework AudioToolbox -framework AudioUnit -framework Carbon
5 EXECUTABLE ?= squeezelite-ppc64
6
7 SOURCES = main.c slimproto.c buffer.c stream.c utils.c output.c output_alsa.c output_pa.c output_stdout.c output_pack.c decode.c flac.c pcm.c mad.c vorbis.c faad.c mpg.c
8
9 DEPS = squeezelite.h slimproto.h
10
11 OBJECTS = $(SOURCES:.c=.o)
12
13 all: $(EXECUTABLE)
14
15 $(EXECUTABLE): $(OBJECTS)
16 $(CC) $(OBJECTS) $(LDFLAGS) -o $@
17
18 $(OBJECTS): $(DEPS)
19
20 .c.o:
21 $(CC) $(CFLAGS) $< -c -o $@
22
23 clean:
24 rm -f $(OBJECTS) $(EXECUTABLE)
0 # Make with PulseAudio rather than direct alsa
1 OPTS += -DPULSEAUDIO
2 LDADD = -lrt -lpulse -lpthread -lm
3 EXECUTABLE = squeezelite-pulse
4
5 include Makefile
0 OPTS = -DOPUS -DALAC -DRESAMPLE -DVISEXPORT -DDSD -DIR -DGPIO -DRPI -DUSE_SSL -DLINKALL -I./include -I./include/opus -I./include/alac -I/usr/local/include -s -march=armv6 -mfloat-abi=hard -mfpu=vfp
1
2 LDFLAGS=-L./lib -L/usr/local/lib -s -lgomp
3
4 include Makefile
0 # Solaris SPARC portaudio v18 api
1 CC = gcc
2 CPP = cpp
3 CFLAGS ?= -fPIC -Wall -O3 -DRESAMPLE -DGPIO -I`pwd`/include -s
4 LDFLAGS ?= -lpthread -lsocket -lnsl -ldl -lrt -lm -L`pwd`/lib -lportaudio -R/opt/squeezelite/lib -s
5 EXECUTABLE ?= squeezelite-sun
6
7 SOURCES = main.c slimproto.c utils.c buffer.c stream.c decode.c flac.c pcm.c mad.c vorbis.c output_alsa.c output.c output_pa.c output_pack.c output_stdout.c output_vis.c daemonize.c faad.c mpg.c resample.c process.c gpio.c ffmpeg.c
8 DEPS = squeezelite.h slimproto.h dsd2pcm/dsd2pcm.h
9
10 OBJECTS = $(SOURCES:.c=.o)
11
12 all: $(EXECUTABLE)
13
14 $(EXECUTABLE): $(OBJECTS)
15 $(CC) $(OBJECTS) $(LDFLAGS) -o $@
16
17 $(OBJECTS): $(DEPS)
18
19 .c.o:
20 $(CC) $(CFLAGS) $< -c -o $@
21
22 clean:
23 rm -f $(OBJECTS) $(EXECUTABLE)
0 # OSX 10.7+ 64-bit only
1 OPTS = -DPORTAUDIO -DALAC -DOPUS -DRESAMPLE -DGPIO -DLINKALL -DVISEXPORT -DDSD -DUSE_SSL -I./include64 -I./include64/opus -I./include64/alac -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk -arch x86_64 -mmacosx-version-min=10.7
2
3 LDFLAGS = -Wl,-syslibroot,/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk -arch x86_64 -mmacosx-version-min=10.7 -L./lib64
4
5 LDADD = -lportaudio -lpthread -ldl -lm -framework CoreVideo -framework VideoDecodeAcceleration -framework CoreAudio -framework AudioToolbox -framework AudioUnit -framework Carbon
6
7 include Makefile
0 Squeezelite v1.9.x, Copyright 2012-2015 Adrian Smith, 2015-2019 Ralph Irving.<br>
1 <br>
2 See the squeezelite manpage for usage details.<br>
3 https://ralph-irving.github.io/squeezelite.html<br>
4 <br>
5 This program is free software: you can redistribute it and/or modify<br>
6 it under the terms of the GNU General Public License as published by<br>
7 the Free Software Foundation, either version 3 of the License, or<br>
8 (at your option) any later version.<br>
9 <br>
10 This program is distributed in the hope that it will be useful,<br>
11 but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br>
13 GNU General Public License for more details.<br>
14 <br>
15 You should have received a copy of the GNU General Public License<br>
16 along with this program. If not, see <http://www.gnu.org/licenses/>.<br>
17 <br>
18 Contains dsd2pcm library Copyright 2009, 2011 Sebastian Gesemann which<br>
19 is subject to its own license.<br>
20 <br>
21 Contains the Daphile Project full dsd patch Copyright 2013-2017 Daphile,<br>
22 which is subject to its own license.<br>
23 <br>
24 Option to allow server side upsampling for PCM streams (-W) from<br>
25 squeezelite-R2 (c) Marco Curti 2015, marcoc1712@gmail.com.<br>
26 <br>
27 RaspberryPi minimal GPIO Interface<br>
28 http://abyz.me.uk/rpi/pigpio/examples.html#Misc_minimal_gpio.<br>
29 <br>
30 This software uses libraries from the FFmpeg project under<br>
31 the LGPLv2.1 and its source can be downloaded from<br>
32 https://sourceforge.net/projects/lmsclients/files/source/<br>
0 /*
1 * Squeezelite - lightweight headless squeezebox emulator
2 *
3 * (c) Adrian Smith 2012-2015, triode1@btinternet.com
4 * (c) Philippe, philippe_44@outlook.com
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 #include "squeezelite.h"
22
23 #if ALAC
24 #include "alac_wrapper.h"
25
26 #if BYTES_PER_FRAME == 4
27 #define ALIGN8(n) (n << 8)
28 #define ALIGN16(n) (n)
29 #define ALIGN24(n) (n >> 8)
30 #define ALIGN32(n) (n >> 16)
31 #else
32 #define ALIGN8(n) (n << 24)
33 #define ALIGN16(n) (n << 16)
34 #define ALIGN24(n) (n << 8)
35 #define ALIGN32(n) (n)
36 #endif
37
38 #define BLOCK_SIZE (4096 * BYTES_PER_FRAME)
39 #define MIN_READ BLOCK_SIZE
40 #define MIN_SPACE (MIN_READ * 4)
41
42 struct chunk_table {
43 u32_t sample, offset;
44 };
45
46 struct alac {
47 void *decoder;
48 u8_t *writebuf;
49 // following used for mp4 only
50 u32_t consume;
51 u32_t pos;
52 u32_t sample;
53 u32_t nextchunk;
54 void *stsc;
55 u32_t skip;
56 u64_t samples;
57 u64_t sttssamples;
58 bool empty;
59 struct chunk_table *chunkinfo;
60 u32_t *block_size, default_block_size, block_index;
61 unsigned sample_rate;
62 unsigned char channels, sample_size;
63 unsigned trak, play;
64 };
65
66 static struct alac *l;
67
68 extern log_level loglevel;
69
70 extern struct buffer *streambuf;
71 extern struct buffer *outputbuf;
72 extern struct streamstate stream;
73 extern struct outputstate output;
74 extern struct decodestate decode;
75 extern struct processstate process;
76
77 #define LOCK_S mutex_lock(streambuf->mutex)
78 #define UNLOCK_S mutex_unlock(streambuf->mutex)
79 #define LOCK_O mutex_lock(outputbuf->mutex)
80 #define UNLOCK_O mutex_unlock(outputbuf->mutex)
81 #if PROCESS
82 #define LOCK_O_direct if (decode.direct) mutex_lock(outputbuf->mutex)
83 #define UNLOCK_O_direct if (decode.direct) mutex_unlock(outputbuf->mutex)
84 #define LOCK_O_not_direct if (!decode.direct) mutex_lock(outputbuf->mutex)
85 #define UNLOCK_O_not_direct if (!decode.direct) mutex_unlock(outputbuf->mutex)
86 #define IF_DIRECT(x) if (decode.direct) { x }
87 #define IF_PROCESS(x) if (!decode.direct) { x }
88 #else
89 #define LOCK_O_direct mutex_lock(outputbuf->mutex)
90 #define UNLOCK_O_direct mutex_unlock(outputbuf->mutex)
91 #define LOCK_O_not_direct
92 #define UNLOCK_O_not_direct
93 #define IF_DIRECT(x) { x }
94 #define IF_PROCESS(x)
95 #endif
96
97 // read mp4 header to extract config data
98 static int read_mp4_header(void) {
99 size_t bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf));
100 char type[5];
101 u32_t len;
102
103 while (bytes >= 8) {
104 // count trak to find the first playable one
105 u32_t consume;
106
107 len = unpackN((u32_t *)streambuf->readp);
108 memcpy(type, streambuf->readp + 4, 4);
109 type[4] = '\0';
110
111 if (!strcmp(type, "moov")) {
112 l->trak = 0;
113 l->play = 0;
114 }
115 if (!strcmp(type, "trak")) {
116 l->trak++;
117 }
118
119 // extract audio config from within alac
120 if (!strcmp(type, "alac") && bytes > len) {
121 u8_t *ptr = streambuf->readp + 36;
122 l->decoder = alac_create_decoder(len - 36, ptr, &l->sample_size, &l->sample_rate, &l->channels);
123 l->play = l->trak;
124 }
125
126 // extract the total number of samples from stts
127 if (!strcmp(type, "stsz") && bytes > len) {
128 u32_t i;
129 u8_t *ptr = streambuf->readp + 12;
130 l->default_block_size = unpackN((u32_t *) ptr); ptr += 4;
131 if (!l->default_block_size) {
132 u32_t entries = unpackN((u32_t *)ptr); ptr += 4;
133 l->block_size = malloc((entries + 1)* 4);
134 for (i = 0; i < entries; i++) {
135 l->block_size[i] = unpackN((u32_t *)ptr); ptr += 4;
136 }
137 l->block_size[entries] = 0;
138 LOG_DEBUG("total blocksize contained in stsz %u", entries);
139 } else {
140 LOG_DEBUG("fixed blocksize in stsz %u", l->default_block_size);
141 }
142 }
143
144 // extract the total number of samples from stts
145 if (!strcmp(type, "stts") && bytes > len) {
146 u32_t i;
147 u8_t *ptr = streambuf->readp + 12;
148 u32_t entries = unpackN((u32_t *)ptr);
149 ptr += 4;
150 for (i = 0; i < entries; ++i) {
151 u32_t count = unpackN((u32_t *)ptr);
152 u32_t size = unpackN((u32_t *)(ptr + 4));
153 l->sttssamples += count * size;
154 ptr += 8;
155 }
156 LOG_DEBUG("total number of samples contained in stts: " FMT_u64, l->sttssamples);
157 }
158
159 // stash sample to chunk info, assume it comes before stco
160 if (!strcmp(type, "stsc") && bytes > len && !l->chunkinfo) {
161 l->stsc = malloc(len - 12);
162 if (l->stsc == NULL) {
163 LOG_WARN("malloc fail");
164 return -1;
165 }
166 memcpy(l->stsc, streambuf->readp + 12, len - 12);
167 }
168
169 // build offsets table from stco and stored stsc
170 if (!strcmp(type, "stco") && bytes > len && l->play == l->trak) {
171 u32_t i;
172 // extract chunk offsets
173 u8_t *ptr = streambuf->readp + 12;
174 u32_t entries = unpackN((u32_t *)ptr);
175 ptr += 4;
176 l->chunkinfo = malloc(sizeof(struct chunk_table) * (entries + 1));
177 if (l->chunkinfo == NULL) {
178 LOG_WARN("malloc fail");
179 return -1;
180 }
181 for (i = 0; i < entries; ++i) {
182 l->chunkinfo[i].offset = unpackN((u32_t *)ptr);
183 l->chunkinfo[i].sample = 0;
184 ptr += 4;
185 }
186 l->chunkinfo[i].sample = 0;
187 l->chunkinfo[i].offset = 0;
188 // fill in first sample id for each chunk from stored stsc
189 if (l->stsc) {
190 u32_t stsc_entries = unpackN((u32_t *)l->stsc);
191 u32_t sample = 0;
192 u32_t last = 0, last_samples = 0;
193 u8_t *ptr = (u8_t *)l->stsc + 4;
194 while (stsc_entries--) {
195 u32_t first = unpackN((u32_t *)ptr);
196 u32_t samples = unpackN((u32_t *)(ptr + 4));
197 if (last) {
198 for (i = last - 1; i < first - 1; ++i) {
199 l->chunkinfo[i].sample = sample;
200 sample += last_samples;
201 }
202 }
203 if (stsc_entries == 0) {
204 for (i = first - 1; i < entries; ++i) {
205 l->chunkinfo[i].sample = sample;
206 sample += samples;
207 }
208 }
209 last = first;
210 last_samples = samples;
211 ptr += 12;
212 }
213 free(l->stsc);
214 l->stsc = NULL;
215 }
216 }
217
218 // found media data, advance to start of first chunk and return
219 if (!strcmp(type, "mdat")) {
220 _buf_inc_readp(streambuf, 8);
221 l->pos += 8;
222 bytes -= 8;
223 if (l->play) {
224 LOG_DEBUG("type: mdat len: %u pos: %u", len, l->pos);
225 if (l->chunkinfo && l->chunkinfo[0].offset > l->pos) {
226 u32_t skip = l->chunkinfo[0].offset - l->pos;
227 LOG_DEBUG("skipping: %u", skip);
228 if (skip <= bytes) {
229 _buf_inc_readp(streambuf, skip);
230 l->pos += skip;
231 } else {
232 l->consume = skip;
233 }
234 }
235 l->sample = l->nextchunk = 1;
236 l->block_index = 0;
237 return 1;
238 } else {
239 LOG_DEBUG("type: mdat len: %u, no playable track found", len);
240 return -1;
241 }
242 }
243
244 // parse key-value atoms within ilst ---- entries to get encoder padding within iTunSMPB entry for gapless
245 if (!strcmp(type, "----") && bytes > len) {
246 u8_t *ptr = streambuf->readp + 8;
247 u32_t remain = len - 8, size;
248 if (!memcmp(ptr + 4, "mean", 4) && (size = unpackN((u32_t *)ptr)) < remain) {
249 ptr += size; remain -= size;
250 }
251 if (!memcmp(ptr + 4, "name", 4) && (size = unpackN((u32_t *)ptr)) < remain && !memcmp(ptr + 12, "iTunSMPB", 8)) {
252 ptr += size; remain -= size;
253 }
254 if (!memcmp(ptr + 4, "data", 4) && remain > 16 + 48) {
255 // data is stored as hex strings: 0 start end samples
256 u32_t b, c; u64_t d;
257 if (sscanf((const char *)(ptr + 16), "%x %x %x " FMT_x64, &b, &b, &c, &d) == 4) {
258 LOG_DEBUG("iTunSMPB start: %u end: %u samples: " FMT_u64, b, c, d);
259 if (l->sttssamples && l->sttssamples < b + c + d) {
260 LOG_DEBUG("reducing samples as stts count is less");
261 d = l->sttssamples - (b + c);
262 }
263 l->skip = b;
264 l->samples = d;
265 }
266 }
267 }
268
269 // default to consuming entire box
270 consume = len;
271
272 // read into these boxes so reduce consume
273 if (!strcmp(type, "moov") || !strcmp(type, "trak") || !strcmp(type, "mdia") || !strcmp(type, "minf") || !strcmp(type, "stbl") ||
274 !strcmp(type, "udta") || !strcmp(type, "ilst")) {
275 consume = 8;
276 }
277 // special cases which mix mix data in the enclosing box which we want to read into
278 if (!strcmp(type, "stsd")) consume = 16;
279 if (!strcmp(type, "mp4a")) consume = 36;
280 if (!strcmp(type, "meta")) consume = 12;
281
282 // consume rest of box if it has been parsed (all in the buffer) or is not one we want to parse
283 if (bytes >= consume) {
284 LOG_DEBUG("type: %s len: %u consume: %u", type, len, consume);
285 _buf_inc_readp(streambuf, consume);
286 l->pos += consume;
287 bytes -= consume;
288 } else if ( !(!strcmp(type, "esds") || !strcmp(type, "stts") || !strcmp(type, "stsc") ||
289 !strcmp(type, "stsz") || !strcmp(type, "stco") || !strcmp(type, "----")) ) {
290 LOG_DEBUG("type: %s len: %u consume: %u - partial consume: %u", type, len, consume, bytes);
291 _buf_inc_readp(streambuf, bytes);
292 l->pos += bytes;
293 l->consume = consume - bytes;
294 break;
295 } else if (len > streambuf->size) {
296 // can't process an atom larger than streambuf!
297 LOG_ERROR("atom %s too large for buffer %u %u", type, len, streambuf->size);
298 return -1;
299 } else {
300 // make sure there is 'len' contiguous space
301 _buf_unwrap(streambuf, len);
302 break;
303 }
304 }
305
306 return 0;
307 }
308
309 static decode_state alac_decode(void) {
310 size_t bytes;
311 bool endstream;
312 u8_t *iptr;
313 u32_t frames, block_size;
314
315 LOCK_S;
316
317 // data not reached yet
318 if (l->consume) {
319 u32_t consume = min(l->consume, _buf_used(streambuf));
320 LOG_DEBUG("consume: %u of %u", consume, l->consume);
321 _buf_inc_readp(streambuf, consume);
322 l->pos += consume;
323 l->consume -= consume;
324 UNLOCK_S;
325 return DECODE_RUNNING;
326 }
327
328 if (decode.new_stream) {
329 int found = 0;
330
331 // mp4 - read header
332 found = read_mp4_header();
333
334 if (found == 1) {
335 bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf));
336
337 LOG_INFO("setting track_start");
338 LOCK_O;
339
340 output.next_sample_rate = decode_newstream(l->sample_rate, output.supported_rates);
341 IF_DSD( output.next_fmt = PCM; )
342 output.track_start = outputbuf->writep;
343 if (output.fade_mode) _checkfade(true);
344 decode.new_stream = false;
345
346 UNLOCK_O;
347 } else if (found == -1) {
348 LOG_WARN("[%p]: error reading stream header");
349 UNLOCK_S;
350 return DECODE_ERROR;
351 } else {
352 // not finished header parsing come back next time
353 UNLOCK_S;
354 return DECODE_RUNNING;
355 }
356 }
357
358 bytes = _buf_used(streambuf);
359 block_size = l->default_block_size ? l->default_block_size : l->block_size[l->block_index];
360
361 // stream terminated
362 if (stream.state <= DISCONNECT && (bytes == 0 || block_size == 0)) {
363 UNLOCK_S;
364 LOG_DEBUG("end of stream");
365 return DECODE_COMPLETE;
366 }
367
368 // is there enough data for decoding
369 if (bytes < block_size) {
370 UNLOCK_S;
371 return DECODE_RUNNING;
372 } else if (block_size != l->default_block_size) l->block_index++;
373
374 bytes = min(bytes, _buf_cont_read(streambuf));
375
376 // need to create a buffer with contiguous data
377 if (bytes < block_size) {
378 u8_t *buffer = malloc(block_size);
379 memcpy(buffer, streambuf->readp, bytes);
380 memcpy(buffer + bytes, streambuf->buf, block_size - bytes);
381 iptr = buffer;
382 } else iptr = streambuf->readp;
383
384 if (!alac_to_pcm(l->decoder, iptr, l->writebuf, 2, &frames)) {
385 LOG_ERROR("decode error");
386 UNLOCK_S;
387 return DECODE_ERROR;
388 }
389
390 // and free it
391 if (bytes < block_size) free(iptr);
392
393 LOG_SDEBUG("block of %u bytes (%u frames)", block_size, frames);
394
395 endstream = false;
396 // mp4 end of chunk - skip to next offset
397 if (l->chunkinfo && l->chunkinfo[l->nextchunk].offset && l->sample++ == l->chunkinfo[l->nextchunk].sample) {
398 if (l->chunkinfo[l->nextchunk].offset > l->pos) {
399 u32_t skip = l->chunkinfo[l->nextchunk].offset - l->pos;
400 if (_buf_used(streambuf) >= skip) {
401 _buf_inc_readp(streambuf, skip);
402 l->pos += skip;
403 } else {
404 l->consume = skip;
405 }
406 l->nextchunk++;
407 } else {
408 LOG_ERROR("error: need to skip backwards!");
409 endstream = true;
410 }
411 // mp4 when not at end of chunk
412 } else if (frames) {
413 _buf_inc_readp(streambuf, block_size);
414 l->pos += block_size;
415 } else {
416 endstream = true;
417 }
418
419 UNLOCK_S;
420
421 if (endstream) {
422 LOG_WARN("unable to decode further");
423 return DECODE_ERROR;
424 }
425
426 // now point at the beginning of decoded samples
427 iptr = l->writebuf;
428
429 if (l->skip) {
430 u32_t skip;
431 if (l->empty) {
432 l->empty = false;
433 l->skip -= frames;
434 LOG_DEBUG("gapless: first frame empty, skipped %u frames at start", frames);
435 }
436 skip = min(frames, l->skip);
437 LOG_DEBUG("gapless: skipping %u frames at start", skip);
438 frames -= skip;
439 l->skip -= skip;
440 iptr += skip * l->channels * l->sample_size;
441 }
442
443 if (l->samples) {
444 if (l->samples < frames) {
445 LOG_DEBUG("gapless: trimming %u frames from end", frames - l->samples);
446 frames = (u32_t) l->samples;
447 }
448 l->samples -= frames;
449 }
450
451 LOCK_O_direct;
452
453 while (frames > 0) {
454 size_t f, count;
455 ISAMPLE_T *optr;
456
457 IF_DIRECT(
458 f = min(frames, _buf_cont_write(outputbuf) / BYTES_PER_FRAME);
459 optr = (ISAMPLE_T *)outputbuf->writep;
460 );
461 IF_PROCESS(
462 f = min(frames, process.max_in_frames - process.in_frames);
463 optr = (ISAMPLE_T *)((u8_t *) process.inbuf + process.in_frames * BYTES_PER_FRAME);
464 );
465
466 f = min(f, frames);
467 count = f;
468
469 if (l->sample_size == 8) {
470 while (count--) {
471 *optr++ = ALIGN8(*iptr++);
472 *optr++ = ALIGN8(*iptr++);
473 }
474 } else if (l->sample_size == 16) {
475 u16_t *_iptr = (u16_t*) iptr;
476 while (count--) {
477 *optr++ = ALIGN16(*_iptr++);
478 *optr++ = ALIGN16(*_iptr++);
479 }
480 } else if (l->sample_size == 24) {
481 while (count--) {
482 *optr++ = ALIGN24(*(u32_t*) iptr);
483 *optr++ = ALIGN24(*(u32_t*) (iptr + 3));
484 iptr += 6;
485 }
486 } else if (l->sample_size == 32) {
487 u32_t *_iptr = (u32_t*) iptr;
488 while (count--) {
489 *optr++ = ALIGN32(*_iptr++);
490 *optr++ = ALIGN32(*_iptr++);
491 }
492 } else {
493 LOG_ERROR("unsupported bits per sample: %u", l->sample_size);
494 }
495
496 frames -= f;
497
498 IF_DIRECT(
499 _buf_inc_writep(outputbuf, f * BYTES_PER_FRAME);
500 );
501 IF_PROCESS(
502 process.in_frames = f;
503 // called only if there is enough space in process buffer
504 if (frames) LOG_ERROR("unhandled case");
505 );
506 }
507
508 UNLOCK_O_direct;
509
510 return DECODE_RUNNING;
511 }
512
513 static void alac_open(u8_t size, u8_t rate, u8_t chan, u8_t endianness) {
514 if (l->decoder) alac_delete_decoder(l->decoder);
515 else l->writebuf = malloc(BLOCK_SIZE * 2);
516
517 if (l->chunkinfo) free(l->chunkinfo);
518 if (l->block_size) free(l->block_size);
519 if (l->stsc) free(l->stsc);
520 l->decoder = l->chunkinfo = l->stsc = l->block_size = NULL;
521 l->skip = 0;
522 l->samples = l->sttssamples = 0;
523 l->empty = false;
524 l->pos = l->consume = l->sample = l->nextchunk = 0;
525 }
526
527 static void alac_close(void) {
528 if (l->decoder) alac_delete_decoder(l->decoder);
529 if (l->chunkinfo) free(l->chunkinfo);
530 if (l->block_size) free(l->block_size);
531 if (l->stsc) free(l->stsc);
532 l->decoder = l->chunkinfo = l->stsc = l->block_size = NULL;
533 free(l->writebuf);
534 }
535
536 struct codec *register_alac(void) {
537 static struct codec ret = {
538 'l', // id
539 "alc", // types
540 MIN_READ, // min read
541 MIN_SPACE, // min space assuming a ratio of 2
542 alac_open, // open
543 alac_close, // close
544 alac_decode, // decode
545 };
546
547 l = malloc(sizeof(struct alac));
548 if (!l) {
549 return NULL;
550 }
551
552 l->decoder = l->chunkinfo = l->stsc = l->block_size = NULL;
553
554 LOG_INFO("using alac to decode alc");
555 return &ret;
556 }
557
558 #endif /* ALAC */
0 /*
1 * alac_wrapper.c - ALAC decoder wrapper
2 *
3 * (c) Philippe, philippe_44@outlook.com
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 */
19
20 #include <stdlib.h>
21
22 #include "ALACDecoder.h"
23 #include "ALACBitUtilities.h"
24 #include "alac_wrapper.h"
25
26 typedef struct alac_codec_s {
27 ALACDecoder *Decoder;
28 unsigned block_size, frames_per_packet;
29 } alac_codec_t;
30
31 /*----------------------------------------------------------------------------*/
32 extern "C" struct alac_codec_s *alac_create_decoder(int magic_cookie_size, unsigned char *magic_cookie,
33 unsigned char *sample_size, unsigned *sample_rate,
34 unsigned char *channels) {
35 struct alac_codec_s *codec = (struct alac_codec_s*) malloc(sizeof(struct alac_codec_s));
36
37 codec->Decoder = new ALACDecoder;
38 codec->Decoder->Init(magic_cookie, magic_cookie_size);
39
40 *channels = codec->Decoder->mConfig.numChannels;
41 *sample_rate = codec->Decoder->mConfig.sampleRate;
42 *sample_size = codec->Decoder->mConfig.bitDepth;
43
44 codec->frames_per_packet = codec->Decoder->mConfig.frameLength;
45 codec->block_size = codec->frames_per_packet * (*channels) * (*sample_size) / 8;
46
47 return codec;
48 }
49
50 /*----------------------------------------------------------------------------*/
51 extern "C" void alac_delete_decoder(struct alac_codec_s *codec) {
52 delete (ALACDecoder*) codec->Decoder;
53 free(codec);
54 }
55
56 /*----------------------------------------------------------------------------*/
57 extern "C" bool alac_to_pcm(struct alac_codec_s *codec, unsigned char* input,
58 unsigned char *output, char channels, unsigned *out_frames) {
59 BitBuffer input_buffer;
60
61 BitBufferInit(&input_buffer, input, codec->block_size);
62 return codec->Decoder->Decode(&input_buffer, output, codec->frames_per_packet, channels, out_frames) == ALAC_noErr;
63 }
64
0 /*****************************************************************************
1 * alac_wrapper.h: ALAC coder wrapper
2 *
3 * Copyright (C) 2016 Philippe <philippe44@outlook.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 2 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, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
18 *****************************************************************************/
19 #ifndef __ALAC_WRAPPER_H_
20 #define __ALAC_WRAPPER_H_
21
22 struct alac_codec_s;
23
24 #ifdef __cplusplus
25 extern "C" {
26 #endif
27
28 struct alac_codec_s *alac_create_decoder(int magic_cookie_size, unsigned char *magic_cookie,
29 unsigned char *sample_size, unsigned *sample_rate,
30 unsigned char *channels);
31 void alac_delete_decoder(struct alac_codec_s *codec);
32 bool alac_to_pcm(struct alac_codec_s *codec, unsigned char* input,
33 unsigned char *output, char channels, unsigned *out_frames);
34
35 #ifdef __cplusplus
36 }
37 #endif
38
39 #endif
0 # Contributor: Carl Chave <online@chave.us>
1 # Maintainer: Ralph Irving <ralph.irving@gmail.com>
2 pkgname=squeezelite
3 pkgver=1.9.7.1273
4 pkgrel=1
5 pkgdesc="Lightweight headless squeezebox player for Logitech Media Server"
6 url="https://github.com/ralph-irving/squeezelite"
7 arch="all"
8 license="GPL-3.0-or-later3"
9 options="!check" # No test suite
10 depends="flac alsa-lib faad2 mpg123 libvorbis libmad soxr openssl opusfile libalac"
11 makedepends="flac-dev alsa-lib-dev faad2-dev mpg123-dev libvorbis-dev libmad-dev soxr-dev openssl-dev opusfile-dev opus-dev libalac-dev"
12 install="$pkgname.pre-install"
13 subpackages="$pkgname-doc $pkgname-openrc"
14 source="$pkgname-$pkgver.zip::https://github.com/ralph-irving/squeezelite/archive/master.zip load-libtremor-first.patch $pkgname.confd $pkgname.initd"
15 builddir="$srcdir/$pkgname-master"
16
17 build() {
18 cd "$builddir"
19 make OPTS="-DRESAMPLE -DDSD -DGPIO -DVISEXPORT -DUSE_SSL -DNO_SSLSYM -DOPUS -DALAC -I/usr/include/opus -I/usr/include/alac"
20 gcc -Os -fomit-frame-pointer -fcommon -s -o find_servers tools/find_servers.c
21 gcc -Os -fomit-frame-pointer -fcommon -s -o alsacap tools/alsacap.c -lasound
22 }
23
24 package() {
25 cd "$builddir"
26 install -Dm 755 squeezelite \
27 "$pkgdir"/usr/bin/squeezelite
28 install -Dm 755 alsacap \
29 "$pkgdir"/usr/bin/alsacap
30 install -Dm 755 find_servers \
31 "$pkgdir"/usr/bin/find_servers
32 install -Dm 644 doc/squeezelite.1 \
33 "$pkgdir"/usr/share/man/man1/squeezelite.1
34 install -Dm 644 "$srcdir"/squeezelite.confd \
35 "$pkgdir"/etc/conf.d/squeezelite
36 install -Dm 755 "$srcdir"/squeezelite.initd \
37 "$pkgdir"/etc/init.d/squeezelite
38 }
39
40 sha512sums="93d7695abb0bf670590cef73c2d9d484771e63acca39864b60cd819bf4b42fff87f9a82f7d419acce469c493d6bedfaba1207e646dde151bc76af959874f16cd load-libtremor-first.patch
41 ff552fcbbbf2b2291958fa1c61057f54ba0d9b19620666036dd1e19897b5d7bcc543c40699c3ee53b2eec7a38b9cf46cb9205c2048f7d5488c23085d9904f114 squeezelite.confd
42 fdc0358c10c56772d5e70178eac88f62729c22965c530ad989ebcc8aa4af8c871085bdeb8b4ccd96d8cf2e87388258180054d908719f81f2745d97654f6d60eb squeezelite.initd"
0 # Maintainer: Ralph Irving <ralph.irving@gmail.com>
1 pkgname=libalac
2 pkgver=1.0.0
3 pkgrel=1
4 pkgdesc="Apple Lossless Audio Codec (ALAC) library"
5 url="https://github.com/TimothyGu/alac"
6 arch="all"
7 subpackages="$pkgname-doc $pkgname-dev"
8 license="Apache 2.0"
9 makedepends="git autoconf automake make tar"
10 source="fix-arm-segfault.patch \
11 alac-version.patch"
12
13 prepare() {
14 cd "$builddir/../"
15
16 git clone $url $pkgname-$pkgver
17
18 cd $pkgname-$pkgver
19
20 for patchfile in $source; do
21 patch -p1 -i ../$patchfile
22 done
23 }
24
25 build() {
26 cd "$builddir"
27 autoreconf -if
28 ./configure \
29 --build=$CBUILD \
30 --host=$CHOST \
31 --prefix=/usr
32
33 make -j1
34 }
35
36 check() {
37 cd "$builddir"
38 make check
39 }
40
41 package() {
42 cd "$builddir"
43 make DESTDIR="$pkgdir" install
44 install -Dm644 LICENSE "$pkgdir"/usr/share/licenses/$pkgname/COPYING
45 }
46
47 sha512sums="e72b13714476170108844b84c0043dc06d2ff2e8c9b651a7ad1571d148fc5567aca48048646d16fb82630d6972a31b9328f04e522972b297d1cf8e804785867f fix-arm-segfault.patch
48 093379f79b5dc9f5b8aa45826d61738b088d78305a7d514df33851ae34d02ee9034a8ecddf2558fcb1bf4daaf64c620ea4411521908cfc748e31fd0a2d50bbf7 alac-version.patch"
0 --- libalac-1.0.0/configure.ac.orig 2020-09-06 10:55:00.450562777 -0400
1 +++ libalac-1.0.0/configure.ac 2020-09-06 10:56:39.308930134 -0400
2 @@ -14,7 +14,7 @@
3 dnl See the License for the specific language governing permissions and
4 dnl limitations under the License.
5
6 -AC_INIT([alac], [0.0r4+tg1], [nobody])
7 +AC_INIT([alac], [1.0.0], [nobody])
8 AC_CONFIG_AUX_DIR(.)
9 AC_CONFIG_MACRO_DIR([m4])
10 AM_INIT_AUTOMAKE([tar-ustar foreign])
0 diff --git a/codec/EndianPortable.c b/codec/EndianPortable.c
1 index 5a7d5b8..b8423c9 100644
2 --- a/codec/EndianPortable.c
3 +++ b/codec/EndianPortable.c
4 @@ -40,6 +40,8 @@
5 #define TARGET_RT_LITTLE_ENDIAN 1
6 #elif defined (TARGET_OS_WIN32)
7 #define TARGET_RT_LITTLE_ENDIAN 1
8 +#elif defined (__arm__) || defined(__aarch64__)
9 +#define TARGET_RT_LITTLE_ENDIAN 1
10 #endif
11
12 uint16_t Swap16NtoB(uint16_t inUInt16)
0 # Maintainer: Ralph Irving <ralph.irving@gmail.com>
1 pkgname=libtremor
2 pkgver=0.19681
3 pkgrel=0
4 pkgdesc="Fixed Point Ogg Vorbis compliant software decoder library"
5 url="https://svn.xiph.org/trunk/Tremor"
6 arch="all"
7 license="GPL-3.0-only"
8 subpackages="$pkgname-doc $pkgname-dev"
9 makedepends="libogg-dev subversion autoconf automake"
10 depends="libogg"
11 options="!check"
12
13 build() {
14 cd "$builddir/../"
15
16 svn checkout https://svn.xiph.org/trunk/Tremor $pkgname-$pkgver
17
18 cd $pkgname-$pkgver
19
20 # Patch for error:
21 # ./configure: line 9215: syntax error near unexpected token `,'
22 # ./configure: line 9215: ` XIPH_PATH_OGG(, as_fn_error $? "must have Ogg installed!" "$LINENO" 5)'
23 sed -i "s/\(XIPH_PATH_OGG(, AC_MSG_ERROR(must have Ogg installed!))\)/#\1/" configure.in
24
25 ./autogen.sh \
26 --build=$CBUILD \
27 --host=$CHOST \
28 --prefix=/usr \
29 --enable-static=no
30
31 make
32 }
33
34 package() {
35 cd "$builddir"
36
37 make DESTDIR="$pkgdir" install
38 install -Dm644 COPYING "$pkgdir"/usr/share/licenses/$pkgname/COPYING
39 }
0 Index: vorbis.c
1 ===================================================================
2 --- squeezelite/vorbis.c (revision 1213)
3 +++ squeezelite/vorbis.c (working copy)
4 @@ -320,14 +320,14 @@
5
6 static bool load_vorbis() {
7 #if !LINKALL
8 - void *handle = dlopen(LIBVORBIS, RTLD_NOW);
9 + void *handle = dlopen(LIBTREMOR, RTLD_NOW);
10 char *err;
11 - bool tremor = false;
12 + bool tremor = true;
13
14 if (!handle) {
15 - handle = dlopen(LIBTREMOR, RTLD_NOW);
16 + handle = dlopen(LIBVORBIS, RTLD_NOW);
17 if (handle) {
18 - tremor = true;
19 + tremor = false;
20 } else {
21 LOG_INFO("dlerror: %s", dlerror());
22 return false;
0 # Copyright 1999-2017 Gentoo Foundation
1 # Distributed under the terms of the GNU General Public License v2
2
3 # Configuration for /etc/init.d/squeezelite
4
5 # IP address of Logitech Media Server; leave this blank to try to
6 # locate the server via auto-discovery.
7 # If you fill this in then include "-s" before the IP address, eg:
8 # SL_SERVER_IP="-s 1.2.3.4"
9 SL_SERVERIP=""
10
11 # User that Squeezelite should run as. The dedicated 'squeezelite'
12 # user is preferred to avoid running with high privilege. This user
13 # should be a member of the 'audio' group to allow access to the audio
14 # hardware. Running as the 'root' user allows the sound output thread
15 # to run at a very high priority -- this can help avoid gaps in
16 # playback, but could be a potential security problem if there are
17 # exploitable vulnerabilities in Squeezelite.
18 SL_USER=squeezelite
19
20 # Any other switches to pass to Squeezelite. See 'squeezelite -h' for
21 # a description of all possible switches.
22
23 # Example setting:
24 # 1. the ALSA output device
25 # 2. the player name
26 # 3. turning on visualiser support (-v)
27 #
28 # SL_OPTS="-o sysdefault -n $HOSTNAME -v"
29 #
30 SL_OPTS=""
0 #!/sbin/openrc-run
1 # Copyright 1999-2015 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
3
4 depend() {
5 need net
6 use alsasound
7 after bootmisc
8 }
9
10 start() {
11 ebegin "Starting squeezelite"
12 start-stop-daemon \
13 --start \
14 --exec /usr/bin/squeezelite \
15 --pidfile /run/squeezelite.pid \
16 --make-pidfile \
17 --user ${SL_USER} \
18 --background \
19 -- ${SL_OPTS} ${SL_SERVERIP}
20 eend $?
21 }
22
23 stop() {
24 ebegin "Stopping squeezelite"
25 start-stop-daemon \
26 --stop \
27 --exec /usr/bin/squeezelite \
28 --pidfile /run/squeezelite.pid
29 eend $?
30 }
0 #!/bin/sh
1
2 adduser -S -D -H -h /dev/null -s /sbin/nologin -G audio -g squeezelite squeezelite 2>/dev/null
3
4 exit 0
11 * Squeezelite - lightweight headless squeezebox emulator
22 *
33 * (c) Adrian Smith 2012-2015, triode1@btinternet.com
4 * Ralph Irving 2015-2017, ralph_irving@hotmail.com
45 *
56 * This program is free software: you can redistribute it and/or modify
67 * it under the terms of the GNU General Public License as published by
9293 buf->base_size = size;
9394 }
9495
96 void _buf_unwrap(struct buffer *buf, size_t cont) {
97 ssize_t len, by = cont - (buf->wrap - buf->readp);
98 size_t size;
99 u8_t *scratch;
100
101 // do nothing if we have enough space
102 if (by <= 0 || cont >= buf->size) return;
103
104 // buffer already unwrapped, just move it up
105 if (buf->writep >= buf->readp) {
106 memmove(buf->readp - by, buf->readp, buf->writep - buf->readp);
107 buf->readp -= by;
108 buf->writep -= by;
109 return;
110 }
111
112 // how much is overlapping
113 size = by - (buf->readp - buf->writep);
114 len = buf->writep - buf->buf;
115
116 // buffer is wrapped and enough free space to move data up directly
117 if (size <= 0) {
118 memmove(buf->readp - by, buf->readp, buf->wrap - buf->readp);
119 buf->readp -= by;
120 memcpy(buf->wrap - by, buf->buf, min(len, by));
121 if (len > by) {
122 memmove(buf->buf, buf->buf + by, len - by);
123 buf->writep -= by;
124 } else buf->writep += buf->size - by;
125 return;
126 }
127
128 scratch = malloc(size);
129
130 // buffer is wrapped but not enough free room => use scratch zone
131 if (scratch) {
132 memcpy(scratch, buf->writep - size, size);
133 memmove(buf->readp - by, buf->readp, buf->wrap - buf->readp);
134 buf->readp -= by;
135 memcpy(buf->wrap - by, buf->buf, by);
136 memmove(buf->buf, buf->buf + by, len - by - size);
137 buf->writep -= by;
138 memcpy(buf->writep - size, scratch, size);
139 free(scratch);
140 } else {
141 _buf_unwrap(buf, cont / 2);
142 _buf_unwrap(buf, cont - cont / 2);
143 }
144 }
145
95146 void buf_init(struct buffer *buf, size_t size) {
96147 buf->buf = malloc(size);
97148 buf->readp = buf->buf;
0 /*
1 * Copyright (c) 2013 Ralph Irving
2 *
3 * daemonize.c is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * daemonize.c is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with SlimProtoLib; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
17
18 #include "squeezelite.h"
19
20 #include <syslog.h>
21 #include <sys/stat.h>
22
23 void fork_child_handler(int signum)
24 {
25 switch(signum) {
26 case SIGALRM: exit(EXIT_FAILURE); break;
27 case SIGUSR1: exit(EXIT_SUCCESS); break;
28 case SIGCHLD: exit(EXIT_FAILURE); break;
29 }
30 }
31
32 pid_t parent;
33 void init_daemonize()
34 {
35 pid_t pid, sid;
36
37 /* already a daemon */
38 if ( getppid() == 1 ) return;
39
40 /* Trap signals that we expect to recieve */
41 signal(SIGCHLD,fork_child_handler);
42 signal(SIGUSR1,fork_child_handler);
43 signal(SIGALRM,fork_child_handler);
44
45 /* Fork off the parent process */
46 pid = fork();
47 if (pid < 0) {
48 syslog( LOG_ERR, "unable to fork daemon, code=%d (%s)",
49 errno, strerror(errno) );
50 exit(EXIT_FAILURE);
51 }
52
53 /* If we got a good PID, then we can exit the parent process. */
54 if (pid > 0) {
55
56 /* Wait for confirmation from the child via SIGTERM or SIGCHLD, or
57 for two seconds to elapse (SIGALRM). pause() should not return. */
58 alarm(2);
59 pause();
60
61 exit(EXIT_FAILURE);
62 }
63
64 /* At this point we are executing as the child process */
65 parent = getppid();
66
67 /* Cancel certain signals */
68 signal(SIGCHLD,SIG_DFL); /* A child process dies */
69 signal(SIGTSTP,SIG_IGN); /* Various TTY signals */
70 signal(SIGTTOU,SIG_IGN);
71 signal(SIGTTIN,SIG_IGN);
72 signal(SIGHUP, SIG_IGN); /* Ignore hangup signal */
73 signal(SIGTERM,SIG_DFL); /* Die on SIGTERM */
74
75 /* Change the file mode mask */
76 umask(0);
77
78 /* Create a new SID for the child process */
79 sid = setsid();
80 if (sid < 0) {
81 syslog( LOG_ERR, "unable to create a new session, code %d (%s)",
82 errno, strerror(errno) );
83 exit(EXIT_FAILURE);
84 }
85
86 /* Change the current working directory. This prevents the current
87 directory from being locked; hence not being able to remove it. */
88 if ((chdir("/")) < 0) {
89 syslog( LOG_ERR, "unable to change directory to %s, code %d (%s)",
90 "/", errno, strerror(errno) );
91 exit(EXIT_FAILURE);
92 }
93 }
94
95 int daemon( int nochdir, int noclose ) {
96
97 if ( ! noclose )
98 {
99 /* Redirect standard files to /dev/null */
100 freopen( "/dev/null", "r", stdin);
101 freopen( "/dev/null", "w", stdout);
102 freopen( "/dev/null", "w", stderr);
103 }
104
105 /* Tell the parent process that we are A-okay */
106 kill( parent, SIGUSR1 );
107
108 return 0;
109 }
11 * Squeezelite - lightweight headless squeezebox emulator
22 *
33 * (c) Adrian Smith 2012-2015, triode1@btinternet.com
4 * Ralph Irving 2015-2017, ralph_irving@hotmail.com
45 *
56 * This program is free software: you can redistribute it and/or modify
67 * it under the terms of the GNU General Public License as published by
118119 return 0;
119120 }
120121
122 static void sort_codecs(int pry, struct codec* ptr) {
123 static int priority[MAX_CODECS];
124 int i, tpry;
125 struct codec* tptr;
126
127 for (i = 0; i < MAX_CODECS; i++) {
128 if (!codecs[i]) {
129 codecs[i] = ptr;
130 priority[i] = pry;
131 return;
132 }
133 if (pry < priority[i]) {
134 tptr = codecs[i];
135 codecs[i] = ptr;
136 ptr = tptr;
137 tpry = priority[i];
138 priority[i] = pry;
139 pry = tpry;
140 }
141 }
142 }
143
121144 static thread_type thread;
122145
123146 void decode_init(log_level level, const char *include_codecs, const char *exclude_codecs) {
124147 int i;
148 char* order_codecs;
125149
126150 loglevel = level;
127151
128 LOG_INFO("init decode, include codecs: %s exclude codecs: %s", include_codecs ? include_codecs : "", exclude_codecs);
152 LOG_INFO("init decode");
129153
130154 // register codecs
131155 // dsf,dff,alc,wma,wmap,wmal,aac,spt,ogg,ogf,flc,aif,pcm,mp3
132156 i = 0;
133157 #if DSD
134 if (!strstr(exclude_codecs, "dsd") && (!include_codecs || strstr(include_codecs, "dsd"))) codecs[i++] = register_dsd();
135 #endif
136 #if FFMPEG
137 if (!strstr(exclude_codecs, "alac") && (!include_codecs || strstr(include_codecs, "alac"))) codecs[i++] = register_ff("alc");
138 if (!strstr(exclude_codecs, "wma") && (!include_codecs || strstr(include_codecs, "wma"))) codecs[i++] = register_ff("wma");
139 #endif
140 if (!strstr(exclude_codecs, "aac") && (!include_codecs || strstr(include_codecs, "aac"))) codecs[i++] = register_faad();
141 if (!strstr(exclude_codecs, "ogg") && (!include_codecs || strstr(include_codecs, "ogg"))) codecs[i++] = register_vorbis();
142 if (!strstr(exclude_codecs, "flac") && (!include_codecs || strstr(include_codecs, "flac"))) codecs[i++] = register_flac();
143 if (!strstr(exclude_codecs, "pcm") && (!include_codecs || strstr(include_codecs, "pcm"))) codecs[i++] = register_pcm();
158 if (!strstr(exclude_codecs, "dsd") && (!include_codecs || (order_codecs = strstr(include_codecs, "dsd"))))
159 sort_codecs((include_codecs ? order_codecs - include_codecs : i), register_dsd());
160 #endif
161 #if ALAC
162 if (!strstr(exclude_codecs, "alac") && (!include_codecs || (order_codecs = strstr(include_codecs, "alac"))))
163 sort_codecs((include_codecs ? order_codecs - include_codecs : i), register_alac());
164 #elif FFMPEG
165 if (!strstr(exclude_codecs, "alac") && (!include_codecs || (order_codecs = strstr(include_codecs, "alac"))))
166 sort_codecs((include_codecs ? order_codecs - include_codecs : i), register_ff("alc"));
167 if (!strstr(exclude_codecs, "wma") && (!include_codecs || (order_codecs = strstr(include_codecs, "wma"))))
168 sort_codecs((include_codecs ? order_codecs - include_codecs : i), register_ff("wma"));
169 #endif
170 #ifndef NO_FAAD
171 if (!strstr(exclude_codecs, "aac") && (!include_codecs || (order_codecs = strstr(include_codecs, "aac"))))
172 sort_codecs((include_codecs ? order_codecs - include_codecs : i), register_faad());
173 #endif
174 if (!strstr(exclude_codecs, "ogg") && (!include_codecs || (order_codecs = strstr(include_codecs, "ogg"))))
175 sort_codecs((include_codecs ? order_codecs - include_codecs : i), register_vorbis());
176 #if OPUS
177 if (!strstr(exclude_codecs, "ops") && (!include_codecs || (order_codecs = strstr(include_codecs, "ops"))))
178 sort_codecs((include_codecs ? order_codecs - include_codecs : i), register_opus());
179 #endif
180 if (!strstr(exclude_codecs, "flac") && (!include_codecs || (order_codecs = strstr(include_codecs, "flac"))))
181 sort_codecs((include_codecs ? order_codecs - include_codecs : i), register_flac());
182 if (!strstr(exclude_codecs, "pcm") && (!include_codecs || (order_codecs = strstr(include_codecs, "pcm"))))
183 sort_codecs((include_codecs ? order_codecs - include_codecs : i), register_pcm());
144184
145185 // try mad then mpg for mp3 unless command line option passed
146186 if (!(strstr(exclude_codecs, "mp3") || strstr(exclude_codecs, "mad")) &&
147 (!include_codecs || strstr(include_codecs, "mp3") || strstr(include_codecs, "mad"))) codecs[i] = register_mad();
148 if (!(strstr(exclude_codecs, "mp3") || strstr(exclude_codecs, "mpg")) && !codecs[i] &&
149 (!include_codecs || strstr(include_codecs, "mp3") || strstr(include_codecs, "mpg"))) codecs[i] = register_mpg();
187 (!include_codecs || (order_codecs = strstr(include_codecs, "mp3")) || (order_codecs = strstr(include_codecs, "mad"))))
188 sort_codecs((include_codecs ? order_codecs - include_codecs : i), register_mad());
189 else if (!(strstr(exclude_codecs, "mp3") || strstr(exclude_codecs, "mpg")) &&
190 (!include_codecs || (order_codecs = strstr(include_codecs, "mp3")) || (order_codecs = strstr(include_codecs, "mpg"))))
191 sort_codecs((include_codecs ? order_codecs - include_codecs : i), register_mpg());
192
193 LOG_DEBUG("include codecs: %s exclude codecs: %s", include_codecs ? include_codecs : "", exclude_codecs);
150194
151195 mutex_create(decode.mutex);
152196
153197 #if LINUX || OSX || FREEBSD
154198 pthread_attr_t attr;
155199 pthread_attr_init(&attr);
200 #ifdef PTHREAD_STACK_MIN
156201 pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN + DECODE_THREAD_STACK_SIZE);
202 #endif
157203 pthread_create(&thread, &attr, decode_thread, NULL);
158204 pthread_attr_destroy(&attr);
159205 #endif
0 .\" Hey, EMACS: -*- nroff -*-
1 .\" (C) Copyright 2013-4 Chris Boot <bootc@debian.org>
2 .\"
3 .\" First parameter, NAME, should be all caps
4 .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
5 .\" other parameters are allowed: see man(7), man(1)
6 .TH SQUEEZELITE 1 "2020-07-16" "Debian Project"
7 .\" Please adjust this date whenever revising the manpage.
8 .\"
9 .\" Some roff macros, for reference:
10 .\" .nh disable hyphenation
11 .\" .hy enable hyphenation
12 .\" .ad l left justify
13 .\" .ad b justify to both left and right margins
14 .\" .nf disable filling
15 .\" .fi enable filling
16 .\" .br insert line break
17 .\" .sp <n> insert n+1 empty lines
18 .\" for manpage-specific macros, see man(7)
19 .SH NAME
20 squeezelite \- Lightweight headless Squeezebox emulator
21 .SH SYNOPSIS
22 .B squeezelite
23 .RI [ options ]
24 .SH DESCRIPTION
25 .B Squeezelite
26 is a small headless Logitech Squeezebox emulator. It is aimed at supporting high
27 quality audio including USB DAC based output at multiple sample rates.
28 .PP
29 The player is controlled using, and media is streamed from, a Logitech Media
30 Server instance running somewhere on the local network.
31 .SH OPTIONS
32 This program supports the following options:
33 .TP
34 .B \-?
35 Show a summary of the available command-line options.
36 .TP
37 .B \-s <server>[:<port>]
38 Connect to the specified Logitech Media Server, otherwise uses automatic
39 discovery to find server on the local network. This option should only be needed
40 if automatic discovery does not work, or the server is not on the local network
41 segment (e.g. behind a router).
42 .TP
43 .B \-o <output device>
44 Specify the audio output device; the default value is
45 .IR default .
46 Use the
47 .B \-l
48 option to list available output devices.
49 .I -
50 can be used to output raw samples to standard output.
51 .TP
52 .B \-l
53 List available audio output devices to stdout and exit. These device names can
54 be passed to the
55 .B \-o
56 option in order to select a particular device or configuration to use for audio
57 playback.
58 .TP
59 .B \-a <params>
60 Specify parameters used when opening an audio output device.
61 .PP
62 .RS
63 For ALSA, the format
64 .B <b>:<p>:<f>:<m>:<d>
65 is used where
66 .B <b>
67 is the buffer time in milliseconds (values less than 500) or size in bytes (default
68 .IR 40 ms);
69 .B <p>
70 is the period count (values less than 50) or size in bytes (default
71 .IR 4 " periods);"
72 .B <f>
73 is the sample format (possible values:
74 .IR 16 ", " 24 ", " 24_3 " or " 32 );
75 .B <m>
76 is whether to use mmap (possible values:
77 .IR 0 " or " 1 ).
78 .B <d>
79 open ALSA output device twice. (possible values:
80 .IR 0 " or " 1 ).
81 .RE
82 .RS
83 .PP
84 For Linux PortAudio, the value
85 .B <l>
86 is simply the target latency in milliseconds.
87 .RE
88 .RS
89 .PP
90 For MacOS,
91 .B <l>:<r>
92 .B <l>
93 is target latency in milliseconds.
94 .B <r>
95 open device in Pro Mode or Play Nice (respective values:
96 .IR 0 " or " 1 ).
97 .RE
98 .RS
99 .PP
100 For Windows,
101 .B <l>:<e>
102 .B <l>
103 is target latency in milliseconds.
104 .B <e>
105 use exclusive mode for WASAPI (possible values:
106 .IR 0 " or " 1 ).
107 .RE
108 .RS
109 .PP
110 When the output is sent to standard output, the value can be
111 .IR 16 ", " 24 " or " 32 ,
112 which denotes the sample size in bits. Little Endian only.
113 .RE
114 .TP
115 .B \-b <stream>:<output>
116 Specify internal stream and output buffer sizes in kilobytes. Default is 2048:3446.
117 .TP
118 .B \-c <codec1>,...
119 Restrict codecs to those specified, otherwise load all available codecs. Use
120 .B squeezelite -?
121 to obtain the list of codecs built into \fBsqueezelite\fR.
122 .TP
123 .B \-C <timeout>
124 Close the output device after
125 .B <timeout>
126 seconds of the player being idle; the default is to always keep the device open
127 as long as the payer is "on".
128 .TP
129 .B \-d <category>=<level>
130 Set logging level. Categories are:
131 .IR all ", " slimproto ", " stream ", " decode ", " output " or " ir .
132 Levels can be:
133 .IR info ", " debug " or " sdebug .
134 The option can be repeated to set different log levels for different categories.
135 .TP
136 .B \-e <codec1>,...
137 Explicitly exclude native support of one or more codecs. See also
138 .BR \-c ,
139 above.
140 .TP
141 .B \-f <logfile>
142 Send logging output to a log file instead of standard output or standard error.
143 .TP
144 .B \-G <Rpi GPIO#>:<H/L>
145 Specify the BCM GPIO# to use for Amp Power Relay and if the output
146 should be Active High or Low. This cannot be used with the \fB-S\fR option.
147 .TP
148 .B \-i [<filename>]
149 Enable LIRC remote control support. If the optional
150 .B <filename>
151 is not provided,
152 .I ~/.lircrc
153 is used instead.
154 .TP
155 .B \-m <mac addr>
156 Override the player's MAC address. The format must be colon-delimited
157 hexadecimal, for example: ab:cd:ef:12:34:56. This is usually automatically
158 detected, and should not need to be provided in most circumstances.
159 .TP
160 .B \-M <modelname>
161 Override the player's hardware model name. The default value is
162 .IR SqueezeLite .
163 .TP
164 .B \-n <name>
165 Set the player name. This name is used by the Logitech Media Server to refer to
166 the player by name. This option is mututally exclusive with
167 .BR \-N .
168 .TP
169 .B \-N <filename>
170 Allow the server to set the player's name. The player name is stored in the file
171 pointed to by
172 .B <filename>
173 so that it can persist between restarts. This option is mututally exclusive with
174 .BR \-n .
175 .TP
176 .B \-O <mixer device>
177 Specify mixer device, defaults to \fB<output device>\fR.
178 \.
179 .TP
180 .B \-p <priority>
181 Set real time priority of output thread (1-99; default
182 .IR 45 ).
183 Not applicable when using PortAudio.
184 .TP
185 .B \-P <filename>
186 Write the process ID (PID) number to the given
187 .BR <filename> .
188 This may be useful when running \fBsqueezelite\fR as a daemon.
189 .TP
190 .B \-r <rates>[:<delay>]
191 Specify sample rates supported by the output device; this is required if the
192 output device is switched off when \fBsqueezelite\fR is started. The format is
193 either a single maximum sample rate, a range of sample rates in the format
194 .IR <min> - <max> ,
195 or a comma-separated list of available rates. Delay is an optional time to wait
196 when switching sample rates between tracks, in milliseconds.
197 .TP
198 .B \-S <power script>
199 Absolute path to script to launch on power commands from LMS. This
200 cannot be used with the \fB-G\fR option.
201 .TP
202 .B \-u|-R [params]
203 Enable upsampling of played audio. The argument is optional; see
204 .B RESAMPLING
205 (below) for more information. The options
206 .BR -u " and " -R
207 are synonymous.
208 .TP
209 .B \-D [delay]
210 Output device supports DSD over PCM (DoP). DSD streams will be converted to DoP
211 before output. If this option is not supplied, DSD streams will be converted to
212 PCM and resampled, so they can be played on a PCM DAC. Delay is an optional time
213 to wait when switching between PCM and DoP between tracks, in milliseconds.
214 .TP
215 .B \-v
216 Enable visualiser support. This creates a shared memory segment that contains
217 some of the audio being played, so that an external visualiser can read and
218 process this to create visualisations.
219 .TP
220 .B \-W
221 Read wave and aiff format from header, ignoring server parameters.
222 .TP
223 .B \-L
224 List available volume controls for the output device. Only applicable when
225 using ALSA output.
226 .TP
227 .B \-U <control>
228 Unmute the given ALSA
229 .B <control>
230 at daemon startup and set it to full volume. Use software volume adjustment for
231 playback. This option is mutually exclusive with the \fB\-V\fR option. Only
232 applicable when using ALSA output.
233 .TP
234 .B \-V <control>
235 Use the given ALSA
236 .B <control>
237 for volume adjustment during playback. This prevents the use of software volume
238 control within \fBsqueezelite\fR. This option is mutually exclusive with the
239 \fB\-U\fR option. If neither \fB\-U\fR nor \fB\-V\fR options are provided,
240 no ALSA controls are adjusted while running \fBsqueezelite\fR and software
241 volume control is used instead. Only applicable when using ALSA output.
242 .TP
243 .B \-X
244 Use linear volume adjustments instead of in terms of dB (only for
245 hardware volume control).
246 .TP
247 .B \-z
248 Cause \fBsqueezelite\fR to run as a daemon. That is, it detaches itself from the
249 terminal and runs in the background.
250 .TP
251 .B \-Z <rate>
252 Report rate to server in helo as the maximum sample rate we can support.
253 .TP
254 .B \-t
255 Display version and license information.
256 .SH RESAMPLING
257 Audio can be resampled or upsampled before being sent to the output device. This
258 can be enabled simply by passing the \fB\-u\fR option to \fBsqueezelite\fR, but
259 further configuration can be given as an argument to the option.
260 .PP
261 Resampling is performed using the SoX Resampler library; the documentation for
262 that library and the SoX \fIrate\fR effect many be helpful when configuring
263 upsampling for \fBsqueezelite\fR.
264 .PP
265 The format of the argument is
266 .B <recipe>:<flags>:<attenuation>:<precision>:<passband_end>:<stopband_start>:<phase_response>
267 .SS recipe
268 This part of the argument string is made up of a number of single-character
269 flags: \fB[v|h|m|l|q][L|I|M][s][E|X]\fR. The default value is \fBhL\fR.
270 .TP
271 .IR v ", " h ", " m ", " l " or " q
272 are mutually exclusive and correspond to very high, high, medium, low or quick
273 quality.
274 .TP
275 .IR L ", " I " or " M
276 correspond to linear, intermediate or minimum phase.
277 .TP
278 .IR s
279 changes resampling bandwidth from the default 95% (based on the 3dB point) to
280 99%.
281 .TP
282 .IR E
283 exception - avoids resampling if the output device supports the playback sample
284 rate natively.
285 .TP
286 .IR X
287 resamples to the maximum sample rate for the output device ("asynchronous"
288 resampling).
289 .TP
290 .B Examples
291 .B \-u vLs
292 would use very high quality setting, linear phase filter and steep cut-off.
293 .br
294 .B \-u hM
295 would specify high quality, with the minimum phase filter.
296 .br
297 .B \-u hMX
298 would specify high quality, with the minimum phase filter and async upsampling
299 to max device rate.
300 .SS flags
301 The second optional argument to \fB\-u\fR allows the user to specify the
302 following arguments (taken from the \fIsoxr.h\fR header file), in hex:
303 .sp
304 #define SOXR_ROLLOFF_SMALL 0u /* <= 0.01 dB */
305 .br
306 #define SOXR_ROLLOFF_MEDIUM 1u /* <= 0.35 dB */
307 .br
308 #define SOXR_ROLLOFF_NONE 2u /* For Chebyshev bandwidth. */
309 .sp
310 #define SOXR_MAINTAIN_3DB_PT 4u /* Reserved for internal use. */
311 .br
312 #define SOXR_HI_PREC_CLOCK 8u /* Increase 'irrational' ratio accuracy. */
313 .br
314 #define SOXR_DOUBLE_PRECISION 16u /* Use D.P. calcs even if precision <= 20. */
315 .br
316 #define SOXR_VR 32u /* Experimental, variable-rate resampling. */
317 .TP
318 .B Examples
319 .B \-u :2
320 would specify \fBSOXR_ROLLOFF_NONE\fR.
321 .sp
322 \fBNB:\fR In the example above the first option, \fB<quality>\fR, has not been
323 specified so would default to \fBhL\fR. Therefore, specifying \fB\-u :2\fR is
324 equivalent to having specified \fB\-u hL:2\fR.
325 .SS attenuation
326 Internally, data is passed to the SoX resample process as 32 bit integers and
327 output from the SoX resample process as 32 bit integers. Why does this matter?
328 There is the possibility that integer samples, once resampled may be clipped
329 (i.e. exceed the maximum value). By default, if you do not specify an
330 \fBattenuation\fR value, it will default to \-1db. A value of \fI0\fR on the
331 command line, i.e. \fB-u ::0\fR will disable the default \-1db attenuation being
332 applied.
333 .sp
334 \fBNB:\fR Clipped samples will be logged. Keep an eye on the log file.
335 .TP
336 .B Examples
337 .B \-u ::6
338 specifies to apply \-6db (ie. halve the volume) prior to the resampling process.
339 .SS precision
340 The internal 'bit' precision used in the re-sampling calculations (ie. quality).
341 .sp
342 \fBNB:\fR HQ = 20, VHQ = 28.
343 .TP
344 .B Examples
345 .B \-u :::28
346 specifies 28-bit precision.
347 .SS passband_end
348 A percentage value between 0 and 100, where 100 is the Nyquist frequency. The
349 default if not explicitly set is \fI91.3\fR.
350 .TP
351 .B Examples
352 .B \-u ::::98
353 specifies passband ends at 98 percent of the Nyquist frequency.
354 .SS stopband_start
355 A percentage value between 0 and 100, where 100 is the Nyquist frequency. The
356 default if not explicitly set is \fI100\fR.
357 .TP
358 .B Examples
359 .B \-u :::::100
360 specifies that the stopband starts at the Nyquist frequency.
361 .SS phase_response
362 A value between 0-100, where \fI0\fR is equivalent to the recipe \fIM\fR flag
363 for minimum phase, \fI25\fR is equivalent to the recipe \fII\fR flag for
364 intermediate phase and \fI50\fR is equivalent to the recipe \fIL\fR flag for
365 linear phase.
366 .TP
367 .B Examples
368 .B \-u ::::::50
369 specifies linear phase.
370 .SH SEE ALSO
371 .TP
372 http://wiki.slimdevices.com/index.php/Squeezelite
373 .TP
374 http://wiki.slimdevices.com/index.php/Logitech_Media_Server
375 .TP
376 sox(1)
377 for further information about resampling.
+13
-29
dop.c less more
2929 #define LOCK_O mutex_lock(outputbuf->mutex)
3030 #define UNLOCK_O mutex_unlock(outputbuf->mutex)
3131
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) {
32 // check for 32 dop marker frames to see if this is a dop stream
33 // dop is always encoded in 24 bit samples with markers 0x05 or 0xFA in MSB
34 bool is_stream_dop(u8_t *lptr, u8_t *rptr, int step, frames_t frames) {
3535 int matched = 0;
3636 u32_t next = 0;
3737
3838 while (frames--) {
39 if (((*lptr & 0x00FF0000) == 0x00050000 && (*rptr & 0x00FF0000) == 0x00050000) ||
40 ((*lptr & 0x00FF0000) == 0x00FA0000 && (*rptr & 0x00FF0000) == 0x00FA0000)) {
41 if (*lptr >> 24 == next) {
39 if ((*lptr == 0x05 && *rptr == 0x05) ||
40 (*lptr == 0xFA && *rptr == 0xFA)) {
41 if (*lptr == next) {
4242 matched++;
43 next = ( 0x05 + 0xFA ) - next;
4443 } else {
45 next = *lptr >> 24;
44 next = *lptr;
4645 matched = 1;
4746 }
47 next = ( 0x05 + 0xFA ) - next;
4848 } else {
4949 return false;
5050 }
5252 return true;
5353 }
5454
55 ++lptr; ++rptr;
55 lptr+=step; rptr+=step;
5656 }
5757 return false;
5858 }
6464 if (!invert) {
6565 while (frames--) {
6666 u32_t scaled_marker = marker << 24;
67 *ptr = (*ptr & 0x00FFFFFF) | scaled_marker;
67 *ptr = (*ptr & 0x00FFFF00) | scaled_marker;
6868 ++ptr;
69 *ptr = (*ptr & 0x00FFFFFF) | scaled_marker;
69 *ptr = (*ptr & 0x00FFFF00) | scaled_marker;
7070 ++ptr;
7171 marker = ( 0x05 + 0xFA ) - marker;
7272 }
7373 } else {
7474 while (frames--) {
7575 u32_t scaled_marker = marker << 24;
76 *ptr = ((~(*ptr)) & 0x00FFFFFF) | scaled_marker;
76 *ptr = ((~(*ptr)) & 0x00FFFF00) | scaled_marker;
7777 ++ptr;
78 *ptr = ((~(*ptr)) & 0x00FFFFFF) | scaled_marker;
78 *ptr = ((~(*ptr)) & 0x00FFFF00) | scaled_marker;
7979 ++ptr;
8080 marker = ( 0x05 + 0xFA ) - marker;
8181 }
8282 }
8383 }
8484
85 // fill silence buffer with 10101100 which represents dop silence
86 // leave marker zero it will be updated at output, leave lsb zero
87 void dop_silence_frames(u32_t *ptr, frames_t frames) {
88 while (frames--) {
89 *ptr++ = 0x00ACAC00;
90 *ptr++ = 0x00ACAC00;
91 }
92 }
93
94 void dop_init(bool enable, unsigned delay) {
95 LOCK_O;
96 output.has_dop = enable;
97 output.dop_delay = delay;
98 UNLOCK_O;
99 }
100
10185 #endif // DSD
+332
-30
dsd.c less more
11 * Squeezelite - lightweight headless squeezebox emulator
22 *
33 * (c) Adrian Smith 2012-2015, triode1@btinternet.com
4 * Ralph Irving 2015-2017, ralph_irving@hotmail.com
45 *
56 * This program is free software: you can redistribute it and/or modify
67 * it under the terms of the GNU General Public License as published by
5758
5859 #define BLOCK 4096 // expected size of dsd block
5960 #define BLOCK_FRAMES BLOCK * BYTES_PER_FRAME
60 #define WRAP_BUF_SIZE 16
61 #define WRAP_BUF_SIZE 32 // max 4 bytes per frame and 8 channels
6162
6263 typedef enum { UNKNOWN=0, DSF, DSDIFF } dsd_type;
6364
64 static bool dop = false; // local copy of output.has_dop to avoid holding output lock
65 static dsd_format outfmt = PCM; // local copy of output.dsdfmt to avoid holding output lock
6566
6667 struct dsd {
6768 dsd_type type;
210211
211212 unsigned bytes = _buf_used(streambuf);
212213 unsigned block_left = d->block_size;
213
214 unsigned bytes_per_frame = dop ? 2 : 1;
214 unsigned padding = 0;
215
216 unsigned bytes_per_frame;
217 switch (outfmt) {
218 case DSD_U32_LE:
219 case DSD_U32_BE:
220 bytes_per_frame = 4;
221 break;
222 case DSD_U16_LE:
223 case DSD_U16_BE:
224 case DOP:
225 case DOP_S24_LE:
226 case DOP_S24_3LE:
227 bytes_per_frame = 2;
228 break;
229 default:
230 bytes_per_frame = 1;
231 }
215232
216233 if (bytes < d->block_size * d->channels) {
217234 LOG_INFO("stream too short"); // this can occur when scanning the track
235252 iptrr -= streambuf->size;
236253 }
237254
255 // Remove zero padding from last block in case of inaccurate sample count
256 if ((_buf_used(streambuf) == d->block_size * d->channels)
257 && (d->sample_bytes > _buf_used(streambuf))) {
258 int i;
259 u8_t *ipl, *ipr;
260 for (i = d->block_size - 1; i > 0; i--) {
261 ipl = iptrl + i;
262 if (ipl >= streambuf->wrap) ipl -= streambuf->size;
263 ipr = iptrr + i;
264 if (ipr >= streambuf->wrap) ipr -= streambuf->size;
265 if (*ipl || *ipr) break;
266 padding++;
267 }
268 block_left -= padding;
269 }
270
238271 bytes = min(block_left, min(streambuf->wrap - iptrl, streambuf->wrap - iptrr));
239272
240273 IF_DIRECT(
248281
249282 frames = min(bytes, d->sample_bytes) / bytes_per_frame;
250283 if (frames == 0) {
251 if (dop && d->sample_bytes == 1 && bytes >= 2) {
252 // 1 byte left add a byte of silence and play
253 *(iptrl + 1) = *(iptrr + 1) = 0x69;
284 if (d->sample_bytes && bytes >= (2 * d->sample_bytes)) {
285 // byte(s) left fill frame with silence byte(s) and play
286 int i;
287 for (i = d->sample_bytes; i < bytes_per_frame; i++)
288 *(iptrl + i) = *(iptrr + i) = 0x69;
254289 frames = 1;
255290 } else {
256 // should not get here due to wrapping m/2 for dop should never result in 0 as header len is always even
291 // should not get here due to wrapping m/2 for dsd should never result in 0 as header len is always even
257292 LOG_INFO("frames got to zero");
258293 return DECODE_COMPLETE;
259294 }
265300
266301 count = frames;
267302
268 if (dop) {
303 switch (outfmt) {
304
305 case DSD_U32_LE:
306 case DSD_U32_BE:
307
308 if (d->channels == 1) {
309 if (d->lsb_first) {
310 while (count--) {
311 *(optr++) = dsd2pcm_bitreverse[*(iptrl)] << 24 | dsd2pcm_bitreverse[*(iptrl+1)] << 16
312 | dsd2pcm_bitreverse[*(iptrl+2)] << 8 | dsd2pcm_bitreverse[*(iptrl+3)];
313 *(optr++) = dsd2pcm_bitreverse[*(iptrl)] << 24 | dsd2pcm_bitreverse[*(iptrl+1)] << 16
314 | dsd2pcm_bitreverse[*(iptrl+2)] << 8 | dsd2pcm_bitreverse[*(iptrl+3)];
315 iptrl += 4;
316 }
317 } else {
318 while (count--) {
319 *(optr++) = *(iptrl) << 24 | *(iptrl+1) << 16 | *(iptrl+2) << 8 | *(iptrl+3);
320 *(optr++) = *(iptrl) << 24 | *(iptrl+1) << 16 | *(iptrl+2) << 8 | *(iptrl+3);
321 iptrl += 4;
322 }
323 }
324 } else {
325 if (d->lsb_first) {
326 while (count--) {
327 *(optr++) = dsd2pcm_bitreverse[*(iptrl)] << 24 | dsd2pcm_bitreverse[*(iptrl+1)] << 16
328 | dsd2pcm_bitreverse[*(iptrl+2)] << 8 | dsd2pcm_bitreverse[*(iptrl+3)];
329 *(optr++) = dsd2pcm_bitreverse[*(iptrr)] << 24 | dsd2pcm_bitreverse[*(iptrr+1)] << 16
330 | dsd2pcm_bitreverse[*(iptrr+2)] << 8 | dsd2pcm_bitreverse[*(iptrr+3)];
331 iptrl += 4;
332 iptrr += 4;
333 }
334 } else {
335 while (count--) {
336 *(optr++) = *(iptrl) << 24 | *(iptrl+1) << 16 | *(iptrl+2) << 8 | *(iptrl+3);
337 *(optr++) = *(iptrr) << 24 | *(iptrr+1) << 16 | *(iptrr+2) << 8 | *(iptrr+3);
338 iptrl += 4;
339 iptrr += 4;
340 }
341 }
342 }
343
344 break;
345
346 case DSD_U16_LE:
347 case DSD_U16_BE:
348
349 if (d->channels == 1) {
350 if (d->lsb_first) {
351 while (count--) {
352 *(optr++) = dsd2pcm_bitreverse[*(iptrl)] << 24 | dsd2pcm_bitreverse[*(iptrl+1)] << 16;
353 *(optr++) = dsd2pcm_bitreverse[*(iptrl)] << 24 | dsd2pcm_bitreverse[*(iptrl+1)] << 16;
354 iptrl += 2;
355 }
356 } else {
357 while (count--) {
358 *(optr++) = *(iptrl) << 24 | *(iptrl+1) << 16;
359 *(optr++) = *(iptrl) << 24 | *(iptrl+1) << 16;
360 iptrl += 2;
361 }
362 }
363 } else {
364 if (d->lsb_first) {
365 while (count--) {
366 *(optr++) = dsd2pcm_bitreverse[*(iptrl)] << 24 | dsd2pcm_bitreverse[*(iptrl+1)] << 16;
367 *(optr++) = dsd2pcm_bitreverse[*(iptrr)] << 24 | dsd2pcm_bitreverse[*(iptrr+1)] << 16;
368 iptrl += 2;
369 iptrr += 2;
370 }
371 } else {
372 while (count--) {
373 *(optr++) = *(iptrl) << 24 | *(iptrl+1) << 16;
374 *(optr++) = *(iptrr) << 24 | *(iptrr+1) << 16;
375 iptrl += 2;
376 iptrr += 2;
377 }
378 }
379 }
380
381 break;
382
383 case DSD_U8:
384
385 if (d->channels == 1) {
386 if (d->lsb_first) {
387 while (count--) {
388 *(optr++) = dsd2pcm_bitreverse[*(iptrl)] << 24;
389 *(optr++) = dsd2pcm_bitreverse[*(iptrl)] << 24;
390 iptrl += 1;
391 }
392 } else {
393 while (count--) {
394 *(optr++) = *(iptrl) << 24;
395 *(optr++) = *(iptrl) << 24;
396 iptrl += 1;
397 }
398 }
399 } else {
400 if (d->lsb_first) {
401 while (count--) {
402 *(optr++) = dsd2pcm_bitreverse[*(iptrl)] << 24;
403 *(optr++) = dsd2pcm_bitreverse[*(iptrr)] << 24;
404 iptrl += 1;
405 iptrr += 1;
406 }
407 } else {
408 while (count--) {
409 *(optr++) = *(iptrl) << 24;
410 *(optr++) = *(iptrr) << 24;
411 iptrl += 1;
412 iptrr += 1;
413 }
414 }
415 }
416
417 break;
418
419 case DOP:
420 case DOP_S24_LE:
421 case DOP_S24_3LE:
269422
270423 if (d->channels == 1) {
271424 if (d->lsb_first) {
299452 }
300453 }
301454
302 } else {
455 break;
456
457 case PCM:
303458
304459 if (d->channels == 1) {
305460 float *iptrf = d->transfer[0];
328483 }
329484 }
330485
486 break;
487
331488 }
332489
333490 _buf_inc_readp(streambuf, bytes_read);
352509 LOG_SDEBUG("write %u frames", frames);
353510 }
354511
512 if (padding) {
513 _buf_inc_readp(streambuf, padding);
514 LOG_INFO("Zero padding removed: %u bytes", padding);
515 }
516
355517 // skip the other channel blocks
356518 // the right channel has already been read and is guarenteed to be in streambuf so can be skipped immediately
357519 if (d->channels > 1) {
384546 out = process.max_in_frames;
385547 );
386548
387 if (dop) {
549 switch (outfmt) {
550 case DSD_U32_LE:
551 case DSD_U32_BE:
552 bytes_per_frame = d->channels * 4;
553 break;
554 case DSD_U16_LE:
555 case DSD_U16_BE:
556 case DOP:
557 case DOP_S24_LE:
558 case DOP_S24_3LE:
388559 bytes_per_frame = d->channels * 2;
389 } else {
560 break;
561 default:
390562 bytes_per_frame = d->channels;
391563 out = min(out, BLOCK);
392564 }
403575 optr = (u32_t *)process.inbuf;
404576 );
405577
406 // handle wrap around end of streambuf and partial dop frame at end of stream
578 // handle wrap around end of streambuf and partial dsd frame at end of stream
407579 if (!frames && bytes < bytes_per_frame) {
408580 memset(tmp, 0x69, WRAP_BUF_SIZE); // 0x69 = dsd silence
409581 memcpy(tmp, streambuf->readp, bytes);
419591
420592 count = frames;
421593
422 if (dop) {
594 switch (outfmt) {
595
596 case DSD_U32_LE:
597 case DSD_U32_BE:
598
599 if (d->channels == 1) {
600 while (count--) {
601 *(optr++) = *(iptr) << 24 | *(iptr+1) << 16 | *(iptr+2) << 8 | *(iptr+3);
602 *(optr++) = *(iptr) << 24 | *(iptr+1) << 16 | *(iptr+2) << 8 | *(iptr+3);
603 iptr += bytes_per_frame;
604 }
605 } else {
606 while (count--) {
607 *(optr++) = *(iptr ) << 24 | *(iptr + d->channels) << 16
608 | *(iptr + 2 * d->channels) << 8 | *(iptr + 3 * d->channels);
609 *(optr++) = *(iptr+1) << 24 | *(iptr + d->channels + 1) << 16
610 | *(iptr + 2 * d->channels + 1) << 8 | *(iptr + 3 * d->channels + 1);
611 iptr += bytes_per_frame;
612 }
613 }
614
615 break;
616
617 case DSD_U16_LE:
618 case DSD_U16_BE:
619
620 if (d->channels == 1) {
621 while (count--) {
622 *(optr++) = *(iptr) << 24 | *(iptr+1) << 16;
623 *(optr++) = *(iptr) << 24 | *(iptr+1) << 16;
624 iptr += bytes_per_frame;
625 }
626 } else {
627 while (count--) {
628 *(optr++) = *(iptr ) << 24 | *(iptr + d->channels) << 16;
629 *(optr++) = *(iptr+1) << 24 | *(iptr + d->channels + 1) << 16;
630 iptr += bytes_per_frame;
631 }
632 }
633
634 break;
635
636 case DSD_U8:
637
638 if (d->channels == 1) {
639 while (count--) {
640 *(optr++) = *(iptr) << 24;
641 *(optr++) = *(iptr) << 24;
642 iptr += bytes_per_frame;
643 }
644 } else {
645 while (count--) {
646 *(optr++) = *(iptr ) << 24;
647 *(optr++) = *(iptr+1) << 24;
648 iptr += bytes_per_frame;
649 }
650 }
651
652 break;
653
654 case DOP:
655 case DOP_S24_LE:
656 case DOP_S24_3LE:
423657
424658 if (d->channels == 1) {
425659 while (count--) {
435669 }
436670 }
437671
438 } else {
672 break;
673
674 case PCM:
439675
440676 if (d->channels == 1) {
441677 float *iptrf = d->transfer[0];
464700 }
465701 }
466702
703 break;
704
467705 }
468706
469707 _buf_inc_readp(streambuf, bytes_read);
490728
491729 static decode_state dsd_decode(void) {
492730 decode_state ret;
731 char *fmtstr;
732
733 fmtstr = "None";
493734
494735 LOCK_S;
495736
526767 LOG_INFO("setting track_start");
527768 output.track_start = outputbuf->writep;
528769
529 dop = output.has_dop;
530
531 if (dop && d->sample_rate / 16 > output.supported_rates[0]) {
532 LOG_INFO("DOP sample rate too high for device - converting to PCM");
533 dop = false;
534 }
535
536 if (dop) {
537 LOG_INFO("DOP output");
538 output.next_dop = true;
770 outfmt = output.dsdfmt;
771
772 switch (outfmt) {
773 case DSD_U32_LE:
774 fmtstr = "DSD_U32_LE";
775 output.next_sample_rate = d->sample_rate / 32;
776 break;
777 case DSD_U32_BE:
778 fmtstr = "DSD_U32_BE";
779 output.next_sample_rate = d->sample_rate / 32;
780 break;
781 case DSD_U16_LE:
782 fmtstr = "DSD_U16_LE";
539783 output.next_sample_rate = d->sample_rate / 16;
540 output.fade = FADE_INACTIVE;
541 } else {
784 break;
785 case DSD_U16_BE:
786 fmtstr = "DSD_U16_BE";
787 output.next_sample_rate = d->sample_rate / 16;
788 break;
789 case DSD_U8:
790 fmtstr = "DSD_U8";
791 output.next_sample_rate = d->sample_rate / 8;
792 break;
793 case DOP:
794 fmtstr = "DOP";
795 output.next_sample_rate = d->sample_rate / 16;
796 break;
797 case DOP_S24_LE:
798 fmtstr = "DOP_S24_LE";
799 output.next_sample_rate = d->sample_rate / 16;
800 break;
801 case DOP_S24_3LE:
802 fmtstr = "DOP_S24_3LE";
803 output.next_sample_rate = d->sample_rate / 16;
804 break;
805 case PCM:
806 // PCM case after DSD rate check and possible fallback to PCM conversion
807 break;
808 }
809
810 if (outfmt != PCM && output.next_sample_rate > output.supported_rates[0]) {
811 LOG_INFO("DSD sample rate too high for device - converting to PCM");
812 outfmt = PCM;
813 }
814
815 if (outfmt == PCM) {
542816 LOG_INFO("DSD to PCM output");
543 output.next_dop = false;
544817 output.next_sample_rate = decode_newstream(d->sample_rate / 8, output.supported_rates);
545818 if (output.fade_mode) _checkfade(true);
546 }
547
819 } else {
820 LOG_INFO("DSD%u stream, format: %s, rate: %uHz\n", d->sample_rate / 44100, fmtstr, output.next_sample_rate);
821 output.fade = FADE_INACTIVE;
822 }
823
824 output.next_fmt = outfmt;
548825 decode.new_stream = false;
549826
550827 UNLOCK_O;
567844 UNLOCK_S;
568845
569846 return ret;
847 }
848
849 void dsd_init(dsd_format format, unsigned delay) {
850 LOCK_O;
851 output.dsdfmt = format;
852 output.dsd_delay = delay;
853 UNLOCK_O;
570854 }
571855
572856 static void dsd_open(u8_t size, u8_t rate, u8_t chan, u8_t endianness) {
624908 return &ret;
625909 }
626910
911 // invert polarity for frames in the output buffer
912 void dsd_invert(u32_t *ptr, frames_t frames) {
913 while (frames--) {
914 *ptr = ~(*ptr);
915 ++ptr;
916 *ptr = ~(*ptr);
917 ++ptr;
918 }
919 }
920
921 // fill silence buffer with 10101100 which represents dsd silence
922 void dsd_silence_frames(u32_t *ptr, frames_t frames) {
923 while (frames--) {
924 *ptr++ = 0x69696969;
925 *ptr++ = 0x69696969;
926 }
927 }
928
627929 #endif // DSD
11 * Squeezelite - lightweight headless squeezebox emulator
22 *
33 * (c) Adrian Smith 2012-2015, triode1@btinternet.com
4 * Ralph Irving 2015-2017, ralph_irving@hotmail.com
45 *
56 * This program is free software: you can redistribute it and/or modify
67 * it under the terms of the GNU General Public License as published by
2021 #include "squeezelite.h"
2122
2223 #include <neaacdec.h>
24
25 #if BYTES_PER_FRAME == 4
26 #define ALIGN(n) (n)
27 #else
28 #define ALIGN(n) (n << 8)
29 #endif
2330
2431 #define WRAPBUF_LEN 2048
2532
301308 a->pos += bytes;
302309 a->consume = consume - bytes;
303310 break;
311 } else if (len > streambuf->size) {
312 // can't process an atom larger than streambuf!
313 LOG_ERROR("atom %s too large for buffer %u %u", type, len, streambuf->size);
314 return -1;
304315 } else {
316 // make sure there is 'len' contiguous space
317 _buf_unwrap(streambuf, len);
305318 break;
306319 }
307320 }
312325 static decode_state faad_decode(void) {
313326 size_t bytes_total;
314327 size_t bytes_wrap;
315 NeAACDecFrameInfo info;
316 s32_t *iptr;
328 static NeAACDecFrameInfo info;
329 ISAMPLE_T *iptr;
317330 bool endstream;
318331 frames_t frames;
319332
375388 LOCK_O;
376389 LOG_INFO("setting track_start");
377390 output.next_sample_rate = decode_newstream(samplerate, output.supported_rates);
378 IF_DSD( output.next_dop = false; )
391 IF_DSD( output.next_fmt = PCM; )
379392 output.track_start = outputbuf->writep;
380393 if (output.fade_mode) _checkfade(true);
381394 decode.new_stream = false;
398411 if (bytes_wrap < WRAPBUF_LEN && bytes_total > WRAPBUF_LEN) {
399412
400413 // make a local copy of frames which may have wrapped round the end of streambuf
401 u8_t buf[WRAPBUF_LEN];
414 static u8_t buf[WRAPBUF_LEN];
402415 memcpy(buf, streambuf->readp, bytes_wrap);
403416 memcpy(buf + bytes_wrap, streambuf->buf, WRAPBUF_LEN - bytes_wrap);
404417
489502 while (frames > 0) {
490503 frames_t f;
491504 frames_t count;
492 s32_t *optr;
505 ISAMPLE_T *optr;
493506
494507 IF_DIRECT(
495508 f = _buf_cont_write(outputbuf) / BYTES_PER_FRAME;
496 optr = (s32_t *)outputbuf->writep;
509 optr = (ISAMPLE_T *)outputbuf->writep;
497510 );
498511 IF_PROCESS(
499512 f = process.max_in_frames;
500 optr = (s32_t *)process.inbuf;
513 optr = (ISAMPLE_T *)process.inbuf;
501514 );
502515
503516 f = min(f, frames);
504517 count = f;
505518
506519 if (info.channels == 2) {
520 #if BYTES_PER_FRAME == 4
521 memcpy(optr, iptr, count * BYTES_PER_FRAME);
522 iptr += count * 2;
523 #else
507524 while (count--) {
508 *optr++ = *iptr++ << 8;
509 *optr++ = *iptr++ << 8;
510 }
525 *optr++ = ALIGN(*iptr++);
526 *optr++ = ALIGN(*iptr++);
527 }
528 #endif
511529 } else if (info.channels == 1) {
512530 while (count--) {
513 *optr++ = *iptr << 8;
514 *optr++ = *iptr++ << 8;
531 *optr++ = ALIGN(*iptr);
532 *optr++ = ALIGN(*iptr++);
515533 }
516534 } else {
517535 LOG_WARN("unsupported number of channels");
561579
562580 conf = NEAAC(a, GetCurrentConfiguration, a->hAac);
563581
582 #if BYTES_PER_FRAME == 4
583 conf->outputFormat = FAAD_FMT_16BIT;
584 #else
564585 conf->outputFormat = FAAD_FMT_24BIT;
586 #endif
587 conf->defSampleRate = 44100;
565588 conf->downMatrix = 1;
566589
567590 if (!NEAAC(a, SetConfiguration, a->hAac, conf)) {
11 * Squeezelite - lightweight headless squeezebox emulator
22 *
33 * (c) Adrian Smith 2012-2015, triode1@btinternet.com
4 * Ralph Irving 2015-2017, ralph_irving@hotmail.com
45 *
56 * This program is free software: you can redistribute it and/or modify
67 * it under the terms of the GNU General Public License as published by
4142 AVInputFormat *input_format;
4243 AVFormatContext *formatC;
4344 AVCodecContext *codecC;
45 AVCodecParameters *codecP;
4446 AVFrame *frame;
4547 AVPacket *avpkt;
4648 unsigned mmsh_bytes_left;
5153 unsigned (* avcodec_version)(void);
5254 AVCodec * (* avcodec_find_decoder)(int);
5355 int attribute_align_arg (* avcodec_open2)(AVCodecContext *, const AVCodec *, AVDictionary **);
56 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55,28,1)
57 AVFrame * (* av_frame_alloc)(void);
58 void (* av_frame_free)(AVFrame **);
59 #else
5460 AVFrame * (* avcodec_alloc_frame)(void);
5561 void (* avcodec_free_frame)(AVFrame **);
62 #endif
5663 int attribute_align_arg (* avcodec_decode_audio4)(AVCodecContext *, AVFrame *, int *, const AVPacket *);
64 AVCodecContext * (* avcodec_alloc_context3)(const AVCodec *);
65 void (* avcodec_free_context)(AVCodecContext **);
66 int (* avcodec_parameters_to_context)(AVCodecContext *, const AVCodecParameters *);
5767 // ffmpeg symbols to be dynamically loaded from libavformat
5868 unsigned (* avformat_version)(void);
5969 AVFormatContext * (* avformat_alloc_context)(void);
6373 AVIOContext * (* avio_alloc_context)(unsigned char *, int, int, void *,
6474 int (*read_packet)(void *, uint8_t *, int), int (*write_packet)(void *, uint8_t *, int), int64_t (*seek)(void *, int64_t, int));
6575 void (* av_init_packet)(AVPacket *);
76 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57,24,102)
77 void (* av_packet_unref)(AVPacket *);
78 #else
6679 void (* av_free_packet)(AVPacket *);
80 #endif
6781 int (* av_read_frame)(AVFormatContext *, AVPacket *);
6882 AVInputFormat * (* av_find_input_format)(const char *);
6983 void (* av_register_all)(void);
118132
119133
120134 // our own version of useful error function not included in earlier ffmpeg versions
121 static char *av__err2str(errnum) {
135 static char *av__err2str(int errnum) {
122136 static char buf[64];
123137 AV(ff, strerror, errnum, buf, 64);
124138 return buf;
156170 }
157171
158172 static int _read_data(void *opaque, u8_t *buffer, int buf_size) {
159 size_t bytes;
173 unsigned int bytes;
160174
161175 LOCK_S;
162176
263277 ff->mmsh_bytes_left = ff->mmsh_bytes_pad = ff->mmsh_packet_len = 0;
264278
265279 if (!ff->readbuf) {
266 ff->readbuf = AV(ff, malloc, READ_SIZE + FF_INPUT_BUFFER_PADDING_SIZE);
280 ff->readbuf = AV(ff, malloc, READ_SIZE + AV_INPUT_BUFFER_PADDING_SIZE);
267281 }
268282
269283 avio = AVIO(ff, alloc_context, ff->readbuf, READ_SIZE, 0, NULL, _read_data, NULL, NULL);
293307 }
294308
295309 if (ff->wma && ff->wma_playstream < ff->formatC->nb_streams) {
296 if (ff->formatC->streams[ff->wma_playstream]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
310 if (ff->formatC->streams[ff->wma_playstream]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
297311 LOG_INFO("using wma stream sent from server: %i", ff->wma_playstream);
298312 audio_stream = ff->wma_playstream;
299313 }
300314 }
301315
302316 if (audio_stream == -1) {
303 int i;
317 unsigned int i;
304318 for (i = 0; i < ff->formatC->nb_streams; ++i) {
305 if (ff->formatC->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
319 if (ff->formatC->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
306320 audio_stream = i;
307321 LOG_INFO("found stream: %i", i);
308322 break;
317331
318332 av_stream = ff->formatC->streams[audio_stream];
319333
320 ff->codecC = av_stream->codec;
321
322 codec = AVCODEC(ff, find_decoder, ff->codecC->codec_id);
334 ff->codecC = AVCODEC (ff, alloc_context3, NULL);
335 if ( ff->codecC == NULL ) {
336 LOG_ERROR("can't allocate avctx");
337 return DECODE_ERROR;
338 }
339
340 ff->codecP = av_stream->codecpar;
341
342 if ( (AVCODEC(ff, parameters_to_context, ff->codecC, ff->codecP) ) < 0) {
343 AVCODEC(ff, free_context, &ff->codecC);
344
345 LOG_ERROR("can't initialize avctx");
346 return DECODE_ERROR;
347 }
348
349 codec = AVCODEC(ff, find_decoder, ff->codecP->codec_id);
323350
324351 AVCODEC(ff, open2, ff->codecC, codec, NULL);
325352
353 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55,28,1)
354 ff->frame = AV(ff, frame_alloc);
355 #else
326356 ff->frame = AVCODEC(ff, alloc_frame);
357 #endif
327358
328359 ff->avpkt = AV(ff, malloc, sizeof(AVPacket));
329360 if (ff->avpkt == NULL) {
337368
338369 LOCK_O;
339370 LOG_INFO("setting track_start");
340 output.next_sample_rate = decode_newstream(ff->codecC->sample_rate, output.supported_rates);
341 IF_DSD( output.next_dop = false; )
371 output.next_sample_rate = decode_newstream(ff->codecP->sample_rate, output.supported_rates);
372 IF_DSD( output.next_fmt = PCM; )
342373 output.track_start = outputbuf->writep;
343374 if (output.fade_mode) _checkfade(true);
344375 decode.new_stream = false;
374405 len = AVCODEC(ff, decode_audio4, ff->codecC, ff->frame, &got_frame, &pkt_c);
375406 if (len < 0) {
376407 LOG_ERROR("avcodec_decode_audio4 error: %i %s", len, av__err2str(len));
377 return DECODE_RUNNING;
408 break; // exit loop, free the packet, and continue decoding
378409 }
379410
380411 pkt_c.data += len;
504535 }
505536 }
506537
538 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57,24,102)
539 AV(ff, packet_unref, ff->avpkt);
540 #else
507541 AV(ff, free_packet, ff->avpkt);
542 #endif
508543
509544 return DECODE_RUNNING;
510545 }
511546
512547 static void _free_ff_data(void) {
548 if (ff->codecC) {
549 AVCODEC(ff, free_context, &ff->codecC);
550 ff->codecC = NULL;
551 }
552
513553 if (ff->formatC) {
514 if (ff->formatC->pb) AV(ff, freep, &ff->formatC->pb);
554 if (ff->formatC->pb) {
555 // per ffmpeg docs, the buffer originally pointed to by ff->readbuf may be dynamically freed and reallocated behind the scenes, so this is the one that must be freed
556 // otherwise, a double free can occur (seen by valgrind), resulting in e.g. SIGILL
557 AV(ff, freep, &ff->formatC->pb->buffer);
558 ff->readbuf = NULL;
559 AV(ff, freep, &ff->formatC->pb);
560 }
561
515562 AVFORMAT(ff, free_context, ff->formatC);
516563 ff->formatC = NULL;
517564 }
519566 if (ff->frame) {
520567 // ffmpeg version dependant free function
521568 #if !LINKALL
569 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55,28,1)
570 ff->av_frame_free ? AV(ff, frame_free, &ff->frame) : AV(ff, freep, &ff->frame);
571 #else
522572 ff->avcodec_free_frame ? AVCODEC(ff, free_frame, &ff->frame) : AV(ff, freep, &ff->frame);
573 #endif
523574 #elif LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54,28,0)
575 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55,28,1)
576 AV(ff, frame_free, &ff->frame);
577 #else
524578 AVCODEC(ff, free_frame, &ff->frame);
579 #endif
525580 #else
526581 AV(ff, freep, &ff->frame);
527582 #endif
529584 }
530585
531586 if (ff->avpkt) {
587 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57,24,102)
588 AV(ff, packet_unref, ff->avpkt);
589 #else
532590 AV(ff, free_packet, ff->avpkt);
591 #endif
533592 AV(ff, freep, &ff->avpkt);
534593 ff->avpkt = NULL;
535594 }
567626
568627 static void ff_close(void) {
569628 _free_ff_data();
570
571 if (ff->readbuf) {
572 AV(ff, freep, &ff->readbuf);
573 ff->readbuf = NULL;
574 }
575629 }
576630
577631 static bool load_ff() {
606660 ff->avcodec_version = dlsym(handle_codec, "avcodec_version");
607661 ff->avcodec_find_decoder = dlsym(handle_codec, "avcodec_find_decoder");
608662 ff->avcodec_open2 = dlsym(handle_codec, "avcodec_open2");
663 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55,28,1)
664 ff->av_frame_alloc = dlsym(handle_codec, "av_frame_alloc");
665 ff->av_frame_free = dlsym(handle_codec, "av_frame_free");
666 #else
609667 ff->avcodec_alloc_frame = dlsym(handle_codec, "avcodec_alloc_frame");
610668 ff->avcodec_free_frame = dlsym(handle_codec, "avcodec_free_frame");
669 #endif
611670 ff->avcodec_decode_audio4 = dlsym(handle_codec, "avcodec_decode_audio4");
671 ff->avcodec_alloc_context3 = dlsym(handle_format, "avcodec_alloc_context3");
672 ff->avcodec_free_context = dlsym(handle_format, "avcodec_free_context");
673 ff->avcodec_parameters_to_context = dlsym(handle_format, "avcodec_parameters_to_context");
612674 ff->av_init_packet = dlsym(handle_codec, "av_init_packet");
675 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57,24,102)
676 ff->av_packet_unref = dlsym(handle_codec, "av_packet_unref");
677 #else
613678 ff->av_free_packet = dlsym(handle_codec, "av_free_packet");
679 #endif
614680
615681 if ((err = dlerror()) != NULL) {
616682 LOG_INFO("dlerror: %s", err);
703769
704770 static struct codec ret = {
705771 'w', // id
706 "wma,wmap,wmal", // types
772 "wma,wmap", // types
707773 READ_SIZE, // min read
708774 WRITE_SIZE, // min space
709775 ff_open_wma, // open
711777 ff_decode, // decode
712778 };
713779
714 LOG_INFO("using ffmpeg to decode wma,wmap,wmal");
780 LOG_INFO("using ffmpeg to decode wma,wmap");
715781 return &ret;
716782 }
717783
2121
2222 #include <FLAC/stream_decoder.h>
2323
24 #if BYTES_PER_FRAME == 4
25 #define ALIGN8(n) (n << 8)
26 #define ALIGN16(n) (n)
27 #define ALIGN24(n) (n >> 8)
28 #define ALIGN32(n) (n >> 16)
29 #else
30 #define ALIGN8(n) (n << 24)
31 #define ALIGN16(n) (n << 16)
32 #define ALIGN24(n) (n << 8)
33 #define ALIGN32(n) (n)
34 #endif
35
2436 struct flac {
2537 FLAC__StreamDecoder *decoder;
38 u8_t container;
2639 #if !LINKALL
2740 // FLAC symbols to be dynamically loaded
2841 const char **FLAC__StreamDecoderErrorStatusString;
4255 FLAC__StreamDecoderErrorCallback error_callback,
4356 void *client_data
4457 );
58 FLAC__StreamDecoderInitStatus (* FLAC__stream_decoder_init_ogg_stream)(
59 FLAC__StreamDecoder *decoder,
60 FLAC__StreamDecoderReadCallback read_callback,
61 FLAC__StreamDecoderSeekCallback seek_callback,
62 FLAC__StreamDecoderTellCallback tell_callback,
63 FLAC__StreamDecoderLengthCallback length_callback,
64 FLAC__StreamDecoderEofCallback eof_callback,
65 FLAC__StreamDecoderWriteCallback write_callback,
66 FLAC__StreamDecoderMetadataCallback metadata_callback,
67 FLAC__StreamDecoderErrorCallback error_callback,
68 void *client_data
69 );
4570 FLAC__bool (* FLAC__stream_decoder_process_single)(FLAC__StreamDecoder *decoder);
4671 FLAC__StreamDecoderState (* FLAC__stream_decoder_get_state)(const FLAC__StreamDecoder *decoder);
4772 #endif
117142 decode.new_stream = false;
118143
119144 #if DSD
120 if (output.has_dop && bits_per_sample == 24 && is_flac_dop((u32_t *)lptr, (u32_t *)rptr, frames)) {
145 #if SL_LITTLE_ENDIAN
146 #define MARKER_OFFSET 2
147 #else
148 #define MARKER_OFFSET 1
149 #endif
150 if (bits_per_sample == 24 && is_stream_dop(((u8_t *)lptr) + MARKER_OFFSET, ((u8_t *)rptr) + MARKER_OFFSET, 4, frames)) {
121151 LOG_INFO("file contains DOP");
122 output.next_dop = true;
152 if (output.dsdfmt == DOP_S24_LE || output.dsdfmt == DOP_S24_3LE)
153 output.next_fmt = output.dsdfmt;
154 else
155 output.next_fmt = DOP;
123156 output.next_sample_rate = frame->header.sample_rate;
124157 output.fade = FADE_INACTIVE;
125158 } else {
126159 output.next_sample_rate = decode_newstream(frame->header.sample_rate, output.supported_rates);
127 output.next_dop = false;
160 output.next_fmt = PCM;
128161 if (output.fade_mode) _checkfade(true);
129162 }
130163 #else
140173 while (frames > 0) {
141174 frames_t f;
142175 frames_t count;
143 s32_t *optr;
176 ISAMPLE_T *optr;
144177
145178 IF_DIRECT(
146 optr = (s32_t *)outputbuf->writep;
179 optr = (ISAMPLE_T *)outputbuf->writep;
147180 f = min(_buf_space(outputbuf), _buf_cont_write(outputbuf)) / BYTES_PER_FRAME;
148181 );
149182 IF_PROCESS(
150 optr = (s32_t *)process.inbuf;
183 optr = (ISAMPLE_T *)process.inbuf;
151184 f = process.max_in_frames;
152185 );
153186
157190
158191 if (bits_per_sample == 8) {
159192 while (count--) {
160 *optr++ = *lptr++ << 24;
161 *optr++ = *rptr++ << 24;
193 *optr++ = ALIGN8(*lptr++);
194 *optr++ = ALIGN8(*rptr++);
162195 }
163196 } else if (bits_per_sample == 16) {
164197 while (count--) {
165 *optr++ = *lptr++ << 16;
166 *optr++ = *rptr++ << 16;
198 *optr++ = ALIGN16(*lptr++);
199 *optr++ = ALIGN16(*rptr++);
167200 }
168201 } else if (bits_per_sample == 24) {
169202 while (count--) {
170 *optr++ = *lptr++ << 8;
171 *optr++ = *rptr++ << 8;
203 *optr++ = ALIGN24(*lptr++);
204 *optr++ = ALIGN24(*rptr++);
172205 }
173206 } else if (bits_per_sample == 32) {
174207 while (count--) {