summaryrefslogtreecommitdiffstats
path: root/ahl-binding
diff options
context:
space:
mode:
authorLoïc Collignon <loic.collignon@iot.bzh>2018-11-15 15:45:30 +0100
committerLoïc Collignon <loic.collignon@iot.bzh>2018-11-19 10:24:01 +0100
commit04f89b1c4f49372aea2f9d1c7e0adad5fb8bd99b (patch)
treed8746fd5f74ba9bb285f5655593456b8e13a7fe1 /ahl-binding
parent14cc9c639e9837f81901297c8163c1c151840300 (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>
Diffstat (limited to 'ahl-binding')
-rw-r--r--ahl-binding/interrupt.cpp117
-rw-r--r--ahl-binding/interrupt.hpp11
-rw-r--r--ahl-binding/role.cpp114
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!");
}