1 /* 2 This file is part of Telegram Desktop, 3 the official desktop application for the Telegram messaging service. 4 5 For license and copyright information please follow this link: 6 https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL 7 */ 8 #pragma once 9 10 #include "data/data_audio_msg_id.h" 11 #include "data/data_shared_media.h" 12 13 class AudioMsgId; 14 class DocumentData; 15 16 namespace Media { 17 namespace Audio { 18 class Instance; 19 } // namespace Audio 20 } // namespace Media 21 22 namespace Media { 23 namespace View { 24 class PlaybackProgress; 25 } // namespace View 26 } // namespace Media 27 28 namespace Media { 29 namespace Streaming { 30 class Document; 31 class Instance; 32 struct PlaybackOptions; 33 struct Update; 34 enum class Error; 35 } // namespace Streaming 36 } // namespace Media 37 38 namespace Media { 39 namespace Player { 40 41 class Instance; 42 struct TrackState; 43 44 void start(not_null<Audio::Instance*> instance); 45 void finish(not_null<Audio::Instance*> instance); 46 47 void SaveLastPlaybackPosition( 48 not_null<DocumentData*> document, 49 const TrackState &state); 50 51 not_null<Instance*> instance(); 52 53 class Instance : private base::Subscriber { 54 public: 55 enum class Seeking { 56 Start, 57 Finish, 58 Cancel, 59 }; 60 61 void play(AudioMsgId::Type type); 62 void pause(AudioMsgId::Type type); 63 void stop(AudioMsgId::Type type); 64 void playPause(AudioMsgId::Type type); 65 bool next(AudioMsgId::Type type); 66 bool previous(AudioMsgId::Type type); 67 68 AudioMsgId::Type getActiveType() const; 69 play()70 void play() { 71 play(getActiveType()); 72 } pause()73 void pause() { 74 pause(getActiveType()); 75 } stop()76 void stop() { 77 stop(getActiveType()); 78 } playPause()79 void playPause() { 80 playPause(getActiveType()); 81 } next()82 bool next() { 83 return next(getActiveType()); 84 } previous()85 bool previous() { 86 return previous(getActiveType()); 87 } 88 89 void playPauseCancelClicked(AudioMsgId::Type type); 90 91 void play(const AudioMsgId &audioId); 92 void playPause(const AudioMsgId &audioId); 93 [[nodiscard]] TrackState getState(AudioMsgId::Type type) const; 94 95 [[nodiscard]] Streaming::Instance *roundVideoStreamed( 96 HistoryItem *item) const; 97 [[nodiscard]] View::PlaybackProgress *roundVideoPlayback( 98 HistoryItem *item) const; 99 current(AudioMsgId::Type type)100 [[nodiscard]] AudioMsgId current(AudioMsgId::Type type) const { 101 if (const auto data = getData(type)) { 102 return data->current; 103 } 104 return AudioMsgId(); 105 } 106 repeatEnabled(AudioMsgId::Type type)107 [[nodiscard]] bool repeatEnabled(AudioMsgId::Type type) const { 108 if (const auto data = getData(type)) { 109 return data->repeatEnabled; 110 } 111 return false; 112 } toggleRepeat(AudioMsgId::Type type)113 void toggleRepeat(AudioMsgId::Type type) { 114 if (const auto data = getData(type)) { 115 data->repeatEnabled = !data->repeatEnabled; 116 _repeatChangedNotifier.notify(type); 117 } 118 } 119 isSeeking(AudioMsgId::Type type)120 [[nodiscard]] bool isSeeking(AudioMsgId::Type type) const { 121 if (const auto data = getData(type)) { 122 return (data->seeking == data->current); 123 } 124 return false; 125 } 126 void startSeeking(AudioMsgId::Type type); 127 void finishSeeking(AudioMsgId::Type type, float64 progress); 128 void cancelSeeking(AudioMsgId::Type type); 129 130 void updateVoicePlaybackSpeed(); 131 132 [[nodiscard]] bool nextAvailable(AudioMsgId::Type type) const; 133 [[nodiscard]] bool previousAvailable(AudioMsgId::Type type) const; 134 135 struct Switch { 136 AudioMsgId from; 137 FullMsgId to; 138 }; 139 switchToNextNotifier()140 base::Observable<Switch> &switchToNextNotifier() { 141 return _switchToNextNotifier; 142 } playerWidgetOver()143 base::Observable<bool> &playerWidgetOver() { 144 return _playerWidgetOver; 145 } tracksFinishedNotifier()146 base::Observable<AudioMsgId::Type> &tracksFinishedNotifier() { 147 return _tracksFinishedNotifier; 148 } trackChangedNotifier()149 base::Observable<AudioMsgId::Type> &trackChangedNotifier() { 150 return _trackChangedNotifier; 151 } repeatChangedNotifier()152 base::Observable<AudioMsgId::Type> &repeatChangedNotifier() { 153 return _repeatChangedNotifier; 154 } 155 156 rpl::producer<> playlistChanges(AudioMsgId::Type type) const; 157 updatedNotifier()158 rpl::producer<TrackState> updatedNotifier() const { 159 return _updatedNotifier.events(); 160 } 161 162 rpl::producer<> stops(AudioMsgId::Type type) const; 163 rpl::producer<> startsPlay(AudioMsgId::Type type) const; 164 165 rpl::producer<Seeking> seekingChanges(AudioMsgId::Type type) const; 166 167 bool pauseGifByRoundVideo() const; 168 169 void documentLoadProgress(DocumentData *document); 170 171 private: 172 using SharedMediaType = Storage::SharedMediaType; 173 using SliceKey = SparseIdsMergedSlice::Key; 174 struct Streamed; 175 struct Data { 176 Data(AudioMsgId::Type type, SharedMediaType overview); 177 Data(Data &&other); 178 Data &operator=(Data &&other); 179 ~Data(); 180 181 AudioMsgId::Type type; 182 Storage::SharedMediaType overview; 183 AudioMsgId current; 184 AudioMsgId seeking; 185 std::optional<SparseIdsMergedSlice> playlistSlice; 186 std::optional<SliceKey> playlistSliceKey; 187 std::optional<SliceKey> playlistRequestedKey; 188 std::optional<int> playlistIndex; 189 rpl::lifetime playlistLifetime; 190 rpl::lifetime sessionLifetime; 191 rpl::event_stream<> playlistChanges; 192 History *history = nullptr; 193 History *migrated = nullptr; 194 Main::Session *session = nullptr; 195 bool repeatEnabled = false; 196 bool isPlaying = false; 197 bool resumeOnCallEnd = false; 198 std::unique_ptr<Streamed> streamed; 199 }; 200 201 struct SeekingChanges { 202 Seeking seeking; 203 AudioMsgId::Type type; 204 }; 205 206 Instance(); 207 ~Instance(); 208 209 friend void start(not_null<Audio::Instance*> instance); 210 friend void finish(not_null<Audio::Instance*> instance); 211 212 void setupShortcuts(); 213 void playStreamed( 214 const AudioMsgId &audioId, 215 std::shared_ptr<Streaming::Document> shared); 216 Streaming::PlaybackOptions streamingOptions( 217 const AudioMsgId &audioId, 218 crl::time position = -1); 219 220 // Observed notifications. 221 void handleSongUpdate(const AudioMsgId &audioId); 222 223 void pauseOnCall(AudioMsgId::Type type); 224 void resumeOnCall(AudioMsgId::Type type); 225 226 void setCurrent(const AudioMsgId &audioId); 227 void refreshPlaylist(not_null<Data*> data); 228 std::optional<SliceKey> playlistKey(not_null<Data*> data) const; 229 bool validPlaylist(not_null<Data*> data); 230 void validatePlaylist(not_null<Data*> data); 231 void playlistUpdated(not_null<Data*> data); 232 bool moveInPlaylist(not_null<Data*> data, int delta, bool autonext); 233 HistoryItem *itemByIndex(not_null<Data*> data, int index); 234 void stopAndClear(not_null<Data*> data); 235 236 void handleStreamingUpdate( 237 not_null<Data*> data, 238 Streaming::Update &&update); 239 void handleStreamingError( 240 not_null<Data*> data, 241 Streaming::Error &&error); 242 243 void clearStreamed(not_null<Data*> data, bool savePosition = true); 244 void emitUpdate(AudioMsgId::Type type); 245 template <typename CheckCallback> 246 void emitUpdate(AudioMsgId::Type type, CheckCallback check); 247 getData(AudioMsgId::Type type)248 Data *getData(AudioMsgId::Type type) { 249 if (type == AudioMsgId::Type::Song) { 250 return &_songData; 251 } else if (type == AudioMsgId::Type::Voice) { 252 return &_voiceData; 253 } 254 return nullptr; 255 } 256 getData(AudioMsgId::Type type)257 const Data *getData(AudioMsgId::Type type) const { 258 if (type == AudioMsgId::Type::Song) { 259 return &_songData; 260 } else if (type == AudioMsgId::Type::Voice) { 261 return &_voiceData; 262 } 263 return nullptr; 264 } 265 266 HistoryItem *roundVideoItem() const; 267 void requestRoundVideoResize() const; 268 void requestRoundVideoRepaint() const; 269 270 void setHistory(not_null<Data*> data, History *history); 271 void setSession(not_null<Data*> data, Main::Session *session); 272 273 Data _songData; 274 Data _voiceData; 275 bool _roundPlaying = false; 276 277 base::Observable<Switch> _switchToNextNotifier; 278 base::Observable<bool> _playerWidgetOver; 279 base::Observable<AudioMsgId::Type> _tracksFinishedNotifier; 280 base::Observable<AudioMsgId::Type> _trackChangedNotifier; 281 base::Observable<AudioMsgId::Type> _repeatChangedNotifier; 282 283 rpl::event_stream<AudioMsgId::Type> _playerStopped; 284 rpl::event_stream<AudioMsgId::Type> _playerStartedPlay; 285 rpl::event_stream<TrackState> _updatedNotifier; 286 rpl::event_stream<SeekingChanges> _seekingChanges; 287 rpl::lifetime _lifetime; 288 289 }; 290 291 } // namespace Player 292 } // namespace Media 293