summaryrefslogtreecommitdiffstats
path: root/ahl-binding/ahl-binding.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ahl-binding/ahl-binding.cpp')
-rw-r--r--ahl-binding/ahl-binding.cpp235
1 files changed, 168 insertions, 67 deletions
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);
+}