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