[Mediacontroller] added subtitles feature and related ability 23/213623/13
authorPiotr Kosko/Native/Web API (PLT) /SRPOL/Engineer/삼성전자 <p.kosko@samsung.com>
Thu, 12 Sep 2019 09:40:52 +0000 (11:40 +0200)
committerPiotr Kosko <p.kosko@samsung.com>
Thu, 19 Sep 2019 10:02:56 +0000 (10:02 +0000)
[ACR] http://suprem.sec.samsung.net/jira/browse/TWDAPI-230

[Verification] Code compiles without errors.
Basic test in chrome console works properly.

/// 1. adding command listener
var mcServer = tizen.mediacontroller.createServer();
mcServer.updatePlaybackState("PLAY");
var changeListener = function(enabled, clientName)
{
    console.log("Subtitles mode change requested to: " + enabled + " by " + clientName);
    return new tizen.mediacontroller.RequestReply(new tizen.Bundle({"message": "Not allowed"}), 13);
};
watcherId = mcServer.subtitles.addChangeRequestListener(changeListener);

/// 2. checking NotSupportedError when sending without enabled ability
var mcClient = tizen.mediacontroller.getClient();
var mcServerInfo = mcClient.getLatestServerInfo()
var enabled = true;
mcServerInfo.subtitles.sendRequest(enabled,
    function(data, code)
    {
      console.log(
          "Server replied with return data: " + JSON.stringify(data) + " and code: " + code);
    });

/// 3. register listener for mode changes (client side)
watcherId = mcServerInfo.subtitles.addModeChangeListener(function(status)
{
  console.log(mcServerInfo.name + " server subtitles mode changed to " + status);
});

/// 4. change the value of subtitles (should trigger listener from point 3)
mcServer.subtitles.enabled = true

/// 5. enable ability of server
mcServer.abilities.subtitles = "YES"

/// sendRequest again (should trigger listener from point 1)
mcServerInfo.subtitles.sendRequest(enabled,
function(data, code)
{
  console.log(
      "Server replied with return data: " + JSON.stringify(data) + " and code: " + code);
});

/// 6. register ability change listener and trigger the update
var listener =
{
  onsimpleabilitychanged: function(server, type, ability)
  {
    console.log(type + " ability changed, server name: " + server.name + ", ability: " + ability);
  }
};
mcClient.addAbilityChangeListener(listener);

/// call updates to trigger listener
mcServer.abilities.subtitles = "NO"
mcServer.abilities.subtitles = "NO"
/// Listener should be triggered once

Change-Id: I00ad78a44b696a7d885d13499af77cf762e54c7e

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_utils.cc

index 1d3f2fa..037b83f 100755 (executable)
@@ -358,6 +358,7 @@ var MediaControllerSimpleAbility = {
     PLAYLIST: 'PLAYLIST',
     CLIENT_CUSTOM: 'CLIENT_CUSTOM',
     SEARCH: 'SEARCH',
+    SUBTITLES: 'SUBTITLES',
     MODE_360: 'MODE_360'
 };
 
