2023-08-24 Fred Gleason <fredg@paravelsystems.com>

* 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 <fredg@paravelsystems.com>
This commit is contained in:
Fred Gleason 2023-08-24 13:10:10 -04:00
parent d9e16f65a0
commit ba1e2d84ab
12 changed files with 215 additions and 41 deletions

View File

@ -24365,3 +24365,11 @@
2023-08-24 Fred Gleason <fredg@paravelsystems.com>
* Fixed a regression in the 'RDHPIPlayStream' that could cause
audio play-out to be truncated.
2023-08-24 Fred Gleason <fredg@paravelsystems.com>
* 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.

View File

@ -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;i<RD_MAX_PORTS;i++) {
dvr->setOutputVolume(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;i<RD_MAX_STREAMS;i++) {
if(i==port) {
dvr->setOutputVolume(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;i<RD_MAX_PORTS;i++) {
dvr->setOutputVolume(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;j<RD_MAX_STREAMS;j++) {
for(int k=0;k<RD_MAX_PORTS;k++) {
dvr->setOutputVolume(i,j,k,initial_output_volume);
}
}
}
}
else {
delete dvr;

View File

@ -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);

View File

@ -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<RD_MAX_CARDS)) {
unsigned stream=f0.at(2).toUInt(&ok);
if(ok&&(stream<RD_MAX_STREAMS)) {
if(ok) {
unsigned port=f0.at(3).toUInt(&ok);
if(ok&&(port<RD_MAX_PORTS)) {
int level=f0.at(4).toInt(&ok);
if(ok) {
emit setOutputPortReq(id,card,stream,port,level);
was_processed=true;
}
}
}
}
}
}
if((f0.at(0)=="OV")&&(f0.size()==5)) { // Set Output Volume
unsigned card=f0.at(1).toUInt(&ok);
if(ok&&(card<RD_MAX_CARDS)) {
unsigned stream=f0.at(2).toUInt(&ok);
if(ok&&(stream<RD_MAX_STREAMS)) {
if(ok) {
int port=f0.at(3).toInt(&ok);
if(ok&&(port<RD_MAX_PORTS)) {
int level=f0.at(4).toInt(&ok);
if(ok) {

View File

@ -2,7 +2,7 @@
//
// Network server for caed(8).
//
// (C) Copyright 2019 Fred Gleason <fredg@paravelsystems.com>
// (C) Copyright 2019-2023 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
@ -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);

View File

@ -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

View File

@ -173,7 +173,8 @@
<sect2>
<title><command>Unload Playback</command></title>
<para>
Free an audio playback interface.
Free an audio playback interface. This will also mute all associated
output stream->output port volume controls.
</para>
<para>
<userinput>UP <replaceable>conn-handle</replaceable>!</userinput>
@ -662,6 +663,70 @@
</variablelist>
</sect2>
<sect2>
<title><command>Set Output Port</command></title>
<para>
Configure an output stream to use a particular output port.
</para>
<para>
This will cause the <replaceable>stream-num</replaceable> output volume
control feeding the <replaceable>port-num</replaceable> port to be set
to the level given by <replaceable>level</replaceable>, while all other
output_volume controls for that stream to be muted --e.g. set to
-100 dB.
</para>
<para>
<userinput>OP <replaceable>card-num</replaceable>
<replaceable>stream-num</replaceable>
<replaceable>port-num</replaceable>
<replaceable>level</replaceable>!</userinput>
</para>
<variablelist>
<varlistentry>
<term>
<replaceable>card-num</replaceable>
</term>
<listitem>
<para>
The number of the audio adapter to use.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<replaceable>stream-num</replaceable>
</term>
<listitem>
<para>
The stream number to use. This is relative to the audio adapter
selected.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<replaceable>port-num</replaceable>
</term>
<listitem>
<para>
The port number to use. This is relative to the audio adapter
selected.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<replaceable>level</replaceable>
</term>
<listitem>
<para>
The level, in hundreths of a dB.
</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
<sect2>
<title><command>Set Output Volume</command></title>
<para>
@ -702,7 +767,10 @@
<listitem>
<para>
The port number to use. This is relative to the audio adapter
selected.
selected. If a value less than <userinput>0</userinput> is
provided, then <emphasis>all</emphasis> output ports for
<replaceable>stream-num</replaceable> will have their volume
controls set to <replaceable>level</replaceable>.
</para>
</listitem>
</varlistentry>

View File

@ -2,7 +2,7 @@
//
// Connection to the Rivendell Core Audio Engine
//
// (C) Copyright 2002-2021 Fred Gleason <fredg@paravelsystems.com>
// (C) Copyright 2002-2023 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
@ -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<RD_MAX_PORTS;i++) {
if(i!=port) {
setOutputVolume(card,stream,i,-10000);
}
}
setOutputVolume(card,stream,port,0);
SendCommand(QString::asprintf("OP %d %d %d 0!",card,stream,port));
}

View File

@ -2,7 +2,7 @@
//
// Connection to the Rivendell Core Audio Engine
//
// (C) Copyright 2002-2021 Fred Gleason <fredg@paravelsystems.com>
// (C) Copyright 2002-2023 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
@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;i<RD_MAX_PORTS;i++) {
play_cae->setOutputVolume(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)) {