[MediaController] Custom commands native implementation.
authorRafal Galka <r.galka@samsung.com>
Tue, 28 Apr 2015 10:31:07 +0000 (12:31 +0200)
committerRafal Galka <r.galka@samsung.com>
Tue, 28 Apr 2015 10:31:07 +0000 (12:31 +0200)
- MediaControllerServerInfo.sendCommand()
- MediaControllerServer.addCommandListener()

Change-Id: I76741c1f551ba134da89c12caa24dd775a913ffd
Signed-off-by: Rafal Galka <r.galka@samsung.com>
Signed-off-by: Pawel Kaczmarek <p.kaczmarek3@samsung.com>
src/mediacontroller/mediacontroller_api.js
src/mediacontroller/mediacontroller_client.cc
src/mediacontroller/mediacontroller_client.h
src/mediacontroller/mediacontroller_instance.cc
src/mediacontroller/mediacontroller_instance.h
src/mediacontroller/mediacontroller_server.cc
src/mediacontroller/mediacontroller_server.h
src/mediacontroller/mediacontroller_types.cc

index d41e3a416abdd6e160dc9f1f2353bb043c7e6829..df6153e0d4ba11d3e061e150091d6ccd324bb670 100644 (file)
@@ -26,7 +26,10 @@ ListenerManager.prototype.addListener = function(callback, data) {
     this.native.addListener(this.listenerName, function(msg) {
       for (var watchId in this.listeners) {
         if (this.listeners.hasOwnProperty(watchId)) {
-          this.handle(msg, this.listeners[watchId], watchId);
+          var stop = this.handle(msg, this.listeners[watchId], watchId);
+          if (stop) {
+            break;
+          }
         }
       }
     }.bind(this));
@@ -45,11 +48,15 @@ ListenerManager.prototype.removeListener = function(watchId) {
 };
 
 var ServerCommandListener = new ListenerManager(native_, '_ServerCommandListener', function(msg, listener) {
-  var d = native_.getResultObject(msg);
-  var data = listener(d.clientName, d.command, d.data);
+  var data = listener(msg.clientName, msg.command, msg.data);
+
+  if (type_.isNullOrUndefined(data)) {
+    return;
+  }
 
   var nativeData = {
-    clientName: d.clientName,
+    clientName: msg.clientName,
+    replyId: msg.replyId,
     data: data
   };
 
@@ -60,8 +67,13 @@ var ServerCommandListener = new ListenerManager(native_, '_ServerCommandListener
 });
 
 var ReplyCommandListener = new ListenerManager(native_, '_ReplyCommandListener', function(msg, listener, watchId) {
-  listener(msg.reply);
-  this.removeListener(watchId);
+  if (msg.replyId === watchId) {
+    listener(msg.data);
+    this.removeListener(watchId);
+    return true;
+  }
+
+  return false;
 });
 
 var ServerPlaybackInfoListener = new ListenerManager(native_, '_ServerPlaybackInfoListener', function(msg, listener) {
index d36a8ca64ebeaef2617bf9ec3e7e8b8d0114d871..e4ec5e3eb33ae9eddbfb965b4823612c43d8af82 100644 (file)
@@ -4,6 +4,9 @@
 
 #include "mediacontroller/mediacontroller_client.h"
 
+#include <bundle.h>
+#include <memory>
+
 #include "common/logger.h"
 #include "common/scope_exit.h"
 
@@ -97,7 +100,10 @@ PlatformResult MediaControllerClient::GetLatestServerInfo(
 
   int ret;
 
-  char* name;
+  char* name = nullptr;
+  SCOPE_EXIT {
+    free(name);
+  };
   mc_server_state_e state;
   ret = mc_client_get_latest_server_info(handle_, &name, &state);
   if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
@@ -106,15 +112,11 @@ PlatformResult MediaControllerClient::GetLatestServerInfo(
                           "Error getting latest server info");
   }
 
-  if (NULL == name) {
+  if (!name) {
     LOGGER(DEBUG) << "No active server available";
     return PlatformResult(ErrorCode::NO_ERROR);
   }
 
-  SCOPE_EXIT {
-    free(name);
-  };
-
   std::string state_str;
   PlatformResult result = Types::PlatformEnumToString(
       Types::kMediaControllerServerState, static_cast<int>(state), &state_str);
@@ -476,6 +478,97 @@ void MediaControllerClient::OnMetadataUpdate(const char* server_name,
   client->playback_info_listener_(&data);
 }
 
+PlatformResult MediaControllerClient::SendCommand(
+    const std::string& server_name,
+    const std::string& command,
+    const picojson::value& data,
+    const std::string& reply_id,
+    const JsonCallback& reply_cb) {
+  LOGGER(DEBUG) << "entered";
+
+  int ret;
+
+  bundle* bundle = bundle_create();
+  SCOPE_EXIT {
+    bundle_free(bundle);
+  };
+
+  ret = bundle_add(bundle, "replyId", reply_id.c_str());
+  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+    LOGGER(ERROR) << "bundle_add(replyId) failed, error: " << ret;
+    return PlatformResult(ErrorCode::UNKNOWN_ERR,
+                          "Unable to add replyId to bundle");
+  }
+
+  ret = bundle_add(bundle, "data", data.serialize().c_str());
+  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+    LOGGER(ERROR) << "bundle_add(data) failed, error: " << ret;
+    return PlatformResult(ErrorCode::UNKNOWN_ERR,
+                          "Unable to add data to bundle");
+  }
+
+  ret = mc_client_send_custom_command(handle_,
+                                      server_name.c_str(),
+                                      command.c_str(),
+                                      bundle,
+                                      OnCommandReply,
+                                      this);
+  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+    LOGGER(ERROR) << "mc_client_send_custom_command failed, error: " << ret;
+    return PlatformResult(ErrorCode::UNKNOWN_ERR,
+                          "Error sending custom command");
+  }
+
+  command_reply_callback_ = reply_cb;
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+void MediaControllerClient::OnCommandReply(const char* server_name,
+                                           int result_code,
+                                           bundle* bundle,
+                                           void* user_data) {
+  LOGGER(DEBUG) << "entered";
+
+  MediaControllerClient* client = static_cast<MediaControllerClient*>(user_data);
+
+  picojson::value reply = picojson::value(picojson::object());
+  picojson::object& reply_o = reply.get<picojson::object>();
+
+  int ret;
+  char* reply_id_str = nullptr;
+  char* data_str = nullptr;
+  SCOPE_EXIT {
+    free(reply_id_str);
+    free(data_str);
+  };
+
+  ret = bundle_get_str(bundle, "replyId", &reply_id_str);
+  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+    LOGGER(ERROR) << "bundle_get_str(replyId) failed, error: " << ret;
+    return;
+  }
+
+  reply_o["replyId"] = picojson::value(std::string(reply_id_str));
+
+  ret = bundle_get_str(bundle, "data", &data_str);
+  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+    LOGGER(ERROR) << "bundle_get_str(data) failed, error: " << ret;
+    return;
+  }
+
+  picojson::value data;
+  std::string err;
+  picojson::parse(data, data_str, data_str + strlen(data_str), &err);
+  if (!err.empty()) {
+    LOGGER(ERROR) << "Failed to parse bundle data: " << err;
+    return;
+  }
+  reply_o["data"] = data;
+
+  client->command_reply_callback_(&reply);
+}
+
 PlatformResult MediaControllerClient::SendPlaybackState(
     const std::string& server_name,
     const std::string& state) {
index 8cf04b37a2f20f0525ea5825556e75407abbd9e9..948122a6cde0350cd2a79b0a1774b938a99f8ec8 100644 (file)
@@ -31,19 +31,31 @@ class MediaControllerClient {
   common::PlatformResult SendPlaybackState(const std::string& server_name,
                                            const std::string& state);
 
+  common::PlatformResult SendCommand(const std::string& server_name,
+                                     const std::string& command,
+                                     const picojson::value& data,
+                                     const std::string& reply_id,
+                                     const JsonCallback& reply_cb);
+
   common::PlatformResult SetServerStatusChangeListener(JsonCallback callback);
   common::PlatformResult SetPlaybackInfoListener(JsonCallback callback);
 
  private:
   mc_client_h handle_;
+
   JsonCallback playback_info_listener_;
   JsonCallback server_status_listener_;
+  JsonCallback command_reply_callback_;
 
   static bool FindServersCallback(const char* server_name, void* user_data);
 
   static void OnServerStatusUpdate(const char *server_name,
                                    mc_server_state_e state,
                                    void *user_data);
+  static void OnCommandReply(const char* server_name,
+                             int result_code,
+                             bundle* bundle,
+                             void* user_data);
   static void OnPlaybackUpdate(const char *server_name,
                                mc_playback_h playback,
                                void *user_data);
index 229383df9dd9efa763f9e147197a726f3d2ca50d..66657d67bbc7e943d5bd86ab000c3af05ed4eb25 100644 (file)
@@ -54,6 +54,8 @@ MediaControllerInstance::MediaControllerInstance() {
       MediaControllerServerRemoveChangeRequestPlaybackInfoListener);
   REGISTER_SYNC("MediaControllerServer_addCommandListener",
       MediaControllerServerAddCommandListener);
+  REGISTER_SYNC("MediaControllerServer_replyCommand",
+      MediaControllerServerReplyCommand);
   REGISTER_SYNC("MediaControllerServer_removeCommandListener",
       MediaControllerServerRemoveCommandListener);
 
@@ -283,28 +285,64 @@ void MediaControllerInstance::MediaControllerServerRemoveChangeRequestPlaybackIn
 void MediaControllerInstance::MediaControllerServerAddCommandListener(
     const picojson::value& args,
     picojson::object& out) {
+  LOGGER(DEBUG) << "entered";
 
-  // implement it
+  if (!server_) {
+    ReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR,
+                               "Server not initialized."), &out);
+    return;
+  }
 
-  // if success
-  // ReportSuccess(out);
-  // if error
-  // ReportError(out);
+  JsonCallback on_command = [this, args](picojson::value* request) -> void {
+    LOGGER(DEBUG) << "entered";
+
+    picojson::object& request_o = request->get<picojson::object>();
+    request_o["listenerId"] = args.get("listenerId");
+
+    PostMessage(request->serialize().c_str());
+  };
+
+  server_->set_command_listener(on_command);
+
+  ReportSuccess(out);
+}
+
+void MediaControllerInstance::MediaControllerServerReplyCommand(
+    const picojson::value& args,
+    picojson::object& out) {
+  LOGGER(DEBUG) << "entered";
+
+  if (!server_) {
+    ReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR,
+                               "Server not initialized."), &out);
+    return;
+  }
+
+  CHECK_EXIST(args, "clientName", out)
+  CHECK_EXIST(args, "replyId", out)
+  CHECK_EXIST(args, "data", out)
+
+  server_->CommandReply(args.get("clientName").get<std::string>(),
+                        args.get("replyId").to_str(),
+                        args.get("data"));
+
+  ReportSuccess(out);
 }
 
 void MediaControllerInstance::MediaControllerServerRemoveCommandListener(
     const picojson::value& args,
     picojson::object& out) {
-  CHECK_EXIST(args, "watchId", out)
+  LOGGER(DEBUG) << "entered";
 
-  double watchId = args.get("watchId").get<double>();
+  if (!server_) {
+    ReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR,
+                               "Server not initialized."), &out);
+    return;
+  }
 
