/*
* Copyright (C) 2010-2011 Mamadou Diop.
*
* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
*	
* This file is part of Open Source Doubango Framework.
*
* DOUBANGO is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*	
* DOUBANGO 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 General Public License for more details.
*	
* You should have received a copy of the GNU General Public License
* along with DOUBANGO.
*
*/

/**@file ProxyProducer.c
 * @brief Audio/Video proxy producers.
 *
 * @author Mamadou Diop <diopmamadou(at)doubango.org>
 *

 */
#include "ProxyProducer.h"

#include "tsk_timer.h"
#include "tsk_memory.h"
#include "tsk_debug.h"
#include "AudioResampler.h"

#include "tinydav/audio/tdav_producer_audio.h"


/* ============ Audio Media Producer Interface ================= */
typedef struct twrap_producer_proxy_audio_s
{
	TDAV_DECLARE_PRODUCER_AUDIO;
	
	uint64_t id;
	tsk_bool_t started;
}
twrap_producer_proxy_audio_t;
#define TWRAP_PRODUCER_PROXY_AUDIO(self) ((twrap_producer_proxy_audio_t*)(self))

static int twrap_producer_proxy_audio_set(tmedia_producer_t* _self, const tmedia_param_t* param)
{
	twrap_producer_proxy_audio_t* self = (twrap_producer_proxy_audio_t*)_self;
	if(param->plugin_type == tmedia_ppt_producer){
		// specific proxy producer
	}
	return tdav_producer_audio_set(TDAV_PRODUCER_AUDIO(self), param);
}

static int twrap_producer_proxy_audio_prepare(tmedia_producer_t* self, const tmedia_codec_t* codec)
{
	ProxyPluginMgr* manager;
	int ret = -1;
	if(codec && (manager = ProxyPluginMgr::getInstance())){
		const ProxyAudioProducer* audioProducer;
		if((audioProducer = manager->findAudioProducer(TWRAP_PRODUCER_PROXY_AUDIO(self)->id)) && audioProducer->getCallback()){
			self->audio.channels = codec->plugin->audio.channels;
			self->audio.rate = codec->plugin->rate;
			self->audio.ptime = codec->plugin->audio.ptime;
			ret = audioProducer->getCallback()->prepare((int)codec->plugin->audio.ptime, codec->plugin->rate, codec->plugin->audio.channels);
		}
	}
	return ret;
}

static int twrap_producer_proxy_audio_start(tmedia_producer_t* self)
{
	ProxyPluginMgr* manager;
	int ret = -1;
	if((manager = ProxyPluginMgr::getInstance())){
		const ProxyAudioProducer* audioProducer;
		if((audioProducer = manager->findAudioProducer(TWRAP_PRODUCER_PROXY_AUDIO(self)->id)) && audioProducer->getCallback()){
			const_cast<ProxyAudioProducer*>(audioProducer)->startPushCallback();
			ret = audioProducer->getCallback()->start();
		}
	}
	
	TWRAP_PRODUCER_PROXY_AUDIO(self)->started = (ret == 0);
	return ret;
}

static int twrap_producer_proxy_audio_pause(tmedia_producer_t* self)
{
	ProxyPluginMgr* manager;
	int ret = -1;
	if((manager = ProxyPluginMgr::getInstance())){
		const ProxyAudioProducer* audioProducer;
		if((audioProducer = manager->findAudioProducer(TWRAP_PRODUCER_PROXY_AUDIO(self)->id)) && audioProducer->getCallback()){
			ret = audioProducer->getCallback()->pause();
		}
	}
	return ret;
}

static int twrap_producer_proxy_audio_stop(tmedia_producer_t* self)
{
	ProxyPluginMgr* manager;
	int ret = -1;
	if((manager = ProxyPluginMgr::getInstance())){
		const ProxyAudioProducer* audioProducer;
		if((audioProducer = manager->findAudioProducer(TWRAP_PRODUCER_PROXY_AUDIO(self)->id)) && audioProducer->getCallback()){
			const_cast<ProxyAudioProducer*>(audioProducer)->stopPushCallback();
			ret = audioProducer->getCallback()->stop();
		}
	}
	TWRAP_PRODUCER_PROXY_AUDIO(self)->started = (ret == 0) ? tsk_false : tsk_true;
	return ret;
}


