From df83729280b6540b9a5eb796b404cc70dc1566c4 Mon Sep 17 00:00:00 2001 From: Loïc Collignon Date: Thu, 13 Dec 2018 09:30:54 +0100 Subject: Added volume_changed event plus verbs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New subscribe and unsubscribe verbs to get the volume_changed event. Bug: SPEC-2053 Change-Id: Iedeb542c7c3d880f0d6294b0310d2662e0ac11f1 Signed-off-by: Loïc Collignon --- ahl-binding/ahl-binding.cpp | 92 ++++++++++++++++++++++++++++++++++++++++----- ahl-binding/ahl-binding.hpp | 6 ++- ahl-binding/role.cpp | 40 +++++++++++++++----- 3 files changed, 118 insertions(+), 20 deletions(-) diff --git a/ahl-binding/ahl-binding.cpp b/ahl-binding/ahl-binding.cpp index 036ed88..98d36b6 100644 --- a/ahl-binding/ahl-binding.cpp +++ b/ahl-binding/ahl-binding.cpp @@ -88,6 +88,24 @@ void ahl_api_get_roles(afb_req_t req) ahl_binding_t::instance().get_roles(req); } +/** + * @brief Callback invoked when clients call the verb 'subscribe'. + * @param[in] req Request to handle. + */ +void ahl_api_subscribe(afb_req_t req) +{ + ahl_binding_t::instance().subscribe(req); +} + +/** + * @brief Callback invoked when clients call the verb 'unsubscribe'. + * @param[in] req Request to handle. + */ +void ahl_api_unsubscribe(afb_req_t req) +{ + ahl_binding_t::instance().unsubscribe(req); +} + /** * @brief Callback invoked when clients call a 'role' verb. * @param[in] req Request to handle. @@ -166,6 +184,13 @@ int ahl_binding_t::init() afb_api_seal(handle_); AFB_API_NOTICE(handle_, "API is now sealed!"); + volume_changed_ = afb_api_make_event(handle_, "volume_changed"); + if(!afb_event_is_valid(volume_changed_)) + { + AFB_API_ERROR(handle_, "Failed to create the \"volume_changed\" event!"); + return -2; + } + if (update_streams()) return -1; return 0; } @@ -283,6 +308,30 @@ void ahl_binding_t::load_static_verbs() { throw std::runtime_error("Failed to add 'get_role' verb to the API."); } + + if (afb_api_add_verb( + handle_, + "subscribe", + "Subscribe to \"volume_changed\" event", + ahl_api_subscribe, + nullptr, + nullptr, + AFB_SESSION_NONE_X2, 0)) + { + throw std::runtime_error("Failed to add 'subscribe' verb to the API."); + } + + if (afb_api_add_verb( + handle_, + "unsubscribe", + "Unsubscribe to \"volume_changed\" event", + ahl_api_unsubscribe, + nullptr, + nullptr, + AFB_SESSION_NONE_X2, 0)) + { + throw std::runtime_error("Failed to add 'unsubscribe' verb to the API."); + } } void ahl_binding_t::load_controller_configs() @@ -381,26 +430,51 @@ int ahl_binding_t::create_api_verb(role_t* r) return 0; } -void ahl_binding_t::get_roles(afb_req_t req) +void ahl_binding_t::get_roles(afb_req_t req) const { - json_bool verbose = FALSE; - json_object* arg = afb_req_json(req); + json_bool verbose = FALSE; + json_object* arg = afb_req_json(req); json_object* jverbose; if (arg != nullptr) { - json_bool ret = json_object_object_get_ex(arg, "verbose", &jverbose); - if (ret) verbose = json_object_get_boolean(jverbose); + json_bool ret = json_object_object_get_ex(arg, "verbose", &jverbose); + if (ret) verbose = json_object_get_boolean(jverbose); } json_object* result = json_object_new_array(); for(const auto& r : roles_) - { - if (verbose == TRUE || r.device_uri().size()) - json_object_array_add(result, json_object_new_string(r.uid().c_str())); - } + { + if (verbose == TRUE || r.device_uri().size()) + json_object_array_add(result, json_object_new_string(r.uid().c_str())); + } afb_req_success(req, result, nullptr); } +void ahl_binding_t::subscribe(afb_req_t req) const +{ + if (afb_req_subscribe(req, volume_changed_)) + afb_req_fail(req, "Failed to subscribe to \"volume_changed\" event!", nullptr); + else + afb_req_success(req, nullptr, "Subscribed to \"volume_changed\" event!"); +} + +void ahl_binding_t::unsubscribe(afb_req_t req) const +{ + if (afb_req_unsubscribe(req, volume_changed_)) + afb_req_fail(req, "Failed to unsubscribe from \"volume_changed\" event!", nullptr); + else + afb_req_success(req, nullptr, "Unsubscribed from \"volume_changed\" event!"); +} + +int ahl_binding_t::emit_volume_changed(const std::string& role, int volume) const +{ + json_object* data = json_object_new_object(); + json_object_object_add(data, "role", json_object_new_string(role.c_str())); + json_object_object_add(data, "volume", json_object_new_int(volume)); + + return afb_event_push(volume_changed_, data); +} + const std::vector ahl_binding_t::roles() const { return roles_; diff --git a/ahl-binding/ahl-binding.hpp b/ahl-binding/ahl-binding.hpp index 0e7bd63..24f4acb 100644 --- a/ahl-binding/ahl-binding.hpp +++ b/ahl-binding/ahl-binding.hpp @@ -40,6 +40,7 @@ class ahl_binding_t private: afb_api_t handle_; + afb_event_t volume_changed_; std::vector roles_; explicit ahl_binding_t(); @@ -60,7 +61,10 @@ public: int preinit(afb_api_t handle); int init(); void event(std::string name, json_object* arg); - void get_roles(afb_req_t req); + void get_roles(afb_req_t req) const; + void subscribe(afb_req_t req) const; + void unsubscribe(afb_req_t req) const; + int emit_volume_changed(const std::string& role, int volume) const; const std::vector roles() const; afb_api_t handle() const; diff --git a/ahl-binding/role.cpp b/ahl-binding/role.cpp index 06caa98..7d35889 100644 --- a/ahl-binding/role.cpp +++ b/ahl-binding/role.cpp @@ -229,18 +229,18 @@ void role_t::close(afb_req_t r, json_object* o) } void role_t::mute(afb_req_t r, json_object* o) { - do_mute(r, true); + do_mute(r, true); } void role_t::unmute(afb_req_t r, json_object *o) { - do_mute(r, false); + do_mute(r, false); } void role_t::do_mute(afb_req_t r, bool v) { - json_object* a = json_object_new_object(); + json_object* a = json_object_new_object(); json_object_object_add(a, "mute", json_object_new_boolean(v)); - afb_api_t api = ahl_binding_t::instance().handle(); + afb_api_t api = ahl_binding_t::instance().handle(); afb_api_call( api, @@ -260,9 +260,15 @@ void role_t::do_mute(afb_req_t r, bool v) { afb_req_addref(r)); } +struct volumeclosure +{ + std::string role; + afb_req_t req; +}; + void role_t::volume(afb_req_t r, json_object* o) { - afb_api_t api = ahl_binding_t::instance().handle(); + afb_api_t api = ahl_binding_t::instance().handle(); if(!afb_req_has_permission(r, "urn:AGL:permission::public:4a-audio-mixer")) { @@ -296,6 +302,10 @@ void role_t::volume(afb_req_t r, json_object* o) json_object* a = json_object_new_object(); json_object_object_add(a, "volume", value); + volumeclosure* userdata = new volumeclosure(); + userdata->role = uid_; + userdata->req = afb_req_addref(r); + afb_api_call( api, hal_.c_str(), @@ -304,14 +314,24 @@ void role_t::volume(afb_req_t r, json_object* o) [](void* closure, json_object* result, const char* error, const char* info, afb_api_t handle) { AFB_API_DEBUG(handle, "Got the following answer: %s", json_object_to_json_string(result)); - afb_req_t r = (afb_req_t)closure; + volumeclosure* r = reinterpret_cast(closure); json_object_get(result); - if (error) afb_req_fail(r, json_object_to_json_string(result), nullptr); - else afb_req_success(r, result, nullptr); - afb_req_unref(r); + if (error) afb_req_fail(r->req, json_object_to_json_string(result), nullptr); + else + { + json_object* volnew; + if (json_object_object_get_ex(result, "volnew", &volnew)) + { + ahl_binding_t::instance().emit_volume_changed(r->role, json_object_get_int(volnew)); + } + afb_req_success(r->req, result, nullptr); + } + afb_req_unref(r->req); + delete r; }, - afb_req_addref(r)); + userdata + ); } void role_t::interrupt(afb_req_t r, json_object* o) -- cgit 1.2.3-korg