/*
* Copyright (c) 2002-2010 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:  In this state, streaming is active.
*
*/




// INCLUDE FILES
#include "btsacStateStreaming.h"
#include "btsacStateListening.h"
#include "btsacStateSuspended.h"
#include "btsacStateConnected.h"
#include "btsacStateAborting.h"
#include "btsacactive.h"
#include "btsacGavdp.h"
#include "btsacSEPManager.h"
#include "btsacStreamerController.h"
#include "debug.h"

// A2DP codec-specific element definitions
// in bluetoothAV.h
using namespace SymbianBluetoothAV;   

// Subband codec-specific values
// in bluetoothAV.h
using namespace SymbianSBC;   


// ================= MEMBER FUNCTIONS =======================

// -----------------------------------------------------------------------------
// CBtsacStreaming::NewL
// -----------------------------------------------------------------------------
//
CBtsacStreaming* CBtsacStreaming::NewL(CBTSAController& aParent, TAudioOpenedBy aAudioOpenedBy, TBool aStartCollision)
    {
    CBtsacStreaming* self = new( ELeave ) CBtsacStreaming(aParent, aAudioOpenedBy, aStartCollision);
    return self;
    }

// -----------------------------------------------------------------------------
// CBtsacStreaming::CBtsacStreaming
// -----------------------------------------------------------------------------
//
CBtsacStreaming::CBtsacStreaming(CBTSAController& aParent, TAudioOpenedBy aAudioOpenedBy, TBool aStartCollision)
:   CBtsacState(aParent, EStateStreaming), iSuspending(EFalse), iAudioOpenedBy(aAudioOpenedBy),
	iStartCollision(aStartCollision)
    {
    }
  
// -----------------------------------------------------------------------------
// CBtsacStreaming::~CBtsacStreaming
// -----------------------------------------------------------------------------
//    
CBtsacStreaming::~CBtsacStreaming()
    {
    TRACE_FUNC
    }

// -----------------------------------------------------------------------------
// CBtsacStreaming::EnterL
// -----------------------------------------------------------------------------
//
void CBtsacStreaming::EnterL()
    {
	TRACE_STATE(_L("[BTSAC State] Streaming"))
	_LIT(KName, "CBtsacStateStreaming");
	const TDesC& Name = KName;
	Parent().iGavdp->RegisterObserver(this, Name);
	if( iAudioOpenedBy == EAudioOpenedByAcc )
	 	{
 		Parent().AccessoryOpenedAudio(Parent().GetRemoteAddr());
	 	}
    }

// -----------------------------------------------------------------------------
// CBtsacStreaming::CancelActionL
// -----------------------------------------------------------------------------
//
void CBtsacStreaming::CancelActionL(TInt aError)
	{
	TRACE_FUNC
	TInt ret = Parent().iStreamer->StopStream();
	if ( ret )
		{
		TRACE_INFO((_L("CBtsacStreaming::Cancel() iStreamer.StopStream() returned error(%d) !!!"), ret))
		}
	Parent().CompletePendingRequests(KCompleteAllReqs, aError);
	Parent().ChangeStateL(CBtsacListening::NewL(Parent(), EResetGavdp, aError));
	}

// -----------------------------------------------------------------------------
// CBtsacStreaming::OpenAudioLinkL
// -----------------------------------------------------------------------------
//
void CBtsacStreaming::OpenAudioLinkL(const TBTDevAddr& /*aAddr*/)
	{  
	TRACE_FUNC
	// It is not allowed to open audio in streaming state, audio is allready opened
	// by an accessory. Inform accessory fw about this by returning KErrInUse.
	Parent().CompletePendingRequests(KOpenAudioReq, KErrInUse);
	}

// -----------------------------------------------------------------------------
// CBtsacStreaming::CloseAudioLinkL
// -----------------------------------------------------------------------------
//
void CBtsacStreaming::CloseAudioLinkL(const TBTDevAddr& /*aAddr*/)
	{  
	TRACE_FUNC
	iStartCollision = EFalse;
	TInt ret = Parent().iStreamer->StopStream();
	if ( ret )
		{
		TRACE_INFO((_L("CBtsacStreaming::CloseAudio() iStreamer.StopStream() returned error(%d) !!!"), ret))
		}
	TAvdtpSEPInfo SEPInfo;
	ret = Parent().iRemoteSEPs->GetInfo(Parent().GetSEPIndex(), SEPInfo); 
	if ( ret )
		{
		TRACE_INFO((_L("CBtsacStreaming::CloseAudio() Couldn't retrieve SEP Info !")))
		CancelActionL(KErrCancel); 
 		return;   
		}
	// Suspend audio
	TSEID remoteSEPid = SEPInfo.SEID(); 	
	TRACE_INFO((_L("CBtsacStreaming::CloseAudio() Suspending remote SEID(%d)"), remoteSEPid.SEID()))	
	iSuspending = ETrue;
	Parent().iGavdp->SuspendStreams(remoteSEPid);
	}

