New upstream version 1.8
tony mancill
2 years ago
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) |
0 | Squeezelite - lightweight headless squeezebox emulator | |
1 | ||
2 | (c) Adrian Smith 2012-2015, triode1@btinternet.com | |
3 | ||
4 | Released under GPLv3 license: | |
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 | ||
22 | If built with DSD support, this software also includes code subject to the following license: | |
23 | ||
24 | Copyright 2009, 2011 Sebastian Gesemann. All rights reserved. | |
25 | ||
26 | Redistribution and use in source and binary forms, with or without modification, are | |
27 | permitted provided that the following conditions are met: | |
28 | ||
29 | 1. Redistributions of source code must retain the above copyright notice, this list of | |
30 | conditions and the following disclaimer. | |
31 | ||
32 | 2. Redistributions in binary form must reproduce the above copyright notice, this list | |
33 | of conditions and the following disclaimer in the documentation and/or other materials | |
34 | provided with the distribution. | |
35 | ||
36 | THIS SOFTWARE IS PROVIDED BY SEBASTIAN GESEMANN ''AS IS'' AND ANY EXPRESS OR IMPLIED | |
37 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
38 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SEBASTIAN GESEMANN OR | |
39 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
40 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
41 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
42 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
43 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | |
44 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
45 | ||
46 | The views and conclusions contained in the software and documentation are those of the | |
47 | authors and should not be interpreted as representing official policies, either expressed | |
48 | or implied, of Sebastian Gesemann. |
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 | |
3 | EXECUTABLE ?= squeezelite | |
4 | ||
5 | # passing one or more of these in $(OPTS) enables optional feature inclusion | |
6 | OPT_DSD = -DDSD | |
7 | OPT_FF = -DFFMPEG | |
8 | OPT_LINKALL = -DLINKALL | |
9 | OPT_RESAMPLE= -DRESAMPLE | |
10 | OPT_VIS = -DVISEXPORT | |
11 | OPT_IR = -DIR | |
12 | ||
13 | SOURCES = \ | |
14 | 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 | |
17 | ||
18 | SOURCES_DSD = dsd.c dop.c dsd2pcm/dsd2pcm.c | |
19 | SOURCES_FF = ffmpeg.c | |
20 | SOURCES_RESAMPLE = process.c resample.c | |
21 | SOURCES_VIS = output_vis.c | |
22 | SOURCES_IR = ir.c | |
23 | ||
24 | LINK_LINUX = -ldl | |
25 | ||
26 | LINKALL = -lFLAC -lmad -lvorbisfile -lfaad -lmpg123 | |
27 | LINKALL_FF = -lavcodec -lavformat -lavutil | |
28 | LINKALL_RESAMPLE = -lsoxr | |
29 | LINKALL_IR = -llirc_client | |
30 | ||
31 | DEPS = squeezelite.h slimproto.h | |
32 | ||
33 | UNAME = $(shell uname -s) | |
34 | ||
35 | # add optional sources | |
36 | ifneq (,$(findstring $(OPT_DSD), $(CFLAGS))) | |
37 | SOURCES += $(SOURCES_DSD) | |
38 | endif | |
39 | ifneq (,$(findstring $(OPT_FF), $(CFLAGS))) | |
40 | SOURCES += $(SOURCES_FF) | |
41 | endif | |
42 | ifneq (,$(findstring $(OPT_RESAMPLE), $(CFLAGS))) | |
43 | SOURCES += $(SOURCES_RESAMPLE) | |
44 | endif | |
45 | ifneq (,$(findstring $(OPT_VIS), $(CFLAGS))) | |
46 | SOURCES += $(SOURCES_VIS) | |
47 | endif | |
48 | ifneq (,$(findstring $(OPT_IR), $(CFLAGS))) | |
49 | SOURCES += $(SOURCES_IR) | |
50 | endif | |
51 | ||
52 | # add optional link options | |
53 | ifneq (,$(findstring $(OPT_LINKALL), $(CFLAGS))) | |
54 | LDFLAGS += $(LINKALL) | |
55 | ifneq (,$(findstring $(OPT_FF), $(CFLAGS))) | |
56 | LDFLAGS += $(LINKALL_FF) | |
57 | endif | |
58 | ifneq (,$(findstring $(OPT_RESAMPLE), $(CFLAGS))) | |
59 | LDFLAGS += $(LINKALL_RESAMPLE) | |
60 | endif | |
61 | ifneq (,$(findstring $(OPT_IR), $(CFLAGS))) | |
62 | LDFLAGS += $(LINKALL_IR) | |
63 | endif | |
64 | else | |
65 | # if not LINKALL and linux add LINK_LINUX | |
66 | ifeq ($(UNAME), Linux) | |
67 | LDFLAGS += $(LINK_LINUX) | |
68 | endif | |
69 | endif | |
70 | ||
71 | OBJECTS = $(SOURCES:.c=.o) | |
72 | ||
73 | all: $(EXECUTABLE) | |
74 | ||
75 | $(EXECUTABLE): $(OBJECTS) | |
76 | $(CC) $(OBJECTS) $(LDFLAGS) -o $@ | |
77 | ||
78 | $(OBJECTS): $(DEPS) | |
79 | ||
80 | .c.o: | |
81 | $(CC) $(CFLAGS) $(CPPFLAGS) $< -c -o $@ | |
82 | ||
83 | clean: | |
84 | rm -f $(OBJECTS) $(EXECUTABLE) |
0 | 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 | ||
3 | include Makefile |
0 | # OSX build - adjust -I to point to header files for codecs and portaudio | |
1 | CFLAGS = -arch x86_64 -arch i386 -Wall -fPIC -O2 -I./include $(OPTS) | |
2 | LDFLAGS = -arch x86_64 -arch i386 -lpthread libportaudio.a -framework CoreAudio -framework AudioToolbox -framework AudioUnit -framework Carbon | |
3 | ||
4 | EXECUTABLE ?= squeezelite-osx | |
5 | ||
6 | include Makefile |
0 | # Make with portaudio rather than direct alsa | |
1 | OPTS += -DPORTAUDIO | |
2 | LDFLAGS = -lportaudio -lpthread -ldl -lrt | |
3 | EXECUTABLE = squeezelite-pa | |
4 | ||
5 | include Makefile |
0 | /* | |
1 | * Squeezelite - lightweight headless squeezebox emulator | |
2 | * | |
3 | * (c) Adrian Smith 2012-2015, triode1@btinternet.com | |
4 | * | |
5 | * This program is free software: you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation, either version 3 of the License, or | |
8 | * (at your option) any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
17 | * | |
18 | */ | |
19 | ||
20 | // fifo bufffers | |
21 | ||
22 | #define _GNU_SOURCE | |
23 | ||
24 | #include "squeezelite.h" | |
25 | ||
26 | // _* called with muxtex locked | |
27 | ||
28 | inline unsigned _buf_used(struct buffer *buf) { | |
29 | return buf->writep >= buf->readp ? buf->writep - buf->readp : buf->size - (buf->readp - buf->writep); | |
30 | } | |
31 | ||
32 | unsigned _buf_space(struct buffer *buf) { | |
33 | return buf->size - _buf_used(buf) - 1; // reduce by one as full same as empty otherwise | |
34 | } | |
35 | ||
36 | unsigned _buf_cont_read(struct buffer *buf) { | |
37 | return buf->writep >= buf->readp ? buf->writep - buf->readp : buf->wrap - buf->readp; | |
38 | } | |
39 | ||
40 | unsigned _buf_cont_write(struct buffer *buf) { | |
41 | return buf->writep >= buf->readp ? buf->wrap - buf->writep : buf->readp - buf->writep; | |
42 | } | |
43 | ||
44 | void _buf_inc_readp(struct buffer *buf, unsigned by) { | |
45 | buf->readp += by; | |
46 | if (buf->readp >= buf->wrap) { | |
47 | buf->readp -= buf->size; | |
48 | } | |
49 | } | |
50 | ||
51 | void _buf_inc_writep(struct buffer *buf, unsigned by) { | |
52 | buf->writep += by; | |
53 | if (buf->writep >= buf->wrap) { | |
54 | buf->writep -= buf->size; | |
55 | } | |
56 | } | |
57 | ||
58 | void buf_flush(struct buffer *buf) { | |
59 | mutex_lock(buf->mutex); | |
60 | buf->readp = buf->buf; | |
61 | buf->writep = buf->buf; | |
62 | mutex_unlock(buf->mutex); | |
63 | } | |
64 | ||
65 | // adjust buffer to multiple of mod bytes so reading in multiple always wraps on frame boundary | |
66 | void buf_adjust(struct buffer *buf, size_t mod) { | |
67 | size_t size; | |
68 | mutex_lock(buf->mutex); | |
69 | size = ((unsigned)(buf->base_size / mod)) * mod; | |
70 | buf->readp = buf->buf; | |
71 | buf->writep = buf->buf; | |
72 | buf->wrap = buf->buf + size; | |
73 | buf->size = size; | |
74 | mutex_unlock(buf->mutex); | |
75 | } | |
76 | ||
77 | // called with mutex locked to resize, does not retain contents, reverts to original size if fails | |
78 | void _buf_resize(struct buffer *buf, size_t size) { | |
79 | free(buf->buf); | |
80 | buf->buf = malloc(size); | |
81 | if (!buf->buf) { | |
82 | size = buf->size; | |
83 | buf->buf= malloc(size); | |
84 | if (!buf->buf) { | |
85 | size = 0; | |
86 | } | |
87 | } | |
88 | buf->readp = buf->buf; | |
89 | buf->writep = buf->buf; | |
90 | buf->wrap = buf->buf + size; | |
91 | buf->size = size; | |
92 | buf->base_size = size; | |
93 | } | |
94 | ||
95 | void buf_init(struct buffer *buf, size_t size) { | |
96 | buf->buf = malloc(size); | |
97 | buf->readp = buf->buf; | |
98 | buf->writep = buf->buf; | |
99 | buf->wrap = buf->buf + size; | |
100 | buf->size = size; | |
101 | buf->base_size = size; | |
102 | mutex_create_p(buf->mutex); | |
103 | } | |
104 | ||
105 | void buf_destroy(struct buffer *buf) { | |
106 | if (buf->buf) { | |
107 | free(buf->buf); | |
108 | buf->buf = NULL; | |
109 | buf->size = 0; | |
110 | buf->base_size = 0; | |
111 | mutex_destroy(buf->mutex); | |
112 | } | |
113 | } |
0 | /* | |
1 | * Squeezelite - lightweight headless squeezebox emulator | |
2 | * | |
3 | * (c) Adrian Smith 2012-2015, triode1@btinternet.com | |
4 | * | |
5 | * This program is free software: you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation, either version 3 of the License, or | |
8 | * (at your option) any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
17 | * | |
18 | */ | |
19 | ||
20 | // decode thread | |
21 | ||
22 | #include "squeezelite.h" | |
23 | ||
24 | log_level loglevel; | |
25 | ||
26 | extern struct buffer *streambuf; | |
27 | extern struct buffer *outputbuf; | |
28 | extern struct streamstate stream; | |
29 | extern struct outputstate output; | |
30 | extern struct processstate process; | |
31 | ||
32 | struct decodestate decode; | |
33 | struct codec *codecs[MAX_CODECS]; | |
34 | struct codec *codec; | |
35 | static bool running = true; | |
36 | ||
37 | #define LOCK_S mutex_lock(streambuf->mutex) | |
38 | #define UNLOCK_S mutex_unlock(streambuf->mutex) | |
39 | #define LOCK_O mutex_lock(outputbuf->mutex) | |
40 | #define UNLOCK_O mutex_unlock(outputbuf->mutex) | |
41 | #define LOCK_D mutex_lock(decode.mutex); | |
42 | #define UNLOCK_D mutex_unlock(decode.mutex); | |
43 | ||
44 | #if PROCESS | |
45 | #define IF_DIRECT(x) if (decode.direct) { x } | |
46 | #define IF_PROCESS(x) if (!decode.direct) { x } | |
47 | #define MAY_PROCESS(x) { x } | |
48 | #else | |
49 | #define IF_DIRECT(x) { x } | |
50 | #define IF_PROCESS(x) | |
51 | #define MAY_PROCESS(x) | |
52 | #endif | |
53 | ||
54 | static void *decode_thread() { | |
55 | ||
56 | while (running) { | |
57 | size_t bytes, space, min_space; | |
58 | bool toend; | |
59 | bool ran = false; | |
60 | ||
61 | LOCK_S; | |
62 | bytes = _buf_used(streambuf); | |
63 | toend = (stream.state <= DISCONNECT); | |
64 | UNLOCK_S; | |
65 | LOCK_O; | |
66 | space = _buf_space(outputbuf); | |
67 | UNLOCK_O; | |
68 | ||
69 | LOCK_D; | |
70 | ||
71 | if (decode.state == DECODE_RUNNING && codec) { | |
72 | ||
73 | LOG_SDEBUG("streambuf bytes: %u outputbuf space: %u", bytes, space); | |
74 | ||
75 | IF_DIRECT( | |
76 | min_space = codec->min_space; | |
77 | ); | |
78 | IF_PROCESS( | |
79 | min_space = process.max_out_frames * BYTES_PER_FRAME; | |
80 | ); | |
81 | ||
82 | if (space > min_space && (bytes > codec->min_read_bytes || toend)) { | |
83 | ||
84 | decode.state = codec->decode(); | |
85 | ||
86 | IF_PROCESS( | |
87 | if (process.in_frames) { | |
88 | process_samples(); | |
89 | } | |
90 | ||
91 | if (decode.state == DECODE_COMPLETE) { | |
92 | process_drain(); | |
93 | } | |
94 | ); | |
95 | ||
96 | if (decode.state != DECODE_RUNNING) { | |
97 | ||
98 | LOG_INFO("decode %s", decode.state == DECODE_COMPLETE ? "complete" : "error"); | |
99 | ||
100 | LOCK_O; | |
101 | if (output.fade_mode) _checkfade(false); | |
102 | UNLOCK_O; | |
103 | ||
104 | wake_controller(); | |
105 | } | |
106 | ||
107 | ran = true; | |
108 | } | |
109 | } | |
110 | ||
111 | UNLOCK_D; | |
112 | ||
113 | if (!ran) { | |
114 | usleep(100000); | |
115 | } | |
116 | } | |
117 | ||
118 | return 0; | |
119 | } | |
120 | ||
121 | static thread_type thread; | |
122 | ||
123 | void decode_init(log_level level, const char *include_codecs, const char *exclude_codecs) { | |
124 | int i; | |
125 | ||
126 | loglevel = level; | |
127 | ||
128 | LOG_INFO("init decode, include codecs: %s exclude codecs: %s", include_codecs ? include_codecs : "", exclude_codecs); | |
129 | ||
130 | // register codecs | |
131 | // dsf,dff,alc,wma,wmap,wmal,aac,spt,ogg,ogf,flc,aif,pcm,mp3 | |
132 | i = 0; | |
133 | #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(); | |
144 | ||
145 | // try mad then mpg for mp3 unless command line option passed | |
146 | 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(); | |
150 | ||
151 | mutex_create(decode.mutex); | |
152 | ||
153 | #if LINUX || OSX || FREEBSD | |
154 | pthread_attr_t attr; | |
155 | pthread_attr_init(&attr); | |
156 | pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN + DECODE_THREAD_STACK_SIZE); | |
157 | pthread_create(&thread, &attr, decode_thread, NULL); | |
158 | pthread_attr_destroy(&attr); | |
159 | #endif | |
160 | #if WIN | |
161 | thread = CreateThread(NULL, DECODE_THREAD_STACK_SIZE, (LPTHREAD_START_ROUTINE)&decode_thread, NULL, 0, NULL); | |
162 | #endif | |
163 | ||
164 | decode.new_stream = true; | |
165 | decode.state = DECODE_STOPPED; | |
166 | ||
167 | MAY_PROCESS( | |
168 | decode.direct = true; | |
169 | decode.process = false; | |
170 | ); | |
171 | } | |
172 | ||
173 | void decode_close(void) { | |
174 | LOG_INFO("close decode"); | |
175 | LOCK_D; | |
176 | if (codec) { | |
177 | codec->close(); | |
178 | codec = NULL; | |
179 | } | |
180 | running = false; | |
181 | UNLOCK_D; | |
182 | #if LINUX || OSX || FREEBSD | |
183 | pthread_join(thread, NULL); | |
184 | #endif | |
185 | mutex_destroy(decode.mutex); | |
186 | } | |
187 | ||
188 | void decode_flush(void) { | |
189 | LOG_INFO("decode flush"); | |
190 | LOCK_D; | |
191 | decode.state = DECODE_STOPPED; | |
192 | IF_PROCESS( | |
193 | process_flush(); | |
194 | ); | |
195 | UNLOCK_D; | |
196 | } | |
197 | ||
198 | unsigned decode_newstream(unsigned sample_rate, unsigned supported_rates[]) { | |
199 | ||
200 | // called with O locked to get sample rate for potentially processed output stream | |
201 | // release O mutex during process_newstream as it can take some time | |
202 | ||
203 | MAY_PROCESS( | |
204 | if (decode.process) { | |
205 | UNLOCK_O; | |
206 | sample_rate = process_newstream(&decode.direct, sample_rate, supported_rates); | |
207 | LOCK_O; | |
208 | } | |
209 | ); | |
210 | ||
211 | return sample_rate; | |
212 | } | |
213 | ||
214 | void codec_open(u8_t format, u8_t sample_size, u8_t sample_rate, u8_t channels, u8_t endianness) { | |
215 | int i; | |
216 | ||
217 | LOG_INFO("codec open: '%c'", format); | |
218 | ||
219 | LOCK_D; | |
220 | ||
221 | decode.new_stream = true; | |
222 | decode.state = DECODE_STOPPED; | |
223 | ||
224 | MAY_PROCESS( | |
225 | decode.direct = true; // potentially changed within codec when processing enabled | |
226 | ); | |
227 | ||
228 | // find the required codec | |
229 | for (i = 0; i < MAX_CODECS; ++i) { | |
230 | ||
231 | if (codecs[i] && codecs[i]->id == format) { | |
232 | ||
233 | if (codec && codec != codecs[i]) { | |
234 | LOG_INFO("closing codec: '%c'", codec->id); | |
235 | codec->close(); | |
236 | } | |
237 | ||
238 | codec = codecs[i]; | |
239 | ||
240 | codec->open(sample_size, sample_rate, channels, endianness); | |
241 | ||
242 | decode.state = DECODE_READY; | |
243 | ||
244 | UNLOCK_D; | |
245 | return; | |
246 | } | |
247 | } | |
248 | ||
249 | UNLOCK_D; | |
250 | ||
251 | LOG_ERROR("codec not found"); | |
252 | } | |
253 |
0 | /* | |
1 | * Squeezelite - lightweight headless squeezebox emulator | |
2 | * | |
3 | * (c) Adrian Smith 2012, 2013, triode1@btinternet.com | |
4 | * | |
5 | * This program is free software: you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation, either version 3 of the License, or | |
8 | * (at your option) any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
17 | * | |
18 | */ | |
19 | ||
20 | // DSP over PCM (DOP) specific functions | |
21 | ||
22 | #include "squeezelite.h" | |
23 | ||
24 | #if DSD | |
25 | ||
26 | extern struct buffer *outputbuf; | |
27 | extern struct outputstate output; | |
28 | ||
29 | #define LOCK_O mutex_lock(outputbuf->mutex) | |
30 | #define UNLOCK_O mutex_unlock(outputbuf->mutex) | |
31 | ||
32 | // check for 32 dop marker frames to see if this is dop in flac | |
33 | // dop is always encoded in 24 bit samples with marker 0x0005xxxx or 0x00FAxxxx | |
34 | bool is_flac_dop(u32_t *lptr, u32_t *rptr, frames_t frames) { | |
35 | int matched = 0; | |
36 | u32_t next = 0; | |
37 | ||
38 | while (frames--) { | |
39 | if (((*lptr & 0x00FF0000) == 0x00050000 && (*rptr & 0x00FF0000) == 0x00050000) || | |
40 | ((*lptr & 0x00FF0000) == 0x00FA0000 && (*rptr & 0x00FF0000) == 0x00FA0000)) { | |
41 | if (*lptr >> 24 == next) { | |
42 | matched++; | |
43 | next = ( 0x05 + 0xFA ) - next; | |
44 | } else { | |
45 | next = *lptr >> 24; | |
46 | matched = 1; | |
47 | } | |
48 | } else { | |
49 | return false; | |
50 | } | |
51 | if (matched == 32) { | |
52 | return true; | |
53 | } | |
54 | ||
55 | ++lptr; ++rptr; | |
56 | } | |
57 | return false; | |
58 | } | |
59 | ||
60 | // update the dop marker and potentially invert polarity for frames in the output buffer | |
61 | // performaned on all output including silence to maintain marker phase consitency | |
62 | void update_dop(u32_t *ptr, frames_t frames, bool invert) { | |
63 | static u32_t marker = 0x05; | |
64 | if (!invert) { | |
65 | while (frames--) { | |
66 | u32_t scaled_marker = marker << 24; | |
67 | *ptr = (*ptr & 0x00FFFFFF) | scaled_marker; | |
68 | ++ptr; | |
69 | *ptr = (*ptr & 0x00FFFFFF) | scaled_marker; | |
70 | ++ptr; | |
71 | marker = ( 0x05 + 0xFA ) - marker; | |
72 | } | |
73 | } else { | |
74 | while (frames--) { | |
75 | u32_t scaled_marker = marker << 24; | |
76 | *ptr = ((~(*ptr)) & 0x00FFFFFF) | scaled_marker; | |
77 | ++ptr; | |
78 | *ptr = ((~(*ptr)) & 0x00FFFFFF) | scaled_marker; | |
79 | ++ptr; | |
80 | marker = ( 0x05 + 0xFA ) - marker; | |
81 | } | |
82 | } | |
83 | } | |
84 | ||
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 | ||
101 | #endif // DSD |
0 | /* | |
1 | * Squeezelite - lightweight headless squeezebox emulator | |
2 | * | |
3 | * (c) Adrian Smith 2012-2015, triode1@btinternet.com | |
4 | * | |
5 | * This program is free software: you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation, either version 3 of the License, or | |
8 | * (at your option) any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
17 | * | |
18 | */ | |
19 | ||
20 | // dsd support | |
21 | ||
22 | #include "squeezelite.h" | |
23 | ||
24 | #if DSD | |
25 | ||
26 | // use dsd2pcm from Sebastian Gesemann for conversion to pcm: | |
27 | #include "./dsd2pcm/dsd2pcm.h" | |
28 | ||
29 | extern log_level loglevel; | |
30 | ||
31 | extern struct buffer *streambuf; | |
32 | extern struct buffer *outputbuf; | |
33 | extern struct streamstate stream; | |
34 | extern struct outputstate output; | |
35 | extern struct decodestate decode; | |
36 | extern struct processstate process; | |
37 | ||
38 | #define LOCK_S mutex_lock(streambuf->mutex) | |
39 | #define UNLOCK_S mutex_unlock(streambuf->mutex) | |
40 | #define LOCK_O mutex_lock(outputbuf->mutex) | |
41 | #define UNLOCK_O mutex_unlock(outputbuf->mutex) | |
42 | #if PROCESS | |
43 | #define LOCK_O_direct if (decode.direct) mutex_lock(outputbuf->mutex) | |
44 | #define UNLOCK_O_direct if (decode.direct) mutex_unlock(outputbuf->mutex) | |
45 | #define LOCK_O_not_direct if (!decode.direct) mutex_lock(outputbuf->mutex) | |
46 | #define UNLOCK_O_not_direct if (!decode.direct) mutex_unlock(outputbuf->mutex) | |
47 | #define IF_DIRECT(x) if (decode.direct) { x } | |
48 | #define IF_PROCESS(x) if (!decode.direct) { x } | |
49 | #else | |
50 | #define LOCK_O_direct mutex_lock(outputbuf->mutex) | |
51 | #define UNLOCK_O_direct mutex_unlock(outputbuf->mutex) | |
52 | #define LOCK_O_not_direct | |
53 | #define UNLOCK_O_not_direct | |
54 | #define IF_DIRECT(x) { x } | |
55 | #define IF_PROCESS(x) | |
56 | #endif | |
57 | ||
58 | #define BLOCK 4096 // expected size of dsd block | |
59 | #define BLOCK_FRAMES BLOCK * BYTES_PER_FRAME | |
60 | #define WRAP_BUF_SIZE 16 | |
61 | ||
62 | typedef enum { UNKNOWN=0, DSF, DSDIFF } dsd_type; | |
63 | ||
64 | static bool dop = false; // local copy of output.has_dop to avoid holding output lock | |
65 | ||
66 | struct dsd { | |
67 | dsd_type type; | |
68 | u32_t consume; | |
69 | u32_t sample_rate; | |
70 | u32_t channels; | |
71 | u64_t sample_bytes; | |
72 | u32_t block_size; | |
73 | bool lsb_first; | |
74 | dsd2pcm_ctx *dsd2pcm_ctx[2]; | |
75 | float *transfer[2]; | |
76 | }; | |
77 | ||
78 | static struct dsd *d; | |
79 | ||
80 | static u64_t unpack64be(const u8_t *p) { | |
81 | return | |
82 | (u64_t)p[0] << 56 | (u64_t)p[1] << 48 | (u64_t)p[2] << 40 | (u64_t)p[3] << 32 | | |
83 | (u64_t)p[4] << 24 | (u64_t)p[5] << 16 | (u64_t)p[6] << 8 | (u64_t)p[7]; | |
84 | } | |
85 | ||
86 | static u64_t unpack64le(const u8_t *p) { | |
87 | return | |
88 | (u64_t)p[7] << 56 | (u64_t)p[6] << 48 | (u64_t)p[5] << 40 | (u64_t)p[4] << 32 | | |
89 | (u64_t)p[3] << 24 | (u64_t)p[2] << 16 | (u64_t)p[1] << 8 | (u64_t)p[0]; | |
90 | } | |
91 | ||
92 | static u32_t unpack32le(const u8_t *p) { | |
93 | return | |
94 | (u32_t)p[3] << 24 | (u32_t)p[2] << 16 | (u32_t)p[1] << 8 | (u32_t)p[0]; | |
95 | } | |
96 | ||
97 | static int _read_header(void) { | |
98 | unsigned bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf)); | |
99 | s32_t consume; | |
100 | ||
101 | if (!d->type && bytes >= 4) { | |
102 | if (!memcmp(streambuf->readp, "FRM8", 4)) { | |
103 | d->type = DSDIFF; | |
104 | } else if (!memcmp(streambuf->readp, "DSD ", 4)) { | |
105 | d->type = DSF; | |
106 | } else { | |
107 | LOG_WARN("bad type"); | |
108 | return -1; | |
109 | } | |
110 | } | |
111 | ||
112 | while (bytes >= 16) { | |
113 | char id[5]; | |
114 | u64_t len = d->type == DSDIFF ? unpack64be(streambuf->readp + 4) : unpack64le(streambuf->readp + 4); | |
115 | memcpy(id, streambuf->readp, 4); | |
116 | id[4] = '\0'; | |
117 | consume = 0; | |
118 | ||
119 | if (d->type == DSDIFF) { | |
120 | if (!strcmp(id, "FRM8")) { | |
121 | if (!memcmp(streambuf->readp + 12, "DSD ", 4)) { | |
122 | consume = 16; // read into | |
123 | } else { | |
124 | LOG_WARN("bad dsdiff FRM8"); | |
125 | return -1; | |
126 | } | |
127 | } | |
128 | if (!strcmp(id, "PROP") && !memcmp(streambuf->readp + 12, "SND ", 4)) { | |
129 | consume = 16; // read into | |
130 | } | |
131 | if (!strcmp(id, "FVER")) { | |
132 | LOG_INFO("DSDIFF version: %u.%u.%u.%u", *(streambuf->readp + 12), *(streambuf->readp + 13), | |
133 | *(streambuf->readp + 14), *(streambuf->readp + 15)); | |
134 | } | |
135 | if (!strcmp(id, "FS ")) { | |
136 | d->sample_rate = unpackN((void *)(streambuf->readp + 12)); | |
137 | LOG_INFO("sample rate: %u", d->sample_rate); | |
138 | } | |
139 | if (!strcmp(id, "CHNL")) { | |
140 | d->channels = unpackn((void *)(streambuf->readp + 12)); | |
141 | LOG_INFO("channels: %u", d->channels); | |
142 | } | |
143 | if (!strcmp(id, "DSD ")) { | |
144 | LOG_INFO("found dsd len: " FMT_u64, len); | |
145 | d->sample_bytes = len; | |
146 | _buf_inc_readp(streambuf, 12); | |
147 | bytes -= 12; | |
148 | return 1; // got to the audio | |
149 | } | |
150 | } | |
151 | ||
152 | if (d->type == DSF) { | |
153 | if (!strcmp(id, "fmt ")) { | |
154 | if (bytes >= len && bytes >= 52) { | |
155 | u32_t version = unpack32le((void *)(streambuf->readp + 12)); | |
156 | u32_t format = unpack32le((void *)(streambuf->readp + 16)); | |
157 | LOG_INFO("DSF version: %u format: %u", version, format); | |
158 | if (format != 0) { | |
159 | LOG_WARN("only support DSD raw format"); | |
160 | return -1; | |
161 | } | |
162 | d->channels = unpack32le((void *)(streambuf->readp + 24)); | |
163 | d->sample_rate = unpack32le((void *)(streambuf->readp + 28)); | |
164 | d->lsb_first = (unpack32le((void *)(streambuf->readp + 32)) == 1); | |
165 | d->sample_bytes = unpack64le((void *)(streambuf->readp + 36)) / 8; | |
166 | d->block_size = unpack32le((void *)(streambuf->readp + 44)); | |
167 | LOG_INFO("channels: %u", d->channels); | |
168 | LOG_INFO("sample rate: %u", d->sample_rate); | |
169 | LOG_INFO("lsb first: %u", d->lsb_first); | |
170 | LOG_INFO("sample bytes: " FMT_u64, d->sample_bytes); | |
171 | LOG_INFO("block size: %u", d->block_size); | |
172 | } else { | |
173 | consume = -1; // come back later | |
174 | } | |
175 | } | |
176 | if (!strcmp(id, "data")) { | |
177 | LOG_INFO("found dsd len: " FMT_u64, len); | |
178 | _buf_inc_readp(streambuf, 12); | |
179 | bytes -= 12; | |
180 | return 1; // got to the audio | |
181 | } | |
182 | } | |
183 | ||
184 | // default to consuming whole chunk | |
185 | if (!consume) { | |
186 | consume = (s32_t)((d->type == DSDIFF) ? len + 12 : len); | |
187 | } | |
188 | ||
189 | if (bytes >= consume) { | |
190 | LOG_DEBUG("id: %s len: " FMT_u64 " consume: %d", id, len, consume); | |
191 | _buf_inc_readp(streambuf, consume); | |
192 | bytes -= consume; | |
193 | } else if (consume > 0) { | |
194 | LOG_DEBUG("id: %s len: " FMT_u64 " consume: %d - partial consume: %u", id, len, consume, bytes); | |
195 | _buf_inc_readp(streambuf, bytes); | |
196 | d->consume = consume - bytes; | |
197 | break; | |
198 | } else { | |
199 | break; | |
200 | } | |
201 | } | |
202 | ||
203 | return 0; | |
204 | } | |
205 | ||
206 | static decode_state _decode_dsf(void) { | |
207 | ||
208 | // samples in streambuf are interleaved on block basis | |
209 | // we transfer whole blocks for all channels in one call and so itterate the while loop below to handle wraps | |
210 | ||
211 | unsigned bytes = _buf_used(streambuf); | |
212 | unsigned block_left = d->block_size; | |
213 | ||
214 | unsigned bytes_per_frame = dop ? 2 : 1; | |
215 | ||
216 | if (bytes < d->block_size * d->channels) { | |
217 | LOG_INFO("stream too short"); // this can occur when scanning the track | |
218 | return DECODE_COMPLETE; | |
219 | } | |
220 | ||
221 | IF_PROCESS( | |
222 | process.in_frames = 0; | |
223 | ); | |
224 | ||
225 | while (block_left) { | |
226 | ||
227 | frames_t frames, out, count; | |
228 | unsigned bytes_read; | |
229 | ||
230 | u8_t *iptrl = (u8_t *)streambuf->readp; | |
231 | u8_t *iptrr = (u8_t *)streambuf->readp + d->block_size; | |
232 | u32_t *optr; | |
233 | ||
234 | if (iptrr >= streambuf->wrap) { | |
235 | iptrr -= streambuf->size; | |
236 | } | |
237 | ||
238 | bytes = min(block_left, min(streambuf->wrap - iptrl, streambuf->wrap - iptrr)); | |
239 | ||
240 | IF_DIRECT( | |
241 | out = min(_buf_space(outputbuf), _buf_cont_write(outputbuf)) / BYTES_PER_FRAME; | |
242 | optr = (u32_t *)outputbuf->writep; | |
243 | ); | |
244 | IF_PROCESS( | |
245 | out = process.max_in_frames - process.in_frames; | |
246 | optr = (u32_t *)(process.inbuf + process.in_frames * BYTES_PER_FRAME); | |
247 | ); | |
248 | ||
249 | frames = min(bytes, d->sample_bytes) / bytes_per_frame; | |
250 | if (frames == 0) { | |
251 | 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; | |
254 | frames = 1; | |
255 | } else { | |
256 | // should not get here due to wrapping m/2 for dop should never result in 0 as header len is always even | |
257 | LOG_INFO("frames got to zero"); | |
258 | return DECODE_COMPLETE; | |
259 | } | |
260 | } | |
261 | ||
262 | frames = min(frames, out); | |
263 | frames = min(frames, BLOCK); | |
264 | bytes_read = frames * bytes_per_frame; | |
265 | ||
266 | count = frames; | |
267 | ||
268 | if (dop) { | |
269 | ||
270 | if (d->channels == 1) { | |
271 | if (d->lsb_first) { | |
272 | while (count--) { | |
273 | *(optr++) = dsd2pcm_bitreverse[*(iptrl)] << 16 | dsd2pcm_bitreverse[*(iptrl+1)] << 8; | |
274 | *(optr++) = dsd2pcm_bitreverse[*(iptrl)] << 16 | dsd2pcm_bitreverse[*(iptrl+1)] << 8; | |
275 | iptrl += 2; | |
276 | } | |
277 | } else { | |
278 | while (count--) { | |
279 | *(optr++) = *(iptrl) << 16 | *(iptrl+1) << 8; | |
280 | *(optr++) = *(iptrl) << 16 | *(iptrl+1) << 8; | |
281 | iptrl += 2; | |
282 | } | |
283 | } | |
284 | } else { | |
285 | if (d->lsb_first) { | |
286 | while (count--) { | |
287 | *(optr++) = dsd2pcm_bitreverse[*(iptrl)] << 16 | dsd2pcm_bitreverse[*(iptrl+1)] << 8; | |
288 | *(optr++) = dsd2pcm_bitreverse[*(iptrr)] << 16 | dsd2pcm_bitreverse[*(iptrr+1)] << 8; | |
289 | iptrl += 2; | |
290 | iptrr += 2; | |
291 | } | |
292 | } else { | |
293 | while (count--) { | |
294 | *(optr++) = *(iptrl) << 16 | *(iptrl+1) << 8; | |
295 | *(optr++) = *(iptrr) << 16 | *(iptrr+1) << 8; | |
296 | iptrl += 2; | |
297 | iptrr += 2; | |
298 | } | |
299 | } | |
300 | } | |
301 | ||
302 | } else { | |
303 | ||
304 | if (d->channels == 1) { | |
305 | float *iptrf = d->transfer[0]; | |
306 | dsd2pcm_translate(d->dsd2pcm_ctx[0], frames, iptrl, 1, d->lsb_first, iptrf, 1); | |
307 | while (count--) { | |
308 | double scaled = *iptrf++ * 0x7fffffff; | |
309 | if (scaled > 2147483647.0) scaled = 2147483647.0; | |
310 | if (scaled < -2147483648.0) scaled = -2147483648.0; | |
311 | *optr++ = (s32_t)scaled; | |
312 | *optr++ = (s32_t)scaled; | |
313 | } | |
314 | } else { | |
315 | float *iptrfl = d->transfer[0]; | |
316 | float *iptrfr = d->transfer[1]; | |
317 | dsd2pcm_translate(d->dsd2pcm_ctx[0], frames, iptrl, 1, d->lsb_first, iptrfl, 1); | |
318 | dsd2pcm_translate(d->dsd2pcm_ctx[1], frames, iptrr, 1, d->lsb_first, iptrfr, 1); | |
319 | while (count--) { | |
320 | double scaledl = *iptrfl++ * 0x7fffffff; | |
321 | double scaledr = *iptrfr++ * 0x7fffffff; | |
322 | if (scaledl > 2147483647.0) scaledl = 2147483647.0; | |
323 | if (scaledl < -2147483648.0) scaledl = -2147483648.0; | |
324 | if (scaledr > 2147483647.0) scaledr = 2147483647.0; | |
325 | if (scaledr < -2147483648.0) scaledr = -2147483648.0; | |
326 | *optr++ = (s32_t)scaledl; | |
327 | *optr++ = (s32_t)scaledr; | |
328 | } | |
329 | } | |
330 | ||
331 | } | |
332 | ||
333 | _buf_inc_readp(streambuf, bytes_read); | |
334 | ||
335 | block_left -= bytes_read; | |
336 | ||
337 | if (d->sample_bytes > bytes_read) { | |
338 | d->sample_bytes -= bytes_read; | |
339 | } else { | |
340 | LOG_INFO("end of track samples"); | |
341 | block_left = 0; | |
342 | d->sample_bytes = 0; | |
343 | } | |
344 | ||
345 | IF_DIRECT( | |
346 | _buf_inc_writep(outputbuf, frames * BYTES_PER_FRAME); | |
347 | ); | |
348 | IF_PROCESS( | |
349 | process.in_frames += frames; | |
350 | ); | |
351 | ||
352 | LOG_SDEBUG("write %u frames", frames); | |
353 | } | |
354 | ||
355 | // skip the other channel blocks | |
356 | // the right channel has already been read and is guarenteed to be in streambuf so can be skipped immediately | |
357 | if (d->channels > 1) { | |
358 | _buf_inc_readp(streambuf, d->block_size); | |
359 | } | |
360 | if (d->channels > 2) { | |
361 | d->consume = d->block_size * (d->channels - 2); | |
362 | } | |
363 | ||
364 | return DECODE_RUNNING; | |
365 | } | |
366 | ||
367 | static decode_state _decode_dsdiff(void) { | |
368 | ||
369 | // samples in streambuf are interleaved on byte per channel | |
370 | // we process as little as necessary per call and only need to handle frames wrapping round streambuf | |
371 | ||
372 | unsigned bytes_per_frame, bytes_read; | |
373 | frames_t out, frames, count; | |
374 | u8_t *iptr; | |
375 | u32_t *optr; | |
376 | u8_t tmp[WRAP_BUF_SIZE]; | |
377 | ||
378 | unsigned bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf)); | |
379 | ||
380 | IF_DIRECT( | |
381 | out = min(_buf_space(outputbuf), _buf_cont_write(outputbuf)) / BYTES_PER_FRAME; | |
382 | ); | |
383 | IF_PROCESS( | |
384 | out = process.max_in_frames; | |
385 | ); | |
386 | ||
387 | if (dop) { | |
388 | bytes_per_frame = d->channels * 2; | |
389 | } else { | |
390 | bytes_per_frame = d->channels; | |
391 | out = min(out, BLOCK); | |
392 | } | |
393 | ||
394 | frames = min(min(bytes, d->sample_bytes) / bytes_per_frame, out); | |
395 | bytes_read = frames * bytes_per_frame; | |
396 | ||
397 | iptr = (u8_t *)streambuf->readp; | |
398 | ||
399 | IF_DIRECT( | |
400 | optr = (u32_t *)outputbuf->writep; | |
401 | ); | |
402 | IF_PROCESS( | |
403 | optr = (u32_t *)process.inbuf; | |
404 | ); | |
405 | ||
406 | // handle wrap around end of streambuf and partial dop frame at end of stream | |
407 | if (!frames && bytes < bytes_per_frame) { | |
408 | memset(tmp, 0x69, WRAP_BUF_SIZE); // 0x69 = dsd silence | |
409 | memcpy(tmp, streambuf->readp, bytes); | |
410 | if (_buf_used(streambuf) > bytes_per_frame) { | |
411 | memcpy(tmp + bytes, streambuf->buf, bytes_per_frame - bytes); | |
412 | bytes_read = bytes_per_frame; | |
413 | } else { | |
414 | bytes_read = bytes; | |
415 | } | |
416 | iptr = tmp; | |
417 | frames = 1; | |
418 | } | |
419 | ||
420 | count = frames; | |
421 | ||
422 | if (dop) { | |
423 | ||
424 | if (d->channels == 1) { | |
425 | while (count--) { | |
426 | *(optr++) = *(iptr) << 16 | *(iptr+1) << 8; | |
427 | *(optr++) = *(iptr) << 16 | *(iptr+1) << 8; | |
428 | iptr += bytes_per_frame; | |
429 | } | |
430 | } else { | |
431 | while (count--) { | |
432 | *(optr++) = *(iptr ) << 16 | *(iptr + d->channels) << 8; | |
433 | *(optr++) = *(iptr+1) << 16 | *(iptr + d->channels + 1) << 8; | |
434 | iptr += bytes_per_frame; | |
435 | } | |
436 | } | |
437 | ||
438 | } else { | |
439 | ||
440 | if (d->channels == 1) { | |
441 | float *iptrf = d->transfer[0]; | |
442 | dsd2pcm_translate(d->dsd2pcm_ctx[0], frames, iptr, 1, 0, iptrf, 1); | |
443 | while (count--) { | |
444 | double scaled = *iptrf++ * 0x7fffffff; | |
445 | if (scaled > 2147483647.0) scaled = 2147483647.0; | |
446 | if (scaled < -2147483648.0) scaled = -2147483648.0; | |
447 | *optr++ = (s32_t)scaled; | |
448 | *optr++ = (s32_t)scaled; | |
449 | } | |
450 | } else { | |
451 | float *iptrfl = d->transfer[0]; | |
452 | float *iptrfr = d->transfer[1]; | |
453 | dsd2pcm_translate(d->dsd2pcm_ctx[0], frames, iptr, d->channels, 0, iptrfl, 1); | |
454 | dsd2pcm_translate(d->dsd2pcm_ctx[1], frames, iptr + 1, d->channels, 0, iptrfr, 1); | |
455 | while (count--) { | |
456 | double scaledl = *iptrfl++ * 0x7fffffff; | |
457 | double scaledr = *iptrfr++ * 0x7fffffff; | |
458 | if (scaledl > 2147483647.0) scaledl = 2147483647.0; | |
459 | if (scaledl < -2147483648.0) scaledl = -2147483648.0; | |
460 | if (scaledr > 2147483647.0) scaledr = 2147483647.0; | |
461 | if (scaledr < -2147483648.0) scaledr = -2147483648.0; | |
462 | *optr++ = (s32_t)scaledl; | |
463 | *optr++ = (s32_t)scaledr; | |
464 | } | |
465 | } | |
466 | ||
467 | } | |
468 | ||
469 | _buf_inc_readp(streambuf, bytes_read); | |
470 | ||
471 | if (d->sample_bytes > bytes_read) { | |
472 | d->sample_bytes -= bytes_read; | |
473 | } else { | |
474 | LOG_INFO("end of track samples"); | |
475 | d->sample_bytes = 0; | |
476 | } | |
477 | ||
478 | IF_DIRECT( | |
479 | _buf_inc_writep(outputbuf, frames * BYTES_PER_FRAME); | |
480 | ); | |
481 | IF_PROCESS( | |
482 | process.in_frames = frames; | |
483 | ); | |
484 | ||
485 | LOG_SDEBUG("write %u frames", frames); | |
486 | ||
487 | return DECODE_RUNNING; | |
488 | } | |
489 | ||
490 | ||
491 | static decode_state dsd_decode(void) { | |
492 | decode_state ret; | |
493 | ||
494 | LOCK_S; | |
495 | ||
496 | if ((stream.state <= DISCONNECT && !_buf_used(streambuf)) || (!decode.new_stream && d->sample_bytes == 0)) { | |
497 | UNLOCK_S; | |
498 | return DECODE_COMPLETE; | |
499 | } | |
500 | ||
501 | if (d->consume) { | |
502 | unsigned consume = min(d->consume, min(_buf_used(streambuf), _buf_cont_read(streambuf))); | |
503 | LOG_DEBUG("consume: %u of %u", consume, d->consume); | |
504 | _buf_inc_readp(streambuf, consume); | |
505 | d->consume -= consume; | |
506 | if (d->consume) { | |
507 | UNLOCK_S; | |
508 | return DECODE_RUNNING; | |
509 | } | |
510 | } | |
511 | ||
512 | if (decode.new_stream) { | |
513 | int r = _read_header(); | |
514 | if (r < 1) { | |
515 | UNLOCK_S; | |
516 | return DECODE_ERROR; | |
517 | } | |
518 | if (r == 0) { | |
519 | UNLOCK_S; | |
520 | return DECODE_RUNNING; | |
521 | } | |
522 | // otherwise got to start of audio | |
523 | ||
524 | LOCK_O; | |
525 | ||
526 | LOG_INFO("setting track_start"); | |
527 | output.track_start = outputbuf->writep; | |
528 | ||
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; | |
539 | output.next_sample_rate = d->sample_rate / 16; | |
540 | output.fade = FADE_INACTIVE; | |
541 | } else { | |
542 | LOG_INFO("DSD to PCM output"); | |
543 | output.next_dop = false; | |
544 | output.next_sample_rate = decode_newstream(d->sample_rate / 8, output.supported_rates); | |
545 | if (output.fade_mode) _checkfade(true); | |
546 | } | |
547 | ||
548 | decode.new_stream = false; | |
549 | ||
550 | UNLOCK_O; | |
551 | } | |
552 | ||
553 | LOCK_O_direct; | |
554 | ||
555 | switch (d->type) { | |
556 | case DSF: | |
557 | ret = _decode_dsf(); | |
558 | break; | |
559 | case DSDIFF: | |
560 | ret = _decode_dsdiff(); | |
561 | break; | |
562 | default: | |
563 | ret = DECODE_ERROR; | |
564 | } | |
565 | ||
566 | UNLOCK_O_direct; | |
567 | UNLOCK_S; | |
568 | ||
569 | return ret; | |
570 | } | |
571 | ||
572 | static void dsd_open(u8_t size, u8_t rate, u8_t chan, u8_t endianness) { | |
573 | d->type = UNKNOWN; | |
574 | ||
575 | if (!d->dsd2pcm_ctx[0]) { | |
576 | d->dsd2pcm_ctx[0] = dsd2pcm_init(); | |
577 | d->dsd2pcm_ctx[1] = dsd2pcm_init(); | |
578 | } else { | |
579 | dsd2pcm_reset(d->dsd2pcm_ctx[0]); | |
580 | dsd2pcm_reset(d->dsd2pcm_ctx[1]); | |
581 | } | |
582 | if (!d->transfer[1]) { | |
583 | d->transfer[0] = malloc(sizeof(float) * BLOCK); | |
584 | d->transfer[1] = malloc(sizeof(float) * BLOCK); | |
585 | } | |
586 | } | |
587 | ||
588 | static void dsd_close(void) { | |
589 | if (d->dsd2pcm_ctx[0]) { | |
590 | dsd2pcm_destroy(d->dsd2pcm_ctx[0]); | |
591 | dsd2pcm_destroy(d->dsd2pcm_ctx[1]); | |
592 | d->dsd2pcm_ctx[0] = NULL; | |
593 | d->dsd2pcm_ctx[1] = NULL; | |
594 | } | |
595 | if (d->transfer[0]) { | |
596 | free(d->transfer[0]); | |
597 | free(d->transfer[1]); | |
598 | d->transfer[0] = NULL; | |
599 | d->transfer[1] = NULL; | |
600 | } | |
601 | } | |
602 | ||
603 | struct codec *register_dsd(void) { | |
604 | static struct codec ret = { | |
605 | 'd', // id | |
606 | "dsf,dff", // types | |
607 | BLOCK * 2, // min read | |
608 | BLOCK_FRAMES,// min space | |
609 | dsd_open, // open | |
610 | dsd_close, // close | |
611 | dsd_decode, // decode | |
612 | }; | |
613 | ||
614 | d = malloc(sizeof(struct dsd)); | |
615 | if (!d) { | |
616 | return NULL; | |
617 | } | |
618 | ||
619 | memset(d, 0, sizeof(struct dsd)); | |
620 | ||
621 | dsd2pcm_precalc(); | |
622 | ||
623 | LOG_INFO("using dsd to decode dsf,dff"); | |
624 | return &ret; | |
625 | } | |
626 | ||
627 | #endif // DSD |
0 | Copyright 2009, 2011 Sebastian Gesemann. All rights reserved. | |
1 | ||
2 | Redistribution and use in source and binary forms, with or without modification, are | |
3 | permitted provided that the following conditions are met: | |
4 | ||
5 | 1. Redistributions of source code must retain the above copyright notice, this list of | |
6 | conditions and the following disclaimer. | |
7 | ||
8 | 2. Redistributions in binary form must reproduce the above copyright notice, this list | |
9 | of conditions and the following disclaimer in the documentation and/or other materials | |
10 | provided with the distribution. | |
11 | ||
12 | THIS SOFTWARE IS PROVIDED BY SEBASTIAN GESEMANN ''AS IS'' AND ANY EXPRESS OR IMPLIED | |
13 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
14 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SEBASTIAN GESEMANN OR | |
15 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
16 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
17 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
18 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
19 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | |
20 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
21 | ||
22 | The views and conclusions contained in the software and documentation are those of the | |
23 | authors and should not be interpreted as representing official policies, either expressed | |
24 | or implied, of Sebastian Gesemann. |
0 | /* | |
1 | ||
2 | Copyright 2009, 2011 Sebastian Gesemann. All rights reserved. | |
3 | ||
4 | Redistribution and use in source and binary forms, with or without modification, are | |
5 | permitted provided that the following conditions are met: | |
6 | ||
7 | 1. Redistributions of source code must retain the above copyright notice, this list of | |
8 | conditions and the following disclaimer. | |
9 | ||
10 | 2. Redistributions in binary form must reproduce the above copyright notice, this list | |
11 | of conditions and the following disclaimer in the documentation and/or other materials | |
12 | provided with the distribution. | |
13 | ||
14 | THIS SOFTWARE IS PROVIDED BY SEBASTIAN GESEMANN ''AS IS'' AND ANY EXPRESS OR IMPLIED | |
15 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
16 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SEBASTIAN GESEMANN OR | |
17 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
18 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
20 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
21 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | |
22 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
23 | ||
24 | The views and conclusions contained in the software and documentation are those of the | |
25 | authors and should not be interpreted as representing official policies, either expressed | |
26 | or implied, of Sebastian Gesemann. | |
27 | ||
28 | ---- | |
29 | ||
30 | Additions (c) Adrian Smith, 2013 under same licence terms: | |
31 | - expose bitreverse array as dsd2pcm_bitreverse | |
32 | - expose precalc function as dsd2pcm_precalc to allow it to be initalised | |
33 | ||
34 | */ | |
35 | ||
36 | #include <stdlib.h> | |
37 | #include <string.h> | |
38 | ||
39 | #include "dsd2pcm.h" | |
40 | ||
41 | #define HTAPS 48 /* number of FIR constants */ | |
42 | #define FIFOSIZE 16 /* must be a power of two */ | |
43 | #define FIFOMASK (FIFOSIZE-1) /* bit mask for FIFO offsets */ | |
44 | #define CTABLES ((HTAPS+7)/8) /* number of "8 MACs" lookup tables */ | |
45 | ||
46 | #if FIFOSIZE*8 < HTAPS*2 | |
47 | #error "FIFOSIZE too small" | |
48 | #endif | |
49 | ||
50 | /* | |
51 | * Properties of this 96-tap lowpass filter when applied on a signal | |
52 | * with sampling rate of 44100*64 Hz: | |
53 | * | |
54 | * () has a delay of 17 microseconds. | |
55 | * | |
56 | * () flat response up to 48 kHz | |
57 | * | |
58 | * () if you downsample afterwards by a factor of 8, the | |
59 | * spectrum below 70 kHz is practically alias-free. | |
60 | * | |
61 | * () stopband rejection is about 160 dB | |
62 | * | |
63 | * The coefficient tables ("ctables") take only 6 Kibi Bytes and | |
64 | * should fit into a modern processor's fast cache. | |
65 | */ | |
66 | ||
67 | /* | |
68 | * The 2nd half (48 coeffs) of a 96-tap symmetric lowpass filter | |
69 | */ | |
70 | static const double htaps[HTAPS] = { | |
71 | 0.09950731974056658, | |
72 | 0.09562845727714668, | |
73 | 0.08819647126516944, | |
74 | 0.07782552527068175, | |
75 | 0.06534876523171299, | |
76 | 0.05172629311427257, | |
77 | 0.0379429484910187, | |
78 | 0.02490921351762261, | |
79 | 0.0133774746265897, | |
80 | 0.003883043418804416, | |
81 | -0.003284703416210726, | |
82 | -0.008080250212687497, | |
83 | -0.01067241812471033, | |
84 | -0.01139427235000863, | |
85 | -0.0106813877974587, | |
86 | -0.009007905078766049, | |
87 | -0.006828859761015335, | |
88 | -0.004535184322001496, | |
89 | -0.002425035959059578, | |
90 | -0.0006922187080790708, | |
91 | 0.0005700762133516592, | |
92 | 0.001353838005269448, | |
93 | 0.001713709169690937, | |
94 | 0.001742046839472948, | |
95 | 0.001545601648013235, | |
96 | 0.001226696225277855, | |
97 | 0.0008704322683580222, | |
98 | 0.0005381636200535649, | |
99 | 0.000266446345425276, | |
100 | 7.002968738383528e-05, | |
101 | -5.279407053811266e-05, | |
102 | -0.0001140625650874684, | |
103 | -0.0001304796361231895, | |
104 | -0.0001189970287491285, | |
105 | -9.396247155265073e-05, | |
106 | -6.577634378272832e-05, | |
107 | -4.07492895872535e-05, | |
108 | -2.17407957554587e-05, | |
109 | -9.163058931391722e-06, | |
110 | -2.017460145032201e-06, | |
111 | 1.249721855219005e-06, | |
112 | 2.166655190537392e-06, | |
113 | 1.930520892991082e-06, | |
114 | 1.319400334374195e-06, | |
115 | 7.410039764949091e-07, | |
116 | 3.423230509967409e-07, | |
117 | 1.244182214744588e-07, | |
118 | 3.130441005359396e-08 | |
119 | }; | |
120 | ||
121 | static float ctables[CTABLES][256]; | |
122 | unsigned char dsd2pcm_bitreverse[256]; | |
123 | static int precalculated = 0; | |
124 | ||
125 | void dsd2pcm_precalc(void) | |
126 | { | |
127 | int t, e, m, k; | |
128 | double acc; | |
129 | if (precalculated) return; | |
130 | for (t=0, e=0; t<256; ++t) { | |
131 | dsd2pcm_bitreverse[t] = e; | |
132 | for (m=128; m && !((e^=m)&m); m>>=1) | |
133 | ; | |
134 | } | |
135 | for (t=0; t<CTABLES; ++t) { | |
136 | k = HTAPS - t*8; | |
137 | if (k>8) k=8; | |
138 | for (e=0; e<256; ++e) { | |
139 | acc = 0.0; | |
140 | for (m=0; m<k; ++m) { | |
141 | acc += (((e >> (7-m)) & 1)*2-1) * htaps[t*8+m]; | |
142 | } | |
143 | ctables[CTABLES-1-t][e] = (float)acc; | |
144 | } | |
145 | } | |
146 | precalculated = 1; | |
147 | } | |
148 | ||
149 | struct dsd2pcm_ctx_s | |
150 | { | |
151 | unsigned char fifo[FIFOSIZE]; | |
152 | unsigned fifopos; | |
153 | }; | |
154 | ||
155 | extern dsd2pcm_ctx* dsd2pcm_init() | |
156 | { | |
157 | dsd2pcm_ctx* ptr; | |
158 | if (!precalculated) dsd2pcm_precalc(); | |
159 | ptr = (dsd2pcm_ctx*) malloc(sizeof(dsd2pcm_ctx)); | |
160 | if (ptr) dsd2pcm_reset(ptr); | |
161 | return ptr; | |
162 | } | |
163 | ||
164 | extern void dsd2pcm_destroy(dsd2pcm_ctx* ptr) | |
165 | { | |
166 | free(ptr); | |
167 | } | |
168 | ||
169 | extern dsd2pcm_ctx* dsd2pcm_clone(dsd2pcm_ctx* ptr) | |
170 | { | |
171 | dsd2pcm_ctx* p2; | |
172 | p2 = (dsd2pcm_ctx*) malloc(sizeof(dsd2pcm_ctx)); | |
173 | if (p2) { | |
174 | memcpy(p2,ptr,sizeof(dsd2pcm_ctx)); | |
175 | } | |
176 | return p2; | |
177 | } | |
178 | ||
179 | extern void dsd2pcm_reset(dsd2pcm_ctx* ptr) | |
180 | { | |
181 | int i; | |
182 | for (i=0; i<FIFOSIZE; ++i) | |
183 | ptr->fifo[i] = 0x69; /* my favorite silence pattern */ | |
184 | ptr->fifopos = 0; | |
185 | /* 0x69 = 01101001 | |
186 | * This pattern "on repeat" makes a low energy 352.8 kHz tone | |
187 | * and a high energy 1.0584 MHz tone which should be filtered | |
188 | * out completely by any playback system --> silence | |
189 | */ | |
190 | } | |
191 | ||
192 | extern void dsd2pcm_translate( | |
193 | dsd2pcm_ctx* ptr, | |
194 | size_t samples, | |
195 | const unsigned char *src, ptrdiff_t src_stride, | |
196 | int lsbf, | |
197 | float *dst, ptrdiff_t dst_stride) | |
198 | { | |
199 | unsigned ffp; | |
200 | unsigned i; | |
201 | unsigned bite1, bite2; | |
202 | unsigned char* p; | |
203 | double acc; | |
204 | ffp = ptr->fifopos; | |
205 | lsbf = lsbf ? 1 : 0; | |
206 | while (samples-- > 0) { | |
207 | bite1 = *src & 0xFFu; | |
208 | if (lsbf) bite1 = dsd2pcm_bitreverse[bite1]; | |
209 | ptr->fifo[ffp] = bite1; src += src_stride; | |
210 | p = ptr->fifo + ((ffp-CTABLES) & FIFOMASK); | |
211 | *p = dsd2pcm_bitreverse[*p & 0xFF]; | |
212 | acc = 0; | |
213 | for (i=0; i<CTABLES; ++i) { | |
214 | bite1 = ptr->fifo[(ffp -i) & FIFOMASK] & 0xFF; | |
215 | bite2 = ptr->fifo[(ffp-(CTABLES*2-1)+i) & FIFOMASK] & 0xFF; | |
216 | acc += ctables[i][bite1] + ctables[i][bite2]; | |
217 | } | |
218 | *dst = (float)acc; dst += dst_stride; | |
219 | ffp = (ffp + 1) & FIFOMASK; | |
220 | } | |
221 | ptr->fifopos = ffp; | |
222 | } | |
223 |
0 | /* | |
1 | ||
2 | Copyright 2009, 2011 Sebastian Gesemann. All rights reserved. | |
3 | ||
4 | Redistribution and use in source and binary forms, with or without modification, are | |
5 | permitted provided that the following conditions are met: | |
6 | ||
7 | 1. Redistributions of source code must retain the above copyright notice, this list of | |
8 | conditions and the following disclaimer. | |
9 | ||
10 | 2. Redistributions in binary form must reproduce the above copyright notice, this list | |
11 | of conditions and the following disclaimer in the documentation and/or other materials | |
12 | provided with the distribution. | |
13 | ||
14 | THIS SOFTWARE IS PROVIDED BY SEBASTIAN GESEMANN ''AS IS'' AND ANY EXPRESS OR IMPLIED | |
15 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
16 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SEBASTIAN GESEMANN OR | |
17 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
18 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
20 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
21 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | |
22 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
23 | ||
24 | The views and conclusions contained in the software and documentation are those of the | |
25 | authors and should not be interpreted as representing official policies, either expressed | |
26 | or implied, of Sebastian Gesemann. | |
27 | ||
28 | ---- | |
29 | ||
30 | Marked additions (c) Adrian Smith, 2013 under same licence terms | |
31 | ||
32 | */ | |
33 | ||
34 | #ifndef DSD2PCM_H_INCLUDED | |
35 | #define DSD2PCM_H_INCLUDED | |
36 | ||
37 | #include <stddef.h> | |
38 | #include <string.h> | |
39 | ||
40 | #ifdef __cplusplus | |
41 | extern "C" { | |
42 | #endif | |
43 | ||
44 | struct dsd2pcm_ctx_s; | |
45 | ||
46 | typedef struct dsd2pcm_ctx_s dsd2pcm_ctx; | |
47 | ||
48 | /** | |
49 | * initializes a "dsd2pcm engine" for one channel | |
50 | * (precomputes tables and allocates memory) | |
51 | * | |
52 | * This is the only function that is not thread-safe in terms of the | |
53 | * POSIX thread-safety definition because it modifies global state | |
54 | * (lookup tables are computed during the first call) | |
55 | */ | |
56 | extern dsd2pcm_ctx* dsd2pcm_init(void); | |
57 | ||
58 | /** | |
59 | * deinitializes a "dsd2pcm engine" | |
60 | * (releases memory, don't forget!) | |
61 | */ | |
62 | extern void dsd2pcm_destroy(dsd2pcm_ctx *ctx); | |
63 | ||
64 | /** | |
65 | * clones the context and returns a pointer to the | |
66 | * newly allocated copy | |
67 | */ | |
68 | extern dsd2pcm_ctx* dsd2pcm_clone(dsd2pcm_ctx *ctx); | |
69 | ||
70 | /** | |
71 | * resets the internal state for a fresh new stream | |
72 | */ | |
73 | extern void dsd2pcm_reset(dsd2pcm_ctx *ctx); | |
74 | ||
75 | /** | |
76 | * "translates" a stream of octets to a stream of floats | |
77 | * (8:1 decimation) | |
78 | * @param ctx -- pointer to abstract context (buffers) | |
79 | * @param samples -- number of octets/samples to "translate" | |
80 | * @param src -- pointer to first octet (input) | |
81 | * @param src_stride -- src pointer increment | |
82 | * @param lsbitfirst -- bitorder, 0=msb first, 1=lsbfirst | |
83 | * @param dst -- pointer to first float (output) | |
84 | * @param dst_stride -- dst pointer increment | |
85 | */ | |
86 | extern void dsd2pcm_translate(dsd2pcm_ctx *ctx, | |
87 | size_t samples, | |
88 | const unsigned char *src, ptrdiff_t src_stride, | |
89 | int lsbitfirst, | |
90 | float *dst, ptrdiff_t dst_stride); | |
91 | ||
92 | /** | |
93 | * Additions by Adrian Smith (c) 2013 for Squeezelite | |
94 | */ | |
95 | extern unsigned char dsd2pcm_bitreverse[]; | |
96 | ||
97 | extern void dsd2pcm_precalc(void); | |
98 | /** | |
99 | * End of addition | |
100 | */ | |
101 | ||
102 | #ifdef __cplusplus | |
103 | } /* extern "C" */ | |
104 | #endif | |
105 | ||
106 | #endif /* include guard DSD2PCM_H_INCLUDED */ | |
107 |
0 | /* | |
1 | * Squeezelite - lightweight headless squeezebox emulator | |
2 | * | |
3 | * (c) Adrian Smith 2012-2015, triode1@btinternet.com | |
4 | * | |
5 | * This program is free software: you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation, either version 3 of the License, or | |
8 | * (at your option) any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
17 | * | |
18 | */ | |
19 | ||
20 | #include "squeezelite.h" | |
21 | ||
22 | #include <neaacdec.h> | |
23 | ||
24 | #define WRAPBUF_LEN 2048 | |
25 | ||
26 | struct chunk_table { | |
27 | u32_t sample, offset; | |
28 | }; | |
29 | ||
30 | struct faad { | |
31 | NeAACDecHandle hAac; | |
32 | u8_t type; | |
33 | // following used for mp4 only | |
34 | u32_t consume; | |
35 | u32_t pos; | |
36 | u32_t sample; | |
37 | u32_t nextchunk; | |
38 | void *stsc; | |
39 | u32_t skip; | |
40 | u64_t samples; | |
41 | u64_t sttssamples; | |
42 | bool empty; | |
43 | struct chunk_table *chunkinfo; | |
44 | // faad symbols to be dynamically loaded | |
45 | #if !LINKALL | |
46 | NeAACDecConfigurationPtr (* NeAACDecGetCurrentConfiguration)(NeAACDecHandle); | |
47 | unsigned char (* NeAACDecSetConfiguration)(NeAACDecHandle, NeAACDecConfigurationPtr); | |
48 | NeAACDecHandle (* NeAACDecOpen)(void); | |
49 | void (* NeAACDecClose)(NeAACDecHandle); | |
50 | long (* NeAACDecInit)(NeAACDecHandle, unsigned char *, unsigned long, unsigned long *, unsigned char *); | |
51 | char (* NeAACDecInit2)(NeAACDecHandle, unsigned char *pBuffer, unsigned long, unsigned long *, unsigned char *); | |
52 | void *(* NeAACDecDecode)(NeAACDecHandle, NeAACDecFrameInfo *, unsigned char *, unsigned long); | |
53 | char *(* NeAACDecGetErrorMessage)(unsigned char); | |
54 | #endif | |
55 | }; | |
56 | ||
57 | static struct faad *a; | |
58 | ||
59 | extern log_level loglevel; | |
60 | ||
61 | extern struct buffer *streambuf; | |
62 | extern struct buffer *outputbuf; | |
63 | extern struct streamstate stream; | |
64 | extern struct outputstate output; | |
65 | extern struct decodestate decode; | |
66 | extern struct processstate process; | |
67 | ||
68 | #define LOCK_S mutex_lock(streambuf->mutex) | |
69 | #define UNLOCK_S mutex_unlock(streambuf->mutex) | |
70 | #define LOCK_O mutex_lock(outputbuf->mutex) | |
71 | #define UNLOCK_O mutex_unlock(outputbuf->mutex) | |
72 | #if PROCESS | |
73 | #define LOCK_O_direct if (decode.direct) mutex_lock(outputbuf->mutex) | |
74 | #define UNLOCK_O_direct if (decode.direct) mutex_unlock(outputbuf->mutex) | |
75 | #define IF_DIRECT(x) if (decode.direct) { x } | |
76 | #define IF_PROCESS(x) if (!decode.direct) { x } | |
77 | #else | |
78 | #define LOCK_O_direct mutex_lock(outputbuf->mutex) | |
79 | #define UNLOCK_O_direct mutex_unlock(outputbuf->mutex) | |
80 | #define IF_DIRECT(x) { x } | |
81 | #define IF_PROCESS(x) | |
82 | #endif | |
83 | ||
84 | #if LINKALL | |
85 | #define NEAAC(h, fn, ...) (NeAACDec ## fn)(__VA_ARGS__) | |
86 | #else | |
87 | #define NEAAC(h, fn, ...) (h)->NeAACDec##fn(__VA_ARGS__) | |
88 | #endif | |
89 | ||
90 | // minimal code for mp4 file parsing to extract audio config and find media data | |
91 | ||
92 | // adapted from faad2/common/mp4ff | |
93 | u32_t mp4_desc_length(u8_t **buf) { | |
94 | u8_t b; | |
95 | u8_t num_bytes = 0; | |
96 | u32_t length = 0; | |
97 | ||
98 | do { | |
99 | b = **buf; | |
100 | *buf += 1; | |
101 | num_bytes++; | |
102 | length = (length << 7) | (b & 0x7f); | |
103 | } while ((b & 0x80) && num_bytes < 4); | |
104 | ||
105 | return length; | |
106 | } | |
107 | ||
108 | // read mp4 header to extract config data | |
109 | static int read_mp4_header(unsigned long *samplerate_p, unsigned char *channels_p) { | |
110 | size_t bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf)); | |
111 | char type[5]; | |
112 | u32_t len; | |
113 | ||
114 | while (bytes >= 8) { | |
115 | // count trak to find the first playable one | |
116 | static unsigned trak, play; | |
117 | u32_t consume; | |
118 | ||
119 | len = unpackN((u32_t *)streambuf->readp); | |
120 | memcpy(type, streambuf->readp + 4, 4); | |
121 | type[4] = '\0'; | |
122 | ||
123 | if (!strcmp(type, "moov")) { | |
124 | trak = 0; | |
125 | play = 0; | |
126 | } | |
127 | if (!strcmp(type, "trak")) { | |
128 | trak++; | |
129 | } | |
130 | ||
131 | // extract audio config from within esds and pass to DecInit2 | |
132 | if (!strcmp(type, "esds") && bytes > len) { | |
133 | unsigned config_len; | |
134 | u8_t *ptr = streambuf->readp + 12; | |
135 | if (*ptr++ == 0x03) { | |
136 | mp4_desc_length(&ptr); | |
137 | ptr += 4; | |
138 | } else { | |
139 | ptr += 3; | |
140 | } | |
141 | mp4_desc_length(&ptr); | |
142 | ptr += 13; | |
143 | if (*ptr++ != 0x05) { | |
144 | LOG_WARN("error parsing esds"); | |
145 | return -1; | |
146 | } | |
147 | config_len = mp4_desc_length(&ptr); | |
148 | if (NEAAC(a, Init2, a->hAac, ptr, config_len, samplerate_p, channels_p) == 0) { | |
149 | LOG_DEBUG("playable aac track: %u", trak); | |
150 | play = trak; | |
151 | } | |
152 | } | |
153 | ||
154 | // extract the total number of samples from stts | |
155 | if (!strcmp(type, "stts") && bytes > len) { | |
156 | u32_t i; | |
157 | u8_t *ptr = streambuf->readp + 12; | |
158 | u32_t entries = unpackN((u32_t *)ptr); | |
159 | ptr += 4; | |
160 | for (i = 0; i < entries; ++i) { | |
161 | u32_t count = unpackN((u32_t *)ptr); | |
162 | u32_t size = unpackN((u32_t *)(ptr + 4)); | |
163 | a->sttssamples += count * size; | |
164 | ptr += 8; | |
165 | } | |
166 | LOG_DEBUG("total number of samples contained in stts: " FMT_u64, a->sttssamples); | |
167 | } | |
168 | ||
169 | // stash sample to chunk info, assume it comes before stco | |
170 | if (!strcmp(type, "stsc") && bytes > len && !a->chunkinfo) { | |
171 | a->stsc = malloc(len - 12); | |
172 | if (a->stsc == NULL) { | |
173 | LOG_WARN("malloc fail"); | |
174 | return -1; | |
175 | } | |
176 | memcpy(a->stsc, streambuf->readp + 12, len - 12); | |
177 | } | |
178 | ||
179 | // build offsets table from stco and stored stsc | |
180 | if (!strcmp(type, "stco") && bytes > len && play == trak) { | |
181 | u32_t i; | |
182 | // extract chunk offsets | |
183 | u8_t *ptr = streambuf->readp + 12; | |
184 | u32_t entries = unpackN((u32_t *)ptr); | |
185 | ptr += 4; | |
186 | a->chunkinfo = malloc(sizeof(struct chunk_table) * (entries + 1)); | |
187 | if (a->chunkinfo == NULL) { | |
188 | LOG_WARN("malloc fail"); | |
189 | return -1; | |
190 | } | |
191 | for (i = 0; i < entries; ++i) { | |
192 | a->chunkinfo[i].offset = unpackN((u32_t *)ptr); | |
193 | a->chunkinfo[i].sample = 0; | |
194 | ptr += 4; | |
195 | } | |
196 | a->chunkinfo[i].sample = 0; | |
197 | a->chunkinfo[i].offset = 0; | |
198 | // fill in first sample id for each chunk from stored stsc | |
199 | if (a->stsc) { | |
200 | u32_t stsc_entries = unpackN((u32_t *)a->stsc); | |
201 | u32_t sample = 0; | |
202 | u32_t last = 0, last_samples = 0; | |
203 | u8_t *ptr = (u8_t *)a->stsc + 4; | |
204 | while (stsc_entries--) { | |
205 | u32_t first = unpackN((u32_t *)ptr); | |
206 | u32_t samples = unpackN((u32_t *)(ptr + 4)); | |
207 | if (last) { | |
208 | for (i = last - 1; i < first - 1; ++i) { | |
209 | a->chunkinfo[i].sample = sample; | |
210 | sample += last_samples; | |
211 | } | |
212 | } | |
213 | if (stsc_entries == 0) { | |
214 | for (i = first - 1; i < entries; ++i) { | |
215 | a->chunkinfo[i].sample = sample; | |
216 | sample += samples; | |
217 | } | |
218 | } | |
219 | last = first; | |
220 | last_samples = samples; | |
221 | ptr += 12; | |
222 | } | |
223 | free(a->stsc); | |
224 | a->stsc = NULL; | |
225 | } | |
226 | } | |
227 | ||
228 | // found media data, advance to start of first chunk and return | |
229 | if (!strcmp(type, "mdat")) { | |
230 | _buf_inc_readp(streambuf, 8); | |
231 | a->pos += 8; | |
232 | bytes -= 8; | |
233 | if (play) { | |
234 | LOG_DEBUG("type: mdat len: %u pos: %u", len, a->pos); | |
235 | if (a->chunkinfo && a->chunkinfo[0].offset > a->pos) { | |
236 | u32_t skip = a->chunkinfo[0].offset - a->pos; | |
237 | LOG_DEBUG("skipping: %u", skip); | |
238 | if (skip <= bytes) { | |
239 | _buf_inc_readp(streambuf, skip); | |
240 | a->pos += skip; | |
241 | } else { | |
242 | a->consume = skip; | |
243 | } | |
244 | } | |
245 | a->sample = a->nextchunk = 1; | |
246 | return 1; | |
247 | } else { | |
248 | LOG_DEBUG("type: mdat len: %u, no playable track found", len); | |
249 | return -1; | |
250 | } | |
251 | } | |
252 | ||
253 | // parse key-value atoms within ilst ---- entries to get encoder padding within iTunSMPB entry for gapless | |
254 | if (!strcmp(type, "----") && bytes > len) { | |
255 | u8_t *ptr = streambuf->readp + 8; | |
256 | u32_t remain = len - 8, size; | |
257 | if (!memcmp(ptr + 4, "mean", 4) && (size = unpackN((u32_t *)ptr)) < remain) { | |
258 | ptr += size; remain -= size; | |
259 | } | |
260 | if (!memcmp(ptr + 4, "name", 4) && (size = unpackN((u32_t *)ptr)) < remain && !memcmp(ptr + 12, "iTunSMPB", 8)) { | |
261 | ptr += size; remain -= size; | |
262 | } | |
263 | if (!memcmp(ptr + 4, "data", 4) && remain > 16 + 48) { | |
264 | // data is stored as hex strings: 0 start end samples | |
265 | u32_t b, c; u64_t d; | |
266 | if (sscanf((const char *)(ptr + 16), "%x %x %x " FMT_x64, &b, &b, &c, &d) == 4) { | |
267 | LOG_DEBUG("iTunSMPB start: %u end: %u samples: " FMT_u64, b, c, d); | |
268 | if (a->sttssamples && a->sttssamples < b + c + d) { | |
269 | LOG_DEBUG("reducing samples as stts count is less"); | |
270 | d = a->sttssamples - (b + c); | |
271 | } | |
272 | a->skip = b; | |
273 | a->samples = d; | |
274 | } | |
275 | } | |
276 | } | |
277 | ||
278 | // default to consuming entire box | |
279 | consume = len; | |
280 | ||
281 | // read into these boxes so reduce consume | |
282 | if (!strcmp(type, "moov") || !strcmp(type, "trak") || !strcmp(type, "mdia") || !strcmp(type, "minf") || !strcmp(type, "stbl") || | |
283 | !strcmp(type, "udta") || !strcmp(type, "ilst")) { | |
284 | consume = 8; | |
285 | } | |
286 | // special cases which mix mix data in the enclosing box which we want to read into | |
287 | if (!strcmp(type, "stsd")) consume = 16; | |
288 | if (!strcmp(type, "mp4a")) consume = 36; | |
289 | if (!strcmp(type, "meta")) consume = 12; | |
290 | ||
291 | // consume rest of box if it has been parsed (all in the buffer) or is not one we want to parse | |
292 | if (bytes >= consume) { | |
293 | LOG_DEBUG("type: %s len: %u consume: %u", type, len, consume); | |
294 | _buf_inc_readp(streambuf, consume); | |
295 | a->pos += consume; | |
296 | bytes -= consume; | |
297 | } else if ( !(!strcmp(type, "esds") || !strcmp(type, "stts") || !strcmp(type, "stsc") || | |
298 | !strcmp(type, "stco") || !strcmp(type, "----")) ) { | |
299 | LOG_DEBUG("type: %s len: %u consume: %u - partial consume: %u", type, len, consume, bytes); | |
300 | _buf_inc_readp(streambuf, bytes); | |
301 | a->pos += bytes; | |
302 | a->consume = consume - bytes; | |
303 | break; | |
304 | } else { | |
305 | break; | |
306 | } | |
307 | } | |
308 | ||
309 | return 0; | |
310 | } | |
311 | ||
312 | static decode_state faad_decode(void) { | |
313 | size_t bytes_total; | |
314 | size_t bytes_wrap; | |
315 | NeAACDecFrameInfo info; | |
316 | s32_t *iptr; | |
317 | bool endstream; | |
318 | frames_t frames; | |
319 | ||
320 | LOCK_S; | |
321 | bytes_total = _buf_used(streambuf); | |
322 | bytes_wrap = min(bytes_total, _buf_cont_read(streambuf)); | |
323 | ||
324 | if (stream.state <= DISCONNECT && !bytes_total) { | |
325 | UNLOCK_S; | |
326 | return DECODE_COMPLETE; | |
327 | } | |
328 | ||
329 | if (a->consume) { | |
330 | u32_t consume = min(a->consume, bytes_wrap); | |
331 | LOG_DEBUG("consume: %u of %u", consume, a->consume); | |
332 | _buf_inc_readp(streambuf, consume); | |
333 | a->pos += consume; | |
334 | a->consume -= consume; | |
335 | UNLOCK_S; | |
336 | return DECODE_RUNNING; | |
337 | } | |
338 | ||
339 | if (decode.new_stream) { | |
340 | int found = 0; | |
341 | static unsigned char channels; | |
342 | static unsigned long samplerate; | |
343 | ||
344 | if (a->type == '2') { | |
345 | ||
346 | // adts stream - seek for header | |
347 | while (bytes_wrap >= 2 && (*(streambuf->readp) != 0xFF || (*(streambuf->readp + 1) & 0xF6) != 0xF0)) { | |
348 | _buf_inc_readp(streambuf, 1); | |
349 | bytes_total--; | |
350 | bytes_wrap--; | |
351 | } | |
352 | ||
353 | if (bytes_wrap >= 2) { | |
354 | long n = NEAAC(a, Init, a->hAac, streambuf->readp, bytes_wrap, &samplerate, &channels); | |
355 | if (n < 0) { | |
356 | found = -1; | |
357 | } else { | |
358 | _buf_inc_readp(streambuf, n); | |
359 | found = 1; | |
360 | } | |
361 | } | |
362 | ||
363 | } else { | |
364 | ||
365 | // mp4 - read header | |
366 | found = read_mp4_header(&samplerate, &channels); | |
367 | } | |
368 | ||
369 | if (found == 1) { | |
370 | ||
371 | LOG_INFO("samplerate: %u channels: %u", samplerate, channels); | |
372 | bytes_total = _buf_used(streambuf); | |
373 | bytes_wrap = min(bytes_total, _buf_cont_read(streambuf)); | |
374 | ||
375 | LOCK_O; | |
376 | LOG_INFO("setting track_start"); | |
377 | output.next_sample_rate = decode_newstream(samplerate, output.supported_rates); | |
378 | IF_DSD( output.next_dop = false; ) | |
379 | output.track_start = outputbuf->writep; | |
380 | if (output.fade_mode) _checkfade(true); | |
381 | decode.new_stream = false; | |
382 | UNLOCK_O; | |
383 | ||
384 | } else if (found == -1) { | |
385 | ||
386 | LOG_WARN("error reading stream header"); | |
387 | UNLOCK_S; | |
388 | return DECODE_ERROR; | |
389 | ||
390 | } else { | |
391 | ||
392 | // not finished header parsing come back next time | |
393 | UNLOCK_S; | |
394 | return DECODE_RUNNING; | |
395 | } | |
396 | } | |
397 | ||
398 | if (bytes_wrap < WRAPBUF_LEN && bytes_total > WRAPBUF_LEN) { | |
399 | ||
400 | // make a local copy of frames which may have wrapped round the end of streambuf | |
401 | u8_t buf[WRAPBUF_LEN]; | |
402 | memcpy(buf, streambuf->readp, bytes_wrap); | |
403 | memcpy(buf + bytes_wrap, streambuf->buf, WRAPBUF_LEN - bytes_wrap); | |
404 | ||
405 | iptr = NEAAC(a, Decode, a->hAac, &info, buf, WRAPBUF_LEN); | |
406 | ||
407 | } else { | |
408 | ||
409 | iptr = NEAAC(a, Decode, a->hAac, &info, streambuf->readp, bytes_wrap); | |
410 | } | |
411 | ||
412 | if (info.error) { | |
413 | LOG_WARN("error: %u %s", info.error, NEAAC(a, GetErrorMessage, info.error)); | |
414 | } | |
415 | ||
416 | endstream = false; | |
417 | ||
418 | // mp4 end of chunk - skip to next offset | |
419 | if (a->chunkinfo && a->chunkinfo[a->nextchunk].offset && a->sample++ == a->chunkinfo[a->nextchunk].sample) { | |
420 | ||
421 | if (a->chunkinfo[a->nextchunk].offset > a->pos) { | |
422 | u32_t skip = a->chunkinfo[a->nextchunk].offset - a->pos; | |
423 | if (skip != info.bytesconsumed) { | |
424 | LOG_DEBUG("skipping to next chunk pos: %u consumed: %u != skip: %u", a->pos, info.bytesconsumed, skip); | |
425 | } | |
426 | if (bytes_total >= skip) { | |
427 | _buf_inc_readp(streambuf, skip); | |
428 | a->pos += skip; | |
429 | } else { | |
430 | a->consume = skip; | |
431 | } | |
432 | a->nextchunk++; | |
433 | } else { | |
434 | LOG_ERROR("error: need to skip backwards!"); | |
435 | endstream = true; | |
436 | } | |
437 | ||
438 | // adts and mp4 when not at end of chunk | |
439 | } else if (info.bytesconsumed != 0) { | |
440 | ||
441 | _buf_inc_readp(streambuf, info.bytesconsumed); | |
442 | a->pos += info.bytesconsumed; | |
443 | ||
444 | // error which doesn't advance streambuf - end | |
445 | } else { | |
446 | endstream = true; | |
447 | } | |
448 | ||
449 | UNLOCK_S; | |
450 | ||
451 | if (endstream) { | |
452 | LOG_WARN("unable to decode further"); | |
453 | return DECODE_ERROR; | |
454 | } | |
455 | ||
456 | if (!info.samples) { | |
457 | a->empty = true; | |
458 | return DECODE_RUNNING; | |
459 | } | |
460 | ||
461 | frames = info.samples / info.channels; | |
462 | ||
463 | if (a->skip) { | |
464 | u32_t skip; | |
465 | if (a->empty) { | |
466 | a->empty = false; | |
467 | a->skip -= frames; | |
468 | LOG_DEBUG("gapless: first frame empty, skipped %u frames at start", frames); | |
469 | } | |
470 | skip = min(frames, a->skip); | |
471 | LOG_DEBUG("gapless: skipping %u frames at start", skip); | |
472 | frames -= skip; | |
473 | a->skip -= skip; | |
474 | iptr += skip * info.channels; | |
475 | } | |
476 | ||
477 | if (a->samples) { | |
478 | if (a->samples < frames) { | |
479 | LOG_DEBUG("gapless: trimming %u frames from end", frames - a->samples); | |
480 | frames = (frames_t)a->samples; | |
481 | } | |
482 | a->samples -= frames; | |
483 | } | |
484 | ||
485 | LOG_SDEBUG("write %u frames", frames); | |
486 | ||
487 | LOCK_O_direct; | |
488 | ||
489 | while (frames > 0) { | |
490 | frames_t f; | |
491 | frames_t count; | |
492 | s32_t *optr; | |
493 | ||
494 | IF_DIRECT( | |
495 | f = _buf_cont_write(outputbuf) / BYTES_PER_FRAME; | |
496 | optr = (s32_t *)outputbuf->writep; | |
497 | ); | |
498 | IF_PROCESS( | |
499 | f = process.max_in_frames; | |
500 | optr = (s32_t *)process.inbuf; | |
501 | ); | |
502 | ||
503 | f = min(f, frames); | |
504 | count = f; | |
505 | ||
506 | if (info.channels == 2) { | |
507 | while (count--) { | |
508 | *optr++ = *iptr++ << 8; | |
509 | *optr++ = *iptr++ << 8; | |
510 | } | |
511 | } else if (info.channels == 1) { | |
512 | while (count--) { | |
513 | *optr++ = *iptr << 8; | |
514 | *optr++ = *iptr++ << 8; | |
515 | } | |
516 | } else { | |
517 | LOG_WARN("unsupported number of channels"); | |
518 | } | |
519 | ||
520 | frames -= f; | |
521 | ||
522 | IF_DIRECT( | |
523 | _buf_inc_writep(outputbuf, f * BYTES_PER_FRAME); | |
524 | ); | |
525 | IF_PROCESS( | |
526 | process.in_frames = f; | |
527 | if (frames) LOG_ERROR("unhandled case"); | |
528 | ); | |
529 | } | |
530 | ||
531 | UNLOCK_O_direct; | |
532 | ||
533 | return DECODE_RUNNING; | |
534 | } | |
535 | ||
536 | static void faad_open(u8_t size, u8_t rate, u8_t chan, u8_t endianness) { | |
537 | NeAACDecConfigurationPtr conf; | |
538 | ||
539 | LOG_INFO("opening %s stream", size == '2' ? "adts" : "mp4"); | |
540 | ||
541 | a->type = size; | |
542 | a->pos = a->consume = a->sample = a->nextchunk = 0; | |
543 | ||
544 | if (a->chunkinfo) { | |
545 | free(a->chunkinfo); | |
546 | } | |
547 | if (a->stsc) { | |
548 | free(a->stsc); | |
549 | } | |
550 | a->chunkinfo = NULL; | |
551 | a->stsc = NULL; | |
552 | a->skip = 0; | |
553 | a->samples = 0; | |
554 | a->sttssamples = 0; | |
555 | a->empty = false; | |
556 | ||
557 | if (a->hAac) { | |
558 | NEAAC(a, Close, a->hAac); | |
559 | } | |
560 | a->hAac = NEAAC(a, Open); | |
561 | ||
562 | conf = NEAAC(a, GetCurrentConfiguration, a->hAac); | |
563 | ||
564 | conf->outputFormat = FAAD_FMT_24BIT; | |
565 | conf->downMatrix = 1; | |
566 | ||
567 | if (!NEAAC(a, SetConfiguration, a->hAac, conf)) { | |
568 | LOG_WARN("error setting config"); | |
569 | }; | |
570 | } | |
571 | ||
572 | static void faad_close(void) { | |
573 | NEAAC(a, Close, a->hAac); | |
574 | a->hAac = NULL; | |
575 | if (a->chunkinfo) { | |
576 | free(a->chunkinfo); | |
577 | a->chunkinfo = NULL; | |
578 | } | |
579 | if (a->stsc) { | |
580 | free(a->stsc); | |
581 | a->stsc = NULL; | |
582 | } | |
583 | } | |
584 | ||
585 | static bool load_faad() { | |
586 | #if !LINKALL | |
587 | void *handle = dlopen(LIBFAAD, RTLD_NOW); | |
588 | char *err; | |
589 | ||
590 | if (!handle) { | |
591 | LOG_INFO("dlerror: %s", dlerror()); | |
592 | return false; | |
593 | } | |
594 | ||
595 | a->NeAACDecGetCurrentConfiguration = dlsym(handle, "NeAACDecGetCurrentConfiguration"); | |
596 | a->NeAACDecSetConfiguration = dlsym(handle, "NeAACDecSetConfiguration"); | |
597 | a->NeAACDecOpen = dlsym(handle, "NeAACDecOpen"); | |
598 | a->NeAACDecClose = dlsym(handle, "NeAACDecClose"); | |
599 | a->NeAACDecInit = dlsym(handle, "NeAACDecInit"); | |
600 | a->NeAACDecInit2 = dlsym(handle, "NeAACDecInit2"); | |
601 | a->NeAACDecDecode = dlsym(handle, "NeAACDecDecode"); | |
602 | a->NeAACDecGetErrorMessage = dlsym(handle, "NeAACDecGetErrorMessage"); | |
603 | ||
604 | if ((err = dlerror()) != NULL) { | |
605 | LOG_INFO("dlerror: %s", err); | |
606 | return false; | |
607 | } | |
608 | ||
609 | LOG_INFO("loaded "LIBFAAD""); | |
610 | #endif | |
611 | ||
612 | return true; | |
613 | } | |
614 | ||
615 | struct codec *register_faad(void) { | |
616 | static struct codec ret = { | |
617 | 'a', // id | |
618 | "aac", // types | |
619 | WRAPBUF_LEN, // min read | |
620 | 20480, // min space | |
621 | faad_open, // open | |
622 | faad_close, // close | |
623 | faad_decode, // decode | |
624 | }; | |
625 | ||
626 | a = malloc(sizeof(struct faad)); | |
627 | if (!a) { | |
628 | return NULL; | |
629 | } | |
630 | ||
631 | a->hAac = NULL; | |
632 | a->chunkinfo = NULL; | |
633 | a->stsc = NULL; | |
634 | ||
635 | if (!load_faad()) { | |
636 | return NULL; | |
637 | } | |
638 | ||
639 | LOG_INFO("using faad to decode aac"); | |
640 | return &ret; | |
641 | } |
0 | /* | |
1 | * Squeezelite - lightweight headless squeezebox emulator | |
2 | * | |
3 | * (c) Adrian Smith 2012-2015, triode1@btinternet.com | |
4 | * | |
5 | * This program is free software: you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation, either version 3 of the License, or | |
8 | * (at your option) any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
17 | * | |
18 | */ | |
19 | ||
20 | #include "squeezelite.h" | |
21 | ||
22 | #if FFMPEG | |
23 | ||
24 | #include <libavformat/avformat.h> | |
25 | #include <libavcodec/avcodec.h> | |
26 | ||
27 | #define READ_SIZE 4096 * 4 // this is large enough to ensure ffmpeg always gets new data when decode is called | |
28 | #define WRITE_SIZE 256 * 1024 // FIXME - make smaller, but still to absorb max wma output | |
29 | ||
30 | // FIXME - do we need to align these params as per ffmpeg on i386? | |
31 | #define attribute_align_arg | |
32 | ||
33 | struct ff_s { | |
34 | // state for ffmpeg decoder | |
35 | bool wma; | |
36 | u8_t wma_mmsh; | |
37 | u8_t wma_playstream; | |
38 | u8_t wma_metadatastream; | |
39 | u8_t *readbuf; | |
40 | bool end_of_stream; | |
41 | AVInputFormat *input_format; | |
42 | AVFormatContext *formatC; | |
43 | AVCodecContext *codecC; | |
44 | AVFrame *frame; | |
45 | AVPacket *avpkt; | |
46 | unsigned mmsh_bytes_left; | |
47 | unsigned mmsh_bytes_pad; | |
48 | unsigned mmsh_packet_len; | |
49 | #if !LINKALL | |
50 | // ffmpeg symbols to be dynamically loaded from libavcodec | |
51 | unsigned (* avcodec_version)(void); | |
52 | AVCodec * (* avcodec_find_decoder)(int); | |
53 | int attribute_align_arg (* avcodec_open2)(AVCodecContext *, const AVCodec *, AVDictionary **); | |
54 | AVFrame * (* avcodec_alloc_frame)(void); | |
55 | void (* avcodec_free_frame)(AVFrame **); | |
56 | int attribute_align_arg (* avcodec_decode_audio4)(AVCodecContext *, AVFrame *, int *, const AVPacket *); | |
57 | // ffmpeg symbols to be dynamically loaded from libavformat | |
58 | unsigned (* avformat_version)(void); | |
59 | AVFormatContext * (* avformat_alloc_context)(void); | |
60 | void (* avformat_free_context)(AVFormatContext *); | |
61 | int (* avformat_open_input)(AVFormatContext **, const char *, AVInputFormat *, AVDictionary **); | |
62 | int (* avformat_find_stream_info)(AVFormatContext *, AVDictionary **); | |
63 | AVIOContext * (* avio_alloc_context)(unsigned char *, int, int, void *, | |
64 | int (*read_packet)(void *, uint8_t *, int), int (*write_packet)(void *, uint8_t *, int), int64_t (*seek)(void *, int64_t, int)); | |
65 | void (* av_init_packet)(AVPacket *); | |
66 | void (* av_free_packet)(AVPacket *); | |
67 | int (* av_read_frame)(AVFormatContext *, AVPacket *); | |
68 | AVInputFormat * (* av_find_input_format)(const char *); | |
69 | void (* av_register_all)(void); | |
70 | // ffmpeg symbols to be dynamically loaded from libavutil | |
71 | unsigned (* avutil_version)(void); | |
72 | void (* av_log_set_callback)(void (*)(void*, int, const char*, va_list)); | |
73 | void (* av_log_set_level)(int); | |
74 | int (* av_strerror)(int, char *, size_t); | |
75 | void * (* av_malloc)(size_t); | |
76 | void (* av_freep)(void *); | |
77 | #endif | |
78 | }; | |
79 | ||
80 | static struct ff_s *ff; | |
81 | ||
82 | extern log_level loglevel; | |
83 | ||
84 | extern struct buffer *streambuf; | |
85 | extern struct buffer *outputbuf; | |
86 | extern struct streamstate stream; | |
87 | extern struct outputstate output; | |
88 | extern struct decodestate decode; | |
89 | extern struct processstate process; | |
90 | ||
91 | #define LOCK_S mutex_lock(streambuf->mutex) | |
92 | #define UNLOCK_S mutex_unlock(streambuf->mutex) | |
93 | #define LOCK_O mutex_lock(outputbuf->mutex) | |
94 | #define UNLOCK_O mutex_unlock(outputbuf->mutex) | |
95 | #if PROCESS | |
96 | #define LOCK_O_direct if (decode.direct) mutex_lock(outputbuf->mutex) | |
97 | #define UNLOCK_O_direct if (decode.direct) mutex_unlock(outputbuf->mutex) | |
98 | #define IF_DIRECT(x) if (decode.direct) { x } | |
99 | #define IF_PROCESS(x) if (!decode.direct) { x } | |
100 | #else | |
101 | #define LOCK_O_direct mutex_lock(outputbuf->mutex) | |
102 | #define UNLOCK_O_direct mutex_unlock(outputbuf->mutex) | |
103 | #define IF_DIRECT(x) { x } | |
104 | #define IF_PROCESS(x) | |
105 | #endif | |
106 | ||
107 | #if LINKALL | |
108 | #define AV(h, fn, ...) (av_ ## fn)(__VA_ARGS__) | |
109 | #define AVIO(h, fn, ...) (avio_ ## fn)(__VA_ARGS__) | |
110 | #define AVCODEC(h, fn, ...) (avcodec_ ## fn)(__VA_ARGS__) | |
111 | #define AVFORMAT(h, fn, ...) (avformat_ ## fn)(__VA_ARGS__) | |
112 | #else | |
113 | #define AV(h, fn, ...) (h)->av_##fn(__VA_ARGS__) | |
114 | #define AVIO(h, fn, ...) (h)->avio_##fn(__VA_ARGS__) | |
115 | #define AVCODEC(h, fn, ...) (h)->avcodec_##fn(__VA_ARGS__) | |
116 | #define AVFORMAT(h, fn, ...) (h)->avformat_##fn(__VA_ARGS__) | |
117 | #endif | |
118 | ||
119 | ||
120 | // our own version of useful error function not included in earlier ffmpeg versions | |
121 | static char *av__err2str(errnum) { | |
122 | static char buf[64]; | |
123 | AV(ff, strerror, errnum, buf, 64); | |
124 | return buf; | |
125 | } | |
126 | ||
127 | // parser to extract asf data packet length from asf header | |
128 | const u8_t header_guid[16] = { 0x30, 0x26, 0xB2, 0x75, 0x8E, 0x66, 0xCF, 0x11, 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C }; | |
129 | const u8_t file_props_guid[16] = { 0xA1, 0xDC, 0xAB, 0x8C, 0x47, 0xA9, 0xCF, 0x11, 0x8E, 0xE4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 }; | |
130 | ||
131 | static int _parse_packlen(void) { | |
132 | int bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf)); | |
133 | u8_t *ptr = streambuf->readp; | |
134 | int remain = 1; | |
135 | ||
136 | while (bytes >= 24 && remain > 0) { | |
137 | u32_t len = *(ptr+16) | *(ptr+17) << 8 | *(ptr+18) << 16 | *(ptr+19) << 24; // assume msb 32 bits are 0 | |
138 | if (!memcmp(ptr, header_guid, 16) && bytes >= 30) { | |
139 | ptr += 30; | |
140 | bytes -= 30; | |
141 | remain = len - 30; | |
142 | continue; | |
143 | } | |
144 | if (!memcmp(ptr, file_props_guid, 16) && len == 104) { | |
145 | u32_t packlen = *(ptr+92) | *(ptr+93) << 8 | *(ptr+94) << 16 | *(ptr+95) << 24; | |
146 | LOG_INFO("asf packet len: %u", packlen); | |
147 | return packlen; | |
148 | } | |
149 | ptr += len; | |
150 | bytes -= len; | |
151 | remain -= len; | |
152 | } | |
153 | ||
154 | LOG_WARN("could not parse packet length"); | |
155 | return 0; | |
156 | } | |
157 | ||
158 | static int _read_data(void *opaque, u8_t *buffer, int buf_size) { | |
159 | size_t bytes; | |
160 | ||
161 | LOCK_S; | |
162 | ||
163 | bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf)); | |
164 | ff->end_of_stream = (stream.state <= DISCONNECT && bytes == 0); | |
165 | bytes = min(bytes, buf_size); | |
166 | ||
167 | // for chunked wma extract asf header and data frames from framing structure | |
168 | // pad asf data frames to size of packet extracted from asf header | |
169 | if (ff->wma_mmsh) { | |
170 | unsigned chunk_type = 0, chunk_len = 0; | |
171 | ||
172 | if (ff->mmsh_bytes_left) { | |
173 | // bytes remaining from previous frame | |
174 | if (bytes >= ff->mmsh_bytes_left) { | |
175 | bytes = ff->mmsh_bytes_left; | |
176 | ff->mmsh_bytes_left = 0; | |
177 | } else { | |
178 | ff->mmsh_bytes_left -= bytes; | |
179 | } | |
180 | } else if (ff->mmsh_bytes_pad) { | |
181 | // add padding for previous frame | |
182 | bytes = min(ff->mmsh_bytes_pad, buf_size); | |
183 | memset(buffer, 0, bytes); | |
184 | ff->mmsh_bytes_pad -= bytes; | |
185 | UNLOCK_S; | |
186 | return bytes; | |
187 | } else if (bytes >= 12) { | |
188 | // new chunk header | |
189 | chunk_type = (*(streambuf->readp) & 0x7f) | *(streambuf->readp + 1) << 8; | |
190 | chunk_len = *(streambuf->readp + 2) | *(streambuf->readp + 3) << 8; | |
191 | _buf_inc_readp(streambuf, 12); | |
192 | bytes -= 12; | |
193 | } else if (_buf_used(streambuf) >= 12) { | |
194 | // new chunk header split over end of streambuf, read in two | |
195 | u8_t header[12]; | |
196 | memcpy(header, streambuf->readp, bytes); | |
197 | _buf_inc_readp(streambuf, bytes); | |
198 | memcpy(header + bytes, streambuf->readp, 12 - bytes); | |
199 | _buf_inc_readp(streambuf, 12 - bytes); | |
200 | chunk_type = (header[0] & 0x7f) | header[1] << 8; | |
201 | chunk_len = header[2] | header[3] << 8; | |
202 | bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf)); | |
203 | bytes = min(bytes, buf_size); | |
204 | } else { | |
205 | // should not get here... | |
206 | LOG_ERROR("chunk parser stalled bytes: %u %u", bytes, _buf_used(streambuf)); | |
207 | UNLOCK_S; | |
208 | return 0; | |
209 | } | |
210 | ||
211 | if (chunk_type && chunk_len) { | |
212 | if (chunk_type == 0x4824) { | |
213 | // asf header - parse packet length | |
214 | ff->mmsh_packet_len = _parse_packlen(); | |
215 | ff->mmsh_bytes_pad = 0; | |
216 | } else if (chunk_type == 0x4424 && ff->mmsh_packet_len) { | |
217 | // asf data packet - add padding | |
218 | ff->mmsh_bytes_pad = ff->mmsh_packet_len - chunk_len + 8; | |
219 | } else { | |
220 | LOG_INFO("unknown chunk: %04x", chunk_type); | |
221 | // other packet - no padding | |
222 | ff->mmsh_bytes_pad = 0; | |
223 | } | |
224 | ||
225 | if (chunk_len - 8 <= bytes) { | |
226 | bytes = chunk_len - 8; | |
227 | ff->mmsh_bytes_left = 0; | |
228 | } else { | |
229 | ff->mmsh_bytes_left = chunk_len - 8 - bytes; | |
230 | } | |
231 | } | |
232 | ||
233 | } | |
234 | ||
235 | memcpy(buffer, streambuf->readp, bytes); | |
236 | ||
237 | _buf_inc_readp(streambuf, bytes); | |
238 | ||
239 | if (ff->mmsh_bytes_pad && bytes + ff->mmsh_bytes_pad < buf_size) { | |
240 | memset(buffer + bytes, 0, ff->mmsh_bytes_pad); | |
241 | bytes += ff->mmsh_bytes_pad; | |
242 | ff->mmsh_bytes_pad = 0; | |
243 | } | |
244 | ||
245 | UNLOCK_S; | |
246 | ||
247 | return bytes; | |
248 | } | |
249 | ||
250 | static decode_state ff_decode(void) { | |
251 | int r, len, got_frame; | |
252 | AVPacket pkt_c; | |
253 | s32_t *optr = NULL; | |
254 | ||
255 | if (decode.new_stream) { | |
256 | ||
257 | AVIOContext *avio; | |
258 | AVStream *av_stream; | |
259 | AVCodec *codec; | |
260 | int o; | |
261 | int audio_stream = -1; | |
262 | ||
263 | ff->mmsh_bytes_left = ff->mmsh_bytes_pad = ff->mmsh_packet_len = 0; | |
264 | ||
265 | if (!ff->readbuf) { | |
266 | ff->readbuf = AV(ff, malloc, READ_SIZE + FF_INPUT_BUFFER_PADDING_SIZE); | |
267 | } | |
268 | ||
269 | avio = AVIO(ff, alloc_context, ff->readbuf, READ_SIZE, 0, NULL, _read_data, NULL, NULL); | |
270 | avio->seekable = 0; | |
271 | ||
272 | ff->formatC = AVFORMAT(ff, alloc_context); | |
273 | if (ff->formatC == NULL) { | |
274 | LOG_ERROR("null context"); | |
275 | return DECODE_ERROR; | |
276 | } | |
277 | ||
278 | ff->formatC->pb = avio; | |
279 | ff->formatC->flags |= AVFMT_FLAG_CUSTOM_IO | AVFMT_FLAG_NOPARSE; | |
280 | ||
281 | o = AVFORMAT(ff, open_input, &ff->formatC, "", ff->input_format, NULL); | |
282 | if (o < 0) { | |
283 | LOG_WARN("avformat_open_input: %d %s", o, av__err2str(o)); | |
284 | return DECODE_ERROR; | |
285 | } | |
286 | ||
287 | LOG_INFO("format: name:%s lname:%s", ff->formatC->iformat->name, ff->formatC->iformat->long_name); | |
288 | ||
289 | o = AVFORMAT(ff, find_stream_info, ff->formatC, NULL); | |
290 | if (o < 0) { | |
291 | LOG_WARN("avformat_find_stream_info: %d %s", o, av__err2str(o)); | |
292 | return DECODE_ERROR; | |
293 | } | |
294 | ||
295 | if (ff->wma && ff->wma_playstream < ff->formatC->nb_streams) { | |
296 | if (ff->formatC->streams[ff->wma_playstream]->codec->codec_type == AVMEDIA_TYPE_AUDIO) { | |
297 | LOG_INFO("using wma stream sent from server: %i", ff->wma_playstream); | |
298 | audio_stream = ff->wma_playstream; | |
299 | } | |
300 | } | |
301 | ||
302 | if (audio_stream == -1) { | |
303 | int i; | |
304 | for (i = 0; i < ff->formatC->nb_streams; ++i) { | |
305 | if (ff->formatC->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) { | |
306 | audio_stream = i; | |
307 | LOG_INFO("found stream: %i", i); | |
308 | break; | |
309 | } | |
310 | } | |
311 | } | |
312 | ||
313 | if (audio_stream == -1) { | |
314 | LOG_WARN("no audio stream found"); | |
315 | return DECODE_ERROR; | |
316 | } | |
317 | ||
318 | av_stream = ff->formatC->streams[audio_stream]; | |
319 | ||
320 | ff->codecC = av_stream->codec; | |
321 | ||
322 | codec = AVCODEC(ff, find_decoder, ff->codecC->codec_id); | |
323 | ||
324 | AVCODEC(ff, open2, ff->codecC, codec, NULL); | |
325 | ||
326 | ff->frame = AVCODEC(ff, alloc_frame); | |
327 | ||
328 | ff->avpkt = AV(ff, malloc, sizeof(AVPacket)); | |
329 | if (ff->avpkt == NULL) { | |
330 | LOG_ERROR("can't allocate avpkt"); | |
331 | return DECODE_ERROR; | |
332 | } | |
333 | ||
334 | AV(ff, init_packet, ff->avpkt); | |
335 | ff->avpkt->data = NULL; | |
336 | ff->avpkt->size = 0; | |
337 | ||
338 | LOCK_O; | |
339 | 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; ) | |
342 | output.track_start = outputbuf->writep; | |
343 | if (output.fade_mode) _checkfade(true); | |
344 | decode.new_stream = false; | |
345 | UNLOCK_O; | |
346 | } | |
347 | ||
348 | got_frame = 0; | |
349 | ||
350 | if ((r = AV(ff, read_frame, ff->formatC, ff->avpkt)) < 0) { | |
351 | if (r == AVERROR_EOF) { | |
352 | if (ff->end_of_stream) { | |
353 | LOG_INFO("decode complete"); | |
354 | return DECODE_COMPLETE; | |
355 | } else { | |
356 | LOG_INFO("codec end of file"); | |
357 | } | |
358 | } else { | |
359 | LOG_ERROR("av_read_frame error: %i %s", r, av__err2str(r)); | |
360 | } | |
361 | return DECODE_RUNNING; | |
362 | } | |
363 | ||
364 | // clone packet as we are adjusting it | |
365 | pkt_c = *ff->avpkt; | |
366 | ||
367 | IF_PROCESS( | |
368 | optr = (s32_t *)process.inbuf; | |
369 | process.in_frames = 0; | |
370 | ); | |
371 | ||
372 | while (pkt_c.size > 0 || got_frame) { | |
373 | ||
374 | len = AVCODEC(ff, decode_audio4, ff->codecC, ff->frame, &got_frame, &pkt_c); | |
375 | if (len < 0) { | |
376 | LOG_ERROR("avcodec_decode_audio4 error: %i %s", len, av__err2str(len)); | |
377 | return DECODE_RUNNING; | |
378 | } | |
379 | ||
380 | pkt_c.data += len; | |
381 | pkt_c.size -= len; | |
382 | ||
383 | if (got_frame) { | |
384 | ||
385 | s16_t *iptr16 = (s16_t *)ff->frame->data[0]; | |
386 | s32_t *iptr32 = (s32_t *)ff->frame->data[0]; | |
387 | s16_t *iptr16l = (s16_t *)ff->frame->data[0]; | |
388 | s16_t *iptr16r = (s16_t *)ff->frame->data[1]; | |
389 | s32_t *iptr32l = (s32_t *)ff->frame->data[0]; | |
390 | s32_t *iptr32r = (s32_t *)ff->frame->data[1]; | |
391 | float *iptrfl = (float *)ff->frame->data[0]; | |
392 | float *iptrfr = (float *)ff->frame->data[1]; | |
393 | ||
394 | frames_t frames = ff->frame->nb_samples; | |
395 | ||
396 | LOG_SDEBUG("got audio channels: %u samples: %u format: %u", ff->codecC->channels, ff->frame->nb_samples, | |
397 | ff->codecC->sample_fmt); | |
398 | ||
399 | LOCK_O_direct; | |
400 | ||
401 | while (frames > 0) { | |
402 | frames_t count; | |
403 | frames_t f; | |
404 | ||
405 | IF_DIRECT( | |
406 | optr = (s32_t *)outputbuf->writep; | |
407 | f = min(_buf_space(outputbuf), _buf_cont_write(outputbuf)) / BYTES_PER_FRAME; | |
408 | f = min(f, frames); | |
409 | ); | |
410 | ||
411 | IF_PROCESS( | |
412 | if (process.in_frames + frames > process.max_in_frames) { | |
413 | LOG_WARN("exceeded process buffer size - dropping frames"); | |
414 | break; | |
415 | } | |
416 | f = frames; | |
417 | ); | |
418 | ||
419 | count = f; | |
420 | ||
421 | if (ff->codecC->channels == 2) { | |
422 | if (ff->codecC->sample_fmt == AV_SAMPLE_FMT_S16) { | |
423 | while (count--) { | |
424 | *optr++ = *iptr16++ << 16; | |
425 | *optr++ = *iptr16++ << 16; | |
426 | } | |
427 | } else if (ff->codecC->sample_fmt == AV_SAMPLE_FMT_S32) { | |
428 | while (count--) { | |
429 | *optr++ = *iptr32++; | |
430 | *optr++ = *iptr32++; | |
431 | } | |
432 | } else if (ff->codecC->sample_fmt == AV_SAMPLE_FMT_S16P) { | |
433 | while (count--) { | |
434 | *optr++ = *iptr16l++ << 16; | |
435 | *optr++ = *iptr16r++ << 16; | |
436 | } | |
437 | } else if (ff->codecC->sample_fmt == AV_SAMPLE_FMT_S32P) { | |
438 | while (count--) { | |
439 | *optr++ = *iptr32l++; | |
440 | *optr++ = *iptr32r++; | |
441 | } | |
442 | } else if (ff->codecC->sample_fmt == AV_SAMPLE_FMT_FLTP) { | |
443 | while (count--) { | |
444 | double scaledl = *iptrfl++ * 0x7fffffff; | |
445 | double scaledr = *iptrfr++ * 0x7fffffff; | |
446 | if (scaledl > 2147483647.0) scaledl = 2147483647.0; | |
447 | if (scaledl < -2147483648.0) scaledl = -2147483648.0; | |
448 | if (scaledr > 2147483647.0) scaledr = 2147483647.0; | |
449 | if (scaledr < -2147483648.0) scaledr = -2147483648.0; | |
450 | *optr++ = (s32_t)scaledl; | |
451 | *optr++ = (s32_t)scaledr; | |
452 | } | |
453 | } else { | |
454 | LOG_WARN("unsupported sample format: %u", ff->codecC->sample_fmt); | |
455 | } | |
456 | } else if (ff->codecC->channels == 1) { | |
457 | if (ff->codecC->sample_fmt == AV_SAMPLE_FMT_S16) { | |
458 | while (count--) { | |
459 | *optr++ = *iptr16 << 16; | |
460 | *optr++ = *iptr16++ << 16; | |
461 | } | |
462 | } else if (ff->codecC->sample_fmt == AV_SAMPLE_FMT_S32) { | |
463 | while (count--) { | |
464 | *optr++ = *iptr32; | |
465 | *optr++ = *iptr32++; | |
466 | } | |
467 | } else if (ff->codecC->sample_fmt == AV_SAMPLE_FMT_S16P) { | |
468 | while (count--) { | |
469 | *optr++ = *iptr16l << 16; | |
470 | *optr++ = *iptr16l++ << 16; | |
471 | } | |
472 | } else if (ff->codecC->sample_fmt == AV_SAMPLE_FMT_S32P) { | |
473 | while (count--) { | |
474 | *optr++ = *iptr32l; | |
475 | *optr++ = *iptr32l++; | |
476 | } | |
477 | } else if (ff->codecC->sample_fmt == AV_SAMPLE_FMT_FLTP) { | |
478 | while (count--) { | |
479 | double scaled = *iptrfl++ * 0x7fffffff; | |
480 | if (scaled > 2147483647.0) scaled = 2147483647.0; | |
481 | if (scaled < -2147483648.0) scaled = -2147483648.0; | |
482 | *optr++ = (s32_t)scaled; | |
483 | *optr++ = (s32_t)scaled; | |
484 | } | |
485 | } else { | |
486 | LOG_WARN("unsupported sample format: %u", ff->codecC->sample_fmt); | |
487 | } | |
488 | } else { | |
489 | LOG_WARN("unsupported number of channels"); | |
490 | } | |
491 | ||
492 | frames -= f; | |
493 | ||
494 | IF_DIRECT( | |
495 | _buf_inc_writep(outputbuf, f * BYTES_PER_FRAME); | |
496 | ); | |
497 | ||
498 | IF_PROCESS( | |
499 | process.in_frames += f; | |
500 | ); | |
501 | } | |
502 | ||
503 | UNLOCK_O_direct; | |
504 | } | |
505 | } | |
506 | ||
507 | AV(ff, free_packet, ff->avpkt); | |
508 | ||
509 | return DECODE_RUNNING; | |
510 | } | |
511 | ||
512 | static void _free_ff_data(void) { | |
513 | if (ff->formatC) { | |
514 | if (ff->formatC->pb) AV(ff, freep, &ff->formatC->pb); | |
515 | AVFORMAT(ff, free_context, ff->formatC); | |
516 | ff->formatC = NULL; | |
517 | } | |
518 | ||
519 | if (ff->frame) { | |
520 | // ffmpeg version dependant free function | |
521 | #if !LINKALL | |
522 | ff->avcodec_free_frame ? AVCODEC(ff, free_frame, &ff->frame) : AV(ff, freep, &ff->frame); | |
523 | #elif LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54,28,0) | |
524 | AVCODEC(ff, free_frame, &ff->frame); | |
525 | #else | |
526 | AV(ff, freep, &ff->frame); | |
527 | #endif | |
528 | ff->frame = NULL; | |
529 | } | |
530 | ||
531 | if (ff->avpkt) { | |
532 | AV(ff, free_packet, ff->avpkt); | |
533 | AV(ff, freep, &ff->avpkt); | |
534 | ff->avpkt = NULL; | |
535 | } | |
536 | } | |
537 | ||
538 | static void ff_open_wma(u8_t size, u8_t rate, u8_t chan, u8_t endianness) { | |
539 | _free_ff_data(); | |
540 | ||
541 | ff->input_format = AV(ff, find_input_format, "asf"); | |
542 | if (ff->input_format == NULL) { | |
543 | LOG_ERROR("asf format not supported by ffmpeg library"); | |
544 | } | |
545 | ||
546 | ff->wma = true; | |
547 | ff->wma_mmsh = size - '0'; | |
548 | ff->wma_playstream = rate - 1; | |
549 | ff->wma_metadatastream = chan != '?' ? chan : 0; | |
550 | ||
551 | LOG_INFO("open wma chunking: %u playstream: %u metadatastream: %u", ff->wma_mmsh, ff->wma_playstream, ff->wma_metadatastream); | |
552 | } | |
553 | ||
554 | static void ff_open_alac(u8_t size, u8_t rate, u8_t chan, u8_t endianness) { | |
555 | _free_ff_data(); | |
556 | ||
557 | ff->input_format = AV(ff, find_input_format, "mp4"); | |
558 | if (ff->input_format == NULL) { | |
559 | LOG_ERROR("mp4 format not supported by ffmpeg library"); | |
560 | } | |
561 | ||
562 | ff->wma = false; | |
563 | ff->wma_mmsh = 0; | |
564 | ||
565 | LOG_INFO("open alac"); | |
566 | } | |
567 | ||
568 | static void ff_close(void) { | |
569 | _free_ff_data(); | |
570 | ||
571 | if (ff->readbuf) { | |
572 | AV(ff, freep, &ff->readbuf); | |
573 | ff->readbuf = NULL; | |
574 | } | |
575 | } | |
576 | ||
577 | static bool load_ff() { | |
578 | #if !LINKALL | |
579 | void *handle_codec = NULL, *handle_format = NULL, *handle_util = NULL; | |
580 | char name[30]; | |
581 | char *err; | |
582 | ||
583 | // we try to load the ffmpeg library version which matches the header file we are compiled with as structs differ between versions | |
584 | ||
585 | sprintf(name, LIBAVCODEC, LIBAVCODEC_VERSION_MAJOR); | |
586 | handle_codec = dlopen(name, RTLD_NOW); | |
587 | if (!handle_codec) { | |
588 | LOG_INFO("dlerror: %s", dlerror()); | |
589 | return false; | |
590 | } | |
591 | ||
592 | sprintf(name, LIBAVFORMAT, LIBAVFORMAT_VERSION_MAJOR); | |
593 | handle_format = dlopen(name, RTLD_NOW); | |
594 | if (!handle_format) { | |
595 | LOG_INFO("dlerror: %s", dlerror()); | |
596 | return false; | |
597 | } | |
598 | ||
599 | sprintf(name, LIBAVUTIL, LIBAVUTIL_VERSION_MAJOR); | |
600 | handle_util = dlopen(name, RTLD_NOW); | |
601 | if (!handle_util) { | |
602 | LOG_INFO("dlerror: %s", dlerror()); | |
603 | return false; | |
604 | } | |
605 | ||
606 | ff->avcodec_version = dlsym(handle_codec, "avcodec_version"); | |
607 | ff->avcodec_find_decoder = dlsym(handle_codec, "avcodec_find_decoder"); | |
608 | ff->avcodec_open2 = dlsym(handle_codec, "avcodec_open2"); | |
609 | ff->avcodec_alloc_frame = dlsym(handle_codec, "avcodec_alloc_frame"); | |
610 | ff->avcodec_free_frame = dlsym(handle_codec, "avcodec_free_frame"); | |
611 | ff->avcodec_decode_audio4 = dlsym(handle_codec, "avcodec_decode_audio4"); | |
612 | ff->av_init_packet = dlsym(handle_codec, "av_init_packet"); | |
613 | ff->av_free_packet = dlsym(handle_codec, "av_free_packet"); | |
614 | ||
615 | if ((err = dlerror()) != NULL) { | |
616 | LOG_INFO("dlerror: %s", err); | |
617 | return false; | |
618 | } | |
619 | ||
620 | LOG_INFO("loaded "LIBAVCODEC" (%u.%u.%u)", LIBAVCODEC_VERSION_MAJOR, ff->avcodec_version() >> 16, (ff->avcodec_version() >> 8) & 0xff, ff->avcodec_version() & 0xff); | |
621 | ||
622 | ff->avformat_version = dlsym(handle_format, "avformat_version"); | |
623 | ff->avformat_alloc_context = dlsym(handle_format, "avformat_alloc_context"); | |
624 | ff->avformat_free_context = dlsym(handle_format, "avformat_free_context"); | |
625 | ff->avformat_open_input = dlsym(handle_format, "avformat_open_input"); | |
626 | ff->avformat_find_stream_info = dlsym(handle_format, "avformat_find_stream_info"); | |
627 | ff->avio_alloc_context = dlsym(handle_format, "avio_alloc_context"); | |
628 | ff->av_read_frame = dlsym(handle_format, "av_read_frame"); | |
629 | ff->av_find_input_format= dlsym(handle_format, "av_find_input_format"); | |
630 | ff->av_register_all = dlsym(handle_format, "av_register_all"); | |
631 | ||
632 | if ((err = dlerror()) != NULL) { | |
633 | LOG_INFO("dlerror: %s", err); | |
634 | return false; | |
635 | } | |
636 | ||
637 | LOG_INFO("loaded "LIBAVFORMAT" (%u.%u.%u)", LIBAVFORMAT_VERSION_MAJOR, ff->avformat_version() >> 16, (ff->avformat_version() >> 8) & 0xff, ff->avformat_version() & 0xff); | |
638 | ||
639 | ff->avutil_version = dlsym(handle_util, "avutil_version"); | |
640 | ff->av_log_set_callback = dlsym(handle_util, "av_log_set_callback"); | |
641 | ff->av_log_set_level = dlsym(handle_util, "av_log_set_level"); | |
642 | ff->av_strerror = dlsym(handle_util, "av_strerror"); | |
643 | ff->av_malloc = dlsym(handle_util, "av_malloc"); | |
644 | ff->av_freep = dlsym(handle_util, "av_freep"); | |
645 | ||
646 | if ((err = dlerror()) != NULL) { | |
647 | LOG_INFO("dlerror: %s", err); | |
648 | return false; | |
649 | } | |
650 | ||
651 | LOG_INFO("loaded "LIBAVUTIL" (%u.%u.%u)", LIBAVUTIL_VERSION_MAJOR, ff->avutil_version() >> 16, (ff->avutil_version() >> 8) & 0xff, ff->avutil_version() & 0xff); | |
652 | ||
653 | #endif | |
654 | ||
655 | return true; | |
656 | } | |
657 | ||
658 | static int ff_log_level = 0; | |
659 | ||
660 | void av_err_callback(void *avcl, int level, const char *fmt, va_list vl) { | |
661 | if (level > ff_log_level) return; | |
662 | fprintf(stderr, "%s ffmpeg: ", logtime()); | |
663 | vfprintf(stderr, fmt, vl); | |
664 | fflush(stderr); | |
665 | } | |
666 | ||
667 | static bool registered = false; | |
668 | ||
669 | struct codec *register_ff(const char *codec) { | |
670 | if (!registered) { | |
671 | ||
672 | ff = malloc(sizeof(struct ff_s)); | |
673 | if (!ff) { | |
674 | return NULL; | |
675 | } | |
676 | ||
677 | memset(ff, 0, sizeof(struct ff_s)); | |
678 | ||
679 | if (!load_ff()) { | |
680 | return NULL; | |
681 | } | |
682 | ||
683 | switch (loglevel) { | |
684 | case lERROR: | |
685 | ff_log_level = AV_LOG_ERROR; break; | |
686 | case lWARN: | |
687 | ff_log_level = AV_LOG_WARNING; break; | |
688 | case lINFO: | |
689 | ff_log_level = AV_LOG_INFO; break; | |
690 | case lDEBUG: | |
691 | ff_log_level = AV_LOG_VERBOSE; break; | |
692 | default: break; | |
693 | } | |
694 | ||
695 | AV(ff, log_set_callback, av_err_callback); | |
696 | ||
697 | AV(ff, register_all); | |
698 | ||
699 | registered = true; | |
700 | } | |
701 | ||
702 | if (!strcmp(codec, "wma")) { | |
703 | ||
704 | static struct codec ret = { | |
705 | 'w', // id | |
706 | "wma,wmap,wmal", // types | |
707 | READ_SIZE, // min read | |
708 | WRITE_SIZE, // min space | |
709 | ff_open_wma, // open | |
710 | ff_close, // close | |
711 | ff_decode, // decode | |
712 | }; | |
713 | ||
714 | LOG_INFO("using ffmpeg to decode wma,wmap,wmal"); | |
715 | return &ret; | |
716 | } | |
717 | ||
718 | if (!strcmp(codec, "alc")) { | |
719 | ||
720 | static struct codec ret = { | |
721 | 'l', // id | |
722 | "alc", // types | |
723 | READ_SIZE, // min read | |
724 | WRITE_SIZE, // min space | |
725 | ff_open_alac,// open | |
726 | ff_close, // close | |
727 | ff_decode, // decode | |
728 | }; | |
729 | ||
730 | LOG_INFO("using ffmpeg to decode alc"); | |
731 | return &ret; | |
732 | } | |
733 |