//
//	Audio producer object definition
//
/* constructor */
static tsk_object_t* twrap_producer_proxy_audio_ctor(tsk_object_t * self, va_list * app)
{
	twrap_producer_proxy_audio_t *producer = (twrap_producer_proxy_audio_t *)self;
	if(producer){
		/* init base */
		tdav_producer_audio_init(TDAV_PRODUCER_AUDIO(producer));
		/* init self */

		/* Add the plugin to the manager */
		ProxyPluginMgr* manager = ProxyPluginMgr::getInstance();
		if(manager){
			ProxyPlugin* proxyProducer = new ProxyAudioProducer(producer);
			uint64_t id = proxyProducer->getId();
			manager->addPlugin(&proxyProducer);
			manager->getCallback()->OnPluginCreated(id, twrap_proxy_plugin_audio_producer);
		}
	}
	return self;
}
/* destructor */
static tsk_object_t* twrap_producer_proxy_audio_dtor(tsk_object_t * self)
{ 
	twrap_producer_proxy_audio_t *producer = (twrap_producer_proxy_audio_t *)self;
	if(producer){

		/* stop */
		if(producer->started){
			twrap_producer_proxy_audio_stop(TMEDIA_PRODUCER(producer));
		}

		/* deinit base */
		tdav_producer_audio_deinit(TDAV_PRODUCER_AUDIO(producer));
		/* deinit self */
		
		/* Remove plugin from the manager */
		ProxyPluginMgr* manager = ProxyPluginMgr::getInstance();
		if(manager){
			manager->getCallback()->OnPluginDestroyed(producer->id, twrap_proxy_plugin_audio_producer);
			manager->removePlugin(producer->id);
		}
	}

	return self;
}
/* object definition */
static const tsk_object_def_t twrap_producer_proxy_audio_def_s = 
{
	sizeof(twrap_producer_proxy_audio_t),
	twrap_producer_proxy_audio_ctor, 
	twrap_producer_proxy_audio_dtor,
	tdav_producer_audio_cmp, 
};
/* plugin definition*/
static const tmedia_producer_plugin_def_t twrap_producer_proxy_audio_plugin_def_s = 
{
	&twrap_producer_proxy_audio_def_s,
	
	tmedia_audio,
	"Audio Proxy Producer",
	
	twrap_producer_proxy_audio_set,
	twrap_producer_proxy_audio_prepare,
	twrap_producer_proxy_audio_start,
	twrap_producer_proxy_audio_pause,
	twrap_producer_proxy_audio_stop
};

TINYWRAP_GEXTERN const tmedia_producer_plugin_def_t *twrap_producer_proxy_audio_plugin_def_t = &twrap_producer_proxy_audio_plugin_def_s;



/* ============ ProxyAudioProducer Class ================= */

ProxyAudioProducer::ProxyAudioProducer(twrap_producer_proxy_audio_t* pProducer)
:m_pCallback(tsk_null), m_pWrappedPlugin(pProducer), m_bUsePushCallback(false), m_hPushTimerMgr(tsk_null), ProxyPlugin(twrap_proxy_plugin_audio_producer)
{
  	memset(&m_PushBuffer, 0, sizeof(m_PushBuffer));
	memset(&m_Resampler, 0, sizeof(m_Resampler));
	if(m_pWrappedPlugin){
		m_pWrappedPlugin->id = this->getId();
	}
	//m_pWrappedPlugin->id = this->getId();
	//m_PushBuffer.pPushBufferPtr = tsk_null;
	//m_PushBuffer.nPushBufferSize = 0;
}


ProxyAudioProducer::~ProxyAudioProducer()
{
	TSK_FREE(m_Resampler.pInBufferPtr);
	m_Resampler.nInBufferSizeInByte = 0;
	if(m_Resampler.pResampler){
		delete m_Resampler.pResampler, m_Resampler.pResampler = tsk_null;
	}

	stopPushCallback();
}

