#pragma once #include #include #include #include #include #include #include #include "ipc/internal.pb.h" struct PlaybackStream { double length; std::string name; int id; }; class PlaybackBackendHelper; class PlaybackBackend { protected: double length; std::vector streams; std::string current_file; std::string current_title; bool open; SDL_AudioSpec spec; double position; std::map property_defaults; std::map properties; public: using map = std::map; 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 get(std::string path) {return properties.contains(path) ? properties[path] : std::optional();} inline virtual std::optional 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 get_streams() { return streams; } inline virtual uint64_t get_min_samples() {return 0;} inline virtual std::optional 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 get_current_file() { return open ? current_file : std::optional(); } inline virtual std::optional get_title() { return open ? current_title : std::optional(); } inline virtual int get_stream_idx() {return 0;} inline virtual ~PlaybackBackend() { } static map backends; template 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 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 static void unregister_backend() { unregister_backend(get_backend_id()); } static void deinit_backends(); static inline std::optional get_backend(std::string id) { if (backends.contains(id)) { return backends[id]; } else { return {}; } } template static inline std::optional get_backend() { auto id = get_backend_id(); 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);