-  // implement it
+  server_->set_command_listener(nullptr);
 
-  // if success
-  // ReportSuccess(out);
-  // if error
-  // ReportError(out);
+  ReportSuccess(out);
 }
 
 void MediaControllerInstance::MediaControllerManagerGetClient(
@@ -508,22 +546,42 @@ void MediaControllerInstance::MediaControllerServerInfoSendRepeatMode(
 void MediaControllerInstance::MediaControllerServerInfoSendCommand(
     const picojson::value& args,
     picojson::object& out) {
-  CHECK_EXIST(args, "callbackId", out)
+
+  if (!client_) {
+    LOGGER(ERROR) << "Client not initialized.";
+    ReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR,
+                               "Client not initialized."), &out);
+    return;
+  }
+
+  CHECK_EXIST(args, "listenerId", out)
+  CHECK_EXIST(args, "replyId", out)
+  CHECK_EXIST(args, "name", out)
   CHECK_EXIST(args, "command", out)
   CHECK_EXIST(args, "data", out)
 
-  int callbackId = static_cast<int>(args.get("callbackId").get<double>());
-  const std::string& command = args.get("command").get<std::string>();
-  const picojson::object data = args.get("data").get<picojson::object>();
+  JsonCallback reply_cb = [this, args](picojson::value* reply) -> void {
+    LOGGER(DEBUG) << "entered";
 
-  // implement it
+    picojson::object& reply_obj = reply->get<picojson::object>();
 
-  // call ReplyAsync in later (Asynchronously)
+    reply_obj["listenerId"] = args.get("listenerId");
 
-  // if success
-  // ReportSuccess(out);
-  // if error
-  // ReportError(out);
+    PostMessage(reply->serialize().c_str());
+  };
+
+  PlatformResult result = client_->SendCommand(
+      args.get("name").get<std::string>(),
+      args.get("command").get<std::string>(),
+      args.get("data"),
+      args.get("replyId").to_str(),
+      reply_cb);
+
+  if (result) {
+    ReportSuccess(out);
+  } else {
+    ReportError(result, &out);
+  }
 }
 
 void MediaControllerInstance::MediaControllerServerInfoAddServerStatusChangeListener(
index f48db2f9ef6c64174c93da83d04703812c77ad74..20eee06302df7ad7abb1d0aafaf2ca744f9613d4 100644 (file)
@@ -30,6 +30,7 @@ class MediaControllerInstance : public common::ParsedInstance {
   void MediaControllerServerAddChangeRequestPlaybackInfoListener(const picojson::value& args, picojson::object& out);
   void MediaControllerServerRemoveChangeRequestPlaybackInfoListener(const picojson::value& args, picojson::object& out);
   void MediaControllerServerAddCommandListener(const picojson::value& args, picojson::object& out);
+  void MediaControllerServerReplyCommand(const picojson::value& args, picojson::object& out);
   void MediaControllerServerRemoveCommandListener(const picojson::value& args, picojson::object& out);
 
   // client
index 23c409c4a26d24e8b9458d8501c589d592630865..7a0465486b8b23b506ea568fc7d4e428304261c0 100644 (file)
@@ -4,7 +4,10 @@
 
 #include "mediacontroller/mediacontroller_server.h"
 
+#include <bundle.h>
+
 #include "common/logger.h"
+#include "common/scope_exit.h"
 
 #include "mediacontroller/mediacontroller_types.h"
 
@@ -20,27 +23,41 @@ MediaControllerServer::MediaControllerServer() : handle_(nullptr) {
 MediaControllerServer::~MediaControllerServer() {
 
   if (handle_) {
-    int ret = mc_server_destroy(handle_);
+    int ret;
+    ret = mc_server_unset_custom_command_received_cb(handle_);
+    if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+      LOGGER(ERROR) << "Unable to unset command callback, error: " << ret;
+    }
+
+    ret = mc_server_destroy(handle_);
     if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
-      LOGGER(ERROR) << "Unable to destroy media controller server";
+      LOGGER(ERROR) << "mc_server_destroy() failed, error: " << ret;
     }
   }
 }
 
-common::PlatformResult MediaControllerServer::Init() {
-  PlatformResult result = PlatformResult(ErrorCode::NO_ERROR);
+PlatformResult MediaControllerServer::Init() {
 
   int ret = mc_server_create(&handle_);
   if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
     LOGGER(ERROR) << "Unable to create media controller server, error: " << ret;
-    result = PlatformResult(ErrorCode::UNKNOWN_ERR,
-                            "Unable to create media controller server");
+    return PlatformResult(ErrorCode::UNKNOWN_ERR,
+                          "Unable to create media controller server");
+  }
+
+  ret = mc_server_set_custom_command_received_cb(handle_,
+                                                 OnCommandReceived,
+                                                 this);
+  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+    LOGGER(ERROR) << "Unable to set command callback, error: " << ret;
+    return PlatformResult(ErrorCode::UNKNOWN_ERR,
+                          "Unable to set command callback");
   }
 
-  return result;
+  return PlatformResult(ErrorCode::NO_ERROR);
 }
 