/*
ProxyAudioProducer::ProxyAudioProducer(twrap_producer_proxy_audio_t* pProducer)
:m_pCallback(tsk_null), m_pWrappedPlugin(pProducer), m_bUsePushCallback(false), m_hPushTimerMgr(tsk_null), ProxyPlugin(twrap_proxy_plugin_audio_producer)
{
	m_pWrappedPlugin->id = this->getId();
	m_PushBuffer.pPushBufferPtr = tsk_null;
	m_PushBuffer.nPushBufferSize = 0;
}

ProxyAudioProducer::~ProxyAudioProducer()
{
	stopPushCallback();
}
*/


bool ProxyAudioProducer::setPushBuffer(const void* pPushBufferPtr, unsigned nPushBufferSize, bool bUsePushCallback/*=false*/)
{
	m_PushBuffer.pPushBufferPtr = pPushBufferPtr;
	m_PushBuffer.nPushBufferSize = nPushBufferSize;
	m_bUsePushCallback = bUsePushCallback;

	if(!pPushBufferPtr || !nPushBufferSize || !bUsePushCallback){
		return stopPushCallback();
	}
	else if(m_bUsePushCallback && m_pWrappedPlugin && m_pWrappedPlugin->started){
		return startPushCallback();
	}
	return true;
}

#if 0
int ProxyAudioProducer::push(const void* _pBuffer/*=tsk_null*/, unsigned _nSize/*=0*/)
{
	if(m_pWrappedPlugin && TMEDIA_PRODUCER(m_pWrappedPlugin)->enc_cb.callback){
		const void* pBuffer;
		unsigned nSize;
		if(_pBuffer && _nSize){
			pBuffer = _pBuffer, nSize = _nSize;
		}
		else{
			pBuffer = m_PushBuffer.pPushBufferPtr, nSize = m_PushBuffer.nPushBufferSize;
		}
		return TMEDIA_PRODUCER(m_pWrappedPlugin)->enc_cb.callback(TMEDIA_PRODUCER(m_pWrappedPlugin)->enc_cb.callback_data, pBuffer, nSize);
	}
	return 0;
}

#endif
int ProxyAudioProducer::push(const void* _pBuffer/*=tsk_null*/, unsigned _nSize/*=0*/)
{
	if(m_pWrappedPlugin && TMEDIA_PRODUCER(m_pWrappedPlugin)->enc_cb.callback){
		const void* pBuffer;
		void* pOutput;
		unsigned nSize;
		unsigned retSize = nSize;
		if(_pBuffer && _nSize){
			pBuffer = _pBuffer, nSize = _nSize;
		}
		else{
			pBuffer = m_PushBuffer.pPushBufferPtr, nSize = m_PushBuffer.nPushBufferSize;
		}
//		 TSK_DEBUG_ERROR(" push nSize =%d",nSize);
		tsk_size_t nRetSize = 0;
		if(m_Resampler.pResampler && pBuffer){
		   if(nSize){
		      retSize =  m_Resampler.nInBufferSizeInByte;       
                     nRetSize = m_Resampler.pResampler->process(pBuffer, nSize,m_Resampler.pInBufferPtr,retSize);
                   }
//                   TSK_DEBUG_ERROR(" push retSize =%d nRetSize =%d",retSize,nRetSize);
                   return TMEDIA_PRODUCER(m_pWrappedPlugin)->enc_cb.callback(TMEDIA_PRODUCER(m_pWrappedPlugin)->enc_cb.callback_data, m_Resampler.pInBufferPtr, retSize);
		}
		else{
//           TSK_DEBUG_ERROR(" push nSize =%d",nSize);
		   return TMEDIA_PRODUCER(m_pWrappedPlugin)->enc_cb.callback(TMEDIA_PRODUCER(m_pWrappedPlugin)->enc_cb.callback_data, pBuffer, nSize);
		}
	}
	return 0;
}


