From 22c3fc2ae2ba2125bc3af55ab8e6de4bc4102ac6 Mon Sep 17 00:00:00 2001 From: Loïc Collignon Date: Thu, 15 Nov 2018 15:45:30 +0100 Subject: Fix issues with session and policies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a policy does a 'ramp-down' on an audio role, it never does the 'ramp-up' when closing the role that triggered the policy. Also, session handling was very buggy and had to be reworked to allow the policy to do its job. Bug: SPEC-1949 Bug: SPEC-1950 Change-Id: I668044201c9addbc185ea953c6e3239abfda91c5 Signed-off-by: Loïc Collignon --- ahl-binding/interrupt.cpp | 113 ++++++++++++++++++++++++++++++++++++++++++++++ ahl-binding/interrupt.hpp | 11 ++++- ahl-binding/role.cpp | 86 ++++++++++++----------------------- 3 files changed, 152 insertions(+), 58 deletions(-) diff --git a/ahl-binding/interrupt.cpp b/ahl-binding/interrupt.cpp index 9c247b3..5bf0b79 100644 --- a/ahl-binding/interrupt.cpp +++ b/ahl-binding/interrupt.cpp @@ -1,4 +1,7 @@ +#include +#include "ahl-binding.hpp" #include "interrupt.hpp" +#include "role.hpp" interrupt_t::interrupt_t(json_object* o) { @@ -36,3 +39,113 @@ void interrupt_t::args(json_object* v) { args_ = v; } + +int interrupt_t::apply(afb_req_t req, const role_t& role) +{ + /*if (type_ == "mute") + { + } + else if (type_ == "continue") + { + } + else if (type_ == "cancel") + { + } + else */if (type_ == "ramp") + { + for(const auto& r: ahl_binding_t::instance().roles()) + { + if (r.opened() && role.priority() > r.priority()) + { + // { "ramp" : { "uid" : "ramp-slow", "volume" : 30 } } + json_object* arg = json_object_new_object(); + json_object_object_add(arg, "ramp", args_); + json_object_get(args_); + json_object* result = nullptr; + + AFB_API_DEBUG(ahl_binding_t::instance().handle(), + "Call '%s'/'%s' '%s'", + r.hal().c_str(), r.stream().c_str(), json_object_to_json_string(arg)); + + if(afb_api_call_sync(ahl_binding_t::instance().handle(), r.hal().c_str(), r.stream().c_str(), arg, &result, nullptr, nullptr)) + { + afb_req_fail(req, "Failed to call 'ramp' action on stream", nullptr); + return -1; + } + json_object* jvolold = nullptr; + if (json_object_object_get_ex(result, "volold", &jvolold)) + { + applied_on_.push_back(std::make_tuple(r.uid(), json_object_get_int(jvolold))); + AFB_API_DEBUG(ahl_binding_t::instance().handle(), + "POLICY: Applying a ramp to '%s' stream because '%s' is opened and have higher priority!", + r.stream().c_str(), role.stream().c_str()); + } + } + } + return 0; + } + else + { + afb_req_fail(req, "Unkown interrupt uid!", nullptr); + return -1; + } +} + +void interrupt_t::clear() +{ + for (const std::tuple& state : applied_on_) + { + std::string role; + int vol; + std::tie(role, vol) = state; + /*if (type_ == "mute") + { + } + else if (type_ == "continue") + { + } + else if (type_ == "cancel") + { + } + else */if (type_ == "ramp") + { + for(const auto& r: ahl_binding_t::instance().roles()) + { + if (r.uid() == role) + { + // { "ramp" : { "uid" : "ramp-slow", "volume" : 30 } } + // Create an fake-interrupt, with the old volume + json_object* interrupt = json_tokener_parse(json_object_to_json_string(args_)); + json_object_object_add(interrupt, "volume", json_object_new_int(vol)); // Replace the volume + /* + json_object* volume = nullptr; + if (json_object_object_get_ex(interrupt, "volume", &volume)) + { + json_object_set_int(volume, vol); + } + */ + + json_object* arg = json_object_new_object(); + json_object_object_add(arg, "ramp", interrupt); + json_object* result = nullptr; + + AFB_API_DEBUG(ahl_binding_t::instance().handle(), + "Call '%s'/'%s' '%s", + r.hal().c_str(), r.stream().c_str(), json_object_to_json_string(arg)); + + if(afb_api_call_sync(ahl_binding_t::instance().handle(), r.hal().c_str(), r.stream().c_str(), arg, &result, nullptr, nullptr)) + { + AFB_API_ERROR(ahl_binding_t::instance().handle(), + "Failed to call 'ramp' action on '%s'", role.c_str()); + } + else + { + AFB_API_DEBUG(ahl_binding_t::instance().handle(), + "Called 'ramp' action on '%s'", role.c_str()); + } + } + } + } + } + applied_on_.clear(); +} diff --git a/ahl-binding/interrupt.hpp b/ahl-binding/interrupt.hpp index caf5cda..c123699 100644 --- a/ahl-binding/interrupt.hpp +++ b/ahl-binding/interrupt.hpp @@ -1,12 +1,19 @@ #pragma once - +#include +#include +#include +#include "afb-binding-common.h" #include "jsonc_utils.hpp" +// Forward declaration +class role_t; + class interrupt_t { private: std::string type_; json_object* args_; + std::vector> applied_on_; public: explicit interrupt_t() = default; @@ -25,4 +32,6 @@ public: void type(std::string v); void args(json_object* v); + int apply(afb_req_t req, const role_t& role); + void clear(); }; diff --git a/ahl-binding/role.cpp b/ahl-binding/role.cpp index 0da9304..3a4dd0e 100644 --- a/ahl-binding/role.cpp +++ b/ahl-binding/role.cpp @@ -15,10 +15,13 @@ * limitations under the License. */ +#include #include "role.hpp" #include "jsonc_utils.hpp" #include "ahl-binding.hpp" +using session_t = std::vector; + role_t::role_t(json_object* j) { jcast(uid_, j, "uid"); @@ -111,50 +114,7 @@ const std::vector& role_t::interrupts() const int role_t::apply_policy(afb_req_t req) { - if(interrupts_.size()) - { - const interrupt_t& i = interrupts_[0]; - /*if (i.type() == "mute") - { - } - else if (i.type() == "continue") - { - } - else if (i.type() == "cancel") - { - } - else */if (i.type() == "ramp") - { - for(const auto& r: ahl_binding_t::instance().roles()) - { - if (r.opened() && priority_ > r.priority()) - { - // { "ramp" : { "uid" : "ramp-slow", "volume" : 30 } } - json_object* arg = json_object_new_object(); - json_object_object_add(arg, "ramp", i.args()); - json_object_get(i.args()); - json_object* result = nullptr; - - AFB_API_DEBUG(ahl_binding_t::instance().handle(), "Call '%s'/'%s' '%s", - r.hal().c_str(), r.stream().c_str(), json_object_to_json_string(arg)); - - if(afb_api_call_sync(ahl_binding_t::instance().handle(), r.hal().c_str(), r.stream().c_str(), arg, &result, nullptr, nullptr)) - { - afb_req_fail(req, "Failed to call 'ramp' action on stream", nullptr); - return -1; - } - AFB_API_DEBUG(ahl_binding_t::instance().handle(), "POLICY: Applying a ramp to '%s' stream because '%s' is opened and have higher priority!", - r.stream().c_str(), stream_.c_str()); - } - } - } - else - { - afb_req_fail(req, "Unkown interrupt uid!", nullptr); - return -1; - } - } - return 0; + return interrupts_.size() ? interrupts_[0].apply(req, *this) : 0; } void role_t::invoke(afb_req_t req) @@ -200,22 +160,20 @@ void role_t::open(afb_req_t r, json_object* o) if (!apply_policy(r)) { - afb_req_context_set( - r, - this, - [](void* arg) - { - role_t * role = (role_t*) arg; - - if (role->opened_) + afb_req_context(r, + 0, // Do not replace previous context if any + [](void* arg) -> void* { return new session_t(); }, + [](void* arg) { + afb_api_t api = ahl_binding_t::instance().handle(); + session_t* opened_roles = reinterpret_cast(arg); + for(role_t* role : *opened_roles) { - afb_api_t api = ahl_binding_t::instance().handle(); - AFB_API_DEBUG(api, "Released role %s\n", role->uid_.c_str()); role->opened_ = false; + if(role->interrupts_.size()) role->interrupts_[0].clear(); // send a mute command to the HAL. We cannot reuse the do_mute function, - // because in the context here, the afb_req_t is no longer valid. + // because in the context here, the afb_request is no longer valid. json_object* a = json_object_new_object(); json_object_object_add(a, "mute", json_object_new_boolean(true)); @@ -227,10 +185,17 @@ void role_t::open(afb_req_t r, json_object* o) NULL, NULL); } - } + delete opened_roles; + }, + nullptr ); + opened_ = true; + // Add the current role to the session + session_t* context = reinterpret_cast(afb_req_context_get(r)); + if(context) context->push_back(this); + json_object* result = json_object_new_object(); json_object_object_add(result, "device_uri", json_object_new_string(device_uri_.c_str())); @@ -246,13 +211,20 @@ void role_t::close(afb_req_t r, json_object* o) return; } - if(!afb_req_context_get(r)) + session_t* context = reinterpret_cast(afb_req_context_get(r)); + if(!context) { afb_req_fail(r, "Stream is opened by another client!", nullptr); return; } + // Remove the current role from the session. + std::string uid = uid_; + std::remove_if(context->begin(), context->end(), [uid](role_t* r) { return r->uid_ == uid; }); + context->push_back(this); + opened_ = false; + if(interrupts_.size()) interrupts_[0].clear(); afb_req_success(r, nullptr, "Stream closed!"); } -- cgit 1.2.3-korg