2 * Asterisk -- A telephony toolkit for Linux.
6 * Copyright (C) 1999, Adtran Inc. and Linux Support Services, LLC
8 * Mark Spencer <markster@linux-support.net>
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
21 #include <asterisk/sched.h>
22 #include <asterisk/options.h>
23 #include <asterisk/channel.h>
24 #include <asterisk/channel_pvt.h>
25 #include <asterisk/logger.h>
26 #include <asterisk/file.h>
32 struct ast_channel * (*requester)(char *type, int format, void *data);
33 struct chanlist *next;
36 /* Protect the channel list (highly unlikely that two things would change
37 it at the same time, but still! */
39 static pthread_mutex_t chlock = PTHREAD_MUTEX_INITIALIZER;
41 int ast_channel_register(char *type, char *description, int capabilities,
42 struct ast_channel *(*requester)(char *type, int format, void *data))
44 struct chanlist *chan, *last=NULL;
45 if (pthread_mutex_lock(&chlock)) {
46 ast_log(LOG_WARNING, "Unable to lock channel list\n");
51 if (!strcasecmp(type, chan->type)) {
52 ast_log(LOG_WARNING, "Already have a handler for type '%s'\n", type);
53 pthread_mutex_unlock(&chlock);
59 chan = malloc(sizeof(struct chanlist));
61 ast_log(LOG_WARNING, "Out of memory\n");
62 pthread_mutex_unlock(&chlock);
65 strncpy(chan->type, type, sizeof(chan->type));
66 strncpy(chan->description, description, sizeof(chan->description));
67 chan->capabilities = capabilities;
68 chan->requester = requester;
75 ast_log(LOG_DEBUG, "Registered handler for '%s' (%s)\n", chan->type, chan->description);
76 else if (option_verbose > 1)
77 ast_verbose( VERBOSE_PREFIX_2 "Registered channel type '%s' (%s)\n", chan->type, chan->description);
78 pthread_mutex_unlock(&chlock);
82 struct ast_channel *ast_channel_alloc(void)
84 struct ast_channel *tmp;
85 struct ast_channel_pvt *pvt;
86 tmp = malloc(sizeof(struct ast_channel));
87 memset(tmp, 0, sizeof(struct ast_channel));
89 pvt = malloc(sizeof(struct ast_channel_pvt));
91 memset(pvt, 0, sizeof(struct ast_channel_pvt));
92 tmp->sched = sched_context_create();
95 strncpy(tmp->name, "**Unknown**", sizeof(tmp->name));
97 tmp->state = AST_STATE_DOWN;
100 strncpy(tmp->context, "default", sizeof(tmp->context));
101 strncpy(tmp->exten, "s", sizeof(tmp->exten));
104 ast_log(LOG_WARNING, "Unable to create schedule context\n");
109 ast_log(LOG_WARNING, "Out of memory\n");
114 ast_log(LOG_WARNING, "Out of memory\n");
118 int ast_softhangup(struct ast_channel *chan)
122 ast_stopstream(chan);
124 ast_log(LOG_DEBUG, "Soft-Hanging up channel '%s'\n", chan->name);
126 ast_log(LOG_WARNING, "Soft hangup called on '%s' while a translator is in place! Expect a failure.\n", chan->name);
127 if (chan->pvt->hangup)
128 res = chan->pvt->hangup(chan);
130 ast_log(LOG_WARNING, "Channel '%s' may not have been hung up properly\n", chan->name);
132 ast_log(LOG_WARNING, "PBX may not have been terminated properly on '%s'\n", chan->name);
133 /* Interrupt any select call or such */
135 pthread_kill(chan->blocker, SIGURG);
139 int ast_hangup(struct ast_channel *chan)
143 ast_stopstream(chan);
145 sched_context_destroy(chan->sched);
147 ast_log(LOG_WARNING, "Hard hangup called, while fd is blocking! Expect a failure\n");
149 ast_log(LOG_DEBUG, "Hanging up channel '%s'\n", chan->name);
150 if (chan->pvt->hangup)
151 res = chan->pvt->hangup(chan);
153 ast_log(LOG_WARNING, "Channel '%s' may not have been hung up properly\n", chan->name);
155 ast_log(LOG_WARNING, "Hard hangup called on '%s' while a translator is in place! Expect a failure.\n", chan->name);
157 ast_log(LOG_WARNING, "PBX may not have been terminated properly on '%s'\n", chan->name);
161 free(chan->callerid);
167 void ast_channel_unregister(char *type)
169 struct chanlist *chan, *last=NULL;
171 ast_log(LOG_DEBUG, "Unregistering channel type '%s'\n", type);
172 if (pthread_mutex_lock(&chlock)) {
173 ast_log(LOG_WARNING, "Unable to lock channel list\n");
178 if (!strcasecmp(chan->type, type)) {
180 last->next = chan->next;
182 backends = backends->next;
184 pthread_mutex_unlock(&chlock);
190 pthread_mutex_unlock(&chlock);
193 int ast_answer(struct ast_channel *chan)
195 /* Answer the line, if possible */
196 if (chan->state == AST_STATE_RING) {
197 if (chan->pvt->answer)
198 return chan->pvt->answer(chan);
203 int ast_waitfor_n_fd(int *fds, int n, int *ms)
205 /* Wait for x amount of time on a file descriptor to have input. */
212 tv.tv_sec = *ms / 1000;
213 tv.tv_usec = (*ms % 1000) * 1000;
217 FD_SET(fds[x], &rfds);
218 FD_SET(fds[x], &efds);
223 res = select(max + 1, &rfds, NULL, &efds, &tv);
225 res = select(max + 1, &rfds, NULL, &efds, NULL);
227 if ((FD_ISSET(fds[x], &rfds) || FD_ISSET(fds[x], &efds)) && (winner < 0))
230 *ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
236 struct ast_channel *ast_waitfor_n(struct ast_channel **c, int n, int *ms)
238 /* Wait for x amount of time on a file descriptor to have input. */
243 struct ast_channel *winner = NULL;
245 tv.tv_sec = *ms / 1000;
246 tv.tv_usec = (*ms % 1000) * 1000;
250 FD_SET(c[x]->fd, &rfds);
251 FD_SET(c[x]->fd, &efds);
252 CHECK_BLOCKING(c[x]);
257 res = select(max + 1, &rfds, NULL, &efds, &tv);
259 res = select(max + 1, &rfds, NULL, &efds, NULL);
262 if ((FD_ISSET(c[x]->fd, &rfds) || FD_ISSET(c[x]->fd, &efds)) && !winner)
265 *ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
271 int ast_waitfor(struct ast_channel *c, int ms)
273 if (ast_waitfor_n(&c, 1, &ms)) {
278 /* Error if ms < 0 */
284 char ast_waitfordigit(struct ast_channel *c, int ms)
288 /* Wait for a digit, no more than ms milliseconds total. */
289 while(ms && !result) {
290 ms = ast_waitfor(c, ms);
291 if (ms < 0) /* Error */
297 if (f->frametype == AST_FRAME_DTMF)
298 result = f->subclass;
307 struct ast_frame *ast_read(struct ast_channel *chan)
309 struct ast_frame *f = NULL;
310 chan->blocker = pthread_self();
312 f = chan->pvt->read(chan);
314 ast_log(LOG_WARNING, "No read routine on channel %s\n", chan);
318 int ast_write(struct ast_channel *chan, struct ast_frame *fr)
321 CHECK_BLOCKING(chan);
322 switch(fr->frametype) {
323 case AST_FRAME_CONTROL:
324 /* XXX Interpret control frames XXX */
325 ast_log(LOG_WARNING, "Don't know how to handle control frames yet\n");
329 if (chan->pvt->send_digit)
330 res = chan->pvt->send_digit(chan, fr->subclass);
333 if (chan->pvt->write)
334 res = chan->pvt->write(chan, fr);
340 struct ast_channel *ast_request(char *type, int format, void *data)
342 struct chanlist *chan;
343 struct ast_channel *c = NULL;
344 if (pthread_mutex_lock(&chlock)) {
345 ast_log(LOG_WARNING, "Unable to lock channel list\n");
350 if (!strcasecmp(type, chan->type)) {
352 c = chan->requester(type, format, data);
353 pthread_mutex_unlock(&chlock);
359 ast_log(LOG_WARNING, "No channel type registered for '%s'\n", type);
363 int ast_call(struct ast_channel *chan, char *addr, int timeout)
365 /* Place an outgoing call, but don't wait any longer than timeout ms before returning.
366 If the remote end does not answer within the timeout, then do NOT hang up, but
370 res = chan->pvt->call(chan, addr, timeout);
374 int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int ftimeout, char *enders)
382 if (c->streamid > -1) {
383 d = ast_waitstream(c, AST_DIGIT_ANY);
386 d = ast_waitfordigit(c, to);
388 d = ast_waitfordigit(c, to);
392 if (!strchr(enders, d))
394 if ((d == 0) || strchr(enders, d) || (pos >= len - 1)) {