Examples.
#define _GNU_SOURCE
#include <pthread.h>
#include <sched.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#ifndef __QNX__
#include <sys/prctl.h>
#include <sys/sysinfo.h>
#include <sys/syscall.h>
#endif
#include <errno.h>
#include <math.h>
#ifndef SYS_gettid
#warning "SYS_gettid unavailable on this system"
#else
#define gettid() ((pid_t)syscall(SYS_gettid))
#endif
#include "ModuleList.h"
#define NUM_CHANNELS (2)
#define SAMPLE_RATE (48000.f)
#define NUM_INSTANCES (3)
#define CORE_SPEED (1.2e9)
#define PROFILE_SPEED (10e6)
#define AUDIO_CALLBACK_PRIO_OFFSET (0)
#define AUDIO_PUMPALL_PRIO_OFFSET (1)
#ifndef PI
#define PI (3.141592653589793f)
#endif
UINT32 portNo = 15002;
UINT32 portNos[NUM_INSTANCES];
UINT32 uniqueSocketsFlag = 0;
UINT32 enableLoggingFlag = 0;
UINT32 blockSize = 32;
INT32 * inputBuffer;
INT32 * outputBuffer;
static UINT32 quiet = 0;
UINT64 count;
static const void* moduleDescriptorTable[] =
{
LISTOFCLASSOBJECTS
};
UINT32 moduleDescriptorTableSize = sizeof(moduleDescriptorTable) / sizeof(moduleDescriptorTable[0]);
pthread_t audioCallbackThreadHandle;
pthread_mutex_t audioThreadMutex;
pthread_cond_t audioThreadCond;
pthread_t audioPumpAllThreadHandles[NUM_INSTANCES];
sem_t pumpSems[NUM_INSTANCES];
INT32 audioStarted = 0;
INT32 exitAudioCallbackThread = 0;
INT32 pumpActive[NUM_INSTANCES];
UINT32 pumpCnts[NUM_INSTANCES];
UINT32 errMask;
UINT32 setCPUAffinity = 0;
UINT32 threadCpuToSet = 1;
void sig_handler(int signo)
{
if (!quiet)
{
printf("Exiting Multi-Instance App\n");
}
exit(0);
}
static void usage(const char *program)
{
printf(
"Usage: %s [args]\n"
" -portno:<uint> Port Number to open the single multi-instance tuning interface socket. Default 15002\n"
" -uniquesockets If this flag is defined, then an individual tuning interface socket will be opened on each instance\n"
" -portnos:<comma separated uints> Multi sockets mode only - comma separated port numbers to open the socket for each instance. Default 15002,15004,15006 and so on\n"
" -enableLogging Enable tuning interface logging. with -uniquesockets enabled, an individual tuning log file is generated per instance. Disabled by default\n"
" -bsize Block size (default 32)\n"
" -enableCPUAffinity Enable the logic in audioStart callback which will query thread PIDs and attempt to set CPU affinity per layout \n"
" -help Show usage.\n"
"This program demonstrates multi instance functionality in AWE Core OS.\n",
program);
exit(0);
}
static INT32 getTargetPriorityOffset(INT32 instanceNum)
{
UINT32 priorityOffset = 0;
while (--instanceNum >= 0)
{
priorityOffset += (configParams[instanceNum].
numThreads + 1);
}
return priorityOffset;
}
{
INT32 i = 0;
while (i < NUM_INSTANCES)
{
if (pAWEOS == g_AWEOSInstanceArray[i])
{
break;
}
i++;
}
return i;
}
void* audioCallbackSimulator(void * args)
{
struct timespec ts;
struct timespec ts_tmp;
long long accumulated_time1;
long long accumulated_time2;
long long overshoot = 0.0;
(void) args;
pthread_mutex_lock(&audioThreadMutex);
audioStarted = 1;
pthread_cond_signal(&audioThreadCond);
pthread_mutex_unlock(&audioThreadMutex);
const long time_nsec = (long) ((float)1000000000L * ((float)blockSize / SAMPLE_RATE));
ts.tv_sec = 0;
ts_tmp.tv_sec = 0;
ts_tmp.tv_nsec = 0;
int max_priority = sched_get_priority_max(SCHED_FIFO);
struct sched_param audio_sched_param = {0};
pthread_t currentHandle = pthread_self();
int target_priority = max_priority - AUDIO_CALLBACK_PRIO_OFFSET;
audio_sched_param.sched_priority = target_priority;
pthread_setschedparam(currentHandle, SCHED_FIFO, &audio_sched_param);
int policy;
pthread_getschedparam(currentHandle, &policy, &audio_sched_param);
if ((SCHED_FIFO != policy) ||
(audio_sched_param.sched_priority != target_priority))
{
printf("Warning: Failed to increase priority of audio simulation thread to %d\nTry running as root\n", target_priority);
}
#if defined(SYS_gettid)
if (setCPUAffinity)
{
cpu_set_t callbackthread_set;
pid_t callbackPID;
INT32 ret;
static const int cpuToSet = 0;
CPU_ZERO(&callbackthread_set);
CPU_SET(cpuToSet, &callbackthread_set);
callbackPID = gettid();
ret = sched_setaffinity(callbackPID, sizeof(cpu_set_t), &callbackthread_set);
if (ret == 0)
{
printf("Set audio callback thread (PID = %d) to CPU %d \n", callbackPID, cpuToSet);
}
else
{
printf("Could not set CPU affinity of audio callback thread (PID = %d) to CPU %d , errno: %d \n", callbackPID, cpuToSet, errno);
}
}
#endif
while (!exitAudioCallbackThread)
{
INT32 i;
for (i = 0; i < NUM_INSTANCES; i++)
{
sem_post(&pumpSems[i]);
}
while (overshoot > time_nsec)
{
overshoot -= time_nsec;
for (i = 0; i < NUM_INSTANCES; i++)
{
sem_post(&pumpSems[i]);
}
}
ts.tv_nsec = time_nsec;
clock_gettime(CLOCK_MONOTONIC, &ts_tmp);
accumulated_time1 = ((long long)ts_tmp.tv_sec*1000000000) + ts_tmp.tv_nsec + time_nsec;
while(1)
{
clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);
clock_gettime(CLOCK_MONOTONIC, &ts_tmp);
accumulated_time2 = ((long long)ts_tmp.tv_sec*1000000000) + ts_tmp.tv_nsec;
if (accumulated_time2 >= accumulated_time1)
{
overshoot += (accumulated_time2 - accumulated_time1);
break;
}
else
{
ts.tv_nsec = (long)(accumulated_time1 - accumulated_time2);
}
}
}
return NULL;
}
void* aweOSuser_pumpAudio(void * args)
{
INT32 schedPolicy, ret, targetPriority, priorityOffset;
struct sched_param schedParam;
INT32 instanceNum = getInstanceNumber(pAWEOS);
priorityOffset = getTargetPriorityOffset(instanceNum);
pthread_t currentHandle = pthread_self();
int max_priority = sched_get_priority_max(SCHED_FIFO);
targetPriority = max_priority - AUDIO_PUMPALL_PRIO_OFFSET - priorityOffset;
schedParam.sched_priority = targetPriority;
schedPolicy = SCHED_FIFO;
pthread_setschedparam(currentHandle, schedPolicy, &schedParam);
int policy;
pthread_getschedparam(currentHandle, &policy, &schedParam);
if ((SCHED_FIFO != policy) || (schedParam.sched_priority != targetPriority))
{
printf("Warning: Failed to increase priority of instance %d pumpall thread to %d\nTry running as root\n", instanceNum, targetPriority);
}
char threadNameBuffer[16];
snprintf(threadNameBuffer, 16, "awe%d_pumpall", instanceNum);
ret = pthread_setname_np(audioPumpAllThreadHandles[instanceNum], threadNameBuffer);
#if defined(SYS_gettid)
if (setCPUAffinity)
{
cpu_set_t pumpthread_set;
pid_t pumpAllPID;
INT32 ret;
static const int cpuToSet = 0;
CPU_ZERO(&pumpthread_set);
CPU_SET(cpuToSet, &pumpthread_set);
pumpAllPID = gettid();
ret = sched_setaffinity(pumpAllPID, sizeof(cpu_set_t), &pumpthread_set);
if (ret == 0)
{
printf("Set audio callback thread (PID = %d) to CPU %d \n", pumpAllPID, cpuToSet);
}
else
{
printf("Could not set CPU affinity of pumpall thread (PID = %d) to CPU %d , errno: %d \n", pumpAllPID, cpuToSet, errno);
}
}
#endif
UINT32 * inputBuffer, * outputBuffer;
inputBuffer = malloc(inSize * sizeof(UINT32));
outputBuffer = malloc(outSize * sizeof(UINT32));
for (int i = 0; i < blockSize; i++)
{
for (int j = 0; j < NUM_CHANNELS; j++)
{
inputBuffer[i * NUM_CHANNELS + j] =
float_to_fract32(sinf(2.f * PI * (j + 1) * (SAMPLE_RATE / blockSize) * (i / SAMPLE_RATE))) >> 2;
}
}
if (!quiet)
{
printf("Starting pump thread for instance %d\n", instanceNum);
}
while (1)
{
sem_wait(&pumpSems[instanceNum]);
{
for (
int i = 0; i < configParams[instanceNum].
inChannels ; i++)
{
if (ret)
{
printf("Error: instance %d aweOS_audioImportSamples() failed, channel = %d, error = %d\n", instanceNum, i, ret);
}
}
for (
int i = 0; i < configParams[instanceNum].
outChannels ; i++)
{
if (ret)
{
printf("Error: instance %d aweOS_audioExportSamples() failed, channel = %d, error = %d\n", instanceNum, i, ret);
}
}
pumpCnts[instanceNum]++;
}
}
free(inputBuffer);
free(outputBuffer);
return NULL;
}
{
INT32 ret;
UINT32 layoutInChannels, layoutOutChannels, blockSize;
FLOAT32 sampleRate;
INT32 instanceNum = getInstanceNumber(pAWEOS);
{
}
{
}
{
}
printf("Loaded layout on instance %d with inChans = %u, outChans = %u, blockSize = %u, sampleRate = %f\n",
instanceNum, layoutInChannels, layoutOutChannels, blockSize, sampleRate);
#if defined(SYS_gettid)
if (setCPUAffinity)
{
if (ret != 0)
{
printf("aweOS_getThreadPIDs failed with error %d. Not setting CPU affinity... \n ", ret);
}
else
{
INT32 availableProcessors = get_nprocs();
{
INT32 cpuToSet;
cpu_set_t pumpthread_set;
CPU_ZERO(&pumpthread_set);
cpuToSet = threadCpuToSet++ % availableProcessors;
CPU_SET(cpuToSet, &pumpthread_set);
ret = sched_setaffinity(threadPIDs.
pumpThreadPIDs[i],
sizeof(cpu_set_t), &pumpthread_set);
if (ret == 0)
{
if (!quiet)
{
printf(
"Set pumpThread %d (PID = %u) to CPU %d \n", i, threadPIDs.
pumpThreadPIDs[i], cpuToSet);
}
}
else
{
printf("Could not set CPU affinity of pumpThread %d to CPU %d , errno: %d \n", i, cpuToSet, errno);
}
}
}
}
#endif
pthread_mutex_lock(&audioThreadMutex);
pumpActive[instanceNum] = 1;
if (!audioStarted)
{
pthread_mutex_unlock(&audioThreadMutex);
exitAudioCallbackThread = 0;
ret = pthread_create(&audioCallbackThreadHandle, NULL, audioCallbackSimulator, NULL);
if (0 != ret)
{
printf("Error creating audio callback simulator! ret = %d\n", ret);
return 0;
}
memset(pumpCnts, 0, NUM_INSTANCES*sizeof(UINT32));
pthread_mutex_lock(&audioThreadMutex);
while (audioStarted != 1)
{
pthread_cond_wait(&audioThreadCond, &audioThreadMutex);
}
pthread_mutex_unlock(&audioThreadMutex);
}
else
{
pthread_mutex_unlock(&audioThreadMutex);
}
printf("audio start, instance %d, active %d\n", instanceNum, pumpActive[instanceNum]);
return 0;
}
{
INT32 i, anyActive = 0;
INT32 ret, realStop = 0;
INT32 instanceNum = getInstanceNumber(pAWEOS);
printf("audio stop, instance %d, active %d\n", instanceNum, pumpActive[instanceNum]);
pthread_mutex_lock(&audioThreadMutex);
realStop = pumpActive[instanceNum];
pumpActive[instanceNum] = 0;
for (i = 0; i < NUM_INSTANCES; i++)
{
anyActive |= pumpActive[i];
}
if (!anyActive && audioStarted)
{
pthread_mutex_unlock(&audioThreadMutex);
exitAudioCallbackThread = 1;
ret = pthread_join(audioCallbackThreadHandle, NULL);
if (0 != ret)
{
printf("Failed to join audio simulator thread: ret = %d\n", ret);
}
pthread_mutex_lock(&audioThreadMutex);
audioStarted = 0;
pthread_mutex_unlock(&audioThreadMutex);
errMask = 0;
threadCpuToSet = 1;
}
else
{
pthread_mutex_unlock(&audioThreadMutex);
}
if (!quiet && realStop)
{
UINT32 avgCycles;
printf("\nAudio Stopped on instance %d\n", instanceNum);
{
avgCycles = 0;
}
printf("-- Pumped instance %d for %u times, average cycles per pump: %f\n", instanceNum, pumpCnts[instanceNum],
(avgCycles >> 8) * clockRatios);
}
return 0;
}
int main(int argc, char **argv)
{
UINT32 i;
char *token = NULL;
for (i = 0; i < NUM_INSTANCES; i++)
{
portNos[i] = 15002 + (i * 2);
}
if (1 == argc)
{
printf("No command line options specified. Opening in default single socket mode with TCP socket on port number %u\n", portNo);
}
else
{
for (i = 1; i < argc; i++)
{
char *arg = argv[i];
if (0 == strncmp(arg, "-portno:", 8))
{
portNo = atoi(arg + 8);
}
else if ((0 == strncmp(arg, "-portnos:", 9)))
{
i = 0;
token = strtok(arg + 9, ",");
while ( token != NULL )
{
portNos[i] = atoi(token);
i++;
if (i >= NUM_INSTANCES)
{
break;
}
token = strtok(NULL, ",");
}
}
else if (0 == strncmp(arg, "-uniquesockets", 14))
{
uniqueSocketsFlag = 1;
}
else if ((0 == strncmp(arg, "-enableLogging", 14)))
{
enableLoggingFlag = 1;
printf("enableLogging set to true. Tuning logging enabled\n");
}
else if ((0 == strncmp(arg, "-bsize:", 7)))
{
blockSize = atoi(arg + 7);;
printf("blockSize set to %d\n", (INT32)blockSize);
}
else if ((0 == strncmp(arg, "-enableCPUAffinity", 13)))
{
setCPUAffinity = 1;
printf(" enableCPUAffinity activated\n");
}
else if ((0 == strncmp(arg, "-help", 5)))
{
usage(argv[0]);
}
else
{
printf("main: unknown option '%s'\n", arg);
}
}
if (uniqueSocketsFlag)
{
printf("uniquesockets mode enabled. Opening an individual socket for each of the %d AWEOSInstances\n", NUM_INSTANCES);
for (i = 0; i < NUM_INSTANCES; i++)
{
printf("Instance %u on port no: %u\n", i, portNos[i]);
}
}
else
{
printf("singlesocket mode: portno for socket is %u\n", portNo);
}
}
for (i = 0; i < NUM_INSTANCES; i++)
{
}
if (uniqueSocketsFlag == 1)
{
for (i = 0; i < NUM_INSTANCES; i++)
{
configParams[i].
pName = malloc(
sizeof(
char) * 8);
sprintf((char*)configParams[i].pName, "#%u-soc%u", (i+1), (i+1));
}
}
else
{
for (i = 0; i < NUM_INSTANCES; i++)
{
configParams[i].
pName = malloc(
sizeof(
char) * 8);
sprintf((char*)configParams[i].pName, "aweOS#%u", i);
}
}
for (i = 0; i < NUM_INSTANCES; i++)
{
}
for (i = 0; i < NUM_INSTANCES; i++)
{
ret =
aweOS_init(&g_AWEOSInstanceArray[i], &configParams[i], moduleDescriptorTable, moduleDescriptorTableSize);
if (ret)
{
printf(
"aweOS init failed for instance %d, ret = %d: %s\nExiting application\n", (INT32)i, ret,
aweOS_errorToString(ret));
}
}
if (!uniqueSocketsFlag)
{
printf("Single Socket Mode\n");
if (enableLoggingFlag)
{
if (loggingRet != 0)
{
printf("failed to open tuning log: ret = %d\n", ret);
}
else
{
printf("Tuning Logging enabled, a single log file will be generated for both AWEOSInstances.\n");
}
}
if (interfaceRet != 0)
{
printf("failed to open aweOS integrated tuning interface\n");
}
else
{
printf("Succesfully opened a TCP single socket tuning interface on port number %u\n ", portNo);
}
}
else
{
for (i = 0; i < NUM_INSTANCES; i++)
{
if (enableLoggingFlag)
{
if (loggingRet != 0)
{
printf("failed to open tuning log: ret = %d\n", ret);
}
else
{
printf("Tuning Logging enabled, individual log files created for socket %u\n", portNos[i]);
}
}
if (interfaceRet != 0)
{
printf("failed to open aweOS integrated tuning interface\n");
}
else
{
printf("Successfully opened a TCP socket for the AWEOSInstance %u on port number %u\n", i, portNos[i]);
}
}
}
for (i = 0; i < NUM_INSTANCES; i++)
{
pumpActive[i] = 0;
}
for (i = 0; i < NUM_INSTANCES; i++)
{
sem_init(&pumpSems[i], 0, 0);
pthread_create(&audioPumpAllThreadHandles[i], NULL, aweOSuser_pumpAudio, g_AWEOSInstanceArray[i]);
}
for (i = 0; i < NUM_INSTANCES; i++)
{
pthread_join(audioPumpAllThreadHandles[i], NULL);
}
for (i = 0; i < NUM_INSTANCES; i++)
{
}
return 0;
}
The AWE Core OS API header file.
The AWECore Helper Functions File.
INT32 float_to_fract32(FLOAT32 x)
Convert audio data from floating point to Fract32 sample by sample.
#define E_SUCCESS
OK result.
Definition: Errors.h:31
@ Sample32bit
Data is 32 bit PCM .
Definition: StandardDefs.h:231
#define TUNING_LOG_INFO
AWE Core OS internal tuning interface logging verbosity level: medium – log errors and header info fr...
Definition: AWECoreOS.h:52
void AWEOSInstance
The AWE Core OS Instance instance type.
Definition: AWECoreOS.h:103
INT32 aweOS_layoutGetSampleRate(const AWEOSInstance *pAWEOS, FLOAT32 *sampleRate)
Returns the sample rate of the loaded layout.
INT32 aweOS_audioExportSamples(AWEOSInstance *pAWEOS, void *outSamples, INT32 outStride, INT32 channel, SampleType outType)
Export samples to a user buffer from a specific channel of the AWEOSInstance's output pin.
INT32 aweOS_audioPumpAll(AWEOSInstance *pAWEOS)
Pump one fundamental block size of audio through the loaded layout and all of its sublayouts.
INT32 aweOS_audioIsStarted(const AWEOSInstance *pAWEOS)
Check if this instance has received an Audio Start command.
INT32 aweOS_init(AWEOSInstance **pAWEOS, const AWEOSConfigParameters *aweParams, const void *pModuleDescriptorTable, UINT32 moduleDescriptorTableSize)
Initialize the AWEOSInstance with the specified configuration parameters.
INT32 aweOS_tuningLoggingEnable(AWEOSInstance *pAWEOS, char *path, char *baseName, UINT32 verbosity)
Enable logging of the tuning packets sent and received by the AWEOSInstance.
INT32 aweOS_layoutGetBlockSize(const AWEOSInstance *pAWEOS, UINT32 *blockSize)
Returns the block size of the loaded layout.
INT32 aweOS_layoutIsValid(const AWEOSInstance *pAWEOS)
Determines if a layout is loaded and valid.
INT32 aweOS_layoutGetChannelCount(const AWEOSInstance *pAWEOS, UINT32 *inCount, UINT32 *outCount)
Returns the number of input and output channels in the loaded layout.
INT32 aweOS_tuningSocketOpen(AWEOSInstance **pAWEOS, INT32 portNo, UINT32 numInstances)
Initialize and open an integrated TCP/IP tuning interface socket.
INT32 aweOS_setInstancesInfo(AWEOSInstance **pInstances, INT32 numInstances)
Profiling related setup function only intended for systems with multiple AWEOS Instances in a single ...
UINT32 aweOS_getThreadPIDs(AWEOSInstance *pAWEOS, AWEOSThreadPIDs_t *threadPIDs)
Return the PIDs of all internally spawned AWE Core OS threads.
INT32 aweOS_destroy(AWEOSInstance **pAWEOS)
Destroys the AWEOSInstance and closes all associated threads.
const char * aweOS_errorToString(INT32 errorCode)
Convert an error code (INT32) to its corresponding error string.
INT32 aweOS_audioImportSamples(AWEOSInstance *pAWEOS, void *inSamples, INT32 inStride, INT32 channel, SampleType inType)
Import samples from an audio buffer to a specific channel of the AWEOSInstance's input pin.
INT32 aweOS_getParamDefaults(AWEOSConfigParameters *aweParams)
Populates an AWEOSConfigParameters structure with defaults.
INT32 aweOS_getAverageLayoutCycles(AWEOSInstance *pAWEOS, UINT32 idx, UINT32 *averageCycles)
Get the average cycles of a running layout, in units of cycles at profileSpeed.
Internal threading PID structure, meant to be used with aweOS_getThreadPIDs.
Definition: AWECoreOS.h:81
UINT32 numPumpThreads
The number of running pump threads.
Definition: AWECoreOS.h:84
UINT32 * pumpThreadPIDs
Pointer to an array of the running pump thread PIDs of size pumpThreadPIDs[numPumpThreads].
Definition: AWECoreOS.h:85
AWEOSConfigParameters.
Definition: AWECoreOS.h:114
float profileSpeed
Application profiling speed in Hz.
Definition: AWECoreOS.h:129
const char * pName
Name of target.
Definition: AWECoreOS.h:130
INT32 instanceId
ID number of instance.
Definition: AWECoreOS.h:136
float coreSpeed
Processor clock speed in Hz.
Definition: AWECoreOS.h:128
UINT32 numThreads
Maximum number of supported sublayouts.
Definition: AWECoreOS.h:131
UINT32 fundamentalBlockSize
Fundamental block size of audio driver.
Definition: AWECoreOS.h:133
UINT32 outChannels
Number of output channels of audio device.
Definition: AWECoreOS.h:135
INT32(* cbAudioStop)(AWEOSInstance *pAWEOS)
Pointer to user created callback function for audio stop commands.
Definition: AWECoreOS.h:123
UINT32 inChannels
Number of input channels of audio device.
Definition: AWECoreOS.h:134
INT32(* cbAudioStart)(AWEOSInstance *pAWEOS)
Pointer to user created callback function for audio start commands.
Definition: AWECoreOS.h:122