bluetoothengine/headsetsimulator/core/src/RemoteControl/hsremotecontrolserver.cpp
/*
* Component Name: Headset Simulator
* Author: Comarch S.A.
* Version: 1.0
* Copyright (c) 2010 Comarch S.A.
*
* This Software is submitted by Comarch S.A. to Symbian Foundation Limited on
* the basis of the Member Contribution Agreement entered between Comarch S.A.
* and Symbian Foundation Limited on 5th June 2009 (“Agreement”) and may be
* used only in accordance with the terms and conditions of the Agreement.
* Any other usage, duplication or redistribution of this Software is not
* allowed without written permission of Comarch S.A.
*
*/
#include "hsremotecontrolserver.h"
#include "hscore.h"
#include "hsremotecontroldatahandler.h"
#include "hsremotecontroltools.h"
#include "debug.h"
_LIT8(KHsATVGS,"AT+VGS=");
_LIT8(KHsATCommandEnding,"\r\n");
_LIT8(KHsATVGM,"AT+VGM=");
CHsControlServer* CHsControlServer::NewL( RSocketServ& aSocketServ,
CHsCore* aHsCore )
{
CHsControlServer* self = CHsControlServer::NewLC( aSocketServ, aHsCore );
CleanupStack::Pop( self );
return self;
}
CHsControlServer* CHsControlServer::NewLC( RSocketServ& aSocketServ,
CHsCore* aHsCore )
{
CHsControlServer* self = new ( ELeave ) CHsControlServer( aSocketServ,
aHsCore );
CleanupStack::PushL( self );
self->ConstructL();
return self;
}
CHsControlServer::CHsControlServer( RSocketServ& aSocketServ, CHsCore* aHsCore ) :
iState( ENone ), iSocketServ( aSocketServ ), iHsCore( aHsCore )
{
}
void CHsControlServer::ConstructL()
{
iDataHandler = CHsRemoteControlDataHandler::NewL();
}
CHsControlServer::~CHsControlServer()
{
TRACE_FUNC_ENTRY
CancelListen();
if ( iSocket )
{
delete iSocket;
}
if ( iListenSocket )
{
delete iListenSocket;
}
if ( iDataHandler )
{
delete iDataHandler;
}
TRACE_FUNC_EXIT
}
void CHsControlServer::StartRemoteControlServerL()
{
TRACE_FUNC_ENTRY
if ( iState != ENone )
{
TRACE_INFO (_L("ControlServer is already listening"))
TRACE_FUNC_EXIT
User::Leave( KErrInUse );
}
iState = EConnecting;
TProtocolDesc ProtocolDesc;
User::LeaveIfError( iSocketServ.FindProtocol( KHsRFComm(), ProtocolDesc ) );
if ( iListenSocket )
{
// Return value may be ignored
iListenSocket->Shutdown( RSocket::EImmediate );
delete iListenSocket;
iListenSocket = NULL;
}
iListenSocket = CBluetoothSocket::NewL( *this, iSocketServ,
ProtocolDesc.iSockType, ProtocolDesc.iProtocol );
User::LeaveIfError( iListenSocket->GetOpt(
KRFCOMMGetAvailableServerChannel, KSolBtRFCOMM, iServerPort ) );
TBTSockAddr btSockAddr;
btSockAddr.SetPort( iServerPort );
RegisterSdpL( iServerPort );
User::LeaveIfError( iListenSocket->Bind( btSockAddr ) );
TRACE_INFO( ( _L("Control Server port = %d"), iServerPort) )
User::LeaveIfError( iListenSocket->Listen( KHsSizeOfListenQueue ) );
TBTServiceSecurity secSettings;
TUid settingsUID = TUid::Uid( (TInt) KHsRemoteControlServiceID );
secSettings.SetUid( settingsUID );
secSettings.SetAuthentication( EFalse );
secSettings.SetAuthorisation( EFalse );
secSettings.SetEncryption( EFalse );
btSockAddr.SetSecurity( secSettings );
if ( iSocket )
{
// Return value may be ignored
iSocket->Shutdown( RSocket::EImmediate );
delete iSocket;
iSocket = NULL;
}
iSocket = CBluetoothSocket::NewL( *this, iSocketServ );
User::LeaveIfError( iListenSocket->Accept( *iSocket ) );
iInitialized = ETrue;
TRACE_INFO( _L("CHSControlServer::Listen() status = OK" ) )
TRACE_FUNC_EXIT
}
void CHsControlServer::CancelListen()
{
TRACE_FUNC_ENTRY
if ( iState == EWaiting )//Client is connected to socket
{
iSocket->CancelAll();
// Return value may be ignored
iSocket->Shutdown( RSocket::EImmediate );
delete iSocket;
iSocket = NULL;
iListenSocket->CancelAll();
// Return value may be ignored
iListenSocket->Shutdown( RSocket::EImmediate );
delete iListenSocket;
iListenSocket = NULL;
}
else
{ //Sockets are ready, but client is not connected
delete iSocket;
iSocket = NULL;
delete iListenSocket;
iListenSocket = NULL;
}
DeleteRecordSdp();
iInitialized = EFalse;
iState = ENone;
TRACE_FUNC_EXIT
}
void CHsControlServer::SetConnectionObserver(
MRemoteControllerConnectionObserver &aRemoteControllerObserver )
{
iConnectionObserver = &aRemoteControllerObserver;
}
void CHsControlServer::HandleConnectCompleteL( TInt aErr )
{
TRACE_FUNC_ENTRY
TRACE_INFO( ( _L("aErr = %d"), aErr) );
TRACE_FUNC_EXIT
}
void CHsControlServer::HandleAcceptCompleteL( TInt aErr )
{
TRACE_FUNC_ENTRY
TRACE_INFO( ( _L("aErr = %d"), aErr) );
iState = EWaiting;
Receive();
if ( iConnectionObserver )
{
iConnectionObserver->HandleRemoteControllerConnected( aErr );
}
TRACE_FUNC_EXIT
}
void CHsControlServer::HandleShutdownCompleteL( TInt aErr )
{
TRACE_FUNC_ENTRY
TRACE_INFO( ( _L("aErr = %d"), aErr) );
TRACE_FUNC_EXIT
}
void CHsControlServer::HandleSendCompleteL( TInt aErr )
{
TRACE_FUNC_ENTRY
TRACE_INFO( ( _L8("ControlServer sent %d bytes of data: [%S] with err [%d]")
,iSendDataBuffer.Length(), &iSendDataBuffer, aErr) )
TInt error = KErrNone;
if ( aErr == KErrNone )
{
iSendDataBuffer.Zero();
if ( iTempDataBuffer.Length() > 0 )
{
iSendDataBuffer.Append( iTempDataBuffer );
iTempDataBuffer.Zero();
error = iSocket->Write( iSendDataBuffer );
}
}
Receive();
User::LeaveIfError( error );
TRACE_FUNC_EXIT
}
void CHsControlServer::HandleReceiveCompleteL( TInt aErr )
{
TRACE_FUNC_ENTRY
TRACE_INFO( ( _L8("[ControlServer] received %d bytes of data: [%S]"
"with err [%d]"), iReceiveDataBuffer.Length(), &iReceiveDataBuffer,
aErr) )
if ( aErr == KErrNone )
{
TInt error = KErrNone;
if ( iSendDataBuffer.Length() > 0 )
{
error = iSocket->Write( iSendDataBuffer );
}
else if ( iTempDataBuffer.Length() > 0 )
{
iSendDataBuffer.Append( iTempDataBuffer );
iTempDataBuffer.Zero();
error = iSocket->Write( iSendDataBuffer );
}
TRAP_IGNORE( HandleRequestL( iReceiveDataBuffer ) );
Receive();
User::LeaveIfError( error );
}
else
{
TRACE_INFO( _L("ControlClient is disconnected") )
if ( iConnectionObserver )
{
iConnectionObserver->HandleRemoteControllerDisconnected( aErr );
}
CancelListen();
StartRemoteControlServerL();
}
TRACE_FUNC_EXIT
}
void CHsControlServer::HandleIoctlCompleteL( TInt /*aErr*/)
{
TRACE_FUNC_ENTRY
TRACE_FUNC_EXIT
}
void CHsControlServer::HandleActivateBasebandEventNotifierCompleteL(
TInt /*aErr*/, TBTBasebandEventNotification& /*aEventNotification*/)
{
TRACE_FUNC_ENTRY
TRACE_FUNC_EXIT
}
TInt CHsControlServer::Send( const TDesC8& aData )
{
TRACE_FUNC_ENTRY
TInt error = KErrNone;
if ( iState != EWaiting )
{
error = KErrNotReady;
TRACE_INFO( _L("ControlServer not ready") )
return error;
}
if ( iSendDataBuffer.Length() == 0 )
{
iSendDataBuffer.Append( iTempDataBuffer );
iTempDataBuffer.Zero();
iSendDataBuffer.Append( aData );
}
else
{
iTempDataBuffer.Append( aData );
}
if ( iSendDataBuffer.Length() > 0 )
{
iSocket->CancelRecv();
error = iSocket->Write( iSendDataBuffer );
Receive();
}
else
{
Receive();
}
TRACE_FUNC_EXIT
return error;
}
void CHsControlServer::Receive()
{
TRACE_FUNC_ENTRY
// Return value may be ignored,
// error will be notified to HandleReceiveCompleteL
iSocket->RecvOneOrMore( iReceiveDataBuffer, 0, iDataLength );
TRACE_FUNC_EXIT
}
void CHsControlServer::RegisterSdpL( TInt aChannel )
{
TRACE_FUNC_ENTRY
User::LeaveIfError( iSdpServer.Connect() );
User::LeaveIfError( iSdpDB.Open( iSdpServer ) );
TUUID serviceUUID( KHsRemoteControlServiceID );
iSdpDB.CreateServiceRecordL( serviceUUID, iSdpRecordHandle );
CSdpAttrValueDES* valDES = CSdpAttrValueDES::NewDESL( NULL );
CleanupStack::PushL( valDES );
valDES->StartListL()->BuildDESL()->StartListL()->BuildUUIDL( TUUID(
KL2CAPUUID ) )->EndListL()->BuildDESL()->StartListL()->BuildUUIDL(
TUUID( KRFCommUUID ) )->BuildUintL(
TSdpIntBuf <TUint8> ( aChannel ) )->EndListL()->EndListL();
iSdpDB.UpdateAttributeL( iSdpRecordHandle,
KSdpAttrIdProtocolDescriptorList, *valDES );
CleanupStack::PopAndDestroy( valDES );
iSdpDB.UpdateAttributeL( iSdpRecordHandle, KSdpAttrIdBasePrimaryLanguage
+ KSdpAttrIdOffsetServiceName, KServiceName );
iSdpDB.UpdateAttributeL( iSdpRecordHandle, KSdpAttrIdBasePrimaryLanguage
+ KSdpAttrIdOffsetServiceDescription, KServiceDesc );
UpdateAvailabilityL( ETrue );
TRACE_INFO ( _L("CHsControlServer::RegisterSdpL, status = OK") )
TRACE_FUNC_EXIT
}
void CHsControlServer::UpdateAvailabilityL( TBool aAvailable )
{
TInt state = ( aAvailable ? KServicAvailable : KServiceUnavailable );
// Set availability
iSdpDB.UpdateAttributeL( iSdpRecordHandle, KSdpAttrIdServiceAvailability,
state );
// Mark record changed
iSdpDB.UpdateAttributeL( iSdpRecordHandle, KSdpAttrIdServiceRecordState,
++iRecordState );
}
void CHsControlServer::DeleteRecordSdp()
{
TRACE_FUNC_ENTRY
iSdpDB.DeleteRecord( iSdpRecordHandle );
iSdpRecordHandle = 0;
iSdpDB.Close();
iSdpServer.Close();
TRACE_FUNC_EXIT
}
void CHsControlServer::HandleRequestL( TDes8 &aRequest )
{
TRACE_FUNC_ENTRY
TBuf8 <KHsRemoteControlPackageLength> buf;
THsControlCommandData dummyBuf( KNullDesC8 );
THsRemoteControlCommand command( dummyBuf, EHsLast );
if ( iDataHandler )
{
TInt err = iDataHandler->RecognizeCommand( aRequest, command );
if ( KErrNone != err )
{
User::Leave( KErrArgument );
}
}
THsRemoteControlCommandType type = EHsLast;
command.GetType( type );
switch ( type )
{
case EHsTurnOn:
{
command.GetData( buf );
RBuf8 cod;
RBuf8 sdp;
RBuf8 plugin;
cod.CleanupClosePushL();
sdp.CleanupClosePushL();
plugin.CleanupClosePushL();
RetrieveStartupParamsL( buf, cod, sdp, plugin );
iHsCore->StartSimulationL( cod, sdp, plugin );
CleanupStack::PopAndDestroy( 3 );
}
break;
case EHsTurnOff:
{
iHsCore->StopSimulation();
}
break;
case EHsConnectLastconnected:
{
iHsCore->ConnectWithLastConnectedL();
}
break;
case EHsConnectDevAddress:
{
command.GetData( buf );
iHsCore->ConnectWithDevAddress( buf.Expand() );
}
break;
case EHsConnectName:
{
command.GetData( buf );
iHsCore->ConnectWithName( buf.Expand() );
}
break;
case EHsDisconnectAGs:
{
iHsCore->DisconnectClients();
}
break;
case EHsAcceptCall:
{
User::LeaveIfError( iHsCore->AcceptIncomingCall() );
}
break;
case EHsReleaseCall:
{
User::LeaveIfError( iHsCore->ReleaseOngoingCall() );
}
break;
case EHsSetSpeakerVolume:
{
command.GetData( buf );
RBuf8 tempBuf;
tempBuf.CreateL( buf.Length() + KHsATCommandEnding().Length()
+ KHsATVGS().Length() );
tempBuf.Copy( KHsATVGS );
tempBuf.Append( buf );
tempBuf.Append( KHsATCommandEnding );
iHsCore->Send( tempBuf );
tempBuf.Close();
}
break;
case EHsSetMicVolume:
{
command.GetData( buf );
RBuf8 tempBuf;
tempBuf.CreateL( buf.Length() + KHsATCommandEnding().Length()
+ KHsATVGM().Length() );
tempBuf.Copy( KHsATVGM );
tempBuf.Append( buf );
tempBuf.Append( KHsATCommandEnding );
iHsCore->Send( tempBuf );
tempBuf.Close();
}
break;
case EHsSendAnyAt:
{
command.GetData( buf );
User::LeaveIfError( iHsCore->Send( buf ) );
}
break;
default:
User::Leave( KErrArgument );
}
TRACE_FUNC_EXIT
}
void CHsControlServer::RetrieveStartupParamsL( const TDesC8& aParams,
RBuf8& aPluginCod, RBuf8& aPluginSdp, RBuf8& aPluginProfile )
{
TRACE_FUNC_ENTRY
TInt sepPos = aParams.Find( KHsRemoteRequestParamSeparator );
User::LeaveIfError( sepPos );
aPluginCod.CreateL( aParams.Left( sepPos ) );
sepPos += 2;
TInt sepPos2 = aParams.Mid( sepPos, aParams.Length() - sepPos ).Find(
KHsRemoteRequestParamSeparator );
User::LeaveIfError( sepPos2 );
aPluginSdp.CreateL( aParams.Mid( sepPos, sepPos2 ) );
sepPos += 2;
sepPos += sepPos2;
aPluginProfile.CreateL( aParams.Mid( sepPos, aParams.Length() - sepPos ) );
TRACE_FUNC_EXIT
}