2024-03-23 18:41:26 -07:00
|
|
|
#pragma once
|
2024-04-24 09:59:51 -07:00
|
|
|
#ifdef DBUS_ENABLED
|
2024-03-23 18:41:26 -07:00
|
|
|
#include <sdbus-c++/sdbus-c++.h>
|
2024-04-09 10:15:05 -07:00
|
|
|
#include <sdbus-c++/StandardInterfaces.h>
|
|
|
|
#include "assets/dbus_stub_adaptor.hpp"
|
|
|
|
#include "assets/dbus_stub_proxy.hpp"
|
|
|
|
#include "assets/mpris_stub_adaptor.hpp"
|
2024-04-24 09:59:51 -07:00
|
|
|
#endif
|
2024-03-23 18:41:26 -07:00
|
|
|
#include "playback.h"
|
2024-04-09 10:15:05 -07:00
|
|
|
#include <mutex>
|
|
|
|
#include <optional>
|
|
|
|
#include <random>
|
|
|
|
#include <thread>
|
2024-04-24 09:59:51 -07:00
|
|
|
#ifdef DBUS_ENABLED
|
2024-12-17 11:06:29 -08:00
|
|
|
#ifdef OLD_SDBUS
|
|
|
|
#define OBJECT_PATH(path) path
|
|
|
|
#define VARIANT(value) value
|
|
|
|
#define BUS_NAME(name) name
|
|
|
|
#define SERVICE_NAME(name) name
|
|
|
|
#define MEMBER_NAME(name) name
|
|
|
|
#define INTERFACE_NAME(name) name
|
|
|
|
namespace sdbus {
|
|
|
|
typedef std::string MemberName;
|
|
|
|
typedef std::string ServiceName;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#define OBJECT_PATH(path) sdbus::ObjectPath{path}
|
|
|
|
#define VARIANT(value) sdbus::Variant{value}
|
|
|
|
#define BUS_NAME(name) sdbus::BusName{name}
|
|
|
|
#define SERVICE_NAME(name) sdbus::ServiceName{name}
|
|
|
|
#define MEMBER_NAME(name) sdbus::MemberName{name}
|
|
|
|
#define INTERFACE_NAME(name) sdbus::InterfaceName{name}
|
|
|
|
#endif
|
|
|
|
|
2024-04-09 10:15:05 -07:00
|
|
|
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;
|
2024-04-14 10:19:46 -07:00
|
|
|
const std::string streamPrefix = "/com/complecwaft/looper/Streams/";
|
2024-04-09 10:15:05 -07:00
|
|
|
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) {
|
2024-12-11 10:01:40 -08:00
|
|
|
std::vector<sdbus::MemberName> property_vec;
|
2024-04-09 10:15:05 -07:00
|
|
|
for (auto property : properties) {
|
2024-12-17 11:06:29 -08:00
|
|
|
property_vec.push_back(MEMBER_NAME(property));
|
|
|
|
}
|
|
|
|
emitPropertiesChangedSignal(INTERFACE_NAME(interface), property_vec);
|
2024-04-09 10:15:05 -07:00
|
|
|
}
|
|
|
|
public:
|
|
|
|
#define meta_t std::map<std::string, sdbus::Variant>
|
|
|
|
#define track_id_t sdbus::ObjectPath
|
2024-12-17 11:06:29 -08:00
|
|
|
const sdbus::ObjectPath playing_track_id = OBJECT_PATH("/com/complecwaft/Looper/PlayingTrack");
|
|
|
|
const sdbus::ObjectPath empty_track_id = OBJECT_PATH("/org/mpris/MediaPlayer2/TrackList/NoTrack");
|
2024-04-09 10:15:05 -07:00
|
|
|
|
|
|
|
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);
|
2024-09-16 15:05:53 -07:00
|
|
|
virtual ~MprisAPI();
|
2024-04-09 10:15:05 -07:00
|
|
|
};
|
2024-04-24 09:59:51 -07:00
|
|
|
#endif
|
|
|
|
class DBusAPI
|
|
|
|
#ifdef DBUS_ENABLED
|
2024-09-16 15:05:53 -07:00
|
|
|
: public sdbus::AdaptorInterfaces<com::complecwaft::looper_adaptor, com::complecwaft::looper::Errors_adaptor, org::freedesktop::Application_adaptor>
|
2024-04-24 09:59:51 -07:00
|
|
|
#endif
|
|
|
|
{
|
2024-04-09 10:15:05 -07:00
|
|
|
std::map<std::string, void*> handles;
|
|
|
|
size_t handle_idx = 0;
|
2024-04-24 09:59:51 -07:00
|
|
|
public:
|
|
|
|
static const char *objectPath;
|
|
|
|
static const char *busName;
|
|
|
|
#ifdef DBUS_ENABLED
|
|
|
|
private:
|
2024-04-09 10:15:05 -07:00
|
|
|
MprisAPI *mpris;
|
2024-04-24 09:59:51 -07:00
|
|
|
sdbus::IConnection &connection;
|
2024-04-09 10:15:05 -07:00
|
|
|
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;
|
2024-03-23 18:41:26 -07:00
|
|
|
public:
|
2024-04-09 10:15:05 -07:00
|
|
|
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
|
2024-04-13 12:56:39 -07:00
|
|
|
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;
|
2024-04-09 10:15:05 -07:00
|
|
|
// 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;
|
2024-04-13 12:56:39 -07:00
|
|
|
uint32_t StreamIdx() override;
|
2024-04-14 13:25:49 -07:00
|
|
|
std::vector<sdbus::Struct<double, std::string, int32_t>> GetStreams() override;
|
2024-04-13 12:56:39 -07:00
|
|
|
void PlayStream(const uint32_t &idx) override;
|
2024-04-09 10:15:05 -07:00
|
|
|
|
2024-04-24 09:59:51 -07:00
|
|
|
#endif
|
|
|
|
public:
|
2024-04-09 10:15:05 -07:00
|
|
|
// API
|
2024-03-23 18:41:26 -07:00
|
|
|
Playback *playback;
|
2024-04-24 09:59:51 -07:00
|
|
|
#ifdef DBUS_ENABLED
|
2024-04-09 10:15:05 -07:00
|
|
|
void Update();
|
|
|
|
DBusAPI(Playback *playback, sdbus::IConnection &connection, std::string objectPath, bool daemon);
|
2024-04-24 09:59:51 -07:00
|
|
|
#endif
|
|
|
|
DBusAPI(Playback *playback, bool daemon);
|
2024-09-16 15:05:53 -07:00
|
|
|
virtual ~DBusAPI();
|
2024-04-09 10:15:05 -07:00
|
|
|
static DBusAPI *Create(Playback *playback, bool daemon = false);
|
2024-03-23 18:41:26 -07:00
|
|
|
};
|
2024-04-24 09:59:51 -07:00
|
|
|
class DBusAPISender : public Playback
|
|
|
|
#ifdef DBUS_ENABLED
|
2024-04-28 12:31:40 -07:00
|
|
|
, public sdbus::ProxyInterfaces<com::complecwaft::looper_proxy, com::complecwaft::looper::Errors_proxy, org::freedesktop::Application_proxy, sdbus::Peer_proxy>
|
2024-09-16 15:05:53 -07:00
|
|
|
#endif
|
2024-04-24 09:59:51 -07:00
|
|
|
{
|
2024-04-09 10:15:05 -07:00
|
|
|
// 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;
|
2024-09-16 15:05:53 -07:00
|
|
|
|
2024-04-09 10:15:05 -07:00
|
|
|
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();
|
|
|
|
|
2024-04-24 09:59:51 -07:00
|
|
|
#ifdef DBUS_ENABLED
|
2024-04-09 10:15:05 -07:00
|
|
|
// 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;
|
2024-04-13 12:56:39 -07:00
|
|
|
void Start(std::string filePath, int streamIdx = 0) override;
|
2024-04-09 10:15:05 -07:00
|
|
|
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;
|
2024-04-13 12:56:39 -07:00
|
|
|
int get_current_stream() override;
|
|
|
|
void Load(std::string filePath) override;
|
2024-04-14 13:25:49 -07:00
|
|
|
std::vector<PlaybackStream> get_streams() override;
|
2024-04-09 10:15:05 -07:00
|
|
|
// 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);
|
2024-03-23 18:41:26 -07:00
|
|
|
public:
|
2024-09-16 15:05:53 -07:00
|
|
|
virtual ~DBusAPISender();
|
2024-04-24 09:59:51 -07:00
|
|
|
#else
|
|
|
|
public:
|
|
|
|
~DBusAPISender() = default;
|
|
|
|
#endif
|
2024-09-16 15:05:53 -07:00
|
|
|
};
|