/*
* Copyright (c) 2005 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:
*
*/
// USER
#include "musengmceoutsession.h"
#include "musengoutsessionobserver.h"
#include "musenglivesessionobserver.h"
#include "mussettings.h"
#include "musengmceutils.h"
#include "musenguriparser.h"
#include "musenglogger.h"
#include "mussesseioninformationapi.h"
#include "mussipprofilehandler.h"
// SYSTEM
#include <mcestreambundle.h>
#include <mcemediastream.h>
#include <mceoutsession.h>
#include <mcevideostream.h>
#include <mcemediasource.h>
#include <mcefilesource.h>
#include <mcemediasink.h>
#include <mcertpsink.h>
#include <mcespeakersink.h>
#include <mcedisplaysink.h>
#include <mcevideocodec.h>
#include <mceaudiocodec.h>
#include <sipprofile.h>
#include <sipextensionheader.h>
#include <sipaddress.h>
#include <uri8.h>
#include <e32property.h>
const TInt KMusEngSipReasonCodeBadRequest = 400;
const TInt KMusEngSipReasonCodeUnauthorized = 401;
const TInt KMusEngSipReasonCodePaymentRequired = 402;
const TInt KMusEngSipReasonCodeRecipientNotFound = 404;
const TInt KMusEngSipReasonCodeProxyAuthenticationRequired = 407;
const TInt KMusEngSipReasonCodeRequestTimeout = 408;
const TInt KMusEngSipReasonCodeUnsupportedMediaType = 415;
const TInt KMusEngSipReasonCodeUnsupportedUriScheme = 416;
const TInt KMusEngSipReasonCodeTemporarilyNotAvailable = 480;
const TInt KMusEngSipReasonCodeBusyHere = 486;
const TInt KMusEngSipReasonCodeRequestCancelled = 487;
const TInt KMusEngSipReasonCodeNotAcceptableHere = 488;
const TInt KMusEngSipReasonCodeDecline = 603;
const TInt KMusEngSipReasonCodeNotAcceptable = 606;
// The next code represents unofficial sip error code
// "478 Unresolveable Destination, we were not able to process the URI (478/TM)
const TInt KMusEngSipReasonCode478NotAbleToProcessURI = 478;
// The next code represents unofficial sip error code
// "479 Regretfuly, we were not able to process the URI (479/SL)
const TInt KMusEngSipReasonCode479NotAbleToProcessURI = 479;
const TUint8 KMusEngPayloadTypeVideoH263 = 96;
const TUint8 KMusEngPayloadTypeAudio = 97;
const TUint8 KMusEngPayloadTypeVideoAvc = 98;
using namespace NMusSessionInformationApi;
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
//
CMusEngMceOutSession::~CMusEngMceOutSession()
{
MUS_LOG( "mus: [ENGINE] -> CMusEngMceOutSession::~CMusEngMceOutSession()" )
delete iRecipient;
delete iVideoCodecList;
MUS_LOG( "mus: [ENGINE] <- CMusEngMceOutSession::~CMusEngMceOutSession()" )
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
//
EXPORT_C void CMusEngMceOutSession::InviteL( const TDesC& aRecipient )
{
MUS_LOG( "mus: [ENGINE] -> CMusEngMceOutSession::InviteL()")
if ( iSession )
{
MUS_ENG_LOG_SESSION_STATE( *iSession )
if ( iSession->State() == CMceSession::EIdle ||
iSession->State() == CMceSession::ETerminated )
{
// This is the case when last invite has ended up to an error,
// last sharing has ended normally, or construction of the session
// stucture has not been completed. Delete old session and try to
// continue normally.
delete iSession;
iSession = NULL;
MUS_LOG( "mus: [ENGINE] Existing session deleted")
}
else
{
// Session is already ongoing. Leave.
User::Leave( KErrAlreadyExists );
}
}
MUS_LOG_TDESC( "mus: [ENGINE] CMusEngMceOutSession::InviteL() recipient=",
aRecipient )
// delete possibly existing recipient
delete iRecipient;
iRecipient = NULL;
TMusEngUriParser parser( aRecipient );
parser.ParseUriL();
iRecipient = parser.GetUri8L();
CreateMceSessionStructureL();
EstablishSessionL();
MUS_LOG( "mus: [ENGINE] <- CMusEngMceOutSession::InviteL()")
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
//
EXPORT_C void CMusEngMceOutSession::CancelInviteL()
{
MUS_LOG( "mus: [ENGINE] -> CMusEngMceOutSession::CancelInviteL()" )
__ASSERT_ALWAYS( iSession, User::Leave( KErrNotReady ) );
MUS_ENG_LOG_SESSION_STATE( *iSession )
if( iSession->State() == CMceSession::EOffering )
{
MUS_LOG( "mus: [ENGINE] CMceOutSession->CancelL()" )
static_cast<CMceOutSession*>( iSession )->CancelL();
}
MUS_LOG( "mus: [ENGINE] <- CMusEngMceOutSession::CancelInviteL()" )
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
//
EXPORT_C void CMusEngMceOutSession::SetSupportedVideoCodecListL(
const TDesC& aVideoCodecs )
{
MUS_LOG_TDESC( "mus: [ENGINE] -> CMusEngMceOutSession::SetSupportedVideoCodecListL: ",
aVideoCodecs )
HBufC8* newVideoCodecList =
CnvUtfConverter::ConvertFromUnicodeToUtf8L( aVideoCodecs );
delete iVideoCodecList;
iVideoCodecList = newVideoCodecList;
MUS_LOG( "mus: [ENGINE] <- CMusEngMceOutSession::SetSupportedVideoCodecListL" )
}
// -----------------------------------------------------------------------------
// Calls MCE function EstablishL with feature tag in Accept-Contact header.
// Adjusts stream and codec values.
// -----------------------------------------------------------------------------
//
void CMusEngMceOutSession::EstablishSessionL()
{
MUS_LOG( "mus: [ENGINE] -> CMusEngMceOutSession::EstablishSessionL()" )
__ASSERT_ALWAYS( iSession, User::Leave( KErrNotReady ) );
AdjustStreamsAndCodecsL();
CDesC8Array* headers = new ( ELeave ) CDesC8ArrayFlat( 1 );
CleanupStack::PushL( headers );
headers->AppendL( KMusEngAcceptContactHeader() );
headers->AppendL( KMusAcceptHeader() );
if ( iOperatorVariant )
{
CUri8* originator = iSipProfileHandler->UserFromProfileLC();
CSIPExtensionHeader* header = CSIPExtensionHeader::NewLC(
KMusPPreferredIdentity, originator->Uri().UriDes() );
HBufC8* headInText = header->ToTextL();
MUS_LOG_TDESC8( " mus: [ENGINE] P-Preferred-Identity header : ", headInText->Des() );
CleanupStack::PopAndDestroy( header );
CleanupStack::PopAndDestroy( originator );
CleanupStack::PushL( headInText );
headers->AppendL( *headInText );
CleanupStack::PopAndDestroy( headInText );
}
/* Add the privacy header if cs call privacy setting is switched on */
if ( iPrivate && iPrivateNumber )
{
AddPrivacyHeaderL( *headers );
}
static_cast<CMceOutSession*>( iSession )->EstablishL( 0, headers );
CleanupStack::Pop( headers );
MUS_LOG( "mus: [ENGINE] <- CMusEngMceOutSession::EstablishSessionL()" )
}
// -----------------------------------------------------------------------------
// Handle MCE session termination. Called by MCE observer function of the
// base class.
// -----------------------------------------------------------------------------
//
void CMusEngMceOutSession::HandleTermination( TInt aStatusCode,
const TDesC8& aReasonPhrase )
{
MUS_LOG( "mus: [ENGINE] -> CMusEngMceOutSession::HandleTermination()" )
switch ( aStatusCode )
{
case KMusEngSipReasonCodeBadRequest :
{
iOutSessionObserver.SessionBadRequest();
break;
}
case KMusEngSipReasonCodeUnauthorized :
{
iOutSessionObserver.SessionUnauthorized();
break;
}
case KMusEngSipReasonCodePaymentRequired :
{
iOutSessionObserver.SessionPaymentRequired();
break;
}
case KMusEngSipReasonCodeRecipientNotFound :
//lint -fallthrough
case KMusEngSipReasonCode478NotAbleToProcessURI:
//lint -fallthrough
case KMusEngSipReasonCode479NotAbleToProcessURI:
//lint -fallthrough
case KMusEngSipReasonCodeUnsupportedUriScheme :
{
iOutSessionObserver.SessionRecipientNotFound();
break;
}
case KMusEngSipReasonCodeProxyAuthenticationRequired :
{
iOutSessionObserver.SessionProxyAuthenticationRequired();
break;
}
case KMusEngSipReasonCodeRequestTimeout :
{
iOutSessionObserver.SessionRequestTimeOut();
break;
}
case KMusEngSipReasonCodeUnsupportedMediaType :
//lint -fallthrough
case KMusEngSipReasonCodeNotAcceptableHere:
//lint -fallthrough
case KMusEngSipReasonCodeNotAcceptable:
{
iOutSessionObserver.SessionUnsupportedMediaType();
break;
}
case KMusEngSipReasonCodeBusyHere :
{
// Operator variant uses 486 to rejection instead of 603
if ( iOperatorVariant )
{
iOutSessionObserver.SessionRejected();
}
else
{
iOutSessionObserver.SessionBusyHere();
}
break;
}
case KMusEngSipReasonCodeRequestCancelled :
{
iOutSessionObserver.SessionRequestCancelled();
break;
}
case KMusEngSipReasonCodeDecline :
{
iOutSessionObserver.SessionRejected();
break;
}
case KMusEngSipReasonCodeTemporarilyNotAvailable :
{
iOutSessionObserver.SessionTemporarilyNotAvailable();
break;
}
default:
{
// Termination reason is not outsession specific.
// Let the base class to handle the termination.
CMusEngMceSession::HandleTermination( aStatusCode, aReasonPhrase );
}
}
MUS_LOG( "mus: [ENGINE] <- CMusEngMceOutSession::HandleTermination()" )
}
// -----------------------------------------------------------------------------
// Sets payload type and calls overridden base class version
// -----------------------------------------------------------------------------
//
void CMusEngMceOutSession::AdjustVideoCodecL( CMceVideoCodec& aVideoCodec )
{
MUS_LOG( "mus: [ENGINE] -> CMusEngMceOutSession::AdjustVideoCodecL()" )
CMusEngMceSession::AdjustVideoCodecL( aVideoCodec );
if ( aVideoCodec.SdpName() == KMceSDPNameH263() ||
aVideoCodec.SdpName() == KMceSDPNameH2632000() )
{
User::LeaveIfError(
aVideoCodec.SetPayloadType( KMusEngPayloadTypeVideoH263 ) );
}
else if ( aVideoCodec.SdpName() == KMceSDPNameH264() )
{
User::LeaveIfError(
aVideoCodec.SetPayloadType( KMusEngPayloadTypeVideoAvc ) );
}
else
{
// NOP
}
MUS_LOG( "mus: [ENGINE] <- CMusEngMceOutSession::AdjustVideoCodecL()" )
}
// -----------------------------------------------------------------------------
// Sets payload type and calls overridden base class version
// -----------------------------------------------------------------------------
//
void CMusEngMceOutSession::AdjustAudioCodecL( CMceAudioCodec& aAudioCodec )
{
MUS_LOG( "mus: [ENGINE] -> CMusEngMceOutSession::AdjustAudioCodecL()" )
CMusEngMceSession::AdjustAudioCodecL( aAudioCodec );
User::LeaveIfError( aAudioCodec.SetPayloadType( KMusEngPayloadTypeAudio ) );
MUS_LOG( "mus: [ENGINE] <- CMusEngMceOutSession::AdjustAudioCodecL()" )
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
//
CMusEngMceOutSession::CMusEngMceOutSession(
const TRect& aRect,
MMusEngSessionObserver& aSessionObserver,
MMusEngOutSessionObserver& aOutSessionObserver )
: CMusEngMceSession( aRect, aSessionObserver ),
iOutSessionObserver( aOutSessionObserver )
{
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
//
void CMusEngMceOutSession::ConstructL( TUint aSipProfileId )
{
MUS_LOG( "mus: [ENGINE] -> CMusEngMceOutSession::ConstructL()" )
CMusEngMceSession::ConstructL();
iSipProfileHandler->CreateProfileL( aSipProfileId );
// Check if feature specific behavior is expected
iPrivate = ( MultimediaSharingSettings::PrivacySetting());
NMusSessionInformationApi::TMusClirSetting clir;
// Ignore RProperty::Get return value.Incase of error it should behave default.
RProperty::Get( NMusSessionInformationApi::KCategoryUid,
NMusSessionInformationApi::KMusClirSetting,
reinterpret_cast<TInt&>( clir ) );
iPrivateNumber = ( clir == NMusSessionInformationApi::ESendOwnNumber )? EFalse: ETrue;
MUS_LOG( "mus: [ENGINE] <- CMusEngMceOutSession::ConstructL()" )
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
//
void CMusEngMceOutSession::CreateMceSessionStructureL()
{
MUS_LOG( "mus: [ENGINE] -> CMusEngMceOutSession::CreateMceSessionStructureL()" )
CSIPProfile* profile = iSipProfileHandler->Profile();
__ASSERT_ALWAYS( profile != NULL, User::Leave( KErrNotReady ) );
// Create session
if ( iPrivate && iPrivateNumber )
{
HBufC8* originator = KMusAnonymousHeader().AllocLC();
iSession = CMceOutSession::NewL( *iManager, *profile, *iRecipient, originator );
CleanupStack::Pop();
}
else
{
iSession = CMceOutSession::NewL( *iManager, *profile, *iRecipient );
}
// Remove QoS-lines if needed
if ( profile->Type().iSIPProfileClass ==
TSIPProfileTypeInfo::EInternet ||
MultimediaSharingSettings::ForceInternetSignalingSettingL() ==
MusSettingsKeys::EForceInternetSignaling ||
iOperatorVariant)
{
iSession->SetModifierL( KMcePreconditions, KMcePreconditionsNotUsed );
MUS_LOG( "mus: [ENGINE] Usage of preconditions denied" )
}
SetSessionSdpLinesL( *iSession );
// Create bundle for local streams
CMceStreamBundle* localBundle =
CMceStreamBundle::NewLC( CMceStreamBundle::ELS );
// To complete session structure, let the sibling classes add video out
// and possibly needed audio streams
CompleteSessionStructureL( *localBundle );
// Create stream to display and share source with video outstream
CMceVideoStream* streamForDisplay = CMceVideoStream::NewLC();
CMceVideoStream* videoOut = MusEngMceUtils::GetVideoOutStreamL( *iSession );
SetMediaSdpLinesL( *videoOut );
streamForDisplay->SetSourceL( videoOut->Source() );
MusEngMceUtils::AddDisplayL( *streamForDisplay, *iManager, Rect() );
iSession->AddStreamL( streamForDisplay );
CleanupStack::Pop( streamForDisplay );
// Check if there are audio streams to bundle with
if ( localBundle->Streams().Count() > 0 )
{
localBundle->AddStreamL( *streamForDisplay );
iSession->AddBundleL( localBundle );
CleanupStack::Pop( localBundle );
}
else
{
CleanupStack::PopAndDestroy( localBundle );
}
MUS_LOG( "mus: [ENGINE] <- CMusEngMceOutSession::CreateMceSessionStructureL()" )
}
// -----------------------------------------------------------------------------
// Add Privacy header if own phone number/id should not be sent to remote party
// -----------------------------------------------------------------------------
//
void CMusEngMceOutSession::AddPrivacyHeaderL( CDesC8Array& aHeaders )
{
MUS_LOG( "mus: [ENGINE] -> AddPrivacyHeaderL()" )
_LIT8( KMusPrivacyHeaderValue, "id" );
CSIPExtensionHeader* header = CSIPExtensionHeader::NewLC(
KMusPrivacyHeader, KMusPrivacyHeaderValue );
HBufC8* headInText = header->ToTextL();
MUS_LOG_TDESC8( " mus: [ENGINE] Privacy header : ", headInText->Des() );
CleanupStack::PopAndDestroy( header );
CleanupStack::PushL( headInText );
aHeaders.AppendL( *headInText );
CleanupStack::PopAndDestroy( headInText );
MUS_LOG( "mus: [ENGINE] <- AddPrivacyHeaderL()" )
}