[MediaController] Implementation of:
authorRafal Galka <r.galka@samsung.com>
Wed, 29 Apr 2015 07:58:54 +0000 (09:58 +0200)
committerRafal Galka <r.galka@samsung.com>
Wed, 29 Apr 2015 08:05:09 +0000 (17:05 +0900)
- sendPlaybackPosition
- sendShuffleMode
- sendRepeatMode
with corresponding server change listeners.

[Remark] CAPI have no dedicated methods.
Implementation is based on custom commands.
It should be updated when new version of CAPI will be available.

Change-Id: Ic7361e6a85cbeff98019aec61d56625d8bf7f1ba
Signed-off-by: Rafal Galka <r.galka@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_server.cc
src/mediacontroller/mediacontroller_server.h

index df6153e..17c7c19 100644 (file)
@@ -10,6 +10,14 @@ var validator_ = utils_.validator;
 var types_ = validator_.Types;
 var native_ = new xwalk.utils.NativeManager(extension);
 
+// TODO(r.galka) CAPI have no dedicated methods for position/shuffle/repeat change.
+// It should be updated when new version of CAPI will be available.
+// For now implementation is using internal commands.
+var internal_commands_ = {
+  sendPlaybackPosition: '__internal_sendPlaybackPosition',
+  sendShuffleMode: '__internal_sendShuffleMode',
+  sendRepeatMode: '__internal_sendRepeatMode'
+};
 
 function ListenerManager(native, listenerName, handle) {
   this.listeners = {};
@@ -20,7 +28,7 @@ function ListenerManager(native, listenerName, handle) {
   this.handle = handle || function(msg, listener, watchId) {};
 }
 
-ListenerManager.prototype.addListener = function(callback, data) {
+ListenerManager.prototype.addListener = function(callback) {
   var id = this.nextId;
   if (!this.nativeSet) {
     this.native.addListener(this.listenerName, function(msg) {
@@ -33,10 +41,11 @@ ListenerManager.prototype.addListener = function(callback, data) {
         }
       }
     }.bind(this));
+
     this.nativeSet = true;
   }
+
   this.listeners[id] = callback;
-  this.listeners[id].data = data || {};
   ++this.nextId;
   return id;
 };
@@ -581,16 +590,7 @@ MediaControllerServerInfo.prototype.sendPlaybackPosition = function(position, su
   var data = {
     position: args.position
   };
-
-  var callback = function(result) {
-    if (native_.isFailure(result)) {
-      native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
-      return;
-    }
-    native_.callIfPossible(args.successCallback);
-  };
-
-  native_.call('MediaControllerServerInfo_sendPlaybackPosition', data, callback);
+  this.sendCommand(internal_commands_.sendPlaybackPosition, data, successCallback, errorCallback);
 };
 
 MediaControllerServerInfo.prototype.sendShuffleMode = function(mode, successCallback, errorCallback) {
@@ -603,16 +603,7 @@ MediaControllerServerInfo.prototype.sendShuffleMode = function(mode, successCall
   var data = {
     mode: args.mode
   };
-
-  var callback = function(result) {
-    if (native_.isFailure(result)) {
-      native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
-      return;
-    }
-    native_.callIfPossible(args.successCallback);
-  };
-
-  native_.call('MediaControllerServerInfo_sendShuffleMode', data, callback);
+  this.sendCommand(internal_commands_.sendShuffleMode, data, successCallback, errorCallback);
 };
 
 MediaControllerServerInfo.prototype.sendRepeatMode = function(mode, successCallback, errorCallback) {
@@ -625,16 +616,7 @@ MediaControllerServerInfo.prototype.sendRepeatMode = function(mode, successCallb
   var data = {
     mode: args.mode
   };
-
-  var callback = function(result) {
-    if (native_.isFailure(result)) {
-      native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
-      return;
-    }
-    native_.callIfPossible(args.successCallback);
-  };
-
-  native_.call('MediaControllerServerInfo_sendRepeatMode', data, callback);
+  this.sendCommand(internal_commands_.sendRepeatMode, data, successCallback, errorCallback);
 };
 
 MediaControllerServerInfo.prototype.sendCommand = function(command, data, successCallback, errorCallback) {
@@ -651,7 +633,7 @@ MediaControllerServerInfo.prototype.sendCommand = function(command, data, succes
     name: this.name
   };
 
-  var replyId = ReplyCommandListener.addListener(successCallback, nativeData);
+  var replyId = ReplyCommandListener.addListener(successCallback);
 
   nativeData.replyId = replyId;
   nativeData.listenerId = ReplyCommandListener.listenerName;
index e4ec5e3..8c09fb4 100644 (file)
@@ -595,5 +595,32 @@ PlatformResult MediaControllerClient::SendPlaybackState(
   return PlatformResult(ErrorCode::NO_ERROR);
 }
 
+PlatformResult MediaControllerClient::SendPlaybackPosition(
+    const std::string& server_name,
+    double position) {
+
+  // TODO(r.galka) implement when dedicated method will be available in CAPI
+
+  return PlatformResult(ErrorCode::NOT_SUPPORTED_ERR);
+}
+
+PlatformResult MediaControllerClient::SendShuffleMode(
+    const std::string& server_name,
+    bool mode) {
+
+  // TODO(r.galka) implement when dedicated method will be available in CAPI
+
+  return PlatformResult(ErrorCode::NOT_SUPPORTED_ERR);
+}
+
+PlatformResult MediaControllerClient::SendRepeatMode(
+    const std::string& server_name,
+    bool mode) {
+
+  // TODO(r.galka) implement when dedicated method will be available in CAPI
+
+  return PlatformResult(ErrorCode::NOT_SUPPORTED_ERR);
+}
+
 } // namespace mediacontroller
 } // namespace extension
index 948122a..4dbdf16 100644 (file)
@@ -30,6 +30,12 @@ class MediaControllerClient {
 
   common::PlatformResult SendPlaybackState(const std::string& server_name,
                                            const std::string& state);
+  common::PlatformResult SendPlaybackPosition(const std::string& server_name,
+                                              double position);
+  common::PlatformResult SendShuffleMode(const std::string& server_name,
+                                         bool mode);
+  common::PlatformResult SendRepeatMode(const std::string& server_name,
+                                        bool mode);
 
   common::PlatformResult SendCommand(const std::string& server_name,
                                      const std::string& command,
index 66657d6..c2075f8 100644 (file)
@@ -250,9 +250,8 @@ void MediaControllerInstance::MediaControllerServerAddChangeRequestPlaybackInfoL
   CHECK_EXIST(args, "listenerId", out)
 
   JsonCallback callback = [this, args](picojson::value* data) -> void {
-    LOGGER(DEBUG) << "entered";
 
-    if (nullptr == data) {
+    if (!data) {
       LOGGER(ERROR) << "No data passed to json callback";
       return;
     }
@@ -462,8 +461,6 @@ void MediaControllerInstance::MediaControllerServerInfoSendPlaybackState(
   CHECK_EXIST(args, "state", out)
 
   auto send = [this, args]() -> void {
-    LOGGER(DEBUG) << "entered";
-
     picojson::value response = picojson::value(picojson::object());
     picojson::object& response_obj = response.get<picojson::object>();
     response_obj["callbackId"] = args.get("callbackId");
@@ -489,58 +486,114 @@ void MediaControllerInstance::MediaControllerServerInfoSendPlaybackState(
 void MediaControllerInstance::MediaControllerServerInfoSendPlaybackPosition(
     const picojson::value& args,
     picojson::object& out) {
+
+  if (!client_) {
+    ReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR,
+                               "Client not initialized."), &out);
+    return;
+  }
+
   CHECK_EXIST(args, "callbackId", out)
+  CHECK_EXIST(args, "name", out)
   CHECK_EXIST(args, "position", out)
 
-  int callbackId = static_cast<int>(args.get("callbackId").get<double>());
-  double position = args.get("position").get<double>();
+  auto send = [this, args]() -> void {
+    picojson::value response = picojson::value(picojson::object());
+    picojson::object& response_obj = response.get<picojson::object>();
+    response_obj["callbackId"] = args.get("callbackId");
 
-  // implement it
+    PlatformResult result = client_->SendPlaybackPosition(
+        args.get("name").get<std::string>(),
+        args.get("position").get<double>());
 
-  // call ReplyAsync in later (Asynchronously)
+    if (result) {
+      ReportSuccess(response_obj);
+    } else {
+      ReportError(result, &response_obj);
+    }
+
+    PostMessage(response.serialize().c_str());
+  };
+
+  TaskQueue::GetInstance().Async(send);
 
-  // if success
-  // ReportSuccess(out);
-  // if error
-  // ReportError(out);
+  ReportSuccess(out);
 }
 
 void MediaControllerInstance::MediaControllerServerInfoSendShuffleMode(
     const picojson::value& args,
     picojson::object& out) {
+
+  if (!client_) {
+    LOGGER(ERROR) << "Client not initialized.";
+    ReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR,
+                               "Client not initialized."), &out);
+    return;
+  }
+
   CHECK_EXIST(args, "callbackId", out)
+  CHECK_EXIST(args, "name", out)
   CHECK_EXIST(args, "mode", out)
 
-  int callbackId = static_cast<int>(args.get("callbackId").get<double>());
-  bool mode = args.get("mode").get<bool>();
+  auto send = [this, args]() -> void {
+    picojson::value response = picojson::value(picojson::object());
+    picojson::object& response_obj = response.get<picojson::object>();
+    response_obj["callbackId"] = args.get("callbackId");
 
-  // implement it
+    PlatformResult result = client_->SendShuffleMode(
+        args.get("name").get<std::string>(),
+        args.get("mode").get<bool>());
 
-  // call ReplyAsync in later (Asynchronously)
+    if (result) {
+      ReportSuccess(response_obj);
+    } else {
+      ReportError(result, &response_obj);
+    }
 
-  // if success
-  // ReportSuccess(out);
-  // if error
-  // ReportError(out);
+    PostMessage(response.serialize().c_str());
+  };
+
+  TaskQueue::GetInstance().Async(send);
+
+  ReportSuccess(out);
 }
 
 void MediaControllerInstance::MediaControllerServerInfoSendRepeatMode(
     const picojson::value& args,
     picojson::object& out) {
+
+  if (!client_) {
+    LOGGER(ERROR) << "Client not initialized.";
+    ReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR,
+                               "Client not initialized."), &out);
+    return;
+  }
+
   CHECK_EXIST(args, "callbackId", out)
+  CHECK_EXIST(args, "name", out)
   CHECK_EXIST(args, "mode", out)
 
-  int callbackId = static_cast<int>(args.get("callbackId").get<double>());
-  bool mode = args.get("mode").get<bool>();
+  auto send = [this, args]() -> void {
+    picojson::value response = picojson::value(picojson::object());
+    picojson::object& response_obj = response.get<picojson::object>();
+    response_obj["callbackId"] = args.get("callbackId");
+
+    PlatformResult result = client_->SendRepeatMode(
+        args.get("name").get<std::string>(),
+        args.get("mode").get<bool>());
 
-  // implement it
+    if (result) {
+      ReportSuccess(response_obj);
+    } else {
+      ReportError(result, &response_obj);
+    }
 
-  // call ReplyAsync in later (Asynchronously)
+    PostMessage(response.serialize().c_str());
+  };
 
-  // if success
-  // ReportSuccess(out);
-  // if error
-  // ReportError(out);
+  TaskQueue::GetInstance().Async(send);
+
+  ReportSuccess(out);
 }
 
 void MediaControllerInstance::MediaControllerServerInfoSendCommand(
index 7a04654..01e1752 100644 (file)
 namespace extension {
 namespace mediacontroller {
 
+namespace {
+// The privileges that are required in Application API
+const std::string kInternalCommandSendPlaybackPosition
+    = "__internal_sendPlaybackPosition";
+const std::string kInternalCommandSendShuffleMode
+    = "__internal_sendShuffleMode";
+const std::string kInternalCommandSendRepeatMode
+    = "__internal_sendRepeatMode";
+}  // namespace
+
 using common::PlatformResult;
 using common::ErrorCode;
 
@@ -169,20 +179,64 @@ 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);
 
+  int ret;
+  char* data_str = nullptr;
+  SCOPE_EXIT {
+    free(data_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;
+  }
+
+  // TODO(r.galka) CAPI have no dedicated methods for position/shuffle/repeat change.
+  // It should be updated when new version of CAPI will be available.
+  // For now implementation is using internal commands.
+  if (command == kInternalCommandSendPlaybackPosition) {
+    double position = data.get("position").get<double>();
+    server->SetPlaybackPosition(position);
+    server->OnPlaybackPositionCommand(client_name,
+                                      static_cast<unsigned long long>(position),
+                                      server);
+    return;
+  }
+  if (command == kInternalCommandSendShuffleMode) {
+    bool mode = data.get("mode").get<bool>();
+    server->SetShuffleMode(mode);
+    server->OnShuffleModeCommand(client_name,
+                                 mode ? SHUFFLE_MODE_ON : SHUFFLE_MODE_OFF,
+                                 server);
+    return;
+  }
+  if (command == kInternalCommandSendRepeatMode) {
+    bool mode = data.get("mode").get<bool>();
+    server->SetRepeatMode(mode);
+    server->OnRepeatModeCommand(client_name,
+                                mode ? REPEAT_MODE_ON : REPEAT_MODE_OFF,
+                                server);
+    return;
+  }
+
   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);
@@ -191,20 +245,6 @@ void MediaControllerServer::OnCommandReceived(const char* client_name,
       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));
@@ -285,7 +325,6 @@ PlatformResult MediaControllerServer::SetChangeRequestPlaybackInfoListener(
 void MediaControllerServer::OnPlaybackStateCommand(const char* client_name,
                                                    mc_playback_states_e state_e,
                                                    void *user_data) {
-  LOGGER(DEBUG) << "entered";
 
   MediaControllerServer* server = static_cast<MediaControllerServer*>(user_data);
 
@@ -312,5 +351,66 @@ void MediaControllerServer::OnPlaybackStateCommand(const char* client_name,
   server->change_request_playback_info_listener_(&data);
 }
 
+void MediaControllerServer::OnPlaybackPositionCommand(
+    const char* client_name,
+    unsigned long long position,
+    void* user_data) {
+
+  MediaControllerServer* server = static_cast<MediaControllerServer*>(user_data);
+
+  if (!server->change_request_playback_info_listener_) {
+    LOGGER(DEBUG) << "No change request playback info listener registered, skipping";
+    return;
+  }
+
+  picojson::value data = picojson::value(picojson::object());
+  picojson::object& data_o = data.get<picojson::object>();
+
+  data_o["action"] = picojson::value(std::string("onplaybackpositionrequest"));
+  data_o["position"] = picojson::value(static_cast<double>(position));
+
+  server->change_request_playback_info_listener_(&data);
+}
+
+void MediaControllerServer::OnShuffleModeCommand(const char* client_name,
+                                                 mc_shuffle_mode_e mode,
+                                                 void* user_data) {
+
+  MediaControllerServer* server = static_cast<MediaControllerServer*>(user_data);
+
+  if (!server->change_request_playback_info_listener_) {
+    LOGGER(DEBUG) << "No change request playback info listener registered, skipping";
+    return;
+  }
+
+  picojson::value data = picojson::value(picojson::object());
+  picojson::object& data_o = data.get<picojson::object>();
+
+  data_o["action"] = picojson::value(std::string("onshufflemoderequest"));
+  data_o["mode"] = picojson::value(mode == SHUFFLE_MODE_ON);
+
+  server->change_request_playback_info_listener_(&data);
+}
+
+void MediaControllerServer::OnRepeatModeCommand(const char* client_name,
+                                                mc_repeat_mode_e mode,
+                                                void* user_data) {
+
+  MediaControllerServer* server = static_cast<MediaControllerServer*>(user_data);
+
+  if (!server->change_request_playback_info_listener_) {
+    LOGGER(DEBUG) << "No change request playback info listener registered, skipping";
+    return;
+  }
+
+  picojson::value data = picojson::value(picojson::object());
+  picojson::object& data_o = data.get<picojson::object>();
+
+  data_o["action"] = picojson::value(std::string("onrepeatmoderequest"));
+  data_o["mode"] = picojson::value(mode == REPEAT_MODE_ON);
+
+  server->change_request_playback_info_listener_(&data);
+}
+
 } // namespace mediacontroller
 } // namespace extension
index dad266d..d051afb 100644 (file)
@@ -46,6 +46,16 @@ class MediaControllerServer {
   static void OnPlaybackStateCommand(const char* client_name,
                                      mc_playback_states_e state_e,
                                      void *user_data);
+  static void OnPlaybackPositionCommand(const char* client_name,
+                                        unsigned long long position,
+                                        void* user_data);
+  static void OnShuffleModeCommand(const char* client_name,
+                                   mc_shuffle_mode_e mode,
+                                   void* user_data);
+  static void OnRepeatModeCommand(const char* client_name,
+                                  mc_repeat_mode_e mode,
+                                  void* user_data);
+
   static void OnCommandReceived(const char* client_name,
                                 const char* command,
                                 bundle* data,