npv:osd:smooth timer glyph rendering
[nyanmp.git] / npa / npa.c
blob989c1540b3e0237127c4a950755054807fd2dc87
1 #ifndef NPA_C
2 #define NPA_C
3 /*
4 * code protected with a GNU affero GPLv3 license
5 * copyright (C) 2020 Sylvain BERTRAND
6 */
7 /*
8 * ABBREVIATIONS
10 * abuf : Audio BUFfer
11 * async : ASYNChronous
12 * b(s) : Byte(S) (often)
13 * buf(s) : BUFfer(S)
14 * cb : Cicular Buffer
15 * chan(s) : CHANnel(S)
16 * cmd(s) : CoMmanD(S)
17 * cp(s) : Code Point(s)
18 * cfg : ConFiGuration
19 * ctx : ConTeX
20 * dec : DECoder/DECoded
21 * desc : DESCription
22 * dev : DEVice
23 * e : End (usually a pointer on the byte past the last valid byte)
24 * eof : End Of File
25 * esc : ESCape
26 * ep : EPoll
27 * evt(s) : EVenT(S)
28 * err : ERRor
29 * fd : File Descriptor
30 * ff : FFmpeg
31 * filt : FILTer
32 * fmt : ForMaT
33 * fr(s) : FRame(S)
34 * inc : INCrement
35 * idx(s) : InDeX(S)
36 * l10n : LocalizatioN (10 chars between L and N)
37 * min(s) : MINute(S)
38 * msec(s) : MilliSECond(S)
39 * n : couNt
40 * nr : NumbeR
41 * out : OUTput
42 * pkt(s) : PacKeT(S)
43 * pts : Presentation TimeStamp
44 * rd : ReaD
45 * ref(s) : REFerence(S)
46 * s : Start
47 * sd : SenD
48 * sec(s) : SECond(S)
49 * seq : SEQuence
50 * sig(s) : SIGnal(S)
51 * st : STream
52 * str : STRing
53 * sync : SYNChronous
54 * sz : SiZe
55 * thd(s) : THreaD(S)
56 * tb : Time Base
57 * ts : TimeStamp
58 * vol : VOLume
61 * this is not a library, then we could not care less about memory management
62 * and/or similar cleanup: we have a virtual machine with a garbage collector,
63 * it is linux.
65 * we do presume we won't play more than 8 chans and ff chans layout will
66 * fit alsa chans map
68 * XXX: we don't know how the alsa silence machinery works, then we use brutal
69 * silence bufs
71 /*----------------------------------------------------------------------------*/
72 /* C/posix */
73 #include <stdbool.h>
74 #include <locale.h>
75 #include <stdarg.h>
76 #include <stdio.h>
77 #include <stdlib.h>
78 #include <string.h>
79 #include <errno.h>
80 #include <signal.h>
81 #include <pthread.h>
82 #include <unistd.h>
83 #include <termios.h>
84 #include <stdint.h>
85 #include <fcntl.h>
86 #if __GNUC__ > 4
87 #include <stdatomic.h>
88 #endif
89 #include <limits.h>
90 #include <time.h>
91 #include <stdarg.h>
92 /* linux and compatible */
93 #include <sys/epoll.h>
94 #include <sys/signalfd.h>
95 #include <sys/timerfd.h>
96 /* ff */
97 #include <libavformat/avformat.h>
98 #include <libavcodec/avcodec.h>
99 #include <libavfilter/avfilter.h>
100 #include <libavfilter/buffersrc.h>
101 #include <libavfilter/buffersink.h>
102 #include <libavutil/opt.h>
103 /* alsa */
104 #include <alsa/asoundlib.h>
105 /*============================================================================*/
106 /* namespaces -- START */
107 /*----------------------------------------------------------------------------*/
108 /* fix C -- START */
109 #define u8 uint8_t
110 #define U8_MAX 255
111 #define u32 uint32_t
112 #define u16 uint16_t
113 #define f32 float
114 #define loop for(;;)
115 #if UCHAR_WIDTH == 8
116 #if __GNUC__ > 4
117 #define atomic_u8 atomic_uchar
118 #else
119 #define atomic_u8 u8
120 #define atomic_uint unsigned int
121 #define atomic_int int
122 #define atomic_load(x) __atomic_load_n(x,__ATOMIC_SEQ_CST)
123 #define atomic_store(x,y) __atomic_store_n(x,y,__ATOMIC_SEQ_CST)
124 #endif
125 #else
126 #error "unable to find the right atomic for a 8 bits byte, be sure to have __STDC_WANT_IEC_60559_BFP_EXT__ defined on recent gcc"
127 #endif
128 /* fix C -- END */
129 /*----------------------------------------------------------------------------*/
130 /* ff namespace -- START*/
131 #define AV_FR_FMT_NONE AV_SAMPLE_FMT_NONE
132 #define av_bufsink_get_frs av_buffersink_get_frame
133 #define av_bufsrc_add_frs_flags av_buffersrc_add_frame_flags
134 #define AV_BUFSRC_FLAG_KEEP_REF AV_BUFFERSRC_FLAG_KEEP_REF
135 #define AV_BUFSRC_FLAG_PUSH AV_BUFFERSRC_FLAG_PUSH
136 #define av_codec const AVCodec
137 #define av_codec_ctx AVCodecContext
138 #define av_dump_fmt av_dump_format
139 #define av_duration_estimation_method AVDurationEstimationMethod
140 #define av_filt AVFilter
141 #define av_filt_ctx AVFilterContext
142 #define av_filt_get_by_name avfilter_get_by_name
143 #define av_filt_graph AVFilterGraph
144 #define av_filt_graph_alloc avfilter_graph_alloc
145 #define av_filt_graph_alloc_filt avfilter_graph_alloc_filter
146 #define av_filt_graph_cfg avfilter_graph_config
147 #define av_filt_graph_dump avfilter_graph_dump
148 #define av_filt_graph_free avfilter_graph_free
149 #define av_filt_graph_send_cmd avfilter_graph_send_command
150 #define av_filt_init_str avfilter_init_str
151 #define av_filt_link avfilter_link
152 #define av_find_best_st av_find_best_stream
153 #define av_flush_bufs avcodec_flush_buffers
154 #define av_fmt_ctx AVFormatContext
155 #define AV_FMT_DURATION_FROM_BITRATE AVFMT_DURATION_FROM_BITRATE
156 #define AV_FMT_DURATION_FROM_PTS AVFMT_DURATION_FROM_PTS
157 #define AV_FMT_DURATION_FROM_ST AVFMT_DURATION_FROM_STREAM
158 #define av_fmt_find_st_info avformat_find_stream_info
159 #define av_fmt_flush avformat_flush
160 #define av_fmt_open_input avformat_open_input
161 #define av_fr_fmt_is_planar av_sample_fmt_is_planar
162 #define AV_FR_FMT_DBL AV_SAMPLE_FMT_DBL
163 #define AV_FR_FMT_DBLP AV_SAMPLE_FMT_DBLP
164 #define AV_FR_FMT_FLT AV_SAMPLE_FMT_FLT
165 #define AV_FR_FMT_FLTP AV_SAMPLE_FMT_FLTP
166 #define AV_FR_FMT_S16 AV_SAMPLE_FMT_S16
167 #define AV_FR_FMT_S16P AV_SAMPLE_FMT_S16P
168 #define AV_FR_FMT_S32 AV_SAMPLE_FMT_S32
169 #define AV_FR_FMT_S32P AV_SAMPLE_FMT_S32P
170 #define AV_FR_FMT_U8P AV_SAMPLE_FMT_U8P
171 #define AV_FR_FMT_U8 AV_SAMPLE_FMT_U8
172 #define av_frs_alloc av_frame_alloc
173 #define av_frs_set_silence av_samples_set_silence
174 #define av_frs_unref av_frame_unref
175 #define av_get_fr_fmt_name av_get_sample_fmt_name
176 #define av_get_fr_fmt_str av_get_sample_fmt_string
177 #define av_io_flush avio_flush
178 #define AV_MEDIA_TYPE_AUDIO AVMEDIA_TYPE_AUDIO
179 #define av_pkt AVPacket
180 #define av_pkt_unref av_packet_unref
181 #define av_read_pkt av_read_frame
182 #define av_rational AVRational
183 #define av_seek_pkt av_seek_frame
184 #define av_receive_frs avcodec_receive_frame
185 #define av_fr_fmt AVSampleFormat
186 #define av_frs AVFrame
187 #define av_sd_pkt avcodec_send_packet
188 #define av_st AVStream
189 #define fmt format
190 #define fr_fmt sample_fmt
191 #define fr_rate sample_rate
192 #define frs_n nb_samples
193 #define st_idx stream_index
194 #define sts streams
195 #define tb time_base
196 /* ff namespace -- END */
197 /*----------------------------------------------------------------------------*/
198 /* alsa namespace -- START */
199 #define snd_pcm_fmt_desc snd_pcm_format_description
200 #define snd_pcm_fmt_set_silence snd_pcm_format_set_silence
201 #define SND_PCM_FMT_FLT SND_PCM_FORMAT_FLOAT
202 #define SND_PCM_FMT_S16 SND_PCM_FORMAT_S16
203 #define SND_PCM_FMT_S24 SND_PCM_FORMAT_S24
204 #define SND_PCM_FMT_S32 SND_PCM_FORMAT_S32
205 #define SND_PCM_FMT_S8 SND_PCM_FORMAT_S8
206 #define snd_pcm_fmt_t snd_pcm_format_t
207 #define SND_PCM_FMT_U16 SND_PCM_FORMAT_U16
208 #define SND_PCM_FMT_U24 SND_PCM_FORMAT_U24
209 #define SND_PCM_FMT_U32 SND_PCM_FORMAT_U32
210 #define SND_PCM_FMT_U8 SND_PCM_FORMAT_U8
211 #define snd_pcm_frs_to_bytes snd_pcm_frames_to_bytes
212 #define snd_pcm_hw_params_get_buf_size snd_pcm_hw_params_get_buffer_size
213 #define snd_pcm_hw_params_get_chans snd_pcm_hw_params_get_channels
214 #define snd_pcm_hw_params_get_chans_max snd_pcm_hw_params_get_channels_max
215 #define snd_pcm_hw_params_get_chans_min snd_pcm_hw_params_get_channels_min
216 #define snd_pcm_hw_params_get_fmt snd_pcm_hw_params_get_format
217 #define snd_pcm_hw_params_set_buf_size_near snd_pcm_hw_params_set_buffer_size_near
218 #define snd_pcm_hw_params_set_chans snd_pcm_hw_params_set_channels
219 #define snd_pcm_hw_params_set_fmt snd_pcm_hw_params_set_format
220 #define snd_pcm_hw_params_test_chans snd_pcm_hw_params_test_channels
221 #define snd_pcm_hw_params_test_fmt snd_pcm_hw_params_test_format
222 #define snd_pcm_sfrs_t snd_pcm_sframes_t
223 #define SND_PCM_ST_PLAYBACK SND_PCM_STREAM_PLAYBACK
224 #define snd_pcm_ufrs_t snd_pcm_uframes_t
225 /* alsa namespace -- END */
226 /* namespaces -- END */
227 /*============================================================================*/
228 #define ARRAY_N(x) (sizeof(x) / sizeof((x)[0]))
229 #define STR_SZ 255 /* sz and idx fit in 1 byte */
230 /*---------------------------------------------------------------------------*/
231 static u8 *current_url;
232 static int current_st_idx;
233 /* cmd_info must be fast, then a lockless copy of its data */
234 static struct {
235 struct {
236 int64_t duration;
237 enum av_duration_estimation_method m;
238 } fmt;
239 struct {
240 av_rational tb;
241 int id;
242 int64_t duration;
243 } st;
244 } cmd_info_data;
245 /*---------------------------------------------------------------------------*/
246 /* linux and compatible */
247 static int ep_fd;
248 static int sig_fd;
249 /*---------------------------------------------------------------------------*/
250 /* alsa */
251 static snd_pcm_t *pcm_g;
252 static snd_output_t *pcm_pout;
253 static snd_output_t *pcm_perr;
254 #define PCM_POLLFDS_N_MAX 16 /* banzai */
255 static struct pollfd pcm_pollfds[PCM_POLLFDS_N_MAX];
256 static u8 pcm_pollfds_n;
257 /*---------------------------------------------------------------------------*/
258 /* ff dec */
259 static av_pkt *rd_thd_pkt;
260 static av_fmt_ctx *fmt_ctx;
261 static pthread_mutex_t fmt_ctx_mutex;
262 static av_codec *dec;
263 static av_codec_ctx *dec_ctx;
264 /*---------------------------------------------------------------------------*/
265 /* ff filt graph */
266 static av_filt_graph *filt_graph;
267 static av_filt_ctx *abufsrc_ctx;
268 static const av_filt *abufsrc_filt;
269 static struct { /* used to detected reconfiguration */
270 AVChannelLayout chans_layout;
271 int rate;
272 enum av_fr_fmt fmt;
273 } abufsrc_key;
274 static av_filt_ctx *vol_ctx;
275 static const av_filt *vol_filt;
276 static u8 double_zero_l10n_str[sizeof("xxx.xx")];
277 static av_filt_ctx *afmt_ctx;
278 static const av_filt *afmt_filt;
279 static av_filt_ctx *abufsink_ctx;
280 static const av_filt *abufsink_filt;
281 /*---------------------------------------------------------------------------*/
282 /* a formally proven concurrently accessed lockless cb */
283 struct {
284 atomic_u8 reset;
285 atomic_u8 hold;
287 atomic_int st_idx;
288 av_pkt **pkts;
289 unsigned int pkts_n;
290 atomic_uint rd;
291 atomic_uint sd;
292 } cb;
293 /* running state */
294 struct {
295 av_frs *av;
296 bool pushed_in_filt_graph;
297 int64_t most_recent_ts; /* a very "coarse-grained" clock */
298 } dec_frs;
299 struct {
300 av_frs *av;
301 float vol;
302 bool muted;
303 snd_pcm_ufrs_t pcm_written_ufrs_n;
304 } filt_frs;
305 /* we will inject silence frs while paused */
306 bool paused;
307 void *silence_bufs[AV_NUM_DATA_POINTERS];
308 /*----------------------------------------------------------------------------*/
309 /* tty */
310 static bool stdin_tty_cfg_modified;
311 static struct termios stdin_tio_save;
312 static int stdin_flags_save;
313 static bool stdout_is_tty;
314 /*----------------------------------------------------------------------------*/
315 static void cmd_quit(void);
316 static void cmd_rewind(void);
317 static void cmd_fastforward(void);
318 static void cmd_rewind_big(void);
319 static void cmd_fastforward_big(void);
320 static void cmd_vol_up(void);
321 static void cmd_vol_down(void);
322 static void cmd_vol_up_small(void);
323 static void cmd_vol_down_small(void);
324 static void cmd_mute(void);
325 static void cmd_info(void);
326 static void cmd_pause(void);
327 /*--------------------------------------------------------------------------*/
328 #include "npa_config.h"
329 /*----------------------------------------------------------------------------*/
330 /* input "state" machine (2 major states: "utf8" and "esc seq" */
331 static int input_timer_fd;
332 static bool input_esc_seq_mode;
333 static u8 input_b; /* input byte */
335 static u8 utf8_cp[4];
336 static u8 utf8_cp_next_byte; /* idx in utf8_cp */
337 static u8 utf8_cp_sz;
339 static u8 esc_seq[STR_SZ];
340 static u8 esc_seq_next_byte; /* idx in esc_seq */
341 #define esc_seq_sz esc_seq_next_byte /* the idx of the next byte is its sz */
342 /*----------------------------------------------------------------------------*/
343 static void pout(u8 *fmt, ...);
344 static void perr(u8 *fmt, ...);
345 static void warning(u8 *fmt, ...);
346 static void fatal(u8 *fmt, ...);
347 static void exit_ok(u8 *fmt, ...);
348 /*----------------------------------------------------------------------------*/
349 static void stdin_flags_restore(void)
351 int r;
353 r = fcntl(0, F_SETFL, stdin_flags_save);
354 if (r == -1)
355 warning("input:unable to restore the file flags of the standard input\n");
357 static void stdin_tty_cfg_restore(void)
359 int r;
360 struct termios tio_chk;
362 if (!stdin_tty_cfg_modified)
363 return;
364 r = tcsetattr(0, TCSANOW, &stdin_tio_save);
365 if (r == -1) {
366 warning("input:unable to restore the terminal line attributes\t");
367 return;
369 memset(&tio_chk, 0, sizeof(tio_chk));
370 r = tcgetattr(0, &tio_chk);
371 if (r == -1) {
372 warning("input:unable to get the current terminal line attributes for restoration checking\n");
373 return;
375 r = memcmp(&tio_chk, &stdin_tio_save, sizeof(tio_chk));
376 if (r != 0)
377 warning("input:only partial restoration of the terminal line attributes\n");
379 /*----------------------------------------------------------------------------*/
380 static void pout(u8 *fmt, ...)
382 va_list ap;
384 va_start(ap, fmt);
385 vfprintf(stdout, fmt, ap);
386 va_end(ap);
388 static void perr(u8 *fmt, ...)
390 va_list ap;
392 va_start(ap, fmt);
393 vfprintf(stderr, fmt, ap);
394 va_end(ap);
396 static void warning(u8 *fmt, ...)
398 va_list ap;
400 fprintf(stderr, "warning:");
401 va_start(ap, fmt);
402 vfprintf(stderr, fmt, ap);
403 va_end(ap);
405 static void fatal(u8 *fmt, ...)
407 va_list ap;
409 fprintf(stderr, "fatal:");
410 va_start(ap, fmt);
411 vfprintf(stderr, fmt, ap);
412 va_end(ap);
413 stdin_flags_restore();
414 stdin_tty_cfg_restore();
415 exit(EXIT_FAILURE);
417 static void exit_ok(u8 *fmt, ...)
419 va_list ap;
421 fprintf(stderr, "exit_ok:");
422 va_start(ap, fmt);
423 vfprintf(stderr, fmt, ap);
424 va_end(ap);
425 stdin_flags_restore();
426 stdin_tty_cfg_restore();
427 exit(EXIT_SUCCESS);
429 /*----------------------------------------------------------------------------*/
430 static void fmt_ctx_lock(void)
432 int r;
434 r = pthread_mutex_lock(&fmt_ctx_mutex);
435 if (r != 0)
436 fatal("unable to lock the format context\n");
438 static void fmt_ctx_unlock(void)
440 int r;
442 r = pthread_mutex_unlock(&fmt_ctx_mutex);
443 if (r != 0)
444 fatal("unable to unlock the format context\n");
446 static u8 *duration_estimate_to_str(enum av_duration_estimation_method m)
448 switch (m) {
449 case AV_FMT_DURATION_FROM_PTS:
450 return "from PTS(Presentation TimeStamp)";
451 case AV_FMT_DURATION_FROM_ST:
452 return "from stream";
453 case AV_FMT_DURATION_FROM_BITRATE:
454 return "from bitrate";
455 default:
456 return "unkwown";
459 /* meh... */
460 static u8 *ts_to_str(int64_t ts, av_rational tb, int64_t *remaining)
462 static u8 str[sizeof("~S00:00:00.000 remains S9223372036854775807 time base units")];
463 bool is_neg;
464 int64_t hours_n;
465 int64_t mins_n;
466 int64_t secs_n;
467 int64_t msecs_n;
468 int64_t one_hour; /* in ff tb units */
469 int64_t one_min; /* in ff tb units */
470 int64_t one_sec; /* in ff tb units */
471 int64_t one_msec; /* in ff tb units */
473 if (ts < 0) {
474 ts = -ts;
475 is_neg = true;
476 } else
477 is_neg = false;
478 one_hour = INT64_C(3600) * (int64_t)tb.den / (int64_t)tb.num;
479 one_min = INT64_C(60) * (int64_t)tb.den / (int64_t)tb.num;
480 one_sec = (int64_t)tb.den / (int64_t)tb.num;
481 one_msec = one_sec / INT64_C(1000);
483 hours_n = ts / one_hour;
485 *remaining = ts % one_hour;
486 mins_n = *remaining / one_min;
488 *remaining = *remaining % one_min;
489 secs_n = *remaining / one_sec;
491 *remaining = *remaining % one_sec;
492 msecs_n = *remaining / one_msec;
494 /* account for all rounding errors */
495 *remaining = ts - (hours_n * one_hour + mins_n * one_min
496 + secs_n * one_sec + msecs_n * one_msec);
497 if (!is_neg)
498 snprintf(str, sizeof(str), "%02"PRId64":%02"PRId64":%02"PRId64".%03"PRId64, hours_n, mins_n, secs_n, msecs_n);
499 else {
500 str[0] = '-';
501 snprintf(str + 1, sizeof(str) - 1, "%02"PRId64":%02"PRId64":%02"PRId64".%03"PRId64, hours_n, mins_n, secs_n, msecs_n);
503 return str;
505 #define RED if (stdout_is_tty) pout("\x1b[38;2;255;0;0m")
506 #define GREEN if (stdout_is_tty) pout("\x1b[38;2;0;255;0m")
507 #define BLUE if (stdout_is_tty) pout("\x1b[38;2;0;0;255m")
508 #define PURPLE if (stdout_is_tty) pout("\x1b[38;2;255;0;255m")
509 #define RESTORE if (stdout_is_tty) pout("\x1b[39;49m")
510 static void cmd_info(void)
512 u8 *ts_str;
513 int64_t remaining;
514 u8 duration_str[sizeof("S9223372036854775807")];
516 RESTORE;
517 GREEN;pout("================================================================================\n");RESTORE;
518 PURPLE;pout("%s\n", current_url);RESTORE;
519 ts_str = ts_to_str(dec_frs.most_recent_ts, cmd_info_data.st.tb, &remaining);
520 RED;pout("%s", ts_str);RESTORE;
521 if (remaining != 0)
522 pout(" remaining %"PRId64" time base units", remaining);
523 else
524 pout("\n");
525 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);
526 BLUE;pout("--------------------------------------------------------------------------------\n");RESTORE;
527 pout("format:");
528 if (cmd_info_data.fmt.duration == AV_NOPTS_VALUE) {
529 pout("duration is not provided\n");
530 } else {
531 snprintf(duration_str, sizeof(duration_str), "%"PRId64, cmd_info_data.fmt.duration);
532 ts_str = ts_to_str(cmd_info_data.fmt.duration, AV_TIME_BASE_Q,
533 &remaining);
534 pout("duration=");RED;pout("%s", ts_str);RESTORE;
535 if (remaining != 0)
536 pout(" remaining %"PRId64" av_time_base units\n", remaining);
537 else
538 pout("\n");
539 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));
541 pout("stream:id=%d", cmd_info_data.st.id);
542 if (cmd_info_data.st.duration == AV_NOPTS_VALUE) {
543 pout(";duration is not provided\n");
544 } else {
545 snprintf(duration_str, sizeof(duration_str), "%"PRId64, cmd_info_data.st.duration);
546 ts_str = ts_to_str(cmd_info_data.st.duration, cmd_info_data.st.tb, &remaining);
547 pout(";duration=");RED;pout("%s\n", ts_str);RESTORE;
548 if (remaining != 0)
549 pout(" remaining %"PRId64" stream time base units\n", remaining);
550 else
551 pout("\n");
552 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);
554 BLUE;pout("--------------------------------------------------------------------------------\n");RESTORE;
555 pout("circular buffer: %u/%u/%u (read/send/max)\n", atomic_load(&cb.rd), atomic_load(&cb.sd), cb.pkts_n);
556 if (paused) {
557 RED;pout("paused\n");RESTORE;
559 if (filt_frs.muted) {
560 RED;pout("muted\n");RESTORE;
562 GREEN;pout("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");RESTORE;
564 #undef RED
565 #undef GREEN
566 #undef BLUE
567 #undef PURPLE
568 #undef RESTORE
569 static void wait(long ns)
571 struct timespec wanted;
572 struct timespec rem;
574 memset(&wanted, 0, sizeof(wanted));
575 memset(&rem, 0, sizeof(rem));
576 wanted.tv_nsec = ns;
577 loop {
578 int r;
580 /* linux bug: cannot specify CLOCK_MONOTONIC_RAW */
581 r = clock_nanosleep(CLOCK_MONOTONIC, 0, &wanted, &rem);
582 if (r == 0)
583 break;
584 if (r != EINTR)
585 fatal("wait timer failed:%d\n", r);
586 /* r == EINTR */
587 memcpy(&wanted, &rem, sizeof(wanted));
588 memset(&rem, 0, sizeof(rem));
591 static void wait_cb_filling(void)
593 struct timespec wanted;
594 struct timespec rem;
596 memset(&wanted, 0, sizeof(wanted));
597 memset(&rem, 0, sizeof(rem));
598 wanted.tv_nsec = 4000000; /* 4 ms */
599 loop {
600 int r;
602 /* linux bug: cannot specify CLOCK_MONOTONIC_RAW */
603 r = clock_nanosleep(CLOCK_MONOTONIC, 0, &wanted, &rem);
604 if (r == 0) {
605 unsigned int rd;
607 rd = atomic_load(&cb.rd);
608 if (rd == (cb.pkts_n - 1))
609 break;
610 memset(&wanted, 0, sizeof(wanted));
611 memset(&rem, 0, sizeof(rem));
612 wanted.tv_nsec = 4000000; /* 4 ms */
613 continue;
615 if (r != EINTR)
616 fatal("wait cb filling timer failed:%d\n", r);
617 /* r == EINTR */
618 memcpy(&wanted, &rem, sizeof(wanted));
619 memset(&rem, 0, sizeof(rem));
622 #define RESET_DONE 0
623 static void do_reset(void)
625 unsigned int i;
627 fmt_ctx_lock();
628 av_fmt_flush(fmt_ctx);
629 av_io_flush(fmt_ctx->pb);
630 fmt_ctx_unlock();
631 i = 0;
632 loop {
633 av_pkt_unref(cb.pkts[i]);
634 if (i == cb.pkts_n)
635 break;
636 ++i;
638 atomic_store(&cb.rd, 0);
639 atomic_store(&cb.sd, 0);
640 atomic_store(&cb.reset, RESET_DONE);
642 #undef RESET_DONE
643 #define DO_RESET 1
644 #define HOLD 1
645 static void rd_loop(void) { loop /* infinite loop */
647 int r;
648 unsigned int rd;
649 unsigned int next_rd;
650 unsigned int sd;
651 u8 reset;
652 int st_idx;
653 u8 hold;
655 * XXX: we actually perform reset on this thd, with a little lockfree
656 * protocol and reasonable wait loops
658 reset = atomic_load(&cb.reset);
659 if (reset == DO_RESET)
660 do_reset();
661 /*--------------------------------------------------------------------*/
662 hold = atomic_load(&cb.hold);
663 if (hold == HOLD) {
664 wait(1000000); /* 1ms */
665 continue;
667 /*--------------------------------------------------------------------*/
668 rd = atomic_load(&cb.rd);
669 sd = atomic_load(&cb.sd);
670 next_rd = (rd + 1) % cb.pkts_n;
671 if (next_rd == sd) { /* must sd first the sd slot */
672 wait(1000000); /* 1ms */
673 continue;
675 /*--------------------------------------------------------------------*/
676 fmt_ctx_lock();
677 r = av_read_pkt(fmt_ctx, rd_thd_pkt);
678 fmt_ctx_unlock();
679 if (r == AVERROR(EAGAIN)) {
680 /* 1ms: it is sort of aggressive to check for reset */
681 wait(1000000);
682 continue;
683 } else if (r == AVERROR_EOF) {
684 /* The "NULL" pkt ref to signal the EOF to the dec */
685 cb.pkts[rd]->data = 0;
686 cb.pkts[rd]->size = 0;
687 } else if (r != 0)
688 fatal("ffmpeg:error while demuxing coded/compressed data into packets\n");
689 else { /* r == 0 */
690 st_idx = atomic_load(&cb.st_idx);
691 if (rd_thd_pkt->st_idx != st_idx) { /* sd_idx can be -1 */
692 av_pkt_unref(rd_thd_pkt);
693 continue;
695 av_packet_move_ref(cb.pkts[rd], rd_thd_pkt);
697 atomic_store(&cb.rd, next_rd);
699 #undef DO_RESET
700 #undef HOLD
701 static void *rd_thd_entry(void *arg)
703 int r;
704 sigset_t sset;
706 r = sigfillset(&sset);
707 if (r == -1)
708 fatal("read thread:unable to get a full signal mask\n");
709 r = pthread_sigmask(SIG_SETMASK, &sset, 0);
710 if (r != 0)
711 fatal("read thread:unable to \"block\" \"all\" signals\n");
712 rd_loop();
713 /* unreachable */
715 static void rd_thd_start(int st_index)
717 int r;
718 pthread_t id;
719 pthread_attr_t attr;
721 atomic_store(&cb.st_idx, st_index);
722 r = pthread_attr_init(&attr);
723 if (r != 0)
724 fatal("read thread:unable to initialize read thread attribute\n");
725 r = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
726 if (r != 0)
727 fatal("read thread:unable to set the read thread attribute to detach mode\n");
728 r = pthread_create(&id, &attr, &rd_thd_entry, 0);
729 if (r != 0)
730 fatal("read thread:unable to create the read thread\n");
731 pout("read thread %lu\n", (unsigned long)id);
732 pthread_attr_destroy(&attr);
734 static void cmd_quit(void)
736 exit_ok("quit command received\n");
738 #define RESET_DONE 0
739 #define DO_RESET 1
740 static void rd_thd_reset(int st_idx)
742 u32 loops_n;
744 loops_n = 0;
745 /* reset = RESET_DONE */
746 atomic_store(&cb.st_idx, st_idx);
747 atomic_store(&cb.reset, DO_RESET);
748 loop {
749 u8 reset;
751 reset = atomic_load(&cb.reset);
752 if (reset == RESET_DONE)
753 break;
754 wait(1000000); /* 1ms */
755 ++loops_n;
756 if (loops_n == 4000) /* 1ms * 4000 = 4s */
757 fatal("read thread reset timeout\n");
759 /* reset = DO_RESET */
761 #undef RESET_DONE
762 #undef DO_RESET
764 * XXX: if it is ever used significantly, a fine granularity wiring strategy
765 * will be implemented instead of using the default wiring
767 static void pcm_chmaps2ff_chans_layout(AVChannelLayout *ff_chans_layout,
768 snd_pcm_t *pcm, unsigned int pcm_chans_n, bool print_info)
770 int r;
772 snd_pcm_chmap_t *pcm_chmap;
773 u8 chans_layout_str[STR_SZ]; /* should be overkill */
775 pcm_chmap = snd_pcm_get_chmap(pcm);
776 if (pcm_chmap == 0) {
777 if (print_info)
778 pout("alsa:no pcm channel map available, wiring to default ffmpeg channel layout\n");
779 } else {
780 if (print_info)
781 pout("alsa:your pcm device support channel maps, but fine granularity wiring strategy is not implemented\n");
782 free(pcm_chmap);
784 av_channel_layout_default(ff_chans_layout, (int)pcm_chans_n);
785 av_channel_layout_describe(ff_chans_layout, chans_layout_str,
786 sizeof(chans_layout_str));
787 if (print_info)
788 pout("alsa channel map wired to ffmpeg channel layout:\"%s\" (%u pcm channels)\n", chans_layout_str, pcm_chans_n);
790 /* fatal if the wiring cannot be done */
791 static void pcm_layout2ff_fmt_strict(snd_pcm_fmt_t alsa_fmt,
792 snd_pcm_access_t alsa_access, enum av_fr_fmt *ff_fmt, bool print_info)
795 * ff fmt byte order is always native.
796 * here we handle little endian only
798 switch (alsa_fmt) {
799 case SND_PCM_FMT_FLT:
800 if (alsa_access == SND_PCM_ACCESS_RW_INTERLEAVED)
801 *ff_fmt = AV_FR_FMT_FLT;
802 else
803 *ff_fmt = AV_FR_FMT_FLTP;
804 break;
805 case SND_PCM_FMT_S32:
806 if (alsa_access == SND_PCM_ACCESS_RW_INTERLEAVED)
807 *ff_fmt = AV_FR_FMT_S32;
808 else
809 *ff_fmt = AV_FR_FMT_S32P;
810 break;
811 case SND_PCM_FMT_S16:
812 if (alsa_access == SND_PCM_ACCESS_RW_INTERLEAVED)
813 *ff_fmt = AV_FR_FMT_S16;
814 else
815 *ff_fmt = AV_FR_FMT_S16P;
816 break;
817 case SND_PCM_FMT_U8:
818 if (alsa_access == SND_PCM_ACCESS_RW_INTERLEAVED)
819 *ff_fmt = AV_FR_FMT_U8;
820 else
821 *ff_fmt = AV_FR_FMT_U8P;
822 break;
823 default:
824 fatal("unable to wire strictly alsa layout \"%s\"/\"%s\" to a ffmpeg format\n", snd_pcm_fmt_desc(alsa_fmt), snd_pcm_access_name(alsa_access));
826 if (print_info) {
827 u8 ff_fmt_str[STR_SZ];
829 av_get_fr_fmt_str(ff_fmt_str, sizeof(ff_fmt_str), *ff_fmt);
830 pout("alsa pcm layout \"%s\"/\"%s\" wired strictly to ffmpeg format \"%sbits\"\n", snd_pcm_fmt_desc(alsa_fmt), snd_pcm_access_name(alsa_access), ff_fmt_str);
833 static void pcm2ff(snd_pcm_t *pcm, enum av_fr_fmt *ff_fmt, int *ff_rate,
834 AVChannelLayout *ff_chans_layout, bool print_info)
836 int r;
837 snd_pcm_hw_params_t *hw_params;
838 snd_pcm_access_t pcm_access;
839 snd_pcm_fmt_t pcm_fmt;
840 unsigned int pcm_rate;
841 unsigned int pcm_chans_n;
843 r = snd_pcm_hw_params_malloc(&hw_params);
844 if (r < 0)
845 fatal("alsa:unable to allocate hardware parameters context for ffmpeg filter wiring\n");
846 r = snd_pcm_hw_params_current(pcm, hw_params);
847 if (r != 0)
848 fatal("alsa:unable to get current hardware parameters for ffmpeg filter wiring\n");
849 r = snd_pcm_hw_params_get_access(hw_params, &pcm_access);
850 if (r < 0)
851 fatal("alsa:unable to get the pcm access for ffmpeg filter wiring\n");
852 r = snd_pcm_hw_params_get_fmt(hw_params, &pcm_fmt);
853 if (r < 0)
854 fatal("alsa:unable to get the pcm format for ffmpeg filter wiring\n");
855 /*--------------------------------------------------------------------*/
856 pcm_layout2ff_fmt_strict(pcm_fmt, pcm_access, ff_fmt, print_info);
857 /*--------------------------------------------------------------------*/
858 r = snd_pcm_hw_params_get_rate(hw_params, &pcm_rate,
859 SND_PCM_ST_PLAYBACK);
860 if (r < 0)
861 fatal("alsa:unable to get the pcm rate for ffmpeg filter wiring\n");
862 *ff_rate = (int)pcm_rate;
863 r = snd_pcm_hw_params_get_chans(hw_params, &pcm_chans_n);
864 if (r < 0)
865 fatal("alsa:unable to get the pcm count of channels for ffmpeg filter wiring\n");
866 /*--------------------------------------------------------------------*/
867 pcm_chmaps2ff_chans_layout(ff_chans_layout, pcm, pcm_chans_n,
868 print_info);
869 /*--------------------------------------------------------------------*/
870 snd_pcm_hw_params_free(hw_params);
872 /* XXX: we don't program the tb of the filter since it should not be used */
873 static void abufsrc_cfg(enum av_fr_fmt fmt, int rate,
874 AVChannelLayout *chans_layout, bool print_info)
876 int r;
877 u8 chans_layout_str[STR_SZ]; /* should be overkill */
879 abufsrc_filt = av_filt_get_by_name("abuffer");
880 if (abufsrc_filt == 0)
881 fatal("audio buffer source:could not find the filter\n");
882 abufsrc_ctx = av_filt_graph_alloc_filt(filt_graph, abufsrc_filt,
883 "src_abuf");
884 if (abufsrc_ctx == 0)
885 fatal("audio buffer source context:could not allocate the instance in the filter graph\n");
886 r = av_opt_set(abufsrc_ctx, "sample_fmt", av_get_fr_fmt_name(fmt),
887 AV_OPT_SEARCH_CHILDREN);
888 if (r < 0)
889 fatal("audio buffer source context:unable to set the decoder frame format option\n");
890 r = av_opt_set_int(abufsrc_ctx, "sample_rate", rate,
891 AV_OPT_SEARCH_CHILDREN);
892 if (r < 0)
893 fatal("audio buffer source context:unable to set the decoder rate option\n");
894 av_channel_layout_describe(chans_layout, chans_layout_str,
895 sizeof(chans_layout_str));
896 if (print_info)
897 pout("audio buffer source context:using channels layout \"%s\"\n", chans_layout_str);
898 r = av_opt_set(abufsrc_ctx, "channel_layout", chans_layout_str,
899 AV_OPT_SEARCH_CHILDREN);
900 if (r < 0)
901 fatal("audio buffer source context:unable to set the decoder channel layout option\n");
902 r = av_filt_init_str(abufsrc_ctx, 0);
903 if (r < 0)
904 fatal("audio buffer source context:unable to initialize\n");
906 static void vol_cfg(bool muted, double vol)
908 double vol_double;
909 u8 vol_l10n_str[sizeof("xxx.xx")]; /* should be overkill */
910 int r;
912 vol_filt = av_filt_get_by_name("volume");
913 if (vol_filt == 0)
914 fatal("volume:could not find the filter\n");
915 vol_ctx = av_filt_graph_alloc_filt(filt_graph, vol_filt, "vol");
916 if (vol_ctx == 0)
917 fatal("volume context:could not allocate the instance in the filter graph\n");
918 if (muted)
919 vol_double = 0.0;
920 else
921 vol_double = vol;
922 /* yeah the radix is localized, can be '.', ','... */
923 snprintf(vol_l10n_str, sizeof(vol_l10n_str), "%f", vol_double);
924 r = av_opt_set(vol_ctx, "volume", vol_l10n_str, AV_OPT_SEARCH_CHILDREN);
925 if (r < 0)
926 fatal("volume context:unable to set the volume option\n");
927 r = av_filt_init_str(vol_ctx, 0);
928 if (r < 0)
929 fatal("volume buffer context:unable to initialize\n");
931 static void afmt_cfg(enum av_fr_fmt fmt, int rate,
932 AVChannelLayout *chans_layout, bool print_info)
934 int r;
935 u8 rate_str[sizeof("dddddd")];
936 u8 chans_layout_str[STR_SZ]; /* should be overkill */
938 afmt_filt = av_filt_get_by_name("aformat");
939 if (afmt_filt == 0)
940 fatal("audio format:could not find the filter");
941 afmt_ctx = av_filt_graph_alloc_filt(filt_graph, afmt_filt, "afmt");
942 if (afmt_ctx == 0)
943 fatal("audio format:could not allocate the instance in the filter graph\n");
944 r = av_opt_set(afmt_ctx, "sample_fmts", av_get_fr_fmt_name(fmt),
945 AV_OPT_SEARCH_CHILDREN);
946 if (r < 0)
947 fatal("audio format context:could to set the pcm sample format\n");
948 snprintf(rate_str, sizeof(rate_str), "%d", rate);
949 r = av_opt_set(afmt_ctx, "sample_rates", rate_str,
950 AV_OPT_SEARCH_CHILDREN);
951 if (r < 0)
952 fatal("audio format context:could not set the pcm rate\n");
953 av_channel_layout_describe(chans_layout, chans_layout_str,
954 sizeof(chans_layout_str));
955 r = av_opt_set(afmt_ctx, "channel_layouts", chans_layout_str,
956 AV_OPT_SEARCH_CHILDREN);
957 if (r < 0)
958 fatal("audio format context:could not set the layout of channels\n");
959 if (print_info)
960 pout("audio format context:channel layout is \"%s\"\n", chans_layout_str);
961 r = av_filt_init_str(afmt_ctx, 0);
962 if (r < 0)
963 fatal("audio format context:unable to initialize\n");
965 static void abufsink_cfg(void)
967 int r;
969 abufsink_filt = av_filt_get_by_name("abuffersink");
970 if (abufsink_filt == 0)
971 fatal("audio buffer sink:could not find the filter\n");
972 abufsink_ctx = av_filt_graph_alloc_filt(filt_graph, abufsink_filt,
973 "sink_abuf");
974 if (abufsink_ctx == 0)
975 fatal("audio buffer sink context:could not allocate the instance in the filter graph\n");
976 r = av_filt_init_str(abufsink_ctx, 0);
977 if (r < 0)
978 fatal("audio buffer sink context:unable to initialize\n");
980 static void dec_ctx_cfg(AVCodecParameters *params)
982 int r;
984 dec = avcodec_find_decoder(params->codec_id);
985 if (dec == 0)
986 fatal("ffmpeg:unable to find a proper decoder\n");
987 avcodec_free_context(&dec_ctx);
988 dec_ctx = avcodec_alloc_context3(dec);
989 if (dec_ctx == 0)
990 fatal("ffmpeg:unable to allocate a decoder context\n");
991 /* XXX: useless ? */
992 r = avcodec_parameters_to_context(dec_ctx, params);
993 if (r < 0)
994 fatal("ffmpeg:unable to apply codec parameters in codec context\n");
995 /* XXX: ffmpeg thread count default is 1, set to 0 = auto */
996 dec_ctx->thread_count = 0;
997 r = avcodec_open2(dec_ctx, dec, 0);
998 if (r < 0)
999 fatal("ffmpeg:unable to open the decoder context\n");
1001 static void filt_graph_cfg(
1002 enum av_fr_fmt src_fmt, int src_rate,
1003 AVChannelLayout *src_chans_layout,
1004 bool muted, double vol,
1005 enum av_fr_fmt dst_fmt, int dst_rate,
1006 AVChannelLayout *dst_chans_layout, bool print_info)
1008 int r;
1009 char *dump_str;
1011 av_filt_graph_free(&filt_graph);
1013 filt_graph = av_filt_graph_alloc();
1014 if (filt_graph == 0)
1015 fatal("unable to create filter graph\n");
1016 abufsrc_cfg(src_fmt, src_rate, src_chans_layout, print_info);
1017 /*--------------------------------------------------------------------*/
1018 r = av_channel_layout_copy(&abufsrc_key.chans_layout, src_chans_layout);
1019 if (r < 0)
1020 fatal("unable to copy the source channel layout in the key\n");
1021 abufsrc_key.rate = src_rate;
1022 abufsrc_key.fmt = src_fmt;
1023 /*--------------------------------------------------------------------*/
1024 vol_cfg(muted, vol);
1025 afmt_cfg(dst_fmt, dst_rate, dst_chans_layout, print_info);
1026 abufsink_cfg();
1027 r = av_filt_link(abufsrc_ctx, 0, vol_ctx, 0);
1028 if (r < 0)
1029 fatal("unable to connect the audio buffer source filter to the volume filter\n");
1030 r = av_filt_link(vol_ctx, 0, afmt_ctx, 0);
1031 if (r < 0)
1032 fatal("unable to connect the volume filter to the audio format filter\n");
1033 r = av_filt_link(afmt_ctx, 0, abufsink_ctx, 0);
1034 if (r < 0)
1035 fatal("unable to connect the audio format filter to the audio buffer sink filter\n");
1036 r = av_filt_graph_cfg(filt_graph, 0);
1037 if (r < 0)
1038 fatal("unable to configure the filter graph\n");
1039 /*--------------------------------------------------------------------*/
1040 if (!print_info)
1041 return;
1042 dump_str = av_filt_graph_dump(filt_graph, 0);
1043 if (dump_str == 0) {
1044 warning("unable to get a filter graph description\n");
1045 return;
1047 pout("GRAPH START-------------------------------------------------------\n");
1048 pout("%s", dump_str);
1049 av_free(dump_str);
1050 pout("GRAPH END---------------------------------------------------------\n");
1052 #define DONT_PRINT_INFO false
1053 static void filt_flush(void)
1055 enum av_fr_fmt dst_fmt;
1056 int dst_rate;
1057 int dst_chans_n;
1058 AVChannelLayout src_chans_layout;
1059 AVChannelLayout dst_chans_layout;
1060 int r;
1062 memset(&src_chans_layout, 0, sizeof(src_chans_layout));
1063 memset(&dst_chans_layout, 0, sizeof(dst_chans_layout));
1065 av_frs_unref(filt_frs.av);
1066 filt_frs.pcm_written_ufrs_n = 0;
1068 pcm2ff(pcm_g, &dst_fmt, &dst_rate, &dst_chans_layout,
1069 DONT_PRINT_INFO);
1070 /* the audio dec ctx may not have a valid chans layout */
1071 r = av_channel_layout_check(&dec_ctx->ch_layout);
1072 if (r == 0) /* XXX: we expect at least chans_n to be valid */
1073 av_channel_layout_default(&src_chans_layout,
1074 dec_ctx->ch_layout.nb_channels);
1075 else
1076 av_channel_layout_copy(&src_chans_layout, &dec_ctx->ch_layout);
1077 filt_graph_cfg(
1078 dec_ctx->fr_fmt, dec_ctx->fr_rate, &src_chans_layout,
1079 filt_frs.muted, filt_frs.vol,
1080 dst_fmt, dst_rate, &dst_chans_layout,
1081 DONT_PRINT_INFO);
1082 av_channel_layout_uninit(&src_chans_layout);
1083 av_channel_layout_uninit(&dst_chans_layout);
1085 #undef DONT_PRINT_INFO
1086 static void stdin_tty_init_once(void)
1088 int r;
1089 struct termios tio_new;
1090 struct termios tio_chk;
1092 r = isatty(0);
1093 if (r == 0) {
1094 pout("input:standard input is not a terminal\n");
1095 return;
1097 memset(&tio_new, 0, sizeof(tio_new));
1098 memset(&tio_chk, 0, sizeof(tio_chk));
1099 memset(&stdin_tio_save, 0, sizeof(stdin_tio_save));
1100 r = tcgetattr(0, &stdin_tio_save);
1101 if (r == -1)
1102 fatal("input:unable to get the current standard input terminal line attributes\n");
1103 tio_new = stdin_tio_save;
1104 tio_new.c_lflag &= ~(ICANON|ECHO);
1105 tio_new.c_cc[VMIN] = 1; /* 1 "char", could be bytes from a utf8 code point */
1106 tio_new.c_cc[VTIME] = 0;
1107 r = tcsetattr(0, TCSANOW, &tio_new);
1108 stdin_tty_cfg_modified = true;
1109 if (r == -1)
1110 fatal("input:unable to set all standard input terminal line\n");
1111 r = tcgetattr(0, &tio_chk);
1112 if (r == -1)
1113 fatal("input:unable to get the current standard input terminal line attributes for checking\n");
1114 r = memcmp(&tio_chk, &tio_new, sizeof(tio_chk));
1115 if (r != 0)
1116 fatal("input:setting the wanted terminal line attributes failed\n");
1118 static void stdin_flags_init_once(void)
1120 int r;
1121 /* switch the standard input to non-blocking */
1122 r = fcntl(0, F_GETFL);
1123 if (r == -1)
1124 fatal("input:unable to get the file flags of the standard input\n");
1125 stdin_flags_save = r;
1126 r |= O_NONBLOCK;
1127 r = fcntl(0, F_SETFL, r);
1128 if (r == -1)
1129 fatal("input:unable to set non-blocking operations on the standard input\n");
1131 static void stdout_init_once(void)
1133 int r;
1135 r = isatty(1);
1136 if (r == 0) {
1137 pout("output:standard output not is not a terminal\n");
1138 stdout_is_tty = false;
1139 return;
1141 stdout_is_tty = true;
1144 * block as much as possible.
1145 * handle only async "usual" sigs, with sync signalfd.
1146 * allow some signals to go thru though.
1147 * always presume the process "controlling terminal" is different than the
1148 * terminal connected on standard input and standard output
1150 static void sigs_init_once(void)
1152 int r;
1153 sigset_t sset;
1155 r = sigfillset(&sset);
1156 if (r == -1)
1157 fatal("unable to get a full signal mask\n");
1158 /* the "controlling terminal" line asks for a core dump, leave it be */
1159 r = sigdelset(&sset, SIGQUIT);
1160 if (r == -1)
1161 fatal("unable to remove SIGQUIT from our signal mask\n");
1162 r = pthread_sigmask(SIG_SETMASK, &sset, 0);
1163 if (r != 0)
1164 fatal("unable to \"block\" \"all\" signals\n");
1165 /* from here, we "steal" signals with signalfd */
1166 r = sigemptyset(&sset);
1167 if (r == -1)
1168 fatal("unable to get an empty signal mask\n");
1169 /* we are asked nicely to terminate */
1170 r = sigaddset(&sset, SIGTERM);
1171 if (r == -1)
1172 fatal("unable to add SIGTERM to our signal mask\n");
1173 /* the "controlling terminal" line (^c) asks nicely to terminate */
1174 r = sigaddset(&sset, SIGINT);
1175 if (r == -1)
1176 fatal("unable to add SIGINT to our signal mask\n");
1177 r = signalfd(-1, &sset, SFD_NONBLOCK);
1178 if (r == -1)
1179 fatal("unable to get a signalfd file descriptor\n");
1180 sig_fd = r;
1182 static void evt_init_once(void)
1184 int r;
1185 u8 i;
1186 struct epoll_event evt;
1188 ep_fd = epoll_create1(0);
1189 if (ep_fd == -1)
1190 fatal("unable to create the epoll file descriptor\n");
1191 /*--------------------------------------------------------------------*/
1192 /* signals */
1193 evt.events = EPOLLIN;
1194 evt.data.fd = sig_fd;
1195 r = epoll_ctl(ep_fd, EPOLL_CTL_ADD, sig_fd, &evt);
1196 if (r == -1)
1197 fatal("unable to add the signalfd file descriptior to the epoll file descriptor\n");
1198 /*--------------------------------------------------------------------*/
1199 /* standard input/terminal */
1200 evt.events = EPOLLIN;
1201 evt.data.fd = 0;
1202 r = epoll_ctl(ep_fd, EPOLL_CTL_ADD, 0, &evt);
1203 if (r == -1)
1204 fatal("unable to add the standard input to the epoll file descriptor\n");
1205 /*--------------------------------------------------------------------*/
1206 /* the timer in charge of accounting unknown esc seq */
1207 evt.events = EPOLLIN;
1208 evt.data.fd = input_timer_fd;
1209 r = epoll_ctl(ep_fd, EPOLL_CTL_ADD, input_timer_fd, &evt);
1210 if (r == -1)
1211 fatal("unable to add the timer file descriptor accounting for unknown escape sequences to epoll file descriptor\n");
1213 static void input_state_init_once(void)
1215 input_timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
1216 if (input_timer_fd == -1)
1217 fatal("unable to get a timer file descriptor\n");
1219 input_esc_seq_mode = false;
1221 esc_seq_next_byte = 0;
1222 utf8_cp_next_byte = 0;
1224 static void input_utf8_cp_bind_cmd(void)
1226 u16 i;
1228 i = 0;
1229 loop {
1230 struct tty_bind_t *bind;
1232 if (i == ARRAY_N(tty_binds))
1233 break;
1234 bind = tty_binds + i;
1236 /* exclude esc seq binds */
1237 if ((bind->c[0] != 0x1b) && (utf8_cp_sz == bind->sz)) {
1238 int r;
1240 r = memcmp(utf8_cp, bind->c, utf8_cp_sz);
1241 if (r == 0) {
1242 bind->cmd();
1243 return;
1246 ++i;
1250 * to exit the esc seq input mode, we could implement a smart tree in order to
1251 * know if it is not possible to get any defined esc seq, or we could already
1252 * use the maximum bind esc seq sz
1254 static bool input_esc_seq_bind_cmd(void)
1256 u16 i;
1258 i = 0;
1259 loop {
1260 struct tty_bind_t *bind;
1262 if (i == ARRAY_N(tty_binds))
1263 break;
1264 bind = tty_binds + i;
1265 /* only esc seq binds */
1266 if ((bind->c[0] == 0x1b) && (esc_seq_sz == bind->sz)) {
1267 int r;
1269 r = memcmp(esc_seq, bind->c, esc_seq_sz);
1270 if (r == 0) {
1271 bind->cmd();
1272 return true;
1275 ++i;
1277 return false;
1279 static void input_byte_esc_seq(void)
1281 int r;
1282 struct itimerspec t;
1284 if (input_b == 0x1b) {
1285 esc_seq[0] = 0x1b;
1286 esc_seq_next_byte = 1;
1287 memset(&t, 0, sizeof(t));
1288 t.it_value.tv_sec = INPUT_ESC_SEQ_TIMEOUT_SECS_N;
1289 r = timerfd_settime(input_timer_fd, 0, &t, 0);
1290 if (r == -1)
1291 fatal("unable to arm the timer to account for unknown input escape sequence from the terminal\n");
1292 return;
1294 esc_seq[esc_seq_next_byte] = input_b;
1295 ++esc_seq_next_byte;
1296 if (!input_esc_seq_bind_cmd() && (esc_seq_next_byte != STR_SZ))
1297 return;
1298 memset(&t, 0, sizeof(t));
1299 r = timerfd_settime(input_timer_fd, 0, &t, 0);
1300 if (r == -1)
1301 fatal("unable to disarm the timer used to account for unknown input escape sequence from the terminal\n");
1302 esc_seq_next_byte = 0;
1303 input_esc_seq_mode = false;
1304 utf8_cp_next_byte = 0;
1306 static void input_byte_utf8_cp(void)
1308 if ((input_b & 0x80) != 0) { /* utf8 cp > 0x7f */
1309 if ((input_b & 0x40) != 0) { /* utf8 cp start byte */
1310 utf8_cp[0] = input_b;
1311 utf8_cp_next_byte = 1;
1312 if ((input_b & 0x20) == 0)
1313 utf8_cp_sz = 2;
1314 else if ((input_b & 0x10) == 0)
1315 utf8_cp_sz = 3;
1316 else /* if ((input_b & 0x08) == 0) */
1317 utf8_cp_sz = 4; /* must be 4 */
1318 return;
1320 /* (b & 0x40) == 0, utf8 cp continuation byte */
1322 * no start byte, discard (but should skip all following
1323 * continuation bytes and send the utf8 "invalid" cp)
1325 if (utf8_cp_next_byte == 0)
1326 return;
1327 utf8_cp[utf8_cp_next_byte] = input_b;
1328 ++utf8_cp_next_byte;
1329 if (utf8_cp_next_byte != utf8_cp_sz)
1330 return;
1331 } else {/* ascii 0x00 - 0x7f */
1332 if (input_b == 0x1b) {/* esc */
1333 /* change state and process the esc byte */
1334 input_esc_seq_mode = true;
1335 input_byte_esc_seq();
1336 return;
1338 utf8_cp[0] = input_b;
1339 utf8_cp_sz = 1;
1341 input_utf8_cp_bind_cmd();
1343 /* we are either reading an utf8 cp or an esc seq */
1344 static void evt_input_drain(void) { loop
1346 ssize_t r;
1348 errno = 0;
1349 r = read(0, &input_b, 1);
1350 if (r == -1) {
1351 if (errno == EAGAIN) /* no more input data */
1352 break;
1353 if (errno == EINTR) /* restart manually the call */
1354 continue;
1355 fatal("an error occured while reading the input\n");
1357 if (r == 0)
1358 fatal("input end of file\n");
1359 if (!input_esc_seq_mode)
1360 input_byte_utf8_cp();
1361 else
1362 input_byte_esc_seq();
1364 static void evt_sigs(void)
1366 int r;
1367 struct signalfd_siginfo siginfo;
1369 /* no short reads */
1370 r = read(sig_fd, &siginfo, sizeof(siginfo));
1371 if (r != sizeof(siginfo))
1372 fatal("unable to read signal information\n");
1374 switch (siginfo.ssi_signo) {
1375 case SIGTERM:
1376 exit_ok("received SIGTERM\n");
1377 case SIGINT:
1378 exit_ok("received SIGINT\n");
1379 default:
1380 warning("signal handle:unwanted signal %d received, discarding\n", siginfo.ssi_signo);
1383 static void evt_timer(void)
1385 int r;
1386 struct itimerspec t;
1388 memset(&t, 0, sizeof(t));
1389 r = timerfd_settime(input_timer_fd, 0, &t, 0);
1390 if (r == -1)
1391 fatal("unable to disarm the timer used to account for unknown input escape sequences from the terminal\n");
1393 esc_seq_next_byte = 0;
1394 input_esc_seq_mode = false;
1396 utf8_cp_next_byte = 0;
1398 static void evt_handle(struct epoll_event *evt, bool *pcm_evt)
1400 if (evt->data.fd == 0) {
1401 if ((evt->events & EPOLLIN) != 0)
1402 evt_input_drain();
1403 else
1404 fatal("event loop wait:input:unexpected event\n");
1405 } else if (evt->data.fd == sig_fd) {
1406 if ((evt->events & EPOLLIN) != 0)
1407 evt_sigs();
1408 else
1409 fatal("event loop wait:signal:unexpected event\n");
1410 } else if (evt->data.fd == input_timer_fd) {
1411 if ((evt->events & EPOLLIN) != 0)
1412 evt_timer();
1413 else
1414 fatal("event loop wait:timer:unexpected event\n");
1415 } else { /* only update alsa fds */
1416 u8 i;
1418 i = 0;
1419 loop {
1420 if (i == pcm_pollfds_n)
1421 break;
1423 if (evt->data.fd == pcm_pollfds[i].fd) {
1424 pcm_pollfds[i].revents = evt->events;
1425 *pcm_evt = true;
1427 ++i;
1431 /* fill the dec with pkts */
1432 static void dec_fill(void) { loop
1434 unsigned int sd;
1435 unsigned int rd;
1436 unsigned int next_sd;
1437 int r;
1439 rd = atomic_load(&cb.rd);
1440 sd = atomic_load(&cb.sd);
1441 /* at start, we must read pkt before we can send one */
1442 if (rd == sd)
1443 break;
1444 r = av_sd_pkt(dec_ctx, cb.pkts[sd]);
1445 /* dec is full and the pkt was rejected, or the decoder is in EOF */
1446 if (r == AVERROR(EAGAIN) || r == AVERROR_EOF)
1447 break;
1448 else if (r != 0)
1449 fatal("ffmpeg:error while sending the packet to the decoder\n");
1450 /* r == 0 */
1451 av_pkt_unref(cb.pkts[sd]);
1452 next_sd = (sd + 1) % cb.pkts_n;
1453 atomic_store(&cb.sd, next_sd);
1455 static void dec_frs_get(void) { loop
1457 int r;
1459 dec_fill();
1461 /* will unref the dec_frs.av bufs for us */
1462 r = av_receive_frs(dec_ctx, dec_frs.av);
1463 if (r == AVERROR(EAGAIN))
1464 continue;
1465 else if (r == 0) {
1466 if (dec_frs.av->pts != AV_NOPTS_VALUE)
1467 dec_frs.most_recent_ts = dec_frs.av->pts;
1468 else if (dec_frs.av->pkt_dts != AV_NOPTS_VALUE)
1469 dec_frs.most_recent_ts = dec_frs.av->pkt_dts;
1470 else
1471 dec_frs.most_recent_ts = dec_frs.av->pkt_dts;
1472 dec_frs.pushed_in_filt_graph = false;
1473 return; /* "return" the current dec_frs.av */
1474 } else if (r == AVERROR_EOF) {
1475 pout("ffmpeg:last decoder frames reached (receiving)\n");
1476 loop { /* spinning */
1477 snd_pcm_state_t state;
1479 r = snd_pcm_drain(pcm_g);
1480 if (r == 0)
1481 break;
1482 if (r == -EAGAIN)
1483 continue;
1485 * the pcm state can change asynchronously.
1486 * _old_ behavior:
1487 * if the draining was successful, the pcm
1488 * should be in SETUP state, and in this
1489 * state, snd_pcm_drain will fail
1490 * _new and fixed__ behavior:
1491 * this won't happen because calling
1492 * snd_pcm_drain while in the SETUP state
1493 * won't return an error anymore
1495 state = snd_pcm_state(pcm_g);
1496 if (state == SND_PCM_STATE_SETUP)
1497 break;
1499 /**********************************************/
1500 exit_ok("finished playing\n");
1501 /**********************************************/
1503 fatal("ffmpeg:error while receiving frames from the decoder\n");
1505 static bool is_recfg_required(av_frs *frs)
1507 if (av_channel_layout_compare(&frs->ch_layout,
1508 &abufsrc_key.chans_layout) != 0
1509 || frs->fr_rate != abufsrc_key.rate
1510 || frs->fmt != abufsrc_key.fmt)
1511 return true;
1512 return false;
1514 #define AGAIN 0
1515 #define PUSHED 1
1516 #define FILT_RECFG_REQUIRED 2
1517 static u8 filt_graph_push_dec_frs(AVChannelLayout *new_chans_layout,
1518 int *new_fr_rate, enum av_fr_fmt *new_fmt)
1520 int r;
1522 if (dec_frs.pushed_in_filt_graph)
1523 dec_frs_get();
1524 if (is_recfg_required(dec_frs.av)) {
1525 r = av_channel_layout_copy(new_chans_layout,
1526 &dec_frs.av->ch_layout);
1527 if (r < 0)
1528 fatal("ffmpeg:unable to copy the decoder channel layout as the new channel layout\n");
1529 *new_fr_rate = dec_frs.av->fr_rate;
1530 *new_fmt = dec_frs.av->fmt;
1531 return FILT_RECFG_REQUIRED;
1533 /* the dec_frs.av bufs will be unref in av_receive_frs */
1534 r = av_bufsrc_add_frs_flags(abufsrc_ctx, dec_frs.av,
1535 AV_BUFSRC_FLAG_KEEP_REF);
1536 if (r >= 0) {
1537 dec_frs.pushed_in_filt_graph = true;
1538 return PUSHED;
1539 } else if (r == AVERROR(EAGAIN))
1540 return AGAIN;
1541 fatal("ffmpeg:unable to submit a decoder set of frames to the filter source audio buffer context\n");
1543 #undef AGAIN
1544 #undef PUSHED
1545 #undef FILT_RECFG_REQUIRED
1546 static void filt_frs_get(void)
1548 int r;
1550 r = av_bufsink_get_frs(abufsink_ctx, filt_frs.av);
1551 if (r >= 0) {
1552 filt_frs.pcm_written_ufrs_n = 0;
1553 return;
1555 fatal("ffmpeg:error while getting frames from the filter\n");
1557 #define FILT_RECFG_REQUIRED 2
1558 #define EOF_FILT 2
1559 #define DRAINING 3
1560 #define HAVE_FILT_SET 1
1561 #define PRINT_INFO true
1562 /* synchronous filtering */
1563 static void dec_frs_filter(void)
1565 loop {
1566 u8 r;
1567 AVChannelLayout new_chans_layout;
1568 int new_fr_rate;
1569 enum av_fr_fmt new_fmt;
1570 AVChannelLayout dst_chans_layout;
1571 int dst_rate;
1572 enum av_fr_fmt dst_fmt;
1574 memset(&new_chans_layout, 0, sizeof(new_chans_layout));
1575 memset(&dst_chans_layout, 0, sizeof(dst_chans_layout));
1577 r = filt_graph_push_dec_frs(&new_chans_layout, &new_fr_rate,
1578 &new_fmt);
1579 if (r != FILT_RECFG_REQUIRED) {
1580 /* PUSHED | AGAIN */
1581 av_channel_layout_uninit(&new_chans_layout);
1582 break;
1584 /* FILT_RECFG_REQUIRED */
1585 pcm2ff(pcm_g, &dst_fmt, &dst_rate, &dst_chans_layout,
1586 PRINT_INFO);
1587 filt_graph_cfg(
1588 new_fmt, new_fr_rate, &new_chans_layout,
1589 filt_frs.muted, filt_frs.vol,
1590 dst_fmt, dst_rate, &dst_chans_layout, PRINT_INFO);
1591 av_channel_layout_uninit(&new_chans_layout);
1592 av_channel_layout_uninit(&dst_chans_layout);
1594 filt_frs_get();
1596 #undef FILT_RECFG_REQUIRED
1597 #undef EOF_FILT
1598 #undef DRAINING
1599 #undef HAVE_FILT_SET
1600 #undef PRINT_INFO
1601 #define NO 0
1602 static void chans_buf_init(u8 **chans_buf, int start_fr_idx)
1604 int is_planar_fmt;
1605 int sample_bytes_n;
1607 sample_bytes_n = av_get_bytes_per_sample(filt_frs.av->fmt);
1609 is_planar_fmt = av_fr_fmt_is_planar(filt_frs.av->fmt);
1610 if (is_planar_fmt == NO) { /* or is pcm interleaved */
1611 int fr_bytes_n;
1613 fr_bytes_n = sample_bytes_n
1614 * filt_frs.av->ch_layout.nb_channels;
1615 chans_buf[0] = (u8*)filt_frs.av->data[0] + start_fr_idx
1616 * fr_bytes_n;
1617 } else { /* ff planar or pcm noninterleaved */
1618 int p;
1620 p = 0;
1621 loop {
1622 if (p == filt_frs.av->ch_layout.nb_channels)
1623 break;
1624 chans_buf[p] = (u8*)filt_frs.av->data[p]
1625 + start_fr_idx * sample_bytes_n;
1626 ++p;
1630 #undef NO
1631 #define NO 0
1632 static void chans_buf_inc(u8 **chans_buf, int frs_inc)
1634 int is_planar_fmt;
1635 int sample_bytes_n;
1637 sample_bytes_n = av_get_bytes_per_sample(filt_frs.av->fmt);
1639 is_planar_fmt = av_fr_fmt_is_planar(filt_frs.av->fmt);
1640 if (is_planar_fmt == NO) { /* or is pcm interleaved */
1641 int fr_bytes_n;
1643 fr_bytes_n = sample_bytes_n
1644 * filt_frs.av->ch_layout.nb_channels;
1645 chans_buf[0] += frs_inc * fr_bytes_n;
1646 } else { /* ff planar or pcm noninterleaved */
1647 u8 p;
1649 p = 0;
1650 loop {
1651 if (p == filt_frs.av->ch_layout.nb_channels)
1652 break;
1653 chans_buf[p] += frs_inc * sample_bytes_n;
1654 ++p;
1658 #undef NO
1659 #define NO 0
1660 static void pcm_silence_frs_write(snd_pcm_ufrs_t ufrs_n)
1662 int is_planar_fmt;
1664 if (ufrs_n == 0)
1665 return;
1667 is_planar_fmt = av_fr_fmt_is_planar(filt_frs.av->fmt);
1668 if (is_planar_fmt == NO)
1669 (void)snd_pcm_writei(pcm_g, silence_bufs[0], ufrs_n);
1670 else
1671 (void)snd_pcm_writen(pcm_g, silence_bufs, ufrs_n);
1673 #undef NO
1674 #define NO 0
1675 static void pcm_filt_frs_write(snd_pcm_ufrs_t ufrs_n) { loop
1677 u8 chan_buf;
1678 u8 *chans_buf[AV_NUM_DATA_POINTERS];
1679 snd_pcm_sfrs_t r0;
1680 snd_pcm_ufrs_t ufrs_to_write_n;
1681 snd_pcm_ufrs_t filt_frs_remaining_ufrs_n; /* for clarity */
1683 if (ufrs_n == 0)
1684 return;
1685 if (filt_frs.pcm_written_ufrs_n == (snd_pcm_ufrs_t)filt_frs.av->frs_n) {
1686 av_frs_unref(filt_frs.av);
1687 dec_frs_filter(); /* synchronous filtering */
1689 /* create the chan buf pointers */
1690 chans_buf_init(chans_buf, (int)filt_frs.pcm_written_ufrs_n);
1691 filt_frs_remaining_ufrs_n = (snd_pcm_ufrs_t)filt_frs.av->frs_n
1692 - filt_frs.pcm_written_ufrs_n;
1693 if (filt_frs_remaining_ufrs_n > ufrs_n)
1694 ufrs_to_write_n = ufrs_n;
1695 else
1696 ufrs_to_write_n = filt_frs_remaining_ufrs_n;
1698 loop {
1699 int is_planar_fmt;
1700 snd_pcm_ufrs_t written_ufrs_n;
1702 is_planar_fmt = av_fr_fmt_is_planar(filt_frs.av->fmt);
1703 if (is_planar_fmt == NO)
1704 r0 = snd_pcm_writei(pcm_g, chans_buf[0],
1705 ufrs_to_write_n);
1706 else
1707 r0 = snd_pcm_writen(pcm_g, (void**)chans_buf,
1708 ufrs_to_write_n);
1709 if (r0 < 0) {
1710 if (r0 == -EAGAIN) /* return to epoll */
1711 return;
1712 else if (r0 == -EPIPE || r0 == -ESTRPIPE) {
1713 /* underrun or suspended */
1714 int r1;
1716 r1 = snd_pcm_recover(pcm_g, (int)r0, 0);
1717 if (r1 == 0) {
1718 warning("alsa:pcm recovered going back to epoll\n");
1719 return; /* recovered, go back to epoll */
1721 fatal("alsa:unable to recover from suspend/underrun\n");
1723 fatal("alsa:fatal/unhandled error while writing the frames\n");
1725 /* r0 >= 0 */
1726 written_ufrs_n = (snd_pcm_ufrs_t)r0;
1727 filt_frs.pcm_written_ufrs_n += written_ufrs_n;
1728 ufrs_n -= written_ufrs_n;
1729 ufrs_to_write_n -= written_ufrs_n;
1730 chans_buf_inc(chans_buf, (int)written_ufrs_n);
1731 if (ufrs_to_write_n == 0)
1732 break;
1735 #undef NO
1736 static void evt_pcm_write(void)
1738 snd_pcm_sfrs_t r0;
1739 /* try only 2 times */
1740 r0 = snd_pcm_avail(pcm_g);
1741 if (r0 < 0) {
1742 if (r0 == -EPIPE || r0 == -ESTRPIPE) {
1743 /* underrun or suspended */
1744 int r1;
1746 r1 = snd_pcm_recover(pcm_g, (int)r0, 0);
1747 if (r1 == 0) {
1748 warning("alsa:pcm recovered retrying to get some available frames\n");
1749 r0 = snd_pcm_avail(pcm_g);
1750 if (r0 < 0)
1751 fatal("alsa:unable to get some available frames after recovery\n");
1752 } else
1753 fatal("alsa:unable to recover from suspend/underrun\n");
1754 } else
1755 fatal("alsa:error getting some available frames\n");
1758 if (paused)
1759 pcm_silence_frs_write((snd_pcm_ufrs_t)r0);
1760 else
1761 pcm_filt_frs_write((snd_pcm_ufrs_t)r0);
1763 #define EPOLL_EVTS_N 8 /* why not */
1764 static void evts_loop(void)
1766 int fds_n;
1767 int fd_idx;
1768 struct epoll_event evts[EPOLL_EVTS_N];
1769 bool pcm_evt;
1770 int r;
1771 short pcm_evts;
1773 errno = 0;
1774 memset(evts, 0, sizeof(evts));
1775 fds_n = epoll_wait(ep_fd, evts, EPOLL_EVTS_N, -1);
1776 if (fds_n == -1) {
1777 if (errno == EINTR) {
1778 warning("event loop wait:was interrupted by a signal\n");
1779 return;
1781 fatal("event loop wait:an error occured\n");
1783 pcm_evt = false;
1784 fd_idx = 0;
1785 loop {
1786 if (fd_idx == fds_n)
1787 break;
1788 evt_handle(&evts[fd_idx], &pcm_evt);
1789 ++fd_idx;
1791 if (!pcm_evt)
1792 return;
1794 * since alsa could use several file descriptors, only once the
1795 * pollfds were properly updated we can actually know we got
1796 * something from alsa
1798 r = snd_pcm_poll_descriptors_revents(pcm_g, pcm_pollfds, pcm_pollfds_n,
1799 &pcm_evts);
1800 if (r != 0)
1801 fatal("alsa:error processing the poll file descriptors\n");
1802 if ((pcm_evts & ~POLLOUT) != 0)
1803 fatal("alsa:unexpected events\n");
1804 if ((pcm_evts & POLLOUT) != 0)
1805 evt_pcm_write();
1807 #undef EPOLL_EVTS_N
1808 static void silence_bufs_init_once(void)
1810 memset(silence_bufs, 0, sizeof(silence_bufs));
1812 static void silence_bufs_cfg(snd_pcm_t *pcm, bool print_info)
1814 int r;
1815 snd_pcm_hw_params_t *hw_params;
1816 snd_pcm_ufrs_t buf_ufrs_n;
1817 snd_pcm_fmt_t fmt;
1818 snd_pcm_access_t access;
1819 unsigned int chans_n;
1820 u8 c;
1822 r = snd_pcm_hw_params_malloc(&hw_params);
1823 if (r < 0)
1824 fatal("silence:alsa:unable to allocate memory for a hardware parameters container\n");
1825 r = snd_pcm_hw_params_current(pcm, hw_params);
1826 if (r != 0)
1827 fatal("silence:alsa:unable to get the pcm hardware parameters\n");
1828 r = snd_pcm_hw_params_get_buf_size(hw_params, &buf_ufrs_n);
1829 if (r < 0)
1830 fatal("silence:alsa:unable to get the number of frs in the pcm buffer\n");
1831 r = snd_pcm_hw_params_get_fmt(hw_params, &fmt);
1832 if (r < 0)
1833 fatal("silence:alsa:unable to get the pcm format\n");
1834 r = snd_pcm_hw_params_get_access(hw_params, &access);
1835 if (r < 0)
1836 fatal("silence:alsa:unable to get the pcm access mode\n");
1837 r = snd_pcm_hw_params_get_chans(hw_params, &chans_n);
1838 if (r < 0)
1839 fatal("silence:alsa:unable to get the pcm number of channels\n");
1840 /* wipe silence bufs first */
1841 c = 0;
1842 loop {
1843 if (c == AV_NUM_DATA_POINTERS)
1844 break;
1845 if (silence_bufs[c] != 0) {
1846 free(silence_bufs[c]);
1847 silence_bufs[c] = 0;
1849 ++c;
1851 if (access == SND_PCM_ACCESS_RW_INTERLEAVED
1852 || access == SND_PCM_ACCESS_MMAP_INTERLEAVED) {
1853 ssize_t buf_bytes_n;
1855 buf_bytes_n = snd_pcm_frs_to_bytes(pcm,
1856 (snd_pcm_sfrs_t)buf_ufrs_n);
1857 if (buf_bytes_n <= 0)
1858 fatal("silence:alsa:interleaved:unable to get the pcm number of bytes of all buffer frames\n");
1859 silence_bufs[0] = malloc((size_t)buf_bytes_n);
1860 if (silence_bufs[0] == 0)
1861 fatal("silence:interleaved:unable to allocate the silence buffer of %d bytes\n", (int)buf_bytes_n);
1862 if (print_info)
1863 pout("silence:interleaved:buffer of %d bytes is allocated\n", (int)buf_bytes_n);
1864 r = snd_pcm_fmt_set_silence(fmt, silence_bufs[0],
1865 (unsigned int)buf_ufrs_n);
1866 if (r < 0)
1867 fatal("silence:interleaved:unable to fill with silence the buffer\n");
1868 pout("silence:interleaved:silence buffer filled with %u silence frames\n", buf_ufrs_n);
1869 } else if (access == SND_PCM_ACCESS_RW_NONINTERLEAVED
1870 || access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED) {
1871 ssize_t buf_bytes_n;
1872 long buf_samples_n;
1874 buf_samples_n = (long)buf_ufrs_n;
1875 buf_bytes_n = snd_pcm_samples_to_bytes(pcm, buf_samples_n);
1876 if (buf_bytes_n <= 0)
1877 fatal("silence:alsa:non interleaved:unable to get the pcm number of total bytes of all buffer samples\n");
1878 c = 0;
1879 loop {
1880 if (c == chans_n)
1881 break;
1882 silence_bufs[c] = malloc((size_t)buf_bytes_n);
1883 if (silence_bufs[c] == 0)
1884 fatal("silence:non interleaved:unable to allocate silence buffer %u of %d bytes\n", c, (int)buf_bytes_n);
1885 r = snd_pcm_fmt_set_silence(fmt, silence_bufs[c],
1886 (unsigned int)buf_samples_n);
1887 if (r < 0)
1888 fatal("silence:non interleaved:unable to fill with silence the buffer\n");
1889 if (print_info)
1890 pout("silence:non interleaved:buffer[%u] of %d bytes is allocated\n", c, (int)buf_bytes_n);
1891 ++c;
1893 if (print_info)
1894 pout("silence:non interleaved:allocated %u silence buffers for %u frames\n", chans_n, (unsigned int)buf_ufrs_n);
1895 } else
1896 fatal("silence:the pcm access type is not supported\n");
1897 snd_pcm_hw_params_free(hw_params);
1899 static void ff_log_stdout(void *a, int b, const char *fmt, va_list ap)
1901 vprintf(fmt, ap);
1903 struct ff_supported_fr_fmt_t {
1904 u8 *str;
1905 enum av_fr_fmt fmt;
1907 /* this is the intersection of ff audio fr fmt and alsa pcm fmt */
1908 static struct ff_supported_fr_fmt_t ff_supported_fr_fmts[] = {
1909 {"u8", AV_FR_FMT_U8},
1910 {"u8planar", AV_FR_FMT_U8P},
1911 {"s16", AV_FR_FMT_S16},
1912 {"s16planar", AV_FR_FMT_S16P},
1913 {"s32", AV_FR_FMT_S32},
1914 {"s32planar", AV_FR_FMT_S32P},
1915 {"float32", AV_FR_FMT_FLT},
1916 {"float32planar", AV_FR_FMT_FLTP},
1917 {"float64", AV_FR_FMT_DBL},
1918 {"float64planar", AV_FR_FMT_DBLP},
1919 {0,0}
1921 static void usage(void)
1923 struct ff_supported_fr_fmt_t *fmt;
1925 pout("\
1926 npa [-p alsa pcm] [-v volume(0..100)] [-cb circular buffer slots]\n\
1927 [-fc override initial ffmpeg count of channels used to approximate the alsa\n\
1928 pcm configuration]\n\
1929 [-fr override initial ffmpeg rate(hz) used to approximate the alsa pcm\n\
1930 configuration]\n\
1931 [-ff override initial ffmpeg audio frame format used to approximate the alsa\n\
1932 pcm configuration, see below for a list]\n\
1933 [-h]\n\
1934 url\n\
1936 the ffmpeg audio frame formats which intersect alsa pcm audio formats are:\n");
1938 fmt = ff_supported_fr_fmts;
1939 loop {
1940 if (fmt->str == 0)
1941 break;
1942 pout("\t%s\n", fmt->str);
1943 ++fmt;
1946 static void opts_parse(int argc, u8 **args, u8 **url, u8 **pcm_str,
1947 double *initial_vol, unsigned int *cb_slots_n,
1948 int *override_initial_ff_chans_n,
1949 int *override_initial_ff_rate,
1950 enum av_fr_fmt *override_initial_ff_fr_fmt)
1952 int i;
1953 int url_idx;
1955 i = 1;
1956 url_idx = -1;
1957 loop {
1958 if (i == argc)
1959 break;
1960 if (strcmp("-p", args[i]) == 0) {
1961 if ((i + 1) == argc)
1962 fatal("-p:alsa pcm is missing\n");
1963 *pcm_str = args[i + 1];
1964 pout("-p:alsa pcm \"%s\"\n", *pcm_str);
1965 i += 2;
1966 } else if (strcmp("-v", args[i]) == 0) {
1967 unsigned long vol_ul;
1969 if ((i + 1) == argc)
1970 fatal("-v:initial volume option is missing\n");
1971 vol_ul = strtoul(args[i + 1], 0, 10);
1972 if (vol_ul < 0 || 100 < vol_ul)
1973 fatal("-v:invalid volume value %lu (0..100)\n", vol_ul);
1974 *initial_vol = (double)vol_ul / 100.0;
1975 pout("-v:using initial volume %f\n", *initial_vol);
1976 i += 2;
1977 } else if (strcmp("-cb", args[i]) == 0) {
1978 if ((i + 1) == argc)
1979 fatal("-cb:count of slots is missing\n");
1980 *cb_slots_n = (unsigned int)strtoul(args[i + 1], 0, 10);
1981 pout("-cb:using %u circular buffer slots\n",
1982 *cb_slots_n);
1983 i += 2;
1984 /*------------------------------------------------------------*/
1985 /* ff initial override for alsa pcm cfg -- start */
1986 } else if (strcmp("-fr", args[i]) == 0) {
1987 if ((i + 1) == argc) {
1988 perr("-fr:override initial ffmpeg rate(hz) is missing\n");
1989 usage();
1990 exit(1);
1992 *override_initial_ff_rate = (int)strtol(args[i + 1], 0,
1993 10);
1994 pout("-fr:override initial ffmpeg audio rate to %dHz used for alsa pcm configuration\n", *override_initial_ff_rate);
1995 i += 2;
1996 } else if (strcmp("-fc", args[i]) == 0) {
1997 if ((i + 1) == argc) {
1998 perr("-fc:override initial ffmpeg channel count is missing\n");
1999 usage();
2000 exit(1);
2002 *override_initial_ff_chans_n = (int)strtol(args[i + 1],
2003 0, 10);
2004 pout("-fc:override initial ffmpeg count of channels to %d used for alsa pcm configuration\n", *override_initial_ff_chans_n);
2005 i += 2;
2006 } else if (strcmp("-ff", args[i]) == 0) {
2007 struct ff_supported_fr_fmt_t *fmt;
2009 if ((i + 1) == argc) {
2010 perr("-fc:override initial ffmpeg audio frame format is missing\n");
2011 usage();
2012 exit(1);
2014 fmt = ff_supported_fr_fmts;
2015 loop {
2016 if (fmt->str == 0) {
2017 perr("-ff:unknown ffmpeg audio frame format\n");
2018 usage();
2019 exit(1);
2021 if (strcmp(fmt->str, args[i + 1]) == 0) {
2022 *override_initial_ff_fr_fmt = fmt->fmt;
2023 break;
2025 ++fmt;
2027 pout("-ff:override initial ffmpeg audio frame format is %s\n", av_get_fr_fmt_name(*override_initial_ff_fr_fmt));
2028 i += 2;
2029 /* ff initial override for alsa pcm cfg -- end */
2030 /*------------------------------------------------------------*/
2031 } else if (strcmp("-h", args[i]) == 0) {
2032 usage();
2033 exit(0);
2034 } else {
2035 url_idx = i;
2036 ++i;
2039 if (url_idx == -1)
2040 fatal("missing url\n");
2041 *url = args[url_idx];
2042 pout("playing ####%s####\n", *url);
2044 #define RESET_DONE 0
2045 #define DONT_HOLD 0
2046 static void cb_init_once(unsigned int cb_slots_n)
2048 unsigned int i;
2050 cb.pkts = malloc(cb_slots_n * sizeof(*cb.pkts));
2051 i = 0;
2052 loop {
2053 cb.pkts[i] = av_packet_alloc();
2054 if (cb.pkts[i] == 0)
2055 fatal("unable to allocate a packet reference for the circular buffer\n");
2056 if (i == cb_slots_n)
2057 break;
2058 ++i;
2060 cb.pkts_n = cb_slots_n;
2061 atomic_store(&cb.rd, 0);
2062 atomic_store(&cb.sd, 0);
2063 atomic_store(&cb.st_idx, -1);
2064 atomic_store(&cb.reset, RESET_DONE);
2065 atomic_store(&cb.hold, DONT_HOLD);
2067 #undef RESET_DONE
2068 #undef DONT_HOLD
2069 static void filt_graph_init_once(void)
2071 filt_graph = 0;
2072 abufsrc_ctx = 0;
2073 abufsrc_filt = 0;
2074 memset(&abufsrc_key, 0, sizeof(abufsrc_key));
2075 vol_ctx = 0;
2076 vol_filt = 0;
2077 afmt_ctx = 0;
2078 afmt_filt = 0;
2079 abufsink_ctx = 0;
2080 abufsink_filt = 0;
2081 /* floating point strs are localized... */
2082 snprintf(double_zero_l10n_str, sizeof(double_zero_l10n_str), "%f", 0.);
2083 memset(&filt_frs, 0, sizeof(filt_frs));
2084 filt_frs.av = av_frs_alloc();
2085 if (filt_frs.av == 0)
2086 fatal("ffmpeg:unable to allocate a filtered frames structure\n");
2087 filt_frs.pcm_written_ufrs_n = 0;
2089 static void dec_init_once(void)
2091 dec = 0;
2092 dec_ctx = 0;
2093 dec_frs.av = av_frs_alloc();
2094 if (dec_frs.av == 0)
2095 fatal("ffmpeg:unable to allocate a decoded frames structure\n");
2096 dec_frs.pushed_in_filt_graph = true;
2097 dec_frs.most_recent_ts = AV_NOPTS_VALUE;
2099 static void rd_thd_init_once(void)
2101 rd_thd_pkt = av_packet_alloc();
2102 if (rd_thd_pkt == 0)
2103 fatal("ffmpeg:unable to allocate a packet for the read thread\n");
2105 static void fmt_init_once(u8 *url)
2107 int r;
2109 fmt_ctx = 0;
2110 r = av_fmt_open_input(&fmt_ctx, url, NULL, NULL);
2111 if (r < 0)
2112 fatal("ffmpeg:unable to open \"%s\"\n", url);
2113 /* probe beyond the header, if any */
2114 r = av_fmt_find_st_info(fmt_ctx, 0);
2115 if (r < 0)
2116 fatal("ffmpeg:unable to probe \"%s\"\n", url);
2117 r = pthread_mutex_init(&fmt_ctx_mutex, 0);
2118 if (r != 0)
2119 fatal("unable to init the format context mutex\n");
2121 static void pcm_init_once(u8 *pcm_str)
2123 int r;
2125 r = snd_output_stdio_attach(&pcm_pout, stdout, 0);
2126 if (r < 0)
2127 fatal("alsa:unable to attach stdout\n");
2128 r = snd_output_stdio_attach(&pcm_perr, stderr, 0);
2129 if (r < 0)
2130 fatal("alsa:unable to attach stderr\n");
2131 r = snd_pcm_open(&pcm_g, pcm_str, SND_PCM_ST_PLAYBACK,
2132 SND_PCM_NONBLOCK);
2133 if (r < 0) {
2134 if (r == -EAGAIN)
2135 fatal("alsa:\"%s\" pcm is already in use\n", pcm_str);
2136 else
2137 fatal("alsa:unable to open \"%s\" pcm for playback\n", pcm_str);
2140 static void init_once(u8 *url, u8 *pcm_str, unsigned int cb_slots_n)
2142 stdin_tty_cfg_modified = false;
2143 current_url = url;
2144 paused = false;
2146 sigs_init_once();
2147 stdin_tty_init_once();
2148 stdin_flags_init_once();
2149 stdout_init_once();
2150 input_state_init_once();
2151 cb_init_once(cb_slots_n);
2152 filt_graph_init_once();
2153 silence_bufs_init_once();
2154 dec_init_once();
2155 pcm_init_once(pcm_str);
2156 rd_thd_init_once();
2157 fmt_init_once(url);
2158 evt_init_once();
2160 static int find_best_st(void)
2162 int r;
2164 r = av_find_best_st(fmt_ctx, AV_MEDIA_TYPE_AUDIO, -1, -1, 0, 0);
2165 if (r < 0)
2166 fatal("ffmpeg:no audio stream found\n");
2167 return r;
2169 static void pcm_hw_chans_n_decide(snd_pcm_t *pcm,
2170 snd_pcm_hw_params_t *pcm_hw_params, unsigned int chans_n)
2172 int r;
2173 unsigned int chans_n_max;
2174 unsigned int chans_n_min;
2176 r = snd_pcm_hw_params_test_chans(pcm, pcm_hw_params, chans_n);
2177 if (r == 0) {
2178 r = snd_pcm_hw_params_set_chans(pcm, pcm_hw_params, chans_n);
2179 if (r != 0)
2180 fatal("alsa:unable to restrict pcm device to %u channels, count which was successfully tested\n", chans_n);
2181 pout("alsa:using %u channels\n", chans_n);
2182 return;
2184 pout("alsa:unable to use %u channels\n", chans_n);
2185 /* try to use the max chans n the pcm can */
2186 r = snd_pcm_hw_params_get_chans_max(pcm_hw_params, &chans_n_max);
2187 if (r != 0)
2188 fatal("alsa:unable to get the maximum count of pcm device channels\n");
2189 r = snd_pcm_hw_params_test_chans(pcm, pcm_hw_params, chans_n_max);
2190 if (r == 0) {
2191 r = snd_pcm_hw_params_set_chans(pcm, pcm_hw_params,
2192 chans_n_max);
2193 if (r != 0)
2194 fatal("alsa:unable to restrict pcm device to %u channels, count which was successfully tested\n", chans_n_max);
2195 pout("alsa:using pcm maximum %u channels\n", chans_n_max);
2196 return;
2198 /* ok... last try, the pcm dev min chans n */
2199 r = snd_pcm_hw_params_get_chans_min(pcm_hw_params, &chans_n_min);
2200 if (r != 0)
2201 fatal("alsa:unable to get the minimum count of pcm device channels\n");
2202 r = snd_pcm_hw_params_test_chans(pcm, pcm_hw_params, chans_n_min);
2203 if (r == 0) {
2204 r = snd_pcm_hw_params_set_chans(pcm, pcm_hw_params,
2205 chans_n_min);
2206 if (r != 0)
2207 fatal("alsa:unable to restrict pcm device to %u channels, count which was successfully tested\n", chans_n_min);
2208 pout("alsa:using pcm device minimum %u channels\n", chans_n_min);
2209 return;
2211 fatal("alsa:unable to find a suitable count of channels\n");
2213 static void pcm_hw_rate_decide(snd_pcm_t *pcm,
2214 snd_pcm_hw_params_t *pcm_hw_params, unsigned int rate)
2216 int r;
2217 unsigned int rate_max;
2218 unsigned int rate_near;
2219 unsigned int rate_min;
2221 r = snd_pcm_hw_params_test_rate(pcm, pcm_hw_params, rate,
2222 SND_PCM_ST_PLAYBACK);
2223 if (r == 0) {
2224 r = snd_pcm_hw_params_set_rate(pcm, pcm_hw_params, rate,
2225 SND_PCM_ST_PLAYBACK);
2226 if (r != 0)
2227 fatal("alsa:unable to restrict pcm device to %uHz, which was successfully tested\n", rate);
2228 pout("alsa:using %uHz\n", rate);
2229 return;
2231 pout("alsa:unable to use %uHz\n", rate);
2232 /* try to use the max rate the pcm can */
2233 r = snd_pcm_hw_params_get_rate_max(pcm_hw_params, &rate_max,
2234 SND_PCM_ST_PLAYBACK);
2235 if (r != 0)
2236 fatal("alsa:unable to get the maximum rate of pcm device\n");
2237 r = snd_pcm_hw_params_test_rate(pcm, pcm_hw_params, rate_max,
2238 SND_PCM_ST_PLAYBACK);
2239 if (r == 0) {
2240 r = snd_pcm_hw_params_set_rate(pcm, pcm_hw_params, rate_max,
2241 SND_PCM_ST_PLAYBACK);
2242 if (r != 0)
2243 fatal("alsa:unable to restrict pcm device to %uHz, which was successfully tested\n", rate_max);
2244 pout("alsa:using pcm device %uHz\n", rate_max);
2245 return;
2247 /* try to use a rate "near" of what the pcm dev can */
2248 rate_near = rate;
2249 r = snd_pcm_hw_params_set_rate_near(pcm, pcm_hw_params, &rate_near,
2250 SND_PCM_ST_PLAYBACK);
2251 if (r == 0) {
2252 pout("alsa:using pcm device %uHz\n", rate_near);
2253 return;
2255 /* even a "near" rate did failed... try the min */
2256 r = snd_pcm_hw_params_get_rate_min(pcm_hw_params, &rate_min,
2257 SND_PCM_ST_PLAYBACK);
2258 if (r != 0)
2259 fatal("alsa:unable to get the minimum rate of pcm device\n");
2260 r = snd_pcm_hw_params_test_rate(pcm, pcm_hw_params, rate_min,
2261 SND_PCM_ST_PLAYBACK);
2262 if (r == 0) {
2263 r = snd_pcm_hw_params_set_rate(pcm, pcm_hw_params, rate_min,
2264 SND_PCM_ST_PLAYBACK);
2265 if (r != 0)
2266 fatal("alsa:unable to restrict pcm device to %uHz, which was successfully tested\n", rate_min);
2267 pout("alsa:using pcm device %uHz\n", rate_min);
2268 return;
2270 fatal("alsa:unable to find a suitable rate\n");
2272 static bool ff_fmt2pcm_layout_best_effort(enum av_fr_fmt ff_fmt,
2273 snd_pcm_fmt_t *alsa_fmt, snd_pcm_access_t *alsa_access)
2275 static u8 ff_fmt_str[STR_SZ];
2277 av_get_fr_fmt_str(ff_fmt_str, STR_SZ, ff_fmt);
2278 /* XXX: only classic non-mmap ones */
2279 switch (ff_fmt) {
2280 case AV_FR_FMT_U8:
2281 *alsa_fmt = SND_PCM_FMT_U8;
2282 *alsa_access = SND_PCM_ACCESS_RW_INTERLEAVED;
2283 break;
2284 case AV_FR_FMT_S16:
2285 *alsa_fmt = SND_PCM_FMT_S16;
2286 *alsa_access = SND_PCM_ACCESS_RW_INTERLEAVED;
2287 break;
2288 case AV_FR_FMT_S32:
2289 *alsa_fmt = SND_PCM_FMT_S32;
2290 *alsa_access = SND_PCM_ACCESS_RW_INTERLEAVED;
2291 break;
2292 case AV_FR_FMT_FLT:
2293 *alsa_fmt = SND_PCM_FMT_FLT;
2294 *alsa_access = SND_PCM_ACCESS_RW_INTERLEAVED;
2295 break;
2296 /* ff "planar" fmts are actually non interleaved fmts */
2297 case AV_FR_FMT_U8P:
2298 *alsa_fmt = SND_PCM_FMT_U8;
2299 *alsa_access = SND_PCM_ACCESS_RW_NONINTERLEAVED;
2300 break;
2301 case AV_FR_FMT_S16P:
2302 *alsa_fmt = SND_PCM_FMT_S16;
2303 *alsa_access = SND_PCM_ACCESS_RW_NONINTERLEAVED;
2304 break;
2305 case AV_FR_FMT_S32P:
2306 *alsa_fmt = SND_PCM_FMT_S32;
2307 *alsa_access = SND_PCM_ACCESS_RW_NONINTERLEAVED;
2308 break;
2309 case AV_FR_FMT_FLTP:
2310 *alsa_fmt = SND_PCM_FMT_FLT;
2311 *alsa_access = SND_PCM_ACCESS_RW_NONINTERLEAVED;
2312 break;
2313 default:
2314 pout("best effort:unable to wire ffmpeg sample format \"%sbits\" to alsa sample format, \n,", ff_fmt_str);
2315 return false;
2317 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_fmt_desc(*alsa_fmt), snd_pcm_access_name(*alsa_access));
2318 return true;
2320 static bool pcm_hw_fmt_decide_x(snd_pcm_t *pcm,
2321 snd_pcm_hw_params_t *pcm_hw_params, snd_pcm_fmt_t fmt)
2323 int r;
2325 r = snd_pcm_hw_params_test_fmt(pcm, pcm_hw_params, fmt);
2326 if (r != 0)
2327 return false;
2328 r = snd_pcm_hw_params_set_fmt(pcm, pcm_hw_params, fmt);
2329 if (r != 0)
2330 fatal("alsa:unable to restrict pcm device to \"%s\", which was successfully tested\n", snd_pcm_fmt_desc(fmt));
2331 pout("alsa:using \"%s\" format\n", snd_pcm_fmt_desc(fmt));
2332 return true;
2334 #define PCM_HW_FMT_DECIDE_X(fmt) pcm_hw_fmt_decide_x(pcm, pcm_hw_params, fmt)
2335 static void pcm_hw_fmt_decide(snd_pcm_t *pcm,
2336 snd_pcm_hw_params_t *pcm_hw_params, bool force,
2337 snd_pcm_fmt_t forced_fmt)
2339 int r;
2340 snd_pcm_fmt_t *fmt;
2342 if (force) {
2343 r = snd_pcm_hw_params_test_fmt(pcm, pcm_hw_params, forced_fmt);
2344 if (r == 0) {
2345 r = snd_pcm_hw_params_set_fmt(pcm, pcm_hw_params,
2346 forced_fmt);
2347 if (r != 0)
2348 fatal("alsa:unable to restrict pcm device to \"%s\", which was successfully tested\n", snd_pcm_fmt_desc(forced_fmt));
2349 pout("alsa:using forced \"%s\" format\n", snd_pcm_fmt_desc(forced_fmt));
2350 return;
2353 /* then we try to select from the reasonable "best" to the lowest */
2354 /* prefer fmts we know supported by ff */
2355 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FMT_FLT))
2356 return;
2357 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FMT_S32))
2358 return;
2359 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FMT_S16))
2360 return;
2361 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FMT_U8))
2362 return;
2364 * from here, at the time of writting, those fmts have no ff
2365 * wiring, but we are alsa centric here, validate that later
2367 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FMT_U32))
2368 return;
2369 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FMT_S24))
2370 return;
2371 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FMT_U24))
2372 return;
2373 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FMT_U16))
2374 return;
2375 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FMT_S8))
2376 return;
2377 fatal("alsa:unable to find a suitable format\n");
2379 #undef PCM_HW_FMT_DECIDE_X
2380 static bool pcm_hw_access_decide_x(snd_pcm_t *pcm,
2381 snd_pcm_hw_params_t *pcm_hw_params, snd_pcm_access_t access)
2383 int r;
2385 r = snd_pcm_hw_params_test_access(pcm, pcm_hw_params, access);
2386 if (r != 0)
2387 return false;
2388 r = snd_pcm_hw_params_set_access(pcm, pcm_hw_params, access);
2389 if (r != 0)
2390 fatal("alsa:unable to restrict pcm device to \"%s\", which was successfully tested\n", snd_pcm_access_name(access));
2391 pout("alsa:using \"%s\" access\n", snd_pcm_access_name(access));
2392 return true;
2394 #define PCM_HW_ACCESS_DECIDE_X(access) \
2395 pcm_hw_access_decide_x(pcm, pcm_hw_params, access)
2396 /* XXX: only classic non-mmap ones */
2397 static void pcm_hw_access_decide(snd_pcm_t *pcm,
2398 snd_pcm_hw_params_t *pcm_hw_params, bool force,
2399 snd_pcm_access_t forced_access)
2401 int r;
2402 snd_pcm_access_t access;
2404 if (force) {
2405 r = snd_pcm_hw_params_test_access(pcm, pcm_hw_params,
2406 forced_access);
2407 if (r == 0) {
2408 r = snd_pcm_hw_params_set_access(pcm, pcm_hw_params,
2409 forced_access);
2410 if (r != 0)
2411 fatal("alsa:unable to restrict pcm device to \"%s\", which was successfully tested\n", snd_pcm_access_name(forced_access));
2412 pout("alsa:using forced \"%s\" access\n", snd_pcm_access_name(forced_access));
2413 return;
2416 /* brute force */
2417 if (PCM_HW_ACCESS_DECIDE_X(SND_PCM_ACCESS_RW_INTERLEAVED))
2418 return;
2419 if (PCM_HW_ACCESS_DECIDE_X(SND_PCM_ACCESS_RW_NONINTERLEAVED))
2420 return;
2421 fatal("alsa:unable to find a suitable access\n");
2423 #undef PCM_HW_ACCESS_DECIDE_X
2425 * latency control: some audio bufs can be huge (tested on a pulseaudio with 10
2426 * secs audio buf). if we are careless, we will quickly fill this buf which is
2427 * worth a significant amount of time, hence will add huge latency to our
2428 * interactive audio filtering (vol...). in the case of the 10 secs pulseaudio
2429 * buf, it means if you want to mute the audio, it will happen 10 secs later.
2430 * we add lantency control by limiting the sz of the dev audio buf, in periods
2431 * n.
2432 * we choose roughly 0.25 secs, or roughly (rate / 4) frs.
2434 static void pcm_hw_buf_sz_cfg(snd_pcm_t *pcm,
2435 snd_pcm_hw_params_t *pcm_hw_params)
2437 int r;
2438 snd_pcm_ufrs_t latency_control_target_buf_ufrs_n;
2439 snd_pcm_ufrs_t latency_control_buf_ufrs_n;
2440 unsigned int rate;
2442 r = snd_pcm_hw_params_get_rate(pcm_hw_params, &rate, 0);
2443 if (r < 0) {
2444 warning("alsa:latency control:DISABLING LATENCY CONTROL:unable to get the decided rate from the current device parameters\n");
2445 return;
2447 latency_control_target_buf_ufrs_n = (snd_pcm_ufrs_t)rate;
2448 latency_control_target_buf_ufrs_n /= 4;
2449 latency_control_buf_ufrs_n = latency_control_target_buf_ufrs_n;
2450 r = snd_pcm_hw_params_set_buf_size_near(pcm, pcm_hw_params,
2451 &latency_control_buf_ufrs_n);
2452 if (r < 0) {
2453 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);
2454 return;
2456 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);
2458 static void pcm_cfg_sw(snd_pcm_t *pcm)
2460 int r;
2461 snd_pcm_sw_params_t *sw_params;
2463 pout("ALSA:SW_PARAMS START------------------------------------------------------------\n");
2464 r = snd_pcm_sw_params_malloc(&sw_params);
2465 if (r != 0)
2466 fatal("alsa:unable to allocate software parameters structure\n");
2467 r = snd_pcm_sw_params_current(pcm, sw_params);
2468 if (r != 0)
2469 fatal("alsa:unable to get current software parameters\n");
2470 r = snd_pcm_sw_params_set_period_event(pcm, sw_params, 1);
2471 if (r != 0)
2472 fatal("alsa:unable to enable period event\n");
2473 r = snd_pcm_sw_params(pcm, sw_params);
2474 if (r != 0)
2475 fatal("alsa:unable to install sotfware parameters\n");
2476 snd_pcm_sw_params_dump(sw_params, pcm_pout);
2477 snd_pcm_sw_params_free(sw_params);
2478 pout("ALSA:SW_PARAMS END--------------------------------------------------------------\n");
2481 * this function will "decide" the pcm dev cfg:
2482 * the goal is to be the "closest" to the provided params,
2483 * the "gap" will have to "filled" with ff filts
2485 * the "strategy" is a "fall-thru" (chans n then ... then ...) which
2486 * will "restrict" the pcm dev cfg further at each step
2488 * we try to use a sensible restrict order regarding audio props
2490 static void pcm_cfg_hw_core(snd_pcm_t *pcm, snd_pcm_hw_params_t *pcm_hw_params,
2491 int chans_n, int rate, enum av_fr_fmt ff_fmt)
2493 int r;
2494 bool best_effort_wiring_success;
2495 snd_pcm_fmt_t fmt_from_best_effort;
2496 snd_pcm_access_t access_from_best_effort;
2498 /* the return value is from a first refine of the raw hw params */
2499 r = snd_pcm_hw_params_any(pcm, pcm_hw_params);
2500 if (r < 0)
2501 fatal("alsa:unable to populate the hardware parameters context\n");
2502 pcm_hw_chans_n_decide(pcm, pcm_hw_params, (unsigned int)chans_n);
2503 pcm_hw_rate_decide(pcm, pcm_hw_params, (unsigned int)rate);
2504 /* try our best */
2505 best_effort_wiring_success = ff_fmt2pcm_layout_best_effort(
2506 ff_fmt, &fmt_from_best_effort, &access_from_best_effort);
2507 pcm_hw_fmt_decide(pcm, pcm_hw_params, best_effort_wiring_success,
2508 fmt_from_best_effort);
2509 pcm_hw_access_decide(pcm, pcm_hw_params, best_effort_wiring_success,
2510 access_from_best_effort);
2511 pcm_hw_buf_sz_cfg(pcm, pcm_hw_params);
2513 static void pcm_cfg_hw(snd_pcm_t *pcm, unsigned int chans_n, unsigned int rate,
2514 enum av_fr_fmt ff_fmt)
2516 int r;
2517 snd_pcm_access_t access;
2518 snd_pcm_hw_params_t *hw_params;
2520 pout("ALSA:HW_PARAMS START------------------------------------------------------------\n");
2521 r = snd_pcm_hw_params_malloc(&hw_params);
2522 if (r < 0)
2523 fatal("alsa:unable to allocate hardware parameters context\n");
2524 pcm_cfg_hw_core(pcm, hw_params, chans_n, rate, ff_fmt);
2525 r = snd_pcm_hw_params(pcm, hw_params);
2526 if (r != 0)
2527 fatal("alsa:unable to install the hardware parameters\n");
2528 r = snd_pcm_hw_params_current(pcm, hw_params);
2529 if (r != 0)
2530 fatal("alsa:unable to get current hardware parameters\n");
2531 snd_pcm_hw_params_dump(hw_params, pcm_pout);
2532 snd_pcm_hw_params_free(hw_params);
2533 pout("ALSA:HW_PARAMS END--------------------------------------------------------------\n");
2535 static void pcm_cfg_epoll(snd_pcm_t *pcm)
2537 int r;
2539 r = snd_pcm_poll_descriptors_count(pcm);
2540 pout("alsa:have %d poll file descriptors\n", r);
2541 if ((r <= 0) || (r > PCM_POLLFDS_N_MAX))
2542 fatal("alsa:invalid count of alsa poll file descriptors\n");
2543 pcm_pollfds_n =(u8)r;
2544 memset(pcm_pollfds, 0, sizeof(pcm_pollfds));
2545 snd_pcm_poll_descriptors(pcm, pcm_pollfds,
2546 (unsigned int)pcm_pollfds_n);
2548 static void pcm_cfg(snd_pcm_t *pcm, unsigned int chans_n, unsigned int rate,
2549 enum av_fr_fmt ff_fmt)
2551 pcm_cfg_hw(pcm, chans_n, rate, ff_fmt);
2552 pcm_cfg_sw(pcm);
2553 pcm_cfg_epoll(pcm); /* This must be done AFTER the sw params are set */
2554 pout("ALSA PCM DUMP START-------------------------------------------------------------\n");
2555 snd_pcm_dump(pcm, pcm_pout);
2556 pout("ALSA PCM DUMP END---------------------------------------------------------------\n");
2558 static void evt_pcm_install(void)
2560 u8 i;
2562 i = 0;
2563 loop {
2564 struct epoll_event evt;
2565 int r;
2567 if (i == pcm_pollfds_n)
2568 break;
2569 evt.events = pcm_pollfds[i].events;
2570 evt.data.fd = pcm_pollfds[i].fd;
2571 r = epoll_ctl(ep_fd, EPOLL_CTL_ADD, pcm_pollfds[i].fd, &evt);
2572 if (r == -1)
2573 fatal("unable to add alsa poll file descriptor[%d]=%d to epoll file descriptor\n", i, pcm_pollfds[i].fd);
2574 ++i;
2576 pout("alsa:pcm events installed\n");
2578 #define PRINT_INFO true
2579 #define CHANS_N_NOT_OVERRIDDEN 0
2580 #define RATE_NOT_OVERRIDDEN 0
2581 #define FR_FMT_NOT_OVERRIDDEN AV_FR_FMT_NONE
2582 static void prepare(int st_idx, double initial_vol,
2583 int override_initial_ff_chans_n, int override_initial_ff_rate,
2584 enum av_fr_fmt override_initial_ff_audio_fr_fmt)
2586 enum av_fr_fmt dst_fmt;
2587 int initial_ff_chans_n;
2588 int initial_ff_rate;
2589 enum av_fr_fmt initial_ff_audio_fr_fmt;
2591 current_st_idx = st_idx;
2592 fmt_ctx_lock();
2593 dec_ctx_cfg(fmt_ctx->sts[st_idx]->codecpar);
2594 dec_frs.most_recent_ts = fmt_ctx->sts[st_idx]->start_time;
2595 cmd_info_data.fmt.duration = fmt_ctx->duration;
2596 cmd_info_data.fmt.m = fmt_ctx->duration_estimation_method;
2597 cmd_info_data.st.tb = fmt_ctx->sts[st_idx]->tb;
2598 cmd_info_data.st.id = fmt_ctx->sts[st_idx]->id;
2599 cmd_info_data.st.duration = fmt_ctx->sts[st_idx]->duration;
2600 fmt_ctx_unlock();
2602 if (override_initial_ff_chans_n == CHANS_N_NOT_OVERRIDDEN)
2603 initial_ff_chans_n = dec_ctx->ch_layout.nb_channels;
2604 else
2605 initial_ff_chans_n = override_initial_ff_chans_n;
2606 if (override_initial_ff_rate == RATE_NOT_OVERRIDDEN)
2607 initial_ff_rate = dec_ctx->fr_rate;
2608 else
2609 initial_ff_rate = override_initial_ff_rate;
2610 if (override_initial_ff_audio_fr_fmt == FR_FMT_NOT_OVERRIDDEN)
2611 initial_ff_audio_fr_fmt = dec_ctx->fr_fmt;
2612 else
2613 initial_ff_audio_fr_fmt = override_initial_ff_audio_fr_fmt;
2614 /* best effort configuration of the pcm based on initial ff params */
2615 pcm_cfg(pcm_g, initial_ff_chans_n, initial_ff_rate,
2616 initial_ff_audio_fr_fmt);
2617 silence_bufs_cfg(pcm_g, PRINT_INFO);
2618 evt_pcm_install();
2619 filt_frs.vol = initial_vol;
2621 #undef PRINT_INFO
2622 #undef CHANS_N_NOT_OVERRIDDEN
2623 #undef RATE_NOT_OVERRIDDEN
2624 #undef AUDIO_FR_FMT_NOT_OVERRIDDEN
2625 #define HOLD 1
2626 #define DONT_HOLD 0
2627 static void seek_x(int64_t delta)
2629 int r;
2630 int64_t new_ts;
2631 av_st *st;
2632 av_rational st_tb;
2634 if (dec_frs.most_recent_ts == AV_NOPTS_VALUE)
2635 warning("unable to seek because no time stamp are currently available\n");
2636 fmt_ctx_lock();
2637 st = fmt_ctx->sts[current_st_idx];
2638 st_tb = st->tb;
2639 fmt_ctx_unlock();
2641 new_ts = dec_frs.most_recent_ts + delta * (int64_t)st_tb.den
2642 / (int64_t)st_tb.num;
2643 /* rewind capping */
2644 pout("trying to seek to %"PRId64" stream time base units\n", new_ts);
2646 atomic_store(&cb.hold, HOLD);
2647 rd_thd_reset(current_st_idx);
2648 fmt_ctx_lock();
2649 r = av_seek_pkt(fmt_ctx, st->id, new_ts, 0);
2650 fmt_ctx_unlock();
2651 if (r < 0)
2652 warning("unable to seek to %"PRId64" stream time base units\n", new_ts);
2653 dec_frs.most_recent_ts = AV_NOPTS_VALUE;
2654 av_flush_bufs(dec_ctx);
2655 filt_flush();
2656 atomic_store(&cb.hold, DONT_HOLD);
2658 #undef HOLD
2659 #undef DONT_HOLD
2660 static void cmd_rewind(void)
2662 pout("COMMAND:rewind\n");
2663 seek_x(-SEEK_DELTA);
2665 static void cmd_rewind_big(void)
2667 pout("COMMAND:rewind big\n");
2668 seek_x(-SEEK_DELTA_BIG);
2670 static void cmd_fastforward(void)
2672 pout("COMMAND:fastforward\n");
2673 seek_x(SEEK_DELTA);
2675 static void cmd_fastforward_big(void)
2677 pout("COMMAND:fastforward big\n");
2678 seek_x(SEEK_DELTA_BIG);
2680 static void cmd_pause(void)
2682 if (paused) {
2683 pout("COMMAND:unpause\n");
2684 paused = false;
2685 } else {
2686 pout("COMMAND:pause\n");
2687 paused = true;
2690 static void cmd_vol_up(void)
2692 int r;
2693 u8 vol_l10n_str[sizeof("xxx.xx")]; /* should be overkill */
2694 u8 response[STR_SZ];
2696 filt_frs.vol += VOL_DELTA;
2697 if (filt_frs.vol > 1.0)
2698 filt_frs.vol = 1.0;
2699 snprintf(vol_l10n_str, sizeof(vol_l10n_str), "%f", filt_frs.vol);
2700 pout("COMMAND:volume up to value %s(%s)\n", vol_l10n_str, filt_frs.muted ? "muted" : "unmuted");
2701 if (filt_frs.muted)
2702 return;
2703 r = av_filt_graph_send_cmd(filt_graph, "vol", "volume", vol_l10n_str,
2704 response, sizeof(response), 0);
2705 if (r < 0)
2706 warning("ffmpeg:volume context:unable to set the volume up to \"%s\":response from volume filter:\"%s\"\n", response);
2708 static void cmd_vol_down(void)
2710 int r;
2711 u8 vol_l10n_str[sizeof("xxx.xx")]; /* should be overkill */
2712 u8 response[STR_SZ];
2714 filt_frs.vol -= VOL_DELTA;
2715 if (filt_frs.vol < 0.0)
2716 filt_frs.vol = 0.0;
2717 snprintf(vol_l10n_str, sizeof(vol_l10n_str), "%f", filt_frs.vol);
2718 pout("COMMAND:volume down to value %s(%s)\n", vol_l10n_str, filt_frs.muted ? "muted" : "unmuted");
2719 if (filt_frs.muted)
2720 return;
2721 r = av_filt_graph_send_cmd(filt_graph, "vol", "volume", vol_l10n_str,
2722 response, sizeof(response), 0);
2723 if (r < 0)
2724 warning("ffmpeg:volume context:unable to set the volume down to \"%s\":response from volume filter:\"%s\"\n", response);
2726 static void cmd_vol_up_small(void)
2728 int r;
2729 u8 vol_l10n_str[sizeof("xxx.xx")]; /* should be overkill */
2730 u8 response[STR_SZ];
2732 filt_frs.vol += VOL_DELTA_SMALL;
2733 if (filt_frs.vol > 1.0)
2734 filt_frs.vol = 1.0;
2735 snprintf(vol_l10n_str, sizeof(vol_l10n_str), "%f", filt_frs.vol);
2736 pout("COMMAND:volume up to value %s(%s)\n", vol_l10n_str, filt_frs.muted ? "muted" : "unmuted");
2737 if (filt_frs.muted)
2738 return;
2739 r = av_filt_graph_send_cmd(filt_graph, "vol", "volume", vol_l10n_str,
2740 response, sizeof(response), 0);
2741 if (r < 0)
2742 warning("ffmpeg:volume context:unable to set the volume up to \"%s\":response from volume filter:\"%s\"\n", response);
2744 static void cmd_vol_down_small(void)
2746 int r;
2747 u8 vol_l10n_str[sizeof("xxx.xx")]; /* should be overkill */
2748 u8 response[STR_SZ];
2750 filt_frs.vol -= VOL_DELTA_SMALL;
2751 if (filt_frs.vol < 0.0)
2752 filt_frs.vol = 0.0;
2753 snprintf(vol_l10n_str, sizeof(vol_l10n_str), "%f", filt_frs.vol);
2754 pout("COMMAND:volume down to value %s(%s)\n", vol_l10n_str, filt_frs.muted ? "muted" : "unmuted");
2755 if (filt_frs.muted)
2756 return;
2757 r = av_filt_graph_send_cmd(filt_graph, "vol", "volume", vol_l10n_str,
2758 response, sizeof(response), 0);
2759 if (r < 0)
2760 warning("ffmpeg:volume context:unable to set the volume down to \"%s\":response from volume filter:\"%s\"\n", response);
2762 static void cmd_mute(void)
2764 int r;
2765 u8 vol_l10n_str[sizeof("xxx.xx")]; /* should be overkill */
2766 u8 response[STR_SZ];
2768 if (filt_frs.muted) {
2769 pout("COMMAND:unmuting\n");
2771 snprintf(vol_l10n_str, sizeof(vol_l10n_str), "%f",
2772 filt_frs.vol);
2773 r = av_filt_graph_send_cmd(filt_graph, "vol", "volume",
2774 vol_l10n_str, response, sizeof(response), 0);
2775 if (r < 0) {
2776 warning("ffmpeg:volume context:unable to mute the volume to 0:response from volume filter:%s\n", response);
2777 } else {
2778 filt_frs.muted = false;
2780 } else {
2781 pout("COMMAND:muting\n");
2783 r = av_filt_graph_send_cmd(filt_graph, "vol", "volume",
2784 double_zero_l10n_str, response, sizeof(response), 0);
2785 if (r < 0) {
2786 warning("ffmpeg:volume context:unable to mute the volume to 0:response from volume filter:%s\n", response);
2787 } else {
2788 filt_frs.muted = true;
2792 #define CHANS_N_NOT_OVERRIDDEN 0
2793 #define RATE_NOT_OVERRIDDEN 0
2794 #define FR_FMT_NOT_OVERRIDDEN AV_FR_FMT_NONE
2795 int main(int argc, u8 **args)
2797 u8 *url;
2798 u8 *pcm_str;
2799 double initial_vol;
2800 unsigned int cb_slots_n;
2801 int best_st_idx;
2802 /* audio override -- start */
2804 * we could have got direct parameters for alsa, but doing only an
2805 * override triggers an autoconfiguration of any missing parameters
2806 * based on initial codec params. In other words, the user is not
2807 * required to provide all audio params, the code will try to fit the
2808 * missing ones with the initial codec params, which is the default
2809 * behavior.
2811 int override_initial_ff_chans_n;
2812 int override_initial_ff_rate;
2813 enum av_fr_fmt override_initial_ff_audio_fr_fmt;
2814 /* audio override -- end */
2815 /* "turn on utf8" processing in used libs if any *AND* locale system */
2816 setlocale(LC_ALL, "");
2817 /* av_log_set_level(AV_LOG_VERBOSE); */
2818 /* av_log_set_level(AV_LOG_DEBUG); */
2819 url = 0;
2820 override_initial_ff_chans_n = CHANS_N_NOT_OVERRIDDEN;
2821 override_initial_ff_rate = RATE_NOT_OVERRIDDEN;
2822 override_initial_ff_audio_fr_fmt = FR_FMT_NOT_OVERRIDDEN;
2823 pcm_str = "default";
2824 initial_vol = 1.;
2825 cb_slots_n = 250;
2826 opts_parse(argc, args, &url, &pcm_str, &initial_vol, &cb_slots_n,
2827 &override_initial_ff_chans_n, &override_initial_ff_rate,
2828 &override_initial_ff_audio_fr_fmt);
2829 init_once(url, pcm_str, cb_slots_n);
2830 best_st_idx = find_best_st();
2831 rd_thd_start(best_st_idx);
2832 prepare(best_st_idx, initial_vol, override_initial_ff_chans_n,
2833 override_initial_ff_rate, override_initial_ff_audio_fr_fmt);
2834 wait_cb_filling();
2835 /* switch the ff log to stdout for metadata/etc dump */
2836 av_log_set_callback(ff_log_stdout);
2837 fmt_ctx_lock();
2838 av_dump_fmt(fmt_ctx, 0, url, 0);
2839 fmt_ctx_unlock();
2840 av_log_set_callback(av_log_default_callback);
2841 loop evts_loop();
2842 /* unreachable */
2844 #undef CHANS_N_NOT_OVERRIDDEN
2845 #undef RATE_NOT_OVERRIDDEN
2846 #undef AUDIO_FR_FMT_NOT_OVERRIDDEN
2847 /*----------------------------------------------------------------------------*/
2848 /* alsa */
2849 #undef snd_pcm_fmt_desc
2850 #undef snd_pcm_fmt_set_silence
2851 #undef SND_PCM_FMT_FLT
2852 #undef SND_PCM_FMT_S16
2853 #undef SND_PCM_FMT_S24
2854 #undef SND_PCM_FMT_S32
2855 #undef SND_PCM_FMT_S8
2856 #undef snd_pcm_fmt_t
2857 #undef SND_PCM_FMT_U16
2858 #undef SND_PCM_FMT_U24
2859 #undef SND_PCM_FMT_U32
2860 #undef SND_PCM_FMT_U8
2861 #undef SND_PCM_ST_PLAYBACK
2862 #undef snd_pcm_frs_to_bytes
2863 #undef snd_pcm_hw_params_get_chans
2864 #undef snd_pcm_hw_params_get_chans_max
2865 #undef snd_pcm_hw_params_get_chans_min
2866 #undef snd_pcm_hw_params_get_buf_size
2867 #undef snd_pcm_hw_params_get_fmt
2868 #undef snd_pcm_hw_params_set_buf_size_near
2869 #undef snd_pcm_hw_params_set_chans
2870 #undef snd_pcm_hw_params_set_fmt
2871 #undef snd_pcm_hw_params_test_chans
2872 #undef snd_pcm_hw_params_test_fmt
2873 #undef snd_pcm_sfrs_t
2874 #undef snd_pcm_ufrs_t
2875 /*----------------------------------------------------------------------------*/
2876 /* ff */
2877 #undef AV_AUDIO_FR_FMT_NONE
2878 #undef av_bufsink_get_frs
2879 #undef av_bufsrc_add_frs_flags
2880 #undef AV_BUFSRC_FLAG_KEEP_REF
2881 #undef AV_BUFSRC_FLAG_PUSH
2882 #undef av_codec
2883 #undef av_codec_ctx
2884 #undef av_dump_fmt
2885 #undef av_duration_estimation_method
2886 #undef av_filt
2887 #undef av_filt_ctx
2888 #undef av_filt_get_by_name
2889 #undef av_filt_graph
2890 #undef av_filt_graph_alloc
2891 #undef av_filt_graph_alloc_filt
2892 #undef av_filt_graph_cfg
2893 #undef av_filt_graph_dump
2894 #undef av_filt_graph_free
2895 #undef av_filt_graph_send_cmd
2896 #undef av_filt_init_str
2897 #undef av_filt_link
2898 #undef av_find_best_st
2899 #undef av_flush_bufs
2900 #undef av_fmt_ctx
2901 #undef AV_FMT_DURATION_FROM_BITRATE
2902 #undef AV_FMT_DURATION_FROM_PTS
2903 #undef AV_FMT_DURATION_FROM_ST
2904 #undef av_fmt_find_st_info
2905 #undef av_fmt_flush
2906 #undef av_fmt_open_input
2907 #undef av_fr_fmt_is_planar
2908 #undef AV_FR_FMT_FLT
2909 #undef AV_FR_FMT_FLTP
2910 #undef AV_FR_FMT_S16
2911 #undef AV_FR_FMT_S16P
2912 #undef AV_FR_FMT_S32
2913 #undef AV_FR_FMT_S32P
2914 #undef AV_FR_FMT_U8P
2915 #undef AV_FR_FMT_U8
2916 #undef av_frs_alloc
2917 #undef av_frs_set_silence
2918 #undef av_frs_unref
2919 #undef av_get_fr_fmt_name
2920 #undef av_get_fr_fmt_str
2921 #undef av_io_flush
2922 #undef AV_MEDIA_TYPE_AUDIO
2923 #undef av_pkt
2924 #undef av_pkt_unref
2925 #undef av_read_pkt
2926 #undef av_rational
2927 #undef av_seek_pkt
2928 #undef av_receive_frs
2929 #undef av_fr_fmt
2930 #undef av_frs
2931 #undef av_sd_pkt
2932 #undef av_st
2933 #undef format
2934 #undef fr_fmt
2935 #undef fr_rate
2936 #undef frs_n
2937 #undef st_idx
2938 #undef sts
2939 /*----------------------------------------------------------------------------*/
2940 #if __GNUC__ > 4
2941 #undef atomic_u8
2942 #else
2943 #undef atomic_u8
2944 #undef atomic_uint
2945 #undef atomic_int
2946 #undef atomic_load
2947 #undef atomic_store
2948 #endif
2949 /*----------------------------------------------------------------------------*/
2950 #undef ARRAY_N
2951 #undef esc_seq_sz
2952 #undef f32
2953 #undef INPUT_ESC_SEQ_TIMEOUT_SECS_N
2954 #undef loop
2955 #undef PCM_POLLFDS_N_MAX
2956 #undef PKTS_N_MAX
2957 #undef SEEK_DELTA
2958 #undef SEEK_DELTA_BIG
2959 #undef STR_SZ
2960 #undef u16
2961 #undef u32
2962 #undef u8
2963 #undef U8_MAX
2964 #undef VOL_DELTA
2965 #endif