Various warning cleanups
[asterisk/asterisk.git] / apps / app_record.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Trivial application to record a sound file
5  * 
6  * Copyright (C) 2001, Linux Support Services, Inc.
7  *
8  * Matthew Fredrickson <creslin@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13  
14 #include <asterisk/lock.h>
15 #include <asterisk/file.h>
16 #include <asterisk/logger.h>
17 #include <asterisk/channel.h>
18 #include <asterisk/pbx.h>
19 #include <asterisk/module.h>
20 #include <asterisk/translate.h>
21 #include <asterisk/dsp.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <pthread.h>
25
26 static char *tdesc = "Trivial Record Application";
27
28 static char *app = "Record";
29
30 static char *synopsis = "Record to a file";
31
32 static char *descrip = 
33 "  Record(filename:extension|silence): Records from the  channel into a given\n"
34 "filename. If the file exists it will be overwritten. The 'extension'\n"
35 "is the extension of the file type  to  be  recorded (wav, gsm, etc).\n"
36 "'silence' is the number of seconds of silence to allow before returning.\n"
37 "Returns -1 when the user hangs up.\n";
38
39 STANDARD_LOCAL_USER;
40
41 LOCAL_USER_DECL;
42
43 static int record_exec(struct ast_channel *chan, void *data)
44 {
45         int res = 0;
46         int count = 0;
47         int percentflag = 0;
48         char fil[256];
49         char tmp[256];
50         char ext[10];
51         char * vdata;  /* Used so I don't have to typecast every use of *data */
52         int i = 0;
53         int j = 0;
54
55         struct ast_filestream *s = '\0';
56         struct localuser *u;
57         struct ast_frame *f = NULL;
58         
59         struct ast_dsp *sildet = NULL;          /* silence detector dsp */
60         int totalsilence = 0;
61         int dspsilence = 0;
62         int silence = 0;                /* amount of silence to allow */
63         int gotsilence = 0;             /* did we timeout for silence? */
64         char silencestr[5];
65         int k = 0;
66         int rfmt = 0;
67
68         vdata = data; /* explained above */
69
70         /* The next few lines of code parse out the filename and header from the input string */
71         if (!vdata) { /* no data implies no filename or anything is present */
72                 ast_log(LOG_WARNING, "Record requires an argument (filename)\n");
73                 return -1;
74         }
75         
76         for (; vdata[i] && (vdata[i] != ':') && (vdata[i] != '|'); i++ ) {
77                 if ((vdata[i] == '%') && (vdata[i+1] == 'd')) {
78                         percentflag = 1;                      /* the wildcard is used */
79                 }
80                 
81                 if (i == strlen(vdata) ) {
82                         ast_log(LOG_WARNING, "No extension found\n");
83                         return -1;
84                 }
85                 fil[i] = vdata[i];
86         }
87         fil[i++] = '\0';
88
89         for (; j < 10 && i < strlen(data) && (vdata[i] != '|'); i++, j++)
90                 ext[j] = vdata[i];
91         ext[j] = '\0';
92
93         if (vdata[i] && (vdata[i] == '|')) i++;
94         for (; vdata[i] && (vdata[i] != '|') && (k < 3) && i < strlen(data); i++, k++)
95                 silencestr[k] = vdata[i];
96         silencestr[k] = '\0';
97
98         if (silencestr) {
99                 silence = atoi(silencestr);
100                 if (silence > 0)
101                         silence *= 1000;
102         }
103
104         /* done parsing */
105         
106         
107         /* these are to allow the use of the %d in the config file for a wild card of sort to
108           create a new file with the inputed name scheme */
109         if (percentflag) {
110                 do {
111                         snprintf(tmp, 256, fil, count);
112                         count++;
113                 } while ( ast_fileexists(tmp, ext, chan->language) != -1 );
114         } else
115                 strncpy(tmp, fil, 256-1);
116         /* end of routine mentioned */
117
118         LOCAL_USER_ADD(u);
119
120         if (chan->_state != AST_STATE_UP) {
121                 res = ast_answer(chan); /* Shouldn't need this, but checking to see if channel is already answered
122                                          * Theoretically asterisk should already have answered before running the app */
123         }
124         
125         if (!res) {
126                 /* Some code to play a nice little beep to signify the start of the record operation */
127                 res = ast_streamfile(chan, "beep", chan->language);
128                 if (!res) {
129                         res = ast_waitstream(chan, "");
130                 } else {
131                         ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", chan->name);
132                 }
133                 ast_stopstream(chan);
134
135                 /* The end of beep code.  Now the recording starts */
136
137
138                 if (silence > 0) {
139                         rfmt = chan->readformat;
140                         res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
141                         if (res < 0) {
142                                 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
143                                 return -1;
144                         }
145                         sildet = ast_dsp_new();
146                         if (!sildet) {
147                                 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
148                                 return -1;
149                         }
150                         ast_dsp_set_threshold(sildet, 256);
151                 }
152
153                 s = ast_writefile( tmp, ext, NULL, O_CREAT|O_TRUNC|O_WRONLY , 0, 0644);
154         
155                 if (s) {
156                         while (ast_waitfor(chan, -1) > -1) {
157                                 f = ast_read(chan);
158                                 if (!f) {
159                                         res = -1;
160                                         break;
161                                 }
162                                 if (f->frametype == AST_FRAME_VOICE) {
163                                         res = ast_writestream(s, f);
164                                         
165                                         if (res) {
166                                                 ast_log(LOG_WARNING, "Problem writing frame\n");
167                                                 break;
168                                         }
169
170                                         if (silence > 0) {
171                                                 dspsilence = 0;
172                                                 ast_dsp_silence(sildet, f, &dspsilence);
173                                                 if (dspsilence) {
174                                                         totalsilence = dspsilence;
175                                                 } else {
176                                                         totalsilence = 0;
177                                                 }
178                                                 if (totalsilence > silence) {
179                                                         /* Ended happily with silence */
180                                                         ast_frfree(f);
181                                                         gotsilence = 1;
182                                                         break;
183                                                 }
184                                         }
185                                 }
186                                 if (f->frametype == AST_FRAME_VIDEO) {
187                                         res = ast_writestream(s, f);
188                                         
189                                         if (res) {
190                                                 ast_log(LOG_WARNING, "Problem writing frame\n");
191                                                 break;
192                                         }
193                                 }
194                                 if ((f->frametype == AST_FRAME_DTMF) &&
195                                         (f->subclass == '#')) {
196                                         ast_frfree(f);
197                                         break;
198                                 }
199                                 ast_frfree(f);
200                         }
201                         if (!f) {
202                                         ast_log(LOG_DEBUG, "Got hangup\n");
203                                         res = -1;
204                         }
205
206                         if (gotsilence) {
207                                 ast_stream_rewind(s, silence-1000);
208                                 ast_truncstream(s);
209                         } else {
210                                 /* Strip off the last 1/4 second of it */
211                                 ast_stream_rewind(s, 250);
212                                 ast_truncstream(s);
213                         }
214                         ast_closestream(s);
215                 } else                  
216                         ast_log(LOG_WARNING, "Could not create file %s\n", fil);
217         } else
218                 ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name);
219
220         LOCAL_USER_REMOVE(u);
221         if (silence > 0) {
222                 res = ast_set_read_format(chan, rfmt);
223                 if (res)
224                         ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
225                 if (sildet)
226                         ast_dsp_free(sildet);
227         }
228         return res;
229 }
230
231 int unload_module(void)
232 {
233         STANDARD_HANGUP_LOCALUSERS;
234         return ast_unregister_application(app);
235 }
236
237 int load_module(void)
238 {
239         return ast_register_application(app, record_exec, synopsis, descrip);
240 }
241
242 char *description(void)
243 {
244         return tdesc;
245 }
246
247 int usecount(void)
248 {
249         int res;
250         STANDARD_USECOUNT(res);
251         return res;
252 }
253
254 char *key()
255 {
256         return ASTERISK_GPL_KEY;
257 }