Sample code of audio playback and capture
#include "legato.h"
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include "interfaces.h"
//--------------------------------------------------------------------------------------------------
// Symbol and Enum definitions.
//--------------------------------------------------------------------------------------------------
#define ID_RIFF 0x46464952
#define ID_WAVE 0x45564157
#define ID_FMT 0x20746d66
#define ID_DATA 0x61746164
#define FORMAT_PCM 1
//--------------------------------------------------------------------------------------------------
// Data structures.
//--------------------------------------------------------------------------------------------------
struct
{
enum
{
STOP,
PLAY,
PAUSE,
RESUME,
RECORD,
DISCONNECT
} typeOption;
} OptionContext;
typedef struct {
uint32_t riffId;
uint32_t riffSize;
uint32_t riffFmt;
uint32_t fmtId;
uint32_t fmtSize;
uint16_t audioFormat;
uint16_t channelsCount;
uint32_t sampleRate;
uint32_t byteRate;
uint16_t blockAlign;
uint16_t bitsPerSample;
uint32_t dataId;
uint32_t dataSize;
} WavHeader_t;
typedef struct
{
WavHeader_t hd;
uint32_t wroteLen;
int pipefd[2];
le_thread_Ref_t mainThreadRef;
bool playDone;
}
PbRecSamplesThreadCtx_t;
//--------------------------------------------------------------------------------------------------
// Static declarations
//--------------------------------------------------------------------------------------------------
static le_audio_StreamRef_t MdmRxAudioRef = NULL;
static le_audio_StreamRef_t MdmTxAudioRef = NULL;
static le_audio_StreamRef_t FeInRef = NULL;
static le_audio_StreamRef_t FeOutRef = NULL;
static le_audio_StreamRef_t FileAudioRef = NULL;
static le_audio_ConnectorRef_t AudioInputConnectorRef = NULL;
static le_audio_ConnectorRef_t AudioOutputConnectorRef = NULL;
static le_audio_MediaHandlerRef_t MediaHandlerRef = NULL;
static const char* AudioTestCase;
static const char* MainAudioSoundPath;
static const char* AudioFilePath;
static int AudioFileFd = -1;
static bool PlayInLoop = false;
le_timer_Ref_t OptionTimerRef;
le_timer_Ref_t GainTimerRef = NULL;
le_timer_Ref_t MuteTimerRef = NULL;
static PbRecSamplesThreadCtx_t PbRecSamplesThreadCtx;
static le_thread_Ref_t RecPbThreadRef = NULL;
static uint32_t ChannelsCount;
static uint32_t SampleRate;
static uint32_t BitsPerSample;
static void DisconnectAllAudio(void);
static void PlaySamples(void* param1Ptr,void* param2Ptr);
static uint8_t NextOptionArg;
static le_audio_Format_t AudioFormat;
static bool DtxActivation;
static le_audio_AmrMode_t AmrMode;
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
static void GainTimerHandler
(
le_timer_Ref_t timerRef
)
{
static int32_t vol = 0, getVol = 0;
static bool increase = true;
le_result_t result;
if ( increase )
{
vol+=1;
if (vol == 100)
{
increase = false;
}
}
else
{
vol-=1;
if (vol == 0)
{
increase = true;
}
}
LE_INFO("Playback volume: vol %d", vol);
result = le_audio_SetGain(FileAudioRef, vol);
if (result != LE_OK)
{
LE_FATAL("le_audio_SetGain error : %d", result);
}
result = le_audio_GetGain(FileAudioRef, &getVol);
if ((result != LE_OK) || (vol != getVol))
{
LE_FATAL("le_audio_GetGain error : %d read volume: %d", result, getVol);
}
}
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
static void MuteTimerHandler
(
le_timer_Ref_t timerRef
)
{
static bool mute = false;
le_result_t result;
if ( mute )
{
result = le_audio_Unmute(FileAudioRef);
mute = false;
LE_INFO("Unmute audio Playback");
}
else
{
result = le_audio_Mute(FileAudioRef);
mute = true;
LE_INFO("Mute audio Playback");
}
if (result != LE_OK)
{
LE_FATAL("le_audio_Mute/le_audio_Unmute Failed %d", result);
}
}
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
static void DestroyRecThread
(
void *contextPtr
)
{
PbRecSamplesThreadCtx_t *threadCtxPtr = (PbRecSamplesThreadCtx_t*) contextPtr;
LE_INFO("wroteLen %d", threadCtxPtr->wroteLen);
close(AudioFileFd);
}
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
static void* RecSamplesThread
(
void* contextPtr
)
{
int pipefd[2];
int32_t len = 1024;
char data[len];
uint32_t channelsCount;
uint32_t sampleRate;
uint32_t bitsPerSample;
PbRecSamplesThreadCtx_t *threadCtxPtr = (PbRecSamplesThreadCtx_t*) contextPtr;
lseek(AudioFileFd, 0, SEEK_SET);
if (pipe(pipefd) == -1)
{
LE_ERROR("Failed to create the pipe");
return NULL;
}
LE_ASSERT(le_audio_SetSamplePcmChannelNumber(FileAudioRef, ChannelsCount) == LE_OK);
LE_ASSERT(le_audio_SetSamplePcmSamplingRate(FileAudioRef, SampleRate) == LE_OK);
LE_ASSERT(le_audio_SetSamplePcmSamplingResolution(FileAudioRef, BitsPerSample) == LE_OK);
LE_ASSERT(le_audio_GetSamplePcmChannelNumber(FileAudioRef, &channelsCount) == LE_OK);
LE_ASSERT(channelsCount == ChannelsCount);
LE_ASSERT(le_audio_GetSamplePcmSamplingRate(FileAudioRef, &sampleRate) == LE_OK);
LE_ASSERT(sampleRate == SampleRate);
LE_ASSERT(le_audio_GetSamplePcmSamplingResolution(FileAudioRef, &bitsPerSample) == LE_OK);
LE_ASSERT(bitsPerSample == BitsPerSample);
LE_ASSERT(le_audio_GetSamples(FileAudioRef, pipefd[1]) == LE_OK);
LE_INFO("Start getting samples...");
int32_t readLen;
while ((readLen = read( pipefd[0], data, len )))
{
int32_t len = write( AudioFileFd, data, readLen );
if (len < 0)
{
LE_ERROR("write error %d %d", readLen, len);
break;
}
threadCtxPtr->wroteLen += len;
}
return NULL;
}
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
static void RecSamples
(
void
)
{
memset(&PbRecSamplesThreadCtx,0,sizeof(PbRecSamplesThreadCtx_t));
RecPbThreadRef = le_thread_Create("RecSamples", RecSamplesThread, &PbRecSamplesThreadCtx);
DestroyRecThread,
&PbRecSamplesThreadCtx);
le_thread_Start(RecPbThreadRef);
}
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
static void DestroyPlayThread
(
void *contextPtr
)
{
PbRecSamplesThreadCtx_t *threadCtxPtr = (PbRecSamplesThreadCtx_t*) contextPtr;
LE_INFO("DestroyPlayThread playDone %d PlayInLoop %d", threadCtxPtr->playDone, PlayInLoop);
if( threadCtxPtr->playDone && PlayInLoop )
{
le_event_QueueFunctionToThread(threadCtxPtr->mainThreadRef,
PlaySamples,
contextPtr,
NULL);
}
else
{
LE_DEBUG("Close pipe Tx");
close(threadCtxPtr->pipefd[1]);
}
RecPbThreadRef = NULL;
}
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
static void* PlaySamplesThread
(
void* contextPtr
)
{
char data[1024];
int32_t len = 1;
uint32_t channelsCount;
uint32_t sampleRate;
uint32_t bitsPerSample;
PbRecSamplesThreadCtx_t *threadCtxPtr = (PbRecSamplesThreadCtx_t*) contextPtr;
lseek(AudioFileFd, 0, SEEK_SET);
if ( ( threadCtxPtr->pipefd[0] == -1 ) && ( threadCtxPtr->pipefd[1] == -1 ) )
{
if (pipe(threadCtxPtr->pipefd) == -1)
{
LE_ERROR("Failed to create the pipe");
return NULL;
}
LE_ASSERT(le_audio_SetSamplePcmChannelNumber(FileAudioRef, ChannelsCount) == LE_OK);
LE_ASSERT(le_audio_SetSamplePcmSamplingRate(FileAudioRef, SampleRate) == LE_OK);
LE_ASSERT(le_audio_SetSamplePcmSamplingResolution(FileAudioRef, BitsPerSample) == LE_OK);
LE_ASSERT(le_audio_GetSamplePcmChannelNumber(FileAudioRef, &channelsCount) == LE_OK);
LE_ASSERT(channelsCount == ChannelsCount);
LE_ASSERT(le_audio_GetSamplePcmSamplingRate(FileAudioRef, &sampleRate) == LE_OK);
LE_ASSERT(sampleRate == SampleRate);
LE_ASSERT(le_audio_GetSamplePcmSamplingResolution(FileAudioRef, &bitsPerSample) == LE_OK);
LE_ASSERT(bitsPerSample == BitsPerSample);
LE_ASSERT(le_audio_PlaySamples(FileAudioRef, threadCtxPtr->pipefd[0]) == LE_OK);
LE_INFO("Start playing samples...");
}
while ((len = read(AudioFileFd, data, 1024)) > 0)
{
int32_t wroteLen = write( threadCtxPtr->pipefd[1], data, len );
if (wroteLen <= 0)
{
LE_ERROR("write error %d", wroteLen);
return NULL;
}
}
threadCtxPtr->playDone = true;
return NULL;
}
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
static void PlaySamples
(
void* param1Ptr,
void* param2Ptr
)
{
if (RecPbThreadRef == NULL)
{
RecPbThreadRef = le_thread_Create("PlaySamples", PlaySamplesThread, param1Ptr);
DestroyPlayThread,
param1Ptr);
le_thread_Start(RecPbThreadRef);
}
}
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
static void ExecuteNextOption
(
void
)
{
bool nextOption = false;
if ( NextOptionArg < le_arg_NumArgs() )
{
if ( strncmp(le_arg_GetArg(NextOptionArg), "STOP", 4) == 0 )
{
le_clk_Time_t interval={0};
const char* stop = le_arg_GetArg(NextOptionArg);
if (strlen(stop) > 5) // higher than "STOP="
{
LE_INFO("STOP will be done in %d seconds", atoi(stop+5));
interval.sec = atoi(stop+5);
le_timer_SetInterval(OptionTimerRef, interval);
OptionContext.typeOption = STOP;
le_timer_Start(OptionTimerRef);
}
}
else if ( strncmp(le_arg_GetArg(NextOptionArg), "PLAY", 4) == 0 )
{
le_clk_Time_t interval={0};
const char* play = le_arg_GetArg(NextOptionArg);
if (strlen(play) > 5) // higher than "PLAY="
{
LE_INFO("PLAY will be done in %d seconds", atoi(play+5));
interval.sec = atoi(play+5);
le_timer_SetInterval(OptionTimerRef, interval);
OptionContext.typeOption = PLAY;
le_timer_Start(OptionTimerRef);
}
}
else if ( strncmp(le_arg_GetArg(NextOptionArg), "RECORD", 6) == 0 )
{
le_clk_Time_t interval={0};
const char* play = le_arg_GetArg(NextOptionArg);
if (strlen(play) > 7) // higher than "RECORD="
{
LE_INFO("RECORD will be done in %d seconds", atoi(play+7));
interval.sec = atoi(play+7);
le_timer_SetInterval(OptionTimerRef, interval);
OptionContext.typeOption = RECORD;
le_timer_Start(OptionTimerRef);
}
}
else if ( strncmp(le_arg_GetArg(NextOptionArg), "PAUSE", 5) == 0 )
{
le_clk_Time_t interval={0};
const char* pause = le_arg_GetArg(NextOptionArg);
if (strlen(pause) > 6) // higher than "PAUSE="
{
LE_INFO("PAUSE will be done in %d seconds", atoi(pause+6));
interval.sec = atoi(pause+6);
le_timer_SetInterval(OptionTimerRef, interval);
OptionContext.typeOption = PAUSE;
le_timer_Start(OptionTimerRef);
}
}
else if ( strncmp(le_arg_GetArg(NextOptionArg), "RESUME", 6) == 0 )
{
le_clk_Time_t interval={0};
const char* resume = le_arg_GetArg(NextOptionArg);
if (strlen(resume) > 7) // higher than "RESUME="
{
LE_INFO("RESUME will be done in %d seconds", atoi(resume+7));
interval.sec = atoi(resume+7);
le_timer_SetInterval(OptionTimerRef, interval);
OptionContext.typeOption = RESUME;
le_timer_Start(OptionTimerRef);
}
}
else if ( strncmp(le_arg_GetArg(NextOptionArg), "DISCONNECT", 10) == 0 )
{
le_clk_Time_t interval={0};
const char* resume = le_arg_GetArg(NextOptionArg);
if (strlen(resume) > 11) // higher than "DISCONNECT="
{
LE_INFO("DISCONNECT will be done in %d seconds", atoi(resume+11));
interval.sec = atoi(resume+11);
le_timer_SetInterval(OptionTimerRef, interval);
OptionContext.typeOption = DISCONNECT;
le_timer_Start(OptionTimerRef);
}
}
else if ( strncmp(le_arg_GetArg(NextOptionArg), "LOOP", 4) == 0 )
{
PlayInLoop = true;
nextOption = true;
}
else if ( strncmp(le_arg_GetArg(NextOptionArg), "MUTE", 4) == 0 )
{
le_clk_Time_t interval;
interval.sec = 1;
interval.usec = 0;
LE_INFO("Test the MUTE function");
MuteTimerRef = le_timer_Create ( "Mute timer" );
le_timer_SetHandler(MuteTimerRef, MuteTimerHandler);
le_timer_SetInterval(MuteTimerRef, interval);
le_timer_SetRepeat(MuteTimerRef,0);
le_timer_Start(MuteTimerRef);
}
else if ( strncmp(le_arg_GetArg(NextOptionArg),"GAIN",4) == 0 )
{
le_clk_Time_t interval;
interval.sec = 0;
interval.usec = 100000;
LE_INFO("Test the playback volume");
GainTimerRef = le_timer_Create ( "Gain timer" );
le_timer_SetHandler(GainTimerRef, GainTimerHandler);
le_audio_SetGain(FileAudioRef, 0);
le_timer_SetInterval(GainTimerRef, interval);
le_timer_SetRepeat(GainTimerRef,0);
le_timer_Start(GainTimerRef);
}
NextOptionArg++;
}
if (nextOption)
{
ExecuteNextOption();
}
}
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
void OptionTimerHandler
(
le_timer_Ref_t timerRef
)
{
le_result_t result;
LE_INFO("timeout for %d", OptionContext.typeOption);
switch (OptionContext.typeOption)
{
case STOP:
result = le_audio_Stop(FileAudioRef);
LE_INFO("Stop result %d", result);
if (RecPbThreadRef)
{
le_thread_Cancel(RecPbThreadRef);
RecPbThreadRef = NULL;
}
if ( strncmp(AudioTestCase,"PB_SAMPLES",10)==0 )
{
close(PbRecSamplesThreadCtx.pipefd[0]);
close(PbRecSamplesThreadCtx.pipefd[1]);
PbRecSamplesThreadCtx.pipefd[0] = -1;
PbRecSamplesThreadCtx.pipefd[1] = -1;
PbRecSamplesThreadCtx.playDone = 0;
}
break;
case PLAY:
if ( strncmp(AudioTestCase,"PB_SAMPLES",10)==0 )
{
PlaySamples(&PbRecSamplesThreadCtx, NULL);
}
else
{
result = le_audio_PlayFile(FileAudioRef,LE_AUDIO_NO_FD);
LE_INFO("Play result %d", result);
}
break;
case RECORD:
if ( strncmp(AudioTestCase,"REC_SAMPLES",11)==0 )
{
RecSamples();
}
else
{
result = le_audio_RecordFile(FileAudioRef,LE_AUDIO_NO_FD);
LE_INFO("Record result %d", result);
}
break;
case PAUSE:
result = le_audio_Pause(FileAudioRef);
LE_INFO("Pause result %d", result);
break;
case RESUME:
result = le_audio_Resume(FileAudioRef);
LE_INFO("Resume result %d", result);
break;
case DISCONNECT:
LE_INFO("disconnect all audio");
DisconnectAllAudio();
break;
default:
break;
}
ExecuteNextOption();
}
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
static void MyMediaEventHandler
(
void* contextPtr
)
{
if (!streamRef)
{
LE_ERROR("Bad streamRef");
return;
}
switch(event)
{
LE_INFO("File event is LE_AUDIO_MEDIA_ENDED.");
if (PlayInLoop)
{
}
break;
LE_INFO("File event is LE_AUDIO_MEDIA_ERROR.");
break;
LE_INFO("File event is LE_AUDIO_MEDIA_NO_MORE_SAMPLES.");
break;
default:
LE_INFO("File event is %d.", event);
break;
}
if (GainTimerRef)
{
le_timer_Stop (GainTimerRef);
le_timer_Delete (GainTimerRef);
GainTimerRef = NULL;
}
if (MuteTimerRef)
{
le_timer_Stop (MuteTimerRef);
le_timer_Delete (MuteTimerRef);
le_audio_Unmute(FileAudioRef);
MuteTimerRef = NULL;
}
}
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
static void ConnectAudioToUsb
(
void
)
{
// Redirect audio to the USB.
FeOutRef = le_audio_OpenUsbTx();
LE_ERROR_IF((FeOutRef==NULL), "OpenUsbTx returns NULL!");
FeInRef = le_audio_OpenUsbRx();
LE_ERROR_IF((FeInRef==NULL), "OpenUsbRx returns NULL!");
AudioInputConnectorRef = le_audio_CreateConnector();
LE_ERROR_IF((AudioInputConnectorRef==NULL), "AudioInputConnectorRef is NULL!");
AudioOutputConnectorRef = le_audio_CreateConnector();
LE_ERROR_IF((AudioOutputConnectorRef==NULL), "AudioOutputConnectorRef is NULL!");
{
res = le_audio_Connect(AudioInputConnectorRef, FeInRef);
LE_ERROR_IF((res!=LE_OK), "Failed to connect USB Rx on Input connector!");
res = le_audio_Connect(AudioOutputConnectorRef, FeOutRef);
LE_ERROR_IF((res!=LE_OK), "Failed to connect USB Tx on Output connector!");
}
}
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
static void ConnectAudioToFileLocalPlay
(
void
)
{
if ((AudioFileFd=open(AudioFilePath, O_RDONLY)) == -1)
{
LE_ERROR("Open file %s failure: errno.%d (%s)", AudioFilePath, errno, strerror(errno));
DisconnectAllAudio();
exit(0);
}
else
{
LE_INFO("Open file %s with AudioFileFd.%d", AudioFilePath, AudioFileFd);
}
// Play local on output connector.
FileAudioRef = le_audio_OpenPlayer();
LE_ERROR_IF((FileAudioRef==NULL), "OpenFilePlayback returns NULL!");
le_audio_Unmute(FileAudioRef);
MediaHandlerRef = le_audio_AddMediaHandler(FileAudioRef, MyMediaEventHandler, NULL);
if (FileAudioRef && AudioOutputConnectorRef)
{
res = le_audio_Connect(AudioOutputConnectorRef, FileAudioRef);
if(res != LE_OK)
{
LE_ERROR("Failed to connect FilePlayback on output connector!");
return;
}
if (strncmp(AudioTestCase,"PB_SAMPLES",10)==0)
{
memset(&PbRecSamplesThreadCtx,0,sizeof(PbRecSamplesThreadCtx_t));
PbRecSamplesThreadCtx.pipefd[0] = -1;
PbRecSamplesThreadCtx.pipefd[1] = -1;
PbRecSamplesThreadCtx.mainThreadRef = le_thread_GetCurrent();
PlaySamples(&PbRecSamplesThreadCtx, NULL);
}
else
{
LE_INFO("FilePlayback is now connected.");
res = le_audio_PlayFile(FileAudioRef, AudioFileFd);
if(res != LE_OK)
{
LE_ERROR("Failed to play the file!");
return;
}
else
{
LE_INFO("File is now playing");
}
}
ExecuteNextOption();
}
}
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
static void ConnectAudioToFileLocalRec
(
void
)
{
LE_ASSERT(le_audio_SetGain( FeInRef, 0x5000 ) == LE_OK);
if ((AudioFileFd=open(AudioFilePath, O_WRONLY | O_CREAT | O_TRUNC)) == -1)
{
LE_ERROR("Open file %s failure: errno.%d (%s)", AudioFilePath, errno, strerror(errno));
DisconnectAllAudio();
exit(0);
}
else
{
LE_INFO("Open file %s with AudioFileFd.%d", AudioFilePath, AudioFileFd);
}
// Capture local on input connector.
FileAudioRef = le_audio_OpenRecorder();
LE_ERROR_IF((FileAudioRef==NULL), "OpenFileRecording returns NULL!");
MediaHandlerRef = le_audio_AddMediaHandler(FileAudioRef, MyMediaEventHandler, NULL);
if (FileAudioRef && AudioInputConnectorRef)
{
res = le_audio_Connect(AudioInputConnectorRef, FileAudioRef);
if(res!=LE_OK)
{
LE_ERROR("Failed to connect FileRecording on input connector!");
return;
}
LE_INFO("Recorder is now connected.");
if ( strncmp(AudioTestCase,"REC_SAMPLES",11)==0 )
{
memset(&PbRecSamplesThreadCtx,0,sizeof(PbRecSamplesThreadCtx_t));
RecSamples();
ExecuteNextOption();
}
else
{
res = le_audio_SetEncodingFormat(FileAudioRef, AudioFormat);
if(res!=LE_OK)
{
LE_ERROR("Failed to set audio format");
return;
}
if (AudioFormat == LE_AUDIO_AMR)
{
LE_INFO("Set AMR mode %d", AmrMode);
res = le_audio_SetSampleAmrMode(FileAudioRef, AmrMode);
if(res!=LE_OK)
{
LE_ERROR("Failed to set AMR bitrate");
return;
}
LE_INFO("Set AMR DTX %d", DtxActivation);
res = le_audio_SetSampleAmrDtx(FileAudioRef, DtxActivation);
if(res!=LE_OK)
{
LE_ERROR("Failed to set DTX");
return;
}
}
res = le_audio_RecordFile(FileAudioRef, AudioFileFd);
if(res!=LE_OK)
{
LE_ERROR("Failed to record the file");
return;
}
else
{
LE_INFO("File is now recording.");
}
sleep(1);
LE_INFO("Try again to record");
LE_ASSERT(le_audio_RecordFile(FileAudioRef, LE_AUDIO_NO_FD) != LE_OK);
ExecuteNextOption();
}
}
}
#ifdef ENABLE_CODEC
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
static void ConnectAudioToCodec
(
void
)
{
// Redirect audio to the in-built Microphone and Speaker.
FeOutRef = le_audio_OpenSpeaker();
LE_ERROR_IF((FeOutRef==NULL), "OpenSpeaker returns NULL!");
FeInRef = le_audio_OpenMic();
LE_ERROR_IF((FeInRef==NULL), "OpenMic returns NULL!");
AudioInputConnectorRef = le_audio_CreateConnector();
LE_ERROR_IF((AudioInputConnectorRef==NULL), "AudioInputConnectorRef is NULL!");
AudioOutputConnectorRef = le_audio_CreateConnector();
LE_ERROR_IF((AudioOutputConnectorRef==NULL), "AudioOutputConnectorRef is NULL!");
{
res = le_audio_Connect(AudioInputConnectorRef, FeInRef);
LE_ERROR_IF((res!=LE_OK), "Failed to connect Mic on Input connector!");
res = le_audio_Connect(AudioOutputConnectorRef, FeOutRef);
LE_ERROR_IF((res!=LE_OK), "Failed to connect Speaker on Output connector!");
}
}
#endif
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
static void ConnectAudioToPcm
(
void
)
{
// Redirect audio to the PCM interface.
FeOutRef = le_audio_OpenPcmTx(0);
LE_ERROR_IF((FeOutRef==NULL), "OpenPcmTx returns NULL!");
FeInRef = le_audio_OpenPcmRx(0);
LE_ERROR_IF((FeInRef==NULL), "OpenPcmRx returns NULL!");
AudioInputConnectorRef = le_audio_CreateConnector();
LE_ERROR_IF((AudioInputConnectorRef==NULL), "AudioInputConnectorRef is NULL!");
AudioOutputConnectorRef = le_audio_CreateConnector();
LE_ERROR_IF((AudioOutputConnectorRef==NULL), "AudioOutputConnectorRef is NULL!");
{
res = le_audio_Connect(AudioInputConnectorRef, FeInRef);
LE_ERROR_IF((res!=LE_OK), "Failed to connect PCM RX on Input connector!");
res = le_audio_Connect(AudioOutputConnectorRef, FeOutRef);
LE_ERROR_IF((res!=LE_OK), "Failed to connect PCM TX on Output connector!");
}
}
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
static void ConnectAudioToI2s
(
void
)
{
// Redirect audio to the I2S interface.
LE_ERROR_IF((FeOutRef==NULL), "OpenI2sTx returns NULL!");
LE_ERROR_IF((FeInRef==NULL), "OpenI2sRx returns NULL!");
LE_INFO("Open I2s: FeInRef.%p FeOutRef.%p", FeInRef, FeOutRef);
AudioInputConnectorRef = le_audio_CreateConnector();
LE_ERROR_IF((AudioInputConnectorRef==NULL), "AudioInputConnectorRef is NULL!");
AudioOutputConnectorRef = le_audio_CreateConnector();
LE_ERROR_IF((AudioOutputConnectorRef==NULL), "AudioOutputConnectorRef is NULL!");
{
res = le_audio_Connect(AudioInputConnectorRef, FeInRef);
LE_ERROR_IF((res!=LE_OK), "Failed to connect I2S RX on Input connector!");
res = le_audio_Connect(AudioOutputConnectorRef, FeOutRef);
LE_ERROR_IF((res!=LE_OK), "Failed to connect I2S TX on Output connector!");
}
LE_INFO("Open I2s: FeInRef.%p FeOutRef.%p", FeInRef, FeOutRef);
}
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
static void ConnectAudio
(
void
)
{
if ((strncmp(AudioTestCase,"PB",2)==0) || (strncmp(AudioTestCase,"REC",3)==0))
{
#ifdef ENABLE_CODEC
if (strcmp(MainAudioSoundPath,"MIC")==0)
{
LE_INFO("Connect MIC and SPEAKER ");
ConnectAudioToCodec();
}
else
#endif
if (strcmp(MainAudioSoundPath,"PCM")==0)
{
LE_INFO("Connect PCM ");
ConnectAudioToPcm();
}
else if (strcmp(MainAudioSoundPath,"I2S")==0)
{
LE_INFO("Connect I2S");
ConnectAudioToI2s();
}
else if (strcmp(MainAudioSoundPath,"USB")==0)
{
LE_INFO("Connect USB ");
ConnectAudioToUsb();
}
else
{
LE_INFO("Error in format could not connect audio");
}
// Connect SW-PCM
if (strncmp(AudioTestCase,"PB",2)==0)
{
LE_INFO("Connect Local Play");
ConnectAudioToFileLocalPlay();
}
else if (strncmp(AudioTestCase,"REC",3)==0)
{
LE_INFO("Connect Local Rec ");
ConnectAudioToFileLocalRec();
}
else
{
LE_INFO("Error in format could not connect audio");
}
}
else
{
LE_INFO("Error in format could not connect audio");
}
}
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
static void DisconnectAllAudio
(
void
)
{
if (AudioInputConnectorRef)
{
if(FileAudioRef)
{
LE_INFO("Disconnect %p from connector.%p", FileAudioRef, AudioInputConnectorRef);
le_audio_Disconnect(AudioInputConnectorRef, FileAudioRef);
}
if (FeInRef)
{
LE_INFO("Disconnect %p from connector.%p", FeInRef, AudioInputConnectorRef);
le_audio_Disconnect(AudioInputConnectorRef, FeInRef);
}
if(MdmTxAudioRef)
{
LE_INFO("Disconnect %p from connector.%p", MdmTxAudioRef, AudioInputConnectorRef);
le_audio_Disconnect(AudioInputConnectorRef, MdmTxAudioRef);
}
}
if(AudioOutputConnectorRef)
{
if(FileAudioRef)
{
LE_INFO("Disconnect %p from connector.%p", FileAudioRef, AudioOutputConnectorRef);
le_audio_Disconnect(AudioOutputConnectorRef, FileAudioRef);
}
if(FeOutRef)
{
LE_INFO("Disconnect %p from connector.%p", FeOutRef, AudioOutputConnectorRef);
le_audio_Disconnect(AudioOutputConnectorRef, FeOutRef);
}
if(MdmRxAudioRef)
{
LE_INFO("Disconnect %p from connector.%p", MdmRxAudioRef, AudioOutputConnectorRef);
le_audio_Disconnect(AudioOutputConnectorRef, MdmRxAudioRef);
}
}
if(AudioInputConnectorRef)
{
le_audio_DeleteConnector(AudioInputConnectorRef);
AudioInputConnectorRef = NULL;
}
if(AudioOutputConnectorRef)
{
le_audio_DeleteConnector(AudioOutputConnectorRef);
AudioOutputConnectorRef = NULL;
}
if(FileAudioRef)
{
le_audio_Close(FileAudioRef);
FeOutRef = NULL;
}
if(FeInRef)
{
le_audio_Close(FeInRef);
FeInRef = NULL;
}
if(FeOutRef)
{
le_audio_Close(FeOutRef);
FeOutRef = NULL;
}
if(MdmRxAudioRef)
{
le_audio_Close(MdmRxAudioRef);
FeOutRef = NULL;
}
if(MdmTxAudioRef)
{
le_audio_Close(MdmTxAudioRef);
FeOutRef = NULL;
}
close(AudioFileFd);
exit(0);
}
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
static void PrintUsage()
{
int idx;
bool sandboxed = (getuid() != 0);
const char * usagePtr[] = {
"Usage of the audioPlaybackRec test is:",
" execInApp audioPlaybackRec audioPlaybackRecTest <test case>"
"[main audio path] [file's name] [option]",
"",
"Test cases are:",
" - PB (for Local playback)",
" - REC (for Local recording)",
" - PB_SAMPLES (for Local samples play)",
" - REC_SAMPLES (for Local samples recording) [option]",
"",
"Main audio paths are: (for file playback/recording only)",
#if (ENABLE_CODEC == 1)
" - MIC (for mic/speaker)",
#endif
" - PCM (for devkit's codec use, execute 'wm8940_demo --pcm' command)",
" - I2S (for devkit's codec use, execute 'wm8940_demo --i2s' command)",
" - USB (for USB)",
"",
"Options are:",
" - ChannelNmbr SampleRate BitsPerSample (for REC_SAMPLES)",
" - AMR AmrMode DTX (for REC in AMR Narrowband format)",
" - WAV (for REC in WAV format)",
" - GAIN (for playback gain testing)",
" - LOOP (to replay a file in loop) (optional)",
" - PLAY=<timer value> (to replay a file after a delay) (optional)",
" - RECORD=<timer value> (to record a file after a delay) (optional)",
" - STOP=<timer value> (to stop a file playback/capture after a delay) (optional)",
" - PAUSE=<timer value> (to pause a file playback/capture after a delay) (optional)",
" - RESUME=<timer value> (to resume a file playback/capture after a delay) (optional)",
" - DISCONNECT=<timer value> (to disconnect connectors and streams"
" after a delay) (optional)",
" - MUTE (for playback MUTE testing)",
"",
"File's name can be the complete file's path.",
};
for(idx = 0; idx < NUM_ARRAY_MEMBERS(usagePtr); idx++)
{
if(sandboxed)
{
LE_INFO("%s", usagePtr[idx]);
}
else
{
fprintf(stderr, "%s\n", usagePtr[idx]);
}
}
}
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
static void SigHandler
(
int sigNum
)
{
LE_INFO("Disconnect All Audio and end test");
if (RecPbThreadRef)
{
le_thread_Cancel(RecPbThreadRef);
RecPbThreadRef = NULL;
}
DisconnectAllAudio();
exit(EXIT_SUCCESS);
}
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
{
LE_INFO("Init");
if (le_arg_NumArgs() >= 1)
{
// Register a signal event handler for SIGINT when user interrupts/terminates process
signal(SIGINT, SigHandler);
LE_INFO("======== Start Audio implementation Test (audioPlaybackRecTest) ========");
AudioTestCase = le_arg_GetArg(0);
LE_INFO(" Test case.%s", AudioTestCase);
if(le_arg_NumArgs() >= 3)
{
MainAudioSoundPath = le_arg_GetArg(1);
AudioFilePath = le_arg_GetArg(2);
LE_INFO(" Main audio path.%s", MainAudioSoundPath);
LE_INFO(" Audio file [%s]", AudioFilePath);
}
if ( (strncmp(AudioTestCase,"REC_SAMPLES",11)==0) ||
(strncmp(AudioTestCase,"PB_SAMPLES",10)==0) )
{
if(le_arg_NumArgs() < 6)
{
PrintUsage();
LE_INFO("EXIT audioPlaybackRec");
exit(EXIT_FAILURE);
}
ChannelsCount = atoi(le_arg_GetArg(3));
SampleRate = atoi(le_arg_GetArg(4));
BitsPerSample = atoi(le_arg_GetArg(5));
LE_INFO(" Get/Play PCM samples with ChannelsCount.%d SampleRate.%d BitsPerSample.%d",
ChannelsCount, SampleRate, BitsPerSample);
NextOptionArg = 6;
}
else if (strncmp(AudioTestCase,"REC", 3)==0)
{
const char* recFormat = le_arg_GetArg(3);
if (strncmp(recFormat,"WAV", 3)==0)
{
AudioFormat = LE_AUDIO_WAVE;
}
else if (strncmp(recFormat,"AMR", 3)==0)
{
AudioFormat = LE_AUDIO_AMR;
}
else
{
PrintUsage();
LE_INFO("EXIT audioPlaybackRec");
exit(EXIT_FAILURE);
}
if (AudioFormat == LE_AUDIO_WAVE)
{
NextOptionArg = 4;
}
else
{
AmrMode = atoi(le_arg_GetArg(4));
DtxActivation = atoi(le_arg_GetArg(5));
NextOptionArg = 6;
}
}
else
{
NextOptionArg = 3;
}
OptionTimerRef = le_timer_Create("OptionTimer");
le_timer_SetHandler(OptionTimerRef, OptionTimerHandler);
ConnectAudio();
LE_INFO("======== Audio implementation Test (audioPlaybackRec) started successfully ========");
}
else
{
PrintUsage();
LE_INFO("EXIT audioPlaybackRec");
exit(EXIT_FAILURE);
}
}