Codebase list squeezelite / d406a5a
Update upstream source from tag 'upstream/1.9+git20201216.e02fa87' Update to upstream version '1.9+git20201216.e02fa87' with Debian dir 1c157845617e497b67190acda039bb0505921d41 tony mancill 3 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--) {
175 *optr++ = *lptr++;
176 *optr++ = *rptr++;
208 *optr++ = ALIGN32(*lptr++);
209 *optr++ = ALIGN32(*rptr++);
177210 }
178211 } else {
179212 LOG_ERROR("unsupported bits per sample: %u", bits_per_sample);
199232 LOG_INFO("flac error: %s", FLAC_A(f, StreamDecoderErrorStatusString)[status]);
200233 }
201234
235 static void flac_close(void) {
236 FLAC(f, stream_decoder_delete, f->decoder);
237 f->decoder = NULL;
238 }
239
202240 static void flac_open(u8_t sample_size, u8_t sample_rate, u8_t channels, u8_t endianness) {
241 if ( f->decoder && f->container != sample_size ) {
242 flac_close();
243 }
244
245 f->container = sample_size;
246
203247 if (f->decoder) {
204248 FLAC(f, stream_decoder_reset, f->decoder);
205249 } else {
206250 f->decoder = FLAC(f, stream_decoder_new);
207251 }
208 FLAC(f, stream_decoder_init_stream, f->decoder, &read_cb, NULL, NULL, NULL, NULL, &write_cb, NULL, &error_cb, NULL);
209 }
210
211 static void flac_close(void) {
212 FLAC(f, stream_decoder_delete, f->decoder);
213 f->decoder = NULL;
252
253 if ( f->container == 'o' ) {
254 LOG_INFO("ogg/flac container - using init_ogg_stream");
255 FLAC(f, stream_decoder_init_ogg_stream, f->decoder, &read_cb, NULL, NULL, NULL, NULL, &write_cb, NULL, &error_cb, NULL);
256 } else {
257 FLAC(f, stream_decoder_init_stream, f->decoder, &read_cb, NULL, NULL, NULL, NULL, &write_cb, NULL, &error_cb, NULL);
258 }
214259 }
215260
216261 static decode_state flac_decode(void) {
246291 f->FLAC__stream_decoder_reset = dlsym(handle, "FLAC__stream_decoder_reset");
247292 f->FLAC__stream_decoder_delete = dlsym(handle, "FLAC__stream_decoder_delete");
248293 f->FLAC__stream_decoder_init_stream = dlsym(handle, "FLAC__stream_decoder_init_stream");
294 f->FLAC__stream_decoder_init_ogg_stream = dlsym(handle, "FLAC__stream_decoder_init_ogg_stream");
249295 f->FLAC__stream_decoder_process_single = dlsym(handle, "FLAC__stream_decoder_process_single");
250296 f->FLAC__stream_decoder_get_state = dlsym(handle, "FLAC__stream_decoder_get_state");
251297
263309 struct codec *register_flac(void) {
264310 static struct codec ret = {
265311 'f', // id
266 "flc", // types
267 8192, // min read
268 102400, // min space
312 "ogf,flc", // types
313 16384, // min read
314 204800, // min space
269315 flac_open, // open
270316 flac_close, // close
271317 flac_decode, // decode
282328 return NULL;
283329 }
284330
285 LOG_INFO("using flac to decode flc");
331 LOG_INFO("using flac to decode ogf,flc");
286332 return &ret;
287333 }
0 /*
1 * Squeezelite - lightweight headless squeezebox emulator
2 *
3 * (c) Adrian Smith 2012-2015, triode1@btinternet.com
4 * Ralph Irving 2015-2017, ralph_irving@hotmail.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 * gpio.c (c) Paul Hermann, 2015-2017 under the same license terms
20 * -Control of Raspberry pi GPIO for amplifier power
21 * -Launch script on power status change from LMS
22 */
23
24 #if GPIO
25
26 #include "squeezelite.h"
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30
31 static int gpio_state = -1;
32 static int initialized = -1;
33 static int power_state = -1;
34
35 void relay( int state) {
36 #ifdef RPI
37 gpio_state = state;
38
39 // Set up gpio using BCM Pin #'s
40 if (initialized == -1){
41 if ( gpioInitialise() == 0 ){
42 initialized = 1;
43 }
44 }
45 if ( initialized == 1){
46 gpioSetMode (gpio_pin, PI_OUTPUT);
47 }
48
49 if(gpio_state == 1)
50 gpioWrite(gpio_pin, PI_HIGH^gpio_active_low);
51 else if(gpio_state == 0)
52 gpioWrite(gpio_pin, PI_LOW^gpio_active_low);
53 // Done!
54 #endif
55 }
56
57 char *cmdline;
58 int argloc;
59
60 void relay_script( int state) {
61 gpio_state = state;
62 int err;
63
64 // Call script with init parameter
65 if (initialized == -1){
66 int strsize = strlen(power_script);
67 cmdline = (char*) malloc(strsize+3);
68 argloc = strsize + 1;
69
70 strcpy(cmdline, power_script);
71 strcat(cmdline, " 2");
72 if ((err = system(cmdline)) != 0){
73 fprintf (stderr, "%s exit status = %d\n", cmdline, err);
74 }
75 else{
76 initialized = 1;
77 }
78 }
79
80 // Call Script to turn on or off on = 1, off = 0
81 // Checks current status to avoid calling script excessivly on track changes where alsa re-inits.
82
83 if( (gpio_state == 1) && (power_state != 1)){
84 cmdline[argloc] = '1';
85 if ((err = system(cmdline)) != 0){
86 fprintf (stderr, "%s exit status = %d\n", cmdline, err);
87 }
88 else {
89 power_state = 1;
90 }
91 }
92 else if( (gpio_state == 0) && (power_state != 0)){
93 cmdline[argloc] = '0';
94 if ((err = system(cmdline)) != 0){
95 fprintf (stderr, "%s exit status = %d\n", cmdline, err);
96 }
97 else {
98 power_state = 0;
99 }
100 }
101 // Done!
102 }
103
104 #endif // GPIO
+57
-11
ir.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
1920
2021 // ir thread - linux only
2122
23 #if IR
24
25 #include <lirc/lirc_client.h>
26
27 /* Avoid name conflicts from syslog.h inclusion in lirc client header */
28 #ifdef LOG_DEBUG
29 #undef LOG_DEBUG
30 #endif
31 #ifdef LOG_INFO
32 #undef LOG_INFO
33 #endif
34
2235 #include "squeezelite.h"
23
24 #if IR
25
26 #include <lirc/lirc_client.h>
2736
2837 #define LIRC_CLIENT_ID "squeezelite"
2938
5968 #define LIRC(h, fn, ...) (h)->lirc_##fn(__VA_ARGS__)
6069 #endif
6170
62 // cmds based on entires in Slim_Device_Remote.ir
71 // cmds based on entries in Slim_Device_Remote.ir
6372 // these may appear as config entries in .lircrc files
6473 static struct {
6574 char *cmd;
7584 { "muting", 0x7689c43b },
7685 { "power_on", 0x76898f70 },
7786 { "power_off",0x76898778 },
87 { "preset_1", 0x76898a75 },
88 { "preset_2", 0x76894ab5 },
89 { "preset_3", 0x7689ca35 },
90 { "preset_4", 0x76892ad5 },
91 { "preset_5", 0x7689aa55 },
92 { "preset_6", 0x76896a95 },
7893 { NULL, 0 },
7994 };
8095
86101 } keymap[] = {
87102 { "KEY_VOLUMEDOWN", 0x768900ff, true },
88103 { "KEY_VOLUMEUP", 0x7689807f, true },
89 { "KEY_PREVIOUS", 0x7689c03f, false },
90 { "KEY_REWIND", 0x7689c03f, false },
91 { "KEY_NEXT", 0x7689a05f, false },
92 { "KEY_FORWARD", 0x7689a05f, false },
104 { "KEY_PREVIOUS", 0x7689c03f, true },
105 { "KEY_REWIND", 0x7689c03f, true },
106 { "KEY_NEXT", 0x7689a05f, true },
107 { "KEY_FORWARD", 0x7689a05f, true },
93108 { "KEY_PAUSE", 0x768920df, true },
94109 { "KEY_PLAY", 0x768910ef, false },
95110 { "KEY_POWER", 0x768940bf, false },
96111 { "KEY_MUTE", 0x7689c43b, false },
112 { "KEY_0", 0x76899867, true },
113 { "KEY_1", 0x7689f00f, true },
114 { "KEY_2", 0x768908f7, true },
115 { "KEY_3", 0x76898877, true },
116 { "KEY_4", 0x768948b7, true },
117 { "KEY_5", 0x7689c837, true },
118 { "KEY_6", 0x768928d7, true },
119 { "KEY_7", 0x7689a857, true },
120 { "KEY_8", 0x76896897, true },
121 { "KEY_9", 0x7689e817, true },
122 { "KEY_FAVORITES", 0x768918e7, false },
123 { "KEY_FAVORITES", 0x7689e21d, false },
124 { "KEY_SEARCH", 0x768958a7, false },
125 { "KEY_SEARCH", 0x7689629d, false },
126 { "KEY_SHUFFLE", 0x7689d827, false },
127 { "KEY_SLEEP", 0x7689b847, false },
128 { "KEY_INSERT", 0x7689609f, false }, // Add
129 { "KEY_UP", 0x7689e01f, true },
130 { "KEY_LEFT", 0x7689906f, true },
131 { "KEY_RIGHT", 0x7689d02f, true },
132 { "KEY_DOWN", 0x7689b04f, true },
133 { "KEY_HOME", 0x768922dd, false },
134 { "KEY_MEDIA_REPEAT", 0x768938c7, false },
135 // { "KEY_TITLE", 0x76897887, false }, // Now Playing
136 // { "KEY_TITLE", 0x7689a25d, false }, // Now Playing
137 // { "KEY_TEXT", 0x7689f807, false }, // Size
138 // { "KEY_BRIGHTNESS_CYCLE", 0x768904fb, false },
97139 { NULL, 0 , false },
98140 };
99141
111153 int i;
112154 for (i = 0; keymap[i].lirc; i++) {
113155 if (!strcmp(c, keymap[i].lirc)) {
114 if (keymap[i].repeat || !strcmp(r, "00")) {
156 // inputlirc issues "0", while LIRC uses "00"
157 if (keymap[i].repeat || !strcmp(r, "0") || !strcmp(r,"00")) {
115158 return keymap[i].code;
116159 }
117160 LOG_DEBUG("repeat suppressed");
213256 fd = LIRC(i, init, LIRC_CLIENT_ID, 0);
214257
215258 if (fd > 0) {
216 if (LIRC(i, readconfig,lircrc, &config, NULL) != 0) {
259 if (LIRC(i, readconfig, lircrc, &config, NULL) != 0) {
217260 LOG_WARN("error reading config: %s", lircrc);
218261 }
262 else {
263 LOG_DEBUG("loaded lircrc config: %s", lircrc);
264 }
219265
220266 mutex_create(ir.mutex);
221267
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
8687 #endif
8788
8889 // based on libmad minimad.c scale
89 static inline u32_t scale(mad_fixed_t sample) {
90 static inline ISAMPLE_T scale(mad_fixed_t sample) {
9091 sample += (1L << (MAD_F_FRACBITS - 24));
9192
9293 if (sample >= MAD_F_ONE)
9394 sample = MAD_F_ONE - 1;
9495 else if (sample < -MAD_F_ONE)
9596 sample = -MAD_F_ONE;
96
97 return (s32_t)(sample >> (MAD_F_FRACBITS + 1 - 24)) << 8;
97 #if BYTES_PER_FRAME == 4
98 return (ISAMPLE_T)((sample >> (MAD_F_FRACBITS + 1 - 24)) >> 8);
99 #else
100 return (ISAMPLE_T)((sample >> (MAD_F_FRACBITS + 1 - 24)) << 8);
101 #endif
98102 }
99103
100104 // check for id3.2 tag at start of file - http://id3.org/id3v2.4.0-structure, return length
218222 decode_state ret;
219223 if (!eos && m->stream.error == MAD_ERROR_BUFLEN) {
220224 ret = DECODE_RUNNING;
221 } else if (eos && (m->stream.error == MAD_ERROR_BUFLEN || m->stream.error == MAD_ERROR_LOSTSYNC)) {
225 } else if (eos && (m->stream.error == MAD_ERROR_BUFLEN || m->stream.error == MAD_ERROR_LOSTSYNC
226 || m->stream.error == MAD_ERROR_BADBITRATE)) {
222227 ret = DECODE_COMPLETE;
223228 } else if (!MAD_RECOVERABLE(m->stream.error)) {
224229 LOG_INFO("mad_frame_decode error: %s - stopping decoder", MAD(m, stream_errorstr, &m->stream));
240245 LOCK_O;
241246 LOG_INFO("setting track_start");
242247 output.next_sample_rate = decode_newstream(m->synth.pcm.samplerate, output.supported_rates);
243 IF_DSD( output.next_dop = false; )
248 IF_DSD( output.next_fmt = PCM; )
244249 output.track_start = outputbuf->writep;
245250 if (output.fade_mode) _checkfade(true);
246251 decode.new_stream = false;
297302
298303 while (frames > 0) {
299304 size_t f, count;
300 s32_t *optr;
305 ISAMPLE_T *optr;
301306
302307 IF_DIRECT(
303308 f = min(frames, _buf_cont_write(outputbuf) / BYTES_PER_FRAME);
304 optr = (s32_t *)outputbuf->writep;
309 optr = (ISAMPLE_T *)outputbuf->writep;
305310 );
306311 IF_PROCESS(
307312 f = min(frames, process.max_in_frames - process.in_frames);
308 optr = (s32_t *)((u8_t *)process.inbuf + process.in_frames * BYTES_PER_FRAME);
313 optr = (ISAMPLE_T *)((u8_t *)process.inbuf + process.in_frames * BYTES_PER_FRAME);
309314 );
310315
311316 count = f;
341346 m->samples = 0;
342347 m->readbuf_len = 0;
343348 m->last_error = MAD_ERROR_NONE;
349
350 // explicitly clear before calling mad_*_init (again) to free the malloc'd memory
351 MAD(m, stream_finish, &m->stream);
352 MAD(m, frame_finish, &m->frame);
353 mad_synth_finish(&m->synth);
354
344355 MAD(m, stream_init, &m->stream);
345356 MAD(m, frame_init, &m->frame);
346357 MAD(m, synth_init, &m->synth);
396407 mad_decode, // decode
397408 };
398409
399 m = malloc(sizeof(struct mad));
410 m = calloc(1, sizeof(struct mad));
400411 if (!m) {
401412 return NULL;
402413 }
+259
-41
main.c less more
11 * Squeezelite - lightweight headless squeezebox emulator
22 *
33 * (c) Adrian Smith 2012-2015, triode1@btinternet.com
4 * Ralph Irving 2015-2020, 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
1516 * You should have received a copy of the GNU General Public License
1617 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1718 *
19 * Additions (c) Paul Hermann, 2015-2017 under the same license terms
20 * -Control of Raspberry pi GPIO for amplifier power
21 * -Launch script on power status change from LMS
1822 */
1923
2024 #include "squeezelite.h"
2125
2226 #include <signal.h>
2327
24 #define TITLE "Squeezelite " VERSION ", Copyright 2012-2015 Adrian Smith."
25
26 #define CODECS_BASE "flac,pcm,mp3,ogg,aac"
27 #if FFMPEG
28 #define TITLE "Squeezelite " VERSION ", Copyright 2012-2015 Adrian Smith, 2015-2020 Ralph Irving."
29
30 #define CODECS_BASE "flac,pcm,mp3,ogg"
31 #if NO_FAAD
32 #define CODECS_AAC ""
33 #else
34 #define CODECS_AAC ",aac"
35 #endif
36 #if ALAC
37 #define CODECS_FF ",alac"
38 #elif FFMPEG
2839 #define CODECS_FF ",wma,alac"
2940 #else
3041 #define CODECS_FF ""
42 #endif
43 #if OPUS
44 #define CODECS_OPUS ",ops"
45 #else
46 #define CODECS_OPUS ""
3147 #endif
3248 #if DSD
3349 #define CODECS_DSD ",dsd"
3652 #endif
3753 #define CODECS_MP3 " (mad,mpg for specific mp3 codec)"
3854
39 #define CODECS CODECS_BASE CODECS_FF CODECS_DSD CODECS_MP3
55 #define CODECS CODECS_BASE CODECS_AAC CODECS_FF CODECS_OPUS CODECS_DSD CODECS_MP3
4056
4157 static void usage(const char *argv0) {
4258 printf(TITLE " See -t for license terms\n"
4864 " -a <b>:<p>:<f>:<m>\tSpecify ALSA params to open output device, b = buffer time in ms or size in bytes, p = period count or size in bytes, f sample format (16|24|24_3|32), m = use mmap (0|1)\n"
4965 #endif
5066 #if PORTAUDIO
51 #if OSX
67 #if PA18API
68 " -a <frames>:<buffers>\tSpecify output target 4 byte frames per buffer, number of buffers\n"
69 #elif OSX && !defined(OSXPPC)
5270 " -a <l>:<r>\t\tSpecify Portaudio params to open output device, l = target latency in ms, r = allow OSX to resample (0|1)\n"
71 #elif WIN
72 " -a <l>:<e>\t\tSpecify Portaudio params to open output device, l = target latency in ms, e = use exclusive mode for WASAPI (0|1)\n"
5373 #else
5474 " -a <l>\t\tSpecify Portaudio params to open output device, l = target latency in ms\n"
5575 #endif
5777 " -a <f>\t\tSpecify sample format (16|24|32) of output file when using -o - to output samples to stdout (interleaved little endian only)\n"
5878 " -b <stream>:<output>\tSpecify internal Stream and Output buffer sizes in Kbytes\n"
5979 " -c <codec1>,<codec2>\tRestrict codecs to those specified, otherwise load all available codecs; known codecs: " CODECS "\n"
80 " \t\t\tCodecs reported to LMS in order listed, allowing codec priority refinement.\n"
6081 " -C <timeout>\t\tClose output device when idle after timeout seconds, default is to keep it open while player is 'on'\n"
6182 #if !IR
6283 " -d <log>=<level>\tSet logging level, logs: all|slimproto|stream|decode|output, level: info|debug|sdebug\n"
6384 #else
6485 " -d <log>=<level>\tSet logging level, logs: all|slimproto|stream|decode|output|ir, level: info|debug|sdebug\n"
6586 #endif
87 #if defined(GPIO) && defined(RPI)
88 " -G <Rpi GPIO#>:<H/L>\tSpecify the BCM GPIO# to use for Amp Power Relay and if the output should be Active High or Low\n"
89 #endif
6690 " -e <codec1>,<codec2>\tExplicitly exclude native support of one or more codecs; known codecs: " CODECS "\n"
6791 " -f <logfile>\t\tWrite debug to logfile\n"
6892 #if IR
7296 " -M <modelname>\tSet the squeezelite player model name sent to the server (default: " MODEL_NAME_STRING ")\n"
7397 " -n <name>\t\tSet the player name\n"
7498 " -N <filename>\t\tStore player name in filename to allow server defined name changes to be shared between servers (not supported with -n)\n"
99 " -W\t\t\tRead wave and aiff format from header, ignore server parameters\n"
75100 #if ALSA
76101 " -p <priority>\t\tSet real time priority of output thread (1-99)\n"
77102 #endif
78 #if LINUX || FREEBSD
103 #if LINUX || FREEBSD || SUN
79104 " -P <filename>\t\tStore the process id (PID) in filename\n"
80105 #endif
81106 " -r <rates>[:<delay>]\tSample rates supported, allows output to be off when squeezelite is started; rates = <maxrate>|<minrate>-<maxrate>|<rate1>,<rate2>,<rate3>; delay = optional delay switching rates in ms\n"
107 #if GPIO
108 " -S <Power Script>\tAbsolute path to script to launch on power commands from LMS\n"
109 #endif
82110 #if RESAMPLE
83111 " -R -u [params]\tResample, params = <recipe>:<flags>:<attenuation>:<precision>:<passband_end>:<stopband_start>:<phase_response>,\n"
84112 " \t\t\t recipe = (v|h|m|l|q)(L|I|M)(s) [E|X], E = exception - resample only if native rate not supported, X = async - resample to max rate for device, otherwise to max sync rate\n"
90118 " \t\t\t phase_response = 0-100 (0 = minimum / 50 = linear / 100 = maximum)\n"
91119 #endif
92120 #if DSD
93 " -D [delay]\t\tOutput device supports DSD over PCM (DoP), delay = optional delay switching between PCM and DoP in ms\n"
121 #if ALSA
122 " -D [delay][:format]\tOutput device supports DSD, delay = optional delay switching between PCM and DSD in ms\n"
123 " \t\t\t format = dop (default if not specified), u8, u16le, u16be, u32le or u32be.\n"
124 #else
125 " -D [delay]\t\tOutput device supports DSD over PCM (DoP), delay = optional delay switching between PCM and DoP in ms\n"
126 #endif
94127 #endif
95128 #if VISEXPORT
96 " -v \t\t\tVisualiser support\n"
129 " -v \t\t\tVisualizer support\n"
97130 #endif
98131 # if ALSA
132 " -O <mixer device>\tSpecify mixer device, defaults to 'output device'\n"
99133 " -L \t\t\tList volume controls for output device\n"
100134 " -U <control>\t\tUnmute ALSA control and set to full volume (not supported with -V)\n"
101135 " -V <control>\t\tUse ALSA control for volume adjustment, otherwise use software volume adjustment\n"
102 #endif
103 #if LINUX || FREEBSD
136 " -X \t\t\tUse linear volume adjustments instead of in terms of dB (only for hardware volume control)\n"
137 #endif
138 #if LINUX || FREEBSD || SUN
104139 " -z \t\t\tDaemonize\n"
140 #endif
141 #if RESAMPLE
142 " -Z <rate>\t\tReport rate to server in helo as the maximum sample rate we can support\n"
105143 #endif
106144 " -t \t\t\tLicense terms\n"
107145 " -? \t\t\tDisplay this help text\n"
108146 "\n"
109147 "Build options:"
110 #if LINUX
148 #if SUN
149 " SOLARIS"
150 #elif LINUX
111151 " LINUX"
112152 #endif
113153 #if WIN
116156 #if OSX
117157 " OSX"
118158 #endif
159 #if OSXPPC
160 "PPC"
161 #endif
119162 #if FREEBSD
120163 " FREEBSD"
121164 #endif
124167 #endif
125168 #if PORTAUDIO
126169 " PORTAUDIO"
170 #if PA18API
171 "18"
172 #endif
173 #endif
174 #if PULSEAUDIO
175 " PULSEAUDIO"
127176 #endif
128177 #if EVENTFD
129178 " EVENTFD"
141190 " RESAMPLE"
142191 #endif
143192 #endif
144 #if FFMPEG
193 #if ALAC
194 " ALAC"
195 #elif FFMPEG
145196 " FFMPEG"
197 #endif
198 #if OPUS
199 " OPUS"
200 #endif
201 #if NO_FAAD
202 " NO_FAAD"
146203 #endif
147204 #if VISEXPORT
148205 " VISEXPORT"
150207 #if IR
151208 " IR"
152209 #endif
210 #if GPIO
211 " GPIO"
212 #endif
213 #if RPI
214 " RPI"
215 #endif
153216 #if DSD
154217 " DSD"
218 #endif
219 #if USE_SSL
220 " SSL"
221 #endif
222 #if NO_SSLSYM
223 " NO_SSLSYM"
155224 #endif
156225 #if LINKALL
157226 " LINKALL"
171240 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
172241 "GNU General Public License for more details.\n\n"
173242 "You should have received a copy of the GNU General Public License\n"
174 "along with this program. If not, see <http://www.gnu.org/licenses/>.\n\n"
243 "along with this program. If not, see <http://www.gnu.org/licenses/>.\n"
244
245 "\nThe Squeezelite source code is available on github.\n"
246 "<https://github.com/ralph-irving/squeezelite>\n"
247
248 "\nThe source and patches for bundled 3rd party libraries can be found on\n"
249 "SourceForge. <https://sourceforge.net/projects/lmsclients/files/source/>\n"
175250 #if DSD
176 "Contains dsd2pcm library Copyright 2009, 2011 Sebastian Gesemann which\n"
177 "is subject to its own license.\n\n"
178 #endif
251 "\nContains dsd2pcm library Copyright 2009, 2011 Sebastian Gesemann which\n"
252 "is subject to its own license.\n"
253 "\nContains the Daphile Project full dsd patch Copyright 2013-2017 Daphile,\n"
254 "which is subject to its own license.\n"
255 #endif
256 "\nOption to allow server side upsampling for PCM streams (-W) from\n"
257 "squeezelite-R2 (c) Marco Curti 2015, marcoc1712@gmail.com.\n"
258 #if RPI
259 "\nContains minimal GPIO Interface <http://abyz.me.uk/rpi/pigpio/>.\n"
260 #endif
261 #if FFMPEG
262 "\nThis software uses libraries from the FFmpeg project under\n"
263 "the LGPLv2.1 and its source can be downloaded from\n"
264 "<https://sourceforge.net/projects/lmsclients/files/source/>\n"
265 #endif
266 #if OPUS
267 "\nOpus decoder support (c) Philippe 2018-2019, philippe_44@outlook.com\n"
268 #endif
269 #if ALAC
270 "\nContains Apple Lossless (ALAC) decoder. Apache License Version 2.0\n"
271 "Apple ALAC decoder support (c) Philippe 2018-2019, philippe_44@outlook.com\n"
272 #endif
273 "\n"
179274 );
180275 }
181276
194289 char *name = NULL;
195290 char *namefile = NULL;
196291 char *modelname = NULL;
292 extern bool pcm_check_header;
293 extern bool user_rates;
197294 char *logfile = NULL;
198295 u8_t mac[6];
199296 unsigned stream_buf_size = STREAMBUF_SIZE;
203300 char *resample = NULL;
204301 char *output_params = NULL;
205302 unsigned idle = 0;
206 #if LINUX || FREEBSD
303 #if LINUX || FREEBSD || SUN
207304 bool daemonize = false;
208305 char *pidfile = NULL;
209306 FILE *pidfp = NULL;
210307 #endif
211308 #if ALSA
212309 unsigned rt_priority = OUTPUT_RT_PRIORITY;
310 char *mixer_device = output_device;
213311 char *output_mixer = NULL;
214312 bool output_mixer_unmute = false;
313 bool linear_volume = false;
215314 #endif
216315 #if DSD
217 bool dop = false;
218 unsigned dop_delay = 0;
316 unsigned dsd_delay = 0;
317 dsd_format dsd_outfmt = PCM;
219318 #endif
220319 #if VISEXPORT
221320 bool visexport = false;
232331 log_level log_ir = lWARN;
233332 #endif
234333
334 int maxSampleRate = 0;
335
235336 char *optarg = NULL;
236337 int optind = 1;
237338 int i;
250351 char *opt = argv[optind] + 1;
251352 if (strstr("oabcCdefmMnNpPrs"
252353 #if ALSA
253 "UV"
354 "UVO"
355 #endif
356 /*
357 * only allow '-Z <rate>' override of maxSampleRate
358 * reported by client if built with the capability to resample!
359 */
360 #if RESAMPLE
361 "Z"
254362 #endif
255363 , opt) && optind < argc - 1) {
256364 optarg = argv[optind + 1];
257365 optind += 2;
258 } else if (strstr("ltz?"
259 #if ALSA
260 "L"
366 } else if (strstr("ltz?W"
367 #if ALSA
368 "LX"
261369 #endif
262370 #if RESAMPLE
263371 "uR"
270378 #endif
271379 #if IR
272380 "i"
381 #endif
382 #if defined(GPIO) && defined(RPI)
383 "G"
384 #endif
385 #if GPIO
386 "S"
273387 #endif
274388
275389 , opt)) {
284398 switch (opt[0]) {
285399 case 'o':
286400 output_device = optarg;
401 #if ALSA
402 mixer_device = optarg;
403 #endif
287404 break;
288405 case 'a':
289406 output_params = optarg;
394511 if (dstr) {
395512 rate_delay = atoi(dstr);
396513 }
514 if (rates[0]) {
515 user_rates = true;
516 }
397517 }
398518 break;
399519 case 's':
404524 break;
405525 case 'N':
406526 namefile = optarg;
527 break;
528 case 'W':
529 pcm_check_header = true;
407530 break;
408531 #if ALSA
409532 case 'p':
415538 }
416539 break;
417540 #endif
418 #if LINUX || FREEBSD
541 #if LINUX || FREEBSD || SUN
419542 case 'P':
420543 pidfile = optarg;
421544 break;
424547 list_devices();
425548 exit(0);
426549 break;
427 #if ALSA
428 case 'L':
429 list_mixers(output_device);
430 exit(0);
431 break;
432 #endif
433550 #if RESAMPLE
434551 case 'u':
435552 case 'R':
439556 resample = "";
440557 }
441558 break;
559 case 'Z':
560 maxSampleRate = atoi(optarg);
561 break;
442562 #endif
443563 #if DSD
444564 case 'D':
445 dop = true;
565 dsd_outfmt = DOP;
446566 if (optind < argc && argv[optind] && argv[optind][0] != '-') {
447 dop_delay = atoi(argv[optind++]);
567 char *dstr = next_param(argv[optind++], ':');
568 char *fstr = next_param(NULL, ':');
569 dsd_delay = dstr ? atoi(dstr) : 0;
570 if (fstr) {
571 if (!strcmp(fstr, "dop")) dsd_outfmt = DOP;
572 if (!strcmp(fstr, "u8")) dsd_outfmt = DSD_U8;
573 if (!strcmp(fstr, "u16le")) dsd_outfmt = DSD_U16_LE;
574 if (!strcmp(fstr, "u32le")) dsd_outfmt = DSD_U32_LE;
575 if (!strcmp(fstr, "u16be")) dsd_outfmt = DSD_U16_BE;
576 if (!strcmp(fstr, "u32be")) dsd_outfmt = DSD_U32_BE;
577 if (!strcmp(fstr, "dop24")) dsd_outfmt = DOP_S24_LE;
578 if (!strcmp(fstr, "dop24_3")) dsd_outfmt = DOP_S24_3LE;
579 }
448580 }
449581 break;
450582 #endif
454586 break;
455587 #endif
456588 #if ALSA
589 case 'O':
590 mixer_device = optarg;
591 break;
592 case 'L':
593 list_mixers(mixer_device);
594 exit(0);
595 break;
596 case 'X':
597 linear_volume = true;
598 break;
457599 case 'U':
458600 output_mixer_unmute = true;
459601 case 'V':
473615 }
474616 break;
475617 #endif
476 #if LINUX || FREEBSD
618 #if defined(GPIO) && defined(RPI)
619 case 'G':
620 if (power_script != NULL){
621 fprintf(stderr, "-G and -S options cannot be used together \n\n" );
622 usage(argv[0]);
623 exit(1);
624 }
625 if (optind < argc && argv[optind] && argv[optind][0] != '-') {
626 char *gp = next_param(argv[optind++], ':');
627 char *go = next_param (NULL, ':');
628 gpio_pin = atoi(gp);
629 if (go != NULL){
630 if ((strcmp(go, "H")==0)|(strcmp(go, "h")==0)){
631 gpio_active_low=false;
632 }else if((strcmp(go, "L")==0)|(strcmp(go, "l")==0)){
633 gpio_active_low=true;
634 }else{
635 fprintf(stderr,"Must set output to be active High or Low i.e. -G18:H or -G18:L\n");
636 usage(argv[0]);
637 exit(1);
638 }
639 }else{
640 fprintf(stderr,"-G Option Error\n");
641 usage(argv[0]);
642 exit(1);
643 }
644 gpio_active = true;
645 relay(0);
646
647 } else {
648 fprintf(stderr, "Error in GPIO Pin assignment.\n");
649 usage(argv[0]);
650 exit(1);
651 }
652 break;
653 #endif
654 #if GPIO
655 case 'S':
656 if (gpio_active){
657 fprintf(stderr, "-G and -S options cannot be used together \n\n" );
658 usage(argv[0]);
659 exit(1);
660 }
661 if (optind < argc && argv[optind] && argv[optind][0] != '-') {
662 power_script = argv[optind++];
663 if( access( power_script, R_OK|X_OK ) == -1 ) {
664 // file doesn't exist
665 fprintf(stderr, "Script %s, not found\n\n", argv[optind-1]);
666 usage(argv[0]);
667 exit(1);
668 }
669 } else {
670 fprintf(stderr, "No Script Name Given.\n\n");
671 usage(argv[0]);
672 exit(1);
673 }
674 relay_script(0);
675 break;
676 #endif
677 #if LINUX || FREEBSD || SUN
477678 case 'z':
478679 daemonize = true;
680 #if SUN
681 init_daemonize();
682 #endif /* SUN */
479683 break;
480684 #endif
481685 case 't':
504708 #endif
505709 #if defined(SIGHUP)
506710 signal(SIGHUP, sighandler);
711 #endif
712
713 #if USE_SSL && !LINKALL && !NO_SSLSYM
714 ssl_loaded = load_ssl_symbols();
507715 #endif
508716
509717 // set the output buffer size if not specified on the command line, take account of resampling
530738 }
531739 }
532740
533 #if LINUX || FREEBSD
741 #if LINUX || FREEBSD || SUN
534742 if (pidfile) {
535743 if (!(pidfp = fopen(pidfile, "w")) ) {
536744 fprintf(stderr, "Error opening pidfile %s: %s\n", pidfile, strerror(errno));
546754 }
547755
548756 if (pidfp) {
549 fprintf(pidfp, "%d\n", getpid());
757 fprintf(pidfp, "%d\n", (int) getpid());
550758 fclose(pidfp);
551759 }
552760 #endif
561769 output_init_stdout(log_output, output_buf_size, output_params, rates, rate_delay);
562770 } else {
563771 #if ALSA
564 output_init_alsa(log_output, output_device, output_buf_size, output_params, rates, rate_delay, rt_priority, idle, output_mixer,
565 output_mixer_unmute);
772 output_init_alsa(log_output, output_device, output_buf_size, output_params, rates, rate_delay, rt_priority, idle, mixer_device, output_mixer,
773 output_mixer_unmute, linear_volume);
566774 #endif
567775 #if PORTAUDIO
568776 output_init_pa(log_output, output_device, output_buf_size, output_params, rates, rate_delay, idle);
569777 #endif
778 #if PULSEAUDIO
779 output_init_pulse(log_output, output_device, output_buf_size, output_params, rates, rate_delay, idle);
780 #endif
570781 }
571782
572783 #if DSD
573 dop_init(dop, dop_delay);
784 dsd_init(dsd_outfmt, dsd_delay);
574785 #endif
575786
576787 #if VISEXPORT
598809 exit(1);
599810 }
600811
601 slimproto(log_slimproto, server, mac, name, namefile, modelname);
812 slimproto(log_slimproto, server, mac, name, namefile, modelname, maxSampleRate);
602813
603814 decode_close();
604815 stream_close();
612823 #if PORTAUDIO
613824 output_close_pa();
614825 #endif
826 #if PULSEAUDIO
827 output_close_pulse();
828 #endif
615829 }
616830
617831 #if IR
622836 winsock_close();
623837 #endif
624838
625 #if LINUX || FREEBSD
839 #if LINUX || FREEBSD || SUN
626840 if (pidfile) {
627841 unlink(pidfile);
628842 free(pidfile);
629843 }
630844 #endif
631845
846 #if USE_SSL && !LINKALL && !NO_SSLSYM
847 free_ssl_symbols();
848 #endif
849
632850 exit(0);
633851 }
0 /*
1 minimal_gpio.c
2 2019-07-03
3 Public Domain
4
5 Original Site: http://abyz.me.uk/rpi/pigpio/examples.html
6
7 */
8
9 #include <stdio.h>
10 #include <unistd.h>
11 #include <stdint.h>
12 #include <string.h>
13 #include <fcntl.h>
14 #include <sys/mman.h>
15 #include <sys/stat.h>
16 #include <sys/types.h>
17
18 static volatile uint32_t piPeriphBase = 0x20000000;
19
20 static volatile int pi_is_2711 = 0;
21
22 #define SYST_BASE (piPeriphBase + 0x003000)
23 #define DMA_BASE (piPeriphBase + 0x007000)
24 #define CLK_BASE (piPeriphBase + 0x101000)
25 #define GPIO_BASE (piPeriphBase + 0x200000)
26 #define UART0_BASE (piPeriphBase + 0x201000)
27 #define PCM_BASE (piPeriphBase + 0x203000)
28 #define SPI0_BASE (piPeriphBase + 0x204000)
29 #define I2C0_BASE (piPeriphBase + 0x205000)
30 #define PWM_BASE (piPeriphBase + 0x20C000)
31 #define BSCS_BASE (piPeriphBase + 0x214000)
32 #define UART1_BASE (piPeriphBase + 0x215000)
33 #define I2C1_BASE (piPeriphBase + 0x804000)
34 #define I2C2_BASE (piPeriphBase + 0x805000)
35 #define DMA15_BASE (piPeriphBase + 0xE05000)
36
37 #define DMA_LEN 0x1000 /* allow access to all channels */
38 #define CLK_LEN 0xA8
39 #define GPIO_LEN 0xF4
40 #define SYST_LEN 0x1C
41 #define PCM_LEN 0x24
42 #define PWM_LEN 0x28
43 #define I2C_LEN 0x1C
44 #define BSCS_LEN 0x40
45
46 #define GPSET0 7
47 #define GPSET1 8
48
49 #define GPCLR0 10
50 #define GPCLR1 11
51
52 #define GPLEV0 13
53 #define GPLEV1 14
54
55 #define GPPUD 37
56 #define GPPUDCLK0 38
57 #define GPPUDCLK1 39
58
59 /* BCM2711 has different pulls */
60
61 #define GPPUPPDN0 57
62 #define GPPUPPDN1 58
63 #define GPPUPPDN2 59
64 #define GPPUPPDN3 60
65
66 #define SYST_CS 0
67 #define SYST_CLO 1
68 #define SYST_CHI 2
69
70 static volatile uint32_t *gpioReg = MAP_FAILED;
71 static volatile uint32_t *systReg = MAP_FAILED;
72 static volatile uint32_t *bscsReg = MAP_FAILED;
73
74 #define PI_BANK (gpio>>5)
75 #define PI_BIT (1<<(gpio&0x1F))
76
77 /* gpio modes. */
78
79 #define PI_INPUT 0
80 #define PI_OUTPUT 1
81 #define PI_ALT0 4
82 #define PI_ALT1 5
83 #define PI_ALT2 6
84 #define PI_ALT3 7
85 #define PI_ALT4 3
86 #define PI_ALT5 2
87
88 void gpioSetMode(unsigned gpio, unsigned mode)
89 {
90 int reg, shift;
91
92 reg = gpio/10;
93 shift = (gpio%10) * 3;
94
95 gpioReg[reg] = (gpioReg[reg] & ~(7<<shift)) | (mode<<shift);
96 }
97
98 int gpioGetMode(unsigned gpio)
99 {
100 int reg, shift;
101
102 reg = gpio/10;
103 shift = (gpio%10) * 3;
104
105 return (*(gpioReg + reg) >> shift) & 7;
106 }
107
108 /* Values for pull-ups/downs off, pull-down and pull-up. */
109
110 #define PI_PUD_OFF 0
111 #define PI_PUD_DOWN 1
112 #define PI_PUD_UP 2
113
114 void gpioSetPullUpDown(unsigned gpio, unsigned pud)
115 {
116 int shift = (gpio & 0xf) << 1;
117 uint32_t bits;
118 uint32_t pull = 0;
119
120 if (pi_is_2711)
121 {
122 switch (pud)
123 {
124 case PI_PUD_OFF: pull = 0; break;
125 case PI_PUD_UP: pull = 1; break;
126 case PI_PUD_DOWN: pull = 2; break;
127 }
128
129 bits = *(gpioReg + GPPUPPDN0 + (gpio>>4));
130 bits &= ~(3 << shift);
131 bits |= (pull << shift);
132 *(gpioReg + GPPUPPDN0 + (gpio>>4)) = bits;
133 }
134 else
135 {
136 *(gpioReg + GPPUD) = pud;
137
138 usleep(20);
139
140 *(gpioReg + GPPUDCLK0 + PI_BANK) = PI_BIT;
141
142 usleep(20);
143
144 *(gpioReg + GPPUD) = 0;
145
146 *(gpioReg + GPPUDCLK0 + PI_BANK) = 0;
147 }
148 }
149
150 int gpioRead(unsigned gpio)
151 {
152 if ((*(gpioReg + GPLEV0 + PI_BANK) & PI_BIT) != 0) return 1;
153 else return 0;
154 }
155
156 void gpioWrite(unsigned gpio, unsigned level)
157 {
158 if (level == 0) *(gpioReg + GPCLR0 + PI_BANK) = PI_BIT;
159 else *(gpioReg + GPSET0 + PI_BANK) = PI_BIT;
160 }
161
162 void gpioTrigger(unsigned gpio, unsigned pulseLen, unsigned level)
163 {
164 if (level == 0) *(gpioReg + GPCLR0 + PI_BANK) = PI_BIT;
165 else *(gpioReg + GPSET0 + PI_BANK) = PI_BIT;
166
167 usleep(pulseLen);
168
169 if (level != 0) *(gpioReg + GPCLR0 + PI_BANK) = PI_BIT;
170 else *(gpioReg + GPSET0 + PI_BANK) = PI_BIT;
171 }
172
173 /* Bit (1<<x) will be set if gpio x is high. */
174
175 uint32_t gpioReadBank1(void) { return (*(gpioReg + GPLEV0)); }
176 uint32_t gpioReadBank2(void) { return (*(gpioReg + GPLEV1)); }
177
178 /* To clear gpio x bit or in (1<<x). */
179
180 void gpioClearBank1(uint32_t bits) { *(gpioReg + GPCLR0) = bits; }
181 void gpioClearBank2(uint32_t bits) { *(gpioReg + GPCLR1) = bits; }
182
183 /* To set gpio x bit or in (1<<x). */
184
185 void gpioSetBank1(uint32_t bits) { *(gpioReg + GPSET0) = bits; }
186 void gpioSetBank2(uint32_t bits) { *(gpioReg + GPSET1) = bits; }
187
188 unsigned gpioHardwareRevision(void)
189 {
190 static unsigned rev = 0;
191
192 FILE *filp;
193 char buf[512];
194 char term;
195 int chars=4; /* number of chars in revision string */
196
197 filp = fopen ("/proc/cpuinfo", "r");
198
199 if (filp != NULL)
200 {
201 while (fgets(buf, sizeof(buf), filp) != NULL)
202 {
203 if (!strncasecmp("revision", buf, 8))
204 {
205 if (sscanf(buf+strlen(buf)-(chars+1),
206 "%x%c", &rev, &term) == 2)
207 {
208 if (term != '\n') rev = 0;
209 else rev &= 0xFFFFFF; /* mask out warranty bit */
210 }
211 }
212 }
213
214 fclose(filp);
215 }
216
217 filp = fopen("/proc/device-tree/soc/ranges" , "rb");
218
219 if (filp != NULL)
220 {
221 if (fread(buf, 1, sizeof(buf), filp) >= 8)
222 {
223 piPeriphBase = buf[4]<<24 | buf[5]<<16 | buf[6]<<8 | buf[7];
224 if (!piPeriphBase)
225 piPeriphBase = buf[8]<<24 | buf[9]<<16 | buf[10]<<8 | buf[11];
226
227 if (piPeriphBase == 0xFE000000) pi_is_2711 = 1;
228 }
229 fclose(filp);
230 }
231
232 return rev;
233 }
234
235 /* Returns the number of microseconds after system boot. Wraps around
236 after 1 hour 11 minutes 35 seconds.
237 */
238
239 uint32_t gpioTick(void) { return systReg[SYST_CLO]; }
240
241
242 /* Map in registers. */
243
244 static uint32_t * initMapMem(int fd, uint32_t addr, uint32_t len)
245 {
246 return (uint32_t *) mmap(0, len,
247 PROT_READ|PROT_WRITE|PROT_EXEC,
248 MAP_SHARED|MAP_LOCKED,
249 fd, addr);
250 }
251
252 int gpioInitialise(void)
253 {
254 int fd;
255
256 gpioHardwareRevision(); /* sets rev and peripherals base address */
257
258 fd = open("/dev/mem", O_RDWR | O_SYNC) ;
259
260 if (fd < 0)
261 {
262 fprintf(stderr,
263 "This program needs root privileges. Try using sudo\n");
264 return -1;
265 }
266
267 gpioReg = initMapMem(fd, GPIO_BASE, GPIO_LEN);
268 systReg = initMapMem(fd, SYST_BASE, SYST_LEN);
269 bscsReg = initMapMem(fd, BSCS_BASE, BSCS_LEN);
270
271 close(fd);
272
273 if ((gpioReg == MAP_FAILED) ||
274 (systReg == MAP_FAILED) ||
275 (bscsReg == MAP_FAILED))
276 {
277 fprintf(stderr,
278 "Bad, mmap failed\n");
279 return -1;
280 }
281 return 0;
282 }
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
123124 LOG_INFO("setting track_start");
124125 LOCK_O_not_direct;
125126 output.next_sample_rate = decode_newstream(rate, output.supported_rates);
126 IF_DSD( output.next_dop = false; )
127 IF_DSD( output.next_fmt = PCM; )
127128 output.track_start = outputbuf->writep;
128129 if (output.fade_mode) _checkfade(true);
129130 decode.new_stream = false;
0 /*
1 * Squeezelite - lightweight headless squeezebox emulator
2 *
3 * (c) Adrian Smith 2012-2015, triode1@btinternet.com
4 * Ralph Irving 2015-2017, ralph_irving@hotmail.com
5 * Philippe 2018-2019, philippe_44@outlook.com
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22 #include "squeezelite.h"
23 #if OPUS
24
25 /*
26 * with some low-end CPU, the decode call takes a fair bit of time and if the outputbuf is locked during that
27 * period, the output_thread (or equivalent) will be locked although there is plenty of samples available.
28 * Normally, with PRIO_INHERIT, that thread should increase decoder priority and get the lock quickly but it
29 * seems that when the streambuf has plenty of data, the decode thread grabs the CPU to much, even it the output
30 * thread has a higher priority. Using an interim buffer where opus decoder writes the output is not great from
31 * an efficiency (one extra memory copy) point of view, but it allows the lock to not be kept for too long
32 */
33 #if EMBEDDED
34 #define FRAME_BUF 2048
35 #endif
36
37 #if BYTES_PER_FRAME == 4
38 #define ALIGN(n) (n)
39 #else
40 #define ALIGN(n) (n << 16)
41 #endif
42
43 #include <opusfile.h>
44
45 struct opus {
46 struct OggOpusFile *of;
47 #if FRAME_BUF
48 u8_t *write_buf;
49 #endif
50 #if !LINKALL
51 // opus symbols to be dynamically loaded
52 void (*op_free)(OggOpusFile *_of);
53 int (*op_read)(OggOpusFile *_of, opus_int16 *_pcm, int _buf_size, int *_li);
54 const OpusHead* (*op_head)(OggOpusFile *_of, int _li);
55 OggOpusFile* (*op_open_callbacks) (void *_source, OpusFileCallbacks *_cb, unsigned char *_initial_data, size_t _initial_bytes, int *_error);
56 #endif
57 };
58
59 static struct opus *u;
60
61 extern log_level loglevel;
62
63 extern struct buffer *streambuf;
64 extern struct buffer *outputbuf;
65 extern struct streamstate stream;
66 extern struct outputstate output;
67 extern struct decodestate decode;
68 extern struct processstate process;
69
70 #define LOCK_S mutex_lock(streambuf->mutex)
71 #define UNLOCK_S mutex_unlock(streambuf->mutex)
72 #define LOCK_O mutex_lock(outputbuf->mutex)
73 #define UNLOCK_O mutex_unlock(outputbuf->mutex)
74 #if PROCESS
75 #define LOCK_O_direct if (decode.direct) mutex_lock(outputbuf->mutex)
76 #define UNLOCK_O_direct if (decode.direct) mutex_unlock(outputbuf->mutex)
77 #define LOCK_O_not_direct if (!decode.direct) mutex_lock(outputbuf->mutex)
78 #define UNLOCK_O_not_direct if (!decode.direct) mutex_unlock(outputbuf->mutex)
79 #define IF_DIRECT(x) if (decode.direct) { x }
80 #define IF_PROCESS(x) if (!decode.direct) { x }
81 #else
82 #define LOCK_O_direct mutex_lock(outputbuf->mutex)
83 #define UNLOCK_O_direct mutex_unlock(outputbuf->mutex)
84 #define LOCK_O_not_direct
85 #define UNLOCK_O_not_direct
86 #define IF_DIRECT(x) { x }
87 #define IF_PROCESS(x)
88 #endif
89
90 #if LINKALL
91 #define OP(h, fn, ...) (op_ ## fn)(__VA_ARGS__)
92 #else
93 #define OP(h, fn, ...) (h)->op_ ## fn(__VA_ARGS__)
94 #endif
95
96 // called with mutex locked within vorbis_decode to avoid locking O before S
97 static int _read_cb(void *datasource, char *ptr, int size) {
98 size_t bytes;
99
100 LOCK_S;
101
102 bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf));
103 bytes = min(bytes, size);
104
105 memcpy(ptr, streambuf->readp, bytes);
106 _buf_inc_readp(streambuf, bytes);
107
108 UNLOCK_S;
109
110 return bytes;
111 }
112
113 static decode_state opus_decompress(void) {
114 frames_t frames;
115 int n;
116 static int channels;
117 u8_t *write_buf;
118
119 LOCK_S;
120
121 if (stream.state <= DISCONNECT && !_buf_used(streambuf)) {
122 UNLOCK_S;
123 return DECODE_COMPLETE;
124 }
125
126 UNLOCK_S;
127
128 if (decode.new_stream) {
129 struct OpusFileCallbacks cbs;
130 const struct OpusHead *info;
131 int err;
132
133 cbs.read = (op_read_func) _read_cb;
134 cbs.seek = NULL; cbs.tell = NULL; cbs.close = NULL;
135
136 if ((u->of = OP(u, open_callbacks, streambuf, &cbs, NULL, 0, &err)) == NULL) {
137 LOG_WARN("open_callbacks error: %d", err);
138 return DECODE_COMPLETE;
139 }
140
141 info = OP(u, head, u->of, -1);
142
143 LOCK_O;
144 output.next_sample_rate = decode_newstream(48000, output.supported_rates);
145 IF_DSD( output.next_fmt = PCM; )
146 output.track_start = outputbuf->writep;
147 if (output.fade_mode) _checkfade(true);
148 decode.new_stream = false;
149 UNLOCK_O;
150
151 channels = info->channel_count;
152
153 LOG_INFO("setting track_start");
154 }
155
156 #if FRAME_BUF
157 IF_DIRECT(
158 frames = min(_buf_space(outputbuf), _buf_cont_write(outputbuf)) / BYTES_PER_FRAME;
159 frames = min(frames, FRAME_BUF);
160 write_buf = u->write_buf;
161 );
162 #else
163 LOCK_O_direct;
164 IF_DIRECT(
165 frames = min(_buf_space(outputbuf), _buf_cont_write(outputbuf)) / BYTES_PER_FRAME;
166 write_buf = outputbuf->writep;
167 );
168 #endif
169 IF_PROCESS(
170 frames = process.max_in_frames;
171 write_buf = process.inbuf;
172 );
173
174 // write the decoded frames into outputbuf then unpack them (they are 16 bits)
175 n = OP(u, read, u->of, (opus_int16*) write_buf, frames * channels, NULL);
176
177 #if FRAME_BUF
178 LOCK_O_direct;
179 #endif
180
181 if (n > 0) {
182 frames_t count;
183 s16_t *iptr;
184 ISAMPLE_T *optr;
185
186 frames = n;
187 count = frames * channels;
188
189 // work backward to unpack samples (if needed)
190 iptr = (s16_t *) write_buf + count;
191 optr = (ISAMPLE_T *) write_buf + frames * 2;
192
193 if (channels == 2) {
194 #if BYTES_PER_FRAME == 4
195 #if FRAME_BUF
196 // copy needed only when DIRECT and FRAME_BUF
197 IF_DIRECT(
198 memcpy(outputbuf->writep, write_buf, frames * BYTES_PER_FRAME);
199 )
200 #endif
201 #else
202 while (count--) {
203 *--optr = ALIGN(*--iptr);
204 }
205 #endif
206 } else if (channels == 1) {
207 while (count--) {
208 *--optr = ALIGN(*--iptr);
209 *--optr = ALIGN(*iptr);
210 }
211 }
212
213 IF_DIRECT(
214 _buf_inc_writep(outputbuf, frames * BYTES_PER_FRAME);
215 );
216 IF_PROCESS(
217 process.in_frames = frames;
218 );
219
220 LOG_SDEBUG("wrote %u frames", frames);
221
222 } else if (n == 0) {
223
224 if (stream.state <= DISCONNECT) {
225 LOG_INFO("partial decode");
226 UNLOCK_O_direct;
227 UNLOCK_S;
228 return DECODE_COMPLETE;
229 } else {
230 LOG_INFO("no frame decoded");
231 }
232
233 } else if (n == OP_HOLE) {
234
235 // recoverable hole in stream, seen when skipping
236 LOG_DEBUG("hole in stream");
237
238 } else {
239
240 LOG_INFO("op_read error: %d", n);
241 UNLOCK_O_direct;
242 return DECODE_COMPLETE;
243 }
244
245 UNLOCK_O_direct;
246
247 return DECODE_RUNNING;
248 }
249
250
251 static void opus_open(u8_t size, u8_t rate, u8_t chan, u8_t endianness) {
252 if (!u->of) {
253 #if FRAME_BUF
254 if (!u->write_buf) u->write_buf = malloc(FRAME_BUF * BYTES_PER_FRAME);
255 #endif
256 } else {
257 OP(u, free, u->of);
258 u->of = NULL;
259 }
260 }
261
262 static void opus_close(void) {
263 if (u->of) {
264 OP(u, free, u->of);
265 u->of = NULL;
266 }
267 #if FRAME_BUF
268 free(u->write_buf);
269 u->write_buf = NULL;
270 #endif
271 }
272
273 static bool load_opus(void) {
274 #if !LINKALL
275 void *handle = dlopen(LIBOPUS, RTLD_NOW);
276 char *err;
277
278 if (!handle) {
279 LOG_INFO("dlerror: %s", dlerror());
280 return false;
281 }
282
283 u->op_free = dlsym(handle, "op_free");
284 u->op_read = dlsym(handle, "op_read");
285 u->op_head = dlsym(handle, "op_head");
286 u->op_open_callbacks = dlsym(handle, "op_open_callbacks");
287
288 if ((err = dlerror()) != NULL) {
289 LOG_INFO("dlerror: %s", err);
290 return false;
291 }
292
293 LOG_INFO("loaded "LIBOPUS);
294 #endif
295
296 return true;
297 }
298
299 struct codec *register_opus(void) {
300 static struct codec ret = {
301 'u', // id
302 "ops", // types
303 4*1024, // min read
304 32*1024, // min space
305 opus_open, // open
306 opus_close, // close
307 opus_decompress, // decode
308 };
309
310 u = malloc(sizeof(struct opus));
311 if (!u) {
312 return NULL;
313 }
314
315 u->of = NULL;
316 #if FRAME_BUF
317 u->write_buf = NULL;
318 #endif
319 if (!load_opus()) {
320 return NULL;
321 }
322
323 LOG_INFO("using opus to decode ops");
324 return &ret;
325 }
326 #endif /* OPUS */
327
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
3132
3233 u8_t *silencebuf;
3334 #if DSD
34 u8_t *silencebuf_dop;
35 u8_t *silencebuf_dsd;
3536 #endif
37
38 bool user_rates = false;
3639
3740 #define LOCK mutex_lock(outputbuf->mutex)
3841 #define UNLOCK mutex_unlock(outputbuf->mutex)
5558 silence = false;
5659
5760 // start when threshold met
58 if (output.state == OUTPUT_BUFFER && frames > output.threshold * output.next_sample_rate / 100 && frames > output.start_frames) {
61 if (output.state == OUTPUT_BUFFER && frames > output.threshold * output.next_sample_rate / 10 && frames > output.start_frames) {
5962 output.state = OUTPUT_RUNNING;
6063 LOG_INFO("start buffer frames: %u", frames);
6164 wake_controller();
123126 unsigned delay = 0;
124127 if (output.current_sample_rate != output.next_sample_rate) {
125128 delay = output.rate_delay;
129 #if PULSEAUDIO
130 set_sample_rate(output.next_sample_rate);
131 #endif
126132 }
127133 IF_DSD(
128 if (output.dop != output.next_dop) {
129 delay = output.dop_delay;
134 if (output.outfmt != output.next_fmt) {
135 delay = output.dsd_delay;
130136 }
131137 )
132138 frames -= size;
148154 output.track_start_time = gettime_ms();
149155 output.current_sample_rate = output.next_sample_rate;
150156 IF_DSD(
151 output.dop = output.next_dop;
157 output.outfmt = output.next_fmt;
152158 )
153 if (!output.fade == FADE_ACTIVE || !output.fade_mode == FADE_CROSSFADE) {
159 if (output.fade == FADE_INACTIVE || output.fade_mode != FADE_CROSSFADE) {
154160 output.current_replay_gain = output.next_replay_gain;
155161 }
156162 output.track_start = NULL;
162168 }
163169
164170 IF_DSD(
165 if (output.dop) {
171 if (output.outfmt != PCM) {
166172 gainL = gainR = FIXED_ONE;
167173 }
168174 )
281287
282288 bytes = output.next_sample_rate * BYTES_PER_FRAME * output.fade_secs;
283289 if (output.fade_mode == FADE_INOUT) {
284 bytes /= 2;
290 /* align on a frame boundary */
291 bytes = ((bytes / 2) / BYTES_PER_FRAME) * BYTES_PER_FRAME;
285292 }
286293
287294 if (start && (output.fade_mode == FADE_IN || (output.fade_mode == FADE_INOUT && _buf_used(outputbuf) == 0))) {
358365 memset(silencebuf, 0, MAX_SILENCE_FRAMES * BYTES_PER_FRAME);
359366
360367 IF_DSD(
361 silencebuf_dop = malloc(MAX_SILENCE_FRAMES * BYTES_PER_FRAME);
362 if (!silencebuf_dop) {
363 LOG_ERROR("unable to malloc silence dop buffer");
368 silencebuf_dsd = malloc(MAX_SILENCE_FRAMES * BYTES_PER_FRAME);
369 if (!silencebuf_dsd) {
370 LOG_ERROR("unable to malloc silence dsd buffer");
364371 exit(0);
365372 }
366 dop_silence_frames((u32_t *)silencebuf_dop, MAX_SILENCE_FRAMES);
373 dsd_silence_frames((u32_t *)silencebuf_dsd, MAX_SILENCE_FRAMES);
367374 )
368375
369376 LOG_DEBUG("idle timeout: %u", idle);
375382 output.error_opening = false;
376383 output.idle_to = (u32_t) idle;
377384
378 if (!rates[0]) {
379 if (!test_open(output.device, output.supported_rates)) {
380 LOG_ERROR("unable to open output device");
385 /* Skip test_open for stdout, set default sample rates */
386 if ( output.device[0] == '-' ) {
387 for (i = 0; i < MAX_SUPPORTED_SAMPLERATES; ++i) {
388 output.supported_rates[i] = rates[i];
389 }
390 }
391 else {
392 if (!test_open(output.device, output.supported_rates, user_rates)) {
393 LOG_ERROR("unable to open output device: %s", output.device);
381394 exit(0);
382395 }
383 } else {
396 }
397
398 if (user_rates) {
384399 for (i = 0; i < MAX_SUPPORTED_SAMPLERATES; ++i) {
385400 output.supported_rates[i] = rates[i];
386401 }
414429 buf_destroy(outputbuf);
415430 free(silencebuf);
416431 IF_DSD(
417 free(silencebuf_dop);
432 free(silencebuf_dsd);
418433 )
419434 }
420435
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
1516 * You should have received a copy of the GNU General Public License
1617 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1718 *
19 * Additions (c) Paul Hermann, 2015-2017 under the same license terms
20 * -Control of Raspberry pi GPIO for amplifier power
21 * -Launch script on power status change from LMS
1822 */
1923
2024 // Output using Alsa
4246 // ouput device
4347 static struct {
4448 char device[MAX_DEVICE_LEN + 1];
49 char *ctl;
50 char *mixer_ctl;
4551 snd_pcm_format_t format;
52 #if DSD
53 dsd_format outfmt;
54 snd_pcm_format_t pcmfmt;
55 #endif
4656 snd_pcm_uframes_t buffer_size;
4757 snd_pcm_uframes_t period_size;
4858 unsigned rate;
5060 bool reopen;
5161 u8_t *write_buf;
5262 const char *volume_mixer_name;
53 int volume_mixer_index;
63 bool mixer_linear;
64 snd_mixer_elem_t* mixer_elem;
65 snd_mixer_t *mixer_handle;
66 long mixer_min;
67 long mixer_max;
5468 } alsa;
5569
5670 static snd_pcm_t *pcmp = NULL;
5771
5872 extern u8_t *silencebuf;
5973 #if DSD
60 extern u8_t *silencebuf_dop;
74 extern u8_t *silencebuf_dsd;
6175 #endif
6276
6377 static log_level loglevel;
6983
7084 #define LOCK mutex_lock(outputbuf->mutex)
7185 #define UNLOCK mutex_unlock(outputbuf->mutex)
86
87 static char *ctl4device(const char *device) {
88 char *ctl = NULL;
89
90 if (!strncmp(device, "hw:", 3))
91 ctl = strdup(device);
92 else if (!strncmp(device, "plughw:", 7))
93 ctl = strdup(device + 4);
94
95 if (ctl) {
96 char *comma;
97 if ((comma = strrchr(ctl, ',')))
98 *comma = '\0';
99 } else
100 ctl = strdup(device);
101
102 return ctl;
103 }
72104
73105 void list_devices(void) {
74106 void **hints, **n;
100132 snd_mixer_t *handle;
101133 snd_mixer_selem_id_t *sid;
102134 snd_mixer_elem_t *elem;
135 char *ctl = ctl4device(output_device);
103136 snd_mixer_selem_id_alloca(&sid);
104137
105138 LOG_INFO("listing mixers for: %s", output_device);
108141 LOG_ERROR("open error: %s", snd_strerror(err));
109142 return;
110143 }
111 if ((err = snd_mixer_attach(handle, output_device)) < 0) {
144 if ((err = snd_mixer_attach(handle, ctl)) < 0) {
112145 LOG_ERROR("attach error: %s", snd_strerror(err));
113146 snd_mixer_close(handle);
147 free(ctl);
114148 return;
115149 }
150 free(ctl);
116151 if ((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0) {
117152 LOG_ERROR("register error: %s", snd_strerror(err));
118153 snd_mixer_close(handle);
142177
143178 #define MINVOL_DB 72 // LMS volume map for SqueezePlay sends values in range ~ -72..0 dB
144179
145 static void set_mixer(const char *device, const char *mixer, int mixer_index, bool setmax, float ldB, float rdB) {
180 static void set_mixer(bool setmax, float ldB, float rdB) {
146181 int err;
147182 long nleft, nright;
148 long min, max;
149 snd_mixer_t *handle;
150 snd_mixer_selem_id_t *sid;
151 snd_mixer_elem_t* elem;
152
153 if ((err = snd_mixer_open(&handle, 0)) < 0) {
154 LOG_ERROR("open error: %s", snd_strerror(err));
155 return;
156 }
157 if ((err = snd_mixer_attach(handle, device)) < 0) {
158 LOG_ERROR("attach error: %s", snd_strerror(err));
159 snd_mixer_close(handle);
160 return;
161 }
162 if ((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0) {
163 LOG_ERROR("register error: %s", snd_strerror(err));
164 snd_mixer_close(handle);
165 return;
166 }
167 if ((err = snd_mixer_load(handle)) < 0) {
168 LOG_ERROR("load error: %s", snd_strerror(err));
169 snd_mixer_close(handle);
170 return;
171 }
172
173 snd_mixer_selem_id_alloca(&sid);
174
175 snd_mixer_selem_id_set_index(sid, mixer_index);
176 snd_mixer_selem_id_set_name(sid, mixer);
177
178 if ((elem = snd_mixer_find_selem(handle, sid)) == NULL) {
179 LOG_ERROR("error find selem %s", mixer);
180 snd_mixer_close(handle);
181 return;
182 }
183
184 if (snd_mixer_selem_has_playback_switch(elem)) {
185 snd_mixer_selem_set_playback_switch_all(elem, 1); // unmute
186 }
187
188 err = snd_mixer_selem_get_playback_dB_range(elem, &min, &max);
189
190 if (err < 0 || max - min < 1000) {
191 // unable to get db range or range is less than 10dB - ignore and set using raw values
192 if ((err = snd_mixer_selem_get_playback_volume_range(elem, &min, &max)) < 0) {
193 LOG_ERROR("unable to get volume raw range");
194 } else {
195 long lraw, rraw;
196 if (setmax) {
197 lraw = rraw = max;
198 } else {
199 lraw = ((ldB > -MINVOL_DB ? MINVOL_DB + floor(ldB) : 0) / MINVOL_DB * (max-min)) + min;
200 rraw = ((rdB > -MINVOL_DB ? MINVOL_DB + floor(rdB) : 0) / MINVOL_DB * (max-min)) + min;
201 }
202 LOG_DEBUG("setting vol raw [%ld..%ld]", min, max);
203 if ((err = snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, lraw)) < 0) {
204 LOG_ERROR("error setting left volume: %s", snd_strerror(err));
205 }
206 if ((err = snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, rraw)) < 0) {
207 LOG_ERROR("error setting right volume: %s", snd_strerror(err));
208 }
209 }
183
184 if (alsa.mixer_linear) {
185 long lraw, rraw;
186 if (setmax) {
187 lraw = rraw = alsa.mixer_max;
188 } else {
189 lraw = ((ldB > -MINVOL_DB ? MINVOL_DB + floor(ldB) : 0) / MINVOL_DB * (alsa.mixer_max-alsa.mixer_min)) + alsa.mixer_min;
190 rraw = ((rdB > -MINVOL_DB ? MINVOL_DB + floor(rdB) : 0) / MINVOL_DB * (alsa.mixer_max-alsa.mixer_min)) + alsa.mixer_min;
191 }
192 LOG_DEBUG("setting vol raw [%ld..%ld]", alsa.mixer_min, alsa.mixer_max);
193 if ((err = snd_mixer_selem_set_playback_volume(alsa.mixer_elem, SND_MIXER_SCHN_FRONT_LEFT, lraw)) < 0) {
194 LOG_ERROR("error setting left volume: %s", snd_strerror(err));
195 }
196 if ((err = snd_mixer_selem_set_playback_volume(alsa.mixer_elem, SND_MIXER_SCHN_FRONT_RIGHT, rraw)) < 0) {
197 LOG_ERROR("error setting right volume: %s", snd_strerror(err));
198 }
210199 } else {
211200 // set db directly
212 LOG_DEBUG("setting vol dB [%ld..%ld]", min, max);
201 LOG_DEBUG("setting vol dB [%ld..%ld]", alsa.mixer_min, alsa.mixer_max);
213202 if (setmax) {
214203 // set to 0dB if available as this should be max volume for music recored at max pcm values
215 if (max >= 0 && min <= 0) {
204 if (alsa.mixer_max >= 0 && alsa.mixer_min <= 0) {
216205 ldB = rdB = 0;
217206 } else {
218 ldB = rdB = max;
219 }
220 }
221 if ((err = snd_mixer_selem_set_playback_dB(elem, SND_MIXER_SCHN_FRONT_LEFT, 100 * ldB, 1)) < 0) {
207 ldB = rdB = alsa.mixer_max;
208 }
209 }
210 if ((err = snd_mixer_selem_set_playback_dB(alsa.mixer_elem, SND_MIXER_SCHN_FRONT_LEFT, 100 * ldB, 1)) < 0) {
222211 LOG_ERROR("error setting left volume: %s", snd_strerror(err));
223212 }
224 if ((err = snd_mixer_selem_set_playback_dB(elem, SND_MIXER_SCHN_FRONT_RIGHT, 100 * rdB, 1)) < 0) {
213 if ((err = snd_mixer_selem_set_playback_dB(alsa.mixer_elem, SND_MIXER_SCHN_FRONT_RIGHT, 100 * rdB, 1)) < 0) {
225214 LOG_ERROR("error setting right volume: %s", snd_strerror(err));
226215 }
227216 }
228217
229 if ((err = snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, &nleft)) < 0) {
218 if ((err = snd_mixer_selem_get_playback_volume(alsa.mixer_elem, SND_MIXER_SCHN_FRONT_LEFT, &nleft)) < 0) {
230219 LOG_ERROR("error getting left vol: %s", snd_strerror(err));
231220 }
232 if ((err = snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, &nright)) < 0) {
221 if ((err = snd_mixer_selem_get_playback_volume(alsa.mixer_elem, SND_MIXER_SCHN_FRONT_RIGHT, &nright)) < 0) {
233222 LOG_ERROR("error getting right vol: %s", snd_strerror(err));
234223 }
235224
236 LOG_DEBUG("%s left: %3.1fdB -> %ld right: %3.1fdB -> %ld", mixer, ldB, nleft, rdB, nright);
237
238 snd_mixer_close(handle);
225 LOG_DEBUG("%s left: %3.1fdB -> %ld right: %3.1fdB -> %ld", alsa.volume_mixer_name, ldB, nleft, rdB, nright);
239226 }
240227
241228 void set_volume(unsigned left, unsigned right) {
259246 ldB = 20 * log10( left / 65536.0F );
260247 rdB = 20 * log10( right / 65536.0F );
261248
262 set_mixer(output.device, alsa.volume_mixer_name, alsa.volume_mixer_index, false, ldB, rdB);
249 set_mixer(false, ldB, rdB);
263250 }
264251
265252 static void *alsa_error_handler(const char *file, int line, const char *function, int err, const char *fmt, ...) {
281268 }
282269 }
283270
284 bool test_open(const char *device, unsigned rates[]) {
271 bool test_open(const char *device, unsigned rates[], bool userdef_rates) {
285272 int err;
286273 snd_pcm_t *pcm;
287274 snd_pcm_hw_params_t *hw_params;
301288 }
302289
303290 // find supported sample rates to enable client side resampling of non supported rates
304 unsigned i, ind;
305 unsigned ref[] TEST_RATES;
306
307 for (i = 0, ind = 0; ref[i]; ++i) {
308 if (snd_pcm_hw_params_test_rate(pcm, hw_params, ref[i], 0) == 0) {
309 rates[ind++] = ref[i];
291 if (!userdef_rates) {
292 unsigned i, ind;
293 unsigned ref[] TEST_RATES;
294
295 for (i = 0, ind = 0; ref[i]; ++i) {
296 if (snd_pcm_hw_params_test_rate(pcm, hw_params, ref[i], 0) == 0) {
297 rates[ind++] = ref[i];
298 }
310299 }
311300 }
312301
333322 return true;
334323 }
335324
325 #if DSD
326 static int alsa_open(const char *device, unsigned sample_rate, unsigned alsa_buffer, unsigned alsa_period, dsd_format outfmt) {
327 #else
336328 static int alsa_open(const char *device, unsigned sample_rate, unsigned alsa_buffer, unsigned alsa_period) {
329 #endif
337330 int err;
338331 snd_pcm_hw_params_t *hw_params;
339332 snd_pcm_hw_params_alloca(&hw_params);
343336
344337 // reset params
345338 alsa.rate = 0;
339 #if DSD
340 alsa.outfmt = PCM;
341 #endif
346342 alsa.period_size = 0;
347343 strcpy(alsa.device, device);
348344
399395 }
400396
401397 // set the sample format
398 #if DSD
399 switch (outfmt) {
400 case DSD_U8:
401 alsa.format = SND_PCM_FORMAT_DSD_U8; break;
402 case DSD_U16_LE:
403 alsa.format = SND_PCM_FORMAT_DSD_U16_LE; break;
404 case DSD_U16_BE:
405 alsa.format = SND_PCM_FORMAT_DSD_U16_BE; break;
406 case DSD_U32_LE:
407 alsa.format = SND_PCM_FORMAT_DSD_U32_LE; break;
408 case DSD_U32_BE:
409 alsa.format = SND_PCM_FORMAT_DSD_U32_BE; break;
410 case DOP_S24_LE:
411 alsa.format = SND_PCM_FORMAT_S24_LE; break;
412 case DOP_S24_3LE:
413 alsa.format = SND_PCM_FORMAT_S24_3LE; break;
414 default:
415 alsa.format = alsa.pcmfmt;
416 }
417 #endif
402418 snd_pcm_format_t *fmt = alsa.format ? &alsa.format : (snd_pcm_format_t *)fmts;
403419 do {
404420 if (snd_pcm_hw_params_set_format(pcmp, hw_params, *fmt) >= 0) {
427443 output.format = S24_3LE; break;
428444 case SND_PCM_FORMAT_S16_LE:
429445 output.format = S16_LE; break;
446 #if DSD
447 case SND_PCM_FORMAT_DSD_U32_LE:
448 output.format = U32_LE; break;
449 case SND_PCM_FORMAT_DSD_U32_BE:
450 output.format = U32_BE; break;
451 case SND_PCM_FORMAT_DSD_U16_LE:
452 output.format = U16_LE; break;
453 case SND_PCM_FORMAT_DSD_U16_BE:
454 output.format = U16_BE; break;
455 case SND_PCM_FORMAT_DSD_U8:
456 output.format = U8; break;
457 #endif
430458 default:
431459 break;
432460 }
511539
512540 // this indicates we have opened the device ok
513541 alsa.rate = sample_rate;
514
542 #if DSD
543 alsa.outfmt = outfmt;
544 #endif
545
515546 return 0;
516547 }
517548
547578 inputptr = (s32_t *) (silence ? silencebuf : outputbuf->readp);
548579
549580 IF_DSD(
550 if (output.dop) {
581 if (output.outfmt != PCM) {
551582 if (silence) {
552 inputptr = (s32_t *) silencebuf_dop;
553 }
554 update_dop((u32_t *) inputptr, out_frames, output.invert && !silence);
583 inputptr = (s32_t *) silencebuf_dsd;
584 }
585 if (output.outfmt == DOP || output.outfmt == DOP_S24_LE || output.outfmt == DOP_S24_3LE)
586 update_dop((u32_t *) inputptr, out_frames, output.invert && !silence);
587 else if (output.invert && !silence)
588 dsd_invert((u32_t *) inputptr, out_frames);
555589 }
556590 )
557591
632666 }
633667 probe_device = false;
634668 }
669 #if DSD
670 if (!pcmp || alsa.rate != output.current_sample_rate || alsa.outfmt != output.outfmt ) {
671 #else
635672
636673 if (!pcmp || alsa.rate != output.current_sample_rate) {
674 #endif
675 #if GPIO
676 // Wake up amp
677 if (gpio_active) {
678 ampstate = 1;
679 relay(1);
680 }
681 if (power_script != NULL) {
682 ampstate = 1;
683 relay_script(1);
684 }
685 #endif
637686 LOG_INFO("open output device: %s", output.device);
638687 LOCK;
639688
640689 // FIXME - some alsa hardware requires opening twice for a new sample rate to work
641690 // this is a workaround which should be removed
642691 if (alsa.reopen) {
692 #if DSD
693 alsa_open(output.device, output.current_sample_rate, output.buffer, output.period, output.outfmt);
694 #else
643695 alsa_open(output.device, output.current_sample_rate, output.buffer, output.period);
644 }
645
696 #endif
697 }
698 #if DSD
699 if (!!alsa_open(output.device, output.current_sample_rate, output.buffer, output.period, output.outfmt)) {
700 #else
646701 if (!!alsa_open(output.device, output.current_sample_rate, output.buffer, output.period)) {
702 #endif
647703 output.error_opening = true;
648704 UNLOCK;
649705 sleep(5);
660716 LOG_INFO("XRUN");
661717 if ((err = snd_pcm_recover(pcmp, -EPIPE, 1)) < 0) {
662718 LOG_INFO("XRUN recover failed: %s", snd_strerror(err));
719 usleep(10000);
663720 }
664721 start = true;
665722 continue;
710767 start = false;
711768 }
712769 } else {
713 if ((err = snd_pcm_wait(pcmp, 1000)) < 0) {
770 usleep(10000);
771 if ((err = snd_pcm_wait(pcmp, 1000)) <= 0) {
772 if ( err == 0 ) {
773 LOG_INFO("pcm wait timeout");
774 }
714775 if ((err = snd_pcm_recover(pcmp, err, 1)) < 0) {
715776 LOG_INFO("pcm wait error: %s", snd_strerror(err));
716777 }
745806 pcmp = NULL;
746807 output_off = true;
747808 vis_stop();
809 #if GPIO
810 // Put Amp to Sleep
811 if (gpio_active){
812 ampstate = 0;
813 relay(0);
814 }
815 if (power_script != NULL ){
816 ampstate = 0;
817 relay_script(0);
818 }
819 #endif
748820 continue;
749821 }
750822
785857 return 0;
786858 }
787859
860 int mixer_init_alsa(const char *device, const char *mixer, int mixer_index) {
861 int err;
862 snd_mixer_selem_id_t *sid;
863
864 if ((err = snd_mixer_open(&alsa.mixer_handle, 0)) < 0) {
865 LOG_ERROR("open error: %s", snd_strerror(err));
866 return -1;
867 }
868 if ((err = snd_mixer_attach(alsa.mixer_handle, device)) < 0) {
869 LOG_ERROR("attach error: %s", snd_strerror(err));
870 snd_mixer_close(alsa.mixer_handle);
871 return -1;
872 }
873 if ((err = snd_mixer_selem_register(alsa.mixer_handle, NULL, NULL)) < 0) {
874 LOG_ERROR("register error: %s", snd_strerror(err));
875 snd_mixer_close(alsa.mixer_handle);
876 return -1;
877 }
878 if ((err = snd_mixer_load(alsa.mixer_handle)) < 0) {
879 LOG_ERROR("load error: %s", snd_strerror(err));
880 snd_mixer_close(alsa.mixer_handle);
881 return -1;
882 }
883
884 snd_mixer_selem_id_alloca(&sid);
885 snd_mixer_selem_id_set_index(sid, mixer_index);
886 snd_mixer_selem_id_set_name(sid, mixer);
887
888 if ((alsa.mixer_elem = snd_mixer_find_selem(alsa.mixer_handle, sid)) == NULL) {
889 LOG_ERROR("error find selem %s", alsa.mixer_handle);
890 snd_mixer_close(alsa.mixer_handle);
891 return -1;
892 }
893
894 if (snd_mixer_selem_has_playback_switch(alsa.mixer_elem)) {
895 snd_mixer_selem_set_playback_switch_all(alsa.mixer_elem, 1); // unmute
896 }
897
898 err = snd_mixer_selem_get_playback_dB_range(alsa.mixer_elem, &alsa.mixer_min, &alsa.mixer_max);
899
900 if (err < 0 || alsa.mixer_max - alsa.mixer_min < 1000 || alsa.mixer_linear) {
901 alsa.mixer_linear = 1;
902 // unable to get db range or range is less than 10dB - ignore and set using raw values
903 if ((err = snd_mixer_selem_get_playback_volume_range(alsa.mixer_elem, &alsa.mixer_min, &alsa.mixer_max)) < 0)
904 {
905 LOG_ERROR("Unable to get volume raw range");
906 return -1;
907 }
908 }
909 return 0;
910 }
911
788912 static pthread_t thread;
789913
790 void output_init_alsa(log_level level, const char *device, unsigned output_buf_size, char *params, unsigned rates[],
791 unsigned rate_delay, unsigned rt_priority, unsigned idle, char *volume_mixer, bool mixer_unmute) {
914 void output_init_alsa(log_level level, const char *device, unsigned output_buf_size, char *params, unsigned rates[], unsigned rate_delay, unsigned rt_priority, unsigned idle, char *mixer_device, char *volume_mixer, bool mixer_unmute, bool mixer_linear) {
792915
793916 unsigned alsa_buffer = ALSA_BUFFER_TIME;
794917 unsigned alsa_period = ALSA_PERIOD_COUNT;
819942
820943 alsa.mmap = alsa_mmap;
821944 alsa.write_buf = NULL;
945 #if DSD
946 alsa.pcmfmt = 0;
947 #else
822948 alsa.format = 0;
949 #endif
823950 alsa.reopen = alsa_reopen;
824
825 if (!mixer_unmute) {
826 alsa.volume_mixer_name = volume_mixer_name;
827 alsa.volume_mixer_index = volume_mixer_index ? atoi(volume_mixer_index) : 0;
828 }
951 alsa.mixer_handle = NULL;
952 alsa.ctl = ctl4device(device);
953 alsa.mixer_ctl = mixer_device ? ctl4device(mixer_device) : alsa.ctl;
954 alsa.volume_mixer_name = volume_mixer_name;
955 alsa.mixer_linear = mixer_linear;
829956
830957 output.format = 0;
831958 output.buffer = alsa_buffer;
835962 output.rate_delay = rate_delay;
836963
837964 if (alsa_sample_fmt) {
965 #if DSD
966 if (!strcmp(alsa_sample_fmt, "32")) alsa.pcmfmt = SND_PCM_FORMAT_S32_LE;
967 if (!strcmp(alsa_sample_fmt, "24")) alsa.pcmfmt = SND_PCM_FORMAT_S24_LE;
968 if (!strcmp(alsa_sample_fmt, "24_3")) alsa.pcmfmt = SND_PCM_FORMAT_S24_3LE;
969 if (!strcmp(alsa_sample_fmt, "16")) alsa.pcmfmt = SND_PCM_FORMAT_S16_LE;
970 #else
838971 if (!strcmp(alsa_sample_fmt, "32")) alsa.format = SND_PCM_FORMAT_S32_LE;
839972 if (!strcmp(alsa_sample_fmt, "24")) alsa.format = SND_PCM_FORMAT_S24_LE;
840973 if (!strcmp(alsa_sample_fmt, "24_3")) alsa.format = SND_PCM_FORMAT_S24_3LE;
841974 if (!strcmp(alsa_sample_fmt, "16")) alsa.format = SND_PCM_FORMAT_S16_LE;
975 #endif
842976 }
843977
844978 LOG_INFO("requested alsa_buffer: %u alsa_period: %u format: %s mmap: %u", output.buffer, output.period,
847981 snd_lib_error_set_handler((snd_lib_error_handler_t)alsa_error_handler);
848982
849983 output_init_common(level, device, output_buf_size, rates, idle);
850
851 if (mixer_unmute && volume_mixer_name) {
852 set_mixer(output.device, volume_mixer_name, volume_mixer_index ? atoi(volume_mixer_index) : 0, true, 0, 0);
984
985 if (volume_mixer_name) {
986 if (mixer_init_alsa(alsa.mixer_ctl, alsa.volume_mixer_name, volume_mixer_index ?
987 atoi(volume_mixer_index) : 0) < 0)
988 {
989 LOG_ERROR("Initialization of mixer failed, reverting to software volume");
990 alsa.mixer_handle = NULL;
991 alsa.volume_mixer_name = NULL;
992 }
993 }
994 if (mixer_unmute && alsa.volume_mixer_name) {
995 set_mixer(true, 0, 0);
996 alsa.volume_mixer_name = NULL;
853997 }
854998
855999 #if LINUX
8611005 LOG_INFO("memory locked");
8621006 }
8631007
1008 #ifdef __GLIBC__
8641009 mallopt(M_TRIM_THRESHOLD, -1);
8651010 mallopt(M_MMAP_MAX, 0);
1011 LOG_INFO("glibc detected using mallopt");
1012 #endif
8661013
8671014 touch_memory(silencebuf, MAX_SILENCE_FRAMES * BYTES_PER_FRAME);
8681015 touch_memory(outputbuf->buf, outputbuf->size);
8951042 pthread_join(thread, NULL);
8961043
8971044 if (alsa.write_buf) free(alsa.write_buf);
1045 if (alsa.ctl) free(alsa.ctl);
1046 if (alsa.mixer_ctl) free(alsa.mixer_ctl);
1047 if (alsa.mixer_handle != NULL) snd_mixer_close(alsa.mixer_handle);
8981048
8991049 output_close_common();
9001050 }
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
2425 #if PORTAUDIO
2526
2627 #include <portaudio.h>
27 #if OSX
28
29 #if WIN
30 #ifndef PA18API
31 #include <pa_win_wasapi.h>
32 #endif
33 #define snprintf _snprintf
34 #endif
35
36 #if OSX && !defined(OSXPPC)
2837 #include <pa_mac_core.h>
2938 #endif
39
40 #if PA18API
41 typedef int PaDeviceIndex;
42 typedef double PaTime;
43
44 typedef struct PaStreamParameters
45 {
46 PaDeviceIndex device;
47 int channelCount;
48 PaSampleFormat sampleFormat;
49 PaTime suggestedLatency;
50
51 } PaStreamParameters;
52
53 static int paContinue=0; /* Signal that the stream should continue invoking the callback and processing audio. */
54 static int paComplete=1; /* Signal that the stream should stop invoking the callback and finish once all output */
55 /* samples have played. */
56
57 static unsigned paFramesPerBuffer = 4096;
58 static unsigned paNumberOfBuffers = 4;
59 #endif /* PA18API */
3060
3161 // ouput device
3262 static struct {
4676
4777 extern u8_t *silencebuf;
4878 #if DSD
49 extern u8_t *silencebuf_dop;
79 extern u8_t *silencebuf_dsd;
5080 #endif
5181
5282 void list_devices(void) {
5989 }
6090
6191 printf("Output devices:\n");
92 #ifndef PA18API
6293 for (i = 0; i < Pa_GetDeviceCount(); ++i) {
63 if (Pa_GetDeviceInfo(i)->maxOutputChannels) {
94 if (Pa_GetDeviceInfo(i)->maxOutputChannels > 1) {
6495 printf(" %i - %s [%s]\n", i, Pa_GetDeviceInfo(i)->name, Pa_GetHostApiInfo(Pa_GetDeviceInfo(i)->hostApi)->name);
6596 }
97 #else
98 for (i = 0; i < Pa_CountDevices(); ++i) {
99 printf(" %i - %s\n", i, Pa_GetDeviceInfo(i)->name);
100 #endif
66101 }
67102 printf("\n");
68103
84119 int i;
85120
86121 if (!strncmp(device, "default", 7)) {
122 #ifndef PA18API
87123 return Pa_GetDefaultOutputDevice();
124 #else
125 return Pa_GetDefaultOutputDeviceID();
126 #endif
88127 }
89128 if (len >= 1 && len <= 2 && device[0] >= '0' && device[0] <= '9') {
90129 return atoi(device);
91130 }
92131
132 #ifndef PA18API
93133 #define DEVICE_ID_MAXLEN 256
94134 for (i = 0; i < Pa_GetDeviceCount(); ++i) {
95135 char tmp[DEVICE_ID_MAXLEN];
96136 snprintf(tmp, DEVICE_ID_MAXLEN, "%s [%s]", Pa_GetDeviceInfo(i)->name, Pa_GetHostApiInfo(Pa_GetDeviceInfo(i)->hostApi)->name);
97137 if (!strncmp(tmp, device, len)) {
138 #else
139 for (i = 0; i < Pa_CountDevices(); ++i) {
140 if (!strncmp(Pa_GetDeviceInfo(i)->name, device, len)) {
141 #endif
98142 return i;
99143 }
100144 }
102146 return -1;
103147 }
104148
149 #ifndef PA18API
105150 static int pa_callback(const void *pa_input, void *pa_output, unsigned long pa_frames_wanted,
106151 const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData);
107152
108 bool test_open(const char *device, unsigned rates[]) {
153 #else
154 static int pa_callback(void *pa_input, void *pa_output, unsigned long pa_frames_wanted,
155 PaTimestamp outTime, void *userData);
156 #endif
157 bool test_open(const char *device, unsigned rates[], bool userdef_rates) {
109158 PaStreamParameters outputParameters;
110159 PaError err;
111160 unsigned ref[] TEST_RATES;
112161 int device_id, i, ind;
113
162 #if WIN
163 PaWasapiStreamInfo wasapiInfo;
164 const PaDeviceInfo * paDeviceInfo;
165 const PaHostApiInfo *paHostApiInfo;
166
167 #endif
114168 if ((device_id = pa_device_id(device)) == -1) {
115169 LOG_INFO("device %s not found", device);
116170 return false;
119173 outputParameters.device = device_id;
120174 outputParameters.channelCount = 2;
121175 outputParameters.sampleFormat = paInt32;
176 #ifndef PA18API
122177 outputParameters.suggestedLatency =
123178 output.latency ? (double)output.latency/(double)1000 : Pa_GetDeviceInfo(outputParameters.device)->defaultHighOutputLatency;
124179 outputParameters.hostApiSpecificStreamInfo = NULL;
180 #if WIN
181 paDeviceInfo = Pa_GetDeviceInfo( outputParameters.device );
182 paHostApiInfo = Pa_GetHostApiInfo ( paDeviceInfo->hostApi );
183
184 if ( paHostApiInfo != NULL )
185 {
186 if ( paHostApiInfo->type == paWASAPI )
187 {
188 /* Use exclusive mode for WasApi device, default is shared */
189 if (output.pa_hostapi_option == 1)
190 {
191 wasapiInfo.size = sizeof(PaWasapiStreamInfo);
192 wasapiInfo.hostApiType = paWASAPI;
193 wasapiInfo.version = 1;
194 wasapiInfo.flags = paWinWasapiExclusive;
195 outputParameters.hostApiSpecificStreamInfo = &wasapiInfo;
196 LOG_INFO("opening WASAPI device in exclusive mode");
197 }
198 }
199 }
200 #endif /* WIN */
201 #endif
125202
126203 // check supported sample rates
127204 // Note use Pa_OpenStream as it appears more reliable than Pa_IsFormatSupported on some windows apis
128205 for (i = 0, ind = 0; ref[i]; ++i) {
129 err = Pa_OpenStream(&pa.stream, NULL, &outputParameters, (double)ref[i], paFramesPerBufferUnspecified, paNoFlag,
130 pa_callback, NULL);
131 if (err == paNoError) {
132 Pa_CloseStream(pa.stream);
133 rates[ind++] = ref[i];
134 }
135 }
136
137 if (!rates[0]) {
206 #ifndef PA18API
207 err = Pa_OpenStream(&pa.stream, NULL, &outputParameters, (double)ref[i],
208 paFramesPerBufferUnspecified, paNoFlag, pa_callback, NULL);
209 #else
210 err = Pa_OpenStream(&pa.stream, paNoDevice, 0, 0, NULL, outputParameters.device,
211 outputParameters.channelCount, outputParameters.sampleFormat, NULL, (double)ref[i],
212 paFramesPerBuffer, paNumberOfBuffers, paNoFlag, pa_callback, NULL);
213 #endif
214 switch (err) {
215 case paInvalidSampleRate:
216 continue;
217 #if WIN
218 #ifndef PA18API
219 /* Ignore these errors for device probe */
220 case paUnanticipatedHostError:
221 continue;
222
223 case paInvalidDevice:
224 continue;
225 #endif
226 #endif
227 case paNoError:
228 Pa_CloseStream(pa.stream);
229 if (!userdef_rates) {
230 rates[ind++] = ref[i];
231 }
232 continue;
233
234 default:
235 /* Any other error is a failure */
236 LOG_WARN("error opening portaudio stream: %s", Pa_GetErrorText(err));
237 return false;
238 }
239 }
240
241 if (!rates[0] && !userdef_rates) {
138242 LOG_WARN("no available rate found");
139243 return false;
140244 }
212316 PaStreamParameters outputParameters;
213317 PaError err = paNoError;
214318 int device_id;
215
319 #if WIN
320 PaWasapiStreamInfo wasapiInfo;
321 const PaDeviceInfo * paDeviceInfo;
322 const PaHostApiInfo *paHostApiInfo;
323
324 #endif
216325 if (pa.stream) {
217326 if ((err = Pa_CloseStream(pa.stream)) != paNoError) {
218327 LOG_WARN("error closing stream: %s", Pa_GetErrorText(err));
233342 outputParameters.device = device_id;
234343 outputParameters.channelCount = 2;
235344 outputParameters.sampleFormat = paInt32;
345 #ifndef PA18API
236346 outputParameters.suggestedLatency =
237347 output.latency ? (double)output.latency/(double)1000 : Pa_GetDeviceInfo(outputParameters.device)->defaultHighOutputLatency;
238348 outputParameters.hostApiSpecificStreamInfo = NULL;
239349
240 #if OSX
241 // enable pro mode which aims to avoid resampling if possible
242 // see http://code.google.com/p/squeezelite/issues/detail?id=11 & http://code.google.com/p/squeezelite/issues/detail?id=37
243 // command line controls osx_playnice which is -1 if not specified, 0 or 1 - choose playnice if -1 or 1
350 #endif
351 #if OSX && !defined(OSXPPC)
352 /* enable pro mode which aims to avoid resampling if possible */
353 /* command line controls pa_hostapi_option which is -1 if not specified, 0 or 1 - choose playnice if -1 or 1 */
244354 PaMacCoreStreamInfo macInfo;
245355 unsigned long streamInfoFlags;
246 if (output.osx_playnice) {
356 if (output.pa_hostapi_option) {
247357 LOG_INFO("opening device in PlayNice mode");
248358 streamInfoFlags = paMacCorePlayNice;
249359 } else {
253363 PaMacCore_SetupStreamInfo(&macInfo, streamInfoFlags);
254364 outputParameters.hostApiSpecificStreamInfo = &macInfo;
255365 #endif
366 #if WIN
367 paDeviceInfo = Pa_GetDeviceInfo( outputParameters.device );
368 paHostApiInfo = Pa_GetHostApiInfo ( paDeviceInfo->hostApi );
369
370 if ( paHostApiInfo != NULL )
371 {
372 if ( paHostApiInfo->type == paWASAPI )
373 {
374 /* Use exclusive mode for WasApi device, default is shared */
375 if (output.pa_hostapi_option == 1)
376 {
377 wasapiInfo.size = sizeof(PaWasapiStreamInfo);
378 wasapiInfo.hostApiType = paWASAPI;
379 wasapiInfo.version = 1;
380 wasapiInfo.flags = paWinWasapiExclusive;
381 outputParameters.hostApiSpecificStreamInfo = &wasapiInfo;
382 LOG_INFO("opening WASAPI device in exclusive mode");
383 }
384 }
385 }
386 #endif
256387 }
257388
258389 if (!err &&
390 #ifndef PA18API
259391 (err = Pa_OpenStream(&pa.stream, NULL, &outputParameters, (double)output.current_sample_rate, paFramesPerBufferUnspecified,
260392 paPrimeOutputBuffersUsingStreamCallback | paDitherOff, pa_callback, NULL)) != paNoError) {
393 LOG_WARN("error opening device %i - %s [%s] : %s", outputParameters.device, Pa_GetDeviceInfo(outputParameters.device)->name,
394 Pa_GetHostApiInfo(Pa_GetDeviceInfo(outputParameters.device)->hostApi)->name, Pa_GetErrorText(err));
395 #else
396 (err = Pa_OpenStream(&pa.stream, paNoDevice, 0, 0, NULL, outputParameters.device, outputParameters.channelCount,
397 outputParameters.sampleFormat, NULL, (double)output.current_sample_rate, paFramesPerBuffer,
398 paNumberOfBuffers, paDitherOff, pa_callback, NULL)) != paNoError) {
261399 LOG_WARN("error opening device %i - %s : %s", outputParameters.device, Pa_GetDeviceInfo(outputParameters.device)->name,
262400 Pa_GetErrorText(err));
401 #endif
263402 }
264403
265404 if (!err) {
266 LOG_INFO("opened device %i - %s at %u latency %u ms", outputParameters.device, Pa_GetDeviceInfo(outputParameters.device)->name,
405 #ifndef PA18API
406 LOG_INFO("opened device %i - %s [%s] at %u latency %u ms", outputParameters.device, Pa_GetDeviceInfo(outputParameters.device)->name,
407 Pa_GetHostApiInfo(Pa_GetDeviceInfo(outputParameters.device)->hostApi)->name,
267408 (unsigned int)Pa_GetStreamInfo(pa.stream)->sampleRate, (unsigned int)(Pa_GetStreamInfo(pa.stream)->outputLatency * 1000));
268
409 #else
410 LOG_INFO("opened device %i - %s at %u fpb %u nbf %u", outputParameters.device, Pa_GetDeviceInfo(outputParameters.device)->name,
411 (unsigned int)output.current_sample_rate, paFramesPerBuffer, paNumberOfBuffers);
412
413 #endif
269414 pa.rate = output.current_sample_rate;
270415
416 #ifndef PA18API
271417 if ((err = Pa_SetStreamFinishedCallback(pa.stream, pa_stream_finished)) != paNoError) {
272418 LOG_WARN("error setting finish callback: %s", Pa_GetErrorText(err));
273419 }
274420
275421 UNLOCK; // StartStream can call pa_callback in a sychronised thread on freebsd, remove lock while it is called
276422
423 #endif
277424 if ((err = Pa_StartStream(pa.stream)) != paNoError) {
278425 LOG_WARN("error starting stream: %s", Pa_GetErrorText(err));
279426 }
280427
428 #ifndef PA18API
281429 LOCK;
430 #endif
282431 }
283432
284433 if (err && !monitor_thread_running) {
312461 }
313462
314463 IF_DSD(
315 if (output.dop) {
464 if (output.outfmt == DOP) {
316465 update_dop((u32_t *) outputbuf->readp, out_frames, output.invert);
317 }
466 } else if (output.outfmt != PCM && output.invert)
467 dsd_invert((u32_t *) outputbuf->readp, out_frames);
318468 )
319469
320470 memcpy(optr, outputbuf->readp, out_frames * BYTES_PER_FRAME);
324474 u8_t *buf = silencebuf;
325475
326476 IF_DSD(
327 if (output.dop) {
328 buf = silencebuf_dop;
477 if (output.outfmt != PCM) {
478 buf = silencebuf_dsd;
329479 update_dop((u32_t *) buf, out_frames, false); // don't invert silence
330480 }
331481 )
338488 return (int)out_frames;
339489 }
340490
491 #ifndef PA18API
341492 static int pa_callback(const void *pa_input, void *pa_output, unsigned long pa_frames_wanted,
342493 const PaStreamCallbackTimeInfo *time_info, PaStreamCallbackFlags statusFlags, void *userData) {
494 #else
495 static int pa_callback(void *pa_input, void *pa_output, unsigned long pa_frames_wanted,PaTimestamp outTime, void *userData) {
496 #endif
343497 int ret;
344 double stream_time;
345498 frames_t frames;
346499
347500 optr = (u8_t *)pa_output;
348501
349502 LOCK;
350503
351 stream_time = Pa_GetStreamTime(pa.stream);
352
353 if (time_info->outputBufferDacTime > stream_time) {
504 #ifndef PA18API
505 if (time_info->outputBufferDacTime > time_info->currentTime) {
354506 // workaround for wdm-ks which can return outputBufferDacTime with a different epoch
355 output.device_frames = (unsigned)((time_info->outputBufferDacTime - stream_time) * output.current_sample_rate);
507 output.device_frames = (unsigned)((time_info->outputBufferDacTime - time_info->currentTime) * output.current_sample_rate);
356508 } else {
357509 output.device_frames = 0;
358510 }
359511
512 #else
513 output.device_frames = 0;
514 #endif
360515 output.updated = gettime_ms();
361516 output.frames_played_dmp = output.frames_played;
362517
381536
382537 UNLOCK;
383538
539 #ifdef PA18API
540 if ( ret == paComplete )
541 pa_stream_finished (userData);
542 #endif
384543 return ret;
385544 }
386545
387546 void output_init_pa(log_level level, const char *device, unsigned output_buf_size, char *params, unsigned rates[], unsigned rate_delay,
388547 unsigned idle) {
389548 PaError err;
549 #ifndef PA18API
390550 unsigned latency = 0;
391 int osx_playnice = -1;
392
551 int pa_hostapi_option = -1;
552
553 #else
554 unsigned pa_frames = 0;
555 unsigned pa_nbufs = 0;
556 #endif /* PA18API */
557 #ifndef PA18API
393558 char *l = next_param(params, ':');
394559 char *p = next_param(NULL, ':');
395560
396561 if (l) latency = (unsigned)atoi(l);
397 if (p) osx_playnice = atoi(p);
562 if (p) pa_hostapi_option = atoi(p);
563 #else
564 char *t = next_param(params, ':');
565 char *c = next_param(NULL, ':');
566 if (t) pa_frames = atoi(t);
567 if (c) pa_nbufs = atoi(c);
568 #endif
398569
399570 loglevel = level;
400571
402573
403574 memset(&output, 0, sizeof(output));
404575
576 #ifndef PA18API
405577 output.latency = latency;
406 output.osx_playnice = osx_playnice;
578 output.pa_hostapi_option = pa_hostapi_option;
579 #else
580 if ( pa_frames != 0 )
581 paFramesPerBuffer = pa_frames;
582 if ( pa_nbufs != 0 )
583 paNumberOfBuffers = pa_nbufs;
584 #endif /* PA18API */
407585 output.format = 0;
408586 output.start_frames = 0;
409587 output.write_cb = &_write_frames;
410588 output.rate_delay = rate_delay;
411589 pa.stream = NULL;
412590
591 #ifndef PA18API
413592 LOG_INFO("requested latency: %u", output.latency);
593 #endif
414594
415595 if ((err = Pa_Initialize()) != paNoError) {
416596 LOG_WARN("error initialising port audio: %s", Pa_GetErrorText(err));
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
4344
4445 void _scale_and_pack_frames(void *outputptr, s32_t *inputptr, frames_t cnt, s32_t gainL, s32_t gainR, output_format format) {
4546 switch(format) {
47 #if DSD
48 case U32_LE:
49 {
50 #if SL_LITTLE_ENDIAN
51 memcpy(outputptr, inputptr, cnt * BYTES_PER_FRAME);
52 #else
53 u32_t *optr = (u32_t *)(void *)outputptr;
54 while (cnt--) {
55 s32_t lsample = *(inputptr++);
56 s32_t rsample = *(inputptr++);
57 *(optr++) =
58 (lsample & 0xff000000) >> 24 | (lsample & 0x00ff0000) >> 8 |
59 (lsample & 0x0000ff00) << 8 | (lsample & 0x000000ff) << 24;
60 *(optr++) =
61 (rsample & 0xff000000) >> 24 | (rsample & 0x00ff0000) >> 8 |
62 (rsample & 0x0000ff00) << 8 | (rsample & 0x000000ff) << 24;
63 }
64 #endif
65 }
66 break;
67 case U32_BE:
68 {
69 #if SL_LITTLE_ENDIAN
70 u32_t *optr = (u32_t *)(void *)outputptr;
71 while (cnt--) {
72 s32_t lsample = *(inputptr++);
73 s32_t rsample = *(inputptr++);
74 *(optr++) =
75 (lsample & 0xff000000) >> 24 | (lsample & 0x00ff0000) >> 8 |
76 (lsample & 0x0000ff00) << 8 | (lsample & 0x000000ff) << 24;
77 *(optr++) =
78 (rsample & 0xff000000) >> 24 | (rsample & 0x00ff0000) >> 8 |
79 (rsample & 0x0000ff00) << 8 | (rsample & 0x000000ff) << 24;
80 }
81 #else
82 memcpy(outputptr, inputptr, cnt * BYTES_PER_FRAME);
83 #endif
84 }
85 break;
86 case U16_LE:
87 {
88 u32_t *optr = (u32_t *)(void *)outputptr;
89 #if SL_LITTLE_ENDIAN
90 while (cnt--) {
91 *(optr++) = (*(inputptr) >> 16 & 0x0000ffff) | (*(inputptr + 1) & 0xffff0000);
92 inputptr += 2;
93 }
94 #else
95 while (cnt--) {
96 s32_t lsample = *(inputptr++);
97 s32_t rsample = *(inputptr++);
98 *(optr++) =
99 (lsample & 0x00ff0000) << 8 | (lsample & 0xff000000) >> 8 |
100 (rsample & 0x00ff0000) >> 8 | (rsample & 0xff000000) >> 24;
101 }
102 #endif
103 }
104 break;
105 case U16_BE:
106 {
107 u32_t *optr = (u32_t *)(void *)outputptr;
108 #if SL_LITTLE_ENDIAN
109 while (cnt--) {
110 s32_t lsample = *(inputptr++);
111 s32_t rsample = *(inputptr++);
112 *(optr++) =
113 (lsample & 0xff000000) >> 24 | (lsample & 0x00ff0000) >> 8 |
114 (rsample & 0xff000000) >> 8 | (rsample & 0x00ff0000) << 8;
115 }
116 #else
117 while (cnt--) {
118 *(optr++) = (*(inputptr) & 0xffff0000) | (*(inputptr + 1) >> 16 & 0x0000ffff);
119 inputptr += 2;
120 }
121 #endif
122 }
123 break;
124 case U8:
125 {
126 u16_t *optr = (u16_t *)(void *)outputptr;
127 #if SL_LITTLE_ENDIAN
128 while (cnt--) {
129 *(optr++) = (u16_t)((*(inputptr) >> 24 & 0x000000ff) | (*(inputptr + 1) >> 16 & 0x0000ff00));
130 inputptr += 2;
131 }
132 #else
133 while (cnt--) {
134 *(optr++) = (u16_t)((*(inputptr) >> 16 & 0x0000ff00) | (*(inputptr + 1) >> 24 & 0x000000ff));
135 inputptr += 2;
136 }
137 #endif
138 }
139 break;
140 #endif
46141 case S16_LE:
47142 {
48143 u32_t *optr = (u32_t *)(void *)outputptr;
0 /*
1 * Squeezelite - lightweight headless squeezebox emulator
2 *
3 * (c) Adrian Smith 2012-2015, triode1@btinternet.com
4 * Ralph Irving 2015-2020, ralph_irving@hotmail.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 * Additions (c) Paul Hermann, 2015-2017 under the same license terms
20 * -Control of Raspberry pi GPIO for amplifier power
21 * -Launch script on power status change from LMS
22 */
23
24 // Output using PulseAudio
25
26 #include "squeezelite.h"
27
28 #if PULSEAUDIO
29
30 #include <pulse/pulseaudio.h>
31 #include <math.h>
32
33 // To report timing information back to the LMS the latency information needs to be
34 // retrieved from the PulseAudio server. However this eats some CPU cycles and a few
35 // bytes of RAM. Here you can decide if you want to retrieve precise timing information
36 // or save a few CPU cycles. If you are running squeezelite on resource constrained
37 // device (e.g. Raspberry Pi) and you want to keep the CPU temperature down then you
38 // can set the PULSEAUDIO_TIMING to zero. In this case the sound card latency and
39 // PulseAudio buffering won't be accounted for which might give you a slightly skewed
40 // playback timing information. Otherwise keep this to default value of 2 and you
41 // will get precise timing information.
42 #ifndef PULSEAUDIO_TIMING
43 # define PULSEAUDIO_TIMING 2
44 #endif
45
46 typedef enum {
47 readiness_unknown,
48 readiness_ready,
49 readiness_terminated,
50 } pulse_readiness;
51
52 typedef struct {
53 pa_mainloop *loop;
54 pa_context *ctx;
55 pulse_readiness readiness;
56 } pulse_connection;
57
58 struct pulse {
59 bool running;
60 pa_stream *stream;
61 pulse_readiness stream_readiness;
62 pulse_connection conn;
63 pa_sample_spec sample_spec;
64 char *sink_name;
65 };
66
67 static struct pulse pulse;
68
69 static log_level loglevel;
70
71 extern struct outputstate output;
72 extern struct buffer *outputbuf;
73
74 #define OUTPUT_STATE_TIMER_INTERVAL_USEC 100000
75
76 #define LOCK mutex_lock(outputbuf->mutex)
77 #define UNLOCK mutex_unlock(outputbuf->mutex)
78
79 extern u8_t *silencebuf;
80
81 static void pulse_state_cb(pa_context *c, void *userdata) {
82 pa_context_state_t state;
83 pulse_connection *conn = userdata;
84
85 state = pa_context_get_state(c);
86 switch (state) {
87 // There are just here for reference
88 case PA_CONTEXT_UNCONNECTED:
89 case PA_CONTEXT_CONNECTING:
90 case PA_CONTEXT_AUTHORIZING:
91 case PA_CONTEXT_SETTING_NAME:
92 default:
93 break;
94 case PA_CONTEXT_FAILED:
95 case PA_CONTEXT_TERMINATED:
96 conn->readiness = readiness_terminated;
97 break;
98 case PA_CONTEXT_READY:
99 conn->readiness = readiness_ready;
100 break;
101 }
102 }
103
104 static inline bool pulse_connection_is_ready(pulse_connection *conn) {
105 return conn->readiness == readiness_ready;
106 }
107
108 static inline bool pulse_connection_check_ready(pulse_connection *conn) {
109 if (!pulse_connection_is_ready(conn)) {
110 LOG_ERROR("connection to PulseAudio server has been terminated");
111 return false;
112 }
113 return true;
114 }
115
116 static inline void pulse_connection_iterate(pulse_connection *conn) {
117 pa_mainloop_iterate(conn->loop, 1, NULL);
118 }
119
120 static inline pa_context * pulse_connection_get_context(pulse_connection *conn) {
121 return conn->ctx;
122 }
123
124 static bool pulse_connection_init(pulse_connection *conn) {
125 bool ret;
126
127 conn->loop = pa_mainloop_new();
128 pa_mainloop_api *api = pa_mainloop_get_api(conn->loop);
129 pa_proplist *proplist = pa_proplist_new();
130 pa_proplist_sets(proplist, PA_PROP_APPLICATION_VERSION, VERSION);
131 conn->ctx = pa_context_new_with_proplist(api, MODEL_NAME_STRING, proplist);
132 pa_proplist_free(proplist);
133
134 conn->readiness = readiness_unknown;
135
136 bool connected = false;
137
138 if (pa_context_connect(conn->ctx, (const char *)NULL, PA_CONTEXT_NOFLAGS, (const pa_spawn_api *)NULL) < 0) {
139 LOG_ERROR("failed to connect to PulseAudio server: %s", pa_strerror(pa_context_errno(conn->ctx)));
140 ret = false;
141 } else {
142 connected = true;
143 pa_context_set_state_callback(conn->ctx, pulse_state_cb, conn);
144 while (conn->readiness == readiness_unknown) {
145 pa_mainloop_iterate(conn->loop, 1, NULL);
146 }
147
148 ret = pulse_connection_is_ready(conn);
149 }
150
151 if (!ret) {
152 if (connected) pa_context_disconnect(conn->ctx);
153 pa_context_unref(conn->ctx);
154 pa_mainloop_free(conn->loop);
155 }
156
157 return ret;
158 }
159
160 static void pulse_connection_destroy(pulse_connection *conn) {
161 pa_context_disconnect(conn->ctx);
162 pa_context_unref(conn->ctx);
163 pa_mainloop_free(conn->loop);
164 }
165
166 static bool pulse_operation_wait(pulse_connection *conn, pa_operation *op) {
167 if (op == NULL) {
168 LOG_ERROR("PulseAudio operation failed: %s", pa_strerror(pa_context_errno(conn->ctx)));
169 return false;
170 }
171
172 pa_operation_state_t op_state;
173 while (pulse_connection_check_ready(conn) && (op_state = pa_operation_get_state(op)) == PA_OPERATION_RUNNING) {
174 pulse_connection_iterate(conn);
175 }
176
177 pa_operation_unref(op);
178
179 if (!pulse_connection_is_ready(conn))
180 return false;
181
182 return op_state == PA_OPERATION_DONE;
183 }
184
185 static void pulse_stream_state_cb(pa_stream *stream, void *userdata) {
186 struct pulse *p = userdata;
187 switch (pa_stream_get_state(stream)) {
188 case PA_STREAM_UNCONNECTED:
189 case PA_STREAM_CREATING:
190 p->stream_readiness = readiness_unknown;
191 break;
192 case PA_STREAM_READY:
193 p->stream_readiness = readiness_ready;
194 break;
195 case PA_STREAM_FAILED:
196 case PA_STREAM_TERMINATED:
197 p->stream_readiness = readiness_terminated;
198 break;
199 }
200 }
201
202 static void pulse_stream_success_noop_cb(pa_stream *s, int success, void *userdata) {
203 }
204
205 static bool pulse_stream_create(struct pulse *p) {
206 p->sample_spec.rate = output.current_sample_rate;
207 p->sample_spec.format = PA_SAMPLE_S32LE; // SqueezeLite internally always uses this format, let PulseAudio deal with eventual resampling.
208 p->sample_spec.channels = 2;
209
210 pa_proplist *proplist = pa_proplist_new();
211 pa_proplist_sets(proplist, PA_PROP_MEDIA_ROLE, "music");
212 pa_proplist_sets(proplist, PA_PROP_MEDIA_SOFTWARE, "Logitech Media Server");
213
214 p->stream = pa_stream_new_with_proplist(pulse_connection_get_context(&p->conn), "Logitech Media Server stream", &p->sample_spec, (const pa_channel_map *)NULL, proplist);
215 pa_proplist_free(proplist);
216 if (p->stream == NULL)
217 return false;
218
219 p->stream_readiness = readiness_unknown;
220 pa_stream_set_state_callback(p->stream, pulse_stream_state_cb, p);
221
222 if (pa_stream_connect_playback(p->stream, p->sink_name, (const pa_buffer_attr *)NULL,
223 #if PULSEAUDIO_TIMING == 2
224 PA_STREAM_VARIABLE_RATE | PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_INTERPOLATE_TIMING,
225 #else
226 PA_STREAM_VARIABLE_RATE,
227 #endif
228 (const pa_cvolume *)NULL, (pa_stream *)NULL) < 0) {
229 pa_stream_unref(p->stream);
230 p->stream = NULL;
231 return false;
232 }
233
234 bool ok;
235 while ((ok = pulse_connection_check_ready(&p->conn) && p->running) && p->stream_readiness == readiness_unknown) {
236 pulse_connection_iterate(&p->conn);
237 }
238
239 ok = ok && p->stream_readiness == readiness_ready;
240
241 if (ok) {
242 pa_buffer_attr attr = { 0, };
243 attr.maxlength = (uint32_t)(-1);
244 attr.tlength = (uint32_t)(-1);
245 attr.prebuf = (uint32_t)(-1);
246 attr.minreq = (uint32_t)(-1);
247 pa_operation *op = pa_stream_set_buffer_attr(p->stream, &attr, pulse_stream_success_noop_cb, NULL);
248 ok = pulse_operation_wait(&p->conn, op);
249 }
250
251 if (!ok) {
252 pa_stream_disconnect(p->stream);
253 pa_stream_unref(p->stream);
254 p->stream = NULL;
255 }
256
257 return ok;
258 }
259
260 static void pulse_stream_destroy(struct pulse *p) {
261 if (p->stream) {
262 pa_stream_disconnect(p->stream);
263 pa_stream_unref(p->stream);
264 p->stream = NULL;
265 }
266 }
267
268 static void pulse_sinklist_cb(pa_context *c, const pa_sink_info *l, int eol, void *userdata) {
269 if (eol == 0) {
270 printf(" %-50s %s\n", l->name, l->description);
271 } else if (eol < 0) {
272 LOG_WARN("error while listing PulseAudio sinks");
273 }
274 }
275
276 void list_devices(void) {
277 pulse_connection conn;
278 if (!pulse_connection_init(&conn))
279 return;
280
281 int state = 0;
282 pa_operation *op;
283
284 while (pulse_connection_check_ready(&conn)) {
285 if (state == 0) {
286 printf("Output devices:\n");
287 op = pa_context_get_sink_info_list(pulse_connection_get_context(&conn), pulse_sinklist_cb, NULL);
288 ++state;
289 } else if (pa_operation_get_state(op) == PA_OPERATION_DONE) {
290 pa_operation_unref(op);
291 break;
292 }
293
294 pulse_connection_iterate(&conn);
295 }
296
297 pulse_connection_destroy(&conn);
298 }
299
300 static void pulse_set_volume(struct pulse *p, unsigned left, unsigned right) {
301 uint32_t sink_input_idx = pa_stream_get_index(p->stream);
302 pa_cvolume volume;
303 pa_cvolume_init(&volume);
304 volume.channels = 2;
305 volume.values[0] = pa_sw_volume_from_dB(20 * log10(left / 65536.0));
306 volume.values[1] = left == right ? volume.values[0] : pa_sw_volume_from_dB(20 * log10(right / 65536.0));
307 pa_operation *op = pa_context_set_sink_input_volume(pulse_connection_get_context(&p->conn), sink_input_idx, &volume, NULL, NULL);
308 if (op != NULL) {
309 // This is send and forget operation, dereference it right away.
310 if (loglevel >= lDEBUG) {
311 char s[20];
312 LOG_DEBUG("sink input volume set to %s", pa_cvolume_snprint(s, sizeof(s), &volume));
313 }
314 pa_operation_unref(op);
315 }
316 }
317
318 void set_volume(unsigned left, unsigned right) {
319 bool adjust_sink_input = false;
320
321 LOCK;
322 adjust_sink_input = (left != output.gainL) || (right != output.gainR);
323 output.gainL = left;
324 output.gainR = right;
325 UNLOCK;
326
327 if (adjust_sink_input && pulse.stream != NULL) {
328 pulse_set_volume(&pulse, left, right);
329 }
330 }
331
332 void set_sample_rate(uint32_t sample_rate) {
333 pa_operation *op = pa_stream_update_sample_rate(pulse.stream, sample_rate, NULL, NULL);
334 if (op != NULL) {
335 if (loglevel >= lDEBUG) {
336 LOG_DEBUG("stream sample rate set to %d Hz", sample_rate);
337 }
338 pa_operation_unref(op);
339 }
340 else {
341 LOG_WARN("failed to set stream sample rate to %d Hz", sample_rate);
342 }
343 }
344
345 struct test_open_data {
346 unsigned *rates;
347 bool userdef_rates;
348 pa_sample_spec *sample_spec;
349 bool is_default_device;
350 char *default_sink_name;
351 bool got_device;
352 };
353
354 static void pulse_sinkinfo_cb(pa_context *c, const pa_sink_info *l, int eol, void *userdata) {
355 if (eol) return;
356
357 struct test_open_data *d = userdata;
358 d->got_device = true;
359
360 if (d->is_default_device)
361 d->default_sink_name = strdup(l->name);
362
363 if (!d->userdef_rates) {
364 d->rates[0] = l->sample_spec.rate;
365 }
366
367 *d->sample_spec = l->sample_spec;
368 }
369
370 bool test_open(const char *device, unsigned rates[], bool userdef_rates) {
371 struct test_open_data d = {0, };
372 d.rates = rates;
373 d.userdef_rates = userdef_rates;
374 d.sample_spec = &pulse.sample_spec;
375 d.is_default_device = strcmp(device, "default") == 0;
376 const char *sink_name = d.is_default_device ? NULL : device;
377 pa_operation *op = pa_context_get_sink_info_by_name(pulse_connection_get_context(&pulse.conn), sink_name, pulse_sinkinfo_cb, &d);
378 if (!pulse_operation_wait(&pulse.conn, op))
379 return false;
380 if (!d.got_device)
381 return false;
382
383 pulse.sink_name = d.is_default_device ? d.default_sink_name : (char *)device;
384
385 return true;
386 }
387
388 static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR,
389 s32_t cross_gain_in, s32_t cross_gain_out, s32_t **cross_ptr) {
390 pa_stream_write(pulse.stream, silence ? silencebuf : outputbuf->readp, out_frames * BYTES_PER_FRAME, (pa_free_cb_t)NULL, 0, PA_SEEK_RELATIVE);
391 return (int)out_frames;
392 }
393
394 void output_state_timer_cb(pa_mainloop_api *api, pa_time_event *e, const struct timeval *tv_, void *userdata) {
395 struct pulse *p = userdata;
396 pa_context_rttime_restart(pulse_connection_get_context(&p->conn), e, pa_rtclock_now() + OUTPUT_STATE_TIMER_INTERVAL_USEC);
397 }
398
399 #if PULSEAUDIO_TIMING == 0
400 # define DECLARE_LATENCY(n) (void)0
401 # define pulse_retrieve_latency(n) true
402 # define pulse_get_latency(n) 0
403 #elif PULSEAUDIO_TIMING == 2
404 # define DECLARE_LATENCY(n) pa_usec_t n
405 static inline bool pulse_retrieve_latency(pa_usec_t *usec) {
406 return pa_stream_get_latency(pulse.stream, usec, NULL) == 0;
407 }
408 #endif
409
410 #if PULSEAUDIO_TIMING > 0
411 static inline unsigned pulse_get_latency(pa_usec_t usec) {
412 return (unsigned)((usec * output.current_sample_rate) / PA_USEC_PER_SEC);
413 }
414 #endif
415
416 static void * output_thread(void *arg) {
417 bool output_off = (output.state == OUTPUT_OFF);
418 pa_time_event *output_state_timer = NULL;
419
420 while (pulse.running) {
421 if (output_off) {
422 if (pulse.stream != NULL) {
423 LOG_DEBUG("destroying PulseAudio playback stream");
424 pulse_stream_destroy(&pulse);
425 }
426
427 if (output_state_timer == NULL) {
428 output_state_timer = pa_context_rttime_new(pulse_connection_get_context(&pulse.conn),
429 pa_rtclock_now() + OUTPUT_STATE_TIMER_INTERVAL_USEC, output_state_timer_cb, &pulse);
430 }
431 } else {
432 if (output_state_timer != NULL) {
433 pa_mainloop_api *api = pa_mainloop_get_api(pulse.conn.loop);
434 api->time_free(output_state_timer);
435 output_state_timer = NULL;
436 }
437
438 if (pulse.stream == NULL) {
439 if (pulse_stream_create(&pulse)) {
440 LOG_DEBUG("PulseAudio playback stream on sink %s open", pulse.sink_name);
441
442 unsigned left, right;
443 LOCK;
444 left = output.gainL;
445 right = output.gainR;
446 UNLOCK;
447 pulse_set_volume(&pulse, left, right);
448 } else {
449 if (!pulse.running)
450 break;
451 output.error_opening = true;
452 }
453 }
454
455 if (pulse.stream != NULL) {
456 size_t writable = pa_stream_writable_size(pulse.stream);
457 if (writable > 0) {
458
459 DECLARE_LATENCY(latency);
460 bool latency_ok = pulse_retrieve_latency(&latency);
461
462 frames_t frame_count = writable / pa_sample_size(pa_stream_get_sample_spec(pulse.stream));
463
464 LOCK;
465
466 if (latency_ok) {
467 output.device_frames = pulse_get_latency(latency);
468 output.updated = gettime_ms();
469 output.frames_played_dmp = output.frames_played;
470 }
471
472 _output_frames(frame_count);
473
474 UNLOCK;
475 }
476 }
477 }
478
479 pulse_connection_iterate(&pulse.conn);
480
481 output_off = (output.state == OUTPUT_OFF);
482 }
483
484 pulse_stream_destroy(&pulse);
485
486 return NULL;
487 }
488
489 static pthread_t thread;
490
491 void output_init_pulse(log_level level, const char *device, unsigned output_buf_size, char *params, unsigned rates[], unsigned rate_delay, unsigned idle) {
492 loglevel = level;
493
494 LOG_INFO("init output");
495
496 output.format = 0;
497 output.start_frames = 0;
498 output.write_cb = &_write_frames;
499 output.rate_delay = rate_delay;
500
501 if (!pulse_connection_init(&pulse.conn)) {
502 // In case of an error, the message is logged by the pulse_connection_init itself.
503 exit(1);
504 }
505
506 output_init_common(level, device, output_buf_size, rates, idle);
507
508 // start output thread
509 pulse.running = true;
510 pthread_attr_t attr;
511 pthread_attr_init(&attr);
512 pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN + OUTPUT_THREAD_STACK_SIZE);
513 pthread_create(&thread, &attr, output_thread, NULL);
514 pthread_attr_destroy(&attr);
515 }
516
517 void output_close_pulse(void) {
518 LOG_INFO("close output");
519
520 pulse.running = false;
521 pa_mainloop_wakeup(pulse.conn.loop);
522 pthread_join(thread, NULL);
523
524 if (output.device != pulse.sink_name)
525 free(pulse.sink_name);
526
527 pulse_connection_destroy(&pulse.conn);
528
529 output_close_common();
530 }
531
532 #endif
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
3536
3637 extern u8_t *silencebuf;
3738 #if DSD
38 extern u8_t *silencebuf_dop;
39 extern u8_t *silencebuf_dsd;
3940 #endif
4041
4142 // buffer to hold output data so we can block on writing outside of output lock, allocated on init
6263 }
6364
6465 IF_DSD(
65 if (output.dop) {
66 if (output.outfmt != PCM) {
6667 if (silence) {
67 obuf = silencebuf_dop;
68 obuf = silencebuf_dsd;
6869 }
69 update_dop((u32_t *)obuf, out_frames, output.invert && !silence);
70 if (output.outfmt == DOP)
71 update_dop((u32_t *)obuf, out_frames, output.invert && !silence);
72 else if (output.invert && !silence)
73 dsd_invert((u32_t *)obuf, out_frames);
7074 }
7175 )
7276
154158 #if LINUX || OSX || FREEBSD
155159 pthread_attr_t attr;
156160 pthread_attr_init(&attr);
161 #ifdef PTHREAD_STACK_MIN
157162 pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN + OUTPUT_THREAD_STACK_SIZE);
163 #endif
158164 pthread_create(&thread, &attr, output_thread, NULL);
159165 pthread_attr_destroy(&attr);
160166 #endif
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
1718 *
1819 */
1920
20 // Export audio samples for visualiser process (16 bit only best endevours)
21 // Export audio samples for visualizer process (16 bit only best endevours)
2122
2223 #include "squeezelite.h"
2324
2627 #include <sys/stat.h>
2728 #include <sys/mman.h>
2829 #include <fcntl.h>
30 #if OSX
31 #include <mach/clock.h>
32 #include <mach/mach.h>
33
34 static int pthread_rwlock_timedwrlock( pthread_rwlock_t * restrict rwlock, const struct timespec * restrict abs_timeout )
35 {
36 ( void )rwlock;
37 ( void )abs_timeout;
38
39 return 0;
40 }
41 #endif
2942
3043 #define VIS_BUF_SIZE 16384
3144 #define VIS_LOCK_NS 1000000 // ns to wait for vis wrlock
5467 err = pthread_rwlock_trywrlock(&vis_mmap->rwlock);
5568 if (err) {
5669 struct timespec ts;
70 #if OSX
71 clock_serv_t cclock;
72 mach_timespec_t mts;
73 host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
74 clock_get_time(cclock, &mts);
75 mach_port_deallocate(mach_task_self(), cclock);
76 ts.tv_sec = mts.tv_sec;
77 ts.tv_nsec = mts.tv_nsec;
78 #else
5779 clock_gettime(CLOCK_REALTIME, &ts);
80 #endif
5881 ts.tv_nsec += VIS_LOCK_NS;
5982 if (ts.tv_nsec > 1000000000) {
6083 ts.tv_sec += 1;
115138
116139 mode_t old_mask = umask(000); // allow any user to read our shm when created
117140
141 #if OSX
142 /* ftruncate on MacOS only works on the initial segment creation */
143 shm_unlink(vis_shm_path);
144 #endif
118145 vis_fd = shm_open(vis_shm_path, O_CREAT | O_RDWR, 0666);
119146 if (vis_fd != -1) {
120147 if (ftruncate(vis_fd, sizeof(struct vis_t)) == 0) {
+138
-36
pcm.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
1920
2021 #include "squeezelite.h"
2122
23 #if BYTES_PER_FRAME == 4
24 #define SHIFT 16
25 #define OPTR_T u16_t
26 #else
27 #define OPTR_T u32_t
28 #define SHIFT 0
29 #endif
30
2231 extern log_level loglevel;
2332
2433 extern struct buffer *streambuf;
2736 extern struct outputstate output;
2837 extern struct decodestate decode;
2938 extern struct processstate process;
39
40 bool pcm_check_header = false;
3041
3142 #define LOCK_S mutex_lock(streambuf->mutex)
3243 #define UNLOCK_S mutex_unlock(streambuf->mutex)
5162 #define MAX_DECODE_FRAMES 4096
5263
5364 static u32_t sample_rates[] = {
54 11025, 22050, 32000, 44100, 48000, 8000, 12000, 16000, 24000, 96000, 88200, 176400, 192000, 352800, 384000
65 11025, 22050, 32000, 44100, 48000, 8000, 12000, 16000, 24000, 96000, 88200, 176400, 192000, 352800, 384000, 705600, 768000
5566 };
5667
5768 static u32_t sample_rate;
103114 ptr += 8;
104115 _buf_inc_readp(streambuf, ptr - streambuf->readp);
105116 audio_left = len;
106 LOG_INFO("audio size: %u", audio_left);
107 limit = true;
117
118 if ((audio_left == 0xFFFFFFFF) || (audio_left == 0x7FFFEFFC)) {
119 LOG_INFO("wav audio size unknown: %u", audio_left);
120 limit = false;
121 } else {
122 LOG_INFO("wav audio size: %u", audio_left);
123 limit = true;
124 }
108125 return;
109126 }
110127
113130 // following 4 bytes is blocksize - ignored
114131 ptr += 8 + 8;
115132 _buf_inc_readp(streambuf, ptr + offset - streambuf->readp);
116 audio_left = len - 8 - offset;
117 LOG_INFO("audio size: %u", audio_left);
118 limit = true;
133
134 // Reading from an upsampled stream, length could be wrong.
135 // Only use length in header for files.
136 if (stream.state == STREAMING_FILE) {
137 audio_left = len - 8 - offset;
138 LOG_INFO("aif audio size: %u", audio_left);
139 limit = true;
140 }
119141 return;
120142 }
121143
160182 static decode_state pcm_decode(void) {
161183 unsigned bytes, in, out;
162184 frames_t frames, count;
163 u32_t *optr;
185 OPTR_T *optr;
164186 u8_t *iptr;
165 u8_t tmp[16];
187 u8_t tmp[3*8];
166188
167189 LOCK_S;
168190
169 if (decode.new_stream && stream.state == STREAMING_FILE) {
191 if ( decode.new_stream && ( ( stream.state == STREAMING_FILE ) || pcm_check_header ) ) {
170192 _check_header();
171193 }
172194
181203 out = process.max_in_frames;
182204 );
183205
184 if ((stream.state <= DISCONNECT && bytes == 0) || (limit && audio_left == 0)) {
206 if ((stream.state <= DISCONNECT && bytes < bytes_per_frame) || (limit && audio_left == 0)) {
185207 UNLOCK_O_direct;
186208 UNLOCK_S;
187209 return DECODE_COMPLETE;
190212 if (decode.new_stream) {
191213 LOG_INFO("setting track_start");
192214 LOCK_O_not_direct;
215 output.track_start = outputbuf->writep;
216 decode.new_stream = false;
217 #if DSD
218 if (sample_size == 3 &&
219 is_stream_dop(((u8_t *)streambuf->readp) + (bigendian?0:2),
220 ((u8_t *)streambuf->readp) + (bigendian?0:2) + sample_size,
221 sample_size * channels, bytes / (sample_size * channels))) {
222 LOG_INFO("file contains DOP");
223 if (output.dsdfmt == DOP_S24_LE || output.dsdfmt == DOP_S24_3LE)
224 output.next_fmt = output.dsdfmt;
225 else
226 output.next_fmt = DOP;
227 output.next_sample_rate = sample_rate;
228 output.fade = FADE_INACTIVE;
229 } else {
230 output.next_sample_rate = decode_newstream(sample_rate, output.supported_rates);
231 output.next_fmt = PCM;
232 if (output.fade_mode) _checkfade(true);
233 }
234 #else
193235 output.next_sample_rate = decode_newstream(sample_rate, output.supported_rates);
194 output.track_start = outputbuf->writep;
195 IF_DSD( output.next_dop = false; )
196236 if (output.fade_mode) _checkfade(true);
197 decode.new_stream = false;
237 #endif
198238 UNLOCK_O_not_direct;
199239 IF_PROCESS(
200240 out = process.max_in_frames;
203243 }
204244
205245 IF_DIRECT(
206 optr = (u32_t *)outputbuf->writep;
246 optr = (OPTR_T *)outputbuf->writep;
207247 );
208248 IF_PROCESS(
209 optr = (u32_t *)process.inbuf;
249 optr = (OPTR_T *)process.inbuf;
210250 );
211251 iptr = (u8_t *)streambuf->readp;
212252
234274 if (channels == 2) {
235275 if (sample_size == 1) {
236276 while (count--) {
237 *optr++ = *iptr++ << 24;
277 *optr++ = *iptr++ << (24-SHIFT);
238278 }
239279 } else if (sample_size == 2) {
240280 if (bigendian) {
241 while (count--) {
242 *optr++ = *(iptr) << 24 | *(iptr+1) << 16;
281 #if BYTES_PER_FRAME == 4 && !SL_LITTLE_ENDIAN
282 // while loop below works as is, but memcpy is a win for that 16/16 typical case
283 memcpy(optr, iptr, count * BYTES_PER_FRAME / 2);
284 #else
285 while (count--) {
286 *optr++ = *(iptr) << (24-SHIFT) | *(iptr+1) << (16-SHIFT);
243287 iptr += 2;
244288 }
245 } else {
246 while (count--) {
247 *optr++ = *(iptr) << 16 | *(iptr+1) << 24;
289 #endif
290 } else {
291 #if BYTES_PER_FRAME == 4 && SL_LITTLE_ENDIAN
292 // while loop below works as is, but memcpy is a win for that 16/16 typical case
293 memcpy(optr, iptr, count * BYTES_PER_FRAME / 2);
294 #else
295 while (count--) {
296 *optr++ = *(iptr) << (16-SHIFT) | *(iptr+1) << (24-SHIFT);
248297 iptr += 2;
249298 }
299 #endif
250300 }
251301 } else if (sample_size == 3) {
252302 if (bigendian) {
253303 while (count--) {
304 #if BYTES_PER_FRAME == 4
305 *optr++ = *(iptr) << 8 | *(iptr+1);
306 #else
254307 *optr++ = *(iptr) << 24 | *(iptr+1) << 16 | *(iptr+2) << 8;
308 #endif
255309 iptr += 3;
256310 }
257311 } else {
258312 while (count--) {
313 #if BYTES_PER_FRAME == 4
314 *optr++ = *(iptr+1) | *(iptr+2) << 8;
315 #else
259316 *optr++ = *(iptr) << 8 | *(iptr+1) << 16 | *(iptr+2) << 24;
317 #endif
260318 iptr += 3;
261319 }
262320 }
263321 } else if (sample_size == 4) {
264322 if (bigendian) {
265323 while (count--) {
324 #if BYTES_PER_FRAME == 4
325 *optr++ = *(iptr) << 8 | *(iptr+1);
326 #else
266327 *optr++ = *(iptr) << 24 | *(iptr+1) << 16 | *(iptr+2) << 8 | *(iptr+3);
328 #endif
267329 iptr += 4;
268330 }
269331 } else {
270332 while (count--) {
333 #if BYTES_PER_FRAME == 4
334 *optr++ = *(iptr+2) | *(iptr+3) << 8;
335 #else
271336 *optr++ = *(iptr) | *(iptr+1) << 8 | *(iptr+2) << 16 | *(iptr+3) << 24;
337 #endif
272338 iptr += 4;
273339 }
274340 }
276342 } else if (channels == 1) {
277343 if (sample_size == 1) {
278344 while (count--) {
279 *optr = *iptr++ << 24;
345 *optr = *iptr++ << (24-SHIFT);
280346 *(optr+1) = *optr;
281347 optr += 2;
282348 }
283349 } else if (sample_size == 2) {
284350 if (bigendian) {
285351 while (count--) {
286 *optr = *(iptr) << 24 | *(iptr+1) << 16;
352 *optr = *(iptr) << (24-SHIFT) | *(iptr+1) << (16-SHIFT);
287353 *(optr+1) = *optr;
288354 iptr += 2;
289355 optr += 2;
290356 }
291357 } else {
292358 while (count--) {
293 *optr = *(iptr) << 16 | *(iptr+1) << 24;
359 *optr = *(iptr) << (16-SHIFT) | *(iptr+1) << (24-SHIFT);
294360 *(optr+1) = *optr;
295361 iptr += 2;
296362 optr += 2;
299365 } else if (sample_size == 3) {
300366 if (bigendian) {
301367 while (count--) {
368 #if BYTES_PER_FRAME == 4
369 *optr++ = *(iptr) << 8 | *(iptr+1);
370 #else
302371 *optr = *(iptr) << 24 | *(iptr+1) << 16 | *(iptr+2) << 8;
372 #endif
303373 *(optr+1) = *optr;
304374 iptr += 3;
305375 optr += 2;
306376 }
307377 } else {
308378 while (count--) {
379 #if BYTES_PER_FRAME == 4
380 *optr++ = *(iptr+1) | *(iptr+2) << 8;
381 #else
309382 *optr = *(iptr) << 8 | *(iptr+1) << 16 | *(iptr+2) << 24;
383 #endif
310384 *(optr+1) = *optr;
311385 iptr += 3;
312386 optr += 2;
315389 } else if (sample_size == 4) {
316390 if (bigendian) {
317391 while (count--) {
392 #if BYTES_PER_FRAME == 4
393 *optr++ = *(iptr) << 8 | *(iptr+1);
394 #else
318395 *optr++ = *(iptr) << 24 | *(iptr+1) << 16 | *(iptr+2) << 8 | *(iptr+3);
396 #endif
319397 *(optr+1) = *optr;
320398 iptr += 4;
321399 optr += 2;
322400 }
323401 } else {
324402 while (count--) {
403 #if BYTES_PER_FRAME == 4
404 *optr++ = *(iptr+2) | *(iptr+3) << 8;
405 #else
325406 *optr++ = *(iptr) | *(iptr+1) << 8 | *(iptr+2) << 16 | *(iptr+3) << 24;
407 #endif
326408 *(optr+1) = *optr;
327409 iptr += 4;
328410 optr += 2;
370452 }
371453
372454 struct codec *register_pcm(void) {
373 static struct codec ret = {
374 'p', // id
375 "aif,pcm", // types
376 4096, // min read
377 102400, // min space
378 pcm_open, // open
379 pcm_close, // close
380 pcm_decode, // decode
381 };
382
383 LOG_INFO("using pcm to decode aif,pcm");
384 return &ret;
455 if ( pcm_check_header )
456 {
457 static struct codec ret = {
458 'p', // id
459 "wav,aif,pcm", // types
460 4096, // min read
461 102400, // min space
462 pcm_open, // open
463 pcm_close, // close
464 pcm_decode, // decode
465 };
466
467 LOG_INFO("using pcm to decode wav,aif,pcm");
468 return &ret;
469 }
470 else
471 {
472 static struct codec ret = {
473 'p', // id
474 "aif,pcm", // types
475 4096, // min read
476 102400, // min space
477 pcm_open, // open
478 pcm_close, // close
479 pcm_decode, // decode
480 };
481
482 LOG_INFO("using pcm to decode aif,pcm");
483 return &ret;
484 }
485
486 return NULL;
385487 }
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
4849
4950 // transfer all processed frames to the output buf
5051 static void _write_samples(void) {
51 size_t frames = process.out_frames;
52 frames_t frames = process.out_frames;
5253 u32_t *iptr = (u32_t *)process.outbuf;
5354 unsigned cnt = 10;
5455
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
Binary diff not shown
Binary diff not shown
Binary diff not shown
Binary diff not shown
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
1516 * You should have received a copy of the GNU General Public License
1617 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1718 *
19 * Additions (c) Paul Hermann, 2015-2017 under the same license terms
20 * -Control of Raspberry pi GPIO for amplifier power
21 * -Launch script on power status change from LMS
1822 */
1923
2024 #include "squeezelite.h"
2125 #include "slimproto.h"
2226
2327 static log_level loglevel;
28
29 #define SQUEEZENETWORK "mysqueezebox.com:3483"
2430
2531 #define PORT 3483
2632
107113 }
108114
109115 static void sendHELO(bool reconnect, const char *fixed_cap, const char *var_cap, u8_t mac[6]) {
110 const char *base_cap = "Model=squeezelite,AccuratePlayPoints=1,HasDigitalOut=1,HasPolarityInversion=1,Firmware=" VERSION;
116 #define BASE_CAP "Model=squeezelite,AccuratePlayPoints=1,HasDigitalOut=1,HasPolarityInversion=1,Firmware=" VERSION
117 #define SSL_CAP "CanHTTPS=1"
118 const char *base_cap;
111119 struct HELO_packet pkt;
120
121 #if USE_SSL
122 #if !LINKALL && !NO_SSLSYM
123 if (ssl_loaded) base_cap = SSL_CAP "," BASE_CAP;
124 else base_cap = BASE_CAP;
125 #endif
126 base_cap = SSL_CAP "," BASE_CAP;
127 #else
128 base_cap = BASE_CAP;
129 #endif
112130
113131 memset(&pkt, 0, sizeof(pkt));
114132 memcpy(&pkt.opcode, "HELO", 4);
282300 output.pause_frames = interval * status.current_sample_rate / 1000;
283301 if (interval) {
284302 output.state = OUTPUT_PAUSE_FRAMES;
285 } else {
303 } else if (output.state != OUTPUT_OFF) {
286304 output.state = OUTPUT_STOPPED;
287305 output.stop_time = gettime_ms();
288306 }
308326 output.state = jiffies ? OUTPUT_START_AT : OUTPUT_RUNNING;
309327 output.start_at = jiffies;
310328 UNLOCK_O;
329
311330 LOG_DEBUG("unpause at: %u now: %u", jiffies, gettime_ms());
312331 sendSTAT("STMr", 0);
313332 }
324343 strm->autostart, strm->transition_period, strm->transition_type - '0', strm->format);
325344
326345 autostart = strm->autostart - '0';
346
327347 sendSTAT("STMf", 0);
328348 if (header_len > MAX_HEADER -1) {
329349 LOG_WARN("header too long: %u", header_len);
343363 stream_file(header, header_len, strm->threshold * 1024);
344364 autostart -= 2;
345365 } else {
346 stream_sock(ip, port, header, header_len, strm->threshold * 1024, autostart >= 2);
366 stream_sock(ip, port, strm->flags & 0x20, header, header_len, strm->threshold * 1024, autostart >= 2);
347367 }
348368 sendSTAT("STMc", 0);
349369 sentSTMu = sentSTMo = sentSTMl = false;
450470 static void process_serv(u8_t *pkt, int len) {
451471 struct serv_packet *serv = (struct serv_packet *)pkt;
452472
473 unsigned slimproto_port = 0;
474 char squeezeserver[] = SQUEEZENETWORK;
475
476 if(pkt[4] == 0 && pkt[5] == 0 && pkt[6] == 0 && pkt[7] == 1) {
477 server_addr(squeezeserver, &new_server, &slimproto_port);
478 } else {
479 new_server = serv->server_ip;
480 }
481
453482 LOG_INFO("switch server");
454
455 new_server = serv->server_ip;
456483
457484 if (len - sizeof(struct serv_packet) == 10) {
458485 if (!new_server_cap) {
599626 #endif
600627 last = now;
601628
629
602630 LOCK_S;
603631 status.stream_full = _buf_used(streambuf);
604632 status.stream_size = streambuf->size;
626654 UNLOCK_S;
627655
628656 LOCK_D;
629 if ((status.stream_state == STREAMING_HTTP || status.stream_state == STREAMING_FILE) && !sentSTMl
630 && decode.state == DECODE_READY) {
657 if ((status.stream_state == STREAMING_HTTP || status.stream_state == STREAMING_FILE ||
658 (status.stream_state == DISCONNECT && stream.disconnect == DISCONNECT_OK)) &&
659 !sentSTMl && decode.state == DECODE_READY) {
631660 if (autostart == 0) {
632661 decode.state = DECODE_RUNNING;
633662 _sendSTMl = true;
668697 output.pa_reopen = false;
669698 }
670699 #endif
671 if (_start_output && (output.state == OUTPUT_STOPPED || OUTPUT_OFF)) {
700 if (_start_output && (output.state == OUTPUT_STOPPED || output.state == OUTPUT_OFF)) {
672701 output.state = OUTPUT_BUFFER;
673702 }
674703 if (output.state == OUTPUT_RUNNING && !sentSTMu && status.output_full == 0 && status.stream_state <= DISCONNECT &&
675704 _decode_state == DECODE_STOPPED) {
705
676706 _sendSTMu = true;
677707 sentSTMu = true;
678708 LOG_DEBUG("output underrun");
680710 output.stop_time = now;
681711 }
682712 if (output.state == OUTPUT_RUNNING && !sentSTMo && status.output_full == 0 && status.stream_state == STREAMING_HTTP) {
713
683714 _sendSTMo = true;
684715 sentSTMo = true;
685716 }
729760 wake_signal(wake_e);
730761 }
731762
732 in_addr_t discover_server(void) {
763 in_addr_t discover_server(char *default_server) {
733764 struct sockaddr_in d;
734765 struct sockaddr_in s;
735766 char *buf;
736767 struct pollfd pollinfo;
768 unsigned port;
737769
738770 int disc_sock = socket(AF_INET, SOCK_DGRAM, 0);
739771
766798 LOG_INFO("got response from: %s:%d", inet_ntoa(s.sin_addr), ntohs(s.sin_port));
767799 }
768800
801 if (default_server) {
802 server_addr(default_server, &s.sin_addr.s_addr, &port);
803 }
804
769805 } while (s.sin_addr.s_addr == 0 && running);
770806
771807 closesocket(disc_sock);
776812 #define FIXED_CAP_LEN 256
777813 #define VAR_CAP_LEN 128
778814
779 void slimproto(log_level level, char *server, u8_t mac[6], const char *name, const char *namefile, const char *modelname) {
815 void slimproto(log_level level, char *server, u8_t mac[6], const char *name, const char *namefile, const char *modelname, int maxSampleRate) {
780816 struct sockaddr_in serv_addr;
781817 static char fixed_cap[FIXED_CAP_LEN], var_cap[VAR_CAP_LEN] = "";
782818 bool reconnect = false;
783819 unsigned failed_connect = 0;
784820 unsigned slimproto_port = 0;
821 in_addr_t previous_server = 0;
785822 int i;
823
824 memset(&status, 0, sizeof(status));
786825
787826 wake_create(wake_e);
788827
794833 }
795834
796835 if (!slimproto_ip) {
797 slimproto_ip = discover_server();
836 slimproto_ip = discover_server(server);
798837 }
799838
800839 if (!slimproto_port) {
829868
830869 LOCK_O;
831870 snprintf(fixed_cap, FIXED_CAP_LEN, ",ModelName=%s,MaxSampleRate=%u", modelname ? modelname : MODEL_NAME_STRING,
832 output.supported_rates[0]);
871 ((maxSampleRate > 0) ? maxSampleRate : output.supported_rates[0]));
833872
834873 for (i = 0; i < MAX_CODECS; i++) {
835874 if (codecs[i] && codecs[i]->id && strlen(fixed_cap) < FIXED_CAP_LEN - 10) {
851890 while (running) {
852891
853892 if (new_server) {
893 previous_server = slimproto_ip;
854894 slimproto_ip = serv_addr.sin_addr.s_addr = new_server;
855895 LOG_INFO("switching server to %s:%d", inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port));
856896 new_server = 0;
864904
865905 if (connect_timeout(sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr), 5) != 0) {
866906
867 LOG_INFO("unable to connect to server %u", failed_connect);
868 sleep(5);
907 if (previous_server) {
908 slimproto_ip = serv_addr.sin_addr.s_addr = previous_server;
909 LOG_INFO("new server not reachable, reverting to previous server %s:%d", inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port));
910 } else {
911 LOG_INFO("unable to connect to server %u", failed_connect);
912 sleep(5);
913 }
869914
870915 // rediscover server if it was not set at startup
871916 if (!server && ++failed_connect > 5) {
872 slimproto_ip = serv_addr.sin_addr.s_addr = discover_server();
917 slimproto_ip = serv_addr.sin_addr.s_addr = discover_server(NULL);
873918 }
874919
875920 } else {
910955 usleep(100000);
911956 }
912957
958 previous_server = 0;
959
913960 closesocket(sock);
914961 }
915962 }
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
1920
2021 // packet formats for slimproto
2122
23 #ifndef SUN
2224 #pragma pack(push, 1)
25 #else
26 #pragma pack(1)
27 #endif
2328
2429 // from S:N:Slimproto _hello_handler
2530 struct HELO_packet {
172177 u8_t pcm_endianness;
173178 };
174179
180 #ifndef SUN
175181 #pragma pack(pop)
182 #else
183 #pragma pack()
184 #endif
0 
1 Microsoft Visual Studio Solution File, Format Version 10.00
2 # Visual C++ Express 2008
3 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "squeezelite-dll", "squeezelite-dll.vcproj", "{7CB5A216-CEFA-4932-93CD-E9BFA33DD349}"
4 EndProject
5 Global
6 GlobalSection(SolutionConfigurationPlatforms) = preSolution
7 Debug|Win32 = Debug|Win32
8 Release|Win32 = Release|Win32
9 EndGlobalSection
10 GlobalSection(ProjectConfigurationPlatforms) = postSolution
11 {7CB5A216-CEFA-4932-93CD-E9BFA33DD349}.Debug|Win32.ActiveCfg = Debug|Win32
12 {7CB5A216-CEFA-4932-93CD-E9BFA33DD349}.Debug|Win32.Build.0 = Debug|Win32
13 {7CB5A216-CEFA-4932-93CD-E9BFA33DD349}.Release|Win32.ActiveCfg = Release|Win32
14 {7CB5A216-CEFA-4932-93CD-E9BFA33DD349}.Release|Win32.Build.0 = Release|Win32
15 EndGlobalSection
16 GlobalSection(SolutionProperties) = preSolution
17 HideSolutionNode = FALSE
18 EndGlobalSection
19 EndGlobal
0 <?xml version="1.0" encoding="UTF-8"?>
1 <VisualStudioProject
2 ProjectType="Visual C++"
3 Version="9.00"
4 Name="squeezelite-dll"
5 ProjectGUID="{7CB5A216-CEFA-4932-93CD-E9BFA33DD349}"
6 RootNamespace="squeezelite"
7 Keyword="Win32Proj"
8 TargetFrameworkVersion="0"
9 >
10 <Platforms>
11 <Platform
12 Name="Win32"
13 />
14 </Platforms>
15 <ToolFiles>
16 </ToolFiles>
17 <Configurations>
18 <Configuration
19 Name="Debug|Win32"
20 OutputDirectory="Debug"
21 IntermediateDirectory="Debug"
22 ConfigurationType="1"
23 >
24 <Tool
25 Name="VCPreBuildEventTool"
26 />
27 <Tool
28 Name="VCCustomBuildTool"
29 />
30 <Tool
31 Name="VCXMLDataGeneratorTool"
32 />
33 <Tool
34 Name="VCWebServiceProxyGeneratorTool"
35 />
36 <Tool
37 Name="VCMIDLTool"
38 />
39 <Tool
40 Name="VCCLCompilerTool"
41 Optimization="0"
42 PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"
43 MinimalRebuild="true"
44 BasicRuntimeChecks="3"
45 RuntimeLibrary="3"
46 UsePrecompiledHeader="0"
47 WarningLevel="3"
48 Detect64BitPortabilityProblems="true"
49 DebugInformationFormat="4"
50 />
51 <Tool
52 Name="VCManagedResourceCompilerTool"
53 />
54 <Tool
55 Name="VCResourceCompilerTool"
56 />
57 <Tool
58 Name="VCPreLinkEventTool"
59 />
60 <Tool
61 Name="VCLinkerTool"
62 LinkIncremental="2"
63 GenerateDebugInformation="true"
64 SubSystem="1"
65 TargetMachine="1"
66 />
67 <Tool
68 Name="VCALinkTool"
69 />
70 <Tool
71 Name="VCManifestTool"
72 />
73 <Tool
74 Name="VCXDCMakeTool"
75 />
76 <Tool
77 Name="VCBscMakeTool"
78 />
79 <Tool
80 Name="VCFxCopTool"
81 />
82 <Tool
83 Name="VCAppVerifierTool"
84 />
85 <Tool
86 Name="VCPostBuildEventTool"
87 />
88 </Configuration>
89 <Configuration
90 Name="Release|Win32"
91 OutputDirectory="Release"
92 IntermediateDirectory="Release"
93 ConfigurationType="1"
94 >
95 <Tool
96 Name="VCPreBuildEventTool"
97 />
98 <Tool
99 Name="VCCustomBuildTool"
100 />
101 <Tool
102 Name="VCXMLDataGeneratorTool"
103 />
104 <Tool
105 Name="VCWebServiceProxyGeneratorTool"
106 />
107 <Tool
108 Name="VCMIDLTool"
109 />
110 <Tool
111 Name="VCCLCompilerTool"
112 AdditionalIncludeDirectories="&quot;include-dll\opus&quot;;&quot;include-dll&quot;"
113 PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;RESAMPLE;OPUS;DSD;USE_SSL;NO_SSLSYM"
114 RuntimeLibrary="2"
115 UsePrecompiledHeader="0"
116 WarningLevel="3"
117 Detect64BitPortabilityProblems="false"
118 DebugInformationFormat="0"
119 />
120 <Tool
121 Name="VCManagedResourceCompilerTool"
122 />
123 <Tool
124 Name="VCResourceCompilerTool"
125 />
126 <Tool
127 Name="VCPreLinkEventTool"
128 />
129 <Tool
130 Name="VCLinkerTool"
131 AdditionalDependencies="ws2_32.lib lib-dll\portaudio.lib lib-dll\ssleay32.lib lib-dll\libeay32.lib lib-dll\opus.lib lib-dll\opusfile.lib"
132 OutputFile="$(OutDir)\$(ProjectName).exe"
133 LinkIncremental="1"
134 ModuleDefinitionFile=""
135 GenerateDebugInformation="false"
136 SubSystem="1"
137 OptimizeReferences="2"
138 EnableCOMDATFolding="2"
139 TargetMachine="1"
140 />
141 <Tool
142 Name="VCALinkTool"
143 />
144 <Tool
145 Name="VCManifestTool"
146 />
147 <Tool
148 Name="VCXDCMakeTool"
149 />
150 <Tool
151 Name="VCBscMakeTool"
152 />
153 <Tool
154 Name="VCFxCopTool"
155 />
156 <Tool
157 Name="VCAppVerifierTool"
158 />
159 <Tool
160 Name="VCPostBuildEventTool"
161 />
162 </Configuration>
163 </Configurations>
164 <References>
165 </References>
166 <Files>
167 <Filter
168 Name="Header Files"
169 Filter="h;hpp;hxx;hm;inl;inc;xsd"
170 UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
171 >
172 <File
173 RelativePath=".\include\flac\all.h"
174 >
175 </File>
176 <File
177 RelativePath=".\include\flac\assert.h"
178 >
179 </File>
180 <File
181 RelativePath=".\include\flac\callback.h"
182 >
183 </File>
184 <File
185 RelativePath=".\include\vorbis\codec.h"
186 >
187 </File>
188 <File
189 RelativePath=".\include\ogg\config_types.h"
190 >
191 </File>
192 <File
193 RelativePath=".\dsd2pcm\dsd2pcm.h"
194 >
195 </File>
196 <File
197 RelativePath=".\include\flac\export.h"
198 >
199 </File>
200 <File
201 RelativePath=".\include\flac\format.h"
202 >
203 </File>
204 <File
205 RelativePath=".\include\mad.h"
206 >
207 </File>
208 <File
209 RelativePath=".\include\flac\metadata.h"
210 >
211 </File>
212 <File
213 RelativePath=".\include\mpg123.h"
214 >
215 </File>
216 <File
217 RelativePath=".\include\neaacdec.h"
218 >
219 </File>
220 <File
221 RelativePath=".\include\ogg\ogg.h"
222 >
223 </File>
224 <File
225 RelativePath=".\include\flac\ordinals.h"
226 >
227 </File>
228 <File
229 RelativePath=".\include\ogg\os_types.h"
230 >
231 </File>
232 <File
233 RelativePath=".\include\portaudio.h"
234 >
235 </File>
236 <File
237 RelativePath=".\slimproto.h"
238 >
239 </File>
240 <File
241 RelativePath=".\include\soxr.h"
242 >
243 </File>
244 <File
245 RelativePath=".\squeezelite.h"
246 >
247 </File>
248 <File
249 RelativePath=".\include\flac\stream_decoder.h"
250 >
251 </File>
252 <File
253 RelativePath=".\include\flac\stream_encoder.h"
254 >
255 </File>
256 <File
257 RelativePath=".\include\vorbis\vorbisenc.h"
258 >
259 </File>
260 <File
261 RelativePath=".\include\vorbis\vorbisfile.h"
262 >
263 </File>
264 </Filter>
265 <Filter
266 Name="Resource Files"
267 Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
268 UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
269 >
270 </Filter>
271 <Filter
272 Name="Source Files"
273 Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
274 UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
275 >
276 <File
277 RelativePath=".\buffer.c"
278 >
279 </File>
280 <File
281 RelativePath=".\decode.c"
282 >
283 </File>
284 <File
285 RelativePath=".\dop.c"
286 >
287 </File>
288 <File
289 RelativePath=".\dsd.c"
290 >
291 </File>
292 <File
293 RelativePath=".\dsd2pcm\dsd2pcm.c"
294 >
295 </File>
296 <File
297 RelativePath=".\faad.c"
298 >
299 </File>
300 <File
301 RelativePath=".\ffmpeg.c"
302 >
303 </File>
304 <File
305 RelativePath=".\flac.c"
306 >
307 </File>
308 <File
309 RelativePath=".\mad.c"
310 >
311 </File>
312 <File
313 RelativePath=".\main.c"
314 >
315 </File>
316 <File
317 RelativePath=".\mpg.c"
318 >
319 </File>
320 <File
321 RelativePath=".\opus.c"
322 >
323 </File>
324 <File
325 RelativePath=".\output.c"
326 >
327 </File>
328 <File
329 RelativePath=".\output_alsa.c"
330 >
331 </File>
332 <File
333 RelativePath=".\output_pa.c"
334 >
335 </File>
336 <File
337 RelativePath=".\output_pack.c"
338 >
339 </File>
340 <File
341 RelativePath=".\output_stdout.c"
342 >
343 </File>
344 <File
345 RelativePath=".\output_vis.c"
346 >
347 </File>
348 <File
349 RelativePath=".\pcm.c"
350 >
351 </File>
352 <File
353 RelativePath=".\process.c"
354 >
355 </File>
356 <File
357 RelativePath=".\resample.c"
358 >
359 </File>
360 <File
361 RelativePath=".\slimproto.c"
362 >
363 </File>
364 <File
365 RelativePath=".\sslsym.c"
366 >
367 </File>
368 <File
369 RelativePath=".\stream.c"
370 >
371 </File>
372 <File
373 RelativePath=".\utils.c"
374 >
375 </File>
376 <File
377 RelativePath=".\vorbis.c"
378 >
379 </File>
380 </Filter>
381 </Files>
382 <Globals>
383 </Globals>
384 </VisualStudioProject>
0 
1 Microsoft Visual Studio Solution File, Format Version 12.00
2 # Visual Studio 15
3 VisualStudioVersion = 15.0.28307.1062
4 MinimumVisualStudioVersion = 10.0.40219.1
5 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "squeezelite-x64", "squeezelite-x64.vcxproj", "{7CB5A216-CEFA-4932-93CD-E9BFA33DD349}"
6 EndProject
7 Global
8 GlobalSection(SolutionConfigurationPlatforms) = preSolution
9 Debug|Win32 = Debug|Win32
10 Debug|x64 = Debug|x64
11 Release|Win32 = Release|Win32
12 Release|x64 = Release|x64
13 EndGlobalSection
14 GlobalSection(ProjectConfigurationPlatforms) = postSolution
15 {7CB5A216-CEFA-4932-93CD-E9BFA33DD349}.Debug|Win32.ActiveCfg = Release|Win32
16 {7CB5A216-CEFA-4932-93CD-E9BFA33DD349}.Debug|Win32.Build.0 = Release|Win32
17 {7CB5A216-CEFA-4932-93CD-E9BFA33DD349}.Debug|x64.ActiveCfg = Debug|x64
18 {7CB5A216-CEFA-4932-93CD-E9BFA33DD349}.Debug|x64.Build.0 = Debug|x64
19 {7CB5A216-CEFA-4932-93CD-E9BFA33DD349}.Release|Win32.ActiveCfg = Release|Win32
20 {7CB5A216-CEFA-4932-93CD-E9BFA33DD349}.Release|Win32.Build.0 = Release|Win32
21 {7CB5A216-CEFA-4932-93CD-E9BFA33DD349}.Release|x64.ActiveCfg = Release|x64
22 {7CB5A216-CEFA-4932-93CD-E9BFA33DD349}.Release|x64.Build.0 = Release|x64
23 EndGlobalSection
24 GlobalSection(SolutionProperties) = preSolution
25 HideSolutionNode = FALSE
26 EndGlobalSection
27 GlobalSection(ExtensibilityGlobals) = postSolution
28 SolutionGuid = {BB7D547A-95FA-4A5F-82FC-E013A35756B4}
29 EndGlobalSection
30 EndGlobal
0 <?xml version="1.0" encoding="utf-8"?>
1 <Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
2 <ItemGroup Label="ProjectConfigurations">
3 <ProjectConfiguration Include="Debug|Win32">
4 <Configuration>Debug</Configuration>
5 <Platform>Win32</Platform>
6 </ProjectConfiguration>
7 <ProjectConfiguration Include="Debug|x64">
8 <Configuration>Debug</Configuration>
9 <Platform>x64</Platform>
10 </ProjectConfiguration>
11 <ProjectConfiguration Include="Release|Win32">
12 <Configuration>Release</Configuration>
13 <Platform>Win32</Platform>
14 </ProjectConfiguration>
15 <ProjectConfiguration Include="Release|x64">
16 <Configuration>Release</Configuration>
17 <Platform>x64</Platform>
18 </ProjectConfiguration>
19 </ItemGroup>
20 <PropertyGroup Label="Globals">
21 <ProjectGuid>{7CB5A216-CEFA-4932-93CD-E9BFA33DD349}</ProjectGuid>
22 <RootNamespace>squeezelite</RootNamespace>
23 <Keyword>Win32Proj</Keyword>
24 </PropertyGroup>
25 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
26 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
27 <ConfigurationType>Application</ConfigurationType>
28 <PlatformToolset>v141</PlatformToolset>
29 </PropertyGroup>
30 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
31 <ConfigurationType>Application</ConfigurationType>
32 <PlatformToolset>v141</PlatformToolset>
33 </PropertyGroup>
34 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
35 <ConfigurationType>Application</ConfigurationType>
36 <PlatformToolset>v141</PlatformToolset>
37 </PropertyGroup>
38 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
39 <ConfigurationType>Application</ConfigurationType>
40 <PlatformToolset>v141</PlatformToolset>
41 </PropertyGroup>
42 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
43 <ImportGroup Label="ExtensionSettings">
44 </ImportGroup>
45 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
46 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
47 </ImportGroup>
48 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
49 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
50 </ImportGroup>
51 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
52 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
53 </ImportGroup>
54 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
55 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
56 </ImportGroup>
57 <PropertyGroup Label="UserMacros" />
58 <PropertyGroup>
59 <_ProjectFileVersion>15.0.28307.799</_ProjectFileVersion>
60 </PropertyGroup>
61 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
62 <OutDir>Debug\</OutDir>
63 <IntDir>Debug\</IntDir>
64 <LinkIncremental>true</LinkIncremental>
65 </PropertyGroup>
66 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
67 <LinkIncremental>true</LinkIncremental>
68 </PropertyGroup>
69 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
70 <OutDir>Release\</OutDir>
71 <IntDir>Release\</IntDir>
72 <LinkIncremental>false</LinkIncremental>
73 </PropertyGroup>
74 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
75 <LinkIncremental>false</LinkIncremental>
76 </PropertyGroup>
77 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
78 <ClCompile>
79 <Optimization>Disabled</Optimization>
80 <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
81 <MinimalRebuild>true</MinimalRebuild>
82 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
83 <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
84 <PrecompiledHeader />
85 <WarningLevel>Level3</WarningLevel>
86 <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
87 </ClCompile>
88 <Link>
89 <GenerateDebugInformation>true</GenerateDebugInformation>
90 <SubSystem>Console</SubSystem>
91 <TargetMachine>MachineX86</TargetMachine>
92 </Link>
93 </ItemDefinitionGroup>
94 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
95 <ClCompile>
96 <Optimization>Disabled</Optimization>
97 <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
98 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
99 <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
100 <PrecompiledHeader>
101 </PrecompiledHeader>
102 <WarningLevel>Level3</WarningLevel>
103 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
104 </ClCompile>
105 <Link>
106 <GenerateDebugInformation>true</GenerateDebugInformation>
107 <SubSystem>Console</SubSystem>
108 </Link>
109 </ItemDefinitionGroup>
110 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
111 <ClCompile>
112 <AdditionalIncludeDirectories>include\alac;include\opus;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
113 <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;RESAMPLE;ALAC;OPUS;DSD;USE_SSL;FLAC__NO_DLL;LINKALL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
114 <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
115 <PrecompiledHeader />
116 <WarningLevel>Level3</WarningLevel>
117 <DebugInformationFormat />
118 </ClCompile>
119 <Link>
120 <AdditionalOptions>/NODEFAULTLIB:LIBCMT %(AdditionalOptions)</AdditionalOptions>
121 <AdditionalDependencies>ws2_32.lib;lib\portaudio.lib;lib\libogg.lib;lib\libvorbisfile.lib;lib\libvorbis.lib;lib\libmad.lib;lib\libFLAC.lib;lib\libfaad.lib;lib\libmpg123.lib;lib\libsoxr.lib;lib\libalac.lib;lib\ssleay32.lib;lib\libeay32.lib;lib\opus.lib;lib\opusfile.lib;%(AdditionalDependencies)</AdditionalDependencies>
122 <OutputFile>$(OutDir)$(ProjectName).exe</OutputFile>
123 <ModuleDefinitionFile />
124 <GenerateDebugInformation>false</GenerateDebugInformation>
125 <SubSystem>Console</SubSystem>
126 <OptimizeReferences>true</OptimizeReferences>
127 <EnableCOMDATFolding>true</EnableCOMDATFolding>
128 <TargetMachine>MachineX86</TargetMachine>
129 </Link>
130 </ItemDefinitionGroup>
131 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
132 <ClCompile>
133 <AdditionalIncludeDirectories>include\alac;include\opus;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
134 <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;RESAMPLE;DSD;ALAC;OPUS;USE_SSL;FLAC__NO_DLL;LINKALL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
135 <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
136 <PrecompiledHeader>
137 </PrecompiledHeader>
138 <WarningLevel>Level3</WarningLevel>
139 <DebugInformationFormat>
140 </DebugInformationFormat>
141 </ClCompile>
142 <Link>
143 <AdditionalOptions>/NODEFAULTLIB:LIBCMT %(AdditionalOptions)</AdditionalOptions>
144 <AdditionalDependencies>ws2_32.lib;crypt32.lib;lib\portaudio.lib;lib\libogg.lib;lib\libvorbisfile.lib;lib\libvorbis.lib;lib\libmad.lib;lib\libFLAC.lib;lib\libfaad.lib;lib\libmpg123.lib;lib\libsoxr.lib;lib\libalac.lib;lib\libssl.lib;lib\libcrypto.lib;lib\opus.lib;lib\opusfile.lib;%(AdditionalDependencies)</AdditionalDependencies>
145 <OutputFile>$(OutDir)$(ProjectName).exe</OutputFile>
146 <ModuleDefinitionFile>
147 </ModuleDefinitionFile>
148 <GenerateDebugInformation>false</GenerateDebugInformation>
149 <SubSystem>Console</SubSystem>
150 <OptimizeReferences>true</OptimizeReferences>
151 <EnableCOMDATFolding>true</EnableCOMDATFolding>
152 </Link>
153 </ItemDefinitionGroup>
154 <ItemGroup>
155 <ClInclude Include="alac_wrapper.h" />
156 <ClInclude Include="dsd2pcm\dsd2pcm.h" />
157 <ClInclude Include="include\flac\all.h" />
158 <ClInclude Include="include\flac\assert.h" />
159 <ClInclude Include="include\flac\callback.h" />
160 <ClInclude Include="include\flac\export.h" />
161 <ClInclude Include="include\flac\format.h" />
162 <ClInclude Include="include\flac\metadata.h" />
163 <ClInclude Include="include\flac\ordinals.h" />
164 <ClInclude Include="include\flac\stream_decoder.h" />
165 <ClInclude Include="include\flac\stream_encoder.h" />
166 <ClInclude Include="include\mad.h" />
167 <ClInclude Include="include\mpg123.h" />
168 <ClInclude Include="include\neaacdec.h" />
169 <ClInclude Include="include\ogg\config_types.h" />
170 <ClInclude Include="include\ogg\ogg.h" />
171 <ClInclude Include="include\ogg\os_types.h" />
172 <ClInclude Include="include\portaudio.h" />
173 <ClInclude Include="include\soxr.h" />
174 <ClInclude Include="include\vorbis\codec.h" />
175 <ClInclude Include="include\vorbis\vorbisenc.h" />
176 <ClInclude Include="include\vorbis\vorbisfile.h" />
177 <ClInclude Include="resource.h" />
178 <ClInclude Include="slimproto.h" />
179 <ClInclude Include="squeezelite.h" />
180 </ItemGroup>
181 <ItemGroup>
182 <ClCompile Include="alac.c" />
183 <ClCompile Include="alac_wrapper.cpp" />
184 <ClCompile Include="buffer.c" />
185 <ClCompile Include="decode.c" />
186 <ClCompile Include="dop.c" />
187 <ClCompile Include="dsd.c" />
188 <ClCompile Include="dsd2pcm\dsd2pcm.c" />
189 <ClCompile Include="faad.c" />
190 <ClCompile Include="ffmpeg.c" />
191 <ClCompile Include="flac.c" />
192 <ClCompile Include="mad.c" />
193 <ClCompile Include="main.c" />
194 <ClCompile Include="mpg.c" />
195 <ClCompile Include="opus.c" />
196 <ClCompile Include="output.c" />
197 <ClCompile Include="output_alsa.c" />
198 <ClCompile Include="output_pa.c" />
199 <ClCompile Include="output_pack.c" />
200 <ClCompile Include="output_stdout.c" />
201 <ClCompile Include="output_vis.c" />
202 <ClCompile Include="pcm.c" />
203 <ClCompile Include="process.c" />
204 <ClCompile Include="resample.c" />
205 <ClCompile Include="slimproto.c" />
206 <ClCompile Include="sslsym.c" />
207 <ClCompile Include="stream.c" />
208 <ClCompile Include="utils.c" />
209 <ClCompile Include="vorbis.c" />
210 </ItemGroup>
211 <ItemGroup>
212 <ResourceCompile Include="Resource.rc" />
213 </ItemGroup>
214 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
215 <ImportGroup Label="ExtensionTargets">
216 </ImportGroup>
217 </Project>
0 
1 Microsoft Visual Studio Solution File, Format Version 10.00
2 # Visual Studio 2008
3 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "squeezelite-x86", "squeezelite-x86.vcproj", "{7CB5A216-CEFA-4932-93CD-E9BFA33DD349}"
4 EndProject
5 Global
6 GlobalSection(SolutionConfigurationPlatforms) = preSolution
7 Debug|Win32 = Debug|Win32
8 Release|Win32 = Release|Win32
9 EndGlobalSection
10 GlobalSection(ProjectConfigurationPlatforms) = postSolution
11 {7CB5A216-CEFA-4932-93CD-E9BFA33DD349}.Debug|Win32.ActiveCfg = Release|Win32
12 {7CB5A216-CEFA-4932-93CD-E9BFA33DD349}.Debug|Win32.Build.0 = Release|Win32
13 {7CB5A216-CEFA-4932-93CD-E9BFA33DD349}.Release|Win32.ActiveCfg = Release|Win32
14 {7CB5A216-CEFA-4932-93CD-E9BFA33DD349}.Release|Win32.Build.0 = Release|Win32
15 EndGlobalSection
16 GlobalSection(SolutionProperties) = preSolution
17 HideSolutionNode = FALSE
18 EndGlobalSection
19 EndGlobal
0 <?xml version="1.0" encoding="UTF-8"?>
1 <VisualStudioProject
2 ProjectType="Visual C++"
3 Version="9.00"
4 Name="squeezelite-x86"
5 ProjectGUID="{7CB5A216-CEFA-4932-93CD-E9BFA33DD349}"
6 RootNamespace="squeezelite"
7 Keyword="Win32Proj"
8 TargetFrameworkVersion="0"
9 >
10 <Platforms>
11 <Platform
12 Name="Win32"
13 />
14 </Platforms>
15 <ToolFiles>
16 </ToolFiles>
17 <Configurations>
18 <Configuration
19 Name="Debug|Win32"
20 OutputDirectory="Debug"
21 IntermediateDirectory="Debug"
22 ConfigurationType="1"
23 >
24 <Tool
25 Name="VCPreBuildEventTool"
26 />
27 <Tool
28 Name="VCCustomBuildTool"
29 />
30 <Tool
31 Name="VCXMLDataGeneratorTool"
32 />
33 <Tool
34 Name="VCWebServiceProxyGeneratorTool"
35 />
36 <Tool
37 Name="VCMIDLTool"
38 />
39 <Tool
40 Name="VCCLCompilerTool"
41 Optimization="0"
42 PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"
43 MinimalRebuild="true"
44 BasicRuntimeChecks="3"
45 RuntimeLibrary="3"
46 UsePrecompiledHeader="0"
47 WarningLevel="3"
48 Detect64BitPortabilityProblems="true"
49 DebugInformationFormat="4"
50 />
51 <Tool
52 Name="VCManagedResourceCompilerTool"
53 />
54 <Tool
55 Name="VCResourceCompilerTool"
56 />
57 <Tool
58 Name="VCPreLinkEventTool"
59 />
60 <Tool
61 Name="VCLinkerTool"
62 LinkIncremental="2"
63 GenerateDebugInformation="true"
64 SubSystem="1"
65 TargetMachine="1"
66 />
67 <Tool
68 Name="VCALinkTool"
69 />
70 <Tool
71 Name="VCManifestTool"
72 />
73 <Tool
74 Name="VCXDCMakeTool"
75 />
76 <Tool
77 Name="VCBscMakeTool"
78 />
79 <Tool
80 Name="VCFxCopTool"
81 />
82 <Tool
83 Name="VCAppVerifierTool"
84 />
85 <Tool
86 Name="VCPostBuildEventTool"
87 />
88 </Configuration>
89 <Configuration
90 Name="Release|Win32"
91 OutputDirectory="Release"
92 IntermediateDirectory="Release"
93 ConfigurationType="1"
94 >
95 <Tool
96 Name="VCPreBuildEventTool"
97 />
98 <Tool
99 Name="VCCustomBuildTool"
100 />
101 <Tool
102 Name="VCXMLDataGeneratorTool"
103 />
104 <Tool
105 Name="VCWebServiceProxyGeneratorTool"
106 />
107 <Tool
108 Name="VCMIDLTool"
109 />
110 <Tool
111 Name="VCCLCompilerTool"
112 AdditionalIncludeDirectories="include\alac;include\opus;include"
113 PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;RESAMPLE;ALAC;OPUS;DSD;USE_SSL;FLAC__NO_DLL;LINKALL"
114 RuntimeLibrary="0"
115 UsePrecompiledHeader="0"
116 WarningLevel="3"
117 Detect64BitPortabilityProblems="false"
118 DebugInformationFormat="0"
119 />
120 <Tool
121 Name="VCManagedResourceCompilerTool"
122 />
123 <Tool
124 Name="VCResourceCompilerTool"
125 />
126 <Tool
127 Name="VCPreLinkEventTool"
128 />
129 <Tool
130 Name="VCLinkerTool"
131 AdditionalOptions="/NODEFAULTLIB:LIBCMT"
132 AdditionalDependencies="ws2_32.lib crypt32.lib lib\portaudio.lib lib\libogg.lib lib\libvorbisfile.lib lib\libvorbis.lib lib\libmad.lib lib\libFLAC.lib lib\libfaad.lib lib\libmpg123.lib lib\libsoxr.lib lib\libalac.lib lib\ssleay32.lib lib\libeay32.lib lib\opus.lib lib\opusfile.lib"
133 OutputFile="$(OutDir)\$(ProjectName).exe"
134 LinkIncremental="1"
135 ModuleDefinitionFile=""
136 GenerateDebugInformation="false"
137 SubSystem="1"
138 OptimizeReferences="2"
139 EnableCOMDATFolding="2"
140 TargetMachine="1"
141 />
142 <Tool
143 Name="VCALinkTool"
144 />
145 <Tool
146 Name="VCManifestTool"
147 />
148 <Tool
149 Name="VCXDCMakeTool"
150 />
151 <Tool
152 Name="VCBscMakeTool"
153 />
154 <Tool
155 Name="VCFxCopTool"
156 />
157 <Tool
158 Name="VCAppVerifierTool"
159 />
160 <Tool
161 Name="VCPostBuildEventTool"
162 />
163 </Configuration>
164 </Configurations>
165 <References>
166 </References>
167 <Files>
168 <Filter
169 Name="Header Files"
170 Filter="h;hpp;hxx;hm;inl;inc;xsd"
171 UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
172 >
173 <File
174 RelativePath=".\alac_wrapper.h"
175 >
176 </File>
177 <File
178 RelativePath=".\include\flac\all.h"
179 >
180 </File>
181 <File
182 RelativePath=".\include\flac\assert.h"
183 >
184 </File>
185 <File
186 RelativePath=".\include\flac\callback.h"
187 >
188 </File>
189 <File
190 RelativePath=".\include\vorbis\codec.h"
191 >
192 </File>
193 <File
194 RelativePath=".\include\ogg\config_types.h"
195 >
196 </File>
197 <File
198 RelativePath=".\dsd2pcm\dsd2pcm.h"
199 >
200 </File>
201 <File
202 RelativePath=".\include\flac\export.h"
203 >
204 </File>
205 <File
206 RelativePath=".\include\flac\format.h"
207 >
208 </File>
209 <File
210 RelativePath=".\include\mad.h"
211 >
212 </File>
213 <File
214 RelativePath=".\include\flac\metadata.h"
215 >
216 </File>
217 <File
218 RelativePath=".\include\mpg123.h"
219 >
220 </File>
221 <File
222 RelativePath=".\include\neaacdec.h"
223 >
224 </File>
225 <File
226 RelativePath=".\include\ogg\ogg.h"
227 >
228 </File>
229 <File
230 RelativePath=".\include\flac\ordinals.h"
231 >
232 </File>
233 <File
234 RelativePath=".\include\ogg\os_types.h"
235 >
236 </File>
237 <File
238 RelativePath=".\include\portaudio.h"
239 >
240 </File>
241 <File
242 RelativePath=".\slimproto.h"
243 >
244 </File>
245 <File
246 RelativePath=".\include\soxr.h"
247 >
248 </File>
249 <File
250 RelativePath=".\squeezelite.h"
251 >
252 </File>
253 <File
254 RelativePath=".\include\flac\stream_decoder.h"
255 >
256 </File>
257 <File
258 RelativePath=".\include\flac\stream_encoder.h"
259 >
260 </File>
261 <File
262 RelativePath=".\include\vorbis\vorbisenc.h"
263 >
264 </File>
265 <File
266 RelativePath=".\include\vorbis\vorbisfile.h"
267 >
268 </File>
269 </Filter>
270 <Filter
271 Name="Resource Files"
272 Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
273 UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
274 >
275 </Filter>
276 <Filter
277 Name="Source Files"
278 Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
279 UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
280 >
281 <File
282 RelativePath=".\alac.c"
283 >
284 </File>
285 <File
286 RelativePath=".\alac_wrapper.cpp"
287 >
288 </File>
289 <File
290 RelativePath=".\buffer.c"
291 >
292 </File>
293 <File
294 RelativePath=".\decode.c"
295 >
296 </File>
297 <File
298 RelativePath=".\dop.c"
299 >
300 </File>
301 <File
302 RelativePath=".\dsd.c"
303 >
304 </File>
305 <File
306 RelativePath=".\dsd2pcm\dsd2pcm.c"
307 >
308 </File>
309 <File
310 RelativePath=".\faad.c"
311 >
312 </File>
313 <File
314 RelativePath=".\ffmpeg.c"
315 >
316 </File>
317 <File
318 RelativePath=".\flac.c"
319 >
320 </File>
321 <File
322 RelativePath=".\mad.c"
323 >
324 </File>
325 <File
326 RelativePath=".\main.c"
327 >
328 </File>
329 <File
330 RelativePath=".\mpg.c"
331 >
332 </File>
333 <File
334 RelativePath=".\opus.c"
335 >
336 </File>
337 <File
338 RelativePath=".\output.c"
339 >
340 </File>
341 <File
342 RelativePath=".\output_alsa.c"
343 >
344 </File>
345 <File
346 RelativePath=".\output_pa.c"
347 >
348 </File>
349 <File
350 RelativePath=".\output_pack.c"
351 >
352 </File>
353 <File
354 RelativePath=".\output_stdout.c"
355 >
356 </File>
357 <File
358 RelativePath=".\output_vis.c"
359 >
360 </File>
361 <File
362 RelativePath=".\pcm.c"
363 >
364 </File>
365 <File
366 RelativePath=".\process.c"
367 >
368 </File>
369 <File
370 RelativePath=".\resample.c"
371 >
372 </File>
373 <File
374 RelativePath=".\slimproto.c"
375 >
376 </File>
377 <File
378 RelativePath=".\sslsym.c"
379 >
380 </File>
381 <File
382 RelativePath=".\stream.c"
383 >
384 </File>
385 <File
386 RelativePath=".\utils.c"
387 >
388 </File>
389 <File
390 RelativePath=".\vorbis.c"
391 >
392 </File>
393 </Filter>
394 </Files>
395 <Globals>
396 </Globals>
397 </VisualStudioProject>
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
1516 * You should have received a copy of the GNU General Public License
1617 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1718 *
19 * Additions (c) Paul Hermann, 2015-2017 under the same license terms
20 * -Control of Raspberry pi GPIO for amplifier power
21 * -Launch script on power status change from LMS
1822 */
1923
20 // make may define: PORTAUDIO, SELFPIPE, RESAMPLE, RESAMPLE_MP, VISEXPORT, IR, DSD, LINKALL to influence build
21
22 #define VERSION "v1.8"
24 // make may define: PORTAUDIO, SELFPIPE, RESAMPLE, RESAMPLE_MP, VISEXPORT, GPIO, IR, DSD, LINKALL to influence build
25
26 #define MAJOR_VERSION "1.9"
27 #define MINOR_VERSION "8"
28 #define MICRO_VERSION "1307"
29
30 #if defined(CUSTOM_VERSION)
31 #define VERSION "v" MAJOR_VERSION "." MINOR_VERSION "-" MICRO_VERSION STR(CUSTOM_VERSION)
32 #else
33 #define VERSION "v" MAJOR_VERSION "." MINOR_VERSION "-" MICRO_VERSION
34 #endif
35
2336
2437 #if !defined(MODEL_NAME)
2538 #define MODEL_NAME SqueezeLite
3952 #define LINUX 0
4053 #define OSX 1
4154 #define WIN 0
55 #define PORTAUDIO 1
4256 #define FREEBSD 0
4357 #elif defined (_MSC_VER)
4458 #define LINUX 0
4559 #define OSX 0
4660 #define WIN 1
61 #define PORTAUDIO 1
4762 #define FREEBSD 0
4863 #elif defined(__FreeBSD__)
4964 #define LINUX 0
5065 #define OSX 0
5166 #define WIN 0
67 #define PORTAUDIO 1
5268 #define FREEBSD 1
69 #elif defined (__sun)
70 #define SUN 1
71 #define LINUX 1
72 #define PORTAUDIO 1
73 #define PA18API 1
74 #define OSX 0
75 #define WIN 0
5376 #else
5477 #error unknown target
5578 #endif
5679
57 #if LINUX && !defined(PORTAUDIO)
58 #define ALSA 1
59 #define PORTAUDIO 0
60 #else
61 #define ALSA 0
62 #define PORTAUDIO 1
63 #endif
64
65 #if LINUX && !defined(SELFPIPE)
80 #if LINUX && !defined(PORTAUDIO) && !defined(PULSEAUDIO)
81 #define ALSA 1
82 #else
83 #define ALSA 0
84 #endif
85
86 #if SUN
87 #define EVENTFD 0
88 #define WINEVENT 0
89 #define SELFPIPE 1
90 #elif LINUX && !defined(SELFPIPE)
6691 #define EVENTFD 1
6792 #define SELFPIPE 0
6893 #define WINEVENT 0
93118 #define RESAMPLE_MP 0
94119 #endif
95120
121 #if defined(ALAC)
122 #undef ALAC
123 #define ALAC 1
124 #else
125 #define ALAC 0
126 #endif
127
96128 #if defined(FFMPEG)
97129 #undef FFMPEG
98130 #define FFMPEG 1
100132 #define FFMPEG 0
101133 #endif
102134
103 #if LINUX && defined(VISEXPORT)
135 #if defined(OPUS)
136 #undef OPUS
137 #define OPUS 1
138 #else
139 #define OPUS 0
140 #endif
141
142 #if (LINUX || OSX) && defined(VISEXPORT)
104143 #undef VISEXPORT
105144 #define VISEXPORT 1 // visulizer export support uses linux shared memory
106145 #else
131170 #define LINKALL 0
132171 #endif
133172
173 #if defined (USE_SSL)
174 #undef USE_SSL
175 #define USE_SSL 1
176 #else
177 #define USE_SSL 0
178 #endif
179
180 #if defined (NO_SSLSYM)
181 #undef NO_SSLSYM
182 #define NO_SSLSYM 1
183 #else
184 #define NO_SSLSYM 0
185 #endif
134186
135187 #if !LINKALL
136188
141193 #define LIBMAD "libmad.so.0"
142194 #define LIBMPG "libmpg123.so.0"
143195 #define LIBVORBIS "libvorbisfile.so.3"
196 #define LIBOPUS "libopusfile.so.0"
144197 #define LIBTREMOR "libvorbisidec.so.1"
145198 #define LIBFAAD "libfaad.so.2"
146199 #define LIBAVUTIL "libavutil.so.%d"
156209 #define LIBMPG "libmpg123.0.dylib"
157210 #define LIBVORBIS "libvorbisfile.3.dylib"
158211 #define LIBTREMOR "libvorbisidec.1.dylib"
212 #define LIBOPUS "libopusfile.0.dylib"
159213 #define LIBFAAD "libfaad.2.dylib"
160214 #define LIBAVUTIL "libavutil.%d.dylib"
161215 #define LIBAVCODEC "libavcodec.%d.dylib"
168222 #define LIBMAD "libmad-0.dll"
169223 #define LIBMPG "libmpg123-0.dll"
170224 #define LIBVORBIS "libvorbisfile.dll"
225 #define LIBOPUS "libopusfile-0.dll"
171226 #define LIBTREMOR "libvorbisidec.dll"
172227 #define LIBFAAD "libfaad2.dll"
173228 #define LIBAVUTIL "avutil-%d.dll"
177232 #endif
178233
179234 #if FREEBSD
180 #define LIBFLAC "libFLAC.so.11"
181 #define LIBMAD "libmad.so.2"
235 #define LIBFLAC "libFLAC.so.8"
236 #define LIBMAD "libmad.so.0"
182237 #define LIBMPG "libmpg123.so.0"
183 #define LIBVORBIS "libvorbisfile.so.6"
238 #define LIBVORBIS "libvorbisfile.so.3"
184239 #define LIBTREMOR "libvorbisidec.so.1"
240 #define LIBOPUS "libopusfile.so.1"
185241 #define LIBFAAD "libfaad.so.2"
186242 #define LIBAVUTIL "libavutil.so.%d"
187243 #define LIBAVCODEC "libavcodec.so.%d"
188244 #define LIBAVFORMAT "libavformat.so.%d"
245 #define LIBSOXR "libsoxr.so.0"
189246 #endif
190247
191248 #endif // !LINKALL
204261 #endif
205262
206263 #define SL_LITTLE_ENDIAN (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
264
265 #if SUN || OSXPPC
266 #undef SL_LITTLE_ENDIAN
267 #endif
207268
208269 #include <stdio.h>
209270 #include <stdlib.h>
224285 #include <dlfcn.h>
225286 #include <pthread.h>
226287 #include <signal.h>
288 #if SUN
289 #include <sys/types.h>
290 #endif /* SUN */
227291
228292 #define STREAM_THREAD_STACK_SIZE 64 * 1024
229293 #define DECODE_THREAD_STACK_SIZE 128 * 1024
230294 #define OUTPUT_THREAD_STACK_SIZE 64 * 1024
231295 #define IR_THREAD_STACK_SIZE 64 * 1024
296 #if !OSX
232297 #define thread_t pthread_t;
298 #endif
233299 #define closesocket(s) close(s)
234300 #define last_error() errno
235301 #define ERROR_WOULDBLOCK EWOULDBLOCK
236302
303 #ifdef SUN
304 typedef uint8_t u8_t;
305 typedef uint16_t u16_t;
306 typedef uint32_t u32_t;
307 typedef uint64_t u64_t;
308 #else
237309 typedef u_int8_t u8_t;
238310 typedef u_int16_t u16_t;
239311 typedef u_int32_t u32_t;
240312 typedef u_int64_t u64_t;
313 #endif /* SUN */
241314 typedef int16_t s16_t;
242315 typedef int32_t s32_t;
243316 typedef int64_t s64_t;
341414 #if (LINUX && __WORDSIZE == 64) || (FREEBSD && __LP64__)
342415 #define FMT_u64 "%lu"
343416 #define FMT_x64 "%lx"
344 #elif __GLIBC_HAVE_LONG_LONG || defined __GNUC__ || WIN
417 #elif __GLIBC_HAVE_LONG_LONG || defined __GNUC__ || WIN || SUN
345418 #define FMT_u64 "%llu"
346419 #define FMT_x64 "%llx"
347420 #else
353426 #define FIXED_ONE 0x10000
354427
355428 #define BYTES_PER_FRAME 8
429
430 #if BYTES_PER_FRAME == 8
431 #define ISAMPLE_T s32_t
432 #else
433 #define ISAMPLE_T s16_t
434 #endif
356435
357436 #define min(a,b) (((a) < (b)) ? (a) : (b))
358437
370449
371450 // utils.c (non logging)
372451 typedef enum { EVENT_TIMEOUT = 0, EVENT_READ, EVENT_WAKE } event_type;
452 #if WIN && USE_SSL
453 char* strcasestr(const char *haystack, const char *needle);
454 #endif
373455
374456 char *next_param(char *src, char c);
375457 u32_t gettime_ms(void);
388470 #else
389471 #define set_nosigpipe(s)
390472 #endif
473 #if SUN
474 void init_daemonize(void);
475 int daemon(int,int);
476 #endif
391477 #if WIN
392478 void winsock_init(void);
393479 void winsock_close(void);
419505 void _buf_inc_readp(struct buffer *buf, unsigned by);
420506 void _buf_inc_writep(struct buffer *buf, unsigned by);
421507 void buf_flush(struct buffer *buf);
508 void _buf_unwrap(struct buffer *buf, size_t cont);
422509 void buf_adjust(struct buffer *buf, size_t mod);
423510 void _buf_resize(struct buffer *buf, size_t size);
424511 void buf_init(struct buffer *buf, size_t size);
425512 void buf_destroy(struct buffer *buf);
426513
427514 // slimproto.c
428 void slimproto(log_level level, char *server, u8_t mac[6], const char *name, const char *namefile, const char *modelname);
515 void slimproto(log_level level, char *server, u8_t mac[6], const char *name, const char *namefile, const char *modelname, int maxSampleRate);
429516 void slimproto_stop(void);
430517 void wake_controller(void);
431518
452539 void stream_init(log_level level, unsigned stream_buf_size);
453540 void stream_close(void);
454541 void stream_file(const char *header, size_t header_len, unsigned threshold);
455 void stream_sock(u32_t ip, u16_t port, const char *header, size_t header_len, unsigned threshold, bool cont_wait);
542 void stream_sock(u32_t ip, u16_t port, bool use_ssl, const char *header, size_t header_len, unsigned threshold, bool cont_wait);
456543 bool stream_disconnect(void);
457544
458545 // decode.c
516603 typedef enum { OUTPUT_OFF = -1, OUTPUT_STOPPED = 0, OUTPUT_BUFFER, OUTPUT_RUNNING,
517604 OUTPUT_PAUSE_FRAMES, OUTPUT_SKIP_FRAMES, OUTPUT_START_AT } output_state;
518605
606 #if DSD
607 typedef enum { PCM, DOP, DSD_U8, DSD_U16_LE, DSD_U32_LE, DSD_U16_BE, DSD_U32_BE, DOP_S24_LE, DOP_S24_3LE } dsd_format;
608 typedef enum { S32_LE, S24_LE, S24_3LE, S16_LE, U8, U16_LE, U16_BE, U32_LE, U32_BE } output_format;
609 #else
519610 typedef enum { S32_LE, S24_LE, S24_3LE, S16_LE } output_format;
611 #endif
520612
521613 typedef enum { FADE_INACTIVE = 0, FADE_DUE, FADE_ACTIVE } fade_state;
522614 typedef enum { FADE_UP = 1, FADE_DOWN, FADE_CROSS } fade_dir;
523615 typedef enum { FADE_NONE = 0, FADE_CROSSFADE, FADE_IN, FADE_OUT, FADE_INOUT } fade_mode;
524616
525 #define MAX_SUPPORTED_SAMPLERATES 16
526 #define TEST_RATES = { 384000, 352800, 192000, 176400, 96000, 88200, 48000, 44100, 32000, 24000, 22500, 16000, 12000, 11025, 8000, 0 }
617 #define MAX_SUPPORTED_SAMPLERATES 18
618 #define TEST_RATES = { 768000, 705600, 384000, 352800, 192000, 176400, 96000, 88200, 48000, 44100, 32000, 24000, 22500, 16000, 12000, 11025, 8000, 0 }
527619
528620 struct outputstate {
529621 output_state state;
537629 #if PORTAUDIO
538630 bool pa_reopen;
539631 unsigned latency;
540 int osx_playnice;
632 int pa_hostapi_option;
541633 #endif
542634 int (* write_cb)(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR, s32_t cross_gain_in, s32_t cross_gain_out, s32_t **cross_ptr);
543635 unsigned start_frames;
574666 u32_t stop_time;
575667 u32_t idle_to;
576668 #if DSD
577 bool next_dop; // set in decode thread
578 bool dop;
579 bool has_dop; // set in dop_init - output device supports dop
580 unsigned dop_delay; // set in dop_init - delay in ms switching to/from dop
669 dsd_format next_fmt; // set in decode thread
670 dsd_format outfmt;
671 dsd_format dsdfmt; // set in dsd_init - output for DSD: DOP, DSD_U8, ...
672 unsigned dsd_delay; // set in dsd_init - delay in ms switching to/from dop
581673 #endif
582674 };
583675
593685 void list_devices(void);
594686 void list_mixers(const char *output_device);
595687 void set_volume(unsigned left, unsigned right);
596 bool test_open(const char *device, unsigned rates[]);
597 void output_init_alsa(log_level level, const char *device, unsigned output_buf_size, char *params, unsigned rates[],
598 unsigned rate_delay, unsigned rt_priority, unsigned idle, char *volume_mixer, bool mixer_unmute);
688 bool test_open(const char *device, unsigned rates[], bool userdef_rates);
689 void output_init_alsa(log_level level, const char *device, unsigned output_buf_size, char *params, unsigned rates[], unsigned rate_delay, unsigned rt_priority, unsigned idle, char *mixer_device, char *volume_mixer, bool mixer_unmute, bool mixer_linear);
599690 void output_close_alsa(void);
600691 #endif
601692
603694 #if PORTAUDIO
604695 void list_devices(void);
605696 void set_volume(unsigned left, unsigned right);
606 bool test_open(const char *device, unsigned rates[]);
697 bool test_open(const char *device, unsigned rates[], bool userdef_rates);
607698 void output_init_pa(log_level level, const char *device, unsigned output_buf_size, char *params, unsigned rates[], unsigned rate_delay, unsigned idle);
608699 void output_close_pa(void);
609700 void _pa_open(void);
701 #endif
702
703 // output_pulse.c
704 #if PULSEAUDIO
705 void list_devices(void);
706 void set_volume(unsigned left, unsigned right);
707 void set_sample_rate(uint32_t sample_rate);
708 bool test_open(const char *device, unsigned rates[], bool userdef_rates);
709 void output_init_pulse(log_level level, const char *device, unsigned output_buf_size, char *params, unsigned rates[], unsigned rate_delay, unsigned idle);
710 void output_close_pulse(void);
610711 #endif
611712
612713 // output_stdout.c
632733
633734 // dop.c
634735 #if DSD
635 bool is_flac_dop(u32_t *lptr, u32_t *rptr, frames_t frames);
736 bool is_stream_dop(u8_t *lptr, u8_t *rptr, int step, frames_t frames);
636737 void update_dop(u32_t *ptr, frames_t frames, bool invert);
637 void dop_silence_frames(u32_t *ptr, frames_t frames);
638 void dop_init(bool enable, unsigned delay);
738 void dsd_silence_frames(u32_t *ptr, frames_t frames);
739 void dsd_invert(u32_t *ptr, frames_t frames);
740 void dsd_init(dsd_format format, unsigned delay);
639741 #endif
640742
641743 // codecs
642 #define MAX_CODECS 9
744 #define MAX_CODECS 10
643745
644746 struct codec *register_flac(void);
645747 struct codec *register_pcm(void);
646748 struct codec *register_mad(void);
647749 struct codec *register_mpg(void);
648750 struct codec *register_vorbis(void);
751 #if ALAC
752 struct codec *register_alac(void);
753 #endif
649754 struct codec *register_faad(void);
650755 struct codec *register_dsd(void);
651756 struct codec *register_ff(const char *codec);
757 #if OPUS
758 struct codec *register_opus(void);
759 #endif
760
761 //gpio.c
762 #if GPIO
763 void relay( int state);
764 void relay_script(int state);
765 int gpio_pin;
766 bool gpio_active_low;
767 bool gpio_active;
768 char *power_script;
769 // my amp state
770 int ampstate;
771 #if RPI
772 #define PI_INPUT 0
773 #define PI_OUTPUT 1
774 #define PI_LOW 0
775 #define PI_HIGH 1
776 void gpioSetMode(unsigned gpio, unsigned mode);
777 void gpioWrite(unsigned gpio, unsigned level);
778 int gpioInitialise(void);
779 #endif
780 #endif
652781
653782 // ir.c
654783 #if IR
661790 void ir_init(log_level level, char *lircrc);
662791 void ir_close(void);
663792 #endif
793
794 // sslsym.c
795 #if USE_SSL && !LINKALL && !NO_SSLSYM
796 bool load_ssl_symbols(void);
797 void free_ssl_symbols(void);
798 bool ssl_loaded;
799 #endif
800
0 
1 Microsoft Visual Studio Solution File, Format Version 10.00
2 # Visual Studio 2008
3 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "squeezelite", "squeezelite.vcproj", "{7CB5A216-CEFA-4932-93CD-E9BFA33DD349}"
4 EndProject
5 Global
6 GlobalSection(SolutionConfigurationPlatforms) = preSolution
7 Debug|Win32 = Debug|Win32
8 Release|Win32 = Release|Win32
9 EndGlobalSection
10 GlobalSection(ProjectConfigurationPlatforms) = postSolution
11 {7CB5A216-CEFA-4932-93CD-E9BFA33DD349}.Debug|Win32.ActiveCfg = Release|Win32
12 {7CB5A216-CEFA-4932-93CD-E9BFA33DD349}.Debug|Win32.Build.0 = Release|Win32
13 {7CB5A216-CEFA-4932-93CD-E9BFA33DD349}.Release|Win32.ActiveCfg = Release|Win32
14 {7CB5A216-CEFA-4932-93CD-E9BFA33DD349}.Release|Win32.Build.0 = Release|Win32
15 EndGlobalSection
16 GlobalSection(SolutionProperties) = preSolution
17 HideSolutionNode = FALSE
18 EndGlobalSection
19 EndGlobal
0 <?xml version="1.0" encoding="UTF-8"?>
1 <VisualStudioProject
2 ProjectType="Visual C++"
3 Version="9.00"
4 Name="squeezelite"
5 ProjectGUID="{7CB5A216-CEFA-4932-93CD-E9BFA33DD349}"
6 RootNamespace="squeezelite"
7 Keyword="Win32Proj"
8 TargetFrameworkVersion="0"
9 >
10 <Platforms>
11 <Platform
12 Name="Win32"
13 />
14 </Platforms>
15 <ToolFiles>
16 </ToolFiles>
17 <Configurations>
18 <Configuration
19 Name="Debug|Win32"
20 OutputDirectory="Debug"
21 IntermediateDirectory="Debug"
22 ConfigurationType="1"
23 >
24 <Tool
25 Name="VCPreBuildEventTool"
26 />
27 <Tool
28 Name="VCCustomBuildTool"
29 />
30 <Tool
31 Name="VCXMLDataGeneratorTool"
32 />
33 <Tool
34 Name="VCWebServiceProxyGeneratorTool"
35 />
36 <Tool
37 Name="VCMIDLTool"
38 />
39 <Tool
40 Name="VCCLCompilerTool"
41 Optimization="0"
42 PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"
43 MinimalRebuild="true"
44 BasicRuntimeChecks="3"
45 RuntimeLibrary="3"
46 UsePrecompiledHeader="0"
47 WarningLevel="3"
48 Detect64BitPortabilityProblems="true"
49 DebugInformationFormat="4"
50 />
51 <Tool
52 Name="VCManagedResourceCompilerTool"
53 />
54 <Tool
55 Name="VCResourceCompilerTool"
56 />
57 <Tool
58 Name="VCPreLinkEventTool"
59 />
60 <Tool
61 Name="VCLinkerTool"
62 LinkIncremental="2"
63 GenerateDebugInformation="true"
64 SubSystem="1"
65 TargetMachine="1"
66 />
67 <Tool
68 Name="VCALinkTool"
69 />
70 <Tool
71 Name="VCManifestTool"
72 />
73 <Tool
74 Name="VCXDCMakeTool"
75 />
76 <Tool
77 Name="VCBscMakeTool"
78 />
79 <Tool
80 Name="VCFxCopTool"
81 />
82 <Tool
83 Name="VCAppVerifierTool"
84 />
85 <Tool
86 Name="VCPostBuildEventTool"
87 />
88 </Configuration>
89 <Configuration
90 Name="Release|Win32"
91 OutputDirectory="Release"
92 IntermediateDirectory="Release"
93 ConfigurationType="1"
94 >
95 <Tool
96 Name="VCPreBuildEventTool"
97 />
98 <Tool
99 Name="VCCustomBuildTool"
100 />
101 <Tool
102 Name="VCXMLDataGeneratorTool"
103 />
104 <Tool
105 Name="VCWebServiceProxyGeneratorTool"
106 />
107 <Tool
108 Name="VCMIDLTool"
109 />
110 <Tool
111 Name="VCCLCompilerTool"
112 AdditionalIncludeDirectories="include\opus;include"
113 PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;RESAMPLE;FFMPEG;OPUS;DSD;USE_SSL;FLAC__NO_DLL;LINKALL"
114 RuntimeLibrary="0"
115 UsePrecompiledHeader="0"
116 WarningLevel="3"
117 Detect64BitPortabilityProblems="false"
118 DebugInformationFormat="0"
119 />
120 <Tool
121 Name="VCManagedResourceCompilerTool"
122 />
123 <Tool
124 Name="VCResourceCompilerTool"
125 />
126 <Tool
127 Name="VCPreLinkEventTool"
128 />
129 <Tool
130 Name="VCLinkerTool"
131 AdditionalOptions="/NODEFAULTLIB:LIBCMT"
132 AdditionalDependencies="ws2_32.lib lib\portaudio.lib lib\libogg.lib lib\libvorbisfile.lib lib\libvorbis.lib lib\libmad.lib lib\libFLAC.lib lib\libfaad.lib lib\libmpg123.lib lib\libsoxr.lib lib\libavformat.a lib\libavcodec.a lib\libavutil.a lib\ssleay32.lib lib\libeay32.lib lib\opus.lib lib\opusfile.lib"
133 OutputFile="$(OutDir)\$(ProjectName)-ffmpeg.exe"
134 LinkIncremental="1"
135 ModuleDefinitionFile=""
136 GenerateDebugInformation="false"
137 SubSystem="1"
138 OptimizeReferences="2"
139 EnableCOMDATFolding="2"
140 TargetMachine="1"
141 />
142 <Tool
143 Name="VCALinkTool"
144 />
145 <Tool
146 Name="VCManifestTool"
147 />
148 <Tool
149 Name="VCXDCMakeTool"
150 />
151 <Tool
152 Name="VCBscMakeTool"
153 />
154 <Tool
155 Name="VCFxCopTool"
156 />
157 <Tool
158 Name="VCAppVerifierTool"
159 />
160 <Tool
161 Name="VCPostBuildEventTool"
162 />
163 </Configuration>
164 </Configurations>
165 <References>
166 </References>
167 <Files>
168 <Filter
169 Name="Header Files"
170 Filter="h;hpp;hxx;hm;inl;inc;xsd"
171 UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
172 >
173 <File
174 RelativePath=".\include\flac\all.h"
175 >
176 </File>
177 <File
178 RelativePath=".\include\flac\assert.h"
179 >
180 </File>
181 <File
182 RelativePath=".\include\flac\callback.h"
183 >
184 </File>
185 <File
186 RelativePath=".\include\vorbis\codec.h"
187 >
188 </File>
189 <File
190 RelativePath=".\include\ogg\config_types.h"
191 >
192 </File>
193 <File
194 RelativePath=".\dsd2pcm\dsd2pcm.h"
195 >
196 </File>
197 <File
198 RelativePath=".\include\flac\export.h"
199 >
200 </File>
201 <File
202 RelativePath=".\include\flac\format.h"
203 >
204 </File>
205 <File
206 RelativePath=".\include\mad.h"
207 >
208 </File>
209 <File
210 RelativePath=".\include\flac\metadata.h"
211 >
212 </File>
213 <File
214 RelativePath=".\include\mpg123.h"
215 >
216 </File>
217 <File
218 RelativePath=".\include\neaacdec.h"
219 >
220 </File>
221 <File
222 RelativePath=".\include\ogg\ogg.h"
223 >
224 </File>
225 <File
226 RelativePath=".\include\flac\ordinals.h"
227 >
228 </File>
229 <File
230 RelativePath=".\include\ogg\os_types.h"
231 >
232 </File>
233 <File
234 RelativePath=".\include\portaudio.h"
235 >
236 </File>
237 <File
238 RelativePath=".\slimproto.h"
239 >
240 </File>
241 <File
242 RelativePath=".\include\soxr.h"
243 >
244 </File>
245 <File
246 RelativePath=".\squeezelite.h"
247 >
248 </File>
249 <File
250 RelativePath=".\include\flac\stream_decoder.h"
251 >
252 </File>
253 <File
254 RelativePath=".\include\flac\stream_encoder.h"
255 >
256 </File>
257 <File
258 RelativePath=".\include\vorbis\vorbisenc.h"
259 >
260 </File>
261 <File
262 RelativePath=".\include\vorbis\vorbisfile.h"
263 >
264 </File>
265 </Filter>
266 <Filter
267 Name="Resource Files"
268 Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
269 UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
270 >
271 </Filter>
272 <Filter
273 Name="Source Files"
274 Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
275 UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
276 >
277 <File
278 RelativePath=".\buffer.c"
279 >
280 </File>
281 <File
282 RelativePath=".\decode.c"
283 >
284 </File>
285 <File
286 RelativePath=".\dop.c"
287 >
288 </File>
289 <File
290 RelativePath=".\dsd.c"
291 >
292 </File>
293 <File
294 RelativePath=".\dsd2pcm\dsd2pcm.c"
295 >
296 </File>
297 <File
298 RelativePath=".\faad.c"
299 >
300 </File>
301 <File
302 RelativePath=".\ffmpeg.c"
303 >
304 </File>
305 <File
306 RelativePath=".\flac.c"
307 >
308 </File>
309 <File
310 RelativePath=".\mad.c"
311 >
312 </File>
313 <File
314 RelativePath=".\main.c"
315 >
316 </File>
317 <File
318 RelativePath=".\mpg.c"
319 >
320 </File>
321 <File
322 RelativePath=".\opus.c"
323 >
324 </File>
325 <File
326 RelativePath=".\output.c"
327 >
328 </File>
329 <File
330 RelativePath=".\output_alsa.c"
331 >
332 </File>
333 <File
334 RelativePath=".\output_pa.c"
335 >
336 </File>
337 <File
338 RelativePath=".\output_pack.c"
339 >
340 </File>
341 <File
342 RelativePath=".\output_stdout.c"
343 >
344 </File>
345 <File
346 RelativePath=".\output_vis.c"
347 >
348 </File>
349 <File
350 RelativePath=".\pcm.c"
351 >
352 </File>
353 <File
354 RelativePath=".\process.c"
355 >
356 </File>
357 <File
358 RelativePath=".\resample.c"
359 >
360 </File>
361 <File
362 RelativePath=".\slimproto.c"
363 >
364 </File>
365 <File
366 RelativePath=".\sslsym.c"
367 >
368 </File>
369 <File
370 RelativePath=".\stream.c"
371 >
372 </File>
373 <File
374 RelativePath=".\utils.c"
375 >
376 </File>
377 <File
378 RelativePath=".\vorbis.c"
379 >
380 </File>
381 </Filter>
382 </Files>
383 <Globals>
384 </Globals>
385 </VisualStudioProject>
0 /*
1 * SSL symbols dynamic loader
2 *
3 * This program 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 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18 #include "squeezelite.h"
19
20 #if USE_SSL && !LINKALL && !NO_SSLSYM
21
22 #if WIN
23 #define dlclose FreeLibrary
24 #else
25 #include <dlfcn.h>
26 #endif
27
28 #include "openssl/ssl.h"
29 #include "openssl/err.h"
30 #include <openssl/rand.h>
31 #include <openssl/rsa.h>
32 #include <openssl/engine.h>
33 #include <openssl/aes.h>
34 #include <openssl/bio.h>
35
36 static void *SSLhandle = NULL;
37 static void *CRYPThandle = NULL;
38
39 #if WIN
40 static char *LIBSSL[] = { "libssl.dll",
41 "ssleay32.dll", NULL };
42 static char *LIBCRYPTO[] = { "libcrypto.dll",
43 "libeay32.dll", NULL };
44 #elif OSX
45 static char *LIBSSL[] = { "libssl.dylib", NULL };
46 static char *LIBCRYPTO[] = { "libcrypto.dylib", NULL };
47 #else
48 static char *LIBSSL[] = { "libssl.so",
49 "libssl.so.1.1",
50 "libssl.so.1.0.2",
51 "libssl.so.1.0.1",
52 "libssl.so.1.0.0", NULL };
53 static char *LIBCRYPTO[] = { "libcrypto.so",
54 "libcrypto.so.1.1",
55 "libcrypto.so.1.0.2",
56 "libcrypto.so.1.0.1",
57 "libcrypto.so.1.0.0", NULL };
58 #endif
59
60 #define P0() void
61 #define P1(t1, p1) t1 p1
62 #define P2(t1, p1, t2, p2) t1 p1, t2 p2
63 #define P3(t1, p1, t2, p2, t3, p3) t1 p1, t2 p2, t3 p3
64 #define P4(t1, p1, t2, p2, t3, p3, t4, p4) t1 p1, t2 p2, t3 p3, t4 p4
65 #define P5(t1, p1, t2, p2, t3, p3, t4, p4, t5, p5) t1 p1, t2 p2, t3 p3, t4 p4, t5 p5
66 #define P6(t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6) t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6
67 #define V0()
68 #define V1(t1, p1) p1
69 #define V2(t1, p1, t2, p2) p1, p2
70 #define V3(t1, p1, t2, p2, t3, p3) p1, p2, p3
71 #define V4(t1, p1, t2, p2, t3, p3, t4, p4) p1, p2, p3, p4
72 #define V5(t1, p1, t2, p2, t3, p3, t4, p4, t5, p5) p1, p2, p3, p4, p5
73 #define V6(t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6) p1, p2, p3, p4, p5, p6
74
75 #define P(n, ...) P##n(__VA_ARGS__)
76 #define V(n, ...) V##n(__VA_ARGS__)
77
78 #define SYM(fn) dlsym_##fn
79 #define SYMDECL(fn, ret, n, ...) \
80 static ret (*dlsym_##fn)(P(n,__VA_ARGS__)); \
81 ret fn(P(n,__VA_ARGS__)) { \
82 return (*dlsym_##fn)(V(n,__VA_ARGS__)); \
83 }
84
85 #define SYMDECLVOID(fn, n, ...) \
86 static void (*dlsym_##fn)(P(n,__VA_ARGS__)); \
87 void fn(P(n,__VA_ARGS__)) { \
88 (*dlsym_##fn)(V(n,__VA_ARGS__)); \
89 }
90
91 #define SYMLOAD(h, fn) dlsym_##fn = dlsym(h, #fn)
92
93 SYMDECL(SSL_read, int, 3, SSL*, s, void*, buf, int, len);
94 SYMDECL(SSL_write, int, 3, SSL*, s, const void*, buf, int, len);
95 SYMDECL(SSLv23_client_method, const SSL_METHOD*, 0);
96 SYMDECL(TLS_client_method, const SSL_METHOD*, 0);
97 SYMDECL(SSL_library_init, int, 0);
98 SYMDECL(SSL_CTX_new, SSL_CTX*, 1, const SSL_METHOD *, meth);
99 SYMDECL(SSL_CTX_ctrl, long, 4, SSL_CTX *, ctx, int, cmd, long, larg, void*, parg);
100 SYMDECL(SSL_new, SSL*, 1, SSL_CTX*, s);
101 SYMDECL(SSL_connect, int, 1, SSL*, s);
102 SYMDECL(SSL_shutdown, int, 1, SSL*, s);
103 SYMDECL(SSL_get_fd, int, 1, const SSL*, s);
104 SYMDECL(SSL_set_fd, int, 2, SSL*, s, int, fd);
105 SYMDECL(SSL_get_error, int, 2, const SSL*, s, int, ret_code);
106 SYMDECL(SSL_ctrl, long, 4, SSL*, ssl, int, cmd, long, larg, void*, parg);
107 SYMDECL(SSL_pending, int, 1, const SSL*, s);
108 SYMDECLVOID(SSL_free, 1, SSL*, s);
109 SYMDECLVOID(SSL_CTX_free, 1, SSL_CTX *, ctx);
110 SYMDECL(ERR_get_error, unsigned long, 0);
111 SYMDECLVOID(ERR_clear_error, 0);
112
113 static void *dlopen_try(char **filenames, int flag) {
114 void *handle;
115 for (handle = NULL; !handle && *filenames; filenames++) handle = dlopen(*filenames, flag);
116 return handle;
117 }
118
119 static int lambda(void) {
120 return true;
121 }
122
123 bool load_ssl_symbols(void) {
124 CRYPThandle = dlopen_try(LIBCRYPTO, RTLD_NOW);
125 SSLhandle = dlopen_try(LIBSSL, RTLD_NOW);
126
127 if (!SSLhandle || !CRYPThandle) {
128 free_ssl_symbols();
129 return false;
130 }
131
132 SYMLOAD(SSLhandle, SSL_CTX_new);
133 SYMLOAD(SSLhandle, SSL_CTX_ctrl);
134 SYMLOAD(SSLhandle, SSL_CTX_free);
135 SYMLOAD(SSLhandle, SSL_ctrl);
136 SYMLOAD(SSLhandle, SSL_free);
137 SYMLOAD(SSLhandle, SSL_new);
138 SYMLOAD(SSLhandle, SSL_connect);
139 SYMLOAD(SSLhandle, SSL_get_fd);
140 SYMLOAD(SSLhandle, SSL_set_fd);
141 SYMLOAD(SSLhandle, SSL_get_error);
142 SYMLOAD(SSLhandle, SSL_shutdown);
143 SYMLOAD(SSLhandle, SSL_read);
144 SYMLOAD(SSLhandle, SSL_write);
145 SYMLOAD(SSLhandle, SSL_pending);
146 SYMLOAD(SSLhandle, SSLv23_client_method);
147 SYMLOAD(SSLhandle, TLS_client_method);
148 SYMLOAD(SSLhandle, SSL_library_init);
149
150 SYMLOAD(CRYPThandle, ERR_clear_error);
151 SYMLOAD(CRYPThandle, ERR_get_error);
152
153 // managed deprecated functions
154 if (!SYM(SSLv23_client_method)) SYM(SSLv23_client_method) = SYM(TLS_client_method);
155 if (!SYM(SSL_library_init)) SYM(SSL_library_init) = &lambda;
156
157 return true;
158 }
159
160 void free_ssl_symbols(void) {
161 if (SSLhandle) dlclose(SSLhandle);
162 if (CRYPThandle) dlclose(CRYPThandle);
163 }
164
165 #endif
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
1920
2021 // stream thread
2122
23 #define _GNU_SOURCE
24
2225 #include "squeezelite.h"
2326
2427 #include <fcntl.h>
2528
29 #if USE_SSL
30 #include "openssl/ssl.h"
31 #include "openssl/err.h"
32 #endif
33
34 #if SUN
35 #include <signal.h>
36 #endif
2637 static log_level loglevel;
2738
2839 static struct buffer buf;
3243 #define UNLOCK mutex_unlock(streambuf->mutex)
3344
3445 static sockfd fd;
46 static struct sockaddr_in addr;
47 static char host[256];
48 static int header_mlen;
3549
3650 struct streamstate stream;
3751
38 static void send_header(void) {
52 #if USE_SSL
53 #define _last_error() ERROR_WOULDBLOCK
54
55 static SSL_CTX *SSLctx;
56 SSL *ssl;
57
58 static int _recv(SSL *ssl, int fd, void *buffer, size_t bytes, int options) {
59 int n;
60 if (!ssl) return recv(fd, buffer, bytes, options);
61 n = SSL_read(ssl, (u8_t*) buffer, bytes);
62 if (n <= 0 && SSL_get_error(ssl, n) == SSL_ERROR_ZERO_RETURN) return 0;
63 return n;
64 }
65
66 static int _send(SSL *ssl, int fd, void *buffer, size_t bytes, int options) {
67 int n;
68 if (!ssl) return send(fd, buffer, bytes, options);
69 while (1) {
70 int err;
71 ERR_clear_error();
72 if ((n = SSL_write(ssl, (u8_t*) buffer, bytes)) >= 0) return n;
73 err = SSL_get_error(ssl, n);
74 if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) continue;
75 LOG_INFO("SSL write error %d", err );
76 return n;
77 }
78 }
79
80 /*
81 can't mimic exactly poll as SSL is a real pain. Even if SSL_pending returns
82 0, there might be bytes to read but when select (poll) return > 0, there might
83 be no frame available. As well select (poll) < 0 does not mean that there is
84 no data pending
85 */
86 static int _poll(SSL *ssl, struct pollfd *pollinfo, int timeout) {
87 if (!ssl) return poll(pollinfo, 1, timeout);
88 if (pollinfo->events & POLLIN && SSL_pending(ssl)) {
89 if (pollinfo->events & POLLOUT) poll(pollinfo, 1, 0);
90 pollinfo->revents = POLLIN;
91 return 1;
92 }
93 return poll(pollinfo, 1, timeout);
94 }
95 #else
96 #define _recv(ssl, fc, buf, n, opt) recv(fd, buf, n, opt)
97 #define _send(ssl, fd, buf, n, opt) send(fd, buf, n, opt)
98 #define _poll(ssl, pollinfo, timeout) poll(pollinfo, 1, timeout)
99 #define _last_error() last_error()
100 #endif // USE_SSL
101
102
103 static bool send_header(void) {
39104 char *ptr = stream.header;
40105 int len = stream.header_len;
41106
43108 ssize_t n;
44109
45110 while (len) {
46 n = send(fd, ptr, len, MSG_NOSIGNAL);
111 n = _send(ssl, fd, ptr, len, MSG_NOSIGNAL);
47112 if (n <= 0) {
48 if (n < 0 && last_error() == ERROR_WOULDBLOCK && try < 10) {
113 if (n < 0 && _last_error() == ERROR_WOULDBLOCK && try < 10) {
49114 LOG_SDEBUG("retrying (%d) writing to socket", ++try);
50115 usleep(1000);
51116 continue;
54119 stream.disconnect = LOCAL_DISCONNECT;
55120 stream.state = DISCONNECT;
56121 wake_controller();
57 return;
122 return false;
58123 }
59124 LOG_SDEBUG("wrote %d bytes to socket", n);
60125 ptr += n;
61126 len -= n;
62127 }
63128 LOG_SDEBUG("wrote header");
129 return true;
64130 }
65131
66132 static bool running = true;
68134 static void _disconnect(stream_state state, disconnect_code disconnect) {
69135 stream.state = state;
70136 stream.disconnect = disconnect;
137 #if USE_SSL
138 if (ssl) {
139 SSL_shutdown(ssl);
140 SSL_free(ssl);
141 ssl = NULL;
142 }
143 #endif
71144 closesocket(fd);
72145 fd = -1;
73146 wake_controller();
74147 }
75148
149 static int connect_socket(bool use_ssl) {
150 int sock = socket(AF_INET, SOCK_STREAM, 0);
151
152 if (sock < 0) {
153 LOG_ERROR("failed to create socket");
154 return -1;
155 }
156
157 LOG_INFO("connecting to %s:%d", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
158
159 set_nonblock(sock);
160 set_nosigpipe(sock);
161
162 if (connect_timeout(sock, (struct sockaddr *) &addr, sizeof(addr), 10) < 0) {
163 LOG_INFO("unable to connect to server");
164 closesocket(sock);
165 return -1;
166 }
167
168 #if USE_SSL
169 if (use_ssl) {
170 ssl = SSL_new(SSLctx);
171 SSL_set_fd(ssl, sock);
172
173 // add SNI
174 if (*host) SSL_set_tlsext_host_name(ssl, host);
175
176 while (1) {
177 int status, err = 0;
178
179 ERR_clear_error();
180 status = SSL_connect(ssl);
181
182 // successful negotiation
183 if (status == 1) break;
184
185 // error or non-blocking requires more time
186 if (status < 0) {
187 err = SSL_get_error(ssl, status);
188 if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
189 usleep(1000);
190 continue;
191 }
192 }
193
194 LOG_WARN("unable to open SSL socket %d (%d)", status, err);
195 closesocket(sock);
196 SSL_free(ssl);
197 ssl = NULL;
198
199 return -1;
200 }
201 }
202 #endif
203
204 return sock;
205 }
206
76207 static void *stream_thread() {
77
78208 while (running) {
79209
80210 struct pollfd pollinfo;
121251
122252 UNLOCK;
123253
124 if (poll(&pollinfo, 1, 100)) {
254 if (_poll(ssl, &pollinfo, 100)) {
125255
126256 LOCK;
127257
132262 }
133263
134264 if ((pollinfo.revents & POLLOUT) && stream.state == SEND_HEADERS) {
135 send_header();
265 if (send_header()) stream.state = RECV_HEADERS;
266 header_mlen = stream.header_len;
136267 stream.header_len = 0;
137 stream.state = RECV_HEADERS;
138268 UNLOCK;
139269 continue;
140270 }
148278 char c;
149279 static int endtok;
150280
151 int n = recv(fd, &c, 1, 0);
281 int n = _recv(ssl, fd, &c, 1, 0);
152282 if (n <= 0) {
153 if (n < 0 && last_error() == ERROR_WOULDBLOCK) {
283 if (n < 0 && _last_error() == ERROR_WOULDBLOCK) {
154284 UNLOCK;
155285 continue;
156286 }
157287 LOG_INFO("error reading headers: %s", n ? strerror(last_error()) : "closed");
288 #if USE_SSL
289 if (!ssl && !stream.header_len) {
290 int sock;
291 closesocket(fd);
292 fd = -1;
293 stream.header_len = header_mlen;
294 LOG_INFO("now attempting with SSL");
295
296 // must be performed locked in case slimproto sends a disconnects
297 sock = connect_socket(true);
298
299 if (sock >= 0) {
300 fd = sock;
301 stream.state = SEND_HEADERS;
302 UNLOCK;
303 continue;
304 }
305 }
306 #endif
158307 _disconnect(STOPPED, LOCAL_DISCONNECT);
159308 UNLOCK;
160309 continue;
190339 if (stream.meta_left == 0) {
191340 // read meta length
192341 u8_t c;
193 int n = recv(fd, &c, 1, 0);
342 int n = _recv(ssl, fd, &c, 1, 0);
194343 if (n <= 0) {
195 if (n < 0 && last_error() == ERROR_WOULDBLOCK) {
344 if (n < 0 && _last_error() == ERROR_WOULDBLOCK) {
196345 UNLOCK;
197346 continue;
198347 }
207356 }
208357
209358 if (stream.meta_left) {
210 int n = recv(fd, stream.header + stream.header_len, stream.meta_left, 0);
359 int n = _recv(ssl, fd, stream.header + stream.header_len, stream.meta_left, 0);
211360 if (n <= 0) {
212 if (n < 0 && last_error() == ERROR_WOULDBLOCK) {
361 if (n < 0 && _last_error() == ERROR_WOULDBLOCK) {
213362 UNLOCK;
214363 continue;
215364 }
243392 space = min(space, stream.meta_next);
244393 }
245394
246 n = recv(fd, streambuf->writep, space, 0);
395 n = _recv(ssl, fd, streambuf->writep, space, 0);
247396 if (n == 0) {
248397 LOG_INFO("end of stream");
249398 _disconnect(DISCONNECT, DISCONNECT_OK);
250399 }
251 if (n < 0 && last_error() != ERROR_WOULDBLOCK) {
400 if (n < 0 && _last_error() != ERROR_WOULDBLOCK) {
252401 LOG_INFO("error reading: %s", strerror(last_error()));
253402 _disconnect(DISCONNECT, REMOTE_DISCONNECT);
254403 }
259408 if (stream.meta_interval) {
260409 stream.meta_next -= n;
261410 }
411 } else {
412 UNLOCK;
413 continue;
262414 }
263415
264416 if (stream.state == STREAMING_BUFFERING && stream.bytes > stream.threshold) {
277429 LOG_SDEBUG("poll timeout");
278430 }
279431 }
432
433 #if USE_SSL
434 if (SSLctx) {
435 SSL_CTX_free(SSLctx);
436 }
437 #endif
280438
281439 return 0;
282440 }
295453 exit(0);
296454 }
297455
456 #if USE_SSL
457 #if !LINKALL && !NO_SSLSYM
458 if (ssl_loaded) {
459 #endif
460 SSL_library_init();
461 SSLctx = SSL_CTX_new(SSLv23_client_method());
462 if (SSLctx == NULL) {
463 LOG_ERROR("unable to allocate SSL context");
464 exit(0);
465 }
466 SSL_CTX_set_options(SSLctx, SSL_OP_NO_SSLv2);
467 #if !LINKALL && !NO_SSLSYM
468 }
469 #endif
470 ssl = NULL;
471 #endif
472
473 #if SUN
474 signal(SIGPIPE, SIG_IGN); /* Force sockets to return -1 with EPIPE on pipe signal */
475 #endif
298476 stream.state = STOPPED;
299477 stream.header = malloc(MAX_HEADER);
300478 *stream.header = '\0';
308486 #if LINUX || OSX || FREEBSD
309487 pthread_attr_t attr;
310488 pthread_attr_init(&attr);
489 #ifdef PTHREAD_STACK_MIN
311490 pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN + STREAM_THREAD_STACK_SIZE);
491 #endif
312492 pthread_create(&thread, &attr, stream_thread, NULL);
313493 pthread_attr_destroy(&attr);
314494 #endif
365545 UNLOCK;
366546 }
367547
368 void stream_sock(u32_t ip, u16_t port, const char *header, size_t header_len, unsigned threshold, bool cont_wait) {
369 struct sockaddr_in addr;
370
371 int sock = socket(AF_INET, SOCK_STREAM, 0);
372
373 if (sock < 0) {
374 LOG_ERROR("failed to create socket");
375 return;
376 }
548 void stream_sock(u32_t ip, u16_t port, bool use_ssl, const char *header, size_t header_len, unsigned threshold, bool cont_wait) {
549 char *p;
550 int sock;
377551
378552 memset(&addr, 0, sizeof(addr));
379553 addr.sin_family = AF_INET;
380554 addr.sin_addr.s_addr = ip;
381555 addr.sin_port = port;
382556
383 LOG_INFO("connecting to %s:%d", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
384
385 set_nonblock(sock);
386 set_nosigpipe(sock);
387
388 if (connect_timeout(sock, (struct sockaddr *) &addr, sizeof(addr), 10) < 0) {
389 LOG_INFO("unable to connect to server");
557 *host = '\0';
558 p = strcasestr(header,"Host:");
559 if (p) sscanf(p, "Host:%255[^:]", host);
560
561 port = ntohs(port);
562 sock = connect_socket(use_ssl || port == 443);
563
564 // try one more time with plain socket
565 if (sock < 0 && port == 443 && !use_ssl) sock = connect_socket(false);
566
567 if (sock < 0) {
390568 LOCK;
391569 stream.state = DISCONNECT;
392570 stream.disconnect = UNREACHABLE;
421599 bool stream_disconnect(void) {
422600 bool disc = false;
423601 LOCK;
602 #if USE_SSL
603 if (ssl) {
604 SSL_shutdown(ssl);
605 SSL_free(ssl);
606 ssl = NULL;
607 }
608 #endif
424609 if (fd != -1) {
425610 closesocket(fd);
426611 fd = -1;
0 /*
1 * ALSA parameter test program
2 *
3 * Copyright (c) 2007 Volker Schatz (alsacap at the domain volkerschatz.com)
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
12 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
13 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
14 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
15 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 *
17 *
18 * This program was originally written by Volker Schatz. Shawn Wilson
19 * bundled it into an autotools package and cut and pasted some code
20 * from the alsa speaker-test command to display min/max buffer and
21 * period sizes.
22 *
23 */
24
25
26 /*============================================================================
27 Includes
28 ============================================================================*/
29
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <alsa/asoundlib.h>
33 #include <errno.h>
34 #include <ctype.h>
35 #include <string.h>
36
37
38 /*============================================================================
39 Constant and type definitions
40 ============================================================================*/
41
42 #define RATE_KHZ_LIMIT 200
43
44 #define HWP_END 0
45 #define HWP_RATE 1
46 #define HWP_NCH 2
47 #define HWP_FORMAT 3
48 #define SIZE_HWP 7
49
50 typedef struct {
51 int recdevices, verbose, card, dev;
52 char *device;
53 int hwparams[SIZE_HWP];
54 }
55 aiopts;
56
57
58 /*============================================================================
59 Global variables
60 ============================================================================*/
61
62 static snd_ctl_t *handle= NULL;
63 static snd_pcm_t *pcm= NULL;
64 static snd_ctl_card_info_t *info;
65 static snd_pcm_info_t *pcminfo;
66 static snd_pcm_hw_params_t *pars;
67 static snd_pcm_format_mask_t *fmask;
68
69
70 /*============================================================================
71 Prototypes
72 ============================================================================*/
73
74 void usagemsg(int code);
75 void errnumarg(char optchar);
76 void errarg(char optchar);
77 void errtoomany();
78
79 void scancards(snd_pcm_stream_t stream, int thecard, int thedev);
80 int sc_errcheck(int retval, const char *doingwhat, int cardnr, int devnr);
81
82 void testconfig(snd_pcm_stream_t stream, const char *device, const int *hwpars);
83 void tc_errcheck(int retval, const char *doingwhat);
84
85 const char *alsaerrstr(const int errcode);
86 const char *dirstr(int dir);
87
88 int parse_alsaformat(const char *fmtstr);
89 const char *alsafmtstr(int fmtnum);
90
91 void printfmtmask(const snd_pcm_format_mask_t *fmask);
92
93
94 /*============================================================================
95 Main program
96 ============================================================================*/
97
98 int main(int argc, char **argv)
99 {
100 aiopts options= { 0, 1, -1, -1, NULL };
101 snd_pcm_stream_t stream;
102 char *argpar;
103 int argind, hwpind;
104
105 snd_ctl_card_info_alloca(&info);
106 snd_pcm_info_alloca(&pcminfo);
107 snd_pcm_hw_params_alloca(&pars);
108 snd_pcm_format_mask_alloca(&fmask);
109
110 hwpind= 0;
111 for( argind= 1; argind< argc; ++argind )
112 {
113 if( argv[argind][0]!='-' ) {
114 fprintf(stderr, "Unrecognised command-line argument `%s'.\n", argv[argind]);
115 usagemsg(1);
116 }
117 if( argv[argind][2] ) argpar= argv[argind]+2;
118 else {
119 if( argind+1 >= argc ) argpar= NULL;
120 else argpar= argv[argind+1];
121 }
122 if( argv[argind][1]=='h' || !strcmp(argv[argind]+1, "-help") )
123 usagemsg(0);
124 else if( argv[argind][1]=='R' ) {
125 options.recdevices= 1;
126 argpar= NULL; // set to NULL if unused to keep track of next arg index
127 }
128 else if( argv[argind][1]=='C' ) {
129 if( !argpar || !isdigit(*argpar) ) errnumarg('C');
130 options.card= strtol(argpar, NULL, 0);
131 }
132 else if( argv[argind][1]=='D' ) {
133 if( !argpar || !isdigit(*argpar) ) errnumarg('D');
134 options.dev= strtol(argpar, NULL, 0);
135 }
136 else if( argv[argind][1]=='d' ) {
137 if( !argpar ) errarg('d');
138 options.device= argpar;
139 }
140 else if( argv[argind][1]=='r' ) {
141 if( !argpar || !isdigit(*argpar) ) errnumarg('r');
142 if( hwpind+3 > SIZE_HWP ) errtoomany();
143 options.hwparams[hwpind++]= HWP_RATE;
144 options.hwparams[hwpind]= strtol(argpar, NULL, 0);
145 if( options.hwparams[hwpind] <= RATE_KHZ_LIMIT )
146 options.hwparams[hwpind] *= 1000; // sanity check: Hz or kHz ?
147 ++hwpind;
148 }
149 else if( argv[argind][1]=='c' ) {
150 if( !argpar || !isdigit(*argpar) ) errnumarg('c');
151 if( hwpind+3 > SIZE_HWP ) errtoomany();
152 options.hwparams[hwpind++]= HWP_NCH;
153 options.hwparams[hwpind++]= strtol(argpar, NULL, 0);
154 }
155 else if( argv[argind][1]=='f' ) {
156 if( !argpar ) errarg('f');
157 if( hwpind+3 > SIZE_HWP ) errtoomany();
158 options.hwparams[hwpind++]= HWP_FORMAT;
159 options.hwparams[hwpind++]= parse_alsaformat(argpar);
160 }
161 else {
162 fprintf(stderr, "Unrecognised command-line option `%s'.\n", argv[argind]);
163 usagemsg(1);
164 }
165 if( argpar && !argv[argind][2] )
166 ++argind; // additional increment if separate parameter argument was used
167 }
168 options.hwparams[hwpind]= HWP_END;
169 if( options.dev >= 0 && options.card < 0 ) {
170 fprintf(stderr, "The card has to be specified with -C if a device number is given (-D).\n");
171 exit(1);
172 }
173 if( options.device && (options.card>=0 || options.dev>=0) ) {
174 fprintf(stderr, "Specifying a device name (-d) and a card and possibly device number (-C, -D) is mutually exclusive.\n");
175 exit(1);
176 }
177 stream= options.recdevices? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK;
178
179 if( !options.device )
180 scancards(stream, options.card, options.dev);
181 else
182 testconfig(stream, options.device, options.hwparams);
183
184 }
185
186
187
188 /*============================================================================
189 Usage message and command-line argument error functions
190 ============================================================================*/
191
192 void usagemsg(int code)
193 {
194 fprintf(stderr, "Usage: alsacap [-R] [-C <card #> [-D <device #>]]\n"
195 " alsacap [-R] -d <device name> [-r <rate>|-c <# of channels>|-f <sample format>]...\n"
196 "ALSA capability lister.\n"
197 "First form: Scans one or all soundcards known to ALSA for devices, \n"
198 "subdevices and parameter ranges. -R causes a scan for recording\n"
199 "rather than playback devices. The other options specify the sound\n"
200 "card and possibly the device by number.\n"
201 "Second form: Displays ranges of configuration parameters for the given\n"
202 "ALSA device. Unlike with the first form, a non-hardware device may be\n"
203 "given. Up to three optional command-line arguments fix the rate,\n"
204 "number of channels and sample format in the order in which they are\n"
205 "given. The remaining parameter ranges are output. If unique, the\n"
206 "number of significant bits of the sample values is output. (Some\n"
207 "sound cards ignore some of the bits.)\n");
208 exit(code);
209 }
210
211 void errnumarg(char optchar)
212 {
213 fprintf(stderr, "The -%c option requires a numerical argument! Aborting.\n", optchar);
214 exit(1);
215 }
216
217 void errarg(char optchar)
218 {
219 fprintf(stderr, "The -%c option requires an argument! Aborting.\n", optchar);
220 exit(1);
221 }
222
223 void errtoomany()
224 {
225 fprintf(stderr, "Too many -r/-c/-f options given! (Maximum is %d.) Aborting.\n", (SIZE_HWP-1)/2);
226 exit(1);
227 }
228
229
230 /*============================================================================
231 Function for scanning all cards
232 ============================================================================*/
233
234 #define HWCARDTEMPL "hw:%d"
235 #define HWDEVTEMPL "hw:%d,%d"
236 #define HWDEVLEN 32
237
238 void scancards(snd_pcm_stream_t stream, int thecard, int thedev)
239 {
240 char hwdev[HWDEVLEN+1];
241 unsigned min, max;
242 int card, err, dev, subd, nsubd;
243 snd_pcm_uframes_t period_size_min;
244 snd_pcm_uframes_t period_size_max;
245 snd_pcm_uframes_t buffer_size_min;
246 snd_pcm_uframes_t buffer_size_max;
247
248
249 printf("*** Scanning for %s devices",
250 stream == SND_PCM_STREAM_CAPTURE? "recording" : "playback");
251 if( thecard >= 0 )
252 printf(" on card %d", thecard);
253 if( thedev >= 0 )
254 printf(", device %d", thedev);
255 printf(" ***\n");
256
257 hwdev[HWDEVLEN]= 0;
258
259 if( thecard >= 0 )
260 card= thecard;
261 else {
262 card= -1;
263 if( snd_card_next(&card) < 0 )
264 return;
265 }
266
267
268 while( card >= 0 )
269 {
270 snprintf(hwdev, HWDEVLEN, HWCARDTEMPL, card);
271 err= snd_ctl_open(&handle, hwdev, 0);
272 if( sc_errcheck(err, "opening control interface", card, -1) ) goto nextcard;
273 err= snd_ctl_card_info(handle, info);
274 if( sc_errcheck(err, "obtaining card info", card, -1) ) {
275 snd_ctl_close(handle);
276 goto nextcard;
277 }
278 printf("\nCard %d, ID `%s', name `%s'\n",
279 card, snd_ctl_card_info_get_id(info),
280 snd_ctl_card_info_get_name(info));
281 if( thedev >= 0 )
282 dev= thedev;
283 else {
284 dev= -1;
285 if( snd_ctl_pcm_next_device(handle, &dev) < 0 ) {
286 snd_ctl_close(handle);
287 goto nextcard;
288 }
289 }
290 while( dev >= 0 )
291 {
292 snd_pcm_info_set_device(pcminfo, dev);
293 snd_pcm_info_set_subdevice(pcminfo, 0);
294 snd_pcm_info_set_stream(pcminfo, stream);
295 err= snd_ctl_pcm_info(handle, pcminfo);
296
297 if( thedev<0 && err == -ENOENT )
298 goto nextdev;
299 if( sc_errcheck(err, "obtaining device info", card, dev) )
300 goto nextdev;
301 nsubd= snd_pcm_info_get_subdevices_count(pcminfo);
302 if( sc_errcheck(nsubd, "obtaining device info", card, dev) )
303 goto nextdev;
304
305 printf(
306 " Device %d, ID `%s', name `%s', %d subdevices (%d available)\n",
307 dev, snd_pcm_info_get_id(pcminfo), snd_pcm_info_get_name(pcminfo),
308 nsubd, snd_pcm_info_get_subdevices_avail(pcminfo));
309 snprintf(hwdev, HWDEVLEN, HWDEVTEMPL, card, dev);
310
311 err= snd_pcm_open(&pcm, hwdev, stream, SND_PCM_NONBLOCK);
312 if( sc_errcheck(err, "opening sound device", card, dev) ) goto nextdev;
313 err= snd_pcm_hw_params_any(pcm, pars);
314 if( sc_errcheck(err, "obtaining hardware parameters", card, dev) ) {
315 snd_pcm_close(pcm);
316 goto nextdev;
317 }
318 snd_pcm_hw_params_get_channels_min(pars, &min);
319 snd_pcm_hw_params_get_channels_max(pars, &max);
320 if( min == max )
321 if( min == 1 )
322 printf(" 1 channel, ");
323 else
324 printf(" %d channels, ", min);
325 else
326 printf(" %u..%u channels, ", min, max);
327
328 /* Find and print out min/max sampling rates. */
329 snd_pcm_hw_params_get_rate_min(pars, &min, NULL);
330 snd_pcm_hw_params_get_rate_max(pars, &max, NULL);
331 printf("sampling rate %u..%u Hz\n", min, max);
332
333 /* Find and print out possible PCM formats. */
334 snd_pcm_hw_params_get_format_mask(pars, fmask);
335 printf(" Sample formats: ");
336 printfmtmask(fmask);
337 printf("\n");
338
339 /* Find and print out min/max buffer and period sizes. */
340 err = snd_pcm_hw_params_get_buffer_size_min(
341 pars, &buffer_size_min);
342 err = snd_pcm_hw_params_get_buffer_size_max(
343 pars, &buffer_size_max);
344 err = snd_pcm_hw_params_get_period_size_min(
345 pars, &period_size_min, NULL);
346 err = snd_pcm_hw_params_get_period_size_max(
347 pars, &period_size_max, NULL);
348
349 printf(" Buffer size range from %lu to %lu\n",
350 buffer_size_min, buffer_size_max);
351 printf(" Period size range from %lu to %lu\n",
352 period_size_min, period_size_max);
353
354
355 snd_pcm_close(pcm);
356 pcm= NULL;
357
358 for( subd= 0; subd< nsubd; ++subd ) {
359 snd_pcm_info_set_subdevice(pcminfo, subd);
360 err= snd_ctl_pcm_info(handle, pcminfo);
361 if( sc_errcheck(err, "obtaining subdevice info", card, dev) )
362 goto nextdev;
363
364 printf(" Subdevice %d, name `%s'\n",
365 subd, snd_pcm_info_get_subdevice_name(pcminfo));
366 }
367
368 nextdev:
369 if( thedev >= 0 || snd_ctl_pcm_next_device(handle, &dev) < 0 )
370 break;
371 }
372 snd_ctl_close(handle);
373 nextcard:
374 if( thecard >= 0 || snd_card_next(&card) < 0 )
375 break;
376 }
377 }
378
379
380 int sc_errcheck(int retval, const char *doingwhat, int cardnr, int devnr)
381 {
382 if( retval<0 ) {
383 if( devnr>= 0 )
384 fprintf(stderr, "Error %s for card %d, device %d: %s. Skipping.\n", doingwhat, cardnr, devnr, alsaerrstr(retval));
385 else
386 fprintf(stderr, "Error %s for card %d: %s. Skipping.\n", doingwhat, cardnr, alsaerrstr(retval));
387 return 1;
388 }
389 return 0;
390 }
391
392
393
394 /*============================================================================
395 Function for investigating device configurations
396 ============================================================================*/
397
398 void testconfig(snd_pcm_stream_t stream, const char *device, const int *hwpars)
399 {
400 unsigned min, max, param;
401 int err, count, dir, result;
402 snd_pcm_uframes_t period_size_min;
403 snd_pcm_uframes_t period_size_max;
404 snd_pcm_uframes_t buffer_size_min;
405 snd_pcm_uframes_t buffer_size_max;
406
407 printf("*** Exploring configuration space of device `%s' for %s ***\n", device,
408 stream==SND_PCM_STREAM_CAPTURE? "recording" : "playback");
409 err= snd_pcm_open(&pcm, device, stream, SND_PCM_NONBLOCK);
410 tc_errcheck(err, "opening sound device");
411 err= snd_pcm_hw_params_any(pcm, pars);
412 tc_errcheck(err, "initialising hardware parameters");
413 for( count= 0; hwpars[count]!=HWP_END; count += 2 )
414
415 switch(hwpars[count])
416 {
417 case HWP_RATE:param= hwpars[count+1];
418 err= snd_pcm_hw_params_set_rate_near(pcm, pars, &param, &result);
419 if( err<0 )
420 fprintf(stderr, "Could not set sampling rate to %d Hz: %s. "
421 "Continuing regardless.\n", hwpars[count+1], alsaerrstr(err));
422 else
423 printf("Set sampling rate %d Hz --> got %u Hz, %s requested.\n", hwpars[count+1], param, dirstr(dir));
424 break;
425 case HWP_NCH:err= snd_pcm_hw_params_set_channels(pcm, pars, hwpars[count+1]);
426 if( err<0 )
427 fprintf(stderr, "Could not set # of channels to %d: %s. "
428 "Continuing regardless.\n", hwpars[count+1], alsaerrstr(err));
429 else
430 printf("Set number of channels to %d.\n", hwpars[count+1]);
431 break;
432 case HWP_FORMAT:err= snd_pcm_hw_params_set_format(pcm, pars, hwpars[count+1]);
433 if( err<0 )
434 fprintf(stderr, "Could not set sample format to %s: %s."
435 " Continuing regardless.\n", alsafmtstr(hwpars[count+1]), alsaerrstr(err));
436 else
437 printf("Set sample format to %s.\n", alsafmtstr(hwpars[count+1]));
438 break;
439 default:
440 break;
441 }
442 if( count>0 )
443 printf("Parameter ranges remaining after these settings:\n");
444 snd_pcm_hw_params_get_channels_min(pars, &min);
445 snd_pcm_hw_params_get_channels_max(pars, &max);
446 if( min==max )
447 if( min==1 )
448 printf("1 channel\n");
449 else
450 printf("%u channels\n", min);
451 else
452 printf("%u..%u channels\n", min, max);
453 snd_pcm_hw_params_get_rate_min(pars, &min, NULL);
454 snd_pcm_hw_params_get_rate_max(pars, &max, NULL);
455 if( min==max )
456 printf("Sampling rate %u Hz\n", min);
457 else
458 printf("Sampling rate %u..%u Hz\n", min, max);
459
460 /* Find and print out possible PCM formats. */
461 snd_pcm_hw_params_get_format_mask(pars, fmask);
462 printf(" Sample formats: ");
463 printfmtmask(fmask);
464 printf("\n");
465
466 /* Find and print out min/max buffer and period sizes. */
467 err = snd_pcm_hw_params_get_buffer_size_min(
468 pars, &buffer_size_min);
469 err = snd_pcm_hw_params_get_buffer_size_max(
470 pars, &buffer_size_max);
471 err = snd_pcm_hw_params_get_period_size_min(
472 pars, &period_size_min, NULL);
473 err = snd_pcm_hw_params_get_period_size_max(
474 pars, &period_size_max, NULL);
475
476 printf(" Buffer size range from %lu to %lu\n",
477 buffer_size_min, buffer_size_max);
478 printf(" Period size range from %lu to %lu\n",
479 period_size_min, period_size_max);
480
481 result= snd_pcm_hw_params_get_sbits(pars);
482 if( result >= 0 ) // only available if bit width of all formats is the same
483 printf("Significant bits: %d\n", result);
484 snd_pcm_close(pcm);
485 }
486
487
488 void tc_errcheck(int retval, const char *doingwhat)
489 {
490 if( retval<0 ) {
491 fprintf(stderr, "Error %s: %s. Aborting.\n", doingwhat, alsaerrstr(retval));
492 if( pcm )
493 snd_pcm_close(pcm);
494 exit(1);
495 }
496 }
497
498
499 /*============================================================================
500 String-building functions
501 ============================================================================*/
502
503 struct alsaerr { int err; char *msg; };
504 struct alsaerr aelist[]= {
505 -EBADFD, "PCM device is in a bad state",
506 -EPIPE, "An underrun occurred",
507 -ESTRPIPE, "A suspend event occurred",
508 -ENOTTY, "Hotplug device has been removed",
509 -ENODEV, "Hotplug device has been removed",
510 -ENOENT, "Device does not exist",
511 0, NULL
512 };
513 const char *alsaerrstr(const int errcode)
514 {
515 struct alsaerr *search;
516
517 if( errcode >= 0 )
518 return "No error";
519 for( search= aelist; search->msg && search->err!=errcode; ++search);
520 if( search->msg )
521 return search->msg;
522 else
523 return strerror(-errcode);
524 }
525
526
527 const char *dirstr(int dir)
528 {
529 if( !dir )
530 return "=";
531 else if( dir<0 )
532 return "<";
533 else
534 return ">";
535 }
536
537
538 /*============================================================================
539 Functions for parsing and string output of ALSA sample formats
540 ============================================================================*/
541
542 struct fmtdef { char *fmtname; int format; };
543 static struct fmtdef fmtlist[]= {
544 "S8", SND_PCM_FORMAT_S8,
545 "U8", SND_PCM_FORMAT_U8,
546 "S16_LE", SND_PCM_FORMAT_S16_LE,
547 "S16_BE", SND_PCM_FORMAT_S16_BE,
548 "U16_LE", SND_PCM_FORMAT_U16_LE,
549 "U16_BE", SND_PCM_FORMAT_U16_BE,
550 "S24_LE", SND_PCM_FORMAT_S24_LE,
551 "S24_BE", SND_PCM_FORMAT_S24_BE,
552 "U24_LE", SND_PCM_FORMAT_U24_LE,
553 "U24_BE", SND_PCM_FORMAT_U24_BE,
554 "S32_LE", SND_PCM_FORMAT_S32_LE,
555 "S32_BE", SND_PCM_FORMAT_S32_BE,
556 "U32_LE", SND_PCM_FORMAT_U32_LE,
557 "U32_BE", SND_PCM_FORMAT_U32_BE,
558 "FLOAT_LE", SND_PCM_FORMAT_FLOAT_LE,
559 "FLOAT_BE", SND_PCM_FORMAT_FLOAT_BE,
560 "FLOAT64_LE", SND_PCM_FORMAT_FLOAT64_LE,
561 "FLOAT64_BE", SND_PCM_FORMAT_FLOAT64_BE,
562 "IEC958_SUBFRAME_LE", SND_PCM_FORMAT_IEC958_SUBFRAME_LE,
563 "IEC958_SUBFRAME_BE", SND_PCM_FORMAT_IEC958_SUBFRAME_BE,
564 "MU_LAW", SND_PCM_FORMAT_MU_LAW,
565 "A_LAW", SND_PCM_FORMAT_A_LAW,
566 "IMA_ADPCM", SND_PCM_FORMAT_IMA_ADPCM,
567 "MPEG", SND_PCM_FORMAT_MPEG,
568 "GSM", SND_PCM_FORMAT_GSM,
569 "SPECIAL", SND_PCM_FORMAT_SPECIAL,
570 "S24_3LE", SND_PCM_FORMAT_S24_3LE,
571 "S24_3BE", SND_PCM_FORMAT_S24_3BE,
572 "U24_3LE", SND_PCM_FORMAT_U24_3LE,
573 "U24_3BE", SND_PCM_FORMAT_U24_3BE,
574 "S20_3LE", SND_PCM_FORMAT_S20_3LE,
575 "S20_3BE", SND_PCM_FORMAT_S20_3BE,
576 "U20_3LE", SND_PCM_FORMAT_U20_3LE,
577 "U20_3BE", SND_PCM_FORMAT_U20_3BE,
578 "S18_3LE", SND_PCM_FORMAT_S18_3LE,
579 "S18_3BE", SND_PCM_FORMAT_S18_3BE,
580 "U18_3LE", SND_PCM_FORMAT_U18_3LE,
581 "U18_3BE", SND_PCM_FORMAT_U18_3BE,
582 "S16", SND_PCM_FORMAT_S16,
583 "U16", SND_PCM_FORMAT_U16,
584 "S24", SND_PCM_FORMAT_S24,
585 "U24", SND_PCM_FORMAT_U24,
586 "S32", SND_PCM_FORMAT_S32,
587 "U32", SND_PCM_FORMAT_U32,
588 "FLOAT", SND_PCM_FORMAT_FLOAT,
589 "FLOAT64", SND_PCM_FORMAT_FLOAT64,
590 "IEC958_SUBFRAME", SND_PCM_FORMAT_IEC958_SUBFRAME,
591 NULL, 0
592 };
593
594 int parse_alsaformat(const char *fmtstr)
595 {
596 struct fmtdef *search;
597
598 for( search= fmtlist; search->fmtname && strcmp(search->fmtname, fmtstr); ++search );
599 if( !search->fmtname ) {
600 fprintf(stderr, "Unknown sample format `%s'. Aborting.\n", fmtstr);
601 exit(1);
602 }
603 return search->format;
604 }
605
606 const char *alsafmtstr(int fmtnum)
607 {
608 struct fmtdef *search;
609
610 for( search= fmtlist; search->fmtname && search->format!=fmtnum; ++search );
611 if( !search->fmtname )
612 return "(unknown)";
613 else
614 return search->fmtname;
615 }
616
617
618 /*============================================================================
619 Printout functions
620 ============================================================================*/
621
622 void printfmtmask(const snd_pcm_format_mask_t *fmask)
623 {
624 int fmt, prevformat= 0;
625
626 for( fmt= 0; fmt <= SND_PCM_FORMAT_LAST; ++fmt )
627 if( snd_pcm_format_mask_test(fmask, (snd_pcm_format_t)fmt) ) {
628 if( prevformat )
629 printf(", ");
630 printf("%s", snd_pcm_format_name((snd_pcm_format_t)fmt));
631 prevformat= 1;
632 }
633 if( !prevformat )
634 printf("(none)");
635 }
636
637
0 /*
1 * SlimProtoLib is distributed in the hope that it will be useful,
2 * but WITHOUT ANY WARRANTY; without even the implied warranty of
3 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4 * GNU General Public License for more details.
5 *
6 * You should have received a copy of the GNU General Public License
7 * along with SlimProtoLib; if not, write to the Free Software
8 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
9 *
10 */
11
12 #include <assert.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <sys/types.h>
16 #include <signal.h>
17 #include <stdlib.h>
18 #include <ctype.h>
19
20 #ifdef __WIN32__
21 #include <winsock2.h>
22 #include <ws2tcpip.h>
23 #include "poll.h"
24 #define CLOSESOCKET(s) closesocket(s)
25 #define MSG_DONTWAIT (0)
26 #else
27 #include <sys/poll.h>
28 #include <arpa/inet.h>
29 #include <unistd.h>
30 #include <sys/types.h>
31 #include <netinet/in.h>
32 #include <netinet/tcp.h>
33 #include <netdb.h>
34 #include <sys/socket.h>
35 #include <sys/time.h>
36 #include <errno.h>
37 #define CLOSESOCKET(s) close(s)
38 #endif
39
40 #define BUF_LENGTH 4096
41
42 /* fprintf(stderr, __VA_ARGS__) */
43 #define DEBUGF(...)
44 #define VDEBUGF(...)
45
46 #define packN4(ptr, off, v) { ptr[off] = (char)(v >> 24) & 0xFF; ptr[off+1] = (v >> 16) & 0xFF; ptr[off+2] = (v >> 8) & 0xFF; ptr[off+3] = v & 0xFF; }
47 #define packN2(ptr, off, v) { ptr[off] = (char)(v >> 8) & 0xFF; ptr[off+1] = v & 0xFF; }
48 #define packC(ptr, off, v) { ptr[off] = v & 0xFF; }
49 #define packA4(ptr, off, v) { strncpy((char*)(&ptr[off]), v, 4); }
50
51 #define unpackN4(ptr, off) ((ptr[off] << 24) | (ptr[off+1] << 16) | (ptr[off+2] << 8) | ptr[off+3])
52 #define unpackN2(ptr, off) ((ptr[off] << 8) | ptr[off+1])
53 #define unpackC(ptr, off) (ptr[off])
54
55 #define bool int
56 #define true 1
57 #define false 0
58
59 #define DISCOVERY_PKTSIZE 1516
60 #define SLIMPROTO_DISCOVERY "eNAME\0JSON\0"
61
62 int slimproto_discover(char *server_addr, int server_addr_len, int port, unsigned int *jsonport, bool scan)
63 {
64 int sockfd;
65 int try;
66 char *packet;
67 int pktlen;
68 int pktidx;
69 char *t;
70 unsigned int l;
71 char *v;
72 char *server_name;
73 char *server_json;
74 struct pollfd pollfd;
75 struct sockaddr_in sendaddr;
76 struct sockaddr_in recvaddr;
77 #ifdef __WIN32__
78 WSADATA info;
79 #endif
80
81 socklen_t sockaddr_len = sizeof(sendaddr);
82
83 int broadcast=1;
84 int serveraddr_len = -1;
85
86 #ifdef __WIN32__
87 /* Need to initialize winsock if scanning on windows as slimproto_init has not been called */
88 if ( scan )
89 {
90 if (WSAStartup(MAKEWORD(1,1), &info) != 0)
91 {
92 fprintf(stderr, "Cannot initialize WinSock");
93 return -1;
94 }
95 }
96 #endif
97
98 if((sockfd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
99 {
100 perror("sockfd");
101 return -1;
102 }
103
104 pollfd.fd = sockfd;
105 pollfd.events = POLLIN;
106
107 if((setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (const void*) &broadcast, sizeof broadcast)) == -1)
108 {
109 perror("setsockopt - SO_BROADCAST");
110 return -1;
111 }
112
113 sendaddr.sin_family = AF_INET;
114 sendaddr.sin_port = htons(0);
115 sendaddr.sin_addr.s_addr = INADDR_ANY;
116 memset(sendaddr.sin_zero,'\0',sizeof sendaddr.sin_zero);
117
118 if(bind(sockfd, (struct sockaddr*) &sendaddr, sizeof sendaddr) == -1)
119 {
120 perror("bind");
121 return -1;
122 }
123
124 recvaddr.sin_family = AF_INET;
125 recvaddr.sin_port = htons(port);
126 recvaddr.sin_addr.s_addr = INADDR_BROADCAST;
127
128 memset(recvaddr.sin_zero,'\0',sizeof recvaddr.sin_zero);
129
130 packet = malloc ( sizeof ( char ) * DISCOVERY_PKTSIZE );
131 v = malloc ( sizeof ( char ) * 256 );
132 t = malloc ( sizeof ( char ) * 256 );
133 server_name = malloc ( sizeof ( char ) * 256 );
134 server_json = malloc ( sizeof ( char ) * 256 );
135 if ( (packet == NULL) ||
136 (v == NULL) ||
137 (t == NULL) ||
138 (server_name == NULL) ||
139 (server_json == NULL) )
140 {
141 perror("malloc");
142 return -1;
143 }
144
145 for (try = 0; try < 5; try ++)
146 {
147 if (sendto(sockfd, SLIMPROTO_DISCOVERY, sizeof(SLIMPROTO_DISCOVERY), 0,
148 (struct sockaddr *)&recvaddr, sizeof(recvaddr)) == -1)
149 {
150 CLOSESOCKET(sockfd);
151 perror("sendto");
152 return -1;
153 }
154
155 DEBUGF("slimproto_discover: discovery packet sent\n");
156
157 /* Wait up to 1 second for response */
158 while (poll(&pollfd, 1, 1000))
159 {
160 memset(packet,0,sizeof(packet));
161
162 pktlen = recvfrom(sockfd, packet, DISCOVERY_PKTSIZE, MSG_DONTWAIT,
163 (struct sockaddr *)&sendaddr, &sockaddr_len);
164
165 if ( pktlen == -1 ) continue;
166
167 /* Invalid response packet, try again */
168 if ( packet[0] != 'E') continue;
169
170 memset(server_name,0,sizeof(server_name));
171 memset(server_json,0,sizeof(server_json));
172
173 VDEBUGF("slimproto_discover: pktlen:%d\n",pktlen);
174
175 /* Skip the E */
176 pktidx = 1;
177
178 while ( pktidx < (pktlen - 5) )
179 {
180 strncpy ( t, &packet[pktidx], pktidx + 3 );
181 t[4] = '\0';
182 l = (unsigned int) ( packet[pktidx + 4] );
183 strncpy ( v, &packet[pktidx + 5], pktidx + 4 + l);
184 v[l] = '\0';
185 pktidx = pktidx + 5 + l;
186
187 if ( memcmp ( t, "NAME", 4 ) == 0 )
188 {
189 strncpy ( server_name, v, l );
190 server_name[l] = '\0';
191 }
192 else if ( memcmp ( t, "JSON", 4 ) == 0 )
193 {
194 strncpy ( server_json, v, l );
195 server_json[l] = '\0';
196 }
197
198 VDEBUGF("slimproto_discover: key: %s len: %d value: %s pktidx: %d\n",
199 t, l, v, pktidx);
200 }
201
202 inet_ntop(AF_INET, &sendaddr.sin_addr.s_addr, server_addr, server_addr_len);
203
204 *jsonport = (unsigned int) strtoul(server_json, NULL, 10);
205
206 DEBUGF("slimproto_discover: discovered %s:%u (%s)\n",
207 server_name, *jsonport, server_addr);
208
209 serveraddr_len = strlen(server_addr);
210
211 /* Server(s) responded, so don't try again */
212 try = 5;
213
214 if ( scan )
215 printf("%s:%u (%s)\n", server_name, *jsonport, server_addr);
216 else
217 break ; /* Return first server that replied */
218 }
219 }
220
221 CLOSESOCKET(sockfd);
222
223 if ( scan )
224 {
225 strcpy ( server_addr, "0.0.0.0" );
226 *jsonport = 0;
227 serveraddr_len = -1;
228 #ifdef __WIN32__
229 WSACleanup();
230 #endif
231 }
232
233 if ( server_json != NULL )
234 free (server_json);
235
236 if ( server_name != NULL )
237 free (server_name);
238
239 if ( t != NULL )
240 free (t);
241
242 if ( v != NULL )
243 free (v);
244
245 if ( packet != NULL )
246 free (packet);
247
248 DEBUGF("slimproto_discover: end\n");
249
250 return serveraddr_len ;
251 }
252
253 static void license(void) {
254 printf( "\n"
255 "This program is free software: you can redistribute it and/or modify\n"
256 "it under the terms of the GNU General Public License as published by\n"
257 "the Free Software Foundation, either version 3 of the License, or\n"
258 "(at your option) any later version.\n\n"
259 "This program is distributed in the hope that it will be useful,\n"
260 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
261 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
262 "GNU General Public License for more details.\n\n"
263 "You should have received a copy of the GNU General Public License\n"
264 "along with this program. If not, see <http://www.gnu.org/licenses/>.\n\n"
265 "The source is available from https://github.com/ralph-irving/squeezelite\n"
266 );
267 }
268
269 int main(int argc, char **argv)
270 {
271 char slimserver_address[256] = "127.0.0.1";
272 int port = 3483;
273 unsigned int json;
274 int len ;
275
276 if (argc > 1)
277 {
278 license();
279 exit (1);
280 }
281
282 /* Scan */
283 len = slimproto_discover(slimserver_address, sizeof (slimserver_address), port, &json, true);
284
285 VDEBUGF("main: slimproto_discover_scan: address:%s len:%d json:%u\n", slimserver_address, len, json );
286
287 return 0;
288 }
289
0 #!/bin/sh
1
2 # Define GPIO
3 GPIO_OUT=18
4
5 # Turn on, and turn off functions
6 turn_on() {
7 echo "1" > /sys/class/gpio/gpio$GPIO_OUT/value
8 }
9
10 turn_off() {
11 echo "0" > /sys/class/gpio/gpio$GPIO_OUT/value
12 }
13
14 init_gpio_out() {
15 #================================================= ==========================
16 # Initial GPIO OUT setup
17 #---------------------------------------------------------------------------
18 sudo sh -c 'echo '"$GPIO_OUT"' > /sys/class/gpio/export'
19 # Relay is active low, so this reverses the logic
20 sudo sh -c 'echo "1" > /sys/class/gpio/gpio'"$GPIO_OUT"'/active_low'
21 sudo sh -c 'echo "out" > /sys/class/gpio/gpio'"$GPIO_OUT"'/direction'
22 sudo sh -c 'echo "0" > /sys/class/gpio/gpio'"$GPIO_OUT"'/value'
23 #---------------------------------------------------------------------------
24 }
25
26 case "${1}" in
27
28 # 2 from cmdline is for first initialization commands, this is run once
29 2)
30 init_gpio_out
31 ;;
32
33 # 0 from cmdline is for Off Commands
34 0)
35 turn_off
36 ;;
37
38 # 1 from cmdline is for On Commands
39 1)
40 turn_on
41 ;;
42 esac
0 #
1 # using lirc-0.9.4(userspace) on Thu Apr 30 10:29:59 2020
2 #
3 # contributed by Ralph Irving
4 #
5 # brand: Slim Devices
6 # model no. of remote control: Squeezebox3 Touch
7 # devices being controlled by this remote: Squeezelite
8 #
9
10 begin remote
11
12 name Slim_Devices_Squeezebox3
13 bits 16
14 flags SPACE_ENC|CONST_LENGTH
15 eps 30
16 aeps 100
17
18 header 9100 4416
19 one 649 1593
20 zero 647 473
21 ptrail 649
22 pre_data_bits 16
23 pre_data 0x7689
24 gap 107995
25 min_repeat 1
26 suppress_repeat 6
27 toggle_bit_mask 0x0
28
29 begin codes
30 KEY_VOLUMEDOWN 0x00FF
31 KEY_VOLUMEUP 0x807F
32 KEY_REWIND 0xC03F
33 KEY_FORWARD 0xA05F
34 KEY_PAUSE 0x20DF
35 KEY_PLAY 0x10EF
36 KEY_POWER 0x40BF
37 KEY_UP 0xE01F
38 KEY_LEFT 0x906F
39 KEY_RIGHT 0xD02F
40 KEY_DOWN 0xB04F
41 KEY_1 0xF00F
42 KEY_2 0x08F7
43 KEY_3 0x8877
44 KEY_4 0x48B7
45 KEY_5 0xC837
46 KEY_6 0x28D7
47 KEY_7 0xA857
48 KEY_8 0x6897
49 KEY_9 0xE817
50 KEY_0 0x9867
51 KEY_FAVORITES 0x18E7
52 KEY_SEARCH 0x58A7
53 KEY_SHUFFLE 0xD827
54 KEY_MEDIA_REPEAT 0x38C7
55 KEY_SLEEP 0xB847
56 KEY_INSERT 0x609F ## Add
57 KEY_BRIGHTNESS_CYCLE 0x04FB ## Brightness
58 KEY_TEXT 0xF807 ## Size
59 KEY_TITLE 0x7887 ## Now Playing
60 KEY_FAVORITES 0xE21D ## Touch:FAVOURITES
61 KEY_SEARCH 0x629D ## Touch:SEARCH
62 KEY_HOME 0x22DD ## Touch:HOME
63 KEY_TITLE 0xA25D ## Touch:NOW PLAYING
64 end codes
65
66 end remote
0 ############################
1 ## KEY_POWER (0x768940bf) ##
2 ############################
3
4 begin
5 remote = Slim_Devices_Squeezebox3
6 button = KEY_POWER
7 repeat = 0
8 prog = squeezelite
9 config = power
10 end
11
12 #################################
13 ## KEY_VOLUMEDOWN (0x768900ff) ##
14 #################################
15
16 begin
17 remote = Slim_Devices_Squeezebox3
18 button = KEY_VOLUMEDOWN
19 repeat = 0
20 prog = squeezelite
21 config = voldown
22 end
23
24 ###############################
25 ## KEY_VOLUMEUP (0x7689807f) ##
26 ###############################
27
28 begin
29 remote = Slim_Devices_Squeezebox3
30 button = KEY_VOLUMEUP
31 repeat = 0
32 prog = squeezelite
33 config = volup
34 end
35
36 ###########################
37 ## KEY_MUTE (0x7689c43b) ##
38 ###########################
39
40 begin
41 remote = Slim_Devices_Squeezebox3
42 button = Brightness
43 repeat = 0
44 prog = squeezelite
45 config = muting
46 end
47
48 ###########################
49 ## KEY_PLAY (0x768910ef) ##
50 ###########################
51
52 begin
53 remote = Slim_Devices_Squeezebox3
54 button = KEY_PLAY
55 repeat = 0
56 prog = squeezelite
57 config = play
58 end
59
60 ############################
61 ## KEY_PAUSE (0x768920df) ##
62 ############################
63
64 begin
65 remote = Slim_Devices_Squeezebox3
66 button = KEY_PAUSE
67 repeat = 0
68 prog = squeezelite
69 config = pause
70 end
71
72 ###########################
73 ## KEY_NEXT (0x7689a05f) ##
74 ###########################
75
76 begin
77 remote = Slim_Devices_Squeezebox3
78 button = KEY_FORWARD
79 repeat = 0
80 prog = squeezelite
81 config = fwd
82 end
83
84 ###############################
85 ## KEY_PREVIOUS (0x7689c03f) ##
86 ###############################
87
88 begin
89 remote = Slim_Devices_Squeezebox3
90 button = KEY_REWIND
91 repeat = 0
92 prog = squeezelite
93 config = rew
94 end
95
96 ###########################
97 ## power_on (0x76898f70) ##
98 ###########################
99
100 ############################
101 ## power_off (0x76898778) ##
102 ############################
103
104 ###########################
105 ## preset_1 (0x76898a75) ##
106 ###########################
107
108 ###########################
109 ## preset_2 (0x76894ab5) ##
110 ###########################
111
112 ###########################
113 ## preset_3 (0x7689ca35) ##
114 ###########################
115
116 ###########################
117 ## preset_4 (0x76892ad5) ##
118 ###########################
119
120 ###########################
121 ## preset_5 (0x7689aa55) ##
122 ###########################
123
124 ###########################
125 ## preset_6 (0x76896a95) ##
126 ###########################
0 /************************************************************************/
1 /* setrpath */
2 /* */
3 /* By Davin Milun (milun@cs.buffalo.edu) */
4 /* Last modified: Sun Feb 26 12:21:06 EST 1995 */
5 /* */
6 /* Program to set the RPATH in an ELF executable. */
7 /* However, it cannot set the RPATH longer than the RPATH set at */
8 /* compile time. */
9 /* */
10 /* Send any bug reports/fixes/suggestions to milun@cs.buffalo.edu */
11 /************************************************************************/
12
13 /************************************************************************/
14 /* Copyright (C) 1995, Davin Milun */
15 /* Permission to use and modify this software for any purpose other */
16 /* than its incorporation into a commercial product is hereby granted */
17 /* without fee. */
18 /* */
19 /* Permission to copy and distribute this software only for */
20 /* non-commercial use is also granted without fee, provided, however, */
21 /* that the above copyright notice appear in all copies, that both that */
22 /* copyright notice and this permission notice appear in supporting */
23 /* documentation. The author makes no representations about the */
24 /* suitability of this software for any purpose. It is provided */
25 /* ``as is'' without express or implied warranty. */
26 /* */
27 /* Compile: gcc -o setrpath -lelf -O setrpath.c */
28 /************************************************************************/
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38
39 #include <libelf.h>
40 #include <link.h>
41
42 #define USAGE "USAGE:\t%s [-f] <ELF executable> <new RPATH>\n\
43 \t%s -r <ELF executable>\n"
44
45 #define ORNULL(s) (s?s:"(null)")
46
47 int
48 main(int argc, char *argv[])
49 {
50
51 int file;
52 Elf *elf;
53 Elf_Scn *scn, *strscn;
54 Elf32_Shdr *scn_shdr;
55 Elf32_Ehdr *scn_ehdr;
56 Elf_Data *data, *strdata;
57 Elf32_Dyn *dyn;
58 size_t strscnndx;
59 int oldlen, newlen=0, extra_space;
60 char *oldrpath, *newrpath=NULL;
61 unsigned char *strbuffer;
62 int strbuffersize;
63 int forceflag=0, readonly=0;
64 int hasrpath=0;
65
66 extern char *optarg;
67 extern int optind;
68 int c;
69
70 while ((c = getopt(argc, argv, "fr")) != EOF){
71 switch(c){
72 case 'f': forceflag=1;
73 break;
74 case 'r': readonly=1;
75 break;
76 case '?': fprintf(stderr, USAGE, argv[0], argv[0]);
77 break;
78 }
79 }
80
81 if (argc != (optind+2-readonly)) {
82 fprintf(stderr,"Wrong number of arguments\n");
83 fprintf(stderr, USAGE, argv[0], argv[0]);
84 exit(1);
85 }
86
87 if (!readonly){
88 newrpath = strdup(argv[optind+1]);
89 newlen = strlen(newrpath);
90 }
91
92 if (elf_version(EV_CURRENT) == EV_NONE) {
93 fprintf(stderr,"Old version of ELF.\n");
94 exit(2);
95 }
96
97 if ((file = open(argv[optind],(readonly?O_RDONLY:O_RDWR))) == -1) {
98 fprintf(stderr,"Cannot open %s for %s\n",(readonly?"reading":"writing"),
99 ORNULL(argv[optind]));
100 perror("open");
101 exit(3);
102 }
103
104 elf = elf_begin(file, (readonly?ELF_C_READ:ELF_C_RDWR), (Elf *)NULL);
105
106 if (elf_kind(elf) != ELF_K_ELF) {
107 fprintf(stderr,"%s is not an ELF file.\n",argv[optind]);
108 exit(4);
109 }
110
111 if ((scn_ehdr = elf32_getehdr(elf)) == 0) {
112 fprintf(stderr,"elf32_getehdr failed.\n");
113 exit(5);
114 }
115
116 scn = NULL;
117
118 /* Process sections */
119 while ((scn = elf_nextscn(elf, scn)) != NULL) {
120 scn_shdr = elf32_getshdr(scn);
121
122 /* Only look at SHT_DYNAMIC section */
123 if (scn_shdr->sh_type == SHT_DYNAMIC) {
124 data = NULL;
125
126 /* Process data blocks in the section */
127 while ((data = elf_getdata(scn, data)) != NULL) {
128 dyn = (Elf32_Dyn *) data->d_buf;
129
130 /* Process entries in dynamic linking table */
131 while (dyn->d_tag != DT_NULL) {
132 /* Look at DT_RPATH entry */
133 if (dyn->d_tag == DT_RPATH) {
134 hasrpath++;
135 scn_shdr = elf32_getshdr(scn);
136 strscnndx = scn_shdr->sh_link;
137 oldrpath = elf_strptr(elf, strscnndx, dyn->d_un.d_ptr);
138 printf("%s RPATH: %s\n",(readonly?"Current":"Old"),ORNULL(oldrpath));
139 oldlen = strlen(oldrpath);
140
141 if (readonly) { /* Quit now if readonly*/
142 elf_end(elf);
143 exit(0);
144 }
145
146 /* Load the section that contains the strings */
147 strscn = elf_getscn(elf,strscnndx);
148 strdata = NULL;
149 while ((strdata = elf_getdata(strscn, strdata)) != NULL) {
150 strbuffersize = strdata->d_size;
151 strbuffer = strdata->d_buf;
152
153 /* Get next data block if needed */
154 if ((dyn->d_un.d_ptr > (strdata->d_off + strdata->d_size)) ||
155 (dyn->d_un.d_ptr < strdata->d_off)) {
156 fprintf(stderr,"The string table is not in one data block\n");
157 fprintf(stderr,"This is not handled by this program\n");
158 exit(6);
159 }
160
161 /* See if there is "slack" after end of RPATH */
162 extra_space = strdata->d_size - (dyn->d_un.d_ptr + oldlen + 1);
163
164 /* Mark the data block as dirty */
165 elf_flagdata(strdata,ELF_C_SET,ELF_F_DIRTY);
166
167 if (newlen > (oldlen + extra_space)) {
168 fprintf(stderr,"New RPATH would be longer than current RPATH \
169 plus any extra space.\n");
170 fprintf(stderr,"Aborting...\n");
171 exit(7);
172 }
173
174 if ((newlen > oldlen) && !forceflag) {
175 fprintf(stderr,"New RPATH would be longer than current RPATH.\n");
176 fprintf(stderr,"(Use -f to use any extra space in string table)\n");
177 exit(8);
178 }
179
180 /* Since it will fit in the old place, we can do it */
181 memmove(&strbuffer[dyn->d_un.d_ptr], newrpath, newlen);
182 strbuffer[dyn->d_un.d_ptr+newlen] = 0;
183
184 } /* while elf_getdata on the string table */
185
186 } /* if (dyn->d_tag == DT_RPATH) */
187 dyn++;
188 } /* while (dyn->d_tag != DT_NULL) */
189 } /* while elf_getdata */
190 } /* if SHT_DYNAMIC */
191 } /* while elf_nextscn */
192
193 if (readonly) {
194 printf("ELF file \"%s\" contains no RPATH.\n",argv[optind]);
195 exit(0);
196 }
197
198 if (hasrpath) {
199 if (elf_update(elf, ELF_C_WRITE) == -1 ) {
200 fprintf(stderr,"elf_update failed.\n");
201 exit(9);
202 }
203
204 printf("New RPATH set to: %s\n", ORNULL(newrpath));
205 } else {
206 fprintf(stderr,"ELF file \"%s\" contains no RPATH - cannot set one.\n",argv[optind]);
207 exit(10);
208 }
209
210 elf_end(elf);
211
212 exit(0);
213 }
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
2930 #include <net/if_types.h>
3031 #endif
3132 #endif
33 #if SUN
34 #include <sys/socket.h>
35 #include <sys/sockio.h>
36 #include <arpa/inet.h>
37 #include <netinet/in.h>
38 #include <net/if.h>
39 #include <net/if_arp.h>
40 #include <net/if_dl.h>
41 #include <net/if_types.h>
42 #endif
3243 #if WIN
3344 #include <iphlpapi.h>
45 #if USE_SSL
46 #include <stdlib.h>
47 #include <string.h>
48 #include <ctype.h>
49 #endif
3450 #endif
3551 #if OSX
3652 #include <net/if_dl.h>
6177 va_list args;
6278 va_start(args, fmt);
6379 vfprintf(stderr, fmt, args);
80 va_end(args);
6481 fflush(stderr);
6582 }
6683
88105 #else
89106 #if LINUX || FREEBSD
90107 struct timespec ts;
108 #ifdef CLOCK_MONOTONIC
91109 if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
110 #else
111 if (!clock_gettime(CLOCK_REALTIME, &ts)) {
112 #endif
92113 return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
93114 }
94115 #endif
99120 }
100121
101122 // mac address
102 #if LINUX
123 #if LINUX && !defined(SUN)
103124 // search first 4 interfaces returned by IFCONF
104125 void get_mac(u8_t mac[]) {
126 char *utmac;
105127 struct ifconf ifc;
106128 struct ifreq *ifr, *ifend;
107129 struct ifreq ifreq;
108130 struct ifreq ifs[4];
109131
132 utmac = getenv("UTMAC");
133 if (utmac)
134 {
135 if ( strlen(utmac) == 17 )
136 {
137 if (sscanf(utmac,"%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx",
138 &mac[0],&mac[1],&mac[2],&mac[3],&mac[4],&mac[5]) == 6)
139 {
140 return;
141 }
142 }
143
144 }
145
110146 mac[0] = mac[1] = mac[2] = mac[3] = mac[4] = mac[5] = 0;
111147
112148 int s = socket(AF_INET, SOCK_DGRAM, 0);
120156 for (ifr = ifc.ifc_req; ifr < ifend; ifr++) {
121157 if (ifr->ifr_addr.sa_family == AF_INET) {
122158
123 strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
159 strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name) - 1);
124160 if (ioctl (s, SIOCGIFHWADDR, &ifreq) == 0) {
125161 memcpy(mac, ifreq.ifr_hwaddr.sa_data, 6);
126162 if (mac[0]+mac[1]+mac[2] != 0) {
132168 }
133169
134170 close(s);
171 }
172 #endif
173
174 #if SUN
175 void get_mac(u8_t mac[]) {
176 struct arpreq parpreq;
177 struct sockaddr_in *psa;
178 struct in_addr inaddr;
179 struct hostent *phost;
180 char hostname[MAXHOSTNAMELEN];
181 char **paddrs;
182 char *utmac;
183 int sock;
184 int status=0;
185
186 utmac = getenv("UTMAC");
187 if (utmac)
188 {
189 if ( strlen(utmac) == 17 )
190 {
191 if (sscanf(utmac,"%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx",
192 &mac[0],&mac[1],&mac[2],&mac[3],&mac[4],&mac[5]) == 6)
193 {
194 return;
195 }
196 }
197
198 }
199
200 mac[0] = mac[1] = mac[2] = mac[3] = mac[4] = mac[5] = 0;
201
202 gethostname(hostname, MAXHOSTNAMELEN);
203
204 phost = gethostbyname(hostname);
205
206 paddrs = phost->h_addr_list;
207 memcpy(&inaddr.s_addr, *paddrs, sizeof(inaddr.s_addr));
208
209 sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
210
211 if(sock == -1)
212 {
213 mac[5] = 1;
214 return;
215 }
216
217 memset(&parpreq, 0, sizeof(struct arpreq));
218 psa = (struct sockaddr_in *) &parpreq.arp_pa;
219 memset(psa, 0, sizeof(struct sockaddr_in));
220 psa->sin_family = AF_INET;
221 memcpy(&psa->sin_addr, *paddrs, sizeof(struct in_addr));
222
223 status = ioctl(sock, SIOCGARP, &parpreq);
224
225 if(status == -1)
226 {
227 mac[5] = 2;
228 return;
229 }
230
231 mac[0] = (unsigned char) parpreq.arp_ha.sa_data[0];
232 mac[1] = (unsigned char) parpreq.arp_ha.sa_data[1];
233 mac[2] = (unsigned char) parpreq.arp_ha.sa_data[2];
234 mac[3] = (unsigned char) parpreq.arp_ha.sa_data[3];
235 mac[4] = (unsigned char) parpreq.arp_ha.sa_data[4];
236 mac[5] = (unsigned char) parpreq.arp_ha.sa_data[5];
135237 }
136238 #endif
137239
385487 }
386488 }
387489 #endif
490
491 #if WIN && USE_SSL
492 char *strcasestr(const char *haystack, const char *needle) {
493 size_t length_needle;
494 size_t length_haystack;
495 size_t i;
496
497 if (!haystack || !needle)
498 return NULL;
499
500 length_needle = strlen(needle);
501 length_haystack = strlen(haystack) - length_needle + 1;
502
503 for (i = 0; i < length_haystack; i++)
504 {
505 size_t j;
506
507 for (j = 0; j < length_needle; j++)
508 {
509 unsigned char c1;
510 unsigned char c2;
511
512 c1 = haystack[i+j];
513 c2 = needle[j];
514 if (toupper(c1) != toupper(c2))
515 goto next;
516 }
517 return (char *) haystack + i;
518 next:
519 ;
520 }
521
522 return NULL;
523 }
524 #endif
11 * Squeezelite - lightweight headless squeezebox emulator
22 *
33 * (c) Adrian Smith 2012-2015, triode1@btinternet.com
4 * Ralph Irving 2015-2020, 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
1920
2021 #include "squeezelite.h"
2122
23 /*
24 * with some low-end CPU, the decode call takes a fair bit of time and if the outputbuf is locked during that
25 * period, the output_thread (or equivalent) will be locked although there is plenty of samples available.
26 * Normally, with PRIO_INHERIT, that thread should increase decoder priority and get the lock quickly but it
27 * seems that when the streambuf has plenty of data, the decode thread grabs the CPU to much, even it the output
28 * thread has a higher priority. Using an interim buffer where vorbis decoder writes the output is not great from
29 * an efficiency (one extra memory copy) point of view, but it allows the lock to not be kept for too long
30 */
31 #if EMBEDDED
32 #define FRAME_BUF 2048
33 #endif
34
35 #if BYTES_PER_FRAME == 4
36 #define ALIGN(n) (n)
37 #else
38 #define ALIGN(n) (n << 16)
39 #endif
40
2241 // automatically select between floating point (preferred) and fixed point libraries:
2342 // NOTE: works with Tremor version here: http://svn.xiph.org/trunk/Tremor, not vorbisidec.1.0.2 currently in ubuntu
2443
2645 // tremor's OggVorbis_File struct is normally smaller so this is ok, but padding added to malloc in case it is bigger
2746 #define OV_EXCLUDE_STATIC_CALLBACKS
2847
48 #ifdef TREMOR_ONLY
49 #include <ivorbisfile.h>
50 #else
2951 #include <vorbis/vorbisfile.h>
52 #endif
3053
3154 struct vorbis {
3255 OggVorbis_File *vf;
3356 bool opened;
57 #if FRAME_BUF
58 u8_t *write_buf;
59 #endif
3460 #if !LINKALL
3561 // vorbis symbols to be dynamically loaded - from either vorbisfile or vorbisidec (tremor) version of library
3662 vorbis_info *(* ov_info)(OggVorbis_File *vf, int link);
75101 #if LINKALL
76102 #define OV(h, fn, ...) (ov_ ## fn)(__VA_ARGS__)
77103 #define TREMOR(h) 0
104 #if !WIN
78105 extern int ov_read_tremor(); // needed to enable compilation, not linked
106 #endif
79107 #else
80108 #define OV(h, fn, ...) (h)->ov_##fn(__VA_ARGS__)
81109 #define TREMOR(h) (h)->ov_read_tremor
85113 static size_t _read_cb(void *ptr, size_t size, size_t nmemb, void *datasource) {
86114 size_t bytes;
87115
116 LOCK_S;
117
88118 bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf));
89119 bytes = min(bytes, size * nmemb);
90120
91121 memcpy(ptr, streambuf->readp, bytes);
92122 _buf_inc_readp(streambuf, bytes);
93123
124 UNLOCK_S;
125
94126 return bytes / size;
95127 }
96128
97129 // these are needed for older versions of tremor, later versions and libvorbis allow NULL to be used
98 static int _seek_cb(void *datasource, ogg_int64_t offset, int whence) { return -1; }
130 static int _seek_cb(void *datasource, ogg_int64_t offset, int whence) { return -1; }
99131 static int _close_cb(void *datasource) { return 0; }
100132 static long _tell_cb(void *datasource) { return 0; }
101133
102134 static decode_state vorbis_decode(void) {
103135 static int channels;
104 bool end;
105136 frames_t frames;
106137 int bytes, s, n;
107138 u8_t *write_buf;
108139
109140 LOCK_S;
110 LOCK_O_direct;
111 end = (stream.state <= DISCONNECT);
112
113 IF_DIRECT(
114 frames = min(_buf_space(outputbuf), _buf_cont_write(outputbuf)) / BYTES_PER_FRAME;
115 );
116 IF_PROCESS(
117 frames = process.max_in_frames;
118 );
119
120 if (!frames && end) {
121 UNLOCK_O_direct;
141
142 if (stream.state <= DISCONNECT && !_buf_used(streambuf)) {
122143 UNLOCK_S;
123144 return DECODE_COMPLETE;
124145 }
125
146
147 UNLOCK_S;
148
126149 if (decode.new_stream) {
127150 ov_callbacks cbs;
128151 int err;
129152 struct vorbis_info *info;
130153
131154 cbs.read_func = _read_cb;
132
155
133156 if (TREMOR(v)) {
134157 cbs.seek_func = _seek_cb; cbs.close_func = _close_cb; cbs.tell_func = _tell_cb;
135158 } else {
138161
139162 if ((err = OV(v, open_callbacks, streambuf, v->vf, NULL, 0, cbs)) < 0) {
140163 LOG_WARN("open_callbacks error: %d", err);
141 UNLOCK_O_direct;
142 UNLOCK_S;
143164 return DECODE_COMPLETE;
144165 }
166
145167 v->opened = true;
146
147168 info = OV(v, info, v->vf, -1);
148169
149170 LOG_INFO("setting track_start");
150 LOCK_O_not_direct;
151 output.next_sample_rate = decode_newstream(info->rate, output.supported_rates);
152 IF_DSD( output.next_dop = false; )
171 LOCK_O;
172 output.next_sample_rate = decode_newstream(info->rate, output.supported_rates);
173 IF_DSD( output.next_fmt = PCM; )
153174 output.track_start = outputbuf->writep;
154175 if (output.fade_mode) _checkfade(true);
155176 decode.new_stream = false;
156 UNLOCK_O_not_direct;
157
158 IF_PROCESS(
159 frames = process.max_in_frames;
160 );
177 UNLOCK_O;
161178
162179 channels = info->channels;
163180
164181 if (channels > 2) {
165182 LOG_WARN("too many channels: %d", channels);
166 UNLOCK_O_direct;
167 UNLOCK_S;
168183 return DECODE_ERROR;
169184 }
170185 }
171
172 bytes = frames * 2 * channels; // samples returned are 16 bits
173
186
187 #if FRAME_BUF
174188 IF_DIRECT(
189 frames = min(_buf_space(outputbuf), _buf_cont_write(outputbuf)) / BYTES_PER_FRAME;
190 frames = min(frames, FRAME_BUF);
191 write_buf = v->write_buf;
192 );
193 #else
194 LOCK_O_direct;
195 IF_DIRECT(
196 frames = min(_buf_space(outputbuf), _buf_cont_write(outputbuf)) / BYTES_PER_FRAME;
175197 write_buf = outputbuf->writep;
176198 );
199 #endif
177200 IF_PROCESS(
201 frames = process.max_in_frames;
178202 write_buf = process.inbuf;
179203 );
204
205 bytes = frames * 2 * channels; // samples returned are 16 bits
180206
181207 // write the decoded frames into outputbuf even though they are 16 bits per sample, then unpack them
208 #ifdef TREMOR_ONLY
209 n = OV(v, read, v->vf, (char *)write_buf, bytes, &s);
210 #else
182211 if (!TREMOR(v)) {
183212 #if SL_LITTLE_ENDIAN
184213 n = OV(v, read, v->vf, (char *)write_buf, bytes, 0, 2, 1, &s);
185214 #else
186215 n = OV(v, read, v->vf, (char *)write_buf, bytes, 1, 2, 1, &s);
187216 #endif
217 #if !WIN
188218 } else {
189219 n = OV(v, read_tremor, v->vf, (char *)write_buf, bytes, &s);
190 }
220 #endif
221 }
222 #endif
223
224 #if FRAME_BUF
225 LOCK_O_direct;
226 #endif
191227
192228 if (n > 0) {
193
194229 frames_t count;
195230 s16_t *iptr;
196 s32_t *optr;
231 ISAMPLE_T *optr;
197232
198233 frames = n / 2 / channels;
199234 count = frames * channels;
200235
201 // work backward to unpack samples to 4 bytes per sample
202 iptr = (s16_t *)write_buf + count;
203 optr = (s32_t *)write_buf + frames * 2;
236 // work backward to unpack samples (if needed)
237 iptr = (s16_t *) write_buf + count;
238 optr = (ISAMPLE_T *) write_buf + frames * 2;
204239
205240 if (channels == 2) {
241 #if BYTES_PER_FRAME == 4
242 #if FRAME_BUF
243 // copy needed only when DIRECT and FRAME_BUF
244 IF_DIRECT(
245 memcpy(outputbuf->writep, write_buf, frames * BYTES_PER_FRAME);
246 )
247 #endif
248 #else
206249 while (count--) {
207 *--optr = *--iptr << 16;
250 *--optr = ALIGN(*--iptr);
208251 }
252 #endif
209253 } else if (channels == 1) {
210254 while (count--) {
211 *--optr = *--iptr << 16;
212 *--optr = *iptr << 16;
255 *--optr = ALIGN(*--iptr);
256 *--optr = ALIGN(*iptr);
213257 }
214258 }
215
259
216260 IF_DIRECT(
217261 _buf_inc_writep(outputbuf, frames * BYTES_PER_FRAME);
218262 );
224268
225269 } else if (n == 0) {
226270
227 LOG_INFO("end of stream");
228 UNLOCK_O_direct;
229 UNLOCK_S;
230 return DECODE_COMPLETE;
271 if (stream.state <= DISCONNECT) {
272 LOG_INFO("partial decode");
273 UNLOCK_O_direct;
274 return DECODE_COMPLETE;
275 } else {
276 LOG_INFO("no frame decoded");
277 }
231278
232279 } else if (n == OV_HOLE) {
233280
234281 // recoverable hole in stream, seen when skipping
235282 LOG_DEBUG("hole in stream");
236
283
237284 } else {
238285
239286 LOG_INFO("ov_read error: %d", n);
240287 UNLOCK_O_direct;
241 UNLOCK_S;
242288 return DECODE_COMPLETE;
243289 }
244290
245291 UNLOCK_O_direct;
246 UNLOCK_S;
247
248292 return DECODE_RUNNING;
249293 }
250294
252296 if (!v->vf) {
253297 v->vf = malloc(sizeof(OggVorbis_File) + 128); // add some padding as struct size may be larger
254298 memset(v->vf, 0, sizeof(OggVorbis_File) + 128);
299 #if FRAME_BUF
300 v->write_buf = malloc(FRAME_BUF * BYTES_PER_FRAME);
301 #endif
255302 } else {
256303 if (v->opened) {
257304 OV(v, clear, v->vf);
266313 v->opened = false;
267314 }
268315 free(v->vf);
316 #if FRAME_BUF
317 free(v->write_buf);
318 v->write_buf = NULL;
319 #endif
269320 v->vf = NULL;
270321 }
271322
306357 static struct codec ret = {
307358 'o', // id
308359 "ogg", // types
309 2048, // min read
360 4096, // min read
310361 20480, // min space
311362 vorbis_open, // open
312363 vorbis_close, // close