diff --git a/livesupport/etc/debian/rules b/livesupport/etc/debian/rules index e6b3424ad..0c40eb0e0 100755 --- a/livesupport/etc/debian/rules +++ b/livesupport/etc/debian/rules @@ -139,6 +139,8 @@ install-arch: $(CURDIR)/debian/livesupport/opt/livesupport/var/LiveSupport/gLiveSupport*.res \ $(CURDIR)/debian/livesupport/opt/livesupport/var/LiveSupport/livesupport.png \ $(CURDIR)/debian/livesupport/opt/livesupport/var/LiveSupport/stationLogo.png \ + $(CURDIR)/debian/livesupport/opt/livesupport/var/LiveSupport/testAudio.ogg \ + $(CURDIR)/debian/livesupport/opt/livesupport/var/LiveSupport/testAudio.ogg.license \ $(CURDIR)/debian/livesupport-studio/opt/livesupport/var/LiveSupport mkdir -p $(CURDIR)/debian/livesupport-studio/usr/share/applications cp -a $(CURDIR)/debian/livesupport-studio.desktop \ diff --git a/livesupport/src/modules/widgets/include/LiveSupport/Widgets/EntryBin.h b/livesupport/src/modules/widgets/include/LiveSupport/Widgets/EntryBin.h index 21816020b..b37da20fc 100644 --- a/livesupport/src/modules/widgets/include/LiveSupport/Widgets/EntryBin.h +++ b/livesupport/src/modules/widgets/include/LiveSupport/Widgets/EntryBin.h @@ -104,13 +104,24 @@ class EntryBin : public BlueBin return entry; } + /** + * Return the entry held in this container (const version). + * + * @return the entry held in this container. + */ + const Gtk::Entry * + getEntry(void) const throw () + { + return entry; + } + /** * Return the text of the entry. * * @return the get_text() string of the Gtk::Entry. */ Glib::ustring - get_text(void) throw () + get_text(void) const throw () { return getEntry()->get_text(); } diff --git a/livesupport/src/products/gLiveSupport/etc/Makefile.in b/livesupport/src/products/gLiveSupport/etc/Makefile.in index fd7875372..d1c24da26 100644 --- a/livesupport/src/products/gLiveSupport/etc/Makefile.in +++ b/livesupport/src/products/gLiveSupport/etc/Makefile.in @@ -341,8 +341,10 @@ install: all ${MKDIR} ${USR_ETC_DIR} ${MKDIR} ${USR_VAR_DIR}/LiveSupport ${CP} ${TMP_DIR}/*.res ${USR_VAR_DIR}/LiveSupport - ${CP} ${VAR_DIR}/livesupport.png ${VAR_DIR}/stationLogo.png \ - ${USR_VAR_DIR}/LiveSupport + ${CP} ${VAR_DIR}/livesupport.png \ + ${VAR_DIR}/stationLogo.png \ + ${VAR_DIR}/testAudio.ogg \ + ${VAR_DIR}/testAudio.ogg.license ${USR_VAR_DIR}/LiveSupport ${CP} ${BIN_DIR}/gLiveSupport.sh ${USR_BIN_DIR} ${CP} ${G_LIVESUPPORT_EXE} ${USR_BIN_DIR} ${CP} ${ETC_DIR}/gLiveSupport.xml.template ${USR_ETC_DIR} diff --git a/livesupport/src/products/gLiveSupport/etc/gLiveSupport.xml b/livesupport/src/products/gLiveSupport/etc/gLiveSupport.xml index 416c347f9..cf56397bd 100644 --- a/livesupport/src/products/gLiveSupport/etc/gLiveSupport.xml +++ b/livesupport/src/products/gLiveSupport/etc/gLiveSupport.xml @@ -89,6 +89,9 @@ + + + @@ -155,6 +158,8 @@ + + + + + @@ -153,7 +156,9 @@ - + + + + + + @@ -153,7 +156,9 @@ - + + + close(); } + +/*------------------------------------------------------------------------------ + * Test if we can switch back and forth between devices. + *----------------------------------------------------------------------------*/ +void +AudioPlayerTest :: switchDevicesTest(void) + throw (CPPUNIT_NS::Exception) +{ + Ptr::Ref audioPlayerFactory; + audioPlayerFactory = AudioPlayerFactory::getInstance(); + CPPUNIT_ASSERT(audioPlayerFactory.get()); + + Ptr::Ref audioPlayer; + audioPlayer = audioPlayerFactory->getAudioPlayer(); + CPPUNIT_ASSERT(audioPlayer.get()); + + audioPlayer->setAudioDevice("/dev/dsp"); + CPPUNIT_ASSERT_NO_THROW( + audioPlayer->open("file:var/testAudio.ogg") + ); + audioPlayer->start(); + Ptr::Ref sleepT(new time_duration(microseconds(10))); + while (audioPlayer->isPlaying()) { + TimeConversion::sleep(sleepT); + } + audioPlayer->close(); + + audioPlayer->setAudioDevice("plughw:0,0"); + CPPUNIT_ASSERT_NO_THROW( + audioPlayer->open("file:var/testAudio.ogg") + ); + audioPlayer->start(); + while (audioPlayer->isPlaying()) { + TimeConversion::sleep(sleepT); + } + audioPlayer->close(); +} + diff --git a/livesupport/src/products/gLiveSupport/src/AudioPlayerTest.h b/livesupport/src/products/gLiveSupport/src/AudioPlayerTest.h index ac653f280..5d67e37a6 100644 --- a/livesupport/src/products/gLiveSupport/src/AudioPlayerTest.h +++ b/livesupport/src/products/gLiveSupport/src/AudioPlayerTest.h @@ -73,6 +73,7 @@ class AudioPlayerTest : public BaseTestMethod CPPUNIT_TEST(firstTest); CPPUNIT_TEST(playAudioClipTest); CPPUNIT_TEST(playPlaylistTest); + CPPUNIT_TEST(switchDevicesTest); CPPUNIT_TEST_SUITE_END(); private: @@ -108,6 +109,14 @@ class AudioPlayerTest : public BaseTestMethod void playPlaylistTest(void) throw (CPPUNIT_NS::Exception); + /** + * Test if we can switch back and forth between devices. + * + * @exception CPPUNIT_NS::Exception on test failures. + */ + void + switchDevicesTest(void) throw (CPPUNIT_NS::Exception); + public: /** diff --git a/livesupport/src/products/gLiveSupport/src/GLiveSupport.cxx b/livesupport/src/products/gLiveSupport/src/GLiveSupport.cxx index d185ab398..29afe939d 100644 --- a/livesupport/src/products/gLiveSupport/src/GLiveSupport.cxx +++ b/livesupport/src/products/gLiveSupport/src/GLiveSupport.cxx @@ -127,6 +127,11 @@ static const std::string cuePlayerElementName = "cuePlayer"; *----------------------------------------------------------------------------*/ static const std::string stationLogoConfigElementName = "stationLogo"; +/*------------------------------------------------------------------------------ + * The name of the config element for the test audio file location + *----------------------------------------------------------------------------*/ +static const std::string testAudioUrlConfigElementName = "testAudioUrl"; + /*------------------------------------------------------------------------------ * The name of the user preference for storing Scratchpad contents *----------------------------------------------------------------------------*/ @@ -333,6 +338,17 @@ GLiveSupport :: configure(const xmlpp::Element & element) mkdir(configFileName->c_str(), 0700); // create dir if does not exist configFileName->append(configFileNameStr); optionsContainer.reset(new OptionsContainer(element, configFileName)); + + // read the test audio file location + nodes = element.get_children(testAudioUrlConfigElementName); + if (nodes.size() < 1) { + throw std::invalid_argument("no test audio url element"); + } + const xmlpp::Element* testAudioUrlElement + = dynamic_cast(nodes.front()); + testAudioUrl.reset(new Glib::ustring( + testAudioUrlElement->get_attribute("path") + ->get_value() )); } @@ -1487,3 +1503,40 @@ GLiveSupport :: loadWindowPositions(void) throw () } } + +/*------------------------------------------------------------------------------ + * Set the device for the cue audio player. + *----------------------------------------------------------------------------*/ +void +LiveSupport :: GLiveSupport :: +GLiveSupport :: setCueAudioDevice(Ptr::Ref deviceName) + throw () +{ + cuePlayer->setAudioDevice(*deviceName); +} + + +/*------------------------------------------------------------------------------ + * Play a test sound on the cue audio player. + *----------------------------------------------------------------------------*/ +void +LiveSupport :: GLiveSupport :: +GLiveSupport :: playTestSoundOnCue(void) throw () +{ + if (cueItemPlayingNow) { + stopCueAudio(); // stop the audio player and + } // release old resources + + try { + cuePlayer->open(*testAudioUrl); + cuePlayer->start(); + Ptr::Ref sleepT(new time_duration(microseconds(10))); + while (cuePlayer->isPlaying()) { + TimeConversion::sleep(sleepT); + } + } catch (std::runtime_error &e) { + // "invalid device" error from open(); do nothing + } + cuePlayer->close(); +} + diff --git a/livesupport/src/products/gLiveSupport/src/GLiveSupport.h b/livesupport/src/products/gLiveSupport/src/GLiveSupport.h index 2ebabf20e..41ce55982 100644 --- a/livesupport/src/products/gLiveSupport/src/GLiveSupport.h +++ b/livesupport/src/products/gLiveSupport/src/GLiveSupport.h @@ -254,6 +254,11 @@ class GLiveSupport : public LocalizedConfigurable, */ Glib::RefPtr stationLogoPixbuf; + /** + * The location of the test audio file. + */ + Ptr::Ref testAudioUrl; + /** * Read a supportedLanguages configuration element, * and fill the supportedLanguages map with its contents. @@ -907,6 +912,21 @@ class GLiveSupport : public LocalizedConfigurable, detachCueAudioListener(AudioPlayerEventListener * listener) throw (std::invalid_argument); + /** + * Set the device for the cue audio player. + * + * @param deviceName the name of the new device + */ + void + setCueAudioDevice(Ptr::Ref deviceName) + throw (); + + /** + * Play a test sound on the cue audio player. + */ + void + playTestSoundOnCue(void) throw (); + /** * Search in the local storage. * diff --git a/livesupport/src/products/gLiveSupport/src/OptionsWindow.cxx b/livesupport/src/products/gLiveSupport/src/OptionsWindow.cxx index f8d93eec6..3471cc3ed 100644 --- a/livesupport/src/products/gLiveSupport/src/OptionsWindow.cxx +++ b/livesupport/src/products/gLiveSupport/src/OptionsWindow.cxx @@ -219,6 +219,28 @@ OptionsWindow :: onCloseButtonClicked(bool needConfirm) throw () } +/*------------------------------------------------------------------------------ + * Event handler for the test button + *----------------------------------------------------------------------------*/ +void +OptionsWindow :: onTestButtonClicked(const EntryBin * entry) + throw () +{ + Ptr::Ref optionsContainer + = gLiveSupport->getOptionsContainer(); + + Ptr::Ref + oldDevice = optionsContainer->getOptionItem(OptionsContainer:: + outputPlayerDeviceName); + Ptr::Ref + newDevice(new Glib::ustring(entry->get_text())); + + gLiveSupport->setCueAudioDevice(newDevice); // NOTE: we can't use the + gLiveSupport->playTestSoundOnCue(); // output player b/c that + gLiveSupport->setCueAudioDevice(oldDevice); // would trigger onStop() +} + + /*------------------------------------------------------------------------------ * Create a new user entry field item. *----------------------------------------------------------------------------*/ @@ -279,6 +301,20 @@ OptionsWindow :: constructSoundSection(void) throw () OptionsContainer::cuePlayerDeviceName); audioDeviceTable->attach(*cuePlayerEntry, 1, 2, 0, 1); + Button * cueTestButton; + try { + cueTestButton = Gtk::manage(wf->createButton( + *getResourceUstring("testButtonLabel") )); + } catch (std::invalid_argument &e) { + // TODO: signal error + std::cerr << e.what() << std::endl; + std::exit(1); + } + cueTestButton->signal_clicked().connect(sigc::bind( + sigc::mem_fun(*this,&OptionsWindow::onTestButtonClicked), + cuePlayerEntry)); + audioDeviceTable->attach(*cueTestButton, 2, 3, 0, 1); + // display the settings for the output player device Glib::ustring outputPlayerLabelContents; try { @@ -298,6 +334,20 @@ OptionsWindow :: constructSoundSection(void) throw () OptionsContainer::outputPlayerDeviceName); audioDeviceTable->attach(*outputPlayerEntry, 1, 2, 1, 2); + Button * outputTestButton; + try { + outputTestButton = Gtk::manage(wf->createButton( + *getResourceUstring("testButtonLabel") )); + } catch (std::invalid_argument &e) { + // TODO: signal error + std::cerr << e.what() << std::endl; + std::exit(1); + } + outputTestButton->signal_clicked().connect(sigc::bind( + sigc::mem_fun(*this, &OptionsWindow::onTestButtonClicked), + outputPlayerEntry)); + audioDeviceTable->attach(*outputTestButton, 2, 3, 1, 2); + // make a new box and pack the components into it Gtk::VBox * section = Gtk::manage(new Gtk::VBox); section->pack_start(*audioDeviceTable, Gtk::PACK_SHRINK, 5); diff --git a/livesupport/src/products/gLiveSupport/src/OptionsWindow.h b/livesupport/src/products/gLiveSupport/src/OptionsWindow.h index a6e81f918..49e1023d2 100644 --- a/livesupport/src/products/gLiveSupport/src/OptionsWindow.h +++ b/livesupport/src/products/gLiveSupport/src/OptionsWindow.h @@ -152,7 +152,7 @@ class OptionsWindow : public WhiteWindow, public LocalizedObject */ EntryBin * createEntry(OptionsContainer::OptionItemString optionItem) - throw (); + throw (); /** * Construct the "Sound" section. @@ -160,7 +160,7 @@ class OptionsWindow : public WhiteWindow, public LocalizedObject * @return a pointer to the new box (already Gtk::manage()'ed) */ Gtk::VBox* - constructSoundSection(void) throw (); + constructSoundSection(void) throw (); /** * Construct the "Servers" section. @@ -168,7 +168,7 @@ class OptionsWindow : public WhiteWindow, public LocalizedObject * @return a pointer to the new box (already Gtk::manage()'ed) */ Gtk::VBox* - constructServersSection(void) throw (); + constructServersSection(void) throw (); /** * Construct the "About" section. @@ -176,7 +176,7 @@ class OptionsWindow : public WhiteWindow, public LocalizedObject * @return a pointer to the new box (already Gtk::manage()'ed) */ Gtk::VBox* - constructAboutSection(void) throw (); + constructAboutSection(void) throw (); protected: @@ -184,19 +184,19 @@ class OptionsWindow : public WhiteWindow, public LocalizedObject * Event handler for the Cancel button. */ virtual void - onCancelButtonClicked(void) throw (); + onCancelButtonClicked(void) throw (); /** * Event handler for the Apply button. */ virtual void - onApplyButtonClicked(void) throw (); + onApplyButtonClicked(void) throw (); /** * Event handler for the OK button. */ virtual void - onOkButtonClicked(void) throw (); + onOkButtonClicked(void) throw (); /** * Event handler for the Close button. @@ -207,9 +207,19 @@ class OptionsWindow : public WhiteWindow, public LocalizedObject * @see WhiteWindow::onCloseButtonClicked() */ virtual void - onCloseButtonClicked(bool needConfirm = true) throw (); + onCloseButtonClicked(bool needConfirm = true) throw (); + + /** + * Event handler for the test button + * + * @param entry the text entry field containing the new device name + * @see GLiveSupport::setCueAudioDevice() + * @see GLiveSupport::playTestSoundOnCue() + */ + virtual void + onTestButtonClicked(const EntryBin * entry) throw (); + - public: /** * Constructor. @@ -219,14 +229,13 @@ class OptionsWindow : public WhiteWindow, public LocalizedObject * @param bundle the resource bundle holding localized resources */ OptionsWindow(Ptr::Ref gLiveSupport, - Ptr::Ref bundle) - throw (); + Ptr::Ref bundle) throw (); /** * Virtual destructor. */ virtual - ~OptionsWindow(void) throw () + ~OptionsWindow(void) throw () { } diff --git a/livesupport/src/products/gLiveSupport/var/root.txt b/livesupport/src/products/gLiveSupport/var/root.txt index af3fd4125..2fa57641f 100644 --- a/livesupport/src/products/gLiveSupport/var/root.txt +++ b/livesupport/src/products/gLiveSupport/var/root.txt @@ -231,6 +231,7 @@ root:table cueDeviceLabel:string { "Cue audio device:" } outputDeviceLabel:string { "Live Mode audio device:" } + testButtonLabel:string { "Test" } authenticationLabel:string { "Authentication server" } storageLabel:string { "Storage server" } diff --git a/livesupport/src/products/gLiveSupport/var/testAudio.ogg b/livesupport/src/products/gLiveSupport/var/testAudio.ogg new file mode 100644 index 000000000..0667eabe4 Binary files /dev/null and b/livesupport/src/products/gLiveSupport/var/testAudio.ogg differ diff --git a/livesupport/src/products/gLiveSupport/var/testAudio.ogg.license b/livesupport/src/products/gLiveSupport/var/testAudio.ogg.license new file mode 100644 index 000000000..27159cd0f --- /dev/null +++ b/livesupport/src/products/gLiveSupport/var/testAudio.ogg.license @@ -0,0 +1,20 @@ +This is a shortened and reencoded version of the following sound file + +File: + Name: "cowbell.aif" + Url: http://freesound.iua.upf.edu/samplesViewSingle.php?id=14782 + Date of upload: 2006-01-24 20:28:02 + +Designer / Creator / Uploader: + Name: "ignotus" + Url: http://freesound.iua.upf.edu/usersViewSingle.php?id=13366 + +Description: + By "ignotus" : A cow in the high pastures of the Picos de Europa, + northwest Spain. Recorded with a mini-DV camcorder built-in stereo mic. + +Tags: + animal bell field-recording nature + +It was released under the Creative Commons Sampling Plus 1.0 license +http://creativecommons.org/licenses/by-nd/2.0/