/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: Telephony Multimedia Service
*
*/
#include <stdio.h>
#include <tms.h>
#include <tmsstreamobsrvr.h>
#include <tmsbuffer.h>
#include <tmseffect.h>
#include <tmsformat.h>
#include "tmsutility.h"
#include "tmscallproxy.h"
#include "tmsclientserver.h"
#include "tmsshared.h"
#include "tmsstreambodyimpl.h"
#include "tmsmembuffer.h"
#include "tmsclientsourceimpl.h"
#include "tmsclientsinkimpl.h"
#include "tmsvolumeeffectimpl.h"
#include "tmsgaineffectimpl.h"
#include "tmsg711formatimpl.h"
#include "tmsg729formatimpl.h"
#include "tmsilbcformatimpl.h"
#include "tmspcmformatimpl.h"
#include "tmsamrformatimpl.h"
using namespace TMS;
TMSStreamBodyImpl::TMSStreamBodyImpl() :
iProxy(NULL),
iParent(NULL),
iSource(NULL),
iSink(NULL),
iMsgQHandler(NULL),
iObserver(NULL),
iFormat(NULL),
iStreamState(TMS_STREAM_UNINITIALIZED)
{
//TMSStream::Construct(this);
}
TMSStreamBodyImpl::~TMSStreamBodyImpl()
{
if (iMsgQHandler)
{
iMsgQHandler->Cancel();
}
delete iMsgQHandler;
if (iMsgQueue.Handle() > 0)
{
iMsgQueue.Close();
}
iEffectsList.Reset();
if (iContext.CallProxy && (iContext.StreamId != -1))
{
iContext.CallProxy->DeleteStream(iContext.CallType,
iContext.StreamType, iContext.StreamId);
}
}
gint TMSStreamBodyImpl::Create(TMSCallType callType, TMSStreamType stype,
TMSCallProxy* proxy, TMSStream& parent, TMSStreamBody*& bodyimpl)
{
gint ret(TMS_RESULT_INSUFFICIENT_MEMORY);
TMSStreamBodyImpl* self = new TMSStreamBodyImpl;
if (self)
{
ret = self->PostConstruct(callType, stype, proxy, parent);
if (ret != TMS_RESULT_SUCCESS)
{
delete self;
self = NULL;
}
}
bodyimpl = self;
return ret;
}
gint TMSStreamBodyImpl::PostConstruct(TMSCallType callType,
TMSStreamType stype, TMSCallProxy* proxy, TMSStream& parent)
{
gint status(TMS_RESULT_SUCCESS);
iContext.CallProxy = proxy;
iParent = &parent;
iContext.CallType = callType;
iContext.StreamType = stype;
status = CreateQueue(KTMSMsgQSlots);
if (status == TMS_RESULT_SUCCESS)
{
if (iContext.CallProxy)
{
status = (iContext.CallProxy)->CreateStream(iContext.CallType,
iContext.StreamType, iContext.StreamId);
}
else
{
status = TMS_RESULT_UNINITIALIZED_OBJECT;
}
}
return status;
}
gint TMSStreamBodyImpl::AddObserver(TMSStreamObserver& obsrvr,
gpointer user_data)
{
gint ret(TMS_RESULT_SUCCESS);
// TODO allow support for multiple observers
if (!iObserver)
{
iObserver = &obsrvr;
iUserData = user_data;
}
else
{
ret = TMS_RESULT_ALREADY_EXIST;
}
return ret;
}
gint TMSStreamBodyImpl::RemoveObserver(TMSStreamObserver& obsrvr)
{
gint ret(TMS_RESULT_SUCCESS);
if (&obsrvr == iObserver)
{
iObserver = NULL;
}
else
{
ret = TMS_RESULT_DOES_NOT_EXIST;
}
return ret;
}
gint TMSStreamBodyImpl::AddSource(TMSSource* source)
{
gint ret(TMS_RESULT_SUCCESS);
if (iStreamState == TMS_STREAM_UNINITIALIZED)
{
if (!iSource)
{
ret = ValidateSource(source);
}
else
{
ret = TMS_RESULT_ALREADY_EXIST;
}
}
else
{
ret = TMS_RESULT_INVALID_STATE;
}
return ret;
}
gint TMSStreamBodyImpl::RemoveSource(TMSSource* source)
{
gint ret(TMS_RESULT_SUCCESS);
if (iStreamState == TMS_STREAM_UNINITIALIZED)
{
if (source == iSource)
{
iSource = NULL;
}
else
{
ret = TMS_RESULT_DOES_NOT_EXIST;
}
}
else
{
ret = TMS_RESULT_INVALID_STATE;
}
return ret;
}
gint TMSStreamBodyImpl::AddSink(TMSSink* sink)
{
gint ret(TMS_RESULT_SUCCESS);
if (iStreamState == TMS_STREAM_UNINITIALIZED)
{
if (!iSink)
{
ret = ValidateSink(sink);
}
else
{
ret = TMS_RESULT_ALREADY_EXIST;
}
}
else
{
ret = TMS_RESULT_INVALID_STATE;
}
return ret;
}
gint TMSStreamBodyImpl::RemoveSink(TMSSink* sink)
{
gint ret(TMS_RESULT_SUCCESS);
if (iStreamState == TMS_STREAM_UNINITIALIZED)
{
if (sink == iSink)
{
iSink = NULL;
}
else
{
ret = TMS_RESULT_DOES_NOT_EXIST;
}
}
else
{
ret = TMS_RESULT_INVALID_STATE;
}
return ret;
}
gint TMSStreamBodyImpl::SetFormat(TMSFormat* format)
{
gint ret(TMS_RESULT_SUCCESS);
if (iStreamState == TMS_STREAM_UNINITIALIZED)
{
ret = ValidateFormat(format);
}
else
{
ret = TMS_RESULT_INVALID_STATE;
}
return ret;
}
gint TMSStreamBodyImpl::ResetFormat(TMSFormat* format)
{
gint ret(TMS_RESULT_SUCCESS);
if (iStreamState == TMS_STREAM_UNINITIALIZED)
{
if (format == iFormat)
{
iFormat = NULL;
}
else
{
ret = TMS_RESULT_DOES_NOT_EXIST;
}
}
else
{
ret = TMS_RESULT_INVALID_STATE;
}
return ret;
}
gint TMSStreamBodyImpl::AddEffect(TMSEffect* effect)
{
gint ret(TMS_RESULT_SUCCESS);
if (iStreamState == TMS_STREAM_UNINITIALIZED)
{
// Add to list if effect is not already added
ret = iEffectsList.Find(effect);
if (ret == KErrNotFound)
{
ret = iEffectsList.Append(effect);
}
else
{
ret = TMS_RESULT_ALREADY_EXIST;
}
}
else
{
ret = TMS_RESULT_INVALID_STATE;
}
return ret;
}
gint TMSStreamBodyImpl::RemoveEffect(TMSEffect* effect)
{
TInt status(TMS_RESULT_SUCCESS);
if (iStreamState == TMS_STREAM_UNINITIALIZED)
{
TInt index = iEffectsList.Find(effect);
// If found status has index to the effect in the array
// else it would contain KErrNotFound
if (index >= 0)
{
iEffectsList.Remove(index);
}
else
{
status = TMS_RESULT_DOES_NOT_EXIST;
}
}
else
{
status = TMS_RESULT_INVALID_STATE;
}
return status;
}
TMSStreamState TMSStreamBodyImpl::GetState()
{
return iStreamState;
}
TMSStreamType TMSStreamBodyImpl::GetStreamType()
{
return iContext.StreamType;
}
gint TMSStreamBodyImpl::GetStreamId()
{
return iContext.StreamId;
}
gint TMSStreamBodyImpl::Init()
{
gint ret(TMS_RESULT_SUCCESS);
ret = ValidateStream();
RET_REASON_IF_ERR(ret);
TMSFormatType fmttype(TMS_FORMAT_PCM);
if (!iFormat && iContext.CallType == TMS_CALL_IP)
{
return TMS_RESULT_FORMAT_TYPE_UNSPECIFIED;
}
else if (iContext.CallType == TMS_CALL_IP)
{
iFormat->GetType(fmttype);
}
if (iContext.CallProxy)
{
ret = (iContext.CallProxy)->InitStream(iContext.CallType,
iContext.StreamType, iContext.StreamId, fmttype, &iMsgQueue);
}
else
{
ret = TMS_RESULT_UNINITIALIZED_OBJECT;
}
RET_REASON_IF_ERR(ret);
if (iEffectsList.Count())
{
for (TInt i = 0; i < iEffectsList.Count(); i++)
{
TMSEffectType effecttype;
iEffectsList[i]->GetType(effecttype);
switch (effecttype)
{
case TMS_EFFECT_GAIN:
static_cast<TMSGainEffectImpl*>(iEffectsList[i])->SetProxy(
iContext.CallProxy, iMsgQHandler);
break;
case TMS_EFFECT_VOLUME:
static_cast<TMSVolumeEffectImpl*>
(iEffectsList[i])->SetProxy(iContext.CallProxy,
iMsgQHandler);
break;
default:
ret = TMS_RESULT_INVALID_ARGUMENT;
break;
}
}
}
if (iFormat)
{
TMSFormatType fmttype;
iFormat->GetType(fmttype);
switch (fmttype)
{
case TMS_FORMAT_PCM:
static_cast<TMSPCMFormatImpl*>(iFormat)->SetProxy(&iContext,
iMsgQHandler);
break;
case TMS_FORMAT_AMR:
static_cast<TMSAMRFormatImpl*>(iFormat)->SetProxy(&iContext,
iMsgQHandler);
break;
case TMS_FORMAT_G711:
static_cast<TMSG711FormatImpl*>(iFormat)->SetProxy(&iContext,
iMsgQHandler);
break;
case TMS_FORMAT_G729:
static_cast<TMSG729FormatImpl*>(iFormat)->SetProxy(&iContext,
iMsgQHandler);
break;
case TMS_FORMAT_ILBC:
static_cast<TMSILBCFormatImpl*>(iFormat)->SetProxy(&iContext,
iMsgQHandler);
break;
default:
ret = TMS_RESULT_INVALID_ARGUMENT;
break;
}
}
if (iContext.StreamType == TMS_STREAM_UPLINK)
{
if (iSink)
{
TMSSinkType sinkType;
iSink->GetType(sinkType);
switch (sinkType)
{
case TMS_SINK_CLIENT:
static_cast<TMSClientSinkImpl*>(iSink)->SetProxy(
iContext.CallProxy, iMsgQHandler);
break;
case TMS_SINK_MODEM:
case TMS_SINK_SPEAKER:
break;
default:
ret = TMS_RESULT_INVALID_ARGUMENT;
break;
}
}
else
{
ret = TMS_RESULT_UNINITIALIZED_OBJECT;
}
}
else if (iContext.StreamType == TMS_STREAM_DOWNLINK)
{
if (iSource)
{
TMSSourceType sourceType;
iSource->GetType(sourceType);
switch (sourceType)
{
case TMS_SOURCE_CLIENT:
static_cast<TMSClientSourceImpl*>(iSource)->SetProxy(
iContext.CallProxy, iContext.StreamId,
iMsgQHandler);
break;
case TMS_SOURCE_MODEM:
case TMS_SOURCE_MIC:
break;
default:
ret = TMS_RESULT_INVALID_ARGUMENT;
break;
}
}
else
{
ret = TMS_RESULT_UNINITIALIZED_OBJECT;
}
}
return ret;
}
gint TMSStreamBodyImpl::Pause()
{
gint ret(TMS_RESULT_SUCCESS);
if (iContext.CallProxy)
{
ret = (iContext.CallProxy)->PauseStream(iContext.CallType,
iContext.StreamType, iContext.StreamId);
}
else
{
ret = TMS_RESULT_UNINITIALIZED_OBJECT;
}
return ret;
}
gint TMSStreamBodyImpl::Start()
{
gint ret(TMS_RESULT_SUCCESS);
if (iContext.CallProxy)
{
ret = (iContext.CallProxy)->StartStream(iContext.CallType,
iContext.StreamType, iContext.StreamId);
}
else
{
ret = TMS_RESULT_UNINITIALIZED_OBJECT;
}
return ret;
}
gint TMSStreamBodyImpl::Stop()
{
gint ret(TMS_RESULT_SUCCESS);
if (iContext.CallProxy)
{
ret = (iContext.CallProxy)->StopStream(iContext.CallType,
iContext.StreamType, iContext.StreamId);
}
else
{
ret = TMS_RESULT_UNINITIALIZED_OBJECT;
}
return ret;
}
void TMSStreamBodyImpl::Deinit()
{
if (iContext.CallProxy)
{
(iContext.CallProxy)->DeinitStream(iContext.CallType,
iContext.StreamType, iContext.StreamId);
}
}
gint TMSStreamBodyImpl::ValidateSource(TMSSource* source)
{
gint ret(TMS_RESULT_NULL_ARGUMENT);
TMSSourceType sourcetype;
if (source)
{
source->GetType(sourcetype);
switch (sourcetype)
{
case TMS_SOURCE_CLIENT:
{
if (iContext.CallType == TMS_CALL_IP &&
iContext.StreamType == TMS_STREAM_DOWNLINK)
{
iSource = source;
ret = TMS_RESULT_SUCCESS;
}
}
break;
case TMS_SOURCE_MIC:
{
if (iContext.StreamType == TMS_STREAM_UPLINK)
{
iSource = source;
ret = TMS_RESULT_SUCCESS;
}
}
break;
case TMS_SOURCE_MODEM:
{
if (iContext.CallType == TMS_CALL_CS &&
iContext.StreamType == TMS_STREAM_DOWNLINK)
{
iSource = source;
ret = TMS_RESULT_SUCCESS;
}
break;
}
default:
break;
}
}
return ret;
}
gint TMSStreamBodyImpl::ValidateSink(TMSSink* sink)
{
gint ret(TMS_RESULT_NULL_ARGUMENT);
TMSSinkType sinktype;
if (sink)
{
sink->GetType(sinktype);
switch (sinktype)
{
case TMS_SINK_CLIENT:
{
if (iContext.CallType == TMS_CALL_IP &&
iContext.StreamType == TMS_STREAM_UPLINK)
{
iSink = sink;
ret = TMS_RESULT_SUCCESS;
}
}
break;
case TMS_SINK_SPEAKER:
{
if (iContext.StreamType == TMS_STREAM_DOWNLINK)
{
iSink = sink;
ret = TMS_RESULT_SUCCESS;
}
}
break;
case TMS_SINK_MODEM:
{
if (iContext.CallType == TMS_CALL_CS &&
iContext.StreamType == TMS_STREAM_UPLINK)
{
iSink = sink;
ret = TMS_RESULT_SUCCESS;
}
break;
}
default:
break;
}
}
return ret;
}
gint TMSStreamBodyImpl::ValidateFormat(TMSFormat* format)
{
gint ret(TMS_RESULT_NULL_ARGUMENT);
if (format)
{
if (iContext.CallType == TMS_CALL_IP)
{
iFormat = format;
ret = TMS_RESULT_SUCCESS;
}
else
{
ret = TMS_RESULT_INVALID_STATE;
}
}
return ret;
}
gint TMSStreamBodyImpl::ValidateStream()
{
gint ret(TMS_RESULT_INVALID_STATE);
if (iContext.StreamType == TMS_STREAM_UPLINK ||
iContext.StreamType == TMS_STREAM_DOWNLINK)
{
if (iContext.CallType == TMS_CALL_IP)
{
if (ValidateSource(iSource) == TMS_RESULT_SUCCESS &&
ValidateSink(iSink) == TMS_RESULT_SUCCESS &&
ValidateFormat(iFormat) == TMS_RESULT_SUCCESS)
{
ret = TMS_RESULT_SUCCESS;
}
}
else if (iContext.CallType == TMS_CALL_CS)
{
if (ValidateSource(iSource) == TMS_RESULT_SUCCESS &&
ValidateSink(iSink) == TMS_RESULT_SUCCESS)
{
ret = TMS_RESULT_SUCCESS;
}
}
}
return ret;
}
// ---------------------------------------------------------------------------
// TMSStreamBodyImpl::CreateQueue
// ---------------------------------------------------------------------------
//
gint TMSStreamBodyImpl::CreateQueue(const gint aNumSlots)
{
gint err = TMS_RESULT_INVALID_ARGUMENT;
if (iMsgQueue.Handle() <= 0)
{
err = iMsgQueue.CreateGlobal(KNullDesC, aNumSlots);
if (err == KErrNone)
{
TRAP(err, ReceiveMsgQHandlerEventsL());
}
}
return err;
}
// ---------------------------------------------------------------------------
// TMSStreamBodyImpl::ReceiveMsgQHandlerEventsL
// Starts message queue handler (A/O) to monitor communication and transfer
// buffer events between client and the server.
// ---------------------------------------------------------------------------
//
void TMSStreamBodyImpl::ReceiveMsgQHandlerEventsL()
{
if (iMsgQHandler)
{
iMsgQHandler->Cancel();
}
else
{
iMsgQHandler = TMSQueueHandler::NewL(&iMsgQueue, &iContext);
iMsgQHandler->AddObserver(*this, iContext.StreamType);
}
iMsgQHandler->Start();
}
// ======== CALLBACK FUNCTIONS ========
void TMSStreamBodyImpl::QueueEvent(TInt aEventType, TInt aError,
void* user_data)
{
TMSSignalEvent event = {}; //all elements initialized to zeros
event.reason = aError;
event.user_data = user_data;
iStreamState = aEventType;
switch (aEventType)
{
case TMS_STREAM_INITIALIZED:
case TMS_STREAM_UNINITIALIZED:
case TMS_STREAM_PAUSED:
case TMS_STREAM_STARTED:
{
event.curr_state = aEventType;
event.prev_state = iPrevState;
if (iObserver)
{
event.type = TMS_EVENT_STREAM_STATE_CHANGED;
iObserver->TMSStreamEvent(*iParent, event);
}
break;
}
default:
break;
}
iPrevState = aEventType;
}