]> git.sesse.net Git - vlc/blob - modules/audio_filter/audiobargraph_a.c
mediacodec: handle error_state in one place
[vlc] / modules / audio_filter / audiobargraph_a.c
1 /*****************************************************************************
2  * audiobargraph_a.c : audiobargraph audio plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2002-2014 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Clement CHESNIN <clement.chesnin@gmail.com>
8  *          Philippe COENT <philippe.coent@tdf.fr>
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU Lesser General Public License as published by
12  * the Free Software Foundation; either version 2.1 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with this program; if not, write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_aout.h>
35 #include <vlc_filter.h>
36
37 #include <math.h>
38
39 #define BARGRAPH_TEXT N_("Defines if BarGraph information should be sent")
40 #define BARGRAPH_LONGTEXT N_("Defines if BarGraph information should be sent. "\
41                 "1 if the information should be sent, 0 otherwise (default 1)." )
42 #define BARGRAPH_REPETITION_TEXT N_("Sends the barGraph information every n audio packets")
43 #define BARGRAPH_REPETITION_LONGTEXT N_("Defines how often the barGraph information should be sent. "\
44                 "Sends the barGraph information every n audio packets (default 4)." )
45 #define SILENCE_TEXT N_("Defines if silence alarm information should be sent")
46 #define SILENCE_LONGTEXT N_("Defines if silence alarm information should be sent. "\
47                 "1 if the information should be sent, 0 otherwise (default 1)." )
48 #define TIME_WINDOW_TEXT N_("Time window to use in ms")
49 #define TIME_WINDOW_LONGTEXT N_("Time Window during when the audio level is measured in ms for silence detection. "\
50                 "If the audio level is under the threshold during this time, "\
51                 "an alarm is sent (default 5000)." )
52 #define ALARM_THRESHOLD_TEXT N_("Minimum Audio level to raise the alarm")
53 #define ALARM_THRESHOLD_LONGTEXT N_("Threshold to be attained to raise an alarm. "\
54                 "If the audio level is under the threshold during this time, "\
55                 "an alarm is sent (default 0.1)." )
56 #define REPETITION_TIME_TEXT N_("Time between two alarm messages in ms" )
57 #define REPETITION_TIME_LONGTEXT N_("Time between two alarm messages in ms. "\
58                 "This value is used to avoid alarm saturation (default 2000)." )
59
60 #define CFG_PREFIX "audiobargraph_a-"
61
62 /*****************************************************************************
63  * Module descriptor
64  *****************************************************************************/
65 static int  Open( vlc_object_t * );
66 static void Close( vlc_object_t * );
67 static block_t *DoWork( filter_t *, block_t * );
68
69 vlc_module_begin ()
70     set_description( N_("Audio part of the BarGraph function") )
71     set_shortname( N_("Audiobar Graph") )
72     set_capability( "audio filter", 0 )
73     set_category( CAT_AUDIO )
74     set_subcategory( SUBCAT_AUDIO_AFILTER )
75
76     add_obsolete_string( CFG_PREFIX "address" )
77     add_obsolete_integer( CFG_PREFIX "port" )
78     add_integer( CFG_PREFIX "bargraph", 1, BARGRAPH_TEXT, BARGRAPH_LONGTEXT, false ) // FIXME: this is a bool
79     add_integer( CFG_PREFIX "bargraph_repetition", 4, BARGRAPH_REPETITION_TEXT, BARGRAPH_REPETITION_LONGTEXT, false )
80     add_integer( CFG_PREFIX "silence", 1, SILENCE_TEXT, SILENCE_LONGTEXT, false ) // FIXME: this is a bool
81     add_integer( CFG_PREFIX "time_window", 5000, TIME_WINDOW_TEXT, TIME_WINDOW_LONGTEXT, false )
82     add_float( CFG_PREFIX "alarm_threshold", 0.1, ALARM_THRESHOLD_TEXT, ALARM_THRESHOLD_LONGTEXT, false )
83     add_integer( CFG_PREFIX "repetition_time", 2000, REPETITION_TIME_TEXT, REPETITION_TIME_LONGTEXT, false )
84     add_obsolete_integer( CFG_PREFIX "connection_reset" )
85
86     set_callbacks( Open, Close )
87 vlc_module_end ()
88
89 typedef struct ValueDate_t {
90     float value;
91     mtime_t date;
92     struct ValueDate_t* next;
93 } ValueDate_t;
94
95 struct filter_sys_t
96 {
97     bool            bargraph;
98     int             bargraph_repetition;
99     bool            silence;
100     int64_t         time_window;
101     float           alarm_threshold;
102     int64_t         repetition_time;
103     int             counter;
104     ValueDate_t*    first;
105     ValueDate_t*    last;
106     int             started;
107     mtime_t         lastAlarm;
108 };
109
110 /*****************************************************************************
111  * Open: open the visualizer
112  *****************************************************************************/
113 static int Open( vlc_object_t *p_this )
114 {
115     filter_t     *p_filter = (filter_t *)p_this;
116     filter_sys_t *p_sys = p_filter->p_sys = malloc(sizeof(*p_sys));
117     if (!p_sys)
118         return VLC_ENOMEM;
119
120     static const char *const options[] = {
121         "bargraph", "bargraph_repetition", "silence", "time_window",
122         "alarm_threshold", "repetition_time", NULL
123     };
124     config_ChainParse(p_filter, CFG_PREFIX, options, p_filter->p_cfg);
125
126     p_sys->bargraph = !!var_CreateGetInteger(p_filter, CFG_PREFIX "bargraph");
127     p_sys->bargraph_repetition = var_CreateGetInteger(p_filter, CFG_PREFIX "bargraph_repetition");
128     p_sys->silence = !!var_CreateGetInteger(p_filter, CFG_PREFIX "silence");
129     p_sys->time_window = var_CreateGetInteger(p_filter, CFG_PREFIX "time_window") * 1000;
130     p_sys->alarm_threshold = var_CreateGetFloat(p_filter, CFG_PREFIX "alarm_threshold");
131     p_sys->repetition_time = var_CreateGetInteger(p_filter, CFG_PREFIX "repetition_time") * 1000;
132     p_sys->counter = 0;
133     p_sys->first = NULL;
134     p_sys->last = NULL;
135     p_sys->started = 0;
136     p_sys->lastAlarm = 0;
137
138     p_filter->fmt_in.audio.i_format = VLC_CODEC_FL32;
139     p_filter->fmt_out.audio = p_filter->fmt_in.audio;
140     p_filter->pf_audio_filter = DoWork;
141
142     var_Create(p_filter->p_libvlc, "audiobargraph_v-alarm", VLC_VAR_BOOL);
143     var_Create(p_filter->p_libvlc, "audiobargraph_v-i_values", VLC_VAR_STRING);
144
145     return VLC_SUCCESS;
146 }
147
148 static void SendValues(filter_t *p_filter, float *value, int nbChannels)
149 {
150     char msg[256];
151     size_t len = 0;
152
153     for (int i = 0; i < nbChannels; i++) {
154         if (len >= sizeof (msg))
155             break;
156         len += snprintf(msg + len, sizeof (msg) - len, "%f:", value[i]);
157     }
158
159     //msg_Dbg(p_filter, "values: %s", message);
160     var_SetString(p_filter->p_libvlc, "audiobargraph_v-i_values", msg);
161 }
162
163 /*****************************************************************************
164  * DoWork: treat an audio buffer
165  ****************************************************************************/
166 static block_t *DoWork( filter_t *p_filter, block_t *p_in_buf )
167 {
168     filter_sys_t *p_sys = p_filter->p_sys;
169     float *p_sample = (float *)p_in_buf->p_buffer;
170     float i_value[AOUT_CHAN_MAX];
171
172     int nbChannels = aout_FormatNbChannels(&p_filter->fmt_in.audio);
173
174     for (int i = 0; i < nbChannels; i++)
175         i_value[i] = 0.;
176
177     /* 1 - Compute the peak values */
178     float max = 0.0;
179     for (size_t i = 0; i < p_in_buf->i_nb_samples; i++) {
180         for (int j = 0; j<nbChannels; j++) {
181             float ch = (*p_sample++);
182             if (ch > i_value[j])
183                 i_value[j] = ch;
184             if (ch > max)
185                 max = ch;
186         }
187     }
188     max *= max;
189
190     if (p_sys->silence) {
191         /* 2 - store the new value */
192         ValueDate_t *new = xmalloc(sizeof(*new));
193         new->value = max;
194         new->date = p_in_buf->i_pts;
195         new->next = NULL;
196         if (p_sys->last != NULL)
197             p_sys->last->next = new;
198         p_sys->last = new;
199         if (p_sys->first == NULL)
200             p_sys->first = new;
201
202         /* 3 - delete too old values */
203         while (p_sys->first->date < new->date - p_sys->time_window) {
204             p_sys->started = 1; // we have enough values to compute a valid total
205             ValueDate_t *current = p_sys->first;
206             p_sys->first = p_sys->first->next;
207             free(current);
208         }
209
210         /* If last message was sent enough time ago */
211         if (p_sys->started && p_in_buf->i_pts > p_sys->lastAlarm + p_sys->repetition_time) {
212
213             /* 4 - compute the RMS */
214             ValueDate_t *current = p_sys->first;
215             float sum = 0.0;
216             int count = 0;
217             while (current != NULL) {
218                 sum += current->value;
219                 count++;
220                 current = current->next;
221             }
222             sum /= count;
223             sum = sqrtf(sum);
224
225             /* 5 - compare it to the threshold */
226             var_SetBool(p_filter->p_libvlc, "audiobargraph_v-alarm",
227                         sum < p_sys->alarm_threshold);
228
229             p_sys->lastAlarm = p_in_buf->i_pts;
230         }
231     }
232
233     if (p_sys->bargraph && nbChannels > 0 && p_sys->counter++ > p_sys->bargraph_repetition) {
234         SendValues(p_filter, i_value, nbChannels);
235         p_sys->counter = 0;
236     }
237
238     return p_in_buf;
239 }
240
241 /*****************************************************************************
242  * Close: close the plugin
243  *****************************************************************************/
244 static void Close( vlc_object_t *p_this )
245 {
246     filter_t * p_filter = (filter_t *)p_this;
247     filter_sys_t *p_sys = p_filter->p_sys;
248
249     var_Destroy(p_filter->p_libvlc, "audiobargraph_v-i_values");
250     var_Destroy(p_filter->p_libvlc, "audiobargraph_v-alarm");
251
252     while (p_sys->first != NULL) {
253         ValueDate_t *current = p_sys->first;
254         p_sys->first = p_sys->first->next;
255         free(current);
256     }
257     free(p_sys);
258 }