]> git.sesse.net Git - vlc/blob - modules/audio_filter/audiobargraph_a.c
Use var_Inherit* instead of var_CreateGet*.
[vlc] / modules / audio_filter / audiobargraph_a.c
1 /*****************************************************************************
2  * audiobargraph_a.c : audiobargraph audio plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2002-2006 the VideoLAN team
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
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 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 General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, 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 <vlc_network.h>
38 #include <math.h>
39
40
41
42 #define ADDRESS_TEXT N_("TCP address to use (default localhost)")
43 #define ADDRESS_LONGTEXT N_("TCP address to use to communicate with the video "\
44                 "part of the Bar Graph (default localhost)." \
45                 "In the case of bargraph incrustation, use localhost." )
46 #define PORT_TEXT N_("TCP port to use (default 12345)")
47 #define PORT_LONGTEXT N_("TCP port to use to communicate with the video "\
48                 "part of the Bar Graph (default 12345)." \
49                 "Use the same port as the one used in the rc interface." )
50 #define BARGRAPH_TEXT N_("Defines if BarGraph information should be sent (default 1)")
51 #define BARGRAPH_LONGTEXT N_("Defines if BarGraph information should be sent. "\
52                 "1 if the information should be sent, 0 otherwise (default 1)." )
53 #define BARGRAPH_REPETITION_TEXT N_("Sends the barGraph information every n audio packets (default 4)")
54 #define BARGRAPH_REPETITION_LONGTEXT N_("Defines how often the barGraph information should be sent. "\
55                 "Sends the barGraph information every n audio packets (default 4)." )
56 #define SILENCE_TEXT N_("Defines if silence alarm information should be sent (default 1)")
57 #define SILENCE_LONGTEXT N_("Defines if silence alarm information should be sent. "\
58                 "1 if the information should be sent, 0 otherwise (default 1)." )
59 #define TIME_WINDOW_TEXT N_("Time window to use in ms (default 5000)")
60 #define TIME_WINDOW_LONGTEXT N_("Time Window during when the audio level is measured in ms for silence detection. "\
61                 "If the audio level is under the threshold during this time, "\
62                 "an alarm is sent (default 5000)." )
63 #define ALARM_THRESHOLD_TEXT N_("Minimum Audio level to raise the alarm (default 0.1)")
64 #define ALARM_THRESHOLD_LONGTEXT N_("Threshold to be attained to raise an alarm. "\
65                 "If the audio level is under the threshold during this time, "\
66                 "an alarm is sent (default 0.1)." )
67 #define REPETITION_TIME_TEXT N_("Time between two alarm messages in ms (default 2000)" )
68 #define REPETITION_TIME_LONGTEXT N_("Time between two alarm messages in ms. "\
69                 "This value is used to avoid alarm saturation (default 2000)." )
70 #define CONNECTION_RESET_TEXT N_("Force connection reset regularly (default 1)" )
71 #define CONNECTION_RESET_LONGTEXT N_("Defines if the TCP connection should be reset. "\
72                 "This is to be used when using with audiobargraph_v (default 1)." )
73
74 #define CFG_PREFIX "audiobargraph_a-"
75
76 /*****************************************************************************
77  * Module descriptor
78  *****************************************************************************/
79 static int  Open( vlc_object_t * );
80 static void Close( vlc_object_t * );
81 static block_t *DoWork( filter_t *, block_t * );
82
83 vlc_module_begin ()
84     set_description( N_("Audio part of the BarGraph function") )
85     set_shortname( N_("audiobargraph_a") )
86     set_capability( "audio filter", 0 )
87     set_category( CAT_AUDIO )
88     set_subcategory( SUBCAT_AUDIO_AFILTER )
89     
90     add_string( CFG_PREFIX "address", "localhost", NULL, ADDRESS_TEXT, ADDRESS_LONGTEXT, false )
91     add_integer( CFG_PREFIX "port", 12345, NULL, PORT_TEXT, PORT_LONGTEXT, false )
92     add_integer( CFG_PREFIX "bargraph", 1, NULL, BARGRAPH_TEXT, BARGRAPH_LONGTEXT, false )
93     add_integer( CFG_PREFIX "bargraph_repetition", 4, NULL, BARGRAPH_REPETITION_TEXT, BARGRAPH_REPETITION_LONGTEXT, false )
94     add_integer( CFG_PREFIX "silence", 1, NULL, SILENCE_TEXT, SILENCE_LONGTEXT, false )
95     add_integer( CFG_PREFIX "time_window", 5000, NULL, TIME_WINDOW_TEXT, TIME_WINDOW_LONGTEXT, false )
96     add_float( CFG_PREFIX "alarm_threshold", 0.1, NULL, ALARM_THRESHOLD_TEXT, ALARM_THRESHOLD_LONGTEXT, false )
97     add_integer( CFG_PREFIX "repetition_time", 2000, NULL, REPETITION_TIME_TEXT, REPETITION_TIME_LONGTEXT, false )
98     add_integer( CFG_PREFIX "connection_reset", 1, NULL, CONNECTION_RESET_TEXT, CONNECTION_RESET_LONGTEXT, false )
99     
100     set_callbacks( Open, Close )
101 vlc_module_end ()
102
103 typedef struct ValueDate_t {
104     float value;
105     mtime_t date;
106     struct ValueDate_t* next;
107 } ValueDate_t;
108
109 struct filter_sys_t
110 {
111     char*           address;
112     int             port;
113     int             bargraph;
114     int             bargraph_repetition;
115     int             silence;
116     int             time_window;
117     float           alarm_threshold;
118     int             repetition_time;
119     int             connection_reset;
120     int             TCPconnection;
121     int             counter;
122     int             nbChannels;
123     ValueDate_t*    first;
124     ValueDate_t*    last;
125     int             started;
126     mtime_t         lastAlarm;
127 };
128
129 /*****************************************************************************
130  * Open: open the visualizer
131  *****************************************************************************/
132 static int Open( vlc_object_t *p_this )
133 {
134     filter_t     *p_filter = (filter_t *)p_this;
135     filter_sys_t *p_sys;
136
137     if ( !AOUT_FMTS_SIMILAR( &p_filter->fmt_in.audio, &p_filter->fmt_out.audio ) )
138     {
139         msg_Err( p_filter, "input and output formats are not similar" );
140         return VLC_EGENERIC;
141     }
142
143     if( p_filter->fmt_in.audio.i_format != VLC_CODEC_FL32 ||
144         p_filter->fmt_out.audio.i_format != VLC_CODEC_FL32 )
145     {
146         p_filter->fmt_in.audio.i_format = VLC_CODEC_FL32;
147         p_filter->fmt_out.audio.i_format = VLC_CODEC_FL32;
148         msg_Warn( p_filter, "bad input or output format" );
149     }
150
151     p_filter->pf_audio_filter = DoWork;
152
153     p_sys = p_filter->p_sys = malloc( sizeof( *p_sys ) );
154     if( !p_sys )
155         return VLC_ENOMEM;
156         
157     p_sys->bargraph = var_CreateGetIntegerCommand( p_filter, "audiobargraph_a-bargraph" );
158     p_sys->bargraph_repetition = var_CreateGetIntegerCommand( p_filter, "audiobargraph_a-bargraph_repetition" );
159     p_sys->silence = var_CreateGetIntegerCommand( p_filter, "audiobargraph_a-silence" );
160     p_sys->address = var_CreateGetStringCommand( p_filter, "audiobargraph_a-address" );
161     p_sys->port = var_CreateGetIntegerCommand( p_filter, "audiobargraph_a-port" );
162     p_sys->time_window = var_CreateGetIntegerCommand( p_filter, "audiobargraph_a-time_window" );
163     p_sys->alarm_threshold = var_CreateGetFloatCommand( p_filter, "audiobargraph_a-alarm_threshold" );
164     p_sys->repetition_time = var_CreateGetIntegerCommand( p_filter, "audiobargraph_a-repetition_time" );
165     p_sys->connection_reset = var_CreateGetIntegerCommand( p_filter, "audiobargraph_a-connection_reset" );
166     if ((p_sys->TCPconnection = net_ConnectTCP(p_this,p_sys->address,p_sys->port)) == -1) {
167         free(p_sys);
168         return VLC_EGENERIC;
169     }
170     p_sys->counter = 0;
171     p_sys->nbChannels = 0;
172     p_sys->first = NULL;
173     p_sys->last = NULL;
174     p_sys->started = 0;
175     p_sys->lastAlarm = 0;
176
177     return VLC_SUCCESS;
178 }
179
180 /*****************************************************************************
181  * DoWork: treat an audio buffer
182  ****************************************************************************/
183 static block_t *DoWork( filter_t *p_filter, block_t *p_in_buf )
184 {
185     filter_sys_t *p_sys = p_filter->p_sys;
186     int i, j;
187     float *p_sample = (float *)p_in_buf->p_buffer;
188     float *i_value = NULL;
189     float ch;
190     float max = 0.0;
191     //char *message = (char*)malloc(255*sizeof(char));
192     char message[255];
193     int nbChannels = 0;
194     ValueDate_t* new = NULL;
195     ValueDate_t* current = NULL;
196     float sum;
197     int count = 0;
198     int i_ret;
199     
200     nbChannels = aout_FormatNbChannels( &p_filter->fmt_in.audio );
201     p_sys->nbChannels = nbChannels;
202     
203     i_value = (float*)malloc(nbChannels * sizeof(float));
204     
205     for (i=0; i<nbChannels; i++) {
206         i_value[i] = 0;
207     }
208     
209     /* 1 - Compute the peack values */
210     for ( i = 0 ; i < (int)(p_in_buf->i_nb_samples); i++ )
211     {
212         for (j=0; j<nbChannels; j++) {
213             ch = (*p_sample++);
214             if (ch > i_value[j])
215                 i_value[j] = ch;
216             if (ch > max)
217                 max = ch;
218         }
219     }
220     max = pow( max, 2 );
221     
222     if (p_sys->silence) {
223         /* 2 - store the new value */
224         new = (ValueDate_t*)malloc(sizeof(ValueDate_t));
225         new->value = max;
226         new->date = p_in_buf->i_pts;
227         new->next = NULL;
228         if (p_sys->last != NULL) {
229             p_sys->last->next = new;
230         }
231         p_sys->last = new;
232         if (p_sys->first == NULL) {
233             p_sys->first = new;
234         }
235         
236         /* 3 - delete too old values */
237         while (p_sys->first->date < (new->date - (p_sys->time_window*1000))) {
238             p_sys->started = 1; // we have enough values to compute a valid total
239             current = p_sys->first;
240             p_sys->first = p_sys->first->next;
241             free(current);
242         }
243         
244         /* If last message was sent enough time ago */
245         if ((p_sys->started) && (p_in_buf->i_pts > p_sys->lastAlarm + (p_sys->repetition_time*1000))) {
246             
247             /* 4 - compute the RMS */
248             current = p_sys->first;
249             sum = 0.0;
250             while (current != NULL) {
251                 sum += current->value;
252                 count ++;
253                 current = current->next;
254             }
255             sum = sum / count;
256             sum = sqrt(sum);
257         
258             /* 5 - compare it to the threshold */
259             if (sum < p_sys->alarm_threshold) {
260                 i=1;
261             } else {
262                 i=0;
263             }
264             snprintf(message,255,"@audiobargraph_v audiobargraph_v-alarm %d\n",i);
265             
266             msg_Dbg( p_filter, "message alarm : %s", message );
267             //TCPconnection = net_ConnectTCP(p_filter,p_sys->address,p_sys->port);
268             net_Write(p_filter, p_sys->TCPconnection, NULL, message, strlen(message));
269             //net_Close(TCPconnection);
270             
271             p_sys->lastAlarm = p_in_buf->i_pts;
272         }
273     }
274
275     /*for (i=0; i<nbChannels; i++) {
276         value[i] = abs(i_value[i]*100);
277         if ( value[i] > p_sys->value[i] - 6 )
278             p_sys->value[i] = value[i];
279         else
280             p_sys->value[i] = p_sys->value[i] - 6;
281     }*/
282     
283     if (p_sys->bargraph) {
284         /* 6 - sent the message with the values for the BarGraph */
285         if ((nbChannels > 0) && (p_sys->counter%(p_sys->bargraph_repetition) == 0)) {
286             j=snprintf(message,255,"@audiobargraph_v audiobargraph_v-i_values ");
287             for (i=0; i<(nbChannels-1); i++) {
288                 j+=snprintf(message+j,255,"%f:", i_value[i]);
289             }
290             snprintf(message+j,255,"%f\n", i_value[nbChannels-1]);
291             msg_Dbg( p_filter, "message values : %s", message );
292
293             //test = send(p_sys->TCPconnection,message,strlen(message),0);
294             //net_Write(p_filter, p_sys->TCPconnection, NULL, message, strlen(message));
295
296             i_ret= net_Write(p_filter, p_sys->TCPconnection, NULL, message, strlen(message));
297
298         }
299     }
300     
301     free(i_value);
302     
303     if (p_sys->counter > p_sys->bargraph_repetition*100) {
304         if (p_sys->connection_reset) {
305             net_Close(p_sys->TCPconnection);
306             p_sys->TCPconnection = net_ConnectTCP(p_filter,p_sys->address,p_sys->port);
307         }
308         p_sys->counter = 0;
309     }
310     
311     //free(message);
312     p_sys->counter++;
313     
314     return p_in_buf;
315 }
316
317 /*****************************************************************************
318  * Close: close the plugin
319  *****************************************************************************/
320 static void Close( vlc_object_t *p_this )
321 {
322     filter_t * p_filter = (filter_t *)p_this;
323     filter_sys_t *p_sys = p_filter->p_sys;
324     ValueDate_t* current;
325     
326     p_sys->last = NULL;
327     while (p_sys->first != NULL) {
328         current = p_sys->first;
329         p_sys->first = p_sys->first->next;
330         free(current);
331     }
332     net_Close(p_sys->TCPconnection);
333     free(p_sys->address);
334     //free(p_sys->value);
335     free( p_filter->p_sys );
336 }