2021-08-18 Fred Gleason <fredg@paravelsystems.com>

* Refactored the ALSA driver in caed(8) to use virtual inheritance.

Signed-off-by: Fred Gleason <fredg@paravelsystems.com>
This commit is contained in:
Fred Gleason
2021-08-18 17:01:04 -04:00
parent 6ed4643fc1
commit 8888e4cc82
10 changed files with 753 additions and 840 deletions

View File

@@ -22308,3 +22308,5 @@
* Refactored the HPI driver in caed(8) to use virtual inheritance.
* Disabled JACK driver support in caed(8).
* Disabled ALSA driver support in caed(8).
2021-08-18 Fred Gleason <fredg@paravelsystems.com>
* Refactored the ALSA driver in caed(8) to use virtual inheritance.

View File

@@ -29,16 +29,16 @@ moc_%.cpp: %.h
sbin_PROGRAMS = caed
dist_caed_SOURCES = cae.cpp cae.h\
cae_alsa.cpp\
cae_hpi.cpp\
dist_caed_SOURCES = alsadriver.cpp alsadriver.h\
cae.cpp cae.h\
cae_jack.cpp\
cae_server.cpp cae_server.h\
caedriver.cpp caedriver.h\
caedriverfactory.cpp caedriverfactory.h\
hpidriver.cpp hpidriver.h
nodist_caed_SOURCES = moc_cae.cpp\
nodist_caed_SOURCES = moc_alsadriver.cpp\
moc_cae.cpp\
moc_cae_server.cpp\
moc_caedriver.cpp\
moc_hpidriver.cpp

View File