// -----------------------------------------------------------------------------
// CBtsacStreaming::CancelCloseAudioLink
// -----------------------------------------------------------------------------
//
void CBtsacStreaming::CancelCloseAudioLink(const TBTDevAddr& /*aAddr*/)
	{
	TRACE_FUNC
	// For safety sake complete all pending requests
	Parent().CompletePendingRequests(KCompleteAllReqs, KErrNone);
	TRAP_IGNORE(Parent().ChangeStateL(CBtsacListening::NewL(Parent(), EResetGavdp, KErrDisconnected)));
	}


// -----------------------------------------------------------------------------
// CBtsacStreaming::StartRecording
// -----------------------------------------------------------------------------
//
void CBtsacStreaming::StartRecording()
	{  
	TRACE_FUNC	
	iStartCollision = EFalse;
	if ( Parent().iStreamer->StartStream(Parent().iStreamingSockets[0], Parent().iStreamer->FrameLength()) != KErrNone ) 
	 	{
		TRACE_INFO((_L("CBtsacStreaming::StartRecording() [ERR] Could not start streaming!")))	
		TInt err = Parent().AbortStream();
		if(err)
			{
			TRACE_INFO((_L("CBtsacStreaming::StartRecording() Couldn't abort stream.")))	
			}
		TRAP_IGNORE(Parent().ChangeStateL(CBtsacListening::NewL(Parent(), EResetGavdp, KErrDisconnected)));
	 	}
	}

// -----------------------------------------------------------------------------
// CBtsacStreaming::DisconnectL
// -----------------------------------------------------------------------------
//
void CBtsacStreaming::DisconnectL()
	{
	TRACE_FUNC
	TInt ret = Parent().iStreamer->StopStream();
	if ( ret )
		{
		TRACE_INFO((_L("CBtsacStreaming::DisconnectL() StopStream() returned error: %d"), ret))	
		}
	Parent().CompletePendingRequests(KDisconnectReq, ret);
	Parent().ChangeStateL(CBtsacListening::NewL(Parent(), EResetGavdp, KErrNone));
	}

// -----------------------------------------------------------------------------
// CBtsacStreaming::GAVDP_SuspendStreamsConfirm
// -----------------------------------------------------------------------------
//
void CBtsacStreaming::GAVDP_SuspendStreamsConfirm()
	{
	TRACE_FUNC
    // so remote supports suspend 
    iSuspending = EFalse;
	Parent().CompletePendingRequests(KCloseAudioReq, KErrNone);
	TRAP_IGNORE(Parent().ChangeStateL(CBtsacSuspended::NewL(Parent())));
	}

// -----------------------------------------------------------------------------
// CBtsacStreaming::GAVDP_AbortIndication
// -----------------------------------------------------------------------------
//	
void CBtsacStreaming::GAVDP_AbortIndication(TSEID aSEID)
	{
	TRACE_INFO((_L("CBtsacStreaming::GAVDP_AbortIndication() Local SEP Id: %d"), aSEID.SEID()))	
	(void)aSEID;
	TInt ret = Parent().iStreamer->StopStream();
	if ( ret )
		{
		TRACE_INFO((_L("CBtsacStreaming::Cancel() iStreamer.StopStream() returned error(%d) !!!"), ret))
		}
	
	// It is possible the remote disconnected while we have active close audio request.
	Parent().CompletePendingRequests(KCompleteAllReqs, KErrNone);
    TRAP_IGNORE(Parent().ChangeStateL(CBtsacListening::NewL(Parent(), EResetGavdp, KErrDisconnected)));
	}

// -----------------------------------------------------------------------------
// CBtsacStreaming::GAVDP_ReleaseIndication
// -----------------------------------------------------------------------------
//
void CBtsacStreaming::GAVDP_ReleaseIndication(TSEID aSEID)
	{
	TRACE_INFO((_L("CBtsacStreaming::GAVDP_ReleaseIndication() aSEID: %d"), aSEID.SEID()))	
	(void)aSEID;
	if(!iSuspending)
		{		
		TInt ret = Parent().iStreamer->StopStream();
		if ( ret ) 
		 	{
			TRACE_INFO((_L("CBtsacStreaming::GAVDP_ReleaseIndication() [ERR: %d] Could not stop streaming!"), ret))	
		 	}
	 	Parent().AccessoryClosedAudio(Parent().GetRemoteAddr());
		}
	else
		{
		// We are trying to suspend the stream and remote end has sent release indication.
		// Stream is already stopped but we have pending close audio request, complete it.
		Parent().CompletePendingRequests(KCloseAudioReq, KErrNone);
		}
	Parent().CleanSockets();
	TRAP_IGNORE(Parent().ChangeStateL(CBtsacConnected::NewL(Parent(), EConnExists)));
	}

// -----------------------------------------------------------------------------
// CBtsacStreaming::GAVDP_SuspendIndication
// -----------------------------------------------------------------------------
//	
TInt CBtsacStreaming::GAVDP_SuspendIndication(TSEID aSEID)
	{
	TRACE_INFO((_L("CBtsacStreaming::GAVDP_SuspendIndication() aSEID: %d"), aSEID.SEID()))	
	(void)aSEID;
	if(!iSuspending)
		{		
		TInt ret = Parent().iStreamer->StopStream();
		if ( ret )
			{
			TRACE_INFO((_L("CBtsacStreaming::GAVDP_SuspendIndication() iStreamer.StopStream() returned error(%d) !!!"), ret))	
			}
		Parent().AccessorySuspendedAudio(Parent().GetRemoteAddr());
		TRAPD(err, Parent().ChangeStateL(CBtsacSuspended::NewL(Parent())));
		if(err)
			{
			return KErrNoMemory;
			}
		}
	return KErrNone;
	}

// -----------------------------------------------------------------------------
// CBtsacStreaming::HandleGavdpErrorL
// -----------------------------------------------------------------------------
//	
void CBtsacStreaming::HandleGavdpErrorL(TInt aError)
	{
	TRACE_FUNC
	TInt err = KErrNone;

	if(aError == (KErrAvdtpSignallingErrorBase - EAvdtpBadState) && iStartCollision)
		{
		// Start stream collision has happened (src and snk have sent start stream cmd simultaneously).
		// iStreamStartIndCollision flag is set in configured state to indicate possible collision
		// situations.
		// Error can be ignored and we can continue streaming.
		iStartCollision = EFalse;
		TRACE_INFO((_L("CBtsacStreaming::HandleGavdpErrorL() Ignore error, continue streaming.")))
		return;
		}

	if(iSuspending)
		{
		iSuspending = EFalse;
		if(aError == (KErrAvdtpSignallingErrorBase - EAvdtpBadState)) // -18094
			{
			// For some reason remote rejected our suspend command. According to the specification
			// it is acceptor's responsibilty to cope with this situation, so we can move to suspended
			// state and wait for acceptor's reaction.
	        Parent().CompletePendingRequests(KCloseAudioReq, KErrNone);
			Parent().ChangeStateL(CBtsacSuspended::NewL(Parent()));
		    return;
			}
		else if(aError == (KErrAvdtpSignallingErrorBase - EAvdtpNotSupportedCommand)) // -18070 
			{
			// remote doesn't support suspend so close audio 
			Parent().CleanSockets();
	        Parent().CompletePendingRequests(KCloseAudioReq, KErrNone);
			Parent().ChangeStateL(CBtsacConnected::NewL(Parent(), EConnExists));
		    return;
			}
		}
	else
		{
		err = Parent().iStreamer->StopStream();
		if (err)
	 		{
			TRACE_INFO((_L("CBtsacStreaming::HandleGavdpErrorL() [error: %d] Could not stop streaming!"), err))
	 		}
		}
	
	switch (aError)
		{
		case KErrAvdtpRequestTimeout: // -18005
		case (KErrAvdtpSignallingErrorBase - EAvdtpBadState): // 18094
			{
			err = Parent().AbortStream();
			if(!err)
				{
				// Complete pending requests in Aborting state
				Parent().ChangeStateL(CBtsacAborting::NewL(Parent()));
				}
			else
				{
				Parent().CompletePendingRequests(KCompleteAllReqs, aError);
				Parent().ChangeStateL(CBtsacListening::NewL(Parent(), EResetGavdp, KErrDisconnected));
				}
			break;
			}
		case KErrHCILinkDisconnection: // -6305
		case KErrDisconnected: // -36
			{
			Parent().CompletePendingRequests(KCompleteAllReqs, aError);
			Parent().ChangeStateL(CBtsacListening::NewL(Parent(), EResetGavdp, aError));
			break;
			}
		default:
			{
			// Unknown error. For safety's sake let's disconnect a2dp link and inform btaudioman
			TRACE_INFO((_L("CBtsacStreaming::HandleGavdpErrorL() Unknown error, goes to listening")))
			Parent().CompletePendingRequests(KCompleteAllReqs, aError);
			Parent().ChangeStateL(CBtsacListening::NewL(Parent(), EResetGavdp, KErrDisconnected));
			break;
			}
		}
	}
	
//  End of File  
