From ba1e2d84ab8a2a3f6589239e5bb6cd659f599091 Mon Sep 17 00:00:00 2001 From: Fred Gleason Date: Thu, 24 Aug 2023 13:10:10 -0400 Subject: [PATCH] 2023-08-24 Fred Gleason * Added a 'TestOutputStreams=' directive to the '[Caed]' section of rd.conf(5). * Added code to the 'Unload Playback' ['UP'] CAE command to mute all output port volume controls from the subject output stream. * Added a feature to the 'Set Output Port' ['OP'] CAE command where passing a '-1' for the 'port-num' argument will cause all output stream volume controls for the specified stream to be muted. Signed-off-by: Fred Gleason --- ChangeLog | 8 ++++ cae/cae.cpp | 109 +++++++++++++++++++++++++++++++++++--------- cae/cae.h | 4 +- cae/cae_server.cpp | 20 +++++++- cae/cae_server.h | 6 ++- conf/rd.conf-sample | 10 ++++ docs/apis/cae.xml | 72 ++++++++++++++++++++++++++++- lib/rdcae.cpp | 9 +--- lib/rdcae.h | 4 +- lib/rdconfig.cpp | 8 ++++ lib/rdconfig.h | 2 + lib/rdplay_deck.cpp | 4 +- 12 files changed, 215 insertions(+), 41 deletions(-) diff --git a/ChangeLog b/ChangeLog index f8f3a4fc..9c006edd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -24365,3 +24365,11 @@ 2023-08-24 Fred Gleason * Fixed a regression in the 'RDHPIPlayStream' that could cause audio play-out to be truncated. +2023-08-24 Fred Gleason + * Added a 'TestOutputStreams=' directive to the '[Caed]' section + of rd.conf(5). + * Added code to the 'Unload Playback' ['UP'] CAE command to mute all + output port volume controls from the subject output stream. + * Added a feature to the 'Set Output Port' ['OP'] CAE command where + passing a '-1' for the 'port-num' argument will cause all output + stream volume controls for the specified stream to be muted. diff --git a/cae/cae.cpp b/cae/cae.cpp index 32d0364b..6ba82e85 100644 --- a/cae/cae.cpp +++ b/cae/cae.cpp @@ -178,9 +178,13 @@ MainObject::MainObject(QObject *parent) connect(cae_server,SIGNAL(setInputVolumeReq(int,unsigned,unsigned,int)), this,SLOT(setInputVolumeData(int,unsigned,unsigned,int))); connect(cae_server, - SIGNAL(setOutputVolumeReq(int,unsigned,unsigned,unsigned,int)), + SIGNAL(setOutputPortReq(int,unsigned,unsigned,unsigned,int)), this, - SLOT(setOutputVolumeData(int,unsigned,unsigned,unsigned,int))); + SLOT(setOutputPortData(int,unsigned,unsigned,unsigned,int))); + connect(cae_server, + SIGNAL(setOutputVolumeReq(int,unsigned,unsigned,int,int)), + this, + SLOT(setOutputVolumeData(int,unsigned,unsigned,int,int))); connect(cae_server,SIGNAL(fadeOutputVolumeReq(int,unsigned,unsigned, unsigned,int,unsigned)), this,SLOT(fadeOutputVolumeData(int,unsigned,unsigned, @@ -318,6 +322,9 @@ MainObject::MainObject(QObject *parent) if(rda->config()->enableMixerLogging()) { rda->syslog(LOG_INFO,"mixer logging enabled"); } + if(rda->config()->testOutputStreams()) { + rda->syslog(LOG_INFO,"output stream testing enabled"); + } rda->syslog(LOG_INFO,"cae started"); } @@ -379,6 +386,11 @@ void MainObject::unloadPlaybackData(int id,unsigned handle) } if((play_owner[card][stream]==-1)||(play_owner[card][stream]==id)) { if(dvr->unloadPlayback(card,stream)) { + if(!rda->config()->testOutputStreams()) { + for(int i=0;isetOutputVolume(card,stream,i,RD_MUTE_DEPTH); // Clear mixer + } + } play_owner[card][stream]=-1; rda->syslog(LOG_INFO,"UnloadPlayback - Card: %d Stream: %d Handle: %d", card,stream,handle); @@ -668,8 +680,38 @@ void MainObject::setInputVolumeData(int id,unsigned card,unsigned stream, } +void MainObject::setOutputPortData(int id,unsigned card,unsigned stream, + unsigned port,int level) +{ + Driver *dvr=GetDriver(card); + + if(dvr==NULL) { + cae_server->sendCommand(id,QString::asprintf("OP %u %u %u %d -!", + card,stream,port,level)); + return; + } + if(!rda->config()->testOutputStreams()) { + for(unsigned i=0;isetOutputVolume(card,i,port,level); + } + else { + dvr->setOutputVolume(card,i,port,RD_FADE_DEPTH); + } + } + if(rda->config()->enableMixerLogging()) { + rda->syslog(LOG_INFO, + "SetOutputPort - Card: %d Stream: %d Port: %d Level: %d", + card,stream,port,level); + } + } + cae_server->sendCommand(id,QString::asprintf("OV %u %u %u %d +!", + card,stream,port,level)); +} + + void MainObject::setOutputVolumeData(int id,unsigned card,unsigned stream, - unsigned port,int level) + int port,int level) { Driver *dvr=GetDriver(card); @@ -678,15 +720,24 @@ void MainObject::setOutputVolumeData(int id,unsigned card,unsigned stream, card,stream,port,level)); return; } - if(!dvr->setOutputVolume(card,stream,port,level)) { - cae_server->sendCommand(id,QString::asprintf("OV %u %u %u %d -!", - card,stream,port,level)); - return; - } - if(rda->config()->enableMixerLogging()) { - rda->syslog(LOG_INFO, - "SetOutputVolume - Card: %d Stream: %d Port: %d Level: %d", - card,stream,port,level); + if(!rda->config()->testOutputStreams()) { + if(port>=0) { + if(!dvr->setOutputVolume(card,stream,port,level)) { + cae_server->sendCommand(id,QString::asprintf("OV %u %u %u %d -!", + card,stream,port,level)); + return; + } + } + else { + for(int i=0;isetOutputVolume(card,stream,i,level); + } + } + if(rda->config()->enableMixerLogging()) { + rda->syslog(LOG_INFO, + "SetOutputVolume - Card: %d Stream: %d Port: %d Level: %d", + card,stream,port,level); + } } cae_server->sendCommand(id,QString::asprintf("OV %u %u %u %d +!", card,stream,port,level)); @@ -704,16 +755,18 @@ void MainObject::fadeOutputVolumeData(int id,unsigned card,unsigned stream, card,stream,port,level,length)); return; } - if(!dvr->fadeOutputVolume(card,stream,port,level,length)) { - cae_server-> - sendCommand(id,QString::asprintf("FV %u %u %u %d %u -!", - card,stream,port,level,length)); - return; - } - if(rda->config()->enableMixerLogging()) { - rda->syslog(LOG_INFO, - "FadeOutputVolume - Card: %d Stream: %d Port: %d Level: %d Length: %d", - card,stream,port,level,length); + if(!rda->config()->testOutputStreams()) { + if(!dvr->fadeOutputVolume(card,stream,port,level,length)) { + cae_server-> + sendCommand(id,QString::asprintf("FV %u %u %u %d %u -!", + card,stream,port,level,length)); + return; + } + if(rda->config()->enableMixerLogging()) { + rda->syslog(LOG_INFO, + "FadeOutputVolume - Card: %d Stream: %d Port: %d Level: %d Length: %d", + card,stream,port,level,length); + } } cae_server-> sendCommand(id,QString::asprintf("FV %u %u %u %d %u +!", @@ -1620,6 +1673,8 @@ Driver *MainObject::GetDriver(unsigned card) const void MainObject::MakeDriver(unsigned *next_card,RDStation::AudioDriver type) { + unsigned first_card=*next_card; + int initial_output_volume=RD_MUTE_DEPTH; Driver *dvr=NULL; switch(type) { @@ -1653,6 +1708,9 @@ void MainObject::MakeDriver(unsigned *next_card,RDStation::AudioDriver type) case RDStation::None: break; } + if(rda->config()->testOutputStreams()) { + initial_output_volume=0; + } if(dvr!=NULL) { if(dvr->initialize(next_card)) { connect(dvr,SIGNAL(playStateChanged(int,int,int)), @@ -1660,6 +1718,13 @@ void MainObject::MakeDriver(unsigned *next_card,RDStation::AudioDriver type) connect(dvr,SIGNAL(recordStateChanged(int,int,int)), this,SLOT(stateRecordUpdate(int,int,int))); d_drivers.push_back(dvr); + for(unsigned i=first_card;i<*next_card;i++) { + for(int j=0;jsetOutputVolume(i,j,k,initial_output_volume); + } + } + } } else { delete dvr; diff --git a/cae/cae.h b/cae/cae.h index 6ebd29f1..d72c24bb 100644 --- a/cae/cae.h +++ b/cae/cae.h @@ -85,7 +85,9 @@ class MainObject : public QObject int threshold_level); void stopRecordingData(int id,unsigned card,unsigned stream); void setInputVolumeData(int id,unsigned card,unsigned stream,int level); - void setOutputVolumeData(int id,unsigned card,unsigned stream,unsigned port, + void setOutputPortData(int id,unsigned card,unsigned stream,unsigned port, + int level); + void setOutputVolumeData(int id,unsigned card,unsigned stream,int port, int level); void fadeOutputVolumeData(int id,unsigned card,unsigned stream,unsigned port, int level,unsigned length); diff --git a/cae/cae_server.cpp b/cae/cae_server.cpp index f23f535d..27fecdb9 100644 --- a/cae/cae_server.cpp +++ b/cae/cae_server.cpp @@ -413,13 +413,31 @@ bool CaeServer::ProcessCommand(int id,const QString &cmd) } } } - if((f0.at(0)=="OV")&&(f0.size()==5)) { // Set Output Volume + if((f0.at(0)=="OP")&&(f0.size()==5)) { // Set Output Port unsigned card=f0.at(1).toUInt(&ok); if(ok&&(card +// (C) Copyright 2019-2023 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 @@ -79,7 +79,9 @@ class CaeServer : public QObject int threshold_level); void stopRecordingReq(int id,unsigned card,unsigned stream); void setInputVolumeReq(int id,unsigned card,unsigned stream,int level); - void setOutputVolumeReq(int id,unsigned card,unsigned stream,unsigned port, + void setOutputPortReq(int id,unsigned card,unsigned stream,unsigned port, + int level); + void setOutputVolumeReq(int id,unsigned card,unsigned stream,int port, int level); void fadeOutputVolumeReq(int id,unsigned card,unsigned stream,unsigned port, int level,unsigned length); diff --git a/conf/rd.conf-sample b/conf/rd.conf-sample index 4782f7f3..748e039e 100644 --- a/conf/rd.conf-sample +++ b/conf/rd.conf-sample @@ -225,6 +225,16 @@ TranscodingDelay=0 ; ;SuppressRdcatchMeterUpdates=No +[Caed] +; When set to 'Yes', log all CAE mixer operations to syslog. +;EnableMixerLogging=No + +; When set to 'Yes', set all output stream to port volume settings to 0 dB +; and disable 'Set Output Port' ['OP'], 'Set Output Volume' ['OV'] and +; 'Fade Output Volume' ['FV'] CAE commands. +; TestOutputStreams=No +TestOutputStreams=No + [Debugging] ; IMPORTANT NOTE: ; The directives in this section can send large amounts of data to the diff --git a/docs/apis/cae.xml b/docs/apis/cae.xml index 596955c2..68018194 100644 --- a/docs/apis/cae.xml +++ b/docs/apis/cae.xml @@ -173,7 +173,8 @@ <command>Unload Playback</command> - Free an audio playback interface. + Free an audio playback interface. This will also mute all associated + output stream->output port volume controls. UP conn-handle! @@ -662,6 +663,70 @@ + + <command>Set Output Port</command> + + Configure an output stream to use a particular output port. + + + This will cause the stream-num output volume + control feeding the port-num port to be set + to the level given by level, while all other + output_volume controls for that stream to be muted --e.g. set to + -100 dB. + + + OP card-num + stream-num + port-num + level! + + + + + card-num + + + + The number of the audio adapter to use. + + + + + + stream-num + + + + The stream number to use. This is relative to the audio adapter + selected. + + + + + + port-num + + + + The port number to use. This is relative to the audio adapter + selected. + + + + + + level + + + + The level, in hundreths of a dB. + + + + + + <command>Set Output Volume</command> @@ -702,7 +767,10 @@ The port number to use. This is relative to the audio adapter - selected. + selected. If a value less than 0 is + provided, then all output ports for + stream-num will have their volume + controls set to level. diff --git a/lib/rdcae.cpp b/lib/rdcae.cpp index 369a7ef1..2f59a9ce 100644 --- a/lib/rdcae.cpp +++ b/lib/rdcae.cpp @@ -2,7 +2,7 @@ // // Connection to the Rivendell Core Audio Engine // -// (C) Copyright 2002-2021 Fred Gleason +// (C) Copyright 2002-2023 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 @@ -278,12 +278,7 @@ void RDCae::setOutputVolume(int card,int stream,int port,int level) void RDCae::setOutputPort(int card,int stream,int port) { - for(int i=0;i +// (C) Copyright 2002-2023 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 @@ -55,9 +55,7 @@ class RDCae : public QObject void setClockSource(int card,RDCae::ClockSource src); void setInputVolume(int card,int stream,int level); void setOutputVolume(int card,int stream,int port,int level); - void setOutputPort(int card,int stream,int port); - void fadeOutputVolume(int card,int stream,int port,int level,int length); void setInputLevel(int card,int port,int level); void setOutputLevel(int card,int port,int level); diff --git a/lib/rdconfig.cpp b/lib/rdconfig.cpp index 50512b8f..6c79cc44 100644 --- a/lib/rdconfig.cpp +++ b/lib/rdconfig.cpp @@ -489,6 +489,12 @@ bool RDConfig::enableMixerLogging() const } +bool RDConfig::testOutputStreams() const +{ + return conf_test_output_streams; +} + + bool RDConfig::useRealtime() { return conf_use_realtime; @@ -707,6 +713,7 @@ bool RDConfig::load() conf_syslog_facility=profile->intValue("Identity","SyslogFacility",LOG_USER); conf_enable_mixer_logging=profile->boolValue("Caed","EnableMixerLogging"); + conf_test_output_streams=profile->boolValue("Caed","TestOutputStreams"); conf_use_realtime=profile->boolValue("Tuning","UseRealtime",false); conf_realtime_priority=profile->intValue("Tuning","RealtimePriority",9); conf_transcoding_delay=profile->intValue("Tuning","TranscodingDelay"); @@ -824,6 +831,7 @@ void RDConfig::clear() conf_rn_rml_uid=65535; conf_rn_rml_gid=65535; conf_enable_mixer_logging=false; + conf_test_output_streams=false; conf_use_realtime=false; conf_realtime_priority=9; conf_transcoding_delay=0; diff --git a/lib/rdconfig.h b/lib/rdconfig.h index 54d7a4eb..98aa3fa0 100644 --- a/lib/rdconfig.h +++ b/lib/rdconfig.h @@ -112,6 +112,7 @@ class RDConfig bool logSqlQueries() const; int logSqlQueriesLevel() const; bool enableMixerLogging() const; + bool testOutputStreams() const; uid_t uid() const; gid_t gid() const; uid_t pypadUid() const; @@ -204,6 +205,7 @@ class RDConfig uid_t conf_rn_rml_uid; gid_t conf_rn_rml_gid; bool conf_enable_mixer_logging; + bool conf_test_output_streams; bool conf_use_realtime; int conf_transcoding_delay; int conf_realtime_priority; diff --git a/lib/rdplay_deck.cpp b/lib/rdplay_deck.cpp index c1242fb1..8ec19381 100644 --- a/lib/rdplay_deck.cpp +++ b/lib/rdplay_deck.cpp @@ -465,9 +465,7 @@ void RDPlayDeck::play(unsigned pos,int segue_start,int segue_end, pause_called=false; play_cae->positionPlay(play_handle,play_audio_point[0]+pos); play_cae->setPlayPortActive(play_card,play_port,play_stream); - for(int i=0;isetOutputVolume(play_card,play_stream,i,RD_MUTE_DEPTH); - } + play_cae->setOutputVolume(play_card,play_stream,-1,RD_MUTE_DEPTH); if((play_fade_point[0]==-1)||(play_fade_point[0]==play_audio_point[0])|| ((fadeup=play_fade_point[0]-play_audio_point[0]-pos)<=0)|| (play_state==RDPlayDeck::Paused)) {