From: Rafal Galka Date: Tue, 28 Apr 2015 10:22:32 +0000 (+0200) Subject: [MediaController] Client playback info change listener X-Git-Tag: submit/tizen_mobile/20150603.064609~1^2~126 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3f85e84a92288e5e672f273742cb55a27d64746c;p=platform%2Fcore%2Fapi%2Fwebapi-plugins.git [MediaController] Client playback info change listener Change-Id: Ia81805e2bf709f15b996baf7b1bcda0c9eb02ff4 Signed-off-by: Rafal Galka --- diff --git a/src/mediacontroller/mediacontroller_api.js b/src/mediacontroller/mediacontroller_api.js index 8fa58d1..9d296db 100644 --- a/src/mediacontroller/mediacontroller_api.js +++ b/src/mediacontroller/mediacontroller_api.js @@ -17,16 +17,16 @@ function ListenerManager(native, listenerName, handle) { this.nativeSet = false; this.native = native; this.listenerName = listenerName; - this.handle = handle || function(){}; + this.handle = handle || function(msg, listener, watchId) {}; } ListenerManager.prototype.addListener = function(callback, data) { var id = this.nextId; if (!this.nativeSet) { this.native.addListener(this.listenerName, function(msg) { - for (var key in this.listeners) { - if (this.listeners.hasOwnProperty(key)) { - this.handle(msg, this.listeners[key], key); + for (var watchId in this.listeners) { + if (this.listeners.hasOwnProperty(watchId)) { + this.handle(msg, this.listeners[watchId], watchId); } } }.bind(this)); @@ -92,7 +92,15 @@ var ServerInfoStatusListener = new ListenerManager(native_, '_ServerInfoStatusLi }); var ServerInfoPlaybackInfoListener = new ListenerManager(native_, '_ServerInfoPlaybackInfoListener', function(msg, listener) { - listener(msg.status); + if (msg.action === 'onplaybackchanged') { + listener[msg.action](msg.state, msg.position); + } + if (msg.action === 'onshufflemodechanged' || msg.action === 'onrepeatmodechanged') { + listener[msg.action](msg.mode); + } + if (msg.action === 'onmetadatachanged') { + listener[msg.action](new MediaControllerMetadata(msg.metadata)); + } }); var EditManager = function() { @@ -136,8 +144,7 @@ MediaControllerManager.prototype.getClient = function() { throw native_.getErrorObject(result); } - var client = new MediaControllerClient(native_.getResultObject(result)); - return client; + return new MediaControllerClient(native_.getResultObject(result)); }; MediaControllerManager.prototype.createServer = function() { @@ -146,8 +153,7 @@ MediaControllerManager.prototype.createServer = function() { throw native_.getErrorObject(result); } - var server = new MediaControllerServer(native_.getResultObject(result)); - return server; + return new MediaControllerServer(native_.getResultObject(result)); }; @@ -223,7 +229,7 @@ var MediaControllerMetadata = function(data) { if (data instanceof Object) { for (var prop in data) { - if (this.hasOwnProperty(prop)) { + if (data.hasOwnProperty(prop) && this.hasOwnProperty(prop)) { this[prop] = data[prop]; } } @@ -676,12 +682,22 @@ MediaControllerServerInfo.prototype.removeServerStatusChangeListener = function( }; MediaControllerServerInfo.prototype.addPlaybackInfoChangeListener = function(listener) { - var args = validator_.validateArgs(arguments, [ - {name: 'listener', type: types_.LISTENER, values: ['onplaybackstatechanged', 'onplaybackpositionchanged', 'onshufflemodechanged', 'onrepeatmodechanged', 'onmetadatachanged']} - ]); + var args = validator_.validateArgs(arguments, [{ + name: 'listener', + type: types_.LISTENER, + values: [ + 'onplaybackchanged', + 'onshufflemodechanged', + 'onrepeatmodechanged', + 'onmetadatachanged' + ] + }]); if (type_.isEmptyObject(ServerInfoPlaybackInfoListener.listeners)) { - var result = native_.callSync('MediaControllerServerInfo_addPlaybackInfoChangeListener'); + var result = native_.callSync( + 'MediaControllerServerInfo_addPlaybackInfoChangeListener', { + listenerId: ServerInfoPlaybackInfoListener.listenerName + }); if (native_.isFailure(result)) { throw native_.getErrorObject(result); } diff --git a/src/mediacontroller/mediacontroller_client.cc b/src/mediacontroller/mediacontroller_client.cc index 12915b0..282dc67 100644 --- a/src/mediacontroller/mediacontroller_client.cc +++ b/src/mediacontroller/mediacontroller_client.cc @@ -19,8 +19,6 @@ MediaControllerClient::MediaControllerClient() : handle_(nullptr) { } MediaControllerClient::~MediaControllerClient() { - LOGGER(DEBUG) << "entered"; - if (handle_) { int ret = mc_client_destroy(handle_); if (ret != MEDIA_CONTROLLER_ERROR_NONE) { @@ -30,20 +28,17 @@ MediaControllerClient::~MediaControllerClient() { } PlatformResult MediaControllerClient::Init() { - PlatformResult result = PlatformResult(ErrorCode::NO_ERROR); - int ret = mc_client_create(&handle_); if (ret != MEDIA_CONTROLLER_ERROR_NONE) { LOGGER(ERROR) << "Unable to create media controller client, error: " << ret; - result = PlatformResult(ErrorCode::UNKNOWN_ERR, - "Unable to create media controller client"); + return PlatformResult(ErrorCode::UNKNOWN_ERR, + "Unable to create media controller client"); } - return result; + return PlatformResult(ErrorCode::NO_ERROR); } PlatformResult MediaControllerClient::FindServers(picojson::array* servers) { - LOGGER(DEBUG) << "entered"; int ret; @@ -70,9 +65,9 @@ PlatformResult MediaControllerClient::FindServers(picojson::array* servers) { const std::string& latest_name = latest_server.get("name").get(); // update current server state in list - for (picojson::array::iterator it; it != servers->end(); ++it) { - picojson::object& server = it->get(); - if (it->get("name").get() == latest_name) { + for (auto& it : *servers) { + picojson::object& server = it.get(); + if (server["name"].get() == latest_name) { server["state"] = latest_server.get("state"); break; } @@ -83,7 +78,6 @@ PlatformResult MediaControllerClient::FindServers(picojson::array* servers) { bool MediaControllerClient::FindServersCallback(const char* server_name, void* user_data) { - LOGGER(DEBUG) << "entered"; picojson::array* servers = static_cast(user_data); @@ -158,33 +152,19 @@ PlatformResult MediaControllerClient::GetPlaybackInfo( }; // playback state - mc_playback_states_e state; - ret = mc_client_get_playback_state(playback_h, &state); - if (ret != MEDIA_CONTROLLER_ERROR_NONE) { - LOGGER(ERROR) << "mc_client_get_playback_state failed, error: " << ret; - return PlatformResult(ErrorCode::UNKNOWN_ERR, - "Error getting playback state"); - } - if (state == MEDIA_PLAYBACK_STATE_NONE) { - state = MEDIA_PLAYBACK_STATE_STOPPED; - } - - std::string state_str; - PlatformResult result = Types::PlatformEnumToString( - Types::kMediaControllerPlaybackState, - static_cast(state), &state_str); + std::string state; + PlatformResult result = Types::ConvertPlaybackState(playback_h, &state); if (!result) { - LOGGER(ERROR) << "PlatformEnumToString failed, error: " << result.message(); + LOGGER(ERROR) << "ConvertPlaybackState failed, error: " << result.message(); return result; } // playback position - unsigned long long position; - ret = mc_client_get_playback_position(playback_h, &position); - if (ret != MEDIA_CONTROLLER_ERROR_NONE) { - LOGGER(ERROR) << "mc_client_get_playback_position failed, error: " << ret; - return PlatformResult(ErrorCode::UNKNOWN_ERR, - "Error getting playback position"); + double position; + result = Types::ConvertPlaybackPosition(playback_h, &position); + if (!result) { + LOGGER(ERROR) << "ConvertPlaybackPosition failed, error: " << result.message(); + return result; } // shuffle mode @@ -215,8 +195,8 @@ PlatformResult MediaControllerClient::GetPlaybackInfo( } // fill return object - (*playback_info)["state"] = picojson::value(state_str); - (*playback_info)["position"] = picojson::value(static_cast(position)); + (*playback_info)["state"] = picojson::value(state); + (*playback_info)["position"] = picojson::value(position); (*playback_info)["shuffleMode"] = picojson::value(shuffle == SHUFFLE_MODE_ON); (*playback_info)["repeatMode"] = picojson::value(repeat == REPEAT_MODE_ON); (*playback_info)["metadata"] = metadata; @@ -227,7 +207,6 @@ PlatformResult MediaControllerClient::GetPlaybackInfo( PlatformResult MediaControllerClient::GetMetadata( const std::string& server_name, picojson::object* metadata) { - LOGGER(DEBUG) << "entered"; int ret; @@ -244,36 +223,193 @@ PlatformResult MediaControllerClient::GetMetadata( mc_client_destroy_metadata(metadata_h); }; - std::map metadata_fields; - PlatformResult result = Types::GetPlatformEnumMap( - Types::kMediaControllerMetadataAttribute, &metadata_fields); + PlatformResult result = Types::ConvertMetadata(metadata_h, metadata); if (!result) { - LOGGER(ERROR) << "GetPlatformEnumMap failed, error: " << result.message(); return result; } - char* value = nullptr; - SCOPE_EXIT { - free(value); - }; - for (auto& field : metadata_fields) { - ret = mc_client_get_metadata(metadata_h, - static_cast(field.second), - &value); + return PlatformResult(ErrorCode::NO_ERROR); +} + +PlatformResult MediaControllerClient::SetPlaybackInfoListener( + JsonCallback callback) { + + if (callback && playback_info_listener_) { + LOGGER(ERROR) << "Listener already registered"; + return PlatformResult(ErrorCode::INVALID_STATE_ERR, + "Listener already registered"); + } + + playback_info_listener_ = callback; + + int ret; + if (callback) { // set platform callbacks + + ret = mc_client_set_playback_update_cb(handle_, OnPlaybackUpdate, this); + if (ret != MEDIA_CONTROLLER_ERROR_NONE) { + LOGGER(ERROR) << "Unable to register playback listener, error: " << ret; + return PlatformResult(ErrorCode::UNKNOWN_ERR, + "Unable to register playback listener"); + } + + ret = mc_client_set_shuffle_mode_update_cb(handle_, OnShuffleModeUpdate, this); + if (ret != MEDIA_CONTROLLER_ERROR_NONE) { + LOGGER(ERROR) << "Unable to register shuffle mode listener, error: " << ret; + return PlatformResult(ErrorCode::UNKNOWN_ERR, + "Unable to register shuffle mode listener"); + } + + ret = mc_client_set_repeat_mode_update_cb(handle_, OnRepeatModeUpdate, this); + if (ret != MEDIA_CONTROLLER_ERROR_NONE) { + LOGGER(ERROR) << "Unable to register repeat mode listener, error: " << ret; + return PlatformResult(ErrorCode::UNKNOWN_ERR, + "Unable to register repeat mode listener"); + } + + ret = mc_client_set_metadata_update_cb(handle_, OnMetadataUpdate, this); + if (ret != MEDIA_CONTROLLER_ERROR_NONE) { + LOGGER(ERROR) << "Unable to register metadata listener, error: " << ret; + return PlatformResult(ErrorCode::UNKNOWN_ERR, + "Unable to register metadata listener"); + } + + } else { // unset platform callbacks + + ret = mc_client_unset_playback_update_cb(handle_); + if (ret != MEDIA_CONTROLLER_ERROR_NONE) { + LOGGER(ERROR) << "Unable to unregister playback listener, error: " << ret; + return PlatformResult(ErrorCode::UNKNOWN_ERR, + "Unable to unregister playback listener"); + } + + ret = mc_client_unset_shuffle_mode_update_cb(handle_); if (ret != MEDIA_CONTROLLER_ERROR_NONE) { - LOGGER(ERROR) << "mc_client_get_metadata failed for field '" - << field.first << "', error: " << ret; + LOGGER(ERROR) << "Unable to unregister shuffle mode listener, error: " << ret; return PlatformResult(ErrorCode::UNKNOWN_ERR, - "Error getting metadata"); + "Unable to unregister shuffle mode listener"); } - if (!value) { - value = strdup(""); + + ret = mc_client_unset_repeat_mode_update_cb(handle_); + if (ret != MEDIA_CONTROLLER_ERROR_NONE) { + LOGGER(ERROR) << "Unable to unregister repeat mode listener, error: " << ret; + return PlatformResult(ErrorCode::UNKNOWN_ERR, + "Unable to unregister repeat mode listener"); } - (*metadata)[field.first] = picojson::value(std::string(value)); + ret = mc_client_unset_metadata_update_cb(handle_); + if (ret != MEDIA_CONTROLLER_ERROR_NONE) { + LOGGER(ERROR) << "Unable to unregister metadata listener, error: " << ret; + return PlatformResult(ErrorCode::UNKNOWN_ERR, + "Unable to unregister metadata listener"); + } } return PlatformResult(ErrorCode::NO_ERROR); +}; + +void MediaControllerClient::OnPlaybackUpdate(const char *server_name, + mc_playback_h playback, + void *user_data) { + + MediaControllerClient* client = static_cast(user_data); + + if (!client->playback_info_listener_) { + LOGGER(DEBUG) << "No playback info listener registered, skipping"; + return; + } + + // playback state + std::string state; + PlatformResult result = Types::ConvertPlaybackState(playback, &state); + if (!result) { + LOGGER(ERROR) << "ConvertPlaybackState failed, error: " << result.message(); + return; + } + + // playback position + double position; + result = Types::ConvertPlaybackPosition(playback, &position); + if (!result) { + LOGGER(ERROR) << "ConvertPlaybackPosition failed, error: " << result.message(); + return; + } + + picojson::value data = picojson::value(picojson::object()); + picojson::object& data_o = data.get(); + + data_o["action"] = picojson::value(std::string("onplaybackchanged")); + data_o["state"] = picojson::value(state); + data_o["position"] = picojson::value(position); + + client->playback_info_listener_(&data); +} + +void MediaControllerClient::OnShuffleModeUpdate(const char *server_name, + mc_shuffle_mode_e mode, + void *user_data) { + + MediaControllerClient* client = static_cast(user_data); + + if (!client->playback_info_listener_) { + LOGGER(DEBUG) << "No 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("onshufflemodechanged")); + data_o["mode"] = picojson::value(mode == SHUFFLE_MODE_ON); + + client->playback_info_listener_(&data); +} + +void MediaControllerClient::OnRepeatModeUpdate(const char *server_name, + mc_repeat_mode_e mode, + void *user_data) { + + MediaControllerClient* client = static_cast(user_data); + + if (!client->playback_info_listener_) { + LOGGER(DEBUG) << "No 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("onrepeatmodechanged")); + data_o["mode"] = picojson::value(mode == REPEAT_MODE_ON); + + client->playback_info_listener_(&data); +} + +void MediaControllerClient::OnMetadataUpdate(const char* server_name, + mc_metadata_h metadata_h, + void* user_data) { + + MediaControllerClient* client = static_cast(user_data); + + if (!client->playback_info_listener_) { + LOGGER(DEBUG) << "No playback info listener registered, skipping"; + return; + } + + picojson::value data = picojson::value(picojson::object()); + picojson::object& data_o = data.get(); + + picojson::value metadata = picojson::value(picojson::object()); + PlatformResult result = Types::ConvertMetadata( + metadata_h, &metadata.get()); + if (!result) { + LOGGER(ERROR) << "ConvertMetadata failed, error: " << result.message(); + return; + } + + data_o["action"] = picojson::value(std::string("onmetadatachanged")); + data_o["metadata"] = metadata; + + client->playback_info_listener_(&data); } } // namespace mediacontroller diff --git a/src/mediacontroller/mediacontroller_client.h b/src/mediacontroller/mediacontroller_client.h index 939b0ea..f904344 100644 --- a/src/mediacontroller/mediacontroller_client.h +++ b/src/mediacontroller/mediacontroller_client.h @@ -10,6 +10,8 @@ #include "common/platform_result.h" +#include "mediacontroller/mediacontroller_types.h" + namespace extension { namespace mediacontroller { @@ -26,10 +28,24 @@ class MediaControllerClient { common::PlatformResult GetMetadata(const std::string& server_name, picojson::object* metadata); + common::PlatformResult SetPlaybackInfoListener(JsonCallback callback); private: mc_client_h handle_; + JsonCallback playback_info_listener_; static bool FindServersCallback(const char* server_name, void* user_data); + static void OnPlaybackUpdate(const char *server_name, + mc_playback_h playback, + void *user_data); + static void OnShuffleModeUpdate(const char *server_name, + mc_shuffle_mode_e mode, + void *user_data); + static void OnRepeatModeUpdate(const char *server_name, + mc_repeat_mode_e mode, + void *user_data); + static void OnMetadataUpdate(const char* server_name, + mc_metadata_h metadata_h, + void* user_data); }; } // namespace mediacontroller diff --git a/src/mediacontroller/mediacontroller_instance.cc b/src/mediacontroller/mediacontroller_instance.cc index 7ec9e1f..1cb869c 100644 --- a/src/mediacontroller/mediacontroller_instance.cc +++ b/src/mediacontroller/mediacontroller_instance.cc @@ -4,13 +4,13 @@ #include "mediacontroller/mediacontroller_instance.h" -#include - #include "common/logger.h" #include "common/picojson.h" #include "common/platform_result.h" #include "common/task-queue.h" +#include "mediacontroller/mediacontroller_types.h" + namespace extension { namespace mediacontroller { @@ -322,7 +322,6 @@ void MediaControllerInstance::MediaControllerClientFindServers( CHECK_EXIST(args, "callbackId", out) auto search = [this, args]() -> void { - LOGGER(DEBUG) << "entered"; picojson::value response = picojson::value(picojson::object()); picojson::object& response_obj = response.get(); @@ -517,27 +516,43 @@ void MediaControllerInstance::MediaControllerServerInfoAddPlaybackInfoChangeList const picojson::value& args, picojson::object& out) { - // implement it + if (!client_) { + ReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, + "Client not initialized."), &out); + return; + } - // if success - // ReportSuccess(out); - // if error - // ReportError(out); + CHECK_EXIST(args, "listenerId", out) + + JsonCallback callback = [this, args](picojson::value* data) -> void { + + if (!data) { + LOGGER(ERROR) << "No data passed to json callback"; + return; + } + + picojson::object& request_o = data->get(); + request_o["listenerId"] = args.get("listenerId"); + + PostMessage(data->serialize().c_str()); + }; + + client_->SetPlaybackInfoListener(callback); + + ReportSuccess(out); } void MediaControllerInstance::MediaControllerServerInfoRemovePlaybackInfoChangeListener( const picojson::value& args, picojson::object& out) { - CHECK_EXIST(args, "watchId", out) - double watchId = args.get("watchId").get(); - - // implement it + if (!client_) { + ReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, + "Client not initialized."), &out); + return; + } - // if success - // ReportSuccess(out); - // if error - // ReportError(out); + client_->SetPlaybackInfoListener(nullptr); } #undef CHECK_EXIST diff --git a/src/mediacontroller/mediacontroller_server.cc b/src/mediacontroller/mediacontroller_server.cc index 434d8ab..5ecd7aa 100644 --- a/src/mediacontroller/mediacontroller_server.cc +++ b/src/mediacontroller/mediacontroller_server.cc @@ -18,7 +18,6 @@ MediaControllerServer::MediaControllerServer() : handle_(nullptr) { } MediaControllerServer::~MediaControllerServer() { - LOGGER(DEBUG) << "entered"; if (handle_) { int ret = mc_server_destroy(handle_); diff --git a/src/mediacontroller/mediacontroller_types.cc b/src/mediacontroller/mediacontroller_types.cc index 6b5c444..62bf01b 100644 --- a/src/mediacontroller/mediacontroller_types.cc +++ b/src/mediacontroller/mediacontroller_types.cc @@ -4,7 +4,11 @@ #include "mediacontroller/mediacontroller_types.h" +#include + +#include "common/logger.h" #include "common/platform_result.h" +#include "common/scope_exit.h" namespace extension { namespace mediacontroller { @@ -114,5 +118,83 @@ PlatformResult Types::PlatformEnumToString(const std::string& type, return PlatformResult(ErrorCode::INVALID_VALUES_ERR, message); } +PlatformResult Types::ConvertPlaybackState(mc_playback_h playback_h, + std::string* state) { + int ret; + mc_playback_states_e state_e; + ret = mc_client_get_playback_state(playback_h, &state_e); + if (ret != MEDIA_CONTROLLER_ERROR_NONE) { + LOGGER(ERROR) << "mc_client_get_playback_state failed, error: " << ret; + return PlatformResult(ErrorCode::UNKNOWN_ERR, + "Error getting playback state"); + } + if (state_e == MEDIA_PLAYBACK_STATE_NONE) { + state_e = MEDIA_PLAYBACK_STATE_STOPPED; + } + + PlatformResult result = Types::PlatformEnumToString( + Types::kMediaControllerPlaybackState, + static_cast(state_e), state); + if (!result) { + LOGGER(ERROR) << "PlatformEnumToString failed, error: " << result.message(); + return result; + } + + return PlatformResult(ErrorCode::NO_ERROR); +} + +PlatformResult Types::ConvertPlaybackPosition(mc_playback_h playback_h, + double* position) { + int ret; + + unsigned long long pos; + ret = mc_client_get_playback_position(playback_h, &pos); + if (ret != MEDIA_CONTROLLER_ERROR_NONE) { + LOGGER(ERROR) << "mc_client_get_playback_position failed, error: " << ret; + return PlatformResult(ErrorCode::UNKNOWN_ERR, + "Error getting playback position"); + } + + *position = static_cast(pos); + + return PlatformResult(ErrorCode::NO_ERROR); +} + +PlatformResult Types::ConvertMetadata(mc_metadata_h metadata_h, + picojson::object* metadata) { + std::map metadata_fields; + PlatformResult result = GetPlatformEnumMap( + Types::kMediaControllerMetadataAttribute, &metadata_fields); + if (!result) { + LOGGER(ERROR) << "GetPlatformEnumMap failed, error: " << result.message(); + return result; + } + + char* value; + SCOPE_EXIT { + free(value); + }; + + int ret; + for (auto& field : metadata_fields) { + ret = mc_client_get_metadata(metadata_h, + static_cast(field.second), + &value); + if (ret != MEDIA_CONTROLLER_ERROR_NONE) { + LOGGER(ERROR) << "mc_client_get_metadata failed for field '" + << field.first << "', error: " << ret; + return PlatformResult(ErrorCode::UNKNOWN_ERR, + "Error getting metadata"); + } + if (NULL == value) { + value = strdup(""); + } + + (*metadata)[field.first] = picojson::value(std::string(value)); + } + + return PlatformResult(ErrorCode::NO_ERROR); +} + } // namespace mediacontroller } // namespace extension diff --git a/src/mediacontroller/mediacontroller_types.h b/src/mediacontroller/mediacontroller_types.h index 1a8209c..72d1a74 100644 --- a/src/mediacontroller/mediacontroller_types.h +++ b/src/mediacontroller/mediacontroller_types.h @@ -5,6 +5,7 @@ #ifndef MEDIACONTROLLER_MEDIACONTROLLER_TYPES_H_ #define MEDIACONTROLLER_MEDIACONTROLLER_TYPES_H_ +#include #include #include #include @@ -16,6 +17,7 @@ namespace mediacontroller { typedef std::map> PlatformEnumMap; typedef std::map> PlatformEnumReverseMap; +typedef std::function JsonCallback; class Types { public: @@ -34,6 +36,13 @@ class Types { int value, std::string* platform_str); + static common::PlatformResult ConvertPlaybackState(mc_playback_h playback_h, + std::string* state); + static common::PlatformResult ConvertPlaybackPosition(mc_playback_h playback_h, + double* position); + static common::PlatformResult ConvertMetadata(mc_metadata_h metadata_h, + picojson::object* metadata); + private: static const PlatformEnumMap platform_enum_map_; // TODO(r.galka) can be replaced by Boost.Bimap