1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2004-2021 musikcube team
4 //
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are met:
9 //
10 //    * Redistributions of source code must retain the above copyright notice,
11 //      this list of conditions and the following disclaimer.
12 //
13 //    * Redistributions in binary form must reproduce the above copyright
14 //      notice, this list of conditions and the following disclaimer in the
15 //      documentation and/or other materials provided with the distribution.
16 //
17 //    * Neither the name of the author nor the names of other contributors may
18 //      be used to endorse or promote products derived from this software
19 //      without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 // POSSIBILITY OF SUCH DAMAGE.
32 //
33 //////////////////////////////////////////////////////////////////////////////
34 
35 #pragma once
36 
37 #include <sigslot/sigslot.h>
38 
39 #include <musikcore/sdk/IPlaybackService.h>
40 #include <musikcore/sdk/IPlaybackRemote.h>
41 #include <musikcore/library/track/Track.h>
42 #include <musikcore/library/track/TrackList.h>
43 #include <musikcore/library/ILibrary.h>
44 #include <musikcore/audio/MasterTransport.h>
45 #include <musikcore/support/Preferences.h>
46 #include <musikcore/runtime/IMessageQueue.h>
47 
48 #include <mutex>
49 
50 namespace musik { namespace core { namespace audio {
51 
52     class PlaybackService :
53         public musik::core::sdk::IPlaybackService,
54         public musik::core::runtime::IMessageTarget,
55         public sigslot::has_slots<>
56     {
57         public:
58             /* our unique events */
59             sigslot::signal2<size_t, musik::core::TrackPtr> TrackChanged;
60             sigslot::signal0<> ModeChanged;
61             sigslot::signal1<bool> Shuffled;
62             sigslot::signal0<> QueueEdited;
63 
64             /* copied from Transport, but will be automatically called on the
65             specified MessageQueue's thread! */
66             sigslot::signal1<musik::core::sdk::PlaybackState> PlaybackStateChanged;
67             sigslot::signal1<musik::core::sdk::StreamState> StreamStateChanged;
68             sigslot::signal0<> VolumeChanged;
69             sigslot::signal1<double> TimeChanged;
70 
71             PlaybackService(
72                 musik::core::runtime::IMessageQueue& messageQueue,
73                 musik::core::ILibraryPtr library,
74                 std::shared_ptr<musik::core::audio::ITransport> transport);
75 
76             PlaybackService(
77                 musik::core::runtime::IMessageQueue& messageQueue,
78                 musik::core::ILibraryPtr library);
79 
80             virtual ~PlaybackService();
81 
82             /* IMessageTarget */
83             void ProcessMessage(musik::core::runtime::IMessage &message) override;
84 
85             /* IPlaybackService */
86             void Play(size_t index) override;
87             bool Next() override;
88             bool Previous() override;
Stop()89             void Stop()  override { transport->Stop(); }
GetRepeatMode()90             musik::core::sdk::RepeatMode GetRepeatMode()  override { return this->repeatMode; }
91             void SetRepeatMode(musik::core::sdk::RepeatMode mode) override;
92             void ToggleRepeatMode() override;
93             musik::core::sdk::PlaybackState GetPlaybackState() override;
94             bool IsShuffled() override;
95             void ToggleShuffle() override;
96             size_t GetIndex() noexcept override;
97             size_t Count() override;
98             double GetVolume() override;
99             void SetVolume(double vol) override;
100             void PauseOrResume() override;
101             bool IsMuted() override;
102             void ToggleMute() override;
103             double GetPosition() override;
104             void SetPosition(double seconds) override;
105             double GetDuration() override;
106             musik::core::sdk::ITrack* GetTrack(size_t index) override;
107             musik::core::sdk::ITrack* GetPlayingTrack() override;
108             void CopyFrom(const musik::core::sdk::ITrackList* source) override;
109             void Play(const musik::core::sdk::ITrackList* source, size_t index) override;
110             musik::core::sdk::ITrackListEditor* EditPlaylist() override;
111             musik::core::sdk::TimeChangeMode GetTimeChangeMode() noexcept override;
112             void SetTimeChangeMode(musik::core::sdk::TimeChangeMode) noexcept override;
113             void ReloadOutput() override;
114             musik::core::sdk::ITrackList* Clone() override;
115 
116             /* TODO: include in SDK? */
117             virtual bool HotSwap(const TrackList& source, size_t index = 0);
118 
119             /* app-specific implementation. similar to some SDK methods, but use
120             concrete data types with known optimizations */
121             void Play(const musik::core::TrackList& tracks, size_t index);
122             void Prepare(size_t index, double position = 0.0f);
123             void CopyTo(musik::core::TrackList& target);
124             void CopyFrom(const musik::core::TrackList& source);
125             musik::core::TrackPtr GetPlaying();
126 
GetTransport()127             musik::core::audio::ITransport& GetTransport() noexcept {
128                 return *this->transport.get();
129             }
130 
GetTrackList()131             std::shared_ptr<const musik::core::TrackList> GetTrackList() noexcept {
132                 return std::shared_ptr<const musik::core::TrackList>(
133                     &this->playlist, [](const musik::core::TrackList*) {});
134             }
135 
136             /* required to make changes to the playlist. this little data structure
137             privately owns a lock to the internal data structure and will release
138             that lock when it's destructed. */
139             class Editor : public musik::core::sdk::ITrackListEditor {
140                 public:
141                     using IEditor = std::shared_ptr<musik::core::sdk::ITrackListEditor>;
142 
143                     Editor(Editor&& other);
144                     virtual ~Editor();
145 
146                     /* ITrackListEditor */
147                     bool Insert(int64_t id, size_t index) override;
148                     bool Swap(size_t index1, size_t index2) override;
149                     bool Move(size_t from, size_t to) override;
150                     bool Delete(size_t index) override;
151                     void Add(const int64_t id) override;
152                     void Clear() override;
153                     void Shuffle() override;
154                     void Release() noexcept override;
155 
156                 private:
157                     friend class PlaybackService;
158                     using Mutex = std::recursive_mutex;
159                     using Lock = std::unique_lock<Mutex>;
160                     using Queue = musik::core::runtime::IMessageQueue;
161 
162                     Editor(
163                         PlaybackService& playback,
164                         TrackList& tracks,
165                         Queue& queue,
166                         Mutex& mutex);
167 
168                     PlaybackService& playback;
169                     IEditor tracks;
170                     Queue& queue;
171                     Lock lock;
172                     size_t playIndex;
173                     bool nextTrackInvalidated;
174                     bool edited;
175             };
176 
177             Editor Edit();
178 
179         private:
180             void OnStreamEvent(musik::core::sdk::StreamState eventType, std::string uri);
181             void OnPlaybackEvent(musik::core::sdk::PlaybackState eventType);
182             void OnTrackChanged(size_t pos, musik::core::TrackPtr track);
183             void OnVolumeChanged();
184             void OnTimeChanged(double time);
185             void OnIndexerFinished(int trackCount);
186 
187             void NotifyRemotesModeChanged();
188             void PrepareNextTrack();
189             void InitRemotes();
190             void ResetRemotes();
191             void MarkTrackAsPlayed(int64_t trackId);
192 
193             void PlayAt(size_t index, ITransport::StartMode mode);
194 
195             musik::core::TrackPtr TrackAtIndexWithTimeout(size_t index);
196 
197             std::string UriAtIndex(size_t index);
198             musik::core::audio::ITransport::Gain GainAtIndex(size_t index);
199 
200             musik::core::TrackList playlist;
201             musik::core::TrackList unshuffled;
202             std::recursive_mutex playlistMutex;
203 
204             std::vector<std::shared_ptr<musik::core::sdk::IPlaybackRemote>> remotes;
205             std::shared_ptr<musik::core::Preferences> playbackPrefs;
206             std::shared_ptr<musik::core::Preferences> appPrefs;
207             musik::core::TrackPtr playingTrack;
208 
209             musik::core::ILibraryPtr library;
210             std::shared_ptr<musik::core::audio::ITransport> transport;
211             size_t index, nextIndex;
212 
213             musik::core::sdk::RepeatMode repeatMode;
214             musik::core::sdk::TimeChangeMode timeChangeMode;
215 
216             double seekPosition;
217 
218             musik::core::runtime::IMessageQueue& messageQueue;
219     };
220 
221 } } }
222