#pragma once #include "logger.hpp" #include #include #include #include #include #include #include #include #include #include #include class PlaylistController : public QObject { Q_OBJECT Q_PROPERTY(QObject *videoOutputA READ videoOutputA WRITE setVideoOutputA NOTIFY videoOutputChangedA) Q_PROPERTY(QObject *audioOutputA READ audioOutputA WRITE setAudioOutputA NOTIFY audioOutputChangedA) Q_PROPERTY(QObject *videoOutputB READ videoOutputB WRITE setVideoOutputB NOTIFY videoOutputChanged) Q_PROPERTY(QObject *audioOutputB READ audioOutputB WRITE setAudioOutputB NOTIFY audioOutputChangedB) Q_PROPERTY(QString playingState READ playingState NOTIFY playingStateChanged) public: explicit PlaylistController(QObject *parent = nullptr) : QObject(parent) { m_playerA = new QMediaPlayer(this); m_playerB = new QMediaPlayer(this); m_activePlayer = m_playerA; m_nextPlayer = m_playerB; connect(m_playerA, &QMediaPlayer::mediaStatusChanged, this, [this](QMediaPlayer::MediaStatus status) { onMediaStatusChanged(m_playerA, status); }); connect(m_playerB, &QMediaPlayer::mediaStatusChanged, this, [this](QMediaPlayer::MediaStatus status) { onMediaStatusChanged(m_playerB, status); }); } QObject *videoOutputA() const { return m_videoOutputA; } QObject *videoOutputB() const { return m_videoOutputB; } QObject *audioOutputA() const { return m_audioOutputA; } QObject *audioOutputB() const { return m_audioOutputB; } QString playingState() const { return m_playingState ? "playing" : "pause"; } void setVideoOutputA(QObject *output) { if (m_videoOutputA != output) { m_videoOutputA = output; if (m_videoOutputA) { m_playerA->setVideoOutput(m_videoOutputA); } emit videoOutputChangedA(); } } void setAudioOutputA(QObject *output) { if (m_audioOutputA != output) { m_audioOutputA = output; if (m_videoOutputA) { if (auto *audio = qobject_cast(m_audioOutputA)) { m_playerA->setAudioOutput(audio); } } emit audioOutputChangedA(); } } void setVideoOutputB(QObject *output) { if (m_videoOutputB != output) { m_videoOutputB = output; if (m_videoOutputB) { m_playerB->setVideoOutput(m_videoOutputB); } emit videoOutputChangedB(); } } void setAudioOutputB(QObject *output) { if (m_audioOutputB != output) { m_audioOutputB = output; if (m_videoOutputB) { if (auto *audio = qobject_cast(m_audioOutputB)) { m_playerB->setAudioOutput(audio); } } emit audioOutputChangedB(); } } Q_INVOKABLE void prepareNext(const QUrl &url) { // Desplegar hilo que descargue y gestione el mediaplayer Logger::info(url.toString().toStdString()); m_nextPlayer->setSource(url); // Para que se quede listo m_nextPlayer->play(); m_nextPlayer->pause(); m_nextPlayer->setPosition(0); } Q_INVOKABLE void swapAndPlay() { std::swap(m_activePlayer, m_nextPlayer); m_activePlayer->play(); m_playingState = true; // m_activePlayer->setPlaybackRate(1); if (m_queue.size() - 1 > m_queue_index) { prepareNext(QUrl::fromLocalFile(m_queue.at(m_queue_index + 1))); } } Q_INVOKABLE void setVolume(float volume) { if (auto *audio = qobject_cast(m_audioOutputA)) { audio->setVolume(std::clamp(m_volume + volume, 0.0f, 1.0f)); } if (auto *audio = qobject_cast(m_audioOutputB)) { audio->setVolume(std::clamp(m_volume + volume, 0.0f, 1.0f)); } } Q_INVOKABLE void seek(long long time) { m_activePlayer->setPosition(std::clamp(m_activePlayer->position() + time, 0ll, m_activePlayer->duration())); } Q_INVOKABLE void addToQueue(const QString &url) { int n_ele = m_queue.size(); m_queue.push_back(url); if (m_nextPlayer->source() == QUrl()) { prepareNext(m_queue.at(m_queue_index)); } } Q_INVOKABLE void togglePause() { m_playingState = !m_playingState; if (!m_playingState) m_activePlayer->pause(); else m_activePlayer->play(); emit playingStateChanged(); } signals: void videoOutputChanged(); void videoOutputChangedA(); void audioOutputChangedA(); void videoOutputChangedB(); void audioOutputChangedB(); void playingStateChanged(); private: std::vector m_queue = std::vector(); bool m_playing = false; QMediaPlayer *m_playerA{nullptr}; QMediaPlayer *m_playerB{nullptr}; QMediaPlayer *m_activePlayer{nullptr}; QMediaPlayer *m_nextPlayer{nullptr}; QObject *m_videoOutputA{nullptr}; QObject *m_videoOutputB{nullptr}; QObject *m_audioOutputA{nullptr}; QObject *m_audioOutputB{nullptr}; float m_volume = 1; bool m_playingState = false; int m_queue_index = 0; void onMediaStatusChanged(QMediaPlayer *player, QMediaPlayer::MediaStatus status) { bool isActive = (player == m_activePlayer); switch (status) { case QMediaPlayer::LoadedMedia: Logger::info(isActive ? "Active media loaded" : "Next media loaded and ready"); break; case QMediaPlayer::BufferedMedia: Logger::info("Media fully buffered"); if (!isActive) { Logger::info("Next media fully buffered"); } break; case QMediaPlayer::EndOfMedia: if (isActive) { if (m_queue.size() - 1 > m_queue_index) { m_queue_index++; swapAndPlay(); } } break; case QMediaPlayer::InvalidMedia: Logger::error("Failed to load or play media"); break; default: break; } } };