// AudioGetDlg.cpp : implementation file
//

#include "stdafx.h"
#include "AudioGet.h"
#include "AudioGetDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define WATCH_AUDIO_ID 50001

/////////////////////////////////////////////////////////////////////////////
// CAudioGetDlg dialog

CAudioGetDlg::CAudioGetDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CAudioGetDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CAudioGetDlg)
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	m_pVAibo = NULL;
	m_nAiboID = -1;
	m_bConnected = false;
	m_bReceiving = false;
	m_myRequest = false;
	m_pATPDirectSound = NULL;
	m_bGettingAudioData = false;
	m_bPlayingSoundStop = false;
}

void CAudioGetDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAudioGetDlg)
	DDX_Control(pDX, IDC_PROGRESS_R, m_progR);
	DDX_Control(pDX, IDC_PROGRESS_L, m_progL);
	DDX_Control(pDX, IDC_IPADDRESS1, m_ipAddress);
	DDX_Control(pDX, IDC_BTN_START, m_btnStart);
	DDX_Control(pDX, IDC_BTN_REMOTE, m_btnRemote);
	DDX_Control(pDX, IDC_BTN_CONNECT, m_btnConnect);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAudioGetDlg, CDialog)
	//{{AFX_MSG_MAP(CAudioGetDlg)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BTN_CONNECT, OnBtnConnect)
	ON_BN_CLICKED(IDC_BTN_REMOTE, OnBtnRemote)
	ON_BN_CLICKED(IDC_BTN_START, OnBtnStart)
	ON_WM_DESTROY()
	ON_WM_TIMER()
	//}}AFX_MSG_MAP
	// VAIBO Sever Messages
	ON_REGISTERED_MESSAGE(WM_VAIBO_CONNECT, OnVAIBOConnect)
	ON_REGISTERED_MESSAGE(WM_VAIBO_CLIENT_UPDATE, OnVAIBOConnectUpdate)
	ON_REGISTERED_MESSAGE(WM_VAIBO_DISCONNECT, OnVAIBODisconnect)
    ON_REGISTERED_MESSAGE(WM_VAIBO_REMOTE_NOTIFY, OnVAIBORemoteNotify)
	ON_REGISTERED_MESSAGE(WM_AUDIOTP_UPDATE, OnATPWaveUpdate)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CAudioGetDlg message handlers

BOOL CAudioGetDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	if ( m_pVAibo == NULL ) {
		m_pVAibo = new CVAIBO( this->m_hWnd );
	}
	ASSERT(m_pVAibo);

	// Set the default IP address
	INT	nField0, nField1, nField2, nField3;
	LPCTSTR	p = theApp.m_sAiboIP.GetBuffer(128);
	::sscanf( p, "%d.%d.%d.%d", &nField0, &nField1, &nField2, &nField3 );
	theApp.m_sAiboIP.ReleaseBuffer();
	m_ipAddress.SetAddress( nField0, nField1, nField2, nField3 );
	
	// Initialize the Direct Sound wrapper
	m_pATPDirectSound = new CATPDirectSound();
	m_pATPDirectSound->Init( GetSafeHwnd() );
	return TRUE;  // return TRUE  unless you set the focus to a control
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CAudioGetDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CAudioGetDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

//	ON_REGISTERED_MESSAGE(WM_VAIBO_CLIENT_UPDATE, OnVAIBOConnectUpdate)
//	Another application has already connected to AIBO
LRESULT CAudioGetDlg::OnVAIBOConnectUpdate( WPARAM wParam, LPARAM lParam )
{
	LRESULT result;

    if ((unsigned) m_nAiboID != HIWORD(wParam)) {
		// This is not my AIBO that I requested to connect to
		return S_FALSE;
	}
	if (!m_myRequest) {
		// This is not my request, another application changes the connection status.
		return S_FALSE;
	}
	m_myRequest = FALSE;
	if (LOWORD(wParam) == 1) {
		result = OnVAIBOConnect(wParam, lParam );
	} else {
		result = OnVAIBODisconnect(wParam, lParam );
	}
	return result;
}