@@ -1,8 +1,8 @@
// cae_alsa.cpp
// alsadriver.cpp
//
// The ALSA Driver for the Core Audio Engine component of Rivendell
// caed(8) driver for Advanced Linux Audio Architecture devices
//
// (C) Copyright 2002-2021 Fred Gleason <fredg@paravelsystems.com>
// (C) Copyright 2021 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
@@ -18,20 +18,13 @@
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include <math.h>
#include <signal.h>
#include <samplerate.h>
#include <qsignalmapper.h>
#include <rd.h>
#include <rdapplication.h>
#include <rdconf.h>
#include <rdmeteraverage.h>
#include <rdringbuffer.h>
#include <cae.h>
#include "alsadriver.h"
#ifdef ALSA
//
@@ -533,10 +526,10 @@ void *AlsaPlayCallback(void *ptr)
}
void MainObject::AlsaInitCallback()
void AlsaDriver::AlsaInitCallback()
{
int avg_periods=
(330*system_sample_rate)/(1000*rda->config()->alsaPeriodSize());
(330*systemSampleRate())/(1000*rda->config()->alsaPeriodSize());
for(int i=0;i<RD_MAX_CARDS;i++) {
for(int j=0;j<RD_MAX_PORTS;j++) {
alsa_recording[i][j]=false;
@@ -569,69 +562,10 @@ void MainObject::AlsaInitCallback()
#endif // ALSA
void MainObject::alsaStopTimerData(int cardstream)
AlsaDriver::AlsaDriver(QObject *parent)
: CaeDriver(RDStation::Alsa,parent)
{
#ifdef ALSA
int card=cardstream/RD_MAX_STREAMS;
int stream=cardstream-card*RD_MAX_STREAMS;
alsaStopPlayback(card,stream);
statePlayUpdate(card,stream,2);
#endif // ALSA
}
void MainObject::alsaFadeTimerData(int cardstream)
{
#ifdef ALSA
int card=cardstream/RD_MAX_STREAMS;
int stream=cardstream-card*RD_MAX_STREAMS;
int16_t level;
if(alsa_fade_up[card][stream]) {
level=alsa_output_volume_db[card][alsa_fade_port[card][stream]][stream]+
alsa_fade_increment[card][stream];
if(level>=alsa_fade_volume_db[card][stream]) {
level=alsa_fade_volume_db[card][stream];
alsa_fade_timer[card][stream]->stop();
}
}
else {
level=alsa_output_volume_db[card][alsa_fade_port[card][stream]][stream]-
alsa_fade_increment[card][stream];
if(level<=alsa_fade_volume_db[card][stream]) {
level=alsa_fade_volume_db[card][stream];
alsa_fade_timer[card][stream]->stop();
}
}
rda->syslog(LOG_DEBUG,"FadeLevel: %d",level);
alsaSetOutputVolume(card,stream,alsa_fade_port[card][stream],level);
#endif // ALSA
}
void MainObject::alsaRecordTimerData(int cardport)
{
#ifdef ALSA
int card=cardport/RD_MAX_PORTS;
int stream=cardport-card*RD_MAX_PORTS;
alsaStopRecord(card,stream);
stateRecordUpdate(card,stream,2);
#endif // ALSA
}
void MainObject::alsaInit(RDStation *station)
{
#ifdef ALSA
QString dev;
int card=0;
snd_pcm_t *pcm_play_handle;
snd_pcm_t *pcm_capture_handle;
snd_ctl_t *snd_ctl;
snd_ctl_card_info_t *card_info=NULL;
bool pcm_opened;
//
// Initialize Data Structures
//
@@ -652,18 +586,16 @@ void MainObject::alsaInit(RDStation *station)
}
}
}
// alsa_channels=rd_config->channels();
//
// Stop & Fade Timers
//
QSignalMapper *stop_mapper=new QSignalMapper(this);
connect(stop_mapper,SIGNAL(mapped(int)),this,SLOT(alsaStopTimerData(int)));
connect(stop_mapper,SIGNAL(mapped(int)),this,SLOT(stopTimerData(int)));
QSignalMapper *fade_mapper=new QSignalMapper(this);
connect(fade_mapper,SIGNAL(mapped(int)),this,SLOT(alsaFadeTimerData(int)));
connect(fade_mapper,SIGNAL(mapped(int)),this,SLOT(fadeTimerData(int)));
QSignalMapper *record_mapper=new QSignalMapper(this);
connect(record_mapper,SIGNAL(mapped(int)),
this,SLOT(alsaRecordTimerData(int)));
connect(record_mapper,SIGNAL(mapped(int)),this,SLOT(recordTimerData(int)));
for(int i=0;i<RD_MAX_CARDS;i++) {
for(int j=0;j<RD_MAX_STREAMS;j++) {
alsa_stop_timer[i][j]=new QTimer(this);
@@ -689,89 +621,25 @@ void MainObject::alsaInit(RDStation *station)
AlsaInitCallback();
alsa_wave_buffer=new int16_t[RINGBUFFER_SIZE];
alsa_wave24_buffer=new uint8_t[2*RINGBUFFER_SIZE];
//alsa_resample_buffer=new int16_t[2*RINGBUFFER_SIZE];
//
// Start Up Interfaces
//
for(int i=0;i<RD_MAX_CARDS;i++) {
if(cae_driver[i]==RDStation::None) {
pcm_opened=false;
// These are used to flag bits of card that are not setup
// They are cleared just before the pthreads are created.
alsa_play_format[i].exiting = true;
alsa_capture_format[i].exiting = true;
dev=QString().sprintf("rd%d",card);
if(snd_pcm_open(&pcm_play_handle,dev.toUtf8(),
SND_PCM_STREAM_PLAYBACK,0)==0){
pcm_opened=true;
if(AlsaStartPlayDevice(dev,i,pcm_play_handle)) {
cae_driver[i]=RDStation::Alsa;
}
else {
snd_pcm_close(pcm_play_handle);
}
}
if(snd_pcm_open(&pcm_capture_handle,dev.toUtf8(),
SND_PCM_STREAM_CAPTURE,0)==0) {
pcm_opened=true;
if(AlsaStartCaptureDevice(dev,i,pcm_capture_handle)) {
cae_driver[i]=RDStation::Alsa;
}
else {
snd_pcm_close(pcm_capture_handle);
}
}
if(cae_driver[i]==RDStation::Alsa) {
station->setCardDriver(i,RDStation::Alsa);
if(snd_ctl_open(&snd_ctl,dev.toUtf8(),0)<0) {
rda->syslog(LOG_INFO,
"no control device found for %s",
dev.toUtf8().constData());
station->setCardName(i,tr("ALSA Device")+" "+dev);
}
else {
snd_ctl_card_info_malloc(&card_info);
snd_ctl_card_info(snd_ctl,card_info);
station->
setCardName(i,snd_ctl_card_info_get_longname(card_info));
snd_ctl_close(snd_ctl);
}
station->
setCardInputs(i,
alsa_capture_format[i].channels/RD_DEFAULT_CHANNELS);
station->
setCardOutputs(i,alsa_play_format[i].channels/RD_DEFAULT_CHANNELS);
}
else {
i--;
}
card++;
if(!pcm_opened) {
return;
}
}
}
LoadTwoLame();
LoadMad();
#endif // ALSA
}
void MainObject::alsaFree()
AlsaDriver::~AlsaDriver()
{
#ifdef ALSA
for(int i=0;i<RD_MAX_CARDS;i++) {
if(cae_driver[i]==RDStation::Alsa) {
if(hasCard(i)) {
alsa_play_format[i].exiting=true;
pthread_join(alsa_play_format[i].thread,NULL);
snd_pcm_close(alsa_play_format[i].pcm);
if(alsa_capture_format[i].pcm!=NULL) {
printf("SHUTDOWN 1\n");
alsa_capture_format[i].exiting=true;
printf("SHUTDOWN 2\n");
pthread_join(alsa_capture_format[i].thread,NULL);
printf("SHUTDOWN 3\n");
snd_pcm_close(alsa_capture_format[i].pcm);
printf("SHUTDOWN 4\n");
}
}
}
@@ -779,20 +647,94 @@ void MainObject::alsaFree()
}
bool MainObject::alsaLoadPlayback(int card,QString wavename,int *stream)
QString AlsaDriver::version() const
{
return QString();
}
bool AlsaDriver::initialize(unsigned *next_cardnum)
{
QString dev;
snd_pcm_t *pcm_play_handle;
snd_pcm_t *pcm_capture_handle;
snd_ctl_t *snd_ctl;
snd_ctl_card_info_t *card_info=NULL;
bool pcm_opened;
int card=0;
//
// Start Up Interfaces
//
while((*next_cardnum)<RD_MAX_CARDS) {
pcm_opened=false;
alsa_play_format[*next_cardnum].exiting = true;
alsa_capture_format[*next_cardnum].exiting = true;
dev=QString().sprintf("rd%d",card);
if(snd_pcm_open(&pcm_play_handle,dev.toUtf8(),
SND_PCM_STREAM_PLAYBACK,0)==0){
pcm_opened=true;
if(!AlsaStartPlayDevice(dev,*next_cardnum,pcm_play_handle)) {
snd_pcm_close(pcm_play_handle);
}
}
if(snd_pcm_open(&pcm_capture_handle,dev.toUtf8(),
SND_PCM_STREAM_CAPTURE,0)==0) {
pcm_opened=true;
if(!AlsaStartCaptureDevice(dev,*next_cardnum,pcm_capture_handle)) {
snd_pcm_close(pcm_capture_handle);
}
}
rda->station()->setCardDriver(*next_cardnum,RDStation::Alsa);
if(snd_ctl_open(&snd_ctl,dev.toUtf8(),0)<0) {
rda->syslog(LOG_INFO,
"no control device found for %s",
dev.toUtf8().constData());
rda->station()->setCardName(*next_cardnum,tr("ALSA Device")+" "+dev);
}
else {
snd_ctl_card_info_malloc(&card_info);
snd_ctl_card_info(snd_ctl,card_info);
rda->station()->
setCardName(*next_cardnum,snd_ctl_card_info_get_longname(card_info));
snd_ctl_close(snd_ctl);
}
rda->station()->
setCardInputs(*next_cardnum,
alsa_capture_format[*next_cardnum].
channels/RD_DEFAULT_CHANNELS);
rda->station()->
setCardOutputs(*next_cardnum,
alsa_play_format[*next_cardnum].
channels/RD_DEFAULT_CHANNELS);
card++;
if(!pcm_opened) {
return card>0;
}
addCard(*next_cardnum);
(*next_cardnum)++;
}
return card>0;
}
void AlsaDriver::updateMeters()
{
}
bool AlsaDriver::loadPlayback(int card,QString wavename,int *stream)
{
#ifdef ALSA
if(alsa_play_format[card].exiting||((*stream=GetAlsaOutputStream(card))<0)) {
rda->syslog(LOG_DEBUG,
"alsaLoadPlayback(%s) GetAlsaOutputStream():%d < 0",
(const char *)wavename.toUtf8(),*stream);
rda->syslog(LOG_DEBUG,"alsaLoadPlayback(%s) GetAlsaOutputStream():%d < 0",
wavename.toUtf8().constData(),*stream);
return false;
}
alsa_play_wave[card][*stream]=new RDWaveFile(wavename);
if(!alsa_play_wave[card][*stream]->openWave()) {
rda->syslog(LOG_DEBUG,
"alsaLoadPlayback(%s) openWave() failed to open file",
(const char *)wavename.toUtf8());
rda->syslog(LOG_DEBUG,"alsaLoadPlayback(%s) openWave() failed to open file",
wavename.toUtf8().constData());
delete alsa_play_wave[card][*stream];
alsa_play_wave[card][*stream]=NULL;
FreeAlsaOutputStream(card,*stream);
@@ -805,13 +747,19 @@ bool MainObject::alsaLoadPlayback(int card,QString wavename,int *stream)
break;
case WAVE_FORMAT_MPEG:
InitMadDecoder(card,*stream,alsa_play_wave[card][*stream]);
if(!InitMadDecoder(card,*stream,alsa_play_wave[card][*stream])) {
delete alsa_play_wave[card][*stream];
alsa_play_wave[card][*stream]=NULL;
FreeAlsaOutputStream(card,*stream);
*stream=-1;
return false;
}
break;
default:
rda->syslog(LOG_WARNING,
"alsaLoadPlayback(%s) getFormatTag()%d || getBistsPerSample()%d failed",
(const char *)wavename.toUtf8(),
wavename.toUtf8().constData(),
alsa_play_wave[card][*stream]->getFormatTag(),
alsa_play_wave[card][*stream]->getBitsPerSample());
delete alsa_play_wave[card][*stream];
@@ -835,7 +783,7 @@ bool MainObject::alsaLoadPlayback(int card,QString wavename,int *stream)
}
bool MainObject::alsaUnloadPlayback(int card,int stream)
bool AlsaDriver::unloadPlayback(int card,int stream)
{
#ifdef ALSA
if(alsa_play_ring[card][stream]==NULL) {
@@ -858,7 +806,7 @@ bool MainObject::alsaUnloadPlayback(int card,int stream)
}
bool MainObject::alsaPlaybackPosition(int card,int stream,unsigned pos)
bool AlsaDriver::playbackPosition(int card,int stream,unsigned pos)
{
#ifdef ALSA
unsigned offset=0;
@@ -909,8 +857,8 @@ bool MainObject::alsaPlaybackPosition(int card,int stream,unsigned pos)
}
bool MainObject::alsaPlay(int card,int stream,int length,int speed,bool pitch,
bool rates)
bool AlsaDriver::play(int card,int stream,int length,int speed,bool pitch,
bool rates)
{
#ifdef ALSA
if((alsa_play_ring[card][stream]==NULL)||
@@ -929,17 +877,7 @@ bool MainObject::alsaPlay(int card,int stream,int length,int speed,bool pitch,
}
bool MainObject::alsaTimescaleSupported(int card)
{
#ifdef ALSA
return false;
#else
return false;
#endif // ALSA
}
bool MainObject::alsaStopPlayback(int card,int stream)
bool AlsaDriver::stopPlayback(int card,int stream)
{
#ifdef ALSA
if((alsa_play_ring[card][stream]==NULL)||(!alsa_playing[card][stream])) {
@@ -956,95 +894,101 @@ bool MainObject::alsaStopPlayback(int card,int stream)
}
bool MainObject::alsaLoadRecord(int card,int stream,int coding,int chans,
int samprate,int bitrate,QString wavename)
bool AlsaDriver::timescaleSupported(int card)
{
return false;
}
bool AlsaDriver::loadRecord(int card,int port,int coding,int chans,int samprate,
int bitrate,QString wavename)
{
#ifdef ALSA
alsa_record_wave[card][stream]=new RDWaveFile(wavename);
alsa_record_wave[card][port]=new RDWaveFile(wavename);
switch(coding) {
case 0: // PCM16
alsa_record_wave[card][stream]->setFormatTag(WAVE_FORMAT_PCM);
alsa_record_wave[card][stream]->setChannels(chans);
alsa_record_wave[card][stream]->setSamplesPerSec(samprate);
alsa_record_wave[card][stream]->setBitsPerSample(16);
alsa_record_wave[card][port]->setFormatTag(WAVE_FORMAT_PCM);
alsa_record_wave[card][port]->setChannels(chans);
alsa_record_wave[card][port]->setSamplesPerSec(samprate);
alsa_record_wave[card][port]->setBitsPerSample(16);
break;
case 4: // PCM24
alsa_record_wave[card][stream]->setFormatTag(WAVE_FORMAT_PCM);
alsa_record_wave[card][stream]->setChannels(chans);
alsa_record_wave[card][stream]->setSamplesPerSec(samprate);
alsa_record_wave[card][stream]->setBitsPerSample(24);
alsa_record_wave[card][port]->setFormatTag(WAVE_FORMAT_PCM);
alsa_record_wave[card][port]->setChannels(chans);
alsa_record_wave[card][port]->setSamplesPerSec(samprate);
alsa_record_wave[card][port]->setBitsPerSample(24);
break;
case 2: // MPEG Layer 2
if(!InitTwoLameEncoder(card,stream,chans,samprate,bitrate)) {
delete alsa_record_wave[card][stream];
alsa_record_wave[card][stream]=NULL;
if(!InitTwoLameEncoder(card,port,chans,samprate,bitrate)) {
delete alsa_record_wave[card][port];
alsa_record_wave[card][port]=NULL;
return false;
}
alsa_record_wave[card][stream]->setFormatTag(WAVE_FORMAT_MPEG);
alsa_record_wave[card][stream]->setChannels(chans);
alsa_record_wave[card][stream]->setSamplesPerSec(samprate);
alsa_record_wave[card][stream]->setBitsPerSample(16);
alsa_record_wave[card][stream]->setHeadLayer(ACM_MPEG_LAYER2);
alsa_record_wave[card][port]->setFormatTag(WAVE_FORMAT_MPEG);
alsa_record_wave[card][port]->setChannels(chans);
alsa_record_wave[card][port]->setSamplesPerSec(samprate);
alsa_record_wave[card][port]->setBitsPerSample(16);
alsa_record_wave[card][port]->setHeadLayer(ACM_MPEG_LAYER2);
switch(chans) {
case 1:
alsa_record_wave[card][stream]->setHeadMode(ACM_MPEG_SINGLECHANNEL);
alsa_record_wave[card][port]->setHeadMode(ACM_MPEG_SINGLECHANNEL);
break;
case 2:
alsa_record_wave[card][stream]->setHeadMode(ACM_MPEG_STEREO);
alsa_record_wave[card][port]->setHeadMode(ACM_MPEG_STEREO);
break;
default:
rda->syslog(LOG_WARNING,
"requested unsupported channel count %d, card: %d, stream: %d",
chans,card,stream);
delete alsa_record_wave[card][stream];
alsa_record_wave[card][stream]=NULL;
"requested unsupported channel count %d, card: %d, port: %d",
chans,card,port);
delete alsa_record_wave[card][port];
alsa_record_wave[card][port]=NULL;
return false;
}
alsa_record_wave[card][stream]->setHeadBitRate(bitrate);
alsa_record_wave[card][stream]->setMextChunk(true);
alsa_record_wave[card][stream]->setMextHomogenous(true);
alsa_record_wave[card][stream]->setMextPaddingUsed(false);
alsa_record_wave[card][stream]->setMextHackedBitRate(true);
alsa_record_wave[card][stream]->setMextFreeFormat(false);
alsa_record_wave[card][stream]->
setMextFrameSize(144*alsa_record_wave[card][stream]->getHeadBitRate()/
alsa_record_wave[card][stream]->getSamplesPerSec());
alsa_record_wave[card][stream]->setMextAncillaryLength(5);
alsa_record_wave[card][stream]->setMextLeftEnergyPresent(true);
alsa_record_wave[card][port]->setHeadBitRate(bitrate);
alsa_record_wave[card][port]->setMextChunk(true);
alsa_record_wave[card][port]->setMextHomogenous(true);
alsa_record_wave[card][port]->setMextPaddingUsed(false);
alsa_record_wave[card][port]->setMextHackedBitRate(true);
alsa_record_wave[card][port]->setMextFreeFormat(false);
alsa_record_wave[card][port]->
setMextFrameSize(144*alsa_record_wave[card][port]->getHeadBitRate()/
alsa_record_wave[card][port]->getSamplesPerSec());
alsa_record_wave[card][port]->setMextAncillaryLength(5);
alsa_record_wave[card][port]->setMextLeftEnergyPresent(true);
if(chans>1) {
alsa_record_wave[card][stream]->setMextRightEnergyPresent(true);
alsa_record_wave[card][port]->setMextRightEnergyPresent(true);
}
else {
alsa_record_wave[card][stream]->setMextRightEnergyPresent(false);
alsa_record_wave[card][port]->setMextRightEnergyPresent(false);
}
alsa_record_wave[card][stream]->setMextPrivateDataPresent(false);
alsa_record_wave[card][port]->setMextPrivateDataPresent(false);
break;
default:
rda->syslog(LOG_WARNING,
"requested invalid audio encoding %d, card: %d, stream: %d",
coding,card,stream);
delete alsa_record_wave[card][stream];
alsa_record_wave[card][stream]=NULL;
"requested invalid audio encoding %d, card: %d, port: %d",
coding,card,port);
delete alsa_record_wave[card][port];
alsa_record_wave[card][port]=NULL;
return false;
}
alsa_record_wave[card][stream]->setBextChunk(true);
alsa_record_wave[card][stream]->setLevlChunk(true);
if(!alsa_record_wave[card][stream]->createWave()) {
delete alsa_record_wave[card][stream];
alsa_record_wave[card][stream]=NULL;
alsa_record_wave[card][port]->setBextChunk(true);
alsa_record_wave[card][port]->setLevlChunk(true);
if(!alsa_record_wave[card][port]->createWave()) {
delete alsa_record_wave[card][port];
alsa_record_wave[card][port]=NULL;
return false;
}
RDCheckExitCode(rda->config(),"alsaLoadRecord() chown",
chown(wavename.toUtf8(),rda->config()->uid(),rda->config()->gid()));
alsa_input_channels[card][stream]=chans;
alsa_record_ring[card][stream]=new RDRingBuffer(RINGBUFFER_SIZE);
alsa_record_ring[card][stream]->reset();
alsa_ready[card][stream]=true;
alsa_input_channels[card][port]=chans;
alsa_record_ring[card][port]=new RDRingBuffer(RINGBUFFER_SIZE);
alsa_record_ring[card][port]->reset();
alsa_ready[card][port]=true;
return true;
#else
return false;
@@ -1052,20 +996,20 @@ bool MainObject::alsaLoadRecord(int card,int stream,int coding,int chans,
}
bool MainObject::alsaUnloadRecord(int card,int stream,unsigned *len)
bool AlsaDriver::unloadRecord(int card,int port,unsigned *len)
{
#ifdef ALSA
alsa_recording[card][stream]=false;
alsa_ready[card][stream]=false;
EmptyAlsaInputStream(card,stream);
*len=alsa_samples_recorded[card][stream];
alsa_samples_recorded[card][stream]=0;
alsa_record_wave[card][stream]->closeWave(*len);
delete alsa_record_wave[card][stream];
alsa_record_wave[card][stream]=NULL;
delete alsa_record_ring[card][stream];
alsa_record_ring[card][stream]=NULL;
FreeTwoLameEncoder(card,stream);
alsa_recording[card][port]=false;
alsa_ready[card][port]=false;
EmptyAlsaInputStream(card,port);
*len=alsa_samples_recorded[card][port];
alsa_samples_recorded[card][port]=0;
alsa_record_wave[card][port]->closeWave(*len);
delete alsa_record_wave[card][port];
alsa_record_wave[card][port]=NULL;
delete alsa_record_ring[card][port];
alsa_record_ring[card][port]=NULL;
FreeTwoLameEncoder(card,port);
return true;
#else
return false;
@@ -1073,18 +1017,18 @@ bool MainObject::alsaUnloadRecord(int card,int stream,unsigned *len)
}
bool MainObject::alsaRecord(int card,int stream,int length,int thres)
bool AlsaDriver::record(int card,int port,int length,int thres)
{
#ifdef ALSA
if(!alsa_ready[card][stream]) {
if(!alsa_ready[card][port]) {
return false;
}
alsa_recording[card][stream]=true;
if(alsa_input_vox[card][stream]==0.0) {
alsa_recording[card][port]=true;
if(alsa_input_vox[card][port]==0.0) {
if(length>0) {
alsa_record_timer[card][stream]->start(length);
alsa_record_timer[card][port]->start(length);
}
stateRecordUpdate(card,stream,4);
stateRecordUpdate(card,port,4);
}
return true;
#else
@@ -1093,13 +1037,13 @@ bool MainObject::alsaRecord(int card,int stream,int length,int thres)
}
bool MainObject::alsaStopRecord(int card,int stream)
bool AlsaDriver::stopRecord(int card,int port)
{
#ifdef ALSA
if(!alsa_recording[card][stream]) {
if(!alsa_recording[card][port]) {
return false;
}
alsa_recording[card][stream]=false;
alsa_recording[card][port]=false;
return true;
#else
return false;
@@ -1107,7 +1051,17 @@ bool MainObject::alsaStopRecord(int card,int stream)
}
bool MainObject::alsaSetInputVolume(int card,int stream,int level)
bool AlsaDriver::setClockSource(int card,int src)
{
#ifdef ALSA
return true;
#else
return false;
#endif // ALSA
}
bool AlsaDriver::setInputVolume(int card,int stream,int level)
{
#ifdef ALSA
if(level>-10000) {
@@ -1125,7 +1079,7 @@ bool MainObject::alsaSetInputVolume(int card,int stream,int level)
}
bool MainObject::alsaSetOutputVolume(int card,int stream,int port,int level)
bool AlsaDriver::setOutputVolume(int card,int stream,int port,int level)
{
#ifdef ALSA
if(level>-10000) {
@@ -1143,8 +1097,8 @@ bool MainObject::alsaSetOutputVolume(int card,int stream,int port,int level)
}
bool MainObject::alsaFadeOutputVolume(int card,int stream,int port,int level,
int length)
bool AlsaDriver::fadeOutputVolume(int card,int stream,int port,int level,
int length)
{
#ifdef ALSA
int diff;
@@ -1171,7 +1125,7 @@ bool MainObject::alsaFadeOutputVolume(int card,int stream,int port,int level,
}
bool MainObject::alsaSetInputLevel(int card,int port,int level)
bool AlsaDriver::setInputLevel(int card,int port,int level)
{
#ifdef ALSA
return true;
@@ -1181,7 +1135,7 @@ bool MainObject::alsaSetInputLevel(int card,int port,int level)
}
bool MainObject::alsaSetOutputLevel(int card,int port,int level)
bool AlsaDriver::setOutputLevel(int card,int port,int level)
{
#ifdef ALSA
return true;
@@ -1191,7 +1145,7 @@ bool MainObject::alsaSetOutputLevel(int card,int port,int level)
}
bool MainObject::alsaSetInputMode(int card,int stream,int mode)
bool AlsaDriver::setInputMode(int card,int stream,int mode)
{
#ifdef ALSA
return true;
@@ -1201,7 +1155,7 @@ bool MainObject::alsaSetInputMode(int card,int stream,int mode)
}
bool MainObject::alsaSetOutputMode(int card,int stream,int mode)
bool AlsaDriver::setOutputMode(int card,int stream,int mode)
{
#ifdef ALSA
return true;
@@ -1211,7 +1165,7 @@ bool MainObject::alsaSetOutputMode(int card,int stream,int mode)
}
bool MainObject::alsaSetInputVoxLevel(int card,int stream,int level)
bool AlsaDriver::setInputVoxLevel(int card,int stream,int level)
{
#ifdef ALSA
return true;
@@ -1221,7 +1175,7 @@ bool MainObject::alsaSetInputVoxLevel(int card,int stream,int level)
}
bool MainObject::alsaSetInputType(int card,int port,int type)
bool AlsaDriver::setInputType(int card,int port,int type)
{
#ifdef ALSA
return true;
@@ -1231,7 +1185,7 @@ bool MainObject::alsaSetInputType(int card,int port,int type)
}
bool MainObject::alsaGetInputStatus(int card,int port)
bool AlsaDriver::getInputStatus(int card,int port)
{
#ifdef ALSA
return true;
@@ -1241,7 +1195,7 @@ bool MainObject::alsaGetInputStatus(int card,int port)
}
bool MainObject::alsaGetInputMeters(int card,int port,int16_t levels[2])
bool AlsaDriver::getInputMeters(int card,int port,short levels[2])
{
#ifdef ALSA
double meter;
@@ -1266,7 +1220,7 @@ bool MainObject::alsaGetInputMeters(int card,int port,int16_t levels[2])
}
bool MainObject::alsaGetOutputMeters(int card,int port,int16_t levels[2])
bool AlsaDriver::getOutputMeters(int card,int port,short levels[2])
{
#ifdef ALSA
double meter;
@@ -1290,7 +1244,7 @@ bool MainObject::alsaGetOutputMeters(int card,int port,int16_t levels[2])
}
bool MainObject::alsaGetStreamOutputMeters(int card,int stream,int16_t levels[2])
bool AlsaDriver::getStreamOutputMeters(int card,int stream,short levels[2])
{
#ifdef ALSA
double meter;
@@ -1314,25 +1268,8 @@ bool MainObject::alsaGetStreamOutputMeters(int card,int stream,int16_t levels[2]
}
void MainObject::alsaGetOutputPosition(int card,unsigned *pos)
{// pos is in miliseconds
#ifdef ALSA
for(int i=0;i<RD_MAX_STREAMS;i++) {
if((!alsa_play_format[card].exiting)&&(alsa_play_wave[card][i]!=NULL)) {
pos[i]=1000*(unsigned long long)(alsa_offset[card][i]+
alsa_output_pos[card][i])/
alsa_play_wave[card][i]->getSamplesPerSec();
}
else {
pos[i]=0;
}
}
#endif // ALSA
}
bool MainObject::alsaSetPassthroughLevel(int card,int in_port,int out_port,
int level)
bool AlsaDriver::setPassthroughLevel(int card,int in_port,int out_port,
int level)
{
#ifdef ALSA
if(level>-10000) {
@@ -1351,8 +1288,104 @@ bool MainObject::alsaSetPassthroughLevel(int card,int in_port,int out_port,
}
void AlsaDriver::getOutputPosition(int card,unsigned *pos)
{// pos is in miliseconds
#ifdef ALSA
bool MainObject::AlsaStartCaptureDevice(QString &dev,int card,snd_pcm_t *pcm)
for(int i=0;i<RD_MAX_STREAMS;i++) {
if((!alsa_play_format[card].exiting)&&(alsa_play_wave[card][i]!=NULL)) {
pos[i]=1000*(unsigned long long)(alsa_offset[card][i]+
alsa_output_pos[card][i])/
alsa_play_wave[card][i]->getSamplesPerSec();
}
else {
pos[i]=0;
}
}
#endif // ALSA
}
void AlsaDriver::processBuffers()
{
#ifdef ALSA
for(int i=0;i<RD_MAX_CARDS;i++) {
if(hasCard(i)) {
for(int j=0;j<RD_MAX_STREAMS;j++) {
if(alsa_stopping[i][j]) {
alsa_stopping[i][j]=false;
alsa_eof[i][j]=false;
alsa_playing[i][j]=false;
printf("stop card: %d stream: %d\n",i,j);
statePlayUpdate(i,j,2);
}
if(alsa_playing[i][j]) {
FillAlsaOutputStream(i,j);
}
}
for(int j=0;j<RD_MAX_PORTS;j++) {
if(alsa_recording[i][j]) {
EmptyAlsaInputStream(i,j);
}
}
}
}
#endif // ALSA
}
void AlsaDriver::stopTimerData(int cardstream)
{
#ifdef ALSA
int card=cardstream/RD_MAX_STREAMS;
int stream=cardstream-card*RD_MAX_STREAMS;
stopPlayback(card,stream);
#endif // ALSA
}
void AlsaDriver::fadeTimerData(int cardstream)
{
#ifdef ALSA
int card=cardstream/RD_MAX_STREAMS;
int stream=cardstream-card*RD_MAX_STREAMS;
int16_t level;
if(alsa_fade_up[card][stream]) {
level=alsa_output_volume_db[card][alsa_fade_port[card][stream]][stream]+
alsa_fade_increment[card][stream];
if(level>=alsa_fade_volume_db[card][stream]) {
level=alsa_fade_volume_db[card][stream];
alsa_fade_timer[card][stream]->stop();
}
}
else {
level=alsa_output_volume_db[card][alsa_fade_port[card][stream]][stream]-
alsa_fade_increment[card][stream];
if(level<=alsa_fade_volume_db[card][stream]) {
level=alsa_fade_volume_db[card][stream];
alsa_fade_timer[card][stream]->stop();
}
}
rda->syslog(LOG_DEBUG,"FadeLevel: %d",level);
setOutputVolume(card,stream,alsa_fade_port[card][stream],level);
#endif // ALSA
}
void AlsaDriver::recordTimerData(int cardport)
{
#ifdef ALSA
int card=cardport/RD_MAX_PORTS;
int stream=cardport-card*RD_MAX_PORTS;
stopRecord(card,stream);
stateRecordUpdate(card,stream,2);
#endif // ALSA
}
#ifdef ALSA
bool AlsaDriver::AlsaStartCaptureDevice(QString &dev,int card,snd_pcm_t *pcm)
{
snd_pcm_hw_params_t *hwparams;
snd_pcm_sw_params_t *swparams;
@@ -1412,14 +1445,14 @@ bool MainObject::AlsaStartCaptureDevice(QString &dev,int card,snd_pcm_t *pcm)
sr=alsa_play_format[card].sample_rate;
}
else {
sr=system_sample_rate;
sr=systemSampleRate();
}
snd_pcm_hw_params_set_rate_near(pcm,hwparams,&sr,&dir);
if((sr<(system_sample_rate-RD_ALSA_SAMPLE_RATE_TOLERANCE))||
(sr>(system_sample_rate+RD_ALSA_SAMPLE_RATE_TOLERANCE))) {
if((sr<(systemSampleRate()-RD_ALSA_SAMPLE_RATE_TOLERANCE))||
(sr>(systemSampleRate()+RD_ALSA_SAMPLE_RATE_TOLERANCE))) {
rda->syslog(LOG_WARNING,
" Asked for sample rate %u, got %u",
system_sample_rate,sr);
systemSampleRate(),sr);
rda->syslog(LOG_WARNING,
" Sample rate unsupported by device");
return false;
@@ -1519,7 +1552,7 @@ bool MainObject::AlsaStartCaptureDevice(QString &dev,int card,snd_pcm_t *pcm)
}
bool MainObject::AlsaStartPlayDevice(QString &dev,int card,snd_pcm_t *pcm)
bool AlsaDriver::AlsaStartPlayDevice(QString &dev,int card,snd_pcm_t *pcm)
{
snd_pcm_hw_params_t *hwparams;
snd_pcm_sw_params_t *swparams;
@@ -1575,13 +1608,13 @@ bool MainObject::AlsaStartPlayDevice(QString &dev,int card,snd_pcm_t *pcm)
//
// Sample Rate
//
sr=system_sample_rate;
sr=systemSampleRate();
snd_pcm_hw_params_set_rate_near(pcm,hwparams,&sr,&dir);
if((sr<(system_sample_rate-RD_ALSA_SAMPLE_RATE_TOLERANCE))||
(sr>(system_sample_rate+RD_ALSA_SAMPLE_RATE_TOLERANCE))) {
if((sr<(systemSampleRate()-RD_ALSA_SAMPLE_RATE_TOLERANCE))||
(sr>(systemSampleRate()+RD_ALSA_SAMPLE_RATE_TOLERANCE))) {
rda->syslog(LOG_WARNING,
" Asked for sample rate %u, got %u",
system_sample_rate,sr);
systemSampleRate(),sr);
rda->syslog(LOG_WARNING,
" Sample rate unsupported by device");
return false;
@@ -1677,7 +1710,7 @@ bool MainObject::AlsaStartPlayDevice(QString &dev,int card,snd_pcm_t *pcm)
}
int MainObject::GetAlsaOutputStream(int card)
int AlsaDriver::GetAlsaOutputStream(int card)
{
for(int i=0;i<RD_MAX_STREAMS;i++) {
if(alsa_play_ring[card][i]==NULL) {
@@ -1689,14 +1722,14 @@ int MainObject::GetAlsaOutputStream(int card)
}
void MainObject::FreeAlsaOutputStream(int card,int stream)
void AlsaDriver::FreeAlsaOutputStream(int card,int stream)
{
delete alsa_play_ring[card][stream];
alsa_play_ring[card][stream]=NULL;
}
void MainObject::EmptyAlsaInputStream(int card,int stream)
void AlsaDriver::EmptyAlsaInputStream(int card,int stream)
{
unsigned n=alsa_record_ring[card][stream]->
read((char *)alsa_wave_buffer,alsa_record_ring[card][stream]->
@@ -1705,7 +1738,7 @@ void MainObject::EmptyAlsaInputStream(int card,int stream)
}
void MainObject::WriteAlsaBuffer(int card,int stream,int16_t *buffer,unsigned len)
void AlsaDriver::WriteAlsaBuffer(int card,int stream,int16_t *buffer,unsigned len)
{
ssize_t s;
unsigned char mpeg[2048];
@@ -1758,7 +1791,7 @@ void MainObject::WriteAlsaBuffer(int card,int stream,int16_t *buffer,unsigned le
}
void MainObject::FillAlsaOutputStream(int card,int stream)
void AlsaDriver::FillAlsaOutputStream(int card,int stream)
{
unsigned mpeg_frames=0;
unsigned frame_offset=0;
@@ -1869,11 +1902,11 @@ void MainObject::FillAlsaOutputStream(int card,int stream)
#endif // ALSA
void MainObject::AlsaClock()
void AlsaDriver::AlsaClock()
{
#ifdef ALSA
for(int i=0;i<RD_MAX_CARDS;i++) {
if(cae_driver[i]==RDStation::Alsa) {
if(hasCard(i)) {
for(int j=0;j<RD_MAX_STREAMS;j++) {
if(alsa_stopping[i][j]) {
alsa_stopping[i][j]=false;

129
cae/alsadriver.h Normal file
View File

@@ -0,0 +1,129 @@
// alsadriver.h
//
// caed(8) driver for Advanced Linux Audio Architecture devices
//
// (C) Copyright 2021 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
// published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef ALSADRIVER_H
#define ALSADRIVER_H
#include <rdconfig.h>
#include <rdwavefile.h>
#include "caedriver.h"
#ifdef ALSA
#include <alsa/asoundlib.h>
struct alsa_format {
int card;
pthread_t thread;
snd_pcm_t *pcm;
unsigned channels;
unsigned capture_channels;
snd_pcm_uframes_t buffer_size;
snd_pcm_format_t format;
unsigned sample_rate;
char *card_buffer;
char *passthrough_buffer;
unsigned card_buffer_size;
unsigned periods;
bool exiting;
};
#endif // ALSA
class AlsaDriver : public CaeDriver
{
Q_OBJECT
public:
AlsaDriver(QObject *parent=0);
~AlsaDriver();
QString version() const;
bool initialize(unsigned *next_cardnum);
void updateMeters();
bool loadPlayback(int card,QString wavename,int *stream);
bool unloadPlayback(int card,int stream);
bool playbackPosition(int card,int stream,unsigned pos);
bool play(int card,int stream,int length,int speed,bool pitch,
bool rates);
bool stopPlayback(int card,int stream);
bool timescaleSupported(int card);
bool loadRecord(int card,int port,int coding,int chans,int samprate,
int bitrate,QString wavename);
bool unloadRecord(int card,int port,unsigned *len);
bool record(int card,int port,int length,int thres);
bool stopRecord(int card,int port);
bool setClockSource(int card,int src);
bool setInputVolume(int card,int stream,int level);
bool setOutputVolume(int card,int stream,int port,int level);
bool fadeOutputVolume(int card,int stream,int port,int level,
int length);
bool setInputLevel(int card,int port,int level);
bool setOutputLevel(int card,int port,int level);
bool setInputMode(int card,int stream,int mode);
bool setOutputMode(int card,int stream,int mode);
bool setInputVoxLevel(int card,int stream,int level);
bool setInputType(int card,int port,int type);
bool getInputStatus(int card,int port);
bool getInputMeters(int card,int port,short levels[2]);
bool getOutputMeters(int card,int port,short levels[2]);
bool getStreamOutputMeters(int card,int stream,short levels[2]);
bool setPassthroughLevel(int card,int in_port,int out_port,
int level);
void getOutputPosition(int card,unsigned *pos);
public slots:
void processBuffers();
private slots:
void stopTimerData(int cardstream);
void fadeTimerData(int cardstream);
void recordTimerData(int cardport);
private:
#ifdef ALSA
bool AlsaStartCaptureDevice(QString &dev,int card,snd_pcm_t *pcm);
bool AlsaStartPlayDevice(QString &dev,int card,snd_pcm_t *pcm);
void AlsaInitCallback();
int GetAlsaOutputStream(int card);
void FreeAlsaOutputStream(int card,int stream);
void EmptyAlsaInputStream(int card,int stream);
void WriteAlsaBuffer(int card,int stream,short *buffer,unsigned len);
void FillAlsaOutputStream(int card,int stream);
void AlsaClock();
struct alsa_format alsa_play_format[RD_MAX_CARDS];
struct alsa_format alsa_capture_format[RD_MAX_CARDS];
short alsa_input_volume_db[RD_MAX_CARDS][RD_MAX_STREAMS];
short alsa_output_volume_db[RD_MAX_CARDS][RD_MAX_PORTS][RD_MAX_STREAMS];
short alsa_passthrough_volume_db[RD_MAX_CARDS][RD_MAX_PORTS][RD_MAX_PORTS];
short *alsa_wave_buffer;
uint8_t *alsa_wave24_buffer;
RDWaveFile *alsa_record_wave[RD_MAX_CARDS][RD_MAX_STREAMS];
RDWaveFile *alsa_play_wave[RD_MAX_CARDS][RD_MAX_STREAMS];
int alsa_offset[RD_MAX_CARDS][RD_MAX_STREAMS];
QTimer *alsa_fade_timer[RD_MAX_CARDS][RD_MAX_STREAMS];
QTimer *alsa_stop_timer[RD_MAX_CARDS][RD_MAX_STREAMS];
QTimer *alsa_record_timer[RD_MAX_CARDS][RD_MAX_PORTS];
bool alsa_fade_up[RD_MAX_CARDS][RD_MAX_STREAMS];
short alsa_fade_volume_db[RD_MAX_CARDS][RD_MAX_STREAMS];
short alsa_fade_increment[RD_MAX_CARDS][RD_MAX_STREAMS];
int alsa_fade_port[RD_MAX_CARDS][RD_MAX_STREAMS];
unsigned alsa_samples_recorded[RD_MAX_CARDS][RD_MAX_STREAMS];
#endif // ALSA
};
#endif // ALSADRIVER_H

View File

@@ -252,7 +252,7 @@ MainObject::MainObject(QObject *parent)
unsigned next_card=0;
//
// HPI Devices (One driver instance handles them all)
// HPI Devices
//
CaeDriver *dvr=CaeDriverFactory(RDStation::Hpi,this);
if(dvr->initialize(&next_card)) {
@@ -266,6 +266,21 @@ MainObject::MainObject(QObject *parent)
delete dvr;
}
//
// ALSA Devices
//
dvr=CaeDriverFactory(RDStation::Alsa,this);
if(dvr->initialize(&next_card)) {
connect(dvr,SIGNAL(playStateChanged(int,int,int)),
this,SLOT(statePlayUpdate(int,int,int)));
connect(dvr,SIGNAL(recordStateChanged(int,int,int)),
this,SLOT(stateRecordUpdate(int,int,int)));
d_drivers.push_back(dvr);
}
else {
delete dvr;
}
//
// Probe Capabilities
//
@@ -300,6 +315,7 @@ MainObject::MainObject(QObject *parent)
if(jack_client!=NULL) {
pthread_getschedparam(jack_client_thread_id(jack_client),&sched_policy,
&sched_params);
/*
#ifdef ALSA
for(int i=0;i<RD_MAX_CARDS;i++) {
if(cae_driver[i]==RDStation::Alsa) {
@@ -320,6 +336,7 @@ MainObject::MainObject(QObject *parent)
}
}
#endif // ALSA
*/
jack_running=true;
}
#endif // JACK
@@ -328,6 +345,7 @@ MainObject::MainObject(QObject *parent)
sched_params.sched_priority=rda->config()->realtimePriority();
}
sched_policy=SCHED_FIFO;
/*
#ifdef ALSA
for(int i=0;i<RD_MAX_CARDS;i++) {
if(cae_driver[i]==RDStation::Alsa) {
@@ -348,6 +366,7 @@ MainObject::MainObject(QObject *parent)
}
}
#endif // ALSA
*/
if(sched_params.sched_priority>sched_get_priority_min(sched_policy)) {
sched_params.sched_priority--;
}
@@ -1065,6 +1084,7 @@ void MainObject::connectionDroppedData(int id)
void MainObject::statePlayUpdate(int card,int stream,int state)
{
printf("statePlayUpdate(%d,%d,%d)\n",card,stream,state);
int handle=GetHandle(card,stream);
if(handle<0) {
@@ -1143,8 +1163,12 @@ void MainObject::updateMeters()
exit(0);
}
AlsaClock();
JackClock();
//
// Service Disk Buffers
//
for(int i=0;i<d_drivers.size();i++) {
d_drivers.at(i)->processBuffers();
}
for(int i=0;i<RD_MAX_CARDS;i++) {
CaeDriver *dvr=GetDriver(i);
@@ -1539,7 +1563,7 @@ bool MainObject::CheckMp4Decode()
bool MainObject::LoadTwoLame()
{
#ifdef HAVE_TWOLAME
if((twolame_handle=dlopen("libtwolame.so.0",RTLD_NOW))==NULL) {
if((twolame_handle=dlopen("libtwolame.so.0",RTLD_LAZY))==NULL) {
rda->syslog(LOG_INFO,
"TwoLAME encoder library not found, MPEG L2 encoding not supported");
return false;
@@ -1630,7 +1654,7 @@ void MainObject::FreeTwoLameEncoder(int card,int stream)
bool MainObject::LoadMad()
{
#ifdef HAVE_MAD
if((mad_handle=dlopen("libmad.so.0",RTLD_NOW))==NULL) {
if((mad_handle=dlopen("libmad.so.0",RTLD_LAZY))==NULL) {
rda->syslog(LOG_INFO,
"MAD decoder library not found, MPEG L2 decoding not supported");
return false;

View File

@@ -90,7 +90,7 @@ void src_float_to_int_array (const float *in, int *out, int len);
//
// Global CAE Definitions
//
#define RINGBUFFER_SIZE 262144
//#define RINGBUFFER_SIZE 262144
#define CAED_USAGE "[-d]\n\nSupplying the '-d' flag will set 'debug' mode, causing caed(8) to stay\nin the foreground and print debugging info on standard output.\n"
//
@@ -317,6 +317,7 @@ class MainObject : public QObject
//
// ALSA Driver
//
/*
private slots:
void alsaStopTimerData(int cardstream);
void alsaFadeTimerData(int cardstream);
@@ -381,6 +382,7 @@ class MainObject : public QObject
int alsa_fade_port[RD_MAX_CARDS][RD_MAX_STREAMS];
unsigned alsa_samples_recorded[RD_MAX_CARDS][RD_MAX_STREAMS];
#endif // ALSA
*/
bool CheckLame();
bool CheckMp4Decode();

View File

@@ -1,532 +0,0 @@
// cae_hpi.cpp
//
// The HPI Driver for the Core Audio Engine component of Rivendell
//
// (C) Copyright 2002-2021 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
// published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include <syslog.h>
#include <rdapplication.h>
#include <rdconf.h>
#include <rddebug.h>
#include "cae.h"
/*
void MainObject::hpiInit(RDStation *station)
{
#ifdef HPI
for(int i=0;i<RD_MAX_CARDS;i++) {
for(int j=0;j<RD_MAX_STREAMS;j++) {
record[i][j]=NULL;
play[i][j]=NULL;
}
}
sound_card=new RDHPISoundCard(rd_config,this);
sound_card->setFadeProfile(RD_FADE_TYPE);
for(int i=0;i<sound_card->getCardQuantity();i++) {
cae_driver[i]=RDStation::Hpi;
station->setCardDriver(i,RDStation::Hpi);
station->setCardName(i,sound_card->getCardDescription(i));
station->setCardInputs(i,sound_card->getCardInputPorts(i));
station->setCardOutputs(i,sound_card->getCardOutputPorts(i));
}
#endif // HPI
}
void MainObject::hpiFree()
{
#ifdef HPI
#endif // HPI
}
QString MainObject::hpiVersion()
{
#ifdef HPI
if(sound_card==NULL) {
return QString("not active");
}
RDHPIInformation *info=sound_card->hpiInformation(0);
if(info->hpiVersion()==0) {
return QString("not active");
}
return QString().sprintf("%d.%02d.%02d",info->hpiMajorVersion(),
info->hpiMinorVersion(),info->hpiPointVersion());
#else
return QString("not enabled");
#endif // HPI
}
bool MainObject::hpiLoadPlayback(int card,QString wavename,int *stream)
{
#ifdef HPI
RDHPIPlayStream *playstream=new RDHPIPlayStream(sound_card);
playstream->setCard(card);
if(playstream->openWave(wavename)!=RDHPIPlayStream::Ok) {
RDApplication::syslog(rd_config,LOG_DEBUG,
"hpiLoadPlayback(%s) openWave() failed to open file",
(const char *)wavename.toUtf8());
delete playstream;
return false;
}
*stream=playstream->getStream();
play[card][*stream]=playstream;
connect(play[card][*stream],SIGNAL(stateChanged(int,int,int)),
this,SLOT(statePlayUpdate(int,int,int)));
return true;
#else
return false;
#endif // HPI
}
bool MainObject::hpiUnloadPlayback(int card,int stream)
{
#ifdef HPI
if(play[card][stream]==NULL) {
return false;
}
if(play[card][stream]->getState()==RDHPIPlayStream::Playing) {
play[card][stream]->pause();
}
play[card][stream]->disconnect();
play[card][stream]->closeWave();
delete play[card][stream];
play[card][stream]=NULL;
return true;
#else
return false;
#endif // HPI
}
bool MainObject::hpiPlaybackPosition(int card,int stream,unsigned pos)
{
#ifdef HPI
if(play[card][stream]==NULL) {
return false;
}
return play[card][stream]->
setPosition((unsigned)((double)play[card][stream]->getSamplesPerSec()*
(double)pos/1000.0));
#else
return false;
#endif // HPI
}
bool MainObject::hpiPlay(int card,int stream,int length,int speed,bool pitch,
bool rates)
{
#ifdef HPI
if(play[card][stream]==NULL) {
return false;
}
if(!play[card][stream]->setSpeed(speed,pitch,rates)) {
return false;
}
play[card][stream]->setPlayLength(length);
return play[card][stream]->play();
#else
return false;
#endif // HPI
}
bool MainObject::hpiStopPlayback(int card,int stream)
{
#ifdef HPI
if(play[card][stream]==NULL) {
return false;
}
play[card][stream]->pause();
return true;
#else
return false;
#endif // HPI
}
bool MainObject::hpiTimescaleSupported(int card)
{
#ifdef HPI
return sound_card->haveTimescaling(card);
#else
return false;
#endif // HPI
}
bool MainObject::hpiLoadRecord(int card,int stream,int coding,int chans,
int samprate,int bitrate,QString wavename)
{
#ifdef HPI
record[card][stream]=new RDHPIRecordStream(sound_card);
connect(record[card][stream],SIGNAL(stateChanged(int,int,int)),
this,SLOT(stateRecordUpdate(int,int,int)));
record[card][stream]->setCard(card);
record[card][stream]->setStream(stream);
record[card][stream]->nameWave(wavename);
record[card][stream]->setChannels(chans);
record[card][stream]->setSamplesPerSec(samprate);
if(coding==0) { // PCM16
record[card][stream]->setFormatTag(WAVE_FORMAT_PCM);
record[card][stream]->setBitsPerSample(16);
}
if((coding==1)||(coding==2)) { // MPEG-1
record[card][stream]->setFormatTag(WAVE_FORMAT_MPEG);
record[card][stream]->setHeadLayer(coding);
record[card][stream]->setHeadBitRate(bitrate);
record[card][stream]->setMextChunk(true);
switch(chans) {
case 1:
record[card][stream]->setHeadMode(ACM_MPEG_SINGLECHANNEL);
break;
case 2:
record[card][stream]->setHeadMode(ACM_MPEG_STEREO);
break;
default:
delete record[card][stream];
record[card][stream]=NULL;
return false;
}
record[card][stream]->setHeadFlags(ACM_MPEG_ID_MPEG1);
}
if(coding==4) { // PCM24
record[card][stream]->setFormatTag(WAVE_FORMAT_PCM);
record[card][stream]->setBitsPerSample(24);
}
if(coding>4) {
delete record[card][stream];
record[card][stream]=NULL;
return false;
}
record[card][stream]->setBextChunk(true);
record[card][stream]->setCartChunk(true);
record[card][stream]->setLevlChunk(true);
if(record[card][stream]->createWave()!=RDHPIRecordStream::Ok) {
delete record[card][stream];
record[card][stream]=NULL;
return false;
}
RDCheckExitCode(rd_config,"hpiLoadRecord() chown",
chown(wavename.toUtf8(),rd_config->uid(),rd_config->gid()));
if(!record[card][stream]->recordReady()) {
delete record[card][stream];
record[card][stream]=NULL;
return false;
}
return true;
#else
return false;
#endif // HPI
}
bool MainObject::hpiUnloadRecord(int card,int stream,unsigned *len)
{
#ifdef HPI
if(record[card][stream]==NULL) {
return false;
}
if(record[card][stream]->getState()==RDHPIRecordStream::Recording) {
record[card][stream]->pause();
}
record[card][stream]->disconnect();
*len=record[card][stream]->samplesRecorded();
record[card][stream]->closeWave();
delete record[card][stream];
record[card][stream]=NULL;
return true;
#else
return false;
#endif // HPI
}
bool MainObject::hpiRecord(int card,int stream,int length,int thres)
{
#ifdef HPI
if(record[card][stream]==NULL) {
return false;
}
if(thres!=0) {
if(record[card][stream]->haveInputVOX()) {
record[card][stream]->setInputVOX(thres);
}
else {
return false;
}
}
record[card][stream]->setRecordLength(length);
record[card][stream]->record();
return true;
#else
return false;
#endif // HPI
}
bool MainObject::hpiStopRecord(int card,int stream)
{
#ifdef HPI
if(record[card][stream]==NULL) {
return false;
}
record[card][stream]->pause();
record[card][stream]->setInputVOX(-10000);
return true;
#else
return false;
#endif // HPI
}
bool MainObject::hpiSetClockSource(int card,int src)
{
#ifdef HPI
return sound_card->setClockSource(card,(RDHPISoundCard::ClockSource)src);
#else
return false;
#endif // HPI
}
bool MainObject::hpiSetInputVolume(int card,int stream,int level)
{
#ifdef HPI
sound_card->setInputVolume(card,stream,level);
return true;
#else
return false;
#endif // HPI
}
bool MainObject::hpiSetOutputVolume(int card,int stream,int port,int level)
{
#ifdef HPI
sound_card->setOutputVolume(card,stream,port,level);
return true;
#else
return false;
#endif // HPI
}
bool MainObject::hpiFadeOutputVolume(int card,int stream,int port,int level,
int length)
{
#ifdef HPI
sound_card->fadeOutputVolume(card,stream,port,level,length);
return true;
#else
return false;
#endif // HPI
}
bool MainObject::hpiSetInputLevel(int card,int port,int level)
{
#ifdef HPI
sound_card->setInputLevel(card,port,level);
return true;
#else
return false;
#endif // HPI
}
bool MainObject::hpiSetOutputLevel(int card,int port,int level)
{
#ifdef HPI
sound_card->setOutputLevel(card,port,level);
return true;
#else
return false;
#endif // HPI
}
bool MainObject::hpiSetInputMode(int card,int stream,int mode)
{
#ifdef HPI
switch(mode) {
case 0:
sound_card->setInputMode(card,stream,RDHPISoundCard::Normal);
break;
case 1:
sound_card->setInputMode(card,stream,RDHPISoundCard::Swap);
break;
case 2:
sound_card->setInputMode(card,stream,RDHPISoundCard::LeftOnly);
break;
case 3:
sound_card->setInputMode(card,stream,RDHPISoundCard::RightOnly);
break;
default:
return false;
}
return true;
#else
return false;
#endif // HPI
}
bool MainObject::hpiSetOutputMode(int card,int stream,int mode)
{
#ifdef HPI
switch(mode) {
case 0:
sound_card->setOutputMode(card,stream,RDHPISoundCard::Normal);
break;
case 1:
sound_card->setOutputMode(card,stream,RDHPISoundCard::Swap);
break;
case 2:
sound_card->setOutputMode(card,stream,RDHPISoundCard::LeftOnly);
break;
case 3:
sound_card->setOutputMode(card,stream,RDHPISoundCard::RightOnly);
break;
default:
return false;
}
return true;
#else
return false;
#endif // HPI
}
bool MainObject::hpiSetInputVoxLevel(int card,int stream,int level)
{
#ifdef HPI
sound_card->setInputStreamVOX(card,stream,level);
return true;
#else
return false;
#endif // HPI
}
bool MainObject::hpiSetInputType(int card,int port,int type)
{
#ifdef HPI
switch(type) {
case 0:
sound_card->setInputPortMux(card,port,RDHPISoundCard::LineIn);
break;
case 1:
sound_card->setInputPortMux(card,port,RDHPISoundCard::AesEbuIn);
break;
default:
return false;
}
return true;
#else
return false;
#endif // HPI
}
bool MainObject::hpiGetInputStatus(int card,int port)
{
#ifdef HPI
if(sound_card->getInputPortError(card,port)!=0) {
return false;
}
return true;
#else
return false;
#endif // HPI
}
bool MainObject::hpiGetInputMeters(int card,int port,short levels[2])
{
#ifdef HPI
return sound_card->inputStreamMeter(card,port,levels);
#else
return false;
#endif // HPI
}
bool MainObject::hpiGetOutputMeters(int card,int port,short levels[2])
{
#ifdef HPI
return sound_card->outputPortMeter(card,port,levels);
#else
return false;
#endif // HPI
}
bool MainObject::hpiGetStreamOutputMeters(int card,int stream,short levels[2])
{
#ifdef HPI
return sound_card->outputStreamMeter(card,stream,levels);
#else
return false;
#endif // HPI
}
void MainObject::hpiGetOutputPosition(int card,unsigned *pos)
{
#ifdef HPI
for(int i=0;i<RD_MAX_STREAMS;i++) {
if(play[card][i]==NULL) {
pos[i]=0;
}
else {
pos[i]=1000*(unsigned long long)play[card][i]->currentPosition()/
play[card][i]->getSamplesPerSec();
}
}
#endif // HPI
return;
}
bool MainObject::hpiSetPassthroughLevel(int card,int in_port,int out_port,
int level)
{
#ifdef HPI
return sound_card->setPassthroughVolume(card,in_port,out_port,level);
#else
return false;
#endif // HPI
}
*/

View File

@@ -18,12 +18,17 @@
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include <dlfcn.h>
#include "caedriver.h"
CaeDriver::CaeDriver(RDStation::AudioDriver type,QObject *parent)
: QObject(parent)
{
d_driver_type=type;
d_system_sample_rate=rda->system()->sampleRate();
twolame_handle=NULL;
mad_handle=NULL;
}
@@ -39,6 +44,11 @@ bool CaeDriver::hasCard(int cardnum) const
}
void CaeDriver::processBuffers()
{
}
void CaeDriver::statePlayUpdate(int card,int stream,int state)
{
emit playStateChanged(card,stream,state);
@@ -63,3 +73,176 @@ void CaeDriver::addCard(unsigned cardnum)
d_cards.push_back(cardnum);
}
}
unsigned CaeDriver::systemSampleRate() const
{
return d_system_sample_rate;
}
bool CaeDriver::LoadTwoLame()
{
#ifdef HAVE_TWOLAME
if((twolame_handle=dlopen("libtwolame.so.0",RTLD_NOW))==NULL) {
rda->syslog(LOG_INFO,
"TwoLAME encoder library not found, MPEG L2 encoding not supported");
return false;
}
*(void **)(&twolame_init)=dlsym(twolame_handle,"twolame_init");
*(void **)(&twolame_set_mode)=dlsym(twolame_handle,"twolame_set_mode");
*(void **)(&twolame_set_num_channels)=
dlsym(twolame_handle,"twolame_set_num_channels");
*(void **)(&twolame_set_in_samplerate)=
dlsym(twolame_handle,"twolame_set_in_samplerate");
*(void **)(&twolame_set_out_samplerate)=
dlsym(twolame_handle,"twolame_set_out_samplerate");
*(void **)(&twolame_set_bitrate)=
dlsym(twolame_handle,"twolame_set_bitrate");
*(void **)(&twolame_init_params)=
dlsym(twolame_handle,"twolame_init_params");
*(void **)(&twolame_close)=dlsym(twolame_handle,"twolame_close");
*(void **)(&twolame_encode_buffer_interleaved)=
dlsym(twolame_handle,"twolame_encode_buffer_interleaved");
*(void **)(&twolame_encode_buffer_float32_interleaved)=
dlsym(twolame_handle,"twolame_encode_buffer_float32_interleaved");
*(void **)(&twolame_encode_flush)=
dlsym(twolame_handle,"twolame_encode_flush");
*(void **)(&twolame_set_energy_levels)=
dlsym(twolame_handle,"twolame_set_energy_levels");
rda->syslog(LOG_INFO,
"Found TwoLAME encoder library, MPEG L2 encoding supported");
return true;
#else
rda->syslog(LOG_INFO,"MPEG L2 encoding not enabled");
return false;
#endif // HAVE_TWOLAME
}
bool CaeDriver::InitTwoLameEncoder(int card,int stream,int chans,int samprate,
int bitrate)
{
if(twolame_handle==NULL) {
rda->syslog(LOG_WARNING,"MPEG Layer 2 encode not available");
return false;
}
#ifdef HAVE_TWOLAME
TWOLAME_MPEG_mode mpeg_mode=TWOLAME_STEREO;
switch(chans) {
case 1:
mpeg_mode=TWOLAME_MONO;
break;
case 2:
mpeg_mode=TWOLAME_STEREO;
break;
}
if((twolame_lameopts[card][stream]=twolame_init())==NULL) {
rda->syslog(LOG_WARNING,
"unable to initialize twolame instance, card=%d, stream=%d",
card,stream);
return false;
}
twolame_set_mode(twolame_lameopts[card][stream],mpeg_mode);
twolame_set_num_channels(twolame_lameopts[card][stream],chans);
twolame_set_in_samplerate(twolame_lameopts[card][stream],samprate);
twolame_set_out_samplerate(twolame_lameopts[card][stream],samprate);
twolame_set_bitrate(twolame_lameopts[card][stream],bitrate/1000);
twolame_set_energy_levels(twolame_lameopts[card][stream],1);
if(twolame_init_params(twolame_lameopts[card][stream])!=0) {
rda->syslog(LOG_WARNING,
"invalid twolame parameters, card=%d, stream=%d, chans=%d, samprate=%d bitrate=%d",
card,stream,chans,samprate,bitrate);
return false;
}
return true;
#else
return false;
#endif // HAVE_TWOLAME
}
void CaeDriver::FreeTwoLameEncoder(int card,int stream)
{
#ifdef HAVE_TWOLAME
if(twolame_lameopts[card][stream]!=NULL) {
twolame_close(&twolame_lameopts[card][stream]);
twolame_lameopts[card][stream]=NULL;
}
#endif // HAVE_TWOLAME
}
bool CaeDriver::LoadMad()
{
#ifdef HAVE_MAD
if((mad_handle=dlopen("libmad.so.0",RTLD_NOW))==NULL) {
rda->syslog(LOG_INFO,
"MAD decoder library not found, MPEG L2 decoding not supported");
return false;
}
*(void **)(&mad_stream_init)=
dlsym(mad_handle,"mad_stream_init");
*(void **)(&mad_frame_init)=
dlsym(mad_handle,"mad_frame_init");
*(void **)(&mad_synth_init)=
dlsym(mad_handle,"mad_synth_init");
*(void **)(&mad_stream_buffer)=
dlsym(mad_handle,"mad_stream_buffer");
*(void **)(&mad_frame_decode)=
dlsym(mad_handle,"mad_frame_decode");
*(void **)(&mad_synth_frame)=
dlsym(mad_handle,"mad_synth_frame");
*(void **)(&mad_frame_finish)=
dlsym(mad_handle,"mad_frame_finish");
*(void **)(&mad_stream_finish)=
dlsym(mad_handle,"mad_stream_finish");
rda->syslog(LOG_INFO,
"Found MAD decoder library, MPEG L2 decoding supported");
return true;
#else
rda->syslog(LOG_INFO,"MPEG L2 decoding not enabled");
return false;
#endif // HAVE_MAD
}
bool CaeDriver::InitMadDecoder(int card,int stream,RDWaveFile *wave)
{
if(mad_handle==NULL) {
rda->syslog(LOG_WARNING,"MPEG Layer 2 decode not available");
return false;
}
#ifdef HAVE_MAD
if(mad_active[card][stream]) {
FreeMadDecoder(card,stream);
}
mad_stream_init(&mad_stream[card][stream]);
mad_frame_init(&mad_frame[card][stream]);
mad_synth_init(&mad_synth[card][stream]);
mad_frame_size[card][stream]=
144*wave->getHeadBitRate()/wave->getSamplesPerSec();
mad_left_over[card][stream]=0;
mad_active[card][stream]=true;
return true;
#endif // HAVE_MAD
return false;
}
void CaeDriver::FreeMadDecoder(int card,int stream)
{
#ifdef HAVE_MAD
if(mad_active[card][stream]) {
mad_synth_finish(&mad_synth[card][stream]);
mad_frame_finish(&mad_frame[card][stream]);
mad_stream_finish(&mad_stream[card][stream]);
mad_frame_size[card][stream]=0;
mad_left_over[card][stream]=0;
mad_active[card][stream]=false;
}
#endif // HAVE_MAD
}

View File

@@ -21,10 +21,23 @@
#ifndef CAEDRIVER_H
#define CAEDRIVER_H
#ifdef HAVE_TWOLAME
#include <twolame.h>
#endif // HAVE_TWOLAME
#ifdef HAVE_MAD
#include <mad.h>
#endif // HAVE_MAD
#include <QList>
#include <QObject>
#include <QSignalMapper>
#include <rdapplication.h>
#include <rdwavefile.h>
#define RINGBUFFER_SIZE 262144
extern void SigHandler(int signum);
class CaeDriver : public QObject
{
@@ -73,17 +86,73 @@ class CaeDriver : public QObject
void playStateChanged(int card,int stream,int state);
void recordStateChanged(int card,int stream,int state);
public slots:
virtual void processBuffers();
protected slots:
void statePlayUpdate(int card,int stream,int state);
void stateRecordUpdate(int card,int stream,int state);
protected:
void addCard(unsigned cardnum);
unsigned systemSampleRate() const;
RDConfig *config() const;
//
// TwoLAME Encoder
//
bool LoadTwoLame();
bool InitTwoLameEncoder(int card,int stream,int chans,int samprate,
int bitrate);
void FreeTwoLameEncoder(int card,int stream);
void *twolame_handle;
#ifdef HAVE_TWOLAME
twolame_options *(*twolame_init)(void);
void (*twolame_set_mode)(twolame_options *,TWOLAME_MPEG_mode);
void (*twolame_set_num_channels)(twolame_options *,int);
void (*twolame_set_in_samplerate)(twolame_options *,int);
void (*twolame_set_out_samplerate)(twolame_options *,int);
void (*twolame_set_bitrate)(twolame_options *,int);
int (*twolame_init_params)(twolame_options *);
void (*twolame_close)(twolame_options **);
int (*twolame_encode_buffer_interleaved)(twolame_options *,const short int[],
int,unsigned char *,int);
int (*twolame_encode_buffer_float32_interleaved)
(twolame_options *,const float[],int,unsigned char *,int);
int (*twolame_encode_flush)(twolame_options *,unsigned char *,int);
int (*twolame_set_energy_levels)(twolame_options *,int);
twolame_options *twolame_lameopts[RD_MAX_CARDS][RD_MAX_STREAMS];
#endif // HAVE_TWOLAME
//
// MAD Decoder
//
bool LoadMad();
bool InitMadDecoder(int card,int stream,RDWaveFile *wave);
void FreeMadDecoder(int card,int stream);
void *mad_handle;
#ifdef HAVE_MAD
void (*mad_stream_init)(struct mad_stream *);
void (*mad_frame_init)(struct mad_frame *);
void (*mad_synth_init)(struct mad_synth *);
void (*mad_stream_buffer)(struct mad_stream *,unsigned char const *,
unsigned long);
int (*mad_frame_decode)(struct mad_frame *, struct mad_stream *);
void (*mad_synth_frame)(struct mad_synth *, struct mad_frame const *);
void (*mad_frame_finish)(struct mad_frame *);
void (*mad_stream_finish)(struct mad_stream *);
struct mad_stream mad_stream[RD_MAX_CARDS][RD_MAX_STREAMS];
struct mad_frame mad_frame[RD_MAX_CARDS][RD_MAX_STREAMS];
struct mad_synth mad_synth[RD_MAX_CARDS][RD_MAX_STREAMS];
bool mad_active[RD_MAX_CARDS][RD_MAX_STREAMS];
int mad_frame_size[RD_MAX_CARDS][RD_MAX_STREAMS];
int mad_left_over[RD_MAX_CARDS][RD_MAX_STREAMS];
unsigned char *mad_mpeg[RD_MAX_CARDS][RD_MAX_STREAMS];
#endif // HAVE_MAD
private:
RDStation::AudioDriver d_driver_type;
QList<unsigned> d_cards;
unsigned d_system_sample_rate;
};

View File

@@ -18,26 +18,29 @@
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include "alsadriver.h"
#include "caedriverfactory.h"
#include "hpidriver.h"
CaeDriver *CaeDriverFactory(RDStation::AudioDriver dvr,QObject *parent)
{
CaeDriver *ret=NULL;
printf("HERE1\n");
switch(dvr) {
case RDStation::Hpi:
printf("HERE2\n");
ret=new HpiDriver(parent);
break;
case RDStation::Jack:
break;
case RDStation::Alsa:
ret=new AlsaDriver(parent);
break;
case RDStation::None:
printf("HERE3\n");
break;
}
printf("HERE4: %p\n",ret);
return ret;
}