Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-35916

200+ millisecond blocking delay when calling stop() on a QSoundEffect

    XMLWordPrintable

Details

    • Bug
    • Resolution: Done
    • P2: Important
    • 5.9.4
    • 5.2.0, 5.9.1
    • Multimedia
    • None
    • Windows 7 64-bit

    Description

      #include <QtGui>
      
      #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
      #include <QtWidgets>
      #endif
      
      #include <QtMultimedia/QSoundEffect>
      
      class AudioPlayer : public QWidget
      {
          Q_OBJECT
      public:
          AudioPlayer(QWidget *parent) :
              QWidget(parent),
              mLayout(new QVBoxLayout(this)),
              mButton(new QPushButton("Play", this)),
              mLabel(new QLabel("...", this))
          {
              mLayout->addWidget(mButton);
              mLayout->addWidget(mLabel);
              setLayout(mLayout);
      
              mLabel->setAlignment(Qt::AlignHCenter);
      
              connect(mButton, SIGNAL(clicked()), this, SLOT(playPause()));
      
              mTimer.setInterval(5);
              mTimer.start();
              connect(&mTimer, SIGNAL(timeout()), this, SLOT(animate()));
      
              resize(parent->width(), parent->height());
          }
      private slots:
          void playPause() {
              if (!mSound.isPlaying()) {
                  mSound.setSource(QUrl::fromLocalFile("test.wav"));
                  mSound.setLoopCount(QSoundEffect::Infinite);
                  mSound.setVolume(0.25);
                  mSound.play();
      
                  connect(&mSound, SIGNAL(loadedChanged()), this, SLOT(doneLoading()));
      
                  mButton->setEnabled(false);
                  mButton->setText("Stop");
              } else {
                  QElapsedTimer elapsedTimer;
                  elapsedTimer.start();
                  qDebug() << "Before QSoundEffect::stop()";
                  mSound.stop();
                  qDebug() << "After QSoundEffect::stop() (" << elapsedTimer.elapsed() << "ms)";
      
                  mButton->setEnabled(false);
              }
          }
      
          void doneLoading() {
              mButton->setEnabled(true);
          }
      
          void animate() {
              if (mLabel->text().size() == 40) {
                  mLabel->setText(QString());
              }
              mLabel->setText(mLabel->text() + ".");
          }
      
      private:
          QSoundEffect mSound;
          QVBoxLayout *mLayout;
          QPushButton *mButton;
          QLabel *mLabel;
          QTimer mTimer;
      };
      
      int main(int argc, char *argv[])
      {
          QApplication a(argc, argv);
      
          QMainWindow mainWindow;
      
          AudioPlayer *audioPlayer = new AudioPlayer(&mainWindow);
          mainWindow.setCentralWidget(audioPlayer);
      
          mainWindow.show();
      
          return a.exec();
      }
      
      #include "main.moc"
      

      The problem is the Sleep call:

      void QAudioOutputPrivate::close()
      {
          if(deviceState == QAudio::StoppedState)
              return;
      
          deviceState = QAudio::StoppedState;
          errorState = QAudio::NoError;
          QElapsedTimer t;
          t.start();
          int delay = (buffer_size-bytesFree())*1000/(settings.sampleRate()
                        *settings.channelCount()*(settings.sampleSize()/8));
          waveOutReset(hWaveOut);
          Sleep(delay+10);
          qDebug() << t.elapsed() << delay;
      
          freeBlocks(waveBlocks);
          waveOutClose(hWaveOut);
          delete [] audioBuffer;
          audioBuffer = 0;
          buffer_size = 0;
      }
      

      http://msdn.microsoft.com/en-us/library/windows/desktop/dd743856(v=vs.85).aspx says:

      Remarks

      The close operation fails if the device is still playing a waveform-audio buffer that was previously sent by calling waveOutWrite. Before calling waveOutClose, the application must wait for all buffers to finish playing or call the waveOutReset function to terminate playback.

      So the call to Sleep might not be necessary.

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            valentyn.doroshchuk Valentyn Doroshchuk
            mitch_curtis Mitch Curtis
            Votes:
            4 Vote for this issue
            Watchers:
            5 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes