Sound Manager
libsoundmanager.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <stdarg.h>
18 #include <sys/socket.h>
19 #include <iostream>
20 #include <algorithm>
21 #include <thread>
22 #include <errno.h>
24 
25 #define ELOG(args,...) _ELOG(__FUNCTION__,__LINE__,args,##__VA_ARGS__)
26 #define DLOG(args,...) _DLOG(__FUNCTION__,__LINE__,args,##__VA_ARGS__)
27 
28 using namespace std;
29 
30 static void _DLOG(const char* func, const int line, const char* log, ...);
31 static void _ELOG(const char* func, const int line, const char* log, ...);
32 static bool has_verb(const string& verb);
33 static const char API[] = "soundmanager";
34 
35 static void _on_hangup_static(void *closure, struct afb_wsj1 *wsj)
36 {
37  static_cast<LibSoundmanager*>(closure)->on_hangup(NULL,wsj);
38 }
39 
40 static void _on_call_static(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg)
41 {
42  /* LibSoundmanager is not called from other process */
43 }
44 
45 static void _on_event_static(void* closure, const char* event, struct afb_wsj1_msg *msg)
46 {
47  static_cast<LibSoundmanager*>(closure)->on_event(NULL,event,msg);
48 }
49 
50 static void _on_reply_static(void *closure, struct afb_wsj1_msg *msg)
51 {
52  static_cast<LibSoundmanager*>(closure)->on_reply(NULL,msg);
53 }
54 
55 
70 LibSoundmanager::LibSoundmanager(const int port, const string& token)
71 {
72  int ret;
73  if(port > 0 && token.size() > 0)
74  {
75  mport = port;
76  mtoken = token;
77  }
78  else
79  {
80  ELOG("port and token should be > 0, Initial port and token uses.");
81  }
82 
83  ret = initialize_websocket();
84  if(ret != 0 )
85  {
86  ELOG("Failed to initialize websocket");
87  }
88  else{
89  DLOG("Initialized");
90  }
91 }
92 
94 {
95  if(mploop)
96  {
97  sd_event_unref(mploop);
98  }
99  if(sp_websock != NULL)
100  {
101  free(sp_websock);
102  }
103 }
104 
120  void (*event_cb)(const std::string& event, struct json_object* event_contents),
121  void (*reply_cb)(struct json_object* reply_contents))
122 {
123  onEvent = event_cb;
124  onReply = reply_cb;
125 }
126 
127 int LibSoundmanager::initialize_websocket()
128 {
129  mploop = NULL;
130  onEvent = nullptr;
131  onReply = nullptr;
132  int ret = sd_event_default(&mploop);
133  if(ret < 0)
134  {
135  ELOG("Failed to create event loop");
136  goto END;
137  }
138  /* Initialize interface from websocket */
139 
140  minterface.on_hangup = _on_hangup_static;
141  minterface.on_call = _on_call_static; /* Is this necessary? */
142  minterface.on_event = _on_event_static;
143  muri += "ws://localhost:" + to_string(mport) + "/api?token=" + mtoken; /*To be modified*/
144  sp_websock = afb_ws_client_connect_wsj1(mploop, muri.c_str(), &minterface, this);
145  if(sp_websock == NULL)
146  {
147  ELOG("Failed to create websocket connection");
148  goto END;
149  }
150 
151  /* creates the evsrc */
152  //ret = sd_event_add_io(mploop,&mevent_src, sp_websock->fd, EPOLLIN, event_callback, NULL);
153 
154  return 0;
155 END:
156  if(mploop)
157  {
158  sd_event_unref(mploop);
159  }
160  return -1;
161 }
162 
163 static void *event_loop_run(void *args)
164 {
165  struct sd_event* loop = (struct sd_event*)(args);
166  DLOG("start eventloop");
167  for(;;)
168  sd_event_run(loop, 30000000);
169 }
170 
183 {
184  if(mploop && sp_websock)
185  {
186  pthread_t thread_id;
187  int ret = pthread_create(&thread_id, NULL, event_loop_run, mploop);
188  if(ret != 0)
189  {
190  ELOG("Cannot run eventloop due to error:%d", errno);
191  return -1;
192  }
193  else
194  return thread_id;
195  }
196  else
197  {
198  ELOG("Connecting is not established yet");
199  return -1;
200  }
201 }
202 
217 int LibSoundmanager::call(const string& verb, struct json_object* arg)
218 {
219  int ret;
220  if(!sp_websock)
221  {
222  return -1;
223  }
224  if (!has_verb(verb))
225  {
226  ELOG("verb doesn't exit");
227  return -1;
228  }
229  ret = afb_wsj1_call_j(sp_websock, API, verb.c_str(), arg, _on_reply_static, this);
230  if (ret < 0) {
231  ELOG("Failed to call verb:%s",verb.c_str());
232  }
233  return ret;
234 }
235 
236 int LibSoundmanager::call_sync(const string& verb, struct json_object* arg, struct json_object* ret)
237 {
238  /* I haven't implemented yet */
239 }
240 
255 int LibSoundmanager::subscribe(const string& event_name)
256 {
257  if(!sp_websock)
258  {
259  return -1;
260  }
261  struct json_object* j_obj = json_object_new_object();
262  json_object_object_add(j_obj, "event", json_object_new_string(event_name.c_str()));
263 
264  int ret = afb_wsj1_call_j(sp_websock, API, "subscribe", j_obj, _on_reply_static, this);
265  if (ret < 0) {
266  ELOG("Failed to call verb:%s",__FUNCTION__);
267  }
268  return ret;
269 }
270 
284 int LibSoundmanager::unsubscribe(const string& event_name)
285 {
286  if(!sp_websock)
287  {
288  return -1;
289  }
290  struct json_object* j_obj = json_object_new_object();
291  json_object_object_add(j_obj, "event", json_object_new_string(event_name.c_str()));
292 
293  int ret = afb_wsj1_call_j(sp_websock, API, "unsubscribe", j_obj, _on_reply_static, this);
294  if (ret < 0) {
295  ELOG("Failed to call verb:%s",__FUNCTION__);
296  }
297  return ret;
298 }
299 
300 am_Error_e LibSoundmanager::connect(const am_sourceID_t sourceID, const am_sinkID_t sinkID, am_mainConnectionID_t& mainConnectionID)
301 {
302  /*int ret;
303  char *key;
304  rc = asprintf(&key, "%d:%s/%s", ++num, api, "connect");
305  ret = afb_wsj1_call_s(wsj1, api, verb, object, on_reply, key);
306  if(ret < 0)
307  {
308  fprintf(stderr, "calling %s/%s(%s) failed: %m\n", api, verb, object);
309 
310  }*/
311  /* open the json scripts */
312  // get mainconnedction ID */
313  //mainConnectionID = xx;
314  return E_OK;
315 }
316 
317 am_Error_e LibSoundmanager::disconnect(const am_mainConnectionID_t mainConnectionID)
318 {
319  return E_OK;
320 }
321 
322 /*const struct afb_wsj1* LibSoundmanager::get_websocket_handler()
323 {
324  if(sp_websock)
325  {
326  return sp_websock;
327  }
328  return nullptr;
329 }
330 
331 const struct sd_event* LibSoundmanager::get_sd_event()
332 {
333  if(mploop)
334  {
335  return mploop;
336  }
337  return nullptr;
338 }*/
339 
340 /************* Callback Function *************/
341 
342 void LibSoundmanager::on_hangup(void *closure, struct afb_wsj1 *wsj)
343 {
344  DLOG("%s called", __FUNCTION__);
345 }
346 
347 void LibSoundmanager::on_call(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg)
348 {
349 }
350 
351 /*
352 * event is like "soundmanager/newMainConnection"
353 * msg is like {"event":"soundmanager\/newMainConnection","data":{"mainConnectionID":3,"sourceID":101,"sinkID":100,"delay":0,"connectionState":4},"jtype":"afb-event"})}
354 * ^key^ ^^^^^^^^^^^^ value ^^^^^^^^^^^^
355 * so you can get
356  event name : struct json_object obj = json_object_object_get(msg,"event")
357 */
358 void LibSoundmanager::on_event(void *closure, const char *event, struct afb_wsj1_msg *msg)
359 {
360  cout << "ON-EVENT:" << event << "(" << afb_wsj1_msg_object_s(msg) << ")" << endl;
361  if(onEvent != nullptr)
362  {
363  const string ev(event);
364  struct json_object* ev_contents = afb_wsj1_msg_object_j(msg);
365  onEvent(ev, ev_contents);
366  }
367 }
368 
369 void LibSoundmanager::on_reply(void *closure, struct afb_wsj1_msg *msg)
370 {
371  cout << "ON-REPLY:" << "(" << afb_wsj1_msg_object_s(msg) << ")" << endl;
372  if(onReply != nullptr)
373  {
374  struct json_object* reply = afb_wsj1_msg_object_j(msg);
375  onReply(reply);
376  }
377 }
378 
379 /* Internal Function in libsoundmanager */
380 
381 static void _ELOG(const char* func, const int line, const char* log, ...)
382 {
383  char *message;
384  va_list args;
385  va_start(args, log);
386  if (log == NULL || vasprintf(&message, log, args) < 0)
387  message = NULL;
388  cout << "[ERROR]" << func << "(" << line << "):" << message << endl;
389  va_end(args);
390  free(message);
391 }
392 
393 static void _DLOG(const char* func, const int line, const char* log, ...)
394 {
395  char *message;
396  va_list args;
397  va_start(args, log);
398  if (log == NULL || vasprintf(&message, log, args) < 0)
399  message = NULL;
400  cout << "[DEBUG]" << func << "(" << line << "):" << message << endl;
401  va_end(args);
402  free(message);
403 }
404 
405 static bool has_verb(const string& verb)
406 {
407  DLOG("verb is %s", verb.c_str());
408  if(find(api_list.begin(), api_list.end(), verb) != api_list.end())
409  return true;
410  else
411  return false;
412 }
const std::vector< std::string > api_list
int call_sync(const std::string &verb, struct json_object *arg, struct json_object *ret)
int unsubscribe(const std::string &event_name)
int call(const std::string &verb, struct json_object *arg)
void register_callback(void(*event_cb)(const std::string &event, struct json_object *event_contents), void(*reply_cb)(struct json_object *reply_contents))
void on_hangup(void *closure, struct afb_wsj1 *wsj)
int subscribe(const std::string &event_name)
void on_reply(void *closure, struct afb_wsj1_msg *msg)
void on_call(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg)
void on_event(void *closure, const char *event, struct afb_wsj1_msg *msg)
#define ELOG(args,...)
#define DLOG(args,...)