Improve error handling of playback process

This commit is contained in:
Zachary Hall 2024-09-29 15:28:08 -07:00
parent 6f08458f63
commit 7e43808b4d
6 changed files with 75 additions and 10 deletions

View file

@ -14,7 +14,7 @@ void CFile::open(const char *fname) {
name = fname; name = fname;
file = fopen(fname, "rb"); file = fopen(fname, "rb");
if (file == NULL) { if (file == NULL) {
throw std::exception(); throw NotFoundException(fname);
} }
fseek(file, 0, SEEK_END); fseek(file, 0, SEEK_END);
len = ftell(file); len = ftell(file);

View file

@ -9,15 +9,54 @@
#include <stdlib.h> #include <stdlib.h>
#include <SDL.h> #include <SDL.h>
#include <vector> #include <vector>
#include <fmt/core.h>
#include <fmt/format.h>
extern "C" { extern "C" {
#include <vgmstream.h> #include <vgmstream.h>
} }
#include "log.hpp" #include "log.hpp"
#include <stdlib.h>
#include <string.h>
enum class SeekType { enum class SeekType {
SET, SET,
CUR, CUR,
END END
}; };
class CustomException : public std::exception {
const char *message;
protected:
void clear_message(bool free_message = true) {
if (free_message && this->message != nullptr) {
free((void*)this->message);
}
this->message = nullptr;
}
public:
CustomException() {
clear_message(false);
}
CustomException(std::string message) : CustomException() {
set_message(message);
}
void set_message(std::string message) {
clear_message();
this->message = strdup(message.c_str());
}
const char *what() const throw() {
return this->message;
}
~CustomException() {
clear_message();
}
};
class NotFoundException : public CustomException {
public:
NotFoundException(std::string file) : CustomException() {
set_message(fmt::format("File not found: {0}", file));
}
NotFoundException(const char *file) : NotFoundException(std::string(file)) { }
};
class File { class File {
protected: protected:
size_t len; size_t len;

View file

@ -137,9 +137,14 @@ void PlaybackInstance::Load(const char *file, int idx) {
SDL_LockAudioDevice(device); SDL_LockAudioDevice(device);
playback_ready.store(false); playback_ready.store(false);
if (process != nullptr) delete process; if (process != nullptr) delete process;
process = new PlaybackProcess(file, idx); try {
process = new PlaybackProcess(file, idx);
} catch (std::exception e) {
ERROR.writefln("Exception caught when creating process: %s", e.what());
process = nullptr;
}
length = 0.0; length = 0.0;
if (process->process_running()) { if (process != nullptr && process->process_running()) {
length = process->get_length(); length = process->get_length();
auto backend_spec_proxy = process->get_audio_spec(); auto backend_spec_proxy = process->get_audio_spec();
memset(&backend_spec, 0, sizeof(backend_spec)); memset(&backend_spec, 0, sizeof(backend_spec));
@ -186,8 +191,7 @@ void PlaybackInstance::Load(const char *file, int idx) {
load_finished.store(true); load_finished.store(true);
this->process->set_position(0.0); this->process->set_position(0.0);
} else { } else {
ERROR.writeln("Failed to detect valid playback backend for file!"); set_error("Failed to create playback backend.");
set_error("Failed to detect valid backend for file.");
set_signal(PlaybackSignalErrorOccurred); set_signal(PlaybackSignalErrorOccurred);
delete process; delete process;
process = nullptr; process = nullptr;
@ -387,7 +391,11 @@ void PlaybackInstance::LoopFunction() {
} }
flag_mutex.unlock(); flag_mutex.unlock();
} }
position = process->get_position(); if (process) {
position = process->get_position();
} else {
position = 0.0;
}
} }
void PlaybackInstance::DeinitLoopFunction() { void PlaybackInstance::DeinitLoopFunction() {

View file

@ -291,6 +291,7 @@ ResetResponse PlaybackProcessServiceImpl::Reset(const ResetProperty *request) {
return response; return response;
} }
MaybeError PlaybackProcessServiceImpl::Quit(const QuitCmd *request) { MaybeError PlaybackProcessServiceImpl::Quit(const QuitCmd *request) {
if (process == nullptr) return MaybeError();
process->done = true; process->done = true;
cur_backend_lock.get_unsafe()->cleanup(); cur_backend_lock.get_unsafe()->cleanup();
return MaybeError(); return MaybeError();
@ -302,6 +303,15 @@ MaybeError PlaybackProcessServiceImpl::Init(const InitCommand *cmd) {
render_ptr.lock().set(new DynPtr(), true); render_ptr.lock().set(new DynPtr(), true);
lock.clear(); lock.clear();
auto filename = cmd->filename(); auto filename = cmd->filename();
if (!std::filesystem::exists(filename)) {
ErrorResponse *maybe_error = response->mutable_err();
maybe_error->set_desc("File not found");
maybe_error->set_id("not_found");
maybe_error->set_fatal(true);
process->done = true;
return ret;
}
auto idx = cmd->idx(); auto idx = cmd->idx();
for (auto &backend : PlaybackBackendHelper()) { for (auto &backend : PlaybackBackendHelper()) {
DEBUG.writefln("Trying backend: %s", backend.second->get_name().c_str()); DEBUG.writefln("Trying backend: %s", backend.second->get_name().c_str());
@ -317,11 +327,10 @@ MaybeError PlaybackProcessServiceImpl::Init(const InitCommand *cmd) {
break; break;
} }
if (!cur_backend_lock.has_value()) { if (!cur_backend_lock.has_value()) {
ErrorResponse *maybe_error = new ErrorResponse(); ErrorResponse *maybe_error = response->mutable_err();
maybe_error->set_desc("Couldn't find a backend."); maybe_error->set_desc("Couldn't find a backend.");
maybe_error->set_id("no_backend_for_file"); maybe_error->set_id("no_backend_for_file");
maybe_error->set_fatal(true); maybe_error->set_fatal(true);
response->set_allocated_err(maybe_error);
process->done = true; process->done = true;
DEBUG.writefln("Couldn't find any backend."); DEBUG.writefln("Couldn't find any backend.");
return ret; return ret;
@ -401,7 +410,11 @@ PlaybackProcess::PlaybackProcess(std::string filename, int idx) {
call.mutable_init()->CopyFrom(cmd); call.mutable_init()->CopyFrom(cmd);
RPCResponse response = SendCommand(&call); RPCResponse response = SendCommand(&call);
if (response.has_err()) { if (response.has_err()) {
throw std::exception(); this->init_failed = true;
delete other_process;
other_process = nullptr;
auto err = response.err();
throw CustomException(err.has_desc() ? err.desc() : err.id());
} }
} }
bool PlaybackProcess::process_running() { bool PlaybackProcess::process_running() {
@ -577,6 +590,10 @@ AudioSpec *PlaybackProcess::get_audio_spec() {
return get_property_value<AudioSpec>(PropertyId::SpecProperty); return get_property_value<AudioSpec>(PropertyId::SpecProperty);
} }
PlaybackProcess::~PlaybackProcess() { PlaybackProcess::~PlaybackProcess() {
if (init_failed || other_process == nullptr) {
done = true;
return;
}
QuitCmd quit_cmd; QuitCmd quit_cmd;
RPCCall call; RPCCall call;
call.mutable_quit()->CopyFrom(quit_cmd); call.mutable_quit()->CopyFrom(quit_cmd);

View file

@ -45,6 +45,7 @@ class PlaybackProcess {
PlaybackProcess *other_process = nullptr; PlaybackProcess *other_process = nullptr;
PlaybackProcessServiceImpl impl; PlaybackProcessServiceImpl impl;
int pid; int pid;
bool init_failed = false;
std::mutex start_mutex; std::mutex start_mutex;
std::condition_variable started; std::condition_variable started;
bool is_playback_process = false; bool is_playback_process = false;

View file

@ -345,4 +345,4 @@ class DynPtr {
return get_byte_sized<T>(len * sizeof(T)); return get_byte_sized<T>(len * sizeof(T));
} }
} }
}; };