RDK Documentation (Open Sourced RDK Components)
vrexSession.cpp
1 /*
2  * If not stated otherwise in this file or this component's Licenses.txt file the
3  * following copyright and licenses apply:
4  *
5  * Copyright 2016 RDK Management
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18 */
19 
20 
21 /**
22 * @defgroup iarmmgrs
23 * @{
24 * @defgroup vrexmgr
25 * @{
26 **/
27 
28 
29 #include <stdlib.h>
30 #include "vrexMgrInternal.h"
31 #include "vrexMgr.h"
32 #include "iarmUtil.h"
33 #include "libIBus.h"
34 //#include "iarmStatus.h"
35 
36 #include <stdio.h>
37 #include <string.h>
38 #include <sstream>
39 #include <exception>
40 
41 
42 #include <ctime>
43 
44 #include "vrexSession.h" //This needs to go below sstream for G8 stable to build
45 
46 //using namespace std;
47 //static list<char *> vrexData;
48 
49 #if !defined(MIN)
50 #define MIN(a,b) (((a)<(b))?(a):(b))
51 #endif
52 
53 #define MAX_IARMSTATUS_COUNT_LENGTH 10
54 #define TEMP_BUFFER_SIZE 20
55 
56 static void* speechServerThread(void *session)
57 {
58  VREXSession *pVREX = (VREXSession *)session;
59  pVREX->startTransferServer();
60  __TIMESTAMP(); LOG("Exiting speech thread\n");
61  return NULL;
62 }
63 
64 static size_t voice_writeData(void *buffer, size_t size, size_t nmemb, void *userData)
65 {
66  VREXSession *vrex = (VREXSession *)userData;
67  string str;
68  str.append((const char *)buffer, size*nmemb);
69  __TIMESTAMP(); LOG("voice<%i,%i>: %s", size, nmemb, str.c_str());
70 
71  vrex->addSpeechResponse(str);
72 
73  return size*nmemb;
74 }
75 
76 static size_t kk_writeData(void *buffer, size_t size, size_t nmemb, void *userData)
77 {
78  VREXSession *vrex = (VREXSession *)userData;
79  string str;
80  str.append((const char *)buffer, size*nmemb);
81  __TIMESTAMP(); LOG("kk_writeData<%i,%i>: %s", size, nmemb, str.c_str());
82  vrex->addKKResponse(str);
83 
84  return size*nmemb;
85 }
86 
87 static size_t sendState_writeData(void *buffer, size_t size, size_t nmemb, void *userData)
88 {
89  VREXSession *vrex = (VREXSession *)userData;
90  string str;
91  str.append((const char *)buffer, size*nmemb);
92  //__TIMESTAMP(); LOG("sendState_writeData<%i,%i>: %s", size, nmemb, str.c_str());
93  vrex->addSendStateResponse(str);
94 
95  return size*nmemb;
96 }
97 
98 static size_t read_chunked_socket_callback(void *buffer, size_t size, size_t nmemb, void *userData)
99 {
100  VREXSession *vrex = (VREXSession *)userData;
101  return vrex->serverSocketCallback(buffer, size, nmemb);
102 }
103 
104 
105 VREXSession::VREXSession() :
106  m_curlInitialized(false),
107  m_baseRoute("uninit")
108 {
109  //__TIMESTAMP(); LOG("Warning... Empty VREXSession constructor called\n");
110 }
111 
112 #ifdef RF4CE_GENMSO_API
113 VREXSession::VREXSession(unsigned char remoteId, string receiverId, int defaultConversationLength, string route, string aspect_ratio, string language, MSOBusAPI_RfStatus_t *rfStatus, int bindRemotesIndex, string stbName, string appId) :
114 #elif defined(RF4CE_API)
115 VREXSession::VREXSession(unsigned char remoteId, string receiverId, int defaultConversationLength, string route, string aspect_ratio, string language, rf4ce_RfStatus_t *rfStatus, int bindRemotesIndex, string stbName, string appId) :
116 #elif defined(RF4CE_GPMSO_API)
117 VREXSession::VREXSession(unsigned char remoteId, string receiverId, int defaultConversationLength, string route, string aspect_ratio, string language, gpMSOBusAPI_RfStatus_t *rfStatus, int bindRemotesIndex, string stbName, string appId) :
118 #else
119 #error "No RF4CE API defined"
120 #endif
121  m_remoteId(remoteId),
122  m_receiverId(receiverId),
123  m_appId(appId),
124  m_stbName(stbName),
125  m_defaultConversationLength(defaultConversationLength),
126  m_conversationExpires(std::time(0)-200),
127  m_curlInitialized(false),
128  m_logMetrics(true),
129  m_baseRoute(route),
130  m_serverSocket(0),
131  m_dataReadThread(NULL),
132  m_aspect_ratio(aspect_ratio),
133  m_guideLanguage(language)
134 {
135  CURLcode res;
136  __TIMESTAMP(); LOG("VREXSession constructor for remote %i, %s, %d, %s\n", (int)m_remoteId, m_receiverId.c_str(), m_defaultConversationLength, m_appId.c_str());
137  res = curl_global_init(CURL_GLOBAL_DEFAULT);
138  /* Check for errors */
139  if(res != CURLE_OK) {
140  __TIMESTAMP();LOG("Error: Can't init cURL: %s\n", curl_easy_strerror(res));
141  }
142  else {
143  m_curlInitialized = true;
144  }
145 
146  pthread_cond_init(&m_cond, NULL);
147  pthread_mutex_init(&m_mutex, NULL);
148 
149  m_clientSocket = -1;
150 
151  m_sendStates[BeginRecording] = "BEGIN_RECORDING";
152  m_sendStates[FinishedRecording] = "FINISHED_RECORDING";
153  m_sendStates[FinishedRecordingWithResults] = "FINISHED_RECORDING_WITH_RESULTS";
154  m_sendStates[FinishedRecordingWithErrors] = "FINISHED_RECORDING_WITH_ERRORS";
155 
156  if(NULL != rfStatus)
157  {
158  // Get the static stb and remote info.
159  getStaticStbAndRemoteinfo(rfStatus, bindRemotesIndex);
160  }
161 }
162 
163 VREXSession::~VREXSession()
164 {
165  curl_global_cleanup();
166 }
167 
168 void VREXSession::changeServerDetails(string route, string aspect_ratio, string language){
169  m_baseRoute=route;
170 
171  // Make sure the URL from the vrex server has a / on the end
172  if(m_baseRoute[m_baseRoute.length()-1] != '/')
173  m_baseRoute += "/";
174 
175  m_aspect_ratio=aspect_ratio;
176  m_guideLanguage=language;
177 }
178 
179 bool VREXSession::onMotion(MotionInfo motion)
180 {
181  bool retval = false;
182 
183  if(m_conversationExpires==0)
184  {
185  // this is an invalid time which means a previous KK attempt failed. we do
186  // not want to try again from anyone but a sendstate which will fix this before calling
187  return false;
188  }
189  // clear the conversation ID so no other KK's happen till a valid session is created and expires
190  m_conversationExpires=0;
191  __TIMESTAMP(); LOG("KnockKnock for remote %i, %s, %s\n", (int)m_remoteId, m_receiverId.c_str(), m_appId.c_str());
192  if (!m_curlInitialized) return retval;
193 
194  CURL *curl;
195  CURLcode res;
196 
197  curl = curl_easy_init();
198 
199  m_kkResponse.clear();
200 
201  __TIMESTAMP(); LOG("KnockKnock URL: %s", (m_baseRoute + "knockknock").c_str());
202  curl_easy_setopt(curl, CURLOPT_URL, (m_baseRoute + "knockknock").c_str());
203 
204  // Post Data
205  string postData = "receiverId=" + m_receiverId + "&appId=" + m_appId;
206 
207  if (!m_guideLanguage.empty())
208  {
209  postData += "&language=" + m_guideLanguage;
210  }
211 
212  if (!m_aspect_ratio.empty())
213  {
214  postData += "&aspectRatio=" + m_aspect_ratio;
215  }
216 
217 
218 
219  __TIMESTAMP(); LOG("KnockKnock POSTFIELDS: %s", postData.c_str());
220  curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postData.c_str());
221 
222  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, kk_writeData);
223  curl_easy_setopt(curl, CURLOPT_WRITEDATA, this);
224  curl_easy_setopt(curl, CURLOPT_TIMEOUT, DEFAULT_VREX_TIMEOUT);
225  curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
226 
227  //Add the user agent field
228  string userAgentData = getUserAgentString();
229  __TIMESTAMP(); LOG("KnockKnock USERAGENT: %s\n", userAgentData.c_str());
230  curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgentData.c_str());
231 
232  res = curl_easy_perform(curl);
233 
234  // Error?
235  if(res != CURLE_OK) {
236  std::stringstream sstm;
237  sstm << "cURL call failed KnockKnock:(" << res << "): " << curl_easy_strerror(res);
238  string errorMessage = sstm.str();
239  //errorMessage = errorMessage + curl_easy_strerror(res);
240  __TIMESTAMP(); LOG("onMotion(): %s\n", errorMessage.c_str());
241  //long httpErrorCode , long curlErrorCode, long vrexErrorCode ,long rfErrorCode
242  notifyError(0, res,0,0, errorMessage.c_str(),KNOCKKNOCK);
243  }
244  else {
245  JSONParser parser;
246  try{
247  retval = true;
248  m_parameters = parser.parse((const unsigned char *)m_kkResponse.c_str());
249 
250  if (m_parameters["code"]->str == "0") {
251  time_t currentTime = std::time(0);
252  __TIMESTAMP(); LOG("Time now: %s", asctime(localtime(&currentTime)));
253  m_conversationExpires = std::time(0) + m_defaultConversationLength;
254  __TIMESTAMP(); LOG("Conversation expires: %s\n", asctime(localtime(&m_conversationExpires)));
255 
256  LOG("onMotion CID: <%s>\n", m_parameters["cid"]->str.c_str());
257  }
258  else {
259  long responseCode;
260  long returnCode;
261  // Error in the service itself
262  LOG("onMotion response error!\n");
263  LOG("onMotion code: <%s>\n", m_parameters["code"]->str.c_str());
264  LOG("onMotion message: <%s>\n", m_parameters["message"]->str.c_str());
265  curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode);
266  returnCode = strtol(m_parameters["code"]->str.c_str(), NULL, 10);
267  //long httpErrorCode , long curlErrorCode, long vrexErrorCode ,long rfErrorCode
268  notifyError(responseCode, 0,returnCode,0, m_parameters["message"]->str.c_str(),KNOCKKNOCK);
269  }
270  }catch (const std::exception err){
271  __TIMESTAMP(); LOG("exception in OnMotion response: %s",err.what());
272  __TIMESTAMP(); LOG("OnMotion response string for exception: %s",m_kkResponse.c_str());
273  std::stringstream sstm;
274  sstm << "Unknown exception:" << err.what() << ": response:" << m_kkResponse.c_str();
275  string errorMessage = sstm.str();
276  notifyError(0, 0,800,0, errorMessage.c_str(),KNOCKKNOCK);
277  retval = false;
278  }
279 
280  }
281 
282  if (m_logMetrics){
283  char buffer[700];
284  getRequestMetrics(curl,buffer);
285  LOG("%s",buffer);
286  }
287 
288  curl_easy_cleanup(curl);
289 
290  return retval;
291 }
292 
293 void VREXSession::notifySuccess()
294 {
296  memset(&eventData, 0, sizeof(eventData));
297 
298  eventData.remoteId = m_remoteId;
299 
300  IARM_Result_t retval = IARM_Bus_BroadcastEvent(IARM_BUS_VREXMGR_NAME, (IARM_EventId_t)IARM_BUS_VREXMGR_EVENT_SUCCESS,(void *)&eventData,sizeof(eventData));
301  if (retval == IARM_RESULT_SUCCESS) {
302  __TIMESTAMP(); LOG("Success Event sent successfully");
303  }
304  else {
305  __TIMESTAMP(); LOG("Success Event problem, %i", retval);
306  }
307 }
308 
309 
310 void VREXSession::notifyError(long httpErrorCode , long curlErrorCode, long vrexErrorCode ,long rfErrorCode, const char *message, IARM_Bus_VREXMgr_VoiceCallType_t from)
311 {
313  memset(&eventData, 0, sizeof(eventData));
314  eventData.remoteId = m_remoteId;
315 
316 
317 // if(curl!=NULL){
318 // char buffer[700];
319 //
320 // sendMsg+=":curl Details:";
321 // sendMsg+=getRequestMetrics(curl,buffer);
322 // }
323 //
324 
325 //
326 // switch (curlError){
327 // case 6: //CURLE_COULDNT_RESOLVE_HOST
328 // break;
329 // case 60: //CURLE_SSL_CACERT
330 // case 77: //CURLE_SSL_CACERT_BADFILE
331 // {
332 // struct curl_slist *sslEngines;
333 // curl_easy_getinfo(curl, CURLINFO_SSL_ENGINES, &sslEngines);
334 // std::stringstream sstm;
335 // sstm << "::cURL sslEngines:" << sslEngines;
336 // sendMsg+=sstm.str();
337 // curl_slist_free_all(sslEngines);
338 //
339 // }
340 // break;
341 //
342 // case 52: //CURLE_GOT_NOTHING
343 // break;
344 // case 28: //CURLE_OPERATION_TIMEDOUT
345 // break;
346 // }
347 
348  bool needComma=false;
349  std::stringstream jsonString;
350 
351  jsonString<<"{";
352 
353  jsonString<<"\"vrexCallType\":\"";
354  jsonString<<from;
355  jsonString<<"\",";
356  jsonString<<"\"remoteId\":\"";
357  jsonString<<(int)m_remoteId;
358  jsonString<<"\", \"errors\":{";
359 
360  if(httpErrorCode>0){
361  jsonString<<"\"httpErrorCode\":\"";
362  jsonString<<(int)httpErrorCode;
363  needComma=true;
364  jsonString<<"\"";
365  }
366 
367  if(curlErrorCode>0){
368  if(needComma){
369  jsonString<<",";
370  }
371  needComma=true;
372  jsonString<<"\"curlErrorCode\":\"";
373  jsonString<<(int)curlErrorCode;
374  jsonString<<"\"";
375  }
376  if(vrexErrorCode>0){
377  if(needComma){
378  jsonString<<",";
379  }
380  needComma=true;
381  jsonString<<"\"vrexErrorCode\":\"";
382  jsonString<<(int)vrexErrorCode;
383  jsonString<<"\"";
384  }
385 
386  if(rfErrorCode>0){
387  if(needComma){
388  jsonString<<",";
389  }
390  needComma=true;
391  jsonString<<"\"remoteErrorCode\":\"";
392  jsonString<<(int)rfErrorCode;
393  jsonString<<"\"";
394  }
395  if(needComma){
396  jsonString<<",";
397  }
398  needComma=true;
399  jsonString<<"\"message\":\"";
400  jsonString<<message;
401 
402  jsonString<<"\"}}";
403 
404  string erroStr(jsonString.str());
405  LOG("sending event %s",erroStr.c_str());
406  safe_copy(eventData.data.jsonEvent.jsonData, erroStr.c_str(), IARM_BUS_VREXMGR_ERROR_MESSAGE_LENGTH);
407  IARM_Result_t retval = IARM_Bus_BroadcastEvent(IARM_BUS_VREXMGR_NAME, (IARM_EventId_t)IARM_BUS_VREXMGR_EVENT_ERROR,(void *)&eventData,sizeof(eventData));
408  if (retval == IARM_RESULT_SUCCESS) {
409  __TIMESTAMP(); LOG("Error Event sent successfully");
410  }
411  else {
412  __TIMESTAMP(); LOG("Error Event problem, %i", retval);
413  }
414 }
415 
416 
417 void VREXSession::safe_copy(unsigned char *dst, const char *src, size_t len)
418 {
419  if (len < 0) return;
420 
421  len = MIN(strlen(src), (len - 1));
422 
423  // Because glibc maintainers don't like strlcpy....
424  *((char *) mempcpy (dst, src, len)) = '\0';
425 }
426 
427 void VREXSession::addKKResponse(string responseData)
428 {
429  m_kkResponse += responseData;
430 }
431 
432 void VREXSession::addSpeechResponse(string responseData)
433 {
434  m_speechResponse += responseData;
435 }
436 
437 void VREXSession::addSendStateResponse(string responseData)
438 {
439  m_sendStateResponse += responseData;
440 }
441 
442 bool VREXSession::onStreamStart(AudioInfo audioInfo)
443 {
444  string errorMessage;
445  m_audioInfo = audioInfo;
446 
447  // special case that when we get a StreamStart we want to try the conversation regardless
448  // of past failures, so make the timeout valid if needed so KK will go through.
449  if(m_conversationExpires==0){
450  // invalid conversation time so fix
451  m_conversationExpires=std::time(0)-200;
452  }
453 
454  pthread_mutex_lock(&m_mutex);
455 // vrexData.clear();
456  time_t currentTime = std::time(0);
457  if (currentTime > m_conversationExpires) {
458  MotionInfo mi = { 0, 0, 0 };
459  __TIMESTAMP(); LOG("Conversation id has expired! attempting to acquire another one via knock knock\n");
460 
461  if (!onMotion(mi)) {
462  pthread_mutex_unlock(&m_mutex);
463  errorMessage = "Conversation id expired and could not reacquire. Aborting speech call";
464  goto handleError;
465  }
466  }
467 
468  m_speechResponse.clear();
469 
470  if (pthread_create(&m_dataReadThread, NULL, speechServerThread, (void *)this) != 0)
471  {
472  pthread_mutex_unlock(&m_mutex);
473  errorMessage = "Could not create thread to send speech data";
474  goto handleError;
475  }
476  __TIMESTAMP(); LOG("Thread blocked waiting for initialization");
477  pthread_cond_wait(&m_cond, &m_mutex);
478  pthread_mutex_unlock(&m_mutex);
479 
480  // Now start the client side of the code.
481  struct sockaddr_un address;
482  int nbytes;
483  char buffer[256];
484 
485  m_clientSocket = socket(PF_UNIX, SOCK_STREAM, 0);
486  if(m_clientSocket < 0) {
487  errorMessage = "Speech socket call failed";
488  goto handleError;
489  }
490 
491  __TIMESTAMP(); LOG("Server socket name is <%s>", m_serverSocketName.c_str());
492 
493  memset(&address, 0, sizeof(struct sockaddr_un));
494  address.sun_family = AF_UNIX;
495  snprintf(address.sun_path, UNIX_PATH_MAX, m_serverSocketName.c_str());
496 
497  if(connect(m_clientSocket, (struct sockaddr *) &address, sizeof(struct sockaddr_un)) != 0)
498  {
499  errorMessage = "Speech connect call failed";
500  goto handleError;
501  }
502 
503  return true;
504 
505 handleError:
506  __TIMESTAMP(); LOG("Error Message:%s",errorMessage.c_str());
507  //long httpErrorCode , long curlErrorCode, long vrexErrorCode ,long rfErrorCode
508  //TODO need to figure out better messaging
509  notifyError(0, 0,0,0, errorMessage.c_str(),SPEECH);
510  return false;
511 }
512 
513 void VREXSession::onStreamData(void *src, size_t size)
514 {
515  pthread_mutex_lock(&m_mutex);
516  __TIMESTAMP(); LOG("onStreamData: numbytes sent: %i", (int)size);
517  if (m_clientSocket >= 0)
518  write(m_clientSocket, src, size);
519  pthread_mutex_unlock(&m_mutex);
520 }
521 
522 void VREXSession::onStreamEnd(AudioStreamEndReason reason)
523 {
524  if (m_clientSocket >= 0) {
525  pthread_mutex_lock(&m_mutex);
526  __TIMESTAMP(); LOG("Deleting client socket from onStreamEnd\n");
527  close(m_clientSocket);
528  m_clientSocket = -1;
529  pthread_mutex_unlock(&m_mutex);
530 
531  __TIMESTAMP(); LOG("Waiting for server thread to exit\n");
532  pthread_join(m_dataReadThread, NULL);
533  __TIMESTAMP(); LOG("Server thread exited!\n");
534  }
535 
536  if (reason != AudioDone) {
537  string message = "Audio stream ";
538  message = message + ((reason == AudioAbort) ? "canceled" : "aborted due to error") + " from remote";
539  //long httpErrorCode , long curlErrorCode, long vrexErrorCode ,long rfErrorCode
540  //TODO need to figure out better messaging
541  notifyError(0, 0,0,(long)reason, message.c_str(),SPEECH);
542  }
543 
544 }
545 
546 void VREXSession::updateExpiration(int expirationWindow)
547 {
548  time_t currentTime = std::time(0);
549 
550  // we only update a valid expire time that is not expired
551  if (m_conversationExpires>0 && (currentTime + expirationWindow > m_conversationExpires)) {
552  MotionInfo mi = { 0, 0, 0 };
553  __TIMESTAMP(); LOG("VREXSession: updateExpiration, conversation about to expire. Attempting to extend via knock knock\n");
554 
555  // Try to extend
556  if (!onMotion(mi)) {
557  string errorMessage;
558  errorMessage = "Conversation id about to expire and could not reacquire.";
559  __TIMESTAMP(); LOG("Error: %s",errorMessage.c_str());
560  // Do we really want to notify an error here? It's being generated synthetically and
561  // feedback could throw off UI or remote
562  //notifyError(0, 0, errorMessage.c_str());
563  }
564  }
565 }
566 
567 bool VREXSession::sendState(SendState state)
568 {
569  bool retval = false;
570 redoSendState:
571  __TIMESTAMP(); LOG("sendState for remote %i, %i\n", (int)m_remoteId, (int)state);
572 
573  if (!m_curlInitialized) return retval;
574 
575  CURL *curl;
576  CURLcode res;
577 
578  time_t currentTime = std::time(0);
579 
580  curl = curl_easy_init();
581 
582  m_sendStateResponse.clear();
583 
584  if(m_parameters["cid"]!=NULL){
585 
586  string url = m_baseRoute + "xapi/sendstate?cid=" + m_parameters["cid"]->str + "&state=" + m_sendStates[state];
587  __TIMESTAMP(); LOG("sendState URL: %s\n", url.c_str());
588  curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
589 
590  /* Now specify the POST data */
591  string postData = getPostFieldString();
592  __TIMESTAMP(); LOG("sendState POSTFIELDS: %s\n", postData.c_str());
593  curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postData.c_str());
594 
595  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, sendState_writeData);
596  curl_easy_setopt(curl, CURLOPT_WRITEDATA, this);
597  curl_easy_setopt(curl, CURLOPT_TIMEOUT, DEFAULT_VREX_TIMEOUT);
598  curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
599 
600  //Add the user agent field
601  string userAgentData = getUserAgentString();
602  __TIMESTAMP(); LOG("sendState USERAGENT: %s\n", userAgentData.c_str());
603  curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgentData.c_str());
604 
605  /* Perform the request, res will get the return code */
606  res = curl_easy_perform(curl);
607 
608  /* Check for errors */
609  if(res != CURLE_OK) {
610  std::stringstream sstm;
611  sstm << "cURL call failed (" << res << "): " << curl_easy_strerror(res);
612  string errorMessage = sstm.str();
613  //errorMessage = errorMessage + curl_easy_strerror(res);
614  __TIMESTAMP(); LOG("sendstate: %s\n", errorMessage.c_str());
615  // notifyError(0, 0, errorMessage.c_str());
616  }
617  else {
618  try{
619  time_t currentTime = std::time(0);
620  __TIMESTAMP(); LOG("Updating expiration time, time now: %s\n", asctime(localtime(&currentTime)));
621  m_conversationExpires = std::time(0) + m_defaultConversationLength;
622  __TIMESTAMP(); LOG("Conversation expires: %s\n", asctime(localtime(&m_conversationExpires)));
623  JSONParser parser;
624  __TIMESTAMP(); LOG("Result = %s", m_sendStateResponse.c_str());
625 
626  __TIMESTAMP(); LOG("MYRESULT = %s", m_sendStateResponse.c_str());
627  map<string, JSONParser::varVal *> result;
628  result = parser.parse((const unsigned char *)m_sendStateResponse.c_str());
629  __TIMESTAMP(); LOG("AFTER MYRESULT = %s", m_sendStateResponse.c_str());
630 
631 
632  if (result["code"]!=NULL && result["code"]->str != "0") {
633  if (result["code"]->str == "213") {
634  MotionInfo mi = { 0, 0, 0 };
635  __TIMESTAMP(); LOG("Conversation id has expired! attempting to acquire another one via knock knock\n");
636 
637  if (!onMotion(mi)) {
638  __TIMESTAMP(); LOG("could not handle the 213 error\n");
639  }
640  else{
641  goto redoSendState;
642  }
643  }else{
644  __TIMESTAMP(); LOG("not a 213 error\n");
645 
646 
647  }
648 
649 
650  long responseCode;
651  long returnCode;
652  // Error in the service itself
653  LOG("sendstate CODE: <%s>", result["code"]->str.c_str());
654  LOG("sendstate MESSAGE: <%s>", result["message"]->str.c_str());
655 
656  curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode);
657  returnCode = strtol(result["code"]->str.c_str(), NULL, 10);
658  // notifyError(responseCode, returnCode, result["message"].c_str());
659  }
660 
661  retval = true;
662  }catch (const std::exception err){
663  __TIMESTAMP(); LOG("exception in SENDSTATE response: %s", err.what());
664  __TIMESTAMP(); LOG("SENDSTATE response string for exception: %s",m_kkResponse.c_str());
665  std::stringstream sstm;
666  sstm << "Unknown exception:" << err.what() << ":SENDSTATE response:" << m_sendStateResponse.c_str();
667  string errorMessage = sstm.str();
668  notifyError(0, 0,800,0, errorMessage.c_str(),SENDSTATE);
669  retval=false;
670  }
671 
672  }
673 
674  if (m_logMetrics){
675  char buffer[700];
676  getRequestMetrics(curl,buffer);
677  LOG("%s",buffer);
678 
679  }
680 
681  curl_easy_cleanup(curl);
682  }
683 
684  return retval;
685 }
686 
687 size_t VREXSession::serverSocketCallback(void *buffer, size_t size, size_t nmemb)
688 {
689  size_t numBytes;
690 
691  //__TIMESTAMP(); LOG("serverSocketCallback: fill up to bytes: <%i>:", size*nmemb);
692 
693  if(size*nmemb < 1)
694  return 0;
695 
696  numBytes = read(m_serverSocket, buffer, size*nmemb);
697  __TIMESTAMP(); LOG("serverSocketCallback: got bytes: <%i>:", numBytes);
698 
699 // char* mybuff=new char[(numBytes)+2];
700 // *(short *)mybuff=numBytes;
701 // memcpy(mybuff+2,buffer,numBytes);
702 // vrexData.push_back(mybuff);
703 
704 
705  return numBytes;
706 }
707 
708 void VREXSession::startTransferServer()
709 {
710  int nbytes;
711  char buffer[256];
712  int socket_fd;
713  struct sockaddr_un address;
714  socklen_t address_length;
715 
716  __TIMESTAMP(); LOG("startTransferServer\n");
717 
718  socket_fd = socket(PF_UNIX, SOCK_STREAM, 0);
719  if(socket_fd < 0)
720  {
721  __TIMESTAMP(); LOG("socket() failed\n");
722  return;
723  }
724 
725  // Don't want to use itoa
726  ostringstream stream;
727  int remoteId = (int)m_remoteId;
728  __TIMESTAMP(); LOG("remoteId= %i", remoteId);
729  __TIMESTAMP(); LOG("receiverId= %s", m_receiverId.c_str());
730  __TIMESTAMP(); LOG("appId= %s", m_appId.c_str());
731 
732  stream << "/tmp/.vrex" << remoteId << "_socket";
733  string socketName(stream.str());
734 
735  m_serverSocketName = socketName;
736 
737  __TIMESTAMP(); LOG("sts m_serverSocketName = %s\n", m_serverSocketName.c_str());
738  unlink(socketName.c_str());
739 
740  memset(&address, 0, sizeof(struct sockaddr_un));
741  address.sun_family = AF_UNIX;
742  snprintf(address.sun_path, UNIX_PATH_MAX, socketName.c_str());
743 
744  if(bind(socket_fd, (struct sockaddr *) &address,
745  sizeof(struct sockaddr_un)) != 0)
746  {
747  close(socket_fd);
748  __TIMESTAMP(); LOG("sts bind failed");
749  return;
750  }
751 
752  if(listen(socket_fd, 5) != 0)
753  {
754  close(socket_fd);
755  __TIMESTAMP(); LOG("sts listen failed");
756  return;
757  }
758 
759  usleep(5 * 1000); // simple wait to make sure streamStart thread is waiting before broadcast;
760  __TIMESTAMP(); LOG("Unblocking waiting thread(s)");
761  // Unblock parent thread
762  pthread_cond_broadcast(&m_cond);
763  __TIMESTAMP(); LOG("Thread(s) unblocked(s)");
764  address_length = sizeof(sockaddr_un);
765  if ((m_serverSocket = accept(socket_fd, (struct sockaddr *) &address, &address_length)) > -1)
766  {
767  CURL *curl;
768  CURLcode res;
769  struct curl_slist *chunk = NULL;
770 
771  curl = curl_easy_init();
772 
773  if(curl) {
774 
775  string url;
776 
777  url = m_baseRoute + "speech?cid=" + m_parameters["cid"]->str + "&filters=SR,NLP,X1&codec=" + m_audioInfo.subType + "&receiverId=" + m_receiverId + "&appId=" + m_appId;
778 
779  if (!m_guideLanguage.empty())
780  {
781  url += "&language=" + m_guideLanguage;
782  }
783 
784  if (!m_aspect_ratio.empty())
785  {
786  url += "&aspectRatio=" + m_aspect_ratio;
787  }
788 
789  //+ "&mimeType=" + m_audioInfo.mimeType + "&lang=" + m_audioInfo.language;
790  __TIMESTAMP(); LOG("Speech connection to: <%s>", url.c_str());
791 
792  curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
793 
794  curl_easy_setopt(curl, CURLOPT_POST, 1L);
795  curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_chunked_socket_callback);
796 
797  /* pointer to pass to our read function */
798  curl_easy_setopt(curl, CURLOPT_READDATA, this);
799  //curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
800  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, voice_writeData);
801  curl_easy_setopt(curl, CURLOPT_WRITEDATA, this);
802  curl_easy_setopt(curl, CURLOPT_TIMEOUT, DEFAULT_VREX_TIMEOUT);
803  curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
804 
805  chunk = curl_slist_append(chunk, "Transfer-Encoding: chunked");
806  chunk = curl_slist_append(chunk, "Content-Type:application/octet-stream");
807  chunk = curl_slist_append(chunk, "Expect:");
808  res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
809 
810  //Add the user agent field
811  string userAgentData = getUserAgentString();
812  __TIMESTAMP(); LOG("Speech USERAGENT: %s\n", userAgentData.c_str());
813  curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgentData.c_str());
814 
815  /* Perform the request, res will get the return code */
816  res = curl_easy_perform(curl);
817 
818  pthread_mutex_lock(&m_mutex);
819  if (m_clientSocket >= 0) {
820  __TIMESTAMP(); LOG("Deleting client socket from after curl_easy_perform\n");
821  close(m_clientSocket);
822  }
823  m_clientSocket = -1;
824  pthread_mutex_unlock(&m_mutex);
825 
826  curl_slist_free_all(chunk);
827 
828 // {
829 // time_t now = time(0);
830 // struct tm tstruct;
831 // char buf[80];
832 // tstruct = *localtime(&now);
833 // // Visit http://en.cppreference.com/w/cpp/chrono/c/strftime
834 // // for more information about date/time format
835 // strftime(buf, sizeof(buf), "%Y-%m-%d.%X", &tstruct);
836 //
837 // FILE* pFile;
838 // string filename="vrexData";
839 // filename+=buf;
840 // filename+=".raw";
841 // pFile = fopen(filename.c_str(), "wb");
842 // //Here would be some error handling
843 // for (list<char *>::iterator it=vrexData.begin(); it != vrexData.end(); ++it){
844 // //Some calculations to fill a[]
845 // short count=*(short *)(*it);
846 // char * mybuff=(*it);
847 // mybuff+=2;
848 // fwrite(mybuff, 1, count, pFile);
849 // }
850 // fclose(pFile);
851 //
852 // }
853 
854  /* Check for errors */
855  if(res != CURLE_OK) {
856  std::stringstream sstm;
857  sstm << "cURL call failed (" << res << "): " << curl_easy_strerror(res);
858  string errorMessage = sstm.str();
859  //errorMessage = errorMessage + curl_easy_strerror(res);
860  __TIMESTAMP(); LOG("speech(): %s\n", errorMessage.c_str());
861  //long httpErrorCode , long curlErrorCode, long vrexErrorCode ,long rfErrorCode
862  notifyError(0, res,0,0, errorMessage.c_str(),SPEECH);
863 
864  }
865  else {
866  try{
867  JSONParser parser;
868  m_speechResults = parser.parse((const unsigned char *)m_speechResponse.c_str());
869 
870  if (m_speechResults["code"] != NULL) {
871  long responseCode=0;
872  long returnCode=0;
873  // Error in the service itself
874  LOG("onSpeech response error!\n");
875  LOG("onSpeech code: <%s>\n", m_speechResults["code"]->str.c_str());
876  if (m_speechResults["message"]!=NULL){
877  LOG("onSpeech message: <%s>\n", m_speechResults["message"]->str.c_str());
878  }
879  curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode);
880  returnCode = strtol(m_speechResults["code"]->str.c_str(), NULL, 10);
881  if ((responseCode != 200) || (returnCode != 0)) {
882  notifyError(responseCode, 0,returnCode,0, m_speechResults["message"]->str.c_str(),SPEECH);
883  } else {
884  notifySuccess();
885  }
886  }
887  else
888  notifySuccess();
889  }catch (const std::exception err){
890  __TIMESTAMP(); LOG("exception in Speech response: %s",err.what());
891  __TIMESTAMP(); LOG("Speech response string for exception: %s",m_kkResponse.c_str());
892  std::stringstream sstm;
893  sstm << "Unknown exception:" << err.what() << ": speech response:" << m_speechResponse.c_str();
894  string errorMessage = sstm.str();
895  notifyError(0, 0,800,0, errorMessage.c_str(),SPEECH);
896  }
897  }
898 
899  if (m_logMetrics) {
900  char buffer[700];
901  getRequestMetrics(curl,buffer);
902  LOG("%s",buffer);
903  }
904 
905  /* always cleanup */
906  curl_easy_cleanup(curl);
907 
908  close(m_serverSocket);
909  }
910  }
911 
912  close(socket_fd);
913  unlink(socketName.c_str());
914 
915  return;
916 }
917 
918 char * VREXSession::getRequestMetrics(CURL *curl,char *buffer)
919 {
920  double total, connect, startTransfer, resolve, appConnect, preTransfer, redirect;
921  long responseCode,sslVerify;
922  char *url;
923  curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &url);
924  curl_easy_getinfo(curl, CURLINFO_NAMELOOKUP_TIME, &resolve);
925  curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME, &connect);
926  curl_easy_getinfo(curl, CURLINFO_APPCONNECT_TIME, &appConnect);
927  curl_easy_getinfo(curl, CURLINFO_PRETRANSFER_TIME, &preTransfer);
928  curl_easy_getinfo(curl, CURLINFO_STARTTRANSFER_TIME, &startTransfer);
929  curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME , &total);
930  curl_easy_getinfo(curl, CURLINFO_REDIRECT_TIME, &redirect);
931  curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode);
932 
933  curl_easy_getinfo(curl, CURLINFO_SSL_VERIFYRESULT, &sslVerify);
934 
935  sprintf(buffer,"\nHttpRequestEnd %s code=%ld times={total=%g, connect=%g startTransfer=%g resolve=%g, appConnect=%g, preTransfer=%g, redirect=%g, sslVerify=%g}\n", url, responseCode, total, connect, startTransfer, resolve, appConnect, preTransfer, redirect,sslVerify);
936  return buffer;
937 }
938 
939 #ifdef RF4CE_GENMSO_API
940 void VREXSession::getStaticStbAndRemoteinfo(MSOBusAPI_RfStatus_t *rfStatus, int bindRemotesIndex)
941 {
942  MSOBusAPI_BindRemote_t bindRemote;
943 #elif defined(RF4CE_API)
944 void VREXSession::getStaticStbAndRemoteinfo(rf4ce_RfStatus_t *rfStatus, int bindRemotesIndex)
945 {
946  rf4ce_BindRemote_t bindRemote;
947 #elif defined(RF4CE_GPMSO_API)
948 void VREXSession::getStaticStbAndRemoteinfo(gpMSOBusAPI_RfStatus_t *rfStatus, int bindRemotesIndex)
949 {
950  gpMSOBusAPI_BindRemote_t bindRemote;
951 #else
952 #warning "No RF4CE API defined"
953 #endif
954 
955  char tempBuffer[TEMP_BUFFER_SIZE];
956 
957  if(rfStatus->bindRemotes[bindRemotesIndex].ShortAddress != 0xFFFF)
958  {
959  bindRemote = rfStatus->bindRemotes[bindRemotesIndex];
960 
961  //Remote type
962  m_remoteType = bindRemote.Type;
963 
964  //Remote software version
965  sprintf(tempBuffer, "%d.%d.%d.%d", bindRemote.VersionInfoSw[0], \
966  bindRemote.VersionInfoSw[1], \
967  bindRemote.VersionInfoSw[2], \
968  bindRemote.VersionInfoSw[3]);
969  m_remoteSoftwareVersion = tempBuffer;
970 
971  //Remote hardware version
972  sprintf(tempBuffer, "%d.%d.%d.%d", bindRemote.VersionInfoHw.manufacturer, \
973  bindRemote.VersionInfoHw.model, \
974  bindRemote.VersionInfoHw.hwRevision, \
975  bindRemote.VersionInfoHw.lotCode);
976  m_remoteHardwareVersion = tempBuffer;
977 
978  //RF4CE mac address
979  sprintf(tempBuffer, "0x%x%x%x%x%x%x%x%x", rfStatus->macAddress[7],rfStatus->macAddress[6],rfStatus->macAddress[5],rfStatus->macAddress[4],rfStatus->macAddress[3],rfStatus->macAddress[2],rfStatus->macAddress[1],rfStatus->macAddress[0]);
980  m_rf4ceMacAddress = tempBuffer;
981  }
982 
983 #if 0 // Temporarily remove as STB_VERSION_STRING can't be retrieved in a Yocto build
984  //RDK version
985  m_rdkImage = STB_VERSION_STRING;
986 #endif
987 }
988 
989 #if 0 // Temporarily remove this code as the values had been received from iarmStatus check which has been removed
990 void VREXSession::getDynamicStbAndRemoteinfo()
991 {
992  char tempBuffer[TEMP_BUFFER_SIZE];
993 
994  //Remote battery voltage
995  unsigned char batteryLevelLoaded = get_battery_level_loaded(m_remoteId);
996  sprintf(tempBuffer, "%i.%iV", (UInt16)((batteryLevelLoaded >> 6) & 0x03), (UInt16)(((batteryLevelLoaded & 0x3F)*100) >> 6));
997  m_remoteBatteryVoltage = tempBuffer;
998 
999  //IARM status kill count
1000  sprintf(tempBuffer, "%d", get_status_kill_count());
1001  m_iArmStatusKillCount = tempBuffer;
1002 }
1003 #endif
1004 
1005 string VREXSession::getPostFieldString()
1006 {
1007 #if 0 // Temporarily remove this code as the values had been received from iarmStatus check which has been removed
1008  //Get the dynamic stb and remote info
1009  getDynamicStbAndRemoteinfo();
1010 
1011  string postData = "receiverId=" + m_receiverId + "&appId=" + m_appId + "&rf4ceMAC=" + m_rf4ceMacAddress + "&batt=" + m_remoteBatteryVoltage + "&iarmKill=" + m_iArmStatusKillCount;
1012 #else
1013  string postData = "receiverId=" + m_receiverId + "&appId=" + m_appId + "&rf4ceMAC=" + m_rf4ceMacAddress;
1014 #endif
1015 
1016  return postData;
1017 }
1018 
1019 string VREXSession::getUserAgentString()
1020 {
1021 #if 0 // Temporarily remove as STB_VERSION_STRING can't be retrieved in a Yocto build
1022  string userAgentData = "rdk=" + m_rdkImage + "; rmtType=" + m_remoteType + "; rmtSVer=" + m_remoteSoftwareVersion + "; rmtHVer=" + m_remoteHardwareVersion;
1023 #else
1024  string userAgentData = "rmtType=" + m_remoteType + "; rmtSVer=" + m_remoteSoftwareVersion + "; rmtHVer=" + m_remoteHardwareVersion + "; stbName=" + m_stbName;
1025 #endif
1026 
1027  return userAgentData;
1028 
1029 }
1030 
1031 
1032 
1033 /** @} */
1034 /** @} */
VREXSession
Definition: vrexSession.h:82
JSONParser
Definition: jsonParser.h:43
AudioInfo
Definition: deviceUpdateMgrMain.cpp:849
_IARM_BUS_VREXMgr_EventData_t::remoteId
unsigned char remoteId
A unique identifier of the remote that transmitted the motion command.
Definition: vrexMgr.h:181
IARM_BUS_VREXMGR_NAME
#define IARM_BUS_VREXMGR_NAME
Definition: vrexMgr.h:99
vrexMgr.h
IARM-Bus VREX Manager Public API.
IARM_Bus_BroadcastEvent
IARM_Result_t IARM_Bus_BroadcastEvent(const char *ownerName, IARM_EventId_t eventId, void *data, size_t len)
This API is used to publish an Asynchronous event to all IARM client registered for this perticular e...
libIBus.h
RDK IARM-Bus API Declarations.
_IARM_BUS_VREXMgr_EventData_t
Definition: vrexMgr.h:179
MotionInfo
Definition: vrexSession.h:61