Totally redo file formats
[asterisk/asterisk.git] / formats / format_mp3.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Everybody's favorite format: MP3 Files!  Yay!
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@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/channel.h>
16 #include <asterisk/file.h>
17 #include <asterisk/logger.h>
18 #include <asterisk/sched.h>
19 #include <asterisk/module.h>
20 #include <arpa/inet.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <pthread.h>
27 #include <sys/time.h>
28 #include "../channels/adtranvofr.h"
29
30 #define MAX_FRAME_SIZE 1441
31
32 struct ast_filestream {
33         /* First entry MUST be reserved for the channel type */
34         void *reserved[AST_RESERVED_POINTERS];
35         /* This is what a filestream means to us */
36         int fd; /* Descriptor */
37         struct ast_frame fr;    /* Frame representation of buf */
38         char offset[AST_FRIENDLY_OFFSET];
39         unsigned char buf[MAX_FRAME_SIZE * 2];
40         int pos;
41         struct timeval last;
42 };
43
44
45 static struct ast_filestream *glist = NULL;
46 static pthread_mutex_t mp3_lock = AST_MUTEX_INITIALIZER;
47 static int glistcnt = 0;
48
49 static char *name = "mp3";
50 static char *desc = "MPEG-1,2 Layer 3 File Format Support";
51 static char *exts = "mp3|mpeg3";
52
53 #include "../codecs/mp3anal.h"
54
55 static struct ast_filestream *mp3_open(int fd)
56 {
57         /* We don't have any header to read or anything really, but
58            if we did, it would go here.  We also might want to check
59            and be sure it's a valid file.  */
60         struct ast_filestream *tmp;
61         if ((tmp = malloc(sizeof(struct ast_filestream)))) {
62                 if (ast_pthread_mutex_lock(&mp3_lock)) {
63                         ast_log(LOG_WARNING, "Unable to lock mp3 list\n");
64                         free(tmp);
65                         return NULL;
66                 }
67                 tmp->fd = fd;
68                 tmp->last.tv_usec = 0;
69                 tmp->last.tv_sec = 0;
70                 glistcnt++;
71                 ast_pthread_mutex_unlock(&mp3_lock);
72                 ast_update_use_count();
73         }
74         return tmp;
75 }
76
77 static struct ast_filestream *mp3_rewrite(int fd, char *comment)
78 {
79         /* We don't have any header to read or anything really, but
80            if we did, it would go here.  We also might want to check
81            and be sure it's a valid file.  */
82         struct ast_filestream *tmp;
83         if ((tmp = malloc(sizeof(struct ast_filestream)))) {
84                 if (ast_pthread_mutex_lock(&mp3_lock)) {
85                         ast_log(LOG_WARNING, "Unable to lock mp3 list\n");
86                         free(tmp);
87                         return NULL;
88                 }
89                 tmp->fd = fd;
90                 glistcnt++;
91                 ast_pthread_mutex_unlock(&mp3_lock);
92                 ast_update_use_count();
93         } else
94                 ast_log(LOG_WARNING, "Out of memory\n");
95         return tmp;
96 }
97
98 static void mp3_close(struct ast_filestream *s)
99 {
100         if (ast_pthread_mutex_lock(&mp3_lock)) {
101                 ast_log(LOG_WARNING, "Unable to lock mp3 list\n");
102                 return;
103         }
104         glistcnt--;
105         ast_pthread_mutex_unlock(&mp3_lock);
106         ast_update_use_count();
107         close(s->fd);
108         free(s);
109 }
110
111 static struct ast_frame *mp3_read(struct ast_filestream *s, int *whennext)
112 {
113         /* XXX Don't assume frames are this size XXX */
114         u_int32_t delay = -1;
115         int res;
116         int size;
117         if ((res = read(s->fd, s->buf , 4)) != 4) {
118                 ast_log(LOG_WARNING, "Short read (%d of 4 bytes) (%s)!\n", res, strerror(errno));
119                 return NULL;
120         }
121         if (mp3_badheader(s->buf)) {
122                 ast_log(LOG_WARNING, "Bad mp3 header\n");
123                 return NULL;
124         }
125         if ((size = mp3_framelen(s->buf)) < 0) {
126                 ast_log(LOG_WARNING, "Unable to calculate frame size\n");
127                 return NULL;
128         }
129         if ((res = read(s->fd, s->buf + 4 , size - 4)) != size - 4) {
130                 ast_log(LOG_WARNING, "Short read (%d of %d bytes) (%s)!\n", res, size - 4, strerror(errno));
131                 return NULL;
132         }
133         /* Send a frame from the file to the appropriate channel */
134         /* Read the data into the buffer */
135         s->fr.offset = AST_FRIENDLY_OFFSET;
136         s->fr.frametype = AST_FRAME_VOICE;
137         s->fr.subclass = AST_FORMAT_MP3;
138         s->fr.mallocd = 0;
139         s->fr.src = name;
140         s->fr.datalen = size;
141         s->fr.data = s->buf;
142         delay = mp3_samples(s->buf) * 1000 / mp3_samplerate(s->buf);
143         s->fr.samples = delay * 8;
144 #if 0
145         ast_log(LOG_DEBUG, "delay is %d, adjusting by %d, as last was %d\n", delay, s->adj, ms);
146 #endif
147         delay *= 8;
148         if (delay < 1)
149                 delay = 1;
150         *whennext = delay;
151         return &s->fr;
152 }
153
154 static int mp3_write(struct ast_filestream *fs, struct ast_frame *f)
155 {
156         int res;
157         if (f->frametype != AST_FRAME_VOICE) {
158                 ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
159                 return -1;
160         }
161         if (f->subclass != AST_FORMAT_MP3) {
162                 ast_log(LOG_WARNING, "Asked to write non-mp3 frame!\n");
163                 return -1;
164         }
165         if ((res = write(fs->fd, f->data, f->datalen)) != f->datalen) {
166                 ast_log(LOG_WARNING, "Unable to write frame: res=%d (%s)\n", res, strerror(errno));
167                 return -1;
168         }       
169         return 0;
170 }
171
172 static int mp3_seek(struct ast_filestream *fs, long sample_offset, int whence)
173 {
174         return -1;
175 }
176
177 static int mp3_trunc(struct ast_filestream *fs)
178 {
179         return -1;
180 }
181
182 static long mp3_tell(struct ast_filestream *fs)
183 {
184         return -1;
185 }
186
187 static char *mp3_getcomment(struct ast_filestream *s)
188 {
189         return NULL;
190 }
191
192 int load_module()
193 {
194         return ast_format_register(name, exts, AST_FORMAT_MP3,
195                                                                 mp3_open,
196                                                                 mp3_rewrite,
197                                                                 mp3_write,
198                                                                 mp3_seek,
199                                                                 mp3_trunc,
200                                                                 mp3_tell,
201                                                                 mp3_read,
202                                                                 mp3_close,
203                                                                 mp3_getcomment);
204                                                                 
205                                                                 
206 }
207
208 int unload_module()
209 {
210         return ast_format_unregister(name);
211 }       
212
213 int usecount()
214 {
215         int res;
216         if (ast_pthread_mutex_lock(&mp3_lock)) {
217                 ast_log(LOG_WARNING, "Unable to lock mp3 list\n");
218                 return -1;
219         }
220         res = glistcnt;
221         ast_pthread_mutex_unlock(&mp3_lock);
222         return res;
223 }
224
225 char *description()
226 {
227         return desc;
228 }
229
230
231 char *key()
232 {
233         return ASTERISK_GPL_KEY;
234 }