AWECoreOS 8.B.1 User's Guide
RTAudio-alsa.c

Examples

/****************************************************************************
*
* RTAudio-alsa
* --------------
*
****************************************************************************
*
* Description: Pump realtime audio through a layout using the linux alsa API
*
* Copyright: (c) 2020 DSP Concepts, Inc. All rights reserved.
* 3235 Kifer Road
* Santa Clara, CA 95054-1527
*
* This example is demonstrates integration of a realtime audio framework, specifically the alsa API.
* It brings in samples of audio from an alsa callback, and pumps them through a layout with the aweOS_audioPumpAll function.
* This example is meant to show the pumpAll function, and the surrounding import/exportSamples API's
*
* NOTE: AudioStream.c and all alsa related code written by DSPC Concepts is simply for reference, and is not considered robust or full featured...
* The alsa code is meant to be a bare minimum, and the focus of this example should be on this file, and the AWE Core OS API functions.
* See the alsa api doc for more details about realtime audio with alsa
*
* NOTE: This example must be run with superuser priorities, to ensure that we can we set scheduling parameters of the internal threads.
* Please give privileges or run with sudo. aweOS_audioPumpAll will return E_SCHEDULER_PERMISSION_DENIED as a warning.
*
* By default, this example opens the alsa input and output devices "hw:0,0", but any device id can be passed in with cmd line arguments. The device id string must be in ""
*
* NOTE: This device id string is an alsa specific parameter (https://www.alsa-project.org/wiki/Documentation), where "hw:" means the device type, 0 is Card #0, and 0 is Device #0.
* To find the device id string of an output device, enter the command "aplay -l" into the console. This will display alsa's list of all available output Cards/Devices
* Then, enter aplay -L to see the available types. A usb audio device may support both types "hw" and "plughw". For USB devices, use "plughw"
* For example, a USB device on Card 1, Device 0 would take the cmd line arg -outputdevice:"plughw:1,0"
* The process is the same for finding the input device id, but use the commands "arecord -l" and "arecord -L" instead of "aplay -l" and "aplay -L".
* For example, a USB device on Card 1, Device 0 would take the cmd line arg -inputdevice:"plughw:1,0"
*
* Block size, sample rate, and channel counts of the HW device can also be set with cmd line arguments.
* Audio logging can also be enabled with cmd line options, but is disabled by default.
*
* The example opens a tuning interface on port 15002, unless specified otherwise with the -portno: cmd line option.
* An awb can be loaded at run time with the -load: option. If no awb file path is given, then the app waits for one over the tuning interface.
*
***************************************************************************/
#include "AWECoreOS.h"
#include "AudioStream.h"
#include <pthread.h>
#include <sys/prctl.h>
#include "ModuleList.h"
#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>
AudioStream *as;
AWEOSInstance *g_AWEOSInstance;
static AWEOSConfigParameters configParams;
UINT32 hwInputChannels = 1;
UINT32 hwOutputChannels = 2;
char* inputDeviceName;
char* outputDeviceName;
UINT32 portNo = 15002;
UINT32 fundamentalBlockSize = 32;
double sampleRate = 48000.0;
UINT32 enableAudioLogging = 0;
const char* awbPath;
UINT32 loadAWB = 0;
float coreSpeed = 1e9f;
float profileSpeed = 10e6f;
static const void* moduleDescriptorTable[] =
{
LISTOFCLASSOBJECTS
};
UINT32 moduleDescriptorTableSize = sizeof(moduleDescriptorTable) / sizeof(moduleDescriptorTable[0]);
INT32 audioStartCallback(AWEOSInstance *pAWEOS)
{
printf("Audio Start Callback: Starting audio stream \n");
AudioStream_start(as);
return 0;
}
//the user defined callback for audio stop that will be passed into the param structure. Stop PA here
INT32 audioStopCallback(AWEOSInstance *pAWEOS)
{
printf("Audio Stop Callback: Stopping audio stream \n");
AudioStream_stop(as);
return 0;
}
void audioRecordNotifyCallback(AWEOSAudioRecordNotification_t * recordingNotification)
{
if (recordingNotification->notificationStatus == INPUT_OVERRUN)
{
printf("Got xrun on audio recording input stream: total xruns = %d, time of xrun = %f\n", recordingNotification->xruns, recordingNotification->xrunTime);
}
else if (recordingNotification->notificationStatus == OUTPUT_OVERRUN)
{
printf("Got xrun on audio recording output stream: total xruns = %d, time of xrun = %f\n", recordingNotification->xruns, recordingNotification->xrunTime);
}
else
{
printf("Got audio recording error notification: %d\n", recordingNotification->error);
}
}
void loadAWBFile(AWEOSInstance *pAWEOS, const char* filePath)
{
//Load the AWB from the file
UINT32 position = 0;
INT32 ret = aweOS_loadAWBFile(pAWEOS,filePath, &position);
if (0 == ret)
{
printf("The layout %s loaded succesfully\n", filePath);
}
else
{
printf("The layout %s download unsuccessfullu in the position %d with Error = %s \n", filePath, position, strerror(ret));
exit(1);
}
}
//AudioStream audio callback function. This is where the importing/exporting/pumping will happen
AudioStream_CallbackResult audio_callback(const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
AudioStream_CallbackFlag statusFlags,
void *userData)
{
/*suppress warnings for unused variables timeinfo, userData */
(void)userData;
UINT32 i, j;
INT32 pumpRet; //return for pump
if (statusFlags != 0)
{
// Indicate an xrun. These may not appear until after the audio stream is stopped. Enable logging for more details
printf("xrun ");
return AudioStream_CallbackResult_Continue; //Even though there was an xrun, tell the stream to continue. This will cause audio dropouts under high CPU load when xruns are occuring.
}
if (aweOS_layoutIsValid(g_AWEOSInstance))
{
if (aweOS_audioIsStarted(g_AWEOSInstance))
{
INT32 ret;
// import samples for each input device channel
for (i = 0; i < hwInputChannels; i++)
{
ret = aweOS_audioImportSamples(g_AWEOSInstance, ((UINT32*)inputBuffer) + i, hwInputChannels, i, Sample32bit);
if (ret != 0)
{
printf("error import samples: error: %d -- %s\n", ret, aweOS_errorToString(ret));
}
}
// pump the audio through the loaded layout
pumpRet = aweOS_audioPumpAll(g_AWEOSInstance);
if (pumpRet < 0)
{
printf("pumpAll failing with error code: %d -- %s\n", pumpRet, aweOS_errorToString(pumpRet));
}
// export latest samples for each device output channel
for (j = 0; j < hwOutputChannels; j++)
{
ret = aweOS_audioExportSamples(g_AWEOSInstance, ((UINT32*)outputBuffer) + j, hwOutputChannels, j, Sample32bit);
if (ret != 0)
{
printf("Failed on export samples: error: %d -- %s\n", ret, aweOS_errorToString(ret));
}
}
}
}
return AudioStream_CallbackResult_Continue;
}
int initializeAudioStream()
{
as = AudioStream_create();
if (as == NULL)
{
printf("Error initializing AudioStream\n");
}
else
{
printf("AudioStream init success\n");
}
AudioStream_open(as, inputDeviceName, hwInputChannels,
outputDeviceName, hwOutputChannels,
AudioStream_SampleFormat_S32_LE,
sampleRate, fundamentalBlockSize,
audio_callback, NULL);
return 0;
}
static void usage(const char *program)
{
printf(
"Usage: %s [args]\n"
" -load:<file> AWB file to load. If no AWB is specified, then app waits for a layout from tuning interface\n"
" -inputdevice:<str> The alsa device id for the input device. Default hw:0,0 \n"
" -outputdevice:<str> The alsa device id for the output device. Default hw:0,0\n"
" -hwinchannels:<int> The number of hw input channels for the alsa audio device \n"
" -hwoutchannels:<int> The number of hw output channels for the alsa audio device\n"
" -blocksize:<int> The fundamental hw blocksize of the alsa device (DMA)\n"
" -samplerate:<int> The samplerate of the audio hw\n"
" -enabledAudioLog Enable audio logging. Logs will be saved to <appdirectory>/audio-logs/\n"
" -portno:<int> Port number to open the TCP tuning socket on. Default 15002\n"
" -coreSpeed:<float> Processor clock speed in Hz. Default 1 GHz\n"
" -profileSpeed:<float> Application profiling speed in Hz. Default 10 MHz. \n"
" -help Show usage\n"
"This program shows realtime audio integration with the alsa API.\n",
program);
exit(0);
}
int main(int argc, char **argv)
{
inputDeviceName = "hw:0,0";
outputDeviceName = "hw:0,0";
UINT32 i;
if (1 == argc)
{
printf("No command line options specified. Using defaults\n");
}
else
{
for (i = 1; i < argc; i++)
{
const char *arg = argv[i];
if ((0 == strncmp(arg, "-inputdevice:", 13)))
{
inputDeviceName = (char*)(arg + 13);
printf("cmd line arg set inputdevice to %s \n ", inputDeviceName);
}
else if ((0 == strncmp(arg, "-outputdevice:", 14)))
{
outputDeviceName = (char*)(arg + 14);
printf("cmd line arg set outputdevice to %s \n ", outputDeviceName);
}
else if ((0 == strncmp(arg, "-hwinchannels:", 14)))
{
hwInputChannels = atoi(arg + 14);
printf("Hardware input channels set to %d \n ", hwInputChannels);
}
else if ((0 == strncmp(arg, "-hwoutchannels:", 15)))
{
hwOutputChannels = atoi(arg + 15);
printf("Hardware output channels set to %d \n ", hwOutputChannels);
}
else if ((0 == strncmp(arg, "-blocksize:", 11)))
{
fundamentalBlockSize = atoi(arg + 11);
printf("fundamental block size set to %d \n ", fundamentalBlockSize);
}
else if ((0 == strncmp(arg, "-samplerate:", 12)))
{
sampleRate = atof(arg + 12);
printf("sample rate set to %f \n ", sampleRate);
}
else if ((0 == strncmp(arg, "-portno:", 8)))
{
portNo = atoi(arg + 8);
printf("portno for socket is %d \n", portNo);
}
else if (0 == strncmp(arg, "-load:", 6))
{
awbPath = arg + 6;
loadAWB = 1;
printf("-load: %s\n",awbPath);
}
else if ((0 == strncmp(arg, "-enableAudioLog", 15)))
{
enableAudioLogging = 1;
printf("Audio logging enabled \n");
}
else if ((0 == strncmp(arg, "-coreSpeed:", 11)))
{
coreSpeed = atof(arg + 11);
printf("coreSpeed set to %f\n", coreSpeed);
}
else if ((0 == strncmp(arg, "-profileSpeed:", 14)))
{
profileSpeed = atof(arg + 14);
printf("profileSpeed set to %f \n", profileSpeed);
}
else if ((0 == strncmp(arg, "-help", 5)))
{
usage(argv[0]);
}
else
{
printf("main: unknown option '%s'\n", arg);
}
}
}
aweOS_getParamDefaults(&configParams);
configParams.inChannels = hwInputChannels;
configParams.outChannels = hwOutputChannels;
configParams.sampleRate = sampleRate;
configParams.fundamentalBlockSize = fundamentalBlockSize;
configParams.numThreads = 4;
configParams.cbAudioStart = audioStartCallback;
configParams.cbAudioStop = audioStopCallback;
configParams.instanceId = 0;
configParams.coreSpeed = coreSpeed;
configParams.profileSpeed = profileSpeed;
INT32 ret;
ret = aweOS_init(&g_AWEOSInstance, &configParams, moduleDescriptorTable, moduleDescriptorTableSize);
if (ret != 0) //if the initialization fails, don't do anything and exit the app
{
printf("FATAL: aweOS_init failed. exiting application \n");
exit(1);
}
else
{
initializeAudioStream();
if (enableAudioLogging)
{
ret = aweOS_audioRecordingEnable(g_AWEOSInstance, "audio-logs", "rtaudio-alsa", 100, Sample32bit);
if (ret != 0)
{
printf("failed to enable audio logging: ret = %d\n", ret);
}
ret = aweOS_audioRecordingRegisterNotificationCallback(g_AWEOSInstance, audioRecordNotifyCallback, AUDIO_RECORDING_NOTIFICATION_ALL);
if (ret != 0)
{
printf("Failed to register audio logging callback function: ret = %d\n", ret);
}
}
INT32 tuningRet = aweOS_tuningSocketOpen(&g_AWEOSInstance, portNo, 1);
if (tuningRet < 0)
{
printf("Failing opening tuning interface with error %s \n", aweOS_errorToString(tuningRet));
}
else
{
printf("Opened TCP tuning interface on port %d: Waiting for AWE Server Connection from PC... \n", portNo);
}
if (loadAWB)
{
loadAWBFile(g_AWEOSInstance, awbPath);
}
while (1)
{
usleep(1000);
}
}
}
AWEOSAudioRecordNotification::notificationStatus
STATUS notificationStatus
type of notification being reported
Definition: AWECoreOS.h:63
AWEOSConfigParameters::fundamentalBlockSize
UINT32 fundamentalBlockSize
Fundamental block size of audio driver.
Definition: AWECoreOS.h:125
AWEOSConfigParameters::instanceId
INT32 instanceId
ID number of instance.
Definition: AWECoreOS.h:128
aweOS_audioImportSamples
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.
AWEOSConfigParameters::sampleRate
float sampleRate
Sample rate of audio device.
Definition: AWECoreOS.h:124
AWEOSConfigParameters::numThreads
UINT32 numThreads
Maximum number of supported sublayouts.
Definition: AWECoreOS.h:123
AWEOSAudioRecordNotification
Audio recording notification callback argument structure.
Definition: AWECoreOS.h:62
AWEOSAudioRecordNotification::xrunTime
FLOAT32 xrunTime
time in seconds of xrun in recording - 0 if error
Definition: AWECoreOS.h:66
AWEOSConfigParameters::inChannels
UINT32 inChannels
Number of input channels of audio device.
Definition: AWECoreOS.h:126
AWEOSInstance
void AWEOSInstance
The AWE Core OS Instance instance type.
Definition: AWECoreOS.h:95
aweOS_audioRecordingRegisterNotificationCallback
INT32 aweOS_audioRecordingRegisterNotificationCallback(AWEOSInstance *pAWEOS, recordNotificationCallbackFunction recordNotificationCallback, UINT32 recordNotificationMask)
Register a callback function for audio recording event notificiations.
aweOS_getParamDefaults
INT32 aweOS_getParamDefaults(AWEOSConfigParameters *aweParams)
Populates an AWEOSConfigParameters structure with defaults.
AWEOSConfigParameters::profileSpeed
float profileSpeed
Application profiling speed in Hz.
Definition: AWECoreOS.h:121
aweOS_tuningSocketOpen
INT32 aweOS_tuningSocketOpen(AWEOSInstance **pAWEOS, INT32 portNo, UINT32 numInstances)
Initialize and open an integrated TCP/IP tuning interface socket.
aweOS_audioExportSamples
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.
AWEOSAudioRecordNotification::xruns
UINT32 xruns
total xruns on recording stream - 0 if error
Definition: AWECoreOS.h:65
aweOS_layoutIsValid
INT32 aweOS_layoutIsValid(const AWEOSInstance *pAWEOS)
Determines if a layout is loaded and valid.
AWEOSConfigParameters::cbAudioStop
INT32(* cbAudioStop)(AWEOSInstance *pAWEOS)
Pointer to user created callback function for audio stop commands.
Definition: AWECoreOS.h:115
aweOS_init
INT32 aweOS_init(AWEOSInstance **pAWEOS, const AWEOSConfigParameters *aweParams, const void *pModuleDescriptorTable, UINT32 moduleDescriptorTableSize)
Initialize the AWEOSInstance with the specified configuration parameters.
AWEOSConfigParameters::outChannels
UINT32 outChannels
Number of output channels of audio device.
Definition: AWECoreOS.h:127
AWEOSConfigParameters
AWEOSConfigParameters.
Definition: AWECoreOS.h:106
aweOS_errorToString
const char * aweOS_errorToString(INT32 errorCode)
Convert an error code (INT32) to its corresponding error string.
aweOS_audioPumpAll
INT32 aweOS_audioPumpAll(AWEOSInstance *pAWEOS)
Pump one fundamental block size of audio through the loaded layout and all of its sublayouts.
aweOS_audioRecordingEnable
INT32 aweOS_audioRecordingEnable(AWEOSInstance *pAWEOS, char *path, char *baseName, UINT32 bufferLength, SampleType sampleType)
Enables recording of all input and output audio of AWEOSInstance.
AWEOSConfigParameters::cbAudioStart
INT32(* cbAudioStart)(AWEOSInstance *pAWEOS)
Pointer to user created callback function for audio start commands.
Definition: AWECoreOS.h:114
aweOS_loadAWBFile
INT32 aweOS_loadAWBFile(AWEOSInstance *pAWEOS, const char *binaryFile, UINT32 *pErrorOffset)
Executes packet commands from an AWB file on the filesystem.
AWEOSAudioRecordNotification::error
INT32 error
error value - 0 if xrun
Definition: AWECoreOS.h:64
AWECoreOS.h
The AWE Core OS API header file.
AWEOSConfigParameters::coreSpeed
float coreSpeed
Processor clock speed in Hz.
Definition: AWECoreOS.h:120
aweOS_audioIsStarted
INT32 aweOS_audioIsStarted(const AWEOSInstance *pAWEOS)
Check if this instance has received an Audio Start command.
AUDIO_RECORDING_NOTIFICATION_ALL
#define AUDIO_RECORDING_NOTIFICATION_ALL
Audio recording: Notify on errors and overruns.
Definition: AWECoreOS.h:77