2023-12-14 Fred Gleason <fredg@paravelsystems.com>

* Fixed regressions in the CAE subsystem that broke play-out positing
	and active output port reporting.

Signed-off-by: Fred Gleason <fredg@paravelsystems.com>
This commit is contained in:
Fred Gleason
2023-12-14 17:43:26 -05:00
parent b939c2772c
commit f21b526263
27 changed files with 1148 additions and 1024 deletions

View File

@@ -2,7 +2,7 @@
##
## Core Audio Engine Makefile.am for Rivendell
##
## Copyright 2002-2021 Fred Gleason <fredg@paravelsystems.com>
## 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
@@ -34,7 +34,8 @@ dist_caed_SOURCES = cae.cpp cae.h\
driver.cpp driver.h\
driver_alsa.cpp driver_alsa.h\
driver_hpi.cpp driver_hpi.h\
driver_jack.cpp driver_jack.h
driver_jack.cpp driver_jack.h\
playsession.cpp play_session.h
nodist_caed_SOURCES = moc_cae.cpp\
moc_cae_server.cpp\

View File

@@ -114,19 +114,11 @@ MainObject::MainObject(QObject *parent)
}
}
}
for(int i=0;i<256;i++) {
play_handle[i].card=-1;
play_handle[i].stream=-1;
play_handle[i].owner=-1;
}
next_play_handle=0;
for(int i=0;i<RD_MAX_CARDS;i++) {
for(int j=0;j<RD_MAX_STREAMS;j++) {
record_length[i][j]=0;
record_threshold[i][j]=-10000;
record_owner[i][j]=-1;
play_owner[i][j]=-1;
play_length[i][j]=0;
play_speed[i][j]=100;
play_pitch[i][j]=false;
@@ -152,16 +144,18 @@ MainObject::MainObject(QObject *parent)
}
connect(cae_server,SIGNAL(connectionDropped(int)),
this,SLOT(connectionDroppedData(int)));
connect(cae_server,SIGNAL(loadPlaybackReq(int,unsigned,const QString &)),
this,SLOT(loadPlaybackData(int,unsigned,const QString &)));
connect(cae_server,SIGNAL(unloadPlaybackReq(int,unsigned)),
this,SLOT(unloadPlaybackData(int,unsigned)));
connect(cae_server,SIGNAL(playPositionReq(int,unsigned,unsigned)),
this,SLOT(playPositionData(int,unsigned,unsigned)));
connect(cae_server,SIGNAL(playReq(int,unsigned,unsigned,unsigned,unsigned)),
this,SLOT(playData(int,unsigned,unsigned,unsigned,unsigned)));
connect(cae_server,SIGNAL(stopPlaybackReq(int,unsigned)),
this,SLOT(stopPlaybackData(int,unsigned)));
connect(cae_server,
SIGNAL(loadPlaybackReq(uint64_t,unsigned,unsigned,const QString &)),
this,
SLOT(loadPlaybackData(uint64_t,unsigned,unsigned,const QString &)));
connect(cae_server,SIGNAL(unloadPlaybackReq(uint64_t)),
this,SLOT(unloadPlaybackData(uint64_t)));
connect(cae_server,SIGNAL(playPositionReq(uint64_t,unsigned)),
this,SLOT(playPositionData(uint64_t,unsigned)));
connect(cae_server,SIGNAL(playReq(uint64_t,unsigned,unsigned,unsigned)),
this,SLOT(playData(uint64_t,unsigned,unsigned,unsigned)));
connect(cae_server,SIGNAL(stopPlaybackReq(uint64_t)),
this,SLOT(stopPlaybackData(uint64_t)));
connect(cae_server,SIGNAL(timescalingSupportReq(int,unsigned)),
this,SLOT(timescalingSupportData(int,unsigned)));
connect(cae_server,
@@ -178,14 +172,10 @@ MainObject::MainObject(QObject *parent)
this,SLOT(stopRecordingData(int,unsigned,unsigned)));
connect(cae_server,SIGNAL(setInputVolumeReq(int,unsigned,unsigned,int)),
this,SLOT(setInputVolumeData(int,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,
unsigned,int,unsigned)));
connect(cae_server,SIGNAL(setOutputVolumeReq(uint64_t,int)),
this,SLOT(setOutputVolumeData(uint64_t,int)));
connect(cae_server,SIGNAL(fadeOutputVolumeReq(uint64_t,int,unsigned)),
this,SLOT(fadeOutputVolumeData(uint64_t,int,unsigned)));
connect(cae_server,SIGNAL(setInputLevelReq(int,unsigned,unsigned,int)),
this,SLOT(setInputLevelData(int,unsigned,unsigned,int)));
connect(cae_server,SIGNAL(setOutputLevelReq(int,unsigned,unsigned,int)),
@@ -326,194 +316,210 @@ MainObject::MainObject(QObject *parent)
}
void MainObject::loadPlaybackData(int id,unsigned card,const QString &name)
void MainObject::loadPlaybackData(uint64_t phandle,unsigned cardnum,
unsigned portnum,const QString &name)
{
QString wavename;
int new_stream=-1;
int handle;
Driver *dvr=GetDriver(card);
unsigned serial=PlaySession::serialNumber(phandle);
Driver *dvr=GetDriver(cardnum);
if(dvr==NULL) {
cae_server->
sendCommand(id,QString::asprintf("LP %d %s -1 -1 -!",card,
name.toUtf8().constData()));
sendCommand(phandle,QString::asprintf("LP %u %u %u %s -!",
serial,cardnum,portnum,
name.toUtf8().constData()));
return;
}
wavename=rda->config()->audioFileName(name);
if(!dvr->loadPlayback(card,wavename,&new_stream)) {
if(dvr->loadPlayback(cardnum,wavename,&new_stream)) {
play_sessions[phandle]=new PlaySession(phandle,cardnum,portnum,new_stream);
}
else {
cae_server->
sendCommand(id,QString::asprintf("LP %d %s -1 -1 -!",card,
name.toUtf8().constData()));
sendCommand(phandle,QString::asprintf("LP %u %u %u %s -!",
serial,cardnum,portnum,
name.toUtf8().constData()));
rda->syslog(LOG_WARNING,
"unable to allocate stream for card %d",card);
"unable to allocate stream for card %d",cardnum);
return;
}
if((handle=GetHandle(card,new_stream))>=0) {
rda->syslog(LOG_WARNING,
"*** clearing stale stream assignment, card=%d stream=%d ***",
card,new_stream);
play_handle[handle].card=-1;
play_handle[handle].stream=-1;
play_handle[handle].owner=-1;
}
handle=GetNextHandle();
play_handle[handle].card=card;
play_handle[handle].stream=new_stream;
play_handle[handle].owner=id;
play_owner[card][new_stream]=id;
//
// Mute all volume controls for the stream
//
for(int i=0;i<dvr->outputPortQuantity(card);i++) {
dvr->setOutputVolume(card,new_stream,i,RD_MUTE_DEPTH);
for(int i=0;i<dvr->outputPortQuantity(cardnum);i++) {
dvr->setOutputVolume(cardnum,new_stream,i,RD_MUTE_DEPTH);
}
rda->syslog(LOG_INFO,
"LoadPlayback Card: %d Stream: %d Name: %s Handle: %d",
card,new_stream,(const char *)wavename.toUtf8(),handle);
rda->
syslog(LOG_INFO,"LoadPlayback Card: %d Stream: %d Name: %s Serial: %u",
cardnum,new_stream,wavename.toUtf8().constData(),serial);
cae_server->
sendCommand(id,QString::asprintf("LP %d %s %d %d +!",card,
(const char *)name.toUtf8(),
new_stream,handle));
sendCommand(phandle,QString::asprintf("LP %u %u %u %s +!",
serial,cardnum,portnum,
name.toUtf8().constData()));
}
void MainObject::unloadPlaybackData(int id,unsigned handle)
void MainObject::unloadPlaybackData(uint64_t phandle)
{
int card=play_handle[handle].card;
int stream=play_handle[handle].stream;
Driver *dvr=GetDriver(card);
PlaySession *psess=play_sessions.value(phandle);
unsigned serial=PlaySession::serialNumber(phandle);
if(dvr==NULL) {
cae_server->sendCommand(id,QString::asprintf("UP %d -!",handle));
return;
}
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);
cae_server->sendCommand(id,QString::asprintf("UP %d +!",handle));
}
else {
cae_server->sendCommand(id,QString::asprintf("UP %d -!",handle));
}
play_handle[handle].card=-1;
play_handle[handle].stream=-1;
play_handle[handle].owner=-1;
return;
if(psess==NULL) {
cae_server->sendCommand(phandle,QString::asprintf("UP %u -!",serial));
rda->syslog(LOG_WARNING,
"attempted to unload non-existent session, serial:%u",serial);
}
else {
cae_server->sendCommand(id,QString::asprintf("UP %d -!",handle));
}
}
void MainObject::playPositionData(int id,unsigned handle,unsigned pos)
{
int card=play_handle[handle].card;
int stream=play_handle[handle].stream;
Driver *dvr=GetDriver(card);
if(dvr==NULL) {
cae_server->sendCommand(id,QString::asprintf("PP %d %d -!",handle,pos));
return;
}
if(play_owner[card][stream]==id) {
if(dvr->playbackPosition(card,stream,pos)) {
rda->syslog(LOG_INFO,
"PlaybackPosition - Card: %d Stream: %d Pos: %d Handle: %d",
card,stream,pos,handle);
cae_server->sendCommand(id,QString::asprintf("PP %d %d +!",handle,pos));
Driver *dvr=GetDriver(psess->cardNumber());
if(dvr==NULL) {
cae_server->sendCommand(phandle,QString::asprintf("UP %u -!",serial));
rda->syslog(LOG_WARNING,
"attempted to access non-existent card, serial: %u card: %u",
serial,psess->cardNumber());
}
else {
cae_server->sendCommand(id,QString::asprintf("PP %d %d -!",handle,pos));
if(dvr->unloadPlayback(psess->cardNumber(),psess->streamNumber())) {
if(!rda->config()->testOutputStreams()) {
for(int i=0;i<RD_MAX_PORTS;i++) {
dvr->setOutputVolume(psess->cardNumber(),psess->streamNumber(),i,
RD_MUTE_DEPTH); // Clear mixer
}
}
rda->syslog(LOG_INFO,
"UnloadPlayback - Card: %d Stream: %d Serial: %u",
psess->cardNumber(),psess->streamNumber(),
psess->serialNumber());
cae_server->sendCommand(phandle,QString::asprintf("UP %u +!",serial));
}
else {
cae_server->sendCommand(phandle,QString::asprintf("UP %d -!",serial));
rda->syslog(LOG_WARNING,
"failed to unload play session, serial: %u, card: %u stream: %d",
serial,psess->cardNumber(),psess->streamNumber());
}
play_sessions.remove(phandle);
}
return;
}
cae_server->sendCommand(id,QString::asprintf("PP %d %d -!",handle,pos));
}
void MainObject::playData(int id,unsigned handle,unsigned length,unsigned speed,
void MainObject::playPositionData(uint64_t phandle,unsigned pos)
{
PlaySession *psess=play_sessions.value(phandle);
unsigned serial=PlaySession::serialNumber(phandle);
if(psess==NULL) {
cae_server->sendCommand(phandle,QString::asprintf("PP %u %u -!",
serial,pos));
rda->syslog(LOG_WARNING,
"attempted to unload non-existent session, serial: %u",serial);
}
else {
Driver *dvr=GetDriver(psess->cardNumber());
if(dvr==NULL) {
cae_server->sendCommand(phandle,QString::asprintf("PP %u %u -!",
serial,pos));
rda->syslog(LOG_WARNING,
"attempted to access non-existent card, serial: %u pos: %u",
serial,pos);
}
else {
if(dvr->playbackPosition(psess->cardNumber(),psess->streamNumber(),pos)) {
rda->
syslog(LOG_DEBUG,
"PlaybackPosition - Card: %d Stream: %d Pos: %d Serial: %d",
psess->cardNumber(),psess->streamNumber(),pos,serial);
cae_server->
sendCommand(phandle,QString::asprintf("PP %u %u +!",serial,pos));
}
else {
cae_server->
sendCommand(phandle,QString::asprintf("PP %u %u -!",serial,pos));
rda->syslog(LOG_WARNING,"PlaybackPosition failed, serial: %u, pos: %u",
serial,pos);
}
}
}
}
void MainObject::playData(uint64_t phandle,unsigned length,unsigned speed,
unsigned pitch_flag)
{
int card=play_handle[handle].card;
int stream=play_handle[handle].stream;
Driver *dvr=GetDriver(card);
PlaySession *psess=play_sessions.value(phandle);
unsigned serial=PlaySession::serialNumber(phandle);
if(dvr==NULL) {
if(psess==NULL) {
cae_server->
sendCommand(id,QString::asprintf("PY %u %u %u %u -!",
handle,length,speed,pitch_flag));
return;
sendCommand(phandle,QString::asprintf("PY %u %u %u %u -!",
serial,length,speed,pitch_flag));
rda->syslog(LOG_WARNING,
"attempted to play non-existent session, serial:%u",serial);
}
play_length[card][stream]=length;
play_speed[card][stream]=speed;
switch(pitch_flag) {
case 0:
play_pitch[card][stream]=false;
break;
case 1:
play_pitch[card][stream]=true;
break;
default:
else {
Driver *dvr=GetDriver(psess->cardNumber());
if(dvr==NULL) {
cae_server->
sendCommand(id,QString::asprintf("PY %u %u %u %u -!",
handle,length,speed,pitch_flag));
return;
}
if(play_owner[card][stream]==id) {
if(!dvr->play(card,stream,play_length[card][stream],
play_speed[card][stream],play_pitch[card][stream],
RD_ALLOW_NONSTANDARD_RATES)) {
cae_server->
sendCommand(id,QString::asprintf("PY %u %u %u %u -!",
handle,length,speed,pitch_flag));
return;
sendCommand(phandle,QString::asprintf("PY %u %u %u %u -!",
serial,length,speed,pitch_flag));
rda->syslog(LOG_WARNING,
"attempted to access non-existent card, serial: %u card: %u",
serial,psess->cardNumber());
}
else {
psess->setLength(length);
psess->setSpeed(speed);
if(!dvr->play(psess->cardNumber(),psess->streamNumber(),psess->length(),
psess->speed(),false,RD_ALLOW_NONSTANDARD_RATES)) {
cae_server->
sendCommand(phandle,QString::asprintf("PY %u %u %u %u -!",
serial,length,speed,
pitch_flag));
}
else {
rda->syslog(LOG_INFO,
"Play - Card: %d Stream: %d Serial: %d Length: %d Speed: %d Pitch: %d",
psess->cardNumber(),psess->streamNumber(),serial,
psess->length(),psess->speed(),pitch_flag);
// No command echo for success -- statePlayUpdate() sends it!
}
}
rda->syslog(LOG_INFO,
"Play - Card: %d Stream: %d Handle: %d Length: %d Speed: %d Pitch: %d",
card,stream,handle,play_length[card][stream],
play_speed[card][stream],pitch_flag);
// No command echo for success -- statePlayUpdate() sends it!
return;
}
cae_server->
sendCommand(id,QString::asprintf("PY %u %u %u %u -!",
handle,length,speed,pitch_flag));
}
void MainObject::stopPlaybackData(int id,unsigned handle)
void MainObject::stopPlaybackData(uint64_t phandle)
{
int card=play_handle[handle].card;
int stream=play_handle[handle].stream;
Driver *dvr=GetDriver(card);
PlaySession *psess=play_sessions.value(phandle);
unsigned serial=PlaySession::serialNumber(phandle);
if(dvr==NULL) {
cae_server->sendCommand(id,QString::asprintf("SP %u -!",handle));
return;
if(psess==NULL) {
cae_server->sendCommand(phandle,QString::asprintf("SP %u -!",serial));
rda->syslog(LOG_WARNING,
"attempted to stop non-existent session, serial: %u",serial);
}
if(play_owner[card][stream]==id) {
if(!dvr->stopPlayback(card,stream)) {
cae_server->sendCommand(id,QString::asprintf("SP %u -!",handle));
else {
Driver *dvr=GetDriver(psess->cardNumber());
if(dvr==NULL) {
cae_server->sendCommand(phandle,QString::asprintf("SP %u -!",serial));
rda->syslog(LOG_WARNING,
"attempted to access non-existent card, serial: %u card: %u",
serial,psess->cardNumber());
}
else {
if(!dvr->stopPlayback(psess->cardNumber(),psess->streamNumber())) {
cae_server->sendCommand(phandle,QString::asprintf("SP %u -!",serial));
return;
}
rda->syslog(LOG_INFO,"StopPlayback - Card: %d Stream: %d Serial: %d",
psess->cardNumber(),psess->streamNumber(),serial);
return;
}
rda->syslog(LOG_INFO,
"StopPlayback - Card: %d Stream: %d Handle: %d",
card,stream,handle);
return;
}
cae_server->sendCommand(id,QString::asprintf("SP %u -!",handle));
cae_server->sendCommand(phandle,QString::asprintf("SP %u -!",serial));
}
@@ -685,67 +691,97 @@ void MainObject::setInputVolumeData(int id,unsigned card,unsigned stream,
}
void MainObject::setOutputVolumeData(int id,unsigned card,unsigned stream,
int port,int level)
void MainObject::setOutputVolumeData(uint64_t phandle,int level)
{
Driver *dvr=GetDriver(card);
PlaySession *psess=play_sessions.value(phandle);
unsigned serial=PlaySession::serialNumber(phandle);
if(dvr==NULL) {
cae_server->sendCommand(id,QString::asprintf("OV %u %u %u %d -!",
card,stream,port,level));
return;
if(psess==NULL) {
cae_server->sendCommand(phandle,QString::asprintf("SP %u -!",serial));
rda->syslog(LOG_WARNING,
"attempted to operate non-existent session, serial: %u",serial);
}
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 {
Driver *dvr=GetDriver(psess->cardNumber());
if(dvr==NULL) {
cae_server->sendCommand(phandle,QString::asprintf("SP %u -!",serial));
rda->syslog(LOG_WARNING,
"attempted to access non-existent card, serial: %u card: %u",
serial,psess->cardNumber());
}
else {
for(int i=0;i<RD_MAX_PORTS;i++) {
dvr->setOutputVolume(card,stream,i,level);
if(!rda->config()->testOutputStreams()) {
if(psess->portNumber()>=0) {
if(!dvr->setOutputVolume(psess->cardNumber(),psess->streamNumber(),
psess->portNumber(),level)) {
cae_server->sendCommand(phandle,QString::asprintf("OV %u %d -!",
serial,level));
return;
}
}
/* RESET SECTION?
else {
for(int i=0;i<RD_MAX_PORTS;i++) {
dvr->setOutputVolume(card,stream,i,level);
}
}
*/
if(rda->config()->enableMixerLogging()) {
rda->syslog(LOG_INFO,
"[mixer] SetOutputVolume - Serial: %u Card: %d Stream: %d Port: %d Level: %d",
serial,psess->cardNumber(),psess->streamNumber(),
psess->portNumber(),level);
}
}
}
if(rda->config()->enableMixerLogging()) {
rda->syslog(LOG_INFO,
"[mixer] SetOutputVolume - Card: %d Stream: %d Port: %d Level: %d",
card,stream,port,level);
cae_server->sendCommand(phandle,QString::asprintf("OV %u %d +!",
serial,level));
}
}
cae_server->sendCommand(id,QString::asprintf("OV %u %u %u %d +!",
card,stream,port,level));
}
void MainObject::fadeOutputVolumeData(int id,unsigned card,unsigned stream,
unsigned port,int level,unsigned length)
void MainObject::fadeOutputVolumeData(uint64_t phandle,int level,
unsigned length)
{
Driver *dvr=GetDriver(card);
PlaySession *psess=play_sessions.value(phandle);
unsigned serial=PlaySession::serialNumber(phandle);
if(dvr==NULL) {
cae_server->
sendCommand(id,QString::asprintf("FV %u %u %u %d %u -!",
card,stream,port,level,length));
return;
if(psess==NULL) {
cae_server->sendCommand(phandle,QString::asprintf("FV %u %d %u -!",
serial,level,length));
rda->syslog(LOG_WARNING,
"attempted to operate non-existent session, serial: %u",serial);
}
if(!rda->config()->testOutputStreams()) {
if(!dvr->fadeOutputVolume(card,stream,port,level,length)) {
else {
Driver *dvr=GetDriver(psess->cardNumber());
if(dvr==NULL) {
cae_server->sendCommand(phandle,QString::asprintf("FV %u %d %u -!",
serial,level,length));
rda->syslog(LOG_WARNING,
"attempted to access non-existent card, serial: %u card: %u",
serial,psess->cardNumber());
}
else {
if(!rda->config()->testOutputStreams()) {
if(!dvr->fadeOutputVolume(psess->cardNumber(),psess->streamNumber(),
psess->portNumber(),level,length)) {
cae_server->
sendCommand(phandle,QString::asprintf("FV %u %d %u -!",
serial,level,length));
return;
}
if(rda->config()->enableMixerLogging()) {
rda->syslog(LOG_INFO,
"[mixer] FadeOutputVolume - Serial: %u Card: %d Stream: %d Port: %d Level: %d Length: %d",
serial,psess->cardNumber(),psess->streamNumber(),
psess->portNumber(),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,
"[mixer] FadeOutputVolume - Card: %d Stream: %d Port: %d Level: %d Length: %d",
card,stream,port,level,length);
sendCommand(phandle,QString::asprintf("FV %u %d %u +!",
serial,level,length));
}
}
cae_server->
sendCommand(id,QString::asprintf("FV %u %u %u %d %u +!",
card,stream,port,level,length));
}
@@ -1024,33 +1060,31 @@ 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);
rda->syslog(LOG_NOTICE,"statePlayUpdate(%d,%d,%d)\n",card,stream,state);
uint64_t phandle=GetPlayHandle(card,stream);
unsigned serial=PlaySession::serialNumber(phandle);
PlaySession *psess=play_sessions.value(phandle);
if(handle<0) {
if(psess==NULL) {
return;
}
if(play_owner[card][stream]!=-1) {
switch(state) {
case 1: // Playing
cae_server->sendCommand(play_owner[card][stream],
QString::asprintf("PY %d %d %d +!",handle,
play_length[card][stream],
play_speed[card][stream]).toUtf8());
break;
switch(state) {
case 1: // Playing
cae_server->
sendCommand(phandle,QString::asprintf("PY %u %d %d 0 +!",
serial,
psess->length(),
psess->speed()));
break;
case 2: // Paused
cae_server->
sendCommand(play_owner[card][stream],
QString::asprintf("SP %d +!",handle).toUtf8());
break;
case 2: // Paused
cae_server->sendCommand(phandle,QString::asprintf("SP %d +!",serial));
break;
case 0: // Stopped
cae_server->
sendCommand(play_owner[card][stream],
QString::asprintf("SP %d +!",handle).toUtf8());
break;
}
case 0: // Stopped
cae_server->
sendCommand(phandle,QString::asprintf("SP %d +!",serial).toUtf8());
break;
}
}
@@ -1230,16 +1264,19 @@ void MainObject::InitMixers()
}
void MainObject::KillSocket(int ch)
void MainObject::KillSocket(int sock)
{
for(int i=0;i<RD_MAX_CARDS;i++) {
Driver *dvr=GetDriver(i);
for(int j=0;j<RD_MAX_STREAMS;j++) {
if(record_owner[i][j]==ch) {
rda->syslog(LOG_DEBUG,"force unloading record context for connection %s:%u: Card: %d Stream: %d Handle: %d",
cae_server->peerAddress(ch).toString().toUtf8().constData(),
0xFFFF&cae_server->peerPort(ch),
i,j,GetHandle(i,j));
//
// Clear Active Record Events
//
if(record_owner[i][j]==sock) {
rda->syslog(LOG_DEBUG,"force unloading record context for connection %s:%u: Card: %d Stream: %d",
cae_server->peerAddress(sock).toString().toUtf8().constData(),
0xFFFF&cae_server->peerPort(sock),
i,j);
unsigned len=0;
if(dvr!=NULL) {
dvr->unloadRecord(i,j,&len);
@@ -1248,26 +1285,25 @@ void MainObject::KillSocket(int ch)
record_threshold[i][j]=-10000;
record_owner[i][j]=-1;
}
if(play_owner[i][j]==ch) {
rda->syslog(LOG_DEBUG,"force unloading play context for connection %d [%s:%u]: Card: %d Stream: %d Handle: %d",
ch,
cae_server->peerAddress(ch).toString().toUtf8().constData(),
0xFFFF&cae_server->peerPort(ch),
i,j,GetHandle(i,j));
if(dvr!=NULL) {
dvr->unloadPlayback(i,j);
//
// Clear Active Playout Events
//
QMap<uint64_t,PlaySession *>::iterator it=play_sessions.begin();
while(it!=play_sessions.end()) {
if((it.value()!=NULL)&&(it.value()->socketDescriptor()==sock)) {
rda->syslog(LOG_DEBUG,"force unloading play context for connection [%s:%u]: Serial: %u Card: %d Stream: %d",
cae_server->peerAddress(sock).toString().toUtf8().
constData(),
0xFFFF&cae_server->peerPort(sock),
it.value()->serialNumber(),i,j);
dvr->unloadPlayback(it.value()->cardNumber(),
it.value()->streamNumber());
it=play_sessions.erase(it);
}
else {
++it;
}
play_owner[i][j]=-1;
play_length[i][j]=0;
play_speed[i][j]=100;
play_pitch[i][j]=false;
}
}
for(int i=0;i<256;i++) {
if(play_handle[i].owner==ch) {
play_handle[i].card=-1;
play_handle[i].stream=-1;
play_handle[i].owner=-1;
}
}
}
@@ -1300,27 +1336,16 @@ bool MainObject::CheckDaemon(QString name)
}
int MainObject::GetNextHandle()
uint64_t MainObject::GetPlayHandle(unsigned cardnum,unsigned streamnum) const
{
while(play_handle[next_play_handle].card>=0) {
next_play_handle++;
next_play_handle&=0xFF;
}
int handle=next_play_handle;
next_play_handle++;
next_play_handle&=0xFF;
return handle;
}
int MainObject::GetHandle(int card,int stream)
{
for(int i=0;i<256;i++) {
if((play_handle[i].card==card)&&(play_handle[i].stream==stream)) {
return i;
for(QMap<uint64_t,PlaySession *>::const_iterator it=play_sessions.begin();
it!=play_sessions.end();it++) {
if((it.value()->cardNumber()==cardnum)&&
(it.value()->streamNumber()==streamnum)) {
return it.key();
}
}
return -1;
return 0;
}
@@ -1579,14 +1604,18 @@ void MainObject::SendStreamMeterLevelUpdate(int cardnum,int streamnum,
void MainObject::SendMeterPositionUpdate(int cardnum,unsigned pos[])
{
PlaySession *psess=NULL;
QList<int> ids=cae_server->connectionIds();
for(unsigned k=0;k<RD_MAX_STREAMS;k++) {
for(int l=0;l<ids.size();l++) {
if((cae_server->meterPort(ids.at(l))>0)&&
cae_server->metersEnabled(ids.at(l),cardnum)) {
SendMeterUpdate(QString::asprintf("MP %d %d %d",cardnum,k,pos[k]),
ids.at(l));
if((psess=GetPlaySession(cardnum,k))!=NULL) {
for(int l=0;l<ids.size();l++) {
if((cae_server->meterPort(ids.at(l))>0)&&
cae_server->metersEnabled(ids.at(l),cardnum)) {
SendMeterUpdate(QString::asprintf("MP %u %d",
psess->serialNumber(),pos[k]),
psess->socketDescriptor());
}
}
}
}
@@ -1630,6 +1659,12 @@ void MainObject::SendMeterOutputStatusUpdate(int card,int port,int stream)
void MainObject::SendMeterUpdate(const QString &msg,int conn_id)
{
/*
rda->syslog(LOG_NOTICE,"writing %s to %s:%u",
msg.toUtf8().constData(),
cae_server->peerAddress(conn_id).toString().toUtf8().constData(),
0xFFFF&cae_server->meterPort(conn_id));
*/
meter_socket->writeDatagram(msg.toUtf8(),cae_server->peerAddress(conn_id),
cae_server->meterPort(conn_id));
}
@@ -1708,6 +1743,19 @@ void MainObject::MakeDriver(unsigned *next_card,RDStation::AudioDriver type)
}
PlaySession *MainObject::GetPlaySession(unsigned card,unsigned stream) const
{
for(QMap<uint64_t,PlaySession *>::const_iterator it=play_sessions.begin();
it!=play_sessions.end();it++) {
if((it.value()->cardNumber()==card)&&
(it.value()->streamNumber()==stream)) {
return it.value();
}
}
return NULL;
}
int main(int argc,char *argv[])
{
int rc;

View File

@@ -2,7 +2,7 @@
//
// The Core Audio Engine component of Rivendell
//
// (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
@@ -47,6 +47,7 @@
#include "driver.h"
#include "cae_server.h"
#include "playsession.h"
#ifndef HAVE_SRC_CONV
void src_int_to_float_array (const int *in, float *out, int len);
@@ -70,12 +71,13 @@ class MainObject : public QObject
MainObject(QObject *parent=0);
private slots:
void loadPlaybackData(int id,unsigned card,const QString &name);
void unloadPlaybackData(int id,unsigned handle);
void playPositionData(int id,unsigned handle,unsigned pos);
void playData(int id,unsigned handle,unsigned length,unsigned speed,
void loadPlaybackData(uint64_t phandle,unsigned card,unsigned portnum,
const QString &name);
void unloadPlaybackData(uint64_t phandle);
void playPositionData(uint64_t phandle,unsigned pos);
void playData(uint64_t phandle,unsigned length,unsigned speed,
unsigned pitch_flag);
void stopPlaybackData(int id,unsigned handle);
void stopPlaybackData(uint64_t phandle);
void timescalingSupportData(int id,unsigned card);
void loadRecordingData(int id,unsigned card,unsigned port,unsigned coding,
unsigned channels,unsigned samprate,unsigned bitrate,
@@ -85,10 +87,8 @@ 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,int port,
int level);
void fadeOutputVolumeData(int id,unsigned card,unsigned stream,unsigned port,
int level,unsigned length);
void setOutputVolumeData(uint64_t phandle,int level);
void fadeOutputVolumeData(uint64_t phandle,int level,unsigned length);
void setInputLevelData(int id,unsigned card,unsigned stream,int level);
void setOutputLevelData(int id,unsigned card,unsigned port,int level);
void setInputModeData(int id,unsigned card,unsigned stream,unsigned mode);
@@ -116,8 +116,8 @@ class MainObject : public QObject
void KillSocket(int);
bool CheckDaemon(QString);
pid_t GetPid(QString pidfile);
int GetNextHandle();
int GetHandle(int card,int stream);
PlaySession *GetPlaySession(unsigned card,unsigned stream) const;
uint64_t GetPlayHandle(unsigned cardnum,unsigned streamnum) const;
void ProbeCaps(RDStation *station);
void ClearDriverEntries() const;
void SendMeterLevelUpdate(const QString &type,int cardnum,int portnum,
@@ -138,19 +138,12 @@ class MainObject : public QObject
int record_owner[RD_MAX_CARDS][RD_MAX_STREAMS];
int record_length[RD_MAX_CARDS][RD_MAX_STREAMS];
int record_threshold[RD_MAX_CARDS][RD_MAX_STREAMS];
int play_owner[RD_MAX_CARDS][RD_MAX_STREAMS];
int play_length[RD_MAX_CARDS][RD_MAX_STREAMS];
int play_speed[RD_MAX_CARDS][RD_MAX_STREAMS];
bool play_pitch[RD_MAX_CARDS][RD_MAX_STREAMS];
bool port_status[RD_MAX_CARDS][RD_MAX_PORTS];
bool output_status_flag[RD_MAX_CARDS][RD_MAX_PORTS][RD_MAX_STREAMS];
struct {
int card;
int stream;
int owner;
} play_handle[256];
int next_play_handle;
QMap<uint64_t,PlaySession *> play_sessions;
private:
bool CheckLame();
bool CheckMp4Decode();

View File

@@ -27,6 +27,7 @@
#include <rdapplication.h>
#include "cae_server.h"
#include "playsession.h"
//
// Uncomment this to send all protocol messages to syslog (DEBUG priority)
@@ -137,6 +138,12 @@ void CaeServer::sendCommand(const QString &cmd)
}
void CaeServer::sendCommand(uint64_t phandle,const QString &cmd)
{
sendCommand(PlaySession::socketDescriptor(phandle),cmd);
}
void CaeServer::sendCommand(int id,const QString &cmd)
{
#ifdef __CAE_SERVER_LOG_PROTOCOL_MESSAGES
@@ -237,7 +244,7 @@ bool CaeServer::ProcessCommand(int id,const QString &cmd)
// Unpriviledged Commands
//
if(f0.at(0)=="DC") {
connectionClosedData(id);
cae_connections.value(id)->socket->close();
return true;
}
@@ -281,32 +288,41 @@ bool CaeServer::ProcessCommand(int id,const QString &cmd)
}
bool was_processed=false;
if((f0.at(0)=="LP")&&(f0.size()==3)) { // Load Playback
unsigned card=f0.at(1).toUInt(&ok);
if(ok&&(card<RD_MAX_CARDS)) {
emit loadPlaybackReq(id,card,f0.at(2));
was_processed=true;
if((f0.at(0)=="LP")&&(f0.size()==5)) { // Load Playback
unsigned serial=f0.at(1).toUInt(&ok);
if(ok) {
unsigned cardnum=f0.at(2).toUInt(&ok);
if(ok&&(cardnum<RD_MAX_CARDS)) {
unsigned portnum=f0.at(3).toUInt(&ok);
if(ok&&(portnum<RD_MAX_PORTS)) {
printf("makeHandle(%d,%u) = %lu\n",id,serial,
PlaySession::makeHandle(id,serial));
emit loadPlaybackReq(PlaySession::makeHandle(id,serial),cardnum,
portnum,f0.at(4));
was_processed=true;
}
}
}
}
if((f0.at(0)=="UP")&&(f0.size()==2)) { // Unload Playback
unsigned card=f0.at(1).toUInt(&ok);
unsigned serial=f0.at(1).toUInt(&ok);
if(ok) {
emit unloadPlaybackReq(id,card);
emit unloadPlaybackReq(PlaySession::makeHandle(id,serial));
was_processed=true;
}
}
if((f0.at(0)=="PP")&&(f0.size()==3)) { // Play Position
unsigned handle=f0.at(1).toUInt(&ok);
unsigned serial=f0.at(1).toUInt(&ok);
if(ok) {
unsigned pos=f0.at(2).toUInt(&ok);
if(ok) {
emit playPositionReq(id,handle,pos);
emit playPositionReq(PlaySession::makeHandle(id,serial),pos);
was_processed=true;
}
}
}
if((f0.at(0)=="PY")&&(f0.size()==5)) { // Play
unsigned handle=f0.at(1).toUInt(&ok);
unsigned serial=f0.at(1).toUInt(&ok);
if(ok) {
unsigned len=f0.at(2).toUInt(&ok);
if(ok) {
@@ -314,7 +330,7 @@ bool CaeServer::ProcessCommand(int id,const QString &cmd)
if(ok) {
unsigned pitch=f0.at(4).toUInt(&ok);
if(ok) {
emit playReq(id,handle,len,speed,pitch);
emit playReq(PlaySession::makeHandle(id,serial),len,speed,pitch);
was_processed=true;
}
}
@@ -322,9 +338,9 @@ bool CaeServer::ProcessCommand(int id,const QString &cmd)
}
}
if((f0.at(0)=="SP")&&(f0.size()==2)) { // Stop Playback
unsigned handle=f0.at(1).toUInt(&ok);
unsigned serial=f0.at(1).toUInt(&ok);
if(ok) {
emit stopPlaybackReq(id,handle);
emit stopPlaybackReq(PlaySession::makeHandle(id,serial));
was_processed=true;
}
}
@@ -413,41 +429,26 @@ bool CaeServer::ProcessCommand(int id,const QString &cmd)
}
}
}
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) {
emit setOutputVolumeReq(id,card,stream,port,level);
was_processed=true;
}
}
}
if((f0.at(0)=="OV")&&(f0.size()==3)) { // Set Output Volume
unsigned serial=f0.at(1).toUInt(&ok);
if(ok) {
int level=f0.at(2).toInt(&ok);
if(ok) {
emit setOutputVolumeReq(PlaySession::makeHandle(id,serial),level);
was_processed=true;
}
}
}
if((f0.at(0)=="FV")&&(f0.size()==6)) { // Fade 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((f0.at(0)=="FV")&&(f0.size()==4)) { // Fade Output Volume
unsigned serial=f0.at(1).toUInt(&ok);
if(ok) {
int level=f0.at(2).toInt(&ok);
if(ok) {
int len=f0.at(3).toUInt(&ok);
if(ok) {
unsigned port=f0.at(3).toUInt(&ok);
if(ok&&(port<RD_MAX_PORTS)) {
int level=f0.at(4).toInt(&ok);
if(ok) {
int len=f0.at(5).toUInt(&ok);
if(ok) {
emit fadeOutputVolumeReq(id,card,stream,port,level,len);
was_processed=true;
}
}
}
emit fadeOutputVolumeReq(PlaySession::makeHandle(id,serial),level,
len);
was_processed=true;
}
}
}

View File

@@ -42,6 +42,9 @@ class CaeServerConnection
QString accum;
uint16_t meter_port;
bool meters_enabled[RD_MAX_CARDS];
unsigned play_serial;
unsigned play_stream;
bool belongsTo(QTcpSocket *sock,unsigned serial) const;
};
@@ -61,15 +64,18 @@ class CaeServer : public QObject
void setMetersEnabled(int id,unsigned card,bool state);
bool listen(const QHostAddress &addr,uint16_t port);
void sendCommand(const QString &cmd);
void sendCommand(uint64_t phandle,const QString &cmd);
void sendCommand(int id,const QString &cmd);
signals:
void connectionDropped(int id);
void loadPlaybackReq(int id,unsigned card,const QString &name);
void unloadPlaybackReq(int id,unsigned handle);
void playPositionReq(int id,unsigned handle,unsigned pos);
void playReq(int id,unsigned handle,unsigned length,unsigned speed,unsigned pitch_flag);
void stopPlaybackReq(int id,unsigned handle);
void loadPlaybackReq(uint64_t phandle,unsigned card,unsigned port,
const QString &name);
void unloadPlaybackReq(uint64_t phandle);
void playPositionReq(uint64_t phandle,unsigned pos);
void playReq(uint64_t phandle,unsigned length,unsigned speed,
unsigned pitch_flag);
void stopPlaybackReq(uint64_t phandle);
void timescalingSupportReq(int id,unsigned card);
void loadRecordingReq(int id,unsigned card,unsigned port,unsigned coding,
unsigned channels,unsigned samprate,unsigned bitrate,
@@ -79,10 +85,8 @@ 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,int port,
int level);
void fadeOutputVolumeReq(int id,unsigned card,unsigned stream,unsigned port,
int level,unsigned length);
void setOutputVolumeReq(uint64_t phandle,int level);
void fadeOutputVolumeReq(uint64_t phandle,int level,unsigned length);
void setInputLevelReq(int id,unsigned card,unsigned port,int level);
void setOutputLevelReq(int id,unsigned card,unsigned port,int level);
void setInputModeReq(int id,unsigned card,unsigned stream,unsigned mode);

124
cae/playsession.cpp Normal file
View File

@@ -0,0 +1,124 @@
// playsession.cpp
//
// Playout session class for caed(8)
//
// (C) Copyright 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
// 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 "playsession.h"
PlaySession::PlaySession(int sock,unsigned serial,unsigned cardnum,
unsigned portnum,unsigned streamnum)
{
d_socket_descriptor=sock;
d_serial_number=serial;
d_card_number=cardnum;
d_port_number=portnum;
d_stream_number=streamnum;
d_length=0;
d_speed=100000;
}
PlaySession::PlaySession(uint64_t phandle,unsigned cardnum,unsigned portnum,
unsigned streamnum)
{
d_socket_descriptor=PlaySession::socketDescriptor(phandle);
d_serial_number=PlaySession::serialNumber(phandle);
d_card_number=cardnum;
d_port_number=portnum;
d_stream_number=streamnum;
d_length=0;
d_speed=100000;
}
uint64_t PlaySession::handle() const
{
return PlaySession::makeHandle(d_socket_descriptor,d_serial_number);
}
int PlaySession::socketDescriptor() const
{
return d_socket_descriptor;
}
unsigned PlaySession::serialNumber() const
{
return d_serial_number;
}
unsigned PlaySession::cardNumber() const
{
return d_card_number;
}
unsigned PlaySession::portNumber() const
{
return d_port_number;
}
unsigned PlaySession::streamNumber() const
{
return d_stream_number;
}
unsigned PlaySession::length() const
{
return d_length;
}
void PlaySession::setLength(unsigned msec)
{
d_length=msec;
}
unsigned PlaySession::speed() const
{
return d_speed;
}
void PlaySession::setSpeed(unsigned ratio)
{
d_speed=ratio;
}
uint64_t PlaySession::makeHandle(int fd,unsigned serial)
{
return (((uint64_t)fd)<<32)|(0xffffffff&serial);
}
int PlaySession::socketDescriptor(uint64_t phandle)
{
return phandle>>32;
}
unsigned PlaySession::serialNumber(uint64_t phandle)
{
return 0xffffffff&phandle;
}

58
cae/playsession.h Normal file
View File

@@ -0,0 +1,58 @@
// playsession.h
//
// Playout session class for caed(8)
//
// (C) Copyright 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
// 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 PLAYSESSION_H
#define PLAYSESSION_H
#include <stdint.h>
class PlaySession
{
public:
PlaySession(int sock,unsigned serial,unsigned cardnum,unsigned portnum,
unsigned streamnum);
PlaySession(uint64_t phandle,unsigned cardnum,unsigned portnum,
unsigned streamnum);
uint64_t handle() const;
int socketDescriptor() const;
unsigned serialNumber() const;
unsigned cardNumber() const;
unsigned portNumber() const;
unsigned streamNumber() const;
unsigned length() const;
void setLength(unsigned msec);
unsigned speed() const;
void setSpeed(unsigned ratio);
static uint64_t makeHandle(int fd,unsigned serial);
static int socketDescriptor(uint64_t phandle);
static unsigned serialNumber(uint64_t phandle);
private:
int d_socket_descriptor;
unsigned d_serial_number;
unsigned d_card_number;
unsigned d_port_number;
unsigned d_stream_number;
unsigned d_length;
unsigned d_speed;
};
#endif // PLAYSESSION_H