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