4 * code protected with a GNU affero GPLv3 license
5 * copyright (C) 2020 Sylvain BERTRAND
11 * async : ASYNChronous
12 * b(s) : Byte(S) (often)
15 * chan(s) : CHANnel(S)
17 * cp(s) : Code Point(s)
20 * dec : DECoder/DECoded
22 * e : End (usually a pointer on the byte past the last valid byte)
28 * fd : File Descriptor
34 * l10n : LocalizatioN (10 chars between L and N)
36 * msec(s) : MilliSECond(S)
42 * ref(s) : REFerence(S)
58 * this is not a library, then we could not care less about memory management
59 * and/or similar cleanup: we have a virtual machine with a garbage collector,
62 * we do presume we won't play more than 8 chans and ffmpeg chans layout will
65 * XXX: we don't know how the alsa silence machinery works, then we use brutal
68 /*----------------------------------------------------------------------------*/
83 #include <stdatomic.h>
86 /* linux and compatible */
87 #include <sys/epoll.h>
88 #include <sys/signalfd.h>
89 #include <sys/timerfd.h>
91 #include <libavformat/avformat.h>
92 #include <libavcodec/avcodec.h>
93 #include <libavfilter/avfilter.h>
94 #include <libavfilter/buffersrc.h>
95 #include <libavfilter/buffersink.h>
96 #include <libavutil/opt.h>
98 #include <alsa/asoundlib.h>
107 #define atomic_u8 atomic_uchar
109 #error "unable to find the right atomic for a 8 bits byte, be sure to have __STDC_WANT_IEC_60559_BFP_EXT__ defined"
112 #define ARRAY_N(x) (sizeof(x) / sizeof((x)[0]))
114 #define POUT(fmt, ...) fprintf(stdout, fmt, ##__VA_ARGS__)
115 #define PERR(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
116 #define WARNING(fmt, ...) fprintf(stderr, "WARNING:" fmt, ##__VA_ARGS__)
117 #define FATAL(fmt, ...) ({PERR("FATAL:" fmt, ##__VA_ARGS__);stdin_flags_restore();stdin_tty_cfg_restore();exit(1);})
118 #define EXIT(fmt, ...) ({POUT("EXITING:" fmt, ##__VA_ARGS__);stdin_flags_restore();stdin_tty_cfg_restore();exit(0);})
119 #define STR_SZ 255 /* sz and idx fit in 1 byte */
120 /*---------------------------------------------------------------------------*/
121 static u8
*current_url
;
122 static int current_st_idx
;
123 /* cmd_info must be fast, then a lockless copy of its data */
127 enum AVDurationEstimationMethod m
;
135 /*---------------------------------------------------------------------------*/
136 /* linux and compatible */
139 /*---------------------------------------------------------------------------*/
141 static snd_pcm_t
*pcm_g
;
142 static snd_output_t
*pcm_pout
;
143 static snd_output_t
*pcm_perr
;
144 #define PCM_POLLFDS_N_MAX 16 /* banzai */
145 static struct pollfd pcm_pollfds
[PCM_POLLFDS_N_MAX
];
146 static u8 pcm_pollfds_n
;
147 /*---------------------------------------------------------------------------*/
150 * XXX: a ffmpeg fr is not 1 audio fr but a collection of frs.
151 * ffmpeg dec fr "nb_samples" is actually the number of audio frs
152 * av_read_frame is actually av_read_pkt, like av_seek*
153 * we personally did not like the resulting confusion.
154 * we purposely "fix" the namespace even if some others won't like it.
156 #define AVFrames AVFrame
157 #define frames_n nb_samples
158 #define av_frames_alloc av_frame_alloc
159 #define av_read_pkt av_read_frame
160 #define av_seek_pkt av_seek_frame
161 #define avcodec_receive_frames avcodec_receive_frame
162 #define AVFrameFormat AVSampleFormat
163 #define av_frames_set_silence av_samples_set_silence
164 #define av_get_frame_fmt_name av_get_sample_fmt_name
165 #define av_get_frame_fmt_string av_get_sample_fmt_string
166 #define frame_rate sample_rate
167 #define av_frame_fmt_is_planar av_sample_fmt_is_planar
168 #define frame_fmt sample_fmt
169 #define av_frames_unref av_frame_unref
170 static AVPacket
*rd_thd_pkt
;
171 static AVFormatContext
*fmt_ctx
;
172 static pthread_mutex_t fmt_ctx_mutex
;
174 static AVCodecContext
*dec_ctx
;
175 /*---------------------------------------------------------------------------*/
176 /* ffmpeg filter graph */
177 static AVFilterGraph
*filter_graph
;
178 static AVFilterContext
*abufsrc_ctx
;
179 static const AVFilter
*abufsrc_filt
;
180 static AVFilterContext
*vol_ctx
;
181 static const AVFilter
*vol_filt
;
182 static u8 double_zero_l10n_str
[sizeof("xxx.xx")];
183 static AVFilterContext
*afmt_ctx
;
184 static const AVFilter
*afmt_filt
;
185 static AVFilterContext
*abufsink_ctx
;
186 static const AVFilter
*abufsink_filt
;
187 /*---------------------------------------------------------------------------*/
188 /* a formally proven concurrently accessed lockless cb */
193 AVPacket
*pkts
[U8_MAX
+ 1];
200 int64_t most_recent_ts
; /* a very "coarse-grained" clock */
204 bool no_more_dec_frs
;
207 snd_pcm_uframes_t pcm_written_ufrs_n
;
209 /* we will inject silence frs while paused */
211 void *silence_bufs
[AV_NUM_DATA_POINTERS
];
212 /*----------------------------------------------------------------------------*/
214 static bool stdin_tty_cfg_modified
;
215 static struct termios stdin_tio_save
;
216 static int stdin_flags_save
;
217 static bool stdout_is_tty
;
218 /*----------------------------------------------------------------------------*/
219 static void cmd_quit(void);
220 static void cmd_rewind(void);
221 static void cmd_fastforward(void);
222 static void cmd_rewind_big(void);
223 static void cmd_fastforward_big(void);
224 static void cmd_vol_up(void);
225 static void cmd_vol_down(void);
226 static void cmd_mute(void);
227 static void cmd_info(void);
228 static void cmd_pause(void);
229 /*--------------------------------------------------------------------------*/
230 #include "npa_config.h"
231 /*----------------------------------------------------------------------------*/
232 /* input "state" machine (2 major states: "utf8" and "esc seq" */
233 static int input_timer_fd
;
234 static bool input_esc_seq_mode
;
235 static u8 input_b
; /* input byte */
237 static u8 utf8_cp
[4];
238 static u8 utf8_cp_next_byte
; /* idx in utf8_cp */
239 static u8 utf8_cp_sz
;
241 static u8 esc_seq
[STR_SZ
];
242 static u8 esc_seq_next_byte
; /* idx in esc_seq */
243 #define esc_seq_sz esc_seq_next_byte /* the idx of the next byte is its sz */
244 /*----------------------------------------------------------------------------*/
245 static void stdin_flags_restore(void)
249 r
= fcntl(0, F_SETFL
, stdin_flags_save
);
251 WARNING("input:unable to restore the file flags of the standard input\n");
253 static void stdin_tty_cfg_restore(void)
256 struct termios tio_chk
;
258 if (!stdin_tty_cfg_modified
)
261 r
= tcsetattr(0, TCSANOW
, &stdin_tio_save
);
263 WARNING("input:unable to restore the terminal line attributes\t");
267 memset(&tio_chk
, 0, sizeof(tio_chk
));
268 r
= tcgetattr(0, &tio_chk
);
270 WARNING("input:unable to get the current terminal line attributes for restoration checking\n");
274 r
= memcmp(&tio_chk
, &stdin_tio_save
, sizeof(tio_chk
));
276 WARNING("input:only partial restoration of the terminal line attributes\n");
278 static void fmt_ctx_lock(void)
282 r
= pthread_mutex_lock(&fmt_ctx_mutex
);
284 FATAL("unable to lock the format context\n");
286 static void fmt_ctx_unlock(void)
290 r
= pthread_mutex_unlock(&fmt_ctx_mutex
);
292 FATAL("unable to unlock the format context\n");
294 static u8
*duration_estimate_to_str(enum AVDurationEstimationMethod m
)
297 case AVFMT_DURATION_FROM_PTS
:
298 return "from PTS(Presentation TimeStamp)";
299 case AVFMT_DURATION_FROM_STREAM
:
300 return "from stream";
301 case AVFMT_DURATION_FROM_BITRATE
:
302 return "from bitrate";
308 static u8
*ts_to_str(int64_t ts
, AVRational tb
, int64_t *remaining
)
310 static u8 str
[sizeof("~S00:00:00.000 remains S9223372036854775807 time base units")];
316 int64_t one_hour
; /* in ffmpeg time_base units */
317 int64_t one_min
; /* in ffmpeg time_base units */
318 int64_t one_sec
; /* in ffmpeg time_base units */
319 int64_t one_msec
; /* in ffmpeg time_base units */
326 one_hour
= INT64_C(3600) * (int64_t)tb
.den
/ (int64_t)tb
.num
;
327 one_min
= INT64_C(60) * (int64_t)tb
.den
/ (int64_t)tb
.num
;
328 one_sec
= (int64_t)tb
.den
/ (int64_t)tb
.num
;
329 one_msec
= one_sec
/ INT64_C(1000);
331 hours_n
= ts
/ one_hour
;
333 *remaining
= ts
% one_hour
;
334 mins_n
= *remaining
/ one_min
;
336 *remaining
= *remaining
% one_min
;
337 secs_n
= *remaining
/ one_sec
;
339 *remaining
= *remaining
% one_sec
;
340 msecs_n
= *remaining
/ one_msec
;
342 /* account for all rounding errors */
343 *remaining
= ts
- (hours_n
* one_hour
+ mins_n
* one_min
344 + secs_n
* one_sec
+ msecs_n
* one_msec
);
346 snprintf(str
, sizeof(str
), "%02"PRId64
":%02"PRId64
":%02"PRId64
".%03"PRId64
, hours_n
, mins_n
, secs_n
, msecs_n
);
349 snprintf(str
+ 1, sizeof(str
) - 1, "%02"PRId64
":%02"PRId64
":%02"PRId64
".%03"PRId64
, hours_n
, mins_n
, secs_n
, msecs_n
);
353 #define RED if (stdout_is_tty) POUT("\x1b[38;2;255;0;0m")
354 #define GREEN if (stdout_is_tty) POUT("\x1b[38;2;0;255;0m")
355 #define BLUE if (stdout_is_tty) POUT("\x1b[38;2;0;0;255m")
356 #define PURPLE if (stdout_is_tty) POUT("\x1b[38;2;255;0;255m")
357 #define RESTORE if (stdout_is_tty) POUT("\x1b[39;49m");
358 static void cmd_info(void)
362 u8 duration_str
[sizeof("S9223372036854775807")];
365 GREEN
;POUT("================================================================================\n");RESTORE
;
366 PURPLE
;POUT("%s\n", current_url
);RESTORE
;
367 ts_str
= ts_to_str(dec_frs
.most_recent_ts
, cmd_info_data
.st
.tb
, &remaining
);
368 RED
;POUT("%s", ts_str
);RESTORE
;
370 POUT(" remaining %"PRId64
" time base units", remaining
);
373 POUT("\t%"PRId64
" stream time base units (%d/%d seconds)\n", dec_frs
.most_recent_ts
, cmd_info_data
.st
.tb
.num
, cmd_info_data
.st
.tb
.den
);
374 BLUE
;POUT("--------------------------------------------------------------------------------\n");RESTORE
;
376 if (cmd_info_data
.fmt
.duration
== AV_NOPTS_VALUE
) {
377 POUT("duration is not provided\n");
379 snprintf(duration_str
, sizeof(duration_str
), "%"PRId64
, cmd_info_data
.fmt
.duration
);
380 ts_str
= ts_to_str(cmd_info_data
.fmt
.duration
, AV_TIME_BASE_Q
,
382 POUT("duration=");RED
;POUT("%s", ts_str
);RESTORE
;
384 POUT(" remaining %"PRId64
" av_time_base units\n", remaining
);
387 POUT("\t%s av_time_base units (1/%d seconds)\n\testimation method is %s\n", duration_str
, AV_TIME_BASE
, duration_estimate_to_str(cmd_info_data
.fmt
.m
));
389 POUT("stream:id=%d", cmd_info_data
.st
.id
);
390 if (cmd_info_data
.st
.duration
== AV_NOPTS_VALUE
) {
391 POUT(";duration is not provided\n");
393 snprintf(duration_str
, sizeof(duration_str
), "%"PRId64
, cmd_info_data
.st
.duration
);
394 ts_str
= ts_to_str(cmd_info_data
.st
.duration
, cmd_info_data
.st
.tb
, &remaining
);
395 POUT(";duration=");RED
;POUT("%s\n", ts_str
);RESTORE
;
397 POUT(" remaining %"PRId64
" stream time base units\n", remaining
);
400 POUT("\t%s stream time base units (%d/%d seconds)\n", duration_str
, cmd_info_data
.st
.tb
.num
, cmd_info_data
.st
.tb
.den
);
402 BLUE
;POUT("--------------------------------------------------------------------------------\n");RESTORE
;
403 POUT("circular buffer: %u/%u/%u (read/send/max)\n", atomic_load(&cb
.rd
), atomic_load(&cb
.sd
), U8_MAX
);
405 RED
;POUT("paused\n");RESTORE
;
407 if (filt_frs
.muted
) {
408 RED
;POUT("muted\n");RESTORE
;
410 GREEN
;POUT("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");RESTORE
;
417 static void wait(long ns
)
419 struct timespec wanted
;
422 memset(&wanted
, 0, sizeof(wanted
));
423 memset(&rem
, 0, sizeof(rem
));
428 /* linux bug: cannot specify CLOCK_MONOTONIC_RAW */
429 r
= clock_nanosleep(CLOCK_MONOTONIC
, 0, &wanted
, &rem
);
433 FATAL("wait timer failed:%d\n", r
);
435 memcpy(&wanted
, &rem
, sizeof(wanted
));
436 memset(&rem
, 0, sizeof(rem
));
440 static void do_reset(void)
445 avformat_flush(fmt_ctx
);
446 avio_flush(fmt_ctx
->pb
);
450 av_packet_unref(cb
.pkts
[i
]);
455 atomic_store(&cb
.rd
, 0);
456 atomic_store(&cb
.sd
, 0);
457 atomic_store(&cb
.reset
, RESET_DONE
);
461 static void rd_loop(void) { loop
/* infinite loop */
470 * XXX: we actually perform reset on this thd, with a little lockfree
471 * protocol and reasonable wait loops
473 reset
= atomic_load(&cb
.reset
);
474 if (reset
== DO_RESET
)
476 /*--------------------------------------------------------------------*/
477 rd
= atomic_load(&cb
.rd
);
478 sd
= atomic_load(&cb
.sd
);
480 if (next_rd
== sd
) { /* must sd first the sd slot */
481 wait(1000000); /* 1ms */
484 /*--------------------------------------------------------------------*/
486 r
= av_read_pkt(fmt_ctx
, rd_thd_pkt
);
488 if (r
== AVERROR(EAGAIN
)) {
489 /* 1ms: it is sort of aggressive to check for reset */
492 } else if (r
== AVERROR_EOF
) {
493 /* The "NULL" pkt ref to signal the EOF to the dec */
494 cb
.pkts
[rd
]->data
= 0;
495 cb
.pkts
[rd
]->size
= 0;
497 FATAL("ffmpeg:error while demuxing coded/compressed data into packets\n");
499 st_idx
= atomic_load(&cb
.st_idx
);
500 if (rd_thd_pkt
->stream_index
!= st_idx
) { /* sd_idx can be -1 */
501 av_packet_unref(rd_thd_pkt
);
504 av_packet_move_ref(cb
.pkts
[rd
], rd_thd_pkt
);
506 atomic_store(&cb
.rd
, next_rd
);
509 static void *rd_thd_entry(void *arg
)
514 r
= sigfillset(&sset
);
516 FATAL("read thread:unable to get a full signal mask\n");
517 r
= pthread_sigmask(SIG_SETMASK
, &sset
, 0);
519 FATAL("read thread:unable to \"block\" \"all\" signals\n");
523 static void rd_thd_start(void)
529 r
= pthread_attr_init(&attr
);
531 FATAL("read thread:unable to initialize read thread attribute\n");
532 r
= pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
534 FATAL("read thread:unable to set the read thread attribute to detach mode\n");
535 r
= pthread_create(&id
, &attr
, &rd_thd_entry
, 0);
537 FATAL("read thread:unable to create the read thread\n");
538 POUT("read thread %lu\n", (unsigned long)id
);
539 pthread_attr_destroy(&attr
);
541 static void cmd_quit(void)
543 EXIT("quit command received\n");
547 static void rd_thd_reset(int st_idx
)
552 /* reset = RESET_DONE */
553 atomic_store(&cb
.st_idx
, st_idx
);
554 atomic_store(&cb
.reset
, DO_RESET
);
558 reset
= atomic_load(&cb
.reset
);
559 if (reset
== RESET_DONE
)
561 wait(1000000); /* 1ms */
563 if (loops_n
== 4000) /* 1ms * 4000 = 4s */
564 FATAL("read thread reset timeout\n");
566 /* reset = DO_RESET */
571 * XXX: if it is ever used significantly, a fine granularity wiring strategy
572 * will be implemented instead of using the default wiring
574 static uint64_t pcm_chmaps2ff_chans_layout(snd_pcm_t
*pcm
,
575 unsigned int pcm_chans_n
, bool print_info
)
578 uint64_t ff_chans_layout
;
579 snd_pcm_chmap_t
*pcm_chmap
;
580 u8 chans_layout_str
[STR_SZ
]; /* should be overkill */
582 pcm_chmap
= snd_pcm_get_chmap(pcm
);
583 if (pcm_chmap
== 0) {
585 POUT("alsa:no pcm channel map available, wiring to default ffmpeg channel layout\n");
588 POUT("alsa:your pcm device support channel maps, but fine granularity wiring strategy is not implemented\n");
591 ff_chans_layout
= av_get_default_channel_layout((int)pcm_chans_n
);
592 av_get_channel_layout_string(chans_layout_str
, sizeof(chans_layout_str
),
593 (int)pcm_chans_n
, ff_chans_layout
);
595 POUT("alsa channel map wired to ffmpeg channel layout:\"%s\" (%u pcm channels)\n", chans_layout_str
, pcm_chans_n
);
596 return ff_chans_layout
;
598 /* fatal if the wiring cannot be done */
599 static void pcm_layout2ff_fmt_strict(snd_pcm_format_t alsa_fmt
,
600 snd_pcm_access_t alsa_access
, enum AVSampleFormat
*ff_fmt
,
604 * ff fmt byte order is always native.
605 * here we handle little endian only
608 case SND_PCM_FORMAT_FLOAT
:
609 if (alsa_access
== SND_PCM_ACCESS_RW_INTERLEAVED
)
610 *ff_fmt
= AV_SAMPLE_FMT_FLT
;
612 *ff_fmt
= AV_SAMPLE_FMT_FLTP
;
614 case SND_PCM_FORMAT_S32
:
615 if (alsa_access
== SND_PCM_ACCESS_RW_INTERLEAVED
)
616 *ff_fmt
= AV_SAMPLE_FMT_S32
;
618 *ff_fmt
= AV_SAMPLE_FMT_S32P
;
620 case SND_PCM_FORMAT_S16
:
621 if (alsa_access
== SND_PCM_ACCESS_RW_INTERLEAVED
)
622 *ff_fmt
= AV_SAMPLE_FMT_S16
;
624 *ff_fmt
= AV_SAMPLE_FMT_S16P
;
626 case SND_PCM_FORMAT_U8
:
627 if (alsa_access
== SND_PCM_ACCESS_RW_INTERLEAVED
)
628 *ff_fmt
= AV_SAMPLE_FMT_U8
;
630 *ff_fmt
= AV_SAMPLE_FMT_U8P
;
633 FATAL("unable to wire strictly alsa layout \"%s\"/\"%s\" to a ffmpeg format\n", snd_pcm_format_description(alsa_fmt
), snd_pcm_access_name(alsa_access
));
636 u8 ff_fmt_str
[STR_SZ
];
638 av_get_sample_fmt_string(ff_fmt_str
, sizeof(ff_fmt_str
),
640 POUT("alsa pcm layout \"%s\"/\"%s\" wired strictly to ffmpeg format \"%sbits\"\n", snd_pcm_format_description(alsa_fmt
), snd_pcm_access_name(alsa_access
), ff_fmt_str
);
643 static void pcm2ff(snd_pcm_t
*pcm
, enum AVSampleFormat
*ff_fmt
,
644 int *ff_rate
, int *ff_chans_n
, uint64_t *ff_chans_layout
,
648 snd_pcm_hw_params_t
*hw_params
;
649 snd_pcm_access_t pcm_access
;
650 snd_pcm_format_t pcm_fmt
;
651 unsigned int pcm_rate
;
652 unsigned int pcm_chans_n
;
654 r
= snd_pcm_hw_params_malloc(&hw_params
);
656 FATAL("alsa:unable to allocate hardware parameters context for ffmpeg filter wiring\n");
657 r
= snd_pcm_hw_params_current(pcm
, hw_params
);
659 FATAL("alsa:unable to get current hardware parameters for ffmpeg filter wiring\n");
660 r
= snd_pcm_hw_params_get_access(hw_params
, &pcm_access
);
662 FATAL("alsa:unable to get the pcm access for ffmpeg filter wiring\n");
663 r
= snd_pcm_hw_params_get_format(hw_params
, &pcm_fmt
);
665 FATAL("alsa:unable to get the pcm format for ffmpeg filter wiring\n");
666 /*--------------------------------------------------------------------*/
667 pcm_layout2ff_fmt_strict(pcm_fmt
, pcm_access
, ff_fmt
, print_info
);
668 /*--------------------------------------------------------------------*/
669 r
= snd_pcm_hw_params_get_rate(hw_params
, &pcm_rate
,
670 SND_PCM_STREAM_PLAYBACK
);
672 FATAL("alsa:unable to get the pcm rate for ffmpeg filter wiring\n");
673 *ff_rate
= (int)pcm_rate
;
674 r
= snd_pcm_hw_params_get_channels(hw_params
, &pcm_chans_n
);
676 FATAL("alsa:unable to get the pcm count of channels for ffmpeg filter wiring\n");
677 *ff_chans_n
= (int)pcm_chans_n
;
678 /*--------------------------------------------------------------------*/
679 *ff_chans_layout
= pcm_chmaps2ff_chans_layout(pcm
, pcm_chans_n
,
681 /*--------------------------------------------------------------------*/
682 snd_pcm_hw_params_free(hw_params
);
684 static void abufsrc_cfg(enum AVFrameFormat fmt
, int rate
, int chans_n
,
685 uint64_t chans_layout
, bool print_info
)
689 u8 chans_layout_str
[STR_SZ
]; /* should be overkill */
691 abufsrc_filt
= avfilter_get_by_name("abuffer");
692 if (abufsrc_filt
== 0)
693 FATAL("audio buffer source:could not find the filter\n");
694 abufsrc_ctx
= avfilter_graph_alloc_filter(filter_graph
, abufsrc_filt
,
696 if (abufsrc_ctx
== 0)
697 FATAL("audio buffer source context:could not allocate the instance in the filter graph\n");
698 r
= av_opt_set(abufsrc_ctx
, "sample_fmt", av_get_frame_fmt_name(fmt
),
699 AV_OPT_SEARCH_CHILDREN
);
701 FATAL("audio buffer source context:unable to set the decoder frame format option\n");
702 r
= av_opt_set_int(abufsrc_ctx
, "sample_rate", rate
,
703 AV_OPT_SEARCH_CHILDREN
);
705 FATAL("audio buffer source context:unable to set the decoder rate option\n");
707 * XXX: at the time of coding, bug for 1 chans layout... or I did miss
708 * some valuable information
710 av_get_channel_layout_string(chans_layout_str
, sizeof(chans_layout_str
),
711 chans_n
, chans_layout
);
713 POUT("audio buffer source context:using channels layout \"%s\" (%d pcm channels)\n", chans_layout_str
, chans_n
);
714 r
= av_opt_set(abufsrc_ctx
, "channel_layout", chans_layout_str
,
715 AV_OPT_SEARCH_CHILDREN
);
717 FATAL("audio buffer source context:unable to set the decoder channel layout option\n");
718 r
= avfilter_init_str(abufsrc_ctx
, 0);
720 FATAL("audio buffer source context:unable to initialize\n");
722 static void vol_cfg(bool muted
, double vol
)
725 u8 vol_l10n_str
[sizeof("xxx.xx")]; /* should be overkill */
728 vol_filt
= avfilter_get_by_name("volume");
730 FATAL("volume:could not find the filter\n");
731 vol_ctx
= avfilter_graph_alloc_filter(filter_graph
, vol_filt
, "vol");
733 FATAL("volume context:could not allocate the instance in the filter graph\n");
738 /* yeah the radix is localized, can be '.', ','... */
739 snprintf(vol_l10n_str
, sizeof(vol_l10n_str
), "%f", vol_double
);
740 r
= av_opt_set(vol_ctx
, "volume", vol_l10n_str
, AV_OPT_SEARCH_CHILDREN
);
742 FATAL("volume context:unable to set the volume option\n");
743 r
= avfilter_init_str(vol_ctx
, 0);
745 FATAL("volume buffer context:unable to initialize\n");
747 static void afmt_cfg(enum AVFrameFormat fmt
, int rate
, int chans_n
,
748 uint64_t chans_layout
, bool print_info
)
751 u8 rate_str
[sizeof("dddddd")];
752 u8 chans_layout_str
[STR_SZ
]; /* should be overkill */
754 afmt_filt
= avfilter_get_by_name("aformat");
756 FATAL("audio format:could not find the filter");
757 afmt_ctx
= avfilter_graph_alloc_filter(filter_graph
, afmt_filt
, "afmt");
759 FATAL("audio format:could not allocate the instance in the filter graph\n");
760 r
= av_opt_set(afmt_ctx
, "sample_fmts", av_get_frame_fmt_name(fmt
),
761 AV_OPT_SEARCH_CHILDREN
);
763 FATAL("audio format context:could to set the pcm sample format\n");
764 snprintf(rate_str
, sizeof(rate_str
), "%d", rate
);
765 r
= av_opt_set(afmt_ctx
, "sample_rates", rate_str
,
766 AV_OPT_SEARCH_CHILDREN
);
768 FATAL("audio format context:could not set the pcm rate\n");
769 av_get_channel_layout_string(chans_layout_str
, sizeof(chans_layout_str
),
770 chans_n
, chans_layout
);
771 r
= av_opt_set(afmt_ctx
, "channel_layouts", chans_layout_str
,
772 AV_OPT_SEARCH_CHILDREN
);
774 FATAL("audio format context:could not set the layout of channels\n");
776 POUT("audio format context:channel layout is \"%s\"\n", chans_layout_str
);
777 r
= avfilter_init_str(afmt_ctx
, 0);
779 FATAL("audio format context:unable to initialize\n");
781 static void abufsink_cfg(void)
785 abufsink_filt
= avfilter_get_by_name("abuffersink");
786 if (abufsink_filt
== 0)
787 FATAL("audio buffer sink:could not find the filter\n");
788 abufsink_ctx
= avfilter_graph_alloc_filter(filter_graph
, abufsink_filt
,
790 if (abufsink_ctx
== 0)
791 FATAL("audio buffer sink context:could not allocate the instance in the filter graph\n");
792 r
= avfilter_init_str(abufsink_ctx
, 0);
794 FATAL("audio buffer sink context:unable to initialize\n");
796 static void dec_ctx_cfg(AVCodecParameters
*params
)
800 dec
= avcodec_find_decoder(params
->codec_id
);
802 FATAL("ffmpeg:unable to find a proper decoder\n");
803 avcodec_free_context(&dec_ctx
);
804 dec_ctx
= avcodec_alloc_context3(dec
);
806 FATAL("ffmpeg:unable to allocate a decoder context\n");
808 r
= avcodec_parameters_to_context(dec_ctx
, params
);
810 FATAL("ffmpeg:unable to apply codec parameters in codec context\n");
811 /* XXX: ffmpeg thread count default is 1, set to 0 = auto */
812 dec_ctx
->thread_count
= 0;
813 r
= avcodec_open2(dec_ctx
, dec
, 0);
815 FATAL("ffmpeg:unable to open the decoder context\n");
817 static void filter_graph_cfg(
818 enum AVSampleFormat src_fmt
, int src_rate
, int src_chans_n
,
819 uint64_t src_chans_layout
,
820 bool muted
, double vol
,
821 enum AVSampleFormat dst_fmt
, int dst_rate
, int dst_chans_n
,
822 uint64_t dst_chans_layout
, bool print_info
)
827 avfilter_graph_free(&filter_graph
);
829 filter_graph
= avfilter_graph_alloc();
830 if (filter_graph
== 0)
831 FATAL("unable to create filter graph\n");
832 abufsrc_cfg(src_fmt
, src_rate
, src_chans_n
, src_chans_layout
,
835 afmt_cfg(dst_fmt
, dst_rate
, dst_chans_n
, dst_chans_layout
, print_info
);
837 r
= avfilter_link(abufsrc_ctx
, 0, vol_ctx
, 0);
839 FATAL("unable to connect the audio buffer source filter to the volume filter\n");
840 r
= avfilter_link(vol_ctx
, 0, afmt_ctx
, 0);
842 FATAL("unable to connect the volume filter to the audio format filter\n");
843 r
= avfilter_link(afmt_ctx
, 0, abufsink_ctx
, 0);
845 FATAL("unable to connect the audio format filter to the audio buffer sink filter\n");
846 r
= avfilter_graph_config(filter_graph
, 0);
848 FATAL("unable to configure the filter graph\n");
849 /*--------------------------------------------------------------------*/
852 dump_str
= avfilter_graph_dump(filter_graph
, 0);
854 WARNING("unable to get a filter graph description\n");
857 POUT("GRAPH START-------------------------------------------------------\n");
858 POUT("%s", dump_str
);
860 POUT("GRAPH END---------------------------------------------------------\n");
862 #define DONT_PRINT_INFO false
863 static void filt_flush(void)
865 enum AVSampleFormat dst_fmt
;
868 uint64_t dst_chans_layout
;
870 av_frames_unref(filt_frs
.av
);
871 filt_frs
.pcm_written_ufrs_n
= 0;
873 pcm2ff(pcm_g
, &dst_fmt
, &dst_rate
, &dst_chans_n
, &dst_chans_layout
,
876 dec_ctx
->sample_fmt
, dec_ctx
->sample_rate
,
877 dec_ctx
->channels
, dec_ctx
->channel_layout
,
878 filt_frs
.muted
, filt_frs
.vol
,
879 dst_fmt
, dst_rate
, dst_chans_n
, dst_chans_layout
,
882 #undef DONT_PRINT_INFO
883 static void stdin_tty_init_once(void)
886 struct termios tio_new
;
887 struct termios tio_chk
;
891 POUT("input:standard input is not a terminal\n");
894 memset(&stdin_tio_save
, 0, sizeof(stdin_tio_save
));
895 r
= tcgetattr(0, &stdin_tio_save
);
897 FATAL("input:unable to get the current standard input terminal line attributes\n");
898 tio_new
= stdin_tio_save
;
899 tio_new
.c_lflag
&= ~(ICANON
|ECHO
);
900 tio_new
.c_cc
[VMIN
] = 1; /* 1 "char", could be bytes from a utf8 code point */
901 tio_new
.c_cc
[VTIME
] = 0;
902 r
= tcsetattr(0, TCSANOW
, &tio_new
);
903 stdin_tty_cfg_modified
= true;
905 FATAL("input:unable to set all standard input terminal line\n");
906 r
= tcgetattr(0, &tio_chk
);
908 FATAL("input:unable to get the current standard input terminal line attributes for checking\n");
909 r
= memcmp(&tio_chk
, &tio_new
, sizeof(tio_chk
));
911 FATAL("input:setting the wanted terminal line attributes failed\n");
913 static void stdin_flags_init_once(void)
916 /* switch the standard input to non-blocking */
917 r
= fcntl(0, F_GETFL
);
919 FATAL("input:unable to get the file flags of the standard input\n");
920 stdin_flags_save
= r
;
922 r
= fcntl(0, F_SETFL
, r
);
924 FATAL("input:unable to set non-blocking operations on the standard input\n");
926 static void stdout_init_once(void)
932 POUT("output:standard output not is not a terminal\n");
933 stdout_is_tty
= false;
936 stdout_is_tty
= true;
939 * block as much as possible.
940 * handle only async "usual" sigs, with sync signalfd.
941 * allow some signals to go thru though.
942 * always presume the process "controlling terminal" is different than the
943 * terminal connected on standard input and standard output
945 static void sigs_init_once(void)
950 r
= sigfillset(&sset
);
952 FATAL("unable to get a full signal mask\n");
953 /* the "controlling terminal" line asks for a core dump, leave it be */
954 r
= sigdelset(&sset
, SIGQUIT
);
956 FATAL("unable to remove SIGQUIT from our signal mask\n");
957 r
= pthread_sigmask(SIG_SETMASK
, &sset
, 0);
959 FATAL("unable to \"block\" \"all\" signals\n");
960 /* from here, we "steal" signals with signalfd */
961 r
= sigemptyset(&sset
);
963 FATAL("unable to get an empty signal mask\n");
964 /* we are asked nicely to terminate */
965 r
= sigaddset(&sset
, SIGTERM
);
967 FATAL("unable to add SIGTERM to our signal mask\n");
968 /* the "controlling terminal" line (^c) asks nicely to terminate */
969 r
= sigaddset(&sset
, SIGINT
);
971 FATAL("unable to add SIGINT to our signal mask\n");
972 r
= signalfd(-1, &sset
, SFD_NONBLOCK
);
974 FATAL("unable to get a signalfd file descriptor\n");
977 static void evt_init_once(void)
981 struct epoll_event evt
;
983 ep_fd
= epoll_create1(0);
985 FATAL("unable to create the epoll file descriptor\n");
986 /*--------------------------------------------------------------------*/
988 evt
.events
= EPOLLIN
;
989 evt
.data
.fd
= sig_fd
;
990 r
= epoll_ctl(ep_fd
, EPOLL_CTL_ADD
, sig_fd
, &evt
);
992 FATAL("unable to add the signalfd file descriptior to the epoll file descriptor\n");
993 /*--------------------------------------------------------------------*/
994 /* standard input/terminal */
995 evt
.events
= EPOLLIN
;
997 r
= epoll_ctl(ep_fd
, EPOLL_CTL_ADD
, 0, &evt
);
999 FATAL("unable to add the standard input to the epoll file descriptor\n");
1000 /*--------------------------------------------------------------------*/
1001 /* the timer in charge of accounting unknown esc seq */
1002 evt
.events
= EPOLLIN
;
1003 evt
.data
.fd
= input_timer_fd
;
1004 r
= epoll_ctl(ep_fd
, EPOLL_CTL_ADD
, input_timer_fd
, &evt
);
1006 FATAL("unable to add the timer file descriptor accounting for unknown escape sequences to epoll file descriptor\n");
1008 static void input_state_init_once(void)
1010 input_timer_fd
= timerfd_create(CLOCK_MONOTONIC
, TFD_NONBLOCK
);
1011 if (input_timer_fd
== -1)
1012 FATAL("unable to get a timer file descriptor\n");
1014 input_esc_seq_mode
= false;
1016 esc_seq_next_byte
= 0;
1017 utf8_cp_next_byte
= 0;
1019 static void input_utf8_cp_bind_cmd(void)
1025 struct tty_bind_t
*bind
;
1027 if (i
== ARRAY_N(tty_binds
))
1029 bind
= tty_binds
+ i
;
1031 /* exclude esc seq binds */
1032 if ((bind
->c
[0] != 0x1b) && (utf8_cp_sz
== bind
->sz
)) {
1035 r
= memcmp(utf8_cp
, bind
->c
, utf8_cp_sz
);
1045 * to exit the esc seq input mode, we could implement a smart tree in order to
1046 * know if it is not possible to get any defined esc seq, or we could already
1047 * use the maximum bind esc seq sz
1049 static bool input_esc_seq_bind_cmd(void)
1055 struct tty_bind_t
*bind
;
1057 if (i
== ARRAY_N(tty_binds
))
1059 bind
= tty_binds
+ i
;
1060 /* only esc seq binds */
1061 if ((bind
->c
[0] == 0x1b) && (esc_seq_sz
== bind
->sz
)) {
1064 r
= memcmp(esc_seq
, bind
->c
, esc_seq_sz
);
1074 static void input_byte_esc_seq(void)
1077 struct itimerspec t
;
1079 if (input_b
== 0x1b) {
1081 esc_seq_next_byte
= 1;
1082 memset(&t
, 0, sizeof(t
));
1083 t
.it_value
.tv_sec
= INPUT_ESC_SEQ_TIMEOUT_SECS_N
;
1084 r
= timerfd_settime(input_timer_fd
, 0, &t
, 0);
1086 FATAL("unable to arm the timer to account for unknown input escape sequence from the terminal\n");
1089 esc_seq
[esc_seq_next_byte
] = input_b
;
1090 ++esc_seq_next_byte
;
1091 if (!input_esc_seq_bind_cmd() && (esc_seq_next_byte
!= STR_SZ
))
1093 memset(&t
, 0, sizeof(t
));
1094 r
= timerfd_settime(input_timer_fd
, 0, &t
, 0);
1096 FATAL("unable to disarm the timer used to account for unknown input escape sequence from the terminal\n");
1097 esc_seq_next_byte
= 0;
1098 input_esc_seq_mode
= false;
1099 utf8_cp_next_byte
= 0;
1101 static void input_byte_utf8_cp(void)
1103 if ((input_b
& 0x80) != 0) { /* utf8 cp > 0x7f */
1104 if ((input_b
& 0x40) != 0) { /* utf8 cp start byte */
1105 utf8_cp
[0] = input_b
;
1106 utf8_cp_next_byte
= 1;
1107 if ((input_b
& 0x20) == 0)
1109 else if ((input_b
& 0x10) == 0)
1111 else /* if ((input_b & 0x08) == 0) */
1112 utf8_cp_sz
= 4; /* must be 4 */
1115 /* (b & 0x40) == 0, utf8 cp continuation byte */
1117 * no start byte, discard (but should skip all following
1118 * continuation bytes and send the utf8 "invalid" cp)
1120 if (utf8_cp_next_byte
== 0)
1122 utf8_cp
[utf8_cp_next_byte
] = input_b
;
1123 ++utf8_cp_next_byte
;
1124 if (utf8_cp_next_byte
!= utf8_cp_sz
)
1126 } else {/* ascii 0x00 - 0x7f */
1127 if (input_b
== 0x1b) {/* esc */
1128 /* change state and process the esc byte */
1129 input_esc_seq_mode
= true;
1130 input_byte_esc_seq();
1133 utf8_cp
[0] = input_b
;
1136 input_utf8_cp_bind_cmd();
1138 /* we are either reading an utf8 cp or an esc seq */
1139 static void evt_input_drain(void) { loop
1144 r
= read(0, &input_b
, 1);
1146 if (errno
== EAGAIN
) /* no more input data */
1148 if (errno
== EINTR
) /* restart manually the call */
1150 FATAL("an error occured while reading the input\n");
1153 FATAL("input end of file\n");
1154 if (!input_esc_seq_mode
)
1155 input_byte_utf8_cp();
1157 input_byte_esc_seq();
1159 static void evt_sigs(void)
1162 struct signalfd_siginfo siginfo
;
1164 /* no short reads */
1165 r
= read(sig_fd
, &siginfo
, sizeof(siginfo
));
1166 if (r
!= sizeof(siginfo
))
1167 FATAL("unable to read signal information\n");
1169 switch (siginfo
.ssi_signo
) {
1171 EXIT("received SIGTERM\n");
1173 EXIT("received SIGINT\n");
1175 WARNING("signal handle:unwanted signal %d received, discarding\n", siginfo
.ssi_signo
);
1178 static void evt_timer(void)
1181 struct itimerspec t
;
1183 memset(&t
, 0, sizeof(t
));
1184 r
= timerfd_settime(input_timer_fd
, 0, &t
, 0);
1186 FATAL("unable to disarm the timer used to account for unknown input escape sequences from the terminal\n");
1188 esc_seq_next_byte
= 0;
1189 input_esc_seq_mode
= false;
1191 utf8_cp_next_byte
= 0;
1193 static void evt_handle(struct epoll_event
*evt
, bool *pcm_evt
)
1195 if (evt
->data
.fd
== 0) {
1196 if ((evt
->events
& EPOLLIN
) != 0)
1199 FATAL("event loop wait:input:unexpected event\n");
1200 } else if (evt
->data
.fd
== sig_fd
) {
1201 if ((evt
->events
& EPOLLIN
) != 0)
1204 FATAL("event loop wait:signal:unexpected event\n");
1205 } else if (evt
->data
.fd
== input_timer_fd
) {
1206 if ((evt
->events
& EPOLLIN
) != 0)
1209 FATAL("event loop wait:timer:unexpected event\n");
1210 } else { /* only update alsa fds */
1215 if (i
== pcm_pollfds_n
)
1218 if (evt
->data
.fd
== pcm_pollfds
[i
].fd
) {
1219 pcm_pollfds
[i
].revents
= evt
->events
;
1226 /* fill the dec with pkts */
1227 static void dec_fill(void) { loop
1234 rd
= atomic_load(&cb
.rd
);
1235 sd
= atomic_load(&cb
.sd
);
1236 /* at start, we must read pkt before we can send one */
1239 r
= avcodec_send_packet(dec_ctx
, cb
.pkts
[sd
]);
1240 /* dec is full and the pkt was rejected, or the decoder is in EOF */
1241 if (r
== AVERROR(EAGAIN
) || r
== AVERROR_EOF
)
1244 FATAL("ffmpeg:error while sending the packet to the decoder\n");
1246 av_packet_unref(cb
.pkts
[sd
]);
1248 atomic_store(&cb
.sd
, next_sd
);
1251 * return true if we have 1 dec_frs.av, false if no more dec_frs.av
1254 static bool dec_frs_get(void) { loop
1260 /* will unref the dec_frs.av bufs for us */
1261 r
= avcodec_receive_frames(dec_ctx
, dec_frs
.av
);
1262 if (r
== AVERROR(EAGAIN
))
1265 if (dec_frs
.av
->pts
!= AV_NOPTS_VALUE
)
1266 dec_frs
.most_recent_ts
= dec_frs
.av
->pts
;
1267 else if (dec_frs
.av
->pkt_dts
!= AV_NOPTS_VALUE
)
1268 dec_frs
.most_recent_ts
= dec_frs
.av
->pkt_dts
;
1270 dec_frs
.most_recent_ts
= dec_frs
.av
->pkt_dts
;
1271 return true; /* "return" the current dec_frs.av */
1272 } else if (r
== AVERROR_EOF
) {
1273 POUT("ffmpeg:last decoder frames reached (receiving)\n");
1276 FATAL("ffmpeg:error while receiving frames from the decoder\n");
1278 static bool filt_frs_get(void) { loop
1282 if (!filt_frs
.no_more_dec_frs
) {
1283 if(!dec_frs_get()) {
1284 filt_frs
.no_more_dec_frs
= true;
1286 r
= av_buffersrc_add_frame_flags(abufsrc_ctx
,
1287 0 , AV_BUFFERSRC_FLAG_PUSH
1288 | AV_BUFFERSRC_FLAG_KEEP_REF
);
1290 FATAL("ffmpeg:unable to notify the end of data to the filter source audio buffer context\n");
1293 * the dec_frs bufs will be unref in
1294 * avcodec_receive_frames
1296 r
= av_buffersrc_add_frame_flags(abufsrc_ctx
,
1297 dec_frs
.av
, AV_BUFFERSRC_FLAG_PUSH
1298 | AV_BUFFERSRC_FLAG_KEEP_REF
);
1300 FATAL("ffmpeg:unable to submit the decoder frames to the filter source audio buffer context\n");
1304 * the last dec_frs should switch the filter in draining mode,
1305 * and filt_frs.av won't matter.
1307 r
= av_buffersink_get_frame(abufsink_ctx
, filt_frs
.av
);
1308 if (r
== AVERROR(EAGAIN
)) {
1310 * won't happen if no more dec frs are available thanks
1311 * to eof propagation along the processing graph, in theory
1314 } else if (r
>= 0) {
1315 filt_frs
.pcm_written_ufrs_n
= 0;
1317 } else if (r
== AVERROR_EOF
) {
1318 POUT("ffmpeg:last filter frs reached (getting)\n");
1321 FATAL("ffmpeg:error while getting frs from the filter\n");
1324 static void chans_buf_init(u8
**chans_buf
, int start_fr_idx
)
1329 sample_bytes_n
= av_get_bytes_per_sample(filt_frs
.av
->format
);
1331 is_planar_fmt
= av_frame_fmt_is_planar(filt_frs
.av
->format
);
1332 if (is_planar_fmt
== NO
) { /* or is pcm interleaved */
1335 fr_bytes_n
= sample_bytes_n
* filt_frs
.av
->channels
;
1336 chans_buf
[0] = (u8
*)filt_frs
.av
->data
[0] + start_fr_idx
1338 } else { /* ffmpeg planar or pcm noninterleaved */
1343 if (p
== filt_frs
.av
->channels
)
1345 chans_buf
[p
] = (u8
*)filt_frs
.av
->data
[p
]
1346 + start_fr_idx
* sample_bytes_n
;
1353 static void chans_buf_inc(u8
**chans_buf
, int frs_inc
)
1358 sample_bytes_n
= av_get_bytes_per_sample(filt_frs
.av
->format
);
1360 is_planar_fmt
= av_frame_fmt_is_planar(filt_frs
.av
->format
);
1361 if (is_planar_fmt
== NO
) { /* or is pcm interleaved */
1364 fr_bytes_n
= sample_bytes_n
* filt_frs
.av
->channels
;
1365 chans_buf
[0] += frs_inc
* fr_bytes_n
;
1366 } else { /* ffmpeg planar or pcm noninterleaved */
1371 if (p
== filt_frs
.av
->channels
)
1373 chans_buf
[p
] += frs_inc
* sample_bytes_n
;
1380 static void pcm_silence_frs_write(snd_pcm_uframes_t ufrs_n
)
1387 is_planar_fmt
= av_frame_fmt_is_planar(filt_frs
.av
->format
);
1388 if (is_planar_fmt
== NO
)
1389 (void)snd_pcm_writei(pcm_g
, silence_bufs
[0], ufrs_n
);
1391 (void)snd_pcm_writen(pcm_g
, silence_bufs
, ufrs_n
);
1395 static void pcm_filt_frs_write(snd_pcm_uframes_t ufrs_n
) { loop
1398 u8
*chans_buf
[AV_NUM_DATA_POINTERS
];
1399 snd_pcm_sframes_t r0
;
1400 snd_pcm_uframes_t ufrs_to_write_n
;
1401 snd_pcm_uframes_t filt_frs_remaining_ufrs_n
; /* for clarity */
1406 /* create the chan buf pointers */
1407 chans_buf_init(chans_buf
, (int)filt_frs
.pcm_written_ufrs_n
);
1409 filt_frs_remaining_ufrs_n
= (snd_pcm_uframes_t
)filt_frs
.av
->frames_n
1410 - filt_frs
.pcm_written_ufrs_n
;
1411 if (filt_frs_remaining_ufrs_n
> ufrs_n
)
1412 ufrs_to_write_n
= ufrs_n
;
1414 ufrs_to_write_n
= filt_frs_remaining_ufrs_n
;
1418 snd_pcm_uframes_t written_ufrs_n
;
1420 is_planar_fmt
= av_frame_fmt_is_planar(filt_frs
.av
->format
);
1421 if (is_planar_fmt
== NO
)
1422 r0
= snd_pcm_writei(pcm_g
, chans_buf
[0],
1425 r0
= snd_pcm_writen(pcm_g
, (void**)chans_buf
,
1428 if (r0
== -EAGAIN
) /* return to epoll */
1430 else if (r0
== -EPIPE
|| r0
== -ESTRPIPE
) {
1431 /* underrun or suspended */
1434 r1
= snd_pcm_recover(pcm_g
, (int)r0
, 0);
1436 WARNING("alsa:pcm recovered going back to epoll\n");
1437 return; /* recovered, go back to epoll */
1439 FATAL("alsa:unable to recover from suspend/underrun\n");
1441 FATAL("alsa:fatal/unhandled error while writing the frames\n");
1444 written_ufrs_n
= (snd_pcm_uframes_t
)r0
;
1445 filt_frs
.pcm_written_ufrs_n
+= written_ufrs_n
;
1446 ufrs_n
-= written_ufrs_n
;
1447 ufrs_to_write_n
-= written_ufrs_n
;
1449 chans_buf_inc(chans_buf
, (int)written_ufrs_n
);
1451 if (ufrs_to_write_n
== 0)
1454 if (filt_frs
.pcm_written_ufrs_n
1455 == (snd_pcm_uframes_t
)filt_frs
.av
->frames_n
) {
1456 av_frame_unref(filt_frs
.av
);
1458 if (!filt_frs_get()) { /* no more filt frs ? */
1459 loop
{ /* spinning */
1461 snd_pcm_state_t state
;
1463 r1
= snd_pcm_drain(pcm_g
);
1469 * the pcm state can change asynchronously,
1470 * and if the draining was successful, the
1471 * pcm should be in SETUP state, and in this
1472 * state, snd_pcm_drain _must_ fail (direct
1475 state
= snd_pcm_state(pcm_g
);
1476 if (state
== SND_PCM_STATE_SETUP
)
1479 /**********************************************/
1480 EXIT("finished playing\n");
1481 /**********************************************/
1486 static void evt_pcm_write(void)
1488 snd_pcm_sframes_t r0
;
1489 /* try only 2 times */
1490 r0
= snd_pcm_avail(pcm_g
);
1492 if (r0
== -EPIPE
|| r0
== -ESTRPIPE
) {
1493 /* underrun or suspended */
1496 r1
= snd_pcm_recover(pcm_g
, (int)r0
, 0);
1498 WARNING("alsa:pcm recovered retrying to get some available frames\n");
1499 r0
= snd_pcm_avail(pcm_g
);
1501 FATAL("alsa:unable to get some available frames after recovery\n");
1503 FATAL("alsa:unable to recover from suspend/underrun\n");
1505 FATAL("alsa:error getting some available frames\n");
1509 pcm_silence_frs_write((snd_pcm_uframes_t
)r0
);
1511 pcm_filt_frs_write((snd_pcm_uframes_t
)r0
);
1513 #define EPOLL_EVTS_N 8 /* why not */
1514 static void evts_loop(void)
1518 struct epoll_event evts
[EPOLL_EVTS_N
];
1524 memset(evts
, 0, sizeof(evts
));
1525 fds_n
= epoll_wait(ep_fd
, evts
, EPOLL_EVTS_N
, -1);
1527 if (errno
== EINTR
) {
1528 WARNING("event loop wait:was interrupted by a signal\n");
1531 FATAL("event loop wait:an error occured\n");
1536 if (fd_idx
== fds_n
)
1538 evt_handle(&evts
[fd_idx
], &pcm_evt
);
1544 * since alsa could use several file descriptors, only once the
1545 * pollfds were properly updated we can actually know we got
1546 * something from alsa
1548 r
= snd_pcm_poll_descriptors_revents(pcm_g
, pcm_pollfds
, pcm_pollfds_n
,
1551 FATAL("alsa:error processing the poll file descriptors\n");
1552 if ((pcm_evts
& ~POLLOUT
) != 0)
1553 FATAL("alsa:unexpected events\n");
1554 if ((pcm_evts
& POLLOUT
) != 0)
1558 static void silence_bufs_init_once(void)
1560 memset(silence_bufs
, 0, sizeof(silence_bufs
));
1562 static void silence_bufs_cfg(snd_pcm_t
*pcm
, bool print_info
)
1565 snd_pcm_hw_params_t
*hw_params
;
1566 snd_pcm_uframes_t buf_ufrs_n
;
1567 snd_pcm_format_t fmt
;
1568 snd_pcm_access_t access
;
1569 unsigned int chans_n
;
1572 r
= snd_pcm_hw_params_malloc(&hw_params
);
1574 FATAL("silence:alsa:unable to allocate memory for a hardware parameters container\n");
1575 r
= snd_pcm_hw_params_current(pcm
, hw_params
);
1577 FATAL("silence:alsa:unable to get the pcm hardware parameters\n");
1578 r
= snd_pcm_hw_params_get_buffer_size(hw_params
, &buf_ufrs_n
);
1580 FATAL("silence:alsa:unable to get the number of frames in the pcm buffer\n");
1581 r
= snd_pcm_hw_params_get_format(hw_params
, &fmt
);
1583 FATAL("silence:alsa:unable to get the pcm format\n");
1584 r
= snd_pcm_hw_params_get_access(hw_params
, &access
);
1586 FATAL("silence:alsa:unable to get the pcm access mode\n");
1587 r
= snd_pcm_hw_params_get_channels(hw_params
, &chans_n
);
1589 FATAL("silence:alsa:unable to get the pcm number of channels\n");
1590 /* wipe silence bufs first */
1593 if (c
== AV_NUM_DATA_POINTERS
)
1595 if (silence_bufs
[c
] != 0) {
1596 free(silence_bufs
[c
]);
1597 silence_bufs
[c
] = 0;
1601 if (access
== SND_PCM_ACCESS_RW_INTERLEAVED
1602 || access
== SND_PCM_ACCESS_MMAP_INTERLEAVED
) {
1603 ssize_t buf_bytes_n
;
1605 buf_bytes_n
= snd_pcm_frames_to_bytes(pcm
,
1606 (snd_pcm_sframes_t
)buf_ufrs_n
);
1607 if (buf_bytes_n
<= 0)
1608 FATAL("silence:alsa:interleaved:unable to get the pcm number of bytes of all buffer frames\n");
1609 silence_bufs
[0] = malloc((size_t)buf_bytes_n
);
1610 if (silence_bufs
[0] == 0)
1611 FATAL("silence:interleaved:unable to allocate the silence buffer of %d bytes\n", (int)buf_bytes_n
);
1613 POUT("silence:interleaved:buffer of %d bytes is allocated\n", (int)buf_bytes_n
);
1614 r
= snd_pcm_format_set_silence(fmt
, silence_bufs
[0],
1615 (unsigned int)buf_ufrs_n
);
1617 FATAL("silence:interleaved:unable to fill with silence the buffer\n");
1618 POUT("silence:interleaved:silence buffer filled with %u silence frames\n", buf_ufrs_n
);
1619 } else if (access
== SND_PCM_ACCESS_RW_NONINTERLEAVED
1620 || access
== SND_PCM_ACCESS_MMAP_NONINTERLEAVED
) {
1621 ssize_t buf_bytes_n
;
1624 buf_samples_n
= (long)buf_ufrs_n
;
1625 buf_bytes_n
= snd_pcm_samples_to_bytes(pcm
, buf_samples_n
);
1626 if (buf_bytes_n
<= 0)
1627 FATAL("silence:alsa:non interleaved:unable to get the pcm number of total bytes of all buffer samples\n");
1632 silence_bufs
[c
] = malloc((size_t)buf_bytes_n
);
1633 if (silence_bufs
[c
] == 0)
1634 FATAL("silence:non interleaved:unable to allocate silence buffer %u of %d bytes\n", c
, (int)buf_bytes_n
);
1635 r
= snd_pcm_format_set_silence(fmt
, silence_bufs
[c
],
1636 (unsigned int)buf_samples_n
);
1638 FATAL("silence:non interleaved:unable to fill with silence the buffer\n");
1640 POUT("silence:non interleaved:buffer[%u] of %d bytes is allocated\n", c
, (int)buf_bytes_n
);
1644 POUT("silence:non interleaved:allocated %u silence buffers for %u frames\n", chans_n
, (unsigned int)buf_ufrs_n
);
1646 FATAL("silence:the pcm access type is not supported\n");
1647 snd_pcm_hw_params_free(hw_params
);
1649 static void ffmpeg_log_stdout(void *a
, int b
, const char *fmt
, va_list ap
)
1653 static void usage(void)
1656 npa [-p alsa pcm] [-v volume(0..100)] [-h] url\n");
1658 static void opts_parse(int argc
, u8
**args
, u8
**url
, u8
**pcm_str
,
1659 double *initial_vol
)
1669 if (strcmp("-p", args
[i
]) == 0) {
1670 if ((i
+ 1) == argc
)
1671 FATAL("-p:alsa pcm is missing\n");
1672 *pcm_str
= args
[i
+ 1];
1673 POUT("-p:alsa pcm \"%s\"\n", *pcm_str
);
1675 } else if (strcmp("-v", args
[i
]) == 0) {
1676 unsigned long vol_ul
;
1678 if ((i
+ 1) == argc
)
1679 FATAL("-v:initial volume option is missing\n");
1680 vol_ul
= strtoul(args
[i
+ 1], 0, 10);
1681 if (vol_ul
< 0 || 100 < vol_ul
)
1682 FATAL("-v:invalid volume value %lu (0..100)\n", vol_ul
);
1683 *initial_vol
= (double)vol_ul
/ 100.0;
1684 POUT("-v:using initial volume %f\n", *initial_vol
);
1686 } else if (strcmp("-h", args
[i
]) == 0) {
1695 FATAL("missing url\n");
1696 *url
= args
[url_idx
];
1697 POUT("playing ####%s####\n", *url
);
1699 #define RESET_DONE 0
1700 static void cb_init_once(void)
1706 cb
.pkts
[i
] = av_packet_alloc();
1707 if (cb
.pkts
[i
] == 0)
1708 FATAL("unable to allocate a packet reference for the circular buffer\n");
1713 atomic_store(&cb
.rd
, 0);
1714 atomic_store(&cb
.sd
, 0);
1715 atomic_store(&cb
.st_idx
, -1);
1716 atomic_store(&cb
.reset
, RESET_DONE
);
1719 static void filter_graph_init_once(void)
1730 /* floating point strs are localized... */
1731 snprintf(double_zero_l10n_str
, sizeof(double_zero_l10n_str
), "%f", 0.);
1732 memset(&filt_frs
, 0, sizeof(filt_frs
));
1733 filt_frs
.av
= av_frames_alloc();
1734 if (filt_frs
.av
== 0)
1735 FATAL("ffmpeg:unable to allocate a filtered frames structure\n");
1737 static void dec_init_once(void)
1741 dec_frs
.av
= av_frames_alloc();
1742 if (dec_frs
.av
== 0)
1743 FATAL("ffmpeg:unable to allocate a decoded frames structure\n");
1744 dec_frs
.most_recent_ts
= AV_NOPTS_VALUE
;
1746 static void rd_thd_init_once(void)
1748 rd_thd_pkt
= av_packet_alloc();
1749 if (rd_thd_pkt
== 0)
1750 FATAL("ffmpeg:unable to allocate a packet for the read thread\n");
1752 static void fmt_init_once(u8
*url
)
1757 r
= avformat_open_input(&fmt_ctx
, url
, NULL
, NULL
);
1759 FATAL("ffmpeg:unable to open \"%s\"\n", url
);
1760 /* probe beyond the header, if any */
1761 r
= avformat_find_stream_info(fmt_ctx
, 0);
1763 FATAL("ffmpeg:unable to probe \"%s\"\n", url
);
1764 r
= pthread_mutex_init(&fmt_ctx_mutex
, 0);
1766 FATAL("unable to init the format context mutex\n");
1768 static void pcm_init_once(u8
*pcm_str
)
1772 r
= snd_output_stdio_attach(&pcm_pout
, stdout
, 0);
1774 FATAL("alsa:unable to attach stdout\n");
1775 r
= snd_output_stdio_attach(&pcm_perr
, stderr
, 0);
1777 FATAL("alsa:unable to attach stderr\n");
1778 r
= snd_pcm_open(&pcm_g
, pcm_str
, SND_PCM_STREAM_PLAYBACK
,
1782 FATAL("alsa:\"%s\" pcm is already in use\n", pcm_str
);
1784 FATAL("alsa:unable to open \"%s\" pcm for playback\n", pcm_str
);
1786 r
= snd_pcm_poll_descriptors_count(pcm_g
);
1787 POUT("alsa:have %d poll file descriptors\n", r
);
1788 if ((r
<= 0) || (r
> PCM_POLLFDS_N_MAX
))
1789 FATAL("alsa:invalid count of alsa poll file descriptors\n");
1790 pcm_pollfds_n
=(u8
)r
;
1791 memset(pcm_pollfds
, 0, sizeof(pcm_pollfds
));
1792 snd_pcm_poll_descriptors(pcm_g
, pcm_pollfds
, PCM_POLLFDS_N_MAX
);
1794 static void init_once(u8
*url
, u8
*pcm_str
)
1796 stdin_tty_cfg_modified
= false;
1801 stdin_tty_init_once();
1802 stdin_flags_init_once();
1804 input_state_init_once();
1806 filter_graph_init_once();
1807 silence_bufs_init_once();
1809 pcm_init_once(pcm_str
);
1814 static int find_best_st(void)
1818 r
= av_find_best_stream(fmt_ctx
, AVMEDIA_TYPE_AUDIO
, -1, -1, 0, 0);
1820 FATAL("ffmpeg:no audio stream found\n");
1823 static void pcm_hw_chans_n_decide(snd_pcm_t
*pcm
,
1824 snd_pcm_hw_params_t
*pcm_hw_params
, unsigned int chans_n
)
1827 unsigned int chans_n_max
;
1828 unsigned int chans_n_min
;
1830 r
= snd_pcm_hw_params_test_channels(pcm
, pcm_hw_params
, chans_n
);
1832 r
= snd_pcm_hw_params_set_channels(pcm
, pcm_hw_params
, chans_n
);
1834 FATAL("alsa:unable to restrict pcm device to %u channels, count which was successfully tested\n", chans_n
);
1835 POUT("alsa:using %u channels\n", chans_n
);
1838 POUT("alsa:unable to use %u channels\n", chans_n
);
1839 /* try to use the max chans n the pcm can */
1840 r
= snd_pcm_hw_params_get_channels_max(pcm_hw_params
, &chans_n_max
);
1842 FATAL("alsa:unable to get the maximum count of pcm device channels\n");
1843 r
= snd_pcm_hw_params_test_channels(pcm
, pcm_hw_params
, chans_n_max
);
1845 r
= snd_pcm_hw_params_set_channels(pcm
, pcm_hw_params
,
1848 FATAL("alsa:unable to restrict pcm device to %u channels, count which was successfully tested\n", chans_n_max
);
1849 POUT("alsa:using pcm maximum %u channels\n", chans_n_max
);
1852 /* ok... last try, the pcm dev min chans n */
1853 r
= snd_pcm_hw_params_get_channels_min(pcm_hw_params
, &chans_n_min
);
1855 FATAL("alsa:unable to get the minimum count of pcm device channels\n");
1856 r
= snd_pcm_hw_params_test_channels(pcm
, pcm_hw_params
, chans_n_min
);
1858 r
= snd_pcm_hw_params_set_channels(pcm
, pcm_hw_params
,
1861 FATAL("alsa:unable to restrict pcm device to %u channels, count which was successfully tested\n", chans_n_min
);
1862 POUT("alsa:using pcm device minimum %u channels\n", chans_n_min
);
1865 FATAL("alsa:unable to find a suitable count of channels\n");
1867 static void pcm_hw_rate_decide(snd_pcm_t
*pcm
,
1868 snd_pcm_hw_params_t
*pcm_hw_params
, unsigned int rate
)
1871 unsigned int rate_max
;
1872 unsigned int rate_near
;
1873 unsigned int rate_min
;
1875 r
= snd_pcm_hw_params_test_rate(pcm
, pcm_hw_params
, rate
,
1876 SND_PCM_STREAM_PLAYBACK
);
1878 r
= snd_pcm_hw_params_set_rate(pcm
, pcm_hw_params
, rate
,
1879 SND_PCM_STREAM_PLAYBACK
);
1881 FATAL("alsa:unable to restrict pcm device to %uHz, which was successfully tested\n", rate
);
1882 POUT("alsa:using %uHz\n", rate
);
1885 POUT("alsa:unable to use %uHz\n", rate
);
1886 /* try to use the max rate the pcm can */
1887 r
= snd_pcm_hw_params_get_rate_max(pcm_hw_params
, &rate_max
,
1888 SND_PCM_STREAM_PLAYBACK
);
1890 FATAL("alsa:unable to get the maximum rate of pcm device\n");
1891 r
= snd_pcm_hw_params_test_rate(pcm
, pcm_hw_params
, rate_max
,
1892 SND_PCM_STREAM_PLAYBACK
);
1894 r
= snd_pcm_hw_params_set_rate(pcm
, pcm_hw_params
, rate_max
,
1895 SND_PCM_STREAM_PLAYBACK
);
1897 FATAL("alsa:unable to restrict pcm device to %uHz, which was successfully tested\n", rate_max
);
1898 POUT("alsa:using pcm device %uHz\n", rate_max
);
1901 /* try to use a rate "near" of what the pcm dev can */
1903 r
= snd_pcm_hw_params_set_rate_near(pcm
, pcm_hw_params
, &rate_near
,
1904 SND_PCM_STREAM_PLAYBACK
);
1906 POUT("alsa:using pcm device %uHz\n", rate_near
);
1909 /* even a "near" rate did failed... try the min */
1910 r
= snd_pcm_hw_params_get_rate_min(pcm_hw_params
, &rate_min
,
1911 SND_PCM_STREAM_PLAYBACK
);
1913 FATAL("alsa:unable to get the minimum rate of pcm device\n");
1914 r
= snd_pcm_hw_params_test_rate(pcm
, pcm_hw_params
, rate_min
,
1915 SND_PCM_STREAM_PLAYBACK
);
1917 r
= snd_pcm_hw_params_set_rate(pcm
, pcm_hw_params
, rate_min
,
1918 SND_PCM_STREAM_PLAYBACK
);
1920 FATAL("alsa:unable to restrict pcm device to %uHz, which was successfully tested\n", rate_min
);
1921 POUT("alsa:using pcm device %uHz\n", rate_min
);
1924 FATAL("alsa:unable to find a suitable rate\n");
1926 static bool ff_fmt2pcm_layout_best_effort(enum AVSampleFormat ff_fmt
,
1927 snd_pcm_format_t
*alsa_fmt
, snd_pcm_access_t
*alsa_access
)
1929 static u8 ff_fmt_str
[STR_SZ
];
1931 av_get_sample_fmt_string(ff_fmt_str
, STR_SZ
, ff_fmt
);
1932 /* XXX: only classic non-mmap ones */
1934 case AV_SAMPLE_FMT_U8
:
1935 *alsa_fmt
= SND_PCM_FORMAT_U8
;
1936 *alsa_access
= SND_PCM_ACCESS_RW_INTERLEAVED
;
1938 case AV_SAMPLE_FMT_S16
:
1939 *alsa_fmt
= SND_PCM_FORMAT_S16
;
1940 *alsa_access
= SND_PCM_ACCESS_RW_INTERLEAVED
;
1942 case AV_SAMPLE_FMT_S32
:
1943 *alsa_fmt
= SND_PCM_FORMAT_S32
;
1944 *alsa_access
= SND_PCM_ACCESS_RW_INTERLEAVED
;
1946 case AV_SAMPLE_FMT_FLT
:
1947 *alsa_fmt
= SND_PCM_FORMAT_FLOAT
;
1948 *alsa_access
= SND_PCM_ACCESS_RW_INTERLEAVED
;
1950 /* ff "planar" fmts are actually non interleaved fmts */
1951 case AV_SAMPLE_FMT_U8P
:
1952 *alsa_fmt
= SND_PCM_FORMAT_U8
;
1953 *alsa_access
= SND_PCM_ACCESS_RW_NONINTERLEAVED
;
1955 case AV_SAMPLE_FMT_S16P
:
1956 *alsa_fmt
= SND_PCM_FORMAT_S16
;
1957 *alsa_access
= SND_PCM_ACCESS_RW_NONINTERLEAVED
;
1959 case AV_SAMPLE_FMT_S32P
:
1960 *alsa_fmt
= SND_PCM_FORMAT_S32
;
1961 *alsa_access
= SND_PCM_ACCESS_RW_NONINTERLEAVED
;
1963 case AV_SAMPLE_FMT_FLTP
:
1964 *alsa_fmt
= SND_PCM_FORMAT_FLOAT
;
1965 *alsa_access
= SND_PCM_ACCESS_RW_NONINTERLEAVED
;
1968 POUT("best effort:unable to wire ffmpeg sample format \"%sbits\" to alsa sample format, \n,", ff_fmt_str
);
1971 POUT("best effort:ffmpeg format \"%sbits\" (%u bytes) to alsa layout \"%s\" and access \"%s\"\n", ff_fmt_str
, av_get_bytes_per_sample(ff_fmt
), snd_pcm_format_description(*alsa_fmt
), snd_pcm_access_name(*alsa_access
));
1974 static bool pcm_hw_fmt_decide_x(snd_pcm_t
*pcm
,
1975 snd_pcm_hw_params_t
*pcm_hw_params
, snd_pcm_format_t fmt
)
1979 r
= snd_pcm_hw_params_test_format(pcm
, pcm_hw_params
, fmt
);
1982 r
= snd_pcm_hw_params_set_format(pcm
, pcm_hw_params
, fmt
);
1984 FATAL("alsa:unable to restrict pcm device to \"%s\", which was successfully tested\n", snd_pcm_format_description(fmt
));
1985 POUT("alsa:using \"%s\" format\n", snd_pcm_format_description(fmt
));
1988 #define PCM_HW_FMT_DECIDE_X(fmt) pcm_hw_fmt_decide_x(pcm, pcm_hw_params, fmt)
1989 static void pcm_hw_fmt_decide(snd_pcm_t
*pcm
,
1990 snd_pcm_hw_params_t
*pcm_hw_params
, bool force
,
1991 snd_pcm_format_t forced_fmt
)
1994 snd_pcm_format_t
*fmt
;
1997 r
= snd_pcm_hw_params_test_format(pcm
, pcm_hw_params
,
2000 r
= snd_pcm_hw_params_set_format(pcm
, pcm_hw_params
,
2003 FATAL("alsa:unable to restrict pcm device to \"%s\", which was successfully tested\n", snd_pcm_format_description(forced_fmt
));
2004 POUT("alsa:using forced \"%s\" format\n", snd_pcm_format_description(forced_fmt
));
2008 /* then we try to select from the reasonable "best" to the lowest */
2009 /* prefer fmts we know supported by ff */
2010 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FORMAT_FLOAT
))
2012 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FORMAT_S32
))
2014 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FORMAT_S16
))
2016 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FORMAT_U8
))
2019 * from here, at the time of writting, those fmts have no ff
2020 * wiring, but we are alsa centric here, validate that later
2022 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FORMAT_U32
))
2024 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FORMAT_S24
))
2026 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FORMAT_U24
))
2028 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FORMAT_U16
))
2030 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FORMAT_S8
))
2032 FATAL("alsa:unable to find a suitable format\n");
2034 #undef PCM_HW_FMT_DECIDE_X
2035 static bool pcm_hw_access_decide_x(snd_pcm_t
*pcm
,
2036 snd_pcm_hw_params_t
*pcm_hw_params
, snd_pcm_access_t access
)
2040 r
= snd_pcm_hw_params_test_access(pcm
, pcm_hw_params
, access
);
2043 r
= snd_pcm_hw_params_set_access(pcm
, pcm_hw_params
, access
);
2045 FATAL("alsa:unable to restrict pcm device to \"%s\", which was successfully tested\n", snd_pcm_access_name(access
));
2046 POUT("alsa:using \"%s\" access\n", snd_pcm_access_name(access
));
2049 #define PCM_HW_ACCESS_DECIDE_X(access) \
2050 pcm_hw_access_decide_x(pcm, pcm_hw_params, access)
2051 /* XXX: only classic non-mmap ones */
2052 static void pcm_hw_access_decide(snd_pcm_t
*pcm
,
2053 snd_pcm_hw_params_t
*pcm_hw_params
, bool force
,
2054 snd_pcm_access_t forced_access
)
2057 snd_pcm_access_t access
;
2060 r
= snd_pcm_hw_params_test_access(pcm
, pcm_hw_params
,
2063 r
= snd_pcm_hw_params_set_access(pcm
, pcm_hw_params
,
2066 FATAL("alsa:unable to restrict pcm device to \"%s\", which was successfully tested\n", snd_pcm_access_name(forced_access
));
2067 POUT("alsa:using forced \"%s\" access\n", snd_pcm_access_name(forced_access
));
2072 if (PCM_HW_ACCESS_DECIDE_X(SND_PCM_ACCESS_RW_INTERLEAVED
))
2074 if (PCM_HW_ACCESS_DECIDE_X(SND_PCM_ACCESS_RW_NONINTERLEAVED
))
2076 FATAL("alsa:unable to find a suitable access\n");
2078 #undef PCM_HW_ACCESS_DECIDE_X
2080 * latency control: some audio bufs can be huge (tested on a pulseaudio with 10
2081 * secs audio buf). if we are careless, we will quickly fill this buf which is
2082 * worth a significant amount of time, hence will add huge latency to our
2083 * interactive audio filtering (vol...). in the case of the 10 secs pulseaudio
2084 * buf, it means if you want to mute the audio, it will happen 10 secs later.
2085 * we add lantency control by limiting the sz of the dev audio buf, in periods
2087 * we choose roughly 0.25 secs, or roughly (rate / 4) frs.
2089 static void pcm_hw_buf_sz_cfg(snd_pcm_t
*pcm
,
2090 snd_pcm_hw_params_t
*pcm_hw_params
)
2093 snd_pcm_uframes_t latency_control_target_buf_ufrs_n
;
2094 snd_pcm_uframes_t latency_control_buf_ufrs_n
;
2097 r
= snd_pcm_hw_params_get_rate(pcm_hw_params
, &rate
, 0);
2099 WARNING("alsa:latency control:DISABLING LATENCY CONTROL:unable to get the decided rate from the current device parameters\n");
2102 latency_control_target_buf_ufrs_n
= (snd_pcm_uframes_t
)rate
;
2103 latency_control_target_buf_ufrs_n
/= 4;
2104 latency_control_buf_ufrs_n
= latency_control_target_buf_ufrs_n
;
2105 r
= snd_pcm_hw_params_set_buffer_size_near(pcm
, pcm_hw_params
,
2106 &latency_control_buf_ufrs_n
);
2108 WARNING("alsa:latency control:DISABLING_LATENCY_CONTROL:unable to set the audio buffer size (count of frames) to %u periods for the current device parameters\n", latency_control_buf_ufrs_n
);
2111 POUT("alsa:latency control:target buffer frame count is %u (~0.25 sec), got an audio buffer size set to %u frames\n", latency_control_target_buf_ufrs_n
, latency_control_buf_ufrs_n
);
2113 static void pcm_cfg_sw(snd_pcm_t
*pcm
)
2116 snd_pcm_sw_params_t
*sw_params
;
2118 POUT("ALSA:SW_PARAMS START------------------------------------------------------------\n");
2119 r
= snd_pcm_sw_params_malloc(&sw_params
);
2121 FATAL("alsa:unable to allocate software parameters structure\n");
2122 r
= snd_pcm_sw_params_current(pcm
, sw_params
);
2124 FATAL("alsa:unable to get current software parameters\n");
2125 r
= snd_pcm_sw_params_set_period_event(pcm
, sw_params
, 1);
2127 FATAL("alsa:unable to enable period event\n");
2128 r
= snd_pcm_sw_params(pcm
, sw_params
);
2130 FATAL("alsa:unable to install sotfware parameters\n");
2131 snd_pcm_sw_params_dump(sw_params
, pcm_pout
);
2132 snd_pcm_sw_params_free(sw_params
);
2133 POUT("ALSA:SW_PARAMS END--------------------------------------------------------------\n");
2136 * this function will "decide" the pcm dev cfg:
2137 * the goal is to be the "closest" to the provided params,
2138 * the "gap" will have to "filled" with ff filts
2140 * the "strategy" is a "fall-thru" (chans n then ... then ...) which
2141 * will "restrict" the pcm dev cfg further at each step
2143 * we try to use a sensible restrict order regarding audio props
2145 static void pcm_cfg_hw_core(snd_pcm_t
*pcm
, snd_pcm_hw_params_t
*pcm_hw_params
,
2146 int chans_n
, int rate
, enum AVSampleFormat ff_fmt
)
2149 bool best_effort_wiring_success
;
2150 snd_pcm_format_t fmt_from_best_effort
;
2151 snd_pcm_access_t access_from_best_effort
;
2153 /* the return value is from a first refine of the raw hw params */
2154 r
= snd_pcm_hw_params_any(pcm
, pcm_hw_params
);
2156 FATAL("alsa:unable to populate the hardware parameters context\n");
2157 pcm_hw_chans_n_decide(pcm
, pcm_hw_params
, (unsigned int)chans_n
);
2158 pcm_hw_rate_decide(pcm
, pcm_hw_params
, (unsigned int)rate
);
2160 best_effort_wiring_success
= ff_fmt2pcm_layout_best_effort(
2161 ff_fmt
, &fmt_from_best_effort
, &access_from_best_effort
);
2162 pcm_hw_fmt_decide(pcm
, pcm_hw_params
, best_effort_wiring_success
,
2163 fmt_from_best_effort
);
2164 pcm_hw_access_decide(pcm
, pcm_hw_params
, best_effort_wiring_success
,
2165 access_from_best_effort
);
2166 pcm_hw_buf_sz_cfg(pcm
, pcm_hw_params
);
2168 static void pcm_cfg_hw(snd_pcm_t
*pcm
, unsigned int chans_n
, unsigned int rate
,
2169 enum AVSampleFormat ff_fmt
)
2172 snd_pcm_access_t access
;
2173 snd_pcm_hw_params_t
*hw_params
;
2175 POUT("ALSA:HW_PARAMS START------------------------------------------------------------\n");
2176 r
= snd_pcm_hw_params_malloc(&hw_params
);
2178 FATAL("alsa:unable to allocate hardware parameters context\n");
2179 pcm_cfg_hw_core(pcm
, hw_params
, chans_n
, rate
, ff_fmt
);
2180 r
= snd_pcm_hw_params(pcm
, hw_params
);
2182 FATAL("alsa:unable to install the hardware parameters\n");
2183 r
= snd_pcm_hw_params_current(pcm
, hw_params
);
2185 FATAL("alsa:unable to get current hardware parameters\n");
2186 snd_pcm_hw_params_dump(hw_params
, pcm_pout
);
2187 snd_pcm_hw_params_free(hw_params
);
2188 POUT("ALSA:HW_PARAMS END--------------------------------------------------------------\n");
2190 static void pcm_cfg(snd_pcm_t
*pcm
, unsigned int chans_n
, unsigned int rate
,
2191 enum AVSampleFormat ff_fmt
)
2193 pcm_cfg_hw(pcm
, chans_n
, rate
, ff_fmt
);
2195 POUT("ALSA PCM DUMP START-------------------------------------------------------------\n");
2196 snd_pcm_dump(pcm
, pcm_pout
);
2197 POUT("ALSA PCM DUMP END---------------------------------------------------------------\n");
2199 static void evt_pcm_install(void)
2205 struct epoll_event evt
;
2208 if (i
== pcm_pollfds_n
)
2210 evt
.events
= pcm_pollfds
[i
].events
;
2211 evt
.data
.fd
= pcm_pollfds
[i
].fd
;
2212 r
= epoll_ctl(ep_fd
, EPOLL_CTL_ADD
, pcm_pollfds
[i
].fd
, &evt
);
2214 FATAL("unable to add alsa poll file descriptor[%d]=%d to epoll file descriptor\n", i
, pcm_pollfds
[i
].fd
);
2217 POUT("alsa:pcm events installed\n");
2219 static void evt_pcm_uninstall(void)
2225 if (i
== pcm_pollfds_n
)
2227 (void)epoll_ctl(ep_fd
, EPOLL_CTL_DEL
, pcm_pollfds
[i
].fd
, 0);
2230 POUT("alsa:pcm events uninstalled\n");
2232 #define PRINT_INFO true
2233 static void play(int st_idx
, double initial_vol
)
2235 enum AVSampleFormat dst_fmt
;
2238 uint64_t dst_chans_layout
;
2240 current_st_idx
= st_idx
;
2241 rd_thd_reset(st_idx
);
2243 dec_ctx_cfg(fmt_ctx
->streams
[st_idx
]->codecpar
);
2244 dec_frs
.most_recent_ts
= fmt_ctx
->streams
[st_idx
]->start_time
;
2245 cmd_info_data
.fmt
.duration
= fmt_ctx
->duration
;
2246 cmd_info_data
.fmt
.m
= fmt_ctx
->duration_estimation_method
;
2247 cmd_info_data
.st
.tb
= fmt_ctx
->streams
[st_idx
]->time_base
;
2248 cmd_info_data
.st
.id
= fmt_ctx
->streams
[st_idx
]->id
;
2249 cmd_info_data
.st
.duration
= fmt_ctx
->streams
[st_idx
]->duration
;
2252 evt_pcm_uninstall();
2254 * do our best to match the pcm cfg to audio ff dec output, BUT we don't
2255 * expect to match it "exactly": see right below why
2257 pcm_cfg(pcm_g
, dec_ctx
->channels
, dec_ctx
->sample_rate
,
2258 dec_ctx
->sample_fmt
);
2260 /* use a ff filt to fill in the gap between the pcm and audio ff dec */
2261 pcm2ff(pcm_g
, &dst_fmt
, &dst_rate
, &dst_chans_n
,
2262 &dst_chans_layout
, PRINT_INFO
);
2264 dec_ctx
->sample_fmt
, dec_ctx
->sample_rate
,
2265 dec_ctx
->channels
, dec_ctx
->channel_layout
,
2267 dst_fmt
, dst_rate
, dst_chans_n
, dst_chans_layout
,
2269 silence_bufs_cfg(pcm_g
, PRINT_INFO
);
2270 filt_frs
.vol
= initial_vol
;
2273 static void seek_x(int64_t delta
)
2280 if (dec_frs
.most_recent_ts
== AV_NOPTS_VALUE
)
2281 WARNING("unable to seek because no time stamp are currently available\n");
2283 st
= fmt_ctx
->streams
[current_st_idx
];
2284 st_tb
= st
->time_base
;
2287 new_ts
= dec_frs
.most_recent_ts
+ delta
* st_tb
.den
/ st_tb
.num
;
2288 /* rewind capping */
2289 POUT("trying to seek to %"PRId64
" stream time base units\n", new_ts
);
2291 r
= av_seek_pkt(fmt_ctx
, st
->id
, new_ts
, 0);
2294 WARNING("unable to seek to %"PRId64
" stream time base units\n", new_ts
);
2295 dec_frs
.most_recent_ts
= AV_NOPTS_VALUE
;
2296 rd_thd_reset(current_st_idx
);
2297 avcodec_flush_buffers(dec_ctx
);
2298 filt_frs
.no_more_dec_frs
= false; /* reset by the previous line */
2300 if (!filt_frs_get())
2301 EXIT("no more audio frames to play\n");
2303 static void cmd_rewind(void)
2305 POUT("COMMAND:rewind\n");
2306 seek_x(-SEEK_DELTA
);
2308 static void cmd_rewind_big(void)
2310 POUT("COMMAND:rewind big\n");
2311 seek_x(-SEEK_DELTA_BIG
);
2313 static void cmd_fastforward(void)
2315 POUT("COMMAND:fastforward\n");
2318 static void cmd_fastforward_big(void)
2320 POUT("COMMAND:fastforward big\n");
2321 seek_x(SEEK_DELTA_BIG
);
2323 static void cmd_pause(void)
2326 POUT("COMMAND:unpause\n");
2329 POUT("COMMAND:pause\n");
2333 static void cmd_vol_up(void)
2336 u8 vol_l10n_str
[sizeof("xxx.xx")]; /* should be overkill */
2337 u8 response
[STR_SZ
];
2339 filt_frs
.vol
+= VOL_DELTA
;
2340 if (filt_frs
.vol
> 1.0)
2342 snprintf(vol_l10n_str
, sizeof(vol_l10n_str
), "%f", filt_frs
.vol
);
2343 POUT("COMMAND:volume up to value %s(%s)\n", vol_l10n_str
, filt_frs
.muted
? "muted" : "unmuted");
2346 r
= avfilter_graph_send_command(filter_graph
, "vol", "volume",
2347 vol_l10n_str
, response
, sizeof(response
), 0);
2349 WARNING("ffmpeg:volume context:unable to set the volume up to \"%s\":response from volume filter:\"%s\"\n", response
);
2351 static void cmd_vol_down(void)
2354 u8 vol_l10n_str
[sizeof("xxx.xx")]; /* should be overkill */
2355 u8 response
[STR_SZ
];
2357 filt_frs
.vol
-= VOL_DELTA
;
2358 if (filt_frs
.vol
< 0.0)
2360 snprintf(vol_l10n_str
, sizeof(vol_l10n_str
), "%f", filt_frs
.vol
);
2361 POUT("COMMAND:volume down to value %s(%s)\n", vol_l10n_str
, filt_frs
.muted
? "muted" : "unmuted");
2364 r
= avfilter_graph_send_command(filter_graph
, "vol", "volume",
2365 vol_l10n_str
, response
, sizeof(response
), 0);
2367 WARNING("ffmpeg:volume context:unable to set the volume down to \"%s\":response from volume filter:\"%s\"\n", response
);
2369 static void cmd_mute(void)
2372 u8 vol_l10n_str
[sizeof("xxx.xx")]; /* should be overkill */
2373 u8 response
[STR_SZ
];
2375 if (filt_frs
.muted
) {
2376 POUT("COMMAND:unmuting\n");
2378 snprintf(vol_l10n_str
, sizeof(vol_l10n_str
), "%f",
2380 r
= avfilter_graph_send_command(filter_graph
, "vol", "volume",
2381 vol_l10n_str
, response
, sizeof(response
), 0);
2383 WARNING("ffmpeg:volume context:unable to mute the volume to 0:response from volume filter:%s\n", response
);
2385 filt_frs
.muted
= false;
2388 POUT("COMMAND:muting\n");
2390 r
= avfilter_graph_send_command(filter_graph
, "vol", "volume",
2391 double_zero_l10n_str
, response
, sizeof(response
), 0);
2393 WARNING("ffmpeg:volume context:unable to mute the volume to 0:response from volume filter:%s\n", response
);
2395 filt_frs
.muted
= true;
2399 int main(int argc
, u8
**args
)
2405 /* "turn on utf8" processing in used libs if any *AND* locale system */
2406 setlocale(LC_ALL
, "");
2407 /* av_log_set_level(AV_LOG_VERBOSE); */
2408 /* av_log_set_level(AV_LOG_DEBUG); */
2410 pcm_str
= "default";
2412 opts_parse(argc
, args
, &url
, &pcm_str
, &initial_vol
);
2413 init_once(url
, pcm_str
);
2415 best_st_idx
= find_best_st();
2416 play(best_st_idx
, initial_vol
);
2417 /* switch the ffmpeg log to stdout for metadata/etc dump */
2418 av_log_set_callback(ffmpeg_log_stdout
);
2420 av_dump_format(fmt_ctx
, 0, url
, 0);
2422 av_log_set_callback(av_log_default_callback
);
2423 if (!filt_frs_get()) /* must have some frames to play */
2424 EXIT("no initial audio frames to play\n");
2428 /*----------------------------------------------------------------------------*/
2430 #undef av_frames_alloc
2431 #undef av_frame_fmt_is_planar
2432 #undef av_frames_set_silence
2433 #undef av_frames_unref
2434 #undef av_get_frame_fmt_name
2435 #undef av_get_frame_fmt_string
2438 #undef avcodec_receive_frames
2439 #undef AVFrameFormat
2448 #undef INPUT_ESC_SEQ_TIMEOUT_SECS_N
2450 #undef PCM_POLLFDS_N_MAX
2455 #undef SEEK_DELTA_BIG