Merge lp:~phablet-team/media-hub/fix-1498962 into lp:media-hub

Proposed by Jim Hodapp
Status: Merged
Approved by: Alfonso Sanchez-Beato
Approved revision: 190
Merged at revision: 185
Proposed branch: lp:~phablet-team/media-hub/fix-1498962
Merge into: lp:media-hub
Diff against target: 691 lines (+275/-112)
12 files modified
include/core/media/track.h (+30/-46)
src/core/media/CMakeLists.txt (+2/-0)
src/core/media/codec.h (+83/-8)
src/core/media/cover_art_resolver.cpp (+1/-1)
src/core/media/gstreamer/meta_data_extractor.h (+4/-3)
src/core/media/gstreamer/playbin.cpp (+1/-3)
src/core/media/metadata.cpp (+83/-0)
src/core/media/mpris/player.h (+11/-8)
src/core/media/player_implementation.cpp (+40/-2)
src/core/media/player_skeleton.cpp (+2/-2)
src/core/media/player_stub.cpp (+2/-2)
src/core/media/service_skeleton.cpp (+16/-37)
To merge this branch: bzr merge lp:~phablet-team/media-hub/fix-1498962
Reviewer Review Type Date Requested Status
Alfonso Sanchez-Beato Approve
Konrad Zapałowicz (community) code Approve
PS Jenkins bot continuous-integration Pending
Review via email: mp+296604@code.launchpad.net

Commit message

Enable exporting of metadata via MPRIS over dbus. This does not export everything yet and focused solely on track title, track album name and artist name.

Description of the change

Enable exporting of metadata via MPRIS over dbus. This does not export everything yet and focused solely on track title, track album name and artist name.

To post a comment you must log in.
186. By Jim Hodapp

Add metadata.cpp

187. By Jim Hodapp

Make sure we don't lose the album_missing.svg image in indicator-sound when toggling play/pause

188. By Jim Hodapp

Undo last set of extra changes that snuck in to a commit

189. By Jim Hodapp

Make sure that the MPRIS client sees a the same data after switching between MPRIS clients

Revision history for this message
Alfonso Sanchez-Beato (alfonsosanchezbeato) wrote :

Some minor nits around.

review: Needs Fixing
Revision history for this message
Konrad Zapałowicz (kzapalowicz) wrote :

LGTM except on the sizeof thing.

review: Needs Fixing (code)
Revision history for this message
Jim Hodapp (jhodapp) :
190. By Jim Hodapp

Address review comments

Revision history for this message
Konrad Zapałowicz (kzapalowicz) wrote :

LGTM

review: Approve (code)
Revision history for this message
Alfonso Sanchez-Beato (alfonsosanchezbeato) wrote :