//	ON_REGISTERED_MESSAGE(WM_VAIBO_CONNECT, OnVAIBOConnect)
LRESULT CAudioGetDlg::OnVAIBOConnect( WPARAM wParam, LPARAM lParam )
{
	if ((unsigned) m_nAiboID != HIWORD(wParam)) {
		// This is not my AIBO that I requested to connect to
		return S_FALSE;
	}
	m_btnConnect.SetWindowText( "Disconnect" );
	m_bConnected = true;
	m_btnRemote.SetWindowText( "Remote" );
	m_btnRemote.EnableWindow( true );
	m_btnStart.EnableWindow( false );
	// Check another application getting remote control
	if ( m_pVAibo->IsRemote() ) {
		OnVAIBORemoteNotify(wParam, 1);
	} 
	return S_OK;
}

//	ON_REGISTERED_MESSAGE(WM_VAIBO_DISCONNECT, OnVAIBODisconnect)
LRESULT CAudioGetDlg::OnVAIBODisconnect( WPARAM wParam, LPARAM lParam )
{
	if ((unsigned) m_nAiboID != HIWORD(wParam)) {
		// This is not my AIBO that I was connected to
		return S_FALSE;
	}
	m_btnConnect.SetWindowText( "Connect" );
	m_btnRemote.SetWindowText( "Remote" );
	m_btnStart.SetWindowText( "Start" );
	m_btnRemote.EnableWindow( false );
	m_btnStart.EnableWindow( false );
	m_bReceiving = false;
	m_bConnected = false;
    m_nAiboID = -1;
	return S_OK;
}

//  ON_REGISTERED_MESSAGE(WM_VAIBO_REMOTE_NOTIFY, OnVAIBORemoteNotify)
LRESULT CAudioGetDlg::OnVAIBORemoteNotify( WPARAM wParam, LPARAM lParam )
{
    if ((unsigned) m_nAiboID != HIWORD(wParam)) {
        // This is not my AIBO that I requested to connect to
        return S_FALSE;
    }
    if (lParam) {
        // External control
		m_btnRemote.SetWindowText( "Autonomous" );
		m_btnStart.EnableWindow(true);
    } else {
        // Internal control
		m_btnRemote.SetWindowText( "Remote" );
		m_btnStart.EnableWindow(false);
    }
    return S_OK;
}

LRESULT CAudioGetDlg::OnATPWaveUpdate( WPARAM wParam, LPARAM recvLen )
{
	unsigned char	*recvBuf = NULL;

	recvBuf = (unsigned char*)::calloc( 1, recvLen );
	m_pVAibo->AudioGetData( recvBuf, recvLen );

	unsigned char *bLlo, *bLhi, *bRlo, *bRhi;
	int avgL, avgR;

	avgL = 0;
	avgR = 0;
	for ( int i = 0; i < recvLen; i += 4 ) {
		// audio format is 16bit stereo
		// get 4 bytes for each sample
		bLlo = recvBuf + i;
		bLhi = recvBuf + i + 1;
		bRlo = recvBuf + i + 2;
		bRhi = recvBuf + i + 3;

		// Convert the two bytes into one short (for each channel)
		avgL += abs( (short)(*bLlo | (*bLhi << 8)) );	// Left ear
		avgR += abs( (short)(*bRlo | (*bRhi << 8)) ); // Right ear
	}
	// average
	avgL /= recvLen/4;
	avgR /= recvLen/4;

	m_progL.SetPos( avgL/25 );
	m_progR.SetPos( avgR/25 );

	OutputWaveData( recvBuf, recvLen );
	::free( recvBuf );

	m_bGettingAudioData = true;
	if (m_bPlayingSoundStop) {
		// restart playing audio
		m_pATPDirectSound->StartPlay( m_nAudioTPMode );
		m_bPlayingSoundStop = false;
	}

	return S_OK;
}

void CAudioGetDlg::OnBtnConnect() 
{
 	if ( !m_bConnected ) {
		// Connect to AIBO
 		UpdateData();
		
		// Get the IP address to connect to
 		BYTE		nField0, nField1, nField2, nField3;
 		m_ipAddress.GetAddress(nField0, nField1, nField2, nField3 );
 		theApp.m_sAiboIP.Format("%d.%d.%d.%d", nField0, nField1, nField2, nField3 );

		m_btnConnect.SetWindowText( "Connecting..." );
		m_myRequest = TRUE;
		int nAiboID;
 		nAiboID = m_pVAibo->Connect( (LPCTSTR)theApp.m_sAiboIP );
 		if (nAiboID < 0) {	// Connection error
 			CString msgerr;
 			msgerr.Format( "AIBO connection error (%d), see VAIBODef.h", nAiboID );
 			AfxMessageBox( msgerr );
		}else{
			m_nAiboID = nAiboID;
		}
 	} else {
		// Disconnect from AIBO
		m_btnConnect.SetWindowText( "Disconnecting..." );
		m_myRequest = TRUE;
 		int result = m_pVAibo->Disconnect();
		if (result != VAIBO_NOERROR) {
	 		CString msgerr;
 			msgerr.Format( "AIBO disconnection error (%d), see VAIBODef.h", result );
 			AfxMessageBox( msgerr );
		}
	}
}

