mirror of
https://github.com/ElvishArtisan/rivendell.git
synced 2025-04-27 06:36:37 +02:00
* Fixed a regression in rdairplay(1) and rdvairplayd(8) that caused hard timed events with the 'Start Immediately' attribute to fail to start if one or more other events were playing.
3175 lines
73 KiB
C++
3175 lines
73 KiB
C++
// rdlogplay.cpp
|
|
//
|
|
// Rivendell Log Playout Machine
|
|
//
|
|
// (C) Copyright 2002-2019 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 <unistd.h>
|
|
#include <syslog.h>
|
|
|
|
#include <qapplication.h>
|
|
|
|
#include "rdapplication.h"
|
|
#include "rdconf.h"
|
|
#include "rddb.h"
|
|
#include "rddebug.h"
|
|
#include "rdescape_string.h"
|
|
#include "rdlog.h"
|
|
#include "rdlogplay.h"
|
|
#include "rdmixer.h"
|
|
#include "rdnownext.h"
|
|
#include "rdsvc.h"
|
|
#include "rdweb.h"
|
|
|
|
//
|
|
// Debug Settings
|
|
//
|
|
//#define SHOW_SLOTS
|
|
//#define SHOW_METER_SLOTS
|
|
|
|
RDLogPlay::RDLogPlay(int id,RDEventPlayer *player,QObject *parent)
|
|
: QObject(parent),RDLogEvent("")
|
|
{
|
|
//
|
|
// Initialize Data Structures
|
|
//
|
|
play_log=NULL;
|
|
play_id=id;
|
|
play_event_player=player;
|
|
play_onair_flag=false;
|
|
play_segue_length=rda->airplayConf()->segueLength()+1;
|
|
play_trans_length=rda->airplayConf()->transLength()+1;
|
|
play_duck_volume_port1=0;
|
|
play_duck_volume_port2=0;
|
|
play_start_next=false;
|
|
play_running=false;
|
|
play_next_line=0;
|
|
play_post_time=QTime();
|
|
play_post_offset=-1;
|
|
play_active_line=-1;
|
|
play_active_trans=RDLogLine::Play;
|
|
play_trans_line=-1;
|
|
play_grace_line=-1;
|
|
next_channel=0;
|
|
play_timescaling_available=false;
|
|
play_rescan_pos=0;
|
|
play_refreshable=false;
|
|
play_audition_preroll=rda->airplayConf()->auditionPreroll();
|
|
for(int i=0;i<LOGPLAY_MAX_PLAYS;i++) {
|
|
play_slot_id[i]=i;
|
|
}
|
|
|
|
//
|
|
// PAD Server Connection
|
|
//
|
|
play_pad_socket=new RDUnixSocket(this);
|
|
if(!play_pad_socket->connectToAbstract(RD_PAD_SOURCE_UNIX_ADDRESS)) {
|
|
fprintf(stderr,"RDLogPlay: unable to connect to rdpadd\n");
|
|
}
|
|
|
|
//
|
|
// CAE Connection
|
|
//
|
|
play_cae=new RDCae(rda->station(),rda->config(),parent);
|
|
play_cae->connectHost();
|
|
|
|
for(int i=0;i<2;i++) {
|
|
play_card[i]=0;
|
|
play_port[i]=0;
|
|
}
|
|
|
|
//
|
|
// Play Decks
|
|
//
|
|
for(int i=0;i<RD_MAX_STREAMS;i++) {
|
|
play_deck[i]=new RDPlayDeck(play_cae,0,this);
|
|
play_deck_active[i]=false;
|
|
}
|
|
play_macro_running=false;
|
|
play_refresh_pending=false;
|
|
play_now_cartnum=0;
|
|
play_next_cartnum=0;
|
|
play_prevnow_cartnum=0;
|
|
play_prevnext_cartnum=0;
|
|
play_op_mode=RDAirPlayConf::Auto;
|
|
|
|
//
|
|
// Macro Cart Decks
|
|
//
|
|
play_macro_deck=new RDMacroEvent(rda->station()->address(),rda->ripc(),this);
|
|
connect(play_macro_deck,SIGNAL(started()),this,SLOT(macroStartedData()));
|
|
connect(play_macro_deck,SIGNAL(finished()),this,SLOT(macroFinishedData()));
|
|
connect(play_macro_deck,SIGNAL(stopped()),this,SLOT(macroStoppedData()));
|
|
|
|
//
|
|
// CAE Signals
|
|
//
|
|
connect(play_cae,SIGNAL(timescalingSupported(int,bool)),
|
|
this,SLOT(timescalingSupportedData(int,bool)));
|
|
|
|
//
|
|
// RIPC Signals
|
|
//
|
|
connect(rda->ripc(),SIGNAL(onairFlagChanged(bool)),
|
|
this,SLOT(onairFlagChangedData(bool)));
|
|
connect(rda->ripc(),SIGNAL(notificationReceived(RDNotification *)),
|
|
this,SLOT(notificationReceivedData(RDNotification *)));
|
|
|
|
//
|
|
// Audition Player
|
|
//
|
|
play_audition_line=-1;
|
|
if((rda->station()->cueCard()>=0)&&
|
|
(rda->station()->cuePort()>=0)&&
|
|
(qApp->type()!=QApplication::Tty)) {
|
|
play_audition_player=
|
|
new RDSimplePlayer(play_cae,rda->ripc(),rda->station()->cueCard(),
|
|
rda->station()->cuePort(),0,0);
|
|
play_audition_player->playButton()->hide();
|
|
play_audition_player->stopButton()->hide();
|
|
connect(play_audition_player,SIGNAL(played()),
|
|
this,SLOT(auditionStartedData()));
|
|
connect(play_audition_player,SIGNAL(stopped()),
|
|
this,SLOT(auditionStoppedData()));
|
|
}
|
|
else {
|
|
play_audition_player=NULL;
|
|
}
|
|
|
|
//
|
|
// Transition Timers
|
|
//
|
|
play_trans_timer=new QTimer(this);
|
|
play_trans_timer->setSingleShot(true);
|
|
connect(play_trans_timer,SIGNAL(timeout()),
|
|
this,SLOT(transTimerData()));
|
|
play_grace_timer=new QTimer(this);
|
|
play_grace_timer->setSingleShot(true);
|
|
connect(play_grace_timer,SIGNAL(timeout()),
|
|
this,SLOT(graceTimerData()));
|
|
}
|
|
|
|
|
|
QString RDLogPlay::serviceName() const
|
|
{
|
|
if(play_svc_name.isEmpty()) {
|
|
return play_defaultsvc_name;
|
|
}
|
|
return play_svc_name;
|
|
}
|
|
|
|
|
|
void RDLogPlay::setServiceName(const QString &svcname)
|
|
{
|
|
play_svc_name=svcname;
|
|
}
|
|
|
|
|
|
QString RDLogPlay::defaultServiceName() const
|
|
{
|
|
return play_defaultsvc_name;
|
|
}
|
|
|
|
|
|
void RDLogPlay::setDefaultServiceName(const QString &svcname)
|
|
{
|
|
play_defaultsvc_name=svcname;
|
|
}
|
|
|
|
|
|
int RDLogPlay::card(int channum) const
|
|
{
|
|
return play_card[channum];
|
|
}
|
|
|
|
|
|
int RDLogPlay::port(int channum) const
|
|
{
|
|
return play_port[channum];
|
|
}
|
|
|
|
|
|
bool RDLogPlay::channelsValid() const
|
|
{
|
|
return (play_card[0]>=0)&&(play_card[1]>=0)&&
|
|
(play_port[0]>=0)&&(play_port[1]>=0);
|
|
}
|
|
|
|
|
|
RDAirPlayConf::OpMode RDLogPlay::mode() const
|
|
{
|
|
return play_op_mode;
|
|
}
|
|
|
|
|
|
void RDLogPlay::setOpMode(RDAirPlayConf::OpMode mode)
|
|
{
|
|
if(mode==play_op_mode) {
|
|
return;
|
|
}
|
|
play_op_mode=mode;
|
|
UpdateStartTimes(play_line_counter);
|
|
}
|
|
|
|
|
|
void RDLogPlay::setLogName(QString name)
|
|
{
|
|
if(logName()!=name) {
|
|
RDLogEvent::setLogName(name);
|
|
emit renamed();
|
|
rda->airplayConf()->setCurrentLog(play_id,name);
|
|
}
|
|
}
|
|
|
|
|
|
void RDLogPlay::setChannels(int cards[2],int ports[2],
|
|
const QString start_rml[2],const QString stop_rml[2])
|
|
{
|
|
for(int i=0;i<2;i++) {
|
|
play_card[i]=cards[i];
|
|
play_port[i]=ports[i];
|
|
play_start_rml[i]=start_rml[i];
|
|
play_stop_rml[i]=stop_rml[i];
|
|
play_cae->requestTimescale(play_card[i]);
|
|
}
|
|
}
|
|
|
|
|
|
void RDLogPlay::setSegueLength(int len)
|
|
{
|
|
play_segue_length=len;
|
|
}
|
|
|
|
|
|
void RDLogPlay::setNowCart(unsigned cartnum)
|
|
{
|
|
play_now_cartnum=cartnum;
|
|
}
|
|
|
|
|
|
void RDLogPlay::setNextCart(unsigned cartnum)
|
|
{
|
|
play_next_cartnum=cartnum;
|
|
}
|
|
|
|
|
|
void RDLogPlay::auditionHead(int line)
|
|
{
|
|
RDLogLine *logline=logLine(line);
|
|
if((play_audition_player==NULL)||(logline==NULL)) {
|
|
return;
|
|
}
|
|
if(play_audition_line>=0) {
|
|
play_audition_player->stop();
|
|
}
|
|
play_audition_line=line;
|
|
play_audition_head_played=true;
|
|
play_audition_player->setCart(logline->cartNumber());
|
|
play_audition_player->play();
|
|
}
|
|
|
|
|
|
void RDLogPlay::auditionTail(int line)
|
|
{
|
|
RDLogLine *logline=logLine(line);
|
|
if((play_audition_player==NULL)||(logline==NULL)) {
|
|
return;
|
|
}
|
|
if(play_audition_line>=0) {
|
|
play_audition_player->stop();
|
|
}
|
|
play_audition_line=line;
|
|
play_audition_head_played=false;
|
|
play_audition_player->setCart(logline->cartNumber());
|
|
int start_pos=logline->endPoint()-play_audition_preroll;
|
|
if(start_pos<0) {
|
|
start_pos=0;
|
|
}
|
|
play_audition_player->play(start_pos-logline->startPoint());
|
|
}
|
|
|
|
|
|
void RDLogPlay::auditionStop()
|
|
{
|
|
if(play_audition_player==NULL) {
|
|
return;
|
|
}
|
|
if(play_audition_line>=0) {
|
|
play_audition_player->stop();
|
|
}
|
|
}
|
|
|
|
|
|
bool RDLogPlay::play(int line,RDLogLine::StartSource src,
|
|
int mport,bool skip_meta)
|
|
{
|
|
QTime current_time=QTime::currentTime();
|
|
RDLogLine *logline;
|
|
if(!channelsValid()) {
|
|
return false;
|
|
}
|
|
if((logline=logLine(line))==NULL) {
|
|
return false;
|
|
}
|
|
if((runningEvents(NULL)>=LOGPLAY_MAX_PLAYS)&&
|
|
(logline->status()!=RDLogLine::Paused)) {
|
|
return false;
|
|
}
|
|
if(play_op_mode==RDAirPlayConf::Auto) {
|
|
skip_meta=false;
|
|
}
|
|
|
|
//
|
|
// Remove any intervening events
|
|
//
|
|
if(play_line_counter!=line) {
|
|
int start_line=-1;
|
|
int num_lines;
|
|
for(int i=play_line_counter;i<line;i++) {
|
|
if((logline=logLine(i))!=NULL) {
|
|
if(logline->status()==RDLogLine::Scheduled) {
|
|
if(start_line==-1) {
|
|
start_line=i;
|
|
num_lines=1;
|
|
}
|
|
else {
|
|
num_lines++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// Play it
|
|
//
|
|
if(!GetNextPlayable(&line,skip_meta,true)) {
|
|
return false;
|
|
}
|
|
|
|
bool ret = false;
|
|
if(play_segue_length==0) {
|
|
ret = StartEvent(line,RDLogLine::Play,0,src,mport);
|
|
} else {
|
|
ret = StartEvent(line,RDLogLine::Segue,play_segue_length,src,mport);
|
|
}
|
|
SetTransTimer(current_time);
|
|
return ret;
|
|
}
|
|
|
|
|
|
bool RDLogPlay::channelPlay(int mport)
|
|
{
|
|
if(nextLine()<0) {
|
|
return false;
|
|
}
|
|
return play(nextLine(),RDLogLine::StartChannel,mport,false);
|
|
}
|
|
|
|
|
|
bool RDLogPlay::stop(bool all,int port,int fade)
|
|
{
|
|
RDLogLine *logline;
|
|
int lines[TRANSPORT_QUANTITY];
|
|
|
|
int n=runningEvents(lines);
|
|
for(int i=0;i<n;i++) {
|
|
if(all || port<1) {
|
|
stop(lines[i],fade);
|
|
}
|
|
else {
|
|
logline=logLine(lines[i]);
|
|
if((logline->cartType()==RDCart::Audio)
|
|
&&(RDPlayDeck *)logline->playDeck()!=NULL
|
|
&&logline->portName().toInt()==port ) {
|
|
stop(lines[i],fade);
|
|
}
|
|
}
|
|
}
|
|
if(n>0) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
bool RDLogPlay::stop(int line,int fade)
|
|
{
|
|
RDLogLine *logline;
|
|
|
|
if((logline=logLine(line))==NULL) {
|
|
return false;
|
|
}
|
|
switch(logline->cartType()) {
|
|
case RDCart::Audio:
|
|
if(((RDPlayDeck *)logline->playDeck())==NULL) {
|
|
return false;
|
|
}
|
|
((RDPlayDeck *)logline->playDeck())->stop(fade,RD_FADE_DEPTH);
|
|
return true;
|
|
break;
|
|
|
|
case RDCart::Macro:
|
|
play_macro_deck->stop();
|
|
break;
|
|
|
|
case RDCart::All:
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
bool RDLogPlay::channelStop(int mport)
|
|
{
|
|
RDLogLine *logline;
|
|
int lines[TRANSPORT_QUANTITY];
|
|
bool ret=false;
|
|
|
|
int n=runningEvents(lines);
|
|
for(int i=0;i<n;i++) {
|
|
logline=logLine(lines[i]);
|
|
if((logline->cartType()==RDCart::Audio)
|
|
&&((RDPlayDeck *)logline->playDeck()!=NULL)) {
|
|
if(((RDPlayDeck *)logline->playDeck())->channel()==mport) {
|
|
stop(lines[i]);
|
|
ret=true;
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
bool RDLogPlay::pause(int line)
|
|
{
|
|
RDLogLine *logline;
|
|
|
|
if((logline=logLine(line))==NULL) {
|
|
return false;
|
|
}
|
|
switch(logline->cartType()) {
|
|
case RDCart::Audio:
|
|
if(logline->playDeck()==NULL) {
|
|
return false;
|
|
}
|
|
((RDPlayDeck *)logline->playDeck())->pause();
|
|
return true;
|
|
break;
|
|
|
|
case RDCart::Macro:
|
|
case RDCart::All:
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
void RDLogPlay::duckVolume(int level,int fade,int mport)
|
|
{
|
|
RDLogLine *logline;
|
|
int lines[TRANSPORT_QUANTITY];
|
|
|
|
if(mport==-1 || mport==1) {
|
|
play_duck_volume_port1=level;
|
|
}
|
|
if(mport==-1 || mport==2) {
|
|
play_duck_volume_port2=level;
|
|
}
|
|
int n=runningEvents(lines);
|
|
for(int i=0;i<n;i++) {
|
|
logline=logLine(lines[i]);
|
|
if((logline->cartType()==RDCart::Audio)
|
|
&& (RDPlayDeck *)logline->playDeck()!=NULL
|
|
&& ((logline->portName().toInt()==mport) || mport<1) ) {
|
|
((RDPlayDeck *)logline->playDeck())->duckVolume(level,fade);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void RDLogPlay::makeNext(int line,bool refresh_status)
|
|
{
|
|
play_next_line=line;
|
|
SendNowNext();
|
|
SetTransTimer();
|
|
UpdatePostPoint();
|
|
emit nextEventChanged(line);
|
|
emit transportChanged();
|
|
}
|
|
|
|
|
|
void RDLogPlay::load()
|
|
{
|
|
int lines[TRANSPORT_QUANTITY];
|
|
int running=0;
|
|
|
|
play_duck_volume_port1=0;
|
|
play_duck_volume_port2=0;
|
|
|
|
//
|
|
// Remove All Idle Events
|
|
//
|
|
if((running=runningEvents(lines))==0) {
|
|
remove(0,size(),false);
|
|
}
|
|
else {
|
|
if(lines[running-1]<(size()-1)) {
|
|
remove(lines[running-1]+1,size()-lines[running-1]-1,false);
|
|
}
|
|
for(int i=running-1;i>0;i--) {
|
|
remove(lines[i-1]+1,lines[i]-lines[i-1]-1,false);
|
|
}
|
|
if(lines[0]!=0) {
|
|
remove(0,lines[0],false);
|
|
}
|
|
}
|
|
|
|
// Note that events left in the log are holdovers from a previous log.
|
|
// Their IDs may clash with those of events in the log we will now load,
|
|
// and it may be appropriate to ignore them in that case.
|
|
for(int i = 0, ilim = size(); i != ilim; ++i)
|
|
logLine(i)->setHoldover(true);
|
|
|
|
//
|
|
// Load Events
|
|
//
|
|
RDLogEvent::load();
|
|
play_rescan_pos=0;
|
|
if(play_timescaling_available) {
|
|
for(int i=0;i<size();i++) {
|
|
logLine(i)->setTimescalingActive(logLine(i)->enforceLength());
|
|
}
|
|
}
|
|
RefreshEvents(0,size());
|
|
RDLog *log=new RDLog(logName());
|
|
play_svc_name=log->service();
|
|
delete log;
|
|
play_line_counter=0;
|
|
play_next_line=0;
|
|
UpdateStartTimes(0);
|
|
emit reloaded();
|
|
SetTransTimer();
|
|
emit transportChanged();
|
|
UpdatePostPoint();
|
|
if((running>0)&&(size()>running)) {
|
|
makeNext(running);
|
|
}
|
|
|
|
//
|
|
// Update Refreshability
|
|
//
|
|
if(play_log!=NULL) {
|
|
delete play_log;
|
|
}
|
|
play_log=new RDLog(logName());
|
|
play_link_datetime=play_log->linkDatetime();
|
|
play_modified_datetime=play_log->modifiedDatetime();
|
|
if(play_refreshable) {
|
|
play_refreshable=false;
|
|
emit refreshabilityChanged(play_refreshable);
|
|
}
|
|
}
|
|
|
|
|
|
void RDLogPlay::append(const QString &log_name)
|
|
{
|
|
int old_size=size();
|
|
|
|
if(size()==0) {
|
|
// setLogName(RDLog::tableName(log_name));
|
|
load();
|
|
return;
|
|
}
|
|
|
|
RDLogEvent::append(log_name);
|
|
if(play_timescaling_available) {
|
|
for(int i=old_size;i<size();i++) {
|
|
logLine(i)->setTimescalingActive(logLine(i)->enforceLength());
|
|
}
|
|
}
|
|
RefreshEvents(old_size,size()-old_size);
|
|
UpdateStartTimes(old_size);
|
|
emit reloaded();
|
|
SetTransTimer();
|
|
emit transportChanged();
|
|
UpdatePostPoint();
|
|
}
|
|
|
|
|
|
bool RDLogPlay::refresh()
|
|
{
|
|
RDLogLine *s;
|
|
RDLogLine *d;
|
|
int prev_line;
|
|
int prev_id;
|
|
int next_line=-1;
|
|
int next_id=-1;
|
|
int current_id=-1;
|
|
int lines[TRANSPORT_QUANTITY];
|
|
int running;
|
|
int first_non_holdover = 0;
|
|
|
|
if(play_macro_running) {
|
|
play_refresh_pending=true;
|
|
return true;
|
|
}
|
|
emit refreshStatusChanged(true);
|
|
if((size()==0)||(play_log==NULL)) {
|
|
emit refreshStatusChanged(false);
|
|
emit refreshabilityChanged(false);
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// Load the Updated Log
|
|
//
|
|
RDLogEvent *e=new RDLogEvent();
|
|
e->setLogName(logName());
|
|
e->load();
|
|
play_modified_datetime=play_log->modifiedDatetime();
|
|
|
|
//
|
|
// Get the Next Event
|
|
//
|
|
if(nextEvent()!=NULL) { //End of the log?
|
|
next_id=nextEvent()->id();
|
|
}
|
|
|
|
//
|
|
// Get Running Events
|
|
//
|
|
running=runningEvents(lines);
|
|
for(int i=0;i<running;i++) {
|
|
if(lines[i]==play_next_line-1) {
|
|
current_id=logLine(lines[i])->id();
|
|
}
|
|
}
|
|
if(running>0 && next_id==-1) { //Last Event of Log Running?
|
|
current_id=logLine(lines[running-1])->id();
|
|
}
|
|
|
|
//
|
|
// Pass 1: Finished or Active Events
|
|
//
|
|
for(int i=0;i<size();i++) {
|
|
d=logLine(i);
|
|
if(d->status()!=RDLogLine::Scheduled) {
|
|
if((!d->isHoldover()) && (s=e->loglineById(d->id()))!=NULL) {
|
|
// A holdover event may be finished or active,
|
|
// but should not supress the addition of an
|
|
// event with the same ID in this log.
|
|
// Incrementing its ID here may flag it as an orphan
|
|
// to be removed in step 4.
|
|
s->incrementPass();
|
|
}
|
|
d->incrementPass();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Pass 2: Purge Deleted Events
|
|
//
|
|
for(int i=size()-1;i>=0;i--) {
|
|
if(logLine(i)->pass()==0) {
|
|
remove(i,1,false,true);
|
|
}
|
|
}
|
|
|
|
// Find first non-holdover event, where start-of-log
|
|
// new events should be added:
|
|
for(int i=0;i<e->size();i++) {
|
|
if(logLine(i)!=NULL) {
|
|
if(logLine(i)->isHoldover()) {
|
|
++first_non_holdover;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Pass 3: Add New Events
|
|
//
|
|
for(int i=0;i<e->size();i++) {
|
|
s=e->logLine(i);
|
|
if(s->pass()==0) {
|
|
if((prev_line=(i-1))<0) { // First Event
|
|
insert(first_non_holdover,s,false,true);
|
|
}
|
|
else {
|
|
prev_id=e->logLine(prev_line)->id();
|
|
insert(lineById(prev_id, /*ignore_holdovers=*/true)+1,s,false,true);
|
|
}
|
|
}
|
|
else {
|
|
loglineById(s->id(), /*ignore_holdovers=*/true)->incrementPass();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Pass 4: Delete Orphaned Past Playouts
|
|
//
|
|
for(int i=size()-1;i>=0;i--) {
|
|
d=logLine(i);
|
|
if((d->status()==RDLogLine::Finished)&&(d->pass()!=2)) {
|
|
remove(i,1,false,true);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Restore Next Event
|
|
//
|
|
if(current_id!=-1 && e->loglineById(current_id)!=NULL) {
|
|
// Make Next after currently playing cart
|
|
// The next event cannot have been a holdover,
|
|
// as holdovers are always either active or finished.
|
|
if((next_line=lineById(current_id, /*ignore_holdovers=*/true))>=0) {
|
|
makeNext(next_line+1,false);
|
|
}
|
|
}
|
|
else {
|
|
if((next_line=lineById(next_id, /*ignore_holdovers=*/true))>=0) {
|
|
makeNext(next_line,false);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Clean Up
|
|
//
|
|
delete e;
|
|
for(int i=0;i<size();i++) {
|
|
logLine(i)->clearPass();
|
|
}
|
|
RefreshEvents(0,size());
|
|
UpdateStartTimes(next_line);
|
|
UpdatePostPoint();
|
|
SetTransTimer();
|
|
emit transportChanged();
|
|
emit reloaded();
|
|
if(play_refreshable) {
|
|
play_refreshable=false;
|
|
emit refreshabilityChanged(play_refreshable);
|
|
}
|
|
|
|
emit refreshStatusChanged(false);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void RDLogPlay::save(int line)
|
|
{
|
|
RDLogEvent::save(rda->config(),line);
|
|
if(play_log!=NULL) {
|
|
delete play_log;
|
|
}
|
|
play_log=new RDLog(logName());
|
|
QDateTime current_datetime=
|
|
QDateTime(QDate::currentDate(),QTime::currentTime());
|
|
play_log->setModifiedDatetime(current_datetime);
|
|
play_modified_datetime=current_datetime;
|
|
if(play_refreshable) {
|
|
play_refreshable=false;
|
|
emit refreshabilityChanged(play_refreshable);
|
|
}
|
|
}
|
|
|
|
|
|
void RDLogPlay::clear()
|
|
{
|
|
setLogName("");
|
|
int start_line=0;
|
|
play_duck_volume_port1=0;
|
|
play_duck_volume_port2=0;
|
|
while(ClearBlock(start_line++));
|
|
play_svc_name=play_defaultsvc_name;
|
|
play_rescan_pos=0;
|
|
if(play_log!=NULL) {
|
|
delete play_log;
|
|
play_log=NULL;
|
|
}
|
|
SetTransTimer();
|
|
UpdatePostPoint();
|
|
if(play_refreshable) {
|
|
play_refreshable=false;
|
|
emit refreshabilityChanged(play_refreshable);
|
|
}
|
|
emit reloaded();
|
|
}
|
|
|
|
|
|
void RDLogPlay::insert(int line,int cartnum,RDLogLine::TransType next_type,
|
|
RDLogLine::TransType type)
|
|
{
|
|
RDLogLine *logline;
|
|
int lines[TRANSPORT_QUANTITY];
|
|
RDPlayDeck *playdeck;
|
|
int mod_line=-1;
|
|
|
|
if(line<(size()-1)) {
|
|
if(logLine(line)->hasCustomTransition()) {
|
|
mod_line=line+1;
|
|
}
|
|
}
|
|
|
|
int running=runningEvents(lines);
|
|
for(int i=0;i<running;i++) {
|
|
if((logline=logLine(lines[i]))!=NULL) {
|
|
if((playdeck=(RDPlayDeck *)logline->playDeck())!=NULL) {
|
|
if((playdeck->id()>=0)&&
|
|
(playdeck->id()>=line)) {
|
|
playdeck->setId(playdeck->id()+1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(play_macro_deck->line()>=0) {
|
|
play_macro_deck->setLine(play_macro_deck->line()+1);
|
|
}
|
|
RDLogEvent::insert(line,1);
|
|
if((logline=logLine(line))==NULL) {
|
|
RDLogEvent::remove(line,1);
|
|
return;
|
|
}
|
|
if(nextLine()>line) {
|
|
makeNext(nextLine()+1);
|
|
}
|
|
if(nextLine()<0) {
|
|
play_next_line=line;
|
|
}
|
|
logline->loadCart(cartnum,next_type,play_id,play_timescaling_available,type);
|
|
logline->
|
|
setTimescalingActive(play_timescaling_available&&logline->enforceLength());
|
|
UpdateStartTimes(line);
|
|
emit inserted(line);
|
|
UpdatePostPoint();
|
|
if(mod_line>=0) {
|
|
emit modified(mod_line);
|
|
}
|
|
emit transportChanged();
|
|
SetTransTimer();
|
|
UpdatePostPoint();
|
|
}
|
|
|
|
|
|
void RDLogPlay::insert(int line,RDLogLine *l,bool update,bool preserv_custom_transition)
|
|
{
|
|
RDLogLine *logline;
|
|
int lines[TRANSPORT_QUANTITY];
|
|
RDPlayDeck *playdeck;
|
|
int mod_line=-1;
|
|
|
|
if(line<(size()-1)) {
|
|
if(logLine(line)->hasCustomTransition()) {
|
|
mod_line=line+1;
|
|
}
|
|
}
|
|
|
|
int running=runningEvents(lines);
|
|
for(int i=0;i<running;i++) {
|
|
if((logline=logLine(lines[i]))!=NULL) {
|
|
if((playdeck=(RDPlayDeck *)logline->playDeck())!=NULL) {
|
|
if((playdeck->id()>=0)&&
|
|
(playdeck->id()>=line)) {
|
|
playdeck->setId(playdeck->id()+1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(play_macro_deck->line()>=0) {
|
|
play_macro_deck->setLine(play_macro_deck->line()+1);
|
|
}
|
|
RDLogEvent::insert(line,1,preserv_custom_transition);
|
|
if((logline=logLine(line))==NULL) {
|
|
RDLogEvent::remove(line,1);
|
|
return;
|
|
}
|
|
*logline=*l;
|
|
if(nextLine()>line && update) {
|
|
makeNext(nextLine()+1);
|
|
}
|
|
if(nextLine()<0) {
|
|
play_next_line=line;
|
|
}
|
|
logline->
|
|
setTimescalingActive(play_timescaling_available&&logline->enforceLength());
|
|
if(update) {
|
|
UpdateStartTimes(line);
|
|
emit inserted(line);
|
|
UpdatePostPoint();
|
|
if(mod_line>=0) {
|
|
emit modified(mod_line);
|
|
}
|
|
emit transportChanged();
|
|
SetTransTimer();
|
|
UpdatePostPoint();
|
|
}
|
|
}
|
|
|
|
|
|
void RDLogPlay::remove(int line,int num_lines,bool update,bool preserv_custom_transition)
|
|
{
|
|
RDPlayDeck *playdeck;
|
|
RDLogLine *logline;
|
|
int mod_line=-1;
|
|
|
|
if((num_lines==0)||(line<0)||(line>=size())) {
|
|
return;
|
|
}
|
|
if((line+num_lines)<(size()-1)) {
|
|
if(logLine(line+num_lines)->hasCustomTransition()) {
|
|
mod_line=line;
|
|
}
|
|
}
|
|
|
|
for(int i=line;i<(line+num_lines);i++) {
|
|
if((logline=logLine(i))!=NULL) {
|
|
if((playdeck=(RDPlayDeck *)logline->playDeck())!=NULL) {
|
|
playdeck->clear();
|
|
FreePlayDeck(playdeck);
|
|
}
|
|
}
|
|
}
|
|
|
|
int lines[TRANSPORT_QUANTITY];
|
|
|
|
if(update) {
|
|
emit removed(line,num_lines,false);
|
|
}
|
|
int running=runningEvents(lines);
|
|
for(int i=0;i<running;i++) {
|
|
if((logline=logLine(lines[i]))!=NULL) {
|
|
if(logline->type()==RDLogLine::Cart) {
|
|
playdeck=(RDPlayDeck *)logline->playDeck();
|
|
if((playdeck->id()>=0)&&(playdeck->id()>line)) {
|
|
playdeck->setId(playdeck->id()-num_lines);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(play_macro_deck->line()>0) {
|
|
play_macro_deck->setLine(play_macro_deck->line()-num_lines);
|
|
}
|
|
|
|
RDLogEvent::remove(line,num_lines,preserv_custom_transition);
|
|
if(update) {
|
|
if(nextLine()>line) {
|
|
makeNext(nextLine()-num_lines);
|
|
}
|
|
UpdateStartTimes(line);
|
|
if(size()==0) {
|
|
emit reloaded();
|
|
}
|
|
if(mod_line>=0) {
|
|
emit modified(mod_line);
|
|
}
|
|
emit transportChanged();
|
|
SetTransTimer();
|
|
UpdatePostPoint();
|
|
}
|
|
}
|
|
|
|
|
|
void RDLogPlay::move(int from_line,int to_line)
|
|
{
|
|
int offset=0;
|
|
int lines[TRANSPORT_QUANTITY];
|
|
RDLogLine *logline;
|
|
RDPlayDeck *playdeck;
|
|
int mod_line[2]={-1,-1};
|
|
|
|
if(from_line<(size()-1)) {
|
|
if(logLine(from_line+1)->hasCustomTransition()) {
|
|
if(from_line<to_line) {
|
|
mod_line[0]=from_line;
|
|
}
|
|
else {
|
|
mod_line[0]=from_line+1;
|
|
}
|
|
}
|
|
}
|
|
if(to_line<size()) {
|
|
if(logLine(to_line)->hasCustomTransition()) {
|
|
if(from_line>to_line) {
|
|
mod_line[1]=to_line;
|
|
}
|
|
else {
|
|
mod_line[1]=to_line+1;
|
|
}
|
|
}
|
|
}
|
|
|
|
emit removed(from_line,1,true);
|
|
int running=runningEvents(lines,false);
|
|
for(int i=0;i<running;i++) {
|
|
if((logline=logLine(lines[i]))!=NULL) {
|
|
playdeck=(RDPlayDeck *)logline->playDeck();
|
|
if(playdeck->id()>=0) {
|
|
if((playdeck->id()>from_line)&&
|
|
(playdeck->id()<=to_line)) {
|
|
playdeck->setId(playdeck->id()-1);
|
|
}
|
|
else {
|
|
if((playdeck->id()<from_line)&&
|
|
(playdeck->id()>to_line)) {
|
|
playdeck->setId(playdeck->id()+1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(play_macro_deck->line()>=0) {
|
|
if((play_macro_deck->line()>from_line)&&
|
|
(play_macro_deck->line()<=to_line)) {
|
|
play_macro_deck->setLine(play_macro_deck->line()-1);
|
|
}
|
|
else {
|
|
if((play_macro_deck->line()<from_line)&&
|
|
(play_macro_deck->line()>to_line)) {
|
|
play_macro_deck->setLine(play_macro_deck->line()+1);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(to_line>from_line) {
|
|
offset=1;
|
|
}
|
|
RDLogEvent::move(from_line,to_line);
|
|
if(from_line>to_line) {
|
|
UpdateStartTimes(to_line);
|
|
}
|
|
else {
|
|
UpdateStartTimes(from_line);
|
|
}
|
|
SetTransTimer();
|
|
UpdatePostPoint();
|
|
emit inserted(to_line);
|
|
for(int i=0;i<2;i++) {
|
|
if(mod_line[i]>=0) {
|
|
emit modified(mod_line[i]);
|
|
}
|
|
}
|
|
if((nextLine()>from_line)&&(nextLine()<=(to_line+offset))) {
|
|
makeNext(nextLine()-1);
|
|
}
|
|
else {
|
|
if((nextLine()<from_line)&&(nextLine()>to_line)) {
|
|
makeNext(nextLine()+1);
|
|
}
|
|
else {
|
|
emit transportChanged();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void RDLogPlay::copy(int from_line,int to_line,RDLogLine::TransType type)
|
|
{
|
|
RDLogLine *logline;
|
|
|
|
if((logline=logLine(from_line))==NULL) {
|
|
return;
|
|
}
|
|
insert(to_line,logline->cartNumber(),RDLogLine::Play,type);
|
|
}
|
|
|
|
|
|
int RDLogPlay::topLine()
|
|
{
|
|
for(int i=0;i<size();i++) {
|
|
if((logLine(i)->status()==RDLogLine::Playing)||
|
|
(logLine(i)->status()==RDLogLine::Finishing)||
|
|
(logLine(i)->status()==RDLogLine::Paused)) {
|
|
return i;
|
|
}
|
|
}
|
|
return nextLine();
|
|
}
|
|
|
|
|
|
int RDLogPlay::currentLine() const
|
|
{
|
|
return play_line_counter;
|
|
}
|
|
|
|
|
|
int RDLogPlay::nextLine() const
|
|
{
|
|
return play_next_line;
|
|
}
|
|
|
|
|
|
int RDLogPlay::nextLine(int line)
|
|
{
|
|
int lines[TRANSPORT_QUANTITY];
|
|
|
|
// FIXME: Do we really need this codeblock?
|
|
transportEvents(lines);
|
|
for(int i=0;i<(TRANSPORT_QUANTITY-1);i++) {
|
|
if(line==lines[i]) {
|
|
for(int j=i+1;j<TRANSPORT_QUANTITY;j++) {
|
|
if(logLine(lines[j])==NULL) {
|
|
return -1;
|
|
}
|
|
if(logLine(lines[j])->status()==RDLogLine::Scheduled) {
|
|
return lines[j];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// End of FIXME
|
|
|
|
for(int i=line+1;i<size();i++) {
|
|
if(logLine(i)->status()==RDLogLine::Scheduled) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
RDLogLine *RDLogPlay::nextEvent()
|
|
{
|
|
if(play_next_line<0) {
|
|
return NULL;
|
|
}
|
|
return logLine(play_next_line);
|
|
}
|
|
|
|
|
|
RDLogLine::TransType RDLogPlay::nextTrans()
|
|
{
|
|
RDLogLine *logline=nextEvent();
|
|
if(logline==NULL) {
|
|
return RDLogLine::Stop;
|
|
}
|
|
return logline->transType();
|
|
}
|
|
|
|
|
|
RDLogLine::TransType RDLogPlay::nextTrans(int line)
|
|
{
|
|
RDLogLine *logline;
|
|
int next_line;
|
|
|
|
next_line=nextLine(line);
|
|
logline=logLine(next_line);
|
|
if(logline!=NULL) {
|
|
return logline->transType();
|
|
}
|
|
return RDLogLine::Stop;
|
|
}
|
|
|
|
|
|
void RDLogPlay::transportEvents(int line[])
|
|
{
|
|
int count=0;
|
|
int start=topLine();
|
|
RDLogLine *logline;
|
|
|
|
for(int i=0;i<TRANSPORT_QUANTITY;i++) {
|
|
line[i]=-1;
|
|
}
|
|
if((start<0)||(size()==0)) {
|
|
return;
|
|
}
|
|
|
|
count=runningEvents(line);
|
|
if(nextLine()<0) {
|
|
return;
|
|
}
|
|
start=play_next_line;
|
|
if((logline=logLine(start))==NULL) {
|
|
return;
|
|
}
|
|
for(int i=start;i<size();i++) {
|
|
if((logline=logLine(i))==NULL) {
|
|
return;
|
|
}
|
|
switch(logline->status()) {
|
|
case RDLogLine::Scheduled:
|
|
if(count<TRANSPORT_QUANTITY) {
|
|
line[count++]=i;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
if(count==TRANSPORT_QUANTITY) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
int RDLogPlay::runningEvents(int *lines, bool include_paused)
|
|
{
|
|
int count=0;
|
|
int events[TRANSPORT_QUANTITY];
|
|
int table[TRANSPORT_QUANTITY];
|
|
bool changed=true;
|
|
|
|
if(size()==0) {
|
|
return 0;
|
|
}
|
|
for(int i=0;i<TRANSPORT_QUANTITY;i++) {
|
|
if (lines){
|
|
lines[i]=-1;
|
|
}
|
|
table[i]=i;
|
|
}
|
|
|
|
//
|
|
// Build Running Event List
|
|
//
|
|
if(include_paused) {
|
|
for(int i=0;i<size();i++) {
|
|
if((logLine(i)->status()==RDLogLine::Playing)||
|
|
(logLine(i)->status()==RDLogLine::Finishing)||
|
|
(logLine(i)->status()==RDLogLine::Paused)) {
|
|
events[count++]=i;
|
|
if(count==TRANSPORT_QUANTITY) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
for(int i=0;i<size();i++) {
|
|
if((logLine(i)->status()==RDLogLine::Playing)||
|
|
(logLine(i)->status()==RDLogLine::Finishing)) {
|
|
events[count++]=i;
|
|
if(count==TRANSPORT_QUANTITY) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!lines){
|
|
return count;
|
|
}
|
|
//
|
|
// Sort 'Em (by start time)
|
|
//
|
|
while(changed) {
|
|
changed=false;
|
|
for(int i=0;i<(count-1);i++) {
|
|
if(logLine(events[table[i]])->startTime(RDLogLine::Initial)>
|
|
logLine(events[table[i+1]])->startTime(RDLogLine::Initial)) {
|
|
int event=table[i];
|
|
table[i]=table[i+1];
|
|
table[i+1]=event;
|
|
changed=true;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Write out the table
|
|
//
|
|
for(int i=0;i<count;i++) {
|
|
lines[i]=events[table[i]];
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
|
|
void RDLogPlay::lineModified(int line)
|
|
{
|
|
RDLogLine *logline;
|
|
RDLogLine *next_logline;
|
|
|
|
SetTransTimer();
|
|
UpdateStartTimes(line);
|
|
|
|
if((logline=logLine(line))!=NULL) {
|
|
if((next_logline=logLine(line+1))==NULL) {
|
|
logline->loadCart(logline->cartNumber(),RDLogLine::Play,
|
|
play_id,logline->timescalingActive());
|
|
}
|
|
else {
|
|
logline->loadCart(logline->cartNumber(),next_logline->transType(),
|
|
play_id,logline->timescalingActive());
|
|
}
|
|
}
|
|
emit modified(line);
|
|
int lines[TRANSPORT_QUANTITY] = {-1};
|
|
int count;
|
|
count = runningEvents(lines,false);
|
|
if (count > 0){
|
|
line=lines[count-1];
|
|
}
|
|
UpdatePostPoint();
|
|
emit transportChanged();
|
|
}
|
|
|
|
|
|
RDLogLine::Status RDLogPlay::status(int line)
|
|
{
|
|
RDLogLine *logline;
|
|
|
|
if((logline=logLine(line))==NULL) {
|
|
return RDLogLine::Scheduled;
|
|
}
|
|
return logline->status();
|
|
}
|
|
|
|
|
|
QTime RDLogPlay::startTime(int line)
|
|
{
|
|
RDLogLine *logline;
|
|
|
|
if((logline=logLine(line))==NULL) {
|
|
return QTime();
|
|
}
|
|
switch(logline->cartType()) {
|
|
case RDCart::Audio:
|
|
if(((RDPlayDeck *)logline->playDeck())==NULL) {
|
|
return logline->startTime(RDLogLine::Predicted);
|
|
}
|
|
return logline->startTime(RDLogLine::Actual);
|
|
break;
|
|
|
|
case RDCart::Macro:
|
|
case RDCart::All:
|
|
return logline->startTime(RDLogLine::Predicted);
|
|
break;
|
|
}
|
|
return QTime();
|
|
}
|
|
|
|
|
|
QTime RDLogPlay::nextStop() const
|
|
{
|
|
return play_next_stop;
|
|
}
|
|
|
|
|
|
bool RDLogPlay::running(bool include_paused)
|
|
{
|
|
if(runningEvents(NULL,include_paused)==0) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
void RDLogPlay::resync()
|
|
{
|
|
SetTransTimer();
|
|
}
|
|
|
|
|
|
bool RDLogPlay::isRefreshable() const
|
|
{
|
|
if(play_log==NULL) {
|
|
return false;
|
|
}
|
|
return (play_log->exists())&&
|
|
(play_log->linkDatetime()==play_link_datetime)&&
|
|
(play_log->modifiedDatetime()>play_modified_datetime);
|
|
}
|
|
|
|
|
|
void RDLogPlay::transTimerData()
|
|
{
|
|
int lines[TRANSPORT_QUANTITY];
|
|
RDLogLine *logline=NULL;
|
|
int grace=0;
|
|
int trans_line=play_trans_line;
|
|
int running_events=runningEvents(lines);
|
|
|
|
if(play_grace_timer->isActive()) {
|
|
play_grace_timer->stop();
|
|
}
|
|
|
|
if(play_op_mode==RDAirPlayConf::Auto) {
|
|
if((logline=logLine(play_trans_line))!=NULL) {
|
|
if(logline->graceTime()==-1) { // Make Next
|
|
makeNext(play_trans_line);
|
|
SetTransTimer();
|
|
return;
|
|
}
|
|
if(logline->graceTime()>0) {
|
|
if(running_events>0) {
|
|
if(logline->transType()==RDLogLine::Stop) {
|
|
logline->setTransType(RDLogLine::Play);
|
|
}
|
|
logline->setStartTime(RDLogLine::Predicted,logline->
|
|
startTime(RDLogLine::Predicted).
|
|
addMSecs(grace));
|
|
play_grace_line=play_trans_line;
|
|
play_grace_timer->start(logline->graceTime());
|
|
return;
|
|
}
|
|
else {
|
|
}
|
|
}
|
|
}
|
|
if(!GetNextPlayable(&play_trans_line,false)) {
|
|
SetTransTimer();
|
|
return;
|
|
}
|
|
if((logline=logLine(play_trans_line))!=NULL) {
|
|
grace=logline->graceTime();
|
|
}
|
|
makeNext(play_trans_line);
|
|
if(logline->transType()!=RDLogLine::Stop || grace>=0) {
|
|
StartEvent(trans_line,RDLogLine::Play,0,RDLogLine::StartTime);
|
|
}
|
|
}
|
|
SetTransTimer();
|
|
}
|
|
|
|
|
|
void RDLogPlay::graceTimerData()
|
|
{
|
|
int lines[TRANSPORT_QUANTITY];
|
|
int line=play_grace_line;
|
|
|
|
if(play_op_mode==RDAirPlayConf::Auto) {
|
|
if(!GetNextPlayable(&line,false)) {
|
|
SetTransTimer();
|
|
return;
|
|
}
|
|
if((runningEvents(lines)==0)) {
|
|
makeNext(play_grace_line);
|
|
StartEvent(play_grace_line,RDLogLine::Play,0,RDLogLine::StartTime);
|
|
}
|
|
else {
|
|
makeNext(play_grace_line);
|
|
if(play_trans_length==0) {
|
|
StartEvent(play_grace_line,RDLogLine::Play,0,RDLogLine::StartTime);
|
|
}
|
|
else {
|
|
StartEvent(play_grace_line,RDLogLine::Segue,play_trans_length,
|
|
RDLogLine::StartTime);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void RDLogPlay::playStateChangedData(int id,RDPlayDeck::State state)
|
|
{
|
|
#ifdef SHOW_SLOTS
|
|
printf("playStateChangedData(%d,%d), log: %s\n",id,state,(const char *)logName());
|
|
#endif
|
|
switch(state) {
|
|
case RDPlayDeck::Playing:
|
|
Playing(id);
|
|
break;
|
|
|
|
case RDPlayDeck::Paused:
|
|
Paused(id);
|
|
break;
|
|
|
|
case RDPlayDeck::Stopping:
|
|
Stopping(id);
|
|
break;
|
|
|
|
case RDPlayDeck::Stopped:
|
|
Stopped(id);
|
|
break;
|
|
|
|
case RDPlayDeck::Finished:
|
|
Finished(id);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void RDLogPlay::onairFlagChangedData(bool state)
|
|
{
|
|
play_onair_flag=state;
|
|
}
|
|
|
|
|
|
void RDLogPlay::segueStartData(int id)
|
|
{
|
|
#ifdef SHOW_SLOTS
|
|
printf("segueStartData(%d)\n",id);
|
|
#endif
|
|
int line=GetLineById(id);
|
|
RDLogLine *logline;
|
|
RDLogLine *next_logline=nextEvent();
|
|
if(next_logline==NULL) {
|
|
return;
|
|
}
|
|
if((logline=logLine(line))==NULL) {
|
|
return;
|
|
}
|
|
if((play_op_mode==RDAirPlayConf::Auto)&&
|
|
((next_logline->transType()==RDLogLine::Segue))&&
|
|
(logline->status()==RDLogLine::Playing)&&
|
|
(logline->id()!=-1)) {
|
|
if(!GetNextPlayable(&play_next_line,false)) {
|
|
return;
|
|
}
|
|
StartEvent(play_next_line,next_logline->transType(),
|
|
logline->segueTail(next_logline->transType()),
|
|
RDLogLine::StartSegue,-1,
|
|
logline->segueTail(next_logline->transType()));
|
|
SetTransTimer();
|
|
}
|
|
}
|
|
|
|
|
|
void RDLogPlay::segueEndData(int id)
|
|
{
|
|
#ifdef SHOW_SLOTS
|
|
printf("segueEndData(%d)\n",id);
|
|
#endif
|
|
|
|
int line=GetLineById(id);
|
|
RDLogLine *logline;
|
|
if((logline=logLine(line))==NULL) {
|
|
return;
|
|
}
|
|
if((play_op_mode==RDAirPlayConf::Auto)&&
|
|
(logline->status()==RDLogLine::Finishing)) {
|
|
((RDPlayDeck *)logline->playDeck())->stop();
|
|
CleanupEvent(id);
|
|
UpdateStartTimes(line);
|
|
LogTraffic(logline,(RDLogLine::PlaySource)(play_id+1),
|
|
RDAirPlayConf::TrafficFinish,play_onair_flag);
|
|
emit stopped(line);
|
|
emit transportChanged();
|
|
}
|
|
}
|
|
|
|
|
|
void RDLogPlay::talkStartData(int id)
|
|
{
|
|
#ifdef SHOW_SLOTS
|
|
printf("talkStartData(%d)\n",id);
|
|
#endif
|
|
}
|
|
|
|
|
|
void RDLogPlay::talkEndData(int id)
|
|
{
|
|
#ifdef SHOW_SLOTS
|
|
printf("talkEndData(%d)\n",id);
|
|
#endif
|
|
}
|
|
|
|
|
|
void RDLogPlay::positionData(int id,int pos)
|
|
{
|
|
int line=GetLineById(id);
|
|
|
|
RDLogLine *logline;
|
|
if((logline=logLine(line))==NULL) {
|
|
return;
|
|
}
|
|
if(pos>logline->effectiveLength()) {
|
|
return;
|
|
}
|
|
logline->setPlayPosition(pos);
|
|
emit position(line,pos);
|
|
}
|
|
|
|
|
|
void RDLogPlay::macroStartedData()
|
|
{
|
|
#ifdef SHOW_SLOTS
|
|
printf("macroStartedData()\n");
|
|
#endif
|
|
play_macro_running=true;
|
|
int line=play_macro_deck->line();
|
|
RDLogLine *logline;
|
|
if((logline=logLine(line))==NULL) {
|
|
return;
|
|
}
|
|
logline->setStatus(RDLogLine::Playing);
|
|
logline->
|
|
setStartTime(RDLogLine::Initial,
|
|
QTime::currentTime().addMSecs(rda->station()->timeOffset()));
|
|
UpdateStartTimes(line);
|
|
emit played(line);
|
|
UpdatePostPoint();
|
|
emit transportChanged();
|
|
}
|
|
|
|
|
|
void RDLogPlay::macroFinishedData()
|
|
{
|
|
#ifdef SHOW_SLOTS
|
|
printf("macroFinishedData()\n");
|
|
#endif
|
|
int line=play_macro_deck->line();
|
|
play_macro_deck->clear();
|
|
FinishEvent(line);
|
|
RDLogLine *logline;
|
|
if((logline=logLine(line))!=NULL) {
|
|
logline->setStatus(RDLogLine::Finished);
|
|
LogTraffic(logline,(RDLogLine::PlaySource)(play_id+1),
|
|
RDAirPlayConf::TrafficMacro,play_onair_flag);
|
|
}
|
|
play_macro_running=false;
|
|
UpdatePostPoint();
|
|
if(play_refresh_pending) {
|
|
refresh();
|
|
play_refresh_pending=false;
|
|
}
|
|
emit transportChanged();
|
|
}
|
|
|
|
|
|
void RDLogPlay::macroStoppedData()
|
|
{
|
|
#ifdef SHOW_SLOTS
|
|
printf("macroStoppedData()\n");
|
|
#endif
|
|
int line=play_macro_deck->line();
|
|
play_macro_deck->clear();
|
|
RDLogLine *logline;
|
|
if((logline=logLine(line))!=NULL) {
|
|
logline->setStatus(RDLogLine::Finished);
|
|
LogTraffic(logline,(RDLogLine::PlaySource)(play_id+1),
|
|
RDAirPlayConf::TrafficMacro,play_onair_flag);
|
|
}
|
|
UpdatePostPoint();
|
|
emit transportChanged();
|
|
}
|
|
|
|
|
|
void RDLogPlay::timescalingSupportedData(int card,bool state)
|
|
{
|
|
if(card>=0) {
|
|
play_timescaling_supported[card]=state;
|
|
if(play_timescaling_supported[play_card[0]]&&
|
|
play_timescaling_supported[play_card[1]]) {
|
|
play_timescaling_available=true;
|
|
}
|
|
else {
|
|
play_timescaling_available=false;
|
|
}
|
|
}
|
|
else {
|
|
play_timescaling_available=false;
|
|
}
|
|
}
|
|
|
|
|
|
void RDLogPlay::auditionStartedData()
|
|
{
|
|
if(play_audition_head_played) {
|
|
emit auditionHeadPlayed(play_audition_line);
|
|
}
|
|
else {
|
|
emit auditionTailPlayed(play_audition_line);
|
|
}
|
|
}
|
|
|
|
|
|
void RDLogPlay::auditionStoppedData()
|
|
{
|
|
int line=play_audition_line;
|
|
play_audition_line=-1;
|
|
emit auditionStopped(line);
|
|
}
|
|
|
|
|
|
void RDLogPlay::notificationReceivedData(RDNotification *notify)
|
|
{
|
|
RDLogLine *ll=NULL;
|
|
RDLogLine *next_ll=NULL;
|
|
|
|
if(notify->type()==RDNotification::CartType) {
|
|
unsigned cartnum=notify->id().toUInt();
|
|
for(int i=0;i<size();i++) {
|
|
if((ll=logLine(i))!=NULL) {
|
|
if((ll->cartNumber()==cartnum)&&(ll->status()==RDLogLine::Scheduled)&&
|
|
((ll->type()==RDLogLine::Cart)||(ll->type()==RDLogLine::Macro))) {
|
|
switch(ll->state()) {
|
|
case RDLogLine::Ok:
|
|
case RDLogLine::NoCart:
|
|
case RDLogLine::NoCut:
|
|
if((next_ll=logLine(i+1))!=NULL) {
|
|
ll->loadCart(ll->cartNumber(),next_ll->transType(),play_id,
|
|
ll->timescalingActive());
|
|
}
|
|
else {
|
|
ll->loadCart(ll->cartNumber(),RDLogLine::Play,play_id,
|
|
ll->timescalingActive());
|
|
}
|
|
emit modified(i);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(notify->type()==RDNotification::LogType) {
|
|
//
|
|
// Check Refreshability
|
|
//
|
|
if((play_log!=NULL)&&(notify->id().toString()==play_log->name())) {
|
|
if((!play_log->exists())||(play_log->linkDatetime()!=play_link_datetime)||
|
|
(play_log->modifiedDatetime()<=play_modified_datetime)) {
|
|
if(play_refreshable) {
|
|
play_refreshable=false;
|
|
emit refreshabilityChanged(play_refreshable);
|
|
}
|
|
}
|
|
else {
|
|
if(play_log->autoRefresh()) {
|
|
refresh();
|
|
}
|
|
else {
|
|
if(!play_refreshable) {
|
|
play_refreshable=true;
|
|
emit refreshabilityChanged(play_refreshable);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool RDLogPlay::StartEvent(int line,RDLogLine::TransType trans_type,
|
|
int trans_length,RDLogLine::StartSource src,
|
|
int mport,int duck_length)
|
|
{
|
|
int running;
|
|
int lines[TRANSPORT_QUANTITY];
|
|
RDLogLine *logline;
|
|
RDLogLine *next_logline;
|
|
RDPlayDeck *playdeck;
|
|
int card;
|
|
int port;
|
|
int aport;
|
|
bool was_paused=false;
|
|
|
|
if(!channelsValid()) {
|
|
return false;
|
|
}
|
|
if((logline=logLine(line))==NULL) {
|
|
return false;
|
|
}
|
|
if(logline->id()<0) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Transition running events
|
|
//
|
|
running=runningEvents(lines);
|
|
if(play_op_mode!=RDAirPlayConf::Manual) {
|
|
switch(trans_type) {
|
|
case RDLogLine::Play:
|
|
for(int i=0;i<running;i++) {
|
|
if(logLine(lines[i])!=NULL) {
|
|
if(((logLine(lines[i])->type()==RDLogLine::Cart)||
|
|
(logLine(lines[i])->type()==RDLogLine::Macro))&&
|
|
(logLine(lines[i])->status()!=RDLogLine::Paused)) {
|
|
switch(logLine(lines[i])->cartType()) {
|
|
case RDCart::Audio:
|
|
((RDPlayDeck *)logLine(lines[i])->playDeck())->stop();
|
|
break;
|
|
|
|
case RDCart::Macro:
|
|
play_macro_deck->stop();
|
|
break;
|
|
|
|
case RDCart::All:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case RDLogLine::Segue:
|
|
for(int i=0;i<running;i++) {
|
|
RDLogLine *prev_logline=logLine(lines[i]);
|
|
if(prev_logline!=NULL) {
|
|
if(prev_logline->status()==RDLogLine::Playing) {
|
|
if(((prev_logline->type()==RDLogLine::Cart)||
|
|
(prev_logline->type()==RDLogLine::Macro))&&
|
|
(prev_logline->status()!=RDLogLine::Paused)) {
|
|
switch(logLine(lines[i])->cartType()) {
|
|
case RDCart::Audio:
|
|
prev_logline->setStatus(RDLogLine::Finishing);
|
|
((RDPlayDeck *)prev_logline->playDeck())->
|
|
stop(trans_length);
|
|
break;
|
|
|
|
case RDCart::Macro:
|
|
play_macro_deck->stop();
|
|
break;
|
|
|
|
case RDCart::All:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Clear Unplayed Custom Transition
|
|
//
|
|
if(logLine(line-1)!=NULL) {
|
|
if(logLine(line-1)->status()==RDLogLine::Scheduled) {
|
|
logLine(line-1)->clearTrackData(RDLogLine::TrailingTrans);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Start Playout
|
|
//
|
|
logline->setStartSource(src);
|
|
switch(logline->type()) {
|
|
case RDLogLine::Cart:
|
|
if(!StartAudioEvent(line)) {
|
|
rda->airplayConf()->setLogCurrentLine(play_id,nextLine());
|
|
return false;
|
|
}
|
|
aport=GetNextChannel(mport,&card,&port);
|
|
playdeck=(RDPlayDeck *)logline->playDeck();
|
|
playdeck->setCard(card);
|
|
playdeck->setPort(port);
|
|
playdeck->setChannel(aport);
|
|
logline->setPauseCard(card);
|
|
logline->setPausePort(port);
|
|
logline->setPortName(GetPortName(playdeck->card(),
|
|
playdeck->port()));
|
|
if(logline->portName().toInt()==2){
|
|
playdeck->duckVolume(play_duck_volume_port2,0);
|
|
}
|
|
else {
|
|
playdeck->duckVolume(play_duck_volume_port1,0);
|
|
}
|
|
|
|
if(!playdeck->setCart(logline,logline->status()!=RDLogLine::Paused)) {
|
|
// No audio to play, so fake it
|
|
logline->setZombified(true);
|
|
playStateChangedData(playdeck->id(),RDPlayDeck::Playing);
|
|
logline->setStatus(RDLogLine::Playing);
|
|
playStateChangedData(playdeck->id(),RDPlayDeck::Finished);
|
|
logline->setStatus(RDLogLine::Finished);
|
|
rda->syslog(LOG_WARNING,
|
|
"log engine: RDLogPlay::StartEvent(): no audio,CUT=%s",
|
|
(const char *)logline->cutName().toUtf8());
|
|
rda->airplayConf()->setLogCurrentLine(play_id,nextLine());
|
|
return false;
|
|
}
|
|
emit modified(line);
|
|
logline->setCutNumber(playdeck->cut()->cutNumber());
|
|
logline->setEvergreen(playdeck->cut()->evergreen());
|
|
if(play_timescaling_available&&logline->enforceLength()) {
|
|
logline->setTimescalingActive(true);
|
|
}
|
|
RDSetMixerOutputPort(play_cae,playdeck->card(),
|
|
playdeck->stream(),
|
|
playdeck->port());
|
|
if((int)logline->playPosition()>logline->effectiveLength()) {
|
|
rda->syslog(LOG_DEBUG,"log engine: *** position out of bounds: Line: %d Cart: %d Pos: %d ***",line,logline->cartNumber(),logline->playPosition());
|
|
logline->setPlayPosition(0);
|
|
}
|
|
playdeck->play(logline->playPosition(),-1,-1,duck_length);
|
|
if(logline->status()==RDLogLine::RDLogLine::Paused) {
|
|
logline->
|
|
setStartTime(RDLogLine::Actual,playdeck->startTime());
|
|
was_paused=true;
|
|
}
|
|
else {
|
|
logline->
|
|
setStartTime(RDLogLine::Initial,playdeck->startTime());
|
|
}
|
|
logline->setStatus(RDLogLine::Playing);
|
|
if(!play_start_rml[aport].isEmpty()) {
|
|
play_event_player->
|
|
exec(logline->resolveWildcards(play_start_rml[aport]));
|
|
}
|
|
/*
|
|
printf("channelStarted(%d,%d,%d,%d)\n",
|
|
play_id,playdeck->channel(),
|
|
playdeck->card(),playdeck->port());
|
|
*/
|
|
emit channelStarted(play_id,playdeck->channel(),
|
|
playdeck->card(),playdeck->port());
|
|
rda->syslog(LOG_INFO,"log engine: started audio cart: Line: %d Cart: %u Cut: %u Pos: %d Card: %d Stream: %d Port: %d",
|
|
line,logline->cartNumber(),
|
|
playdeck->cut()->cutNumber(),
|
|
logline->playPosition(),
|
|
playdeck->card(),
|
|
playdeck->stream(),
|
|
playdeck->port());
|
|
|
|
//
|
|
// Assign Next Event
|
|
//
|
|
if((play_next_line>=0)&&(!was_paused)) {
|
|
play_next_line=line+1;
|
|
if((next_logline=logLine(play_next_line))!=NULL) {
|
|
if(next_logline->id()==-2) {
|
|
play_start_next=false;
|
|
}
|
|
}
|
|
emit nextEventChanged(play_next_line);
|
|
}
|
|
break;
|
|
|
|
case RDLogLine::Macro:
|
|
//
|
|
// Assign Next Event
|
|
//
|
|
if(play_next_line>=0) {
|
|
play_next_line=line+1;
|
|
if((next_logline=logLine(play_next_line))!=NULL) {
|
|
if(logline->id()==-2) {
|
|
play_start_next=false;
|
|
}
|
|
if(logline->forcedStop()) {
|
|
next_logline->setTransType(RDLogLine::Stop);
|
|
}
|
|
}
|
|
}
|
|
if(logline->asyncronous()) {
|
|
RDMacro *rml=new RDMacro();
|
|
rml->setCommand(RDMacro::EX);
|
|
QHostAddress addr;
|
|
addr.setAddress("127.0.0.1");
|
|
rml->setAddress(addr);
|
|
rml->setRole(RDMacro::Cmd);
|
|
rml->setEchoRequested(false);
|
|
rml->addArg(logline->cartNumber()); // Arg 0
|
|
rda->ripc()->sendRml(rml);
|
|
delete rml;
|
|
emit played(line);
|
|
logline->setStartTime(RDLogLine::Actual,QTime::currentTime());
|
|
logline->setStatus(RDLogLine::Finished);
|
|
LogTraffic(logline,(RDLogLine::PlaySource)(play_id+1),
|
|
RDAirPlayConf::TrafficMacro,play_onair_flag);
|
|
FinishEvent(line);
|
|
emit transportChanged();
|
|
rda->syslog(LOG_INFO,
|
|
"log engine: asynchronously executed macro cart: Line: %d Cart: %u",
|
|
line,logline->cartNumber());
|
|
}
|
|
else {
|
|
play_macro_deck->load(logline->cartNumber());
|
|
play_macro_deck->setLine(line);
|
|
rda->syslog(LOG_INFO,
|
|
"log engine: started macro cart: Line: %d Cart: %u",
|
|
line,logline->cartNumber());
|
|
play_macro_deck->exec();
|
|
}
|
|
break;
|
|
|
|
case RDLogLine::Marker:
|
|
case RDLogLine::Track:
|
|
case RDLogLine::MusicLink:
|
|
case RDLogLine::TrafficLink:
|
|
//
|
|
// Assign Next Event
|
|
//
|
|
if(play_next_line>=0) {
|
|
play_next_line=line+1;
|
|
if((next_logline=logLine(play_next_line))!=NULL) {
|
|
if(logLine(play_next_line)->id()==-2) {
|
|
play_start_next=false;
|
|
}
|
|
}
|
|
else {
|
|
play_start_next=false;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Skip Past
|
|
//
|
|
logline->setStatus(RDLogLine::Finished);
|
|
UpdateStartTimes(line);
|
|
emit played(line);
|
|
FinishEvent(line);
|
|
emit nextEventChanged(play_next_line);
|
|
break;
|
|
|
|
case RDLogLine::Chain:
|
|
//
|
|
// Assign Next Event
|
|
//
|
|
if(play_next_line>0) {
|
|
play_next_line=line+1;
|
|
if((next_logline=logLine(play_next_line))!=NULL) {
|
|
if(logLine(play_next_line)->id()==-2) {
|
|
play_start_next=false;
|
|
}
|
|
}
|
|
else {
|
|
play_start_next=false;
|
|
}
|
|
}
|
|
if(GetTransType(logline->markerLabel(),0)!=RDLogLine::Stop) {
|
|
play_macro_deck->
|
|
load(QString().sprintf("LL %d %s -2!",
|
|
play_id+1,
|
|
(const char *)logline->markerLabel()));
|
|
}
|
|
else {
|
|
play_macro_deck->
|
|
load(QString().sprintf("LL %d %s -2!",
|
|
play_id+1,
|
|
(const char *)logline->markerLabel()));
|
|
}
|
|
play_macro_deck->setLine(line);
|
|
play_macro_deck->exec();
|
|
rda->syslog(LOG_INFO,"log engine: chained to log: Line: %d Log: %s",
|
|
line,(const char *)logline->markerLabel());
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
while((play_next_line<size())&&((logline=logLine(play_next_line))!=NULL)) {
|
|
if((logline->state()==RDLogLine::Ok)||
|
|
(logline->state()==RDLogLine::NoCart)||
|
|
(logline->state()==RDLogLine::NoCut)) {
|
|
rda->airplayConf()->setLogCurrentLine(play_id,nextLine());
|
|
return true;
|
|
}
|
|
play_next_line++;
|
|
}
|
|
play_next_line=-1;
|
|
rda->airplayConf()->setLogCurrentLine(play_id,nextLine());
|
|
return true;
|
|
}
|
|
|
|
|
|
bool RDLogPlay::StartAudioEvent(int line)
|
|
{
|
|
RDLogLine *logline;
|
|
RDPlayDeck *playdeck=NULL;
|
|
|
|
if((logline=logLine(line))==NULL) {
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Get a Play Deck
|
|
//
|
|
if(logline->status()!=RDLogLine::Paused) {
|
|
logline->setPlayDeck(GetPlayDeck());
|
|
if(logline->playDeck()==NULL) {
|
|
return false;
|
|
}
|
|
playdeck=(RDPlayDeck *)logline->playDeck();
|
|
playdeck->setId(line);
|
|
}
|
|
else {
|
|
playdeck=(RDPlayDeck *)logline->playDeck();
|
|
}
|
|
|
|
//
|
|
// Assign Mappings
|
|
//
|
|
connect(playdeck,SIGNAL(stateChanged(int,RDPlayDeck::State)),
|
|
this,SLOT(playStateChangedData(int,RDPlayDeck::State)));
|
|
connect(playdeck,SIGNAL(position(int,int)),
|
|
this,SLOT(positionData(int,int)));
|
|
connect(playdeck,SIGNAL(segueStart(int)),
|
|
this,SLOT(segueStartData(int)));
|
|
connect(playdeck,SIGNAL(segueEnd(int)),
|
|
this,SLOT(segueEndData(int)));
|
|
connect(playdeck,SIGNAL(talkStart(int)),
|
|
this,SLOT(talkStartData(int)));
|
|
connect(playdeck,SIGNAL(talkEnd(int)),
|
|
this,SLOT(talkEndData(int)));
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void RDLogPlay::CleanupEvent(int id)
|
|
{
|
|
int line=GetLineById(id);
|
|
bool top_changed=false;
|
|
RDLogLine *logline;
|
|
RDPlayDeck *playdeck=NULL;
|
|
if((logline=logLine(line))==NULL) {
|
|
return;
|
|
}
|
|
playdeck=(RDPlayDeck *)logline->playDeck();
|
|
if(playdeck->cut()==NULL) {
|
|
rda->syslog(LOG_INFO,"log engine: event failed: Line: %d Cart: %u",line,
|
|
logline->cartNumber());
|
|
}
|
|
else {
|
|
rda->syslog(LOG_INFO,"log engine: finished event: Line: %d Cart: %u Cut: %u Card: %d Stream: %d Port: %d",
|
|
line,logline->cartNumber(),
|
|
playdeck->cut()->cutNumber(),
|
|
playdeck->card(),
|
|
playdeck->stream(),playdeck->port());
|
|
}
|
|
RDLogLine *prev_logline;
|
|
if((prev_logline=logLine(line-1))==NULL) {
|
|
}
|
|
else {
|
|
if((line==0)||(prev_logline->status()!=RDLogLine::Playing)) {
|
|
play_line_counter++;
|
|
top_changed=true;
|
|
}
|
|
}
|
|
logline->setStatus(RDLogLine::Finished);
|
|
FreePlayDeck(playdeck);
|
|
logline->setPlayDeck(NULL);
|
|
UpdatePostPoint();
|
|
if(top_changed) {
|
|
emit topEventChanged(play_line_counter);
|
|
}
|
|
}
|
|
|
|
|
|
void RDLogPlay::UpdateStartTimes(int line)
|
|
{
|
|
QTime time;
|
|
QTime new_time;
|
|
QTime end_time;
|
|
QTime prev_time;
|
|
QTime next_stop;
|
|
int running=0;
|
|
int prev_total_length=0;
|
|
int prev_segue_length=0;
|
|
bool stop_set=false;
|
|
bool stop;
|
|
RDLogLine *logline;
|
|
RDLogLine *next_logline;
|
|
RDLogLine::TransType next_trans;
|
|
int lines[TRANSPORT_QUANTITY];
|
|
|
|
if((running=runningEvents(lines,false))>0) {
|
|
line=lines[0];
|
|
}
|
|
else {
|
|
line=play_next_line;
|
|
}
|
|
for(int i=line;i<size();i++) {
|
|
if((logline=logLine(i))!=NULL) {
|
|
if((next_logline=logLine(nextLine(i)))!=NULL) {
|
|
next_trans=next_logline->transType();
|
|
}
|
|
else {
|
|
next_trans=RDLogLine::Stop;
|
|
}
|
|
stop=false;
|
|
switch(logline->status()) {
|
|
case RDLogLine::Playing:
|
|
case RDLogLine::Finishing:
|
|
time=logline->startTime(RDLogLine::Actual);
|
|
break;
|
|
|
|
default:
|
|
time=GetStartTime(logline->startTime(RDLogLine::Logged),
|
|
logline->transType(),
|
|
logline->timeType(),
|
|
time,prev_total_length,prev_segue_length,
|
|
&stop,running);
|
|
logline->setStartTime(RDLogLine::Predicted,time);
|
|
break;
|
|
}
|
|
if(stop&&(!stop_set)) {
|
|
next_stop=time.addMSecs(prev_total_length);
|
|
stop_set=true;
|
|
}
|
|
|
|
prev_total_length=logline->effectiveLength()-
|
|
logline->playPosition();
|
|
prev_segue_length=
|
|
logline->segueLength(next_trans)-logline->playPosition();
|
|
end_time=
|
|
time.addMSecs(logline->effectiveLength()-
|
|
logline->playPosition());
|
|
|
|
switch(logline->status()) {
|
|
case RDLogLine::Scheduled:
|
|
case RDLogLine::Paused:
|
|
prev_total_length=logline->effectiveLength()-
|
|
logline->playPosition();
|
|
prev_segue_length=
|
|
logline->segueLength(next_trans)-logline->playPosition();
|
|
end_time=
|
|
time.addMSecs(logline->effectiveLength()-
|
|
logline->playPosition());
|
|
break;
|
|
default:
|
|
prev_total_length=logline->effectiveLength();
|
|
prev_segue_length=
|
|
logline->segueLength(next_trans);
|
|
end_time=
|
|
time.addMSecs(logline->effectiveLength());
|
|
}
|
|
}
|
|
}
|
|
next_stop=GetNextStop(line);
|
|
|
|
if(next_stop!=play_next_stop) {
|
|
play_next_stop=next_stop;
|
|
emit nextStopChanged(play_next_stop);
|
|
}
|
|
SendNowNext();
|
|
}
|
|
|
|
|
|
void RDLogPlay::FinishEvent(int line)
|
|
{
|
|
int prev_next_line=play_next_line;
|
|
if(GetNextPlayable(&play_next_line,false)) {
|
|
if(play_next_line>=0) {
|
|
RDLogLine *logline;
|
|
if((logline=logLine(play_next_line))==NULL) {
|
|
return;
|
|
}
|
|
if((play_op_mode==RDAirPlayConf::Auto)&&
|
|
(logline->id()!=-1)&&(play_next_line<size())) {
|
|
if(play_next_line>=0) {
|
|
if(logline->transType()==RDLogLine::Play) {
|
|
StartEvent(play_next_line,RDLogLine::Play,0,RDLogLine::StartPlay);
|
|
SetTransTimer(QTime(),prev_next_line==play_trans_line);
|
|
}
|
|
if(logline->transType()==RDLogLine::Segue) {
|
|
StartEvent(play_next_line,RDLogLine::Segue,0,RDLogLine::StartPlay);
|
|
SetTransTimer(QTime(),prev_next_line==play_trans_line);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
UpdateStartTimes(line);
|
|
emit stopped(line);
|
|
}
|
|
|
|
|
|
QTime RDLogPlay::GetStartTime(QTime sched_time,
|
|
RDLogLine::TransType trans_type,
|
|
RDLogLine::TimeType time_type,QTime prev_time,
|
|
int prev_total_length,int prev_segue_length,
|
|
bool *stop,int running_events)
|
|
{
|
|
QTime time;
|
|
|
|
if((play_op_mode==RDAirPlayConf::LiveAssist)||
|
|
(play_op_mode==RDAirPlayConf::Manual)) {
|
|
*stop=true;
|
|
return QTime();
|
|
}
|
|
switch(trans_type) {
|
|
case RDLogLine::Play:
|
|
if(!prev_time.isNull()) {
|
|
time=prev_time.addMSecs(prev_total_length);
|
|
}
|
|
break;
|
|
|
|
case RDLogLine::Segue:
|
|
if(!prev_time.isNull()) {
|
|
time=prev_time.addMSecs(prev_segue_length);
|
|
}
|
|
break;
|
|
|
|
case RDLogLine::Stop:
|
|
time=QTime();
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
switch(time_type) {
|
|
case RDLogLine::Relative:
|
|
if(!prev_time.isNull()) {
|
|
*stop=false;
|
|
return time;
|
|
}
|
|
*stop=true;
|
|
return QTime();
|
|
break;
|
|
|
|
case RDLogLine::Hard:
|
|
if((time<sched_time)||(time.isNull())) {
|
|
*stop=true;
|
|
}
|
|
else {
|
|
*stop=false;
|
|
}
|
|
if(running_events&&(time<sched_time)&&(trans_type!=RDLogLine::Stop)) {
|
|
return time;
|
|
}
|
|
return sched_time;
|
|
break;
|
|
|
|
case RDLogLine::NoTime:
|
|
break;
|
|
}
|
|
return QTime();
|
|
}
|
|
|
|
|
|
QTime RDLogPlay::GetNextStop(int line)
|
|
{
|
|
bool running=false;
|
|
QTime time;
|
|
RDLogLine *logline;
|
|
if((logline=logLine(line))==NULL) {
|
|
return QTime();
|
|
}
|
|
|
|
for(int i=line;i<size();i++) {
|
|
if((status(i)==RDLogLine::Playing)||
|
|
(status(i)==RDLogLine::Finishing)) {
|
|
if((logLine(i)->type()==RDLogLine::Cart)&&
|
|
((logLine(i)->status()==RDLogLine::Playing)||
|
|
(logLine(i)->status()==RDLogLine::Finishing))) {
|
|
time=
|
|
startTime(i).addMSecs(logLine(i)->segueLength(nextTrans(i))-
|
|
((RDPlayDeck *)logLine(i)->playDeck())->
|
|
lastStartPosition());
|
|
}
|
|
else {
|
|
time=startTime(i).addMSecs(logLine(i)->segueLength(nextTrans(i)));
|
|
}
|
|
running=true;
|
|
}
|
|
else {
|
|
if(running&&(play_op_mode==RDAirPlayConf::Auto)&&
|
|
(status(i)==RDLogLine::Scheduled)) {
|
|
switch(logLine(i)->transType()) {
|
|
case RDLogLine::Stop:
|
|
return time;
|
|
break;
|
|
|
|
case RDLogLine::Play:
|
|
case RDLogLine::Segue:
|
|
time=time.addMSecs(logLine(i)->segueLength(nextTrans(i))-
|
|
logLine(i)->playPosition());
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(running!=play_running) {
|
|
play_running=running;
|
|
emit runStatusChanged(running);
|
|
}
|
|
return time;
|
|
}
|
|
|
|
void RDLogPlay::UpdatePostPoint()
|
|
{
|
|
int lines[TRANSPORT_QUANTITY] = {-1};
|
|
int count = runningEvents(lines,false);
|
|
if (count > 0){
|
|
UpdatePostPoint(lines[count -1]);
|
|
return;
|
|
}
|
|
transportEvents(lines);
|
|
UpdatePostPoint(lines[0]);
|
|
}
|
|
|
|
void RDLogPlay::UpdatePostPoint(int line)
|
|
{
|
|
int post_line=-1;
|
|
QTime post_time;
|
|
int offset=0;
|
|
|
|
if((line<0)||(play_trans_line<0)) {
|
|
post_line=-1;
|
|
post_time=QTime();
|
|
offset=0;
|
|
}
|
|
else {
|
|
if((line<size())&&(play_trans_line>=0)&&(play_trans_line<size())) {
|
|
post_line=play_trans_line;
|
|
post_time=logLine(post_line)->startTime(RDLogLine::Logged);
|
|
offset=length(line,post_line)-QTime::currentTime().msecsTo(post_time);
|
|
}
|
|
}
|
|
if((post_time!=play_post_time)||(offset!=play_post_offset)) {
|
|
play_post_time=post_time;
|
|
play_post_offset=offset;
|
|
emit postPointChanged(play_post_time,offset,post_line>=line,running(false));
|
|
}
|
|
}
|
|
|
|
|
|
void RDLogPlay::AdvanceActiveEvent()
|
|
{
|
|
int line=-1;
|
|
RDLogLine::TransType trans=RDLogLine::Play;
|
|
|
|
for(int i=0;i<LOGPLAY_MAX_PLAYS;i++) {
|
|
RDLogLine *logline;
|
|
if((logline=logLine(play_line_counter+1))!=NULL) {
|
|
if(logline->deck()!=-1) {
|
|
line=play_line_counter+i;
|
|
}
|
|
}
|
|
}
|
|
if(line==-1) {
|
|
if(line!=play_active_line) {
|
|
play_active_line=line;
|
|
emit activeEventChanged(line,RDLogLine::Stop);
|
|
}
|
|
}
|
|
else {
|
|
if(line<(size()-1)) {
|
|
RDLogLine *logline;
|
|
if((logline=logLine(line+1))!=NULL) {
|
|
trans=logLine(line+1)->transType();
|
|
}
|
|
}
|
|
else {
|
|
trans=RDLogLine::Stop;
|
|
}
|
|
if((line!=play_active_line)||(trans!=play_active_trans)) {
|
|
play_active_line=line;
|
|
play_active_trans=trans;
|
|
emit activeEventChanged(line,trans);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
QString RDLogPlay::GetPortName(int card,int port)
|
|
{
|
|
for(int i=0;i<2;i++) {
|
|
for(int j=0;j<2;j++) {
|
|
if((play_card[i]==card)&&(play_port[i]==port)) {
|
|
return QString().sprintf("%d",i+1);
|
|
}
|
|
}
|
|
}
|
|
return QString();
|
|
}
|
|
|
|
|
|
void RDLogPlay::SetTransTimer(QTime current_time,bool stop)
|
|
{
|
|
int next_line=-1;
|
|
QTime next_time=QTime(23,59,59);
|
|
|
|
if(current_time.isNull()) {
|
|
current_time=QTime::currentTime();
|
|
}
|
|
RDLogLine *logline;
|
|
|
|
if(play_trans_timer->isActive()) {
|
|
if(stop) {
|
|
play_trans_timer->stop();
|
|
}
|
|
else {
|
|
return;
|
|
}
|
|
}
|
|
play_trans_line=-1;
|
|
for(int i=0;i<size();i++) {
|
|
if((logline=logLine(i))!=NULL) {
|
|
if((logline->timeType()==RDLogLine::Hard)&&
|
|
((logline->status()==RDLogLine::Scheduled)||
|
|
(logline->status()==RDLogLine::Auditioning))&&
|
|
(logline->startTime(RDLogLine::Logged)>current_time)&&
|
|
(logline->startTime(RDLogLine::Logged)<=next_time)) {
|
|
next_time=logline->startTime(RDLogLine::Logged);
|
|
next_line=i;
|
|
}
|
|
}
|
|
}
|
|
if(next_line>=0) {
|
|
play_trans_line=next_line;
|
|
play_trans_timer->start(current_time.msecsTo(next_time));
|
|
}
|
|
}
|
|
|
|
|
|
int RDLogPlay::GetNextChannel(int mport,int *card,int *port)
|
|
{
|
|
int chan=next_channel;
|
|
if(mport<0) {
|
|
*card=play_card[next_channel];
|
|
*port=play_port[next_channel];
|
|
if(++next_channel>1) {
|
|
next_channel=0;
|
|
}
|
|
}
|
|
else {
|
|
chan=mport;
|
|
*card=play_card[mport];
|
|
*port=play_port[mport];
|
|
next_channel=mport+1;
|
|
if(next_channel>1) {
|
|
next_channel=0;
|
|
}
|
|
}
|
|
return chan;
|
|
}
|
|
|
|
|
|
int RDLogPlay::GetLineById(int id)
|
|
{
|
|
return id;
|
|
}
|
|
|
|
|
|
RDPlayDeck *RDLogPlay::GetPlayDeck()
|
|
{
|
|
for(int i=0;i<RD_MAX_STREAMS;i++) {
|
|
if(!play_deck_active[i]) {
|
|
play_deck_active[i]=true;
|
|
return play_deck[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
void RDLogPlay::FreePlayDeck(RDPlayDeck *deck)
|
|
{
|
|
for(int i=0;i<RD_MAX_STREAMS;i++) {
|
|
if(play_deck[i]==deck) {
|
|
ClearChannel(i);
|
|
play_deck[i]->disconnect();
|
|
play_deck[i]->reset();
|
|
play_deck_active[i]=false;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool RDLogPlay::GetNextPlayable(int *line,bool skip_meta,bool forced_start)
|
|
{
|
|
RDLogLine *logline;
|
|
RDLogLine *next_logline;
|
|
RDLogLine::TransType next_type=RDLogLine::Play;
|
|
int skipped=0;
|
|
|
|
for(int i=*line;i<size();i++) {
|
|
if((logline=logLine(i))==NULL) {
|
|
return false;
|
|
}
|
|
if(skip_meta&&((logline->type()==RDLogLine::Marker)||
|
|
(logline->type()==RDLogLine::OpenBracket)||
|
|
(logline->type()==RDLogLine::CloseBracket)||
|
|
(logline->type()==RDLogLine::Track)||
|
|
(logline->type()==RDLogLine::MusicLink)||
|
|
(logline->type()==RDLogLine::TrafficLink))) {
|
|
logline->setStatus(RDLogLine::Finished);
|
|
skipped++;
|
|
emit modified(i);
|
|
}
|
|
else {
|
|
if(logline->status()==RDLogLine::Scheduled || logline->status()==RDLogLine::Paused ||
|
|
logline->status()==RDLogLine::Auditioning) {
|
|
if(((logline->transType()==RDLogLine::Stop)||
|
|
(play_op_mode==RDAirPlayConf::LiveAssist))&&((i-skipped)!=*line)) {
|
|
makeNext(i);
|
|
return false;
|
|
}
|
|
if((next_logline=logLine(i+1))!=NULL) {
|
|
next_type=next_logline->transType();
|
|
}
|
|
if((logline->setEvent(play_id,next_type,logline->timescalingActive())==
|
|
RDLogLine::Ok)&&((logline->status()==RDLogLine::Scheduled)||
|
|
(logline->status()==RDLogLine::Paused))&&
|
|
(!logline->zombified())) {
|
|
emit modified(i);
|
|
*line=i;
|
|
return true;
|
|
}
|
|
else {
|
|
logline->setStartTime(RDLogLine::Initial,QTime::currentTime());
|
|
if((logline->transType()==RDLogLine::Stop)) {
|
|
if((logline->cutNumber()>=0)&&(!logline->zombified())) {
|
|
emit modified(i);
|
|
*line=i;
|
|
return true;
|
|
}
|
|
else {
|
|
if(!forced_start) {
|
|
emit modified(i);
|
|
*line=i;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
emit modified(i);
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
void RDLogPlay::LogPlayEvent(RDLogLine *logline)
|
|
{
|
|
RDCut *cut=new RDCut(QString().sprintf("%06u_%03d",
|
|
logline->cartNumber(),
|
|
logline->cutNumber()));
|
|
cut->logPlayout();
|
|
delete cut;
|
|
}
|
|
|
|
|
|
void RDLogPlay::RefreshEvents(int line,int line_quan,bool force_update)
|
|
{
|
|
//QTime st=QTime::currentTime();
|
|
|
|
//
|
|
// Check Event Status
|
|
//
|
|
RDLogLine *logline;
|
|
RDLogLine *next_logline;
|
|
RDLogLine::State state=RDLogLine::Ok;
|
|
|
|
for(int i=line;i<(line+line_quan);i++) {
|
|
if((logline=logLine(i))!=NULL) {
|
|
if(logline->type()==RDLogLine::Cart) {
|
|
switch(logline->state()) {
|
|
case RDLogLine::Ok:
|
|
case RDLogLine::NoCart:
|
|
case RDLogLine::NoCut:
|
|
if(logline->status()==RDLogLine::Scheduled) {
|
|
state=logline->state();
|
|
if((next_logline=logLine(i+1))!=NULL) {
|
|
logline->
|
|
loadCart(logline->cartNumber(),next_logline->transType(),
|
|
play_id,logline->timescalingActive());
|
|
}
|
|
else {
|
|
logline->loadCart(logline->cartNumber(),RDLogLine::Play,
|
|
play_id,logline->timescalingActive());
|
|
}
|
|
if(force_update||(state!=logline->state())) {
|
|
emit modified(i);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void RDLogPlay::Playing(int id)
|
|
{
|
|
RDLogLine *logline;
|
|
|
|
int line=GetLineById(id);
|
|
if((logline=logLine(line))==NULL) {
|
|
return;
|
|
}
|
|
UpdateStartTimes(line);
|
|
emit played(line);
|
|
AdvanceActiveEvent();
|
|
UpdatePostPoint();
|
|
if (isRefreshable()&&play_log->autoRefresh()) {
|
|
refresh();
|
|
}
|
|
LogPlayEvent(logline);
|
|
emit transportChanged();
|
|
}
|
|
|
|
|
|
void RDLogPlay::Paused(int id)
|
|
{
|
|
int line=GetLineById(id);
|
|
RDLogLine *logline=logLine(line);
|
|
if(logline!=NULL) {
|
|
logline->playDeck()->disconnect();
|
|
logline->setPortName("");
|
|
logline->setStatus(RDLogLine::Paused);
|
|
}
|
|
UpdateStartTimes(line);
|
|
emit paused(line);
|
|
UpdatePostPoint();
|
|
LogTraffic(logLine(line),(RDLogLine::PlaySource)(play_id+1),
|
|
RDAirPlayConf::TrafficPause,play_onair_flag);
|
|
emit transportChanged();
|
|
}
|
|
|
|
|
|
void RDLogPlay::Stopping(int id)
|
|
{
|
|
}
|
|
|
|
|
|
void RDLogPlay::Stopped(int id)
|
|
{
|
|
int line=GetLineById(id);
|
|
int lines[TRANSPORT_QUANTITY];
|
|
CleanupEvent(id);
|
|
UpdateStartTimes(line);
|
|
emit stopped(line);
|
|
LogTraffic(logLine(line),(RDLogLine::PlaySource)(play_id+1),
|
|
RDAirPlayConf::TrafficStop,play_onair_flag);
|
|
if(play_grace_timer->isActive()) { // Pending Hard Time Event
|
|
play_grace_timer->stop();
|
|
play_grace_timer->start(0);
|
|
return;
|
|
}
|
|
AdvanceActiveEvent();
|
|
UpdatePostPoint();
|
|
if(runningEvents(lines)==0) {
|
|
next_channel=0;
|
|
}
|
|
emit transportChanged();
|
|
}
|
|
|
|
|
|
void RDLogPlay::Finished(int id)
|
|
{
|
|
int line=GetLineById(id);
|
|
RDLogLine *logline;
|
|
int lines[TRANSPORT_QUANTITY];
|
|
if((logline=logLine(line))==NULL) {
|
|
return;
|
|
}
|
|
switch(logline->status()) {
|
|
case RDLogLine::Playing:
|
|
CleanupEvent(id);
|
|
FinishEvent(line);
|
|
break;
|
|
|
|
case RDLogLine::Auditioning:
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
UpdatePostPoint();
|
|
if(runningEvents(lines)==0) {
|
|
next_channel=0;
|
|
}
|
|
LogTraffic(logline,(RDLogLine::PlaySource)(play_id+1),
|
|
RDAirPlayConf::TrafficFinish,play_onair_flag);
|
|
emit transportChanged();
|
|
}
|
|
|
|
|
|
void RDLogPlay::ClearChannel(int deckid)
|
|
{
|
|
if(play_deck[deckid]->channel()<0) {
|
|
return;
|
|
}
|
|
if(play_cae->playPortActive(play_deck[deckid]->card(),
|
|
play_deck[deckid]->port(),
|
|
play_deck[deckid]->stream())) {
|
|
return;
|
|
}
|
|
|
|
if(play_deck[deckid]->channel()>=0) {
|
|
play_event_player->exec(play_stop_rml[play_deck[deckid]->channel()]);
|
|
/*
|
|
printf("Deck: %d channelStopped(%d,%d,%d,%d\n",deckid,
|
|
play_id,play_deck[deckid]->channel(),
|
|
play_deck[deckid]->card(),
|
|
play_deck[deckid]->port());
|
|
*/
|
|
emit channelStopped(play_id,play_deck[deckid]->channel(),
|
|
play_deck[deckid]->card(),
|
|
play_deck[deckid]->port());
|
|
}
|
|
play_deck[deckid]->setChannel(-1);
|
|
}
|
|
|
|
|
|
RDLogLine::TransType RDLogPlay::GetTransType(const QString &logname,int line)
|
|
{
|
|
RDLogLine::TransType trans=RDLogLine::Stop;
|
|
QString sql=QString("select TRANS_TYPE from LOG_LINES where ")+
|
|
"LOG_NAME=\""+RDEscapeString(logname)+"\" && "+
|
|
QString().sprintf("COUNT=%d",line);
|
|
RDSqlQuery *q=new RDSqlQuery(sql);
|
|
if(q->first()) {
|
|
trans=(RDLogLine::TransType)q->value(0).toUInt();
|
|
}
|
|
delete q;
|
|
return trans;
|
|
}
|
|
|
|
|
|
bool RDLogPlay::ClearBlock(int start_line)
|
|
{
|
|
RDLogLine::Status status;
|
|
|
|
for(int i=start_line;i<size();i++) {
|
|
status=logLine(i)->status();
|
|
if((status!=RDLogLine::Scheduled)&&(status!=RDLogLine::Finished)) {
|
|
remove(start_line,i-start_line);
|
|
return true;
|
|
}
|
|
}
|
|
remove(start_line,size()-start_line);
|
|
return false;
|
|
}
|
|
|
|
|
|
void RDLogPlay::SendNowNext()
|
|
{
|
|
QTime end_time;
|
|
QTime time;
|
|
int now_line=-1;
|
|
RDLogLine *logline[2];
|
|
RDLogLine *ll;
|
|
RDLogLine *default_now_logline=NULL;
|
|
RDLogLine *default_next_logline=NULL;
|
|
|
|
//
|
|
// Get NOW PLAYING Event
|
|
//
|
|
int lines[TRANSPORT_QUANTITY];
|
|
int running=runningEvents(lines,false);
|
|
//
|
|
// "Longest running" algorithm
|
|
//
|
|
/*
|
|
for(int i=0;i<running;i++) {
|
|
if((time=logLine(lines[i])->startTime(RDLogLine::Actual).
|
|
addMSecs(logLine(lines[i])->effectiveLength()))>end_time) {
|
|
end_time=time;
|
|
now_line=lines[i];
|
|
}
|
|
}
|
|
*/
|
|
/*
|
|
//
|
|
// "Most recently started" algorithm
|
|
//
|
|
if(running>0) {
|
|
now_line=lines[running-1]; // Most recently started event
|
|
}
|
|
*/
|
|
//
|
|
// "Hybrid" algorithm
|
|
//
|
|
if(running>0) {
|
|
now_line=lines[running-1]; // Most recently started event
|
|
if((!logLine(now_line)->nowNextEnabled())||(logLine(now_line)->cartType()!=RDCart::Macro)) {
|
|
//
|
|
// If the most recently started event is not a Now&Next-enabled macro
|
|
// cart, then use longest running event instead
|
|
//
|
|
for(int i=0;i<running;i++) {
|
|
if((time=logLine(lines[i])->startTime(RDLogLine::Actual).
|
|
addMSecs(logLine(lines[i])->effectiveLength()))>end_time) {
|
|
end_time=time;
|
|
now_line=lines[i];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if((now_line>=0)&&(logLine(now_line)->nowNextEnabled())) {
|
|
logline[0]=logLine(now_line);
|
|
}
|
|
else {
|
|
if(play_now_cartnum==0) {
|
|
logline[0]=NULL;
|
|
}
|
|
else {
|
|
default_now_logline=new RDLogLine(play_now_cartnum);
|
|
logline[0]=default_now_logline;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get NEXT Event
|
|
//
|
|
logline[1]=NULL;
|
|
for(int i=nextLine();i<size();i++) {
|
|
if((ll=logLine(i))!=NULL) {
|
|
if((ll->status()==RDLogLine::Scheduled)&&
|
|
logLine(i)->nowNextEnabled()&&(!logLine(i)->asyncronous())) {
|
|
logline[1]=logLine(i);
|
|
i=size();
|
|
}
|
|
}
|
|
}
|
|
if((logline[1]==NULL)&&(play_next_cartnum!=0)) {
|
|
default_next_logline=new RDLogLine(play_next_cartnum);
|
|
logline[1]=default_next_logline;
|
|
}
|
|
|
|
//
|
|
// Process and Send It
|
|
//
|
|
unsigned nowcart=0;
|
|
unsigned nextcart=0;
|
|
if(logline[0]!=NULL) {
|
|
if(!logline[0]->asyncronous()) {
|
|
nowcart=logline[0]->cartNumber();
|
|
}
|
|
}
|
|
if(logline[1]!=NULL) {
|
|
nextcart=logline[1]->cartNumber();
|
|
}
|
|
if((nowcart==play_prevnow_cartnum)&&(nextcart==play_prevnext_cartnum)) {
|
|
return;
|
|
}
|
|
if(logline[0]==NULL) {
|
|
play_prevnow_cartnum=0;
|
|
}
|
|
else {
|
|
play_prevnow_cartnum=logline[0]->cartNumber();
|
|
}
|
|
if(logline[1]==NULL) {
|
|
play_prevnext_cartnum=0;
|
|
}
|
|
else {
|
|
play_prevnext_cartnum=logline[1]->cartNumber();
|
|
}
|
|
QString svcname=play_svc_name;
|
|
if(svcname.isEmpty()) {
|
|
svcname=play_defaultsvc_name;
|
|
}
|
|
|
|
//
|
|
// Send to PAD Server
|
|
//
|
|
play_pad_socket->write(QString("{\r\n").toUtf8());
|
|
play_pad_socket->write(QString(" \"padUpdate\": {\r\n").toUtf8());
|
|
play_pad_socket->write(RDJsonField("dateTime",QDateTime::currentDateTime(),8).
|
|
toUtf8());
|
|
play_pad_socket->write(RDJsonField("hostName",
|
|
rda->station()->name(),8).toUtf8());
|
|
play_pad_socket->write(RDJsonField("shortHostName",
|
|
rda->station()->shortName(),8).toUtf8());
|
|
play_pad_socket->write(RDJsonField("machine",play_id+1,8));
|
|
play_pad_socket->write(RDJsonField("onairFlag",play_onair_flag,8));
|
|
play_pad_socket->write(RDJsonField("mode",RDAirPlayConf::logModeText(play_op_mode),8));
|
|
|
|
//
|
|
// Service
|
|
//
|
|
if(svcname.isEmpty()) {
|
|
play_pad_socket->write(RDJsonNullField("service",8).toUtf8());
|
|
}
|
|
else {
|
|
RDSvc *svc=new RDSvc(svcname,rda->station(),rda->config(),this);
|
|
play_pad_socket->write(QString(" \"service\": {\r\n").toUtf8());
|
|
play_pad_socket->write(RDJsonField("name",svcname,12).toUtf8());
|
|
play_pad_socket->
|
|
write(RDJsonField("description",svc->description(),12).toUtf8());
|
|
play_pad_socket->
|
|
write(RDJsonField("programCode",svc->programCode(),12,true).toUtf8());
|
|
play_pad_socket->write(QString(" },\r\n").toUtf8());
|
|
delete svc;
|
|
}
|
|
|
|
//
|
|
// Log
|
|
//
|
|
play_pad_socket->write(QString(" \"log\": {\r\n").toUtf8());
|
|
play_pad_socket->write(RDJsonField("name",logName(),12,true).toUtf8());
|
|
play_pad_socket->write(QString(" },\r\n").toUtf8());
|
|
|
|
//
|
|
// Now
|
|
//
|
|
QDateTime start_datetime;
|
|
if(logline[0]!=NULL) {
|
|
start_datetime=
|
|
QDateTime(QDate::currentDate(),logline[0]->startTime(RDLogLine::Actual));
|
|
}
|
|
play_pad_socket->
|
|
write(GetPadJson("now",logline[0],start_datetime,now_line,8,false).
|
|
toUtf8());
|
|
|
|
//
|
|
// Next
|
|
//
|
|
QDateTime next_datetime;
|
|
if((mode()==RDAirPlayConf::Auto)&&(logline[0]!=NULL)) {
|
|
next_datetime=start_datetime.addSecs(logline[0]->forcedLength()/1000);
|
|
}
|
|
play_pad_socket->write(GetPadJson("next",logline[1],
|
|
next_datetime,nextLine(),8,true).toUtf8());
|
|
|
|
//
|
|
// Commit the update
|
|
//
|
|
play_pad_socket->write(QString(" }\r\n").toUtf8());
|
|
play_pad_socket->write(QString("}\r\n\r\n").toUtf8());
|
|
|
|
//
|
|
// Clean up
|
|
//
|
|
if(default_now_logline!=NULL) {
|
|
delete default_now_logline;
|
|
}
|
|
if(default_next_logline!=NULL) {
|
|
delete default_next_logline;
|
|
}
|
|
}
|
|
|
|
|
|
QString RDLogPlay::GetPadJson(const QString &name,RDLogLine *ll,
|
|
const QDateTime &start_datetime,int line,
|
|
int padding,bool final) const
|
|
{
|
|
QString ret;
|
|
|
|
if(ll==NULL) {
|
|
ret=RDJsonNullField(name,padding,final);
|
|
}
|
|
else {
|
|
ret+=RDJsonPadding(padding)+"\""+name+"\": {\r\n";
|
|
if(start_datetime.isValid()) {
|
|
ret+=RDJsonField("startDateTime",start_datetime,4+padding);
|
|
}
|
|
else {
|
|
ret+=RDJsonNullField("startDateTime",4+padding);
|
|
}
|
|
ret+=RDJsonField("lineNumber",line,4+padding);
|
|
ret+=RDJsonField("lineId",ll->id(),4+padding);
|
|
ret+=RDJsonField("cartNumber",ll->cartNumber(),4+padding);
|
|
ret+=RDJsonField("cartType",RDCart::typeText(ll->cartType()),4+padding);
|
|
if(ll->cartType()==RDCart::Audio) {
|
|
ret+=RDJsonField("cutNumber",ll->cutNumber(),4+padding);
|
|
}
|
|
else {
|
|
ret+=RDJsonNullField("cutNumber",4+padding);
|
|
}
|
|
if(ll->useEventLength()) {
|
|
ret+=RDJsonField("length",ll->eventLength(),4+padding);
|
|
}
|
|
else {
|
|
ret+=RDJsonField("length",ll->forcedLength(),4+padding);
|
|
}
|
|
if(ll->year().isValid()) {
|
|
ret+=RDJsonField("year",ll->year().year(),4+padding);
|
|
}
|
|
else {
|
|
ret+=RDJsonNullField("year",4+padding);
|
|
}
|
|
ret+=RDJsonField("groupName",ll->groupName(),4+padding);
|
|
ret+=RDJsonField("title",ll->title(),4+padding);
|
|
ret+=RDJsonField("artist",ll->artist(),4+padding);
|
|
ret+=RDJsonField("publisher",ll->publisher(),4+padding);
|
|
ret+=RDJsonField("composer",ll->composer(),4+padding);
|
|
ret+=RDJsonField("album",ll->album(),4+padding);
|
|
ret+=RDJsonField("label",ll->label(),4+padding);
|
|
ret+=RDJsonField("client",ll->client(),4+padding);
|
|
ret+=RDJsonField("agency",ll->agency(),4+padding);
|
|
ret+=RDJsonField("conductor",ll->conductor(),4+padding);
|
|
ret+=RDJsonField("userDefined",ll->userDefined(),4+padding);
|
|
ret+=RDJsonField("songId",ll->songId(),4+padding);
|
|
ret+=RDJsonField("outcue",ll->outcue(),4+padding);
|
|
ret+=RDJsonField("description",ll->description(),4+padding);
|
|
ret+=RDJsonField("isrc",ll->isrc(),4+padding);
|
|
ret+=RDJsonField("isci",ll->isci(),4+padding);
|
|
ret+=RDJsonField("externalEventId",ll->extEventId(),4+padding);
|
|
ret+=RDJsonField("externalData",ll->extData(),4+padding);
|
|
ret+=RDJsonField("externalAnncType",ll->extAnncType(),4+padding,true);
|
|
if(final) {
|
|
ret+=RDJsonPadding(padding)+"}\r\n";
|
|
}
|
|
else {
|
|
ret+=RDJsonPadding(padding)+"},\r\n";
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
void RDLogPlay::LogTraffic(RDLogLine *logline,RDLogLine::PlaySource src,
|
|
RDAirPlayConf::TrafficAction action,bool onair_flag)
|
|
const
|
|
{
|
|
QString sql;
|
|
QDateTime datetime=QDateTime(QDate::currentDate(),QTime::currentTime());
|
|
int length=logline->startTime(RDLogLine::Actual).msecsTo(datetime.time());
|
|
if(length<0) { // Event crossed midnight!
|
|
length+=86400000;
|
|
datetime.setDate(datetime.date().addDays(-1));
|
|
}
|
|
|
|
if((logline==NULL)||(serviceName().isEmpty())) {
|
|
return;
|
|
}
|
|
|
|
QString eventDateTimeSQL = "NULL";
|
|
|
|
if(datetime.isValid() && logline->startTime(RDLogLine::Actual).isValid())
|
|
eventDateTimeSQL = RDCheckDateTime(QDateTime(datetime.date(),
|
|
logline->startTime(RDLogLine::Actual)), "yyyy-MM-dd hh:mm:ss");
|
|
|
|
sql=QString("insert into ELR_LINES set ")+
|
|
"SERVICE_NAME=\""+RDEscapeString(serviceName())+"\","+
|
|
QString().sprintf("LENGTH=%d,",length)+
|
|
"LOG_NAME=\""+RDEscapeString(logName())+"\","+
|
|
QString().sprintf("LOG_ID=%d,",logline->id())+
|
|
QString().sprintf("CART_NUMBER=%u,",logline->cartNumber())+
|
|
"STATION_NAME=\""+RDEscapeString(rda->station()->name())+"\","+
|
|
"EVENT_DATETIME="+eventDateTimeSQL+","+
|
|
QString().sprintf("EVENT_TYPE=%d,",action)+
|
|
QString().sprintf("EVENT_SOURCE=%d,",logline->source())+
|
|
"EXT_START_TIME="+RDCheckDateTime(logline->extStartTime(),"hh:mm:ss")+","+
|
|
QString().sprintf("EXT_LENGTH=%d,",logline->extLength())+
|
|
"EXT_DATA=\""+RDEscapeString(logline->extData())+"\","+
|
|
"EXT_EVENT_ID=\""+RDEscapeString(logline->extEventId())+"\","+
|
|
"EXT_ANNC_TYPE=\""+RDEscapeString(logline->extAnncType())+"\","+
|
|
QString().sprintf("PLAY_SOURCE=%d,",src)+
|
|
QString().sprintf("CUT_NUMBER=%d,",logline->cutNumber())+
|
|
"EXT_CART_NAME=\""+RDEscapeString(logline->extCartName())+"\","+
|
|
"TITLE=\""+RDEscapeString(logline->title())+"\","+
|
|
"ARTIST=\""+RDEscapeString(logline->artist())+"\","+
|
|
"SCHEDULED_TIME="+RDCheckDateTime(logline->startTime(RDLogLine::Logged),
|
|
"hh:mm:ss")+","+
|
|
"ISRC=\""+RDEscapeString(logline->isrc())+"\","+
|
|
"PUBLISHER=\""+RDEscapeString(logline->publisher())+"\","+
|
|
"COMPOSER=\""+RDEscapeString(logline->composer())+"\","+
|
|
QString().sprintf("USAGE_CODE=%d,",logline->usageCode())+
|
|
QString().sprintf("START_SOURCE=%d,",logline->startSource())+
|
|
"ONAIR_FLAG=\""+RDYesNo(onair_flag)+"\","+
|
|
"ALBUM=\""+RDEscapeString(logline->album())+"\","+
|
|
"LABEL=\""+RDEscapeString(logline->label())+"\","+
|
|
"USER_DEFINED=\""+RDEscapeString(logline->userDefined())+"\","+
|
|
"CONDUCTOR=\""+RDEscapeString(logline->conductor())+"\","+
|
|
"SONG_ID=\""+RDEscapeString(logline->songId())+"\","+
|
|
"DESCRIPTION=\""+RDEscapeString(logline->description())+"\","+
|
|
"OUTCUE=\""+RDEscapeString(logline->outcue())+"\","+
|
|
"ISCI=\""+RDEscapeString(logline->isci())+"\"";
|
|
RDSqlQuery::apply(sql);
|
|
}
|