LGTM

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/core/media/track.h'
2--- include/core/media/track.h 2015-07-02 12:30:09 +0000
3+++ include/core/media/track.h 2016-06-09 16:54:40 +0000
4@@ -39,10 +39,15 @@
5 public:
6 typedef std::string UriType;
7 typedef std::string Id;
8+ typedef std::map<std::string, std::string> MetaDataType;
9
10 class MetaData
11 {
12 public:
13+ static constexpr const char* TrackArtlUrlKey = "mpris:artUrl";
14+ static constexpr const char* TrackLengthKey = "mpris:length";
15+ static constexpr const char* TrackIdKey = "mpris:trackid";
16+
17 bool operator==(const MetaData& rhs) const
18 {
19 return map == rhs.map;
20@@ -90,13 +95,36 @@
21 return map.at(key);
22 }
23
24+ bool is_set(const std::string& key) const
25+ {
26+ try {
27+ return map.at(key).empty();
28+ } catch (const std::out_of_range& e) {
29+ return false;
30+ }
31+ }
32+
33 const std::map<std::string, std::string>& operator*() const
34 {
35 return map;
36 }
37
38+ const std::string& album() const;
39+ const std::string& artist() const;
40+ const std::string& title() const;
41+ const std::string& track_id() const;
42+ const std::string& art_url() const;
43+ const std::string& last_used() const;
44+
45+ void set_album(const std::string& album);
46+ void set_artist(const std::string& artist);
47+ void set_title(const std::string& title);
48+ void set_track_id(const std::string& id);
49+ void set_art_url(const std::string& url);
50+ void set_last_used(const std::string& datetime);
51+
52 private:
53- std::map<std::string, std::string> map;
54+ MetaDataType map;
55 };
56
57 Track(const Id& id);
58@@ -108,51 +136,7 @@
59
60 virtual const Id& id() const;
61 virtual const UriType& uri() const;
62- /*
63- class MetaData
64- {
65- public:
66- MetaData() = default;
67- MetaData(const MetaData&) = default;
68- ~MetaData() = default;
69-
70- MetaData& operator=(const MetaData&) = default;
71-
72- bool operator==(const MetaData&) const
73- {
74- return true;
75- }
76-
77- bool operator!=(const MetaData&) const
78- {
79- return false;
80- }
81-
82- struct NotImplementedFields
83- {
84- NotImplementedFields() = default;
85-
86- virtual const UriType& uri() const = 0;
87- virtual const std::chrono::microseconds length() const = 0;
88- virtual const UriType& art_uri() const = 0;
89- virtual const std::string& album() const = 0;
90- virtual const std::vector<std::string>& album_artist() const = 0;
91- virtual const std::vector<std::string>& artist() const = 0;
92- virtual const std::string& as_text() const = 0;
93- virtual unsigned int audio_bpm() const = 0;
94- virtual float auto_rating() const = 0;
95- virtual const std::vector<std::string>& comment() const = 0;
96- virtual const std::vector<std::string>& composer() const = 0;
97- virtual unsigned int disc_number() const = 0;
98- virtual const std::vector<std::string>& genre() const = 0;
99- virtual const std::vector<std::string>& lyricist() const = 0;
100- virtual const std::string title() const = 0;
101- virtual unsigned int track_number() const = 0;
102- virtual unsigned int use_count() const = 0;
103- virtual float user_rating() const = 0;
104- };
105- };
106-*/
107+
108 private:
109 struct Private;
110 std::unique_ptr<Private> d;
111
112=== modified file 'src/core/media/CMakeLists.txt'
113--- src/core/media/CMakeLists.txt 2016-04-05 15:40:11 +0000
114+++ src/core/media/CMakeLists.txt 2016-06-09 16:54:40 +0000
115@@ -49,6 +49,7 @@
116 service.cpp
117 track.cpp
118 track_list.cpp
119+ metadata.cpp
120
121 player_stub.cpp
122 service_stub.cpp
123@@ -99,6 +100,7 @@
124 hybris_client_death_observer.cpp
125 cover_art_resolver.cpp
126 engine.cpp
127+ metadata.cpp
128
129 apparmor/context.cpp
130 apparmor/ubuntu.cpp
131
132=== modified file 'src/core/media/codec.h'
133--- src/core/media/codec.h 2015-04-14 19:11:15 +0000
134+++ src/core/media/codec.h 2016-06-09 16:54:40 +0000
135@@ -23,10 +23,18 @@
136 #include <core/media/player.h>
137 #include <core/media/track.h>
138
139+#include <core/dbus/types/stl/map.h>
140 #include <core/dbus/types/stl/string.h>
141+#include <core/dbus/types/variant.h>
142 #include <core/dbus/types/stl/vector.h>
143 #include <core/dbus/codec.h>
144
145+#include <boost/lexical_cast.hpp>
146+
147+#include "core/media/xesam.h"
148+
149+#include "core/media/logger/logger.h"
150+
151 namespace core
152 {
153 namespace dbus
154@@ -38,7 +46,7 @@
155 {
156 constexpr static ArgumentType type_value()
157 {
158- return ArgumentType::floating_point;
159+ return ArgumentType::array;
160 }
161 constexpr static bool is_basic_type()
162 {
163@@ -51,7 +59,7 @@
164
165 static std::string signature()
166 {
167- static const std::string s = TypeMapper<double>::signature();
168+ static const std::string s = TypeMapper<std::map<std::string, dbus::types::Variant>>::signature();
169 return s;
170 }
171 };
172@@ -60,16 +68,83 @@
173 template<>
174 struct Codec<core::ubuntu::media::Track::MetaData>
175 {
176- static void encode_argument(core::dbus::Message::Writer& out, const core::ubuntu::media::Track::MetaData& in)
177+ static void encode_argument(core::dbus::Message::Writer& writer, const core::ubuntu::media::Track::MetaData& md)
178 {
179- (void) out;
180- (void) in;
181+ typedef std::pair<std::string, dbus::types::Variant> Pair;
182+ auto dict = writer.open_array(dbus::types::Signature
183+ {dbus::helper::TypeMapper<Pair>::signature()});
184+
185+ for (const auto& pair : *md)
186+ {
187+ auto de = dict.open_dict_entry();
188+ {
189+ if (pair.first == core::ubuntu::media::Track::MetaData::TrackLengthKey
190+ and not pair.second.empty())
191+ {
192+ Codec<Pair>::encode_argument(de, std::make_pair(pair.first,
193+ dbus::types::Variant::encode(
194+ boost::lexical_cast<std::int64_t>(pair.second))));
195+ }
196+ else if (pair.first == xesam::Album::name and not pair.second.empty())
197+ {
198+ Codec<Pair>::encode_argument(de, std::make_pair(pair.first,
199+ dbus::types::Variant::encode(pair.second)));
200+ }
201+ else if (pair.first == xesam::AlbumArtist::name and not pair.second.empty())
202+ {
203+#if 0
204+ // TODO: This code doesn't work but will be needed for full MPRIS compliance.
205+ // Technically there can be more than one album artist stuffed into an array.
206+ // How to satisfy stuffing this data into dbus-cpp is what needs fixing.
207+ auto array = de.open_array(dbus::types::Signature
208+ {dbus::helper::TypeMapper<Pair>::signature()});
209+ {
210+ // TODO: this should really iterate over all artists, but seems
211+ // we only extract one artist from playbin
212+ Codec<Pair>::encode_argument(array, std::make_pair(pair.first,
213+ dbus::types::Variant::encode(pair.second)));
214+ }
215+ de.close_array(std::move(array));
216+#else
217+ Codec<Pair>::encode_argument(de, std::make_pair(pair.first,
218+ dbus::types::Variant::encode(pair.second)));
219+#endif
220+ }
221+ else
222+ {
223+ Codec<Pair>::encode_argument(de, std::make_pair(pair.first,
224+ dbus::types::Variant::encode(pair.second)));
225+ }
226+ }
227+ dict.close_dict_entry(std::move(de));
228+ }
229+ writer.close_array(std::move(dict));
230 }
231
232- static void decode_argument(core::dbus::Message::Reader& out, core::ubuntu::media::Track::MetaData& in)
233+ static void decode_argument(core::dbus::Message::Reader& reader, core::ubuntu::media::Track::MetaData& md)
234 {
235- (void) out;
236- (void) in;
237+ auto array = reader.pop_array();
238+
239+ while (array.type() != dbus::ArgumentType::invalid)
240+ {
241+ auto entry = array.pop_dict_entry();
242+ {
243+ std::string key {entry.pop_string()};
244+ auto variant = entry.pop_variant();
245+ {
246+ if (key == xesam::Album::name)
247+ {
248+ const std::string album = variant.pop_string();
249+ MH_DEBUG("Getting key \"%s\" and value \"%s\"", key, album);
250+ md.set_album(album);
251+ }
252+ else
253+ {
254+ MH_WARNING("Unknown metadata key \"%s\" while decoding dbus message", key);
255+ }
256+ }
257+ }
258+ }
259 }
260 };
261
262
263=== modified file 'src/core/media/cover_art_resolver.cpp'
264--- src/core/media/cover_art_resolver.cpp 2014-09-09 14:02:52 +0000
265+++ src/core/media/cover_art_resolver.cpp 2016-06-09 16:54:40 +0000
266@@ -22,6 +22,6 @@
267 {
268 return [](const std::string&, const std::string&, const std::string&)
269 {
270- return "file:///usr/share/unity/icons/album_missing.png";
271+ return "file:///usr/lib/arm-linux-gnueabihf/unity-scopes/mediascanner-music/album_missing.svg";
272 };
273 }
274
275=== modified file 'src/core/media/gstreamer/meta_data_extractor.h'
276--- src/core/media/gstreamer/meta_data_extractor.h 2015-09-23 11:17:26 +0000
277+++ src/core/media/gstreamer/meta_data_extractor.h 2016-06-09 16:54:40 +0000
278@@ -24,6 +24,8 @@
279
280 #include "bus.h"
281
282+#include "core/media/logger/logger.h"
283+
284 #include <gst/gst.h>
285
286 #include <exception>
287@@ -72,7 +74,7 @@
288 auto md = static_cast<media::Track::MetaData*>(user_data);
289 std::stringstream ss;
290
291- switch(gst_tag_get_type(tag))
292+ switch (gst_tag_get_type(tag))
293 {
294 case G_TYPE_BOOLEAN:
295 {
296@@ -137,8 +139,7 @@
297 break;
298 }
299
300- (*md).set(
301- (gstreamer_to_mpris_tag_lut().count(tag) > 0 ? gstreamer_to_mpris_tag_lut().at(tag) : tag),
302+ (*md).set( (gstreamer_to_mpris_tag_lut().count(tag) > 0 ? gstreamer_to_mpris_tag_lut().at(tag) : tag),
303 ss.str());
304 },
305 &md);
306
307=== modified file 'src/core/media/gstreamer/playbin.cpp'
308--- src/core/media/gstreamer/playbin.cpp 2016-04-06 15:28:29 +0000
309+++ src/core/media/gstreamer/playbin.cpp 2016-06-09 16:54:40 +0000
310@@ -30,8 +30,6 @@
311
312 #include <utility>
313
314-//#define VERBOSE_DEBUG
315-
316 namespace
317 {
318 void setup_video_sink_for_buffer_streaming(GstElement* pipeline)
319@@ -256,7 +254,7 @@
320
321 void gstreamer::Playbin::on_new_message_async(const Bus::Message& message)
322 {
323- switch(message.type)
324+ switch (message.type)
325 {
326 case GST_MESSAGE_ERROR:
327 signals.on_error(message.detail.error_warning_info);
328
329=== added file 'src/core/media/metadata.cpp'
330--- src/core/media/metadata.cpp 1970-01-01 00:00:00 +0000
331+++ src/core/media/metadata.cpp 2016-06-09 16:54:40 +0000
332@@ -0,0 +1,83 @@
333+/*
334+ * Copyright © 2016 Canonical Ltd.
335+ *
336+ * This program is free software: you can redistribute it and/or modify it
337+ * under the terms of the GNU Lesser General Public License version 3,
338+ * as published by the Free Software Foundation.
339+ *
340+ * This program is distributed in the hope that it will be useful,
341+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
342+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
343+ * GNU Lesser General Public License for more details.
344+ *
345+ * You should have received a copy of the GNU Lesser General Public License
346+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
347+ *
348+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
349+ */
350+
351+#include "xesam.h"
352+
353+#include <core/media/track.h>
354+
355+namespace media = core::ubuntu::media;
356+
357+const std::string& media::Track::MetaData::album() const
358+{
359+ return map.at(xesam::Album::name);
360+}
361+
362+const std::string& media::Track::MetaData::artist() const
363+{
364+ return map.at(xesam::Artist::name);
365+}
366+
367+const std::string& media::Track::MetaData::title() const
368+{
369+ return map.at(xesam::Title::name);
370+}
371+
372+const std::string& media::Track::MetaData::track_id() const
373+{
374+ return map.at(media::Track::MetaData::TrackIdKey);
375+}
376+
377+const std::string& media::Track::MetaData::art_url() const
378+{
379+ return map.at(media::Track::MetaData::TrackArtlUrlKey);
380+}
381+
382+const std::string& media::Track::MetaData::last_used() const
383+{
384+ return map.at(xesam::LastUsed::name);
385+}
386+
387+void media::Track::MetaData::set_album(const std::string& album)
388+{
389+ map[xesam::Album::name] = album;
390+}
391+
392+void media::Track::MetaData::set_artist(const std::string& artist)
393+{
394+ map[xesam::Artist::name] = artist;
395+}
396+
397+void media::Track::MetaData::set_title(const std::string& title)
398+{
399+ map[xesam::Title::name] = title;
400+}
401+
402+void media::Track::MetaData::set_track_id(const std::string& id)
403+{
404+ map[media::Track::MetaData::TrackIdKey] = id;
405+}
406+
407+void media::Track::MetaData::set_art_url(const std::string& url)
408+{
409+ map[media::Track::MetaData::TrackArtlUrlKey] = url;
410+}
411+
412+void media::Track::MetaData::set_last_used(const std::string& datetime)
413+{
414+ map[xesam::LastUsed::name] = datetime;
415+}
416
417=== modified file 'src/core/media/mpris/player.h'
418--- src/core/media/mpris/player.h 2016-02-19 16:14:42 +0000
419+++ src/core/media/mpris/player.h 2016-06-09 16:54:40 +0000
420@@ -44,6 +44,8 @@
421
422 #include <cstdint>
423
424+#include "core/media/logger/logger.h"
425+
426 namespace dbus = core::dbus;
427
428 namespace mpris
429@@ -172,8 +174,7 @@
430 DBUS_CPP_WRITABLE_PROPERTY_DEF(PlaybackRate, Player, double)
431 DBUS_CPP_WRITABLE_PROPERTY_DEF(Rate, Player, double)
432 DBUS_CPP_WRITABLE_PROPERTY_DEF(Shuffle, Player, bool)
433- DBUS_CPP_READABLE_PROPERTY_DEF(Metadata, Player, Dictionary)
434- DBUS_CPP_READABLE_PROPERTY_DEF(TypedMetaData, Player, core::ubuntu::media::Track::MetaData)
435+ DBUS_CPP_READABLE_PROPERTY_DEF(Metadata, Player, core::ubuntu::media::Track::MetaData)
436 DBUS_CPP_WRITABLE_PROPERTY_DEF(Volume, Player, double)
437 DBUS_CPP_READABLE_PROPERTY_DEF(Position, Player, std::int64_t)
438 DBUS_CPP_READABLE_PROPERTY_DEF(Duration, Player, std::int64_t)
439@@ -222,7 +223,7 @@
440 Properties::TypedLoopStatus::ValueType typed_loop_status{core::ubuntu::media::Player::LoopStatus::none};
441 Properties::PlaybackRate::ValueType playback_rate{1.f};
442 Properties::Shuffle::ValueType shuffle{false};
443- Properties::TypedMetaData::ValueType typed_meta_data{};
444+ Properties::Metadata::ValueType meta_data{};
445 Properties::Volume::ValueType volume{0.f};
446 Properties::Position::ValueType position{0};
447 Properties::Duration::ValueType duration{0};
448@@ -253,7 +254,7 @@
449 configuration.object->template get_property<Properties::Lifetime>(),
450 configuration.object->template get_property<Properties::PlaybackRate>(),
451 configuration.object->template get_property<Properties::Shuffle>(),
452- configuration.object->template get_property<Properties::TypedMetaData>(),
453+ configuration.object->template get_property<Properties::Metadata>(),
454 configuration.object->template get_property<Properties::Volume>(),
455 configuration.object->template get_property<Properties::Position>(),
456 configuration.object->template get_property<Properties::Duration>(),
457@@ -288,6 +289,7 @@
458 properties.lifetime->set(core::ubuntu::media::Player::Lifetime::normal);
459 properties.playback_rate->set(configuration.defaults.playback_rate);
460 properties.shuffle->set(configuration.defaults.shuffle);
461+ properties.meta_data_for_current_track->set(configuration.defaults.meta_data);
462 properties.position->set(configuration.defaults.position);
463 properties.duration->set(configuration.defaults.duration);
464 properties.minimum_playback_rate->set(configuration.defaults.minimum_rate);
465@@ -351,9 +353,9 @@
466 Dictionary dict; dict[Property::name()] = dbus::types::Variant::encode(value);
467
468 signals.properties_changed->emit(std::make_tuple(
469- dbus::traits::Service<Player>::interface_name(),
470- dict,
471- the_empty_list_of_invalidated_properties()));
472+ dbus::traits::Service<Player>::interface_name(),
473+ dict,
474+ the_empty_list_of_invalidated_properties()));
475 }
476
477 Dictionary get_all_properties()
478@@ -374,6 +376,7 @@
479 dict[Properties::Lifetime::name()] = dbus::types::Variant::encode(properties.lifetime->get());
480 dict[Properties::PlaybackRate::name()] = dbus::types::Variant::encode(properties.playback_rate->get());
481 dict[Properties::Shuffle::name()] = dbus::types::Variant::encode(properties.shuffle->get());
482+ dict[Properties::Metadata::name()] = dbus::types::Variant::encode(properties.meta_data_for_current_track->get());
483 dict[Properties::Duration::name()] = dbus::types::Variant::encode(properties.duration->get());
484 dict[Properties::Position::name()] = dbus::types::Variant::encode(properties.position->get());
485 dict[Properties::MinimumRate::name()] = dbus::types::Variant::encode(properties.minimum_playback_rate->get());
486@@ -405,7 +408,7 @@
487 std::shared_ptr<core::dbus::Property<Properties::Lifetime>> lifetime;
488 std::shared_ptr<core::dbus::Property<Properties::PlaybackRate>> playback_rate;
489 std::shared_ptr<core::dbus::Property<Properties::Shuffle>> shuffle;
490- std::shared_ptr<core::dbus::Property<Properties::TypedMetaData>> typed_meta_data_for_current_track;
491+ std::shared_ptr<core::dbus::Property<Properties::Metadata>> meta_data_for_current_track;
492 std::shared_ptr<core::dbus::Property<Properties::Volume>> volume;
493 std::shared_ptr<core::dbus::Property<Properties::Position>> position;
494 std::shared_ptr<core::dbus::Property<Properties::Duration>> duration;
495
496=== modified file 'src/core/media/player_implementation.cpp'
497--- src/core/media/player_implementation.cpp 2016-05-03 19:08:00 +0000
498+++ src/core/media/player_implementation.cpp 2016-06-09 16:54:40 +0000
499@@ -24,6 +24,7 @@
500 #include "util/timeout.h"
501
502 #include <unistd.h>
503+#include <ctime>
504
505 #include "client_death_observer.h"
506 #include "engine.h"
507@@ -138,9 +139,19 @@
508 }
509 case Engine::State::playing:
510 {
511- // We update the track meta data prior to updating the playback status.
512+ // We update the track metadata prior to updating the playback status.
513 // Some MPRIS clients expect this order of events.
514- parent->meta_data_for_current_track().set(std::get<1>(engine->track_meta_data().get()));
515+ time_t now;
516+ time(&now);
517+ char buf[sizeof("2011-10-08T07:07:09Z")];
518+ strftime(buf, sizeof(buf), "%FT%TZ", gmtime(&now));
519+ media::Track::MetaData metadata{std::get<1>(engine->track_meta_data().get())};
520+ // Setting this with second resolution makes sure that the track_meta_data property changes
521+ // and thus the track_meta_data().changed() signal gets sent out over dbus. Otherwise the
522+ // Property caching mechanism would prevent this.
523+ metadata.set_last_used(std::string{buf});
524+ update_mpris_metadata(metadata);
525+
526 // And update our playback status.
527 parent->playback_status().set(media::Player::playing);
528 MH_INFO("Requesting power state");
529@@ -325,6 +336,27 @@
530 parent->can_go_next().set(has_next);
531 }
532
533+ // Makes sure all relevant metadata fields are set to current data and
534+ // will trigger the track_meta_data().changed() signal to go out over dbus
535+ void update_mpris_metadata(const media::Track::MetaData& md)
536+ {
537+ media::Track::MetaData metadata{md};
538+ if (not metadata.is_set(media::Track::MetaData::TrackIdKey))
539+ {
540+ const std::size_t last_slash = track_list->current().find_last_of("/");
541+ const std::string track_id = track_list->current().substr(last_slash+1);
542+ if (not track_id.empty())
543+ metadata.set_track_id("/org/mpris/MediaPlayer2/Track/" + track_id);
544+ else
545+ MH_WARNING("Failed to set MPRIS track id since the id value is NULL");
546+ }
547+ // TODO: This needs to be extracted from GStreamer and dynamically set
548+ if (not metadata.is_set(media::Track::MetaData::TrackArtlUrlKey))
549+ metadata.set_art_url("file:///usr/lib/arm-linux-gnueabihf/unity-scopes/mediascanner-music/album_missing.svg");
550+
551+ parent->meta_data_for_current_track().set(metadata);
552+ }
553+
554 bool pause_other_players(media::Player::PlayerKey key)
555 {
556 if (not config.parent.player_service)
557@@ -501,6 +533,12 @@
558 d->engine->lifetime().set(lifetime);
559 });
560
561+ d->engine->track_meta_data().changed().connect([this, config](
562+ const std::tuple<media::Track::UriType, media::Track::MetaData>& md)
563+ {
564+ d->update_mpris_metadata(std::get<1>(md));
565+ });
566+
567 d->engine->about_to_finish_signal().connect([this]()
568 {
569 if (d->doing_abandon)
570
571=== modified file 'src/core/media/player_skeleton.cpp'
572--- src/core/media/player_skeleton.cpp 2016-04-06 15:28:29 +0000
573+++ src/core/media/player_skeleton.cpp 2016-06-09 16:54:40 +0000
574@@ -478,7 +478,7 @@
575
576 const core::Property<media::Track::MetaData>& media::PlayerSkeleton::meta_data_for_current_track() const
577 {
578- return *d->skeleton.properties.typed_meta_data_for_current_track;
579+ return *d->skeleton.properties.meta_data_for_current_track;
580 }
581
582 const core::Property<media::Player::Volume>& media::PlayerSkeleton::volume() const
583@@ -608,7 +608,7 @@
584
585 core::Property<media::Track::MetaData>& media::PlayerSkeleton::meta_data_for_current_track()
586 {
587- return *d->skeleton.properties.typed_meta_data_for_current_track;
588+ return *d->skeleton.properties.meta_data_for_current_track;
589 }
590
591 core::Property<media::Player::PlaybackRate>& media::PlayerSkeleton::minimum_playback_rate()
592
593=== modified file 'src/core/media/player_stub.cpp'
594--- src/core/media/player_stub.cpp 2016-04-06 15:28:29 +0000
595+++ src/core/media/player_stub.cpp 2016-06-09 16:54:40 +0000
596@@ -70,7 +70,7 @@
597 object->get_property<mpris::Player::Properties::TypedLoopStatus>(),
598 object->get_property<mpris::Player::Properties::PlaybackRate>(),
599 object->get_property<mpris::Player::Properties::Shuffle>(),
600- object->get_property<mpris::Player::Properties::TypedMetaData>(),
601+ object->get_property<mpris::Player::Properties::Metadata>(),
602 object->get_property<mpris::Player::Properties::Volume>(),
603 object->get_property<mpris::Player::Properties::Position>(),
604 object->get_property<mpris::Player::Properties::Duration>(),
605@@ -118,7 +118,7 @@
606 std::shared_ptr<core::dbus::Property<mpris::Player::Properties::TypedLoopStatus>> loop_status;
607 std::shared_ptr<core::dbus::Property<mpris::Player::Properties::PlaybackRate>> playback_rate;
608 std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Shuffle>> shuffle;
609- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::TypedMetaData>> meta_data_for_current_track;
610+ std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Metadata>> meta_data_for_current_track;
611 std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Volume>> volume;
612 std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Position>> position;
613 std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Duration>> duration;
614
615=== modified file 'src/core/media/service_skeleton.cpp'
616--- src/core/media/service_skeleton.cpp 2016-05-17 17:51:16 +0000
617+++ src/core/media/service_skeleton.cpp 2016-06-09 16:54:40 +0000
618@@ -732,6 +732,21 @@
619 player.properties.can_go_next->set(can_go_next);
620 });
621
622+ // NOTE: the metadata first gets updated in the PlayerImplementation constructor which connects
623+ // and reacts to the Engine track_meta_data changed signal. Setting the
624+ // meta_data_for_current_track here makes sure that the signal uses the MPRIS object path
625+ connections.meta_data_changed = player_sp->meta_data_for_current_track().changed().connect(
626+ [this](const media::Track::MetaData& metadata)
627+ {
628+ player.properties.meta_data_for_current_track->set(metadata);
629+ mpris::Player::Dictionary dict; dict[mpris::Player::Properties::Metadata::name()]
630+ = dbus::types::Variant::encode(metadata);
631+ player.signals.properties_changed->emit(std::make_tuple(
632+ dbus::traits::Service<mpris::Player>::interface_name(),
633+ dict,
634+ mpris::Player::Skeleton::the_empty_list_of_invalidated_properties()));
635+ });
636+
637 // Sync property values between session and player mpris::Player instances
638 // TODO Getters from media::Player actually return values from a
639 // mpris::Player::Skeleton instance different from "player". Each of them use
640@@ -748,43 +763,6 @@
641 player.properties.can_pause->set(player_sp->can_pause().get());
642 player.properties.can_go_previous->set(player_sp->can_go_previous().get());
643 player.properties.can_go_next->set(player_sp->can_go_next().get());
644-
645-#if 0
646- // TODO cover_art_resolver() is not implemented yet
647- connections.meta_data_changed = cp->meta_data_for_current_track().changed().connect(
648- [this](const core::ubuntu::media::Track::MetaData& md)
649- {
650- mpris::Player::Dictionary dict;
651-
652- bool has_title = md.count(xesam::Title::name) > 0;
653- bool has_album_name = md.count(xesam::Album::name) > 0;
654- bool has_artist_name = md.count(xesam::Artist::name) > 0;
655-
656- if (has_title)
657- dict[xesam::Title::name] = dbus::types::Variant::encode(md.get(xesam::Title::name));
658- if (has_album_name)
659- dict[xesam::Album::name] = dbus::types::Variant::encode(md.get(xesam::Album::name));
660- if (has_artist_name)
661- dict[xesam::Artist::name] = dbus::types::Variant::encode(md.get(xesam::Artist::name));
662-
663- dict[mpris::metadata::ArtUrl::name] = dbus::types::Variant::encode(
664- cover_art_resolver(
665- has_title ? md.get(xesam::Title::name) : "",
666- has_album_name ? md.get(xesam::Album::name) : "",
667- has_artist_name ? md.get(xesam::Artist::name) : ""));
668-
669- mpris::Player::Dictionary wrap;
670- wrap[mpris::Player::Properties::Metadata::name()] = dbus::types::Variant::encode(dict);
671-
672- player.signals.properties_changed->emit(
673- std::make_tuple(
674- dbus::traits::Service<
675- mpris::Player::Properties::Metadata::Interface>
676- ::interface_name(),
677- wrap,
678- std::vector<std::string>()));
679- });
680-#endif
681 }
682
683 void reset_current_player()
684@@ -807,6 +785,7 @@
685 connections.can_pause_changed = the_empty_signal.connect([](){});
686 connections.can_go_previous_changed = the_empty_signal.connect([](){});
687 connections.can_go_next_changed = the_empty_signal.connect([](){});
688+ connections.meta_data_changed = the_empty_signal.connect([](){});
689 }
690
691 bool is_current_player(media::Player::PlayerKey key)

Subscribers

People subscribed via source and target branches

to all changes: