192 lines
6.3 KiB
C++
192 lines
6.3 KiB
C++
|
#pragma once
|
||
|
#include <stddef.h>
|
||
|
#include <vector>
|
||
|
#include <string>
|
||
|
#include <map>
|
||
|
#include <optional>
|
||
|
#include <SDL.h>
|
||
|
#include <iterator>
|
||
|
#include "ipc/internal.pb.h"
|
||
|
struct PlaybackStream {
|
||
|
double length;
|
||
|
std::string name;
|
||
|
int id;
|
||
|
};
|
||
|
class PlaybackBackendHelper;
|
||
|
class PlaybackBackend {
|
||
|
protected:
|
||
|
double length;
|
||
|
std::vector<PlaybackStream> streams;
|
||
|
std::string current_file;
|
||
|
std::string current_title;
|
||
|
bool open;
|
||
|
SDL_AudioSpec spec;
|
||
|
double position;
|
||
|
std::map<std::string, google::protobuf::Any> property_defaults;
|
||
|
std::map<std::string, google::protobuf::Any> properties;
|
||
|
public:
|
||
|
using map = std::map<std::string, PlaybackBackend*>;
|
||
|
using iterator = map::iterator;
|
||
|
using const_iterator = map::const_iterator;
|
||
|
using reverse_iterator = map::reverse_iterator;
|
||
|
using const_reverse_iterator = map::const_reverse_iterator;
|
||
|
inline virtual std::string get_id() {return "";}
|
||
|
inline virtual std::string get_name() {return "";}
|
||
|
inline virtual void seek(double position) { }
|
||
|
inline virtual double get_position() {
|
||
|
return position;
|
||
|
}
|
||
|
inline virtual SDL_AudioSpec get_spec() {
|
||
|
return spec;
|
||
|
}
|
||
|
inline virtual bool set(std::string path, google::protobuf::Any value) {properties[path] = value; return true;}
|
||
|
inline virtual std::optional<google::protobuf::Any> get(std::string path) {return properties.contains(path) ? properties[path] : std::optional<google::protobuf::Any>();}
|
||
|
inline virtual std::optional<google::protobuf::Any> reset(std::string path) {
|
||
|
if (property_defaults.contains(path)) {
|
||
|
properties[path] = property_defaults[path];
|
||
|
} else {
|
||
|
properties.erase(path);
|
||
|
}
|
||
|
return get(path);
|
||
|
}
|
||
|
virtual void load(const char *filename);
|
||
|
virtual void init(const char *filename, int idx = 0);
|
||
|
virtual void switch_stream(int idx);
|
||
|
inline virtual std::vector<PlaybackStream> get_streams() {
|
||
|
return streams;
|
||
|
}
|
||
|
inline virtual uint64_t get_min_samples() {return 0;}
|
||
|
inline virtual std::optional<uint64_t> get_max_samples() {return {};}
|
||
|
virtual void cleanup();
|
||
|
virtual size_t render(void *buf, size_t maxlen);
|
||
|
inline virtual double get_length() {
|
||
|
return open ? length : 0.0;
|
||
|
}
|
||
|
inline virtual std::optional<std::string> get_current_file() {
|
||
|
return open ? current_file : std::optional<std::string>();
|
||
|
}
|
||
|
inline virtual std::optional<std::string> get_title() {
|
||
|
return open ? current_title : std::optional<std::string>();
|
||
|
}
|
||
|
inline virtual int get_stream_idx() {return 0;}
|
||
|
inline virtual ~PlaybackBackend() { }
|
||
|
static map backends;
|
||
|
template<class T>
|
||
|
static inline std::string get_backend_id() {
|
||
|
PlaybackBackend *backend = new T();
|
||
|
auto output = backend->get_id();
|
||
|
delete backend;
|
||
|
return output;
|
||
|
}
|
||
|
static inline PlaybackBackend* get_first_backend() {
|
||
|
if (backends.empty()) {
|
||
|
return nullptr;
|
||
|
}
|
||
|
return (*backends.begin()).second;
|
||
|
}
|
||
|
static void register_backend(PlaybackBackend *backend) {
|
||
|
std::string backend_id = backend->get_id();
|
||
|
if (backends.contains(backend_id)) { // Guard against potential memory leak due to reassigning a new pointer without deallocating the previous one
|
||
|
delete backend;
|
||
|
return;
|
||
|
}
|
||
|
backends[backend_id] = backend;
|
||
|
}
|
||
|
template<class T>
|
||
|
static void register_backend() {
|
||
|
PlaybackBackend *backend = new T();
|
||
|
backend->register_self();
|
||
|
}
|
||
|
static inline void unregister_backend(std::string id) {
|
||
|
if (backends.contains(id)) {
|
||
|
auto backend = backends[id];
|
||
|
delete backend;
|
||
|
backends.erase(id);
|
||
|
}
|
||
|
}
|
||
|
inline void unregister_self() {
|
||
|
PlaybackBackend::unregister_backend(get_id());
|
||
|
}
|
||
|
inline void register_self() {
|
||
|
PlaybackBackend::register_backend(this);
|
||
|
}
|
||
|
template<class T>
|
||
|
static void unregister_backend() {
|
||
|
unregister_backend(get_backend_id<T>());
|
||
|
}
|
||
|
static void deinit_backends();
|
||
|
static inline std::optional<PlaybackBackend*> get_backend(std::string id) {
|
||
|
if (backends.contains(id)) {
|
||
|
return backends[id];
|
||
|
} else {
|
||
|
return {};
|
||
|
}
|
||
|
}
|
||
|
template<class T>
|
||
|
static inline std::optional<T*> get_backend() {
|
||
|
auto id = get_backend_id<T>();
|
||
|
auto output = get_backend(id);
|
||
|
if (output.has_value()) {
|
||
|
return (T*)output.value();
|
||
|
} else {
|
||
|
return {};
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
class PlaybackBackendHelper {
|
||
|
using iterator = PlaybackBackend::iterator;
|
||
|
using const_iterator = PlaybackBackend::const_iterator;
|
||
|
using reverse_iterator = PlaybackBackend::reverse_iterator;
|
||
|
using const_reverse_iterator = PlaybackBackend::const_reverse_iterator;
|
||
|
public:
|
||
|
inline iterator begin() {
|
||
|
return PlaybackBackend::backends.begin();
|
||
|
}
|
||
|
inline const_iterator cbegin() const {
|
||
|
return PlaybackBackend::backends.cbegin();
|
||
|
}
|
||
|
inline iterator end() {
|
||
|
return PlaybackBackend::backends.end();
|
||
|
}
|
||
|
inline const_iterator cend() const {
|
||
|
return PlaybackBackend::backends.cend();
|
||
|
}
|
||
|
inline reverse_iterator rbegin() {
|
||
|
return PlaybackBackend::backends.rbegin();
|
||
|
}
|
||
|
inline const_reverse_iterator crbegin() const {
|
||
|
return PlaybackBackend::backends.crbegin();
|
||
|
}
|
||
|
inline reverse_iterator rend() {
|
||
|
return PlaybackBackend::backends.rend();
|
||
|
}
|
||
|
inline const_reverse_iterator crend() const {
|
||
|
return PlaybackBackend::backends.crend();
|
||
|
}
|
||
|
inline size_t size() {
|
||
|
return PlaybackBackend::backends.size();
|
||
|
}
|
||
|
inline bool empty() {
|
||
|
return PlaybackBackend::backends.empty();
|
||
|
}
|
||
|
};
|
||
|
void init_playback_backends();
|
||
|
struct audio_data_t {
|
||
|
size_t size;
|
||
|
bool endian;
|
||
|
bool is_signed;
|
||
|
bool is_float;
|
||
|
};
|
||
|
void init_audio_data();
|
||
|
size_t size_of_sample_type(int type);
|
||
|
bool sample_type_has_endian(int type);
|
||
|
bool sample_type_endian_msb(int type);
|
||
|
bool sample_type_endian_lsb(int type);
|
||
|
bool sample_type_is_float(int type);
|
||
|
bool smaple_type_is_integer(int type);
|
||
|
bool sample_type_is_signed(int type);
|
||
|
bool sample_type_is_unsigned(int type);
|
||
|
int sample_spec_to_sdl(audio_data_t spec);
|
||
|
audio_data_t sdl_to_sample_spec(int type);
|
||
|
std::string sdl_to_str(int type);
|