manageaudioplayer.cpp 15.3 KB
Newer Older
1
/*
Matthieu Gallien's avatar
Matthieu Gallien committed
2
3
4
   SPDX-FileCopyrightText: 2016 (c) Matthieu Gallien <matthieu_gallien@yahoo.fr>

   SPDX-License-Identifier: LGPL-3.0-or-later
5
6
7
8
 */

#include "manageaudioplayer.h"

9
10
#include "mediaplaylist.h"

11
12
#include "elisa_settings.h"

13
#include <QTimer>
14
#include <QDateTime>
15

16
17
18
19
20
21
22
23
24
25
ManageAudioPlayer::ManageAudioPlayer(QObject *parent) : QObject(parent)
{

}

QPersistentModelIndex ManageAudioPlayer::currentTrack() const
{
    return mCurrentTrack;
}

26
27
28
29
30
QAbstractItemModel *ManageAudioPlayer::playListModel() const
{
    return mPlayListModel;
}

31
32
33
34
35
int ManageAudioPlayer::urlRole() const
{
    return mUrlRole;
}

36
37
38
39
40
int ManageAudioPlayer::isPlayingRole() const
{
    return mIsPlayingRole;
}

41
42
43
44
45
46
47
48
49
QUrl ManageAudioPlayer::playerSource() const
{
    if (!mCurrentTrack.isValid()) {
        return QUrl();
    }

    return mCurrentTrack.data(mUrlRole).toUrl();
}

50
QMediaPlayer::MediaStatus ManageAudioPlayer::playerStatus() const
51
52
53
54
{
    return mPlayerStatus;
}

55
QMediaPlayer::State ManageAudioPlayer::playerPlaybackState() const
56
57
58
59
{
    return mPlayerPlaybackState;
}

60
QMediaPlayer::Error ManageAudioPlayer::playerError() const
61
62
63
64
{
    return mPlayerError;
}

65
qint64 ManageAudioPlayer::audioDuration() const
66
67
68
69
70
71
72
73
74
{
    return mAudioDuration;
}

bool ManageAudioPlayer::playerIsSeekable() const
{
    return mPlayerIsSeekable;
}

75
qint64 ManageAudioPlayer::playerPosition() const
76
77
78
79
{
    return mPlayerPosition;
}

80
qint64 ManageAudioPlayer::playControlPosition() const
81
{
82
    return mPlayerPosition;
83
84
}

85
86
87
88
89
QVariantMap ManageAudioPlayer::persistentState() const
{
    auto persistentStateValue = QVariantMap();

    persistentStateValue[QStringLiteral("isPlaying")] = mPlayingState;
90

91
    persistentStateValue[QStringLiteral("playerPosition")] = mPlayerPosition;
stef lep's avatar
stef lep committed
92
93
    persistentStateValue[QStringLiteral("playerDuration")] = mAudioDuration;

94
95
96
97
98
99
100
101
102
    if (mCurrentTrack.isValid()) {
        persistentStateValue[QStringLiteral("audioPlayerCurrentTitle")] = mCurrentTrack.data(mTitleRole);
        persistentStateValue[QStringLiteral("audioPlayerCurrentArtistName")] = mCurrentTrack.data(mArtistNameRole);
        persistentStateValue[QStringLiteral("audioPlayerCurrentAlbumName")] = mCurrentTrack.data(mAlbumNameRole);
    } else {
        persistentStateValue[QStringLiteral("audioPlayerCurrentTitle")] = {};
        persistentStateValue[QStringLiteral("audioPlayerCurrentArtistName")] = {};
        persistentStateValue[QStringLiteral("audioPlayerCurrentAlbumName")] = {};
    }
103
104
105
106

    return persistentStateValue;
}

107
108
109
110
111
112
113
114
115
int ManageAudioPlayer::playListPosition() const
{
    if (mCurrentTrack.isValid()) {
        return mCurrentTrack.row();
    }

    return 0;
}

116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
int ManageAudioPlayer::titleRole() const
{
    return mTitleRole;
}

int ManageAudioPlayer::artistNameRole() const
{
    return mArtistNameRole;
}

int ManageAudioPlayer::albumNameRole() const
{
    return mAlbumNameRole;
}

