AWE Core OS 8.B.20 Documentation
Multi-Instance.c

Examples.

Examples

/****************************************************************************
*
* Multi-Instance
* --------------
*
****************************************************************************
*
* Description: Demonstrate Multi Instance capabilities of the API. Supports single socket mode, and two socket mode.
*
* Copyright: (c) 2020 DSP Concepts, Inc. All rights reserved.
* 3235 Kifer Road
* Santa Clara, CA 95054-1527
*
* This example demonstrates the multi instance capabilities of AWE Core OS, as well as tuning interface logging.
* There are two modes, single socket (default) and uniquesocket.
*
* Single socket mode (default) creates NUM_INSTANCES AWEOSInstances and a single Multi-Instance TCP tuning interface.
* You can specify the port number with cmd line option -portno:<int>, but a default of 15002 is used.
* Upon connection to AWE Server, a dropdown menu will appear in the top left corner, which toggles between the two instances.
* Try configuring the instances individually and recompiling, then reconnect. Notice how the information in Server changes as you toggle between instances. (see the pName changes below)
* With logging enabled (-enableLogging), a single log file will be created for both of the instances.
*
* Unique socket mode (running with "-uniquesockets") will also create NUM_INSTANCES AWEOSInstances instances, but each with their own individual tuning interface TCP socket.
* By default, the first instance's socket is opened on port 15002, and the second on 15004 and so on with even number increments. Port numbers can be specified with "-portnos:[<array of ints>]"
* Windows only allows one instance of AWE Server running on the PC, so to toggle between instances you must disconnect and reconnect to each individual port.
* With logging enabled (-enableLogging) in unique socket mode, individual log files will be created per socket.
*
* This example does not have RT audio capabilities, it is simply meant to demonstrate multi instance functionality, however module regression tests can be run on each individual AWEOSInstance.
* Routing RT audio between AWE Core OS instances is the responsibility of the integrator.
*
***************************************************************************/
#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 /* __QNX__ */
#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 "AWECoreOS.h"
#include "ModuleList.h"
#include "AWECoreUtils.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
//globals for command line args
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;
//Step 1: Declare an Array of AWEOSInstance pointers. Memory for the instances are allocated by aweOS_init()
AWEOSInstance* g_AWEOSInstanceArray[NUM_INSTANCES];
//Step 2: Declare an AWEOSConfigParameters structure. The members of this structure determine the configuration of the AWEInstance members. For this example, it will be populated with defaults
static AWEOSConfigParameters configParams[NUM_INSTANCES];
//Step 3: Define the module descriptor table from ModuleList.h that contains all modules
static const void* moduleDescriptorTable[] =
{
LISTOFCLASSOBJECTS
};
UINT32 moduleDescriptorTableSize = sizeof(moduleDescriptorTable) / sizeof(moduleDescriptorTable[0]);
// Global thread handles and mutexes
pthread_t audioCallbackThreadHandle;
pthread_mutex_t audioThreadMutex;
pthread_cond_t audioThreadCond;
pthread_t audioPumpAllThreadHandles[NUM_INSTANCES];
sem_t pumpSems[NUM_INSTANCES];
// Global variables
INT32 audioStarted = 0;
INT32 exitAudioCallbackThread = 0;
INT32 pumpActive[NUM_INSTANCES];
UINT32 pumpCnts[NUM_INSTANCES];
UINT32 errMask;
UINT32 setCPUAffinity = 0;
UINT32 threadCpuToSet = 1;
AWEOSThreadPIDs_t threadPIDs;
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)
{
// + 1 for the pumpall thread per instance
priorityOffset += (configParams[instanceNum].numThreads + 1);
}
return priorityOffset;
}
static INT32 getInstanceNumber(AWEOSInstance *pAWEOS)
{
INT32 i = 0;
while (i < NUM_INSTANCES)
{
if (pAWEOS == g_AWEOSInstanceArray[i])
{
break;
}
i++;
}
return i;
}
void* audioCallbackSimulator(void * args)
{
// Simple real-time audio simulator. Would be ALSA, PortAudio, etc callback
// Will not achieve exact realtime interrupts
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);
// Calculate sleep time for fundamental blocksize
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;
// Set this thread to run at real time priority
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)
{
// Set the pump all threads to CPU 0 if requested. This handles case of low-latency mode
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;
// Kick off all the audio threads
// This app assumes all instances are the same block size and driven by the same audio device
for (i = 0; i < NUM_INSTANCES; i++)
{
sem_post(&pumpSems[i]);
}
// Might need to post more than once due to clock resolution
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)
{
// Represents the callback function from the audio framework
INT32 schedPolicy, ret, targetPriority, priorityOffset;
struct sched_param schedParam;
AWEOSInstance * pAWEOS = (AWEOSInstance *) args;
INT32 instanceNum = getInstanceNumber(pAWEOS);
priorityOffset = getTargetPriorityOffset(instanceNum);
// Set this thread to run at real time priority
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)
{
// Set the pump all threads to CPU 0 if requested. This handles case of low-latency mode
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
//Prepare the stereo input and output buffers for the audio processing
// The I/O buffers are allocated based on the target info / configParams
size_t inSize = configParams[instanceNum].inChannels * configParams[instanceNum].fundamentalBlockSize;
size_t outSize = configParams[instanceNum].outChannels * configParams[instanceNum].fundamentalBlockSize;
UINT32 * inputBuffer, * outputBuffer;
inputBuffer = malloc(inSize * sizeof(UINT32));
outputBuffer = malloc(outSize * sizeof(UINT32));
// Fill audio input buffers with sin waves scaled by -12 dB
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)
{
// Wait for signal to run thread
sem_wait(&pumpSems[instanceNum]);
if (aweOS_layoutIsValid(pAWEOS) && aweOS_audioIsStarted(pAWEOS))
{
// Import new samples
for (int i = 0; i < configParams[instanceNum].inChannels ; i++)
{
// Import new samples
ret = aweOS_audioImportSamples(pAWEOS, &inputBuffer[i], configParams[instanceNum].inChannels, i, Sample32bit);
if (ret)
{
printf("Error: instance %d aweOS_audioImportSamples() failed, channel = %d, error = %d\n", instanceNum, i, ret);
}
}
// Pump the sublayout
// Export samples
for (int i = 0; i < configParams[instanceNum].outChannels ; i++)
{
// Import new samples
ret = aweOS_audioExportSamples(pAWEOS, &outputBuffer[i], configParams[instanceNum].outChannels, i, Sample32bit);
if (ret)
{
printf("Error: instance %d aweOS_audioExportSamples() failed, channel = %d, error = %d\n", instanceNum, i, ret);
}
}
pumpCnts[instanceNum]++;
} // if layout valid
}
free(inputBuffer);
free(outputBuffer);
return NULL;
}
INT32 aweOSuser_audioStart(AWEOSInstance *pAWEOS)
{
INT32 ret;
UINT32 layoutInChannels, layoutOutChannels, blockSize;
FLOAT32 sampleRate;
INT32 instanceNum = getInstanceNumber(pAWEOS);
// Audio start callback. Can be used to start audio stream from audio framework.
// Could be ALSA, Pulse, Jack, Portaudio, etc.
ret = aweOS_layoutGetChannelCount(pAWEOS, &layoutInChannels, &layoutOutChannels);
if (E_SUCCESS != ret)
{
printf("Failed to get layout channel counts: ret = %d: %s\n", ret, aweOS_errorToString(ret));
}
ret = aweOS_layoutGetBlockSize(pAWEOS, &blockSize);
if (E_SUCCESS != ret)
{
printf("Failed to get layout block size: ret = %d: %s\n", ret, aweOS_errorToString(ret));
}
ret = aweOS_layoutGetSampleRate(pAWEOS, &sampleRate);
if (E_SUCCESS != ret)
{
printf("Failed to get layout sample rate: ret = %d: %s\n", ret, aweOS_errorToString(ret));
}
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)
// Set the core affinity for each processing thread if requested
if (setCPUAffinity)
{
// Get the internally running thread PIDs and print them
ret = aweOS_getThreadPIDs(pAWEOS, &threadPIDs);
if (ret != 0)
{
printf("aweOS_getThreadPIDs failed with error %d. Not setting CPU affinity... \n ", ret);
}
else
{
INT32 availableProcessors = get_nprocs();
for (INT32 i = 0; i < threadPIDs.numPumpThreads; i++)
{
INT32 cpuToSet;
cpu_set_t pumpthread_set;
// Audio streaming thread always set to first cpu
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
// Kick off real-time audio simulation thread, if not already started
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;
}
// Reset the count to 0, at the start of audio processing
memset(pumpCnts, 0, NUM_INSTANCES*sizeof(UINT32));
// Wait for thread to have been created
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 aweOSuser_audioStop(AWEOSInstance *pAWEOS)
{
INT32 i, anyActive = 0;
INT32 ret, realStop = 0;
INT32 instanceNum = getInstanceNumber(pAWEOS);
printf("audio stop, instance %d, active %d\n", instanceNum, pumpActive[instanceNum]);
// Audio stop callback. Can be used to clean up audio stream.
pthread_mutex_lock(&audioThreadMutex);
// Preserve previous pumpActive state to control prints
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);
float clockRatios = configParams[instanceNum].coreSpeed / configParams[instanceNum].profileSpeed;
ret = aweOS_getAverageLayoutCycles(g_AWEOSInstanceArray[instanceNum], 0, &avgCycles);
if (ret != E_SUCCESS)
{
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;
INT32 ret = E_SUCCESS;
char *token = NULL;
// Initialize default unique socket port numbers for each instance
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)))
{
// Walkthrough the list of port numbers and initialize the portNos array.
// If the port numbers entered larger than NUM_INSTANCES, ignore excess values.
i = 0;
/* get the first token */
token = strtok(arg + 9, ",");
/* walk through other tokens */
while ( token != NULL )
{
portNos[i] = atoi(token);
i++;
if (i >= NUM_INSTANCES)
{
// If NUM_INSTANCES reached, break the loop
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);
}
}
//Call this function with an arg to the user declared AWEOSConfigParameters structure.
//This populates the configParams structure with DSPC defined default values.
for (i = 0; i < NUM_INSTANCES; i++)
{
aweOS_getParamDefaults(&configParams[i]);
// Reduce the heap sizes according to the NUM_INSTANCES
configParams[i].fastHeapASize = configParams[i].fastHeapASize / NUM_INSTANCES;
configParams[i].fastHeapBSize = configParams[i].fastHeapBSize / NUM_INSTANCES;
configParams[i].slowHeapSize = configParams[i].slowHeapSize / NUM_INSTANCES;
}
//if the user is running with unique individual tuning sockets per instance, then assign the instanceID of configParams[N>0] to 0.
//This is because when using multiple tuning sockets, AWE Server sees each instance as its own individual target.
//For a single tuning interface that supports multiple instances, we set configParams[1].instanceId to 16 and so on, this lets Server know that there are NUM_INSTANCES AWEOSInstances on the same socket.
if (uniqueSocketsFlag == 1)
{
// Loop through NUM_INSTANCES and configure params accordingly
for (i = 0; i < NUM_INSTANCES; i++)
{
configParams[i].instanceId = 0;
configParams[i].pName = malloc(sizeof(char) * 8);
sprintf((char*)configParams[i].pName, "#%u-soc%u", (i+1), (i+1));
}
}
else
{
//Overwrite the first instances default name to "#1" and the second to "#2" so that we can see this reflected in Server
for (i = 0; i < NUM_INSTANCES; i++)
{
// Note that the instance ID is 16 as opposed to 1. AWE Server takes instanceIds in the order of 0, 16, 32, etc...
configParams[i].instanceId = i * 16;
configParams[i].pName = malloc(sizeof(char) * 8);
sprintf((char*)configParams[i].pName, "aweOS#%u", i);
}
}
// Assign start/stop callbacks to each instance
for (i = 0; i < NUM_INSTANCES; i++)
{
configParams[i].cbAudioStart = aweOSuser_audioStart;
configParams[i].cbAudioStop = aweOSuser_audioStop;
configParams[i].fundamentalBlockSize = blockSize;
}
//Initialize the AWEOSInstance's with their own parameters that were previously set in the config structures.
// The init allocates memory for the aweos instances internally
for (i = 0; i < NUM_INSTANCES; i++)
{
ret = aweOS_init(&g_AWEOSInstanceArray[i], &configParams[i], moduleDescriptorTable, moduleDescriptorTableSize);
//Check if the aweOS_init succeeded. If it didn't then terminate the executable.
if (ret)
{
printf("aweOS init failed for instance %d, ret = %d: %s\nExiting application\n", (INT32)i, ret, aweOS_errorToString(ret));
}
}
if (!uniqueSocketsFlag) //Open in single socket mode
{
printf("Single Socket Mode\n");
if (enableLoggingFlag)
{
INT32 loggingRet = aweOS_tuningLoggingEnable(g_AWEOSInstanceArray[0], "tuning_logs", "aweTuning", TUNING_LOG_INFO);
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");
}
}
//Open the tuning interface.
INT32 interfaceRet = aweOS_tuningSocketOpen(g_AWEOSInstanceArray, portNo, NUM_INSTANCES);
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 //Open in uniquesockets mode
{
for (i = 0; i < NUM_INSTANCES; i++)
{
if (enableLoggingFlag) //enable logging on the first socket
{
INT32 loggingRet = aweOS_tuningLoggingEnable(g_AWEOSInstanceArray[i], "tuning_logs", "aweTuning", TUNING_LOG_INFO);
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]);
}
}
//Open the tuning interface (on the first socket)
INT32 interfaceRet = aweOS_tuningSocketOpen(&g_AWEOSInstanceArray[i], portNos[i], 1); //open the tuning socket
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]);
}
}
}
// Link the instances so profiling is correct (run this app with taskset or -enableCPUAffinity for this to work)
aweOS_setInstancesInfo(g_AWEOSInstanceArray, NUM_INSTANCES);
for (i = 0; i < NUM_INSTANCES; i++)
{
pumpActive[i] = 0;
}
// Start audio pumpall threads for all instances
for (i = 0; i < NUM_INSTANCES; i++)
{
sem_init(&pumpSems[i], 0, 0);
pthread_create(&audioPumpAllThreadHandles[i], NULL, aweOSuser_pumpAudio, g_AWEOSInstanceArray[i]);
}
// Close it all down once ready
for (i = 0; i < NUM_INSTANCES; i++)
{
pthread_join(audioPumpAllThreadHandles[i], NULL);
}
for (i = 0; i < NUM_INSTANCES; i++)
{
aweOS_destroy(&g_AWEOSInstanceArray[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:54
void AWEOSInstance
The AWE Core OS Instance instance type.
Definition: AWECoreOS.h:106
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:84
UINT32 numPumpThreads
The number of running pump threads.
Definition: AWECoreOS.h:87
UINT32 * pumpThreadPIDs
Pointer to an array of the running pump thread PIDs of size pumpThreadPIDs[numPumpThreads].
Definition: AWECoreOS.h:88
AWEOSConfigParameters.
Definition: AWECoreOS.h:117
float profileSpeed
Application profiling speed in Hz.
Definition: AWECoreOS.h:132
UINT32 fastHeapBSize
Size of fast heap B in 32-bit words.
Definition: AWECoreOS.h:123
const char * pName
Name of target.
Definition: AWECoreOS.h:133
INT32 instanceId
ID number of instance.
Definition: AWECoreOS.h:139
float coreSpeed
Processor clock speed in Hz.
Definition: AWECoreOS.h:131
UINT32 numThreads
Maximum number of supported sublayouts.
Definition: AWECoreOS.h:134
UINT32 fundamentalBlockSize
Fundamental block size of audio driver.
Definition: AWECoreOS.h:136
UINT32 outChannels
Number of output channels of audio device.
Definition: AWECoreOS.h:138
UINT32 slowHeapSize
Size of slow heap in 32-bit words.
Definition: AWECoreOS.h:124
INT32(* cbAudioStop)(AWEOSInstance *pAWEOS)
Pointer to user created callback function for audio stop commands.
Definition: AWECoreOS.h:126
UINT32 fastHeapASize
Size of fast heap A in 32-bit words.
Definition: AWECoreOS.h:122
UINT32 inChannels
Number of input channels of audio device.
Definition: AWECoreOS.h:137
INT32(* cbAudioStart)(AWEOSInstance *pAWEOS)
Pointer to user created callback function for audio start commands.
Definition: AWECoreOS.h:125