Music Hub ..
A session-wide music playback service
track_list_stub.cpp
Go to the documentation of this file.
1/*
2 * Copyright © 2013 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: Thomas Voß <thomas.voss@canonical.com>
17 */
18
19#include "track_list_stub.h"
20
21#include <core/media/player.h>
23
24#include "property_stub.h"
25#include "track_list_traits.h"
26#include "the_session_bus.h"
27
28#include "mpris/player.h"
29#include "mpris/track_list.h"
30
32
33#include <core/dbus/property.h>
34#include <core/dbus/types/object_path.h>
35#include <core/dbus/types/variant.h>
36#include <core/dbus/types/stl/map.h>
37#include <core/dbus/types/stl/vector.h>
38
39#include <limits>
40
41namespace dbus = core::dbus;
42namespace media = core::ubuntu::media;
43
45{
48 const std::shared_ptr<media::Player>& parent,
49 const dbus::Object::Ptr& object)
50 : impl(impl),
53 can_edit_tracks(object->get_property<mpris::TrackList::Properties::CanEditTracks>()),
54 tracks(object->get_property<mpris::TrackList::Properties::Tracks>()),
56 {
57 object->get_signal<mpris::TrackList::Signals::TrackAdded>(),
58 object->get_signal<mpris::TrackList::Signals::TracksAdded>(),
59 object->get_signal<mpris::TrackList::Signals::TrackMoved>(),
60 object->get_signal<mpris::TrackList::Signals::TrackRemoved>(),
61 object->get_signal<mpris::TrackList::Signals::TrackListReset>(),
62 object->get_signal<mpris::TrackList::Signals::TrackListReplaced>(),
63 object->get_signal<mpris::TrackList::Signals::TrackChanged>()
64 }
65 {
66 }
67
69 std::shared_ptr<media::Player> parent;
70 dbus::Object::Ptr object;
71
72 std::shared_ptr<core::dbus::Property<mpris::TrackList::Properties::CanEditTracks>> can_edit_tracks;
73 std::shared_ptr<core::dbus::Property<mpris::TrackList::Properties::Tracks>> tracks;
74
75
76 struct Signals
77 {
78 typedef core::dbus::Signal<mpris::TrackList::Signals::TrackAdded, mpris::TrackList::Signals::TrackAdded::ArgumentType> DBusTrackAddedSignal;
79 typedef core::dbus::Signal<mpris::TrackList::Signals::TracksAdded, mpris::TrackList::Signals::TracksAdded::ArgumentType> DBusTracksAddedSignal;
80 typedef core::dbus::Signal<mpris::TrackList::Signals::TrackMoved, mpris::TrackList::Signals::TrackMoved::ArgumentType> DBusTrackMovedSignal;
81 typedef core::dbus::Signal<mpris::TrackList::Signals::TrackRemoved, mpris::TrackList::Signals::TrackRemoved::ArgumentType> DBusTrackRemovedSignal;
82 typedef core::dbus::Signal<
83 mpris::TrackList::Signals::TrackListReset,
84 mpris::TrackList::Signals::TrackListReset::ArgumentType>
86 typedef core::dbus::Signal<mpris::TrackList::Signals::TrackListReplaced, mpris::TrackList::Signals::TrackListReplaced::ArgumentType> DBusTrackListReplacedSignal;
87 typedef core::dbus::Signal<mpris::TrackList::Signals::TrackChanged, mpris::TrackList::Signals::TrackChanged::ArgumentType> DBusTrackChangedSignal;
88
89 Signals(const std::shared_ptr<DBusTrackAddedSignal>& track_added,
90 const std::shared_ptr<DBusTracksAddedSignal>& tracks_added,
91 const std::shared_ptr<DBusTrackMovedSignal>& track_moved,
92 const std::shared_ptr<DBusTrackRemovedSignal>& track_removed,
93 const std::shared_ptr<DBusTrackListResetSignal>& track_list_reset,
94 const std::shared_ptr<DBusTrackListReplacedSignal>& track_list_replaced,
95 const std::shared_ptr<DBusTrackChangedSignal>& track_changed)
103 dbus
104 {
105 track_added,
106 tracks_added,
107 track_moved,
108 track_removed,
109 track_list_reset,
110 track_list_replaced,
111 track_changed,
112 }
113 {
114 dbus.on_track_added->connect([this](const Track::Id& id)
115 {
116 MH_DEBUG("OnTrackAdded signal arrived via the bus.");
117 on_track_added(id);
118 });
119
120 dbus.on_tracks_added->connect([this](const media::TrackList::ContainerURI& tracks)
121 {
122 MH_DEBUG("OnTracksAdded signal arrived via the bus.");
124 });
125
126 dbus.on_track_moved->connect([this](const media::TrackList::TrackIdTuple& ids)
127 {
128 MH_DEBUG("OnTrackMoved signal arrived via the bus.");
129 on_track_moved(ids);
130 });
131
132 dbus.on_track_removed->connect([this](const Track::Id& id)
133 {
134 MH_DEBUG("OnTrackRemoved signal arrived via the bus.");
136 });
137
138 dbus.on_track_list_reset->connect([this](void)
139 {
140 MH_DEBUG("OnTrackListReset signal arrived via the bus.");
142 });
143
144 dbus.on_track_list_replaced->connect([this](const media::TrackList::ContainerTrackIdTuple& list)
145 {
146 MH_DEBUG("OnTrackListReplaced signal arrived via the bus.");
148 });
149
150 dbus.on_track_changed->connect([this](const Track::Id& id)
151 {
152 MH_DEBUG("OnTrackChanged signal arrived via the bus.");
154 });
155 }
156
157 core::Signal<Track::Id> on_track_added;
158 core::Signal<media::TrackList::ContainerURI> on_tracks_added;
159 core::Signal<media::TrackList::TrackIdTuple> on_track_moved;
160 core::Signal<Track::Id> on_track_removed;
161 core::Signal<void> on_track_list_reset;
162 core::Signal<media::TrackList::ContainerTrackIdTuple> on_track_list_replaced;
163 core::Signal<Track::Id> on_track_changed;
164 core::Signal<Track::Id> on_go_to_track;
165 core::Signal<void> on_end_of_tracklist;
166
167 struct DBus
168 {
169 std::shared_ptr<DBusTrackAddedSignal> on_track_added;
170 std::shared_ptr<DBusTracksAddedSignal> on_tracks_added;
171 std::shared_ptr<DBusTrackMovedSignal> on_track_moved;
172 std::shared_ptr<DBusTrackRemovedSignal> on_track_removed;
173 std::shared_ptr<DBusTrackListResetSignal> on_track_list_reset;
174 std::shared_ptr<DBusTrackListReplacedSignal> on_track_list_replaced;
175 std::shared_ptr<DBusTrackChangedSignal> on_track_changed;
178};
179
181 const std::shared_ptr<media::Player>& parent,
182 const core::dbus::Object::Ptr& object)
183 : d(new Private(this, parent, object))
184{
185}
186
188{
189}
190
191const core::Property<bool>& media::TrackListStub::can_edit_tracks() const
192{
193 return *d->can_edit_tracks;
194}
195
196const core::Property<media::TrackList::Container>& media::TrackListStub::tracks() const
197{
198 return *d->tracks;
199}
200
202{
203 auto op = d->object->invoke_method_synchronously<
204 mpris::TrackList::GetTracksMetadata,
205 std::map<std::string, std::string>>(id);
206
207 if (op.is_error())
208 throw std::runtime_error("Problem querying meta data for track: " + op.error());
209
210 media::Track::MetaData md;
211 for(auto pair : op.value())
212 {
213 md.set(pair.first, pair.second);
214 }
215 return md;
216}
217
219{
220 auto op = d->object->invoke_method_synchronously<
221 mpris::TrackList::GetTracksUri,
222 std::string>(id);
223
224 if (op.is_error())
225 throw std::runtime_error("Problem querying track for uri: " + op.error());
226
227 return op.value();
228}
229
231 const media::Track::UriType& uri,
232 const media::Track::Id& position,
233 bool make_current)
234{
235 auto op = d->object->invoke_method_synchronously<mpris::TrackList::AddTrack, void>(
236 uri,
237 position,
238 make_current);
239
240 if (op.is_error())
241 {
242 if (op.error().name() ==
244 throw media::TrackList::Errors::InsufficientPermissionsToAddTrack{};
245 else if (op.error().name() == mpris::Player::Error::UriNotFound::name)
246 throw media::Player::Errors::UriNotFound{op.error().print()};
247 else
248 throw std::runtime_error{op.error().print()};
249 }
250}
251
253{
254 auto op = d->object->invoke_method_synchronously<mpris::TrackList::AddTracks, void>(
255 uris,
256 position);
257
258 if (op.is_error())
259 {
260 if (op.error().name() ==
262 throw media::TrackList::Errors::InsufficientPermissionsToAddTrack{};
263 else if (op.error().name() == mpris::Player::Error::UriNotFound::name)
264 throw media::Player::Errors::UriNotFound{op.error().print()};
265 else
266 throw std::runtime_error{op.error().print()};
267 }
268}
269
271{
272 auto op = d->object->invoke_method_synchronously<mpris::TrackList::MoveTrack, void>(id, to);
273
274 if (op.is_error())
275 {
276 if (op.error().name() ==
278 throw media::TrackList::Errors::FailedToMoveTrack{};
279 else if (op.error().name() ==
281 throw media::TrackList::Errors::FailedToFindMoveTrackSource{op.error().print()};
282 else if (op.error().name() ==
284 throw media::TrackList::Errors::FailedToFindMoveTrackDest{op.error().print()};
285 else
286 throw std::runtime_error{op.error().print()};
287
288 return false;
289 }
290
291 return true;
292}
293
295{
296 auto op = d->object->invoke_method_synchronously<mpris::TrackList::RemoveTrack, void>(
297 track);
298
299 if (op.is_error())
300 {
301 if (op.error().name() ==
303 throw media::TrackList::Errors::TrackNotFound{};
304 else
305 throw std::runtime_error{"Problem removing track: " + op.error().print()};
306 }
307}
308
310{
311 auto op = d->object->invoke_method_synchronously<mpris::TrackList::GoTo, void>(track);
312
313 if (op.is_error())
314 throw std::runtime_error("Problem adding track: " + op.error());
315}
316
318{
319 // TODO: Add this to the dbus interface on the server and implement a proper dbus method call
320 return media::Track::Id{"/empty/track/id"};
321}
322
324{
325 // TODO: Add this to the dbus interface on the server and implement a proper dbus method call
326 return media::Track::Id{"/empty/track/id"};
327}
328
330{
331 auto op = d->object->invoke_method_synchronously<mpris::TrackList::Reset, void>();
332
333 if (op.is_error())
334 throw std::runtime_error("Problem resetting tracklist: " + op.error());
335}
336
337const core::Signal<media::TrackList::ContainerTrackIdTuple>& media::TrackListStub::on_track_list_replaced() const
338{
339 return d->signals.on_track_list_replaced;
340}
341
342const core::Signal<media::Track::Id>& media::TrackListStub::on_track_added() const
343{
344 return d->signals.on_track_added;
345}
346
347const core::Signal<media::TrackList::ContainerURI>& media::TrackListStub::on_tracks_added() const
348{
349 return d->signals.on_tracks_added;
350}
351
352const core::Signal<media::TrackList::TrackIdTuple>& media::TrackListStub::on_track_moved() const
353{
354 return d->signals.on_track_moved;
355}
356
357const core::Signal<media::Track::Id>& media::TrackListStub::on_track_removed() const
358{
359 return d->signals.on_track_removed;
360}
361
362const core::Signal<void>& media::TrackListStub::on_track_list_reset() const
363{
364 return d->signals.on_track_list_reset;
365}
366
367const core::Signal<media::Track::Id>& media::TrackListStub::on_track_changed() const
368{
369 return d->signals.on_track_changed;
370}
371
372const core::Signal<media::Track::Id>& media::TrackListStub::on_go_to_track() const
373{
374 return d->signals.on_go_to_track;
375}
376
377const core::Signal<void>& media::TrackListStub::on_end_of_tracklist() const
378{
379 return d->signals.on_end_of_tracklist;
380}
const core::Signal< Track::Id > & on_track_removed() const
TrackListStub(const std::shared_ptr< Player > &parent, const core::dbus::Object::Ptr &object)
void add_tracks_with_uri_at(const ContainerURI &uris, const Track::Id &position)
void add_track_with_uri_at(const Track::UriType &uri, const Track::Id &position, bool make_current)
const core::Signal< Track::Id > & on_track_changed() const
const core::Signal< ContainerURI > & on_tracks_added() const
Track::MetaData query_meta_data_for_track(const Track::Id &id)
const core::Signal< void > & on_track_list_reset() const
const core::Signal< Track::Id > & on_go_to_track() const
const core::Signal< TrackIdTuple > & on_track_moved() const
const core::Signal< void > & on_end_of_tracklist() const
void go_to(const Track::Id &track)
const core::Property< Container > & tracks() const
const core::Signal< ContainerTrackIdTuple > & on_track_list_replaced() const
const core::Signal< Track::Id > & on_track_added() const
void remove_track(const Track::Id &id)
Track::UriType query_uri_for_track(const Track::Id &id)
bool move_track(const Track::Id &id, const Track::Id &to)
const core::Property< bool > & can_edit_tracks() const
std::tuple< Track::Id, Track::Id > TrackIdTuple
Definition: track_list.h:46
std::tuple< std::vector< Track::Id >, Track::Id > ContainerTrackIdTuple
Definition: track_list.h:45
std::vector< Track::UriType > ContainerURI
Definition: track_list.h:44
void set(const typename Tag::ValueType &value)
Definition: track.h:68
std::string UriType
Definition: track.h:40
#define MH_DEBUG(...)
Definition: logger.h:123
std::shared_ptr< DBusTrackListResetSignal > on_track_list_reset
std::shared_ptr< DBusTrackChangedSignal > on_track_changed
std::shared_ptr< DBusTrackRemovedSignal > on_track_removed
std::shared_ptr< DBusTracksAddedSignal > on_tracks_added
std::shared_ptr< DBusTrackAddedSignal > on_track_added
std::shared_ptr< DBusTrackMovedSignal > on_track_moved
std::shared_ptr< DBusTrackListReplacedSignal > on_track_list_replaced
core::dbus::Signal< mpris::TrackList::Signals::TrackAdded, mpris::TrackList::Signals::TrackAdded::ArgumentType > DBusTrackAddedSignal
Signals(const std::shared_ptr< DBusTrackAddedSignal > &track_added, const std::shared_ptr< DBusTracksAddedSignal > &tracks_added, const std::shared_ptr< DBusTrackMovedSignal > &track_moved, const std::shared_ptr< DBusTrackRemovedSignal > &track_removed, const std::shared_ptr< DBusTrackListResetSignal > &track_list_reset, const std::shared_ptr< DBusTrackListReplacedSignal > &track_list_replaced, const std::shared_ptr< DBusTrackChangedSignal > &track_changed)
struct media::TrackListStub::Private::Signals::DBus dbus
core::Signal< media::TrackList::ContainerURI > on_tracks_added
core::Signal< Track::Id > on_track_added
core::Signal< Track::Id > on_track_removed
core::dbus::Signal< mpris::TrackList::Signals::TrackRemoved, mpris::TrackList::Signals::TrackRemoved::ArgumentType > DBusTrackRemovedSignal
core::dbus::Signal< mpris::TrackList::Signals::TrackMoved, mpris::TrackList::Signals::TrackMoved::ArgumentType > DBusTrackMovedSignal
core::Signal< media::TrackList::TrackIdTuple > on_track_moved
core::dbus::Signal< mpris::TrackList::Signals::TrackListReplaced, mpris::TrackList::Signals::TrackListReplaced::ArgumentType > DBusTrackListReplacedSignal
core::dbus::Signal< mpris::TrackList::Signals::TrackChanged, mpris::TrackList::Signals::TrackChanged::ArgumentType > DBusTrackChangedSignal
core::dbus::Signal< mpris::TrackList::Signals::TrackListReset, mpris::TrackList::Signals::TrackListReset::ArgumentType > DBusTrackListResetSignal
core::Signal< media::TrackList::ContainerTrackIdTuple > on_track_list_replaced
core::dbus::Signal< mpris::TrackList::Signals::TracksAdded, mpris::TrackList::Signals::TracksAdded::ArgumentType > DBusTracksAddedSignal
core::Signal< Track::Id > on_track_changed
core::Signal< Track::Id > on_go_to_track
struct media::TrackListStub::Private::Signals signals
std::shared_ptr< core::dbus::Property< mpris::TrackList::Properties::CanEditTracks > > can_edit_tracks
std::shared_ptr< core::dbus::Property< mpris::TrackList::Properties::Tracks > > tracks
std::shared_ptr< media::Player > parent
Private(TrackListStub *impl, const std::shared_ptr< media::Player > &parent, const dbus::Object::Ptr &object)
static constexpr const char * name
Definition: player.h:133
static constexpr const char * name
Definition: track_list.h:64
static constexpr const char * name
Definition: track_list.h:88