diff --git a/apps/app_dial.c b/apps/app_dial.c index 51cc17e0a2..bb03754f93 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -53,6 +53,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/utils.h" #include "asterisk/app.h" #include "asterisk/causes.h" +#include "asterisk/rtp.h" #include "asterisk/manager.h" #include "asterisk/privacy.h" @@ -310,7 +311,7 @@ static void hanguptree(struct localuser *outgoing, struct ast_channel *exception } while (0) -static int onedigit_goto(struct ast_channel *chan, char *context, char exten, int pri) +static int onedigit_goto(struct ast_channel *chan, const char *context, char exten, int pri) { char rexten[2] = { exten, '\0' }; @@ -380,7 +381,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu int pos; int single; struct ast_channel *winner; - char *context = NULL; + const char *context = NULL; char cidname[AST_MAX_EXTENSION]; single = (outgoing && !outgoing->next && !ast_test_flag(outgoing, OPT_MUSICBACK | OPT_RINGBACK)); @@ -475,6 +476,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu ast_clear_flag(o, DIAL_STILLGOING); HANDLE_CAUSE(cause, in); } else { + ast_rtp_make_compatible(o->chan, in); if (o->chan->cid.cid_num) free(o->chan->cid.cid_num); o->chan->cid.cid_num = NULL; @@ -744,16 +746,17 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags long timelimit = 0; long play_warning = 0; long warning_freq=0; - char *warning_sound=NULL; - char *end_sound=NULL; - char *start_sound=NULL; + const char *warning_sound=NULL; + const char *end_sound=NULL; + const char *start_sound=NULL; char *dtmfcalled=NULL, *dtmfcalling=NULL; - char *var; + const char *var; char status[256]; int play_to_caller=0,play_to_callee=0; int sentringing=0, moh=0; - char *outbound_group = NULL; - char *macro_result = NULL, *macro_transfer_dest = NULL; + const char *outbound_group = NULL; + const char *macro_result = NULL; + char *macro_transfer_dest = NULL; int digit = 0, result = 0; time_t start_time, answer_time, end_time; struct ast_app *app = NULL; @@ -1052,6 +1055,9 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags } } + /* Setup outgoing SDP to match incoming one */ + ast_rtp_make_compatible(tmp->chan, chan); + /* Inherit specially named variables from parent channel */ ast_channel_inherit_variables(chan, tmp->chan); @@ -1190,7 +1196,7 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags if (peer->name) pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", peer->name); - number = pbx_builtin_getvar_helper(peer, "DIALEDPEERNUMBER"); + number = (char *)pbx_builtin_getvar_helper(peer, "DIALEDPEERNUMBER"); if (!number) number = numsubst; pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", number); @@ -1602,7 +1608,8 @@ static int dial_exec(struct ast_channel *chan, void *data) static int retrydial_exec(struct ast_channel *chan, void *data) { - char *announce = NULL, *context = NULL, *dialdata = NULL; + char *announce = NULL, *dialdata = NULL; + const char *context = NULL; int sleep = 0, loops = 0, res = 0; struct localuser *u; struct ast_flags peerflags; diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c index f22616891d..c3b9381192 100644 --- a/channels/chan_mgcp.c +++ b/channels/chan_mgcp.c @@ -2095,7 +2095,6 @@ static int transmit_modify_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp add_header(&resp, "X", sub->txident); add_header(&resp, "I", sub->cxident); /*add_header(&resp, "S", "");*/ - ast_rtp_offered_from_local(sub->rtp, 0); add_sdp(&resp, sub, rtp); /* SC: fill in new fields */ resp.cmd = MGCP_CMD_MDCX; @@ -2129,7 +2128,6 @@ static int transmit_connect_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp /* SC: X header should not be sent. kept for compatibility */ add_header(&resp, "X", sub->txident); /*add_header(&resp, "S", "");*/ - ast_rtp_offered_from_local(sub->rtp, 1); add_sdp(&resp, sub, rtp); /* SC: fill in new fields */ resp.cmd = MGCP_CMD_CRCX; @@ -3948,7 +3946,7 @@ static int mgcp_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, stru /* XXX Is there such thing as video support with MGCP? XXX */ struct mgcp_subchannel *sub; sub = chan->tech_pvt; - if (sub) { + if (sub && !sub->alreadygone) { transmit_modify_with_sdp(sub, rtp, codecs); return 0; } diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 0cbd4b5dfe..c5649c384a 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -4509,7 +4509,6 @@ static int transmit_response_with_sdp(struct sip_pvt *p, char *msg, struct sip_r } respprep(&resp, p, msg, req); if (p->rtp) { - ast_rtp_offered_from_local(p->rtp, 0); add_sdp(&resp, p); } else { ast_log(LOG_ERROR, "Can't add SDP to response, since we have no RTP session allocated. Call-ID %s\n", p->callid); @@ -4583,7 +4582,6 @@ static int transmit_reinvite_with_sdp(struct sip_pvt *p) add_header(&req, "Allow", ALLOWED_METHODS); if (sipdebug) add_header(&req, "X-asterisk-info", "SIP re-invite (RTP bridge)"); - ast_rtp_offered_from_local(p->rtp, 1); add_sdp(&req, p); /* Use this as the basis */ copy_request(&p->initreq, &req); @@ -4924,7 +4922,6 @@ static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init) } } if (sdp && p->rtp) { - ast_rtp_offered_from_local(p->rtp, 1); add_sdp(&req, p); } else { add_header_contentLength(&req, 0); @@ -12691,6 +12688,11 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struc if (!p) return -1; ast_mutex_lock(&p->lock); + if (ast_test_flag(p, SIP_ALREADYGONE)) { + /* If we're destroyed, don't bother */ + ast_mutex_unlock(&p->lock); + return 0; + } if (rtp) ast_rtp_get_peer(rtp, &p->redirip); else diff --git a/frame.c b/frame.c index 41030aaca9..e5b4840c1b 100644 --- a/frame.c +++ b/frame.c @@ -1299,3 +1299,28 @@ int ast_frame_slinear_sum(struct ast_frame *f1, struct ast_frame *f2) return 0; } + +struct ast_frame *ast_frame_enqueue(struct ast_frame *head, struct ast_frame *f, int maxlen, int dupe) +{ + struct ast_frame *cur, *oldhead; + int len=0; + if (f && dupe) + f = ast_frdup(f); + if (!f) + return head; + + f->next = NULL; + if (!head) + return f; + cur = head; + while(cur->next) { + cur = cur->next; + len++; + if (len >= maxlen) { + oldhead = head; + head = head->next; + ast_frfree(oldhead); + } + } + return head; +} diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h index 62c0b0dc06..c0815732b8 100644 --- a/include/asterisk/frame.h +++ b/include/asterisk/frame.h @@ -452,6 +452,10 @@ extern int ast_codec_get_samples(struct ast_frame *f); /*! \brief Returns the number of bytes for the number of samples of the given format */ extern int ast_codec_get_len(int format, int samples); +/*! \brief Appends a frame to the end of a list of frames, truncating the maximum length of the list */ +extern struct ast_frame *ast_frame_enqueue(struct ast_frame *head, struct ast_frame *f, int maxlen, int dupe); + + /*! \brief Gets duration in ms of interpolation frame for a format */ static inline int ast_codec_interp_len(int format) { diff --git a/include/asterisk/rtp.h b/include/asterisk/rtp.h index bdb0391fd9..9654806ebf 100644 --- a/include/asterisk/rtp.h +++ b/include/asterisk/rtp.h @@ -135,7 +135,6 @@ void ast_rtp_set_rtpmap_type(struct ast_rtp* rtp, int pt, /* Mapping between RTP payload format codes and Asterisk codes: */ struct rtpPayloadType ast_rtp_lookup_pt(struct ast_rtp* rtp, int pt); int ast_rtp_lookup_code(struct ast_rtp* rtp, int isAstFormat, int code); -void ast_rtp_offered_from_local(struct ast_rtp* rtp, int local); void ast_rtp_get_current_formats(struct ast_rtp* rtp, int* astFormats, int* nonAstFormats); @@ -154,6 +153,8 @@ int ast_rtp_proto_register(struct ast_rtp_protocol *proto); void ast_rtp_proto_unregister(struct ast_rtp_protocol *proto); +int ast_rtp_make_compatible(struct ast_channel *dest, struct ast_channel *src); + void ast_rtp_stop(struct ast_rtp *rtp); void ast_rtp_init(void); diff --git a/rtp.c b/rtp.c index 0c475ed980..2223f8ffde 100644 --- a/rtp.c +++ b/rtp.c @@ -124,7 +124,6 @@ struct ast_rtp { int rtp_lookup_code_cache_isAstFormat; int rtp_lookup_code_cache_code; int rtp_lookup_code_cache_result; - int rtp_offered_from_local; struct ast_rtcp *rtcp; }; @@ -724,10 +723,98 @@ void ast_rtp_pt_default(struct ast_rtp* rtp) rtp->rtp_lookup_code_cache_result = 0; } +static void ast_rtp_pt_copy(struct ast_rtp *dest, struct ast_rtp *src) +{ + int i; + /* Copy payload types from source to destination */ + for (i=0; i < MAX_RTP_PT; ++i) { + dest->current_RTP_PT[i].isAstFormat = + src->current_RTP_PT[i].isAstFormat; + dest->current_RTP_PT[i].code = + src->current_RTP_PT[i].code; + } + dest->rtp_lookup_code_cache_isAstFormat = 0; + dest->rtp_lookup_code_cache_code = 0; + dest->rtp_lookup_code_cache_result = 0; +} + +/*--- get_proto: Get channel driver interface structure */ +static struct ast_rtp_protocol *get_proto(struct ast_channel *chan) +{ + struct ast_rtp_protocol *cur; + + cur = protos; + while(cur) { + if (cur->type == chan->type) { + return cur; + } + cur = cur->next; + } + return NULL; +} + +int ast_rtp_make_compatible(struct ast_channel *dest, struct ast_channel *src) +{ + struct ast_rtp *destp, *srcp; /* Audio RTP Channels */ + struct ast_rtp *vdestp, *vsrcp; /* Video RTP channels */ + struct ast_rtp_protocol *destpr, *srcpr; + /* Lock channels */ + ast_mutex_lock(&dest->lock); + while(ast_mutex_trylock(&src->lock)) { + ast_mutex_unlock(&dest->lock); + usleep(1); + ast_mutex_lock(&dest->lock); + } + + /* Find channel driver interfaces */ + destpr = get_proto(dest); + srcpr = get_proto(src); + if (!destpr) { + ast_log(LOG_DEBUG, "Channel '%s' has no RTP, not doing anything\n", dest->name); + ast_mutex_unlock(&dest->lock); + ast_mutex_unlock(&src->lock); + return 0; + } + if (!srcpr) { + ast_log(LOG_WARNING, "Channel '%s' has no RTP, not doing anything\n", src->name); + ast_mutex_unlock(&dest->lock); + ast_mutex_unlock(&src->lock); + return 0; + } + + /* Get audio and video interface (if native bridge is possible) */ + destp = destpr->get_rtp_info(dest); + if (destpr->get_vrtp_info) + vdestp = destpr->get_vrtp_info(dest); + else + vdestp = NULL; + srcp = srcpr->get_rtp_info(src); + if (srcpr->get_vrtp_info) + vsrcp = srcpr->get_vrtp_info(src); + else + vsrcp = NULL; + + /* Check if bridge is still possible (In SIP canreinvite=no stops this, like NAT) */ + if (!destp || !srcp) { + /* Somebody doesn't want to play... */ + ast_mutex_unlock(&dest->lock); + ast_mutex_unlock(&src->lock); + return 0; + } + ast_rtp_pt_copy(destp, srcp); + if (vdestp && vsrcp) + ast_rtp_pt_copy(vdestp, vsrcp); + ast_mutex_unlock(&dest->lock); + ast_mutex_unlock(&src->lock); + ast_log(LOG_DEBUG, "Seeded SDP of '%s' with that of '%s'\n", dest->name, src->name); + return 1; +} + /* Make a note of a RTP paymoad type that was seen in a SDP "m=" line. */ /* By default, use the well-known value for this type (although it may */ /* still be set to a different value by a subsequent "a=rtpmap:" line): */ -void ast_rtp_set_m_type(struct ast_rtp* rtp, int pt) { +void ast_rtp_set_m_type(struct ast_rtp* rtp, int pt) +{ if (pt < 0 || pt > MAX_RTP_PT) return; /* bogus payload type */ @@ -739,7 +826,9 @@ void ast_rtp_set_m_type(struct ast_rtp* rtp, int pt) { /* Make a note of a RTP payload type (with MIME type) that was seen in */ /* a SDP "a=rtpmap:" line. */ void ast_rtp_set_rtpmap_type(struct ast_rtp* rtp, int pt, - char* mimeType, char* mimeSubtype) { + char* mimeType, char* mimeSubtype) + +{ int i; if (pt < 0 || pt > MAX_RTP_PT) @@ -770,13 +859,6 @@ void ast_rtp_get_current_formats(struct ast_rtp* rtp, } } -void ast_rtp_offered_from_local(struct ast_rtp* rtp, int local) { - if (rtp) - rtp->rtp_offered_from_local = local; - else - ast_log(LOG_WARNING, "rtp structure is null\n"); -} - struct rtpPayloadType ast_rtp_lookup_pt(struct ast_rtp* rtp, int pt) { struct rtpPayloadType result; @@ -786,8 +868,7 @@ struct rtpPayloadType ast_rtp_lookup_pt(struct ast_rtp* rtp, int pt) return result; /* bogus payload type */ /* Start with the negotiated codecs */ - if (!rtp->rtp_offered_from_local) - result = rtp->current_RTP_PT[pt]; + result = rtp->current_RTP_PT[pt]; /* If it doesn't exist, check our static RTP type list, just in case */ if (!result.code) @@ -829,7 +910,8 @@ int ast_rtp_lookup_code(struct ast_rtp* rtp, const int isAstFormat, const int co return -1; } -char* ast_rtp_lookup_mime_subtype(const int isAstFormat, const int code) { +char* ast_rtp_lookup_mime_subtype(const int isAstFormat, const int code) +{ int i; @@ -1485,21 +1567,6 @@ int ast_rtp_proto_register(struct ast_rtp_protocol *proto) return 0; } -/*--- get_proto: Get channel driver interface structure */ -static struct ast_rtp_protocol *get_proto(struct ast_channel *chan) -{ - struct ast_rtp_protocol *cur; - - cur = protos; - while(cur) { - if (cur->type == chan->type) { - return cur; - } - cur = cur->next; - } - return NULL; -} - /* ast_rtp_bridge: Bridge calls. If possible and allowed, initiate re-invite so the peers exchange media directly outside of Asterisk. */ @@ -1698,11 +1765,11 @@ enum ast_bridge_result ast_rtp_bridge(struct ast_channel *c0, struct ast_channel *rc = who; if (option_debug) ast_log(LOG_DEBUG, "Oooh, got a %s\n", f ? "digit" : "hangup"); - if ((c0->tech_pvt == pvt0) && (!c0->_softhangup)) { + if ((c0->tech_pvt == pvt0)) { if (pr0->set_rtp_peer(c0, NULL, NULL, 0, 0)) ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c0->name); } - if ((c1->tech_pvt == pvt1) && (!c1->_softhangup)) { + if ((c1->tech_pvt == pvt1)) { if (pr1->set_rtp_peer(c1, NULL, NULL, 0, 0)) ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c1->name); }