131
void ManageAudioPlayer::setCurrentTrack(const QPersistentModelIndex &currentTrack)
132
{
133
    mOldCurrentTrack = mCurrentTrack;
134

135
    mCurrentTrack = currentTrack;
136
137
138
139
140

    if (mCurrentTrack.isValid()) {
        restorePreviousState();
    }

141
142
    mPlayerError = QMediaPlayer::NoError;

143
144
145
    if (mOldCurrentTrack != mCurrentTrack || mPlayingState) {
        Q_EMIT currentTrackChanged();
    }
146

147
    switch (mPlayerPlaybackState) {
148
    case QMediaPlayer::StoppedState:
149
        Q_EMIT playerSourceChanged(mCurrentTrack.data(mUrlRole).toUrl());
150
        break;
151
152
    case QMediaPlayer::PlayingState:
    case QMediaPlayer::PausedState:
153
        triggerStop();
154
155
156
        if (mPlayingState && !mCurrentTrack.isValid()) {
            mPlayingState = false;
        }
157
        mSkippingCurrentTrack = true;
158
159
        break;
    }
160
161
}

162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
void ManageAudioPlayer::saveForUndoClearPlaylist(){
    mUndoPlayingState = mPlayingState;

    mUndoPlayerPosition = mPlayerPosition;
    Q_EMIT saveUndoPositionInAudioWrapper(mUndoPlayerPosition);
}

void ManageAudioPlayer::restoreForUndoClearPlaylist(){
    mPlayerPosition = mUndoPlayerPosition;
    Q_EMIT seek(mPlayerPosition);

    mPlayingState = mUndoPlayingState;
    Q_EMIT restoreUndoPositionInAudioWrapper();
}

177
178
179
180
181
182
void ManageAudioPlayer::setPlayListModel(QAbstractItemModel *aPlayListModel)
{
    if (mPlayListModel == aPlayListModel) {
        return;
    }

183
184
185
186
    if (mPlayListModel) {
        disconnect(mPlayListModel, &QAbstractItemModel::dataChanged, this, &ManageAudioPlayer::tracksDataChanged);
    }

187
    mPlayListModel = aPlayListModel;
188
189
190
191
192

    if (mPlayListModel) {
        connect(mPlayListModel, &QAbstractItemModel::dataChanged, this, &ManageAudioPlayer::tracksDataChanged);
    }

193
194
195
    Q_EMIT playListModelChanged();
}

196
197
198
199
void ManageAudioPlayer::setUrlRole(int value)
{
    mUrlRole = value;
    Q_EMIT urlRoleChanged();
200
    notifyPlayerSourceProperty();
201
    restorePreviousState();
202
203
}

204
205
206
207
208
209
210
211
212
213
void ManageAudioPlayer::setIsPlayingRole(int value)
{
    if (mIsPlayingRole == value) {
        return;
    }

    mIsPlayingRole = value;
    Q_EMIT isPlayingRoleChanged();
}

214
void ManageAudioPlayer::setPlayerStatus(QMediaPlayer::MediaStatus playerStatus)
215
{
216
    if (mPlayerStatus == playerStatus) {
217
        return;
218
219
    }

220
    mPlayerStatus = playerStatus;
221
    Q_EMIT playerStatusChanged();
222
223

    switch (mPlayerStatus) {
224
    case QMediaPlayer::NoMedia:
225
        break;
226
    case QMediaPlayer::LoadingMedia:
227
        break;
228
    case QMediaPlayer::LoadedMedia:
229
230
231
232
        if (mPlayingState) {
            triggerPlay();
        }
        break;
233
    case QMediaPlayer::BufferingMedia:
234
        break;
235
    case QMediaPlayer::StalledMedia:
236
        break;
237
    case QMediaPlayer::BufferedMedia:
238
        break;
239
    case QMediaPlayer::EndOfMedia:
240
        break;
241
242
243
244
    case QMediaPlayer::InvalidMedia:
        triggerSkipNextTrack();
        break;
    case QMediaPlayer::UnknownMediaStatus:
245
246
        break;
    }
247
248
}

