diff -r 7fdc9a71d314 -r 8ad140f3dd41 hti/PC_Tools/HTIGateway/ServicePlugins/HtiAudio/HtiAudio.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hti/PC_Tools/HTIGateway/ServicePlugins/HtiAudio/HtiAudio.cpp Wed Oct 13 16:17:58 2010 +0300 @@ -0,0 +1,726 @@ +/* +* Copyright (c) 2009 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: +*/ +#include "HtiAudioH.h" +#include "HtiPlugin.h" +#include "HtiSoapHandlerInterface.h" + +#include +#include + +// Command codes +const unsigned char CMD_LIST_AUDIOFILES = 0x01; +const unsigned char CMD_PLAY_FILE = 0x02; +const unsigned char CMD_PLAY_TONE = 0x03; +const unsigned char CMD_PLAY_DTMF = 0x04; +const unsigned char CMD_STOP = 0x05; +const unsigned char CMD_GET_DURATION = 0x06; +const unsigned char CMD_GET_MAXVOLUME = 0x07; +const unsigned char CMD_SET_VOLUME = 0x08; + +// enums +enum PlayState { + EStopped, + EPlaying, + EError +}; + +enum PlayCommand { + EPlayAudioFile = 0, + EPlayTone, + EPlayDtmf, + ENrOfPlayCommands +}; + +// global variable(s) +int g_PlayCommandState[ENrOfPlayCommands] = { EStopped, EStopped, EStopped }; + + +// predeclarations +bool handle_async_msg(HtiSoapHandlerInterface* handler); +void SetSoapFaultFromReceivedHtiAudioError(struct soap *soap, + BYTE *receivedMsgBody, + int receivedMsgBodyLen); + +//********************************************************************************** +// HELPER CLASSES +// +//********************************************************************************** + +//********************************************************************************** +// CLASS HtiAudioMsg +//********************************************************************************** +class HtiAudioMsg : public HtiMsgHelper +{ +public: + HtiAudioMsg( struct soap *soap ); + HtiAudioMsg( struct soap *soap, DWORD serviceId, BYTE command ); + int ReceiveMsgWithAsyncHandler( int timeout ); + int SendReceiveMsgWithAsyncHandler( int timeout ); + +public: // from HtiMsgHelper + // We need to use SetSoapFaultFromReceivedHtiAudioError handler + int ReceiveMsg( int timeout ); +}; + +//********************************************************************************** +// HtiAudioMsg::HtiAudioMsg +//********************************************************************************** +HtiAudioMsg::HtiAudioMsg( struct soap *soap ) : HtiMsgHelper( soap ) +{ +} + +//********************************************************************************** +// HtiAudioMsg::HtiAudioMsg +//********************************************************************************** +HtiAudioMsg::HtiAudioMsg( struct soap *soap, DWORD serviceId, BYTE command ) + : HtiMsgHelper( soap, serviceId, command ) +{ +} + +//********************************************************************************** +// HtiAudioMsg::ReceiveMsg +//********************************************************************************** +int HtiAudioMsg::ReceiveMsg( int timeout ) +{ + // Clean these up for received HTI message + if(m_msgBody) + { + delete m_msgBody; + m_msgBody = NULL; + m_msgBodyLen = 0; + } + + HtiSoapHandlerInterface* handler = + static_cast(m_soap->user); + + // Wait for OK or error msg + if (handler->WaitForHtiMessage(timeout)) + { + // (handler has ownership of the message body) + m_msgBody = (BYTE*) handler->ReceivedHtiMessageBody(); + m_msgBodyLen = handler->ReceivedHtiMessageBodySize(); + + if ( !handler->IsReceivedHtiError() ) + { + // Get received message + return SOAP_OK; + } + else + { + /// Fill the error description + SetSoapFaultFromReceivedHtiAudioError( + m_soap, m_msgBody, m_msgBodyLen); + return SOAP_FAULT; + } + } + // ...or timeout + else + { + m_soap->error = soap_receiver_fault(m_soap, + "HtiGateway", "No response from symbian side"); + return SOAP_FAULT; + } +} + +//********************************************************************************** +// HtiAudioMsg::SendReceiveMsg +//********************************************************************************** +int HtiAudioMsg::SendReceiveMsgWithAsyncHandler( int timeout ) +{ + SendMsg(); + return ReceiveMsgWithAsyncHandler( timeout ); +} + +//********************************************************************************** +// HtiAudioMsg::ReceiveMsgWithAsyncHandler +//********************************************************************************** +int HtiAudioMsg::ReceiveMsgWithAsyncHandler( int timeout ) +{ + // Clean these up for to be received HTI message + if( m_msgBody ) + { + delete m_msgBody; + m_msgBody = NULL; + m_msgBodyLen = 0; + } + + HtiSoapHandlerInterface* handler = + static_cast( m_soap->user ); + + while(1) + { + if ( handler->WaitForHtiMessage( timeout ) ) + { + // NOTE: this will be destroyed by gateway + m_msgBody = (BYTE*) handler->ReceivedHtiMessageBody(); + m_msgBodyLen = handler->ReceivedHtiMessageBodySize(); + + if ( handle_async_msg( handler ) ) + continue; // async msg received wait for next msg + else + { + // error msg received ? + if( handler->IsReceivedHtiError() ) + { + SetSoapFaultFromReceivedHtiAudioError( + m_soap, m_msgBody, m_msgBodyLen ); + return SOAP_FAULT; + } + return SOAP_OK; + } + } + else + { + // timeout + m_soap->error = soap_receiver_fault(m_soap, + "HtiGateway", "No response from symbian side"); + return SOAP_FAULT; + } + } +} + + +//********************************************************************************** +// HELPER FUNCTIONS +// +//********************************************************************************** + +//********************************************************************************** +// isAudioPlaying +//********************************************************************************** +bool isAudioPlaying(struct soap *soap) +{ + if( (g_PlayCommandState[EPlayAudioFile] == EPlaying) || + (g_PlayCommandState[EPlayTone] == EPlaying) || + (g_PlayCommandState[EPlayDtmf] == EPlaying) ) + { + soap->error = soap_receiver_fault(soap, + "HtiGateway", "already playing audio"); + return TRUE; + } + return FALSE; +} + +//********************************************************************************** +// SetSoapFaultFromReceivedHtiAudioError +//********************************************************************************** +void SetSoapFaultFromReceivedHtiAudioError(struct soap *soap, + BYTE *receivedMsgBody, + int receivedMsgBodyLen) +{ + + if( receivedMsgBodyLen == 10 ) + { + // This is a standard error message + // (eg. not authenticated) + HtiSoapHandlerInterface* handler = + static_cast(soap->user); + handler->SendSoapFaultFromReceivedHtiError(); + return; + } + + + // Get error codes + int frameworkErrorCode = *((BYTE*)(receivedMsgBody + 1)); + int serviceErrorCode = *((DWORD*)(receivedMsgBody + 2)); + + // Get error description + // NOTE: first byte is skipped because it contains the command code + int serviceErrorDescLen = receivedMsgBodyLen - 11; + char* serviceErrorDesc = new char[receivedMsgBodyLen - 11 + 1]; + memcpy(serviceErrorDesc, receivedMsgBody+11, serviceErrorDescLen); + serviceErrorDesc[serviceErrorDescLen] = 0x0; + + // Fill the xml struct + std::stringstream s; + s<<""; + s<"; + s<"; + s<"; + s<<""; + + soap->error = soap_receiver_fault(soap, "HtiError", s.str().c_str() ); + + delete serviceErrorDesc; +} + + +//********************************************************************************** +// handle_async_msg +// Will return TRUE if message is handled +//********************************************************************************** +bool handle_async_msg( HtiSoapHandlerInterface* handler ) +{ + // Get message + BYTE *msgBody = (BYTE*) handler->ReceivedHtiMessageBody(); + int msgBodyLen = handler->ReceivedHtiMessageBodySize(); + + if(handler->IsReceivedHtiError()) + { + // First byte of service error description is the command it concers + int serviceErrorDesPos = 1+1+4+4; + switch(msgBody[serviceErrorDesPos]) + { + case CMD_PLAY_FILE: + g_PlayCommandState[EPlayAudioFile] = EError; + return TRUE; + + case CMD_PLAY_TONE: + g_PlayCommandState[EPlayTone] = EError; + return TRUE; + + case CMD_PLAY_DTMF: + g_PlayCommandState[EPlayDtmf] = EError; + return TRUE; + + default: + return FALSE; + } + } + + switch(msgBody[0]) + { + // Received from symbian side to indicate playing is complete + case CMD_PLAY_FILE: + g_PlayCommandState[EPlayAudioFile] = EStopped; + return TRUE; + + case CMD_PLAY_TONE: + g_PlayCommandState[EPlayTone] = EStopped; + return TRUE; + + case CMD_PLAY_DTMF: + g_PlayCommandState[EPlayDtmf] = EStopped; + return TRUE; + + default: + return FALSE; + } + + // Should never come here + return FALSE; +} + +//********************************************************************************** +// EXPORTED FUNCTIONS +// +//********************************************************************************** +//********************************************************************************** +// hti_serve() +//********************************************************************************** +int hti_serve(HtiSoapHandlerInterface* handler) +{ + handle_async_msg( handler ); + return 0; +} + +//********************************************************************************** +// SOAP FUNCTIONS +// +//********************************************************************************** +//********************************************************************************** +// ns1__listAudioFiles() +//********************************************************************************** +int ns1__listAudioFiles(struct soap* soap, + char *directory, // optional + struct ArrayOfAudioFiles *audiofiles) +{ + // construct & send & receive HTI message + HtiAudioMsg msg( soap, HTI_AUDIO_UID, CMD_LIST_AUDIOFILES ); + msg.AddStringWithLengthByte( directory ); + if ( msg.SendReceiveMsgWithAsyncHandler( HTIMSG_TIMEOUT_10_SECONDS ) ) + return SOAP_FAULT; + + // Check CommandCode + if ( msg.CheckCommandCode( CMD_LIST_AUDIOFILES ) ) + return SOAP_FAULT; + + // get size of array & alloc space for pointers + audiofiles->__size = (int) msg.GetWord(1); + audiofiles->__ptr = (char**) soap_malloc(soap, sizeof(char**)*audiofiles->__size); + + // read files + int offset = 3; + for ( int i = 0; i < audiofiles->__size; i++ ) + { + int fileNameLen = msg.GetByte(offset); + offset += 1; + audiofiles->__ptr[i] = (char*) soap_malloc( soap, fileNameLen+1 ); // +1 for nul + memcpy( audiofiles->__ptr[i], msg.GetMsgBody()+offset, fileNameLen ); + ( audiofiles->__ptr[i] )[fileNameLen] = 0x0; // add nul + offset += fileNameLen; + } + + return SOAP_OK; +} + +//********************************************************************************** +// ns1__startPlayAudioFile() +//********************************************************************************** +int ns1__startPlayAudioFile(struct soap* soap, + char *fileName, + unsigned char volume, + int startPosition, + int stopPosition, + unsigned char nrOfRepeats, + int silenceBetweenRepeats, + char *audioSettings, + struct ns1__startPlayAudioFileResponse *out) +{ + if( check_mandatory_string_parameter(soap, fileName, "fileName") || + check_mandatory_string_parameter(soap, audioSettings, "audioSettings") ) + return SOAP_FAULT; + + if( isAudioPlaying( soap ) ) + return SOAP_FAULT; + + // construct & send HTI message + HtiAudioMsg msg( soap, HTI_AUDIO_UID, CMD_PLAY_FILE ); + msg.AddStringWithLengthByte( fileName ); + msg.AddByte( volume ); + msg.AddInt( startPosition ); + msg.AddInt( stopPosition ); + msg.AddByte( nrOfRepeats ); + msg.AddInt( silenceBetweenRepeats ); + if(!strcmp("Default", audioSettings)) + msg.AddByte( 0x00 ); + else if(!strcmp("General Music", audioSettings)) + msg.AddByte( 0x01 ); + else if(!strcmp("Ring Tone Preview", audioSettings)) + msg.AddByte( 0x02 ); + else + { + soap->error = soap_receiver_fault(soap, "HtiGateway", "unknown audio setting"); + return SOAP_FAULT; + } + msg.SendMsg(); + + g_PlayCommandState[EPlayAudioFile] = EPlaying; + + return SOAP_OK; +} + +//********************************************************************************** +// ns1__playAudioFile() +//********************************************************************************** +int ns1__playAudioFile(struct soap* soap, + char *fileName, + unsigned char volume, + int startPosition, + int stopPosition, + unsigned char nrOfRepeats, + int silenceBetweenRepeats, + char *audioSettings, + int timeout, + struct ns1__playAudioFileResponse *out) +{ + // Start playing + if( ns1__startPlayAudioFile(soap, + fileName, + volume, + startPosition, + stopPosition, + nrOfRepeats, + silenceBetweenRepeats, + audioSettings, + NULL) ) + { + return SOAP_FAULT; + } + + // Set stopped immidietly as this is synchronous call + g_PlayCommandState[EPlayAudioFile] = EStopped; + + // get response + HtiAudioMsg msg( soap ); + if ( msg.ReceiveMsg( timeout ) ) + return SOAP_FAULT; + + return msg.CheckCommandCode( CMD_PLAY_FILE ); +} + +//********************************************************************************** +// ns1__startPlayTone() +//********************************************************************************** +int ns1__startPlayTone(struct soap* soap, + unsigned short frequency, + int duration, + unsigned char volume, + unsigned char nrOfRepeats, + int silenceBetweenRepeats, + struct ns1__startPlayToneResponse *out) +{ + if( isAudioPlaying( soap ) ) + return SOAP_FAULT; + + HtiAudioMsg msg( soap, HTI_AUDIO_UID, CMD_PLAY_TONE ); + msg.AddWord( frequency ); + msg.AddInt( duration ); + msg.AddByte( volume ); + msg.AddByte( nrOfRepeats ); + msg.AddInt( silenceBetweenRepeats ); + msg.SendMsg(); + + g_PlayCommandState[EPlayTone] = EPlaying; + + return SOAP_OK; +} + +//********************************************************************************** +// ns1__playTone() +//********************************************************************************** +int ns1__playTone(struct soap* soap, + unsigned short frequency, + int duration, + unsigned char volume, + unsigned char nrOfRepeats, + int silenceBetweenRepeats, + struct ns1__playToneResponse *out) +{ + // Start playing + if(ns1__startPlayTone(soap, + frequency, + duration, + volume,nrOfRepeats, + silenceBetweenRepeats, + NULL)) + return SOAP_FAULT; + + // Calculate timeout (in milliseconds) + int timeout = duration/1000 + + duration/1000*nrOfRepeats + + silenceBetweenRepeats*nrOfRepeats + + HTIMSG_TIMEOUT_10_SECONDS; + + // Set stopped immidietly as this is synchronous call + g_PlayCommandState[EPlayTone] = EStopped; + + // get response + HtiAudioMsg msg( soap ); + if ( msg.ReceiveMsg( timeout ) ) + return SOAP_FAULT; + + return msg.CheckCommandCode( CMD_PLAY_TONE ); +} + +//********************************************************************************** +// ns1__startPlayDtmf() +//********************************************************************************** +int ns1__startPlayDtmf(struct soap* soap, + char *dtmfString, + int toneLength, + int gapLength, + unsigned char volume, + unsigned char nrOfRepeats, + int silenceBetweenRepeats, + struct ns1__startPlayDtmfResponse *out) +{ + if(check_mandatory_string_parameter(soap, dtmfString, "dtmfString")) + return SOAP_FAULT; + + if(isAudioPlaying(soap)) + return SOAP_FAULT; + + HtiAudioMsg msg( soap, HTI_AUDIO_UID, CMD_PLAY_DTMF ); + msg.AddStringWithLengthByte( dtmfString ); + msg.AddInt( toneLength ); + msg.AddInt( gapLength ); + msg.AddByte( volume ); + msg.AddByte( nrOfRepeats ); + msg.AddInt( silenceBetweenRepeats ); + msg.SendMsg(); + + g_PlayCommandState[EPlayDtmf] = EPlaying; + + return SOAP_OK; +} + +//********************************************************************************** +// ns1__playDtmf() +//********************************************************************************** +int ns1__playDtmf(struct soap* soap, + char *dtmfString, + int toneLength, + int gapLength, + unsigned char volume, + unsigned char nrOfRepeats, + int silenceBetweenRepeats, + struct ns1__playDtmfResponse *out) +{ + // Start playing + if(ns1__startPlayDtmf(soap, + dtmfString, + toneLength, + gapLength, + volume, + nrOfRepeats, + silenceBetweenRepeats, + NULL)) + return SOAP_FAULT; + + // Calculate timeout + int nrOfTones = (int) strlen(dtmfString); + int timeout = toneLength/1000*nrOfTones + + gapLength/1000*nrOfTones + + toneLength/1000*nrOfTones*nrOfRepeats + + gapLength/1000*nrOfTones*nrOfRepeats + + silenceBetweenRepeats/1000*nrOfRepeats + + HTIMSG_TIMEOUT_10_SECONDS; + + // Set stopped immidietly as this is synchronous call + g_PlayCommandState[EPlayDtmf] = EStopped; + + // get response + HtiAudioMsg msg( soap ); + if ( msg.ReceiveMsg( timeout ) ) + return SOAP_FAULT; + + return msg.CheckCommandCode( CMD_PLAY_DTMF ); +} + +//********************************************************************************** +// ns1__getPlayStatus() +//********************************************************************************** +int ns1__getPlayStatus(struct soap* soap, + char* type, + char* &status) +{ + PlayCommand command; + + if( !strcmp(type, "audiofile") ) + command = EPlayAudioFile; + else if( !strcmp(type, "tone") ) + command = EPlayTone; + else if( !strcmp(type, "dtmf") ) + command = EPlayDtmf; + else + { + soap->error = soap_receiver_fault(soap, "HtiGateway", "unknown type"); + return SOAP_FAULT; + } + + switch(g_PlayCommandState[command]) + { + case EStopped: + status = (char*) soap_malloc(soap, strlen("stopped")+1); // +1 for nul char + strcpy(status, "stopped"); + break; + + case EPlaying: + status = (char*) soap_malloc(soap, strlen("playing")+1); // +1 for nul char + strcpy(status, "playing"); + break; + + case EError: + g_PlayCommandState[command] = EStopped; + status = (char*) soap_malloc(soap, strlen("error")+1); // +1 for nul char + strcpy(status, "error"); + break; + + default: + // should not happen ever + soap->error = soap_receiver_fault(soap, "HtiGateway", "unknown state"); + return SOAP_FAULT; + } + + return SOAP_OK; +} + +//********************************************************************************** +// ns1__stopPlayback() +//********************************************************************************** +int ns1__stopPlayback(struct soap* soap, + void *_, + struct ns1__stopPlaybackResponse *out) +{ + for(int i=0; i < ENrOfPlayCommands; i++) + g_PlayCommandState[i] = EStopped; + + HtiAudioMsg msg( soap, HTI_AUDIO_UID, CMD_STOP ); + if ( msg.SendReceiveMsgWithAsyncHandler( HTIMSG_TIMEOUT_10_SECONDS ) ) + return SOAP_FAULT; + + if ( msg.CheckCommandCode( CMD_STOP ) ) + return SOAP_FAULT; + + return SOAP_OK; +} + +//********************************************************************************** +// ns1__getDuration() +//********************************************************************************** +int ns1__getDuration(struct soap* soap, + char *fileName, // optional + int &duration) +{ + HtiAudioMsg msg( soap, HTI_AUDIO_UID, CMD_GET_DURATION ); + msg.AddStringWithLengthByte( fileName ); + if ( msg.SendReceiveMsgWithAsyncHandler( HTIMSG_TIMEOUT_10_SECONDS ) ) + return SOAP_FAULT; + + if ( msg.CheckCommandCode( CMD_GET_DURATION ) ) + return SOAP_FAULT; + + duration = msg.GetInt(1); + + return SOAP_OK; +} + +//********************************************************************************** +// ns1__getMaxVolume() +//********************************************************************************** +int ns1__getMaxVolume(struct soap* soap, + char *fileName, // optional + unsigned char &volume) +{ + HtiAudioMsg msg( soap, HTI_AUDIO_UID, CMD_GET_MAXVOLUME ); + msg.AddStringWithLengthByte( fileName ); + if ( msg.SendReceiveMsgWithAsyncHandler( HTIMSG_TIMEOUT_10_SECONDS ) ) + return SOAP_FAULT; + + if ( msg.CheckCommandCode( CMD_GET_MAXVOLUME ) ) + return SOAP_FAULT; + + volume = msg.GetByte(1); + + return SOAP_OK; +} + +//********************************************************************************** +// ns1__setVolume() +//********************************************************************************** +int ns1__setVolume(struct soap* soap, + unsigned char volume, + unsigned char &volumeSet) +{ + HtiAudioMsg msg( soap, HTI_AUDIO_UID, CMD_SET_VOLUME ); + msg.AddByte( volume ); + if ( msg.SendReceiveMsgWithAsyncHandler( HTIMSG_TIMEOUT_10_SECONDS ) ) + return SOAP_FAULT; + + if ( msg.CheckCommandCode( CMD_SET_VOLUME ) ) + return SOAP_FAULT; + + volumeSet = msg.GetByte(1); + + return SOAP_OK; +} + + +