2018-03-17 Fred Gleason <fredg@paravelsystems.com>

* Added support for DMA bus-mastering to the HPI driver.
This commit is contained in:
Fred Gleason
2018-03-17 16:55:49 -04:00
parent d4e8112bf0
commit 25e9d6fb28
7 changed files with 329 additions and 223 deletions

View File

@@ -2,7 +2,7 @@
//
// A class for playing Microsoft WAV files.
//
// (C) Copyright 2002-2007,2016 Fred Gleason <fredg@paravelsystems.com>
// (C) Copyright 2002-2007,2016-2018 Fred Gleason <fredg@paravelsystems.com>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
@@ -66,7 +66,10 @@ RDHPIPlayStream::RDHPIPlayStream(RDHPISoundCard *card,QWidget *parent)
// hpi_err_t hpi_err;
int quan;
uint16_t type[HPI_MAX_ADAPTERS];
struct hpi_format fmt;
uint32_t dma_size=0;
dma_buffer_size=0;
sound_card=card;
card_number=-1;
stream_number=-1;
@@ -94,16 +97,28 @@ RDHPIPlayStream::RDHPIPlayStream(RDHPISoundCard *card,QWidget *parent)
card_index[i]=i;
}
#else
LogHpi(HPI_SubSysGetNumAdapters(NULL,&quan));
LogHpi(HPI_SubSysGetNumAdapters(NULL,&quan),__LINE__);
for(int i=0;i<quan;i++) {
LogHpi(HPI_SubSysGetAdapter(NULL,i,card_index+i,type+i));
LogHpi(HPI_SubSysGetAdapter(NULL,i,card_index+i,type+i),__LINE__);
}
#endif // HPI_VER
clock=new QTimer(this,"clock");
//
// Calculate DMA Buffer Size
//
memset(&fmt,0,sizeof(fmt)); // Worst case situation
fmt.dwSampleRate=48000;
fmt.wChannels=2;
fmt.wFormat=HPI_FORMAT_PCM32_FLOAT;
if(LogHpi(HPI_StreamEstimateBufferSize(&fmt,FRAGMENT_TIME,&dma_size),
__LINE__)==0) {
dma_buffer_size=dma_size;
}
clock=new QTimer(this);
connect(clock,SIGNAL(timeout()),this,SLOT(tickClock()));
play_timer=new QTimer(this,"play_timer");
play_timer=new QTimer(this);
connect(play_timer,SIGNAL(timeout()),this,SLOT(pause()));
}
@@ -171,7 +186,9 @@ bool RDHPIPlayStream::formatSupported(RDWaveFile::Format format)
}
if(!is_open) {
for(int i=0;i<sound_card->getCardOutputStreams(card_number);i++) {
if(HPI_OutStreamOpen(NULL,card_index[card_number],i,&hostream)==0) {
if(LogHpi(HPI_OutStreamOpen(NULL,card_index[card_number],i,&hostream),
__LINE__)==0) {
syslog(LOG_NOTICE,"buffer_size: %u\n",dma_buffer_size);
found=true;
break;
}
@@ -179,6 +196,11 @@ bool RDHPIPlayStream::formatSupported(RDWaveFile::Format format)
if(!found) {
return false;
}
if(LogHpi(HPI_OutStreamHostBufferAllocate(NULL,hostream,dma_buffer_size),
__LINE__)!=0) {
LogHpi(HPI_OutStreamClose(NULL,hostream),__LINE__);
return false;
}
}
else {
hostream=hpi_stream;
@@ -187,36 +209,46 @@ bool RDHPIPlayStream::formatSupported(RDWaveFile::Format format)
case RDWaveFile::Pcm16:
LogHpi(HPI_FormatCreate(&hpi_format,getChannels(),
HPI_FORMAT_PCM16_SIGNED,
getSamplesPerSec(),getHeadBitRate(),0));
state=HPI_OutStreamQueryFormat(NULL,hostream,&hpi_format);
getSamplesPerSec(),getHeadBitRate(),0),
__LINE__);
state=LogHpi(HPI_OutStreamQueryFormat(NULL,hostream,&hpi_format),
__LINE__);
break;
case RDWaveFile::Pcm24:
LogHpi(HPI_FormatCreate(&hpi_format,getChannels(),
HPI_FORMAT_PCM24_SIGNED,
getSamplesPerSec(),getHeadBitRate(),0));
state=HPI_OutStreamQueryFormat(NULL,hostream,&hpi_format);
getSamplesPerSec(),getHeadBitRate(),0),
__LINE__);
state=LogHpi(HPI_OutStreamQueryFormat(NULL,hostream,&hpi_format),
__LINE__);
break;
case RDWaveFile::MpegL1:
LogHpi(HPI_FormatCreate(&hpi_format,getChannels(),
HPI_FORMAT_MPEG_L1,
getSamplesPerSec(),getHeadBitRate(),0));
state=HPI_OutStreamQueryFormat(NULL,hostream,&hpi_format);
getSamplesPerSec(),getHeadBitRate(),0),
__LINE__);
state=LogHpi(HPI_OutStreamQueryFormat(NULL,hostream,&hpi_format),
__LINE__);
break;
case RDWaveFile::MpegL2:
LogHpi(HPI_FormatCreate(&hpi_format,getChannels(),
HPI_FORMAT_MPEG_L2,
getSamplesPerSec(),getHeadBitRate(),0));
state=HPI_OutStreamQueryFormat(NULL,hostream,&hpi_format);
getSamplesPerSec(),getHeadBitRate(),0),
__LINE__);
state=LogHpi(HPI_OutStreamQueryFormat(NULL,hostream,&hpi_format),
__LINE__);
break;;
case RDWaveFile::MpegL3:
LogHpi(HPI_FormatCreate(&hpi_format,getChannels(),
HPI_FORMAT_MPEG_L3,
getSamplesPerSec(),getHeadBitRate(),0));
state=HPI_OutStreamQueryFormat(NULL,hostream,&hpi_format);
getSamplesPerSec(),getHeadBitRate(),0),
__LINE__);
state=LogHpi(HPI_OutStreamQueryFormat(NULL,hostream,&hpi_format),
__LINE__);
break;
default:
@@ -224,7 +256,8 @@ bool RDHPIPlayStream::formatSupported(RDWaveFile::Format format)
break;
}
if(!is_open) {
LogHpi(HPI_OutStreamClose(NULL,hostream));
LogHpi(HPI_OutStreamHostBufferFree(NULL,hostream),__LINE__);
LogHpi(HPI_OutStreamClose(NULL,hostream),__LINE__);
}
if(state!=0) {
return false;
@@ -396,10 +429,10 @@ bool RDHPIPlayStream::play()
if((!playing)&&(!is_paused)) {
LogHpi(HPI_OutStreamSetTimeScale(NULL,hpi_stream,
(uint16_t)((RD_TIMESCALE_DIVISOR/(double)play_speed)*
HPI_OSTREAM_TIMESCALE_UNITS)));
if(HPI_OutStreamGetInfoEx(NULL,hpi_stream,
&state,&buffer_size,&data_to_play,
&samples_played,&reserved)!=0) {
HPI_OSTREAM_TIMESCALE_UNITS)),__LINE__);
if(LogHpi(HPI_OutStreamGetInfoEx(NULL,hpi_stream,
&state,&buffer_size,&data_to_play,
&samples_played,&reserved),__LINE__)!=0) {
return false;
}
fragment_size=buffer_size/4;
@@ -420,25 +453,25 @@ bool RDHPIPlayStream::play()
case 8:
LogHpi(HPI_FormatCreate(&format,getChannels(),
HPI_FORMAT_PCM8_UNSIGNED,
getSamplesPerSec(),0,0));
getSamplesPerSec(),0,0),__LINE__);
break;
case 16:
LogHpi(HPI_FormatCreate(&format,getChannels(),
HPI_FORMAT_PCM16_SIGNED,
getSamplesPerSec(),0,0));
getSamplesPerSec(),0,0),__LINE__);
break;
case 24:
LogHpi(HPI_FormatCreate(&format,getChannels(),
HPI_FORMAT_PCM24_SIGNED,
getSamplesPerSec(),0,0));
getSamplesPerSec(),0,0),__LINE__);
break;
case 32:
LogHpi(HPI_FormatCreate(&format,getChannels(),
HPI_FORMAT_PCM32_SIGNED,
getSamplesPerSec(),0,0));
getSamplesPerSec(),0,0),__LINE__);
break;
default:
LogHpi(HPI_AdapterClose(NULL,card_index[card_number]));
LogHpi(HPI_AdapterClose(NULL,card_index[card_number]),__LINE__);
return false;
break;
}
@@ -448,20 +481,23 @@ bool RDHPIPlayStream::play()
case 1:
LogHpi(HPI_FormatCreate(&format,getChannels(),
HPI_FORMAT_MPEG_L1,getSamplesPerSec(),
getHeadBitRate(),getHeadFlags()));
getHeadBitRate(),getHeadFlags()),
__LINE__);
break;
case 2:
LogHpi(HPI_FormatCreate(&format,getChannels(),
HPI_FORMAT_MPEG_L2,getSamplesPerSec(),
getHeadBitRate(),getHeadFlags()));
getHeadBitRate(),getHeadFlags()),
__LINE__);
break;
case 3:
LogHpi(HPI_FormatCreate(&format,getChannels(),
HPI_FORMAT_MPEG_L3,getSamplesPerSec(),
getHeadBitRate(),getHeadFlags()));
getHeadBitRate(),getHeadFlags()),
__LINE__);
break;
default:
LogHpi(HPI_AdapterClose(NULL,card_index[card_number]));
LogHpi(HPI_AdapterClose(NULL,card_index[card_number]),__LINE__);
return false;
}
break;
@@ -469,7 +505,8 @@ bool RDHPIPlayStream::play()
return false;
}
#if HPI_VER < 0x00030500
if(HPI_DataCreate(&hpi_data,&format,pdata,fragment_size)!=0) {
if(LogHpi(HPI_DataCreate(&hpi_data,&format,pdata,fragment_size),__LINE__)!=
0) {
return false;
}
#endif
@@ -488,15 +525,15 @@ bool RDHPIPlayStream::play()
}
readWave(pdata,read_bytes);
#if HPI_VER > 0x00030500
LogHpi(HPI_OutStreamWriteBuf(NULL,hpi_stream,pdata,read_bytes,&format));
LogHpi(HPI_OutStreamWriteBuf(NULL,hpi_stream,pdata,read_bytes,&format),
__LINE__);
#else
LogHpi(HPI_DataCreate(&hpi_data,&format,pdata,read_bytes));
LogHpi(HPI_OutStreamWrite(NULL,hpi_stream,&hpi_data));
LogHpi(HPI_DataCreate(&hpi_data,&format,pdata,read_bytes),__LINE__);
LogHpi(HPI_OutStreamWrite(NULL,hpi_stream,&hpi_data),__LINE__);
#endif
if(HPI_OutStreamStart(NULL,hpi_stream)!=0) {
if(LogHpi(HPI_OutStreamStart(NULL,hpi_stream),__LINE__)!=0) {
return false;
}
clock->start(50);
clock->start(FRAGMENT_TIME);
playing=true;
is_paused=false;
@@ -513,7 +550,7 @@ bool RDHPIPlayStream::play()
}
}
if((!playing)&(is_paused|repositioned)) {
LogHpi(HPI_OutStreamStart(NULL,hpi_stream));
LogHpi(HPI_OutStreamStart(NULL,hpi_stream),__LINE__);
clock->start(FRAGMENT_TIME);
playing=true;
stopping=false;
@@ -543,10 +580,11 @@ void RDHPIPlayStream::pause()
return;
}
if(playing) {
LogHpi(HPI_OutStreamStop(NULL,hpi_stream));
LogHpi(HPI_OutStreamStop(NULL,hpi_stream),__LINE__);
clock->stop();
LogHpi(HPI_OutStreamGetInfoEx(NULL,hpi_stream,&state,&buffer_size,
&data_to_play,&samples_played,&reserved));
&data_to_play,&samples_played,&reserved),
__LINE__);
switch(getFormatTag()) {
case WAVE_FORMAT_PCM:
samples_pending=data_to_play/(getChannels()*getBitsPerSample()/8);
@@ -580,12 +618,12 @@ void RDHPIPlayStream::stop()
return;
}
if(playing|is_paused) {
LogHpi(HPI_OutStreamStop(NULL,hpi_stream));
LogHpi(HPI_OutStreamStop(NULL,hpi_stream),__LINE__);
clock->stop();
playing=false;
is_paused=false;
seekWave(0,SEEK_SET);
LogHpi(HPI_OutStreamReset(NULL,hpi_stream));
LogHpi(HPI_OutStreamReset(NULL,hpi_stream),__LINE__);
samples_pending=0;
samples_skipped=0;
stream_state=RDHPIPlayStream::Stopped;
@@ -632,7 +670,7 @@ bool RDHPIPlayStream::setPosition(unsigned samples)
is_paused=false;
repositioned=true;
}
LogHpi(HPI_OutStreamReset(NULL,hpi_stream));
LogHpi(HPI_OutStreamReset(NULL,hpi_stream),__LINE__);
samples_played=0;
switch(getFormatTag()) {
case WAVE_FORMAT_PCM:
@@ -686,24 +724,25 @@ void RDHPIPlayStream::tickClock()
char hpi_text[100];
int n;
hpi_err=HPI_OutStreamGetInfoEx(NULL,hpi_stream,
&state,&buffer_size,&data_to_play,
&samples_played,&reserved);
hpi_err=LogHpi(HPI_OutStreamGetInfoEx(NULL,hpi_stream,
&state,&buffer_size,&data_to_play,
&samples_played,&reserved),__LINE__);
if(!stopping) {
while((buffer_size-data_to_play)>=fragment_size) {
n=readWave(pdata,fragment_size);
if((n<=0)||(((uint32_t)n)<fragment_size)) {
// End of file
#if HPI_VER > 0x00030500
if((hpi_err=HPI_OutStreamWriteBuf(NULL,hpi_stream,
pdata,n,&format))!=0) {
if((hpi_err=LogHpi(HPI_OutStreamWriteBuf(NULL,hpi_stream,
pdata,n,&format),__LINE__))!=
0) {
HPI_GetErrorText(hpi_err,hpi_text);
fprintf(stderr,"*** HPI Error: %s ***\n",hpi_text);
}
#else
HPI_DataCreate(&hpi_data,&format,pdata,n);
if((hpi_err=HPI_OutStreamWrite(NULL,hpi_stream,
&hpi_data))!=0) {
if((hpi_err=LogHpi(HPI_OutStreamWrite(NULL,hpi_stream,
&hpi_data),__LINE__))!=0) {
HPI_GetErrorText(hpi_err,hpi_text);
fprintf(stderr,"*** HPI Error: %s ***\n",hpi_text);
}
@@ -714,26 +753,28 @@ void RDHPIPlayStream::tickClock()
}
left_to_write-=n;
#if HPI_VER > 0x00030500
hpi_err=HPI_OutStreamWriteBuf(NULL,hpi_stream,
pdata,n,&format);
hpi_err=LogHpi(HPI_OutStreamWriteBuf(NULL,hpi_stream,pdata,n,&format),
__LINE__);
#else
hpi_err=HPI_DataCreate(&hpi_data,&format,pdata,n);
hpi_err=HPI_OutStreamWrite(NULL,hpi_stream,&hpi_data);
hpi_err=LogHpi(HPI_DataCreate(&hpi_data,&format,pdata,n),__LINE__);
hpi_err=LogHpi(HPI_OutStreamWrite(NULL,hpi_stream,&hpi_data),__LINE__);
#endif
hpi_err=HPI_OutStreamGetInfoEx(NULL,hpi_stream,
&state,&buffer_size,&data_to_play,
&samples_played,&reserved);
hpi_err=LogHpi(HPI_OutStreamGetInfoEx(NULL,hpi_stream,
&state,&buffer_size,&data_to_play,
&samples_played,&reserved),
__LINE__);
}
}
else {
if(state==HPI_STATE_DRAINED) {
hpi_err=HPI_OutStreamStop(NULL,hpi_stream);
hpi_err=HPI_OutStreamClose(NULL,hpi_stream);
hpi_err=HPI_AdapterClose(NULL,card_index[card_number]);
LogHpi(HPI_OutStreamStop(NULL,hpi_stream),__LINE__);
LogHpi(HPI_OutStreamHostBufferFree(NULL,hpi_stream),__LINE__);
LogHpi(HPI_OutStreamClose(NULL,hpi_stream),__LINE__);
hpi_err=LogHpi(HPI_AdapterClose(NULL,card_index[card_number]),__LINE__);
clock->stop();
playing=false;
seekWave(0,SEEK_SET);
hpi_err=HPI_OutStreamReset(NULL,hpi_stream);
hpi_err=LogHpi(HPI_OutStreamReset(NULL,hpi_stream),__LINE__);
samples_pending=0;
samples_skipped=0;
stream_state=RDHPIPlayStream::Stopped;
@@ -761,7 +802,10 @@ int RDHPIPlayStream::GetStream()
#ifdef RDHPIPLAYSTREAM_USE_LOCAL_MUTEX
for(int i=0;i<sound_card->getCardOutputStreams(card_number);i++) {
if(++stream_mutex[card_number][i]==1) {
LogHpi(HPI_OutStreamOpen(NULL,card_index[card_number],i,&hpi_stream));
LogHpi(HPI_OutStreamOpen(NULL,card_index[card_number],i,&hpi_stream),
__LINE__);
LogHpi(HPI_OutStreamHostBufferAllocate(NULL,hpi_stream,dma_buffer_size),
__LINE__);
stream_number=i;
return stream_number;
}
@@ -772,7 +816,8 @@ int RDHPIPlayStream::GetStream()
return -1;
#else
for(int i=0;i<sound_card->getCardOutputStreams(card_number);i++) {
if(HPI_OutStreamOpen(NULL,card_index[card_number],i,&hpi_stream)==0) {
if(LogHpi(HPI_OutStreamOpen(NULL,card_index[card_number],i,&hpi_stream),
__LINE__)==0) {
stream_number=i;
// syslog(LOG_ERR,"HPI allocating ostream: %d",stream_number);
return stream_number;
@@ -787,23 +832,25 @@ void RDHPIPlayStream::FreeStream()
{
#ifdef RDHPIPLAYSTREAM_USE_LOCAL_MUTEX
stream_mutex[card_number][stream_number]--;
LogHpi(HPI_OutStreamClose(NULL,hpi_stream));
LogHpi(HPI_OutStreamHostBufferFree(NULL,hpi_stream),__LINE__);
LogHpi(HPI_OutStreamClose(NULL,hpi_stream),__LINE__);
stream_number=-1;
#else
LogHpi(HPI_OutStreamClose(NULL,hpi_stream));
LogHpi(HPI_OutStreamHostBufferFree(NULL,hpi_stream),__LINE__);
LogHpi(HPI_OutStreamClose(NULL,hpi_stream),__LINE__);
// syslog(LOG_ERR,"HPI closing ostream: %d",stream_number);
stream_number=-1;
#endif
}
hpi_err_t RDHPIPlayStream::LogHpi(hpi_err_t err)
hpi_err_t RDHPIPlayStream::LogHpi(hpi_err_t err,int lineno)
{
char err_txt[200];
if(err!=0) {
HPI_GetErrorText(err,err_txt);
syslog(LOG_NOTICE,"HPI Error: %s",err_txt);
syslog(LOG_NOTICE,"HPI Error: %s, %s line %d",err_txt,__FILE__,lineno);
}
return err;
}