-common::PlatformResult MediaControllerServer::SetPlaybackState(
+PlatformResult MediaControllerServer::SetPlaybackState(
     const std::string& state) {
 
   int state_int;
@@ -69,8 +86,7 @@ common::PlatformResult MediaControllerServer::SetPlaybackState(
   return PlatformResult(ErrorCode::NO_ERROR);
 }
 
-common::PlatformResult MediaControllerServer::SetPlaybackPosition(
-    double position) {
+PlatformResult MediaControllerServer::SetPlaybackPosition(double position) {
 
   int ret = mc_server_set_playback_position(
       handle_, static_cast<unsigned long long>(position));
@@ -90,7 +106,7 @@ common::PlatformResult MediaControllerServer::SetPlaybackPosition(
   return PlatformResult(ErrorCode::NO_ERROR);
 }
 
-common::PlatformResult MediaControllerServer::SetShuffleMode(bool mode) {
+PlatformResult MediaControllerServer::SetShuffleMode(bool mode) {
 
   int ret = mc_server_update_shuffle_mode(handle_,
                                           mode ? SHUFFLE_MODE_ON
@@ -104,7 +120,7 @@ common::PlatformResult MediaControllerServer::SetShuffleMode(bool mode) {
   return PlatformResult(ErrorCode::NO_ERROR);
 }
 
-common::PlatformResult MediaControllerServer::SetRepeatMode(bool mode) {
+PlatformResult MediaControllerServer::SetRepeatMode(bool mode) {
 
   int ret = mc_server_update_repeat_mode(handle_,
                                          mode ? REPEAT_MODE_ON
@@ -117,16 +133,15 @@ common::PlatformResult MediaControllerServer::SetRepeatMode(bool mode) {
   return PlatformResult(ErrorCode::NO_ERROR);
 }
 
-common::PlatformResult MediaControllerServer::SetMetadata(
+PlatformResult MediaControllerServer::SetMetadata(
     const picojson::object& metadata) {
 
   int attribute_int, ret;
-  PlatformResult result(ErrorCode::NO_ERROR);
   for (picojson::object::const_iterator i = metadata.begin();
        i != metadata.end();
        ++i) {
 
-    result = Types::StringToPlatformEnum(
+    PlatformResult result = Types::StringToPlatformEnum(
         Types::kMediaControllerMetadataAttribute, i->first, &attribute_int);
     if (!result) {
       return result;
@@ -147,7 +162,92 @@ common::PlatformResult MediaControllerServer::SetMetadata(
     return PlatformResult(ErrorCode::UNKNOWN_ERR, "Error updating metadata");
   }
 
-  return result;
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+void MediaControllerServer::OnCommandReceived(const char* client_name,
+                                              const char* command,
+                                              bundle* bundle,
+                                              void* user_data) {
+  LOGGER(DEBUG) << "entered";
+
+  MediaControllerServer* server = static_cast<MediaControllerServer*>(user_data);
+
+  if (server->command_listener_) {
+    picojson::value request = picojson::value(picojson::object());
+    picojson::object& request_o = request.get<picojson::object>();
+
+    int ret;
+    char* reply_id_str = nullptr;
+    char* data_str = nullptr;
+    SCOPE_EXIT {
+      free(reply_id_str);
+      free(data_str);
+    };
+
+    ret = bundle_get_str(bundle, "replyId", &reply_id_str);
+    if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+      LOGGER(ERROR) << "bundle_get_str(replyId) failed, error: " << ret;
+      return;
+    }
+
+    ret = bundle_get_str(bundle, "data", &data_str);
+    if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+      LOGGER(ERROR) << "bundle_get_str(data) failed, error: " << ret;
+      return;
+    }
+
+    picojson::value data;
+    std::string err;
+    picojson::parse(data, data_str, data_str + strlen(data_str), &err);
+    if (!err.empty()) {
+      LOGGER(ERROR) << "Failed to parse bundle data: " << err;
+      return;
+    }
+
+    request_o["clientName"] = picojson::value(std::string(client_name));
+    request_o["command"] = picojson::value(std::string(command));
+    request_o["replyId"] = picojson::value(std::string(reply_id_str));
+    request_o["data"] = data;
+
+    server->command_listener_(&request);
+  }
+}
+
+PlatformResult MediaControllerServer::CommandReply(
+    const std::string& client_name,
+    const std::string& reply_id,
+    const picojson::value& data) {
+  LOGGER(DEBUG) << "entered";
+
+  int ret;
+
+  bundle* bundle = bundle_create();
+  SCOPE_EXIT {
+    bundle_free(bundle);
+  };
+
+  ret = bundle_add(bundle, "replyId", reply_id.c_str());
+  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+    LOGGER(ERROR) << "bundle_add(replyId) failed, error: " << ret;
+    return PlatformResult(ErrorCode::UNKNOWN_ERR,
+                          "Unable to add replyId to bundle");
+  }
+
+  ret = bundle_add(bundle, "data", data.serialize().c_str());
+  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+    LOGGER(ERROR) << "bundle_add(data) failed, error: " << ret;
+    return PlatformResult(ErrorCode::UNKNOWN_ERR,
+                          "Unable to add data to bundle");
+  }
+
+  ret = mc_server_send_command_reply(handle_, client_name.c_str(), 0, bundle, NULL);
+  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+    LOGGER(ERROR) << "mc_server_send_command_reply failed, error: " << ret;
+    return PlatformResult(ErrorCode::UNKNOWN_ERR, "Error sending command reply");
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
 }
 
 PlatformResult MediaControllerServer::SetChangeRequestPlaybackInfoListener(
index 427181e7c7a7e6608d3f1a4f9c1e5726a52d4923..dad266d186290611310d794010c97b3f7c36d8ae 100644 (file)
@@ -29,13 +29,27 @@ class MediaControllerServer {
   common::PlatformResult SetChangeRequestPlaybackInfoListener(
       JsonCallback callback);
 
+  common::PlatformResult CommandReply(const std::string& client_name,
+                                      const std::string& reply_id,
+                                      const picojson::value& data);
+
+  void set_command_listener(const JsonCallback& func) {
+    command_listener_ = func;
+  }
+
  private:
   mc_server_h handle_;
+
   JsonCallback change_request_playback_info_listener_;
+  JsonCallback command_listener_;
 
   static void OnPlaybackStateCommand(const char* client_name,
                                      mc_playback_states_e state_e,
                                      void *user_data);
+  static void OnCommandReceived(const char* client_name,
+                                const char* command,
+                                bundle* data,
+                                void* user_data);
 };
 
 } // namespace mediacontroller
index 62bf01bcafe9ea430358609a35dbed3694c4310d..f732f31bc0d69a9d86e81a4510df8d28b020d3ae 100644 (file)
@@ -170,9 +170,9 @@ PlatformResult Types::ConvertMetadata(mc_metadata_h metadata_h,
     return result;
   }
 
-  char* value;
+  char* value = nullptr;
   SCOPE_EXIT {
-      free(value);
+    free(value);
   };
 
   int ret;