From 9a631c30c9c8792865ce2aa0ec06a1bb5fd16751 Mon Sep 17 00:00:00 2001 From: Loïc Collignon Date: Thu, 7 Jun 2018 15:05:53 +0200 Subject: Add some policy emulation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a very simplistic policy emulation just for demo. The real policy engine will be brought back soon. Change-Id: I6f77c8dc58ba335eabd1a1d858354a84559d9e7f Signed-off-by: Loïc Collignon --- ahl-binding/ahl-binding.cpp | 235 +++++++++++++++++++++++++++++++------------- 1 file changed, 168 insertions(+), 67 deletions(-) (limited to 'ahl-binding/ahl-binding.cpp') diff --git a/ahl-binding/ahl-binding.cpp b/ahl-binding/ahl-binding.cpp index 6493267..fa4c74b 100644 --- a/ahl-binding/ahl-binding.cpp +++ b/ahl-binding/ahl-binding.cpp @@ -20,24 +20,16 @@ afb_dynapi* AFB_default; // BUG: Is it possible to get rid of this ? -ahl_binding_t::ahl_binding_t() - : handle_{nullptr} - , apihandle_{nullptr} -{ -} - -ahl_binding_t& ahl_binding_t::instance() -{ - static ahl_binding_t s; - return s; -} - -int ahl_binding_t::build(afb_dynapi* handle) +/** + * @brief Entry point for dynamic API. + * @param[in] handle Handle to start with for API creation. + * @return Status code, zero if success. + */ +int afbBindingVdyn(afb_dynapi* handle) { using namespace std::placeholders; + assert(handle != nullptr); - if (!handle || handle_) return -1; - handle_ = handle; AFB_default = handle; return afb_dynapi_new_api( @@ -45,28 +37,48 @@ int ahl_binding_t::build(afb_dynapi* handle) HL_API_NAME, HL_API_INFO, 1, - [](void*, afb_dynapi* h) { - return ahl_binding_t::instance().preinit(h); - }, - nullptr); + ahl_api_create, + nullptr + ); +} + +/** + * @brief Callback to create the new api. + * @param[in] handle Handle to the new api. + * @return Status code, zero if success. + */ +int ahl_api_create(void*, struct afb_dynapi* handle) +{ + return ahl_binding_t::instance().preinit(handle); +} + +ahl_binding_t::ahl_binding_t() + : handle_{nullptr} +{ +} + +ahl_binding_t& ahl_binding_t::instance() +{ + static ahl_binding_t s; + return s; } int ahl_binding_t::preinit(afb_dynapi* handle) { - apihandle_ = handle; + handle_ = handle; try { load_static_verbs(); load_controller_api(); - if (afb_dynapi_on_event(handle, + if (afb_dynapi_on_event(handle_, [](afb_dynapi*, const char* e, struct json_object* o) { ahl_binding_t::instance().event(e, o); } ) ) throw std::runtime_error("Failed to register event handler callback."); - if (afb_dynapi_on_init(handle, + if (afb_dynapi_on_init(handle_, [](afb_dynapi*) { return ahl_binding_t::instance().init(); } )) throw std::runtime_error("Failed to register init handler callback."); } @@ -83,42 +95,63 @@ int ahl_binding_t::init() { using namespace std::placeholders; - if (afb_dynapi_require_api(apihandle_, HAL_MGR_API, 1)) + if (afb_dynapi_require_api(handle_, HAL_MGR_API, 1)) { - AFB_DYNAPI_ERROR(apihandle_, "Failed to require '%s' API!", HAL_MGR_API); + AFB_DYNAPI_ERROR(handle_, "Failed to require '%s' API!", HAL_MGR_API); return -1; } - AFB_DYNAPI_NOTICE(apihandle_, "Required '%s' API found!", HAL_MGR_API); + AFB_DYNAPI_NOTICE(handle_, "Required '%s' API found!", HAL_MGR_API); + if (afb_dynapi_require_api(handle_, "smixer", 1)) + { + AFB_DYNAPI_ERROR(handle_, "Failed to require 'smixer' API!"); + return -1; + } + AFB_DYNAPI_NOTICE(handle_, "Required 'smixer' API found!"); + // Requires corresponding API for(const auto& h : config_.hals()) { - if (afb_dynapi_require_api(apihandle_, h.c_str(), 1)) + if (afb_dynapi_require_api(handle_, h.c_str(), 1)) { - AFB_DYNAPI_ERROR(apihandle_, "Failed to require '%s' API!", h.c_str()); + AFB_DYNAPI_ERROR(handle_, "Failed to require '%s' API!", h.c_str()); return -1; } - AFB_DYNAPI_NOTICE(apihandle_, "Required '%s' API found!", h.c_str()); + AFB_DYNAPI_NOTICE(handle_, "Required '%s' API found!", h.c_str()); json_object* result = nullptr; - if(afb_dynapi_call_sync(apihandle_, h.c_str(), "init-mixer", nullptr, &result)) - { - AFB_DYNAPI_ERROR(apihandle_, "Failed to call 'init-mixer' verb on '%s' API!", h.c_str()); - if (result) AFB_DYNAPI_NOTICE(apihandle_, "%s", json_object_to_json_string(result)); - return -1; - } - AFB_DYNAPI_NOTICE(apihandle_, "Mixer initialized using '%s' API.", h.c_str()); + + // if(afb_dynapi_call_sync(handle_, h.c_str(), "init-mixer", nullptr, &result)) + // { + // AFB_DYNAPI_ERROR(handle_, "Failed to call 'init-mixer' verb on '%s' API!", h.c_str()); + // if (result) AFB_DYNAPI_NOTICE(handle_, "%s", json_object_to_json_string(result)); + // return -1; + // } + // AFB_DYNAPI_NOTICE(handle_, "Mixer initialized using '%s' API.", h.c_str()); + + // json_object* response = nullptr; + // json_object* verbose = json_object_new_object(); + // json_object_object_add(verbose, "verbose", json_object_new_int(1)); + // if (afb_dynapi_call_sync(handle_, h.c_str(), "list", verbose, &response)) + // { + // AFB_DYNAPI_ERROR(handle_, "Failed to call 'list' verb on '%s' API!", h.c_str()); + // if (result) AFB_DYNAPI_NOTICE(handle_, "%s", json_object_to_json_string(result)); + // return -1; + // } json_object* response = nullptr; - json_object* verbose = json_object_new_object(); - json_object_object_add(verbose, "verbose", json_object_new_int(1)); - if (afb_dynapi_call_sync(apihandle_, h.c_str(), "list", verbose, &response)) + json_object* arg = json_object_new_object(); + json_object_object_add(arg, "streams", json_object_new_boolean(TRUE)); + + if (afb_dynapi_call_sync(handle_, "smixer", "info", arg, &response)) { - AFB_DYNAPI_ERROR(apihandle_, "Failed to call 'list' verb on '%s' API!", h.c_str()); - if (result) AFB_DYNAPI_NOTICE(apihandle_, "%s", json_object_to_json_string(result)); + AFB_DYNAPI_ERROR(handle_, "Failed to call 'list' verb on '%s' API!", h.c_str()); + if (result) AFB_DYNAPI_NOTICE(handle_, "%s", json_object_to_json_string(result)); return -1; - } + } + + json_object* streams = json_object_object_get(response, "response"); - AFB_DYNAPI_DEBUG(apihandle_, "Called 'list' verb on '%s' API: %s", h.c_str(), json_object_to_json_string(streams)); + AFB_DYNAPI_DEBUG(handle_, "Called 'list' verb on '%s' API: %s", h.c_str(), json_object_to_json_string(streams)); json_object* array = json_object_object_get(streams, "streams"); size_t streams_count = json_object_array_length(array); for(size_t i = 0; i < streams_count; ++i) @@ -127,31 +160,33 @@ int ahl_binding_t::init() std::string device_uri; json_object* item = json_object_array_get_idx(array, i); - jcast(stream_name, item, "name"); - jcast(device_uri, item, "cardId"); + jcast(stream_name, item, "uid"); + jcast(device_uri, item, "alsa"); config_.set_device_uri(stream_name, device_uri); } } - afb_dynapi_seal(apihandle_); - AFB_DYNAPI_NOTICE(apihandle_, "API is now sealed!"); + afb_dynapi_seal(handle_); + AFB_DYNAPI_NOTICE(handle_, "API is now sealed!"); actions_["volume"] = std::bind(&ahl_binding_t::volume, this, _1, _2, _3, _4); actions_["open"] = std::bind(&ahl_binding_t::open, this, _1, _2, _3, _4); + actions_["close"] = std::bind(&ahl_binding_t::close, this, _1, _2, _3, _4); + actions_["interrupt"] = std::bind(&ahl_binding_t::interrupt, this, _1, _2, _3, _4); return 0; } void ahl_binding_t::event(std::string name, json_object* arg) { - AFB_DYNAPI_DEBUG(apihandle_, "Event '%s' received with the following arg: %s", name.c_str(), json_object_to_json_string(arg)); + AFB_DYNAPI_DEBUG(handle_, "Event '%s' received with the following arg: %s", name.c_str(), json_object_to_json_string(arg)); } void ahl_binding_t::load_static_verbs() { if (afb_dynapi_add_verb( - apihandle_, + handle_, "get_roles", "Retrieve array of available audio roles", [](afb_request* r) { ahl_binding_t::instance().get_roles(r); }, @@ -193,10 +228,10 @@ int ahl_binding_t::load_controller_config(const std::string& path) { CtlConfigT* controller_config; - controller_config = CtlLoadMetaData(apihandle_, path.c_str()); + controller_config = CtlLoadMetaData(handle_, path.c_str()); if (!controller_config) { - AFB_DYNAPI_ERROR(apihandle_, "Failed to load controller from config file!"); + AFB_DYNAPI_ERROR(handle_, "Failed to load controller from config file!"); return -1; } @@ -219,7 +254,7 @@ int ahl_binding_t::load_controller_config(const std::string& path) {.key = nullptr, .uid = nullptr, .info = nullptr, .loadCB = nullptr, .handle = nullptr, .actions = nullptr} }; - CtlLoadSections(apihandle_, controller_config, controller_sections); + CtlLoadSections(handle_, controller_config, controller_sections); return 0; } @@ -231,10 +266,10 @@ int ahl_binding_t::load_config(CtlSectionT* section, json_object* o) // Add corresponding verbs for(const auto& r : config_.roles()) { - AFB_DYNAPI_NOTICE(apihandle_, "New audio role: %s", r.name().c_str()); + AFB_DYNAPI_NOTICE(handle_, "New audio role: %s", r.name().c_str()); if (afb_dynapi_add_verb( - apihandle_, + handle_, r.name().c_str(), r.description().c_str(), [](afb_request* r) { ahl_binding_t::instance().audiorole(r); }, @@ -251,12 +286,6 @@ int ahl_binding_t::load_config(CtlSectionT* section, json_object* o) return 0; } -int afbBindingVdyn(afb_dynapi* handle) -{ - if (!handle) return -1; - return ahl_binding_t::instance().build(handle); -} - void ahl_binding_t::audiorole(afb_request* req) { std::string verb = afb_request_get_verb(req); @@ -305,10 +334,10 @@ void ahl_binding_t::volume(afb_request* req, std::string role, std::string strea json_object* a = json_object_new_object(); json_object_object_add(a, "volume", value); - AFB_DYNAPI_DEBUG(apihandle_, "Call the HAL with the following argument: %s", json_object_to_json_string(a)); + AFB_DYNAPI_DEBUG(handle_, "Call the HAL with the following argument: %s", json_object_to_json_string(a)); afb_dynapi_call( - apihandle_, + handle_, config_.hals()[0].c_str(), // BUG: What to do if multiple hals ? stream.c_str(), a, @@ -331,14 +360,86 @@ void ahl_binding_t::open(afb_request* req, std::string role, std::string stream, { if (r.name() == role) { - AFB_DYNAPI_DEBUG(apihandle_, "HELLO"); - - json_object* result = json_object_new_object(); - json_object_object_add(result, "device_uri", json_object_new_string(r.device_uri().c_str())); - - afb_request_success(req, result, nullptr); + if ( + ext::cfind_if(opened_roles_, + [&role](const role_t& r){ return r.name() == role;}) != opened_roles_.end() + ) + { + afb_request_fail(req, "This role is already opened!", nullptr); + return; + } + // Execute policy for current asked role + policy_open(req, r); return; } } afb_request_fail(req, "Can't open the specified role!", nullptr); } + +void ahl_binding_t::policy_open(afb_request* req, const role_t& role) +{ + if(role.interrupts().size()) + { + const interrupt_t& i = role.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: opened_roles_) + { + if (role.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_NOTICE(handle_, "Call 'smixer'/'%s' '%s", r.stream().c_str(), json_object_to_json_string(arg)); + + if(afb_dynapi_call_sync(handle_, "smixer", r.stream().c_str(), arg, &result)) + { + afb_request_fail(req, "Failed to call 'ramp' action on stream", nullptr); + return; + } + AFB_DYNAPI_NOTICE(handle_, "POLICY: Applying a ramp to '%s' stream because '%s' is opened and have higher priority!", r.stream().c_str(), role.stream().c_str()); + } + } + } + else + { + afb_request_fail(req, "Unkown interrupt uid!", nullptr); + return; + } + } + + json_object* result = json_object_new_object(); + json_object_object_add(result, "device_uri", json_object_new_string(role.device_uri().c_str())); + afb_request_success(req, result, nullptr); + opened_roles_.push_back(role); +} + +void ahl_binding_t::close(afb_request* req, std::string role, std::string stream, json_object* arg) +{ + AFB_DYNAPI_DEBUG(handle_, "Got this arg: %s", json_object_to_json_string(arg)); + auto it = ext::cfind_if(opened_roles_, [&role](const role_t& r) { return r.name() == role; }); + if (it == opened_roles_.cend()) + { + afb_request_fail(req, "This role is already closed!", nullptr); + return; + } + opened_roles_.erase(it); + afb_request_success(req, nullptr, "Role closed!"); +} + +void ahl_binding_t::interrupt(afb_request* req, std::string role, std::string stream, json_object* arg) +{ + afb_request_fail(req, "Not implemented yet!", nullptr); +} -- cgit 1.2.3-korg