Index: channels/chan_sip.c =================================================================== --- channels/chan_sip.c (revision 149) +++ channels/chan_sip.c (working copy) @@ -1071,9 +1071,8 @@ #define SIP_PAGE2_T38SUPPORT_TCP (4 << 20) /*!< GDP: T38 Fax Passthrough Support (not implemented) */ #define SIP_PAGE2_CALL_ONHOLD (3 << 23) /*!< D: Call hold states: */ -#define SIP_PAGE2_CALL_ONHOLD_ACTIVE (1 << 23) /*!< D: Active hold */ -#define SIP_PAGE2_CALL_ONHOLD_ONEDIR (2 << 23) /*!< D: One directional hold */ -#define SIP_PAGE2_CALL_ONHOLD_INACTIVE (3 << 23) /*!< D: Inactive hold */ +#define SIP_PAGE2_CALL_ONHOLD_DONTSEND (1 << 23) /*!< D: Don't send any RTP - Conventional i/c HOLD */ +#define SIP_PAGE2_CALL_ONHOLD_DONTRECV (2 << 23) /*!< D: Don't receive any RTP */ #define SIP_PAGE2_RFC2833_COMPENSATE (1 << 25) /*!< DP: Compensate for buggy RFC2833 implementations */ #define SIP_PAGE2_BUGGY_MWI (1 << 26) /*!< DP: Buggy CISCO MWI fix */ @@ -1090,6 +1089,19 @@ /*@}*/ +/*! \name SIPflags3 + a third page of flags (for flags[1] */ +/*@{*/ + +#define SIP_PAGE3_CALL_LCL_ONHOLD (3 << 1) /*!< D: Call hold states: */ +#define SIP_PAGE3_CALL_LCL_ONHOLD_DONTSEND (1 << 1) /*!< D: Don't send any RTP */ +#define SIP_PAGE3_CALL_LCL_ONHOLD_DONTRECV (2 << 1) /*!< D: Don't receive any RTP - o/g HOLD */ +#define SIP_PAGE3_SDP_RECEIVED (1 << 3) /*!< D: Last Incoming Invite contained SDP */ + +#define SIP_PAGE3_FLAGS_TO_COPY \ + (0) + +/*@}*/ /*! \name SIPflagsT38 T.38 set of flags */ @@ -1307,7 +1319,7 @@ ast_group_t pickupgroup; /*!< Pickup group */ int lastinvite; /*!< Last Cseq of invite */ int lastnoninvite; /*!< Last Cseq of non-invite */ - struct ast_flags flags[2]; /*!< SIP_ flags */ + struct ast_flags flags[3]; /*!< SIP_ flags */ /* boolean or small integers that don't belong in flags */ char do_history; /*!< Set if we want to record history */ @@ -1542,7 +1554,7 @@ struct ast_codec_pref prefs; /*!< codec prefs */ int lastmsgssent; unsigned int sipoptions; /*!< Supported SIP options */ - struct ast_flags flags[2]; /*!< SIP_ flags */ + struct ast_flags flags[3]; /*!< SIP_ flags */ /*! Mailboxes that this peer cares about */ AST_LIST_HEAD_NOLOCK(, sip_mailbox) mailboxes; @@ -1956,7 +1968,7 @@ static void add_noncodec_to_sdp(const struct sip_pvt *p, int format, int sample_rate, struct ast_str **m_buf, struct ast_str **a_buf, int debug); -static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int oldsdp, int add_audio, int add_t38); +static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int oldsdp, int add_audio, int add_t38, int sdp_received); static void do_setnat(struct sip_pvt *p, int natflags); static void stop_media_flows(struct sip_pvt *p); @@ -1993,6 +2005,7 @@ static int sip_refer_allocate(struct sip_pvt *p); static void ast_quiet_chan(struct ast_channel *chan); static int attempt_transfer(struct sip_dual *transferer, struct sip_dual *target); +static int set_outgoing_hold(struct sip_pvt *p, int hold_mode); /*! * \brief generic function for determining if a correct transport is being * used to contact a peer @@ -4323,6 +4336,7 @@ ast_copy_flags(&dialog->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY); ast_copy_flags(&dialog->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY); + ast_copy_flags(&dialog->flags[2], &peer->flags[2], SIP_PAGE3_FLAGS_TO_COPY); dialog->capability = peer->capability; if (!ast_test_flag(&dialog->flags[1], SIP_PAGE2_VIDEOSUPPORT_ALWAYS) && (!ast_test_flag(&dialog->flags[1], SIP_PAGE2_VIDEOSUPPORT) || @@ -4682,7 +4696,7 @@ if (sip_debug_test_pvt(p)) ast_verbose("Really destroying SIP dialog '%s' Method: %s\n", p->callid, sip_methods[p->method].text); - if (ast_test_flag(&p->flags[0], SIP_INC_COUNT) || ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD)) { + if (ast_test_flag(&p->flags[0], SIP_INC_COUNT) || ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD_DONTSEND)) { update_call_counter(p, DEC_CALL_LIMIT); ast_debug(2, "This call did not properly clean up call limits. Call ID %s\n", p->callid); } @@ -4813,7 +4827,7 @@ /* Test if we need to check call limits, in order to avoid realtime lookups if we do not need it */ - if (!ast_test_flag(&fup->flags[0], SIP_CALL_LIMIT) && !ast_test_flag(&fup->flags[1], SIP_PAGE2_CALL_ONHOLD)) + if (!ast_test_flag(&fup->flags[0], SIP_CALL_LIMIT) && !ast_test_flag(&fup->flags[1], SIP_PAGE2_CALL_ONHOLD_DONTSEND)) return 0; ast_copy_string(name, fup->username, sizeof(name)); @@ -4868,8 +4882,11 @@ /* Decrement onhold count if applicable */ sip_pvt_lock(fup); ao2_lock(p); - if (ast_test_flag(&fup->flags[1], SIP_PAGE2_CALL_ONHOLD) && global_notifyhold) { - ast_clear_flag(&fup->flags[1], SIP_PAGE2_CALL_ONHOLD); + + /* When does ONHOLD get set without SIP_INC_COUNT? */ + + if (ast_test_flag(&fup->flags[1], SIP_PAGE2_CALL_ONHOLD_DONTSEND) && global_notifyhold) { + ast_clear_flag(&fup->flags[1], SIP_PAGE2_CALL_ONHOLD_DONTSEND); ao2_unlock(p); sip_pvt_unlock(fup); sip_peer_hold(fup, FALSE); @@ -5145,7 +5162,7 @@ p->hangupcause = p->owner->hangupcause; if (ast_test_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER)) { - if (ast_test_flag(&p->flags[0], SIP_INC_COUNT) || ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD)) { + if (ast_test_flag(&p->flags[0], SIP_INC_COUNT) || ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD_DONTSEND)) { if (sipdebug) ast_debug(1, "update_call_counter(%s) - decrement call limit counter on hangup\n", p->username); update_call_counter(p, DEC_CALL_LIMIT); @@ -5172,7 +5189,7 @@ ast_debug(1, "Hangup call %s, SIP callid %s\n", ast->name, p->callid); sip_pvt_lock(p); - if (ast_test_flag(&p->flags[0], SIP_INC_COUNT) || ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD)) { + if (ast_test_flag(&p->flags[0], SIP_INC_COUNT) || ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD_DONTSEND)) { if (sipdebug) ast_debug(1, "update_call_counter(%s) - decrement call limit counter on hangup\n", p->username); update_call_counter(p, DEC_CALL_LIMIT); @@ -5556,6 +5573,37 @@ return res; } +/*! \brief Change the hold status we are outputting */ +static int set_outgoing_hold(struct sip_pvt *p, int do_hold) +{ + /* As we are not going to send MOH, an inactive + hold would be more logical, but Philips switches + only recognize sendonly as initiating a hold! */ + + if (do_hold) { + if (ast_test_flag(&p->flags[2], SIP_PAGE3_CALL_LCL_ONHOLD_DONTRECV)) { + return 0; /* already requested */ + } + ast_set_flag(&p->flags[2], SIP_PAGE3_CALL_LCL_ONHOLD_DONTRECV); + } else { + if (!ast_test_flag(&p->flags[2], SIP_PAGE3_CALL_LCL_ONHOLD_DONTRECV)) { + return 0; /* already requested */ + } + ast_clear_flag(&p->flags[2], SIP_PAGE3_CALL_LCL_ONHOLD_DONTRECV); + } + + if (!p->pendinginvite) { /* We are up, and have no outstanding invite */ + return transmit_reinvite_with_sdp(p, FALSE, FALSE); + + /* I'm not sure that SIP_PENDINGBYE is an issue here, and if it + is, maybe we should have checked earlier! */ + + } else if (!ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) { + ast_set_flag(&p->flags[0], SIP_NEEDREINVITE); + } + return 0; +} + /*! \brief Transfer SIP call */ static int sip_transfer(struct ast_channel *ast, const char *dest) { @@ -6253,6 +6301,7 @@ /* Copy global flags to this PVT at setup. */ ast_copy_flags(&p->flags[0], &global_flags[0], SIP_FLAGS_TO_COPY); ast_copy_flags(&p->flags[1], &global_flags[1], SIP_PAGE2_FLAGS_TO_COPY); + ast_copy_flags(&p->flags[2], &global_flags[2], SIP_PAGE3_FLAGS_TO_COPY); p->do_history = recordhistory; @@ -6885,7 +6934,12 @@ int codec; int destiterator = 0; int iterator; - int sendonly = -1; + int peerdontrecv = FALSE; + int peerdontsend = FALSE; + int dontrecv = ast_test_flag(&p->flags[2], SIP_PAGE3_CALL_LCL_ONHOLD_DONTRECV) != 0; + int dontsend = ast_test_flag(&p->flags[2], SIP_PAGE3_CALL_LCL_ONHOLD_DONTSEND) != 0; + int jointdontrecv; + int jointdontsend; int numberofports; struct ast_rtp *newaudiortp, *newvideortp, *newtextrtp; /* Buffers for codec handling */ int newjointcapability; /* Negotiated capability */ @@ -7231,17 +7285,21 @@ continue; } if (!strcasecmp(a, "sendonly")) { - if (sendonly == -1) - sendonly = 1; + peerdontrecv = TRUE; + peerdontsend = FALSE; continue; } else if (!strcasecmp(a, "inactive")) { - if (sendonly == -1) - sendonly = 2; + peerdontrecv = TRUE; + peerdontsend = TRUE; continue; } else if (!strcasecmp(a, "sendrecv")) { - if (sendonly == -1) - sendonly = 0; + peerdontrecv = FALSE; + peerdontsend = FALSE; continue; + } else if (!strcasecmp(a, "recvonly")) { + peerdontrecv = FALSE; + peerdontsend = TRUE; + continue; } else if (strlen(a) > 5 && !strncasecmp(a, "ptime", 5)) { char *tmp = strrchr(a, ':'); long int framing = 0; @@ -7569,8 +7627,11 @@ ast_set_read_format(p->owner, p->owner->readformat); ast_set_write_format(p->owner, p->owner->writeformat); } + + jointdontrecv = dontrecv || peerdontsend; + jointdontsend = dontsend || peerdontrecv; - if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) && sin.sin_addr.s_addr && (!sendonly || sendonly == -1)) { + if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD_DONTSEND) && sin.sin_addr.s_addr && (!jointdontsend)) { ast_queue_control(p->owner, AST_CONTROL_UNHOLD); /* Activate a re-invite */ ast_queue_frame(p->owner, &ast_null_frame); @@ -7585,20 +7646,19 @@ p->owner->uniqueid); if (global_notifyhold) sip_peer_hold(p, FALSE); - ast_clear_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD); /* Clear both flags */ - } else if (!sin.sin_addr.s_addr || (sendonly && sendonly != -1)) { - int already_on_hold = ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD); + } else if (!sin.sin_addr.s_addr || (jointdontsend)) { + int already_on_hold = ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD_DONTSEND); ast_queue_control_data(p->owner, AST_CONTROL_HOLD, S_OR(p->mohsuggest, NULL), !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0); - if (sendonly) + if (jointdontsend) ast_rtp_stop(p->rtp); /* RTCP needs to go ahead, even if we're on hold!!! */ /* Activate a re-invite */ ast_queue_frame(p->owner, &ast_null_frame); /* Queue Manager Hold event */ append_history(p, "Hold", "%s", req->data->str); - if (global_callevents && !ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD)) { + if (global_callevents && !already_on_hold) { manager_event(EVENT_FLAG_CALL, "Hold", "Status: On\r\n" "Channel: %s\r\n" @@ -7606,15 +7666,45 @@ p->owner->name, p->owner->uniqueid); } - if (sendonly == 1) /* One directional hold (sendonly/recvonly) */ - ast_set_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD_ONEDIR); - else if (sendonly == 2) /* Inactive stream */ - ast_set_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD_INACTIVE); - else - ast_set_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD_ACTIVE); if (global_notifyhold && !already_on_hold) sip_peer_hold(p, TRUE); } + + /* If, for example, we want to make an enquiry down the same "line" + as an incoming call, we need to know when the other side has + definitely accepted that it is on hold. */ + + if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD_DONTRECV) ) { + /* Queue Manager Unhold event */ + append_history(p, "RemoteUnhold", "%s", req->data->str); + if (global_callevents) + manager_event(EVENT_FLAG_CALL, "RemoteHeld", + "Status: Off\r\n" + "Channel: %s\r\n" + "Uniqueid: %s\r\n", + p->owner->name, + p->owner->uniqueid); + } else if (jointdontrecv) { + int already_on_hold = ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD_DONTRECV); + append_history(p, "RemoteHold", "%s", req->data->str); + if (global_callevents && !already_on_hold) { + manager_event(EVENT_FLAG_CALL, "RemoteHeld", + "Status: On\r\n" + "Channel: %s\r\n" + "Uniqueid: %s\r\n", + p->owner->name, + p->owner->uniqueid); + } + } + + if (jointdontrecv) /* We shouldn't receive anything */ + ast_set_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD_DONTRECV); + else + ast_clear_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD_DONTRECV); + if (jointdontsend) /* We shouldn't send anything */ + ast_set_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD_DONTSEND); + else + ast_clear_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD_DONTSEND); return 0; } @@ -8601,7 +8691,7 @@ is used in Session-Timers where RE-INVITEs are used for refreshing SIP sessions without modifying the media session in any way. */ -static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int oldsdp, int add_audio, int add_t38) +static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int oldsdp, int add_audio, int add_t38, int sdp_received) { int len = 0; int alreadysent = 0; @@ -8752,13 +8842,41 @@ ast_str_append(&m_audio, 0, "m=audio %d RTP/AVP", ntohs(dest.sin_port)); - if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) == SIP_PAGE2_CALL_ONHOLD_ONEDIR) - hold = "a=recvonly\r\n"; - else if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) == SIP_PAGE2_CALL_ONHOLD_INACTIVE) - hold = "a=inactive\r\n"; - else - hold = "a=sendrecv\r\n"; + if (sdp_received) { /* Negotiated result */ + + switch (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD)) { + case 0: + hold = "a=sendrecv\r\n"; + break; + case SIP_PAGE2_CALL_ONHOLD_DONTRECV: + hold = "a=sendonly\r\n"; + break; + case SIP_PAGE2_CALL_ONHOLD_DONTSEND: + hold = "a=recvonly\r\n"; + break; + default: + hold = "a=inactive\r\n"; + break; + } + } else { /* Initial offer */ + + switch (ast_test_flag(&p->flags[2], SIP_PAGE3_CALL_LCL_ONHOLD)) { + case 0: + hold = "a=sendrecv\r\n"; + break; + case SIP_PAGE3_CALL_LCL_ONHOLD_DONTRECV: + hold = "a=sendonly\r\n"; + break; + case SIP_PAGE3_CALL_LCL_ONHOLD_DONTSEND: + hold = "a=recvonly\r\n"; + break; + default: + hold = "a=inactive\r\n"; + break; + } + } + /* Now, start adding audio codecs. These are added in this order: - First what was requested by the calling channel - Then preferences in order from sip.conf device config for this peer/user @@ -8959,8 +9077,10 @@ } respprep(&resp, p, msg, req); if (p->udptl) { + int have_received_sdp = ast_test_flag(&p->flags[2], SIP_PAGE3_SDP_RECEIVED); + ast_udptl_offered_from_local(p->udptl, 0); - add_sdp(&resp, p, 0, 0, 1); + add_sdp(&resp, p, 0, 0, 1, have_received_sdp); } else ast_log(LOG_ERROR, "Can't add SDP to response, since we have no UDPTL session allocated. Call-ID %s\n", p->callid); if (retrans && !p->pendinginvite) @@ -9005,15 +9125,17 @@ } respprep(&resp, p, msg, req); if (p->rtp) { + int have_received_sdp = ast_test_flag(&p->flags[2], SIP_PAGE3_SDP_RECEIVED); + if (!p->autoframing && !ast_test_flag(&p->flags[0], SIP_OUTGOING)) { ast_debug(1, "Setting framing from config on incoming call\n"); ast_rtp_codec_setpref(p->rtp, &p->prefs); } try_suggested_sip_codec(p); if (p->t38.state == T38_PEER_DIRECT || p->t38.state == T38_ENABLED) { - add_sdp(&resp, p, oldsdp, TRUE, TRUE); + add_sdp(&resp, p, oldsdp, TRUE, TRUE, have_received_sdp); } else { - add_sdp(&resp, p, oldsdp, TRUE, FALSE); + add_sdp(&resp, p, oldsdp, TRUE, FALSE, have_received_sdp); } } else ast_log(LOG_ERROR, "Can't add SDP to response, since we have no RTP session allocated. Call-ID %s\n", p->callid); @@ -9096,9 +9218,9 @@ if (p->do_history) append_history(p, "ReInv", "Re-invite sent"); if (t38version) - add_sdp(&req, p, oldsdp, FALSE, TRUE); + add_sdp(&req, p, oldsdp, FALSE, TRUE, FALSE); else - add_sdp(&req, p, oldsdp, TRUE, FALSE); + add_sdp(&req, p, oldsdp, TRUE, FALSE, FALSE); /* Use this as the basis */ initialize_initreq(p, &req); @@ -9494,9 +9616,9 @@ if (p->udptl && p->t38.state == T38_LOCAL_REINVITE) { ast_udptl_offered_from_local(p->udptl, 1); ast_debug(1, "T38 is in state %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : ""); - add_sdp(&req, p, FALSE, FALSE, TRUE); + add_sdp(&req, p, FALSE, FALSE, TRUE, FALSE); } else if (p->rtp) - add_sdp(&req, p, FALSE, TRUE, FALSE); + add_sdp(&req, p, FALSE, TRUE, FALSE, FALSE); } else { if (!p->notify_headers) { add_header_contentLength(&req, 0); @@ -12249,6 +12371,7 @@ /* Take the peer */ ast_copy_flags(&p->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY); ast_copy_flags(&p->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY); + ast_copy_flags(&p->flags[2], &peer->flags[2], SIP_PAGE3_FLAGS_TO_COPY); /* Copy SIP extensions profile to peer */ /* XXX is this correct before a successful auth ? */ @@ -12285,6 +12408,7 @@ if (!(res = check_auth(p, req, peer->name, p->peersecret, p->peermd5secret, sipmethod, uri2, reliable, req->ignore))) { ast_copy_flags(&p->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY); ast_copy_flags(&p->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY); + ast_copy_flags(&p->flags[2], &peer->flags[2], SIP_PAGE3_FLAGS_TO_COPY); /* If we have a call limit, set flag */ if (peer->call_limit) ast_set_flag(&p->flags[0], SIP_CALL_LIMIT); @@ -14424,7 +14548,9 @@ S_OR(cur->username, S_OR(cur->cid_num, "(None)")), cur->callid, ast_getformatname_multiple(formatbuf, sizeof(formatbuf), cur->owner ? cur->owner->nativeformats : 0), - cli_yesno(ast_test_flag(&cur->flags[1], SIP_PAGE2_CALL_ONHOLD)), + + /* Maybe should reflect all four dialog direction states here? */ + cli_yesno(ast_test_flag(&cur->flags[1], SIP_PAGE2_CALL_ONHOLD_DONTSEND)), cur->needdestroy ? "(d)" : "", cur->lastmsg , referstatus @@ -16257,19 +16383,19 @@ /* Return to the current call onhold */ /* Status flag needed to be reset */ ast_log(LOG_NOTICE, "SIP transfer to %s failed, call miserably fails. \n", p->refer->refer_to); - p->needdestroy = 1; p->refer->status = REFER_FAILED; if (p->owner) { ast_queue_control_data(p->owner, AST_CONTROL_TRANSFER, &message, sizeof(message)); } + p->needdestroy = 1; break; case 603: /* Transfer declined */ ast_log(LOG_NOTICE, "SIP transfer to %s declined, call miserably fails. \n", p->refer->refer_to); p->refer->status = REFER_FAILED; - p->needdestroy = 1; if (p->owner) { ast_queue_control_data(p->owner, AST_CONTROL_TRANSFER, &message, sizeof(message)); } + p->needdestroy = 1; break; } } @@ -18133,9 +18259,11 @@ ast_debug(1, "No compatible codecs for this SIP call.\n"); return -1; } + ast_set_flag(&p->flags[2], SIP_PAGE3_SDP_RECEIVED); } else { /* No SDP in invite, call control session */ p->jointcapability = p->capability; ast_debug(2, "No SDP in Invite, third party call control\n"); + ast_clear_flag(&p->flags[2], SIP_PAGE3_SDP_RECEIVED); } /* Queue NULL frame to prod ast_rtp_bridge if appropriate */ @@ -18939,7 +19067,7 @@ return 0; } - if (ast_test_flag(&p->flags[0], SIP_INC_COUNT) || ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD)) + if (ast_test_flag(&p->flags[0], SIP_INC_COUNT) || ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD_DONTSEND)) update_call_counter(p, DEC_CALL_LIMIT); stop_media_flows(p); /* Immediately stop RTP, VRTP and UDPTL as applicable */ @@ -20325,14 +20453,29 @@ for video? It really does belong to the RTP structure. */ + /* If we've told them not to send RTP, or they have said they are + not sending (also allows for delay in responding to our + requesting RTP be turned back on) don't check. + + Maybe we should be timing out RTCP here, but doesn't look to + be code to support that at the moment */ + + if (ast_test_flag(&dialog->flags[1], SIP_PAGE2_CALL_ONHOLD_DONTRECV) || + ast_test_flag(&dialog->flags[2], SIP_PAGE3_CALL_LCL_ONHOLD_DONTRECV)) { + return; /* not expecting any RTP */ + } + /* Check AUDIO RTP timers */ if (dialog->lastrtprx && (ast_rtp_get_rtptimeout(dialog->rtp) || ast_rtp_get_rtpholdtimeout(dialog->rtp)) && (t > dialog->lastrtprx + ast_rtp_get_rtptimeout(dialog->rtp))) { - /* Might be a timeout now -- see if we're on hold */ + /* Might be a timeout now -- see if we're on hold. + I think the presumption is that many phones send + a=sendonly, but then send suppressed silence. */ + struct sockaddr_in sin; ast_rtp_get_peer(dialog->rtp, &sin); - if (!ast_test_flag(&dialog->flags[1], SIP_PAGE2_CALL_ONHOLD) || (ast_rtp_get_rtpholdtimeout(dialog->rtp) && + if (!ast_test_flag(&dialog->flags[1], SIP_PAGE2_CALL_ONHOLD_DONTSEND) || (ast_rtp_get_rtpholdtimeout(dialog->rtp) && (t > dialog->lastrtprx + ast_rtp_get_rtpholdtimeout(dialog->rtp)))) { /* Needs a hangup */ if (ast_rtp_get_rtptimeout(dialog->rtp)) { @@ -20851,6 +20994,7 @@ copy_socket_data(&p->socket, &peer->socket); ast_copy_flags(&p->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY); ast_copy_flags(&p->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY); + ast_copy_flags(&p->flags[2], &peer->flags[2], SIP_PAGE3_FLAGS_TO_COPY); /* Send OPTIONs to peer's fullcontact */ if (!ast_strlen_zero(peer->fullcontact)) @@ -21505,6 +21649,7 @@ peer->type = SIP_TYPE_PEER; ast_copy_flags(&peer->flags[0], &global_flags[0], SIP_FLAGS_TO_COPY); ast_copy_flags(&peer->flags[1], &global_flags[1], SIP_PAGE2_FLAGS_TO_COPY); + ast_copy_flags(&peer->flags[2], &global_flags[2], SIP_PAGE3_FLAGS_TO_COPY); strcpy(peer->context, default_context); strcpy(peer->subscribecontext, default_subscribecontext); strcpy(peer->language, default_language);