void CAudioGetDlg::OnBtnRemote() 
{
	if ( m_pVAibo == NULL ) return;

	// Check remote/autonomous mode
	if ( m_pVAibo->IsRemote() ) {
		// Change to autonomous (internal)
		m_btnRemote.SetWindowText( "Autonomous..." );
		if ( !m_pVAibo->InternalControl( FALSE ) ) {
            CString msgerr;
            msgerr.Format( "InternalControl error" );
            AfxMessageBox(msgerr);
		}
	}
	else {
		// Change to remote (external)
		m_btnRemote.SetWindowText( "Remote..." );
		if ( !m_pVAibo->ExternalControl( FALSE ) ) {
            CString msgerr;
            msgerr.Format( "ExternalControl error" );
            AfxMessageBox(msgerr);
		}
	}
}

void CAudioGetDlg::OnBtnStart() 
{
	if ( !m_bReceiving ) {
		m_bReceiving = true;
		m_nAudioTPMode = ATP16K_16BIT_STEREO;	// Audio format

		if (  m_pVAibo->GetStateAudioTP() == AUDIOTP_STATE_CLOSE) {
			m_pVAibo->AudioInit();
			
			// Required command in VAIBO to start receiving audio
			if ( m_pVAibo->AudioGetOpen( m_nAudioTPMode ) != AUDIOTP_NOERROR ) {
				return;
			}
			if ( !m_pVAibo->RequestNetService( AUDIO_IN_ID ) ) {
				return;
			}
		}

		// Send the audio format.
		m_pVAibo->SendCmd( APPCMD_AUDIO_RECV_MODE, true, m_nAudioTPMode );

		// Start playing the recorded sounds from AIBO
		m_pATPDirectSound->StartPlay( m_nAudioTPMode );
		m_bPlayingSoundStop = false;

		// Set Timer to stop audio reproduction in 1000msec
		SetTimer(WATCH_AUDIO_ID, 1000, NULL);
		
		// Command to start receiving audio data
		m_pVAibo->SendCmd( APPCMD_AUDIO_RECV_START );

		// Change the button text
		m_btnStart.SetWindowText( "Stop" );
	}
	else {
		// Turn off the receiving flag.
		m_bReceiving = false;

		// Command to stop receiving audio data
		m_pVAibo->SendCmd( APPCMD_AUDIO_RECV_STOP );

		// Stop audio reproduction
		m_pATPDirectSound->EndPlay();

		KillTimer(WATCH_AUDIO_ID);

		// Change the button text
		m_btnStart.SetWindowText( "Start" );
	}
}

// Reproduce Wave data. (called when Wave data is received)
void CAudioGetDlg::OutputWaveData( unsigned char *buff, int size )
{
	// reproduce audio data
	if ( m_pATPDirectSound ) {
		// Transmit
		m_pATPDirectSound->PlayWaveData( ( char* )buff, size );
	}
}

void CAudioGetDlg::OnDestroy() 
{
	CDialog::OnDestroy();	

	// Delete virtual AIBO
	if ( m_pVAibo != NULL ) {
		if ( m_bConnected ) {
			int result = m_pVAibo->Disconnect();
			if (result != VAIBO_NOERROR) {
	 			CString msgerr;
 				msgerr.Format("AIBO disconnection error (%d), see VAIBODef.h", result);
 				AfxMessageBox(msgerr);
			}
		}
		delete m_pVAibo;
		m_pVAibo = NULL;
	}
}

void CAudioGetDlg::OnTimer(UINT nIDEvent) 
{
	if (nIDEvent == WATCH_AUDIO_ID) {
		if (m_bGettingAudioData) {
			m_bGettingAudioData = false;
			m_bPlayingSoundStop = false;
		} else {
			m_pATPDirectSound->EndPlay();
			m_bPlayingSoundStop = true;
			m_progL.SetPos( 0 );
			m_progR.SetPos( 0 );
		}
	}
	CDialog::OnTimer(nIDEvent);
}
