<a href="content.html"><div class="block">content</div></a>
<a href="download.html"><div class="block">download</div></a>
<a href="filesystem.html"><div class="block">filesystem</div></a>
+<a href="media_renderer.html"><div class="block">Media Renderer</div></a>
<a href="mediaserver.html"><div class="block">mediaserver</div></a>
<a href="network_bearer_selection.html"><div class="block">network bearer selection</div></a>
<a href="notification.html"><div class="block">notification</div></a>
--- /dev/null
+<html>
+<head>
+<title>MediaRenderer example</title>
+</head>
+<body>
+
+<button onclick='scanNetwork()'>Scan for media renderers</button>
+
+<div id='rendererContainer'></div>
+<script>
+navigator.mediaRenderer.addEventListener('rendererfound', onRendererFound);
+navigator.mediaRenderer.addEventListener('rendererlost', onRendererLost);
+
+var renderers = {};
+
+var mute=false;
+var speed=1.0;
+var track=1;
+var volume=1.0;
+function scanNetwork() {
+ emptyContainer('rendererContainer');
+ navigator.mediaRenderer.scanNetwork();
+}
+
+function emptyContainer(id) {
+ var container = document.getElementById(id);
+ while(container && container.hasChildNodes())
+ container.removeChild(container.lastChild);
+}
+
+function openURI(id) {
+ renderers[id].openURI("/home/sragavan/video.avi", "");
+}
+
+function prefetchURI(id) {
+ renderers[id].prefetchURI("/home/sragavan/video1.mp4", "");
+}
+
+function cancel(id) {
+ renderers[id].cancel();
+}
+
+function play(id) {
+ renderers[id].controller.play();
+}
+
+function pause(id) {
+ renderers[id].controller.pause();
+}
+
+function stop(id) {
+ renderers[id].controller.stop();
+}
+
+function next(id) {
+ renderers[id].controller.next();
+}
+
+function previous(id) {
+ renderers[id].controller.previous();
+}
+
+function mute(id) {
+ mute = !mute;
+ renderers[id].controller.mute(mute);
+}
+
+function setSpeed(id) {
+ if (speed > 0.9)
+ speed = 0.5;
+ else
+ speed = 1.0;
+ renderers[id].controller.setSpeed(speed);
+}
+
+function setVolume(id) {
+ if (volume > 0.9)
+ volume = 0.5;
+ else
+ volume = 1.0;
+ renderers[id].controller.setVolume(volume);
+}
+
+function gotoTrack(id) {
+ if (track == 1)
+ track = 2;
+ else
+ track = 1;
+ var renderer = renderers[id];
+ var controller = renderer.controller;
+ renderers[id].controller.gotoTrack(track);
+}
+
+function addButton(container, event, name, action) {
+ var button = document.createElement('button');
+ button.innerHTML = name;
+ button.id = event.renderer.id;
+ button.setAttribute('onclick', action);
+ container.appendChild(button);
+}
+
+function onRendererFound(event) {
+ var container = document.getElementById('rendererContainer');
+ var rendererControls = document.createElement('div');
+ renderers[event.renderer.id] = event.renderer;
+ rendererControls.id = event.renderer.id;
+ rendererControls.innerHTML = 'Renderer: ' + event.renderer.friendlyName;
+ container.appendChild(rendererControls);
+
+ addButton(rendererControls, event, 'Open', 'openURI(this.id)');
+ addButton(rendererControls, event, 'Prefetch', 'prefetchURI(this.id)');
+ addButton(rendererControls, event, 'Cancel', 'cancel(this.id)');
+ addButton(rendererControls, event, 'Play', 'play(this.id)');
+ addButton(rendererControls, event, 'Pause', 'pause(this.id)');
+ addButton(rendererControls, event, 'Stop', 'stop(this.id)');
+ addButton(rendererControls, event, 'Next', 'next(this.id)');
+ addButton(rendererControls, event, 'Previous', 'openURI(this.id)');
+ addButton(rendererControls, event, 'Mute', 'mute(this.id)');
+ addButton(rendererControls, event, 'setSpeed', 'setSpeed(this.id)');
+ addButton(rendererControls, event, 'setVolume', 'setVolume(this.id)');
+ addButton(rendererControls, event, 'gotoTrack', 'gotoTrack(this.id)');
+
+}
+
+function onRendererLost(event) {
+ var button = document.getElementById(event.id);
+ document.removeChild(button);
+}
+
+</script>
+
+</body>
+</html>
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_RENDERER_CALLBACKS_H_
+#define MEDIA_RENDERER_CALLBACKS_H_
+
+struct CallbackData {
+ CallbackData(void* data, double async_id)
+ : data_(data), async_id_(async_id) {}
+ void* data_;
+ double async_id_;
+};
+
+#define CALLBACK_METHOD(METHOD, SENDER, ARG0, DATA_TYPE) \
+ static void METHOD ## CallBack(SENDER sender, ARG0 res, gpointer userdata) { \
+ reinterpret_cast<DATA_TYPE*>(userdata)->METHOD(sender, res); \
+ } \
+ \
+ void METHOD(SENDER, ARG0);
+
+#define CALLBACK_METHOD_WITH_ID(METHOD, SENDER, ARG0, DATA_TYPE) \
+ static void METHOD ## CallBack(SENDER sender, ARG0 res, gpointer userdata) { \
+ CallbackData* d = static_cast<CallbackData*>(userdata); \
+ DATA_TYPE* data = reinterpret_cast<DATA_TYPE*>(d->data_); \
+ if (!data->IsCancelled()) \
+ data->METHOD(sender, res, d->async_id_); \
+ delete d; \
+ } \
+ \
+ void METHOD(SENDER, ARG0, double async_call_id);
+
+#endif // MEDIA_RENDERER_CALLBACKS_H_
--- /dev/null
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<!-- GDBus 2.38.2 -->
+<node>
+ <interface name="com.intel.dLeynaRenderer.Manager">
+ <method name="GetVersion">
+ <arg type="s" name="Version" direction="out">
+ </arg>
+ </method>
+ <method name="Release">
+ </method>
+ <method name="GetRenderers">
+ <arg type="ao" name="Renderers" direction="out">
+ </arg>
+ </method>
+ <method name="Rescan">
+ </method>
+ <signal name="FoundRenderer">
+ <arg type="o" name="Path">
+ </arg>
+ </signal>
+ <signal name="LostRenderer">
+ <arg type="o" name="Path">
+ </arg>
+ </signal>
+ <property type="b" name="NeverQuit" access="readwrite">
+ </property>
+ <property type="as" name="WhiteListEntries" access="readwrite">
+ </property>
+ <property type="b" name="WhiteListEnabled" access="readwrite">
+ </property>
+ </interface>
+</node>
--- /dev/null
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<!-- GDBus 2.38.2 -->
+<node>
+ <interface name="com.intel.dLeynaRenderer.PushHost">
+ <method name="HostFile">
+ <arg type="s" name="Path" direction="in">
+ </arg>
+ <arg type="s" name="Uri" direction="out">
+ </arg>
+ </method>
+ <method name="RemoveFile">
+ <arg type="s" name="Path" direction="in">
+ </arg>
+ </method>
+ </interface>
+</node>
--- /dev/null
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<!-- GDBus 2.38.2 -->
+<node>
+ <interface name="com.intel.dLeynaRenderer.RendererDevice">
+ <method name="Cancel">
+ </method>
+ <method name="GetIcon">
+ <arg type="s" name="RequestedMimeType" direction="in">
+ </arg>
+ <arg type="s" name="Resolution" direction="in">
+ </arg>
+ <arg type="ay" name="Bytes" direction="out">
+ </arg>
+ <arg type="s" name="MimeType" direction="out">
+ </arg>
+ </method>
+ <property type="as" name="DeviceClasses" access="read">
+ </property>
+ <property type="s" name="DeviceType" access="read">
+ </property>
+ <property type="s" name="UDN" access="read">
+ </property>
+ <property type="s" name="FriendlyName" access="read">
+ </property>
+ <property type="s" name="IconURL" access="read">
+ </property>
+ <property type="s" name="Manufacturer" access="read">
+ </property>
+ <property type="s" name="ManufacturerUrl" access="read">
+ </property>
+ <property type="s" name="ModelDescription" access="read">
+ </property>
+ <property type="s" name="ModelName" access="read">
+ </property>
+ <property type="s" name="ModelNumber" access="read">
+ </property>
+ <property type="s" name="SerialNumber" access="read">
+ </property>
+ <property type="s" name="PresentationURL" access="read">
+ </property>
+ <property type="s" name="ProtocolInfo" access="read">
+ </property>
+ </interface>
+</node>
+
--- /dev/null
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<!-- GDBus 2.38.2 -->
+<node>
+ <interface name="org.mpris.MediaPlayer2.Player">
+ <method name="Play">
+ </method>
+ <method name="Pause">
+ </method>
+ <method name="PlayPause">
+ </method>
+ <method name="Stop">
+ </method>
+ <method name="Next">
+ </method>
+ <method name="Previous">
+ </method>
+ <method name="OpenUri">
+ <arg type="s" name="Uri" direction="in">
+ </arg>
+ </method>
+ <method name="OpenUriEx">
+ <arg type="s" name="Uri" direction="in">
+ </arg>
+ <arg type="s" name="Metadata" direction="in">
+ </arg>
+ </method>
+ <method name="OpenNextUri">
+ <arg type="s" name="Uri" direction="in">
+ </arg>
+ <arg type="s" name="Metadata" direction="in">
+ </arg>
+ </method>
+ <method name="SetUri">
+ <arg type="s" name="Uri" direction="in">
+ </arg>
+ <arg type="s" name="Metadata" direction="in">
+ </arg>
+ </method>
+ <method name="Seek">
+ <arg type="x" name="offset" direction="in">
+ </arg>
+ </method>
+ <method name="ByteSeek">
+ <arg type="x" name="offset" direction="in">
+ </arg>
+ </method>
+ <method name="SetPosition">
+ <arg type="o" name="trackid" direction="in">
+ </arg>
+ <arg type="x" name="position" direction="in">
+ </arg>
+ </method>
+ <method name="SetBytePosition">
+ <arg type="o" name="trackid" direction="in">
+ </arg>
+ <arg type="x" name="byte_position" direction="in">
+ </arg>
+ </method>
+ <method name="GotoTrack">
+ <arg type="u" name="TrackNumber" direction="in">
+ </arg>
+ </method>
+ <property type="s" name="PlaybackStatus" access="read">
+ </property>
+ <property type="d" name="Rate" access="readwrite">
+ </property>
+ <property type="d" name="MinimumRate" access="read">
+ </property>
+ <property type="d" name="MaximumRate" access="read">
+ </property>
+ <property type="ad" name="TransportPlaySpeeds" access="read">
+ </property>
+ <property type="d" name="Volume" access="readwrite">
+ </property>
+ <property type="b" name="CanPlay" access="read">
+ </property>
+ <property type="b" name="CanSeek" access="read">
+ </property>
+ <property type="b" name="CanByteSeek" access="read">
+ </property>
+ <property type="b" name="CanControl" access="read">
+ </property>
+ <property type="b" name="CanPause" access="read">
+ </property>
+ <property type="b" name="CanGoNext" access="read">
+ </property>
+ <property type="b" name="CanGoPrevious" access="read">
+ </property>
+ <property type="x" name="Position" access="read">
+ </property>
+ <property type="x" name="BytePosition" access="read">
+ </property>
+ <property type="a{sv}" name="Metadata" access="read">
+ </property>
+ <property type="u" name="CurrentTrack" access="read">
+ </property>
+ <property type="u" name="NumberOfTracks" access="read">
+ </property>
+ <property type="b" name="Mute" access="readwrite">
+ </property>
+ </interface>
+</node>
--- /dev/null
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<!-- GDBus 2.38.2 -->
+<node>
+ <interface name="org.mpris.MediaPlayer2">
+ <method name="Raise">
+ </method>
+ <method name="Quit">
+ </method>
+ <property type="b" name="CanQuit" access="read">
+ </property>
+ <property type="b" name="CanRaise" access="read">
+ </property>
+ <property type="b" name="CanSetFullscreen" access="read">
+ </property>
+ <property type="b" name="HasTrackList" access="read">
+ </property>
+ <property type="s" name="Identity" access="read">
+ </property>
+ <property type="as" name="SupportedUriSchemes" access="read">
+ </property>
+ <property type="as" name="SupportedMimeTypes" access="read">
+ </property>
+ </interface>
+</node>
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media_renderer/media_renderer.h"
+
+#include <map>
+#include "common/extension.h"
+
+namespace {
+
+const gchar kdLeynaRendererInterfaceName[] = "com.intel.dleyna-renderer";
+const gchar kdLeynaPushHostInterfaceName[] = "com.intel.dleyna-renderer";
+const gchar kMprisPlayerInterfaceName[] = "com.intel.dleyna-renderer";
+
+} // namespace
+
+static picojson::value toJSONValue(const gchar* value) {
+ return value ? picojson::value(value) : picojson::value();
+}
+
+static picojson::value toJSONValueArray(GVariant* values) {
+ picojson::array array;
+ GVariantIter iter;
+ GVariant* child;
+ gint value;
+
+ g_variant_iter_init(&iter, values);
+ while (g_variant_iter_next(&iter, "{d}", &value))
+ array.push_back(picojson::value(static_cast<double>(value)));
+ return picojson::value(array);
+}
+
+MediaRenderer::MediaRenderer(common::Instance* instance,
+ const std::string& object_path)
+ : instance_(instance),
+ rendererdevice_proxy_(0),
+ mediaplayer2_proxy_(0),
+ mprisplayer_proxy_(0),
+ object_path_(object_path),
+ cancellable_(g_cancellable_new()) {
+ GError* gerror = NULL;
+
+ rendererdevice_proxy_ = dleyna_renderer_device_proxy_new_for_bus_sync(
+ G_BUS_TYPE_SESSION,
+ G_DBUS_PROXY_FLAGS_NONE,
+ kdLeynaRendererInterfaceName,
+ object_path.c_str(),
+ NULL,
+ &gerror);
+
+ if (gerror) {
+ g_error_free(gerror);
+ return;
+ }
+
+ pushhost_proxy_ = dleyna_push_host_proxy_new_for_bus_sync(
+ G_BUS_TYPE_SESSION,
+ G_DBUS_PROXY_FLAGS_NONE,
+ kdLeynaPushHostInterfaceName,
+ object_path.c_str(),
+ NULL,
+ &gerror);
+
+ if (gerror) {
+ g_error_free(gerror);
+ return;
+ }
+
+ mprisplayer_proxy_ = mprismediaplayer2_player_proxy_new_for_bus_sync(
+ G_BUS_TYPE_SESSION,
+ G_DBUS_PROXY_FLAGS_NONE,
+ kMprisPlayerInterfaceName,
+ object_path.c_str(),
+ NULL,
+ &gerror);
+
+ if (gerror) {
+ g_error_free(gerror);
+ return;
+ }
+}
+
+MediaRenderer::~MediaRenderer() {
+ g_object_unref(rendererdevice_proxy_);
+ g_object_unref(pushhost_proxy_);
+ g_object_unref(mprisplayer_proxy_);
+}
+
+picojson::value MediaRenderer::ToJSON() {
+ if (object_.size())
+ return picojson::value(object_);
+
+ object_["id"] = picojson::value(object_path_);
+ object_["friendlyName"] = toJSONValue(
+ dleyna_renderer_device_get_friendly_name(rendererdevice_proxy_));
+ object_["manufacturer"] = toJSONValue(
+ dleyna_renderer_device_get_manufacturer(rendererdevice_proxy_));
+ object_["manufacturerURL"] = toJSONValue(
+ dleyna_renderer_device_get_manufacturer_url(rendererdevice_proxy_));
+ object_["modelDescription"] = toJSONValue(
+ dleyna_renderer_device_get_model_description(rendererdevice_proxy_));
+ object_["modelName"] = toJSONValue(
+ dleyna_renderer_device_get_model_name(rendererdevice_proxy_));
+ object_["modelNumber"] = toJSONValue(
+ dleyna_renderer_device_get_model_number(rendererdevice_proxy_));
+ object_["serialNumber"] = toJSONValue(
+ dleyna_renderer_device_get_serial_number(rendererdevice_proxy_));
+ object_["UDN"] = toJSONValue(
+ dleyna_renderer_device_get_udn(rendererdevice_proxy_));
+ object_["presentationURL"] = toJSONValue(
+ dleyna_renderer_device_get_presentation_url(rendererdevice_proxy_));
+ object_["iconURL"] = toJSONValue(
+ dleyna_renderer_device_get_icon_url(rendererdevice_proxy_));
+ object_["deviceType"] = toJSONValue(
+ dleyna_renderer_device_get_device_type(rendererdevice_proxy_));
+ object_["protocolInfo"] = toJSONValue(
+ dleyna_renderer_device_get_protocol_info(rendererdevice_proxy_));
+
+ picojson::value::object controller_object;
+ controller_object["id"] = picojson::value(object_path_);
+ controller_object["playbackStatus"] = toJSONValue(
+ mprismediaplayer2_player_get_playback_status(mprisplayer_proxy_));
+ controller_object["muted"] = picojson::value(static_cast<bool>
+ (mprismediaplayer2_player_get_mute(mprisplayer_proxy_)));
+ controller_object["volume"] = picojson::value(
+ mprismediaplayer2_player_get_volume(mprisplayer_proxy_));
+ controller_object["track"] = picojson::value(static_cast<double>
+ (mprismediaplayer2_player_get_current_track(mprisplayer_proxy_)));
+ controller_object["speed"] = picojson::value(
+ mprismediaplayer2_player_get_rate(mprisplayer_proxy_));
+
+ object_["controller"] = picojson::value(controller_object);
+
+ return picojson::value(object_);
+}
+
+// MediaRenderer methods
+void MediaRenderer::OpenURI(const picojson::value& value) {
+ double async_call_id = value.get("asyncCallId").get<double>();
+
+ if (!mprisplayer_proxy_) {
+ PostError(async_call_id);
+ return;
+ }
+
+ if (!pushhost_proxy_) {
+ PostError(async_call_id);
+ return;
+ }
+
+ dleyna_push_host_call_host_file(
+ pushhost_proxy_,
+ value.get("mediaURI").to_str().c_str(),
+ cancellable_,
+ OnHostFileCallBack,
+ new CallbackData(this, async_call_id));
+}
+
+void MediaRenderer::PrefetchURI(const picojson::value& value) {
+ double async_call_id = value.get("asyncCallId").get<double>();
+
+ if (!mprisplayer_proxy_) {
+ PostError(async_call_id);
+ return;
+ }
+
+ mprismediaplayer2_player_call_open_next_uri(
+ mprisplayer_proxy_,
+ value.get("mediaURI").to_str().c_str(),
+ value.get("metaData").to_str().c_str(),
+ cancellable_,
+ OnPrefetchURICallBack,
+ new CallbackData(this, async_call_id));
+}
+
+void MediaRenderer::Cancel(const picojson::value& value) {
+ double async_call_id = value.get("asyncCallId").get<double>();
+
+ if (!rendererdevice_proxy_) {
+ PostError(async_call_id);
+ return;
+ }
+
+ dleyna_renderer_device_call_cancel(
+ rendererdevice_proxy_,
+ cancellable_,
+ OnCancelCallBack,
+ new CallbackData(this, async_call_id));
+}
+
+bool MediaRenderer::IsCancelled() const {
+ return g_cancellable_is_cancelled(cancellable_);
+}
+
+// MediaController methods
+void MediaRenderer::Play(const picojson::value& value) {
+ double async_call_id = value.get("asyncCallId").get<double>();
+
+ if (!mprisplayer_proxy_) {
+ PostError(async_call_id);
+ return;
+ }
+
+ mprismediaplayer2_player_call_play(
+ mprisplayer_proxy_,
+ cancellable_,
+ OnPlayCallBack,
+ new CallbackData(this, async_call_id));
+}
+
+void MediaRenderer::Pause(const picojson::value& value) {
+ double async_call_id = value.get("asyncCallId").get<double>();
+
+ if (!mprisplayer_proxy_) {
+ PostError(async_call_id);
+ return;
+ }
+
+ mprismediaplayer2_player_call_pause(
+ mprisplayer_proxy_,
+ cancellable_,
+ OnPauseCallBack,
+ new CallbackData(this, async_call_id));
+}
+
+void MediaRenderer::Stop(const picojson::value& value) {
+ double async_call_id = value.get("asyncCallId").get<double>();
+
+ if (!mprisplayer_proxy_) {
+ PostError(async_call_id);
+ return;
+ }
+
+ mprismediaplayer2_player_call_stop(
+ mprisplayer_proxy_,
+ cancellable_,
+ OnStopCallBack,
+ new CallbackData(this, async_call_id));
+}
+
+void MediaRenderer::Next(const picojson::value& value) {
+ double async_call_id = value.get("asyncCallId").get<double>();
+
+ if (!mprisplayer_proxy_) {
+ PostError(async_call_id);
+ return;
+ }
+
+ mprismediaplayer2_player_call_next(
+ mprisplayer_proxy_,
+ cancellable_,
+ OnNextCallBack,
+ new CallbackData(this, async_call_id));
+}
+
+void MediaRenderer::Previous(const picojson::value& value) {
+ double async_call_id = value.get("asyncCallId").get<double>();
+
+ if (!mprisplayer_proxy_) {
+ PostError(async_call_id);
+ return;
+ }
+
+ mprismediaplayer2_player_call_previous(
+ mprisplayer_proxy_,
+ cancellable_,
+ OnPreviousCallBack,
+ new CallbackData(this, async_call_id));
+}
+
+void MediaRenderer::Mute(const picojson::value& value) {
+ double async_call_id = value.get("asyncCallId").get<double>();
+
+ if (!mprisplayer_proxy_) {
+ PostError(async_call_id);
+ return;
+ }
+
+ mprismediaplayer2_player_set_mute(
+ mprisplayer_proxy_,
+ (gboolean)value.get("mute").get<double>());
+ PostResult("setMuteCompleted", value.get("asyncCallId").get<double>());
+}
+
+void MediaRenderer::SetSpeed(const picojson::value& value) {
+ double async_call_id = value.get("asyncCallId").get<double>();
+
+ if (!mprisplayer_proxy_) {
+ PostError(async_call_id);
+ return;
+ }
+
+ mprismediaplayer2_player_set_rate(
+ mprisplayer_proxy_,
+ value.get("speed").get<double>());
+ PostResult("setSpeedCompleted", value.get("asyncCallId").get<double>());
+}
+
+void MediaRenderer::SetVolume(const picojson::value& value) {
+ double async_call_id = value.get("asyncCallId").get<double>();
+
+ if (!mprisplayer_proxy_) {
+ PostError(async_call_id);
+ return;
+ }
+ mprismediaplayer2_player_set_rate(
+ mprisplayer_proxy_,
+ value.get("volume").get<double>());
+ PostResult("setVolumeCompleted", value.get("asyncCallId").get<double>());
+}
+
+void MediaRenderer::GotoTrack(const picojson::value& value) {
+ double async_call_id = value.get("asyncCallId").get<double>();
+
+ if (!mprisplayer_proxy_) {
+ PostError(async_call_id);
+ return;
+ }
+
+ mprismediaplayer2_player_call_goto_track(
+ mprisplayer_proxy_,
+ (guint) value.get("track").get<double>(),
+ cancellable_,
+ OnGoToTrackCallBack,
+ new CallbackData(this, async_call_id));
+}
+
+void MediaRenderer::PostResult(
+ const std::string& completed_operation,
+ double async_operation_id) {
+ picojson::value::object object;
+ object["cmd"] = picojson::value(completed_operation);
+ object["asyncCallId"] = picojson::value(async_operation_id);
+ picojson::value value(object);
+ instance_->PostMessage(value.serialize().c_str());
+}
+
+void MediaRenderer::PostError(double async_operation_id) {
+ picojson::value::object object;
+ object["cmd"] = picojson::value("asyncCallError");
+ object["asyncCallId"] = picojson::value(async_operation_id);
+ picojson::value value(object);
+ instance_->PostMessage(value.serialize().c_str());
+}
+
+void MediaRenderer::OnOpenURI(
+ GObject* source_object,
+ GAsyncResult* res,
+ double async_id) {
+ GError* gerror = NULL;
+
+ if (mprismediaplayer2_player_call_open_uri_ex_finish(
+ reinterpret_cast<mprismediaplayer2Player*>(source_object),
+ res,
+ &gerror))
+ PostResult("openURICompleted", async_id);
+ else
+ PostError(async_id);
+
+ if (gerror)
+ g_error_free(gerror);
+}
+
+void MediaRenderer::OnHostFile(
+ GObject* source_object,
+ GAsyncResult* res,
+ double async_id) {
+ GError* gerror = NULL;
+ gchar* uploaded_path = NULL;
+
+ if (dleyna_push_host_call_host_file_finish(
+ reinterpret_cast<dleynaPushHost*>(source_object),
+ &uploaded_path,
+ res,
+ &gerror)) {
+ mprismediaplayer2_player_call_open_uri_ex(
+ mprisplayer_proxy_,
+ uploaded_path,
+ uploaded_path,
+ cancellable_,
+ OnOpenURICallBack,
+ new CallbackData(this, async_id));
+ } else {
+ PostError(async_id);
+ }
+
+ if (gerror)
+ g_error_free(gerror);
+}
+
+void MediaRenderer::OnPrefetchURI(
+ GObject* source_object,
+ GAsyncResult* res,
+ double async_id) {
+ GError* gerror = NULL;
+ GVariant* objects;
+ guint totalItems;
+
+ if (mprismediaplayer2_player_call_open_next_uri_finish(
+ reinterpret_cast<mprismediaplayer2Player*>(source_object),
+ res,
+ &gerror))
+ PostResult("prefetchURICompleted", async_id);
+ else
+ PostError(async_id);
+
+ if (gerror)
+ g_error_free(gerror);
+}
+
+void MediaRenderer::OnCancel(
+ GObject* source_object,
+ GAsyncResult* res,
+ double async_id) {
+ GError* gerror = NULL;
+ gchar** out_Paths = NULL;
+
+ if (dleyna_renderer_device_call_cancel_finish(
+ reinterpret_cast<dleynaRendererDevice*>(source_object),
+ res,
+ &gerror))
+ PostResult("cancelCompleted", async_id);
+ else
+ PostError(async_id);
+
+ if (gerror)
+ g_error_free(gerror);
+}
+
+void MediaRenderer::OnPlay(
+ GObject* source_object,
+ GAsyncResult* res,
+ double async_id) {
+ GError* gerror = NULL;
+ gchar** out_Paths = NULL;
+
+ if (mprismediaplayer2_player_call_play_finish(
+ reinterpret_cast<mprismediaplayer2Player*>(source_object),
+ res,
+ &gerror))
+ PostResult("playCompleted", async_id);
+ else
+ PostError(async_id);
+
+ if (gerror)
+ g_error_free(gerror);
+}
+
+void MediaRenderer::OnPause(
+ GObject* source_object,
+ GAsyncResult* res,
+ double async_id) {
+ GError* gerror = NULL;
+ gchar** out_Paths = NULL;
+
+ if (mprismediaplayer2_player_call_pause_finish(
+ reinterpret_cast<mprismediaplayer2Player*>(source_object),
+ res,
+ &gerror))
+ PostResult("pauseCompleted", async_id);
+ else
+ PostError(async_id);
+
+ if (gerror)
+ g_error_free(gerror);
+}
+
+void MediaRenderer::OnStop(
+ GObject* source_object,
+ GAsyncResult* res,
+ double async_id) {
+ GError* gerror = NULL;
+ gchar** out_Paths = NULL;
+
+ if (mprismediaplayer2_player_call_stop_finish(
+ reinterpret_cast<mprismediaplayer2Player*>(source_object),
+ res,
+ &gerror))
+ PostResult("stopCompleted", async_id);
+ else
+ PostError(async_id);
+
+ if (gerror)
+ g_error_free(gerror);
+}
+
+void MediaRenderer::OnNext(
+ GObject* source_object,
+ GAsyncResult* res,
+ double async_id) {
+ GError* gerror = NULL;
+ gchar** out_Paths = NULL;
+
+ if (mprismediaplayer2_player_call_next_finish(
+ reinterpret_cast<mprismediaplayer2Player*>(source_object),
+ res,
+ &gerror))
+ PostResult("nextCompleted", async_id);
+ else
+ PostError(async_id);
+
+ if (gerror)
+ g_error_free(gerror);
+}
+
+void MediaRenderer::OnPrevious(
+ GObject* source_object,
+ GAsyncResult* res,
+ double async_id) {
+ GError* gerror = NULL;
+ gchar** out_Paths = NULL;
+
+ if (mprismediaplayer2_player_call_previous_finish(
+ reinterpret_cast<mprismediaplayer2Player*>(source_object),
+ res,
+ &gerror))
+ PostResult("previousCompleted", async_id);
+ else
+ PostError(async_id);
+
+ if (gerror)
+ g_error_free(gerror);
+}
+
+void MediaRenderer::OnGoToTrack(
+ GObject* source_object,
+ GAsyncResult* res,
+ double async_id) {
+ GError* gerror = NULL;
+ gchar** out_Paths = NULL;
+
+ if (mprismediaplayer2_player_call_goto_track_finish(
+ reinterpret_cast<mprismediaplayer2Player*>(source_object),
+ res,
+ &gerror))
+ PostResult("gotoTrackCompleted", async_id);
+ else
+ PostError(async_id);
+
+ if (gerror)
+ g_error_free(gerror);
+}
--- /dev/null
+{
+ 'includes':[
+ '../common/common.gypi',
+ ],
+ 'variables': {
+ 'gen_dbus_proxy_path': '<(SHARED_INTERMEDIATE_DIR)/media_renderer',
+ },
+ 'targets': [
+ {
+ 'target_name': 'tizen_media_renderer',
+ 'type': 'loadable_module',
+ 'variables': {
+ 'packages': [
+ 'gio-2.0',
+ 'gio-unix-2.0',
+ ],
+ },
+ 'dependencies': [
+ 'tizen_media_renderer_gen',
+ ],
+ 'sources': [
+ 'media_renderer_api.js',
+ 'media_renderer.cc',
+ 'media_renderer.h',
+ 'media_renderer_extension.cc',
+ 'media_renderer_extension.h',
+ 'media_renderer_instance.cc',
+ 'media_renderer_instance.h',
+ 'media_renderer_manager.cc',
+ 'media_renderer_manager.h',
+ ],
+ 'includes': [
+ '../common/pkg-config.gypi',
+ ],
+ },
+ {
+ 'target_name': 'tizen_media_renderer_gen',
+ 'type': 'static_library',
+ 'variables': {
+ 'packages': [
+ 'gio-2.0',
+ 'gio-unix-2.0',
+ ],
+ },
+ 'include_dirs': [
+ './',
+ ],
+ 'actions': [
+ {
+ 'variables': {
+ 'generate_args': [
+ '--interface-prefix',
+ 'com.intel.dLeynaRenderer.',
+ '--c-namespace',
+ 'dleyna',
+ '--generate-c-code',
+ '<(gen_dbus_proxy_path)/dleyna_manager_gen',
+ ],
+ },
+ 'action_name': 'dleyna_manager_gen',
+ 'inputs': [
+ 'dbus_interfaces/com.intel.dLeynaRenderer.Manager.xml',
+ ],
+ 'outputs': [
+ '<(gen_dbus_proxy_path)/dleyna_manager_gen.c',
+ '<(gen_dbus_proxy_path)/dleyna_manager_gen.h',
+ ],
+ 'action': [
+ 'gdbus-codegen',
+ '<@(generate_args)',
+ '<@(_inputs)',
+ ],
+ },
+ {
+ 'variables': {
+ 'generate_args': [
+ '--interface-prefix',
+ 'com.intel.dLeynaRenderer.',
+ '--c-namespace',
+ 'dleyna',
+ '--generate-c-code',
+ '<(gen_dbus_proxy_path)/dleyna_renderer_device_gen',
+ ],
+ },
+ 'action_name': 'dleyna_media_device_gen',
+ 'inputs': [
+ 'dbus_interfaces/com.intel.dLeynaRenderer.RendererDevice.xml',
+ ],
+ 'outputs': [
+ '<(gen_dbus_proxy_path)/dleyna_renderer_device_gen.c',
+ '<(gen_dbus_proxy_path)/dleyna_renderer_device_gen.h',
+ ],
+ 'action': [
+ 'gdbus-codegen',
+ '<@(generate_args)',
+ '<@(_inputs)',
+ ],
+ },
+ {
+ 'variables': {
+ 'generate_args': [
+ '--interface-prefix',
+ 'com.intel.dLeynaRenderer',
+ '--c-namespace',
+ 'dleyna',
+ '--generate-c-code',
+ '<(gen_dbus_proxy_path)/dleyna_pushhost_gen',
+ ],
+ },
+ 'action_name': 'dleyna_pushhost_gen',
+ 'inputs': [
+ 'dbus_interfaces/com.intel.dLeynaRenderer.PushHost.xml',
+ ],
+ 'outputs': [
+ '<(gen_dbus_proxy_path)/dleyna_pushhost_gen.c',
+ '<(gen_dbus_proxy_path)/dleyna_pushhost_gen.h',
+ ],
+ 'action': [
+ 'gdbus-codegen',
+ '<@(generate_args)',
+ '<@(_inputs)',
+ ],
+ },
+ {
+ 'variables': {
+ 'generate_args': [
+ '--interface-prefix',
+ 'org.mpris.',
+ '--c-namespace',
+ 'mpris',
+ '--generate-c-code',
+ '<(gen_dbus_proxy_path)/mpris_mediaplayer2_gen',
+ ],
+ },
+ 'action_name': 'mpris_mediaplayer2_gen',
+ 'inputs': [
+ 'dbus_interfaces/org.mpris.MediaPlayer2.xml',
+ ],
+ 'outputs': [
+ '<(gen_dbus_proxy_path)/mpris_mediaplayer2_gen.c',
+ '<(gen_dbus_proxy_path)/mpris_mediaplayer2_gen.h',
+ ],
+ 'action': [
+ 'gdbus-codegen',
+ '<@(generate_args)',
+ '<@(_inputs)',
+ ],
+ },
+ {
+ 'variables': {
+ 'generate_args': [
+ '--interface-prefix',
+ 'org.mpris.MediaPlayer2.',
+ '--c-namespace',
+ 'mprismediaplayer2',
+ '--generate-c-code',
+ '<(gen_dbus_proxy_path)/mpris_mediaplayer2_player_gen',
+ ],
+ },
+ 'action_name': 'mpris_mediaplayer2_player_gen',
+ 'inputs': [
+ 'dbus_interfaces/org.mpris.MediaPlayer2.Player.xml',
+ ],
+ 'outputs': [
+ '<(gen_dbus_proxy_path)/mpris_mediaplayer2_player_gen.c',
+ '<(gen_dbus_proxy_path)/mpris_mediaplayer2_player_gen.h',
+ ],
+ 'action': [
+ 'gdbus-codegen',
+ '<@(generate_args)',
+ '<@(_inputs)',
+ ],
+ },
+ ],
+ # Compile generated dbus proxies without C++11 flag
+ 'cflags!': [ '-std=c++0x' ],
+ 'sources': [
+ '<(gen_dbus_proxy_path)/dleyna_manager_gen.c',
+ '<(gen_dbus_proxy_path)/dleyna_manager_gen.h',
+ '<(gen_dbus_proxy_path)/dleyna_renderer_device_gen.c',
+ '<(gen_dbus_proxy_path)/dleyna_renderer_device_gen.h',
+ '<(gen_dbus_proxy_path)/dleyna_pushhost_gen.c',
+ '<(gen_dbus_proxy_path)/dleyna_pushhost_gen.h',
+ '<(gen_dbus_proxy_path)/mpris_mediaplayer2_player_gen.c',
+ '<(gen_dbus_proxy_path)/mpris_mediaplayer2_player_gen.h',
+ '<(gen_dbus_proxy_path)/mpris_mediaplayer2_gen.c',
+ '<(gen_dbus_proxy_path)/mpris_mediaplayer2_gen.h',
+ ],
+ 'includes': [
+ '../common/pkg-config.gypi',
+ ],
+ },
+ ],
+}
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_RENDERER_MEDIA_RENDERER_H_
+#define MEDIA_RENDERER_MEDIA_RENDERER_H_
+
+namespace common {
+
+class Instance;
+
+} // namespace common
+
+#include <string>
+#include "common/picojson.h"
+#include "media_renderer/callbacks.h"
+#include "media_renderer/dleyna_renderer_device_gen.h"
+#include "media_renderer/dleyna_pushhost_gen.h"
+#include "media_renderer/mpris_mediaplayer2_gen.h"
+#include "media_renderer/mpris_mediaplayer2_player_gen.h"
+
+class MediaRenderer {
+ public:
+ MediaRenderer(common::Instance* instance, const std::string& object_path);
+ virtual ~MediaRenderer();
+
+ void OpenURI(const picojson::value& value);
+ void PrefetchURI(const picojson::value& value);
+ void Cancel(const picojson::value& value);
+ bool IsCancelled() const;
+
+ // MediaController methods
+ void Play(const picojson::value& value);
+ void Pause(const picojson::value& value);
+ void Stop(const picojson::value& value);
+ void Next(const picojson::value& value);
+ void Previous(const picojson::value& value);
+ void Mute(const picojson::value& value);
+ void SetSpeed(const picojson::value& value);
+ void SetVolume(const picojson::value& value);
+ void GotoTrack(const picojson::value& value);
+
+ picojson::value ToJSON();
+
+ private:
+ void PostResult(const std::string& completed_operation,
+ double async_operation_id);
+ void PostError(double async_operation_id);
+
+ CALLBACK_METHOD_WITH_ID(OnOpenURI, GObject*, GAsyncResult*, MediaRenderer);
+ CALLBACK_METHOD_WITH_ID(OnPrefetchURI, GObject*,
+ GAsyncResult*, MediaRenderer);
+ CALLBACK_METHOD_WITH_ID(OnCancel, GObject*, GAsyncResult*, MediaRenderer);
+ CALLBACK_METHOD_WITH_ID(OnHostFile, GObject*, GAsyncResult*, MediaRenderer);
+
+ CALLBACK_METHOD_WITH_ID(OnPlay, GObject*, GAsyncResult*, MediaRenderer);
+ CALLBACK_METHOD_WITH_ID(OnPause, GObject*, GAsyncResult*, MediaRenderer);
+ CALLBACK_METHOD_WITH_ID(OnStop, GObject*, GAsyncResult*, MediaRenderer);
+ CALLBACK_METHOD_WITH_ID(OnNext, GObject*, GAsyncResult*, MediaRenderer);
+ CALLBACK_METHOD_WITH_ID(OnPrevious, GObject*, GAsyncResult*, MediaRenderer);
+ CALLBACK_METHOD_WITH_ID(OnGoToTrack, GObject*, GAsyncResult*, MediaRenderer);
+
+ private:
+ common::Instance* instance_;
+ picojson::value::object object_;
+ dleynaRendererDevice* rendererdevice_proxy_;
+ dleynaPushHost* pushhost_proxy_;
+ mprisMediaPlayer2* mediaplayer2_proxy_;
+ mprismediaplayer2Player* mprisplayer_proxy_;
+ std::string object_path_;
+ GCancellable* cancellable_;
+};
+
+#endif // MEDIA_RENDERER_MEDIA_RENDERER_H_
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+///////////////////////////////////////////////////////////////////////////////
+// Utilities
+///////////////////////////////////////////////////////////////////////////////
+
+var g_next_async_call_id = 0;
+var g_async_calls = {};
+
+function AsyncCall(resolve, reject) {
+ this.resolve = resolve;
+ this.reject = reject;
+}
+
+function createPromise(msg) {
+ var promise = new Promise(function(resolve, reject) {
+ g_async_calls[g_next_async_call_id] = new AsyncCall(resolve, reject);
+ });
+ msg.asyncCallId = g_next_async_call_id;
+ extension.postMessage(JSON.stringify(msg));
+ ++g_next_async_call_id;
+ return promise;
+}
+
+function _addConstProperty(obj, propertyKey, propertyValue) {
+ Object.defineProperty(obj, propertyKey, {
+ configurable: true,
+ writable: false,
+ value: propertyValue
+ });
+}
+
+function _addConstructorProperty(obj, constructor) {
+ Object.defineProperty(obj, 'constructor', {
+ enumerable: false,
+ value: constructor
+ });
+}
+
+function _addConstPropertyFromObject(obj, propertyKey, propObject) {
+ if (propObject.hasOwnProperty(propertyKey)) {
+ Object.defineProperty(obj, propertyKey, {
+ configurable: true,
+ writable: false,
+ value: propObject[propertyKey]
+ });
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Exports and main entry point for the MediaRenderer API
+///////////////////////////////////////////////////////////////////////////////
+
+var g_media_renderer_manager = new MediaRendererManager();
+exports = g_media_renderer_manager;
+
+var g_media_renderer_manager_listeners = {};
+g_media_renderer_manager_listeners['rendererfound'] = [];
+g_media_renderer_manager_listeners['rendererlost'] = [];
+
+extension.setMessageListener(function(json) {
+ var msg = JSON.parse(json);
+ switch (msg.cmd) {
+ case 'rendererFound':
+ handleMediaRendererFound(msg);
+ break;
+ case 'rendererLost':
+ handleMediaRendererLost(msg);
+ break;
+ case 'getRenderersCompleted':
+ handleGetRenderersCompleted(msg);
+ break;
+ case 'openURICompleted':
+ case 'prefetchURICompleted':
+ case 'cancelCompleted':
+ case 'playCompleted':
+ case 'pauseCompleted':
+ case 'stopCompleted':
+ case 'nextCompleted':
+ case 'previousCompleted':
+ case 'muteCompleted':
+ case 'setSpeedCompleted':
+ case 'setVolumeCompleted':
+ case 'gotoTrackCompleted':
+ handleAsyncCallSuccess(msg);
+ break;
+ case 'asyncCallError':
+ handleAsyncCallError(msg);
+ break;
+ default:
+ console.error('[MediaRenderer]:' + "Unknown signal: '" + msg.cmd + "' from backend");
+ }
+});
+
+function handleMediaRendererFound(msg) {
+ var event = new CustomEvent('rendererfound');
+ _addConstProperty(event, 'renderer', new MediaRenderer(msg.renderer));
+ g_media_renderer_manager.dispatchEvent(event);
+ if (g_media_renderer_manager.onrendererfound)
+ g_media_renderer_manager.onrendererfound(event);
+}
+
+function handleMediaRendererLost(msg) {
+ var event = new CustomEvent('rendererlost');
+ _addConstProperty(event, 'id', msg.lostRendererId);
+ g_media_renderer_manager.dispatchEvent(event);
+ if (g_media_renderer_manager.onrendererlost)
+ g_media_renderer_manager.onrendererlost(event);
+}
+
+function handleAsyncCallSuccess(msg) {
+ g_async_calls[msg.asyncCallId].resolve();
+}
+
+function handleAsyncCallError(msg) {
+ g_async_calls[msg.asyncCallId].reject(Error('Async operation failed'));
+}
+
+function handleGetRenderersCompleted(msg) {
+ g_async_calls[msg.asyncCallId].resolve(msg.renderers);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// MediaRendererManager
+///////////////////////////////////////////////////////////////////////////////
+
+function MediaRendererManager() {
+ this.onrendererfound = null;
+ this.onrendererlost = null;
+}
+
+function isValidType(type) {
+ return (type === 'rendererlost' || type === 'rendererfound');
+}
+
+MediaRendererManager.prototype.addEventListener = function(type, callback) {
+ if (callback != null && isValidType(type))
+ if (~~g_media_renderer_manager_listeners[type].indexOf(callback))
+ g_media_renderer_manager_listeners[type].push(callback);
+};
+
+MediaRendererManager.prototype.removeEventListener = function(type, callback) {
+ if (callback == null || !isValidType(type))
+ return;
+
+ var index = g_media_renderer_manager_listeners[type].indexOf(callback);
+ if (~index)
+ g_media_renderer_manager_listeners[type].slice(index, 1);
+};
+
+MediaRendererManager.prototype.dispatchEvent = function(event) {
+ var handled = true;
+
+ if (typeof event !== 'object' || !isValidType(event.type))
+ return false;
+
+ g_media_renderer_manager_listeners[event.type].forEach(function(callback) {
+ var res = callback(event);
+ if (!res && handled)
+ handled = false;
+ });
+
+ return handled;
+};
+
+MediaRendererManager.prototype.scanNetwork = function() {
+ var msg = {
+ 'cmd': 'scanNetwork'
+ };
+ extension.postMessage(JSON.stringify(msg));
+};
+
+function getRenderers() {
+ var msg = {
+ 'cmd': 'getRenderers'
+ };
+ return createPromise(msg);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// MediaRenderer
+///////////////////////////////////////////////////////////////////////////////
+
+function MediaRenderer(obj) {
+ _addConstPropertyFromObject(this, 'id', obj);
+ _addConstPropertyFromObject(this, 'friendlyName', obj);
+ _addConstPropertyFromObject(this, 'manufacturer', obj);
+ _addConstPropertyFromObject(this, 'manufacturerURL', obj);
+ _addConstPropertyFromObject(this, 'modelDescription', obj);
+ _addConstPropertyFromObject(this, 'modelName', obj);
+ _addConstPropertyFromObject(this, 'modelNumber', obj);
+ _addConstPropertyFromObject(this, 'serialNumber', obj);
+ _addConstPropertyFromObject(this, 'UDN', obj);
+ _addConstPropertyFromObject(this, 'presentationURL', obj);
+ _addConstPropertyFromObject(this, 'iconURL', obj);
+ _addConstPropertyFromObject(this, 'deviceType', obj);
+ _addConstPropertyFromObject(this, 'protocolInfo', obj);
+ _addConstProperty(this, 'controller', new MediaController(obj.controller));
+ this.oncontainerchanged = null;
+}
+
+MediaRenderer.prototype.openURI = function(mediaURI, metaData) {
+ var msg = {
+ 'cmd': 'openURI',
+ 'rendererId': this.id,
+ 'mediaURI': mediaURI,
+ 'metaData': metaData
+ };
+ return createPromise(msg);
+};
+
+MediaRenderer.prototype.prefetchURI = function(mediaURI, metaData) {
+ var msg = {
+ 'cmd': 'prefetchURI',
+ 'rendererId': this.id,
+ 'mediaURI': mediaURI,
+ 'metaData': metaData
+ };
+ return createPromise(msg);
+};
+
+MediaRenderer.prototype.cancel = function() {
+ var msg = {
+ 'cmd': 'cancel',
+ 'rendererId': this.id
+ };
+ return createPromise(msg);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// MediaController
+///////////////////////////////////////////////////////////////////////////////
+
+function MediaController(obj) {
+ _addConstPropertyFromObject(this, 'id', obj);
+ _addConstPropertyFromObject(this, 'playbackStatus', obj);
+ _addConstPropertyFromObject(this, 'muted', obj);
+ _addConstPropertyFromObject(this, 'volume', obj);
+ _addConstPropertyFromObject(this, 'track', obj);
+ _addConstPropertyFromObject(this, 'speed', obj);
+ _addConstPropertyFromObject(this, 'playSpeeds', obj);
+ this.onstatuschanged = null;
+}
+
+MediaController.prototype.play = function() {
+ var msg = {
+ 'cmd': 'play',
+ 'rendererId': this.id
+ };
+ return createPromise(msg);
+};
+
+MediaController.prototype.pause = function() {
+ var msg = {
+ 'cmd': 'pause',
+ 'rendererId': this.id
+ };
+ return createPromise(msg);
+};
+
+MediaController.prototype.stop = function() {
+ var msg = {
+ 'cmd': 'stop',
+ 'rendererId': this.id
+ };
+ return createPromise(msg);
+};
+
+MediaController.prototype.next = function() {
+ var msg = {
+ 'cmd': 'next',
+ 'rendererId': this.id
+ };
+ return createPromise(msg);
+};
+
+MediaController.prototype.previous = function() {
+ var msg = {
+ 'cmd': 'previous',
+ 'rendererId': this.id
+ };
+ return createPromise(msg);
+};
+
+MediaController.prototype.mute = function(mute) {
+ var msg = {
+ 'cmd': 'mute',
+ 'rendererId': this.id,
+ 'mute': mute
+ };
+ return createPromise(msg);
+};
+
+MediaController.prototype.setSpeed = function(speed) {
+ var msg = {
+ 'cmd': 'setSpeed',
+ 'rendererId': this.id,
+ 'speed': speed
+ };
+ return createPromise(msg);
+};
+
+MediaController.prototype.setVolume = function(volume) {
+ var msg = {
+ 'cmd': 'setVolume',
+ 'rendererId': this.id,
+ 'volume': volume
+ };
+ return createPromise(msg);
+};
+
+MediaController.prototype.gotoTrack = function(track) {
+ var msg = {
+ 'cmd': 'gotoTrack',
+ 'rendererId': this.id,
+ 'track': track
+ };
+ return createPromise(msg);
+};
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media_renderer/media_renderer_extension.h"
+
+#include "media_renderer/media_renderer_instance.h"
+
+common::Extension* CreateExtension() {
+ return new MediaRendererExtension;
+}
+
+extern const char kSource_media_renderer_api[];
+
+MediaRendererExtension::MediaRendererExtension() {
+ SetExtensionName("navigator.mediaRenderer");
+ SetJavaScriptAPI(kSource_media_renderer_api);
+}
+
+MediaRendererExtension::~MediaRendererExtension() {}
+
+common::Instance* MediaRendererExtension::CreateInstance() {
+ return new MediaRendererInstance;
+}
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_RENDERER_MEDIA_RENDERER_EXTENSION_H_
+#define MEDIA_RENDERER_MEDIA_RENDERER_EXTENSION_H_
+
+#include "common/extension.h"
+
+class MediaRendererExtension : public common::Extension {
+ public:
+ MediaRendererExtension();
+ virtual ~MediaRendererExtension();
+
+ private:
+ // common::Extension implementation.
+ virtual common::Instance* CreateInstance();
+};
+
+#endif // MEDIA_RENDERER_MEDIA_RENDERER_EXTENSION_H_
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media_renderer/media_renderer_instance.h"
+
+#include <string>
+
+#include "common/picojson.h"
+#include "media_renderer/media_renderer_manager.h"
+
+MediaRendererInstance::MediaRendererInstance()
+ : worker_thread_(&MediaRendererInstance::InitWorkerThread, this) {
+ worker_thread_.detach();
+}
+
+MediaRendererInstance::~MediaRendererInstance() {
+ g_main_loop_quit(worker_loop_);
+ delete media_renderer_manager_;
+}
+
+gboolean MediaRendererInstance::CreateMediaRendererManager(void* data) {
+ if (!data) {
+ std::cerr << "Null pointer is passed to callback" << std::endl;
+ return FALSE;
+ }
+
+ MediaRendererInstance* instance = static_cast<MediaRendererInstance*>(data);
+ instance->media_renderer_manager_ = new MediaRendererManager(instance);
+ return FALSE;
+}
+
+void MediaRendererInstance::InitWorkerThread() {
+ GMainContext* context = g_main_context_default();
+ worker_loop_ = g_main_loop_new(context, FALSE);
+ g_main_context_push_thread_default(context);
+ GSource* source = g_idle_source_new();
+ g_source_set_callback(source,
+ &MediaRendererInstance::CreateMediaRendererManager,
+ this,
+ NULL);
+ g_source_attach(source, context);
+ g_main_loop_run(worker_loop_);
+ g_source_destroy(source);
+ g_source_unref(source);
+ g_main_loop_unref(worker_loop_);
+}
+
+void MediaRendererInstance::HandleMessage(const char* message) {
+ picojson::value v;
+
+ std::string err;
+ picojson::parse(v, message, message + strlen(message), &err);
+ if (!err.empty()) {
+ return;
+ }
+
+ std::string cmd = v.get("cmd").to_str();
+ if (cmd == "scanNetwork")
+ media_renderer_manager_->ScanNetwork();
+ else if (cmd == "getRenderers")
+ media_renderer_manager_->GetRenderers(v);
+ else if (cmd == "openURI")
+ media_renderer_manager_->HandleOpenURI(v);
+ else if (cmd == "prefetchURI")
+ media_renderer_manager_->HandlePrefetchURI(v);
+ else if (cmd == "cancel")
+ media_renderer_manager_->HandleCancel(v);
+ else if (cmd == "play")
+ media_renderer_manager_->HandlePlay(v);
+ else if (cmd == "pause")
+ media_renderer_manager_->HandlePause(v);
+ else if (cmd == "stop")
+ media_renderer_manager_->HandleStop(v);
+ else if (cmd == "next")
+ media_renderer_manager_->HandleNext(v);
+ else if (cmd == "previous")
+ media_renderer_manager_->HandlePrevious(v);
+ else if (cmd == "mute")
+ media_renderer_manager_->HandleMute(v);
+ else if (cmd == "setSpeed")
+ media_renderer_manager_->HandleSetSpeed(v);
+ else if (cmd == "setVolume")
+ media_renderer_manager_->HandleSetVolume(v);
+ else if (cmd == "gotoTrack")
+ media_renderer_manager_->HandleGotoTrack(v);
+ else
+ std::cerr << "Received unknown message: " << cmd << "\n";
+}
+
+void MediaRendererInstance::HandleSyncMessage(const char* message) {}
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_RENDERER_MEDIA_RENDERER_INSTANCE_H_
+#define MEDIA_RENDERER_MEDIA_RENDERER_INSTANCE_H_
+
+#include <glib.h>
+#include <thread> // NOLINT
+
+#include "common/extension.h"
+
+class MediaRendererManager;
+
+namespace picojson {
+
+class value;
+
+} // namespace picojson
+
+class MediaRendererInstance : public common::Instance {
+ public:
+ MediaRendererInstance();
+ virtual ~MediaRendererInstance();
+
+ private:
+ void InitWorkerThread();
+ static gboolean CreateMediaRendererManager(void* data);
+ // common::Instance implementation.
+ virtual void HandleMessage(const char* msg);
+ virtual void HandleSyncMessage(const char* msg);
+
+ std::thread worker_thread_;
+ GMainLoop* worker_loop_ = NULL;
+ MediaRendererManager* media_renderer_manager_ = NULL;
+};
+
+#endif // MEDIA_RENDERER_MEDIA_RENDERER_INSTANCE_H_
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media_renderer/media_renderer_manager.h"
+
+#include <utility>
+#include <string>
+#include "common/extension.h"
+#include "media_renderer/media_renderer.h"
+
+typedef std::pair<std::string, std::shared_ptr<MediaRenderer>>
+ MediaRendererPair;
+
+MediaRendererManager::MediaRendererManager(common::Instance* instance)
+ : instance_(instance) {
+ GError* gerror = NULL;
+ manager_proxy_ = dleyna_manager_proxy_new_for_bus_sync(
+ G_BUS_TYPE_SESSION,
+ G_DBUS_PROXY_FLAGS_NONE,
+ "com.intel.dleyna-renderer",
+ "/com/intel/dLeynaRenderer",
+ NULL,
+ &gerror);
+
+ if (gerror) {
+ g_error_free(gerror);
+ return;
+ }
+
+ g_signal_connect(
+ manager_proxy_,
+ "found-renderer",
+ G_CALLBACK(OnFoundRendererCallBack),
+ this);
+
+ g_signal_connect(
+ manager_proxy_,
+ "lost-renderer",
+ G_CALLBACK(OnLostRendererCallBack),
+ this);
+}
+
+MediaRendererManager::~MediaRendererManager() {
+ g_object_unref(manager_proxy_);
+}
+
+void MediaRendererManager::ScanNetwork() {
+ if (!manager_proxy_)
+ return;
+
+ dleyna_manager_call_get_renderers(
+ manager_proxy_,
+ NULL,
+ OnScanNetworkCallBack,
+ this);
+}
+
+void MediaRendererManager::GetRenderers(const picojson::value& value) {
+ if (!manager_proxy_)
+ return;
+
+ double async_call_id = value.get("asyncCallId").get<double>();
+
+ dleyna_manager_call_get_renderers(
+ manager_proxy_,
+ cancellable_,
+ OnGetRenderersCallBack,
+ new CallbackData(this, async_call_id));
+}
+
+void MediaRendererManager::HandleOpenURI(const picojson::value& value) {
+ if (MediaRendererPtr renderer = GetMediaRendererById(value))
+ renderer->OpenURI(value);
+}
+
+void MediaRendererManager::HandlePrefetchURI(
+ const picojson::value& value) {
+ if (MediaRendererPtr renderer = GetMediaRendererById(value))
+ renderer->PrefetchURI(value);
+}
+
+void MediaRendererManager::HandleCancel(const picojson::value& value) {
+ if (MediaRendererPtr renderer = GetMediaRendererById(value))
+ renderer->Cancel(value);
+}
+
+void MediaRendererManager::HandlePlay(const picojson::value& value) {
+ if (MediaRendererPtr renderer = GetMediaRendererById(value))
+ renderer->Play(value);
+}
+
+void MediaRendererManager::HandlePause(const picojson::value& value) {
+ if (MediaRendererPtr renderer = GetMediaRendererById(value))
+ renderer->Pause(value);
+}
+
+void MediaRendererManager::HandleStop(const picojson::value& value) {
+ if (MediaRendererPtr renderer = GetMediaRendererById(value))
+ renderer->Stop(value);
+}
+
+void MediaRendererManager::HandleNext(const picojson::value& value) {
+ if (MediaRendererPtr renderer = GetMediaRendererById(value))
+ renderer->Next(value);
+}
+
+void MediaRendererManager::HandlePrevious(const picojson::value& value) {
+ if (MediaRendererPtr renderer = GetMediaRendererById(value))
+ renderer->Previous(value);
+}
+
+void MediaRendererManager::HandleMute(const picojson::value& value) {
+ if (MediaRendererPtr renderer = GetMediaRendererById(value))
+ renderer->Mute(value);
+}
+
+void MediaRendererManager::HandleSetSpeed(const picojson::value& value) {
+ if (MediaRendererPtr renderer = GetMediaRendererById(value))
+ renderer->SetSpeed(value);
+}
+
+void MediaRendererManager::HandleSetVolume(const picojson::value& value) {
+ if (MediaRendererPtr renderer = GetMediaRendererById(value))
+ renderer->SetVolume(value);
+}
+
+void MediaRendererManager::HandleGotoTrack(const picojson::value& value) {
+ if (MediaRendererPtr renderer = GetMediaRendererById(value))
+ renderer->GotoTrack(value);
+}
+
+void MediaRendererManager::PostRendererFound(const std::string& path) {
+ MediaRendererPtr media_renderer(new MediaRenderer(instance_, path));
+ media_renderers_.insert(MediaRendererPair(path, media_renderer));
+ picojson::value::object object;
+ object["cmd"] = picojson::value("rendererFound");
+ object["renderer"] = media_renderer->ToJSON();
+ picojson::value value(object);
+ instance_->PostMessage(value.serialize().c_str());
+}
+
+
+MediaRendererPtr MediaRendererManager::GetMediaRendererById(
+ const picojson::value& id) {
+ return GetMediaRendererById(id.get("rendererId").to_str());
+}
+
+MediaRendererPtr MediaRendererManager::GetMediaRendererById(
+ const std::string& id) {
+ if (!media_renderers_.size())
+ return MediaRendererPtr();
+
+ std::map<std::string, MediaRendererPtr>::const_iterator it;
+ if ((it = media_renderers_.find(id)) != media_renderers_.end())
+ return (*it).second;
+
+ return MediaRendererPtr();
+}
+
+void MediaRendererManager::OnScanNetwork(
+ GObject* source_object,
+ GAsyncResult* res) {
+ GError* gerror = NULL;
+ gchar** out_renderers;
+ if (!dleyna_manager_call_get_renderers_finish(
+ manager_proxy_,
+ &out_renderers,
+ res,
+ &gerror)) {
+ g_error_free(gerror);
+ return;
+ }
+
+ while (gchar* renderer_path = *out_renderers) {
+ PostRendererFound(std::string(*out_renderers));
+ out_renderers++;
+ g_free(renderer_path);
+ }
+}
+
+void MediaRendererManager::OnGetRenderers(
+ GObject* source_object,
+ GAsyncResult* res,
+ double async_id) {
+ GError* gerror = NULL;
+ gchar** out_renderers;
+ if (!dleyna_manager_call_get_renderers_finish(
+ manager_proxy_,
+ &out_renderers,
+ res,
+ &gerror)) {
+ g_error_free(gerror);
+ return;
+ }
+
+ picojson::value::array renderers;
+
+ while (gchar* renderer_path = *out_renderers) {
+ MediaRendererPtr media_renderer(new MediaRenderer(instance_,
+ std::string(*out_renderers)));
+ media_renderers_.insert(MediaRendererPair(std::string(*out_renderers),
+ media_renderer));
+ renderers.push_back(media_renderer->ToJSON());
+ out_renderers++;
+ g_free(renderer_path);
+ }
+
+ picojson::value::object object;
+ object["cmd"] = picojson::value("getRenderersCompleted");
+ object["asyncCallId"] = picojson::value(async_id);
+ object["renderers"] = picojson::value(renderers);
+ picojson::value value(object);
+ instance_->PostMessage(value.serialize().c_str());
+}
+
+void MediaRendererManager::OnFoundRenderer(dleynaManager* object,
+ const gchar* arg_Path) {
+ PostRendererFound(std::string(arg_Path));
+}
+
+void MediaRendererManager::OnLostRenderer(dleynaManager* object,
+ const gchar* arg_Path) {
+ MediaRendererPtr renderer = GetMediaRendererById(std::string(arg_Path));
+ if (!renderer)
+ return;
+
+ picojson::value::object pobject;
+ pobject["cmd"] = picojson::value("rendererLost");
+ pobject["rendererId"] = renderer->ToJSON().get("id");
+ picojson::value value(pobject);
+ instance_->PostMessage(value.serialize().c_str());
+ media_renderers_.erase(arg_Path);
+}
--- /dev/null
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_RENDERER_MEDIA_RENDERER_MANAGER_H_
+#define MEDIA_RENDERER_MEDIA_RENDERER_MANAGER_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include "media_renderer/dleyna_manager_gen.h"
+#include "media_renderer/media_renderer.h"
+#include "media_renderer/callbacks.h"
+
+namespace common {
+
+class Instance;
+
+} // namespace common
+
+typedef std::shared_ptr<MediaRenderer> MediaRendererPtr;
+
+class MediaRendererManager {
+ public:
+ explicit MediaRendererManager(common::Instance* instance);
+ virtual ~MediaRendererManager();
+
+ void ScanNetwork();
+ void GetRenderers(const picojson::value& value);
+ void HandleOpenURI(const picojson::value& value);
+ void HandlePrefetchURI(const picojson::value& value);
+ void HandleCancel(const picojson::value& value);
+ void HandlePlay(const picojson::value& value);
+ void HandlePause(const picojson::value& value);
+ void HandleStop(const picojson::value& value);
+ void HandleNext(const picojson::value& value);
+ void HandlePrevious(const picojson::value& value);
+ void HandleMute(const picojson::value& value);
+ void HandleSetSpeed(const picojson::value& value);
+ void HandleSetVolume(const picojson::value& value);
+ void HandleGotoTrack(const picojson::value& value);
+
+ private:
+ void PostRendererFound(const std::string& path);
+ MediaRendererPtr GetMediaRendererById(const picojson::value& id);
+ MediaRendererPtr GetMediaRendererById(const std::string& id);
+ bool IsCancelled() { return g_cancellable_is_cancelled(cancellable_); }
+
+ CALLBACK_METHOD(OnScanNetwork, GObject*, GAsyncResult*, MediaRendererManager);
+ CALLBACK_METHOD_WITH_ID(OnGetRenderers, GObject*, GAsyncResult*,
+ MediaRendererManager);
+ CALLBACK_METHOD(OnLostRenderer, dleynaManager*,
+ const gchar*, MediaRendererManager);
+ CALLBACK_METHOD(OnFoundRenderer, dleynaManager*,
+ const gchar*, MediaRendererManager);
+
+ private:
+ common::Instance* instance_;
+ dleynaManager* manager_proxy_;
+ std::map<std::string, MediaRendererPtr> media_renderers_;
+ GCancellable* cancellable_;
+};
+
+#endif // MEDIA_RENDERER_MEDIA_RENDERER_MANAGER_H_
'type': 'none',
'dependencies': [
'bluetooth/bluetooth.gyp:*',
+ 'media_renderer/media_renderer.gyp:*',
'mediaserver/mediaserver.gyp:*',
'network_bearer_selection/network_bearer_selection.gyp:*',
'notification/notification.gyp:*',