AudioScience HPI Version_4.10.

HPI Test

Generic HPI example that includes file record and playback.

/******************************************************************************
$Header: /home/eliot/asi/repo/cvsrepo/Repository/drv/linux/test/asihpitest.c,v 1.56 2011/08/12 11:13:16 as-ewb Exp $

  Test Hardware Programming Interface (HPI) using HPI functions

  Usage: asihpitest --help

note to cleanup this file, use "astyle --style=linux -s4 asihpitest.c"
******************************************************************************/
/* Some customization defines */
// Print out the complete list of mixer controls
#define DUMP_MIXER_CONTROLS 0
// Use background bus mastering if available
#define USE_BBM 1
// Record instreams to files "recN.pcm"
#define RECORD_TO_FILE 0
// Card polling interval in milliseconds
#define POLL_INTERVAL 50
// Test runtime
#define RUNTIME (15 * SECONDS)
// Interval at which stream state is printed
#define PRINT_INTERVAL (1 * SECONDS)

/* End customization defines */

#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 <unistd.h>
#include <getopt.h>
#define HPI_BUILD_INCLUDE_INTERNAL
#ifdef __APPLE__
#include <hpi/hpi.h>
#include <hpi/hpidebug.h>
#else
#include <hpi.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;

// local protos
static void HandleError(hpi_err_t err);

// file read/write
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
);

// global
#define BLOCK_SIZE 32768L       //30720L //6144 //12288 //16384 //19200 //9600
static uint8_t abBuffer[BLOCK_SIZE];
static short haveFiles = 0;

/* Option variables */
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 format = HPI_FORMAT_PCM16_SIGNED;
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'},
        {"help", no_argument, 0, 'h'},
        {0, 0, 0, 0}
};

static const char *short_options = "a:bc:df:Fhi:m:o:r:s:y?";

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 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");
        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;
        /*********** Parse the command line options ***************/
        while (1) {
                //int this_option_optind = optind ? optind : 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 '?':
                case 'h':
                        help();
                        break;

                default:
                        printf("?? getopt returned character code 0%o ??\n",
                                c);
                }
        }

        if (optind < argc) {
                // printf ("non-option ARGV-elements: ");
                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,
        hpi_handle_t hMixer,
        struct hpi_control_t asihpi_control,
        hpi_handle_t hControl
)
{
        static hpi_handle_t block_object;
        char name[256];
        char *param_name;
        hpi_err_t err;
        size_t size;
        size_t items;
        enum e_entity_role r;
        hpi_handle_t found_control;

        size = sizeof(name);
        err = HPI_Object_GetInfo( hControl,
                entity_type_cstring, entity_role_classname,
                name, &size, &items);

        if (err)
                HandleError(err);

        err = HPI_Object_GetRole(hControl, &r);
        if (err)
                HandleError(err);

        if ( r == entity_role_block ) {
                block_object = hControl;
                /* test lookup block by name */
                err = HPI_Object_BlockHandle(hMixer,
                        asihpi_control.wSrcNodeType, asihpi_control.wSrcNodeIndex,
                        asihpi_control.wDstNodeType, asihpi_control.wDstNodeIndex,
                        name,
                        &found_control );
        } else if ( r == entity_role_parameter_port ) {
                /* test lookup parameter by name */
                param_name = name;
                err = HPI_Object_ParameterHandle( hMixer, block_object, name, &found_control);
        }

        if (err) {
                HandleError(err);
                printf(" Block/Param lookup (FAILED) ");
        }
}

