npv:vulkan synchronization less wrong
[nyanmp.git] / npv / audio / local / code.frag.c
blob0ae8b7672568d120fde154f44ee2494f6ba2c1b8
1 STATIC void fatal(u8 *fmt, ...)
3 va_list ap;
5 npv_perr("audio:");
6 va_start(ap, fmt);
7 npv_vfatal(fmt, ap);
8 va_end(ap); /* unreachable */
10 STATIC void warning(u8 *fmt, ...)
12 va_list ap;
14 npv_perr("audio:");
15 va_start(ap, fmt);
16 npv_vwarning(fmt, ap);
17 va_end(ap);
19 STATIC void pout(u8 *fmt, ...)
21 va_list ap;
23 npv_pout("audio:");
24 va_start(ap, fmt);
25 npv_vpout(fmt, ap);
26 va_end(ap);
28 /* base on kernel api at the time we wrote this code */
29 STATIC u8 *kernel_ts_types_str_l[] = {
30 "compat",
31 "default",
32 "link",
33 "link absolute",
34 "link estimated",
35 "link synchonized"
38 * XXX: if it is ever used significantly, a fine granularity wiring strategy
39 * will be implemented instead of using the default wiring
41 STATIC void pcm_chmaps2ff_chans_layout(AVChannelLayout *ff_chans_layout,
42 snd_pcm_t *pcm, unsigned int pcm_chans_n, bool print_info)
44 int r;
45 snd_pcm_chmap_t *pcm_chmap;
46 u8 chans_layout_str[STR_SZ]; /* should be overkill */
48 pcm_chmap = snd_pcm_get_chmap(pcm);
49 if (pcm_chmap == 0) {
50 if (print_info)
51 pout("alsa:no pcm channel map available, wiring to default ffmpeg channel layout\n");
52 } else {
53 if (print_info)
54 pout("alsa:your pcm device support channel maps, but fine granularity wiring strategy is not implemented, using default ffmpeg layout\n");
55 free(pcm_chmap);
57 /* XXX: will need to get back at it if a wiring strategy is required */
58 av_channel_layout_default(ff_chans_layout, (int)pcm_chans_n);
59 av_channel_layout_describe(ff_chans_layout, chans_layout_str,
60 sizeof(chans_layout_str));
61 if (print_info)
62 pout("alsa channel map wired to ffmpeg channel layout:\"%s\" (%u pcm channels)\n", chans_layout_str, pcm_chans_n);
64 STATIC bool ff_fmt2pcm_layout_best_effort(enum avutil_audio_fr_fmt_t ff_fmt,
65 snd_pcm_fmt_t *alsa_fmt, snd_pcm_access_t *alsa_access)
67 static u8 ff_fmt_str[STR_SZ];
69 avutil_get_audio_fr_fmt_str(ff_fmt_str, STR_SZ, ff_fmt);
70 /* XXX: only classic non-mmap ones */
71 switch (ff_fmt) {
72 case AVUTIL_AUDIO_FR_FMT_U8:
73 *alsa_fmt = SND_PCM_FMT_U8;
74 *alsa_access = SND_PCM_ACCESS_RW_INTERLEAVED;
75 break;
76 case AVUTIL_AUDIO_FR_FMT_S16:
77 *alsa_fmt = SND_PCM_FMT_S16;
78 *alsa_access = SND_PCM_ACCESS_RW_INTERLEAVED;
79 break;
80 case AVUTIL_AUDIO_FR_FMT_S32:
81 *alsa_fmt = SND_PCM_FMT_S32;
82 *alsa_access = SND_PCM_ACCESS_RW_INTERLEAVED;
83 break;
84 case AVUTIL_AUDIO_FR_FMT_FLT:
85 *alsa_fmt = SND_PCM_FMT_FLOAT;
86 *alsa_access = SND_PCM_ACCESS_RW_INTERLEAVED;
87 break;
88 /* ff "planar" fmts are actually non interleaved fmts */
89 case AVUTIL_AUDIO_FR_FMT_U8P:
90 *alsa_fmt = SND_PCM_FMT_U8;
91 *alsa_access = SND_PCM_ACCESS_RW_NONINTERLEAVED;
92 break;
93 case AVUTIL_AUDIO_FR_FMT_S16P:
94 *alsa_fmt = SND_PCM_FMT_S16;
95 *alsa_access = SND_PCM_ACCESS_RW_NONINTERLEAVED;
96 break;
97 case AVUTIL_AUDIO_FR_FMT_S32P:
98 *alsa_fmt = SND_PCM_FMT_S32;
99 *alsa_access = SND_PCM_ACCESS_RW_NONINTERLEAVED;
100 break;
101 case AVUTIL_AUDIO_FR_FMT_FLTP:
102 *alsa_fmt = SND_PCM_FMT_FLOAT;
103 *alsa_access = SND_PCM_ACCESS_RW_NONINTERLEAVED;
104 break;
105 default:
106 pout("best effort:unable to wire ffmpeg sample format \"%sbits\" to alsa sample format, \n,", ff_fmt_str);
107 return false;
109 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));
110 return true;
112 STATIC void pcm_hw_chans_n_decide(snd_pcm_t *pcm,
113 snd_pcm_hw_params_t *pcm_hw_params, int chans_n)
115 int r;
116 unsigned int chans_n_max;
117 unsigned int chans_n_min;
119 r = snd_pcm_hw_params_test_chans_n(pcm, pcm_hw_params,
120 (unsigned int)chans_n);
121 if (r == 0) {
122 r = snd_pcm_hw_params_set_chans_n(pcm, pcm_hw_params,
123 (unsigned int)chans_n);
124 if (r != 0)
125 fatal("alsa:unable to restrict pcm device to %d channels, count which was successfully tested\n", chans_n);
126 pout("alsa:using %d channels\n", chans_n);
127 return;
129 pout("alsa:unable to use %d channels\n", chans_n);
130 /* try to use the max chans n the pcm can */
131 r = snd_pcm_hw_params_get_chans_n_max(pcm_hw_params, &chans_n_max);
132 if (r != 0)
133 fatal("alsa:unable to get the maximum count of pcm device channels\n");
134 r = snd_pcm_hw_params_test_chans_n(pcm, pcm_hw_params, chans_n_max);
135 if (r == 0) {
136 r = snd_pcm_hw_params_set_chans_n(pcm, pcm_hw_params,
137 chans_n_max);
138 if (r != 0)
139 fatal("alsa:unable to restrict pcm device to %u channels, count which was successfully tested\n", chans_n_max);
140 pout("alsa:using pcm maximum %u channels\n", chans_n_max);
141 return;
143 /* ok... last try, the pcm dev min chans n */
144 r = snd_pcm_hw_params_get_chans_n_min(pcm_hw_params, &chans_n_min);
145 if (r != 0)
146 fatal("alsa:unable to get the minimum count of pcm device channels\n");
147 r = snd_pcm_hw_params_test_chans_n(pcm, pcm_hw_params, chans_n_min);
148 if (r == 0) {
149 r = snd_pcm_hw_params_set_chans_n(pcm, pcm_hw_params,
150 chans_n_min);
151 if (r != 0)
152 fatal("alsa:unable to restrict pcm device to %u channels, count which was successfully tested\n", chans_n_min);
153 pout("alsa:using pcm device minimum %u channels\n", chans_n_min);
154 return;
156 fatal("alsa:unable to find a suitable count of channels\n");
158 STATIC void pcm_hw_rate_decide(snd_pcm_t *pcm,
159 snd_pcm_hw_params_t *pcm_hw_params, int rate)
161 int r;
162 unsigned int rate_max;
163 unsigned int rate_near;
164 unsigned int rate_min;
166 r = snd_pcm_hw_params_test_rate(pcm, pcm_hw_params, (unsigned int)rate,
167 SND_PCM_ST_PLAYBACK);
168 if (r == 0) {
169 r = snd_pcm_hw_params_set_rate(pcm, pcm_hw_params,
170 (unsigned int)rate, SND_PCM_ST_PLAYBACK);
171 if (r != 0)
172 fatal("alsa:unable to restrict pcm device to %dHz, which was successfully tested\n", rate);
173 pout("alsa:using %dHz\n", rate);
174 return;
176 pout("alsa:unable to use %dHz\n", rate);
177 /* try to use the max rate the pcm can */
178 r = snd_pcm_hw_params_get_rate_max(pcm_hw_params, &rate_max,
179 SND_PCM_ST_PLAYBACK);
180 if (r != 0)
181 fatal("alsa:unable to get the maximum rate of pcm device\n");
182 r = snd_pcm_hw_params_test_rate(pcm, pcm_hw_params, rate_max,
183 SND_PCM_ST_PLAYBACK);
184 if (r == 0) {
185 r = snd_pcm_hw_params_set_rate(pcm, pcm_hw_params, rate_max,
186 SND_PCM_ST_PLAYBACK);
187 if (r != 0)
188 fatal("alsa:unable to restrict pcm device to %uHz, which was successfully tested\n", rate_max);
189 pout("alsa:using pcm device %uHz\n", rate_max);
190 return;
192 /* try to use a rate "near" of what the pcm dev can */
193 rate_near = rate;
194 r = snd_pcm_hw_params_set_rate_near(pcm, pcm_hw_params, &rate_near,
195 SND_PCM_ST_PLAYBACK);
196 if (r == 0) {
197 pout("alsa:using pcm device %uHz\n", rate_near);
198 return;
200 /* even a "near" rate did failed... try the min */
201 r = snd_pcm_hw_params_get_rate_min(pcm_hw_params, &rate_min,
202 SND_PCM_ST_PLAYBACK);
203 if (r != 0)
204 fatal("alsa:unable to get the minimum rate of pcm device\n");
205 r = snd_pcm_hw_params_test_rate(pcm, pcm_hw_params, rate_min,
206 SND_PCM_ST_PLAYBACK);
207 if (r == 0) {
208 r = snd_pcm_hw_params_set_rate(pcm, pcm_hw_params, rate_min,
209 SND_PCM_ST_PLAYBACK);
210 if (r != 0)
211 fatal("alsa:unable to restrict pcm device to %uHz, which was successfully tested\n", rate_min);
212 pout("alsa:using pcm device %uHz\n", rate_min);
213 return;
215 fatal("alsa:unable to find a suitable rate\n");
217 STATIC bool pcm_hw_fmt_decide_x(snd_pcm_t *pcm,
218 snd_pcm_hw_params_t *pcm_hw_params, snd_pcm_fmt_t fmt)
220 int r;
222 r = snd_pcm_hw_params_test_fmt(pcm, pcm_hw_params, fmt);
223 if (r != 0)
224 return false;
225 r = snd_pcm_hw_params_set_fmt(pcm, pcm_hw_params, fmt);
226 if (r != 0)
227 fatal("alsa:unable to restrict pcm device to \"%s\", which was successfully tested\n", snd_pcm_fmt_desc(fmt));
228 pout("alsa:using last resort \"%s\" format\n", snd_pcm_fmt_desc(fmt));
229 return true;
231 #define PCM_HW_FMT_DECIDE_X(fmt) pcm_hw_fmt_decide_x(pcm, pcm_hw_params, fmt)
232 STATIC void pcm_hw_fmt_decide(snd_pcm_t *pcm,
233 snd_pcm_hw_params_t *pcm_hw_params, bool best_effort,
234 snd_pcm_fmt_t best_effort_fmt)
236 int r;
237 snd_pcm_fmt_t *fmt;
239 if (best_effort) {
240 r = snd_pcm_hw_params_test_fmt(pcm, pcm_hw_params,
241 best_effort_fmt);
242 if (r == 0) {
243 r = snd_pcm_hw_params_set_fmt(pcm, pcm_hw_params,
244 best_effort_fmt);
245 if (r != 0)
246 fatal("alsa:unable to restrict pcm device to \"%s\", which was successfully tested\n", snd_pcm_fmt_desc(best_effort_fmt));
247 pout("alsa:using best effort \"%s\" format\n", snd_pcm_fmt_desc(best_effort_fmt));
248 return;
251 /* then we try to select from the reasonable "best" to the lowest */
252 /* prefer fmts we know supported by ff */
253 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FMT_FLOAT))
254 return;
255 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FMT_S32))
256 return;
257 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FMT_S16))
258 return;
259 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FMT_U8))
260 return;
262 * from here, at the time of writting, those fmts have no ff
263 * wiring, but we are alsa centric here, validate that later
265 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FMT_U32))
266 return;
267 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FMT_S24))
268 return;
269 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FMT_U24))
270 return;
271 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FMT_U16))
272 return;
273 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FMT_S8))
274 return;
275 fatal("alsa:unable to find a suitable format\n");
277 #undef PCM_HW_FMT_DECIDE_X
278 STATIC bool pcm_hw_access_decide_x(snd_pcm_t *pcm,
279 snd_pcm_hw_params_t *pcm_hw_params, snd_pcm_access_t access)
281 int r;
283 r = snd_pcm_hw_params_test_access(pcm, pcm_hw_params, access);
284 if (r != 0)
285 return false;
286 r = snd_pcm_hw_params_set_access(pcm, pcm_hw_params, access);
287 if (r != 0)
288 fatal("alsa:unable to restrict pcm device to \"%s\", which was successfully tested\n", snd_pcm_access_name(access));
289 pout("alsa:using last resort \"%s\" access\n", snd_pcm_access_name(access));
290 return true;
292 #define PCM_HW_ACCESS_DECIDE_X(access) \
293 pcm_hw_access_decide_x(pcm, pcm_hw_params, access)
294 /* XXX: only classic non-mmap ones */
295 STATIC void pcm_hw_access_decide(snd_pcm_t *pcm,
296 snd_pcm_hw_params_t *pcm_hw_params, bool best_effort,
297 snd_pcm_access_t best_effort_access)
299 int r;
300 snd_pcm_access_t access;
302 if (best_effort) {
303 r = snd_pcm_hw_params_test_access(pcm, pcm_hw_params,
304 best_effort_access);
305 if (r == 0) {
306 r = snd_pcm_hw_params_set_access(pcm, pcm_hw_params,
307 best_effort_access);
308 if (r != 0)
309 fatal("alsa:unable to restrict pcm device to \"%s\", which was successfully tested\n", snd_pcm_access_name(best_effort_access));
310 pout("alsa:using best effort \"%s\" access\n", snd_pcm_access_name(best_effort_access));
311 return;
314 /* brute force */
315 if (PCM_HW_ACCESS_DECIDE_X(SND_PCM_ACCESS_RW_INTERLEAVED))
316 return;
317 if (PCM_HW_ACCESS_DECIDE_X(SND_PCM_ACCESS_RW_NONINTERLEAVED))
318 return;
319 fatal("alsa:unable to find a suitable access\n");
321 #undef PCM_HW_ACCESS_DECIDE_X
323 * latency control: some audio bufs can be huge (tested on a pulseaudio with 10
324 * secs audio buf). if we are careless, we will quickly fill this buf which is
325 * worth a significant amount of time, hence will add huge latency to our
326 * interactive audio filtering (vol...). in the case of the 10 secs pulseaudio
327 * buf, it means if you want to mute the audio, it will happen 10 secs later.
328 * we add lantency control by limiting the sz of the dev audio buf, in periods
329 * n.
330 * we choose roughly 0.25 secs, or roughly (rate / 4) frs.
332 STATIC void pcm_hw_buf_sz_cfg(snd_pcm_t *pcm,
333 snd_pcm_hw_params_t *pcm_hw_params)
335 int r;
336 snd_pcm_ufrs_t latency_control_target_buf_ufrs_n;
337 snd_pcm_ufrs_t latency_control_buf_ufrs_n;
338 unsigned int rate;
340 r = snd_pcm_hw_params_get_rate(pcm_hw_params, &rate, 0);
341 if (r < 0) {
342 warning("alsa:latency control:DISABLING LATENCY CONTROL:unable to get the decided rate from the current device parameters\n");
343 return;
345 latency_control_target_buf_ufrs_n = (snd_pcm_ufrs_t)rate;
346 latency_control_target_buf_ufrs_n /= 4;
347 latency_control_buf_ufrs_n = latency_control_target_buf_ufrs_n;
348 r = snd_pcm_hw_params_set_buf_sz_near(pcm, pcm_hw_params,
349 &latency_control_buf_ufrs_n);
350 if (r < 0) {
351 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);
352 return;
354 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);
357 * this function will "decide" the pcm dev cfg:
358 * the goal is to be the "closest" to the provided params,
359 * the "gap" will have to "filled" with ff filts
361 * the "strategy" is a "fall-thru" (chans n then ... then ...) which
362 * will "restrict" the pcm dev cfg further at each step
364 * we try to use a sensible restrict order regarding audio props
366 STATIC void pcm_cfg_hw_core_best_effort(snd_pcm_t *pcm,
367 snd_pcm_hw_params_t *pcm_hw_params, int chans_n,
368 int rate, enum avutil_audio_fr_fmt_t ff_fmt)
370 int r;
371 bool best_effort_wiring_success;
372 snd_pcm_fmt_t fmt_from_best_effort;
373 snd_pcm_access_t access_from_best_effort;
375 /* the return value is from a first refine of the raw hw params */
376 r = snd_pcm_hw_params_any(pcm, pcm_hw_params);
377 if (r < 0)
378 fatal("alsa:unable to populate the hardware parameters context\n");
379 pcm_hw_chans_n_decide(pcm, pcm_hw_params, chans_n);
380 pcm_hw_rate_decide(pcm, pcm_hw_params, rate);
381 /* try our best with the fmt */
382 best_effort_wiring_success = ff_fmt2pcm_layout_best_effort(
383 ff_fmt, &fmt_from_best_effort, &access_from_best_effort);
384 pcm_hw_fmt_decide(pcm, pcm_hw_params, best_effort_wiring_success,
385 fmt_from_best_effort);
386 pcm_hw_access_decide(pcm, pcm_hw_params, best_effort_wiring_success,
387 access_from_best_effort);
388 pcm_hw_buf_sz_cfg(pcm, pcm_hw_params);
390 STATIC void dec_a_grow(void)
392 u32 new_idx;
394 new_idx = dec_sets_p.n_max;
395 dec_sets_p.a = realloc(dec_sets_p.a, sizeof(*dec_sets_p.a)
396 * (dec_sets_p.n_max + 1));
397 if (dec_sets_p.a == 0)
398 fatal("unable to allocate memory for an additional pointer on a reference of a decoder set of frames\n");
399 dec_sets_p.a[new_idx] = avutil_audio_set_ref_alloc();
400 if (dec_sets_p.a[new_idx] == 0)
401 fatal("ffmpeg:unable to allocate a reference of a decoder set of frames\n");
402 ++dec_sets_p.n_max;
404 #define AGAIN 0
405 #define RECOVERED 1
406 #define CONTINUE 2
407 STATIC u8 alsa_recover(snd_pcm_sfrs_t r)
409 if (r >= 0)
410 return CONTINUE;
411 /* r < 0 */
412 if (r == -EAGAIN)
413 return AGAIN;
414 else if (r == -EPIPE || r == -ESTRPIPE) {
415 /* underrun or suspended */
416 int r_recovered;
418 r_recovered = snd_pcm_recover(pcm_p, (int)r, 0);
419 if (r_recovered == 0) {
420 warning("alsa:pcm recovered\n");
421 return RECOVERED;
423 fatal("alsa:unable to recover from suspend/underrun\n");
425 fatal("alsa:fatal/unhandled error\n");
427 #undef AGAIN
428 #undef RECOVERED
429 #undef CONTINUE
430 #define NO 0
431 #define AGAIN 0
432 #define RECOVERED 1
433 STATIC void pcm_silence_frs_write(snd_pcm_ufrs_t ufrs_n) { loop
435 int alsa_r;
436 u8 r_recover;
437 int is_planar_fmt;
439 if (ufrs_n == 0)
440 break;
441 is_planar_fmt = avutil_audio_fr_fmt_is_planar(
442 npv_audio_filt_p.set->fmt);
443 if (is_planar_fmt == NO)
444 alsa_r = snd_pcm_writei(pcm_p, pcm_silence_bufs_l[0], ufrs_n);
445 else
446 alsa_r = snd_pcm_writen(pcm_p, pcm_silence_bufs_l, ufrs_n);
447 r_recover = alsa_recover(alsa_r);
448 if (r_recover == AGAIN)
449 continue;
450 else if (r_recover == RECOVERED)
451 break;
452 /* r_recover == CONTINUE */
453 ufrs_n -= (snd_pcm_ufrs_t)alsa_r;
455 #undef NO
456 #undef AGAIN
457 #undef RECOVERED
458 #define NO 0
459 STATIC void chans_buf_init(u8 **chans_buf, int start_fr_idx)
461 int is_planar_fmt;
462 int sample_bytes_n;
464 sample_bytes_n = avutil_get_bytes_per_sample(npv_audio_filt_p.set->fmt);
465 is_planar_fmt = avutil_audio_fr_fmt_is_planar(
466 npv_audio_filt_p.set->fmt);
467 if (is_planar_fmt == NO) { /* or is pcm interleaved */
468 int fr_bytes_n;
470 fr_bytes_n = sample_bytes_n
471 * npv_audio_filt_p.set->ch_layout.nb_channels;
472 chans_buf[0] = (u8*)npv_audio_filt_p.set->data[0] + start_fr_idx
473 * fr_bytes_n;
474 } else { /* ff planar or pcm noninterleaved */
475 int p;
477 p = 0;
478 loop {
479 if (p == npv_audio_filt_p.set->ch_layout.nb_channels)
480 break;
481 chans_buf[p] = (u8*)npv_audio_filt_p.set->data[p]
482 + start_fr_idx * sample_bytes_n;
483 ++p;
487 #undef NO
488 #define NO 0
489 STATIC void chans_buf_inc(u8 **chans_buf, int inc)
491 int is_planar_fmt;
492 int sample_bytes_n;
494 sample_bytes_n = avutil_get_bytes_per_sample(npv_audio_filt_p.set->fmt);
495 is_planar_fmt = avutil_audio_fr_fmt_is_planar(
496 npv_audio_filt_p.set->fmt);
497 if (is_planar_fmt == NO) { /* or is pcm interleaved */
498 int fr_bytes_n;
500 fr_bytes_n = sample_bytes_n
501 * npv_audio_filt_p.set->ch_layout.nb_channels;
502 chans_buf[0] = (u8*)chans_buf[0] + inc * fr_bytes_n;
503 } else { /* ff planar or pcm noninterleaved */
504 int p;
506 p = 0;
507 loop {
508 if (p == npv_audio_filt_p.set->ch_layout.nb_channels)
509 break;
510 chans_buf[p] = (u8*)chans_buf[p] + inc * sample_bytes_n;
511 ++p;
515 #undef NO
516 STATIC void draining_state_handle(void)
518 int r;
520 r = snd_pcm_drain(pcm_p);
521 if (r != 0) {
522 snd_pcm_state_t state;
524 if (r == -EAGAIN)
525 return;
527 * the pcm state can change asynchronously.
528 * _old_ behavior:
529 * if the draining was successful, the pcm should be in SETUP
530 * state, and in this state, snd_pcm_drain will fail
531 * _new and fixed__ behavior:
532 * this won't happen because calling snd_pcm_drain while in
533 * the SETUP state won't return an error anymore
535 state = snd_pcm_state(pcm_p);
536 if (state != SND_PCM_STATE_SETUP)
537 fatal("alsa:an error occured switching to/checking the pcm draining state\n");
538 /* here pcm state is SND_PCM_STATE_SETUP */
540 npv_exit("alsa pcm drained or similar, exiting\n");
542 STATIC void draining_state_switch(void)
544 int r;
545 u8 i;
546 struct itimerspec t;
548 draining_p = true;
549 draining_state_handle();
550 /* remove the alsa epoll fds */
551 i = 0;
552 loop {
553 if (i == pcm_pollfds_n_p)
554 break;
555 /* in theory, it is thread safe */
556 r = epoll_ctl(npv_ep_fd_p, EPOLL_CTL_DEL, pcm_pollfds_p[i].fd,
558 if (r == -1)
559 fatal("unable to remove the alsa file descriptors from epoll\n");
560 ++i;
562 /* start the draining timer */
563 memset(&t, 0, sizeof(t));
564 /* initial and interval */
565 t.it_value.tv_nsec = DRAINING_TIMER_INTERVAL_NSECS_N;
566 t.it_interval.tv_nsec = DRAINING_TIMER_INTERVAL_NSECS_N;
567 r = timerfd_settime(draining_timer_fd_p, 0, &t, 0);
568 if (r == -1)
569 fatal("unable to arm the draining timer\n");
571 /* fatal if the wiring cannot be done */
572 STATIC void pcm_layout2ff_fmt_strict(snd_pcm_fmt_t alsa_fmt,
573 snd_pcm_access_t alsa_access, enum avutil_audio_fr_fmt_t *ff_fmt,
574 bool print_info)
577 * ff fmt byte order is always native.
578 * here we handle little endian only
580 switch (alsa_fmt) {
581 case SND_PCM_FMT_FLOAT:
582 if (alsa_access == SND_PCM_ACCESS_RW_INTERLEAVED)
583 *ff_fmt = AVUTIL_AUDIO_FR_FMT_FLT;
584 else
585 *ff_fmt = AVUTIL_AUDIO_FR_FMT_FLTP;
586 break;
587 case SND_PCM_FMT_S32:
588 if (alsa_access == SND_PCM_ACCESS_RW_INTERLEAVED)
589 *ff_fmt = AVUTIL_AUDIO_FR_FMT_S32;
590 else
591 *ff_fmt = AVUTIL_AUDIO_FR_FMT_S32P;
592 break;
593 case SND_PCM_FMT_S16:
594 if (alsa_access == SND_PCM_ACCESS_RW_INTERLEAVED)
595 *ff_fmt = AVUTIL_AUDIO_FR_FMT_S16;
596 else
597 *ff_fmt = AVUTIL_AUDIO_FR_FMT_S16P;
598 break;
599 case SND_PCM_FMT_U8:
600 if (alsa_access == SND_PCM_ACCESS_RW_INTERLEAVED)
601 *ff_fmt = AVUTIL_AUDIO_FR_FMT_U8;
602 else
603 *ff_fmt = AVUTIL_AUDIO_FR_FMT_U8P;
604 break;
605 default:
606 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));
608 if (print_info) {
609 u8 ff_fmt_str[STR_SZ];
611 avutil_get_audio_fr_fmt_str(ff_fmt_str, sizeof(ff_fmt_str),
612 *ff_fmt);
613 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);
616 STATIC void pcm2ff_strict(snd_pcm_t *pcm, AVChannelLayout *ff_chans_layout,
617 int *ff_rate, enum avutil_audio_fr_fmt_t *ff_fmt, bool print_info)
619 int r;
620 snd_pcm_hw_params_t *hw_params;
621 unsigned int pcm_chans_n;
622 unsigned int pcm_rate;
623 snd_pcm_fmt_t pcm_fmt;
624 snd_pcm_access_t pcm_access;
626 r = snd_pcm_hw_params_malloc(&hw_params);
627 if (r < 0)
628 fatal("alsa:unable to allocate hardware parameters context for ffmpeg filter wiring\n");
629 r = snd_pcm_hw_params_current(pcm, hw_params);
630 if (r != 0)
631 fatal("alsa:unable to get current hardware parameters for ffmpeg filter wiring\n");
632 r = snd_pcm_hw_params_get_access(hw_params, &pcm_access);
633 if (r < 0)
634 fatal("alsa:unable to get the pcm access for ffmpeg filter wiring\n");
635 r = snd_pcm_hw_params_get_fmt(hw_params, &pcm_fmt);
636 if (r < 0)
637 fatal("alsa:unable to get the pcm format for ffmpeg filter wiring\n");
638 /*--------------------------------------------------------------------*/
639 pcm_layout2ff_fmt_strict(pcm_fmt, pcm_access, ff_fmt, print_info);
640 /*--------------------------------------------------------------------*/
641 r = snd_pcm_hw_params_get_rate(hw_params, &pcm_rate,
642 SND_PCM_ST_PLAYBACK);
643 if (r < 0)
644 fatal("alsa:unable to get the pcm rate for ffmpeg filter wiring\n");
645 *ff_rate = (int)pcm_rate;
646 r = snd_pcm_hw_params_get_chans_n(hw_params, &pcm_chans_n);
647 if (r < 0)
648 fatal("alsa:unable to get the pcm count of channels for ffmpeg filter wiring\n");
649 /*--------------------------------------------------------------------*/
650 pcm_chmaps2ff_chans_layout(ff_chans_layout, pcm, pcm_chans_n,
651 print_info);
652 /*--------------------------------------------------------------------*/
653 snd_pcm_hw_params_free(hw_params);
655 #define NO_DEC_SET 2
656 #define FILT_RECFG_REQUIRED 4
657 #define EOF_FILT 2
658 #define DRAINING 3
659 #define HAVE_FILT_SET 1
660 #define PRINT_INFO true
661 /* synchronous filt or will end up asynchronous in the pipeline one day */
662 STATIC u8 dec_set_filter(void)
664 u8 r;
666 loop {
667 AVChannelLayout new_chans_layout;
668 int new_rate;
669 enum avutil_audio_fr_fmt_t new_fmt;
670 AVChannelLayout dst_chans_layout;
671 int dst_rate;
672 enum avutil_audio_fr_fmt_t dst_fmt;
674 memset(&new_chans_layout, 0, sizeof(new_chans_layout));
675 memset(&dst_chans_layout, 0, sizeof(dst_chans_layout));
677 r = filt_push_dec_set(&new_chans_layout, &new_rate, &new_fmt);
678 if (r == NO_DEC_SET) {/* pipeline not fast enough */
679 av_channel_layout_uninit(&new_chans_layout);
680 return NO_DEC_SET;
682 else if (r != FILT_RECFG_REQUIRED) {
683 /* FILT_SWITCHED_TO_DRAINING | PUSHED_ONE_SET | AGAIN */
684 av_channel_layout_uninit(&new_chans_layout);
685 break;
687 /* FILT_RECFG_REQUIRED */
688 pcm2ff_strict(npv_audio_pcm_p, &dst_chans_layout, &dst_rate,
689 &dst_fmt, PRINT_INFO);
690 filt_cfg(st_p.tb,
691 &new_chans_layout, new_rate, new_fmt,
692 filt_p.muted, filt_p.vol,
693 &dst_chans_layout, dst_rate, dst_fmt, PRINT_INFO);
694 av_channel_layout_uninit(&new_chans_layout);
695 av_channel_layout_uninit(&dst_chans_layout);
697 r = npv_audio_filt_set_get();
698 if (r == EOF_FILT) {
699 draining_state_switch();
700 return DRAINING;
702 return HAVE_FILT_SET;
704 #undef NO_DEC_SET
705 #undef FILT_RECFG_REQUIRED
706 #undef EOF_FILT
707 #undef DRAINING
708 #undef HAVE_FILT_SET
709 #undef PRINT_INFO
710 #define NO 0
711 #define AGAIN 0
712 #define RECOVERED 1
713 #define CONTINUE 2
714 #define NO_DEC_SET 2
715 #define ALL_FRS_WRITTEN 0
716 /* #define RECOVERED 1 */
717 #define INCOMPLETE_WRITE 2
718 #define DRAINING 3
719 #define PRINT_INFO true
720 STATIC u8 pcm_filt_frs_write(snd_pcm_ufrs_t *ufrs_n) { loop
722 u8 chan_buf;
723 u8 *chans_buf[AVUTIL_DATA_PTRS_N];
724 snd_pcm_ufrs_t ufrs_to_write_n;
725 snd_pcm_ufrs_t filt_set_remaining_ufrs_n; /* for clarity */
726 int is_planar_fmt;
727 snd_pcm_ufrs_t written_ufrs_n; /* for clarity */
729 if (*ufrs_n == 0)
730 return ALL_FRS_WRITTEN;
731 /* synchronous filtering */
732 if (npv_audio_filt_p.set->frs_n == 0) {
733 u8 r;
735 r = dec_set_filter();
736 if (r == NO_DEC_SET || r == DRAINING)
737 return r;
738 /* HAVE_FILT_SET */
739 npv_audio_filt_p.pcm_written_ufrs_n = 0;
741 chans_buf_init(chans_buf, (int)npv_audio_filt_p.pcm_written_ufrs_n);
742 filt_set_remaining_ufrs_n = (snd_pcm_ufrs_t)npv_audio_filt_p.set->frs_n
743 - npv_audio_filt_p.pcm_written_ufrs_n;
744 if (filt_set_remaining_ufrs_n > *ufrs_n)
745 ufrs_to_write_n = *ufrs_n;
746 else
747 ufrs_to_write_n = filt_set_remaining_ufrs_n;
748 is_planar_fmt = avutil_audio_fr_fmt_is_planar(
749 npv_audio_filt_p.set->fmt);
750 written_ufrs_n = 0;
751 loop { /* short write loop */
752 snd_pcm_sfrs_t alsa_r;
753 u8 r_recover;
755 if (is_planar_fmt == NO)
756 alsa_r = snd_pcm_writei(pcm_p, chans_buf[0],
757 ufrs_to_write_n - written_ufrs_n);
758 else
759 alsa_r = snd_pcm_writen(pcm_p, (void**)chans_buf,
760 ufrs_to_write_n - written_ufrs_n);
761 r_recover = alsa_recover(alsa_r);
762 if (r_recover == AGAIN)
763 continue;
764 else if (r_recover == RECOVERED) {
765 /* account for the written frs anyway */
766 if (npv_audio_filt_p.pcm_written_ufrs_n == 0)
767 npv_clk_ref_time_point_update(
768 npv_audio_filt_p.set->pts,
769 written_ufrs_n);
770 npv_audio_filt_p.pcm_written_ufrs_n += written_ufrs_n;
771 if ((int)npv_audio_filt_p.pcm_written_ufrs_n ==
772 npv_audio_filt_p.set->frs_n)
773 /* set audio_filt_p.set->frs_n = 0 */
774 avutil_audio_set_unref(npv_audio_filt_p.set);
775 return RECOVERED;
777 /* r_recover == CONTINUE */
778 written_ufrs_n += (snd_pcm_ufrs_t)alsa_r;
779 if (written_ufrs_n == ufrs_to_write_n)
780 break;
781 chans_buf_inc(chans_buf, (int)alsa_r);
784 * this is here we update our ref time point for the audio clk
785 * because with a new filt set of frs, we get a new ts
787 * XXX: getting the "right" ts from ff is shady/convoluted?
789 if (npv_audio_filt_p.pcm_written_ufrs_n == 0)
790 npv_clk_ref_time_point_update(npv_audio_filt_p.set->pts,
791 written_ufrs_n);
792 npv_audio_filt_p.pcm_written_ufrs_n += written_ufrs_n;
793 *ufrs_n -= written_ufrs_n;
795 if ((int)npv_audio_filt_p.pcm_written_ufrs_n
796 == npv_audio_filt_p.set->frs_n)
797 /* set audio_filt_p.av->frs_n = 0 */
798 avutil_audio_set_unref(npv_audio_filt_p.set);
800 #undef NO
801 #undef AGAIN
802 #undef RECOVERED
803 #undef CONTINUE
804 #undef NO_DEC_SET
805 #undef ALL_FRS_WRITTEN
806 #undef INCOMPLETE_WRITE
807 #undef DRAINING
808 #undef PRINT_INFO
809 STATIC void init_pcm_once_public(u8 *pcm_str)
811 int r;
813 r = snd_pcm_open(&pcm_p, pcm_str, SND_PCM_ST_PLAYBACK,
814 SND_PCM_NONBLOCK);
815 if (r < 0) {
816 if (r == -EAGAIN)
817 fatal("alsa:\"%s\" pcm is already in use\n", pcm_str);
818 else
819 fatal("alsa:unable to open \"%s\" pcm for playback\n", pcm_str);
822 STATIC void init_once_public(u8 *pcm_str)
824 int r;
826 memset(&st_p, 0, sizeof(st_p));
827 pkt_q_p = npv_pkt_q_new("audio");
828 dec_ctx_p = 0;
829 dec_sets_p.eof_receive = false;
830 dec_sets_p.n_max = 0;
831 dec_sets_p.n = 0;
832 dec_sets_p.a = 0;
833 init_pcm_once_public(pcm_str);
834 selected_ts_type_p = -1;
835 /* linux bug: still no CLOCK_MONOTONIC_RAW for timerfd */
836 errno = 0;
837 draining_timer_fd_p = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
838 if (draining_timer_fd_p == -1)
839 fatal("unable to get a draining timer file descriptor:%s\n", strerror(errno));
840 draining_p = false;
841 r = pthread_mutex_init(&dec_ctx_mutex_l, 0);
842 if (r != 0)
843 fatal("%d:unable to init the decoder mutex\n", r);
844 r = pthread_mutex_init(&dec_sets_p.mutex, 0);
845 if (r != 0)
846 fatal("%d:unable to init the mutex for the array of decoder sets\n", r);
848 STATIC void init_once_local(void)
850 int r;
852 dec_l = 0;
853 r = snd_output_stdio_attach(&pcm_pout_l, stdout, 0);
854 if (r < 0)
855 fatal("alsa:unable to attach stdout\n");
856 r = snd_output_stdio_attach(&pcm_perr_l, stderr, 0);
857 if (r < 0)
858 fatal("alsa:unable to attach stderr\n");
859 memset(pcm_silence_bufs_l, 0, sizeof(pcm_silence_bufs_l));
861 STATIC void dec_a_unref_all(void)
863 u16 set;
865 set = 0;
866 loop {
867 if (set == dec_sets_p.n)
868 break;
869 avutil_audio_set_unref(dec_sets_p.a[set]);
870 ++set;
872 dec_sets_p.n = 0;