249
void ManageAudioPlayer::setPlayerPlaybackState(QMediaPlayer::State playerPlaybackState)
250
{
251
252
253
254
    if (mPlayerPlaybackState == playerPlaybackState) {
        return;
    }

255
    mPlayerPlaybackState = playerPlaybackState;
256
    Q_EMIT playerPlaybackStateChanged();
257

258
259
    if (!mSkippingCurrentTrack) {
        switch(mPlayerPlaybackState) {
260
        case QMediaPlayer::StoppedState:
261
            if (mPlayerStatus == QMediaPlayer::EndOfMedia || mPlayerStatus == QMediaPlayer::InvalidMedia) {
262
263
                triggerSkipNextTrack();
            }
264
            if (mPlayListModel && mCurrentTrack.isValid()) {
265
                mPlayListModel->setData(mCurrentTrack, MediaPlayList::NotPlaying, mIsPlayingRole);
266
            }
267
            break;
268
        case QMediaPlayer::PlayingState:
269
            if (mPlayListModel && mCurrentTrack.isValid()) {
270
                mPlayListModel->setData(mCurrentTrack, MediaPlayList::IsPlaying, mIsPlayingRole);
271
                Q_EMIT startedPlayingTrack(mCurrentTrack.data(mUrlRole).toUrl(), QDateTime::currentDateTime());
272
            }
273
            break;
274
        case QMediaPlayer::PausedState:
275
276
277
            if (mPlayListModel && mCurrentTrack.isValid()) {
                mPlayListModel->setData(mCurrentTrack, MediaPlayList::IsPaused, mIsPlayingRole);
            }
278
279
280
281
            break;
        }
    } else {
        switch(mPlayerPlaybackState) {
282
        case QMediaPlayer::StoppedState:
283
            notifyPlayerSourceProperty();
284
            mSkippingCurrentTrack = false;
285
            if (mPlayListModel && mOldCurrentTrack.isValid()) {
286
                mPlayListModel->setData(mOldCurrentTrack, MediaPlayList::NotPlaying, mIsPlayingRole);
287
            }
288
            break;
289
        case QMediaPlayer::PlayingState:
290
            if (mPlayListModel && mCurrentTrack.isValid()) {
291
                mPlayListModel->setData(mCurrentTrack, MediaPlayList::IsPlaying, mIsPlayingRole);
292
                Q_EMIT startedPlayingTrack(mCurrentTrack.data(mUrlRole).toUrl(), QDateTime::currentDateTime());
293
            }
294
            break;
295
        case QMediaPlayer::PausedState:
296
297
298
            if (mPlayListModel && mCurrentTrack.isValid()) {
                mPlayListModel->setData(mCurrentTrack, MediaPlayList::IsPaused, mIsPlayingRole);
            }
299
            break;
300
301
302
303
        }
    }
}

304
void ManageAudioPlayer::setPlayerError(QMediaPlayer::Error playerError)
305
306
307
308
309
{
    if (mPlayerError == playerError) {
        return;
    }

310
    mPlayerError = playerError;
311
    Q_EMIT playerErrorChanged();
312
313

    if (mPlayerError != QMediaPlayer::NoError) {
314
315
316
317
318
319
320
321
322
        auto currentSource = playerSource();

        Q_EMIT sourceInError(currentSource, mPlayerError);

        if (currentSource.isLocalFile()) {
            Q_EMIT displayTrackError(currentSource.toLocalFile());
        } else {
            Q_EMIT displayTrackError(currentSource.toString());
        }
323
    }
324
325
}

326
327
328
329
330
331
332
333
void ManageAudioPlayer::ensurePause()
{
    if (mPlayingState) {
        mPlayingState = false;
        triggerPause();
    }
}

334
335
336
void ManageAudioPlayer::ensurePlay()
{
    if (!mPlayingState) {
337
338
        mPlayingState = true;
        triggerPlay();
339
340
341
    }
}

Alexander Stippich's avatar
Alexander Stippich committed
342
343
344
345
346
347
void ManageAudioPlayer::stop()
{
    mPlayingState = false;
    triggerStop();
}