bool ProxyAudioProducer::setGain(unsigned nGain)
{
	if(m_pWrappedPlugin){
		// see also: MediaSessionMgr.producerSetInt32(org.doubango.tinyWRAP.twrap_media_type_t.twrap_media_audio, "gain", nGain);
		TMEDIA_PRODUCER(m_pWrappedPlugin)->audio.gain = TSK_MIN(nGain,14);
		return true;
	}
	return false;
}

unsigned ProxyAudioProducer::getGain()
{
	if(m_pWrappedPlugin){
		return TMEDIA_PRODUCER(m_pWrappedPlugin)->audio.gain;
	}
	return 0;
}

bool ProxyAudioProducer::startPushCallback()
{
	if(!m_bUsePushCallback){
		return true;
	}

	if(!m_pWrappedPlugin){
		TSK_DEBUG_ERROR("Not wrapping plugin");
		return false;
	}

	if(!m_hPushTimerMgr){
		if(!(m_hPushTimerMgr = tsk_timer_manager_create())){
			TSK_DEBUG_ERROR("Failed to create timer manager");
			return false;
		}
	}

	if(!TSK_RUNNABLE(m_hPushTimerMgr)->started){
		if((tsk_timer_manager_start(m_hPushTimerMgr)) == 0){
			m_uPushTimer = tsk_timer_manager_schedule(m_hPushTimerMgr, TMEDIA_PRODUCER(m_pWrappedPlugin)->audio.ptime, &ProxyAudioProducer::pushTimerCallback, this);
		}
		else{
			TSK_DEBUG_ERROR("Failed to start timer");
			return false;
		}
	}
	return true;
}

bool ProxyAudioProducer::stopPushCallback()
{
	if(m_hPushTimerMgr){
		tsk_timer_manager_destroy(&m_hPushTimerMgr);
	}
	return true;
}

int ProxyAudioProducer::pushTimerCallback(const void* arg, tsk_timer_id_t timer_id)
{
	ProxyAudioProducer* This = (ProxyAudioProducer*)arg;

	This->m_uPushTimer = tsk_timer_manager_schedule(This->m_hPushTimerMgr, TMEDIA_PRODUCER(This->m_pWrappedPlugin)->audio.ptime, &ProxyAudioProducer::pushTimerCallback, This);

	if(This->m_pCallback){
		if(This->m_pCallback->fillPushBuffer() == 0){
			return This->push();
		}
	}
	return 0;
}

bool ProxyAudioProducer::registerPlugin()
{
	/* HACK: Unregister all other audio plugins */
	tmedia_producer_plugin_unregister_by_type(tmedia_audio);
	/* Register our proxy plugin */
	return (tmedia_producer_plugin_register(twrap_producer_proxy_audio_plugin_def_t) == 0);
}























/* ============ Video Media Producer Interface ================= */
typedef struct twrap_producer_proxy_video_s
{
	TMEDIA_DECLARE_PRODUCER;

	int rotation;
	uint64_t id;
	tsk_bool_t started;
	TSK_DECLARE_SAFEOBJ;
}
twrap_producer_proxy_video_t;
#define TWRAP_PRODUCER_PROXY_VIDEO(self) ((twrap_producer_proxy_video_t*)(self))

int twrap_producer_proxy_video_set(tmedia_producer_t* self, const tmedia_param_t* params)
{
	return 0;
}

int twrap_producer_proxy_video_prepare(tmedia_producer_t* self, const tmedia_codec_t* codec)
{
	ProxyPluginMgr* manager;
	int ret = -1;
	if(codec && (manager = ProxyPluginMgr::getInstance())){
		const ProxyVideoProducer* videoProducer;
		if((videoProducer = manager->findVideoProducer(TWRAP_PRODUCER_PROXY_VIDEO(self)->id)) && videoProducer->getCallback()){
			self->video.chroma = videoProducer->getChroma();
			self->video.rotation = videoProducer->getRotation();
			ret = videoProducer->getCallback()->prepare(TMEDIA_CODEC_VIDEO(codec)->out.width, TMEDIA_CODEC_VIDEO(codec)->out.height, TMEDIA_CODEC_VIDEO(codec)->out.fps);
		}
	}
	
	return ret;
}