static void print_universal_control(
        hpi_hsubsys_t *hSubSys,
        hpi_handle_t hMixer,
        hpi_handle_t hControl
)
{
        struct hpi_entity *info;
        enum e_entity_role r;
        hpi_err_t err;
        char name[256];
        char units[256];
        size_t size, items;
        int flags;


        err = HPI_Object_GetInfoEntity(hControl, &info);

        printf("%s", HPI_Entity_GetRoleName(info));

        size = sizeof(name);
        err = HPI_Object_GetInfo( hControl,
                        entity_type_cstring, entity_role_classname,
                        name, &size, &items);
        if (err)
                HandleError(err);
        printf(" %s\n", name);

        err = HPI_Object_GetRole(hControl, &r);
        if (err)
                HandleError(err);

        if ( r == entity_role_parameter_port ) {
                struct hpi_entity *value;
                enum e_entity_type the_type;
                const char *type;
                void *v;
                printf("Value (");
                // flags
                size = sizeof(flags);
                err = HPI_Object_GetInfo( hControl,
                        entity_type_int, entity_role_flags,
                        &flags, &size, &items);
                if (flags & entity_flag_readable)
                        printf("R");
                if (flags & entity_flag_writeable)
                        printf("W");
                if (flags & entity_flag_volatile)
                        printf("Volatile");
                printf(") ");

                err = HPI_Object_GetValueEntity(hControl, &value);
                err = HPI_Entity_Unpack(value, &the_type, &items, &r, &v);
                type = HPI_Entity_GetTypeName(value);
                if (!err) {
                        int vi;
                        printf("%s[%zd]=[ ", type, items);
                        if (the_type == entity_type_mac_address) {
                                the_type = entity_type_octet;
                                items *= 6;
                        }
                        for (vi = 0; vi < items; vi++) {
                                switch (the_type) {
                                case entity_type_int:
                                        printf("%d ", ((int *)v)[vi]); break;
                                case entity_type_float:
                                        printf("%f ", ((float *)v)[vi]); break;
                                case entity_type_boolean:
                                        printf("%c ", ((char *)v)[vi]); break;
                                case entity_type_cstring:
                                        printf("%c", ((char *)v)[vi]); break;
                                case entity_type_ip4_address:
                                        printf("0x%08x ", ((int*)v)[vi]); break;
                                case entity_type_octet:
                                default:
                                        printf("%02x ", ((unsigned char *)v)[vi]); break;
                        }

                        }
                        printf("] ");
                }
                HPI_Entity_Free(value);

                // units
                size = sizeof(units);
                err = HPI_Object_GetInfo( hControl,
                        entity_type_cstring, entity_role_units,
                        units, &size, &items);
                if (!err)
                        printf("%s", units);
        }

        // fetch parameter handles
        if ( r == entity_role_block ) {
                hpi_handle_t params[16]; /* should really use count */
                size_t i;
                size_t number;

                number = sizeof(params)/sizeof(hpi_handle_t);
                err = HPI_Object_BlockParameters(
                        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,
        hpi_handle_t hMixer
)
{
        int f;
        hpi_handle_t hControl;
        hpi_err_t err;
        for (f = 0; f < 10000; f++) {   // put SOME limit to the number
                struct hpi_control_t asihpi_control;

                err = HPI_MixerGetControlByIndex(hSubSys, hMixer, f, &asihpi_control.wSrcNodeType, &asihpi_control.wSrcNodeIndex, &asihpi_control.wDstNodeType, &asihpi_control.wDstNodeIndex, &asihpi_control.wControlType,    // HPI_CONTROL_METER, _VOLUME etc
                        &hControl);
                if (err == HPI_ERROR_CONTROL_DISABLED)
                        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 -
                                HPI_SOURCENODE_NONE],
                        asihpi_control.wSrcNodeIndex,
                        hpi_dst_strings[asihpi_control.wDstNodeType -
                                HPI_DESTNODE_NONE],
                        asihpi_control.wDstNodeIndex);

                switch (asihpi_control.wControlType) {
                        uint16_t s;
                        uint32_t w;
                        short db[2];

                case HPI_CONTROL_MULTIPLEXER:{
                                int l;
                                uint16_t cs, ci;

                                err = HPI_Multiplexer_GetSource(hSubSys, hControl,
                                        &cs, &ci);
                                if (err) {
                                        HandleError(err);
                                        break;
                                }
                                for (l = 0; l < 256; l++) {
                                        err = HPI_Multiplexer_QuerySource
                                                (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 -
                                                                HPI_SOURCENODE_NONE],
                                                        asihpi_control.
                                                        wSrcNodeIndex);
                                        } else
                                                break;
                                }
                                break;
                        }
                case HPI_CONTROL_VOLUME:
                        err = HPI_VolumeGetGain(hSubSys, hControl, db);
                        if (err) {
                                HandleError(err);
                                break;
                        }

                        printf("%5.2fdB %5.2fdB", db[0] / 100.0,
                                db[1] / 100.0);

                        break;
            case HPI_CONTROL_LEVEL:
                err = HPI_LevelGetGain(hSubSys, hControl, db);
                if (err) {
                    HandleError(err);
                    break;
                }

                printf("%5.2fdB %5.2fdB", db[0] / 100.0,
                       db[1] / 100.0);

                break;
            case HPI_CONTROL_METER:
                        err = HPI_MeterGetPeak(hSubSys, hControl, db);
                        if (err) {
                                HandleError(err);
                                break;
                        }

                        printf("%5.2fdB %5.2fdB", db[0] / 100.0,
                                db[1] / 100.0);
                        break;
                case HPI_CONTROL_AESEBU_RECEIVER:
                        err = HPI_AESEBU_Receiver_GetErrorStatus(hSubSys,
                                hControl, &s);
                        printf("status %02x", s);

                        err = HPI_AESEBU_Receiver_GetFormat(hSubSys, hControl,
                                &s);
                        printf(" format %d", s);

                        err = HPI_AESEBU_Receiver_GetSampleRate(hSubSys,
                                hControl, &w);
                        if (!err)
                                printf(" rate %d", w);
                        break;

                case HPI_CONTROL_SAMPLECLOCK:
                        err = HPI_SampleClock_GetSampleRate(hSubSys, hControl,
                                &w);
                        err = HPI_SampleClock_GetSource(hSubSys, hControl,
                                &s);
                        printf("rate %d, source %d", w, s);
                        break;
                case HPI_CONTROL_UNIVERSAL:
                        print_universal_control_lookup_result(hSubSys, hMixer,
                                asihpi_control, hControl);
                        print_universal_control(hSubSys, hMixer, hControl);
                        break;
                }
        }

        printf("\n%d controls found\n", f);
}

