From: Rafal Galka Date: Tue, 28 Apr 2015 10:31:07 +0000 (+0200) Subject: [MediaController] Custom commands native implementation. X-Git-Tag: submit/tizen_tv/20150603.064601~1^2~123 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3a16adbf0cecc51a883da7d359d49afcc0b168ba;p=platform%2Fcore%2Fapi%2Fwebapi-plugins.git [MediaController] Custom commands native implementation. - MediaControllerServerInfo.sendCommand() - MediaControllerServer.addCommandListener() Change-Id: I76741c1f551ba134da89c12caa24dd775a913ffd Signed-off-by: Rafal Galka Signed-off-by: Pawel Kaczmarek --- diff --git a/src/mediacontroller/mediacontroller_api.js b/src/mediacontroller/mediacontroller_api.js index d41e3a41..df6153e0 100644 --- a/src/mediacontroller/mediacontroller_api.js +++ b/src/mediacontroller/mediacontroller_api.js @@ -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) { diff --git a/src/mediacontroller/mediacontroller_client.cc b/src/mediacontroller/mediacontroller_client.cc index d36a8ca6..e4ec5e3e 100644 --- a/src/mediacontroller/mediacontroller_client.cc +++ b/src/mediacontroller/mediacontroller_client.cc @@ -4,6 +4,9 @@ #include "mediacontroller/mediacontroller_client.h" +#include +#include + #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(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(user_data); + + picojson::value reply = picojson::value(picojson::object()); + picojson::object& reply_o = reply.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); + 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) { diff --git a/src/mediacontroller/mediacontroller_client.h b/src/mediacontroller/mediacontroller_client.h index 8cf04b37..948122a6 100644 --- a/src/mediacontroller/mediacontroller_client.h +++ b/src/mediacontroller/mediacontroller_client.h @@ -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); diff --git a/src/mediacontroller/mediacontroller_instance.cc b/src/mediacontroller/mediacontroller_instance.cc index 229383df..66657d67 100644 --- a/src/mediacontroller/mediacontroller_instance.cc +++ b/src/mediacontroller/mediacontroller_instance.cc @@ -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(); + 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(), + 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(); + 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(args.get("callbackId").get()); - const std::string& command = args.get("command").get(); - const picojson::object data = args.get("data").get(); + JsonCallback reply_cb = [this, args](picojson::value* reply) -> void { + LOGGER(DEBUG) << "entered"; - // implement it + picojson::object& reply_obj = reply->get(); - // 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(), + args.get("command").get(), + args.get("data"), + args.get("replyId").to_str(), + reply_cb); + + if (result) { + ReportSuccess(out); + } else { + ReportError(result, &out); + } } void MediaControllerInstance::MediaControllerServerInfoAddServerStatusChangeListener( diff --git a/src/mediacontroller/mediacontroller_instance.h b/src/mediacontroller/mediacontroller_instance.h index f48db2f9..20eee063 100644 --- a/src/mediacontroller/mediacontroller_instance.h +++ b/src/mediacontroller/mediacontroller_instance.h @@ -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 diff --git a/src/mediacontroller/mediacontroller_server.cc b/src/mediacontroller/mediacontroller_server.cc index 23c409c4..7a046548 100644 --- a/src/mediacontroller/mediacontroller_server.cc +++ b/src/mediacontroller/mediacontroller_server.cc @@ -4,7 +4,10 @@ #include "mediacontroller/mediacontroller_server.h" +#include + #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(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(user_data); + + 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); + 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( diff --git a/src/mediacontroller/mediacontroller_server.h b/src/mediacontroller/mediacontroller_server.h index 427181e7..dad266d1 100644 --- a/src/mediacontroller/mediacontroller_server.h +++ b/src/mediacontroller/mediacontroller_server.h @@ -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 diff --git a/src/mediacontroller/mediacontroller_types.cc b/src/mediacontroller/mediacontroller_types.cc index 62bf01bc..f732f31b 100644 --- a/src/mediacontroller/mediacontroller_types.cc +++ b/src/mediacontroller/mediacontroller_types.cc @@ -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;