Merge tag 'upstream/1.5' into develop
Chris Boot
10 years ago
41 | 41 | Minor changes |
42 | 42 | - support of compile time linking for distro packaging, uses -DLINKALL option |
43 | 43 | |
44 | Version 1.4 (beta) | |
45 | ================== | |
44 | Version 1.4 28/12/13 | |
45 | ==================== | |
46 | 46 | |
47 | 47 | Features |
48 | 48 | - native support of dsd playback to dop capable dac or via conversion to pcm and resampling |
54 | 54 | - fix problem with libmpg123 playback not playing to end of track |
55 | 55 | - add ablity for player name change to be stored locally in a file (to emulate hardware where name is stored on player) |
56 | 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 readablity | |
65 |
0 | 0 | Squeezelite - lightweight headless squeezebox emulator |
1 | 1 | |
2 | (c) Adrian Smith 2012, 2013, triode1@btinternet.com | |
2 | (c) Adrian Smith 2012-2014, triode1@btinternet.com | |
3 | 3 | |
4 | 4 | Released under GPLv3 license: |
5 | 5 |
0 | 0 | /* |
1 | 1 | * Squeezelite - lightweight headless squeezebox emulator |
2 | 2 | * |
3 | * (c) Adrian Smith 2012, 2013, triode1@btinternet.com | |
3 | * (c) Adrian Smith 2012-2014, triode1@btinternet.com | |
4 | 4 | * |
5 | 5 | * This program is free software: you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
0 | 0 | /* |
1 | 1 | * Squeezelite - lightweight headless squeezebox emulator |
2 | 2 | * |
3 | * (c) Adrian Smith 2012, 2013, triode1@btinternet.com | |
3 | * (c) Adrian Smith 2012-2014, triode1@btinternet.com | |
4 | 4 | * |
5 | 5 | * This program is free software: you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
80 | 80 | } |
81 | 81 | } |
82 | 82 | |
83 | void dop_init(bool enable) { | |
83 | void dop_init(bool enable, unsigned delay) { | |
84 | 84 | LOCK_O; |
85 | 85 | output.has_dop = enable; |
86 | output.dop_delay = delay; | |
86 | 87 | UNLOCK_O; |
87 | 88 | } |
88 | 89 |
0 | 0 | /* |
1 | 1 | * Squeezelite - lightweight headless squeezebox emulator |
2 | 2 | * |
3 | * (c) Adrian Smith 2012, 2013, triode1@btinternet.com | |
3 | * (c) Adrian Smith 2012-2014, triode1@btinternet.com | |
4 | 4 | * |
5 | 5 | * This program is free software: you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
214 | 214 | unsigned bytes_per_frame = dop ? 2 : 1; |
215 | 215 | |
216 | 216 | if (bytes < d->block_size * d->channels) { |
217 | LOG_WARN("stream too short"); | |
218 | return DECODE_ERROR; | |
217 | LOG_INFO("stream too short"); // this can occur when scanning the track | |
218 | return DECODE_COMPLETE; | |
219 | 219 | } |
220 | 220 | |
221 | 221 | IF_PROCESS( |
248 | 248 | |
249 | 249 | frames = min(bytes, d->sample_bytes) / bytes_per_frame; |
250 | 250 | if (frames == 0) { |
251 | // /2 for dop should never result in 0 as header len is always even | |
252 | LOG_WARN("frames got to zero"); | |
253 | return DECODE_ERROR; | |
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 | } | |
254 | 260 | } |
255 | 261 | |
256 | 262 | frames = min(frames, out); |
0 | 0 | /* |
1 | 1 | * Squeezelite - lightweight headless squeezebox emulator |
2 | 2 | * |
3 | * (c) Adrian Smith 2012, 2013, triode1@btinternet.com | |
3 | * (c) Adrian Smith 2012-2014, triode1@btinternet.com | |
4 | 4 | * |
5 | 5 | * This program is free software: you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
0 | 0 | /* |
1 | 1 | * Squeezelite - lightweight headless squeezebox emulator |
2 | 2 | * |
3 | * (c) Adrian Smith 2012, 2013, triode1@btinternet.com | |
3 | * (c) Adrian Smith 2012-2014, triode1@btinternet.com | |
4 | 4 | * |
5 | 5 | * This program is free software: you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
0 | 0 | /* |
1 | 1 | * Squeezelite - lightweight headless squeezebox emulator |
2 | 2 | * |
3 | * (c) Adrian Smith 2012, 2013, triode1@btinternet.com | |
3 | * (c) Adrian Smith 2012-2014, triode1@btinternet.com | |
4 | 4 | * |
5 | 5 | * This program is free software: you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
0 | 0 | /* |
1 | 1 | * Squeezelite - lightweight headless squeezebox emulator |
2 | 2 | * |
3 | * (c) Adrian Smith 2012, 2013, triode1@btinternet.com | |
3 | * (c) Adrian Smith 2012-2014, triode1@btinternet.com | |
4 | 4 | * |
5 | 5 | * This program is free software: you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
21 | 21 | |
22 | 22 | #include <signal.h> |
23 | 23 | |
24 | #define TITLE "Squeezelite " VERSION ", Copyright 2012, 2013 Adrian Smith." | |
24 | #define TITLE "Squeezelite " VERSION ", Copyright 2012-2014 Adrian Smith." | |
25 | 25 | |
26 | 26 | static void usage(const char *argv0) { |
27 | 27 | printf(TITLE " See -t for license terms\n" |
67 | 67 | " \t\t\t phase_response = 0-100 (0 = minimum / 50 = linear / 100 = maximum)\n" |
68 | 68 | #endif |
69 | 69 | #if DSD |
70 | " -D\t\t\tOutput device supports DSD over PCM (DoP)\n" | |
70 | " -D [delay]\t\tOutput device supports DSD over PCM (DoP), delay = optional delay switching between PCM and DoP in ms\n" | |
71 | 71 | #endif |
72 | 72 | #if VISEXPORT |
73 | 73 | " -v \t\t\tVisulizer support\n" |
168 | 168 | #endif |
169 | 169 | #if DSD |
170 | 170 | bool dop = false; |
171 | unsigned dop_delay = 0; | |
171 | 172 | #endif |
172 | 173 | #if VISEXPORT |
173 | 174 | bool visexport = false; |
330 | 331 | #if DSD |
331 | 332 | case 'D': |
332 | 333 | dop = true; |
334 | if (optind < argc && argv[optind] && argv[optind][0] != '-') { | |
335 | dop_delay = atoi(argv[optind++]); | |
336 | } | |
333 | 337 | break; |
334 | 338 | #endif |
335 | 339 | #if VISEXPORT |
349 | 353 | break; |
350 | 354 | } |
351 | 355 | } |
356 | ||
357 | // warn if command line includes something which isn't parsed | |
358 | if (optind < argc) { | |
359 | usage(argv[0]); | |
360 | exit(0); | |
361 | } | |
352 | 362 | |
353 | 363 | signal(SIGINT, sighandler); |
354 | 364 | signal(SIGTERM, sighandler); |
405 | 415 | } |
406 | 416 | |
407 | 417 | #if DSD |
408 | dop_init(dop); | |
418 | dop_init(dop, dop_delay); | |
409 | 419 | #endif |
410 | 420 | |
411 | 421 | #if VISEXPORT |
0 | 0 | /* |
1 | 1 | * Squeezelite - lightweight headless squeezebox emulator |
2 | 2 | * |
3 | * (c) Adrian Smith 2012, 2013, triode1@btinternet.com | |
3 | * (c) Adrian Smith 2012-2014, triode1@btinternet.com | |
4 | 4 | * |
5 | 5 | * This program is free software: you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
0 | 0 | /* |
1 | 1 | * Squeezelite - lightweight headless squeezebox emulator |
2 | 2 | * |
3 | * (c) Adrian Smith 2012, 2013, triode1@btinternet.com | |
3 | * (c) Adrian Smith 2012-2014, triode1@btinternet.com | |
4 | 4 | * |
5 | 5 | * This program is free software: you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
118 | 118 | |
119 | 119 | if (output.track_start && !silence) { |
120 | 120 | if (output.track_start == outputbuf->readp) { |
121 | frames -= size; | |
122 | IF_DSD( | |
123 | if (output.dop != output.next_dop) { | |
124 | if (output.dop_delay) { | |
125 | // add silence delay in two halves, before and after track start and pcm-dop change | |
126 | if (!output.dop_delay_active) { | |
127 | output.pause_frames = output.current_sample_rate * output.dop_delay / 2000; | |
128 | output.dop_delay_active = true; // first delay - don't process track start | |
129 | break; | |
130 | } else { | |
131 | output.pause_frames = output.next_sample_rate * output.dop_delay / 2000; | |
132 | output.dop_delay_active = false; // second delay - process track start | |
133 | } | |
134 | output.state = OUTPUT_PAUSE_FRAMES; | |
135 | } | |
136 | } | |
137 | output.dop = output.next_dop; | |
138 | ) | |
121 | 139 | LOG_INFO("track start sample rate: %u replay_gain: %u", output.next_sample_rate, output.next_replay_gain); |
122 | 140 | output.frames_played = 0; |
123 | 141 | output.track_started = true; |
124 | 142 | output.current_sample_rate = output.next_sample_rate; |
125 | IF_DSD( output.dop = output.next_dop; ) | |
126 | 143 | if (!output.fade == FADE_ACTIVE || !output.fade_mode == FADE_CROSSFADE) { |
127 | 144 | output.current_replay_gain = output.next_replay_gain; |
128 | 145 | } |
129 | 146 | output.track_start = NULL; |
130 | continue; | |
147 | break; | |
131 | 148 | } else if (output.track_start > outputbuf->readp) { |
132 | 149 | // reduce cont_frames so we find the next track start at beginning of next chunk |
133 | 150 | cont_frames = min(cont_frames, (output.track_start - outputbuf->readp) / BYTES_PER_FRAME); |
223 | 240 | |
224 | 241 | wrote = output.write_cb(out_frames, silence, gainL, gainR, cross_gain_in, cross_gain_out, &cross_ptr); |
225 | 242 | |
226 | if (wrote < 0) { | |
227 | LOG_WARN("error in write cb"); | |
228 | frames -= out_frames; | |
243 | if (wrote <= 0) { | |
244 | frames -= size; | |
229 | 245 | break; |
230 | 246 | } else { |
231 | 247 | out_frames = (frames_t)wrote; |
396 | 412 | if (output.error_opening) { |
397 | 413 | output.current_sample_rate = output.default_sample_rate; |
398 | 414 | } |
415 | IF_DSD( output.dop_delay_active = false; ) | |
399 | 416 | } |
400 | 417 | output.frames_played = 0; |
401 | 418 | UNLOCK; |
0 | 0 | /* |
1 | 1 | * Squeezelite - lightweight headless squeezebox emulator |
2 | 2 | * |
3 | * (c) Adrian Smith 2012, 2013, triode1@btinternet.com | |
3 | * (c) Adrian Smith 2012-2014, triode1@btinternet.com | |
4 | 4 | * |
5 | 5 | * This program is free software: you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
531 | 531 | continue; |
532 | 532 | } |
533 | 533 | LOG_INFO("start error: %s", snd_strerror(err)); |
534 | usleep(10000); | |
534 | 535 | } |
535 | 536 | } else { |
536 | 537 | start = false; |
578 | 579 | // EPIPE indicates underrun - attempt to recover |
579 | 580 | UNLOCK; |
580 | 581 | continue; |
582 | } else if (err == -EIO) { | |
583 | // EIO can occur with non existant pulse server | |
584 | UNLOCK; | |
585 | LOG_SDEBUG("snd_pcm_delay returns: EIO - sleeping"); | |
586 | usleep(100000); | |
587 | continue; | |
581 | 588 | } else { |
582 | 589 | LOG_DEBUG("snd_pcm_delay returns: %d", err); |
583 | 590 | } |
587 | 594 | } |
588 | 595 | |
589 | 596 | // process frames |
590 | _output_frames(avail); | |
597 | frames_t wrote = _output_frames(avail); | |
591 | 598 | |
592 | 599 | UNLOCK; |
600 | ||
601 | // some output devices such as alsa null refuse any data, avoid spinning | |
602 | if (!wrote) { | |
603 | LOG_SDEBUG("wrote 0 - sleeping"); | |
604 | usleep(10000); | |
605 | } | |
593 | 606 | } |
594 | 607 | |
595 | 608 | return 0; |
0 | 0 | /* |
1 | 1 | * Squeezelite - lightweight headless squeezebox emulator |
2 | 2 | * |
3 | * (c) Adrian Smith 2012, 2013, triode1@btinternet.com | |
3 | * (c) Adrian Smith 2012-2014, triode1@btinternet.com | |
4 | 4 | * |
5 | 5 | * This program is free software: you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
57 | 57 | LOG_WARN("error initialising port audio: %s", Pa_GetErrorText(err)); |
58 | 58 | return; |
59 | 59 | } |
60 | ||
60 | ||
61 | 61 | printf("Output devices:\n"); |
62 | 62 | for (i = 0; i < Pa_GetDeviceCount(); ++i) { |
63 | printf(" %i - %s [%s]\n", i, Pa_GetDeviceInfo(i)->name, Pa_GetHostApiInfo(Pa_GetDeviceInfo(i)->hostApi)->name); | |
63 | if (Pa_GetDeviceInfo(i)->maxOutputChannels) { | |
64 | printf(" %i - %s [%s]\n", i, Pa_GetDeviceInfo(i)->name, Pa_GetHostApiInfo(Pa_GetDeviceInfo(i)->hostApi)->name); | |
65 | } | |
64 | 66 | } |
65 | 67 | printf("\n"); |
66 | ||
68 | ||
67 | 69 | if ((err = Pa_Terminate()) != paNoError) { |
68 | 70 | LOG_WARN("error closing port audio: %s", Pa_GetErrorText(err)); |
69 | 71 | } |
327 | 329 | static int pa_callback(const void *pa_input, void *pa_output, unsigned long pa_frames_wanted, |
328 | 330 | const PaStreamCallbackTimeInfo *time_info, PaStreamCallbackFlags statusFlags, void *userData) { |
329 | 331 | int ret; |
332 | double stream_time; | |
330 | 333 | frames_t frames; |
331 | 334 | |
332 | 335 | optr = (u8_t *)pa_output; |
333 | 336 | |
334 | 337 | LOCK; |
335 | 338 | |
336 | output.device_frames = (unsigned)((time_info->outputBufferDacTime - Pa_GetStreamTime(pa.stream)) * output.current_sample_rate); | |
339 | stream_time = Pa_GetStreamTime(pa.stream); | |
340 | ||
341 | if (time_info->outputBufferDacTime > stream_time) { | |
342 | // workaround for wdm-ks which can return outputBufferDacTime with a different epoch | |
343 | output.device_frames = (unsigned)((time_info->outputBufferDacTime - stream_time) * output.current_sample_rate); | |
344 | } else { | |
345 | output.device_frames = 0; | |
346 | } | |
347 | ||
337 | 348 | output.updated = gettime_ms(); |
338 | 349 | |
339 | 350 | frames = _output_frames(pa_frames_wanted); |
0 | 0 | /* |
1 | 1 | * Squeezelite - lightweight headless squeezebox emulator |
2 | 2 | * |
3 | * (c) Adrian Smith 2012, 2013, triode1@btinternet.com | |
3 | * (c) Adrian Smith 2012-2014, triode1@btinternet.com | |
4 | 4 | * |
5 | 5 | * This program is free software: you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
0 | 0 | /* |
1 | 1 | * Squeezelite - lightweight headless squeezebox emulator |
2 | 2 | * |
3 | * (c) Adrian Smith 2012, 2013, triode1@btinternet.com | |
3 | * (c) Adrian Smith 2012-2014, triode1@btinternet.com | |
4 | 4 | * |
5 | 5 | * This program is free software: you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
0 | 0 | /* |
1 | 1 | * Squeezelite - lightweight headless squeezebox emulator |
2 | 2 | * |
3 | * (c) Adrian Smith 2012, 2013, triode1@btinternet.com | |
3 | * (c) Adrian Smith 2012-2014, triode1@btinternet.com | |
4 | 4 | * |
5 | 5 | * This program is free software: you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
23 | 23 | |
24 | 24 | #if VISEXPORT |
25 | 25 | |
26 | #include <sys/stat.h> | |
26 | 27 | #include <sys/mman.h> |
27 | 28 | #include <fcntl.h> |
28 | 29 | |
112 | 113 | |
113 | 114 | sprintf(vis_shm_path, "/squeezelite-%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); |
114 | 115 | |
116 | mode_t old_mask = umask(000); // allow any user to read our shm when created | |
117 | ||
115 | 118 | vis_fd = shm_open(vis_shm_path, O_CREAT | O_RDWR, 0666); |
116 | 119 | if (vis_fd != -1) { |
117 | 120 | if (ftruncate(vis_fd, sizeof(struct vis_t)) == 0) { |
133 | 136 | LOG_WARN("unable to open visualizer shared memory"); |
134 | 137 | vis_mmap = NULL; |
135 | 138 | } |
139 | ||
140 | umask(old_mask); | |
136 | 141 | } |
137 | 142 | |
138 | 143 | #endif // VISEXPORT |
0 | 0 | /* |
1 | 1 | * Squeezelite - lightweight headless squeezebox emulator |
2 | 2 | * |
3 | * (c) Adrian Smith 2012, 2013, triode1@btinternet.com | |
3 | * (c) Adrian Smith 2012-2014, triode1@btinternet.com | |
4 | 4 | * |
5 | 5 | * This program is free software: you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
0 | 0 | /* |
1 | 1 | * Squeezelite - lightweight headless squeezebox emulator |
2 | 2 | * |
3 | * (c) Adrian Smith 2012, 2013, triode1@btinternet.com | |
3 | * (c) Adrian Smith 2012-2014, triode1@btinternet.com | |
4 | 4 | * |
5 | 5 | * This program is free software: you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
0 | 0 | /* |
1 | 1 | * Squeezelite - lightweight headless squeezebox emulator |
2 | 2 | * |
3 | * (c) Adrian Smith 2012, 2013, triode1@btinternet.com | |
3 | * (c) Adrian Smith 2012-2014, triode1@btinternet.com | |
4 | 4 | * |
5 | 5 | * This program is free software: you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
0 | 0 | /* |
1 | 1 | * Squeezelite - lightweight headless squeezebox emulator |
2 | 2 | * |
3 | * (c) Adrian Smith 2012, 2013, triode1@btinternet.com | |
3 | * (c) Adrian Smith 2012-2014, triode1@btinternet.com | |
4 | 4 | * |
5 | 5 | * This program is free software: you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
115 | 115 | |
116 | 116 | LOG_INFO("mac: %02x:%02x:%02x:%02x:%02x:%02x", pkt.mac[0], pkt.mac[1], pkt.mac[2], pkt.mac[3], pkt.mac[4], pkt.mac[5]); |
117 | 117 | |
118 | LOG_DEBUG("cap: %s%s%s", base_cap, fixed_cap, var_cap); | |
118 | LOG_INFO("cap: %s%s%s", base_cap, fixed_cap, var_cap); | |
119 | 119 | |
120 | 120 | send_packet((u8_t *)&pkt, sizeof(pkt)); |
121 | 121 | send_packet((u8_t *)base_cap, strlen(base_cap)); |
131 | 131 | if (status.current_sample_rate && status.frames_played && status.frames_played > status.device_frames) { |
132 | 132 | ms_played = (u32_t)(((u64_t)(status.frames_played - status.device_frames) * (u64_t)1000) / (u64_t)status.current_sample_rate); |
133 | 133 | if (now > status.updated) ms_played += (now - status.updated); |
134 | LOG_SDEBUG("ms_played: %u (frames_played: %u device_frames: %u)", ms_played, status.frames_played, status.device_frames); | |
135 | } else if (status.frames_played && now > status.stream_start) { | |
136 | ms_played = now - status.stream_start; | |
137 | LOG_SDEBUG("ms_played: %u using elapsed time (frames_played: %u device_frames: %u)", ms_played, status.frames_played, status.device_frames); | |
134 | 138 | } else { |
139 | LOG_SDEBUG("ms_played: 0"); | |
135 | 140 | ms_played = 0; |
136 | 141 | } |
137 | 142 | |
155 | 160 | pkt.server_timestamp = server_timestamp; // keep this is server format - don't unpack/pack |
156 | 161 | // error_code; |
157 | 162 | |
158 | LOG_INFO("STAT: %s", event); | |
163 | LOG_DEBUG("STAT: %s", event); | |
159 | 164 | |
160 | 165 | if (loglevel == lSDEBUG) { |
161 | LOG_SDEBUG("received bytesL: %u streambuf: %u outputbuf: %u calc elapsed: %u real elapsed: %u (diff: %u) device: %u delay: %d", | |
166 | LOG_SDEBUG("received bytesL: %u streambuf: %u outputbuf: %u calc elapsed: %u real elapsed: %u (diff: %d) device: %u delay: %d", | |
162 | 167 | (u32_t)status.stream_bytes, status.stream_full, status.output_full, ms_played, now - status.stream_start, |
163 | 168 | ms_played - now + status.stream_start, status.device_frames * 1000 / status.current_sample_rate, now - status.updated); |
164 | 169 | } |
174 | 179 | pkt.length = htonl(sizeof(pkt) - 8); |
175 | 180 | pkt.reason = disconnect & 0xFF; |
176 | 181 | |
177 | LOG_INFO("DSCO: %d", disconnect); | |
182 | LOG_DEBUG("DSCO: %d", disconnect); | |
178 | 183 | |
179 | 184 | send_packet((u8_t *)&pkt, sizeof(pkt)); |
180 | 185 | } |
186 | 191 | memcpy(&pkt_header.opcode, "RESP", 4); |
187 | 192 | pkt_header.length = htonl(sizeof(pkt_header) + len - 8); |
188 | 193 | |
189 | LOG_INFO("RESP"); | |
194 | LOG_DEBUG("RESP"); | |
190 | 195 | |
191 | 196 | send_packet((u8_t *)&pkt_header, sizeof(pkt_header)); |
192 | 197 | send_packet((u8_t *)header, len); |
199 | 204 | memcpy(&pkt_header.opcode, "META", 4); |
200 | 205 | pkt_header.length = htonl(sizeof(pkt_header) + len - 8); |
201 | 206 | |
202 | LOG_INFO("META"); | |
207 | LOG_DEBUG("META"); | |
203 | 208 | |
204 | 209 | send_packet((u8_t *)&pkt_header, sizeof(pkt_header)); |
205 | 210 | send_packet((u8_t *)meta, len); |
214 | 219 | pkt_header.id = 0; // id 0 is playername S:P:Squeezebox2 |
215 | 220 | pkt_header.length = htonl(sizeof(pkt_header) + strlen(name) + 1 - 8); |
216 | 221 | |
217 | LOG_INFO("set playername: %s", name); | |
222 | LOG_DEBUG("set playername: %s", name); | |
218 | 223 | |
219 | 224 | send_packet((u8_t *)&pkt_header, sizeof(pkt_header)); |
220 | 225 | send_packet((u8_t *)name, strlen(name) + 1); |
223 | 228 | static void process_strm(u8_t *pkt, int len) { |
224 | 229 | struct strm_packet *strm = (struct strm_packet *)pkt; |
225 | 230 | |
226 | LOG_INFO("strm command %c", strm->command); | |
231 | LOG_DEBUG("strm command %c", strm->command); | |
227 | 232 | |
228 | 233 | switch(strm->command) { |
229 | 234 | case 't': |
254 | 259 | output.state = interval ? OUTPUT_PAUSE_FRAMES : OUTPUT_STOPPED; |
255 | 260 | UNLOCK_O; |
256 | 261 | if (!interval) sendSTAT("STMp", 0); |
257 | LOG_INFO("pause interval: %u", interval); | |
262 | LOG_DEBUG("pause interval: %u", interval); | |
258 | 263 | } |
259 | 264 | break; |
260 | 265 | case 'a': |
264 | 269 | output.skip_frames = interval * status.current_sample_rate / 1000; |
265 | 270 | output.state = OUTPUT_SKIP_FRAMES; |
266 | 271 | UNLOCK_O; |
267 | LOG_INFO("skip ahead interval: %u", interval); | |
272 | LOG_DEBUG("skip ahead interval: %u", interval); | |
268 | 273 | } |
269 | 274 | break; |
270 | 275 | case 'u': |
277 | 282 | LOCK_D; |
278 | 283 | decode.state = DECODE_RUNNING; |
279 | 284 | UNLOCK_D; |
280 | LOG_INFO("unpause at: %u now: %u", jiffies, gettime_ms()); | |
285 | LOG_DEBUG("unpause at: %u now: %u", jiffies, gettime_ms()); | |
281 | 286 | sendSTAT("STMr", 0); |
282 | 287 | } |
283 | 288 | break; |
289 | 294 | u16_t port = strm->server_port; // keep in network byte order |
290 | 295 | if (ip == 0) ip = slimproto_ip; |
291 | 296 | |
292 | LOG_INFO("strm s autostart: %c transition period: %u transition type: %u codec: %c", | |
293 | strm->autostart, strm->transition_period, strm->transition_type - '0', strm->format); | |
294 | ||
297 | LOG_DEBUG("strm s autostart: %c transition period: %u transition type: %u codec: %c", | |
298 | strm->autostart, strm->transition_period, strm->transition_type - '0', strm->format); | |
299 | ||
295 | 300 | autostart = strm->autostart - '0'; |
296 | 301 | sendSTAT("STMf", 0); |
297 | 302 | if (header_len > MAX_HEADER -1) { |
302 | 307 | codec_open(strm->format, strm->pcm_sample_size, strm->pcm_sample_rate, strm->pcm_channels, strm->pcm_endianness); |
303 | 308 | } else if (autostart >= 2) { |
304 | 309 | // extension to slimproto to allow server to detect codec from response header and send back in codc message |
305 | LOG_INFO("streaming unknown codec"); | |
310 | LOG_DEBUG("streaming unknown codec"); | |
306 | 311 | } else { |
307 | 312 | LOG_WARN("unknown codec requires autostart >= 2"); |
308 | 313 | break; |
321 | 326 | output.next_replay_gain = unpackN(&strm->replay_gain); |
322 | 327 | output.fade_mode = strm->transition_type - '0'; |
323 | 328 | output.fade_secs = strm->transition_period; |
324 | LOG_INFO("set fade mode: %u", output.fade_mode); | |
329 | LOG_DEBUG("set fade mode: %u", output.fade_mode); | |
325 | 330 | UNLOCK_O; |
326 | 331 | } |
327 | 332 | break; |
328 | 333 | default: |
329 | LOG_INFO("unhandled strm %c", strm->command); | |
334 | LOG_WARN("unhandled strm %c", strm->command); | |
330 | 335 | break; |
331 | 336 | } |
332 | 337 | } |
335 | 340 | struct cont_packet *cont = (struct cont_packet *)pkt; |
336 | 341 | cont->metaint = unpackN(&cont->metaint); |
337 | 342 | |
338 | LOG_INFO("cont metaint: %u loop: %u", cont->metaint, cont->loop); | |
343 | LOG_DEBUG("cont metaint: %u loop: %u", cont->metaint, cont->loop); | |
339 | 344 | |
340 | 345 | if (autostart > 1) { |
341 | 346 | autostart -= 2; |
352 | 357 | static void process_codc(u8_t *pkt, int len) { |
353 | 358 | struct codc_packet *codc = (struct codc_packet *)pkt; |
354 | 359 | |
355 | LOG_INFO("codc: %c", codc->format); | |
360 | LOG_DEBUG("codc: %c", codc->format); | |
356 | 361 | codec_open(codc->format, codc->pcm_sample_size, codc->pcm_sample_rate, codc->pcm_channels, codc->pcm_endianness); |
357 | 362 | } |
358 | 363 | |
359 | 364 | static void process_aude(u8_t *pkt, int len) { |
360 | 365 | struct aude_packet *aude = (struct aude_packet *)pkt; |
361 | 366 | |
362 | LOG_INFO("enable spdif: %d dac: %d", aude->enable_spdif, aude->enable_dac); | |
367 | LOG_DEBUG("enable spdif: %d dac: %d", aude->enable_spdif, aude->enable_dac); | |
363 | 368 | |
364 | 369 | LOCK_O; |
365 | 370 | if (!aude->enable_spdif && output.state != OUTPUT_OFF) { |
376 | 381 | audg->gainL = unpackN(&audg->gainL); |
377 | 382 | audg->gainR = unpackN(&audg->gainR); |
378 | 383 | |
379 | LOG_INFO("audg gainL: %u gainR: %u adjust: %u", audg->gainL, audg->gainR, audg->adjust); | |
384 | LOG_DEBUG("audg gainL: %u gainR: %u adjust: %u", audg->gainL, audg->gainR, audg->adjust); | |
380 | 385 | |
381 | 386 | LOCK_O; |
382 | 387 | output.gainL = audg->adjust ? audg->gainL : FIXED_ONE; |
460 | 465 | while (h->handler && strncmp((char *)pack, h->opcode, 4)) { h++; } |
461 | 466 | |
462 | 467 | if (h->handler) { |
463 | LOG_INFO("%s", h->opcode); | |
468 | LOG_DEBUG("%s", h->opcode); | |
464 | 469 | h->handler(pack, len); |
465 | 470 | } else { |
466 | 471 | pack[4] = '\0'; |
467 | LOG_INFO("unhandled %s", (char *)pack); | |
472 | LOG_WARN("unhandled %s", (char *)pack); | |
468 | 473 | } |
469 | 474 | } |
470 | 475 | |
749 | 754 | if (!fgets(player_name, PLAYER_NAME_LEN, fp)) { |
750 | 755 | player_name[PLAYER_NAME_LEN] = '\0'; |
751 | 756 | } else { |
752 | LOG_INFO("retrived name %s from %s", player_name, name_file); | |
757 | // strip any \n from fgets response | |
758 | int len = strlen(player_name); | |
759 | if (len > 0 && player_name[len - 1] == '\n') { | |
760 | player_name[len - 1] = '\0'; | |
761 | } | |
762 | LOG_INFO("retrieved name %s from %s", player_name, name_file); | |
753 | 763 | } |
754 | 764 | fclose(fp); |
755 | 765 | } |
0 | 0 | /* |
1 | 1 | * Squeezelite - lightweight headless squeezebox emulator |
2 | 2 | * |
3 | * (c) Adrian Smith 2012, 2013, triode1@btinternet.com | |
3 | * (c) Adrian Smith 2012-2014, triode1@btinternet.com | |
4 | 4 | * |
5 | 5 | * This program is free software: you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
0 | 0 | /* |
1 | 1 | * Squeezelite - lightweight headless squeezebox emulator |
2 | 2 | * |
3 | * (c) Adrian Smith 2012, 2013, triode1@btinternet.com | |
3 | * (c) Adrian Smith 2012-2014, triode1@btinternet.com | |
4 | 4 | * |
5 | 5 | * This program is free software: you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
19 | 19 | |
20 | 20 | // make may define: PORTAUDIO, SELFPIPE, RESAMPLE, VISEXPORT, DSD, LINKALL to influence build |
21 | 21 | |
22 | #define VERSION "v1.4" | |
22 | #define VERSION "v1.5" | |
23 | 23 | |
24 | 24 | // build detection |
25 | 25 | #if defined(linux) |
527 | 527 | bool next_dop; // set in decode thread |
528 | 528 | bool dop; |
529 | 529 | bool has_dop; // set in dop_init - output device supports dop |
530 | unsigned dop_delay; // set in dop_init - delay in ms switching to/from dop | |
531 | bool dop_delay_active; | |
530 | 532 | #endif |
531 | 533 | }; |
532 | 534 | |
580 | 582 | bool is_flac_dop(u32_t *lptr, u32_t *rptr, frames_t frames); |
581 | 583 | void update_dop_marker(u32_t *ptr, frames_t frames); |
582 | 584 | void dop_silence_frames(u32_t *ptr, frames_t frames); |
583 | void dop_init(bool enable); | |
585 | void dop_init(bool enable, unsigned delay); | |
584 | 586 | #endif |
585 | 587 | |
586 | 588 | // codecs |
0 | 0 | /* |
1 | 1 | * Squeezelite - lightweight headless squeezebox emulator |
2 | 2 | * |
3 | * (c) Adrian Smith 2012, 2013, triode1@btinternet.com | |
3 | * (c) Adrian Smith 2012-2014, triode1@btinternet.com | |
4 | 4 | * |
5 | 5 | * This program is free software: you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
0 | 0 | /* |
1 | 1 | * Squeezelite - lightweight headless squeezebox emulator |
2 | 2 | * |
3 | * (c) Adrian Smith 2012, 2013, triode1@btinternet.com | |
3 | * (c) Adrian Smith 2012-2014, triode1@btinternet.com | |
4 | 4 | * |
5 | 5 | * This program is free software: you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
0 | 0 | /* |
1 | 1 | * Squeezelite - lightweight headless squeezebox emulator |
2 | 2 | * |
3 | * (c) Adrian Smith 2012, 2013, triode1@btinternet.com | |
3 | * (c) Adrian Smith 2012-2014, triode1@btinternet.com | |
4 | 4 | * |
5 | 5 | * This program is free software: you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |