don't take locks when reading usecounts, they are not necessary (bug #4585)
[asterisk/asterisk.git] / formats / format_sln.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * RAW SLINEAR Format
5  * Anthony Minessale (anthmct@yahoo.com)
6  * Derived from format_pcm.c in the asterisk distro
7  *
8  * This program is free software, distributed under the terms of
9  * the GNU General Public License
10  */
11  
12 #include <unistd.h>
13 #include <netinet/in.h>
14 #include <arpa/inet.h>
15 #include <stdlib.h>
16 #include <sys/time.h>
17 #include <stdio.h>
18 #include <errno.h>
19 #include <string.h>
20
21 #include "asterisk.h"
22
23 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
24
25 #include "asterisk/lock.h"
26 #include "asterisk/channel.h"
27 #include "asterisk/file.h"
28 #include "asterisk/logger.h"
29 #include "asterisk/sched.h"
30 #include "asterisk/module.h"
31 #include "asterisk/endian.h"
32
33 #define BUF_SIZE 320            /* 320 samples */
34
35 struct ast_filestream {
36         void *reserved[AST_RESERVED_POINTERS];
37         /* This is what a filestream means to us */
38         int fd; /* Descriptor */
39         struct ast_channel *owner;
40         struct ast_frame fr;                            /* Frame information */
41         char waste[AST_FRIENDLY_OFFSET];        /* Buffer for sending frames, etc */
42         char empty;                                                     /* Empty character */
43         unsigned char buf[BUF_SIZE];                            /* Output Buffer */
44         struct timeval last;
45 };
46
47
48 AST_MUTEX_DEFINE_STATIC(slinear_lock);
49 static int glistcnt = 0;
50
51 static char *name = "sln";
52 static char *desc = "Raw Signed Linear Audio support (SLN)";
53 static char *exts = "sln|raw";
54
55 static struct ast_filestream *slinear_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                 memset(tmp, 0, sizeof(struct ast_filestream));
63                 if (ast_mutex_lock(&slinear_lock)) {
64                         ast_log(LOG_WARNING, "Unable to lock slinear list\n");
65                         free(tmp);
66                         return NULL;
67                 }
68                 tmp->fd = fd;
69                 tmp->fr.data = tmp->buf;
70                 tmp->fr.frametype = AST_FRAME_VOICE;
71                 tmp->fr.subclass = AST_FORMAT_SLINEAR;
72                 /* datalen will vary for each frame */
73                 tmp->fr.src = name;
74                 tmp->fr.mallocd = 0;
75                 glistcnt++;
76                 ast_mutex_unlock(&slinear_lock);
77                 ast_update_use_count();
78         }
79         return tmp;
80 }
81
82 static struct ast_filestream *slinear_rewrite(int fd, const char *comment)
83 {
84         /* We don't have any header to read or anything really, but
85            if we did, it would go here.  We also might want to check
86            and be sure it's a valid file.  */
87         struct ast_filestream *tmp;
88         if ((tmp = malloc(sizeof(struct ast_filestream)))) {
89                 memset(tmp, 0, sizeof(struct ast_filestream));
90                 if (ast_mutex_lock(&slinear_lock)) {
91                         ast_log(LOG_WARNING, "Unable to lock slinear list\n");
92                         free(tmp);
93                         return NULL;
94                 }
95                 tmp->fd = fd;
96                 glistcnt++;
97                 ast_mutex_unlock(&slinear_lock);
98                 ast_update_use_count();
99         } else
100                 ast_log(LOG_WARNING, "Out of memory\n");
101         return tmp;
102 }
103
104 static void slinear_close(struct ast_filestream *s)
105 {
106         if (ast_mutex_lock(&slinear_lock)) {
107                 ast_log(LOG_WARNING, "Unable to lock slinear list\n");
108                 return;
109         }
110         glistcnt--;
111         ast_mutex_unlock(&slinear_lock);
112         ast_update_use_count();
113         close(s->fd);
114         free(s);
115         s = NULL;
116 }
117
118 static struct ast_frame *slinear_read(struct ast_filestream *s, int *whennext)
119 {
120         int res;
121         int delay;
122         /* Send a frame from the file to the appropriate channel */
123
124         s->fr.frametype = AST_FRAME_VOICE;
125         s->fr.subclass = AST_FORMAT_SLINEAR;
126         s->fr.offset = AST_FRIENDLY_OFFSET;
127         s->fr.mallocd = 0;
128         s->fr.data = s->buf;
129         if ((res = read(s->fd, s->buf, BUF_SIZE)) < 1) {
130                 if (res)
131                         ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
132                 return NULL;
133         }
134         s->fr.samples = res/2;
135         s->fr.datalen = res;
136         delay = s->fr.samples;
137         *whennext = delay;
138         return &s->fr;
139 }
140
141 static int slinear_write(struct ast_filestream *fs, struct ast_frame *f)
142 {
143         int res;
144         if (f->frametype != AST_FRAME_VOICE) {
145                 ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
146                 return -1;
147         }
148         if (f->subclass != AST_FORMAT_SLINEAR) {
149                 ast_log(LOG_WARNING, "Asked to write non-slinear frame (%d)!\n", f->subclass);
150                 return -1;
151         }
152         if ((res = write(fs->fd, f->data, f->datalen)) != f->datalen) {
153                         ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno));
154                         return -1;
155         }
156         return 0;
157 }
158
159 static int slinear_seek(struct ast_filestream *fs, long sample_offset, int whence)
160 {
161         off_t offset=0,min,cur,max;
162
163         min = 0;
164         sample_offset <<= 1;
165         cur = lseek(fs->fd, 0, SEEK_CUR);
166         max = lseek(fs->fd, 0, SEEK_END);
167         if (whence == SEEK_SET)
168                 offset = sample_offset;
169         else if (whence == SEEK_CUR || whence == SEEK_FORCECUR)
170                 offset = sample_offset + cur;
171         else if (whence == SEEK_END)
172                 offset = max - sample_offset;
173         if (whence != SEEK_FORCECUR) {
174                 offset = (offset > max)?max:offset;
175         }
176         /* always protect against seeking past begining. */
177         offset = (offset < min)?min:offset;
178         return lseek(fs->fd, offset, SEEK_SET) / 2;
179 }
180
181 static int slinear_trunc(struct ast_filestream *fs)
182 {
183         return ftruncate(fs->fd, lseek(fs->fd,0,SEEK_CUR));
184 }
185
186 static long slinear_tell(struct ast_filestream *fs)
187 {
188         off_t offset;
189         offset = lseek(fs->fd, 0, SEEK_CUR);
190         return offset / 2;
191 }
192
193 static char *slinear_getcomment(struct ast_filestream *s)
194 {
195         return NULL;
196 }
197
198 int load_module()
199 {
200         return ast_format_register(name, exts, AST_FORMAT_SLINEAR,
201                                                                 slinear_open,
202                                                                 slinear_rewrite,
203                                                                 slinear_write,
204                                                                 slinear_seek,
205                                                                 slinear_trunc,
206                                                                 slinear_tell,
207                                                                 slinear_read,
208                                                                 slinear_close,
209                                                                 slinear_getcomment);
210                                                                 
211                                                                 
212 }
213
214 int unload_module()
215 {
216         return ast_format_unregister(name);
217 }       
218
219 int usecount()
220 {
221         return glistcnt;
222 }
223
224 char *description()
225 {
226         return desc;
227 }
228
229
230 char *key()
231 {
232         return ASTERISK_GPL_KEY;
233 }