mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 06:10:04 +00:00 
			
		
		
		
	Move media objects to dedicated thread to avoid main thread delays
This commit is contained in:
		
							parent
							
								
									38d36d37f6
								
							
						
					
					
						commit
						4ed1fda1ae
					
				
					 2 changed files with 84 additions and 44 deletions
				
			
		|  | @ -5,13 +5,10 @@ | ||||||
| #include <QAudioOutput> | #include <QAudioOutput> | ||||||
| #include <QMediaDevices> | #include <QMediaDevices> | ||||||
| #include <QMediaPlayer> | #include <QMediaPlayer> | ||||||
|  | #include <QThread> | ||||||
| #include <QUrl> | #include <QUrl> | ||||||
| 
 | 
 | ||||||
| namespace scwx | namespace scwx::qt::manager | ||||||
| { |  | ||||||
| namespace qt |  | ||||||
| { |  | ||||||
| namespace manager |  | ||||||
| { | { | ||||||
| 
 | 
 | ||||||
| static const std::string logPrefix_ = "scwx::qt::manager::media_manager"; | static const std::string logPrefix_ = "scwx::qt::manager::media_manager"; | ||||||
|  | @ -20,46 +17,80 @@ static const auto        logger_    = scwx::util::Logger::Create(logPrefix_); | ||||||
| class MediaManager::Impl | class MediaManager::Impl | ||||||
| { | { | ||||||
| public: | public: | ||||||
|    explicit Impl(MediaManager* self) : |    explicit Impl() | ||||||
|        self_ {self}, |  | ||||||
|        mediaDevices_ {new QMediaDevices(self)}, |  | ||||||
|        mediaPlayer_ {new QMediaPlayer(self)}, |  | ||||||
|        audioOutput_ {new QAudioOutput(self)} |  | ||||||
|    { |    { | ||||||
|  |       mediaParent_ = std::make_unique<QObject>(); | ||||||
|  |       mediaParent_->moveToThread(&thread_); | ||||||
|  | 
 | ||||||
|  |       thread_.start(); | ||||||
|  | 
 | ||||||
|  |       QMetaObject::invokeMethod( | ||||||
|  |          mediaParent_.get(), | ||||||
|  |          [this]() | ||||||
|  |          { | ||||||
|  |             // QObjects are managed by the parent
 | ||||||
|  |             // NOLINTBEGIN(cppcoreguidelines-owning-memory)
 | ||||||
|  | 
 | ||||||
|  |             logger_->debug("Creating QMediaDevices"); | ||||||
|  |             mediaDevices_ = new QMediaDevices(mediaParent_.get()); | ||||||
|  |             logger_->debug("Creating QMediaPlayer"); | ||||||
|  |             mediaPlayer_ = new QMediaPlayer(mediaParent_.get()); | ||||||
|  |             logger_->debug("Creating QAudioOutput"); | ||||||
|  |             audioOutput_ = new QAudioOutput(mediaParent_.get()); | ||||||
|  | 
 | ||||||
|  |             // NOLINTEND(cppcoreguidelines-owning-memory)
 | ||||||
|  | 
 | ||||||
|             logger_->debug("Audio device: {}", |             logger_->debug("Audio device: {}", | ||||||
|                            audioOutput_->device().description().toStdString()); |                            audioOutput_->device().description().toStdString()); | ||||||
| 
 | 
 | ||||||
|             mediaPlayer_->setAudioOutput(audioOutput_); |             mediaPlayer_->setAudioOutput(audioOutput_); | ||||||
| 
 | 
 | ||||||
|             ConnectSignals(); |             ConnectSignals(); | ||||||
|  |          }); | ||||||
|    } |    } | ||||||
| 
 | 
 | ||||||
|    ~Impl() {} |    ~Impl() | ||||||
|  |    { | ||||||
|  |       // Delete the media parent
 | ||||||
|  |       mediaParent_.reset(); | ||||||
|  | 
 | ||||||
|  |       thread_.quit(); | ||||||
|  |       thread_.wait(); | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    Impl(const Impl&)             = delete; | ||||||
|  |    Impl& operator=(const Impl&)  = delete; | ||||||
|  |    Impl(const Impl&&)            = delete; | ||||||
|  |    Impl& operator=(const Impl&&) = delete; | ||||||
| 
 | 
 | ||||||
|    void ConnectSignals(); |    void ConnectSignals(); | ||||||
| 
 | 
 | ||||||
|    MediaManager* self_; |    QThread thread_ {}; | ||||||
| 
 | 
 | ||||||
|    QMediaDevices* mediaDevices_; |    std::unique_ptr<QObject> mediaParent_ {nullptr}; | ||||||
|    QMediaPlayer*  mediaPlayer_; |    QMediaDevices*           mediaDevices_ {nullptr}; | ||||||
|    QAudioOutput*  audioOutput_; |    QMediaPlayer*            mediaPlayer_ {nullptr}; | ||||||
|  |    QAudioOutput*            audioOutput_ {nullptr}; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| MediaManager::MediaManager() : p(std::make_unique<Impl>(this)) {} | MediaManager::MediaManager() : p(std::make_unique<Impl>()) {} | ||||||
| MediaManager::~MediaManager() = default; | MediaManager::~MediaManager() = default; | ||||||
| 
 | 
 | ||||||
|  | MediaManager::MediaManager(MediaManager&&) noexcept            = default; | ||||||
|  | MediaManager& MediaManager::operator=(MediaManager&&) noexcept = default; | ||||||
|  | 
 | ||||||
| void MediaManager::Impl::ConnectSignals() | void MediaManager::Impl::ConnectSignals() | ||||||
| { | { | ||||||
|    QObject::connect( |    QObject::connect( | ||||||
|       mediaDevices_, |       mediaDevices_, | ||||||
|       &QMediaDevices::audioOutputsChanged, |       &QMediaDevices::audioOutputsChanged, | ||||||
|       self_, |       mediaParent_.get(), | ||||||
|       [this]() |       [this]() | ||||||
|       { audioOutput_->setDevice(QMediaDevices::defaultAudioOutput()); }); |       { audioOutput_->setDevice(QMediaDevices::defaultAudioOutput()); }); | ||||||
| 
 | 
 | ||||||
|    QObject::connect(audioOutput_, |    QObject::connect(audioOutput_, | ||||||
|                     &QAudioOutput::deviceChanged, |                     &QAudioOutput::deviceChanged, | ||||||
|                     self_, |                     mediaParent_.get(), | ||||||
|                     [this]() |                     [this]() | ||||||
|                     { |                     { | ||||||
|                        logger_->debug( |                        logger_->debug( | ||||||
|  | @ -69,7 +100,7 @@ void MediaManager::Impl::ConnectSignals() | ||||||
| 
 | 
 | ||||||
|    QObject::connect(mediaPlayer_, |    QObject::connect(mediaPlayer_, | ||||||
|                     &QMediaPlayer::errorOccurred, |                     &QMediaPlayer::errorOccurred, | ||||||
|                     self_, |                     mediaParent_.get(), | ||||||
|                     [](QMediaPlayer::Error error, const QString& errorString) |                     [](QMediaPlayer::Error error, const QString& errorString) | ||||||
|                     { |                     { | ||||||
|                        logger_->error("Error {}: {}", |                        logger_->error("Error {}: {}", | ||||||
|  | @ -81,30 +112,46 @@ void MediaManager::Impl::ConnectSignals() | ||||||
| void MediaManager::Play(types::AudioFile media) | void MediaManager::Play(types::AudioFile media) | ||||||
| { | { | ||||||
|    const std::string path = types::GetMediaPath(media); |    const std::string path = types::GetMediaPath(media); | ||||||
|  |    Play(path); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void MediaManager::Play(const std::string& mediaPath) | void MediaManager::Play(const std::string& mediaPath) | ||||||
| { | { | ||||||
|    logger_->debug("Playing audio: {}", mediaPath); |    logger_->debug("Playing audio: {}", mediaPath); | ||||||
| 
 | 
 | ||||||
|  |    if (p->mediaPlayer_ == nullptr) | ||||||
|  |    { | ||||||
|  |       logger_->warn("Media player is not yet initialized"); | ||||||
|  |       return; | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|    if (mediaPath.starts_with(':')) |    if (mediaPath.starts_with(':')) | ||||||
|    { |    { | ||||||
|       p->mediaPlayer_->setSource( |       QMetaObject::invokeMethod( | ||||||
|  |          p->mediaPlayer_, | ||||||
|  |          &QMediaPlayer::setSource, | ||||||
|          QUrl(QString("qrc%1").arg(QString::fromStdString(mediaPath)))); |          QUrl(QString("qrc%1").arg(QString::fromStdString(mediaPath)))); | ||||||
|    } |    } | ||||||
|    else |    else | ||||||
|    { |    { | ||||||
|       p->mediaPlayer_->setSource( |       QMetaObject::invokeMethod( | ||||||
|  |          p->mediaPlayer_, | ||||||
|  |          &QMediaPlayer::setSource, | ||||||
|          QUrl::fromLocalFile(QString::fromStdString(mediaPath))); |          QUrl::fromLocalFile(QString::fromStdString(mediaPath))); | ||||||
|    } |    } | ||||||
| 
 | 
 | ||||||
|    p->mediaPlayer_->setPosition(0); |    QMetaObject::invokeMethod(p->mediaPlayer_, &QMediaPlayer::setPosition, 0); | ||||||
| 
 |  | ||||||
|    QMetaObject::invokeMethod(p->mediaPlayer_, &QMediaPlayer::play); |    QMetaObject::invokeMethod(p->mediaPlayer_, &QMediaPlayer::play); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void MediaManager::Stop() | void MediaManager::Stop() | ||||||
| { | { | ||||||
|  |    if (p->mediaPlayer_ == nullptr) | ||||||
|  |    { | ||||||
|  |       logger_->warn("Media player is not yet initialized"); | ||||||
|  |       return; | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|    QMetaObject::invokeMethod(p->mediaPlayer_, &QMediaPlayer::stop); |    QMetaObject::invokeMethod(p->mediaPlayer_, &QMediaPlayer::stop); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -126,6 +173,4 @@ std::shared_ptr<MediaManager> MediaManager::Instance() | ||||||
|    return mediaManager; |    return mediaManager; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace manager
 | } // namespace scwx::qt::manager
 | ||||||
| } // namespace qt
 |  | ||||||
| } // namespace scwx
 |  | ||||||
|  |  | ||||||
|  | @ -4,24 +4,21 @@ | ||||||
| 
 | 
 | ||||||
| #include <memory> | #include <memory> | ||||||
| 
 | 
 | ||||||
| #include <QObject> | namespace scwx::qt::manager | ||||||
| 
 |  | ||||||
| namespace scwx |  | ||||||
| { |  | ||||||
| namespace qt |  | ||||||
| { |  | ||||||
| namespace manager |  | ||||||
| { | { | ||||||
| 
 | 
 | ||||||
| class MediaManager : public QObject | class MediaManager | ||||||
| { | { | ||||||
|    Q_OBJECT |  | ||||||
|    Q_DISABLE_COPY_MOVE(MediaManager) |  | ||||||
| 
 |  | ||||||
| public: | public: | ||||||
|    explicit MediaManager(); |    explicit MediaManager(); | ||||||
|    ~MediaManager(); |    ~MediaManager(); | ||||||
| 
 | 
 | ||||||
|  |    MediaManager(const MediaManager&)            = delete; | ||||||
|  |    MediaManager& operator=(const MediaManager&) = delete; | ||||||
|  | 
 | ||||||
|  |    MediaManager(MediaManager&&) noexcept; | ||||||
|  |    MediaManager& operator=(MediaManager&&) noexcept; | ||||||
|  | 
 | ||||||
|    void Play(types::AudioFile media); |    void Play(types::AudioFile media); | ||||||
|    void Play(const std::string& mediaPath); |    void Play(const std::string& mediaPath); | ||||||
|    void Stop(); |    void Stop(); | ||||||
|  | @ -33,6 +30,4 @@ private: | ||||||
|    std::unique_ptr<Impl> p; |    std::unique_ptr<Impl> p; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace manager
 | } // namespace scwx::qt::manager
 | ||||||
| } // namespace qt
 |  | ||||||
| } // namespace scwx
 |  | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat