diff --git a/livesupport/modules/playlistExecutor/include/LiveSupport/PlaylistExecutor/AudioPlayerInterface.h b/livesupport/modules/playlistExecutor/include/LiveSupport/PlaylistExecutor/AudioPlayerInterface.h index cd07f8cf5..4da240357 100644 --- a/livesupport/modules/playlistExecutor/include/LiveSupport/PlaylistExecutor/AudioPlayerInterface.h +++ b/livesupport/modules/playlistExecutor/include/LiveSupport/PlaylistExecutor/AudioPlayerInterface.h @@ -142,11 +142,15 @@ class AudioPlayerInterface * @param fileUrl a URL to a file * @exception std::invalid_argument if the supplied fileUrl * seems to be invalid. + * @exception std::runtime_error if the file could not be openned, + * for example because the audio device of the player + * is being exclusively used by an other process. * @see #close * @see #start */ virtual void - open(const std::string fileUrl) throw (std::invalid_argument) + open(const std::string fileUrl) throw (std::invalid_argument, + std::runtime_error) = 0; /** diff --git a/livesupport/modules/playlistExecutor/src/GstreamerPlayer.cxx b/livesupport/modules/playlistExecutor/src/GstreamerPlayer.cxx index acf8b2a7d..4e2021728 100644 --- a/livesupport/modules/playlistExecutor/src/GstreamerPlayer.cxx +++ b/livesupport/modules/playlistExecutor/src/GstreamerPlayer.cxx @@ -233,7 +233,8 @@ GstreamerPlayer :: eosEventHandler(GstElement * element, *----------------------------------------------------------------------------*/ void GstreamerPlayer :: open(const std::string fileUrl) - throw (std::invalid_argument) + throw (std::invalid_argument, + std::runtime_error) { std::string filePath; GstElement * pipe; @@ -294,7 +295,12 @@ GstreamerPlayer :: open(const std::string fileUrl) // connect the eos signal handler g_signal_connect(decoder, "eos", G_CALLBACK(eosEventHandler), this); - gst_element_set_state(pipeline, GST_STATE_PAUSED); + if (gst_element_set_state(pipeline,GST_STATE_PAUSED) == GST_STATE_FAILURE) { + close(); + // the error is most probably caused by not being able to open + // the audio device (as it might be blocked by an other process + throw std::runtime_error("can't open audio device " + audioDevice); + } gst_bin_sync_children_state(GST_BIN(pipeline)); } diff --git a/livesupport/modules/playlistExecutor/src/GstreamerPlayer.h b/livesupport/modules/playlistExecutor/src/GstreamerPlayer.h index e1b7e5a4f..309fbe33a 100644 --- a/livesupport/modules/playlistExecutor/src/GstreamerPlayer.h +++ b/livesupport/modules/playlistExecutor/src/GstreamerPlayer.h @@ -295,11 +295,15 @@ class GstreamerPlayer : virtual public Configurable, * @param fileUrl a URL to a file * @exception std::invalid_argument if the supplied fileUrl * seems to be invalid. + * @exception std::runtime_error if the file could not be openned, + * for example because the audio device of the player + * is being exclusively used by an other process. * @see #close * @see #start */ virtual void - open(const std::string fileUrl) throw (std::invalid_argument); + open(const std::string fileUrl) throw (std::invalid_argument, + std::runtime_error); /** * Tell if the object is currently opened (has a file source to diff --git a/livesupport/modules/playlistExecutor/src/GstreamerPlayerTest.cxx b/livesupport/modules/playlistExecutor/src/GstreamerPlayerTest.cxx index 261f93170..0dec8391a 100644 --- a/livesupport/modules/playlistExecutor/src/GstreamerPlayerTest.cxx +++ b/livesupport/modules/playlistExecutor/src/GstreamerPlayerTest.cxx @@ -134,6 +134,8 @@ GstreamerPlayerTest :: simplePlayTest(void) player->open("file:var/test.mp3"); } catch (std::invalid_argument &e) { CPPUNIT_FAIL(e.what()); + } catch (std::runtime_error &e) { + CPPUNIT_FAIL(e.what()); } CPPUNIT_ASSERT(!player->isPlaying()); player->start(); @@ -168,6 +170,8 @@ GstreamerPlayerTest :: getPositionTest(void) player->open("file:var/test.mp3"); } catch (std::invalid_argument &e) { CPPUNIT_FAIL(e.what()); + } catch (std::runtime_error &e) { + CPPUNIT_FAIL(e.what()); } CPPUNIT_ASSERT(!player->isPlaying()); start = TimeConversion::now(); @@ -213,6 +217,8 @@ GstreamerPlayerTest :: setDeviceTest(void) player->open("file:var/test-short.mp3"); } catch (std::invalid_argument &e) { CPPUNIT_FAIL(e.what()); + } catch (std::runtime_error &e) { + CPPUNIT_FAIL(e.what()); } CPPUNIT_ASSERT(!player->isPlaying()); player->start(); @@ -231,6 +237,8 @@ GstreamerPlayerTest :: setDeviceTest(void) player->open("file:var/test-short.mp3"); } catch (std::invalid_argument &e) { CPPUNIT_FAIL(e.what()); + } catch (std::runtime_error &e) { + CPPUNIT_FAIL(e.what()); } CPPUNIT_ASSERT(!player->isPlaying()); player->start(); @@ -249,6 +257,8 @@ GstreamerPlayerTest :: setDeviceTest(void) player->open("file:var/test-short.mp3"); } catch (std::invalid_argument &e) { CPPUNIT_FAIL(e.what()); + } catch (std::runtime_error &e) { + CPPUNIT_FAIL(e.what()); } CPPUNIT_ASSERT(player->setAudioDevice("/dev/dsp")); CPPUNIT_ASSERT(!player->isPlaying()); @@ -282,6 +292,8 @@ GstreamerPlayerTest :: simpleSmilTest(void) player->open("file:var/simpleSmil.smil"); } catch (std::invalid_argument &e) { CPPUNIT_FAIL(e.what()); + } catch (std::runtime_error &e) { + CPPUNIT_FAIL(e.what()); } CPPUNIT_ASSERT(!player->isPlaying()); CPPUNIT_ASSERT_NO_THROW( @@ -311,6 +323,8 @@ GstreamerPlayerTest :: secondSmilTest(void) player->open("file:var/sequentialSmil.smil"); } catch (std::invalid_argument &e) { CPPUNIT_FAIL(e.what()); + } catch (std::runtime_error &e) { + CPPUNIT_FAIL(e.what()); } CPPUNIT_ASSERT(!player->isPlaying()); CPPUNIT_ASSERT_NO_THROW( @@ -341,6 +355,8 @@ GstreamerPlayerTest :: animatedSmilTest(void) player->open("file:var/animatedSmil.smil"); } catch (std::invalid_argument &e) { CPPUNIT_FAIL(e.what()); + } catch (std::runtime_error &e) { + CPPUNIT_FAIL(e.what()); } CPPUNIT_ASSERT(!player->isPlaying()); player->start(); @@ -389,6 +405,8 @@ GstreamerPlayerTest :: checkErrorConditions(void) player->open("totally/bad/URL"); } catch (std::invalid_argument &e) { gotException = true; + } catch (std::runtime_error &e) { + CPPUNIT_FAIL(e.what()); } CPPUNIT_ASSERT(gotException); @@ -405,6 +423,8 @@ GstreamerPlayerTest :: checkErrorConditions(void) player->open("file:var/test.mp3"); } catch (std::invalid_argument &e) { CPPUNIT_FAIL(e.what()); + } catch (std::runtime_error &e) { + CPPUNIT_FAIL(e.what()); } player->close(); gotException = false; @@ -412,6 +432,8 @@ GstreamerPlayerTest :: checkErrorConditions(void) player->open("totally/bad/URL"); } catch (std::invalid_argument &e) { gotException = true; + } catch (std::runtime_error &e) { + CPPUNIT_FAIL(e.what()); } CPPUNIT_ASSERT(gotException); @@ -634,6 +656,8 @@ GstreamerPlayerTest :: timeSteps(const std::string fileName) player->open(fileName); } catch (std::invalid_argument &e) { CPPUNIT_FAIL(e.what()); + } catch (std::runtime_error &e) { + CPPUNIT_FAIL(e.what()); } end = TimeConversion::now(); openTime.reset(new time_duration(*end - *start)); @@ -697,6 +721,8 @@ GstreamerPlayerTest :: pauseResumeTest(void) player->open("file:var/test10001.mp3"); } catch (std::invalid_argument &e) { CPPUNIT_FAIL(e.what()); + } catch (std::runtime_error &e) { + CPPUNIT_FAIL(e.what()); } CPPUNIT_ASSERT(!player->isPlaying()); @@ -729,3 +755,64 @@ GstreamerPlayerTest :: pauseResumeTest(void) player->deInitialize(); } + +/*------------------------------------------------------------------------------ + * Open the same soundcard twice, thus force an error + *----------------------------------------------------------------------------*/ +void +GstreamerPlayerTest :: openSoundcardTwiceTest(void) + throw (CPPUNIT_NS::Exception) +{ + Ptr::Ref sleepT(new time_duration(microseconds(10))); + Ptr::Ref player2; + + // create a second player, with the same config as our usual player + try { + Ptr::Ref parser( + new xmlpp::DomParser(configFileName, true)); + const xmlpp::Document * document = parser->get_document(); + const xmlpp::Element * root = document->get_root_node(); + + player2.reset(new GstreamerPlayer()); + player2->configure(*root); + + } catch (std::invalid_argument &e) { + CPPUNIT_FAIL("semantic error in configuration file"); + } catch (xmlpp::exception &e) { + CPPUNIT_FAIL(e.what()); + } + + // initialize & start playing on the first player + player->initialize(); + try { + player->open("file:var/test.mp3"); + } catch (std::invalid_argument &e) { + CPPUNIT_FAIL(e.what()); + } catch (std::runtime_error &e) { + CPPUNIT_FAIL(e.what()); + } + CPPUNIT_ASSERT(!player->isPlaying()); + player->start(); + CPPUNIT_ASSERT(player->isPlaying()); + + // now open the same again in the second one + player2->initialize(); + try { + player2->open("file:var/test.mp3"); + } catch (std::invalid_argument &e) { + CPPUNIT_FAIL(e.what()); + } catch (std::runtime_error &e) { + // this is what we're expecting, if open failed for the reason of + // the soundcard being blocked. this doesn't always happen with + // ALSA drivers (with dmix, for example) + } + CPPUNIT_ASSERT(!player2->isPlaying()); + + // close everything + player2->close(); + player2->deInitialize(); + player->close(); + player->deInitialize(); +} + + diff --git a/livesupport/modules/playlistExecutor/src/GstreamerPlayerTest.h b/livesupport/modules/playlistExecutor/src/GstreamerPlayerTest.h index f9fb29bb7..15cd9a3e8 100644 --- a/livesupport/modules/playlistExecutor/src/GstreamerPlayerTest.h +++ b/livesupport/modules/playlistExecutor/src/GstreamerPlayerTest.h @@ -78,6 +78,7 @@ class GstreamerPlayerTest : public CPPUNIT_NS::TestFixture, CPPUNIT_TEST(eventListenerOnStopTest); CPPUNIT_TEST(openTimeTest); CPPUNIT_TEST(pauseResumeTest); + CPPUNIT_TEST(openSoundcardTwiceTest); CPPUNIT_TEST_SUITE_END(); private: @@ -209,6 +210,15 @@ class GstreamerPlayerTest : public CPPUNIT_NS::TestFixture, void pauseResumeTest(void) throw (CPPUNIT_NS::Exception); + /** + * Test for opening the same sound card twice + * (thus forcing an error) + * + * @exception CPPUNIT_NS::Exception on test failures. + */ + void + openSoundcardTwiceTest(void) throw (CPPUNIT_NS::Exception); + public: diff --git a/livesupport/products/gLiveSupport/src/GLiveSupport.cxx b/livesupport/products/gLiveSupport/src/GLiveSupport.cxx index ecc11b30f..c19e4ce01 100644 --- a/livesupport/products/gLiveSupport/src/GLiveSupport.cxx +++ b/livesupport/products/gLiveSupport/src/GLiveSupport.cxx @@ -1018,20 +1018,23 @@ GLiveSupport :: playOutputAudio(Ptr::Ref playable) } catch (XmlRpcException &e) { Ptr::Ref eMsg = getResourceUstring("audioErrorMsg"); + eMsg->append("\n"); eMsg->append(e.what()); displayMessageWindow(eMsg); } catch (std::invalid_argument &e) { Ptr::Ref eMsg = getResourceUstring("audioErrorMsg"); + eMsg->append("\n"); eMsg->append(e.what()); displayMessageWindow(eMsg); } catch (std::runtime_error &e) { Ptr::Ref eMsg = getResourceUstring("audioErrorMsg"); + eMsg->append("\n"); eMsg->append(e.what()); displayMessageWindow(eMsg); } - + outputPlayerIsPaused = false; } @@ -1125,16 +1128,19 @@ GLiveSupport :: playCueAudio(Ptr::Ref playable) } catch (XmlRpcException &e) { Ptr::Ref eMsg = getResourceUstring("audioErrorMsg"); + eMsg->append("\n"); eMsg->append(e.what()); displayMessageWindow(eMsg); } catch (std::invalid_argument &e) { Ptr::Ref eMsg = getResourceUstring("audioErrorMsg"); + eMsg->append("\n"); eMsg->append(e.what()); displayMessageWindow(eMsg); } catch (std::runtime_error &e) { Ptr::Ref eMsg = getResourceUstring("audioErrorMsg"); + eMsg->append("\n"); eMsg->append(e.what()); displayMessageWindow(eMsg); } diff --git a/livesupport/products/scheduler/src/PlaylistEvent.cxx b/livesupport/products/scheduler/src/PlaylistEvent.cxx index c92c8e5b4..81afa1c96 100644 --- a/livesupport/products/scheduler/src/PlaylistEvent.cxx +++ b/livesupport/products/scheduler/src/PlaylistEvent.cxx @@ -146,6 +146,9 @@ PlaylistEvent :: start(void) throw () } catch (std::invalid_argument &e) { std::cerr << e.what() << std::endl; // TODO: handle error? + } catch (std::runtime_error &e) { + std::cerr << e.what() << std::endl; + // TODO: handle error? } state = running; }