Generic HPI example that includes file record and playback.
#define DUMP_MIXER_CONTROLS 0
#define USE_BBM 1
#define RECORD_TO_FILE 0
#define POLL_INTERVAL 500
#define RUNTIME (15 * SECONDS)
#define PRINT_INTERVAL (1 * SECONDS)
#define SECONDS (1000/POLL_INTERVAL)
#define MINUTES (60*SECONDS)
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
#include <getopt.h>
#define HPI_BUILD_INCLUDE_INTERNAL
#ifdef __APPLE__
#include <hpi/hpidebug.h>
#else
#include <hpi_version.h>
#include <hpidebug.h>
#endif
static char *hpi_control_strings[] = HPI_CONTROL_TYPE_STRINGS;
static char *hpi_src_strings[] = HPI_SOURCENODE_STRINGS;
static char *hpi_dst_strings[] = HPI_DESTNODE_STRINGS;
static void THPI_WavFileOpen(
short nIndex,
char *pszFile
);
static short THPI_WavFileRead(
short nIndex,
uint8_t *pbData,
long lLength
);
static void THPI_WavFileClose(
short nIndex
);
static int getch(
void
);
#define BLOCK_SIZE 32768L //30720L //6144 //12288 //16384 //19200 //9600
static uint8_t abBuffer[BLOCK_SIZE];
static short haveFiles = 0;
static int instream_bbm = USE_BBM;
static int outstream_bbm = USE_BBM;
static unsigned int record_to_file = RECORD_TO_FILE;
static unsigned int runtime = RUNTIME + 1;
static unsigned int dump_mixer = 0;
static int max_instreams = 999;
static int max_outstreams = 999;
static uint16_t wAdapterIndex = 0;
static int nNumFiles = 0;
static unsigned int samplerate = 48000;
static unsigned int bitrate = 128000;
static unsigned int channels = 2;
static unsigned int new_mode = 0;
static unsigned int yes = 0;
#define MAX_FILES 8
static char szFile[MAX_FILES][80] = { "", "", "", "" };
static struct option long_options[] = {
{"adapter", required_argument, 0, 'a'},
{"dump-mixer", no_argument, 0, 'd'},
{"disable-bbm", no_argument, 0, 'b'},
{"yes", no_argument, 0, 'y'},
{"adapter-mode", required_argument, 0, 'm'},
{"samplerate", required_argument, 0, 's'},
{"channels", required_argument, 0, 'c'},
{"format", required_argument, 0, 'f'},
{"file-record", no_argument, 0, 'F'},
{"max-instreams", required_argument, 0, 'i'},
{"max-outstreams", required_argument, 0, 'o'},
{"runtime", required_argument, 0, 'r'},
{"version", no_argument, 0, 'V'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}
};
static const char *short_options = "a:bc:df:Fhi:m:o:r:s:Vy?";
static const char *option_help[] = {
"<adapter number> to test.",
"Dump list of mixer controls.",
"Disable use of background bus mastering.",
"Don't prompt on error.",
"Set the adapter mode. (need driver reload).",
"<Hz> samplerate.",
"<n> channels to play or record.",
"<f> format index (see hpi.h)",
"Record audio to disk files.",
"<n> Max number of instreams to open.",
"<n> Max number of outstreams to open.",
"<runtime> in seconds.",
"Show the version of this program",
"Show this text."
};
#ifdef _MSC_VER
static void poll_delay(
void
)
{
Sleep(POLL_INTERVAL);
}
#else
#include <time.h>
#define millisec 1000000
static struct timespec poll_interval = {
0, POLL_INTERVAL * millisec
};
static void poll_delay(
void
)
{
nanosleep(&poll_interval, 0);
}
#endif
static void help(
void
)
{
int i = 0;
printf("\nUsage: asihpitest [options] [files to play]\n");
printf("Exercise HPI API.\n\n");
while (long_options[i].name != 0) {
printf(" --%s -%c %s\n",
long_options[i].name,
(char)(long_options[i].val), option_help[i]);
i++;
}
exit(0);
}
static void parse_options(
int argc,
char *argv[]
)
{
int c;
while (1) {
int option_index = 0;
c = getopt_long(argc, argv, short_options,
long_options, &option_index);
if (c == -1)
break;
switch (c) {
case 0:
printf("option %s", long_options[option_index].name);
if (optarg)
printf(" with arg %s", optarg);
printf("\n");
break;
case 'a':
wAdapterIndex = atoi(optarg);
break;
case 'b':
instream_bbm = 0;
outstream_bbm = 0;
break;
case 'c':
channels = atoi(optarg);
break;
case 'd':
dump_mixer = 1;
break;
case 'y':
yes = 1;
break;
case 'F':
record_to_file = 1;
break;
case 'f':
format = atoi(optarg);
break;
case 'i':
max_instreams = atoi(optarg);
if (max_instreams < 0) {
max_instreams = -max_instreams;
instream_bbm = 0;
}
break;
case 'm':
new_mode = atoi(optarg);
break;
case 'o':
max_outstreams = atoi(optarg);
if (max_outstreams < 0) {
max_outstreams = -max_outstreams;
outstream_bbm = 0;
}
break;
case 'r':
runtime = atoi(optarg);
runtime *= SECONDS;
break;
case 's':
samplerate = atoi(optarg);
break;
case 'V':
printf("asihpitest version " HPI_VER_STRING "\n");
exit(0);
break;
case '?':
case 'h':
help();
break;
default:
printf("?? getopt returned character code 0%o ??\n",
c);
}
}
if (optind < argc) {
nNumFiles = 0;
while ((optind < argc) && (nNumFiles < MAX_FILES)) {
strcpy(szFile[nNumFiles], argv[optind++]);
printf("File %d is %s\n", nNumFiles,
szFile[nNumFiles]);
nNumFiles++;
}
}
}
static void print_universal_control_lookup_result(
hpi_hsubsys_t *hSubSys,
)
{
char name[256];
size_t size;
size_t items;
size = sizeof(name);
name, &size, &items);
if (err)
HandleError(err);
if (err)
HandleError(err);
block_object = hControl;
asihpi_control.wSrcNodeType, asihpi_control.wSrcNodeIndex,
asihpi_control.wDstNodeType, asihpi_control.wDstNodeIndex,
name,
&found_control );
}
if (err) {
HandleError(err);
printf(" Block/Param lookup (FAILED) ");
}
}
static void print_universal_control(
hpi_hsubsys_t *hSubSys,
)
{
struct hpi_entity *info;
char name[256];
char units[256];
size_t size, items;
int flags;
size = sizeof(name);
name, &size, &items);
if (err)
HandleError(err);
printf(" %s\n", name);
if (err)
HandleError(err);
struct hpi_entity *value;
const char *type;
void *v;
printf("Value (");
size = sizeof(flags);
&flags, &size, &items);
printf("R");
printf("W");
printf("Volatile");
printf(") ");
if (!err) {
int vi;
printf("%s[%zd]=[ ", type, items);
items *= 6;
}
for (vi = 0; vi < items; vi++) {
switch (the_type) {
printf("%d ", ((int *)v)[vi]); break;
printf("%f ", ((float *)v)[vi]); break;
printf("%c ", ((char *)v)[vi]); break;
printf("%c", ((char *)v)[vi]); break;
printf("0x%08x ", ((int*)v)[vi]); break;
default:
printf("%02x ", ((unsigned char *)v)[vi]); break;
}
}
printf("] ");
}
size = sizeof(units);
units, &size, &items);
if (!err)
printf("%s", units);
}
size_t i;
size_t number;
hMixer,
hControl,
params,
&number);
if (err)
HandleError(err);
printf("Parameter handles=[");
for ( i=0 ; i<number ; i++ ) {
if (i > 0)
printf(", ");
printf("%d",params[i]);
}
printf("]");
}
}
static void print_mixer_controls(
hpi_hsubsys_t *hSubSys,
)
{
int f;
for (f = 0; f < 10000; f++) {
err =
HPI_MixerGetControlByIndex(hSubSys, hMixer, f, &asihpi_control.wSrcNodeType, &asihpi_control.wSrcNodeIndex, &asihpi_control.wDstNodeType, &asihpi_control.wDstNodeIndex, &asihpi_control.wControlType,
&hControl);
printf("DISABLED ");
else if (err)
break;
printf("\nHPI Control %d, %s:%s[%d]->%s[%d] : ",
f,
hpi_control_strings[asihpi_control.wControlType],
hpi_src_strings[asihpi_control.wSrcNodeType -
asihpi_control.wSrcNodeIndex,
hpi_dst_strings[asihpi_control.wDstNodeType -
asihpi_control.wDstNodeIndex);
switch (asihpi_control.wControlType) {
uint16_t s;
uint32_t w;
short db[2];
int l;
uint16_t cs, ci;
&cs, &ci);
if (err) {
HandleError(err);
break;
}
for (l = 0; l < 256; l++) {
(hSubSys, hControl, l,
&asihpi_control.wSrcNodeType,
&asihpi_control.
wSrcNodeIndex);
if (!err) {
if ((cs == asihpi_control.
wSrcNodeType)
&& (ci ==
asihpi_control.
wSrcNodeIndex))
printf("\n->");
else
printf("\n");
printf("\tSource %d %s[%d]",
l,
hpi_src_strings
[asihpi_control.
wSrcNodeType -
asihpi_control.
wSrcNodeIndex);
} else
break;
}
break;
}
if (err) {
HandleError(err);
break;
}
printf("%5.2fdB %5.2fdB", db[0] / 100.0,
db[1] / 100.0);
break;
if (err) {
HandleError(err);
break;
}
printf("%5.2fdB %5.2fdB", db[0] / 100.0,
db[1] / 100.0);
break;
if (err) {
HandleError(err);
break;
}
printf("%5.2fdB %5.2fdB", db[0] / 100.0,
db[1] / 100.0);
break;
hControl, &s);
printf("status %02x", s);
&s);
printf(" format %d", s);
hControl, &w);
if (!err)
printf(" rate %d", w);
break;
&w);
&s);
printf("rate %d, source %d", w, s);
break;
print_universal_control_lookup_result(hSubSys, hMixer,
asihpi_control, hControl);
print_universal_control(hSubSys, hMixer, hControl);
break;
}
}
printf("\n%d controls found\n", f);
}
int main(
int argc,
char *argv[]
)
{
hpi_hsubsys_t *hSubSys;
uint32_t dwVersion = 0;
uint32_t dwDataSizeW, dwDataSizeR = 0;
int numAdapters = 0;
int adapterFound = 0;
uint16_t wVersion;
uint32_t dwSerialNumber;
uint16_t wType;
uint16_t wNumOutStreams;
uint16_t wNumInStreams;
uint32_t current_mode;
uint32_t dwStrBufferSize = 0;
uint32_t dwIStrBufferSize = 0;
short f;
uint32_t i = 0;
short anGainLog[4][2];
long testcount = 0;
parse_options(argc, argv);
printf("********************************************************************\n");
printf("\n** Test HPI using Functions **\n");
if (nNumFiles == 0) {
haveFiles = 0;
nNumFiles = 32;
} else
haveFiles = 1;
printf("HPI_SubSysSetHostNetworkInterface error\n");
HandleError(err);
}
printf("********************************************************************\n");
printf("HPI_SubSysCreate\n");
if (hSubSys == NULL) {
printf("hSubSys==NULL\n");
exit(1);
}
HandleError(err);
printf("HPI_SubSysGetVersionEx=%x\n", dwVersion);
printf("%li HPI_SubSysFindAdapters found %d adapters\n ", testcount++,
numAdapters);
HandleError(err);
for (i = 0; i < (uint32_t)numAdapters; i++) {
uint32_t dwAdapterIndex;
uint16_t wAdapterType;
i,
&dwAdapterIndex,
&wAdapterType
) ;
printf("%d=%X\n ", dwAdapterIndex, wAdapterType);
if (dwAdapterIndex == wAdapterIndex)
adapterFound = 1;
}
if (!adapterFound) {
printf("No adapter with index %d\n", wAdapterIndex);
exit(1);
}
HandleError(err);
printf("HPI_AdapterClose \n");
HandleError(err);
printf("HPI_AdapterOpen \n");
#ifdef GET_INFO_LOOP_TEST
while(1){
poll_delay();
wAdapterIndex,
&wNumOutStreams,
&wNumInStreams, &wVersion, &dwSerialNumber, &wType);
HandleError(err);
printf("HPI_AdapterGetInfo\n");
printf("Adapter ID=%4X Index=%d NumOutStreams=%d NumInStreams=%d S/N=%d\nHw Version %c%d DSP code version %03d\n", wType, wAdapterIndex, wNumOutStreams, wNumInStreams, dwSerialNumber, ((wVersion >> 3) & 0xf) + 'A',
wVersion & 0x7,
((wVersion >> 13) * 100) + ((wVersion >> 7) & 0x3f)
);
}
return 0;
#else
wAdapterIndex,
&wNumOutStreams,
&wNumInStreams, &wVersion, &dwSerialNumber, &wType);
HandleError(err);
printf("HPI_AdapterGetInfo\n");
printf("Adapter ID=%4X Index=%d NumOutStreams=%d NumInStreams=%d S/N=%d\nHw Version %c%d DSP code version %03d\n", wType, wAdapterIndex, wNumOutStreams, wNumInStreams, dwSerialNumber, ((wVersion >> 3) & 0xf) + 'A',
wVersion & 0x7,
((wVersion >> 13) * 100) + ((wVersion >> 7) & 0x3f)
);
if (wNumOutStreams > max_outstreams)
wNumOutStreams = max_outstreams;
if (wNumInStreams > max_instreams)
wNumInStreams = max_instreams;
if (nNumFiles > wNumOutStreams) {
nNumFiles = wNumOutStreams;
}
printf("Adapter current mode %d\n", current_mode);
if (new_mode && (new_mode != current_mode)) {
HandleError(err);
printf("Changed adapter mode. Reload driver to activate.\n");
exit(0);
}
printf("HPI_MixerOpen: handle=%08X\n", hMixer);
HandleError(err);
if (dump_mixer)
print_mixer_controls(hSubSys, hMixer);
&hControl);
if (!err) {
if (err)
printf("HPI_SampleClock_SetLocalRate() error %d\n",err);
}
#ifndef HPI_BUILD_NO_STREAMS
if (wNumOutStreams) {
printf("HPI_OutStreamOpen\n");
for (f = 0; f < wNumOutStreams; f++) {
wAdapterIndex, f, &hOutStream[f]
);
printf(" %i:%08X ", f, hOutStream[f]);
HandleError(err);
if (outstream_bbm) {
printf("HPI_OutStreamHostBufferAllocate ");
hOutStream[f], BLOCK_SIZE);
outstream_bbm = 0;
else
HandleError(err);
}
HandleError(err);
if (hOutStream[f]) {
&dwStrBufferSize, NULL, NULL, NULL);
HandleError(err);
printf(" HPI_OutStreamGetInfo %d: BufferSize=%d\n", f, dwStrBufferSize);
}
}
}
&FormatW,
channels,
format,
samplerate,
bitrate,
0
);
HandleError(err);
dwDataSizeW = BLOCK_SIZE / 2;
if (wNumInStreams) {
printf("\nHPI_InStreamOpen ");
for (f = 0; f < wNumInStreams; f++) {
wAdapterIndex, f, &hInStream[f]
);
printf(" %i:%08X ", f, hInStream[f]);
HandleError(err);
}
if (wNumInStreams) {
hInStream[0],
NULL, &dwIStrBufferSize, NULL, NULL, NULL);
printf("\nHPI_InStreamGetInfo %i: BufferSize=%d\n", 0,
dwStrBufferSize);
HandleError(err);
&FormatR,
channels,
format,
samplerate,
bitrate,
0
);
HandleError(err);
&FormatR);
HandleError(err);
dwDataSizeR = BLOCK_SIZE / 2;
hMixer,
0,
0,
printf("HPI_MixerGetControl - PeakMeter: handle=%08X\n", hMeterControl);
HandleError(err);
}
}
if (wNumOutStreams) {
printf("********************************************************************\n");
printf("Opening files \n");
for (f = 0; f < nNumFiles; f++)
THPI_WavFileOpen(f, szFile[f]);
for (f = 0; f < nNumFiles; f++)
if (hOutStream[f]) {
printf("HPI_OutStreamQueryFormat\n");
hOutStream[f], &FormatW);
HandleError(err);
break;
}
hMixer,
printf("HPI_MixerGetControl - PeakMeter: handle=%08X\n",
hMeterControl);
HandleError(err);
for (f = 1; f >= 0; f--) {
hMixer,
f,
);
if (err == 0) {
printf("HPI_MixerGetControl - Volume: handle=%08X\n", ahGainControl[f]);
anGainLog[f][0] = 0;
anGainLog[f][1] = 0;
ahGainControl[f], anGainLog[f]
);
HandleError(err);
}
}
}
{
uint16_t wState = 0;
uint32_t dwDataToPlay = 0;
FILE *recfile[8];
char recname[] = "rec0.pcm";
if (wNumOutStreams) {
printf("Preload\n");
for (f = 0; f < nNumFiles; f++) {
if (hOutStream[f]) {
for (i = 0;
i <
((dwStrBufferSize -
4) /
dwDataSizeW); i++) {
THPI_WavFileRead(f, abBuffer,
dwDataSizeW);
(hSubSys,
hOutStream[f],
abBuffer, dwDataSizeW,
&FormatW);
HandleError(err);
(hSubSys,
hOutStream[f],
&wState, NULL,
&dwDataToPlay, NULL,
NULL);
HandleError(err);
printf("[%i] D=%03d S=%d \r", f, dwDataToPlay / 1000, wState);
}
printf("\n");
}
}
printf("********************************************************************\n");
printf("HPI_OutStreamStart ");
for (f = 0; f < nNumFiles; f++) {
if (hOutStream[f]) {
hOutStream[f]
);
HandleError(err);
printf("%i ", f);
}
}
printf("\n");
}
for (f = 0; f < wNumInStreams; f++) {
printf("%d: ", f);
if (instream_bbm) {
printf("HPI_InStreamHostBufferAllocate ");
hInStream[f], BLOCK_SIZE);
instream_bbm = 0;
else
HandleError(err);
}
printf("HPI_InStreamSetFormat ");
hInStream[f], &FormatR);
HandleError(err);
printf("HPI_InStreamReset ");
HandleError(err);
printf("HPI_InStreamStart \n");
HandleError(err);
if (record_to_file) {
if (szFile[f][0])
recfile[f] = fopen(szFile[f], "w");
else {
recname[3] = f + '0';
recfile[f] = fopen(recname, "w");
}
}
}
if ( wNumInStreams + wNumOutStreams == 0 )
runtime = 1;
while (--runtime) {
int do_print = ((runtime % PRINT_INTERVAL) == 0);
poll_delay();
if (do_print && wNumInStreams)
printf("IN :");
for (f = 0; f < wNumInStreams; f++) {
hInStream[f],
&wState,
NULL, &dwDataToPlay, NULL, NULL);
HandleError(err);
if (do_print)
printf("%03d %d ",
dwDataToPlay / 1000, wState);
if (dwDataToPlay >= dwDataSizeR) {
dwDataToPlay = dwDataSizeR;
hInStream[f],
abBuffer, dwDataToPlay);
HandleError(err);
if (record_to_file)
fwrite(abBuffer, dwDataToPlay,
1, recfile[f]);
}
}
if (do_print && wNumInStreams)
printf("\n");
if (do_print && wNumOutStreams)
printf("OUT:");
for (f = 0; f < nNumFiles; f++) {
if (hOutStream[f]) {
hOutStream[f],
&wState,
NULL,
&dwDataToPlay, NULL, NULL);
HandleError(err);
if (do_print)
printf("%03d %d ",
dwDataToPlay / 1000,
wState);
if ((dwStrBufferSize - dwDataToPlay) >
dwDataSizeW) {
THPI_WavFileRead(f, abBuffer,
dwDataSizeW);
(hSubSys,
hOutStream[f],
abBuffer, dwDataSizeW,
&FormatW);
HandleError(err);
}
}
}
if (do_print && wNumOutStreams)
printf("\n");
}
if (record_to_file)
for (f = 0; f < wNumInStreams; f++)
fclose(recfile[f]);
printf("\n");
}
for (f = 0; f < nNumFiles; f++)
THPI_WavFileClose(f);
if (wNumOutStreams) {
printf("HPI_OutStreamStop ");
for (f = 0; f < nNumFiles; f++) {
if (hOutStream[f]) {
hOutStream[f]);
printf("%i ", f);
HandleError(err);
}
}
printf("\nHPI_OutStreamClose ");
for (f = 0; f < wNumOutStreams; f++) {
if (hOutStream[f]) {
if (outstream_bbm)
(hSubSys, hOutStream[f]);
hOutStream[f]);
printf("%i ", f);
HandleError(err);
}
}
}
if (wNumInStreams) {
printf("\nHPI_InStreamStop \n");
HandleError(err);
printf("\nHPI_InStreamClose ");
for (f = 0; f < wNumInStreams; f++) {
if (instream_bbm)
hInStream[f]);
printf("%i ", f);
HandleError(err);
}
}
#endif // HPI_BUILD_NO_STREAMS
printf("\nHPI_MixerClose\n");
HandleError(err);
printf("HPI_AdapterClose\n");
HandleError(err);
return 0;
#endif
}
FILE *gpFile[8];
static void THPI_WavFileOpen(
short nIndex,
char *pszFile
)
{
if (haveFiles) {
printf("%s ", pszFile);
gpFile[nIndex] = fopen(pszFile, "rb");
if (!gpFile[nIndex]) {
printf("****ERROR**** - can't open file\n");
getch();
exit(0);
}
if (toupper(pszFile[strlen(pszFile) - 1]) == 'S')
fseek(gpFile[nIndex], 512, SEEK_SET);
else
fseek(gpFile[nIndex], 0x50, SEEK_SET);
}
}
static short THPI_WavFileRead(
short nIndex,
uint8_t *pbData,
long lLength
)
{
long lNumRead;
long i = 0;
uint16_t wSine;
if (haveFiles) {
lNumRead = fread(pbData, 1, lLength, gpFile[nIndex]);
if (lNumRead != lLength)
return (1);
else
return (0);
} else {
for (i = 0; i < lLength / 4; i++) {
wSine = (uint16_t)(32767 * sin(2 * 3.141592653 * i / 32));
pbData[(short)i * 4] = (uint8_t)wSine;
pbData[(short)i * 4 + 1] = (uint8_t)(wSine >> 8);
pbData[(short)i * 4 + 2] = (uint8_t)wSine;
pbData[(short)i * 4 + 3] = (uint8_t)(wSine >> 8);
}
return (0);
}
}
static void THPI_WavFileClose(short nIndex)
{
if (haveFiles)
fclose(gpFile[nIndex]);
}
{
char szError[256];
char nK = 0;
if (err) {
HPI_GetErrorText(err, szError);
printf("ERROR %d %s\n", err, szError);
if (!yes) {
printf("press Enter to continue, (q,Enter) to exit...\n");
nK = getch();
if (nK == 'q')
exit(0);
}
}
}
static int getch(
void
)
{
return getchar();
}