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 #include "pch.hpp"
36 #include "Playback.h"
37 #include <musikcore/library/query/PersistedPlayQueueQuery.h>
38 #include <musikcore/sdk/constants.h>
39 #include <musikcore/support/PreferenceKeys.h>
40 #include <cmath>
41 
42 using namespace musik::core;
43 using namespace musik::core::audio;
44 using namespace musik::core::library::query;
45 using namespace musik::core::sdk;
46 
47 namespace keys = musik::core::prefs::keys;
48 using Prefs = std::shared_ptr<Preferences>;
49 
Session()50 static Prefs Session() {
51     return Preferences::ForComponent(prefs::components::Session);
52 }
53 
Settings()54 static Prefs Settings() {
55     return Preferences::ForComponent(prefs::components::Settings);
56 }
57 
58 namespace musik {
59     namespace core {
60         namespace playback {
PauseOrResume(ITransport & transport)61             void PauseOrResume(ITransport& transport) {
62                 auto state = transport.GetPlaybackState();
63                 if (state == PlaybackState::Paused || state == PlaybackState::Prepared) {
64                     transport.Resume();
65                 }
66                 else if (state == PlaybackState::Playing) {
67                     transport.Pause();
68                 }
69             }
70 
VolumeUp(ITransport & transport)71             void VolumeUp(ITransport& transport) {
72                 double delta = round(transport.Volume() * 100.0) >= 10.0 ? 0.05 : 0.01;
73                 transport.SetVolume(transport.Volume() + delta);
74             }
75 
VolumeDown(ITransport & transport)76             void VolumeDown(ITransport& transport) {
77                 double delta = round(transport.Volume() * 100.0) > 10.0 ? 0.05 : 0.01;
78                 transport.SetVolume(transport.Volume() - delta);
79             }
80 
SeekForward(IPlaybackService & playback)81             void SeekForward(IPlaybackService& playback) {
82                 playback.SetPosition(playback.GetPosition() + 10.0f);
83             }
84 
SeekBack(IPlaybackService & playback)85             void SeekBack(IPlaybackService& playback) {
86                 playback.SetPosition(playback.GetPosition() - 10.0f);
87             }
88 
SeekForwardProportional(IPlaybackService & playback)89             void SeekForwardProportional(IPlaybackService& playback) {
90                 double moveBy = 0.05f * playback.GetDuration();
91                 playback.SetPosition(playback.GetPosition() + moveBy);
92             }
93 
SeekBackProportional(IPlaybackService & playback)94             void SeekBackProportional(IPlaybackService& playback) {
95                 double moveBy = 0.05f * playback.GetDuration();
96                 playback.SetPosition(playback.GetPosition() - moveBy);
97             }
98 
LoadPlaybackContext(ILibraryPtr library,PlaybackService & playback)99             void LoadPlaybackContext(ILibraryPtr library, PlaybackService& playback) {
100                 if (Settings()->GetBool(keys::SaveSessionOnExit, true)) {
101                     auto prefs = Session();
102                     auto query = std::shared_ptr<PersistedPlayQueueQuery>(
103                         PersistedPlayQueueQuery::Restore(library, playback));
104 
105                     library->Enqueue(query, [&playback, prefs, query](auto q) {
106                         int index = prefs->GetInt(keys::LastPlayQueueIndex, -1);
107                         if (index >= 0) {
108                             double time = prefs->GetDouble(keys::LastPlayQueueTime, 0.0f);
109                             playback.Prepare(index, time);
110                             playback.QueueEdited(); /* hack to get the play queue view to scroll
111                                 to the track we just prepared. */
112 
113                             if (Settings()->GetBool(keys::ResumePlaybackOnStartup, false)) {
114                                 playback.GetTransport().Resume();
115                             }
116                         }
117                     });
118                 }
119             }
120 
SavePlaybackContext(ILibraryPtr library,PlaybackService & playback)121             void SavePlaybackContext(ILibraryPtr library, PlaybackService& playback) {
122                 if (Settings()->GetBool(keys::SaveSessionOnExit, true)) {
123                     auto prefs = Session();
124                     if (playback.GetPlaybackState() != sdk::PlaybackState::Stopped) {
125                         prefs->SetInt(keys::LastPlayQueueIndex, (int)playback.GetIndex());
126 
127                         /* streams with a negative duration are of indeterminate length,
128                         and may be infinite, so don't cache the playback position */
129                         double offset = playback.GetDuration() > 0.0 ? playback.GetPosition() : 0.0;
130                         prefs->SetDouble(keys::LastPlayQueueTime, offset);
131                     }
132                     else {
133                         prefs->SetInt(keys::LastPlayQueueIndex, -1);
134                         prefs->SetDouble(keys::LastPlayQueueTime, 0.0f);
135                     }
136 
137                     auto query = std::shared_ptr<PersistedPlayQueueQuery>(
138                         PersistedPlayQueueQuery::Save(library, playback));
139 
140                     library->EnqueueAndWait(query);
141                 }
142             }
143         }
144     }
145 }
146