Files
libraries/SDD/sdd_aupl.c
Philip Smart af833c09ee Initial upload
2019-11-18 00:29:48 +00:00

523 lines
18 KiB
C
Executable File

/******************************************************************************
* Product: ##### ###### ###### # ### ######
* # # # # # # # # # #
* # # # # # # # # #
* ##### # # # # # # ######
* # # # # # # # # #
* # # # # # # # # # #
* ##### ###### ###### ####### ####### ### ######
*
* File: sdd_aupl.c
* Description: Server Data-source Driver library driver to handle playback
* of 16bit Stereo Audio WAV file to the DSP circuitry of
* an underlying sound card.
*
* Version: %I%
* Dated: %D%
* Copyright: P.D. Smart, 1997-2019.
*
* History: 1.0 - Initial Release.
*
******************************************************************************
* This source file is free software: you can redistribute it and#or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This source file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
/* Bring in system header files.
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#if defined(SOLARIS) || defined(SUNOS) || defined(LINUX)
#include <sys/wait.h>
#endif
/* Indicate that we are a C module for any header specifics.
*/
#define SDD_AUPL_C
/* Bring in local specific header files.
*/
#include "sdd.h"
#include "sdd_aupl.h"
/******************************************************************************
* Function: _AUPL_GetStrArg
* Description: Function to scan an input buffer and extract a string based
* argument.
*
* Returns: SDD_FAIL- Couldnt obtain argument.
* SDD_OK - Argument obtained.
******************************************************************************/
int _AUPL_GetStrArg( UCHAR *snzDataBuf, /* I: Input buffer */
int nDataLen, /* I: Len of data */
UCHAR *szArg, /* I: Arg to look for */
UCHAR **pszPath ) /* O: Pointer to argument */
{
/* Local variables.
*/
int nCmpLen;
int nPos;
int nReturn = SDD_FAIL;
UCHAR *szFunc = "_AUPL_GetStrArg";
/* Go through the input buffer looking for 'szArg' within the
* input buffer. If it exists, then note the position just after it
* as this contains the string argument.
*/
for(nPos=0, nCmpLen=strlen(szArg); nPos < nDataLen; nPos++)
{
/* If a match occurs, then setup the pointer to correct location.
*/
if(strncmp(&snzDataBuf[nPos], szArg, nCmpLen) == 0)
{
/* Make sure that the match is not a sub-match as some of the
* variables we are scanning for are similar.
*/
if( (nPos == 0) ||
(nPos > 0 && snzDataBuf[nPos-1] == '\0') ||
(nPos > 0 && isspace(snzDataBuf[nPos-1])) )
{
nPos += nCmpLen;
break;
}
}
}
/* If the pointer did not reach the end of the buffer then we have
* located a valid name.
*/
if(nPos < nDataLen)
{
/* Setup the callers pointer to point to the correct location
* in the buffer.
*/
*pszPath = &snzDataBuf[nPos];
nReturn=SDD_OK;
}
/* Return result code to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: _AUPL_ValidatePath
* Description: Function to validate the existence of a path.
*
* Returns: SDD_FAIL- Couldnt validate PATH.
* SDD_OK - PATH validated.
******************************************************************************/
int _AUPL_ValidatePath( UCHAR *pszPath ) /* I: Path to validate */
{
/* Local variables.
*/
int nReturn = SDD_FAIL;
UCHAR *szFunc = "_AUPL_ValidatePath";
struct stat sStat;
/* Test the path to ensure its valid.
*/
if( (stat(pszPath, &sStat) == -1) ||
((sStat.st_mode & S_IFDIR) == 0) )
{
nReturn=SDD_FAIL;
} else
{
nReturn=SDD_OK;
}
/* Return result code to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: _AUPL_ValidateFile
* Description: Function to validate the existence of a file or to validate
* that a file can be created.
*
* Returns: SDD_FAIL- Couldnt obtain Filename or validate it.
* SDD_OK - Filename obtained and validated.
******************************************************************************/
int _AUPL_ValidateFile( UCHAR *pszPath, /* I: Path to file */
UCHAR *pszFile, /* I: File to validate */
UINT nWriteFlag ) /* I: Read = 0, Write = 1 */
{
/* Local variables.
*/
int nReturn = SDD_FAIL;
UCHAR szTmpBuf[MAX_TMPBUFLEN];
UCHAR *szFunc = "_AUPL_ValidateFile";
struct stat sStat;
FILE *fpTest;
/* Concatenate the file and path together, ready to perform a test.
*/
#if defined(SOLARIS) || defined(SUNOS) || defined(LINUX)
sprintf(szTmpBuf, "%s//%s", pszPath, pszFile);
#endif
#if defined(_WIN32)
sprintf(szTmpBuf, "%s%c%s", pszPath, 0x5c, pszFile);
#endif
/* Is the file to be created?
*/
if(nWriteFlag == TRUE)
{
/* Test the file by trying to create it, see if the underlying OS
* can perform this operation.
*/
if((fpTest=fopen(szTmpBuf, "w")) != NULL)
{
/* Close and remove the file we created, not needed yet.
*/
fclose(fpTest);
unlink(szTmpBuf);
nReturn = SDD_OK;
} else
{
nReturn = SDD_FAIL;
}
} else
{
/* Test the file to ensure that it exists and is readable.
*/
if( (stat(szTmpBuf, &sStat) == -1) ||
((sStat.st_mode & S_IFREG) == 0) )
{
nReturn=SDD_FAIL;
} else
{
nReturn=SDD_OK;
}
}
/* Return result code to caller.
*/
return(nReturn);
}
#if defined(SOLARIS) || defined(SUNOS) || defined(LINUX)
/******************************************************************************
* Function: _AUPL_PlayZ
* Description: Function to play a compressed audio file. Method of attach
* is to launch a child which is the actual decompressor, this
* feeds data back via the stdout of the child to our stdin. The
* data is then buffered in a round robin fashion and fed to the
* audio DSP hardware.
*
* Returns: SDD_FAIL- Command failed during execution.
* SDD_OK - Command executed successfully.
******************************************************************************/
int _AUPL_PlayZ( UCHAR *pszAudioPath, /* I: Path to Audio File */
UCHAR *pszAudioFile, /* I: Audio Filename */
int (*fSendDataCB)(UCHAR *, UINT),
/* I: Func for returning data */
UCHAR *szErrMsg ) /* O: Error message generated */
{
/* Local variables.
*/
int nChar;
int nEnd = FALSE;
int nNdx;
int nResult;
/* int nRetBufSize; */
int nReturn = SDD_OK;
UCHAR *pszTmpBuf;
/* UCHAR *pszRetBuf; */
UCHAR *szFunc = "_AUPL_Exec";
FILE *fpStdIn;
FILE *fpStdOut;
/* Allocate memory for return buffer.
if((pszRetBuf=(UCHAR *)malloc(nRetBufSize)) == NULL)
{
return(SDD_FAIL);
}
*/
/* Concatenate the decompressors file name plus the path and filename of
* the audio file to enable the decompression of the audio file to go
* ahead.
*/
nNdx=strlen(AUPL.szDecompExec)+strlen(pszAudioPath)+strlen(pszAudioFile)+10;
if((pszTmpBuf=(UCHAR *)malloc(nNdx)) == NULL)
{
return(SDD_FAIL);
}
sprintf(pszTmpBuf, "%s %s//%s", AUPL.szDecompExec, pszAudioPath,
pszAudioFile);
/* Execute the program as a child with its stdout connected to a read
* stream such that we can capture its output.
*/
if((fpStdIn=popen(pszTmpBuf, "r")) == NULL)
{
/* Build up an error message to indicate that the decompression
* command failed.
*/
sprintf(szErrMsg, "%s: Failed to de-compress file (%s//%s).",
SDD_EMSG_BADEXEC, pszAudioPath, pszAudioFile);
/* Set exit code to indicate failure.
*/
nReturn = SDD_FAIL;
} else
if((fpStdOut=popen(AUPL.szAudioPlayer, "w")) == NULL)
{
/* Build up an error message to indicate that the Audio Player
* command failed.
*/
sprintf(szErrMsg, "%s: Failed to start Audio Player.",
SDD_EMSG_BADEXEC);
/* Set exit code to indicate failure.
*/
nReturn = SDD_FAIL;
}
while((nChar=fgetc(fpStdIn)) != EOF)
{
fputc(nChar, fpStdOut);
}
/* Close the Decompressor and get its exit code.
*/
nResult=pclose(fpStdIn);
/* Close the Audio Player and get its exit code.
*/
nResult=pclose(fpStdOut);
/* Free up allocated memory block.
*/
free(pszTmpBuf);
/* Return result code to caller.
*/
return(nReturn);
}
#endif
/******************************************************************************
* Function: aupl_InitService
* Description: Entry point which initialises the driver into a defined state.
* It is mandatory that this function is called before any other
* in order for the driver to function correctly. The caller
* provides it with two types of data, 1) A structure containing
* data for it to use in initialising itself, 2) a pointer to a
* buffer which the driver uses to place an error message should
* it not be able to complete initialisation.
*
* Returns: SDD_FAIL- An error occurred in initialising the driver and an
* error message is stored in szErrStr.
* SDD_OK - Driver initialised successfully.
******************************************************************************/
int aupl_InitService( SERVICEDETAILS *sServiceDet, /* I: Init data */
UCHAR *szErrStr ) /* O: Error message */
{
/* Local variables.
*/
int nReturn = SDD_OK;
UCHAR *szFunc = "aupl_InitService";
/* Setup any required constants, variables etc.
*/
strcpy(AUPL.szAudioPlayer, AUPL_AUDIO_PLAYER);
strcpy(AUPL.szDecompExec, AUPL_DECOMPRESSOR);
/* Log if debugging switched on.
*/
Lgr(LOG_MESSAGE, szFunc, "AUPL Driver: Initialised:");
/* Return result code to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: aupl_CloseService
* Description: Entry point which performs a drive closedown. The closedown
* procedure ensure that the driver returns to a virgin state
* (ie.like at power up) so that InitService can be called again.
*
* Returns: SDD_FAIL- An error occurred in closing the driver and an
* error message is stored in szErrStr.
* SDD_OK - Driver successfully closed.
******************************************************************************/
int aupl_CloseService( UCHAR *szErrMsg ) /* O: Error message if failed */
{
/* Local variables.
*/
int nReturn = SDD_OK;
UCHAR *szFunc = "aupl_CloseService";
/* Log if debugging switched on.
*/
Lgr(LOG_MESSAGE, szFunc, "AUPL Driver: Closed.");
/* Return result code to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: aupl_ProcessRequest
* Description: Entry point into driver to initiate the driver into
* processing a request. A data block is passed as a parameter
* to the driver which represents a request with relevant
* parameters. The data within the structure is only relevant
* to the original client and this driver code.
*
* Returns: SDD_FAIL- An error occurred within the driver whilst trying to
* process the request, see error text.
* SDD_OK - Request processed successfully.
******************************************************************************/
int aupl_ProcessRequest( UCHAR *snzDataBuf, /* I: Input data */
int nDataLen, /* I: Len of data */
int (*fSendDataCB)(UCHAR *, UINT),
/* I: CB to send reply*/
UCHAR *szErrMsg ) /* O: Error text */
{
/* Static variables.
*/
/* Local variables.
*/
int nReturn = SDD_OK;
UCHAR *pszAudioFile;
UCHAR *pszAudioPath;
UCHAR *szFunc = "aupl_ProcessRequest";
/* If the request block doesnt contain any data, something went wrong
* somewhere?
*/
if(nDataLen <= 1)
{
sprintf(szErrMsg,
"%s: Illegal request, has size of %dBytes",
SDD_EMSG_BADREQ, nDataLen);
return(SDD_FAIL);
}
/* If we have a PLAY_Z command, then extract relevant information from
* buffer.
*/
if(snzDataBuf[0] == SDD_PLAY_Z)
{
/* Locate the path argument and validate it.
*/
if(_AUPL_GetStrArg(&snzDataBuf[1], nDataLen-1, AUPL_AUDIOPATH,
&pszAudioPath) == SDD_FAIL||
_AUPL_ValidatePath(pszAudioPath) == SDD_FAIL)
{
sprintf(szErrMsg, "%s: Invalid PATH to Audio File provided",
SDD_EMSG_BADPATH);
return(SDD_FAIL);
}
/* Locate the Audio File Name argument and validate it.
*/
if(_AUPL_GetStrArg(&snzDataBuf[1], nDataLen-1, AUPL_AUDIOFILE,
&pszAudioFile) == SDD_FAIL ||
_AUPL_ValidateFile(pszAudioPath, pszAudioFile, FALSE) == SDD_FAIL)
{
sprintf(szErrMsg, "%s: Invalid Audio Filename provided",
SDD_EMSG_BADFILE);
return(SDD_FAIL);
}
}
/* First byte of the request data block indicates actions required, so
* decipher it.
*/
switch(snzDataBuf[0])
{
case SDD_PLAY_Z:
/* Log if debugging switched on.
*/
Lgr(LOG_DEBUG, szFunc,
"AUPL Driver: Req to execute Play Compressed File");
Lgr(LOG_DEBUG, szFunc,
"File Details: Path=%s, File=%s", pszAudioPath, pszAudioFile);
/* Execute the function. The final exit status dictates wether the
* command was a success or failure.
*/
if(_AUPL_PlayZ(pszAudioPath, pszAudioFile, fSendDataCB,
szErrMsg) == SDD_FAIL)
{
return(SDD_FAIL);
}
break;
default:
sprintf(szErrMsg,
"%s: Illegal request in request buffer (%x)",
SDD_EMSG_BADREQ, snzDataBuf[0]);
return(SDD_FAIL);
}
/* Return result code to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: aupl_ProcessOOB
* Description: Entry point into driver to process an out of band command
* that may or may not be relevant to current state of
* operation. The task of this function is to decipher the
* command and act on it immediately, ie. a cancel command
* would abort any ProcessRequest that is in process and
* clean up.
*
* Returns: No returns.
******************************************************************************/
void aupl_ProcessOOB( UCHAR nCommand ) /* I: OOB Command */
{
/* Local variables.
*/
/* Decipher command and perform actions accordingly.
*/
switch(nCommand)
{
/* Request to abort current ProcessRequest command and return daemon
* to a waiting-for-request state.
*/
case SDD_ABORT:
break;
/* Request to close down and exit.
*/
case SDD_EXIT:
break;
default:
break;
}
/* Return to caller.
*/
return;
}