blob: 5e781ffe6e39473d01a8d94d5b200b1ca3c414e2 [file] [log] [blame]
/*
The mediastreamer library aims at providing modular media processing and I/O
for linphone, but also for any telephony application.
Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "msrtpsend.h"
#include <ortp/telephonyevents.h>
#include "mssync.h"
#include "mscodec.h"
static MSRtpSendClass *ms_rtp_send_class=NULL;
MSFilter * ms_rtp_send_new(void)
{
MSRtpSend *r;
r=g_new(MSRtpSend,1);
if (ms_rtp_send_class==NULL)
{
ms_rtp_send_class=g_new(MSRtpSendClass,1);
ms_rtp_send_class_init(ms_rtp_send_class);
}
MS_FILTER(r)->klass=MS_FILTER_CLASS(ms_rtp_send_class);
ms_rtp_send_init(r);
return(MS_FILTER(r));
}
void ms_rtp_send_init(MSRtpSend *r)
{
ms_filter_init(MS_FILTER(r));
MS_FILTER(r)->infifos=r->f_inputs;
MS_FILTER(r)->inqueues=r->q_inputs;
MS_FILTER(r)->r_mingran=MSRTPSEND_DEF_GRAN;
memset(r->f_inputs,0,sizeof(MSFifo*)*MSRTPSEND_MAX_INPUTS);
memset(r->q_inputs,0,sizeof(MSFifo*)*MSRTPSEND_MAX_INPUTS);
r->rtpsession=NULL;
r->ts=0;
r->ts_inc=0;
r->flags=0;
r->delay=0;
}
void ms_rtp_send_class_init(MSRtpSendClass *klass)
{
ms_filter_class_init(MS_FILTER_CLASS(klass));
ms_filter_class_set_name(MS_FILTER_CLASS(klass),"RTPSend");
MS_FILTER_CLASS(klass)->max_qinputs=MSRTPSEND_MAX_INPUTS;
MS_FILTER_CLASS(klass)->max_finputs=MSRTPSEND_MAX_INPUTS;
MS_FILTER_CLASS(klass)->r_maxgran=MSRTPSEND_DEF_GRAN;
MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_rtp_send_destroy;
MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_rtp_send_process;
MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_rtp_send_setup;
}
void ms_rtp_send_set_timing(MSRtpSend *r, guint32 ts_inc, gint payload_size)
{
r->ts_inc=ts_inc;
r->packet_size=payload_size;
if (r->ts_inc!=0) r->flags|=RTPSEND_CONFIGURED;
else r->flags&=~RTPSEND_CONFIGURED;
MS_FILTER(r)->r_mingran=payload_size;
/*g_message("ms_rtp_send_set_timing: ts_inc=%i",ts_inc);*/
}
guint32 get_new_timestamp(MSRtpSend *r,guint32 synctime)
{
guint32 clockts;
/* use the sync system time to compute a timestamp */
PayloadType *pt=rtp_profile_get_payload(r->rtpsession->profile,r->rtpsession->payload_type);
g_return_val_if_fail(pt!=NULL,0);
clockts=(guint32)(((double)synctime * (double)pt->clock_rate)/1000.0);
ms_trace("ms_rtp_send_process: sync->time=%i clock=%i",synctime,clockts);
if (r->flags & RTPSEND_CONFIGURED){
if (RTP_TIMESTAMP_IS_STRICTLY_NEWER_THAN(clockts,r->ts+(2*r->ts_inc) )){
r->ts=clockts;
}
else r->ts+=r->ts_inc;
}else{
r->ts=clockts;
}
return r->ts;
}
void ms_rtp_send_process(MSRtpSend *r)
{
MSFifo *fi;
MSQueue *qi;
MSSync *sync= r->sync;
int gran=ms_sync_get_samples_per_tick(sync);
guint32 ts;
void *s;
guint skip;
guint32 synctime=sync->time;
g_return_if_fail(gran>0);
if (r->rtpsession==NULL) return;
ms_filter_lock(MS_FILTER(r));
skip=r->delay!=0;
if (skip) r->delay--;
/* process output fifo and output queue*/
fi=r->f_inputs[0];
if (fi!=NULL)
{
ts=get_new_timestamp(r,synctime);
/* try to read r->packet_size bytes and send them in a rtp packet*/
ms_fifo_get_read_ptr(fi,r->packet_size,&s);
if (!skip){
rtp_session_send_with_ts(r->rtpsession,s,r->packet_size,ts);
ms_trace("len=%i, ts=%i ",r->packet_size,ts);
}
}
qi=r->q_inputs[0];
if (qi!=NULL)
{
MSMessage *msg;
/* read a MSMessage and send it through the network*/
while ( (msg=ms_queue_get(qi))!=NULL){
ts=get_new_timestamp(r,synctime);
if (!skip) {
/*g_message("Sending packet with ts=%u",ts);*/
rtp_session_send_with_ts(r->rtpsession,msg->data,msg->size,ts);
}
ms_message_destroy(msg);
}
}
ms_filter_unlock(MS_FILTER(r));
}
void ms_rtp_send_destroy( MSRtpSend *obj)
{
g_free(obj);
}
RtpSession * ms_rtp_send_set_session(MSRtpSend *obj,RtpSession *session)
{
RtpSession *old=obj->rtpsession;
obj->rtpsession=session;
obj->ts=0;
obj->ts_inc=0;
return old;
}
void ms_rtp_send_setup(MSRtpSend *r, MSSync *sync)
{
MSFilter *codec;
MSCodecInfo *info;
r->sync=sync;
codec=ms_filter_search_upstream_by_type(MS_FILTER(r),MS_FILTER_AUDIO_CODEC);
if (codec==NULL) codec=ms_filter_search_upstream_by_type(MS_FILTER(r),MS_FILTER_VIDEO_CODEC);
if (codec==NULL){
g_warning("ms_rtp_send_setup: could not find upstream codec.");
return;
}
info=MS_CODEC_INFO(codec->klass->info);
if (info->info.type==MS_FILTER_AUDIO_CODEC){
int ts_inc=info->fr_size/2;
int psize=info->dt_size;
if (ts_inc==0){
/* dont'use the normal frame size: this is a variable frame size codec */
/* use the MS_FILTER(codec)->r_mingran */
ts_inc=MS_FILTER(codec)->r_mingran/2;
psize=0;
}
ms_rtp_send_set_timing(r,ts_inc,psize);
}
}
gint ms_rtp_send_dtmf(MSRtpSend *r, gchar dtmf)
{
gint res;
if (r->rtpsession==NULL) return -1;
if (rtp_session_telephone_events_supported(r->rtpsession)==-1){
g_warning("ERROR : telephone events not supported.\n");
return -1;
}
ms_filter_lock(MS_FILTER(r));
g_message("Sending DTMF.");
res=rtp_session_send_dtmf(r->rtpsession, dtmf, r->ts);
if (res==0){
//r->ts+=r->ts_inc;
r->delay+=2;
}else g_warning("Could not send dtmf.");
ms_filter_unlock(MS_FILTER(r));
return res;
}