@@ -627,6 +628,7 @@ var MediaControllerAbilities = function() {
         _playlist = MediaControllerAbilitySupport.UNDECIDED,
         _clientCustom = MediaControllerAbilitySupport.UNDECIDED,
         _search = MediaControllerAbilitySupport.UNDECIDED,
+        _subtitles = MediaControllerAbilitySupport.NO,
         _mode360 = MediaControllerAbilitySupport.NO;
 
     Object.defineProperties(this, {
@@ -706,6 +708,18 @@ var MediaControllerAbilities = function() {
             },
             enumerable: true
         },
+        subtitles: {
+            get: function() {
+                return _subtitles;
+            },
+            set: function(val) {
+                if (val !== _subtitles) {
+                    setSimpleAbility(MediaControllerSimpleAbility.SUBTITLES, val);
+                    _subtitles = val;
+                }
+            },
+            enumerable: true
+        },
         mode360: {
             get: function() {
                 return _mode360;
@@ -894,6 +908,16 @@ var MediaControllerAbilitiesInfo = function(serverName) {
             set: function() {},
             enumerable: true
         },
+        subtitles: {
+            get: function() {
+                return getSimpleAbility(
+                    serverName,
+                    MediaControllerSimpleAbility.SUBTITLES
+                );
+            },
+            set: function() {},
+            enumerable: true
+        },
         mode360: {
             get: function() {
                 return getSimpleAbility(
@@ -994,9 +1018,201 @@ var MediaControllerPlaybackAbilitiesInfo = function(serverName) {
     });
 };
 
-// TODO subtitles
-var MediaControllerSubtitles = function() {};
-var MediaControllerSubtitlesInfo = function() {};
+// subtitles
+var MediaControllerSubtitles = function() {
+    // the default value is false
+    var _enabled = false;
+    Object.defineProperties(this, {
+        enabled: {
+            get: function() {
+                return _enabled;
+            },
+            set: function(v) {
+                var data = {
+                    enabled: converter_.toBoolean(v)
+                };
+                if (data.enabled !== _enabled) {
+                    var result = native_.callSync(
+                        'MediaControllerSubtitles_updateEnabled',
+                        data
+                    );
+                    if (native_.isFailure(result)) {
+                        throw native_.getErrorObject(result);
+                    }
+                    _enabled = data.enabled;
+                }
+            },
+            enumerable: true
+        }
+    });
+};
+
+var MediaControllerSubtitlesListener = new ListenerManager(
+    native_,
+    '_MediaControllerSubtitlesListener',
+    function(msg, listener) {
+        var reply = listener(msg.clientName, msg.enabled);
+
+        if (!(reply instanceof RequestReply)) {
+            reply = new RequestReply(
+                xwalk.utils.type.isNullOrUndefined(reply) ? null : reply,
+                0
+            );
+        }
+
+        var nativeData = {
+            clientName: msg.clientName,
+            requestId: msg.requestId,
+            reply: reply
+        };
+        var result = native_.callSync('MediaControllerServer_replyCommand', nativeData);
+        if (native_.isFailure(result)) {
+            throw native_.getErrorObject(result);
+        }
+    }
+);
+
+MediaControllerSubtitles.prototype.addChangeRequestListener = function() {
+    var args = validator_.validateArgs(arguments, [
+        {
+            name: 'listener',
+            type: types_.FUNCTION,
+            optional: false,
+            nullable: false
+        }
+    ]);
+
+    if (type_.isEmptyObject(MediaControllerSubtitlesListener.listeners)) {
+        var result = native_.callSync(
+            'MediaControllerSubtitles_addChangeRequestListener',
+            {
+                listenerId: MediaControllerSubtitlesListener.listenerName
+            }
+        );
+        if (native_.isFailure(result)) {
+            throw native_.getErrorObject(result);
+        }
+    }
+    return MediaControllerSubtitlesListener.addListener(args.listener);
+};
+
+MediaControllerSubtitles.prototype.removeChangeRequestListener = function(watchId) {
+    var args = validator_.validateArgs(arguments, [
+        { name: 'watchId', type: types_.LONG }
+    ]);
+
+    MediaControllerSubtitlesListener.removeListener(args.watchId);
+
+    if (type_.isEmptyObject(MediaControllerSubtitlesListener.listeners)) {
+        var result = native_.callSync(
+            'MediaControllerSubtitles_removeChangeRequestListener'
+        );
+        if (native_.isFailure(result)) {
+            throw native_.getErrorObject(result);
+        }
+    }
+};
+
+var SubtitlesChangeListener = new ListenerManager(
+    native_,
+    '_SubtitlesChangeListener',
+    function(msg, listener) {
+        listener(msg.enabled);
+    }
+);
+
+var MediaControllerSubtitlesInfo = function(name) {
+    var _serverName = name;
+    Object.defineProperties(this, {
+        enabled: {
+            get: function() {
+                var result = native_.callSync('MediaControllerSubtitlesInfo_getEnabled', {
+                    name: _serverName
+                });
+                if (native_.isFailure(result)) {
+                    throw new native_.getErrorObject(result);
+                }
+                return native_.getResultObject(result);
+            },
+            set: function(v) {},
+            enumerable: true
+        }
+    });
+
+    this.sendRequest = function() {
+        var args = validator_.validateArgs(arguments, [
+            {
+                name: 'enabled',
+                type: types_.BOOLEAN
+            },
+            {
+                name: 'replyCallback',
+                type: types_.FUNCTION
+            }
+        ]);
+        var callback = function(result) {
+            native_.callIfPossible(
+                args.replyCallback,
+                native_.getResultObject(result).data,
+                native_.getResultObject(result).code
+            );
+        };
+
+        var nativeData = {
+            enabled: args.enabled,
+            name: _serverName,
+            listenerId: ReplyCommandListener.listenerName
+        };
+
+        var result = native_.callSync(
+            'MediaControllerSubtitlesInfo_sendRequest',
+            nativeData
+        );
+        if (native_.isFailure(result)) {
+            throw native_.getErrorObject(result);
+        }
+
+        var replyListenerId = ReplyCommandListener.addListener(callback);
+        ReplyCommandListener.requestIdToListenerId[replyListenerId] = result.requestId;
+    };
+
+    this.addModeChangeListener = function(listener) {
+        var args = validator_.validateArgs(arguments, [
+            { name: 'listener', type: types_.FUNCTION }
+        ]);
+
+        if (type_.isEmptyObject(SubtitlesChangeListener.listeners)) {
+            var result = native_.callSync(
+                'MediaControllerSubtitlesInfo_addModeChangeListener',
+                {
+                    listenerId: SubtitlesChangeListener.listenerName
+                }
+            );
+            if (native_.isFailure(result)) {
+                throw native_.getErrorObject(result);
+            }
+        }
+        return SubtitlesChangeListener.addServerInfoListener(args.listener, _serverName);
+    };
+
+    this.removeModeChangeListener = function(watchId) {
+        var args = validator_.validateArgs(arguments, [
+            { name: 'watchId', type: types_.LONG }
+        ]);
+
+        SubtitlesChangeListener.removeServerInfoListener(args.watchId);
+
+        if (type_.isEmptyObject(SubtitlesChangeListener.listeners)) {
+            var result = native_.callSync(
+                'MediaControllerSubtitlesInfo_removeModeChangeListener'
+            );
+            if (native_.isFailure(result)) {
+                throw native_.getErrorObject(result);
+            }
+        }
+    };
+};
+
 // mode360
 var MediaControllerMode360 = function() {
     // the default value is false
@@ -2107,7 +2323,7 @@ function MediaControllerServerInfo(data) {
             writable: false
         },
         subtitles: {
-            value: new MediaControllerSubtitlesInfo(),
+            value: new MediaControllerSubtitlesInfo(data.name),
             enumerable: true,
             writable: false
         },
index 4fa5788..6bbade4 100644 (file)
@@ -63,6 +63,10 @@ MediaControllerClient::~MediaControllerClient() {
     LoggerE("Failed to unset ability listener");
   }
 
+  if (nullptr != subtitles_update_listener_ && !UnsetSubtitlesInfoChangeListener()) {
+    LoggerE("Failed to unset subtitles listener");
+  }
+
   if (nullptr != mode360_update_listener_ && !UnsetMode360InfoChangeListener()) {
     LoggerE("Failed to unset mode 360 listener");
   }
@@ -1160,7 +1164,77 @@ PlatformResult MediaControllerClient::UnsetPlaylistUpdateListener() {
   return PlatformResult(ErrorCode::NO_ERROR);
 }
 
-// TODO subtitles
+// subtitles
+PlatformResult MediaControllerClient::GetSubtitlesEnabled(const std::string& name, bool* enabled) {
+  ScopeLogger();
+
+  int ret = mc_client_get_server_subtitles_enabled(handle_, name.c_str(), enabled);
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Error getting subtitle enabled",
+                              ("mc_client_get_server_subtitles_enabled() error: %d, message: %s",
+                               ret, get_error_message(ret)));
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult MediaControllerClient::SendSubtitlesEnabled(const std::string& server_name,
+                                                           bool enabled,
+                                                           const JsonCallback& reply_cb,
+                                                           char** request_id) {
+  ScopeLogger();
+  int ret = mc_client_send_subtitles_cmd(handle_, server_name.c_str(), enabled, request_id);
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
+    return LogAndCreateResult(
+        utils::ConvertMediaControllerError(ret), "Error sending subtitle command",
+        ("mc_client_send_subtitles_cmd() error: %d, message: %s", ret, get_error_message(ret)));
+  }
+
+  command_reply_callback_ = reply_cb;
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult MediaControllerClient::SetSubtitlesInfoChangeListener(const JsonCallback& callback) {
+  ScopeLogger();
+
+  int ret = mc_client_set_subtitles_updated_cb(handle_, OnSubtitlesUpdate, this);
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unable to set subtitles listener",
+                              ("mc_client_set_subtitles_updated_cb() error: %d, message: %s", ret,
+                               get_error_message(ret)));
+  }
+
+  subtitles_update_listener_ = callback;
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult MediaControllerClient::UnsetSubtitlesInfoChangeListener() {
+  ScopeLogger();
+  int ret = mc_client_unset_subtitles_updated_cb(handle_);
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unable to unset subtitles listener",
+                              ("mc_client_unset_subtitles_updated_cb() error: %d, message: %s", ret,
+                               get_error_message(ret)));
+  }
+  subtitles_update_listener_ = nullptr;
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+void MediaControllerClient::OnSubtitlesUpdate(const char* server_name, bool enabled,
+                                              void* user_data) {
+  ScopeLogger();
+  MediaControllerClient* client = static_cast<MediaControllerClient*>(user_data);
+
+  picojson::value data = picojson::value(picojson::object());
+  picojson::object& data_o = data.get<picojson::object>();
+
+  data_o["enabled"] = picojson::value(enabled);
+  data_o["name"] = picojson::value(server_name);
+
+  client->subtitles_update_listener_(&data);
+}
+
 // mode360
 PlatformResult MediaControllerClient::GetMode360Enabled(const std::string& name, bool* enabled) {
   ScopeLogger();
index 9b36177..1acf677 100644 (file)
@@ -74,6 +74,11 @@ class MediaControllerClient {
   common::PlatformResult UnsubscribeServer(const std::string& server_name);
   common::PlatformResult FindSubscribedServers(picojson::array* servers);
   // TODO subtitles
+  common::PlatformResult GetSubtitlesEnabled(const std::string& name, bool* enabled);
+  common::PlatformResult SendSubtitlesEnabled(const std::string& server_name, bool enabled,
+                                              const JsonCallback& reply_cb, char** request_id);
+  common::PlatformResult SetSubtitlesInfoChangeListener(const JsonCallback& callback);
+  common::PlatformResult UnsetSubtitlesInfoChangeListener();
   // mode360
   common::PlatformResult GetMode360Enabled(const std::string& name, bool* enabled);
   common::PlatformResult SendMode360Enabled(const std::string& server_name, bool enabled,
@@ -91,6 +96,8 @@ class MediaControllerClient {
   JsonCallback command_reply_callback_;
   JsonCallback playlist_update_listener_;
   JsonCallback ability_listener_;
+  // subtitles
+  JsonCallback subtitles_update_listener_;
   // mode 360
   JsonCallback mode360_update_listener_;
 
@@ -112,7 +119,8 @@ class MediaControllerClient {
                                       void* user_data);
   static void OnSimpleAbilityUpdate(const char* server_name, mc_ability_e type,
                                     mc_ability_support_e mode, void* user_data);
-  // TODO subtitles
+  // subtitles
+  static void OnSubtitlesUpdate(const char* server_name, bool enabled, void* user_data);
   // mode360
   static void OnMode360Update(const char* server_name, bool enabled, void* user_data);
   // TODO displayMode
index f9b35c7..b959539 100644 (file)
@@ -152,7 +152,21 @@ MediaControllerInstance::MediaControllerInstance() {
   REGISTER_SYNC("MediaControllerPlaylist_addItem", MediaControllerPlaylistAddItem);
   REGISTER_ASYNC("MediaControllerPlaylist_getItems", MediaControllerPlaylistGetItems);
 
-  // TODO subtitles
+  // subtitles
+  REGISTER_SYNC("MediaControllerSubtitles_updateEnabled", MediaControllerSubtitlesUpdateEnabled);
+  REGISTER_SYNC("MediaControllerSubtitles_addChangeRequestListener",
+                MediaControllerSubtitlesAddChangeRequestListener);
+  REGISTER_SYNC("MediaControllerSubtitles_removeChangeRequestListener",
+                MediaControllerSubtitlesRemoveChangeRequestListener);
+
+  REGISTER_SYNC("MediaControllerSubtitlesInfo_getEnabled", MediaControllerSubtitlesInfoGetEnabled);
+  REGISTER_ASYNC("MediaControllerSubtitlesInfo_sendRequest",
+                 MediaControllerSubtitlesInfoSendRequest);
+  REGISTER_SYNC("MediaControllerSubtitlesInfo_addModeChangeListener",
+                MediaControllerSubtitlesInfoAddModeChangeListener);
+  REGISTER_SYNC("MediaControllerSubtitlesInfo_removeModeChangeListener",
+                MediaControllerSubtitlesInfoRemoveModeChangeListener);
+
   // mode360
   REGISTER_SYNC("MediaControllerMode360_updateEnabled", MediaControllerMode360UpdateEnabled);
   REGISTER_SYNC("MediaControllerMode360_addChangeRequestListener",
@@ -1597,7 +1611,188 @@ void MediaControllerInstance::MediaControllerPlaylistGetItems(const picojson::va
   ReportSuccess(out);
 }
 
-// TODO subtitles
+// subtitles
+void MediaControllerInstance::MediaControllerSubtitlesUpdateEnabled(const picojson::value& args,
+                                                                    picojson::object& out) {
+  ScopeLogger();
+
+  if (!server_) {
+    LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occurred."), &out,
+                      ("Failed: server_"));
+    return;
+  }
+
+  CHECK_ARGS(args, "enabled", bool, out);
+
+  const bool enabled = args.get("enabled").get<bool>();
+  PlatformResult result = server_->UpdateSubtitlesEnabled(enabled);
+  if (!result) {
+    LogAndReportError(result, &out, ("Failed server_->UpdateSubtitlesEnabled()"));
+    return;
+  }
+  ReportSuccess(out);
+}
+
+void MediaControllerInstance::MediaControllerSubtitlesAddChangeRequestListener(
+    const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+  if (!server_) {
+    LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occurred."), &out,
+                      ("Failed: server_"));
+    return;
+  }
+
+  CHECK_ARGS(args, "listenerId", std::string, out)
+
+  JsonCallback callback = [this, args](picojson::value* data) -> void {
+    if (!data) {
+      LoggerE("No data passed to json callback");
+      return;
+    }
+    picojson::object& request_o = data->get<picojson::object>();
+    request_o["listenerId"] = args.get("listenerId");
+
+    Instance::PostMessage(this, data->serialize().c_str());
+  };
+
+  auto result = server_->SetSubtitlesChangeRequestListener(callback);
+  if (!result) {
+    LogAndReportError(result, &out);
+    return;
+  }
+
+  ReportSuccess(out);
+}
+
+void MediaControllerInstance::MediaControllerSubtitlesRemoveChangeRequestListener(
+    const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+  if (!server_) {
+    LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occurred."), &out,
+                      ("Failed: server_"));
+    return;
+  }
+
+  auto result = server_->UnsetSubtitlesChangeRequestListener();
+  if (!result) {
+    LogAndReportError(result, &out);
+    return;
+  }
+  ReportSuccess(out);
+}
+
+void MediaControllerInstance::MediaControllerSubtitlesInfoGetEnabled(const picojson::value& args,
+                                                                     picojson::object& out) {
+  ScopeLogger();
+  if (!client_) {
+    LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occurred."), &out,
+                      ("Failed: client_"));
+    return;
+  }
+
+  CHECK_ARGS(args, "name", std::string, out)
+
+  bool enabled = false;
+  PlatformResult result =
+      client_->GetSubtitlesEnabled(args.get("name").get<std::string>(), &enabled);
+
+  if (!result) {
+    LogAndReportError(result, &out, ("Failed: client_->GetSubtitlesEnabled"));
+    return;
+  }
+
+  ReportSuccess(picojson::value(enabled), out);
+}
+
+void MediaControllerInstance::MediaControllerSubtitlesInfoSendRequest(const picojson::value& args,
+                                                                      picojson::object& out) {
+  ScopeLogger();
+  if (!client_) {
+    LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occurred."), &out,
+                      ("Failed: client_"));
+    return;
+  }
+
+  CHECK_ARGS(args, "listenerId", std::string, out)
+  CHECK_ARGS(args, "name", std::string, out)
+  CHECK_ARGS(args, "enabled", bool, out)
+
+  JsonCallback reply_cb = [this, args](picojson::value* reply) -> void {
+    if (reply) {
+      picojson::object& reply_obj = reply->get<picojson::object>();
+      reply_obj["listenerId"] = args.get("listenerId");
+      Instance::PostMessage(this, reply->serialize().c_str());
+    } else {
+      LoggerW("No reply passed to json callback, ignoring");
+    }
+  };
+
+  char* request_id = nullptr;
+  SCOPE_EXIT {
+    free(request_id);
+  };
+
+  PlatformResult result = client_->SendSubtitlesEnabled(
+      args.get("name").get<std::string>(), args.get("enabled").get<bool>(), reply_cb, &request_id);
+
+  if (result) {
+    ReportSuccess(out);
+    out["requestId"] = picojson::value(std::string(request_id));
+  } else {
+    LogAndReportError(result, &out, ("Failed to send command."));
+  }
+}
+
+void MediaControllerInstance::MediaControllerSubtitlesInfoAddModeChangeListener(
+    const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+  if (!client_) {
+    LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occured."), &out,
+                      ("Failed: client_"));
+    return;
+  }
+
+  CHECK_ARGS(args, "listenerId", std::string, out)
+
+  JsonCallback callback = [this, args](picojson::value* data) -> void {
+    if (nullptr == data) {
+      LoggerE("No data passed to json callback");
+      return;
+    }
+
+    picojson::object& request_o = data->get<picojson::object>();
+    request_o["listenerId"] = args.get("listenerId");
+
+    Instance::PostMessage(this, data->serialize().c_str());
+  };
+
+  auto result = client_->SetSubtitlesInfoChangeListener(callback);
+  if (!result) {
+    LogAndReportError(result, &out);
+    return;
+  }
+
+  ReportSuccess(out);
+}
+
+void MediaControllerInstance::MediaControllerSubtitlesInfoRemoveModeChangeListener(
+    const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+  if (!client_) {
+    LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occured."), &out,
+                      ("Failed: client_"));
+    return;
+  }
+
+  auto result = client_->UnsetSubtitlesInfoChangeListener();
+  if (!result) {
+    LogAndReportError(result, &out);
+    return;
+  }
+
+  ReportSuccess(out);
+}
+
 // mode360
 void MediaControllerInstance::MediaControllerMode360UpdateEnabled(const picojson::value& args,
                                                                   picojson::object& out) {
index 199fd2c..b820825 100644 (file)
@@ -119,7 +119,19 @@ class MediaControllerInstance : public common::ParsedInstance {
   void MediaControllerPlaylistAddItem(const picojson::value& args, picojson::object& out);
   void MediaControllerPlaylistGetItems(const picojson::value& args, picojson::object& out);
 
-  // TODO subtitles
+  // subtitles
+  void MediaControllerSubtitlesUpdateEnabled(const picojson::value& args, picojson::object& out);
+  void MediaControllerSubtitlesAddChangeRequestListener(const picojson::value& args,
+                                                        picojson::object& out);
+  void MediaControllerSubtitlesRemoveChangeRequestListener(const picojson::value& args,
+                                                           picojson::object& out);
+  void MediaControllerSubtitlesInfoGetEnabled(const picojson::value& args, picojson::object& out);
+  void MediaControllerSubtitlesInfoSendRequest(const picojson::value& args, picojson::object& out);
+  void MediaControllerSubtitlesInfoAddModeChangeListener(const picojson::value& args,
+                                                         picojson::object& out);
+  void MediaControllerSubtitlesInfoRemoveModeChangeListener(const picojson::value& args,
+                                                            picojson::object& out);
+
   // mode360
   void MediaControllerMode360UpdateEnabled(const picojson::value& args, picojson::object& out);
   void MediaControllerMode360AddChangeRequestListener(const picojson::value& args,
index 2a4cc72..5e2a532 100644 (file)
@@ -60,6 +60,10 @@ MediaControllerServer::~MediaControllerServer() {
     LoggerE("Failed to unset search request listener");
   }
 
+  if (nullptr != subtitles_change_request_listener_ && !UnsetSubtitlesChangeRequestListener()) {
+    LoggerE("Failed to unset subtitles listener");
+  }
+
   if (nullptr != mode360_change_request_listener_ && !UnsetMode360ChangeRequestListener()) {
     LoggerE("Failed to unset mode 360 request listener");
   }
@@ -1053,7 +1057,65 @@ void MediaControllerServer::OnPlaybackItemCommand(const char* client_name, const
   server->change_request_playback_info_listener_(&data);
 }
 
-// TODO subtitles
+// subtitles
+common::PlatformResult MediaControllerServer::UpdateSubtitlesEnabled(bool enabled) {
+  ScopeLogger();
+  int ret = mc_server_update_subtitles_enabled(handle_, enabled);
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Error setting server subtitles",
+                              ("mc_server_update_subtitles_enabled() error: %d, message: %s", ret,
+                               get_error_message(ret)));
+  }
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+void MediaControllerServer::OnSubtitlesChangeCommand(const char* client_name,
+                                                     const char* request_id, bool enabled,
+                                                     void* user_data) {
+  ScopeLogger();
+
+  MediaControllerServer* server = static_cast<MediaControllerServer*>(user_data);
+
+  picojson::value data = picojson::value(picojson::object());
+  picojson::object& data_o = data.get<picojson::object>();
+
+  data_o["enabled"] = picojson::value(enabled);
+  data_o["clientName"] = picojson::value(client_name);
+  data_o["requestId"] = picojson::value(std::string(request_id));
+
+  server->subtitles_change_request_listener_(&data);
+}
+
+PlatformResult MediaControllerServer::SetSubtitlesChangeRequestListener(
+    const JsonCallback& callback) {
+  ScopeLogger();
+
+  int ret = mc_server_set_subtitles_cmd_received_cb(handle_, OnSubtitlesChangeCommand, this);
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unable to set subtitles command listener",
+                              ("mc_server_set_subtitles_cmd_received_cb() error: %d, message: %s",
+                               ret, get_error_message(ret)));
+  }
+
+  subtitles_change_request_listener_ = callback;
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult MediaControllerServer::UnsetSubtitlesChangeRequestListener() {
+  ScopeLogger();
+
+  int ret = mc_server_unset_subtitles_cmd_received_cb(handle_);
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unable to unset subtitles command listener",
+                              ("mc_server_unset_subtitles_cmd_received_cb() error: %d, message: %s",
+                               ret, get_error_message(ret)));
+  }
+  subtitles_change_request_listener_ = nullptr;
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
 // mode360
 common::PlatformResult MediaControllerServer::UpdateMode360Enabled(bool enabled) {
   ScopeLogger();
index 7c79faa..6a40137 100644 (file)
@@ -69,7 +69,11 @@ class MediaControllerServer {
   common::PlatformResult SavePlaybackAbilities(const picojson::value& abilities);
   common::PlatformResult SetSimpleAbility(const std::string& ability_type,
                                           const std::string& support_str);
-  // TODO subtitles
+  // subtitles
+  common::PlatformResult UpdateSubtitlesEnabled(bool enabled);
+  common::PlatformResult SetSubtitlesChangeRequestListener(const JsonCallback& callback);
+  common::PlatformResult UnsetSubtitlesChangeRequestListener();
+
   // mode360
   common::PlatformResult UpdateMode360Enabled(bool enabled);
   common::PlatformResult SetMode360ChangeRequestListener(const JsonCallback& callback);
@@ -111,7 +115,10 @@ class MediaControllerServer {
                                       mc_search_h request, void* user_data);
   static void OnCommandReceived(const char* client_name, const char* request_id,
                                 const char* command, bundle* data, void* user_data);
-  // TODO subtitles
+  // subtitles
+  JsonCallback subtitles_change_request_listener_;
+  static void OnSubtitlesChangeCommand(const char* client_name, const char* request_id,
+                                       bool enabled, void* user_data);
   // mode360
   JsonCallback mode360_change_request_listener_;
   static void OnMode360ChangeCommand(const char* client_name, const char* request_id, bool enabled,
index 4aa1d0c..6bd2af3 100644 (file)
@@ -111,6 +111,7 @@ const common::PlatformEnum<mc_ability_e> MediaControllerSimpleAbilityEnum{
     {"PLAYLIST", MC_ABILITY_PLAYLIST},
     {"CLIENT_CUSTOM", MC_ABILITY_CLIENT_CUSTOM},
     {"SEARCH", MC_ABILITY_SEARCH},
+    {"SUBTITLES", MC_ABILITY_SUBTITLES},
     {"MODE_360", MC_ABILITY_360_MODE}};
 
 PlatformResult ConvertPlaybackState(mc_playback_h playback_h, std::string* state) {