/* Send dummy STUN packet to open NAT ports ASAP. */ static void send_stun_packet(SenderData *d, bool_t enable_rtp, bool_t enable_rtcp) { MSStunMessage *msg; mblk_t *mp; RtpSession *s = d->session; char *buf = NULL; int len; if (!d->stun_enabled) return; if (ms_is_multicast_addr((const struct sockaddr *)&s->rtcp.gs.loc_addr)) { ms_debug("Stun packet not sent for session [%p] because of multicast",s); return; } msg = ms_stun_binding_request_create(); len = ms_stun_message_encode(msg, &buf); if (len > 0) { if (enable_rtp) { mp = allocb(len, BPRI_MED); memcpy(mp->b_wptr, buf, len); mp->b_wptr += len; ms_message("Stun packet sent for session [%p]",s); rtp_session_sendm_with_ts(s, mp, 0); } if (enable_rtcp) { mp = allocb(len, BPRI_MED); memcpy(mp->b_wptr, buf, len); mp->b_wptr += len; ms_message("Stun packet sent on rtcp for session [%p]",s); rtp_session_rtcp_sendm_raw(s,mp); } } if (buf != NULL) ms_free(buf); ms_stun_message_destroy(msg); }
static void sender_process(MSFilter * f) { SenderData *d = (SenderData *) f->data; RtpSession *s = d->session; mblk_t *im; uint32_t timestamp; if (s == NULL){ ms_queue_flush(f->inputs[0]); return; } if (d->relay_session_id_size>0 && ( (f->ticker->time-d->last_rsi_time)>5000 || d->last_rsi_time==0) ) { ms_message("relay session id sent in RTCP APP"); rtp_session_send_rtcp_APP(s,0,"RSID",(const uint8_t *)d->relay_session_id,d->relay_session_id_size); d->last_rsi_time=f->ticker->time; } while ((im = ms_queue_get(f->inputs[0])) != NULL) { mblk_t *header; timestamp = get_cur_timestamp(f, mblk_get_timestamp_info(im)); ms_filter_lock(f); if (d->skip) { ms_debug("skipping.."); send_dtmf(f, d->skip_until-d->dtmf_duration, timestamp); d->dtmf_start = FALSE; if (!RTP_TIMESTAMP_IS_NEWER_THAN(timestamp, d->skip_until)) { freemsg(im); ms_filter_unlock(f); continue; } d->skip = FALSE; d->dtmf = 0; } if (d->skip == FALSE && d->mute_mic==FALSE){ int pt = mblk_get_payload_type(im); header = rtp_session_create_packet(s, 12, NULL, 0); if (pt>0) rtp_set_payload_type(header, pt); rtp_set_markbit(header, mblk_get_marker_info(im)); header->b_cont = im; rtp_session_sendm_with_ts(s, header, timestamp); } else{ freemsg(im); } if (d->dtmf != 0) { ms_debug("prepare to send RFC2833 dtmf."); d->skip_until = timestamp + d->dtmf_duration; d->skip = TRUE; d->dtmf_start = TRUE; } ms_filter_unlock(f); } }
static void _sender_process(MSFilter * f) { SenderData *d = (SenderData *) f->data; RtpSession *s = d->session; mblk_t *im; uint32_t timestamp; if (d->relay_session_id_size>0 && ( (f->ticker->time-d->last_rsi_time)>5000 || d->last_rsi_time==0) ) { ms_message("relay session id sent in RTCP APP"); rtp_session_send_rtcp_APP(s,0,"RSID",(const uint8_t *)d->relay_session_id,d->relay_session_id_size); d->last_rsi_time=f->ticker->time; } ms_filter_lock(f); im = ms_queue_get(f->inputs[0]); do { mblk_t *header; timestamp = get_cur_timestamp(f, im); if (d->dtmf != 0 && !d->skip) { ms_debug("prepare to send RFC2833 dtmf."); d->skip_until = timestamp + d->dtmf_duration; d->dtmf_ts_cur=timestamp; d->skip = TRUE; } if (d->skip) { uint32_t origin_ts=d->skip_until-d->dtmf_duration; if (RTP_TIMESTAMP_IS_NEWER_THAN(timestamp,d->dtmf_ts_cur)){ ms_debug("Sending RFC2833 packet, start_timestamp=%u, dtmf_ts_cur=%u",origin_ts,d->dtmf_ts_cur); send_dtmf(f, origin_ts); } } if (im){ if (d->skip == FALSE && d->mute_mic==FALSE){ header = rtp_session_create_packet(s, 12, NULL, 0); rtp_set_markbit(header, mblk_get_marker_info(im)); header->b_cont = im; rtp_session_sendm_with_ts(s, header, timestamp); }else{ freemsg(im); } } }while ((im = ms_queue_get(f->inputs[0])) != NULL); if (d->last_sent_time == -1) { if ((d->last_stun_sent_time == -1) || ((f->ticker->time - d->last_stun_sent_time) >= 500)) { d->last_stun_sent_time = f->ticker->time; } if (d->last_stun_sent_time == f->ticker->time) { send_stun_packet(s); } } ms_filter_unlock(f); }
static void process_cn(MSFilter *f, SenderData *d){ if (d->cng_data.datasize>0){ rtp_header_t *rtp; /* get CN payload type number */ int cn_pt=rtp_profile_find_payload_number(d->session->snd.profile, "CN", 8000, 1); /* create the packet, payload type number is the one used for current codec */ mblk_t *m=rtp_session_create_packet(d->session, 12, d->cng_data.data, d->cng_data.datasize); /* replace payload type in RTP header */ rtp=(rtp_header_t*)m->b_rptr; rtp->paytype = cn_pt; rtp_session_sendm_with_ts(d->session,m,d->last_ts); d->cng_data.datasize=0; } }
/* Send dummy STUN packet to open NAT ports ASAP. */ static void send_stun_packet(RtpSession *s) { StunMessage msg; mblk_t *mp; char buf[STUN_MAX_MESSAGE_SIZE]; int len = STUN_MAX_MESSAGE_SIZE; memset(&msg, 0, sizeof(StunMessage)); stunBuildReqSimple(&msg, NULL, FALSE, FALSE, 1); len = stunEncodeMessage(&msg, buf, len, NULL); if (len > 0) { mp = allocb(len, BPRI_MED); memcpy(mp->b_wptr, buf, len); mp->b_wptr += len; rtp_session_sendm_with_ts(s, mp, 0); } }
/* Send dummy STUN packet to open NAT ports ASAP. */ static void send_stun_packet(RtpSession *s) { StunMessage msg; mblk_t *mp; char buf[STUN_MAX_MESSAGE_SIZE]; int len = STUN_MAX_MESSAGE_SIZE; if (ms_is_multicast_addr((const struct sockaddr *)&s->rtcp.gs.loc_addr)) { ms_debug("Stun packet not sent for session [%p] because of multicast",s); return; } memset(&msg, 0, sizeof(StunMessage)); stunBuildReqSimple(&msg, NULL, FALSE, FALSE, 1); len = stunEncodeMessage(&msg, buf, len, NULL); if (len > 0) { mp = allocb(len, BPRI_MED); memcpy(mp->b_wptr, buf, len); mp->b_wptr += len; ms_message("Stun packet sent for session [%p]",s); rtp_session_sendm_with_ts(s, mp, 0); } }
/** * A variation of rtp_session_send_dtmf() with duration specified. * * @param session a rtp session * @param dtmf a character meaning the dtmf (ex: '1', '#' , '9' ...) * @param userts the timestamp * @param duration duration of the dtmf in timestamp units * @return 0 if successfull, -1 if the session cannot support telephony events or if the dtmf given as argument is not valid. **/ int rtp_session_send_dtmf2(RtpSession *session, char dtmf, uint32_t userts, int duration) { mblk_t *m1,*m2,*m3; int tev_type; int durationtier = duration/3; /* create the first telephony event packet */ switch (dtmf){ case '1': tev_type=TEV_DTMF_1; break; case '2': tev_type=TEV_DTMF_2; break; case '3': tev_type=TEV_DTMF_3; break; case '4': tev_type=TEV_DTMF_4; break; case '5': tev_type=TEV_DTMF_5; break; case '6': tev_type=TEV_DTMF_6; break; case '7': tev_type=TEV_DTMF_7; break; case '8': tev_type=TEV_DTMF_8; break; case '9': tev_type=TEV_DTMF_9; break; case '*': tev_type=TEV_DTMF_STAR; break; case '0': tev_type=TEV_DTMF_0; break; case '#': tev_type=TEV_DTMF_POUND; break; case 'A': case 'a': tev_type=TEV_DTMF_A; break; case 'B': case 'b': tev_type=TEV_DTMF_B; break; case 'C': case 'c': tev_type=TEV_DTMF_C; break; case 'D': case 'd': tev_type=TEV_DTMF_D; break; case '!': tev_type=TEV_FLASH; break; default: ortp_warning("Bad dtmf: %c.",dtmf); return -1; } m1=rtp_session_create_telephone_event_packet(session,1); if (m1==NULL) return -1; rtp_session_add_telephone_event(session,m1,tev_type,0,10,durationtier); /* create a second packet */ m2=rtp_session_create_telephone_event_packet(session,0); if (m2==NULL) return -1; rtp_session_add_telephone_event(session,m2,tev_type,0,10, durationtier+durationtier); /* create a third and final packet */ m3=rtp_session_create_telephone_event_packet(session,0); if (m3==NULL) return -1; rtp_session_add_telephone_event(session,m3,tev_type,1,10,duration); /* and now sends them */ rtp_session_sendm_with_ts(session,m1,userts); rtp_session_sendm_with_ts(session,m2,userts); /* the last packet is sent three times in order to improve reliability*/ m1=copymsg(m3); m2=copymsg(m3); /* NOTE: */ /* we need to copymsg() instead of dupmsg() because the buffers are modified when the packet is sended because of the host-to-network conversion of timestamp,ssrc, csrc, and seq number. */ rtp_session_sendm_with_ts(session,m3,userts); session->rtp.snd_seq--; rtp_session_sendm_with_ts(session,m1,userts); session->rtp.snd_seq--; rtp_session_sendm_with_ts(session,m2,userts); return 0; }
static int send_dtmf(MSFilter * f, uint32_t timestamp_start) { SenderData *d = (SenderData *) f->data; mblk_t *m1; int tev_type; /* create the first telephony event packet */ switch (d->dtmf){ case '1': tev_type=TEV_DTMF_1; break; case '2': tev_type=TEV_DTMF_2; break; case '3': tev_type=TEV_DTMF_3; break; case '4': tev_type=TEV_DTMF_4; break; case '5': tev_type=TEV_DTMF_5; break; case '6': tev_type=TEV_DTMF_6; break; case '7': tev_type=TEV_DTMF_7; break; case '8': tev_type=TEV_DTMF_8; break; case '9': tev_type=TEV_DTMF_9; break; case '*': tev_type=TEV_DTMF_STAR; break; case '0': tev_type=TEV_DTMF_0; break; case '#': tev_type=TEV_DTMF_POUND; break; case 'A': case 'a': tev_type=TEV_DTMF_A; break; case 'B': case 'b': tev_type=TEV_DTMF_B; break; case 'C': case 'c': tev_type=TEV_DTMF_C; break; case 'D': case 'd': tev_type=TEV_DTMF_D; break; case '!': tev_type=TEV_FLASH; break; default: ms_warning("Bad dtmf: %c.",d->dtmf); return -1; } m1=rtp_session_create_telephone_event_packet(d->session,timestamp_start==d->dtmf_ts_cur); if (m1==NULL) return -1; d->dtmf_ts_cur+=d->dtmf_ts_step; if (RTP_TIMESTAMP_IS_NEWER_THAN(d->dtmf_ts_cur, d->skip_until)) { //retransmit end of rtp dtmf event mblk_t *tmp; rtp_session_add_telephone_event(d->session,m1,tev_type,1,10,(d->dtmf_ts_cur-timestamp_start)); tmp=copymsg(m1); rtp_session_sendm_with_ts(d->session,tmp,timestamp_start); d->session->rtp.snd_seq--; tmp=copymsg(m1); rtp_session_sendm_with_ts(d->session,tmp,timestamp_start); d->session->rtp.snd_seq--; rtp_session_sendm_with_ts(d->session,m1,timestamp_start); d->skip = FALSE; d->dtmf = 0; ms_message("Finished sending RFC2833 dtmf %c",d->dtmf); }else { rtp_session_add_telephone_event(d->session,m1,tev_type,0,10,(d->dtmf_ts_cur-timestamp_start)); rtp_session_sendm_with_ts(d->session,m1,timestamp_start); } return 0; }
static void _sender_process(MSFilter * f) { SenderData *d = (SenderData *) f->data; RtpSession *s = d->session; mblk_t *im; uint32_t timestamp; if (d->relay_session_id_size>0 && ( (f->ticker->time-d->last_rsi_time)>5000 || d->last_rsi_time==0) ) { ms_message("relay session id sent in RTCP APP"); rtp_session_send_rtcp_APP(s,0,"RSID",(const uint8_t *)d->relay_session_id,d->relay_session_id_size); d->last_rsi_time=f->ticker->time; } ms_filter_lock(f); im = ms_queue_get(f->inputs[0]); do { mblk_t *header; timestamp = get_cur_timestamp(f, im); if (d->dtmf != 0 && !d->skip) { ms_debug("prepare to send RFC2833 dtmf."); d->skip_until = timestamp + d->dtmf_duration; d->dtmf_ts_cur=timestamp; d->skip = TRUE; } if (d->skip) { uint32_t origin_ts=d->skip_until-d->dtmf_duration; if (RTP_TIMESTAMP_IS_NEWER_THAN(timestamp,d->dtmf_ts_cur)){ ms_debug("Sending RFC2833 packet, start_timestamp=%u, dtmf_ts_cur=%u",origin_ts,d->dtmf_ts_cur); send_dtmf(f, origin_ts); } } if (im){ if (d->skip == FALSE && d->mute==FALSE){ header = rtp_session_create_packet(s, 12, NULL, 0); rtp_set_markbit(header, mblk_get_marker_info(im)); header->b_cont = im; mblk_meta_copy(im, header); rtp_session_sendm_with_ts(s, header, timestamp); } else if (d->mute==TRUE && d->skip == FALSE) { process_cn(f, d, timestamp, im); freemsg(im); //Send STUN packet as RTP keep alive check_stun_sending(f); }else{ freemsg(im); } } else if (d->skip == FALSE) { // Send STUN packet as RTP keep alive even if there is no input check_stun_sending(f); } }while ((im = ms_queue_get(f->inputs[0])) != NULL); if (d->last_sent_time == -1) { check_stun_sending(f); } /*every second, compute output bandwidth*/ if (f->ticker->time % 1000 == 0) rtp_session_compute_send_bandwidth(d->session); ms_filter_unlock(f); }
/** *rtp_session_send_dtmf: *@session : a rtp session *@dtmf : a character meaning the dtmf (ex: '1', '#' , '9' ...) *@userts : the timestamp * * This functions creates telephony events packets for @dtmf and sends them. * It uses rtp_session_create_telephone_event_packet() and * rtp_session_add_telephone_event() to create them and finally * rtp_session_sendm_with_ts() to send them. * *Returns: 0 if successfull, -1 if the session cannot support telephony events or if the dtmf * given as argument is not valid. **/ gint rtp_session_send_dtmf(RtpSession *session, gchar dtmf, guint32 userts) { mblk_t *m1,*m2,*m3; int tev_type; /* create the first telephony event packet */ switch (dtmf){ case '1': tev_type=TEV_DTMF_1; break; case '2': tev_type=TEV_DTMF_2; break; case '3': tev_type=TEV_DTMF_3; break; case '4': tev_type=TEV_DTMF_4; break; case '5': tev_type=TEV_DTMF_5; break; case '6': tev_type=TEV_DTMF_6; break; case '7': tev_type=TEV_DTMF_7; break; case '8': tev_type=TEV_DTMF_8; break; case '9': tev_type=TEV_DTMF_9; break; case '*': tev_type=TEV_DTMF_STAR; break; case '0': tev_type=TEV_DTMF_0; break; case '#': tev_type=TEV_DTMF_POUND; break; default: g_warning("Bad dtmf: %c.",dtmf); return -1; } m1=rtp_session_create_telephone_event_packet(session,1); if (m1==NULL) return -1; rtp_session_add_telephone_event(session,m1,tev_type,0,0,160); /* create a second packet */ m2=rtp_session_create_telephone_event_packet(session,0); if (m2==NULL) return -1; rtp_session_add_telephone_event(session,m2,tev_type,0,0,320); /* create a third and final packet */ m3=rtp_session_create_telephone_event_packet(session,0); if (m3==NULL) return -1; rtp_session_add_telephone_event(session,m3,tev_type,1,0,480); /* and now sends them */ rtp_session_sendm_with_ts(session,m1,userts); rtp_session_sendm_with_ts(session,m2,userts); /* the last packet is sent three times in order to improve reliability*/ m1=copymsg(m3); m2=copymsg(m3); /* NOTE: */ /* we need to copymsg() instead of dupmsg() because the buffers are modified when the packet is sended because of the host-to-network conversion of timestamp,ssrc, csrc, and seq number. It could be avoided by making a copy of the buffer when sending physically the packet, but it add one more copy for every buffer. Using iomapped socket, it is possible to avoid the user to kernel copy. */ rtp_session_sendm_with_ts(session,m3,userts); rtp_session_sendm_with_ts(session,m1,userts); rtp_session_sendm_with_ts(session,m2,userts); return 0; }