some more error handling for sound playing

This commit is contained in:
Dorian Zedler 2020-10-03 18:33:17 +02:00
parent 6709a1fd2b
commit e4700cd355
Signed by: dorian
GPG key ID: D3B255CB8BC7CD37
5 changed files with 64 additions and 32 deletions

View file

@ -134,7 +134,7 @@ private slots:
void handleTimerWantsToBeDisabledChange(ScStwTimer* timer, bool wantsToBeDisabled);
int handleFalseStart();
bool playSoundsAndStartTimers();
bool doDelayAndSoundOfCurrentStartState(double *timeOfSoundPlaybackStart = nullptr);
ScStwSoundPlayer::PlayResult doDelayAndSoundOfCurrentStartState(double *timeOfSoundPlaybackStart = nullptr);
void technicalIncident();
/**

View file

@ -49,6 +49,12 @@ public:
FalseStart = 3
};
enum PlayResult {
Success = 0,
Cancelled = -1,
Error = -2
};
private:
/*!
* \brief A map containing all sound files
@ -91,16 +97,16 @@ public slots:
* \param action The action to play (0: AtYourMarks, 1:Ready, 2:Start)
* \param volume The volume to play at
* \param timeOfStop The time the playback actually started (msecs since epoch)
* \return true if the playback was successfully started, false otherwise
* \return TODO true if the playback was successfully started, false otherwise
*/
bool play(StartSound sound, double volume, double *timeOfStart = nullptr);
ScStwSoundPlayer::PlayResult play(StartSound sound, double volume, double *timeOfStart = nullptr);
/*!
* \brief Function to wait for the playback to finish
* \param timeOfStop the point in time when the plyback actually stopped (msecs since epoch)
* \return false if there was any error (eg. there was no playback currently), true otherwise
*/
bool waitForSoundFinish(double *timeOfStop = nullptr);
ScStwSoundPlayer::PlayResult waitForSoundFinish(double *timeOfStop = nullptr);
/*!
* \brief Function to cancel the current playback

View file

@ -197,6 +197,8 @@ void ScStwRace::technicalIncident() {
foreach(ScStwTimer *timer, this->timers){
timer->cancel();
}
this->soundPlayer->cancel();
this->setState(INCIDENT);
}
@ -223,8 +225,16 @@ bool ScStwRace::playSoundsAndStartTimers() {
return true;
// The check if all timers are ready has already happened at this point
if(!this->doDelayAndSoundOfCurrentStartState())
ScStwSoundPlayer::PlayResult res = this->doDelayAndSoundOfCurrentStartState();
if(res == ScStwSoundPlayer::Error) {
qDebug() << "[ERROR][RACE] error playing at your marks sound";
this->technicalIncident();
return false;
}
else if(res == ScStwSoundPlayer::Cancelled) {
return false;
}
// check if the start was cancelled
if(!this->isStarting())
@ -234,8 +244,6 @@ bool ScStwRace::playSoundsAndStartTimers() {
// do climber readiness tests
// wait until both climbers are ready
// if the automatic ready tone is enabled, wait for the climbers to become ready
if(this->competitionMode && this->getSoundEnabledSetting(ScStwSoundPlayer::Ready)) {
@ -290,11 +298,16 @@ bool ScStwRace::playSoundsAndStartTimers() {
qDebug() << "[DEBUG][RACE] Wait finished, starting now!";
// play ready tone
if(!this->soundPlayer->play(ScStwSoundPlayer::Ready, this->getSoundVolume())) {
qDebug() << "[ERROR][RACE] Ready sound returned false!";
ScStwSoundPlayer::PlayResult res = this->soundPlayer->play(ScStwSoundPlayer::Ready, this->getSoundVolume());
if(res == ScStwSoundPlayer::Error) {
qDebug() << "[ERROR][RACE] error playing ready sound";
this->technicalIncident();
return false;
}
else if(res == ScStwSoundPlayer::Cancelled) {
return false;
}
}
else if(this->competitionMode) {
// wait for climbers and manual start
@ -308,8 +321,14 @@ bool ScStwRace::playSoundsAndStartTimers() {
} while(loopExitCode != LoopManualExit || !this->getIsReadyForNextState());
}
else {
if(!this->doDelayAndSoundOfCurrentStartState()) {
this->cancel();
ScStwSoundPlayer::PlayResult res = this->doDelayAndSoundOfCurrentStartState();
if(res == ScStwSoundPlayer::Error) {
qDebug() << "[ERROR][RACE] error playing ready sound";
this->technicalIncident();
return false;
}
else if(res == ScStwSoundPlayer::Cancelled) {
return false;
}
}
@ -319,10 +338,16 @@ bool ScStwRace::playSoundsAndStartTimers() {
// play start tone
double timeOfSoundPlaybackStart;
if(!this->doDelayAndSoundOfCurrentStartState(&timeOfSoundPlaybackStart)) {
res = this->doDelayAndSoundOfCurrentStartState(&timeOfSoundPlaybackStart);
if(res == ScStwSoundPlayer::Error) {
qDebug() << "[ERROR][RACE] error playing at your marks sound";
this->technicalIncident();
return false;
}
else if(res == ScStwSoundPlayer::Cancelled) {
return false;
}
// perform start
@ -339,7 +364,7 @@ bool ScStwRace::playSoundsAndStartTimers() {
return false;
}
if(!this->soundPlayer->waitForSoundFinish()) {
if(this->soundPlayer->waitForSoundFinish() == ScStwSoundPlayer::Error) {
qDebug() << "[ERROR][RACE] start sound wait error";
this->technicalIncident();
return false;
@ -347,7 +372,7 @@ bool ScStwRace::playSoundsAndStartTimers() {
// check if a false start occured
if(!this->isStarting())
return true;
return false;
this->setState(RUNNING);
@ -356,7 +381,7 @@ bool ScStwRace::playSoundsAndStartTimers() {
}
bool ScStwRace::doDelayAndSoundOfCurrentStartState(double *timeOfSoundPlaybackStart) {
ScStwSoundPlayer::PlayResult ScStwRace::doDelayAndSoundOfCurrentStartState(double *timeOfSoundPlaybackStart) {
ScStwSoundPlayer::StartSound sound = this->getSoundForState(this->state);
if(this->getSoundEnabledSetting(sound)) {
@ -374,18 +399,18 @@ bool ScStwRace::doDelayAndSoundOfCurrentStartState(double *timeOfSoundPlaybackSt
emit this->currentStartDelayChanged();
if(this->startWaitLoop->exec() == LoopCancelExit)
return false;
return ScStwSoundPlayer::Cancelled;
}
}
if(!this->isStarting())
return false;
return ScStwSoundPlayer::Error;
if(!this->soundPlayer->play(sound, this->getSoundVolume(), timeOfSoundPlaybackStart))
return false;
return this->soundPlayer->play(sound, this->getSoundVolume(), timeOfSoundPlaybackStart);
}
return true;
return ScStwSoundPlayer::Success;
}
void ScStwRace::setState(RaceState newState) {

View file

@ -35,9 +35,11 @@ ScStwSoundPlayer::ScStwSoundPlayer(QObject *parent) : QObject(parent)
connect(this->soundEffect, &QSoundEffect::playingChanged, this->waitLoop, &QEventLoop::quit);
}
bool ScStwSoundPlayer::play(ScStwSoundPlayer::StartSound sound, double volume, double *timeOfStart) {
if(!this->soundFiles.contains(sound))
return false;
ScStwSoundPlayer::PlayResult ScStwSoundPlayer::play(ScStwSoundPlayer::StartSound sound, double volume, double *timeOfStart) {
if(!this->soundFiles.contains(sound)) {
qDebug() << "[ERROR][SoundPlayer] Sound file was not found for sound" << sound;
return ScStwSoundPlayer::Error;
}
// stop playback
if(this->soundEffect->isPlaying())
@ -55,6 +57,7 @@ bool ScStwSoundPlayer::play(ScStwSoundPlayer::StartSound sound, double volume, d
// wait for the effect to load
QEventLoop loop;
while(this->soundEffect->status() != QSoundEffect::Ready) {
qDebug() << "[DEBUG][Sound] Sound is not ready yet, status is: " << this->soundEffect->status();
QObject::connect(this->soundEffect, &QSoundEffect::statusChanged, &loop, &QEventLoop::quit);
loop.exec();
}
@ -76,7 +79,7 @@ bool ScStwSoundPlayer::play(ScStwSoundPlayer::StartSound sound, double volume, d
if(sound < Start)
return this->waitForSoundFinish();
return true;
return ScStwSoundPlayer::Success;
}
bool ScStwSoundPlayer::cancel() {
@ -85,17 +88,18 @@ bool ScStwSoundPlayer::cancel() {
// stop playback
this->soundEffect->stop();
this->waitLoop->quit();
this->waitLoop->exit(-1);
return true;
}
bool ScStwSoundPlayer::waitForSoundFinish(double *timeOfStop) {
ScStwSoundPlayer::PlayResult ScStwSoundPlayer::waitForSoundFinish(double *timeOfStop) {
if(!this->soundEffect->isPlaying())
return false;
return ScStwSoundPlayer::Error;
// wait until the audio output reports the sound is over
waitLoop->exec();
if(waitLoop->exec() == -1)
return ScStwSoundPlayer::Cancelled;
// wait until the sound is actually over
// the timeOffset is the buffer time before the audio started!
@ -113,7 +117,7 @@ bool ScStwSoundPlayer::waitForSoundFinish(double *timeOfStop) {
*timeOfStop = QDateTime::currentMSecsSinceEpoch() - latency;
}
return true;
return ScStwSoundPlayer::Success;
}
bool ScStwSoundPlayer::isPlaying() {

View file

@ -217,9 +217,6 @@ QString ScStwTimer::getLetter() {
}
QString ScStwTimer::getText() {
qDebug() << "getting text: start time: " << this->startTime << " state: " << this->state;
QString newText = "";
int newTime = 0;
switch (this->state) {