/************************************** MAIN ***********************/
int main(
        int argc,
        char *argv[]
)
{
        hpi_hsubsys_t *hSubSys;
        hpi_err_t err = 0;              // HPI error
        uint32_t dwVersion = 0;
        uint32_t dwDataSizeW, dwDataSizeR = 0;
        struct hpi_format FormatW, FormatR;
        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;

        hpi_handle_t hOutStream[16];
        hpi_handle_t hInStream[16];

        uint32_t dwStrBufferSize = 0;
        uint32_t dwIStrBufferSize = 0;

        hpi_handle_t hMixer = 0;
        hpi_handle_t hControl;
        hpi_handle_t hMeterControl = 0;
        hpi_handle_t ahGainControl[4] = { 0, 0, 0, 0 };

        short f;

        uint32_t i = 0;
        short anGainLog[4][2];

        long testcount = 0;
        short gwReads = 0;

        // #include "msgsize.c"

        parse_options(argc, argv);

        printf("********************************************************************\n");
        printf("\n** Test HPI using Functions **\n");

        if (nNumFiles == 0) {
                haveFiles = 0;
                nNumFiles = 32;
        } else
                haveFiles = 1;

        // open subsystem and find adapters
        err = HPI_SubSysSetHostNetworkInterface(NULL, "");
        if (err && (err != HPI_ERROR_INVALID_FUNC) ) {
                printf("HPI_SubSysSetHostNetworkInterface error\n");
                HandleError(err);
        }

        printf("********************************************************************\n");
        printf("HPI_SubSysCreate\n");
        hSubSys = HPI_SubSysCreate();
        if (hSubSys == NULL) {
                printf("hSubSys==NULL\n");
                exit(1);
        }

        err = HPI_SubSysGetVersionEx(hSubSys, &dwVersion);
        HandleError(err);
        printf("HPI_SubSysGetVersionEx=%x\n", dwVersion);

        err = HPI_SubSysGetNumAdapters(hSubSys, &numAdapters);
        printf("%li HPI_SubSysFindAdapters found %d adapters\n ", testcount++,
                numAdapters);
        HandleError(err);

        if (numAdapters > HPI_MAX_ADAPTERS)
                numAdapters = HPI_MAX_ADAPTERS;

        for (i = 0; i < (uint32_t)numAdapters; i++) {
                uint32_t dwAdapterIndex;
                uint16_t wAdapterType;
                err =  HPI_SubSysGetAdapter(hSubSys,
                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);
        }

        err = HPI_AdapterClose(hSubSys, wAdapterIndex);
        if ( err && (err != HPI_ERROR_OBJ_NOT_OPEN) )
                HandleError(err);
        printf("HPI_AdapterClose \n");

        // open 1st adapter
        err = HPI_AdapterOpen(hSubSys, wAdapterIndex);
        HandleError(err);
        printf("HPI_AdapterOpen \n");

        err = HPI_AdapterGetInfo(hSubSys,
                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',  // Hw version major
                wVersion & 0x7, // Hw version minor
                ((wVersion >> 13) * 100) + ((wVersion >> 7) & 0x3f)     // DSP code version
                );

        // apply the max streams options
        if (wNumOutStreams > max_outstreams)
                wNumOutStreams = max_outstreams;
        if (wNumInStreams > max_instreams)
                wNumInStreams = max_instreams;

        if (nNumFiles > wNumOutStreams) {
                nNumFiles = wNumOutStreams;
        }

        err = HPI_AdapterGetMode(hSubSys, wAdapterIndex, &current_mode);

        printf("Adapter current mode %d\n", current_mode);
        if (new_mode && (new_mode != current_mode)) {
                err = HPI_AdapterSetMode(hSubSys, wAdapterIndex, new_mode);
                HandleError(err);

                printf("Changed adapter mode. Reload driver to activate.\n");
                exit(0);
        }
        // open the mixer of this adapter
        err = HPI_MixerOpen(hSubSys, wAdapterIndex, &hMixer);
        printf("HPI_MixerOpen: handle=%08X\n", hMixer);
        HandleError(err);

        if (dump_mixer)
                print_mixer_controls(hSubSys, hMixer);

        err = HPI_MixerGetControl(hSubSys, hMixer,
                HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0, HPI_CONTROL_SAMPLECLOCK,
                &hControl);

        if (!err) {
                err = HPI_SampleClock_SetLocalRate(hSubSys, hControl, samplerate);
                /* not all adapters support the above call ie ASI2416s */
                if (err)
                        printf("HPI_SampleClock_SetLocalRate() error %d\n",err);
        }
#ifndef HPI_BUILD_NO_STREAMS
        if (wNumOutStreams) {
                // open the out_streams
                printf("HPI_OutStreamOpen\n");
                for (f = 0; f < wNumOutStreams; f++) {
                        err = HPI_OutStreamOpen(hSubSys,
                                wAdapterIndex, f, &hOutStream[f]
                                );
                        printf(" %i:%08X ", f, hOutStream[f]);
                        HandleError(err);

                        if (outstream_bbm) {
                                printf("HPI_OutStreamHostBufferAllocate ");
                                err = HPI_OutStreamHostBufferAllocate(hSubSys,
                                        hOutStream[f], BLOCK_SIZE);
                                if (err == HPI_ERROR_INVALID_FUNC)
                                        outstream_bbm = 0;
                                else
                                        HandleError(err);
                        }

                        err = HPI_OutStreamReset(hSubSys, hOutStream[f]);
                        HandleError(err);
                        // find out some info about the stream
                        if (hOutStream[f]) {
                                err = HPI_OutStreamGetInfoEx(hSubSys, hOutStream[f], NULL,      // state
                                        &dwStrBufferSize, NULL, NULL, NULL);
                                HandleError(err);
                                printf(" HPI_OutStreamGetInfo %d: BufferSize=%d\n", f, dwStrBufferSize);
                        }
                }
        }
        // setup format and size of data block
        // we will use to send audio data to out_stream
        // we would normally get the format directly from the file
        // or audio data
        err = HPI_FormatCreate(
                &FormatW,
                channels,
                format,
                samplerate,
                bitrate,
                0               // no attributes
                );
        HandleError(err);

        dwDataSizeW = BLOCK_SIZE / 2;
        if (wNumInStreams) {
                // if the adapter has instreams then open them
                printf("\nHPI_InStreamOpen ");
                for (f = 0; f < wNumInStreams; f++) {

                        err = HPI_InStreamOpen(hSubSys,
                                wAdapterIndex, f, &hInStream[f]
                                );
                        printf(" %i:%08X ", f, hInStream[f]);
                        HandleError(err);
                }

                if (wNumInStreams) {
                        // find out some info about stream 0
                        err = HPI_InStreamGetInfoEx(hSubSys,
                                hInStream[0],
                                NULL, &dwIStrBufferSize, NULL, NULL, NULL);
                        printf("\nHPI_InStreamGetInfo %i: BufferSize=%d\n", 0,
                                dwStrBufferSize);
                        HandleError(err);
                        err = HPI_FormatCreate(
                                &FormatR,
                                channels,
                                format,
                                samplerate,
                                bitrate,
                                0       // no attributes
                                );
                        HandleError(err);
                        err = HPI_InStreamQueryFormat(hSubSys, hInStream[0],
                                &FormatR);
                        HandleError(err);

                        dwDataSizeR = BLOCK_SIZE / 2;

                        err = HPI_MixerGetControl(hSubSys,
                                hMixer,
                                0,
                                0,
                                HPI_DESTNODE_ISTREAM,
                                0, HPI_CONTROL_METER, &hMeterControl);
                        printf("HPI_MixerGetControl - PeakMeter: handle=%08X\n", hMeterControl);
                        HandleError(err);
                }
        }
        if (wNumOutStreams) {
                printf("********************************************************************\n");
                gwReads = 0;
                // open some audio files to play
                printf("Opening files \n");
                for (f = 0; f < nNumFiles; f++)
                        THPI_WavFileOpen(f, szFile[f]);

                //check first available open stream to make sure we can play this format
                for (f = 0; f < nNumFiles; f++)
                        if (hOutStream[f]) {
                                printf("HPI_OutStreamQueryFormat\n");
                                err = HPI_OutStreamQueryFormat(hSubSys,
                                        hOutStream[f], &FormatW);
                                HandleError(err);
                                break;
                        }
                // get mixer meter control on out_stream0
                err = HPI_MixerGetControl(hSubSys,
                        hMixer,
                        HPI_SOURCENODE_OSTREAM,
                        0, 0, 0, HPI_CONTROL_METER, &hMeterControl);
                printf("HPI_MixerGetControl - PeakMeter: handle=%08X\n",
                        hMeterControl);
                HandleError(err);

                for (f = 1; f >= 0; f--) {
                        // get mixer volume control on the connection
                        // between out_stream0 and lineOut0
                        err = HPI_MixerGetControl(hSubSys,
                                hMixer,
                                HPI_SOURCENODE_OSTREAM,
                                f,
                                HPI_DESTNODE_LINEOUT,
                                f, HPI_CONTROL_VOLUME, &ahGainControl[f]
                                );
                        // HandleError( err );   Ignore the error, some adapters don't have this control

                        if (err == 0) {
                                printf("HPI_MixerGetControl - Volume: handle=%08X\n", ahGainControl[f]);
                                // test - set gain on stream
                                anGainLog[f][0] = 0;    //-4*f;
                                anGainLog[f][1] = 0;    // -4*f-2;
                                err = HPI_VolumeSetGain(hSubSys,
                                        ahGainControl[f], anGainLog[f]
                                        );
                                HandleError(err);
                        }
                }

        }

        {

                uint16_t wState = 0;
                uint32_t dwDataToPlay = 0;
                FILE *recfile[8];
                char recname[] = "rec0.pcm";

                // preload buffer of stream
                if (wNumOutStreams) {
                        printf("Preload\n");
                        for (f = 0; f < nNumFiles; f++) {
                                if (hOutStream[f]) {
                                        for (i = 0;
                                                i <
                                                ((dwStrBufferSize -
                                                                4) /
                                                        dwDataSizeW); i++) {
                                                //printf("f=%d, i=%d,bs=%d,ds=%d\n",f,i,dwStrBufferSize,DataW.dwDataSize);
                                                // out_stream #1
                                                THPI_WavFileRead(f, abBuffer,
                                                        dwDataSizeW);

                                                err = HPI_OutStreamWriteBuf
                                                        (hSubSys,
                                                        hOutStream[f],
                                                        abBuffer, dwDataSizeW,
                                                        &FormatW);
                                                HandleError(err);

                                                err = HPI_OutStreamGetInfoEx
                                                        (hSubSys,
                                                        hOutStream[f],
                                                        &wState, NULL,
                                                        &dwDataToPlay, NULL,
                                                        NULL);
                                                HandleError(err);

                                                printf("[%i] D=%03d S=%d   \r", f, dwDataToPlay / 1000, wState);

                                        }
                                        printf("\n");
                                }
                        }

                        // start play back

                        printf("********************************************************************\n");
                        printf("HPI_OutStreamStart ");
                        for (f = 0; f < nNumFiles; f++) {
                                if (hOutStream[f]) {

                                        err = HPI_OutStreamStart(hSubSys,
                                                hOutStream[f]
                                                );
                                        HandleError(err);
                                        printf("%i ", f);
                                }
                        }
                        printf("\n");
                }
                for (f = 0; f < wNumInStreams; f++) {
                        printf("%d: ", f);

                        if (instream_bbm) {
                                printf("HPI_InStreamHostBufferAllocate ");
                                err = HPI_InStreamHostBufferAllocate(hSubSys,
                                        hInStream[f], BLOCK_SIZE);
                                if (err == HPI_ERROR_INVALID_FUNC)
                                        instream_bbm = 0;
                                else
                                        HandleError(err);
                        }

                        printf("HPI_InStreamSetFormat ");
                        err = HPI_InStreamSetFormat(hSubSys,
                                hInStream[f], &FormatR);
                        HandleError(err);

                        printf("HPI_InStreamReset ");
                        err = HPI_InStreamReset(hSubSys, hInStream[f]);
                        HandleError(err);

                        printf("HPI_InStreamStart \n");
                        err = HPI_InStreamStart(hSubSys, hInStream[f]);
                        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");
                                }
                        }
                }

                // monitor state of streams and stop when empty

                // don't run anything if there are no in streams or out streams
                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++) {
                                //get state of in stream
                                err = HPI_InStreamGetInfoEx(hSubSys,
                                        hInStream[f],
                                        &wState,
                                        NULL, &dwDataToPlay, NULL, NULL);
                                HandleError(err);

                                if (do_print)
                                        printf("%03d %d ",
                                                dwDataToPlay / 1000, wState);

                                if (dwDataToPlay >= dwDataSizeR) {
                                        dwDataToPlay = dwDataSizeR;

                                        err = HPI_InStreamReadBuf(hSubSys,
                                                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]) {
                                        //get state of stream
                                        err = HPI_OutStreamGetInfoEx(hSubSys,
                                                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);
                                                err = HPI_OutStreamWriteBuf
                                                        (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]) {
                                err = HPI_OutStreamStop(hSubSys,
                                        hOutStream[f]);
                                printf("%i ", f);
                                HandleError(err);
                        }
                }

                printf("\nHPI_OutStreamClose ");
                for (f = 0; f < wNumOutStreams; f++) {
                        if (hOutStream[f]) {
                                if (outstream_bbm)
                                        err = HPI_OutStreamHostBufferFree
                                                (hSubSys, hOutStream[f]);

                                err = HPI_OutStreamClose(hSubSys,
                                        hOutStream[f]);
                                printf("%i ", f);
                                HandleError(err);
                        }
                }
        }

        if (wNumInStreams) {
                printf("\nHPI_InStreamStop \n");
                err = HPI_InStreamStop(hSubSys, hInStream[0]);
                HandleError(err);

                printf("\nHPI_InStreamClose ");
                for (f = 0; f < wNumInStreams; f++) {
                        if (instream_bbm)
                                err = HPI_InStreamHostBufferFree(hSubSys,
                                        hInStream[f]);

                        err = HPI_InStreamClose(hSubSys, hInStream[f]);
                        printf("%i ", f);
                        HandleError(err);
                }
        }
