npv:spurious namespace tag
[nyanmp.git] / npv / audio / local / code.frag.c
blob5b27e36138252932450a3081c4bfaf1c445b24f1
1 STATIC bool ff_fmt2pcm_layout_best_effort(enum avutil_audio_fr_fmt_t ff_fmt,
2 snd_pcm_fmt_t *alsa_fmt, snd_pcm_access_t *alsa_access)
4 static u8 ff_fmt_str[STR_SZ];
6 avutil_get_audio_fr_fmt_str(ff_fmt_str, STR_SZ, ff_fmt);
7 /* XXX: only classic non-mmap ones */
8 switch (ff_fmt) {
9 case AVUTIL_AUDIO_FR_FMT_U8:
10 *alsa_fmt = SND_PCM_FMT_U8;
11 *alsa_access = SND_PCM_ACCESS_RW_INTERLEAVED;
12 break;
13 case AVUTIL_AUDIO_FR_FMT_S16:
14 *alsa_fmt = SND_PCM_FMT_S16;
15 *alsa_access = SND_PCM_ACCESS_RW_INTERLEAVED;
16 break;
17 case AVUTIL_AUDIO_FR_FMT_S32:
18 *alsa_fmt = SND_PCM_FMT_S32;
19 *alsa_access = SND_PCM_ACCESS_RW_INTERLEAVED;
20 break;
21 case AVUTIL_AUDIO_FR_FMT_FLT:
22 *alsa_fmt = SND_PCM_FMT_FLOAT;
23 *alsa_access = SND_PCM_ACCESS_RW_INTERLEAVED;
24 break;
25 /* ff "planar" fmts are actually non interleaved fmts */
26 case AVUTIL_AUDIO_FR_FMT_U8P:
27 *alsa_fmt = SND_PCM_FMT_U8;
28 *alsa_access = SND_PCM_ACCESS_RW_NONINTERLEAVED;
29 break;
30 case AVUTIL_AUDIO_FR_FMT_S16P:
31 *alsa_fmt = SND_PCM_FMT_S16;
32 *alsa_access = SND_PCM_ACCESS_RW_NONINTERLEAVED;
33 break;
34 case AVUTIL_AUDIO_FR_FMT_S32P:
35 *alsa_fmt = SND_PCM_FMT_S32;
36 *alsa_access = SND_PCM_ACCESS_RW_NONINTERLEAVED;
37 break;
38 case AVUTIL_AUDIO_FR_FMT_FLTP:
39 *alsa_fmt = SND_PCM_FMT_FLOAT;
40 *alsa_access = SND_PCM_ACCESS_RW_NONINTERLEAVED;
41 break;
42 default:
43 POUTA("best effort:unable to wire ffmpeg sample format \"%sbits\" to alsa sample format, \n,", ff_fmt_str);
44 return false;
46 POUTA("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));
47 return true;
49 STATIC void pcm_hw_chans_n_decide(snd_pcm_t *pcm,
50 snd_pcm_hw_params_t *pcm_hw_params, unsigned int chans_n)
52 int r;
53 unsigned int chans_n_max;
54 unsigned int chans_n_min;
56 r = snd_pcm_hw_params_test_chans_n(pcm, pcm_hw_params, chans_n);
57 if (r == 0) {
58 r = snd_pcm_hw_params_set_chans_n(pcm, pcm_hw_params, chans_n);
59 if (r != 0)
60 FATALA("alsa:unable to restrict pcm device to %u channels, count which was successfully tested\n", chans_n);
61 POUTA("alsa:using %u channels\n", chans_n);
62 return;
64 POUTA("alsa:unable to use %u channels\n", chans_n);
65 /* try to use the max chans n the pcm can */
66 r = snd_pcm_hw_params_get_chans_n_max(pcm_hw_params, &chans_n_max);
67 if (r != 0)
68 FATALA("alsa:unable to get the maximum count of pcm device channels\n");
69 r = snd_pcm_hw_params_test_chans_n(pcm, pcm_hw_params, chans_n_max);
70 if (r == 0) {
71 r = snd_pcm_hw_params_set_chans_n(pcm, pcm_hw_params,
72 chans_n_max);
73 if (r != 0)
74 FATALA("alsa:unable to restrict pcm device to %u channels, count which was successfully tested\n", chans_n_max);
75 POUTA("alsa:using pcm maximum %u channels\n", chans_n_max);
76 return;
78 /* ok... last try, the pcm dev min chans n */
79 r = snd_pcm_hw_params_get_chans_n_min(pcm_hw_params, &chans_n_min);
80 if (r != 0)
81 FATALA("alsa:unable to get the minimum count of pcm device channels\n");
82 r = snd_pcm_hw_params_test_chans_n(pcm, pcm_hw_params, chans_n_min);
83 if (r == 0) {
84 r = snd_pcm_hw_params_set_chans_n(pcm, pcm_hw_params,
85 chans_n_min);
86 if (r != 0)
87 FATALA("alsa:unable to restrict pcm device to %u channels, count which was successfully tested\n", chans_n_min);
88 POUTA("alsa:using pcm device minimum %u channels\n", chans_n_min);
89 return;
91 FATALA("alsa:unable to find a suitable count of channels\n");
93 STATIC void pcm_hw_rate_decide(snd_pcm_t *pcm,
94 snd_pcm_hw_params_t *pcm_hw_params, unsigned int rate)
96 int r;
97 unsigned int rate_max;
98 unsigned int rate_near;
99 unsigned int rate_min;
101 r = snd_pcm_hw_params_test_rate(pcm, pcm_hw_params, rate,
102 SND_PCM_ST_PLAYBACK);
103 if (r == 0) {
104 r = snd_pcm_hw_params_set_rate(pcm, pcm_hw_params, rate,
105 SND_PCM_ST_PLAYBACK);
106 if (r != 0)
107 FATALA("alsa:unable to restrict pcm device to %uHz, which was successfully tested\n", rate);
108 POUTA("alsa:using %uHz\n", rate);
109 return;
111 POUTA("alsa:unable to use %uHz\n", rate);
112 /* try to use the max rate the pcm can */
113 r = snd_pcm_hw_params_get_rate_max(pcm_hw_params, &rate_max,
114 SND_PCM_ST_PLAYBACK);
115 if (r != 0)
116 FATALA("alsa:unable to get the maximum rate of pcm device\n");
117 r = snd_pcm_hw_params_test_rate(pcm, pcm_hw_params, rate_max,
118 SND_PCM_ST_PLAYBACK);
119 if (r == 0) {
120 r = snd_pcm_hw_params_set_rate(pcm, pcm_hw_params, rate_max,
121 SND_PCM_ST_PLAYBACK);
122 if (r != 0)
123 FATALA("alsa:unable to restrict pcm device to %uHz, which was successfully tested\n", rate_max);
124 POUTA("alsa:using pcm device %uHz\n", rate_max);
125 return;
127 /* try to use a rate "near" of what the pcm dev can */
128 rate_near = rate;
129 r = snd_pcm_hw_params_set_rate_near(pcm, pcm_hw_params, &rate_near,
130 SND_PCM_ST_PLAYBACK);
131 if (r == 0) {
132 POUTA("alsa:using pcm device %uHz\n", rate_near);
133 return;
135 /* even a "near" rate did failed... try the min */
136 r = snd_pcm_hw_params_get_rate_min(pcm_hw_params, &rate_min,
137 SND_PCM_ST_PLAYBACK);
138 if (r != 0)
139 FATALA("alsa:unable to get the minimum rate of pcm device\n");
140 r = snd_pcm_hw_params_test_rate(pcm, pcm_hw_params, rate_min,
141 SND_PCM_ST_PLAYBACK);
142 if (r == 0) {
143 r = snd_pcm_hw_params_set_rate(pcm, pcm_hw_params, rate_min,
144 SND_PCM_ST_PLAYBACK);
145 if (r != 0)
146 FATALA("alsa:unable to restrict pcm device to %uHz, which was successfully tested\n", rate_min);
147 POUTA("alsa:using pcm device %uHz\n", rate_min);
148 return;
150 FATALA("alsa:unable to find a suitable rate\n");
152 STATIC bool pcm_hw_fmt_decide_x(snd_pcm_t *pcm,
153 snd_pcm_hw_params_t *pcm_hw_params, snd_pcm_fmt_t fmt)
155 int r;
157 r = snd_pcm_hw_params_test_fmt(pcm, pcm_hw_params, fmt);
158 if (r != 0)
159 return false;
160 r = snd_pcm_hw_params_set_fmt(pcm, pcm_hw_params, fmt);
161 if (r != 0)
162 FATALA("alsa:unable to restrict pcm device to \"%s\", which was successfully tested\n", snd_pcm_fmt_desc(fmt));
163 POUTA("alsa:using \"%s\" format\n", snd_pcm_fmt_desc(fmt));
164 return true;
166 #define PCM_HW_FMT_DECIDE_X(fmt) pcm_hw_fmt_decide_x(pcm, pcm_hw_params, fmt)
167 STATIC void pcm_hw_fmt_decide(snd_pcm_t *pcm,
168 snd_pcm_hw_params_t *pcm_hw_params, bool force,
169 snd_pcm_fmt_t forced_fmt)
171 int r;
172 snd_pcm_fmt_t *fmt;
174 if (force) {
175 r = snd_pcm_hw_params_test_fmt(pcm, pcm_hw_params, forced_fmt);
176 if (r == 0) {
177 r = snd_pcm_hw_params_set_fmt(pcm, pcm_hw_params,
178 forced_fmt);
179 if (r != 0)
180 FATALA("alsa:unable to restrict pcm device to \"%s\", which was successfully tested\n", snd_pcm_fmt_desc(forced_fmt));
181 POUTA("alsa:using forced \"%s\" format\n", snd_pcm_fmt_desc(forced_fmt));
182 return;
185 /* then we try to select from the reasonable "best" to the lowest */
186 /* prefer fmts we know supported by ff */
187 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FMT_FLOAT))
188 return;
189 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FMT_S32))
190 return;
191 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FMT_S16))
192 return;
193 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FMT_U8))
194 return;
196 * from here, at the time of writting, those fmts have no ff
197 * wiring, but we are alsa centric here, validate that later
199 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FMT_U32))
200 return;
201 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FMT_S24))
202 return;
203 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FMT_U24))
204 return;
205 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FMT_U16))
206 return;
207 if (PCM_HW_FMT_DECIDE_X(SND_PCM_FMT_S8))
208 return;
209 FATALA("alsa:unable to find a suitable format\n");
211 #undef PCM_HW_FMT_DECIDE_X
212 STATIC bool pcm_hw_access_decide_x(snd_pcm_t *pcm,
213 snd_pcm_hw_params_t *pcm_hw_params, snd_pcm_access_t access)
215 int r;
217 r = snd_pcm_hw_params_test_access(pcm, pcm_hw_params, access);
218 if (r != 0)
219 return false;
220 r = snd_pcm_hw_params_set_access(pcm, pcm_hw_params, access);
221 if (r != 0)
222 FATALA("alsa:unable to restrict pcm device to \"%s\", which was successfully tested\n", snd_pcm_access_name(access));
223 POUTA("alsa:using \"%s\" access\n", snd_pcm_access_name(access));
224 return true;
226 #define PCM_HW_ACCESS_DECIDE_X(access) \
227 pcm_hw_access_decide_x(pcm, pcm_hw_params, access)
228 /* XXX: only classic non-mmap ones */
229 STATIC void pcm_hw_access_decide(snd_pcm_t *pcm,
230 snd_pcm_hw_params_t *pcm_hw_params, bool force,
231 snd_pcm_access_t forced_access)
233 int r;
234 snd_pcm_access_t access;
236 if (force) {
237 r = snd_pcm_hw_params_test_access(pcm, pcm_hw_params,
238 forced_access);
239 if (r == 0) {
240 r = snd_pcm_hw_params_set_access(pcm, pcm_hw_params,
241 forced_access);
242 if (r != 0)
243 FATALA("alsa:unable to restrict pcm device to \"%s\", which was successfully tested\n", snd_pcm_access_name(forced_access));
244 POUTA("alsa:using forced \"%s\" access\n", snd_pcm_access_name(forced_access));
245 return;
248 /* brute force */
249 if (PCM_HW_ACCESS_DECIDE_X(SND_PCM_ACCESS_RW_INTERLEAVED))
250 return;
251 if (PCM_HW_ACCESS_DECIDE_X(SND_PCM_ACCESS_RW_NONINTERLEAVED))
252 return;
253 FATALA("alsa:unable to find a suitable access\n");
255 #undef PCM_HW_ACCESS_DECIDE_X
257 * latency control: some audio bufs can be huge (tested on a pulseaudio with 10
258 * secs audio buf). if we are careless, we will quickly fill this buf which is
259 * worth a significant amount of time, hence will add huge latency to our
260 * interactive audio filtering (vol...). in the case of the 10 secs pulseaudio
261 * buf, it means if you want to mute the audio, it will happen 10 secs later.
262 * we add lantency control by limiting the sz of the dev audio buf, in periods
263 * n.
264 * we choose roughly 0.25 secs, or roughly (rate / 4) frs.
266 STATIC void pcm_hw_buf_sz_cfg(snd_pcm_t *pcm,
267 snd_pcm_hw_params_t *pcm_hw_params)
269 int r;
270 snd_pcm_ufrs_t latency_control_target_buf_ufrs_n;
271 snd_pcm_ufrs_t latency_control_buf_ufrs_n;
272 unsigned int rate;
274 r = snd_pcm_hw_params_get_rate(pcm_hw_params, &rate, 0);
275 if (r < 0) {
276 WARNINGA("alsa:latency control:DISABLING LATENCY CONTROL:unable to get the decided rate from the current device parameters\n");
277 return;
279 latency_control_target_buf_ufrs_n = (snd_pcm_ufrs_t)rate;
280 latency_control_target_buf_ufrs_n /= 4;
281 latency_control_buf_ufrs_n = latency_control_target_buf_ufrs_n;
282 r = snd_pcm_hw_params_set_buf_sz_near(pcm, pcm_hw_params,
283 &latency_control_buf_ufrs_n);
284 if (r < 0) {
285 WARNINGA("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);
286 return;
288 POUTA("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);
291 * this function will "decide" the pcm dev cfg:
292 * the goal is to be the "closest" to the provided params,
293 * the "gap" will have to "filled" with ff filts
295 * the "strategy" is a "fall-thru" (chans n then ... then ...) which
296 * will "restrict" the pcm dev cfg further at each step
298 * we try to use a sensible restrict order regarding audio props
300 STATIC void pcm_cfg_hw_core(snd_pcm_t *pcm, snd_pcm_hw_params_t *pcm_hw_params,
301 int chans_n, int rate, enum avutil_audio_fr_fmt_t ff_fmt)
303 int r;
304 bool best_effort_wiring_success;
305 snd_pcm_fmt_t fmt_from_best_effort;
306 snd_pcm_access_t access_from_best_effort;
308 /* the return value is from a first refine of the raw hw params */
309 r = snd_pcm_hw_params_any(pcm, pcm_hw_params);
310 if (r < 0)
311 FATALA("alsa:unable to populate the hardware parameters context\n");
312 pcm_hw_chans_n_decide(pcm, pcm_hw_params, (unsigned int)chans_n);
313 pcm_hw_rate_decide(pcm, pcm_hw_params, (unsigned int)rate);
314 /* try our best */
315 best_effort_wiring_success = ff_fmt2pcm_layout_best_effort(
316 ff_fmt, &fmt_from_best_effort, &access_from_best_effort);
317 pcm_hw_fmt_decide(pcm, pcm_hw_params, best_effort_wiring_success,
318 fmt_from_best_effort);
319 pcm_hw_access_decide(pcm, pcm_hw_params, best_effort_wiring_success,
320 access_from_best_effort);
321 pcm_hw_buf_sz_cfg(pcm, pcm_hw_params);
323 /* base on kernel api at the time we wrote this code */
324 STATIC u8 *kernel_ts_types_str[] = {
325 "compat",
326 "default",
327 "link",
328 "link absolute",
329 "link estimated",
330 "link synchonized"
332 STATIC void pcm_cfg_hw(snd_pcm_t *pcm, unsigned int chans_n, unsigned int rate,
333 enum avutil_audio_fr_fmt_t ff_fmt)
335 int r;
336 s8 i;
337 snd_pcm_access_t access;
338 snd_pcm_hw_params_t *hw_params;
340 POUTA("ALSA:HW_PARAMS START------------------------------------------------------------\n");
341 r = snd_pcm_hw_params_malloc(&hw_params);
342 if (r < 0)
343 FATALA("alsa:unable to allocate hardware parameters context\n");
345 pcm_cfg_hw_core(pcm, hw_params, chans_n, rate, ff_fmt);
347 r = snd_pcm_hw_params(pcm, hw_params);
348 if (r != 0)
349 FATALA("alsa:unable to install the hardware parameters\n");
350 r = snd_pcm_hw_params_current(pcm, hw_params);
351 if (r != 0)
352 FATALA("alsa:unable to get current hardware parameters\n");
353 snd_pcm_hw_params_dump(hw_params, pcm_pout_l);
355 i = 0;
356 selected_ts_type_p = -1;
357 loop {
358 if (i == ARRAY_N(kernel_ts_types_str))
359 break;
360 r = snd_pcm_hw_params_supports_audio_ts_type(hw_params, i);
361 if (r == 1) {
362 selected_ts_type_p = i;
363 POUTA("kernel audio timestamp type \"%s\" is supported for the current configuration\n", kernel_ts_types_str[i]);
365 ++i;
368 * we selected the most accurate, namely with the highest idx, audio ts
369 * type
371 POUTA("%s will be used for the audio based clock\n", kernel_ts_types_str[selected_ts_type_p]);
372 snd_pcm_hw_params_free(hw_params);
373 POUTA("ALSA:HW_PARAMS END--------------------------------------------------------------\n");
375 STATIC void pcm_cfg_sw(snd_pcm_t *pcm)
377 int r;
378 snd_pcm_sw_params_t *sw_params;
380 POUTA("ALSA:SW_PARAMS START------------------------------------------------------------\n");
381 r = snd_pcm_sw_params_malloc(&sw_params);
382 if (r != 0)
383 FATALA("alsa:unable to allocate software parameters structure\n");
384 r = snd_pcm_sw_params_current(pcm, sw_params);
385 if (r != 0)
386 FATALA("alsa:unable to get current software parameters\n");
387 r = snd_pcm_sw_params_set_period_evt(pcm, sw_params, 1);
388 if (r != 0)
389 FATALA("alsa:unable to enable period event\n");
390 /* enable ts to be sure */
391 r = snd_pcm_sw_params_set_tstamp_mode(pcm, sw_params,
392 SND_PCM_TSTAMP_ENABLE);
393 if (r < 0)
394 FATALA("unable to set timestamp mode:%s\n", snd_strerror(r));
395 r = snd_pcm_sw_params(pcm, sw_params);
396 if (r != 0)
397 FATALA("alsa:unable to install sotfware parameters\n");
398 snd_pcm_sw_params_dump(sw_params, pcm_pout_l);
399 snd_pcm_sw_params_free(sw_params);
400 POUTA("ALSA:SW_PARAMS END--------------------------------------------------------------\n");
402 STATIC void dec_a_grow(void)
404 u32 new_idx;
406 new_idx = dec_sets_p.n_max;
407 dec_sets_p.a = realloc(dec_sets_p.a, sizeof(*dec_sets_p.a)
408 * (dec_sets_p.n_max + 1));
409 if (dec_sets_p.a == 0)
410 FATALA("unable to allocate memory for an additional pointer on a reference of a decoder set of frames\n");
411 dec_sets_p.a[new_idx] = avutil_audio_set_ref_alloc();
412 if (dec_sets_p.a[new_idx] == 0)
413 FATALA("ffmpeg:unable to allocate a reference of a decoder set of frames\n");
414 ++dec_sets_p.n_max;
416 #define AGAIN 0
417 #define RECOVERED 1
418 #define CONTINUE 2
419 STATIC u8 alsa_recover(snd_pcm_sfrs_t r)
421 if (r >= 0)
422 return CONTINUE;
423 /* r < 0 */
424 if (r == -EAGAIN)
425 return AGAIN;
426 else if (r == -EPIPE || r == -ESTRPIPE) {
427 /* underrun or suspended */
428 int r_recovered;
430 r_recovered = snd_pcm_recover(pcm_p, (int)r, 0);
431 if (r_recovered == 0) {
432 WARNINGA("alsa:pcm recovered\n");
433 return RECOVERED;
435 FATALA("alsa:unable to recover from suspend/underrun\n");
437 FATALA("alsa:fatal/unhandled error\n");
439 #undef AGAIN
440 #undef RECOVERED
441 #undef CONTINUE
442 #define NO 0
443 #define AGAIN 0
444 #define RECOVERED 1
445 STATIC void pcm_silence_frs_write(snd_pcm_ufrs_t ufrs_n) { loop
447 int alsa_r;
448 u8 r_recover;
449 int is_planar_fmt;
451 if (ufrs_n == 0)
452 break;
453 is_planar_fmt = avutil_audio_fr_fmt_is_planar(
454 npv_audio_filt_p.set->fmt);
455 if (is_planar_fmt == NO)
456 alsa_r = snd_pcm_writei(pcm_p, pcm_silence_bufs_l[0], ufrs_n);
457 else
458 alsa_r = snd_pcm_writen(pcm_p, pcm_silence_bufs_l, ufrs_n);
459 r_recover = alsa_recover(alsa_r);
460 if (r_recover == AGAIN)
461 continue;
462 else if (r_recover == RECOVERED)
463 break;
464 /* r_recover == CONTINUE */
465 ufrs_n -= (snd_pcm_ufrs_t)alsa_r;
467 #undef NO
468 #undef AGAIN
469 #undef RECOVERED
470 #define NO 0
471 STATIC void chans_buf_init(u8 **chans_buf, int start_fr_idx)
473 int is_planar_fmt;
474 int sample_bytes_n;
476 sample_bytes_n = avutil_get_bytes_per_sample(npv_audio_filt_p.set->fmt);
477 is_planar_fmt = avutil_audio_fr_fmt_is_planar(
478 npv_audio_filt_p.set->fmt);
479 if (is_planar_fmt == NO) { /* or is pcm interleaved */
480 int fr_bytes_n;
482 fr_bytes_n = sample_bytes_n * npv_audio_filt_p.set->chans_n;
483 chans_buf[0] = (u8*)npv_audio_filt_p.set->data[0] + start_fr_idx
484 * fr_bytes_n;
485 } else { /* ff planar or pcm noninterleaved */
486 int p;
488 p = 0;
489 loop {
490 if (p == npv_audio_filt_p.set->chans_n)
491 break;
492 chans_buf[p] = (u8*)npv_audio_filt_p.set->data[p]
493 + start_fr_idx * sample_bytes_n;
494 ++p;
498 #undef NO
499 #define NO 0
500 STATIC void chans_buf_inc(u8 **chans_buf, int inc)
502 int is_planar_fmt;
503 int sample_bytes_n;
505 sample_bytes_n = avutil_get_bytes_per_sample(npv_audio_filt_p.set->fmt);
506 is_planar_fmt = avutil_audio_fr_fmt_is_planar(
507 npv_audio_filt_p.set->fmt);
508 if (is_planar_fmt == NO) { /* or is pcm interleaved */
509 int fr_bytes_n;
511 fr_bytes_n = sample_bytes_n * npv_audio_filt_p.set->chans_n;
512 chans_buf[0] = (u8*)chans_buf[0] + inc * fr_bytes_n;
513 } else { /* ff planar or pcm noninterleaved */
514 int p;
516 p = 0;
517 loop {
518 if (p == npv_audio_filt_p.set->chans_n)
519 break;
520 chans_buf[p] = (u8*)chans_buf[p] + inc * sample_bytes_n;
521 ++p;
525 #undef NO
526 STATIC void draining_state_handle(void)
528 int r;
530 r = snd_pcm_drain(pcm_p);
531 if (r != 0) {
532 snd_pcm_state_t state;
534 if (r == -EAGAIN)
535 return;
537 * the pcm state can change asynchronously, and if the draining
538 * was successful, the pcm should be in SETUP state, and in
539 * this state, snd_pcm_drain _must_ fail (direct from alsa
540 * devs)
542 state = snd_pcm_state(pcm_p);
543 if (state != SND_PCM_STATE_SETUP)
544 FATALA("alsa:an error occured switching to/checking the pcm draining state\n");
545 /* here pcm state is SND_PCM_STATE_SETUP */
547 EXIT("alsa pcm drained or similar, exiting\n");
549 STATIC void draining_state_switch(void)
551 int r;
552 u8 i;
553 struct itimerspec t;
555 draining_p = true;
556 draining_state_handle();
557 /* remove the alsa epoll fds */
558 i = 0;
559 loop {
560 if (i == pcm_pollfds_n_p)
561 break;
562 /* in theory, it is thread safe */
563 r = epoll_ctl(npv_ep_fd_p, EPOLL_CTL_DEL, pcm_pollfds_p[i].fd,
565 if (r == -1)
566 FATALA("unable to remove the alsa file descriptors from epoll\n");
567 ++i;
569 /* start the draining timer */
570 memset(&t, 0, sizeof(t));
571 /* initial and interval */
572 t.it_value.tv_nsec = DRAINING_TIMER_INTERVAL_NSECS_N;
573 t.it_interval.tv_nsec = DRAINING_TIMER_INTERVAL_NSECS_N;
574 r = timerfd_settime(draining_timer_fd_p, 0, &t, 0);
575 if (r == -1)
576 FATALA("unable to arm the draining timer\n");
578 #define NO 0
579 #define AGAIN 0
580 #define RECOVERED 1
581 #define CONTINUE 2
582 #define HAVE_FILT_SET 1
583 #define EOF_FILT 2
584 #define NO_DEC_SET 2
585 STATIC void pcm_filt_frs_write(snd_pcm_ufrs_t ufrs_n) { loop
587 u8 chan_buf;
588 u8 *chans_buf[AVUTIL_DATA_PTRS_N];
589 snd_pcm_ufrs_t ufrs_to_write_n;
590 snd_pcm_ufrs_t filt_set_remaining_ufrs_n; /* for clarity */
591 int is_planar_fmt;
592 snd_pcm_ufrs_t written_ufrs_n; /* for clarity */
594 if (ufrs_n == 0)
595 break;
597 * in this loop we try to get some filt frs from what we got from the
598 * dec
600 if (npv_audio_filt_p.set->frs_n == 0) loop {
601 u8 r;
603 /* we _really_ want audio data */
604 (void)filt_push_dec_sets();
605 r = npv_audio_filt_set_try_get();
606 if (r == EOF_FILT) {
607 draining_state_switch();
608 return;
609 } else if (r == HAVE_FILT_SET) {
610 npv_audio_filt_p.pcm_written_ufrs_n = 0;
611 break;
613 /* r == AGAIN */
615 chans_buf_init(chans_buf, (int)npv_audio_filt_p.pcm_written_ufrs_n);
616 filt_set_remaining_ufrs_n = (snd_pcm_ufrs_t)npv_audio_filt_p.set->frs_n
617 - npv_audio_filt_p.pcm_written_ufrs_n;
618 if (filt_set_remaining_ufrs_n > ufrs_n)
619 ufrs_to_write_n = ufrs_n;
620 else
621 ufrs_to_write_n = filt_set_remaining_ufrs_n;
622 is_planar_fmt = avutil_audio_fr_fmt_is_planar(
623 npv_audio_filt_p.set->fmt);
624 written_ufrs_n = 0;
625 loop { /* short write loop */
626 snd_pcm_sfrs_t alsa_r;
627 u8 r_recover;
629 if (is_planar_fmt == NO)
630 alsa_r = snd_pcm_writei(pcm_p, chans_buf[0],
631 ufrs_to_write_n - written_ufrs_n);
632 else
633 alsa_r = snd_pcm_writen(pcm_p, (void**)chans_buf,
634 ufrs_to_write_n - written_ufrs_n);
635 r_recover = alsa_recover(alsa_r);
636 if (r_recover == AGAIN)
637 continue;
638 else if (r_recover == RECOVERED) {
639 /* account for the written frs anyway */
640 if (npv_audio_filt_p.pcm_written_ufrs_n == 0)
641 npv_clk_ref_time_point_update(
642 npv_audio_filt_p.set->pts,
643 written_ufrs_n);
644 npv_audio_filt_p.pcm_written_ufrs_n += written_ufrs_n;
645 if ((int)npv_audio_filt_p.pcm_written_ufrs_n ==
646 npv_audio_filt_p.set->frs_n)
647 /* set audio_filt_p.set->frs_n = 0 */
648 avutil_audio_set_unref(npv_audio_filt_p.set);
649 return;
651 /* r_recover == CONTINUE */
652 written_ufrs_n += (snd_pcm_ufrs_t)alsa_r;
653 if (written_ufrs_n == ufrs_to_write_n)
654 break;
655 chans_buf_inc(chans_buf, (int)alsa_r);
658 * this is here we update our ref time point for the audio clk
659 * because with a new filt set of frs, we get a new ts
661 * XXX: getting the "right" ts from ff is convoluted
663 if (npv_audio_filt_p.pcm_written_ufrs_n == 0)
664 npv_clk_ref_time_point_update(npv_audio_filt_p.set->pts,
665 written_ufrs_n);
666 npv_audio_filt_p.pcm_written_ufrs_n += written_ufrs_n;
667 ufrs_n -= written_ufrs_n;
669 if ((int)npv_audio_filt_p.pcm_written_ufrs_n
670 == npv_audio_filt_p.set->frs_n)
671 /* set audio_filt_p.av->frs_n = 0 */
672 avutil_audio_set_unref(npv_audio_filt_p.set);
674 #undef NO
675 #undef AGAIN
676 #undef RECOVERED
677 #undef CONTINUE
678 #undef HAVE_FILT_SET
679 #undef EOF_FILT
680 #undef NO_DEC_SET
681 /* fatal if the wiring cannot be done */
682 STATIC void pcm_layout2ff_fmt_strict(snd_pcm_fmt_t alsa_fmt,
683 snd_pcm_access_t alsa_access, enum avutil_audio_fr_fmt_t *ff_fmt,
684 bool print_info)
687 * ff fmt byte order is always native.
688 * here we handle little endian only
690 switch (alsa_fmt) {
691 case SND_PCM_FMT_FLOAT:
692 if (alsa_access == SND_PCM_ACCESS_RW_INTERLEAVED)
693 *ff_fmt = AVUTIL_AUDIO_FR_FMT_FLT;
694 else
695 *ff_fmt = AVUTIL_AUDIO_FR_FMT_FLTP;
696 break;
697 case SND_PCM_FMT_S32:
698 if (alsa_access == SND_PCM_ACCESS_RW_INTERLEAVED)
699 *ff_fmt = AVUTIL_AUDIO_FR_FMT_S32;
700 else
701 *ff_fmt = AVUTIL_AUDIO_FR_FMT_S32P;
702 break;
703 case SND_PCM_FMT_S16:
704 if (alsa_access == SND_PCM_ACCESS_RW_INTERLEAVED)
705 *ff_fmt = AVUTIL_AUDIO_FR_FMT_S16;
706 else
707 *ff_fmt = AVUTIL_AUDIO_FR_FMT_S16P;
708 break;
709 case SND_PCM_FMT_U8:
710 if (alsa_access == SND_PCM_ACCESS_RW_INTERLEAVED)
711 *ff_fmt = AVUTIL_AUDIO_FR_FMT_U8;
712 else
713 *ff_fmt = AVUTIL_AUDIO_FR_FMT_U8P;
714 break;
715 default:
716 FATALA("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));
718 if (print_info) {
719 u8 ff_fmt_str[STR_SZ];
721 avutil_get_audio_fr_fmt_str(ff_fmt_str, sizeof(ff_fmt_str),
722 *ff_fmt);
723 POUTA("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);
727 * XXX: if it is ever used significantly, a fine granularity wiring strategy
728 * will be implemented instead of using the default wiring
730 STATIC uint64_t pcm_chmaps2ff_chans_layout(snd_pcm_t *pcm,
731 unsigned int pcm_chans_n, bool print_info)
733 int r;
734 uint64_t ff_chans_layout;
735 snd_pcm_chmap_t *pcm_chmap;
736 u8 chans_layout_str[STR_SZ]; /* should be overkill */
738 pcm_chmap = snd_pcm_get_chmap(pcm);
739 if (pcm_chmap == 0) {
740 if (print_info)
741 POUTA("alsa:no pcm channel map available, wiring to default ffmpeg channel layout\n");
742 } else {
743 if (print_info)
744 POUTA("alsa:your pcm device support channel maps, but fine granularity wiring strategy is not implemented\n");
745 free(pcm_chmap);
747 ff_chans_layout = avutil_get_default_chans_layout((int)pcm_chans_n);
748 avutil_get_chans_layout_str(chans_layout_str, sizeof(chans_layout_str),
749 (int)pcm_chans_n, ff_chans_layout);
750 if (print_info)
751 POUTA("alsa channel map wired to ffmpeg channel layout:\"%s\" (%u pcm channels)\n", chans_layout_str, pcm_chans_n);
752 return ff_chans_layout;
754 STATIC void init_pcm_once_public(u8 *pcm_str)
756 int r;
758 r = snd_pcm_open(&pcm_p, pcm_str, SND_PCM_ST_PLAYBACK,
759 SND_PCM_NONBLOCK);
760 if (r < 0) {
761 if (r == -EAGAIN)
762 FATALA("alsa:\"%s\" pcm is already in use\n", pcm_str);
763 else
764 FATALA("alsa:unable to open \"%s\" pcm for playback\n", pcm_str);
767 r = snd_pcm_poll_descriptors_n(pcm_p);
768 POUTA("alsa:have %d poll file descriptors\n", r);
769 if ((r <= 0) || (r > pcm_pollfds_n_max))
770 FATALA("alsa:invalid count of alsa poll file descriptors\n");
771 pcm_pollfds_n_p =(u8)r;
772 memset(pcm_pollfds_p, 0, sizeof(pcm_pollfds_p));
773 snd_pcm_poll_descriptors(pcm_p, pcm_pollfds_p, pcm_pollfds_n_max);
775 STATIC void init_once_public(u8 *pcm_str)
777 int r;
779 memset(&st_p, 0, sizeof(st_p));
780 pkt_q_p = npv_pkt_q_new("audio");
781 dec_ctx_p = 0;
782 dec_sets_p.eof_receive = false;
783 dec_sets_p.n_max = 0;
784 dec_sets_p.n = 0;
785 dec_sets_p.a = 0;
786 init_pcm_once_public(pcm_str);
787 selected_ts_type_p = -1;
788 /* linux bug: still no CLOCK_MONOTONIC_RAW for timerfd */
789 errno = 0;
790 draining_timer_fd_p = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
791 if (draining_timer_fd_p == -1)
792 FATALA("unable to get a draining timer file descriptor:%s\n", strerror(errno));
793 draining_p = false;
794 r = pthread_mutex_init(&dec_ctx_mutex_l, 0);
795 if (r != 0)
796 FATALA("%d:unable to init the decoder mutex\n", r);
797 r = pthread_mutex_init(&dec_sets_p.mutex, 0);
798 if (r != 0)
799 FATALA("%d:unable to init the mutex for the array of decoder sets\n", r);
801 STATIC void init_once_local(void)
803 int r;
805 dec_l = 0;
806 r = snd_output_stdio_attach(&pcm_pout_l, stdout, 0);
807 if (r < 0)
808 FATALA("alsa:unable to attach stdout\n");
809 r = snd_output_stdio_attach(&pcm_perr_l, stderr, 0);
810 if (r < 0)
811 FATALA("alsa:unable to attach stderr\n");
812 memset(pcm_silence_bufs_l, 0, sizeof(pcm_silence_bufs_l));
814 STATIC void dec_a_unref_all(void)
816 u16 set;
818 set = 0;
819 loop {
820 if (set == dec_sets_p.n)
821 break;
822 avutil_audio_set_unref(dec_sets_p.a[set]);
823 ++set;
825 dec_sets_p.n = 0;