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));
});
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() {
throw native_.getErrorObject(result);
}
- var client = new MediaControllerClient(native_.getResultObject(result));
- return client;
+ return new MediaControllerClient(native_.getResultObject(result));
};
MediaControllerManager.prototype.createServer = function() {
throw native_.getErrorObject(result);
}
- var server = new MediaControllerServer(native_.getResultObject(result));
- return server;
+ return new MediaControllerServer(native_.getResultObject(result));
};
if (data instanceof Object) {
for (var prop in data) {
- if (this.hasOwnProperty(prop)) {
+ if (data.hasOwnProperty(prop) && this.hasOwnProperty(prop)) {
this[prop] = data[prop];
}
}
};
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);
}
}
MediaControllerClient::~MediaControllerClient() {
- LOGGER(DEBUG) << "entered";
-
if (handle_) {
int ret = mc_client_destroy(handle_);
if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
}
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;
const std::string& latest_name = latest_server.get("name").get<std::string>();
// update current server state in list
- for (picojson::array::iterator it; it != servers->end(); ++it) {
- picojson::object& server = it->get<picojson::object>();
- if (it->get("name").get<std::string>() == latest_name) {
+ for (auto& it : *servers) {
+ picojson::object& server = it.get<picojson::object>();
+ if (server["name"].get<std::string>() == latest_name) {
server["state"] = latest_server.get("state");
break;
}
bool MediaControllerClient::FindServersCallback(const char* server_name,
void* user_data) {
- LOGGER(DEBUG) << "entered";
picojson::array* servers = static_cast<picojson::array*>(user_data);
};
// 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<int>(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
}
// fill return object
- (*playback_info)["state"] = picojson::value(state_str);
- (*playback_info)["position"] = picojson::value(static_cast<double>(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;
PlatformResult MediaControllerClient::GetMetadata(
const std::string& server_name,
picojson::object* metadata) {
- LOGGER(DEBUG) << "entered";
int ret;
mc_client_destroy_metadata(metadata_h);
};
- std::map<std::string, int> 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<mc_meta_e>(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<MediaControllerClient*>(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<picojson::object>();
+
+ 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<MediaControllerClient*>(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::object>();
+
+ 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<MediaControllerClient*>(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::object>();
+
+ 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<MediaControllerClient*>(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::object>();
+
+ picojson::value metadata = picojson::value(picojson::object());
+ PlatformResult result = Types::ConvertMetadata(
+ metadata_h, &metadata.get<picojson::object>());
+ 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
#include "mediacontroller/mediacontroller_types.h"
+#include <media_controller_client.h>
+
+#include "common/logger.h"
#include "common/platform_result.h"
+#include "common/scope_exit.h"
namespace extension {
namespace mediacontroller {
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<int>(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<double>(pos);
+
+ return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult Types::ConvertMetadata(mc_metadata_h metadata_h,
+ picojson::object* metadata) {
+ std::map<std::string, int> 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<mc_meta_e>(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