npv: dynamic audio filter configuration
[nyanmp.git] / npv / audio / filt / public / code.frag.c
blob2fd1fef358816ee49a214397ac1e29b173210123
1 /*NSPC*/
2 #define AGAIN 0
3 #define PUSHED_ONE_SET 1
4 #define NO_DEC_SET 2
5 #define FILT_SWITCHED_TO_DRAINING 3
6 #define FILT_RECFG_REQUIRED 4
7 STATIC u8 filt_push_dec_set(int *new_chans_n, uint64_t *new_chans_layout,
8 int *new_rate, enum avutil_audio_fr_fmt_t *new_fmt)
10 u8 r8;
11 int ri;
12 avutil_audio_set_ref_t **a;
14 npv_audio_dec_sets_lock();
15 if (npv_audio_dec_sets_p.n == 0) {
16 if (npv_audio_dec_sets_p.eof_receive) {
17 ri = avfilter_bufsrc_add_audio_set_flags(abufsrc_l.ctx,
18 0, AVFILTER_BUFSRC_FLAG_KEEP_REF);
19 if (ri < 0)
20 fatal("ffmpeg:unable to notify the end of data to the filter source audio buffer context\n");
21 pout("ffmpeg:interactive filter switched to draining\n");
22 r8 = FILT_SWITCHED_TO_DRAINING;
23 goto unlock;
25 r8 = NO_DEC_SET;
26 goto unlock;
28 a = npv_audio_dec_sets_p.a;
30 * XXX: this is were dynamic audio recfg is triggered and we get out of
31 * the critical section asap
33 if (is_recfg_required(a[0])) {
34 /* because we are in a critical section */
35 *new_chans_n = a[0]->chans_n;
36 *new_chans_layout = a[0]->chans_layout;
37 *new_rate = a[0]->rate;
38 *new_fmt = a[0]->fmt;
39 r8 = FILT_RECFG_REQUIRED;
40 goto unlock;
42 /* the dec_sets_p bufs will be unref in avcodec_audio_receive_set */
43 ri = avfilter_bufsrc_add_audio_set_flags(abufsrc_l.ctx, a[0],
44 AVFILTER_BUFSRC_FLAG_KEEP_REF);
45 if (ri >= 0) {
46 /* rotate the ptrs if needed */
47 if (npv_audio_dec_sets_p.n > 1) {
48 avutil_audio_set_ref_t *save;
50 save = a[0];
51 memmove(&a[0], &a[1], sizeof(*a)
52 * (npv_audio_dec_sets_p.n - 1));
53 a[npv_audio_dec_sets_p.n - 1] = save;
55 npv_audio_dec_sets_p.n--;
56 r8 = PUSHED_ONE_SET;
57 goto unlock;
58 } else if (ri == AVERROR(EAGAIN)) {
59 r8 = AGAIN;
60 goto unlock;
62 fatal("ffmpeg:unable to submit a decoder set of frames to the filter source audio buffer context\n");
63 unlock:
64 npv_audio_dec_sets_unlock();
65 return r8;
67 #undef AGAIN
68 #undef PUSHED_ONE_SET
69 #undef NO_DEC_SET
70 #undef PUSHED_NULL_SET
71 #undef FILT_SWITCHED_TO_DRAINING
72 #undef FILT_RECFG_REQUIRED
73 #define HAVE_FILT_SET 1
74 #define EOF_FILT 2
75 STATIC u8 filt_set_get(void)
77 int r;
79 * the last dec set should switch the filt in draining mode, and
80 * filt_p.set won't matter.
82 r = avfilter_bufsink_get_audio_set(abufsink_ctx_l, filt_p.set);
83 if (r >= 0) {
84 filt_p.pcm_written_ufrs_n = 0;
85 return HAVE_FILT_SET;
86 } else if (r == AVUTIL_AVERROR_EOF) {
87 return EOF_FILT;
89 fatal("ffmpeg:error while getting frames from the filter\n");
91 #undef HAVE_FILT_SET
92 #undef EOF_FILT
93 #define DONT_PRINT_INFO false
94 STATIC void filt_flush(void)
96 int dst_chans_n;
97 enum avutil_audio_fr_fmt_t dst_fmt;
98 uint64_t src_chans_layout;
99 uint64_t dst_chans_layout;
100 int dst_rate;
102 avutil_audio_set_unref(filt_p.set);
103 filt_p.pcm_written_ufrs_n = 0;
105 npv_audio_pcm2ff_strict(npv_audio_pcm_p, &dst_chans_n,
106 &dst_chans_layout, &dst_rate, &dst_fmt, DONT_PRINT_INFO);
107 /* the audio dec ctx may not have a valid chans layout */
108 if (npv_audio_dec_ctx_p->chans_layout == 0)
109 src_chans_layout = avutil_get_default_chans_layout(
110 npv_audio_dec_ctx_p->chans_n);
111 else
112 src_chans_layout = npv_audio_dec_ctx_p->chans_layout;
113 cfg(npv_audio_dec_ctx_p->chans_n, src_chans_layout,
114 npv_audio_dec_ctx_p->fr_rate, npv_audio_dec_ctx_p->fr_fmt,
115 filt_p.muted, filt_p.vol,
116 dst_chans_n, dst_chans_layout, dst_rate, dst_fmt,
117 DONT_PRINT_INFO);
119 #undef DONT_PRINT_INFO
120 STATIC void init_once(double initial_vol)
122 init_once_local();
123 init_once_public(initial_vol);
125 STATIC void cfg(int src_chans_n, uint64_t src_chans_layout, int src_rate,
126 enum avutil_audio_fr_fmt_t src_fmt,
127 bool muted, double vol,
128 int dst_chans_n, uint64_t dst_chans_layout, int dst_rate,
129 enum avutil_audio_fr_fmt_t dst_fmt,
130 bool print_info)
132 int r;
133 char *dump_str;
135 avfilter_graph_free(&graph_l);
137 graph_l = avfilter_graph_alloc();
138 if (graph_l == 0)
139 fatal("unable to create filter graph\n");
140 abufsrc_cfg(src_chans_n, src_chans_layout, src_rate, src_fmt,
141 print_info);
142 /*--------------------------------------------------------------------*/
143 abufsrc_l.key.chans_n = src_chans_n;
144 abufsrc_l.key.chans_layout = src_chans_layout;
145 abufsrc_l.key.rate = src_rate;
146 abufsrc_l.key.fmt = src_fmt;
147 /*--------------------------------------------------------------------*/
148 vol_cfg(muted, vol);
149 afmt_cfg(dst_chans_n, dst_chans_layout, dst_rate, dst_fmt, print_info);
150 abufsink_cfg();
151 r = avfilter_link(abufsrc_l.ctx, 0, vol_ctx_l, 0);
152 if (r < 0)
153 fatal("unable to connect the audio buffer source filter to the volume filter\n");
154 r = avfilter_link(vol_ctx_l, 0, afmt_ctx_l, 0);
155 if (r < 0)
156 fatal("unable to connect the volume filter to the audio format filter\n");
157 r = avfilter_link(afmt_ctx_l, 0, abufsink_ctx_l, 0);
158 if (r < 0)
159 fatal("unable to connect the audio format filter to the audio buffer sink filter\n");
160 r = avfilter_graph_config(graph_l, 0);
161 if (r < 0)
162 fatal("unable to configure the filter graph\n");
163 if (!print_info)
164 return;
165 dump_str = avfilter_graph_dump(graph_l, 0);
166 if (dump_str == 0) {
167 warning("unable to get a filter graph description\n");
168 return;
170 pout("GRAPH START-------------------------------------------------------\n");
171 npv_pout("%s", dump_str);
172 avutil_free(dump_str);
173 pout("GRAPH END---------------------------------------------------------\n");
175 STATIC void npv_audio_filt_cmd_mute(void)
177 int r;
178 u8 vol_l10n_str[sizeof("xxx.xx")]; /* should be overkill */
179 u8 resp[STR_SZ];
181 if (filt_p.muted) {
182 pout("COMMAND:unmuting\n");
184 snprintf(vol_l10n_str, sizeof(vol_l10n_str), "%f", filt_p.vol);
185 r = avfilter_graph_send_cmd(graph_l, "vol", "volume",
186 vol_l10n_str, resp, sizeof(resp), 0);
187 if (r < 0) {
188 warning("ffmpeg:volume context:unable to mute the volume to 0:response from volume filter:%s\n", resp);
189 } else {
190 filt_p.muted = false;
192 } else {
193 pout("COMMAND:muting\n");
195 r = avfilter_graph_send_cmd(graph_l, "vol", "volume",
196 double_zero_l10n_str_l, resp, sizeof(resp), 0);
197 if (r < 0) {
198 warning("ffmpeg:volume context:unable to mute the volume to 0:response from volume filter:%s\n", resp);
199 } else {
200 filt_p.muted = true;
204 STATIC void npv_audio_filt_cmd_vol_down(void)
206 int r;
207 u8 vol_l10n_str[sizeof("xxx.xx")]; /* should be overkill */
208 u8 resp[STR_SZ];
210 filt_p.vol -= VOL_DELTA;
211 if (filt_p.vol < 0.)
212 filt_p.vol = 0.;
213 snprintf(vol_l10n_str, sizeof(vol_l10n_str), "%f", filt_p.vol);
214 pout("COMMAND:volume down to value %s\n", vol_l10n_str);
215 if (!filt_p.muted) {
216 r = avfilter_graph_send_cmd(graph_l, "vol", "volume",
217 vol_l10n_str, resp, sizeof(resp), 0);
218 if (r < 0)
219 warning("ffmpeg:volume context:unable to set the volume down to \"%s\":response from volume filter:\"%s\"\n", resp);
222 STATIC void npv_audio_filt_cmd_vol_up(void)
224 int r;
225 u8 vol_l10n_str[sizeof("xxx.xx")]; /* should be overkill */
226 u8 resp[STR_SZ];
228 filt_p.vol += VOL_DELTA;
229 if (filt_p.vol > 1.)
230 filt_p.vol = 1.;
231 snprintf(vol_l10n_str, sizeof(vol_l10n_str), "%f", filt_p.vol);
232 pout("COMMAND:volume up to value %s\n", vol_l10n_str);
233 if (!filt_p.muted) {
234 r = avfilter_graph_send_cmd(graph_l, "vol", "volume",
235 vol_l10n_str, resp, sizeof(resp), 0);
236 if (r < 0)
237 warning("ffmpeg:volume context:unable to set the volume up to \"%s\":response from volume filter:\"%s\"\n", resp);