#pragma once #ifdef DBUS_ENABLED #include #include #include "assets/dbus_stub_adaptor.hpp" #include "assets/dbus_stub_proxy.hpp" #include "assets/mpris_stub_adaptor.hpp" #endif #include "playback.h" #include #include #include #include #ifdef DBUS_ENABLED class DBusAPI; class MprisAPI : public sdbus::AdaptorInterfaces { friend class DBusAPI; DBusAPI *dbus_api; const std::string streamPrefix = "/com/complecwaft/looper/Streams/"; std::string curPlayingObjectPath; sdbus::IConnection &connection; const std::string mainInterface = "org.mpris.MediaPlayer2"; const std::string playerInterface = "org.mpris.MediaPlayer2.Player"; const std::string trackInterface = "org.mpris.MediaPlayer2.TrackList"; inline void sendPropertiesChanged(const std::string interface, const std::initializer_list properties) { std::vector property_vec; for (auto property : properties) { property_vec.push_back(property); } emitPropertiesChangedSignal(interface, property_vec); } public: #define meta_t std::map #define track_id_t sdbus::ObjectPath const sdbus::ObjectPath playing_track_id = "/com/complecwaft/Looper/PlayingTrack"; const sdbus::ObjectPath empty_track_id = "/org/mpris/MediaPlayer2/TrackList/NoTrack"; inline void Raise() override { } void Quit() override; inline std::string Identity() override { return "Looper"; } inline std::vector SupportedUriSchemes() override { std::vector output; output.push_back("file:"); return output; } inline std::vector SupportedMimeTypes() override { std::vector output; output.push_back("audio/*"); return output; } inline void Next() override { } inline void Previous() override { } void Pause() override; void PlayPause() override; void Stop() override; void Play() override; void Seek(const int64_t &offset) override; void SetPosition(const track_id_t &TrackId, const int64_t &Position) override; void OpenUri(const std::string &Uri) override; std::string PlaybackStatus() override; double Rate() override; void Rate(const double &value) override; meta_t Metadata() override; double Volume() override; void Volume(const double& value) override; int64_t Position() override; inline double MinimumRate() override { return 0.25; } inline double MaximumRate() override { return 4.0; } inline bool CanGoNext() override { return false; } inline bool CanGoPrevious() override { return false; } bool CanPlay() override; bool CanPause() override; bool CanSeek() override; inline bool CanControl() override { return true; } inline bool CanRaise() override { return false; } inline bool CanQuit() override { return true; } inline bool HasTrackList() override { return true; } std::vector GetTracksMetadata(const std::vector &TrackIds) override; void AddTrack(const std::string &Uri, const track_id_t &AfterTrack, const bool &SetAsCurrent) override; void RemoveTrack(const track_id_t &TrackId) override; void GoTo(const track_id_t &TrackId) override; std::vector Tracks() override; bool CanEditTracks() override; MprisAPI(sdbus::IConnection &connection, std::string objectPath, DBusAPI *dbus_api); ~MprisAPI(); }; #endif class DBusAPI #ifdef DBUS_ENABLED : public sdbus::AdaptorInterfaces #endif { std::map handles; size_t handle_idx = 0; public: static const char *objectPath; static const char *busName; #ifdef DBUS_ENABLED private: MprisAPI *mpris; sdbus::IConnection &connection; std::minstd_rand rand_engine; std::deque *get_errors_by_handle(const std::string &handle); bool daemon; std::atomic_bool threadExitFlag = false; std::thread threadFunc; public: void Activate(const std::map& platform_data) override; void Open(const std::vector& uris, const std::map& platform_data) override; void ActivateAction(const std::string& action_name, const std::vector& parameter, const std::map& platform_data) override; // com.experimentalcraft.Looper // Properties std::string FilePath() override; std::string FileTitle() override; double Speed() override; void Speed(const double &value) override; double Tempo() override; void Tempo(const double& value) override; double Pitch() override; void Pitch(const double& value) override; double Volume() override; void Volume(const double& value) override; double Position() override; void Position(const double &value) override; double Length() override; // Pausing and Resuming bool Paused() override; void Paused(const bool& value) override; void TogglePause() override; // Starting new Files void Start(const std::string &path, const bool &isUri) override; void StartWithStreamIndex(const std::string& path, const bool& isUri, const uint32_t& streamIndex) override; void Load(const std::string &path, const bool &isUri) override; // Playback stopping void Stop() override; bool IsStopped() override; // Handles std::string CreateHandle() override; void ClearHandle(const std::string& handle) override; // com.experimentalcraft.Looper.Errors // Popping from the queue std::string PopFront(const std::string &handle) override; std::string PopBack(const std::string &handle) override; // Peeking at the values std::string PeekFront(const std::string &handle) override; std::string PeekBack(const std::string &handle) override; // Getting the amount of unread errors. uint32_t GetCount(const std::string &handle) override; bool IsEmpty(const std::string& handle) override; // Getting and Clearing Errors. void Clear(const std::string &handle) override; std::vector PeekAll(const std::string &handle) override; std::vector GetAllAndClear(const std::string &handle) override; bool IsDaemon() override; void Quit() override; uint32_t StreamIdx() override; std::vector> GetStreams() override; void PlayStream(const uint32_t &idx) override; #endif public: // API Playback *playback; #ifdef DBUS_ENABLED void Update(); DBusAPI(Playback *playback, sdbus::IConnection &connection, std::string objectPath, bool daemon); #endif DBusAPI(Playback *playback, bool daemon); ~DBusAPI(); static DBusAPI *Create(Playback *playback, bool daemon = false); }; class DBusAPISender : public Playback #ifdef DBUS_ENABLED , public sdbus::ProxyInterfaces #endif { // Cache double length, pitch, speed, tempo, volume; bool stopped, paused; std::string filePath; std::string title; std::mutex cacheMutex; optional last_error; // Handle for error handling. std::string handle; public: // Public API for creating this object, and checking if it is needed. /// @brief Checks if this is the only instance, by attempting creation and immediately deleting the created object. /// @returns true, if this is the only instance, false otherwise. static bool isOnlyInstance(); /// @brief Creates a proxy playback engine, if possible. /// @returns A proxy to the main instance of the playback engine, or nullptr if there is none. static DBusAPISender *Create(); #ifdef DBUS_ENABLED // Signals. Protected so that they aren't seen as a proper API protected: void onPlaybackEngineStarted() override; void onSpeedChanged(const double &new_speed) override; void onTempoChanged(const double &new_tempo) override; void onPitchChanged(const double &new_pitch) override; void onPauseChanged(const bool &now_paused) override; void onStopped() override; void onErrorOccurred(const std::string &error_desc, const std::string &error_type) override; void onSeeked(const double &to_position) override; void onFileChanged(const std::string &path, const std::string &title) override; // Playback API. This is the API to be used by UI frontends. public: std::optional get_current_file() override; std::optional get_current_title() override; inline bool is_proxy() override { return true; } double GetPosition() override; double GetLength() override; void Seek(double position) override; void Start(std::string filePath, int streamIdx = 0) override; bool IsPaused() override; void Pause() override; void Stop() override; void Update(); bool IsStopped() override; void SetTempo(float tempo) override; void SetPitch(float pitch) override; void SetSpeed(float speed) override; void SetVolume(float volume) override; float GetTempo() override; float GetPitch() override; float GetSpeed() override; float GetVolume() override; int get_current_stream() override; void Load(std::string filePath) override; std::vector get_streams() override; // Constructors and destructors. // The constructor is protected because there is a different API that should be used for creation. protected: DBusAPISender(sdbus::IConnection &connection, std::string busName, std::string objectPath); public: ~DBusAPISender(); #else public: ~DBusAPISender() = default; #endif };