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