bool ProxyAudioProducer::queryForResampler(uint16_t nInFreq, uint16_t nOutFreq, uint16_t nFrameDuration, uint16_t nChannels, uint16_t nResamplerQuality)
{
	TSK_DEBUG_INFO("queryForResampler(%hu,%hu,%hu,%hu,%hu)", nInFreq, nOutFreq, nFrameDuration, nChannels, nResamplerQuality);
	if(nResamplerQuality > 10){
		TSK_DEBUG_WARN("%d is invalid value for quality", nResamplerQuality);
	}
	m_Resampler.pResampler = new AudioResampler(nInFreq, nOutFreq, nFrameDuration, nChannels, nResamplerQuality);
	if(!m_Resampler.pResampler){
		TSK_DEBUG_ERROR("Failed to create new 'AudioResampler' object");
		return false;
	}
	bool bOK = m_Resampler.pResampler->isValid();
	if(!bOK){
		goto bail;
	}
	m_Resampler.nInBufferSizeInByte = m_Resampler.pResampler->getOutputRequiredSizeInShort() * 2;
	m_Resampler.pInBufferPtr = tsk_calloc(m_Resampler.nInBufferSizeInByte, 1);
	bOK = (m_Resampler.pInBufferPtr != tsk_null);

bail:
	if(!bOK){
		if(m_Resampler.pResampler){
			delete m_Resampler.pResampler, m_Resampler.pResampler = tsk_null;
		}
		TSK_FREE(m_Resampler.pInBufferPtr);
		m_Resampler.nInBufferSizeInByte = 0;
	}
	return bOK;
}



int twrap_producer_proxy_video_start(tmedia_producer_t* self)
{
	ProxyPluginMgr* manager;
	int ret = -1;
	if((manager = ProxyPluginMgr::getInstance())){
		const ProxyVideoProducer* videoProducer;
		if((videoProducer = manager->findVideoProducer(TWRAP_PRODUCER_PROXY_VIDEO(self)->id)) && videoProducer->getCallback()){
			tsk_safeobj_lock(TWRAP_PRODUCER_PROXY_VIDEO(self));
			ret = videoProducer->getCallback()->start();
			TWRAP_PRODUCER_PROXY_VIDEO(self)->started = (ret == 0);
			tsk_safeobj_unlock(TWRAP_PRODUCER_PROXY_VIDEO(self));
		}
	}
		
	return ret;
}

int twrap_producer_proxy_video_pause(tmedia_producer_t* self)
{
	ProxyPluginMgr* manager;
	int ret = -1;
	if((manager = ProxyPluginMgr::getInstance())){
		const ProxyVideoProducer* videoProducer;
		if((videoProducer = manager->findVideoProducer(TWRAP_PRODUCER_PROXY_VIDEO(self)->id)) && videoProducer->getCallback()){
			tsk_safeobj_lock(TWRAP_PRODUCER_PROXY_VIDEO(self));
			ret = videoProducer->getCallback()->pause();
			tsk_safeobj_unlock(TWRAP_PRODUCER_PROXY_VIDEO(self));
		}
	}
	
	return ret;
}

int twrap_producer_proxy_video_stop(tmedia_producer_t* self)
{
	ProxyPluginMgr* manager;
	int ret = -1;
	if((manager = ProxyPluginMgr::getInstance())){
		const ProxyVideoProducer* videoProducer;
		if((videoProducer = manager->findVideoProducer(TWRAP_PRODUCER_PROXY_VIDEO(self)->id)) && videoProducer->getCallback()){
			tsk_safeobj_lock(TWRAP_PRODUCER_PROXY_VIDEO(self));
			ret = videoProducer->getCallback()->stop();
			TWRAP_PRODUCER_PROXY_VIDEO(self)->started = ((ret == 0) ? tsk_false : tsk_true);
			tsk_safeobj_unlock(TWRAP_PRODUCER_PROXY_VIDEO(self));
		}
	}
	
	return ret;
}


