summaryrefslogtreecommitdiffstats
path: root/src/libsoundmanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsoundmanager.cpp')
-rw-r--r--src/libsoundmanager.cpp459
1 files changed, 393 insertions, 66 deletions
diff --git a/src/libsoundmanager.cpp b/src/libsoundmanager.cpp
index 9eeac92..ebc3fa3 100644
--- a/src/libsoundmanager.cpp
+++ b/src/libsoundmanager.cpp
@@ -41,13 +41,18 @@ static const std::vector<std::string> api_list{
std::string("volumeStep"),
std::string("setSinkMuteState"),
std::string("getListMainConnections"),
+ std::string("getListMainSources"),
+ std::string("getListMainSinks"),
std::string("ackConnect"),
std::string("ackDisconnect"),
std::string("ackSetSourceState"),
std::string("registerSource"),
std::string("deregisterSource"),
std::string("subscribe"),
- std::string("unsubscribe")
+ std::string("unsubscribe"),
+ std::string("stream_open"),
+ std::string("stream_close"),
+ std::string("set_stream_state")
};
static const std::vector<std::string> event_list{
@@ -59,27 +64,28 @@ static const std::vector<std::string> event_list{
std::string("mainConnectionStateChanged"),
std::string("setRoutingReady"),
std::string("setRoutingRundown"),
- std::string("asyncConnect")
+ std::string("asyncConnect"),
+ std::string("stream_state_event")
};
-static void _on_hangup_static(void *closure, struct afb_wsj1 *wsj)
+static void _onHangupStatic(void *closure, struct afb_wsj1 *wsj)
{
- static_cast<Soundmanager*>(closure)->on_hangup(NULL,wsj);
+ static_cast<Soundmanager*>(closure)->_onHangup(NULL,wsj);
}
-static void _on_call_static(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg)
+static void _onCallStatic(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg)
{
/* Soundmanager is not called from other process */
}
-static void _on_event_static(void* closure, const char* event, struct afb_wsj1_msg *msg)
+static void _onEventStatic(void* closure, const char* event, struct afb_wsj1_msg *msg)
{
- static_cast<Soundmanager*>(closure)->on_event(NULL,event,msg);
+ static_cast<Soundmanager*>(closure)->_onEvent(NULL,event,msg);
}
-static void _on_reply_static(void *closure, struct afb_wsj1_msg *msg)
+static void _onReplyStatic(void *closure, struct afb_wsj1_msg *msg)
{
- static_cast<Soundmanager*>(closure)->on_reply(NULL,msg);
+ static_cast<Soundmanager*>(closure)->_onReply(NULL,msg);
}
Soundmanager::Soundmanager()
@@ -98,7 +104,6 @@ Soundmanager::~Soundmanager()
}
}
-
/**
* This function is initialization function
*
@@ -126,13 +131,13 @@ int Soundmanager::init(int port, const string& token)
return -1;
}
- ret = initialize_websocket();
+ ret = initializeWebsocket();
if(ret != 0 )
{
ELOG("Failed to initialize websocket");
return -1;
}
- ret = init_event();
+ ret = initEvent();
if(ret != 0 )
{
ELOG("Failed to initialize websocket");
@@ -141,7 +146,7 @@ int Soundmanager::init(int port, const string& token)
return 0;
}
-int Soundmanager::initialize_websocket()
+int Soundmanager::initializeWebsocket()
{
mploop = NULL;
onEvent = nullptr;
@@ -154,9 +159,9 @@ int Soundmanager::initialize_websocket()
}
/* Initialize interface from websocket */
{
- minterface.on_hangup = _on_hangup_static;
- minterface.on_call = _on_call_static;
- minterface.on_event = _on_event_static;
+ minterface.on_hangup = _onHangupStatic;
+ minterface.on_call = _onCallStatic;
+ minterface.on_event = _onEventStatic;
string muri = "ws://localhost:" + to_string(mport) + "/api?token=" + mtoken;
sp_websock = afb_ws_client_connect_wsj1(mploop, muri.c_str(), &minterface, this);
}
@@ -175,7 +180,11 @@ END:
return -1;
}
-int Soundmanager::init_event(){
+struct sd_event* Soundmanager::getEventLoop(){
+ return mploop;
+}
+
+int Soundmanager::initEvent(){
/* subscribe most important event for sound right */
return subscribe(string("asyncSetSourceState"));
}
@@ -209,25 +218,37 @@ void Soundmanager::registerCallback(
* registerSource is registration as source for policy management
*
* #### Parameters
- * - sourceName [in] : This argument should be specified to the source name (e.g. "MediaPlayer")
+ * - audio_role [in] : This argument should be specified to the source name (e.g. "MediaPlayer" which is role)
*
* #### Return
* - Returns 0 on success or -1 in case of transmission error.
*
* #### Note
* This function must be called to get source ID
- * mainConnectionID is returned by async reply function
+ * sourceID is returned by async reply function.
+ * {
+ * "response":{
+ * "verb":"registerSource",
+ * "error":0,
+ * "sourceID":101
+ * },
+ * "jtype":"afb-reply",
+ * "request":{
+ * "status":"success",
+ * "info":"OK"
+ * }
+ *
*
*/
-int Soundmanager::registerSource(const string& sourceName)
+int Soundmanager::registerSource(const string& audio_role)
{
if(!sp_websock)
{
return -1;
}
struct json_object* j_obj = json_object_new_object();
- struct json_object* jsn = json_object_new_string(sourceName.c_str());
- json_object_object_add(j_obj, "appname", jsn);
+ struct json_object* jsn = json_object_new_string(audio_role.c_str());
+ json_object_object_add(j_obj, "audio_role", jsn);
return this->call(__FUNCTION__, j_obj);
}
@@ -244,18 +265,30 @@ int Soundmanager::registerSource(const string& sourceName)
*
* #### Note
* This function must be called to get source right
- * connectionID is returned by reply event
- *
+ * connectionID is returned by reply event.
+ * Response is like here.
+ * {
+ * "response":{
+ * "verb":"connect",
+ * "error":0,
+ * "mainConnectionID":2
+ * },
+ * "jtype":"afb-reply",
+ * "request":{
+ * "status":"success",
+ * "info":"OK"
+ * }
+ * }
*/
-int Soundmanager::connect(int sourceID, int sinkID)
+int Soundmanager::connect(int source_id, int sink_id)
{
if(!sp_websock)
{
return -1;
}
struct json_object* j_obj = json_object_new_object();
- struct json_object* jsource = json_object_new_int(sourceID);
- struct json_object* jsink = json_object_new_int(sinkID);
+ struct json_object* jsource = json_object_new_int(source_id);
+ struct json_object* jsink = json_object_new_int(sink_id);
json_object_object_add(j_obj, "sourceID", jsource);
json_object_object_add(j_obj, "sinkID", jsink);
return this->call(__FUNCTION__, j_obj);
@@ -264,12 +297,12 @@ int Soundmanager::connect(int sourceID, int sinkID)
/**
* This function calls the connect of Audio Manager via WebSocket
* This function is overload of connect
- * Instead of sinkID as the number, abstract sinkName will be supported.
+ * Instead of sinkID as the number, abstract sink_name will be supported.
* For now, "default" is only supported
*
* #### Parameters
- * - sourceID [in] : This argument should be specified to the sourceID as int. This parameter is returned value of registerSource
- * - sinkName [in] : This argument should be specified to the sinkID as int. ID is aliased by SoundManager (e.g: "default")
+ * - source_id [in] : This argument should be specified to the sourceID as int. This parameter is returned value of registerSource
+ * - sink_name [in] : This argument should be specified to the sinkID as string. ID is aliased by SoundManager (e.g: "default")
*
* #### Rreturn
* - Returns 0 on success or -1 in case of transmission error.
@@ -279,16 +312,16 @@ int Soundmanager::connect(int sourceID, int sinkID)
* Just "default" is usable.
*
*/
-int Soundmanager::connect(int sourceID, const string& sinkName)
+int Soundmanager::connect(int source_id, const string& sink_name)
{
if(!sp_websock)
{
return -1;
}
struct json_object* j_obj = json_object_new_object();
- struct json_object* jsource = json_object_new_int(sourceID);
+ struct json_object* jsource = json_object_new_int(source_id);
//struct json_object* jsink = json_object_new_int(1);
- struct json_object* jsink = json_object_new_string(sinkName.c_str());
+ struct json_object* jsink = json_object_new_string(sink_name.c_str());
json_object_object_add(j_obj, "sourceID", jsource);
json_object_object_add(j_obj, "sinkID", jsink);
return this->call(__FUNCTION__, j_obj);
@@ -298,23 +331,34 @@ int Soundmanager::connect(int sourceID, const string& sinkName)
* This function calls the disconnect of Audio Manager via WebSocket
*
* #### Parameters
- * - connectionID [in] : This parameter is returned value of connect
+ * - connection_id [in] : This parameter is returned value of connect
*
* #### Return
* - Returns 0 on success or -1 in case of transmission error.
*
* #### Note
- *
+ * Response is like here
+ * {
+ * "response":{
+ * "verb":"disconnect",
+ * "error":0
+ * },
+ * "jtype":"afb-reply",
+ * "request":{
+ * "status":"success",
+ * "info":"OK"
+ * }
+ * }
*
*/
-int Soundmanager::disconnect(int connectionID)
+int Soundmanager::disconnect(int connection_id)
{
if(!sp_websock)
{
return -1;
}
struct json_object* j_obj = json_object_new_object();
- struct json_object* jconnection = json_object_new_int(connectionID);
+ struct json_object* jconnection = json_object_new_int(connection_id);
json_object_object_add(j_obj, "mainConnectionID", jconnection);
return this->call(__FUNCTION__, j_obj);
}
@@ -323,7 +367,6 @@ int Soundmanager::disconnect(int connectionID)
* This function calls the ackSetSourceState of Audio Manager via WebSocket
*
* #### Parameters
- * - sourceID [in] : This parameter is returned value of ackSetSourceState
* - handle [in] : This parameter is returned value of ackSetSourceState
* - errno [in] : If you have some errors, input ohter than 0. 0 means acknowledge
*
@@ -349,6 +392,303 @@ int Soundmanager::ackSetSourceState(int handle, int error)
}
/**
+ * This function calls the getListMainSources of Audio Manager via WebSocket.
+ * Get source list like here.
+ * {
+ * "response":{
+ * "verb":"getListMainSources",
+ * "sources":[
+ * {
+ * "sourceID":102,
+ * "sourceName":"radio",
+ * "availability":1,
+ * "availabilityReason":0,
+ * "sourceClassID":101
+ * }
+ * ]
+ * },
+ * "jtype":"afb-reply",
+ * "request":{
+ * "status":"success",
+ * "info":"Success to get main source list"
+ * }
+ *
+ *
+ * #### Parameters
+ * NULL
+ *
+ * #### Return
+ * - Returns 0 on success or -1 in case of transmission error.
+ *
+ * #### Note
+ */
+int Soundmanager::getListMainSources(){
+ if(!sp_websock)
+ {
+ return -1;
+ }
+ return this->call(__FUNCTION__, json_object_new_object());
+}
+
+/**
+ * This function calls the getListMainSinks of Audio Manager via WebSocket.
+ * Get sink list like here.
+ * {
+ * "response":{
+ * "verb":"getListMainSinks",
+ * "sinks":[
+ * {
+ * "sinkID":1,
+ * "sinkName":"rsnd-dai.0-ak4642-hifi#Analog#Stereo",
+ * "availability":1,
+ * "availabilityReason":0,
+ * "volume":100,
+ * "muteState":2,
+ * "sinkClassID":101
+ * },
+ * {
+ * "sinkID":2,
+ * "sinkName":"Microchip#MOST:0#Multichannel",
+ * "availability":1,
+ * "availabilityReason":0,
+ * "volume":100,
+ * "muteState":2,
+ * "sinkClassID":101
+ * }
+ * ]
+ * },
+ * "jtype":"afb-reply",
+ * "request":{
+ * "status":"success",
+ * "info":"Success to get main sink list",
+ * "uuid":"ba34fdc7-5c9e-436e-90ca-62abe6a7c4d3"
+ * }
+ *
+ * #### Parameters
+ * NULL
+ *
+ * #### Return
+ * - Returns 0 on success or -1 in case of transmission error.
+ *
+ * #### Note
+ */
+int Soundmanager::getListMainSinks(){
+ if(!sp_websock)
+ {
+ return -1;
+ }
+ return this->call(__FUNCTION__, json_object_new_object());
+}
+
+/**
+ * This function calls the getListMainConnections of Audio Manager via WebSocket.
+ * Connection is established with success of "connect".
+ * Get main connection list like here
+ * {
+ * "response":{
+ * "verb":"getListMainConnections",
+ * "connections":[
+ * {
+ * "mainConnectionID":1,
+ * "sourceID":101,
+ * "sinkID":1,
+ * "delay":-1,
+ * "connectionState":2
+ * }
+ * ]
+ * },
+ * "jtype":"afb-reply",
+ * "request":{
+ * "status":"success",
+ * "info":"Success to get main connection list"
+ * }
+ * }
+ *
+ * #### Parameters
+ * NULL
+ *
+ * #### Return
+ * - Returns 0 on success or -1 in case of transmission error.
+ *
+ * #### Note
+ */
+int Soundmanager::getListMainConnections(){
+ if(!sp_websock)
+ {
+ return -1;
+ }
+ return this->call(__FUNCTION__, json_object_new_object());
+}
+
+/**
+ * This function calls the stream_open via WebSocket.
+ * stream_id which is same meaning as sourceID is returned with success.
+ * Sound Manager bypasses registerSource.
+ *
+ * #### Parameters
+ * - audio_role [in] : This argument should be specified to the source name
+ * - endpoint_id [in] : This argument should be specified to the sinkID as int. ID is specified by AudioManager
+ *
+ * #### Return
+ * - Returns 0 on success or -1 in case of transmission error.
+ *
+ * #### Note
+ * Response is like here
+ * {
+ * "response":{
+ * "verb":"stream_open",
+ * "error":0,
+ * "stream_id":102
+ * },
+ * "jtype":"afb-reply",
+ * "request":{
+ * "status":"success",
+ * "info":"OK"
+ * }
+ * }
+ *
+ */
+int Soundmanager::streamOpen(const std::string& audio_role, int endpoint_id){
+ if(!sp_websock)
+ {
+ return -1;
+ }
+ struct json_object* j_obj = json_object_new_object();
+ struct json_object* jsource = json_object_new_string(audio_role.c_str());
+ struct json_object* jsink = json_object_new_int(endpoint_id);
+ json_object_object_add(j_obj, "audio_role", jsource);
+ json_object_object_add(j_obj, "endpoint_id", jsink);
+ return this->call("stream_open", j_obj);
+}
+
+/**
+ * This function is overload function.
+ * "default" is only supported for now.
+ */
+int Soundmanager::streamOpen(const std::string& audio_role, const std::string& endpoint_id){
+ if(!sp_websock)
+ {
+ return -1;
+ }
+ struct json_object* j_obj = json_object_new_object();
+ struct json_object* jsource = json_object_new_string(audio_role.c_str());
+ struct json_object* jsink = json_object_new_string(endpoint_id.c_str());
+ json_object_object_add(j_obj, "audio_role", jsource);
+ json_object_object_add(j_obj, "endpoint_id", jsink);
+ return this->call("stream_open", j_obj);
+}
+
+/**
+ * This function calls the stream_close via WebSocket
+ *
+ * #### Parameters
+ * - stream_id [in] : This parameter is returned value of stream_open
+ *
+ * #### Return
+ * - Returns 0 on success or -1 in case of transmission error.
+ *
+ * #### Note
+ * Response is like here
+ * {
+ * "response":{
+ * "verb":"stream_close",
+ * "error":0
+ * },
+ * "jtype":"afb-reply",
+ * "request":{
+ * "status":"success",
+ * "info":"OK"
+ * }
+ * }
+ *
+ */
+int Soundmanager::streamClose(int stream_id){
+ if(!sp_websock)
+ {
+ return -1;
+ }
+ struct json_object* j_obj = json_object_new_object();
+ struct json_object* jstream = json_object_new_int(stream_id);
+ json_object_object_add(j_obj, "stream_id", jstream);
+ return this->call("stream_close", j_obj);
+}
+
+/**
+ * This function calls set_stream_state via WebSocket.
+ * Sound Manager bypasses connect/disconnect judging with mute state.
+ * If mute is 0, which means unmute, Sound Manager calls connect, but
+ * Sound Manager doesn't return mainConnectionID because Sound Manager stores
+ * and remember mainConnectionID for stream_id inside itself using afb-binder function.
+ * If mute is 1, which means mute, Sound Manager calls disconnect.
+ *
+ * After set_source_state with unmute(call connect),
+ * "stream_state_event" is published.
+ * This event is same as "asyncSetSourceState" and means authorization to output sound.
+ *
+ * The json message of "stream_state_event" is like here.
+ * {
+ * "event":"soundmanager\/stream_state_event",
+ * "data":{
+ * "handle":2,
+ * "sourceID":101,
+ * "sourceState":"on",
+ * "event_name":"ahl_stream_state_event",
+ * "stream_id":101,
+ * "state_event":1
+ * },
+ * "jtype":"afb-event"
+ * }
+ *
+ * stream_id is same as sourceID.
+ * state_event is same as sourceState but type is different.
+ *
+ * This event is same as asyncSetSourceState but application doesn't have to call
+ * "ackSetSourceState" because Sound Manager send it to Audio MAnager on behalf of applicaiton.
+ * if the application uses high level API.
+ *
+ * Not recommend to confuse connect/disconnect with set_stream_state
+ * and confuse registerSource with stream_open even if those are same meanings because
+ * the processes of those functions inside Sound Manager are a little different.
+ *
+ * #### Parameters
+ * - streamID [in] : This parameter is returned value of stream_open
+ *
+ * #### Return
+ * - Returns 0 on success or -1 in case of transmission error.
+ *
+ * #### Note
+ * This function must be called to get source right.
+ * If an application uses "connect" instead of "set_stream_state",
+ * it must send "ackSetSourceState" otherwise connection will be removed.
+ *
+ * Response of this funcion is like here.
+ * {
+ * "response":{
+ * "verb":"set_stream_state",
+ * "error":0
+ * },
+ * "jtype":"afb-reply",
+ * "request":{
+ * "status":"success",
+ * "info":"OK"
+ * }
+ * }
+ *
+ */
+int Soundmanager::setStreamState(int stream_id, int mute_state){
+ if(!sp_websock)
+ {
+ return -1;
+ }
+ struct json_object* j_obj = json_object_new_object();
+ struct json_object* jstream = json_object_new_int(stream_id);
+ struct json_object* jmute = json_object_new_int(mute_state);
+ json_object_object_add(j_obj, "stream_id", jstream);
+ json_object_object_add(j_obj, "mute", jmute);
+ return this->call("set_stream_state", j_obj);
+}
+
+/**
* This function calls the API of Audio Manager via WebSocket
*
* #### Parameters
@@ -364,17 +704,17 @@ int Soundmanager::ackSetSourceState(int handle, int error)
*/
int Soundmanager::call(const string& verb, struct json_object* arg)
{
- int ret;
+ int ret = -1;
if(!sp_websock)
{
- return -1;
+ return ret;
}
if (!has_verb(verb))
{
ELOG("verb doesn't exit");
- return -1;
+ return ret;
}
- ret = afb_wsj1_call_j(sp_websock, API, verb.c_str(), arg, _on_reply_static, this);
+ ret = afb_wsj1_call_j(sp_websock, API, verb.c_str(), arg, _onReplyStatic, this);
if (ret < 0) {
ELOG("Failed to call verb:%s",verb.c_str());
}
@@ -398,17 +738,17 @@ int Soundmanager::call(const string& verb, struct json_object* arg)
*/
int Soundmanager::call(const char* verb, struct json_object* arg)
{
- int ret;
+ int ret = -1;
if(!sp_websock)
{
- return -1;
+ return ret;
}
if (!has_verb(string(verb)))
{
ELOG("verb doesn't exit");
- return -1;
+ return ret;
}
- ret = afb_wsj1_call_j(sp_websock, API, verb, arg, _on_reply_static, this);
+ ret = afb_wsj1_call_j(sp_websock, API, verb, arg, _onReplyStatic, this);
if (ret < 0) {
ELOG("Failed to call verb:%s",verb);
}
@@ -438,7 +778,7 @@ int Soundmanager::subscribe(const string& event_name)
struct json_object* j_obj = json_object_new_object();
json_object_object_add(j_obj, "event", json_object_new_string(event_name.c_str()));
- int ret = afb_wsj1_call_j(sp_websock, API, "subscribe", j_obj, _on_reply_static, this);
+ int ret = afb_wsj1_call_j(sp_websock, API, "subscribe", j_obj, _onReplyStatic, this);
if (ret < 0) {
ELOG("Failed to call verb:%s",__FUNCTION__);
}
@@ -467,7 +807,7 @@ int Soundmanager::unsubscribe(const string& event_name)
struct json_object* j_obj = json_object_new_object();
json_object_object_add(j_obj, "event", json_object_new_string(event_name.c_str()));
- int ret = afb_wsj1_call_j(sp_websock, API, "unsubscribe", j_obj, _on_reply_static, this);
+ int ret = afb_wsj1_call_j(sp_websock, API, "unsubscribe", j_obj, _onReplyStatic, this);
if (ret < 0) {
ELOG("Failed to call verb:%s",__FUNCTION__);
}
@@ -476,7 +816,7 @@ int Soundmanager::unsubscribe(const string& event_name)
/************* Callback Function *************/
-void Soundmanager::on_hangup(void *closure, struct afb_wsj1 *wsj)
+void Soundmanager::_onHangup(void *closure, struct afb_wsj1 *wsj)
{
DLOG("%s called", __FUNCTION__);
if(onHangup != nullptr)
@@ -485,7 +825,7 @@ void Soundmanager::on_hangup(void *closure, struct afb_wsj1 *wsj)
}
}
-void Soundmanager::on_call(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg)
+void Soundmanager::_onCall(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg)
{
}
@@ -496,7 +836,7 @@ void Soundmanager::on_call(void *closure, const char *api, const char *verb, str
* so you can get
event name : struct json_object obj = json_object_object_get(msg,"event")
*/
-void Soundmanager::on_event(void *closure, const char *event, struct afb_wsj1_msg *msg)
+void Soundmanager::_onEvent(void *closure, const char *event, struct afb_wsj1_msg *msg)
{
/* check event is for us */
string ev = string(event);
@@ -514,22 +854,9 @@ void Soundmanager::on_event(void *closure, const char *event, struct afb_wsj1_ms
json_object_put(ev_contents);
}
-void Soundmanager::on_reply(void *closure, struct afb_wsj1_msg *msg)
+void Soundmanager::_onReply(void *closure, struct afb_wsj1_msg *msg)
{
struct json_object* reply = afb_wsj1_msg_object_j(msg);
- /*struct json_object *json_data = json_object_object_get(reply, "response");
- struct json_object *jverb = json_object_object_get(json_data, "verb");
- const char* cverb = json_object_get_string(jverb);
- DLOG("cverb is %s",cverb);
- string verb = string(cverb);
- DLOG("verb is %s",verb.c_str());
-
- if(verb == "registerSource"){
- struct json_object *jsourceID = json_object_object_get(json_data, "sourceID");
- int sourceID = json_object_get_int(jsourceID);
- msourceIDs.push_back(sourceID);
- DLOG("my sourceID is created: %d", sourceID);
- }*/
if(onReply != nullptr)
{
onReply(reply);
@@ -546,7 +873,7 @@ static void _ELOG(const char* func, const int line, const char* log, ...)
va_start(args, log);
if (log == NULL || vasprintf(&message, log, args) < 0)
message = NULL;
- cout << "[ERROR: soundmanager]" << func << "(" << line << "):" << message << endl;
+ cerr << "[ERROR: soundmanager]" << func << "(" << line << "):" << message << endl;
va_end(args);
free(message);
}