aboutsummaryrefslogtreecommitdiffstats
path: root/channels
diff options
context:
space:
mode:
authormatteo <matteo@f38db490-d61c-443f-a65b-d21fe96a405b>2003-02-16 06:00:12 +0000
committermatteo <matteo@f38db490-d61c-443f-a65b-d21fe96a405b>2003-02-16 06:00:12 +0000
commit175c755fefa75d02deeff70541cd7821ce670678 (patch)
tree09bad30a14c0eef808c9d0d2720e797ff76c44f4 /channels
parentdae2009f9537257ba729035caa92eb3661c93aa1 (diff)
Sun Feb 16 07:00:01 CET 2003
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@616 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels')
-rwxr-xr-xchannels/chan_mgcp.c61
-rwxr-xr-xchannels/chan_sip.c227
2 files changed, 242 insertions, 46 deletions
diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c
index 88a0d2cf0..08ef81499 100755
--- a/channels/chan_mgcp.c
+++ b/channels/chan_mgcp.c
@@ -131,6 +131,7 @@ struct mgcp_endpoint {
int outgoing;
struct ast_channel *owner;
struct ast_rtp *rtp;
+ struct sockaddr_in tmpdest;
struct mgcp_endpoint *next;
struct mgcp_gateway *parent;
};
@@ -317,6 +318,7 @@ static int mgcp_hangup(struct ast_channel *ast)
p->owner = NULL;
if (strlen(p->cxident))
transmit_connection_del(p);
+ strcpy(p->cxident, "");
if (!p->alreadygone && (!p->outgoing || (ast->_state == AST_STATE_UP)))
transmit_notify_request(p, "ro", 1);
else
@@ -324,8 +326,9 @@ static int mgcp_hangup(struct ast_channel *ast)
ast->pvt->pvt = NULL;
p->alreadygone = 0;
p->outgoing = 0;
- strcpy(p->cxident, "");
strcpy(p->callid, "");
+ /* Reset temporary destination */
+ memset(&p->tmpdest, 0, sizeof(p->tmpdest));
if (p->rtp) {
ast_rtp_destroy(p->rtp);
p->rtp = NULL;
@@ -515,6 +518,7 @@ static struct ast_channel *mgcp_new(struct mgcp_endpoint *i, int state)
tmp->pvt->indicate = mgcp_indicate;
tmp->pvt->fixup = mgcp_fixup;
tmp->pvt->send_digit = mgcp_senddigit;
+ tmp->pvt->bridge = ast_rtp_bridge;
if (strlen(i->language))
strncpy(tmp->language, i->language, sizeof(tmp->language)-1);
i->owner = tmp;
@@ -951,8 +955,15 @@ static int add_sdp(struct mgcp_request *resp, struct mgcp_endpoint *p, struct as
if (rtp) {
ast_rtp_get_peer(rtp, &dest);
} else {
- dest.sin_addr = p->parent->ourip;
- dest.sin_port = sin.sin_port;
+ if (p->tmpdest.sin_addr.s_addr) {
+ dest.sin_addr = p->tmpdest.sin_addr;
+ dest.sin_port = p->tmpdest.sin_port;
+ /* Reset temporary destination */
+ memset(&p->tmpdest, 0, sizeof(p->tmpdest));
+ } else {
+ dest.sin_addr = p->parent->ourip;
+ dest.sin_port = sin.sin_port;
+ }
}
printf("We're at %s port %d\n", inet_ntoa(p->parent->ourip), ntohs(sin.sin_port));
snprintf(v, sizeof(v), "v=0\r\n");
@@ -991,6 +1002,12 @@ static int transmit_modify_with_sdp(struct mgcp_endpoint *p, struct ast_rtp *rtp
char local[256];
char tmp[80];
int x;
+ if (!strlen(p->cxident) && rtp) {
+ /* We don't have a CXident yet, store the destination and
+ wait a bit */
+ ast_rtp_get_peer(rtp, &p->tmpdest);
+ return 0;
+ }
snprintf(local, sizeof(local), "p:20");
for (x=1;x<= AST_FORMAT_MAX_AUDIO; x <<= 1) {
if (p->capability & x) {
@@ -1003,6 +1020,7 @@ static int transmit_modify_with_sdp(struct mgcp_endpoint *p, struct ast_rtp *rtp
add_header(&resp, "L", local);
add_header(&resp, "M", "sendrecv");
add_header(&resp, "X", p->txident);
+ add_header(&resp, "I", p->cxident);
add_header(&resp, "S", "");
add_sdp(&resp, p, rtp);
p->lastout = oseq;
@@ -1278,8 +1296,14 @@ static int mgcpsock_read(int *id, int fd, short events, void *ignore)
p = find_endpoint(NULL, ident, &sin);
if (p) {
handle_response(p, result, ident);
- if ((c = get_header(&req, "I")))
- strncpy(p->cxident, c, sizeof(p->cxident) - 1);
+ if ((c = get_header(&req, "I"))) {
+ if (strlen(c)) {
+ strncpy(p->cxident, c, sizeof(p->cxident) - 1);
+ if (p->tmpdest.sin_addr.s_addr) {
+ transmit_modify_with_sdp(p, NULL);
+ }
+ }
+ }
if (req.lines)
process_sdp(p, &req);
}
@@ -1483,6 +1507,31 @@ struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
return gw;
}
+static struct ast_rtp *mgcp_get_rtp_peer(struct ast_channel *chan)
+{
+ struct mgcp_endpoint *p;
+ p = chan->pvt->pvt;
+ if (p && p->rtp)
+ return p->rtp;
+ return NULL;
+}
+
+static int mgcp_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp)
+{
+ struct mgcp_endpoint *p;
+ p = chan->pvt->pvt;
+ if (p) {
+ transmit_modify_with_sdp(p, rtp);
+ return 0;
+ }
+ return -1;
+}
+
+static struct ast_rtp_protocol mgcp_rtp = {
+ get_rtp_info: mgcp_get_rtp_peer,
+ set_rtp_peer: mgcp_set_rtp_peer,
+};
+
int load_module()
{
struct ast_config *cfg;
@@ -1590,6 +1639,8 @@ int load_module()
ast_destroy(cfg);
return -1;
}
+ mgcp_rtp.type = type;
+ ast_rtp_proto_register(&mgcp_rtp);
ast_cli_register(&cli_show_endpoints);
/* And start the monitor for the first time */
restart_monitor();
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index b9f235c3c..a057eb89e 100755
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -32,6 +32,7 @@
#include <asterisk/cli.h>
#include <asterisk/md5.h>
#include <asterisk/app.h>
+#include <asterisk/musiconhold.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
@@ -47,8 +48,12 @@
/* #define VOCAL_DATA_HACK */
#define SIPDUMPER
-#define DEFAULT_EXPIREY 120
-#define MAX_EXPIREY 3600
+#define DEFAULT_DEFAULT_EXPIREY 120
+#define DEFAULT_MAX_EXPIREY 3600
+
+static int max_expirey = DEFAULT_MAX_EXPIREY;
+static int default_expirey = DEFAULT_DEFAULT_EXPIREY;
+
#define DEFAULT_MAXMS 2000 /* Must be faster than 2 seconds by default */
#define DEFAULT_MAXMS 2000 /* Must be faster than 2 seconds by default */
@@ -142,6 +147,7 @@ static struct sip_pvt {
char refer_to[AST_MAX_EXTENSION]; /* Place to store REFER-TO extension */
char referred_by[AST_MAX_EXTENSION];/* Place to store REFERRED-BY extension */
char refer_contact[AST_MAX_EXTENSION];/* Place to store Contact info from a REFER extension */
+ struct sip_pvt *refer_call; /* Call we are referring */
char record_route[256];
char record_route_info[256];
char remote_party_id[256];
@@ -728,6 +734,7 @@ static int sip_indicate(struct ast_channel *ast, int condition)
}
+#if 0
static int sip_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc)
{
struct sip_pvt *p0, *p1;
@@ -742,6 +749,7 @@ static int sip_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags,
ast_pthread_mutex_lock(&c1->lock);
p0 = c0->pvt->pvt;
p1 = c1->pvt->pvt;
+ ast_log(LOG_DEBUG, "Reinvite? %s: %s, %s: %s\n", c0->name, p0->canreinvite ? "yes" : "no", c1->name, p1->canreinvite ? "yes" : "no");
if (!p0->canreinvite || !p1->canreinvite) {
/* Not gonna support reinvite */
ast_pthread_mutex_unlock(&c0->lock);
@@ -796,6 +804,7 @@ static int sip_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags,
}
return -1;
}
+#endif
static struct ast_channel *sip_new(struct sip_pvt *i, int state, char *title)
{
@@ -808,7 +817,7 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, char *title)
tmp->nativeformats = capability;
fmt = ast_best_codec(tmp->nativeformats);
if (title)
- snprintf(tmp->name, sizeof(tmp->name), "SIP/%s", title);
+ snprintf(tmp->name, sizeof(tmp->name), "SIP/%s-%04x", title, rand() & 0xffff);
else
snprintf(tmp->name, sizeof(tmp->name), "SIP/%s:%d", inet_ntoa(i->sa.sin_addr), ntohs(i->sa.sin_port));
tmp->type = type;
@@ -830,7 +839,7 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, char *title)
tmp->pvt->indicate = sip_indicate;
tmp->pvt->fixup = sip_fixup;
tmp->pvt->send_digit = sip_senddigit;
- tmp->pvt->bridge = sip_bridge;
+ tmp->pvt->bridge = ast_rtp_bridge;
if (strlen(i->language))
strncpy(tmp->language, i->language, sizeof(tmp->language)-1);
i->owner = tmp;
@@ -1087,7 +1096,7 @@ static int sip_register(char *value, int lineno)
if (secret)
strncpy(reg->secret, secret, sizeof(reg->secret)-1);
reg->expire = -1;
- reg->refresh = DEFAULT_EXPIREY;
+ reg->refresh = default_expirey;
reg->addr.sin_family = AF_INET;
memcpy(&reg->addr.sin_addr, hp->h_addr, sizeof(&reg->addr.sin_addr));
reg->addr.sin_port = porta ? htons(atoi(porta)) : htons(DEFAULT_SIP_PORT);
@@ -1237,11 +1246,21 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
ast_log(LOG_WARNING, "No compatible codecs!\n");
return -1;
}
- if (p->owner && !(p->owner->nativeformats & p->capability)) {
- ast_log(LOG_DEBUG, "Oooh, we need to change our formats since our peer supports only %d and not %d\n", p->capability, p->owner->nativeformats);
- p->owner->nativeformats = p->capability;
- ast_set_read_format(p->owner, p->owner->readformat);
- ast_set_write_format(p->owner, p->owner->writeformat);
+ if (p->owner) {
+ if (p->owner->nativeformats & p->capability) {
+ ast_log(LOG_DEBUG, "Oooh, we need to change our formats since our peer supports only %d and not %d\n", p->capability, p->owner->nativeformats);
+ p->owner->nativeformats = p->capability;
+ ast_set_read_format(p->owner, p->owner->readformat);
+ ast_set_write_format(p->owner, p->owner->writeformat);
+ }
+ if (p->owner->bridge) {
+ /* Turn on/off music on hold if we are holding/unholding */
+ if (sin.sin_addr.s_addr) {
+ ast_moh_stop(p->owner->bridge);
+ } else {
+ ast_moh_start(p->owner->bridge, NULL);
+ }
+ }
}
return 0;
@@ -1830,7 +1849,7 @@ static int transmit_register(struct sip_registry *r, char *cmd, char *auth)
if (auth)
add_header(&req, "Authorization", auth);
- snprintf(tmp, sizeof(tmp), "%d", DEFAULT_EXPIREY);
+ snprintf(tmp, sizeof(tmp), "%d", default_expirey);
add_header(&req, "Expires", tmp);
add_header(&req, "Event", "registration");
copy_request(&p->initreq, &req);
@@ -1933,8 +1952,8 @@ static int parse_contact(struct sip_pvt *pvt, struct sip_peer *p, struct sip_req
strcpy(p->username, "");
if (p->expire > -1)
ast_sched_del(sched, p->expire);
- if ((expirey < 1) || (expirey > MAX_EXPIREY))
- expirey = DEFAULT_EXPIREY;
+ if ((expirey < 1) || (expirey > max_expirey))
+ expirey = max_expirey;
p->expire = ast_sched_add(sched, expirey * 1000, expire_register, p);
pvt->expirey = expirey;
if (memcmp(&p->addr, &oldsin, sizeof(oldsin))) {
@@ -2130,7 +2149,9 @@ static int get_refer_info(struct sip_pvt *p, struct sip_request *oreq)
char tmp2[256] = "", *c2, *a2;
char tmp3[256];
char tmp4[256];
+ char tmp5[256] = ""; /* CallID to replace */
struct sip_request *req;
+ struct sip_pvt *p2;
req = oreq;
if (!req)
@@ -2151,32 +2172,81 @@ static int get_refer_info(struct sip_pvt *p, struct sip_request *oreq)
}
c += 4;
c2 += 4;
- if ((a = strchr(c, '@')) || (a = strchr(c, ';'))) {
+ if ((a = strchr(c, '?'))) {
+ /* Search for arguemnts */
*a = '\0';
+ a++;
+ if (!strncasecmp(a, "REPLACES=", strlen("REPLACES="))) {
+ strncpy(tmp5, a + strlen("REPLACES="), sizeof(tmp5) - 1);
+ if ((a = strchr(tmp5, '%'))) {
+ /* Yuck! Pingtel converts the '@' to a %40, icky icky! Convert
+ back to an '@' */
+ if ((a[1] == '4') && (a[2] == '0')) {
+ *a = '@';
+ memmove(a + 1, a+3, strlen(a + 3));
+ }
+ }
+ if ((a = strchr(tmp5, '%')))
+ *a = '\0';
+ }
}
- if ((a2 = strchr(c2, '@')) || (a2 = strchr(c2, ';'))) {
+
+ if ((a = strchr(c, '@')))
+ *a = '\0';
+ if ((a = strchr(c, ';')))
+ *a = '\0';
+
+
+ if ((a2 = strchr(c2, '@')))
*a2 = '\0';
- }
+
+ if ((a2 = strchr(c2, ';')))
+ *a2 = '\0';
+
if (sipdebug)
ast_verbose("Looking for %s in %s\n", c, p->context);
ast_verbose("Looking for %s in %s\n", c2, p->context);
-
- if (ast_exists_extension(NULL, p->context, c, 1, NULL) && ast_exists_extension(NULL, p->context, c2, 1, NULL)) {
- if (!oreq)
- ast_log(LOG_DEBUG,"Something is wrong with this line.\n"); //This line is ignored for some reason....
- ast_log(LOG_DEBUG,"Assigning Extension %s to REFER-TO\n", c);
- ast_log(LOG_DEBUG,"Assigning Extension %s to REFERRED-BY\n", c2);
- ast_log(LOG_DEBUG,"Assigning Contact Info %s to REFER_CONTACT\n", tmp3);
- ast_log(LOG_DEBUG,"Assigning Remote-Party-ID Info %s to REMOTE_PARTY_ID\n",tmp4);
- strncpy(p->refer_to, c, sizeof(p->refer_to) - 1);
- strncpy(p->referred_by, c2, sizeof(p->referred_by) - 1);
- strncpy(p->refer_contact, tmp3, sizeof(p->refer_contact) - 1);
- strncpy(p->remote_party_id, tmp4, sizeof(p->remote_party_id) - 1);
+
+ if (strlen(tmp5)) {
+ /* This is a supervised transfer */
+ ast_log(LOG_DEBUG,"Assigning Replace-Call-ID Info %s to REPLACE_CALL_ID\n",tmp5);
+
+ strncpy(p->refer_to, "", sizeof(p->refer_to) - 1);
+ strncpy(p->referred_by, "", sizeof(p->referred_by) - 1);
+ strncpy(p->refer_contact, "", sizeof(p->refer_contact) - 1);
+ strncpy(p->remote_party_id, "", sizeof(p->remote_party_id) - 1);
+ p->refer_call = NULL;
+ ast_pthread_mutex_lock(&iflock);
+ /* Search interfaces and find the match */
+ p2 = iflist;
+ while(p2) {
+ if (!strcmp(p2->callid, tmp5)) {
+ /* Go ahead and lock it before returning */
+ ast_pthread_mutex_lock(&p2->lock);
+ p->refer_call = p2;
+ break;
+ }
+ p2 = p2->next;
+ }
+ ast_pthread_mutex_unlock(&iflock);
+ if (p->refer_call)
return 0;
- }
-
- if (ast_canmatch_extension(NULL, p->context, c, 1, NULL)) {
+ else
+ ast_log(LOG_NOTICE, "Supervised transfer requested, but unable to find callid '%s'\n", tmp5);
+ } else if (ast_exists_extension(NULL, p->context, c, 1, NULL) && ast_exists_extension(NULL, p->context, c2, 1, NULL)) {
+ /* This is an unsupervised transfer */
+ ast_log(LOG_DEBUG,"Assigning Extension %s to REFER-TO\n", c);
+ ast_log(LOG_DEBUG,"Assigning Extension %s to REFERRED-BY\n", c2);
+ ast_log(LOG_DEBUG,"Assigning Contact Info %s to REFER_CONTACT\n", tmp3);
+ ast_log(LOG_DEBUG,"Assigning Remote-Party-ID Info %s to REMOTE_PARTY_ID\n",tmp4);
+ strncpy(p->refer_to, c, sizeof(p->refer_to) - 1);
+ strncpy(p->referred_by, c2, sizeof(p->referred_by) - 1);
+ strncpy(p->refer_contact, tmp3, sizeof(p->refer_contact) - 1);
+ strncpy(p->remote_party_id, tmp4, sizeof(p->remote_party_id) - 1);
+ p->refer_call = NULL;
+ return 0;
+ } else if (ast_canmatch_extension(NULL, p->context, c, 1, NULL)) {
return 1;
}
@@ -2735,7 +2805,7 @@ retrylock:
if (r->expire != -1)
ast_sched_del(sched, r->expire);
expires=atoi(get_header(req, "expires"));
- if (!expires) expires=DEFAULT_EXPIREY;
+ if (!expires) expires=default_expirey;
r->expire=ast_sched_add(sched, (expires-2)*1000, sip_reregister, r);
}
@@ -2879,6 +2949,37 @@ static int determine_firstline_parts( struct sip_request *req ) {
return 1;
}
+static int attempt_transfer(struct sip_pvt *p1, struct sip_pvt *p2)
+{
+ if (!p1->owner || !p2->owner) {
+ ast_log(LOG_WARNING, "Transfer attempted without dual ownership?\n");
+ return -1;
+ }
+ if (p1->owner->bridge) {
+ if (p2->owner->bridge)
+ ast_moh_stop(p2->owner->bridge);
+ ast_moh_stop(p1->owner->bridge);
+ ast_moh_stop(p1->owner);
+ ast_moh_stop(p2->owner);
+ if (ast_channel_masquerade(p2->owner, p1->owner->bridge)) {
+ ast_log(LOG_WARNING, "Failed to masquerade %s into %s\n", p2->owner->name, p1->owner->bridge->name);
+ return -1;
+ }
+ } else if (p2->owner->bridge) {
+ ast_moh_stop(p2->owner->bridge);
+ ast_moh_stop(p2->owner);
+ ast_moh_stop(p1->owner);
+ if (ast_channel_masquerade(p1->owner, p2->owner->bridge)) {
+ ast_log(LOG_WARNING, "Failed to masquerade %s into %s\n", p1->owner->name, p2->owner->bridge->name);
+ return -1;
+ }
+ } else {
+ ast_log(LOG_NOTICE, "Transfer attempted with no bridged calls to transfer\n");
+ return -1;
+ }
+ return 0;
+}
+
static int handle_request(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin)
{
struct sip_request resp;
@@ -3048,16 +3149,23 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
transmit_response_with_allow(p, "404 Not Found", req);
else if (res > 0)
transmit_response_with_allow(p, "484 Address Incomplete", req);
- else
+ else {
transmit_response(p, "202 Accepted", req);
- ast_log(LOG_DEBUG,"202 Accepted\n");
- c = p->owner;
- if (c) {
- transfer_to = c->bridge;
- if (transfer_to)
- ast_async_goto(transfer_to,"", p->refer_to,1, 1);
+ if (p->refer_call) {
+ ast_log(LOG_DEBUG,"202 Accepted (supervised)\n");
+ attempt_transfer(p, p->refer_call);
+ ast_pthread_mutex_unlock(&p->refer_call->lock);
+ p->refer_call = NULL;
+ } else {
+ ast_log(LOG_DEBUG,"202 Accepted (blind)\n");
+ c = p->owner;
+ if (c) {
+ transfer_to = c->bridge;
+ if (transfer_to)
+ ast_async_goto(transfer_to,"", p->refer_to,1, 1);
+ }
+ }
}
-
} else if (!strcasecmp(cmd, "CANCEL") || !strcasecmp(cmd, "BYE")) {
copy_request(&p->initreq, req);
p->alreadygone = 1;
@@ -3140,7 +3248,7 @@ static int sipsock_read(int *id, int fd, short events, void *ignore)
/* Must have at least two headers */
return 1;
}
- /* Process request, with iflock held */
+ /* Process request, with netlock held */
ast_pthread_mutex_lock(&netlock);
p = find_call(&req, &sin);
if (p) {
@@ -3495,6 +3603,8 @@ static struct sip_peer *build_peer(char *name, struct ast_variable *v)
peer->expirey = expirey;
}
peer->capability = capability;
+ /* Assume can reinvite */
+ peer->canreinvite = 1;
while(v) {
if (!strcasecmp(v->name, "secret"))
strncpy(peer->secret, v->value, sizeof(peer->secret)-1);
@@ -3619,6 +3729,14 @@ static int reload_config()
strncpy(context, v->value, sizeof(context)-1);
} else if (!strcasecmp(v->name, "language")) {
strncpy(language, v->value, sizeof(language)-1);
+ } else if (!strcasecmp(v->name, "maxexpirey")) {
+ max_expirey = atoi(v->value);
+ if (max_expirey < 1)
+ max_expirey = DEFAULT_MAX_EXPIREY;
+ } else if (!strcasecmp(v->name, "defaultexpirey")) {
+ default_expirey = atoi(v->value);
+ if (default_expirey < 1)
+ default_expirey = DEFAULT_DEFAULT_EXPIREY;
} else if (!strcasecmp(v->name, "bindaddr")) {
if (!(hp = gethostbyname(v->value))) {
ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
@@ -3743,6 +3861,31 @@ static int reload_config()
return 0;
}
+static struct ast_rtp *sip_get_rtp_peer(struct ast_channel *chan)
+{
+ struct sip_pvt *p;
+ p = chan->pvt->pvt;
+ if (p && p->rtp && p->canreinvite)
+ return p->rtp;
+ return NULL;
+}
+
+static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp)
+{
+ struct sip_pvt *p;
+ p = chan->pvt->pvt;
+ if (p) {
+ transmit_reinvite_with_sdp(p, rtp);
+ return 0;
+ }
+ return -1;
+}
+
+static struct ast_rtp_protocol sip_rtp = {
+ get_rtp_info: sip_get_rtp_peer,
+ set_rtp_peer: sip_set_rtp_peer,
+};
+
int load_module()
{
int res;
@@ -3761,6 +3904,8 @@ int load_module()
ast_cli_register(&cli_show_registry);
ast_cli_register(&cli_debug);
ast_cli_register(&cli_no_debug);
+ sip_rtp.type = type;
+ ast_rtp_proto_register(&sip_rtp);
sched = sched_context_create();
if (!sched) {
ast_log(LOG_WARNING, "Unable to create schedule context\n");