looper/dbus.hpp
Zachary Hall ee94b97d19
Some checks failed
Build / build-gentoo (push) Failing after 31s
Build / download-system-deps (push) Successful in 3m5s
Build / get-source-code (push) Successful in 13m4s
Build / build-appimage (push) Successful in 5m0s
Build / build-android (push) Failing after 3m46s
Build / build-windows (push) Failing after 8m42s
Migrate to sdbus-c++ v2
2024-12-11 10:03:32 -08:00

264 lines
10 KiB
C++

#pragma once
#ifdef DBUS_ENABLED
#include <sdbus-c++/sdbus-c++.h>
#include <sdbus-c++/StandardInterfaces.h>
#include "assets/dbus_stub_adaptor.hpp"
#include "assets/dbus_stub_proxy.hpp"
#include "assets/mpris_stub_adaptor.hpp"
#endif
#include "playback.h"
#include <mutex>
#include <optional>
#include <random>
#include <thread>
#ifdef DBUS_ENABLED
class DBusAPI;
class MprisAPI : public sdbus::AdaptorInterfaces<org::mpris::MediaPlayer2_adaptor, org::mpris::MediaPlayer2::Player_adaptor, org::mpris::MediaPlayer2::TrackList_adaptor, sdbus::Properties_adaptor> {
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<std::string> properties) {
std::vector<sdbus::MemberName> property_vec;
for (auto property : properties) {
property_vec.push_back(sdbus::MemberName{property});
}
emitPropertiesChangedSignal(sdbus::InterfaceName{interface}, property_vec);
}
public:
#define meta_t std::map<std::string, sdbus::Variant>
#define track_id_t sdbus::ObjectPath
const sdbus::ObjectPath playing_track_id = sdbus::ObjectPath{"/com/complecwaft/Looper/PlayingTrack"};
const sdbus::ObjectPath empty_track_id = sdbus::ObjectPath{"/org/mpris/MediaPlayer2/TrackList/NoTrack"};
inline void Raise() override { }
void Quit() override;
inline std::string Identity() override {
return "Looper";
}
inline std::vector<std::string> SupportedUriSchemes() override {
std::vector<std::string> output;
output.push_back("file:");
return output;
}
inline std::vector<std::string> SupportedMimeTypes() override {
std::vector<std::string> 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<meta_t> GetTracksMetadata(const std::vector<track_id_t> &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<track_id_t> Tracks() override;
bool CanEditTracks() override;
MprisAPI(sdbus::IConnection &connection, std::string objectPath, DBusAPI *dbus_api);
virtual ~MprisAPI();
};
#endif
class DBusAPI
#ifdef DBUS_ENABLED
: public sdbus::AdaptorInterfaces<com::complecwaft::looper_adaptor, com::complecwaft::looper::Errors_adaptor, org::freedesktop::Application_adaptor>
#endif
{
std::map<std::string, void*> 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<std::string> *get_errors_by_handle(const std::string &handle);
bool daemon;
std::atomic_bool threadExitFlag = false;
std::thread threadFunc;
public:
void Activate(const std::map<std::string, sdbus::Variant>& platform_data) override;
void Open(const std::vector<std::string>& uris, const std::map<std::string, sdbus::Variant>& platform_data) override;
void ActivateAction(const std::string& action_name, const std::vector<sdbus::Variant>& parameter, const std::map<std::string, sdbus::Variant>& 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<std::string> PeekAll(const std::string &handle) override;
std::vector<std::string> GetAllAndClear(const std::string &handle) override;
bool IsDaemon() override;
void Quit() override;
uint32_t StreamIdx() override;
std::vector<sdbus::Struct<double, std::string, int32_t>> 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);
virtual ~DBusAPI();
static DBusAPI *Create(Playback *playback, bool daemon = false);
};
class DBusAPISender : public Playback
#ifdef DBUS_ENABLED
, public sdbus::ProxyInterfaces<com::complecwaft::looper_proxy, com::complecwaft::looper::Errors_proxy, org::freedesktop::Application_proxy, sdbus::Peer_proxy>
#endif
{
// Cache
double length, pitch, speed, tempo, volume;
bool stopped, paused;
std::string filePath;
std::string title;
std::mutex cacheMutex;
optional<std::string> 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<std::string> get_current_file() override;
std::optional<std::string> 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<PlaybackStream> 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:
virtual ~DBusAPISender();
#else
public:
~DBusAPISender() = default;
#endif
};