Music Hub  ..
A session-wide music playback service
track_list_implementation.cpp
Go to the documentation of this file.
1 /*
2  * Copyright © 2013-2015 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 <algorithm>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <tuple>
23 
25 
26 #include "engine.h"
27 
28 namespace dbus = core::dbus;
29 namespace media = core::ubuntu::media;
30 
32 {
33  typedef std::map<Track::Id, std::tuple<Track::UriType, Track::MetaData>> MetaDataCache;
34 
35  dbus::Object::Ptr object;
36  size_t track_counter;
37  MetaDataCache meta_data_cache;
38  std::shared_ptr<media::Engine::MetaDataExtractor> extractor;
39  // Used for caching the original tracklist order to be used to restore the order
40  // to the live TrackList after shuffle is turned off
42 };
43 
45  const dbus::Bus::Ptr& bus,
46  const dbus::Object::Ptr& object,
47  const std::shared_ptr<media::Engine::MetaDataExtractor>& extractor,
48  const media::apparmor::ubuntu::RequestContextResolver::Ptr& request_context_resolver,
49  const media::apparmor::ubuntu::RequestAuthenticator::Ptr& request_authenticator)
50  : media::TrackListSkeleton(bus, object, request_context_resolver, request_authenticator),
52 {
53  can_edit_tracks().set(true);
54 }
55 
57 {
58 }
59 
61 {
62  auto it = d->meta_data_cache.find(id);
63 
64  if (it == d->meta_data_cache.end())
65  return Track::UriType{};
66 
67  return std::get<0>(it->second);
68 }
69 
71 {
72  auto it = d->meta_data_cache.find(id);
73 
74  if (it == d->meta_data_cache.end())
75  return Track::MetaData{};
76 
77  return std::get<1>(it->second);
78 }
79 
81  const media::Track::UriType& uri,
82  const media::Track::Id& position,
83  bool make_current)
84 {
85  std::cout << __PRETTY_FUNCTION__ << std::endl;
86 
87  std::stringstream ss; ss << d->object->path().as_string() << "/" << d->track_counter++;
88  Track::Id id{ss.str()};
89 
90  auto result = tracks().update([this, id, position, make_current](TrackList::Container& container)
91  {
92  auto it = std::find(container.begin(), container.end(), position);
93  container.insert(it, id);
94 
95  return true;
96  });
97 
98  if (result)
99  {
100  if (d->meta_data_cache.count(id) == 0)
101  {
102  try {
103  d->meta_data_cache[id] = std::make_tuple(
104  uri,
105  d->extractor->meta_data_for_track_with_uri(uri));
106  } catch (const std::runtime_error &e) {
107  std::cerr << "Failed to retrieve metadata for track '" << uri << "' (" << e.what() << ")" << std::endl;
108  }
109  } else
110  {
111  std::get<0>(d->meta_data_cache[id]) = uri;
112  }
113 
114  if (make_current)
115  {
116  // Don't automatically call stop() and play() in player_implementation.cpp on_go_to_track()
117  // since this breaks video playback when using open_uri() (stop() and play() are unwanted in
118  // this scenario since the qtubuntu-media will handle this automatically)
119  const bool toggle_player_state = false;
120  go_to(id, toggle_player_state);
121  }
122 
123  // Signal to the client that a track was added to the TrackList
124  on_track_added()(id);
125  }
126 }
127 
129 {
130  auto result = tracks().update([id](TrackList::Container& container)
131  {
132  container.erase(std::find(container.begin(), container.end(), id));
133  return true;
134  });
135 
136  if (result)
137  {
138  d->meta_data_cache.erase(id);
139 
140  on_track_removed()(id);
141  }
142 
143 }
144 
145 void media::TrackListImplementation::go_to(const media::Track::Id& track, bool toggle_player_state)
146 {
147  std::cout << __PRETTY_FUNCTION__ << std::endl;
148  std::pair<const media::Track::Id, bool> p = std::make_pair(track, toggle_player_state);
149  // Signal the Player instance to go to a specific track for playback
150  on_go_to_track()(p);
151  on_track_changed()(track);
152 }
153 
155 {
156  std::cout << __PRETTY_FUNCTION__ << std::endl;
157 
158  auto result = tracks().update([this](TrackList::Container& container)
159  {
160  d->original_tracklist.assign(container.begin(), container.end());
161  std::random_shuffle(container.begin(), container.end());
162  return true;
163  });
164 
165  if (result)
166  {
167  media::TrackList::ContainerTrackIdTuple t{std::make_tuple(tracks().get(), current())};
169  }
170 }
171 
173 {
174  std::cout << __PRETTY_FUNCTION__ << std::endl;
175 
176  auto result = tracks().update([this](TrackList::Container& container)
177  {
178  container.assign(d->original_tracklist.begin(), d->original_tracklist.end());
179  return true;
180  });
181 
182  if (result)
183  {
184  media::TrackList::ContainerTrackIdTuple t{std::make_tuple(tracks().get(), current())};
186  }
187 }
188 
190 {
191  std::cout << __PRETTY_FUNCTION__ << std::endl;
192 
193  auto result = tracks().update([this](TrackList::Container& container)
194  {
195  container.clear();
196  container.resize(0);
197  d->track_counter = 0;
198  return true;
199  });
200 
201  (void) result;
202 }
void add_track_with_uri_at(const Track::UriType &uri, const Track::Id &position, bool make_current)
const core::Property< Container > & tracks() const
const core::Signal< std::pair< Track::Id, bool > > & on_go_to_track() const
const core::Signal< Track::Id > & on_track_changed() const
const core::Signal< Track::Id > & on_track_removed() const
Track::UriType query_uri_for_track(const Track::Id &id)
std::tuple< std::vector< Track::Id >, Track::Id > ContainerTrackIdTuple
Definition: track_list.h:43
TrackListImplementation(const core::dbus::Bus::Ptr &bus, const core::dbus::Object::Ptr &object, const std::shared_ptr< Engine::MetaDataExtractor > &extractor, const core::ubuntu::media::apparmor::ubuntu::RequestContextResolver::Ptr &request_context_resolver, const core::ubuntu::media::apparmor::ubuntu::RequestAuthenticator::Ptr &request_authenticator)
const core::Signal< ContainerTrackIdTuple > & on_track_list_replaced() const
const core::Signal< Track::Id > & on_track_added() const
Track::MetaData query_meta_data_for_track(const Track::Id &id)
std::shared_ptr< media::Engine::MetaDataExtractor > extractor
std::string UriType
Definition: track.h:40
std::vector< Track::Id > Container
Definition: track_list.h:42
std::map< Track::Id, std::tuple< Track::UriType, Track::MetaData > > MetaDataCache
const core::Property< bool > & can_edit_tracks() const
void go_to(const Track::Id &track, bool toggle_player_state)