From baa780c78c36c8b606af32b6c812dd5406de4a3f Mon Sep 17 00:00:00 2001 From: Rafal Galka Date: Wed, 29 Apr 2015 09:58:54 +0200 Subject: [PATCH] [MediaController] Implementation of: - 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 --- src/mediacontroller/mediacontroller_api.js | 48 +++------ src/mediacontroller/mediacontroller_client.cc | 27 +++++ src/mediacontroller/mediacontroller_client.h | 6 ++ src/mediacontroller/mediacontroller_instance.cc | 109 ++++++++++++++----- src/mediacontroller/mediacontroller_server.cc | 138 ++++++++++++++++++++---- src/mediacontroller/mediacontroller_server.h | 10 ++ 6 files changed, 258 insertions(+), 80 deletions(-) diff --git a/src/mediacontroller/mediacontroller_api.js b/src/mediacontroller/mediacontroller_api.js index df6153e..17c7c19 100644 --- a/src/mediacontroller/mediacontroller_api.js +++ b/src/mediacontroller/mediacontroller_api.js @@ -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; diff --git a/src/mediacontroller/mediacontroller_client.cc b/src/mediacontroller/mediacontroller_client.cc index e4ec5e3..8c09fb4 100644 --- a/src/mediacontroller/mediacontroller_client.cc +++ b/src/mediacontroller/mediacontroller_client.cc @@ -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 diff --git a/src/mediacontroller/mediacontroller_client.h b/src/mediacontroller/mediacontroller_client.h index 948122a..4dbdf16 100644 --- a/src/mediacontroller/mediacontroller_client.h +++ b/src/mediacontroller/mediacontroller_client.h @@ -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, diff --git a/src/mediacontroller/mediacontroller_instance.cc b/src/mediacontroller/mediacontroller_instance.cc index 66657d6..c2075f8 100644 --- a/src/mediacontroller/mediacontroller_instance.cc +++ b/src/mediacontroller/mediacontroller_instance.cc @@ -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(); 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(args.get("callbackId").get()); - double position = args.get("position").get(); + auto send = [this, args]() -> void { + picojson::value response = picojson::value(picojson::object()); + picojson::object& response_obj = response.get(); + response_obj["callbackId"] = args.get("callbackId"); - // implement it + PlatformResult result = client_->SendPlaybackPosition( + args.get("name").get(), + args.get("position").get()); - // 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(args.get("callbackId").get()); - bool mode = args.get("mode").get(); + auto send = [this, args]() -> void { + picojson::value response = picojson::value(picojson::object()); + picojson::object& response_obj = response.get(); + response_obj["callbackId"] = args.get("callbackId"); - // implement it + PlatformResult result = client_->SendShuffleMode( + args.get("name").get(), + args.get("mode").get()); - // 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(args.get("callbackId").get()); - bool mode = args.get("mode").get(); + auto send = [this, args]() -> void { + picojson::value response = picojson::value(picojson::object()); + picojson::object& response_obj = response.get(); + response_obj["callbackId"] = args.get("callbackId"); + + PlatformResult result = client_->SendRepeatMode( + args.get("name").get(), + args.get("mode").get()); - // 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( diff --git a/src/mediacontroller/mediacontroller_server.cc b/src/mediacontroller/mediacontroller_server.cc index 7a04654..01e1752 100644 --- a/src/mediacontroller/mediacontroller_server.cc +++ b/src/mediacontroller/mediacontroller_server.cc @@ -14,6 +14,16 @@ 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(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(); + server->SetPlaybackPosition(position); + server->OnPlaybackPositionCommand(client_name, + static_cast(position), + server); + return; + } + if (command == kInternalCommandSendShuffleMode) { + bool mode = data.get("mode").get(); + 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(); + 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(); - 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(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(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(); + + data_o["action"] = picojson::value(std::string("onplaybackpositionrequest")); + data_o["position"] = picojson::value(static_cast(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(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(); + + 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(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(); + + 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 diff --git a/src/mediacontroller/mediacontroller_server.h b/src/mediacontroller/mediacontroller_server.h index dad266d..d051afb 100644 --- a/src/mediacontroller/mediacontroller_server.h +++ b/src/mediacontroller/mediacontroller_server.h @@ -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, -- 2.7.4