#endif // HPI_BUILD_NO_STREAMS

        err = HPI_MixerClose(hSubSys, hMixer);
        printf("\nHPI_MixerClose\n");
        HandleError(err);

        err = HPI_AdapterClose(hSubSys, wAdapterIndex);
        printf("HPI_AdapterClose\n");
        HandleError(err);

        HPI_SubSysFree(hSubSys);

        return 0;
}

/******************************THPI_WavFileOpen **********************/
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);   //.DSS file
                else
                        fseek(gpFile[nIndex], 0x50, SEEK_SET);  //.WAV file
        }
}

/******************************THPI_WavFileRead **********************/
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]);   //read WAV file
                if (lNumRead != lLength)
                        return (1);
                else
                        return (0);
        } else {
                // setup sinewave in buffer
                for (i = 0; i < lLength / 4; i++) {
                        wSine = (uint16_t)(32767 * sin(2 * 3.141592653 * i / 32));
                        pbData[(short)i * 4] = (uint8_t)wSine;  //left LSB
                        pbData[(short)i * 4 + 1] = (uint8_t)(wSine >> 8);       //left MSB
                        pbData[(short)i * 4 + 2] = (uint8_t)wSine;      //right LSB
                        pbData[(short)i * 4 + 3] = (uint8_t)(wSine >> 8);       //right MSB
                }
                return (0);
        }
}

/******************************THPI_WavFileClose **********************/
static void THPI_WavFileClose(short nIndex)
{
        if (haveFiles)
                fclose(gpFile[nIndex]);
}

/****************************** HandleError **********************/
static void HandleError(hpi_err_t err)
{
        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();
}

/* END_OF_CODE */