348
349
350
351
void ManageAudioPlayer::playPause()
{
    mPlayingState = !mPlayingState;

352
    switch (mPlayerStatus) {
353
354
355
356
    case QMediaPlayer::LoadedMedia:
    case QMediaPlayer::BufferingMedia:
    case QMediaPlayer::BufferedMedia:
    case QMediaPlayer::LoadingMedia:
357
358
359
360
361
362
        if (mPlayingState) {
            triggerPlay();
        } else {
            triggerPause();
        }
        break;
363
    case QMediaPlayer::EndOfMedia:
364
        if (mPlayerPlaybackState == QMediaPlayer::PlayingState && !mPlayingState) {
365
            triggerPause();
366
        } else if (mPlayerPlaybackState == QMediaPlayer::PausedState && mPlayingState) {
367
368
            triggerPlay();
        }
369
        break;
370
371
372
373
    case QMediaPlayer::NoMedia:
    case QMediaPlayer::StalledMedia:
    case QMediaPlayer::InvalidMedia:
    case QMediaPlayer::UnknownMediaStatus:
374
        break;
375
    }
376
377
}

378
void ManageAudioPlayer::setAudioDuration(qint64 audioDuration)
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
{
    if (mAudioDuration == audioDuration) {
        return;
    }

    mAudioDuration = audioDuration;
    Q_EMIT audioDurationChanged();
}

void ManageAudioPlayer::setPlayerIsSeekable(bool playerIsSeekable)
{
    if (mPlayerIsSeekable == playerIsSeekable) {
        return;
    }

    mPlayerIsSeekable = playerIsSeekable;
    Q_EMIT playerIsSeekableChanged();
}

398
void ManageAudioPlayer::setPlayerPosition(qint64 playerPosition)
399
{
400
    if (mPlayerPosition == playerPosition) {
401
402
403
        return;
    }

404
405
    mPlayerPosition = playerPosition;
    Q_EMIT playerPositionChanged();
406
    QTimer::singleShot(0, this, [this]() {Q_EMIT playControlPositionChanged();});
407
408
}

Matthieu Gallien's avatar
Matthieu Gallien committed
409
void ManageAudioPlayer::setCurrentPlayingForRadios(const QString &title, const QString &nowPlaying)
410
{
Jerome Guidon's avatar
Jerome Guidon committed
411
    if (mPlayListModel && mCurrentTrack.isValid()) {
412
413
        Q_EMIT updateData(mCurrentTrack, title, MediaPlayList::TitleRole);
        Q_EMIT updateData(mCurrentTrack, nowPlaying, MediaPlayList::ArtistRole);
Jerome Guidon's avatar
Jerome Guidon committed
414
415
416
    }
}

417
418
419
void ManageAudioPlayer::setPlayControlPosition(int playerPosition)
{
    Q_EMIT seek(playerPosition);
420
421
}

422
void ManageAudioPlayer::setPersistentState(const QVariantMap &persistentStateValue)
423
424
425
426
427
428
429
430
{
    if (mPersistentState == persistentStateValue) {
        return;
    }

    mPersistentState = persistentStateValue;

    Q_EMIT persistentStateChanged();
431
432
433
434

    if (mCurrentTrack.isValid()) {
        restorePreviousState();
    }
435
436
}

437
438
void ManageAudioPlayer::playerSeek(int position)
{
439
    Q_EMIT seek(position);
440
}
441

442
443
444
void ManageAudioPlayer::playListFinished()
{
    mPlayingState = false;
445
446
}

447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
void ManageAudioPlayer::tracksDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
{
    if (!mCurrentTrack.isValid()) {
        return;
    }

    if (mCurrentTrack.row() > bottomRight.row() || mCurrentTrack.row() < topLeft.row()) {
        return;
    }

    if (mCurrentTrack.column() > bottomRight.column() || mCurrentTrack.column() < topLeft.column()) {
        return;
    }

    if (roles.isEmpty()) {
        notifyPlayerSourceProperty();
463
        restorePreviousState();
464
465
466
467
    } else {
        for(auto oneRole : roles) {
            if (oneRole == mUrlRole) {
                notifyPlayerSourceProperty();
468
                restorePreviousState();
469
470
471
472
473
            }
        }
    }
}

474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
void ManageAudioPlayer::setTitleRole(int titleRole)
{
    if (mTitleRole == titleRole) {
        return;
    }

    mTitleRole = titleRole;
    Q_EMIT titleRoleChanged();

    if (mCurrentTrack.isValid()) {
        restorePreviousState();
    }
}

