diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c index 9deddf5922..a269ec6cc9 100644 --- a/src/mod/endpoints/mod_sofia/rtp.c +++ b/src/mod/endpoints/mod_sofia/rtp.c @@ -32,15 +32,16 @@ #include #include "mod_sofia.h" -#define kBINDADDRESS "bind_address" #define kLOCALADDR "local_addr" #define kLOCALPORT "local_port" #define kREMOTEADDR "remote_addr" #define kREMOTEPORT "remote_port" #define kCODEC "codec" #define kPTIME "ptime" +#define kPT "pt" #define kRFC2833PT "rfc2833_pt" #define kMODE "mode" +#define kRATE "rate" static struct { switch_memory_pool_t *pool; @@ -53,10 +54,15 @@ typedef struct { switch_codec_t read_codec, write_codec; switch_frame_t read_frame; + + switch_rtp_bug_flag_t rtp_bugs; switch_rtp_t *rtp_session; - const char *bind_address; + uint32_t timestamp_send; + + const char *local_address; + const char *remote_address; const char *codec; int ptime; @@ -67,6 +73,8 @@ typedef struct { switch_port_t local_port; switch_port_t remote_port; + switch_payload_t agreed_pt; /*XXX*/ + sofia_dtmf_t dtmf_type; } crtp_private_t; @@ -100,7 +108,7 @@ void crtp_init(switch_loadable_module_interface_t *module_interface) { switch_endpoint_interface_t *endpoint_interface; //switch_api_interface_t *api_interface; - + crtp.pool = module_interface->pool; endpoint_interface = switch_loadable_module_create_interface(module_interface, SWITCH_ENDPOINT_INTERFACE); endpoint_interface->interface_name = "rtp"; @@ -119,11 +127,30 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi { switch_channel_t *channel; char name[128]; - const char *dname = "PCMU"; - uint32_t interval = 20; - crtp_private_t *tech_pvt = NULL; - //const char *l_sdp = switch_event_get_header(var_event, kLSDP); - //const char *codec_string = switch_event_get_header_nil(var_event, kCODECSTRING); + crtp_private_t *tech_pvt = NULL; + + const char *err; + + const char *local_addr = switch_event_get_header_nil(var_event, kLOCALADDR), + *szlocal_port = switch_event_get_header_nil(var_event, kLOCALPORT), + *remote_addr = switch_event_get_header_nil(var_event, kREMOTEADDR), + *szremote_port = switch_event_get_header_nil(var_event, kREMOTEPORT), + *codec = switch_event_get_header_nil(var_event, kCODEC), + *szptime = switch_event_get_header_nil(var_event, kPTIME), + *mode = switch_event_get_header_nil(var_event, kMODE), + *szrfc2833_pt = switch_event_get_header_nil(var_event, kRFC2833PT), + *szrate = switch_event_get_header_nil(var_event, kRATE), + *szpt = switch_event_get_header_nil(var_event, kPT); + + + switch_port_t local_port = !zstr(szlocal_port) ? atoi(szlocal_port) : 0, + remote_port = !zstr(szremote_port) ? atoi(szremote_port) : 0; + + int ptime = !zstr(szptime) ? atoi(szptime) : 0, + rfc2833_pt = !zstr(szrfc2833_pt) ? atoi(szrfc2833_pt) : 0, + rate = !zstr(szrate) ? atoi(szrate) : 8000, + pt = !zstr(szpt) ? atoi(szpt) : 0; + if (!(*new_session = switch_core_session_request(crtp.endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, 0, pool))) { @@ -133,41 +160,45 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi channel = switch_core_session_get_channel(*new_session); - - tech_pvt = switch_core_session_alloc(*new_session, sizeof *tech_pvt); tech_pvt->session = *new_session; tech_pvt->channel = channel; - tech_pvt->bind_address = switch_core_session_strdup(*new_session, switch_event_get_header_nil(var_event, kBINDADDRESS)); + tech_pvt->local_address = switch_core_session_strdup(*new_session, local_addr); + tech_pvt->local_port = local_port; + tech_pvt->remote_address = switch_core_session_strdup(*new_session, remote_addr); + tech_pvt->remote_port = remote_port; + tech_pvt->ptime = ptime; + tech_pvt->agreed_pt = pt; + tech_pvt->dtmf_type = DTMF_2833; /* XXX */ + switch_core_session_set_private(*new_session, tech_pvt); - snprintf(name, sizeof(name), "rtp/ctrl"); /* TODO add addresses */ + snprintf(name, sizeof(name), "rtp/ctrl"); switch_channel_set_name(channel, name); switch_channel_set_state(channel, CS_INIT); if (switch_core_codec_init(&tech_pvt->read_codec, - dname, + codec, NULL, - 8000, - interval, + rate, + ptime, 1, - SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, + /*SWITCH_CODEC_FLAG_ENCODE |*/ SWITCH_CODEC_FLAG_DECODE, NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); goto fail; } else { if (switch_core_codec_init(&tech_pvt->write_codec, - dname, + codec, NULL, - 8000, - interval, + rate, + ptime, 1, - SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, + SWITCH_CODEC_FLAG_ENCODE /*| SWITCH_CODEC_FLAG_DECODE*/, NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); - switch_core_codec_destroy(&tech_pvt->read_codec); goto fail; } } @@ -178,7 +209,15 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi } if (switch_core_session_set_write_codec(*new_session, &tech_pvt->write_codec) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't set write codec?\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't set write codec?\n"); + goto fail; + } + + if (!(tech_pvt->rtp_session = switch_rtp_new(local_addr, local_port, remote_addr, remote_port, tech_pvt->agreed_pt, + tech_pvt->read_codec.implementation->samples_per_packet, ptime * 1000, + flags, "soft", &err, switch_core_session_get_pool(*new_session)))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't setup RTP session: [%s]\n", err); + goto fail; } if (switch_core_session_thread_launch(*new_session) != SWITCH_STATUS_SUCCESS) { @@ -214,7 +253,7 @@ static switch_status_t channel_on_init(switch_core_session_t *session) switch_channel_set_state(channel, CS_ROUTING); - return SWITCH_STATUS_SUCCESS; + return SWITCH_STATUS_SUCCESS; } static switch_status_t channel_on_destroy(switch_core_session_t *session) @@ -240,6 +279,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch { crtp_private_t *tech_pvt; switch_channel_t *channel; + switch_status_t status; channel = switch_core_session_get_channel(session); assert(channel != NULL); @@ -247,6 +287,31 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch tech_pvt = switch_core_session_get_private(session); assert(tech_pvt != NULL); + if (!tech_pvt->rtp_session) { + goto cng; + } + + if (switch_rtp_has_dtmf(tech_pvt->rtp_session)) { + switch_dtmf_t dtmf = { 0 }; + switch_rtp_dequeue_dtmf(tech_pvt->rtp_session, &dtmf); + switch_channel_queue_dtmf(channel, &dtmf); + } + + tech_pvt->read_frame.flags = SFF_NONE; + status = switch_rtp_zerocopy_read_frame(tech_pvt->rtp_session, &tech_pvt->read_frame, flags); + + if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) { + goto cng; + } + +done: + *frame = &tech_pvt->read_frame; + return SWITCH_STATUS_SUCCESS; + +cng: + *frame = &tech_pvt->read_frame; + tech_pvt->read_frame.flags |= SFF_CNG; + tech_pvt->read_frame.datalen = 0; return SWITCH_STATUS_SUCCESS; } @@ -255,6 +320,7 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc { crtp_private_t *tech_pvt; switch_channel_t *channel; + int frames = 0, bytes = 0, samples = 0; channel = switch_core_session_get_channel(session); assert(channel != NULL); @@ -263,8 +329,20 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc assert(tech_pvt != NULL); - return SWITCH_STATUS_SUCCESS; + if (!switch_test_flag(frame, SFF_CNG) && !switch_test_flag(frame, SFF_PROXY_PACKET)) { + if (tech_pvt->read_codec.implementation->encoded_bytes_per_packet) { + bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_packet; + frames = ((int) frame->datalen / bytes); + } else + frames = 1; + + samples = frames * tech_pvt->read_codec.implementation->samples_per_packet; + } + + tech_pvt->timestamp_send += samples; + switch_rtp_write_frame(tech_pvt->rtp_session, frame); + return SWITCH_STATUS_SUCCESS; } static switch_status_t channel_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf) @@ -274,8 +352,20 @@ static switch_status_t channel_send_dtmf(switch_core_session_t *session, const s tech_pvt = switch_core_session_get_private(session); assert(tech_pvt != NULL); + switch(tech_pvt->dtmf_type) { + case DTMF_2833: + { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Enqueuing RFC2833 DTMF %c of length %d\n", dtmf->digit, dtmf->duration); + return switch_rtp_queue_rfc2833(tech_pvt->rtp_session, dtmf); + } + case DTMF_NONE: + default: + { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Discarding DTMF %c of length %d, DTMF type is NONE\n", dtmf->digit, dtmf->duration); + } + } - return SWITCH_STATUS_SUCCESS; + return SWITCH_STATUS_SUCCESS; } static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg)