Codebase list squeezelite / 5a90fe8
add option to close output device when idle Adrian Smith 9 years ago
8 changed file(s) with 79 addition(s) and 46 deletion(s). Raw diff Collapse all Expand all
125125
126126 Minor changes
127127 - fix crash which could occur when resampling
128
129 Version 1.8
130 ===========
131
132 Features
133 - support for closing output device when idle with -C option
5757 " -a <f>\t\tSpecify sample format (16|24|32) of output file when using -o - to output samples to stdout (interleaved little endian only)\n"
5858 " -b <stream>:<output>\tSpecify internal Stream and Output buffer sizes in Kbytes\n"
5959 " -c <codec1>,<codec2>\tRestrict codecs to those specified, otherwise load all available codecs; known codecs: " CODECS "\n"
60 " -C <timeout>\t\tClose output device when idle after timeout seconds, default is to keep it open while player is 'on'\n"
6061 " -d <log>=<level>\tSet logging level, logs: all|slimproto|stream|decode|output, level: info|debug|sdebug\n"
6162 " -e <codec1>,<codec2>\tExplicitly exclude native support of one or more codecs; known codecs: " CODECS "\n"
6263 " -f <logfile>\t\tWrite debug to logfile\n"
186187 unsigned rate_delay = 0;
187188 char *resample = NULL;
188189 char *output_params = NULL;
190 unsigned idle = 0;
189191 #if LINUX || FREEBSD
190192 bool daemonize = false;
191193 char *pidfile = NULL;
223225
224226 while (optind < argc && strlen(argv[optind]) >= 2 && argv[optind][0] == '-') {
225227 char *opt = argv[optind] + 1;
226 if (strstr("oabcdefmMnNpPrs", opt) && optind < argc - 1) {
228 if (strstr("oabcCdefmMnNpPrs", opt) && optind < argc - 1) {
227229 optarg = argv[optind + 1];
228230 optind += 2;
229231 } else if (strstr("ltz?"
262264 break;
263265 case 'c':
264266 include_codecs = optarg;
267 break;
268 case 'C':
269 if (atoi(optarg) > 0) {
270 idle = atoi(optarg) * 1000;
271 }
265272 break;
266273 case 'e':
267274 exclude_codecs = optarg;
491498 output_init_stdout(log_output, output_buf_size, output_params, rates, rate_delay);
492499 } else {
493500 #if ALSA
494 output_init_alsa(log_output, output_device, output_buf_size, output_params, rates, rate_delay, rt_priority);
501 output_init_alsa(log_output, output_device, output_buf_size, output_params, rates, rate_delay, rt_priority, idle);
495502 #endif
496503 #if PORTAUDIO
497 output_init_pa(log_output, output_device, output_buf_size, output_params, rates, rate_delay);
504 output_init_pa(log_output, output_device, output_buf_size, output_params, rates, rate_delay, idle);
498505 #endif
499506 }
500507
332332 }
333333 }
334334
335 void output_init_common(log_level level, const char *device, unsigned output_buf_size, unsigned rates[]) {
335 void output_init_common(log_level level, const char *device, unsigned output_buf_size, unsigned rates[], unsigned idle) {
336336 unsigned i;
337337
338338 loglevel = level;
366366 output.device = device;
367367 output.fade = FADE_INACTIVE;
368368 output.error_opening = false;
369 output.idle_to = (u32_t) idle;
369370
370371 if (!rates[0]) {
371372 if (!test_open(output.device, output.supported_rates)) {
617617 static pthread_t thread;
618618
619619 void output_init_alsa(log_level level, const char *device, unsigned output_buf_size, char *params, unsigned rates[],
620 unsigned rate_delay, unsigned rt_priority) {
620 unsigned rate_delay, unsigned rt_priority, unsigned idle) {
621621
622622 unsigned alsa_buffer = ALSA_BUFFER_TIME;
623623 unsigned alsa_period = ALSA_PERIOD_COUNT;
666666
667667 snd_lib_error_set_handler((snd_lib_error_handler_t)alsa_error_handler);
668668
669 output_init_common(level, device, output_buf_size, rates);
669 output_init_common(level, device, output_buf_size, rates, idle);
670670
671671 #if LINUX
672672 // RT linux - aim to avoid pagefaults by locking memory:
376376 return ret;
377377 }
378378
379 void output_init_pa(log_level level, const char *device, unsigned output_buf_size, char *params, unsigned rates[], unsigned rate_delay) {
379 void output_init_pa(log_level level, const char *device, unsigned output_buf_size, char *params, unsigned rates[], unsigned rate_delay,
380 unsigned idle) {
380381 PaError err;
381382 unsigned latency = 0;
382383 int osx_playnice = -1;
408409 exit(0);
409410 }
410411
411 output_init_common(level, device, output_buf_size, rates);
412 output_init_common(level, device, output_buf_size, rates, idle);
412413
413414 LOCK;
414415
149149 rates[0] = 44100;
150150 }
151151
152 output_init_common(level, "-", output_buf_size, rates);
152 output_init_common(level, "-", output_buf_size, rates, 0);
153153
154154 #if LINUX || OSX || FREEBSD
155155 pthread_attr_t attr;
256256 unsigned interval = unpackN(&strm->replay_gain);
257257 LOCK_O;
258258 output.pause_frames = interval * status.current_sample_rate / 1000;
259 output.state = interval ? OUTPUT_PAUSE_FRAMES : OUTPUT_STOPPED;
259 if (interval) {
260 output.state = OUTPUT_PAUSE_FRAMES;
261 } else {
262 output.state = OUTPUT_STOPPED;
263 output.stop_time = gettime_ms();
264 }
260265 UNLOCK_O;
261266 if (!interval) sendSTAT("STMp", 0);
262267 LOG_DEBUG("pause interval: %u", interval);
367372 if (!aude->enable_spdif && output.state != OUTPUT_OFF) {
368373 output.state = OUTPUT_OFF;
369374 }
370 if (aude->enable_spdif && output.state == OUTPUT_OFF) {
375 if (aude->enable_spdif && output.state == OUTPUT_OFF && !output.idle_to) {
371376 output.state = OUTPUT_STOPPED;
377 output.stop_time = gettime_ms();
372378 }
373379 UNLOCK_O;
374380 }
560566 bool _sendSTMo = false;
561567 bool _sendSTMn = false;
562568 bool _stream_disconnect = false;
569 bool _start_output = false;
570 decode_state _decode_state;
563571 disconnect_code disconnect_code;
564572 static char header[MAX_HEADER];
565573 size_t header_len = 0;
590598 stream.meta_send = false;
591599 }
592600 UNLOCK_S;
601
602 LOCK_D;
603 if ((status.stream_state == STREAMING_HTTP || status.stream_state == STREAMING_FILE) && !sentSTMl
604 && decode.state == DECODE_READY) {
605 if (autostart == 0) {
606 decode.state = DECODE_RUNNING;
607 _sendSTMl = true;
608 sentSTMl = true;
609 } else if (autostart == 1) {
610 decode.state = DECODE_RUNNING;
611 _start_output = true;
612 }
613 // autostart 2 and 3 require cont to be received first
614 }
615 if (decode.state == DECODE_COMPLETE || decode.state == DECODE_ERROR) {
616 if (decode.state == DECODE_COMPLETE) _sendSTMd = true;
617 if (decode.state == DECODE_ERROR) _sendSTMn = true;
618 decode.state = DECODE_STOPPED;
619 if (status.stream_state == STREAMING_HTTP || status.stream_state == STREAMING_FILE) {
620 _stream_disconnect = true;
621 }
622 }
623 _decode_state = decode.state;
624 UNLOCK_D;
593625
594626 LOCK_O;
595627 status.output_full = _buf_used(outputbuf);
610642 output.pa_reopen = false;
611643 }
612644 #endif
613 if (output.state == OUTPUT_RUNNING && !sentSTMu && status.output_full == 0 && status.stream_state <= DISCONNECT) {
645 if (_start_output && (output.state == OUTPUT_STOPPED || OUTPUT_OFF)) {
646 output.state = OUTPUT_BUFFER;
647 }
648 if (output.state == OUTPUT_RUNNING && !sentSTMu && status.output_full == 0 && status.stream_state <= DISCONNECT &&
649 _decode_state == DECODE_STOPPED) {
614650 _sendSTMu = true;
615651 sentSTMu = true;
652 LOG_DEBUG("output underrun");
653 output.state = OUTPUT_STOPPED;
654 output.stop_time = now;
616655 }
617656 if (output.state == OUTPUT_RUNNING && !sentSTMo && status.output_full == 0 && status.stream_state == STREAMING_HTTP) {
618657 _sendSTMo = true;
619658 sentSTMo = true;
620659 }
621 UNLOCK_O;
622
623 LOCK_D;
624 if (decode.state == DECODE_RUNNING && now - status.last > 1000) {
660 if (output.state == OUTPUT_STOPPED && output.idle_to && (now - output.stop_time > output.idle_to)) {
661 output.state = OUTPUT_OFF;
662 LOG_DEBUG("output timeout");
663 }
664 if (output.state == OUTPUT_RUNNING && now - status.last > 1000) {
625665 _sendSTMt = true;
626666 status.last = now;
627667 }
628 if ((status.stream_state == STREAMING_HTTP || status.stream_state == STREAMING_FILE) && !sentSTMl
629 && decode.state == DECODE_READY) {
630 if (autostart == 0) {
631 decode.state = DECODE_RUNNING;
632 _sendSTMl = true;
633 sentSTMl = true;
634 } else if (autostart == 1) {
635 decode.state = DECODE_RUNNING;
636 LOCK_O;
637 if (output.state == OUTPUT_STOPPED) {
638 output.state = OUTPUT_BUFFER;
639 }
640 UNLOCK_O;
641 }
642 // autostart 2 and 3 require cont to be received first
643 }
644 if (decode.state == DECODE_COMPLETE || decode.state == DECODE_ERROR) {
645 if (decode.state == DECODE_COMPLETE) _sendSTMd = true;
646 if (decode.state == DECODE_ERROR) _sendSTMn = true;
647 decode.state = DECODE_STOPPED;
648 if (status.stream_state == STREAMING_HTTP || status.stream_state == STREAMING_FILE) {
649 _stream_disconnect = true;
650 }
651 }
652 UNLOCK_D;
653
668 UNLOCK_O;
669
654670 if (_stream_disconnect) stream_disconnect();
655671
656672 // send packets once locks released as packet sending can block
1919
2020 // make may define: PORTAUDIO, SELFPIPE, RESAMPLE, RESAMPLE_MP, VISEXPORT, DSD, LINKALL to influence build
2121
22 #define VERSION "v1.7.1"
22 #define VERSION "v1.8-dev"
2323
2424 #if !defined(MODEL_NAME)
2525 #define MODEL_NAME SqueezeLite
561561 unsigned fade_secs; // set by slimproto
562562 unsigned rate_delay;
563563 bool delay_active;
564 u32_t stop_time;
565 u32_t idle_to;
564566 #if DSD
565567 bool next_dop; // set in decode thread
566568 bool dop;
569571 #endif
570572 };
571573
572 void output_init_common(log_level level, const char *device, unsigned output_buf_size, unsigned rates[]);
574 void output_init_common(log_level level, const char *device, unsigned output_buf_size, unsigned rates[], unsigned idle);
573575 void output_close_common(void);
574576 void output_flush(void);
575577 // _* called with mutex locked
581583 void list_devices(void);
582584 bool test_open(const char *device, unsigned rates[]);
583585 void output_init_alsa(log_level level, const char *device, unsigned output_buf_size, char *params, unsigned rates[],
584 unsigned rate_delay, unsigned rt_priority);
586 unsigned rate_delay, unsigned rt_priority, unsigned idle);
585587 void output_close_alsa(void);
586588 #endif
587589
589591 #if PORTAUDIO
590592 void list_devices(void);
591593 bool test_open(const char *device, unsigned rates[]);
592 void output_init_pa(log_level level, const char *device, unsigned output_buf_size, char *params, unsigned rates[], unsigned rate_delay);
594 void output_init_pa(log_level level, const char *device, unsigned output_buf_size, char *params, unsigned rates[], unsigned rate_delay, unsigned idle);
593595 void output_close_pa(void);
594596 void _pa_open(void);
595597 #endif