]> git.sesse.net Git - vlc/blob - modules/audio_filter/audiobargraph_a.c
macosx: reimplement 'fullscreen video device' (fixes #5831)
[vlc] / modules / audio_filter / audiobargraph_a.c
1 /*****************************************************************************
2  * audiobargraph_a.c : audiobargraph audio plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2002-2009 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 #define ADDRESS_TEXT N_("TCP address to use (default localhost)")
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 (default 12345)")
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 (default 1)")
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 (default 4)")
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 (default 1)")
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 (default 5000)")
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 (default 0.1)")
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 (default 2000)" )
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 (default 1)" )
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;
134
135     if ( !AOUT_FMTS_SIMILAR( &p_filter->fmt_in.audio, &p_filter->fmt_out.audio ) )
136     {
137         msg_Err( p_filter, "input and output formats are not similar" );
138         return VLC_EGENERIC;
139     }
140
141     if( p_filter->fmt_in.audio.i_format != VLC_CODEC_FL32 ||
142         p_filter->fmt_out.audio.i_format != VLC_CODEC_FL32 )
143     {
144         p_filter->fmt_in.audio.i_format = VLC_CODEC_FL32;
145         p_filter->fmt_out.audio.i_format = VLC_CODEC_FL32;
146         msg_Warn( p_filter, "bad input or output format" );
147     }
148
149     p_filter->pf_audio_filter = DoWork;
150
151     p_sys = p_filter->p_sys = malloc( sizeof( *p_sys ) );
152     if( !p_sys )
153         return VLC_ENOMEM;
154
155     p_sys->bargraph = var_CreateGetIntegerCommand( p_filter, "audiobargraph_a-bargraph" );
156     p_sys->bargraph_repetition = var_CreateGetIntegerCommand( p_filter, "audiobargraph_a-bargraph_repetition" );
157     p_sys->silence = var_CreateGetIntegerCommand( p_filter, "audiobargraph_a-silence" );
158     p_sys->address = var_CreateGetStringCommand( p_filter, "audiobargraph_a-address" );
159     p_sys->port = var_CreateGetIntegerCommand( p_filter, "audiobargraph_a-port" );
160     p_sys->time_window = var_CreateGetIntegerCommand( p_filter, "audiobargraph_a-time_window" );
161     p_sys->alarm_threshold = var_CreateGetFloatCommand( p_filter, "audiobargraph_a-alarm_threshold" );
162     p_sys->repetition_time = var_CreateGetIntegerCommand( p_filter, "audiobargraph_a-repetition_time" );
163     p_sys->connection_reset = var_CreateGetIntegerCommand( p_filter, "audiobargraph_a-connection_reset" );
164     if ((p_sys->TCPconnection = net_ConnectTCP(p_this,p_sys->address,p_sys->port)) == -1) {
165         free(p_sys);
166         return VLC_EGENERIC;
167     }
168     p_sys->counter = 0;
169     p_sys->nbChannels = 0;
170     p_sys->first = NULL;
171     p_sys->last = NULL;
172     p_sys->started = 0;
173     p_sys->lastAlarm = 0;
174
175     return VLC_SUCCESS;
176 }
177
178 /*****************************************************************************
179  * DoWork: treat an audio buffer
180  ****************************************************************************/
181 static block_t *DoWork( filter_t *p_filter, block_t *p_in_buf )
182 {
183     filter_sys_t *p_sys = p_filter->p_sys;
184     int i, j;
185     float *p_sample = (float *)p_in_buf->p_buffer;
186     float *i_value = NULL;
187     float ch;
188     float max = 0.0;
189     //char *message = (char*)malloc(255*sizeof(char));
190     char message[255];
191     int nbChannels = 0;
192     ValueDate_t* new = NULL;
193     ValueDate_t* current = NULL;
194     float sum;
195     int count = 0;
196
197     nbChannels = aout_FormatNbChannels( &p_filter->fmt_in.audio );
198     p_sys->nbChannels = nbChannels;
199
200     i_value = (float*)malloc(nbChannels * sizeof(float));
201
202     for (i=0; i<nbChannels; i++) {
203         i_value[i] = 0;
204     }
205
206     /* 1 - Compute the peack values */
207     for ( i = 0 ; i < (int)(p_in_buf->i_nb_samples); i++ )
208     {
209         for (j=0; j<nbChannels; j++) {
210             ch = (*p_sample++);
211             if (ch > i_value[j])
212                 i_value[j] = ch;
213             if (ch > max)
214                 max = ch;
215         }
216     }
217     max = pow( max, 2 );
218
219     if (p_sys->silence) {
220         /* 2 - store the new value */
221         new = (ValueDate_t*)malloc(sizeof(ValueDate_t));
222         new->value = max;
223         new->date = p_in_buf->i_pts;
224         new->next = NULL;
225         if (p_sys->last != NULL) {
226             p_sys->last->next = new;
227         }
228         p_sys->last = new;
229         if (p_sys->first == NULL) {
230             p_sys->first = new;
231         }
232
233         /* 3 - delete too old values */
234         while (p_sys->first->date < (new->date - (p_sys->time_window*1000))) {
235             p_sys->started = 1; // we have enough values to compute a valid total
236             current = p_sys->first;
237             p_sys->first = p_sys->first->next;
238             free(current);
239         }
240
241         /* If last message was sent enough time ago */
242         if ((p_sys->started) && (p_in_buf->i_pts > p_sys->lastAlarm + (p_sys->repetition_time*1000))) {
243
244             /* 4 - compute the RMS */
245             current = p_sys->first;
246             sum = 0.0;
247             while (current != NULL) {
248                 sum += current->value;
249                 count ++;
250                 current = current->next;
251             }
252             sum = sum / count;
253             sum = sqrt(sum);
254
255             /* 5 - compare it to the threshold */
256             if (sum < p_sys->alarm_threshold) {
257                 i=1;
258             } else {
259                 i=0;
260             }
261             snprintf(message,255,"@audiobargraph_v audiobargraph_v-alarm %d\n",i);
262
263             msg_Dbg( p_filter, "message alarm : %s", message );
264             //TCPconnection = net_ConnectTCP(p_filter,p_sys->address,p_sys->port);
265             net_Write(p_filter, p_sys->TCPconnection, NULL, message, strlen(message));
266             //net_Close(TCPconnection);
267
268             p_sys->lastAlarm = p_in_buf->i_pts;
269         }
270     }
271
272     /*for (i=0; i<nbChannels; i++) {
273         value[i] = abs(i_value[i]*100);
274         if ( value[i] > p_sys->value[i] - 6 )
275             p_sys->value[i] = value[i];
276         else
277             p_sys->value[i] = p_sys->value[i] - 6;
278     }*/
279
280     if (p_sys->bargraph) {
281         /* 6 - sent the message with the values for the BarGraph */
282         if ((nbChannels > 0) && (p_sys->counter%(p_sys->bargraph_repetition) == 0)) {
283             j=snprintf(message,255,"@audiobargraph_v audiobargraph_v-i_values ");
284             for (i=0; i<(nbChannels-1); i++) {
285                 j+=snprintf(message+j,255,"%f:", i_value[i]);
286             }
287             snprintf(message+j,255,"%f\n", i_value[nbChannels-1]);
288             msg_Dbg( p_filter, "message values : %s", message );
289
290             //test = send(p_sys->TCPconnection,message,strlen(message),0);
291             //net_Write(p_filter, p_sys->TCPconnection, NULL, message, strlen(message));
292
293             net_Write(p_filter, p_sys->TCPconnection, NULL, message, strlen(message));
294
295         }
296     }
297
298     free(i_value);
299
300     if (p_sys->counter > p_sys->bargraph_repetition*100) {
301         if (p_sys->connection_reset) {
302             net_Close(p_sys->TCPconnection);
303             p_sys->TCPconnection = net_ConnectTCP(p_filter,p_sys->address,p_sys->port);
304         }
305         p_sys->counter = 0;
306     }
307
308     //free(message);
309     p_sys->counter++;
310
311     return p_in_buf;
312 }
313
314 /*****************************************************************************
315  * Close: close the plugin
316  *****************************************************************************/
317 static void Close( vlc_object_t *p_this )
318 {
319     filter_t * p_filter = (filter_t *)p_this;
320     filter_sys_t *p_sys = p_filter->p_sys;
321     ValueDate_t* current;
322
323     p_sys->last = NULL;
324     while (p_sys->first != NULL) {
325         current = p_sys->first;
326         p_sys->first = p_sys->first->next;
327         free(current);
328     }
329     net_Close(p_sys->TCPconnection);
330     free(p_sys->address);
331     //free(p_sys->value);
332     free( p_filter->p_sys );
333 }