From 8888e4cc8257cb099eafdeee8e112a2147201d4d Mon Sep 17 00:00:00 2001 From: Fred Gleason Date: Wed, 18 Aug 2021 17:01:04 -0400 Subject: [PATCH] 2021-08-18 Fred Gleason * Refactored the ALSA driver in caed(8) to use virtual inheritance. Signed-off-by: Fred Gleason --- ChangeLog | 2 + cae/Makefile.am | 8 +- cae/{cae_alsa.cpp => alsadriver.cpp} | 621 ++++++++++++++------------- cae/alsadriver.h | 129 ++++++ cae/cae.cpp | 34 +- cae/cae.h | 4 +- cae/cae_hpi.cpp | 532 ----------------------- cae/caedriver.cpp | 183 ++++++++ cae/caedriver.h | 69 +++ cae/caedriverfactory.cpp | 11 +- 10 files changed, 753 insertions(+), 840 deletions(-) rename cae/{cae_alsa.cpp => alsadriver.cpp} (82%) create mode 100644 cae/alsadriver.h delete mode 100644 cae/cae_hpi.cpp diff --git a/ChangeLog b/ChangeLog index 1718ca75..cf0b7168 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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 + * Refactored the ALSA driver in caed(8) to use virtual inheritance. diff --git a/cae/Makefile.am b/cae/Makefile.am index 77558f98..8905e13d 100644 --- a/cae/Makefile.am +++ b/cae/Makefile.am @@ -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 diff --git a/cae/cae_alsa.cpp b/cae/alsadriver.cpp similarity index 82% rename from cae/cae_alsa.cpp rename to cae/alsadriver.cpp index 059bf13d..3d039360 100644 --- a/cae/cae_alsa.cpp +++ b/cae/alsadriver.cpp @@ -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 +// (C) Copyright 2021 Fred Gleason // // 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 #include -#include - -#include - -#include -#include #include #include #include -#include +#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=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;isetCardDriver(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;istation()->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;igetSamplesPerSec(); - } - 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;igetSamplesPerSec(); + } + else { + pos[i]=0; + } + } +#endif // ALSA +} + + +void AlsaDriver::processBuffers() +{ +#ifdef ALSA + for(int i=0;i=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 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 +// +// 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 +#include + +#include "caedriver.h" + +#ifdef ALSA +#include +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 diff --git a/cae/cae.cpp b/cae/cae.cpp index 365b5567..dadca1a8 100644 --- a/cae/cae.cpp +++ b/cae/cae.cpp @@ -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;iconfig()->realtimePriority(); } sched_policy=SCHED_FIFO; + /* #ifdef ALSA for(int i=0;isched_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;iprocessBuffers(); + } for(int i=0;isyslog(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; diff --git a/cae/cae.h b/cae/cae.h index 010e685c..88fa7d82 100644 --- a/cae/cae.h +++ b/cae/cae.h @@ -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(); diff --git a/cae/cae_hpi.cpp b/cae/cae_hpi.cpp deleted file mode 100644 index aed467ba..00000000 --- a/cae/cae_hpi.cpp +++ /dev/null @@ -1,532 +0,0 @@ -// cae_hpi.cpp -// -// The HPI Driver for the Core Audio Engine component of Rivendell -// -// (C) Copyright 2002-2021 Fred Gleason -// -// 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 - -#include -#include -#include - -#include "cae.h" -/* -void MainObject::hpiInit(RDStation *station) -{ -#ifdef HPI - for(int i=0;isetFadeProfile(RD_FADE_TYPE); - for(int i=0;igetCardQuantity();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;icurrentPosition()/ - 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 -} -*/ diff --git a/cae/caedriver.cpp b/cae/caedriver.cpp index 0757930d..2d21238d 100644 --- a/cae/caedriver.cpp +++ b/cae/caedriver.cpp @@ -18,12 +18,17 @@ // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. // +#include + #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 +} diff --git a/cae/caedriver.h b/cae/caedriver.h index e587a636..2f5f89b9 100644 --- a/cae/caedriver.h +++ b/cae/caedriver.h @@ -21,10 +21,23 @@ #ifndef CAEDRIVER_H #define CAEDRIVER_H +#ifdef HAVE_TWOLAME +#include +#endif // HAVE_TWOLAME +#ifdef HAVE_MAD +#include +#endif // HAVE_MAD + #include #include +#include #include +#include + +#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 d_cards; + unsigned d_system_sample_rate; }; diff --git a/cae/caedriverfactory.cpp b/cae/caedriverfactory.cpp index 96962d2e..ca880fa7 100644 --- a/cae/caedriverfactory.cpp +++ b/cae/caedriverfactory.cpp @@ -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; }