diff options
author | Loïc Collignon <loic.collignon@iot.bzh> | 2018-11-15 15:45:30 +0100 |
---|---|---|
committer | Loïc Collignon <loic.collignon@iot.bzh> | 2018-11-19 10:24:01 +0100 |
commit | 04f89b1c4f49372aea2f9d1c7e0adad5fb8bd99b (patch) | |
tree | d8746fd5f74ba9bb285f5655593456b8e13a7fe1 | |
parent | 14cc9c639e9837f81901297c8163c1c151840300 (diff) |
Fix issues with session and policies
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 it's job.
Bug: SPEC-1949
Bug: SPEC-1950
Change-Id: I668044201c9addbc185ea953c6e3239abfda91c5
Signed-off-by: Loïc Collignon <loic.collignon@iot.bzh>
-rw-r--r-- | ahl-binding/interrupt.cpp | 117 | ||||
-rw-r--r-- | ahl-binding/interrupt.hpp | 11 | ||||
-rw-r--r-- | ahl-binding/role.cpp | 114 |
3 files changed, 171 insertions, 71 deletions
diff --git a/ahl-binding/interrupt.cpp b/ahl-binding/interrupt.cpp index 9c247b3..6826764 100644 --- a/ahl-binding/interrupt.cpp +++ b/ahl-binding/interrupt.cpp @@ -1,4 +1,7 @@ +#include <json-c/json.h> +#include "ahl-binding.hpp" #include "interrupt.hpp" +#include "role.hpp" interrupt_t::interrupt_t(json_object* o) { @@ -36,3 +39,117 @@ void interrupt_t::args(json_object* v) { args_ = v; } + +int interrupt_t::apply(afb_request* 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_DYNAPI_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_dynapi_call_sync(ahl_binding_t::instance().handle(), r.hal().c_str(), r.stream().c_str(), arg, &result)) + { + afb_request_fail(req, "Failed to call 'ramp' action on stream", nullptr); + return -1; + } + json_object* response = nullptr; + json_object* jvolold = nullptr; + if (json_object_object_get_ex(result, "response", &response)) + { + if (json_object_object_get_ex(response, "volold", &jvolold)) + { + applied_on_.push_back(std::make_tuple<std::string, int>(r.uid(), json_object_get_int(jvolold))); + AFB_DYNAPI_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_request_fail(req, "Unkown interrupt uid!", nullptr); + return -1; + } +} + +void interrupt_t::clear() +{ + for (const std::tuple<std::string, int>& 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_DYNAPI_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_dynapi_call_sync(ahl_binding_t::instance().handle(), r.hal().c_str(), r.stream().c_str(), arg, &result)) + { + AFB_DYNAPI_ERROR(ahl_binding_t::instance().handle(), + "Failed to call 'ramp' action on '%s'", role.c_str()); + } + else + { + AFB_DYNAPI_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..b540d22 100644 --- a/ahl-binding/interrupt.hpp +++ b/ahl-binding/interrupt.hpp @@ -1,12 +1,19 @@ #pragma once - +#include <vector> +#include <string> +#include <tuple> +#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<std::tuple<std::string, uint32_t>> 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_request* req, const role_t& role); + void clear(); }; diff --git a/ahl-binding/role.cpp b/ahl-binding/role.cpp index a122fc2..a073b33 100644 --- a/ahl-binding/role.cpp +++ b/ahl-binding/role.cpp @@ -15,10 +15,13 @@ * limitations under the License. */ +#include <algorithm> #include "role.hpp" #include "jsonc_utils.hpp" #include "ahl-binding.hpp" +using session_t = std::vector<role_t*>; + role_t::role_t(json_object* j) { jcast(uid_, j, "uid"); @@ -111,52 +114,7 @@ const std::vector<interrupt_t>& role_t::interrupts() const int role_t::apply_policy(afb_request* 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_DYNAPI_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_dynapi_call_sync(ahl_binding_t::instance().handle(), r.hal().c_str(), r.stream().c_str(), arg, &result)) - { - afb_request_fail(req, "Failed to call 'ramp' action on stream", nullptr); - return -1; - } - AFB_DYNAPI_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_request_fail(req, "Unkown interrupt uid!", nullptr); - return -1; - } - } - return 0; + return interrupts_.size() ? interrupts_[0].apply(req, *this) : 0; } void role_t::invoke(afb_request* req) @@ -202,33 +160,42 @@ void role_t::open(afb_request* r, json_object* o) if (!apply_policy(r)) { - afb_request_context_set( - r, - this, - [](void* arg) - { - role_t * role = (role_t*) arg; + afb_req_context(r, + 0, // Do not replace previous context if any + [](void* arg) -> void* { return new session_t(); }, + [](void* arg) { afb_dynapi * api = ahl_binding_t::instance().handle(); - - AFB_DYNAPI_DEBUG(api, "Released role %s\n", role->uid_.c_str()); - role->opened_ = false; - - // send a mute command to the HAL. We cannot reuse the do_mute function, - // 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)); - - afb_dynapi_call( - api, - role->hal_.c_str(), - role->stream_.c_str(), - a, - NULL, - NULL); - } + session_t* opened_roles = reinterpret_cast<session_t*>(arg); + for(role_t* role : *opened_roles) + { + AFB_DYNAPI_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_request is no longer valid. + json_object* a = json_object_new_object(); + json_object_object_add(a, "mute", json_object_new_boolean(true)); + + afb_dynapi_call( + api, + role->hal_.c_str(), + role->stream_.c_str(), + a, + NULL, + NULL); + } + delete opened_roles; + }, + this ); + opened_ = true; + // Add the current role to the session + session_t* context = reinterpret_cast<session_t*>(afb_req_context_get(r)); + 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())); @@ -244,13 +211,20 @@ void role_t::close(afb_request* r, json_object* o) return; } - if(!afb_request_context_get(r)) + session_t* context = reinterpret_cast<session_t*>(afb_req_context_get(r)); + if(!context) { afb_request_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_request_success(r, nullptr, "Stream closed!"); } |