: QObject{parent}, m_player{playerInterface}, m_handle{
mpv::Handle::create()} {
qCDebug(mpvBackend) << "Initialize";
+ m_eventHandler = std::make_unique<mpv::EventHandler<MpvInstance>>(this);
qCDebug(mpvBackend()).nospace()
<< "Client API version: " << (mpv_client_api_version() >> 16) << '.'
maxVolume /= 100.0;
m_player->playbackMaxVolumeChanged(maxVolume);
}
+ m_eventHandler->subscribe(mpv::event::LogMessage, &MpvInstance::onLogMessage);
+ m_eventHandler->subscribe(mpv::event::PropertyChange,
+ &MpvInstance::onPropertyChange);
+ m_eventHandler->subscribe(mpv::event::FileLoaded, &MpvInstance::onFileLoaded);
+ m_eventHandler->subscribe(mpv::event::EndFile, &MpvInstance::onEndFile);
+ m_eventHandler->subscribe(mpv::event::AudioReconfig,
+ &MpvInstance::onAudioReconfig);
}
MpvInstance::~MpvInstance() {
qCDebug(mpvVerboseBackend).nospace()
<< "Event " << mpv_event_name(event->event_id) << '(' << event->event_id
<< "), error: " << event->error;
- switch (event->event_id) {
- case MPV_EVENT_PROPERTY_CHANGE: {
- Q_CHECK_PTR(event->data);
- auto property = static_cast<mpv_event_property *>(event->data);
- Q_CHECK_PTR(property);
- onPropertyChange(property);
- } break;
- case MPV_EVENT_LOG_MESSAGE: {
- Q_CHECK_PTR(event->data);
- auto log = static_cast<mpv_event_log_message *>(event->data);
- Q_CHECK_PTR(log);
- onLogMessage(log);
- } break;
- case MPV_EVENT_FILE_LOADED: {
- onFileLoaded();
- } break;
- case MPV_EVENT_END_FILE: {
- Q_CHECK_PTR(event->data);
- auto endFile = static_cast<mpv_event_end_file *>(event->data);
- onEndFile(endFile);
- } break;
- case MPV_EVENT_AUDIO_RECONFIG: {
- onAudioReconfig();
- } break;
- default:;
- }
+ m_eventHandler->handleEvent(event);
} while (event->event_id != MPV_EVENT_NONE);
}
struct mpv_event_log_message;
struct mpv_event_end_file;
+namespace mpv {
+template<typename T>
+class EventHandler;
+}
+
class BACKEND_MPVSHARED_EXPORT BackendMpv : public QObject,
public BackendPluginBase {
Q_OBJECT
int readTrackIndex(struct mpv_event_property *);
+ std::unique_ptr<mpv::EventHandler<MpvInstance>> m_eventHandler;
PlayerPluginInterface *m_player = nullptr;
mpv::Handle m_handle;
Volume m_volumeToSet = -1;
#include <QVariant>
#include <memory>
+#include <unordered_map>
#include <QLoggingCategory>
struct Event
{
using type = DataType;
+ using type_ptr = type *;
const mpv_event_id id;
constexpr explicit Event(mpv_event_id id) : id{id} {}
};
return detail::WriteFormat(handle, format, property.name, value);
}
+template<typename Class>
+class EventHandler {
+ struct Callback
+ {
+ virtual ~Callback() = default;
+ virtual void run(Class *, mpv_event *) const = 0;
+ };
+ template<typename Event, typename CallbackType, bool IsVoid>
+ struct EventCallback : public Callback
+ {
+ const Event m_event;
+ CallbackType m_callback;
+
+ EventCallback(Event event, CallbackType callback)
+ : m_event{event}, m_callback{callback} {}
+
+ void run(Class *obj, mpv_event *event) const override {
+ assert(event->event_id == m_event.id);
+ if constexpr (IsVoid) {
+ (obj->*m_callback)();
+ } else {
+ assert(event->data != nullptr);
+ auto data = static_cast<typename Event::type_ptr>(event->data);
+ (obj->*m_callback)(data);
+ }
+ }
+ };
+
+ Class *const m_obj;
+
+ std::unordered_map<int, std::unique_ptr<Callback>> m_eventHandlers;
+
+public:
+ explicit EventHandler(Class *obj) : m_obj{obj} {}
+
+ template<typename Event>
+ std::enable_if_t<!std::is_same_v<typename Event::type, void>, bool>
+ subscribe(Event event, void (Class::*handler)(typename Event::type_ptr)) {
+ auto pair = m_eventHandlers.emplace(std::make_pair(
+ event.id,
+ std::make_unique<EventCallback<Event, decltype(handler), false>>(
+ event, handler)));
+ return !pair.second;
+ }
+
+ template<typename Event>
+ bool subscribe(Event event, void (Class::*handler)()) {
+ auto pair = m_eventHandlers.emplace(std::make_pair(
+ event.id,
+ std::make_unique<EventCallback<Event, decltype(handler), true>>(
+ event, handler)));
+ return !pair.second;
+ }
+
+ void handleEvent(mpv_event *event) {
+ assert(event != nullptr);
+ const auto it = m_eventHandlers.find(event->event_id);
+ if (it == std::end(m_eventHandlers)) {
+ return;
+ }
+ it->second->run(m_obj, event);
+ }
+};
+
} // namespace mpv
#endif // MPVHELPER_H