void ManageAudioPlayer::setArtistNameRole(int artistNameRole)
{
    if (mArtistNameRole == artistNameRole) {
        return;
    }

    mArtistNameRole = artistNameRole;
    Q_EMIT artistNameRoleChanged();

    if (mCurrentTrack.isValid()) {
        restorePreviousState();
    }
}

void ManageAudioPlayer::setAlbumNameRole(int albumNameRole)
{
    if (mAlbumNameRole == albumNameRole) {
        return;
    }

    mAlbumNameRole = albumNameRole;
    Q_EMIT albumNameRoleChanged();

    if (mCurrentTrack.isValid()) {
        restorePreviousState();
    }
}

516
517
518
void ManageAudioPlayer::notifyPlayerSourceProperty()
{
    auto newUrlValue = mCurrentTrack.data(mUrlRole);
519
    if (mSkippingCurrentTrack || mOldPlayerSource != newUrlValue) {
Alexander Stippich's avatar
Alexander Stippich committed
520
        Q_EMIT playerSourceChanged(mCurrentTrack.data(mUrlRole).toUrl());
521
522
523
524
525

        mOldPlayerSource = newUrlValue;
    }
}

526
527
void ManageAudioPlayer::triggerPlay()
{
528
    QTimer::singleShot(0, this, [this]() {Q_EMIT playerPlay();});
529
530
531
532
}

void ManageAudioPlayer::triggerPause()
{
533
    QTimer::singleShot(0, this, [this]() {Q_EMIT playerPause();});
534
535
536
537
}

void ManageAudioPlayer::triggerStop()
{
538
    QTimer::singleShot(0, this, [this]() {Q_EMIT playerStop();});
539
540
541
542
}

void ManageAudioPlayer::triggerSkipNextTrack()
{
543
    QTimer::singleShot(0, this, [this]() {Q_EMIT skipNextTrack();});
544
545
}

546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
void ManageAudioPlayer::restorePreviousState()
{
    if (mPersistentState.isEmpty()) {
        return;
    }

    auto itTitle = mPersistentState.find(QStringLiteral("audioPlayerCurrentTitle"));
    auto itArtistName = mPersistentState.find(QStringLiteral("audioPlayerCurrentArtistName"));
    auto itAlbumName = mPersistentState.find(QStringLiteral("audioPlayerCurrentAlbumName"));

    if (itTitle == mPersistentState.end() || itArtistName == mPersistentState.end() ||
            itAlbumName == mPersistentState.end()) {
        return;
    }

561
562
563
    if (*itTitle != mCurrentTrack.data(mTitleRole) ||
            (itArtistName->isValid() && *itArtistName != mCurrentTrack.data(mArtistNameRole)) ||
            (itAlbumName->isValid() && *itAlbumName != mCurrentTrack.data(mAlbumNameRole))) {
564
565
566
567
568
569
570
571
572
573
574
575
576
        if (mCurrentTrack.isValid() && mCurrentTrack.data(mTitleRole).isValid() && mCurrentTrack.data(mArtistNameRole).isValid() &&
                mCurrentTrack.data(mAlbumNameRole).isValid()) {
            mPersistentState.clear();
        }

        return;
    }

    if (!mCurrentTrack.data(mUrlRole).toUrl().isValid()) {
        return;
    }

    auto isPlaying = mPersistentState.find(QStringLiteral("isPlaying"));
577
578
579
    auto currentConfiguration = Elisa::ElisaConfiguration::self();
    bool autoPlay = currentConfiguration->playAtStartup();
    if (autoPlay && isPlaying != mPersistentState.end() && mPlayingState != isPlaying->toBool()) {
580
581
582
583
584
        mPlayingState = isPlaying->toBool();
    }

    auto playerPosition = mPersistentState.find(QStringLiteral("playerPosition"));
    if (playerPosition != mPersistentState.end()) {
stef lep's avatar
stef lep committed
585
        setPlayerPosition(playerPosition->toLongLong());
586
587
        Q_EMIT seek(mPlayerPosition);
    }
stef lep's avatar
stef lep committed
588
589
590
591
    auto playerDuration = mPersistentState.find(QStringLiteral("playerDuration"));
    if (playerDuration != mPersistentState.end()) {
        setAudioDuration(playerDuration->toInt());
    }
592
593
594
595

    mPersistentState.clear();
}

596
597

#include "moc_manageaudioplayer.cpp"