2024-12-01 19:35:24 +00:00
|
|
|
//| Copyright: (C) 2020-2024 Kevin Larke <contact AT larke DOT org>
|
|
|
|
//| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file.
|
2019-12-26 02:44:14 +00:00
|
|
|
#include "cwCommon.h"
|
|
|
|
#include "cwLog.h"
|
|
|
|
#include "cwCommonImpl.h"
|
2024-05-29 16:36:57 +00:00
|
|
|
#include "cwTest.h"
|
2019-12-26 02:44:14 +00:00
|
|
|
#include "cwMem.h"
|
|
|
|
#include "cwTime.h"
|
|
|
|
#include "cwAudioDevice.h"
|
|
|
|
#include "cwText.h"
|
|
|
|
|
|
|
|
namespace cw
|
|
|
|
{
|
|
|
|
namespace audio
|
|
|
|
{
|
|
|
|
namespace device
|
|
|
|
{
|
|
|
|
typedef struct drv_str
|
|
|
|
{
|
|
|
|
unsigned begIdx;
|
|
|
|
unsigned endIdx;
|
|
|
|
driver_t* drv;
|
|
|
|
struct drv_str* link;
|
|
|
|
} drv_t;
|
|
|
|
|
|
|
|
typedef struct device_str
|
|
|
|
{
|
|
|
|
drv_t* drvList = nullptr;
|
|
|
|
unsigned nextDrvIdx = 0;
|
|
|
|
} device_t;
|
|
|
|
|
|
|
|
inline device_t* _handleToPtr( handle_t h ){ return handleToPtr<handle_t,device_t>(h); }
|
|
|
|
|
|
|
|
cw::rc_t _destroy( device_t* p )
|
|
|
|
{
|
|
|
|
drv_t* d = p->drvList;
|
|
|
|
while( d != nullptr )
|
|
|
|
{
|
|
|
|
drv_t* d0 = d->link;
|
2019-12-28 02:51:28 +00:00
|
|
|
mem::release(d);
|
2019-12-26 02:44:14 +00:00
|
|
|
d = d0;
|
|
|
|
}
|
|
|
|
|
2019-12-28 02:51:28 +00:00
|
|
|
mem::release(p);
|
2019-12-26 02:44:14 +00:00
|
|
|
|
|
|
|
return kOkRC;
|
|
|
|
}
|
|
|
|
|
|
|
|
drv_t* _indexToDriver( device_t* p, unsigned idx )
|
|
|
|
{
|
|
|
|
drv_t* l = p->drvList;
|
|
|
|
for(; l != nullptr; l=l->link )
|
|
|
|
if( l->begIdx <= idx && idx <= l->endIdx )
|
|
|
|
return l;
|
|
|
|
|
|
|
|
cwLogError(kInvalidArgRC,"An invalid audio device index (%) was requested.",idx);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
drv_t* _indexToDriver( handle_t h, unsigned idx )
|
|
|
|
{
|
|
|
|
device_t* p = _handleToPtr(h);
|
|
|
|
return _indexToDriver(p,idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cw::rc_t cw::audio::device::create( handle_t& hRef )
|
|
|
|
{
|
|
|
|
rc_t rc;
|
|
|
|
if((rc = destroy(hRef)) != kOkRC)
|
|
|
|
return rc;
|
|
|
|
|
2019-12-28 02:51:28 +00:00
|
|
|
device_t* p = mem::allocZ<device_t>();
|
2019-12-26 02:44:14 +00:00
|
|
|
hRef.set(p);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
cw::rc_t cw::audio::device::destroy( handle_t& hRef )
|
|
|
|
{
|
|
|
|
rc_t rc = kOkRC;
|
|
|
|
if( !hRef.isValid() )
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
device_t* p = _handleToPtr(hRef);
|
|
|
|
|
|
|
|
if((rc = _destroy(p)) != kOkRC )
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
hRef.clear();
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
cw::rc_t cw::audio::device::registerDriver( handle_t h, driver_t* drv )
|
|
|
|
{
|
|
|
|
device_t* p = _handleToPtr(h);
|
|
|
|
|
|
|
|
unsigned n = drv->deviceCount( drv );
|
|
|
|
if( n > 0 )
|
|
|
|
{
|
2019-12-28 02:51:28 +00:00
|
|
|
drv_t* d = mem::allocZ<drv_t>();
|
2019-12-26 02:44:14 +00:00
|
|
|
|
|
|
|
d->begIdx = p->nextDrvIdx;
|
|
|
|
p->nextDrvIdx += n;
|
|
|
|
d->endIdx = p->nextDrvIdx-1;
|
|
|
|
d->drv = drv;
|
|
|
|
d->link = p->drvList;
|
|
|
|
p->drvList = d;
|
|
|
|
}
|
|
|
|
|
|
|
|
return kOkRC;
|
|
|
|
}
|
|
|
|
|
2020-03-23 14:41:28 +00:00
|
|
|
unsigned cw::audio::device::count( handle_t h )
|
2019-12-26 02:44:14 +00:00
|
|
|
{
|
|
|
|
device_t* p = _handleToPtr(h);
|
|
|
|
return p->nextDrvIdx;
|
|
|
|
}
|
|
|
|
|
2020-03-23 14:41:28 +00:00
|
|
|
unsigned cw::audio::device::labelToIndex( handle_t h, const char* label )
|
2019-12-26 02:44:14 +00:00
|
|
|
{
|
2020-03-23 14:41:28 +00:00
|
|
|
unsigned n = count(h);
|
2019-12-26 02:44:14 +00:00
|
|
|
unsigned i;
|
|
|
|
for(i=0; i<n; ++i)
|
|
|
|
{
|
2020-03-23 14:41:28 +00:00
|
|
|
const char* s = device::label(h,i);
|
2019-12-26 02:44:14 +00:00
|
|
|
if( textCompare(s,label)==0)
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
return kInvalidIdx;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-03-23 14:41:28 +00:00
|
|
|
const char* cw::audio::device::label( handle_t h, unsigned devIdx )
|
2019-12-26 02:44:14 +00:00
|
|
|
{
|
|
|
|
drv_t* d;
|
|
|
|
if((d = _indexToDriver(h,devIdx)) != nullptr )
|
|
|
|
return d->drv->deviceLabel( d->drv, devIdx - d->begIdx );
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2020-03-23 14:41:28 +00:00
|
|
|
unsigned cw::audio::device::channelCount( handle_t h, unsigned devIdx, bool inputFl )
|
2019-12-26 02:44:14 +00:00
|
|
|
{
|
|
|
|
drv_t* d;
|
|
|
|
if((d = _indexToDriver(h,devIdx)) != nullptr )
|
|
|
|
return d->drv->deviceChannelCount( d->drv, devIdx - d->begIdx, inputFl );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-03-23 14:41:28 +00:00
|
|
|
double cw::audio::device::sampleRate( handle_t h, unsigned devIdx )
|
2019-12-26 02:44:14 +00:00
|
|
|
{
|
|
|
|
drv_t* d;
|
|
|
|
if((d = _indexToDriver(h,devIdx)) != nullptr )
|
|
|
|
return d->drv->deviceSampleRate( d->drv, devIdx - d->begIdx );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-03-23 14:41:28 +00:00
|
|
|
unsigned cw::audio::device::framesPerCycle( handle_t h, unsigned devIdx, bool inputFl )
|
2019-12-26 02:44:14 +00:00
|
|
|
{
|
|
|
|
drv_t* d;
|
|
|
|
if((d = _indexToDriver(h,devIdx)) != nullptr )
|
|
|
|
return d->drv->deviceFramesPerCycle( d->drv, devIdx - d->begIdx, inputFl );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-03-23 14:41:28 +00:00
|
|
|
cw::rc_t cw::audio::device::setup( handle_t h, unsigned devIdx, double sr, unsigned frmPerCycle, cbFunc_t cb, void* cbData )
|
2019-12-26 02:44:14 +00:00
|
|
|
{
|
|
|
|
drv_t* d;
|
|
|
|
if((d = _indexToDriver(h,devIdx)) != nullptr )
|
2023-02-15 01:46:41 +00:00
|
|
|
return d->drv->deviceSetup( d->drv, devIdx - d->begIdx, sr, frmPerCycle, cb, cbData, devIdx );
|
2019-12-26 02:44:14 +00:00
|
|
|
return kInvalidArgRC;
|
|
|
|
}
|
|
|
|
|
2020-03-23 14:41:28 +00:00
|
|
|
cw::rc_t cw::audio::device::start( handle_t h, unsigned devIdx )
|
2019-12-26 02:44:14 +00:00
|
|
|
{
|
|
|
|
drv_t* d;
|
|
|
|
if((d = _indexToDriver(h,devIdx)) != nullptr )
|
|
|
|
return d->drv->deviceStart( d->drv, devIdx - d->begIdx );
|
|
|
|
return kInvalidArgRC;
|
|
|
|
}
|
|
|
|
|
2020-03-23 14:41:28 +00:00
|
|
|
cw::rc_t cw::audio::device::stop( handle_t h, unsigned devIdx )
|
2019-12-26 02:44:14 +00:00
|
|
|
{
|
|
|
|
drv_t* d;
|
|
|
|
if((d = _indexToDriver(h,devIdx)) != nullptr )
|
|
|
|
return d->drv->deviceStop( d->drv, devIdx - d->begIdx );
|
|
|
|
return kInvalidArgRC;
|
|
|
|
}
|
|
|
|
|
2020-03-23 14:41:28 +00:00
|
|
|
bool cw::audio::device::isStarted(handle_t h, unsigned devIdx )
|
2019-12-26 02:44:14 +00:00
|
|
|
{
|
|
|
|
drv_t* d;
|
|
|
|
if((d = _indexToDriver(h,devIdx)) != nullptr )
|
|
|
|
return d->drv->deviceIsStarted( d->drv, devIdx - d->begIdx );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-02-19 19:16:37 +00:00
|
|
|
|
|
|
|
cw::rc_t cw::audio::device::execute( handle_t h, unsigned devIdx )
|
2019-12-26 02:44:14 +00:00
|
|
|
{
|
2023-02-19 19:16:37 +00:00
|
|
|
rc_t rc = kOkRC;
|
2019-12-26 02:44:14 +00:00
|
|
|
drv_t* d;
|
2023-02-19 19:16:37 +00:00
|
|
|
if((d = _indexToDriver(h,devIdx)) == nullptr )
|
|
|
|
rc = kInvalidArgRC;
|
|
|
|
else
|
|
|
|
rc = d->drv->deviceExecute( d->drv, devIdx - d->begIdx );
|
|
|
|
|
|
|
|
return rc;
|
2019-12-26 02:44:14 +00:00
|
|
|
}
|
|
|
|
|
2023-02-19 19:16:37 +00:00
|
|
|
cw::rc_t cw::audio::device::enable( handle_t h, unsigned devIdx, bool inputFl, bool enableFl )
|
2023-02-15 01:46:41 +00:00
|
|
|
{
|
|
|
|
rc_t rc = kOkRC;
|
|
|
|
drv_t* d;
|
2023-02-19 19:16:37 +00:00
|
|
|
if((d = _indexToDriver(h,devIdx)) == nullptr )
|
|
|
|
rc = kInvalidArgRC;
|
|
|
|
else
|
|
|
|
rc = d->drv->deviceEnable( d->drv, devIdx - d->begIdx, inputFl, enableFl );
|
2023-02-15 01:46:41 +00:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2023-02-19 19:16:37 +00:00
|
|
|
cw::rc_t cw::audio::device::seek( handle_t h, unsigned devIdx, bool inputFl, unsigned frameOffset )
|
|
|
|
{
|
|
|
|
rc_t rc = kOkRC;
|
|
|
|
drv_t* d;
|
|
|
|
if((d = _indexToDriver(h,devIdx)) == nullptr )
|
|
|
|
rc = kInvalidArgRC;
|
|
|
|
else
|
|
|
|
rc = d->drv->deviceSeek( d->drv, devIdx - d->begIdx, inputFl, frameOffset );
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
void cw::audio::device::realTimeReport( handle_t h, unsigned devIdx )
|
|
|
|
{
|
|
|
|
drv_t* d;
|
|
|
|
if((d = _indexToDriver(h,devIdx)) != nullptr )
|
|
|
|
d->drv->deviceRealTimeReport( d->drv, devIdx - d->begIdx );
|
|
|
|
}
|
2023-02-15 01:46:41 +00:00
|
|
|
|
2019-12-26 02:44:14 +00:00
|
|
|
void cw::audio::device::report( handle_t h )
|
|
|
|
{
|
2020-03-23 14:41:28 +00:00
|
|
|
for(unsigned i=0; i<count(h); ++i)
|
2019-12-26 02:44:14 +00:00
|
|
|
{
|
|
|
|
cwLogInfo( "%8.1f in:%i (%i) out:%i (%i) %s",
|
2020-03-23 14:41:28 +00:00
|
|
|
sampleRate(h,i),
|
|
|
|
channelCount(h,i,true), framesPerCycle(h,i,true),
|
|
|
|
channelCount(h,i,false), framesPerCycle(h,i,false),
|
|
|
|
label(h,i));
|
2019-12-26 02:44:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2023-02-15 01:46:41 +00:00
|
|
|
|
|
|
|
void cw::audio::device::realTimeReport( handle_t h )
|
|
|
|
{
|
|
|
|
for(unsigned i=0; i<count(h); ++i)
|
|
|
|
{
|
|
|
|
realTimeReport(h,i);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|