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
=== modified file 'include/core/media/track.h'
--- include/core/media/track.h 2015-07-02 12:30:09 +0000
+++ include/core/media/track.h 2016-06-09 16:54:40 +0000
@@ -39,10 +39,15 @@
39public:39public:
40 typedef std::string UriType;40 typedef std::string UriType;
41 typedef std::string Id;41 typedef std::string Id;
42 typedef std::map<std::string, std::string> MetaDataType;
4243
43 class MetaData44 class MetaData
44 {45 {
45 public:46 public:
47 static constexpr const char* TrackArtlUrlKey = "mpris:artUrl";
48 static constexpr const char* TrackLengthKey = "mpris:length";
49 static constexpr const char* TrackIdKey = "mpris:trackid";
50
46 bool operator==(const MetaData& rhs) const51 bool operator==(const MetaData& rhs) const
47 {52 {
48 return map == rhs.map;53 return map == rhs.map;
@@ -90,13 +95,36 @@
90 return map.at(key);95 return map.at(key);
91 }96 }
9297
98 bool is_set(const std::string& key) const
99 {
100 try {
101 return map.at(key).empty();
102 } catch (const std::out_of_range& e) {
103 return false;
104 }
105 }
106
93 const std::map<std::string, std::string>& operator*() const107 const std::map<std::string, std::string>& operator*() const
94 {108 {
95 return map;109 return map;
96 }110 }
97111
112 const std::string& album() const;
113 const std::string& artist() const;
114 const std::string& title() const;
115 const std::string& track_id() const;
116 const std::string& art_url() const;
117 const std::string& last_used() const;
118
119 void set_album(const std::string& album);
120 void set_artist(const std::string& artist);
121 void set_title(const std::string& title);
122 void set_track_id(const std::string& id);
123 void set_art_url(const std::string& url);
124 void set_last_used(const std::string& datetime);
125
98 private:126 private:
99 std::map<std::string, std::string> map;127 MetaDataType map;
100 };128 };
101129
102 Track(const Id& id);130 Track(const Id& id);
@@ -108,51 +136,7 @@
108136
109 virtual const Id& id() const;137 virtual const Id& id() const;
110 virtual const UriType& uri() const;138 virtual const UriType& uri() const;
111 /*139
112 class MetaData
113 {
114 public:
115 MetaData() = default;
116 MetaData(const MetaData&) = default;
117 ~MetaData() = default;
118
119 MetaData& operator=(const MetaData&) = default;
120
121 bool operator==(const MetaData&) const
122 {
123 return true;
124 }
125
126 bool operator!=(const MetaData&) const
127 {
128 return false;
129 }
130
131 struct NotImplementedFields
132 {
133 NotImplementedFields() = default;
134
135 virtual const UriType& uri() const = 0;
136 virtual const std::chrono::microseconds length() const = 0;
137 virtual const UriType& art_uri() const = 0;
138 virtual const std::string& album() const = 0;
139 virtual const std::vector<std::string>& album_artist() const = 0;
140 virtual const std::vector<std::string>& artist() const = 0;
141 virtual const std::string& as_text() const = 0;
142 virtual unsigned int audio_bpm() const = 0;
143 virtual float auto_rating() const = 0;
144 virtual const std::vector<std::string>& comment() const = 0;
145 virtual const std::vector<std::string>& composer() const = 0;
146 virtual unsigned int disc_number() const = 0;
147 virtual const std::vector<std::string>& genre() const = 0;
148 virtual const std::vector<std::string>& lyricist() const = 0;
149 virtual const std::string title() const = 0;
150 virtual unsigned int track_number() const = 0;
151 virtual unsigned int use_count() const = 0;
152 virtual float user_rating() const = 0;
153 };
154 };
155*/
156private:140private:
157 struct Private;141 struct Private;
158 std::unique_ptr<Private> d;142 std::unique_ptr<Private> d;
159143
=== modified file 'src/core/media/CMakeLists.txt'
--- src/core/media/CMakeLists.txt 2016-04-05 15:40:11 +0000
+++ src/core/media/CMakeLists.txt 2016-06-09 16:54:40 +0000
@@ -49,6 +49,7 @@
49 service.cpp49 service.cpp
50 track.cpp50 track.cpp
51 track_list.cpp51 track_list.cpp
52 metadata.cpp
5253
53 player_stub.cpp54 player_stub.cpp
54 service_stub.cpp55 service_stub.cpp
@@ -99,6 +100,7 @@
99 hybris_client_death_observer.cpp100 hybris_client_death_observer.cpp
100 cover_art_resolver.cpp101 cover_art_resolver.cpp
101 engine.cpp102 engine.cpp
103 metadata.cpp
102104
103 apparmor/context.cpp105 apparmor/context.cpp
104 apparmor/ubuntu.cpp106 apparmor/ubuntu.cpp
105107
=== modified file 'src/core/media/codec.h'
--- src/core/media/codec.h 2015-04-14 19:11:15 +0000
+++ src/core/media/codec.h 2016-06-09 16:54:40 +0000
@@ -23,10 +23,18 @@
23#include <core/media/player.h>23#include <core/media/player.h>
24#include <core/media/track.h>24#include <core/media/track.h>
2525
26#include <core/dbus/types/stl/map.h>
26#include <core/dbus/types/stl/string.h>27#include <core/dbus/types/stl/string.h>
28#include <core/dbus/types/variant.h>
27#include <core/dbus/types/stl/vector.h>29#include <core/dbus/types/stl/vector.h>
28#include <core/dbus/codec.h>30#include <core/dbus/codec.h>
2931
32#include <boost/lexical_cast.hpp>
33
34#include "core/media/xesam.h"
35
36#include "core/media/logger/logger.h"
37
30namespace core38namespace core
31{39{
32namespace dbus40namespace dbus
@@ -38,7 +46,7 @@
38{46{
39 constexpr static ArgumentType type_value()47 constexpr static ArgumentType type_value()
40 {48 {
41 return ArgumentType::floating_point;49 return ArgumentType::array;
42 }50 }
43 constexpr static bool is_basic_type()51 constexpr static bool is_basic_type()
44 {52 {
@@ -51,7 +59,7 @@
5159
52 static std::string signature()60 static std::string signature()
53 {61 {
54 static const std::string s = TypeMapper<double>::signature();62 static const std::string s = TypeMapper<std::map<std::string, dbus::types::Variant>>::signature();
55 return s;63 return s;
56 }64 }
57};65};
@@ -60,16 +68,83 @@
60template<>68template<>
61struct Codec<core::ubuntu::media::Track::MetaData>69struct Codec<core::ubuntu::media::Track::MetaData>
62{70{
63 static void encode_argument(core::dbus::Message::Writer& out, const core::ubuntu::media::Track::MetaData& in)71 static void encode_argument(core::dbus::Message::Writer& writer, const core::ubuntu::media::Track::MetaData& md)
64 {72 {
65 (void) out;73 typedef std::pair<std::string, dbus::types::Variant> Pair;
66 (void) in;74 auto dict = writer.open_array(dbus::types::Signature
75 {dbus::helper::TypeMapper<Pair>::signature()});
76
77 for (const auto& pair : *md)
78 {
79 auto de = dict.open_dict_entry();
80 {
81 if (pair.first == core::ubuntu::media::Track::MetaData::TrackLengthKey
82 and not pair.second.empty())
83 {
84 Codec<Pair>::encode_argument(de, std::make_pair(pair.first,
85 dbus::types::Variant::encode(
86 boost::lexical_cast<std::int64_t>(pair.second))));
87 }
88 else if (pair.first == xesam::Album::name and not pair.second.empty())
89 {
90 Codec<Pair>::encode_argument(de, std::make_pair(pair.first,
91 dbus::types::Variant::encode(pair.second)));
92 }
93 else if (pair.first == xesam::AlbumArtist::name and not pair.second.empty())
94 {
95#if 0
96 // TODO: This code doesn't work but will be needed for full MPRIS compliance.
97 // Technically there can be more than one album artist stuffed into an array.
98 // How to satisfy stuffing this data into dbus-cpp is what needs fixing.
99 auto array = de.open_array(dbus::types::Signature
100 {dbus::helper::TypeMapper<Pair>::signature()});
101 {
102 // TODO: this should really iterate over all artists, but seems
103 // we only extract one artist from playbin
104 Codec<Pair>::encode_argument(array, std::make_pair(pair.first,
105 dbus::types::Variant::encode(pair.second)));
106 }
107 de.close_array(std::move(array));
108#else
109 Codec<Pair>::encode_argument(de, std::make_pair(pair.first,
110 dbus::types::Variant::encode(pair.second)));
111#endif
112 }
113 else
114 {
115 Codec<Pair>::encode_argument(de, std::make_pair(pair.first,
116 dbus::types::Variant::encode(pair.second)));
117 }
118 }
119 dict.close_dict_entry(std::move(de));
120 }
121 writer.close_array(std::move(dict));
67 }122 }
68123
69 static void decode_argument(core::dbus::Message::Reader& out, core::ubuntu::media::Track::MetaData& in)124 static void decode_argument(core::dbus::Message::Reader& reader, core::ubuntu::media::Track::MetaData& md)
70 {125 {
71 (void) out;126 auto array = reader.pop_array();
72 (void) in;127
128 while (array.type() != dbus::ArgumentType::invalid)
129 {
130 auto entry = array.pop_dict_entry();
131 {
132 std::string key {entry.pop_string()};
133 auto variant = entry.pop_variant();
134 {
135 if (key == xesam::Album::name)
136 {
137 const std::string album = variant.pop_string();
138 MH_DEBUG("Getting key \"%s\" and value \"%s\"", key, album);
139 md.set_album(album);
140 }
141 else
142 {
143 MH_WARNING("Unknown metadata key \"%s\" while decoding dbus message", key);
144 }
145 }
146 }
147 }
73 }148 }
74};149};
75150
76151
=== modified file 'src/core/media/cover_art_resolver.cpp'
--- src/core/media/cover_art_resolver.cpp 2014-09-09 14:02:52 +0000
+++ src/core/media/cover_art_resolver.cpp 2016-06-09 16:54:40 +0000
@@ -22,6 +22,6 @@
22{22{
23 return [](const std::string&, const std::string&, const std::string&)23 return [](const std::string&, const std::string&, const std::string&)
24 {24 {
25 return "file:///usr/share/unity/icons/album_missing.png";25 return "file:///usr/lib/arm-linux-gnueabihf/unity-scopes/mediascanner-music/album_missing.svg";
26 };26 };
27}27}
2828
=== modified file 'src/core/media/gstreamer/meta_data_extractor.h'
--- src/core/media/gstreamer/meta_data_extractor.h 2015-09-23 11:17:26 +0000
+++ src/core/media/gstreamer/meta_data_extractor.h 2016-06-09 16:54:40 +0000
@@ -24,6 +24,8 @@
2424
25#include "bus.h"25#include "bus.h"
2626
27#include "core/media/logger/logger.h"
28
27#include <gst/gst.h>29#include <gst/gst.h>
2830
29#include <exception>31#include <exception>
@@ -72,7 +74,7 @@
72 auto md = static_cast<media::Track::MetaData*>(user_data);74 auto md = static_cast<media::Track::MetaData*>(user_data);
73 std::stringstream ss;75 std::stringstream ss;
7476
75 switch(gst_tag_get_type(tag))77 switch (gst_tag_get_type(tag))
76 {78 {
77 case G_TYPE_BOOLEAN:79 case G_TYPE_BOOLEAN:
78 {80 {
@@ -137,8 +139,7 @@
137 break;139 break;
138 }140 }
139141
140 (*md).set(142 (*md).set( (gstreamer_to_mpris_tag_lut().count(tag) > 0 ? gstreamer_to_mpris_tag_lut().at(tag) : tag),
141 (gstreamer_to_mpris_tag_lut().count(tag) > 0 ? gstreamer_to_mpris_tag_lut().at(tag) : tag),
142 ss.str());143 ss.str());
143 },144 },
144 &md);145 &md);
145146
=== modified file 'src/core/media/gstreamer/playbin.cpp'
--- src/core/media/gstreamer/playbin.cpp 2016-04-06 15:28:29 +0000
+++ src/core/media/gstreamer/playbin.cpp 2016-06-09 16:54:40 +0000
@@ -30,8 +30,6 @@
3030
31#include <utility>31#include <utility>
3232
33//#define VERBOSE_DEBUG
34
35namespace33namespace
36{34{
37void setup_video_sink_for_buffer_streaming(GstElement* pipeline)35void setup_video_sink_for_buffer_streaming(GstElement* pipeline)
@@ -256,7 +254,7 @@
256254
257void gstreamer::Playbin::on_new_message_async(const Bus::Message& message)255void gstreamer::Playbin::on_new_message_async(const Bus::Message& message)
258{256{
259 switch(message.type)257 switch (message.type)
260 {258 {
261 case GST_MESSAGE_ERROR:259 case GST_MESSAGE_ERROR:
262 signals.on_error(message.detail.error_warning_info);260 signals.on_error(message.detail.error_warning_info);
263261
=== added file 'src/core/media/metadata.cpp'
--- src/core/media/metadata.cpp 1970-01-01 00:00:00 +0000
+++ src/core/media/metadata.cpp 2016-06-09 16:54:40 +0000
@@ -0,0 +1,83 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
17 */
18
19#include "xesam.h"
20
21#include <core/media/track.h>
22
23namespace media = core::ubuntu::media;
24
25const std::string& media::Track::MetaData::album() const
26{
27 return map.at(xesam::Album::name);
28}
29
30const std::string& media::Track::MetaData::artist() const
31{
32 return map.at(xesam::Artist::name);
33}
34
35const std::string& media::Track::MetaData::title() const
36{
37 return map.at(xesam::Title::name);
38}
39
40const std::string& media::Track::MetaData::track_id() const
41{
42 return map.at(media::Track::MetaData::TrackIdKey);
43}
44
45const std::string& media::Track::MetaData::art_url() const
46{
47 return map.at(media::Track::MetaData::TrackArtlUrlKey);
48}
49
50const std::string& media::Track::MetaData::last_used() const
51{
52 return map.at(xesam::LastUsed::name);
53}
54
55void media::Track::MetaData::set_album(const std::string& album)
56{
57 map[xesam::Album::name] = album;
58}
59
60void media::Track::MetaData::set_artist(const std::string& artist)
61{
62 map[xesam::Artist::name] = artist;
63}
64
65void media::Track::MetaData::set_title(const std::string& title)
66{
67 map[xesam::Title::name] = title;
68}
69
70void media::Track::MetaData::set_track_id(const std::string& id)
71{
72 map[media::Track::MetaData::TrackIdKey] = id;
73}
74
75void media::Track::MetaData::set_art_url(const std::string& url)
76{
77 map[media::Track::MetaData::TrackArtlUrlKey] = url;
78}
79
80void media::Track::MetaData::set_last_used(const std::string& datetime)
81{
82 map[xesam::LastUsed::name] = datetime;
83}
084
=== modified file 'src/core/media/mpris/player.h'
--- src/core/media/mpris/player.h 2016-02-19 16:14:42 +0000
+++ src/core/media/mpris/player.h 2016-06-09 16:54:40 +0000
@@ -44,6 +44,8 @@
4444
45#include <cstdint>45#include <cstdint>
4646
47#include "core/media/logger/logger.h"
48
47namespace dbus = core::dbus;49namespace dbus = core::dbus;
4850
49namespace mpris51namespace mpris
@@ -172,8 +174,7 @@
172 DBUS_CPP_WRITABLE_PROPERTY_DEF(PlaybackRate, Player, double)174 DBUS_CPP_WRITABLE_PROPERTY_DEF(PlaybackRate, Player, double)
173 DBUS_CPP_WRITABLE_PROPERTY_DEF(Rate, Player, double)175 DBUS_CPP_WRITABLE_PROPERTY_DEF(Rate, Player, double)
174 DBUS_CPP_WRITABLE_PROPERTY_DEF(Shuffle, Player, bool)176 DBUS_CPP_WRITABLE_PROPERTY_DEF(Shuffle, Player, bool)
175 DBUS_CPP_READABLE_PROPERTY_DEF(Metadata, Player, Dictionary)177 DBUS_CPP_READABLE_PROPERTY_DEF(Metadata, Player, core::ubuntu::media::Track::MetaData)
176 DBUS_CPP_READABLE_PROPERTY_DEF(TypedMetaData, Player, core::ubuntu::media::Track::MetaData)
177 DBUS_CPP_WRITABLE_PROPERTY_DEF(Volume, Player, double)178 DBUS_CPP_WRITABLE_PROPERTY_DEF(Volume, Player, double)
178 DBUS_CPP_READABLE_PROPERTY_DEF(Position, Player, std::int64_t)179 DBUS_CPP_READABLE_PROPERTY_DEF(Position, Player, std::int64_t)
179 DBUS_CPP_READABLE_PROPERTY_DEF(Duration, Player, std::int64_t)180 DBUS_CPP_READABLE_PROPERTY_DEF(Duration, Player, std::int64_t)
@@ -222,7 +223,7 @@
222 Properties::TypedLoopStatus::ValueType typed_loop_status{core::ubuntu::media::Player::LoopStatus::none};223 Properties::TypedLoopStatus::ValueType typed_loop_status{core::ubuntu::media::Player::LoopStatus::none};
223 Properties::PlaybackRate::ValueType playback_rate{1.f};224 Properties::PlaybackRate::ValueType playback_rate{1.f};
224 Properties::Shuffle::ValueType shuffle{false};225 Properties::Shuffle::ValueType shuffle{false};
225 Properties::TypedMetaData::ValueType typed_meta_data{};226 Properties::Metadata::ValueType meta_data{};
226 Properties::Volume::ValueType volume{0.f};227 Properties::Volume::ValueType volume{0.f};
227 Properties::Position::ValueType position{0};228 Properties::Position::ValueType position{0};
228 Properties::Duration::ValueType duration{0};229 Properties::Duration::ValueType duration{0};
@@ -253,7 +254,7 @@
253 configuration.object->template get_property<Properties::Lifetime>(),254 configuration.object->template get_property<Properties::Lifetime>(),
254 configuration.object->template get_property<Properties::PlaybackRate>(),255 configuration.object->template get_property<Properties::PlaybackRate>(),
255 configuration.object->template get_property<Properties::Shuffle>(),256 configuration.object->template get_property<Properties::Shuffle>(),
256 configuration.object->template get_property<Properties::TypedMetaData>(),257 configuration.object->template get_property<Properties::Metadata>(),
257 configuration.object->template get_property<Properties::Volume>(),258 configuration.object->template get_property<Properties::Volume>(),
258 configuration.object->template get_property<Properties::Position>(),259 configuration.object->template get_property<Properties::Position>(),
259 configuration.object->template get_property<Properties::Duration>(),260 configuration.object->template get_property<Properties::Duration>(),
@@ -288,6 +289,7 @@
288 properties.lifetime->set(core::ubuntu::media::Player::Lifetime::normal);289 properties.lifetime->set(core::ubuntu::media::Player::Lifetime::normal);
289 properties.playback_rate->set(configuration.defaults.playback_rate);290 properties.playback_rate->set(configuration.defaults.playback_rate);
290 properties.shuffle->set(configuration.defaults.shuffle);291 properties.shuffle->set(configuration.defaults.shuffle);
292 properties.meta_data_for_current_track->set(configuration.defaults.meta_data);
291 properties.position->set(configuration.defaults.position);293 properties.position->set(configuration.defaults.position);
292 properties.duration->set(configuration.defaults.duration);294 properties.duration->set(configuration.defaults.duration);
293 properties.minimum_playback_rate->set(configuration.defaults.minimum_rate);295 properties.minimum_playback_rate->set(configuration.defaults.minimum_rate);
@@ -351,9 +353,9 @@
351 Dictionary dict; dict[Property::name()] = dbus::types::Variant::encode(value);353 Dictionary dict; dict[Property::name()] = dbus::types::Variant::encode(value);
352354
353 signals.properties_changed->emit(std::make_tuple(355 signals.properties_changed->emit(std::make_tuple(
354 dbus::traits::Service<Player>::interface_name(),356 dbus::traits::Service<Player>::interface_name(),
355 dict,357 dict,
356 the_empty_list_of_invalidated_properties()));358 the_empty_list_of_invalidated_properties()));
357 }359 }
358360
359 Dictionary get_all_properties()361 Dictionary get_all_properties()
@@ -374,6 +376,7 @@
374 dict[Properties::Lifetime::name()] = dbus::types::Variant::encode(properties.lifetime->get());376 dict[Properties::Lifetime::name()] = dbus::types::Variant::encode(properties.lifetime->get());
375 dict[Properties::PlaybackRate::name()] = dbus::types::Variant::encode(properties.playback_rate->get());377 dict[Properties::PlaybackRate::name()] = dbus::types::Variant::encode(properties.playback_rate->get());
376 dict[Properties::Shuffle::name()] = dbus::types::Variant::encode(properties.shuffle->get());378 dict[Properties::Shuffle::name()] = dbus::types::Variant::encode(properties.shuffle->get());
379 dict[Properties::Metadata::name()] = dbus::types::Variant::encode(properties.meta_data_for_current_track->get());
377 dict[Properties::Duration::name()] = dbus::types::Variant::encode(properties.duration->get());380 dict[Properties::Duration::name()] = dbus::types::Variant::encode(properties.duration->get());
378 dict[Properties::Position::name()] = dbus::types::Variant::encode(properties.position->get());381 dict[Properties::Position::name()] = dbus::types::Variant::encode(properties.position->get());
379 dict[Properties::MinimumRate::name()] = dbus::types::Variant::encode(properties.minimum_playback_rate->get());382 dict[Properties::MinimumRate::name()] = dbus::types::Variant::encode(properties.minimum_playback_rate->get());
@@ -405,7 +408,7 @@
405 std::shared_ptr<core::dbus::Property<Properties::Lifetime>> lifetime;408 std::shared_ptr<core::dbus::Property<Properties::Lifetime>> lifetime;
406 std::shared_ptr<core::dbus::Property<Properties::PlaybackRate>> playback_rate;409 std::shared_ptr<core::dbus::Property<Properties::PlaybackRate>> playback_rate;
407 std::shared_ptr<core::dbus::Property<Properties::Shuffle>> shuffle;410 std::shared_ptr<core::dbus::Property<Properties::Shuffle>> shuffle;
408 std::shared_ptr<core::dbus::Property<Properties::TypedMetaData>> typed_meta_data_for_current_track;411 std::shared_ptr<core::dbus::Property<Properties::Metadata>> meta_data_for_current_track;
409 std::shared_ptr<core::dbus::Property<Properties::Volume>> volume;412 std::shared_ptr<core::dbus::Property<Properties::Volume>> volume;
410 std::shared_ptr<core::dbus::Property<Properties::Position>> position;413 std::shared_ptr<core::dbus::Property<Properties::Position>> position;
411 std::shared_ptr<core::dbus::Property<Properties::Duration>> duration;414 std::shared_ptr<core::dbus::Property<Properties::Duration>> duration;
412415
=== modified file 'src/core/media/player_implementation.cpp'
--- src/core/media/player_implementation.cpp 2016-05-03 19:08:00 +0000
+++ src/core/media/player_implementation.cpp 2016-06-09 16:54:40 +0000
@@ -24,6 +24,7 @@
24#include "util/timeout.h"24#include "util/timeout.h"
2525
26#include <unistd.h>26#include <unistd.h>
27#include <ctime>
2728
28#include "client_death_observer.h"29#include "client_death_observer.h"
29#include "engine.h"30#include "engine.h"
@@ -138,9 +139,19 @@
138 }139 }
139 case Engine::State::playing:140 case Engine::State::playing:
140 {141 {
141 // We update the track meta data prior to updating the playback status.142 // We update the track metadata prior to updating the playback status.
142 // Some MPRIS clients expect this order of events.143 // Some MPRIS clients expect this order of events.
143 parent->meta_data_for_current_track().set(std::get<1>(engine->track_meta_data().get()));144 time_t now;
145 time(&now);
146 char buf[sizeof("2011-10-08T07:07:09Z")];
147 strftime(buf, sizeof(buf), "%FT%TZ", gmtime(&now));
148 media::Track::MetaData metadata{std::get<1>(engine->track_meta_data().get())};
149 // Setting this with second resolution makes sure that the track_meta_data property changes
150 // and thus the track_meta_data().changed() signal gets sent out over dbus. Otherwise the
151 // Property caching mechanism would prevent this.
152 metadata.set_last_used(std::string{buf});
153 update_mpris_metadata(metadata);
154
144 // And update our playback status.155 // And update our playback status.
145 parent->playback_status().set(media::Player::playing);156 parent->playback_status().set(media::Player::playing);
146 MH_INFO("Requesting power state");157 MH_INFO("Requesting power state");
@@ -325,6 +336,27 @@
325 parent->can_go_next().set(has_next);336 parent->can_go_next().set(has_next);
326 }337 }
327338
339 // Makes sure all relevant metadata fields are set to current data and
340 // will trigger the track_meta_data().changed() signal to go out over dbus
341 void update_mpris_metadata(const media::Track::MetaData& md)
342 {
343 media::Track::MetaData metadata{md};
344 if (not metadata.is_set(media::Track::MetaData::TrackIdKey))
345 {
346 const std::size_t last_slash = track_list->current().find_last_of("/");
347 const std::string track_id = track_list->current().substr(last_slash+1);
348 if (not track_id.empty())
349 metadata.set_track_id("/org/mpris/MediaPlayer2/Track/" + track_id);
350 else
351 MH_WARNING("Failed to set MPRIS track id since the id value is NULL");
352 }
353 // TODO: This needs to be extracted from GStreamer and dynamically set
354 if (not metadata.is_set(media::Track::MetaData::TrackArtlUrlKey))
355 metadata.set_art_url("file:///usr/lib/arm-linux-gnueabihf/unity-scopes/mediascanner-music/album_missing.svg");
356
357 parent->meta_data_for_current_track().set(metadata);
358 }
359
328 bool pause_other_players(media::Player::PlayerKey key)360 bool pause_other_players(media::Player::PlayerKey key)
329 {361 {
330 if (not config.parent.player_service)362 if (not config.parent.player_service)
@@ -501,6 +533,12 @@
501 d->engine->lifetime().set(lifetime);533 d->engine->lifetime().set(lifetime);
502 });534 });
503535
536 d->engine->track_meta_data().changed().connect([this, config](
537 const std::tuple<media::Track::UriType, media::Track::MetaData>& md)
538 {
539 d->update_mpris_metadata(std::get<1>(md));
540 });
541
504 d->engine->about_to_finish_signal().connect([this]()542 d->engine->about_to_finish_signal().connect([this]()
505 {543 {
506 if (d->doing_abandon)544 if (d->doing_abandon)
507545
=== modified file 'src/core/media/player_skeleton.cpp'
--- src/core/media/player_skeleton.cpp 2016-04-06 15:28:29 +0000
+++ src/core/media/player_skeleton.cpp 2016-06-09 16:54:40 +0000
@@ -478,7 +478,7 @@
478478
479const core::Property<media::Track::MetaData>& media::PlayerSkeleton::meta_data_for_current_track() const479const core::Property<media::Track::MetaData>& media::PlayerSkeleton::meta_data_for_current_track() const
480{480{
481 return *d->skeleton.properties.typed_meta_data_for_current_track;481 return *d->skeleton.properties.meta_data_for_current_track;
482}482}
483483
484const core::Property<media::Player::Volume>& media::PlayerSkeleton::volume() const484const core::Property<media::Player::Volume>& media::PlayerSkeleton::volume() const
@@ -608,7 +608,7 @@
608608
609core::Property<media::Track::MetaData>& media::PlayerSkeleton::meta_data_for_current_track()609core::Property<media::Track::MetaData>& media::PlayerSkeleton::meta_data_for_current_track()
610{610{
611 return *d->skeleton.properties.typed_meta_data_for_current_track;611 return *d->skeleton.properties.meta_data_for_current_track;
612}612}
613613
614core::Property<media::Player::PlaybackRate>& media::PlayerSkeleton::minimum_playback_rate()614core::Property<media::Player::PlaybackRate>& media::PlayerSkeleton::minimum_playback_rate()
615615
=== modified file 'src/core/media/player_stub.cpp'
--- src/core/media/player_stub.cpp 2016-04-06 15:28:29 +0000
+++ src/core/media/player_stub.cpp 2016-06-09 16:54:40 +0000
@@ -70,7 +70,7 @@
70 object->get_property<mpris::Player::Properties::TypedLoopStatus>(),70 object->get_property<mpris::Player::Properties::TypedLoopStatus>(),
71 object->get_property<mpris::Player::Properties::PlaybackRate>(),71 object->get_property<mpris::Player::Properties::PlaybackRate>(),
72 object->get_property<mpris::Player::Properties::Shuffle>(),72 object->get_property<mpris::Player::Properties::Shuffle>(),
73 object->get_property<mpris::Player::Properties::TypedMetaData>(),73 object->get_property<mpris::Player::Properties::Metadata>(),
74 object->get_property<mpris::Player::Properties::Volume>(),74 object->get_property<mpris::Player::Properties::Volume>(),
75 object->get_property<mpris::Player::Properties::Position>(),75 object->get_property<mpris::Player::Properties::Position>(),
76 object->get_property<mpris::Player::Properties::Duration>(),76 object->get_property<mpris::Player::Properties::Duration>(),
@@ -118,7 +118,7 @@
118 std::shared_ptr<core::dbus::Property<mpris::Player::Properties::TypedLoopStatus>> loop_status;118 std::shared_ptr<core::dbus::Property<mpris::Player::Properties::TypedLoopStatus>> loop_status;
119 std::shared_ptr<core::dbus::Property<mpris::Player::Properties::PlaybackRate>> playback_rate;119 std::shared_ptr<core::dbus::Property<mpris::Player::Properties::PlaybackRate>> playback_rate;
120 std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Shuffle>> shuffle;120 std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Shuffle>> shuffle;
121 std::shared_ptr<core::dbus::Property<mpris::Player::Properties::TypedMetaData>> meta_data_for_current_track;121 std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Metadata>> meta_data_for_current_track;
122 std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Volume>> volume;122 std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Volume>> volume;
123 std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Position>> position;123 std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Position>> position;
124 std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Duration>> duration;124 std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Duration>> duration;
125125
=== modified file 'src/core/media/service_skeleton.cpp'
--- src/core/media/service_skeleton.cpp 2016-05-17 17:51:16 +0000
+++ src/core/media/service_skeleton.cpp 2016-06-09 16:54:40 +0000
@@ -732,6 +732,21 @@
732 player.properties.can_go_next->set(can_go_next);732 player.properties.can_go_next->set(can_go_next);
733 });733 });
734734
735 // NOTE: the metadata first gets updated in the PlayerImplementation constructor which connects
736 // and reacts to the Engine track_meta_data changed signal. Setting the
737 // meta_data_for_current_track here makes sure that the signal uses the MPRIS object path
738 connections.meta_data_changed = player_sp->meta_data_for_current_track().changed().connect(
739 [this](const media::Track::MetaData& metadata)
740 {
741 player.properties.meta_data_for_current_track->set(metadata);
742 mpris::Player::Dictionary dict; dict[mpris::Player::Properties::Metadata::name()]
743 = dbus::types::Variant::encode(metadata);
744 player.signals.properties_changed->emit(std::make_tuple(
745 dbus::traits::Service<mpris::Player>::interface_name(),
746 dict,
747 mpris::Player::Skeleton::the_empty_list_of_invalidated_properties()));
748 });
749
735 // Sync property values between session and player mpris::Player instances750 // Sync property values between session and player mpris::Player instances
736 // TODO Getters from media::Player actually return values from a751 // TODO Getters from media::Player actually return values from a
737 // mpris::Player::Skeleton instance different from "player". Each of them use752 // mpris::Player::Skeleton instance different from "player". Each of them use
@@ -748,43 +763,6 @@
748 player.properties.can_pause->set(player_sp->can_pause().get());763 player.properties.can_pause->set(player_sp->can_pause().get());
749 player.properties.can_go_previous->set(player_sp->can_go_previous().get());764 player.properties.can_go_previous->set(player_sp->can_go_previous().get());
750 player.properties.can_go_next->set(player_sp->can_go_next().get());765 player.properties.can_go_next->set(player_sp->can_go_next().get());
751
752#if 0
753 // TODO cover_art_resolver() is not implemented yet
754 connections.meta_data_changed = cp->meta_data_for_current_track().changed().connect(
755 [this](const core::ubuntu::media::Track::MetaData& md)
756 {
757 mpris::Player::Dictionary dict;
758
759 bool has_title = md.count(xesam::Title::name) > 0;
760 bool has_album_name = md.count(xesam::Album::name) > 0;
761 bool has_artist_name = md.count(xesam::Artist::name) > 0;
762
763 if (has_title)
764 dict[xesam::Title::name] = dbus::types::Variant::encode(md.get(xesam::Title::name));
765 if (has_album_name)
766 dict[xesam::Album::name] = dbus::types::Variant::encode(md.get(xesam::Album::name));
767 if (has_artist_name)
768 dict[xesam::Artist::name] = dbus::types::Variant::encode(md.get(xesam::Artist::name));
769
770 dict[mpris::metadata::ArtUrl::name] = dbus::types::Variant::encode(
771 cover_art_resolver(
772 has_title ? md.get(xesam::Title::name) : "",
773 has_album_name ? md.get(xesam::Album::name) : "",
774 has_artist_name ? md.get(xesam::Artist::name) : ""));
775
776 mpris::Player::Dictionary wrap;
777 wrap[mpris::Player::Properties::Metadata::name()] = dbus::types::Variant::encode(dict);
778
779 player.signals.properties_changed->emit(
780 std::make_tuple(
781 dbus::traits::Service<
782 mpris::Player::Properties::Metadata::Interface>
783 ::interface_name(),
784 wrap,
785 std::vector<std::string>()));
786 });
787#endif
788 }766 }
789767
790 void reset_current_player()768 void reset_current_player()
@@ -807,6 +785,7 @@
807 connections.can_pause_changed = the_empty_signal.connect([](){});785 connections.can_pause_changed = the_empty_signal.connect([](){});
808 connections.can_go_previous_changed = the_empty_signal.connect([](){});786 connections.can_go_previous_changed = the_empty_signal.connect([](){});
809 connections.can_go_next_changed = the_empty_signal.connect([](){});787 connections.can_go_next_changed = the_empty_signal.connect([](){});
788 connections.meta_data_changed = the_empty_signal.connect([](){});
810 }789 }
811790
812 bool is_current_player(media::Player::PlayerKey key)791 bool is_current_player(media::Player::PlayerKey key)

Subscribers

People subscribed via source and target branches

to all changes: