From c25e7f268efc17874b3793b207df08f5463f76e1 Mon Sep 17 00:00:00 2001 From: Konstantin Isakov Date: Sat, 2 Jan 2010 21:16:22 +0300 Subject: [PATCH] Use Phonon framework for audio playback. This is now the default way to play back sound under Windows. The other one, "Use external program", was also made available there. The old method of audio playback under Windows (via PlaySound) was completely removed. Since Phonon uses DirectShow as a backend under Windows, all file types supported by it should now play back. Therefore, the previous limitation to just .wav files is now lifted. Since Phonon is only available starting from Qt 4.6.0 under Windows, no older versions of Qt are supported anymore there. --- src/articleview.cc | 100 +++++++++++++++++++++++++++------------------ src/articleview.hh | 6 +-- src/config.cc | 12 ++++++ src/config.hh | 1 + src/filetype.cc | 11 ++++- src/goldendict.pro | 1 + src/preferences.cc | 18 +++++--- src/preferences.hh | 2 + src/preferences.ui | 75 +++++++++++++++++++++++----------- 9 files changed, 153 insertions(+), 73 deletions(-) diff --git a/src/articleview.cc b/src/articleview.cc index d72295ef..31efa296 100644 --- a/src/articleview.cc +++ b/src/articleview.cc @@ -14,14 +14,38 @@ #include "folding.hh" #include "wstring_qt.hh" -#ifdef Q_OS_WIN32 -#include -#include // For PlaySound -#endif +#include using std::map; using std::list; +/// A phonon-based audio player, created on demand +struct AudioPlayer +{ + Phonon::AudioOutput output; + Phonon::MediaObject object; + + static AudioPlayer & instance(); + +private: + + AudioPlayer(); +}; + +AudioPlayer::AudioPlayer(): + output( Phonon::AccessibilityCategory ) +{ + Phonon::createPath( &object, &output ); +} + +AudioPlayer & AudioPlayer::instance() +{ + static AudioPlayer a; + + return a; +} + + ArticleView::ArticleView( QWidget * parent, ArticleNetworkAccessManager & nm, std::vector< sptr< Dictionary::Class > > const & allDictionaries_, Instances::Groups const & groups_, bool popupView_, @@ -118,15 +142,6 @@ void ArticleView::setGroupComboBox( GroupComboBox const * g ) ArticleView::~ArticleView() { cleanupTemp(); - - #ifdef Q_OS_WIN32 - if ( winWavData.size() ) - { - // If we were playing some sound some time ago, make sure it stopped - // playing before freeing the waveform memory. - PlaySoundA( 0, 0, 0 ); - } - #endif } void ArticleView::showDefinition( QString const & word, unsigned group, @@ -945,42 +960,49 @@ void ArticleView::resourceDownloadFinished() if ( resourceDownloadUrl.scheme() == "gdau" ) { - #ifdef Q_OS_WIN32 - // Windows-only: use system PlaySound function + // Audio data - if ( winWavData.size() ) - PlaySoundA( 0, 0, 0 ); // Stop any currently playing sound to make sure - // previous data isn't used anymore - // - winWavData = data; - - PlaySoundA( &winWavData.front(), 0, - SND_ASYNC | SND_MEMORY | SND_NODEFAULT | SND_NOWAIT ); - #else - - // Use external viewer to play the file - try + if ( !cfg.preferences.useExternalPlayer ) { - ExternalViewer * viewer = new ExternalViewer( this, data, "wav", cfg.preferences.audioPlaybackProgram.trimmed() ); + // Play via Phonon + QBuffer * buf = new QBuffer; + + buf->buffer().append( &data.front(), data.size() ); + + Phonon::MediaSource source( buf ); + source.setAutoDelete( true ); // Dispose of our buf when done + + AudioPlayer::instance().object.stop(); + AudioPlayer::instance().object.clear(); + AudioPlayer::instance().object.enqueue( source ); + AudioPlayer::instance().object.play(); + } + else + { + + // Use external viewer to play the file try { - viewer->start(); + ExternalViewer * viewer = new ExternalViewer( this, data, "wav", cfg.preferences.audioPlaybackProgram.trimmed() ); - // Once started, it will erase itself + try + { + viewer->start(); + + // Once started, it will erase itself + } + catch( ... ) + { + delete viewer; + throw; + } } - catch( ... ) + catch( ExternalViewer::Ex & e ) { - delete viewer; - throw; + QMessageBox::critical( this, tr( "GoldenDict" ), tr( "Failed to run a player to play sound file: %1" ).arg( e.what() ) ); } } - catch( ExternalViewer::Ex & e ) - { - QMessageBox::critical( this, tr( "GoldenDict" ), tr( "Failed to run a player to play sound file: %1" ).arg( e.what() ) ); - } - - #endif } else { diff --git a/src/articleview.hh b/src/articleview.hh index d4d28b1b..e5c3f856 100644 --- a/src/articleview.hh +++ b/src/articleview.hh @@ -12,6 +12,7 @@ #include "instances.hh" #include "groupcombobox.hh" #include "ui_articleview.h" +#include /// A widget with the web view tailored to view and handle articles -- it /// uses the appropriate netmgr, handles link clicks, rmb clicks etc @@ -31,11 +32,6 @@ class ArticleView: public QFrame goBackAction, goForwardAction, openSearchAction; bool searchIsOpened; -#ifdef Q_OS_WIN32 - // Used in Windows only - vector< char > winWavData; -#endif - /// Any resource we've decided to download off the dictionary gets stored here. /// Full vector capacity is used for search requests, where we have to make /// a multitude of requests. diff --git a/src/config.cc b/src/config.cc index 4881ae41..056edd69 100644 --- a/src/config.cc +++ b/src/config.cc @@ -94,6 +94,11 @@ Preferences::Preferences(): scanPopupAltModeSecs( 3 ), pronounceOnLoadMain( false ), pronounceOnLoadPopup( false ), +#ifdef Q_WS_WIN + useExternalPlayer( false ), +#else + useExternalPlayer( true ), // Phonon on Linux still feels quite buggy +#endif checkForNewReleases( true ), disallowContentFromOtherSites( false ), zoomFactor( 1 ) @@ -487,6 +492,9 @@ Class load() throw( exError ) c.preferences.pronounceOnLoadMain = ( preferences.namedItem( "pronounceOnLoadMain" ).toElement().text() == "1" ); c.preferences.pronounceOnLoadPopup = ( preferences.namedItem( "pronounceOnLoadPopup" ).toElement().text() == "1" ); + + if ( !preferences.namedItem( "useExternalPlayer" ).isNull() ) + c.preferences.useExternalPlayer = ( preferences.namedItem( "useExternalPlayer" ).toElement().text() == "1" ); if ( !preferences.namedItem( "audioPlaybackProgram" ).isNull() ) c.preferences.audioPlaybackProgram = preferences.namedItem( "audioPlaybackProgram" ).toElement().text(); @@ -892,6 +900,10 @@ void save( Class const & c ) throw( exError ) opt.appendChild( dd.createTextNode( c.preferences.pronounceOnLoadPopup ? "1" : "0" ) ); preferences.appendChild( opt ); + opt = dd.createElement( "useExternalPlayer" ); + opt.appendChild( dd.createTextNode( c.preferences.useExternalPlayer ? "1" : "0" ) ); + preferences.appendChild( opt ); + opt = dd.createElement( "audioPlaybackProgram" ); opt.appendChild( dd.createTextNode( c.preferences.audioPlaybackProgram ) ); preferences.appendChild( opt ); diff --git a/src/config.hh b/src/config.hh index 38735ca2..b1635041 100644 --- a/src/config.hh +++ b/src/config.hh @@ -156,6 +156,7 @@ struct Preferences // Whether the word should be pronounced on page load, in main window/popup bool pronounceOnLoadMain, pronounceOnLoadPopup; QString audioPlaybackProgram; + bool useExternalPlayer; ProxyServer proxyServer; diff --git a/src/filetype.cc b/src/filetype.cc index 6885e1a7..e33a4495 100644 --- a/src/filetype.cc +++ b/src/filetype.cc @@ -52,7 +52,16 @@ bool isNameOfSound( string const & name ) endsWith( s, ".au" ) || endsWith( s, ".voc" ) || endsWith( s, ".ogg" ) || - endsWith( s, ".mp3" ); + endsWith( s, ".mp3" ) || + endsWith( s, ".mp4" ) || + endsWith( s, ".aac" ) || + endsWith( s, ".flac" ) || + endsWith( s, ".mid" ) || + endsWith( s, ".kar" ) || + endsWith( s, ".mpc" ) || + endsWith( s, ".wma" ) || + endsWith( s, ".wv" ) || + endsWith( s, ".ape" ); } bool isNameOfPicture( string const & name ) diff --git a/src/goldendict.pro b/src/goldendict.pro index 9c3d2472..04151209 100644 --- a/src/goldendict.pro +++ b/src/goldendict.pro @@ -10,6 +10,7 @@ INCLUDEPATH += . QT += webkit QT += xml QT += network +QT += phonon CONFIG += exceptions \ rtti \ stl diff --git a/src/preferences.cc b/src/preferences.cc index 840f26c9..0a9ac6ff 100644 --- a/src/preferences.cc +++ b/src/preferences.cc @@ -125,16 +125,18 @@ Preferences::Preferences( QWidget * parent, Config::Preferences const & p ): // Sound +#ifdef Q_WS_WIN + // Since there's only one Phonon backend under Windows, be more precise + ui.playViaPhonon->setText( tr( "Play via DirectShow" ) ); +#endif + ui.pronounceOnLoadPopup->setEnabled( p.enableScanPopup ); ui.pronounceOnLoadMain->setChecked( p.pronounceOnLoadMain ); ui.pronounceOnLoadPopup->setChecked( p.pronounceOnLoadPopup ); - ui.audioPlaybackProgram->setText( p.audioPlaybackProgram ); -#ifdef Q_OS_WIN32 - ui.audioPlaybackProgram->hide(); - ui.audioPlaybackProgramLabel->hide(); -#endif + ui.useExternalPlayer->setChecked( p.useExternalPlayer ); + ui.audioPlaybackProgram->setText( p.audioPlaybackProgram ); if ( !isRECORDBroken() ) ui.brokenXRECORD->hide(); @@ -203,6 +205,7 @@ Config::Preferences Preferences::getPreferences() p.pronounceOnLoadMain = ui.pronounceOnLoadMain->isChecked(); p.pronounceOnLoadPopup = ui.pronounceOnLoadPopup->isChecked(); + p.useExternalPlayer = ui.useExternalPlayer->isChecked(); p.audioPlaybackProgram = ui.audioPlaybackProgram->text(); p.proxyServer.enabled = ui.useProxyServer->isChecked(); @@ -294,3 +297,8 @@ void Preferences::on_buttonBox_accepted() tr( "Restart the program to apply the language change." ) ); } +void Preferences::on_useExternalPlayer_toggled( bool enabled ) +{ + ui.audioPlaybackProgram->setEnabled( enabled ); +} + diff --git a/src/preferences.hh b/src/preferences.hh index ecbddca0..0a5fc953 100644 --- a/src/preferences.hh +++ b/src/preferences.hh @@ -39,6 +39,8 @@ private slots: void on_enableClipboardHotkey_toggled( bool checked ); void on_buttonBox_accepted(); + + void on_useExternalPlayer_toggled( bool enabled ); }; #endif diff --git a/src/preferences.ui b/src/preferences.ui index 6e80768e..904349e2 100644 --- a/src/preferences.ui +++ b/src/preferences.ui @@ -703,33 +703,65 @@ p, li { white-space: pre-wrap; } - - - Auto-pronounce words in main window + + + Pronunciation + + + + + Auto-pronounce words in main window + + + + + + + Auto-pronounce words in scan popup + + + + - - - Auto-pronounce words in scan popup + + + Playback + + + + + Play via Phonon + + + true + + + + + + + + + Use external program: + + + + + + + false + + + + + + - - - - - - Program to play audio files: - - - - - - - - @@ -973,9 +1005,6 @@ download page. winKey scanPopupAltMode scanPopupAltModeSecs - pronounceOnLoadMain - pronounceOnLoadPopup - audioPlaybackProgram useProxyServer proxyType proxyHost