diff -r 02103bf20ee5 -r 90dbfc0435e3 bluetoothengine/headsetsimulator/core/src/RemoteControl/hsremotecontrolserver.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bluetoothengine/headsetsimulator/core/src/RemoteControl/hsremotecontrolserver.cpp Wed Sep 15 15:59:44 2010 +0200 @@ -0,0 +1,534 @@ +/* + * 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 ( 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 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 + }