Symbian QT: Multithreaded audio menggunakan QAudioOutput
Tutorial Qt for Symbian OS
![Symbian QT: Multithreaded audio menggunakan QAudioOutput](https://symbianesia.com/uploads/images/202407/image_750x_6683a5aacf101.webp)
Saya perhatikan bahwa jika UI QML menjalankan animasi dan pada saat yang sama saya mencoba menggunakan QAudioOutput untuk memutar efek suara, animasinya menjadi tersendat-sendat dengan mudah, setidaknya pada perangkat (Symbian). Saya kira penyebab masalahnya adalah pemrosesan audio terjadi di utas yang sama yang menjalankan loop peristiwa.
Solusi untuk masalah ini cukup jelas – pindahkan hal-hal yang berhubungan dengan audio ke utas yang berbeda. Namun, untuk melakukan ini diperlukan sedikit penyesuaian, jadi saya mendokumentasikan solusinya di sini jika ada orang lain yang menghadapi masalah yang sama. Tentu saja, solusi ini sama sekali tidak eksklusif untuk keluaran audio, solusi ini juga dapat digunakan untuk melakukan pemrosesan apa pun (yang dimulai dengan QML atau C++) di utas terpisah.
Dalam implementasi saya, saya menggunakan dua kelas C++, SfxPlayer dan SfxThread. SfxPlayer diekspos ke sisi QML dan berisi satu slot, play(). Satu-satunya tujuan kelas ini adalah untuk memuat objek SfxThread dan berfungsi sebagai proksi untuk memanggil metode di thread lainnya.
pemutar sfx.h
#ifndef SFXPLAYER_H #define SFXPLAYER_H #include#include "sfxthread.h" class SfxPlayer : public QObject { Q_OBJECT public: explicit SfxPlayer(QObject *parent = 0); signals: public slots: void play(); private: SfxThread _sfxThread; }; #endif // SFXPLAYER_H
pemutar sfx.cpp
#include "sfxplayer.h" SfxPlayer::SfxPlayer(QObject *parent) : QObject(parent) { } void SfxPlayer::play() { // Call playInternal of SfxThread (and invoke it in the other thread) QMetaObject::invokeMethod(&_sfxThread, "play", Qt::QueuedConnection); }
Hal yang sedikit membingungkan adalah bagaimana membuat utas pemain benar-benar melakukan pemrosesan di utas lain, bukan di pemanggil. Solusinya adalah memanggil QObject::moveToThread(this); di konstruktor utas.
sfxthread.h
#ifndef SFXTHREAD_H #define SFXTHREAD_H #include#include #include #include class SfxThread : public QThread { Q_OBJECT public: explicit SfxThread(QObject *parent = 0); ~SfxThread(); void run(); signals: public slots: void play(); void playerStateChanged(QAudio::State state); private: void playNext(); void play(QString& filename); QAudioOutput *_ao; QAudioFormat _af; QBuffer _buf; QQueue playlist; }; #endif // SFXTHREAD_H
sfxthread.cpp
#include#include #include "sfxthread.h" SfxThread::SfxThread(QObject *parent) : QThread(parent) { ...do precaching etc of the sounds here start(); // Move event processing of SfxThread to this thread QObject::moveToThread(this); } SfxThread::~SfxThread() { quit(); wait(); } void SfxThread::play() { playlist.append(...); playNext(); } // Plays the next file from queue void SfxThread::playNext() { if (playlist.length() == 0 || _ao->state() == QAudio::ActiveState) { return; } _ao->stop(); _buf.close(); play(playlist.dequeue()); } void SfxThread::play(QString& filename) { // load content here QByteArray *ptr = ... _buf.setBuffer(ptr); _buf.open(QIODevice::ReadOnly); _ao->setBufferSize(_buf.size()); _ao->start(&_buf); } void SfxThread::playerStateChanged(QAudio::State state) { // Play finished, play next clip if (state == QAudio::IdleState) { playNext(); } } void SfxThread::run() { ...set audio format here (_af.setCodec etc) _ao = new QAudioOutput(_af); connect(_ao, SIGNAL(stateChanged(QAudio::State)), this, SLOT(playerStateChanged(QAudio::State))); exec(); }
Selesai! Kini Anda dapat mengekspos objek SfxPlayer ke QML. Memanggil .play(); di QML kini hanya akan memanggil metode play dari SfxThread di thread baru yang menjalankan loop peristiwanya sendiri.
Apa Reaksi Anda?
![like](https://symbianesia.com/assets/img/reactions/like.png)
![dislike](https://symbianesia.com/assets/img/reactions/dislike.png)
![love](https://symbianesia.com/assets/img/reactions/love.png)
![funny](https://symbianesia.com/assets/img/reactions/funny.png)
![angry](https://symbianesia.com/assets/img/reactions/angry.png)
![sad](https://symbianesia.com/assets/img/reactions/sad.png)
![wow](https://symbianesia.com/assets/img/reactions/wow.png)