//
//	Video producer object definition
//
/* constructor */
static tsk_object_t* twrap_producer_proxy_video_ctor(tsk_object_t * self, va_list * app)
{
	twrap_producer_proxy_video_t *producer = (twrap_producer_proxy_video_t *)self;
	if(producer){
		/* init base */
		tmedia_producer_init(TMEDIA_PRODUCER(producer));
		/* init self */
		tsk_safeobj_init(producer);

		/* Add the plugin to the manager */
		ProxyPluginMgr* manager = ProxyPluginMgr::getInstance();
		if(manager){
			ProxyPlugin* proxyProducer = new ProxyVideoProducer(ProxyVideoProducer::getDefaultChroma(), producer);
			uint64_t id = proxyProducer->getId();
			manager->addPlugin(&proxyProducer);
			manager->getCallback()->OnPluginCreated(id, twrap_proxy_plugin_video_producer);
		}
	}
	return self;
}
/* destructor */
static tsk_object_t* twrap_producer_proxy_video_dtor(tsk_object_t * self)
{ 
	twrap_producer_proxy_video_t *producer = (twrap_producer_proxy_video_t *)self;
	if(producer){
		TSK_DEBUG_INFO("twrap_producer_proxy_video_dtor()");
		/* stop */
		if(producer->started){
			twrap_producer_proxy_video_stop(TMEDIA_PRODUCER(producer));
		}

		/* deinit base */
		tmedia_producer_deinit(TMEDIA_PRODUCER(producer));
		/* deinit self */
		
		/* Remove plugin from the manager */
		ProxyPluginMgr* manager = ProxyPluginMgr::getInstance();
		if(manager){
			manager->getCallback()->OnPluginDestroyed(producer->id, twrap_proxy_plugin_video_producer);
			manager->removePlugin(producer->id);
		}
		tsk_safeobj_deinit(producer);
	}

	return self;
}
/* object definition */
static const tsk_object_def_t twrap_producer_proxy_video_def_s = 
{
	sizeof(twrap_producer_proxy_video_t),
	twrap_producer_proxy_video_ctor, 
	twrap_producer_proxy_video_dtor,
	tsk_null, 
};
/* plugin definition*/
static const tmedia_producer_plugin_def_t twrap_producer_proxy_video_plugin_def_s = 
{
	&twrap_producer_proxy_video_def_s,
	
	tmedia_video,
	"Video Proxy Producer",
	
	twrap_producer_proxy_video_set,
	twrap_producer_proxy_video_prepare,
	twrap_producer_proxy_video_start,
	twrap_producer_proxy_video_pause,
	twrap_producer_proxy_video_stop
};

TINYWRAP_GEXTERN const tmedia_producer_plugin_def_t *twrap_producer_proxy_video_plugin_def_t = &twrap_producer_proxy_video_plugin_def_s;



/* ============ ProxyVideoProducer Class ================= */
tmedia_chroma_t ProxyVideoProducer::s_eDefaultChroma = tmedia_chroma_nv21;

ProxyVideoProducer::ProxyVideoProducer(tmedia_chroma_t eChroma, struct twrap_producer_proxy_video_s* pProducer)
:m_pCallback(tsk_null), m_eChroma(eChroma), m_nRotation(0), m_pWrappedPlugin(pProducer), ProxyPlugin(twrap_proxy_plugin_video_producer)
{
	if(m_pWrappedPlugin){
		m_pWrappedPlugin->id = this->getId();
	}
}

ProxyVideoProducer::~ProxyVideoProducer()
{
	TSK_DEBUG_INFO("~ProxyVideoProducer");
}

int ProxyVideoProducer::getRotation()const
{
	return m_nRotation;
}

bool ProxyVideoProducer::setRotation(int nRot)
{
	m_nRotation = nRot;
	if(m_pWrappedPlugin){
		TMEDIA_PRODUCER(m_pWrappedPlugin)->video.rotation = m_nRotation;
		return true;
	}
	return false;
}

// alert the encoder which size your camera is using because it's very hard to retrieve it from send(buffer, size) function
// this function is only needed if the actual size (output from your camera) is different than the negociated one
bool ProxyVideoProducer::setActualCameraOutputSize(unsigned nWidth, unsigned nHeight)
{
	if(m_pWrappedPlugin){
		TMEDIA_PRODUCER(m_pWrappedPlugin)->video.width = nWidth;
		TMEDIA_PRODUCER(m_pWrappedPlugin)->video.height = nHeight;
		return true;
	}
	return false;
}

// encode() then send()
int ProxyVideoProducer::push(const void* pBuffer, unsigned nSize)
{
	if(m_pWrappedPlugin && TMEDIA_PRODUCER(m_pWrappedPlugin)->enc_cb.callback){
		int ret = -1;
		tsk_safeobj_lock(m_pWrappedPlugin);
		if(m_pWrappedPlugin->started){
			ret = TMEDIA_PRODUCER(m_pWrappedPlugin)->enc_cb.callback(TMEDIA_PRODUCER(m_pWrappedPlugin)->enc_cb.callback_data, pBuffer, nSize);
		}
		tsk_safeobj_unlock(m_pWrappedPlugin);
		return ret;
	}
	return 0;
}

// send() "as is"
// only used by telepresence system with a H.264 SVC hardaware encoder
int ProxyVideoProducer::sendRaw(const void* pBuffer, unsigned nSize, unsigned nDuration, bool bMarker)
{
	if(m_pWrappedPlugin && TMEDIA_PRODUCER(m_pWrappedPlugin)->raw_cb.callback){
		//tmedia_video_encode_result_reset(&TMEDIA_PRODUCER(m_pWrappedPlugin)->raw_cb.chunck_curr);

		TMEDIA_PRODUCER(m_pWrappedPlugin)->raw_cb.chunck_curr.buffer.ptr = pBuffer;
		TMEDIA_PRODUCER(m_pWrappedPlugin)->raw_cb.chunck_curr.buffer.size = nSize;
		TMEDIA_PRODUCER(m_pWrappedPlugin)->raw_cb.chunck_curr.duration = nDuration;
		TMEDIA_PRODUCER(m_pWrappedPlugin)->raw_cb.chunck_curr.last_chunck = (bMarker == true);
		return TMEDIA_PRODUCER(m_pWrappedPlugin)->raw_cb.callback(&TMEDIA_PRODUCER(m_pWrappedPlugin)->raw_cb.chunck_curr);
	}
	return 0;
}

int ProxyVideoProducer::sendRaw(const void* pBuffer, unsigned nSize, const void* proto_hdr)
{
	if(m_pWrappedPlugin && TMEDIA_PRODUCER(m_pWrappedPlugin)->raw_cb.callback){
		//tmedia_video_encode_result_reset(&TMEDIA_PRODUCER(m_pWrappedPlugin)->raw_cb.chunck_curr);

		TMEDIA_PRODUCER(m_pWrappedPlugin)->raw_cb.chunck_curr.buffer.ptr = pBuffer;
		TMEDIA_PRODUCER(m_pWrappedPlugin)->raw_cb.chunck_curr.buffer.size = nSize;
		TMEDIA_PRODUCER(m_pWrappedPlugin)->raw_cb.chunck_curr.proto_hdr = proto_hdr;
		return TMEDIA_PRODUCER(m_pWrappedPlugin)->raw_cb.callback(&TMEDIA_PRODUCER(m_pWrappedPlugin)->raw_cb.chunck_curr);
	}
	return 0;
}

tmedia_chroma_t ProxyVideoProducer::getChroma()const
{
	return m_eChroma;
}

bool ProxyVideoProducer::registerPlugin()
{
	/* HACK: Unregister all other video plugins */
	tmedia_producer_plugin_unregister_by_type(tmedia_video);
	/* Register our proxy plugin */
	return (tmedia_producer_plugin_register(twrap_producer_proxy_video_plugin_def_t) == 0);
}
