/*
  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;
}
