added initial version of gstreamer audio player
This commit is contained in:
parent
e693e4b3a2
commit
7891ff8e9d
10 changed files with 2155 additions and 3 deletions
|
@ -21,7 +21,7 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Author : $Author: maroy $
|
# Author : $Author: maroy $
|
||||||
# Version : $Revision: 1.8 $
|
# Version : $Revision: 1.9 $
|
||||||
# Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/playlistExecutor/etc/Makefile.in,v $
|
# Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/playlistExecutor/etc/Makefile.in,v $
|
||||||
#
|
#
|
||||||
# @configure_input@
|
# @configure_input@
|
||||||
|
@ -77,6 +77,9 @@ VPATH = ${SRC_DIR}
|
||||||
LIBXMLPP_CFLAGS=@LIBXMLPP_CFLAGS@
|
LIBXMLPP_CFLAGS=@LIBXMLPP_CFLAGS@
|
||||||
LIBXMLPP_LIBS=@LIBXMLPP_LIBS@
|
LIBXMLPP_LIBS=@LIBXMLPP_LIBS@
|
||||||
|
|
||||||
|
GSTREAMER_CFLAGS=@GSTREAMER_CFLAGS@
|
||||||
|
GSTREAMER_LIBS=@GSTREAMER_LIBS@
|
||||||
|
|
||||||
TAGLIB_LIBS =`${USR_DIR}/bin/taglib-config --libs`
|
TAGLIB_LIBS =`${USR_DIR}/bin/taglib-config --libs`
|
||||||
|
|
||||||
TEST_RESULTS = ${DOC_DIR}/testResults.xml
|
TEST_RESULTS = ${DOC_DIR}/testResults.xml
|
||||||
|
@ -100,6 +103,7 @@ CPPFLAGS = @CPPFLAGS@
|
||||||
CXXFLAGS = @CXXFLAGS@ @DEFS@ @COVERAGE_CXXFLAGS@ -pthread \
|
CXXFLAGS = @CXXFLAGS@ @DEFS@ @COVERAGE_CXXFLAGS@ -pthread \
|
||||||
-Wall -Wno-long-long \
|
-Wall -Wno-long-long \
|
||||||
${LIBXMLPP_CFLAGS} \
|
${LIBXMLPP_CFLAGS} \
|
||||||
|
${GSTREAMER_CFLAGS} \
|
||||||
${HELIX_CFLAGS} \
|
${HELIX_CFLAGS} \
|
||||||
-I${USR_INCLUDE_DIR} \
|
-I${USR_INCLUDE_DIR} \
|
||||||
-I${BOOST_INCLUDE_DIR} \
|
-I${BOOST_INCLUDE_DIR} \
|
||||||
|
@ -108,6 +112,7 @@ CXXFLAGS = @CXXFLAGS@ @DEFS@ @COVERAGE_CXXFLAGS@ -pthread \
|
||||||
-I${INCLUDE_DIR} -I${TMP_DIR}
|
-I${INCLUDE_DIR} -I${TMP_DIR}
|
||||||
LDFLAGS = @LDFLAGS@ -pthread \
|
LDFLAGS = @LDFLAGS@ -pthread \
|
||||||
${LIBXMLPP_LIBS} \
|
${LIBXMLPP_LIBS} \
|
||||||
|
${GSTREAMER_LIBS} \
|
||||||
${TAGLIB_LIBS} \
|
${TAGLIB_LIBS} \
|
||||||
-L${USR_LIB_DIR} \
|
-L${USR_LIB_DIR} \
|
||||||
-L${CORE_LIB_DIR} \
|
-L${CORE_LIB_DIR} \
|
||||||
|
@ -125,8 +130,11 @@ PLAYLIST_EXECUTOR_LIB_OBJS = ${TMP_DIR}/HelixPlayer.o \
|
||||||
${TMP_DIR}/ClientContext.o \
|
${TMP_DIR}/ClientContext.o \
|
||||||
${TMP_DIR}/ErrorSink.o \
|
${TMP_DIR}/ErrorSink.o \
|
||||||
${TMP_DIR}/HelixIIDs.o \
|
${TMP_DIR}/HelixIIDs.o \
|
||||||
|
${TMP_DIR}/GstreamerPlayer.o \
|
||||||
${TMP_DIR}/AudioPlayerFactory.o
|
${TMP_DIR}/AudioPlayerFactory.o
|
||||||
TEST_RUNNER_OBJS = ${TMP_DIR}/TestRunner.o \
|
TEST_RUNNER_OBJS = ${TMP_DIR}/TestRunner.o \
|
||||||
|
${TMP_DIR}/GstreamerPlayerTest.o
|
||||||
|
DONT_TEST= ${TMP_DIR}/GstreamerPlayerTest.o \
|
||||||
${TMP_DIR}/HelixPlayerTest.o \
|
${TMP_DIR}/HelixPlayerTest.o \
|
||||||
${TMP_DIR}/AudioPlayerFactoryTest.o
|
${TMP_DIR}/AudioPlayerFactoryTest.o
|
||||||
TEST_RUNNER_LIBS = -l${PLAYLIST_EXECUTOR_LIB} -l${CORE_LIB} \
|
TEST_RUNNER_LIBS = -l${PLAYLIST_EXECUTOR_LIB} -l${CORE_LIB} \
|
||||||
|
@ -134,6 +142,7 @@ TEST_RUNNER_LIBS = -l${PLAYLIST_EXECUTOR_LIB} -l${CORE_LIB} \
|
||||||
-lcppunit -ldl -lm -lxmlrpc++
|
-lcppunit -ldl -lm -lxmlrpc++
|
||||||
|
|
||||||
TWOTEST_RUNNER_OBJS = ${TMP_DIR}/TestRunner.o \
|
TWOTEST_RUNNER_OBJS = ${TMP_DIR}/TestRunner.o \
|
||||||
|
${TMP_DIR}/TwoGstreamerPlayersTest.o \
|
||||||
${TMP_DIR}/TwoHelixPlayersTest.o
|
${TMP_DIR}/TwoHelixPlayersTest.o
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ dnl Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
dnl
|
dnl
|
||||||
dnl
|
dnl
|
||||||
dnl Author : $Author: maroy $
|
dnl Author : $Author: maroy $
|
||||||
dnl Version : $Revision: 1.3 $
|
dnl Version : $Revision: 1.4 $
|
||||||
dnl Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/playlistExecutor/etc/configure.ac,v $
|
dnl Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/playlistExecutor/etc/configure.ac,v $
|
||||||
dnl-----------------------------------------------------------------------------
|
dnl-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ dnl-----------------------------------------------------------------------------
|
||||||
AC_INIT(PlaylistExecutor, 1.0, bugs@campware.org)
|
AC_INIT(PlaylistExecutor, 1.0, bugs@campware.org)
|
||||||
AC_PREREQ(2.59)
|
AC_PREREQ(2.59)
|
||||||
AC_COPYRIGHT([Copyright (c) 2004 Media Development Loan Fund under the GNU GPL])
|
AC_COPYRIGHT([Copyright (c) 2004 Media Development Loan Fund under the GNU GPL])
|
||||||
AC_REVISION($Revision: 1.3 $)
|
AC_REVISION($Revision: 1.4 $)
|
||||||
|
|
||||||
AC_CONFIG_SRCDIR(../src/HelixPlayer.cxx)
|
AC_CONFIG_SRCDIR(../src/HelixPlayer.cxx)
|
||||||
|
|
||||||
|
@ -48,6 +48,10 @@ PKG_CHECK_MODULES(LIBXMLPP,[libxml++-2.6 >= 2.6.0])
|
||||||
AC_SUBST(LIBXMLPP_CFLAGS)
|
AC_SUBST(LIBXMLPP_CFLAGS)
|
||||||
AC_SUBST(LIBXMLPP_LIBS)
|
AC_SUBST(LIBXMLPP_LIBS)
|
||||||
|
|
||||||
|
PKG_CHECK_MODULES(GSTREAMER,[gstreamer-0.8 >= 0.8])
|
||||||
|
AC_SUBST(GSTREAMER_CFLAGS)
|
||||||
|
AC_SUBST(GSTREAMER_LIBS)
|
||||||
|
|
||||||
dnl-----------------------------------------------------------------------------
|
dnl-----------------------------------------------------------------------------
|
||||||
dnl enable compilaton for code coverage data
|
dnl enable compilaton for code coverage data
|
||||||
dnl-----------------------------------------------------------------------------
|
dnl-----------------------------------------------------------------------------
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<!DOCTYPE gstreamerPlayer [
|
||||||
|
|
||||||
|
<!ELEMENT gstreamerPlayer EMPTY >
|
||||||
|
<!ATTLIST gstreamerPlayer audioDevice CDATA #IMPLIED >
|
||||||
|
]>
|
||||||
|
<gstreamerPlayer audioDevice = "plughw:0,0"
|
||||||
|
/>
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<!DOCTYPE twoGstreamerPlayers [
|
||||||
|
|
||||||
|
<!ELEMENT twoGstreamerPlayers (gstreamerPlayer,gstreamerPlayer) >
|
||||||
|
|
||||||
|
<!ELEMENT gstreamerPlayer EMPTY >
|
||||||
|
<!ATTLIST gstreamerPlayer audioDevice CDATA #IMPLIED >
|
||||||
|
]>
|
||||||
|
<twoGstreamerPlayers>
|
||||||
|
<gstreamerPlayer audioDevice = "plughw:0,0" />
|
||||||
|
<gstreamerPlayer audioDevice = "plughw:1,0" />
|
||||||
|
</twoGstreamerPlayers>
|
668
livesupport/modules/playlistExecutor/src/GstreamerPlayer.cxx
Normal file
668
livesupport/modules/playlistExecutor/src/GstreamerPlayer.cxx
Normal file
|
@ -0,0 +1,668 @@
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2004 Media Development Loan Fund
|
||||||
|
|
||||||
|
This file is part of the LiveSupport project.
|
||||||
|
http://livesupport.campware.org/
|
||||||
|
To report bugs, send an e-mail to bugs@campware.org
|
||||||
|
|
||||||
|
LiveSupport is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
LiveSupport is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with LiveSupport; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
|
||||||
|
Author : $Author: maroy $
|
||||||
|
Version : $Revision: 1.1 $
|
||||||
|
Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/playlistExecutor/src/GstreamerPlayer.cxx,v $
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* ============================================================ include files */
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "configure.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "LiveSupport/Core/TimeConversion.h"
|
||||||
|
#include "GstreamerPlayer.h"
|
||||||
|
|
||||||
|
|
||||||
|
using namespace boost::posix_time;
|
||||||
|
using namespace LiveSupport::Core;
|
||||||
|
using namespace LiveSupport::PlaylistExecutor;
|
||||||
|
|
||||||
|
/* =================================================== local data structures */
|
||||||
|
|
||||||
|
|
||||||
|
/* ================================================ local constants & macros */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the config element for this class
|
||||||
|
*/
|
||||||
|
const std::string GstreamerPlayer::configElementNameStr = "gstreamerPlayer";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the audio device attribute.
|
||||||
|
*/
|
||||||
|
static const std::string audioDeviceName = "audioDevice";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The factories considered when creating the pipeline
|
||||||
|
*/
|
||||||
|
GList * GstreamerPlayer::factories = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/* =============================================== local function prototypes */
|
||||||
|
|
||||||
|
|
||||||
|
/* ============================================================= module code */
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Configure the Helix Player.
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
GstreamerPlayer :: configure(const xmlpp::Element & element)
|
||||||
|
throw (std::invalid_argument,
|
||||||
|
std::logic_error)
|
||||||
|
{
|
||||||
|
if (element.get_name() != configElementNameStr) {
|
||||||
|
std::string eMsg = "Bad configuration element ";
|
||||||
|
eMsg += element.get_name();
|
||||||
|
throw std::invalid_argument(eMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
const xmlpp::Attribute * attribute;
|
||||||
|
|
||||||
|
if ((attribute = element.get_attribute(audioDeviceName))) {
|
||||||
|
audioDevice = attribute->get_value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Initialize the Helix Player
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
GstreamerPlayer :: initialize(void) throw (std::exception)
|
||||||
|
{
|
||||||
|
if (initialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize the gstreamer library
|
||||||
|
if (!gst_init_check(0, 0)) {
|
||||||
|
throw std::runtime_error("couldn't initialize the gstreamer library");
|
||||||
|
}
|
||||||
|
initFactories();
|
||||||
|
|
||||||
|
// initialize the pipeline
|
||||||
|
pipeline = gst_thread_new("audio-player");
|
||||||
|
// take ownership of the pipeline object
|
||||||
|
gst_object_ref(GST_OBJECT(pipeline));
|
||||||
|
gst_object_sink(GST_OBJECT(pipeline));
|
||||||
|
|
||||||
|
filesrc = gst_element_factory_make("filesrc", "file-source");
|
||||||
|
typefinder = gst_element_factory_make("typefind", "typefind");
|
||||||
|
gst_element_link(filesrc, typefinder);
|
||||||
|
gst_bin_add_many(GST_BIN(pipeline), filesrc, typefinder, NULL);
|
||||||
|
|
||||||
|
g_signal_connect(pipeline, "error", G_CALLBACK(errorHandler), this);
|
||||||
|
g_signal_connect(pipeline, "state-change", G_CALLBACK(stateChange), this);
|
||||||
|
g_signal_connect(typefinder, "have-type", G_CALLBACK(typeFound), this);
|
||||||
|
|
||||||
|
audiosink = gst_element_factory_make("alsasink", "audiosink");
|
||||||
|
setAudioDevice(audioDevice);
|
||||||
|
|
||||||
|
// set up other variables
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Initialize the list of factories
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
GstreamerPlayer :: initFactories(void) throw ()
|
||||||
|
{
|
||||||
|
if (factories) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
factories = gst_registry_pool_feature_filter(
|
||||||
|
(GstPluginFeatureFilter) featureFilter, FALSE, NULL);
|
||||||
|
// sort the factories according to their ranks
|
||||||
|
factories = g_list_sort(factories, (GCompareFunc) compareRanks);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Filter plugins so that only demixers, decoders and parsers are considered
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
gboolean
|
||||||
|
GstreamerPlayer :: featureFilter(GstPluginFeature * feature,
|
||||||
|
gpointer data)
|
||||||
|
throw ()
|
||||||
|
{
|
||||||
|
const gchar * klass;
|
||||||
|
guint rank;
|
||||||
|
|
||||||
|
// we only care about element factories
|
||||||
|
if (!GST_IS_ELEMENT_FACTORY(feature)) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// only parsers, demuxers and decoders
|
||||||
|
klass = gst_element_factory_get_klass(GST_ELEMENT_FACTORY(feature));
|
||||||
|
if (g_strrstr(klass, "Demux") == NULL &&
|
||||||
|
g_strrstr(klass, "Decoder") == NULL &&
|
||||||
|
g_strrstr(klass, "Parse") == NULL) {
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// only select elements with autoplugging rank
|
||||||
|
rank = gst_plugin_feature_get_rank(feature);
|
||||||
|
if (rank < GST_RANK_MARGINAL) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Compare two plugins according to their ranks
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
gint
|
||||||
|
GstreamerPlayer :: compareRanks(GstPluginFeature * feature1,
|
||||||
|
GstPluginFeature * feature2)
|
||||||
|
throw ()
|
||||||
|
{
|
||||||
|
return gst_plugin_feature_get_rank(feature1)
|
||||||
|
- gst_plugin_feature_get_rank(feature2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Handler for gstreamer errors.
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
GstreamerPlayer :: errorHandler(GstElement * pipeline,
|
||||||
|
GstElement * source,
|
||||||
|
GError * error,
|
||||||
|
gchar * debug,
|
||||||
|
gpointer self)
|
||||||
|
throw ()
|
||||||
|
{
|
||||||
|
// TODO: handle error
|
||||||
|
std::cerr << "gstreamer error: " << error->message << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Handler for the event when a matching type has been found
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
GstreamerPlayer :: typeFound(GstElement * typefinder,
|
||||||
|
guint probability,
|
||||||
|
GstCaps * caps,
|
||||||
|
gpointer self)
|
||||||
|
throw ()
|
||||||
|
{
|
||||||
|
// actually plug now
|
||||||
|
GstreamerPlayer * player = (GstreamerPlayer*) self;
|
||||||
|
try {
|
||||||
|
player->tryToPlug(gst_element_get_pad(typefinder, "src"), caps);
|
||||||
|
} catch (std::logic_error &e) {
|
||||||
|
// TODO: handle error
|
||||||
|
std::cerr << e.what() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Try to plug a matching element to the specified pad
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
GstreamerPlayer :: tryToPlug(GstPad * pad,
|
||||||
|
const GstCaps * caps)
|
||||||
|
throw (std::logic_error)
|
||||||
|
{
|
||||||
|
GstObject * parent = GST_OBJECT(gst_pad_get_parent(pad));
|
||||||
|
const gchar * mime;
|
||||||
|
const GList * item;
|
||||||
|
GstCaps * res;
|
||||||
|
GstCaps * audiocaps;
|
||||||
|
|
||||||
|
// don't plug if we're already plugged
|
||||||
|
if (GST_PAD_IS_LINKED(gst_element_get_pad(audiosink, "sink"))) {
|
||||||
|
throw std::logic_error(std::string("Omitting link for pad ")
|
||||||
|
+ gst_object_get_name(parent) + ":"
|
||||||
|
+ gst_pad_get_name(pad)
|
||||||
|
+ " because we're alreadey linked");
|
||||||
|
}
|
||||||
|
|
||||||
|
// only plug audio
|
||||||
|
mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
|
||||||
|
if (!g_strrstr (mime, "audio")) {
|
||||||
|
throw std::logic_error(std::string("Omitting link for pad ")
|
||||||
|
+ gst_object_get_name(parent) + ":"
|
||||||
|
+ gst_pad_get_name(pad)
|
||||||
|
+ " because mimetype "
|
||||||
|
+ mime
|
||||||
|
+ " is non-audio");
|
||||||
|
}
|
||||||
|
|
||||||
|
// can it link to the audiopad?
|
||||||
|
audiocaps = gst_pad_get_caps(gst_element_get_pad(audiosink, "sink"));
|
||||||
|
res = gst_caps_intersect(caps, audiocaps);
|
||||||
|
if (res && !gst_caps_is_empty(res)) {
|
||||||
|
closeLink(pad, audiosink, "sink", NULL);
|
||||||
|
gst_caps_free(audiocaps);
|
||||||
|
gst_caps_free(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gst_caps_free(audiocaps);
|
||||||
|
gst_caps_free(res);
|
||||||
|
|
||||||
|
// try to plug from our list
|
||||||
|
for (item = factories; item != NULL; item = item->next) {
|
||||||
|
GstElementFactory * factory = GST_ELEMENT_FACTORY(item->data);
|
||||||
|
const GList * pads;
|
||||||
|
|
||||||
|
for (pads = gst_element_factory_get_pad_templates (factory);
|
||||||
|
pads != NULL;
|
||||||
|
pads = pads->next) {
|
||||||
|
|
||||||
|
GstPadTemplate * templ = GST_PAD_TEMPLATE(pads->data);
|
||||||
|
|
||||||
|
// find the sink template - need an always pad
|
||||||
|
if (templ->direction != GST_PAD_SINK ||
|
||||||
|
templ->presence != GST_PAD_ALWAYS) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// can it link?
|
||||||
|
res = gst_caps_intersect(caps, templ->caps);
|
||||||
|
if (res && !gst_caps_is_empty(res)) {
|
||||||
|
GstElement *element;
|
||||||
|
|
||||||
|
// close link and return
|
||||||
|
gst_caps_free(res);
|
||||||
|
element = gst_element_factory_create(factory, NULL);
|
||||||
|
closeLink(pad,
|
||||||
|
element,
|
||||||
|
templ->name_template,
|
||||||
|
gst_element_factory_get_pad_templates(factory));
|
||||||
|
|
||||||
|
const gchar *klass =
|
||||||
|
gst_element_factory_get_klass(GST_ELEMENT_FACTORY(factory));
|
||||||
|
if (g_strrstr(klass, "Decoder")) {
|
||||||
|
// if a decoder element, store it
|
||||||
|
decoder = element;
|
||||||
|
decoderSrc = gst_element_get_pad(decoder, "src");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gst_caps_free(res);
|
||||||
|
|
||||||
|
// we only check one sink template per factory, so move on to the
|
||||||
|
// next factory now
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::logic_error(std::string("No compatible pad found to decode ")
|
||||||
|
+ mime
|
||||||
|
+ " on "
|
||||||
|
+ gst_object_get_name (parent) + ":"
|
||||||
|
+ gst_pad_get_name (pad));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Close the element links
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
GstreamerPlayer :: closeLink(GstPad * srcpad,
|
||||||
|
GstElement * sinkelement,
|
||||||
|
const gchar * padname,
|
||||||
|
const GList * templlist)
|
||||||
|
throw ()
|
||||||
|
{
|
||||||
|
gboolean has_dynamic_pads = FALSE;
|
||||||
|
|
||||||
|
// add the element to the pipeline and set correct state
|
||||||
|
gst_element_set_state(sinkelement, GST_STATE_PAUSED);
|
||||||
|
gst_bin_add(GST_BIN(pipeline), sinkelement);
|
||||||
|
gst_pad_link(srcpad, gst_element_get_pad(sinkelement, padname));
|
||||||
|
gst_bin_sync_children_state(GST_BIN(pipeline));
|
||||||
|
|
||||||
|
// if we have static source pads, link those. If we have dynamic
|
||||||
|
// source pads, listen for new-pad signals on the element
|
||||||
|
for ( ; templlist != NULL; templlist = templlist->next) {
|
||||||
|
GstPadTemplate *templ = GST_PAD_TEMPLATE(templlist->data);
|
||||||
|
|
||||||
|
// only sourcepads, no request pads
|
||||||
|
if (templ->direction != GST_PAD_SRC ||
|
||||||
|
templ->presence == GST_PAD_REQUEST) {
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (templ->presence) {
|
||||||
|
case GST_PAD_ALWAYS: {
|
||||||
|
GstPad *pad = gst_element_get_pad(sinkelement,
|
||||||
|
templ->name_template);
|
||||||
|
GstCaps *caps = gst_pad_get_caps(pad);
|
||||||
|
|
||||||
|
// link
|
||||||
|
tryToPlug(pad, caps);
|
||||||
|
gst_caps_free(caps);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case GST_PAD_SOMETIMES:
|
||||||
|
has_dynamic_pads = TRUE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// listen for newly created pads if this element supports that
|
||||||
|
if (has_dynamic_pads) {
|
||||||
|
g_signal_connect(sinkelement, "new-pad", G_CALLBACK(newPad), this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Event handler for when a new dynamic pad is created
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
GstreamerPlayer :: newPad(GstElement * element,
|
||||||
|
GstPad * pad,
|
||||||
|
gpointer self)
|
||||||
|
throw ()
|
||||||
|
{
|
||||||
|
GstreamerPlayer * player = (GstreamerPlayer*) self;
|
||||||
|
GstCaps * caps = gst_pad_get_caps(pad);
|
||||||
|
|
||||||
|
player->tryToPlug(pad, caps);
|
||||||
|
gst_caps_free(caps);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Event handler for when the state of the pipeline changes
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
GstreamerPlayer :: stateChange(GstElement * element,
|
||||||
|
gint oldState,
|
||||||
|
gint newState,
|
||||||
|
gpointer self)
|
||||||
|
throw ()
|
||||||
|
{
|
||||||
|
GstreamerPlayer * player = (GstreamerPlayer*) self;
|
||||||
|
|
||||||
|
if (oldState == GST_STATE_PLAYING && newState != GST_STATE_PLAYING) {
|
||||||
|
player->fireOnStopEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* De-initialize the Gstreamer Player
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
GstreamerPlayer :: deInitialize(void) throw ()
|
||||||
|
{
|
||||||
|
if (initialized) {
|
||||||
|
gst_element_set_state(pipeline, GST_STATE_NULL);
|
||||||
|
gst_bin_sync_children_state(GST_BIN(pipeline));
|
||||||
|
|
||||||
|
if (!gst_element_get_parent(audiosink)) {
|
||||||
|
// delete manually, if audiosink wasn't added to the pipeline
|
||||||
|
// for some reason
|
||||||
|
gst_object_unref(GST_OBJECT(audiosink));
|
||||||
|
}
|
||||||
|
gst_object_unref(GST_OBJECT(pipeline));
|
||||||
|
|
||||||
|
initialized = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Attach an event listener.
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
GstreamerPlayer :: attachListener(AudioPlayerEventListener* eventListener)
|
||||||
|
throw ()
|
||||||
|
{
|
||||||
|
listeners.push_back(eventListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Detach an event listener.
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
GstreamerPlayer :: detachListener(AudioPlayerEventListener* eventListener)
|
||||||
|
throw (std::invalid_argument)
|
||||||
|
{
|
||||||
|
ListenerVector::iterator it = listeners.begin();
|
||||||
|
ListenerVector::iterator end = listeners.end();
|
||||||
|
|
||||||
|
while (it != end) {
|
||||||
|
if (*it == eventListener) {
|
||||||
|
listeners.erase(it);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::invalid_argument("supplied event listener not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Send the onStop event to all attached listeners.
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
GstreamerPlayer :: fireOnStopEvent(void) throw ()
|
||||||
|
{
|
||||||
|
ListenerVector::iterator it = listeners.begin();
|
||||||
|
ListenerVector::iterator end = listeners.end();
|
||||||
|
|
||||||
|
while (it != end) {
|
||||||
|
(*it)->onStop();
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Specify which file to play
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
GstreamerPlayer :: open(const std::string fileUrl)
|
||||||
|
throw (std::invalid_argument)
|
||||||
|
{
|
||||||
|
std::string filePath;
|
||||||
|
|
||||||
|
if (fileUrl.find("file:") == 0) {
|
||||||
|
filePath = fileUrl.substr(5, fileUrl.size());
|
||||||
|
} else if (fileUrl.find("file://") == 0) {
|
||||||
|
filePath = fileUrl.substr(7, fileUrl.size());
|
||||||
|
} else {
|
||||||
|
throw std::invalid_argument("badly formed URL or unsupported protocol");
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_set(G_OBJECT(filesrc), "location", filePath.c_str(), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Tell if we've been opened.
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
bool
|
||||||
|
GstreamerPlayer :: isOpened(void) throw ()
|
||||||
|
{
|
||||||
|
gchar * str;
|
||||||
|
|
||||||
|
g_object_get(G_OBJECT(filesrc), "location", &str, NULL);
|
||||||
|
|
||||||
|
return str != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Get the length of the current audio clip.
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
Ptr<time_duration>::Ref
|
||||||
|
GstreamerPlayer :: getPlaylength(void) throw ()
|
||||||
|
{
|
||||||
|
Ptr<time_duration>::Ref length;
|
||||||
|
gint64 ns;
|
||||||
|
GstFormat format = GST_FORMAT_TIME;
|
||||||
|
|
||||||
|
if (decoderSrc
|
||||||
|
&& gst_pad_query(decoderSrc, GST_QUERY_TOTAL, &format, &ns)
|
||||||
|
&& format == GST_FORMAT_TIME) {
|
||||||
|
|
||||||
|
// use microsec, as nanosec() is not found by the compiler (?)
|
||||||
|
length.reset(new time_duration(microsec(ns / 1000LL)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Start playing
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
GstreamerPlayer :: start(void) throw (std::logic_error)
|
||||||
|
{
|
||||||
|
if (!isOpened()) {
|
||||||
|
throw std::logic_error("GstreamerPlayer not opened yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isPlaying()) {
|
||||||
|
gst_element_set_state(audiosink, GST_STATE_PAUSED);
|
||||||
|
gst_element_set_state(pipeline, GST_STATE_PLAYING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Pause the player
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
GstreamerPlayer :: pause(void) throw (std::logic_error)
|
||||||
|
{
|
||||||
|
if (isPlaying()) {
|
||||||
|
gst_element_set_state(pipeline, GST_STATE_PAUSED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Tell if we're playing
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
bool
|
||||||
|
GstreamerPlayer :: isPlaying(void) throw ()
|
||||||
|
{
|
||||||
|
return gst_element_get_state(pipeline) == GST_STATE_PLAYING;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Stop playing
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
GstreamerPlayer :: stop(void) throw (std::logic_error)
|
||||||
|
{
|
||||||
|
if (!isOpened()) {
|
||||||
|
throw std::logic_error("GstreamerPlayer not opened yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPlaying()) {
|
||||||
|
gst_element_set_state(pipeline, GST_STATE_READY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Close the currently opened audio file.
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
GstreamerPlayer :: close(void) throw ()
|
||||||
|
{
|
||||||
|
if (isPlaying()) {
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_element_set_state(pipeline, GST_STATE_NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Get the volume of the player.
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
unsigned int
|
||||||
|
GstreamerPlayer :: getVolume(void) throw ()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Set the volume of the player.
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
GstreamerPlayer :: setVolume(unsigned int volume) throw ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Open a playlist, with simulated fading.
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
GstreamerPlayer :: openAndStart(Ptr<Playlist>::Ref playlist)
|
||||||
|
throw (std::invalid_argument,
|
||||||
|
std::logic_error,
|
||||||
|
std::runtime_error)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Set the audio device.
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
bool
|
||||||
|
GstreamerPlayer :: setAudioDevice(const std::string &deviceName)
|
||||||
|
throw ()
|
||||||
|
{
|
||||||
|
// TODO: support OSS as well
|
||||||
|
if (deviceName.size() > 0) {
|
||||||
|
g_object_set(G_OBJECT(audiosink), "device", deviceName.c_str(), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
553
livesupport/modules/playlistExecutor/src/GstreamerPlayer.h
Normal file
553
livesupport/modules/playlistExecutor/src/GstreamerPlayer.h
Normal file
|
@ -0,0 +1,553 @@
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2004 Media Development Loan Fund
|
||||||
|
|
||||||
|
This file is part of the LiveSupport project.
|
||||||
|
http://livesupport.campware.org/
|
||||||
|
To report bugs, send an e-mail to bugs@campware.org
|
||||||
|
|
||||||
|
LiveSupport is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
LiveSupport is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with LiveSupport; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
|
||||||
|
Author : $Author: maroy $
|
||||||
|
Version : $Revision: 1.1 $
|
||||||
|
Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/playlistExecutor/src/GstreamerPlayer.h,v $
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------*/
|
||||||
|
#ifndef GstreamerPlayer_h
|
||||||
|
#define GstreamerPlayer_h
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
#error This is a C++ include file
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* ============================================================ include files */
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "configure.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
#include <gst/gst.h>
|
||||||
|
|
||||||
|
#include "LiveSupport/Core/Configurable.h"
|
||||||
|
#include "LiveSupport/PlaylistExecutor/AudioPlayerInterface.h"
|
||||||
|
|
||||||
|
#include "LiveSupport/Core/Playlist.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace LiveSupport {
|
||||||
|
namespace PlaylistExecutor {
|
||||||
|
|
||||||
|
using namespace boost::posix_time;
|
||||||
|
|
||||||
|
using namespace LiveSupport;
|
||||||
|
using namespace LiveSupport::Core;
|
||||||
|
|
||||||
|
/* ================================================================ constants */
|
||||||
|
|
||||||
|
|
||||||
|
/* =================================================================== macros */
|
||||||
|
|
||||||
|
|
||||||
|
/* =============================================================== data types */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class to play audio files and some SMIL files through the Gstreamer
|
||||||
|
* library.
|
||||||
|
* This class can be configured with the following XML element.
|
||||||
|
*
|
||||||
|
* <pre><code>
|
||||||
|
* <helixPlayer dllPath = "../../usr/lib/helix"
|
||||||
|
* audioDevice = "/dev/sound/dsp"
|
||||||
|
* />
|
||||||
|
* <pre><code>
|
||||||
|
*
|
||||||
|
* where the dllPath is the path to the directory containing the Helix
|
||||||
|
* library shared objects. The optional audioDevice argument sets the
|
||||||
|
* AUDIO environment variable which is read by the Helix client.
|
||||||
|
*
|
||||||
|
* There are two parameters which are only there because the current version
|
||||||
|
* of the Helix client does not handle animation tags in SMIL files properly.
|
||||||
|
* They will be removed from later versions.
|
||||||
|
* <ul>
|
||||||
|
* <li>audioStreamTimeOut (milliseconds) - the time to wait for each
|
||||||
|
* GetAudioStream() operation before a timeout occurs;
|
||||||
|
* the default is 5;</li>
|
||||||
|
* <li>fadeLookAheadTime (milliseconds) - each fade-in or fade-out is
|
||||||
|
* scheduled (using IHXAudioCrossFade::CrossFade()) this
|
||||||
|
* much time before it is to happen; the default is 2500. </li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* The DTD for the above configuration is the following:
|
||||||
|
*
|
||||||
|
* <pre><code>
|
||||||
|
* <!ELEMENT helixPlayer EMPTY >
|
||||||
|
* <!ATTLIST helixPlayer dllPath CDATA #REQUIRED >
|
||||||
|
* <!ATTLIST helixPlayer audioDevice CDATA #IMPLIED >
|
||||||
|
* <!ATTLIST helixPlayer audioStreamTimeout #IMPLIED >
|
||||||
|
* <!ATTLIST helixPlayer fadeLookAheatTime #IMPLIED >
|
||||||
|
* </pre></code>
|
||||||
|
*
|
||||||
|
* @author $Author: maroy $
|
||||||
|
* @version $Revision: 1.1 $
|
||||||
|
*/
|
||||||
|
class GstreamerPlayer : virtual public Configurable,
|
||||||
|
virtual public AudioPlayerInterface
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* The name of the configuration XML elmenent used by GstreamerPlayer
|
||||||
|
*/
|
||||||
|
static const std::string configElementNameStr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The pipeline inside the player
|
||||||
|
*/
|
||||||
|
GstElement * pipeline;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The file source element.
|
||||||
|
*/
|
||||||
|
GstElement * filesrc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The typefinder element.
|
||||||
|
*/
|
||||||
|
GstElement * typefinder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The decoder element.
|
||||||
|
*/
|
||||||
|
GstElement * decoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The source pad of the decoder element.
|
||||||
|
* This pad can be used to navigate in a time-based manner.
|
||||||
|
*/
|
||||||
|
GstPad * decoderSrc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The audio sink
|
||||||
|
*/
|
||||||
|
GstElement * audiosink;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of factories considered when creating the pipeline.
|
||||||
|
*/
|
||||||
|
static GList * factories;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URL to play.
|
||||||
|
*/
|
||||||
|
std::string url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag to indicate if this object has been initialized.
|
||||||
|
*/
|
||||||
|
bool initialized;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The audio device to play on.
|
||||||
|
*/
|
||||||
|
std::string audioDevice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type for the vector of listeners.
|
||||||
|
* Just a shorthand notation, to make reference to the type
|
||||||
|
* easier.
|
||||||
|
*/
|
||||||
|
typedef std::vector<AudioPlayerEventListener*>
|
||||||
|
ListenerVector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A vector of event listeners, which are interested in events
|
||||||
|
* related to this player.
|
||||||
|
*/
|
||||||
|
ListenerVector listeners;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the list of factories that we're interested in
|
||||||
|
* when creating the pipeline.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
initFactories(void) throw ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter plugins so that only factories for demuxers, decoders
|
||||||
|
* and parsers are considered.
|
||||||
|
*
|
||||||
|
* @param feature the features of the plugin to check
|
||||||
|
* @param data not used
|
||||||
|
* @return true of the supplied feature is a factory for a demuxer,
|
||||||
|
* decoder or parser, false otherwise
|
||||||
|
*/
|
||||||
|
static gboolean
|
||||||
|
featureFilter(GstPluginFeature * feature,
|
||||||
|
gpointer data)
|
||||||
|
throw ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare the plugin features according to their rank.
|
||||||
|
*
|
||||||
|
* @param feature1 one of the features to compare
|
||||||
|
* @param feature2 the second feature to compare
|
||||||
|
* @return 0 of the ranks are equal, <0 if feature1 is ranked lower,
|
||||||
|
* >0 if feature1 is ranked higher
|
||||||
|
*/
|
||||||
|
static gint
|
||||||
|
compareRanks(GstPluginFeature * feature1,
|
||||||
|
GstPluginFeature * feature2)
|
||||||
|
throw ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler to recieve errors from gstreamer.
|
||||||
|
*
|
||||||
|
* @param pipeline the pipeline generating the error
|
||||||
|
* @param source the source of the error
|
||||||
|
* @param error the error itself
|
||||||
|
* @param debug debug info
|
||||||
|
* @param self pointer to the associated GsreamerPlayer object.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
errorHandler(GstElement * pipeline,
|
||||||
|
GstElement * source,
|
||||||
|
GError * error,
|
||||||
|
gchar * debug,
|
||||||
|
gpointer self) throw ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Even handler for when a matching type was found by typefineder.
|
||||||
|
*
|
||||||
|
* @param typefinder the typefineder that found the match
|
||||||
|
* @param probability the probability of the match
|
||||||
|
* @param caps the capabilities of the found match
|
||||||
|
* @param self pointer to the associated GstreamPlayer object.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
typeFound(GstElement * typefinder,
|
||||||
|
guint probability,
|
||||||
|
GstCaps * caps,
|
||||||
|
gpointer self) throw ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event handler for when a new dynamic pad is found. Plug the found
|
||||||
|
* pad by calling tryToPlug().
|
||||||
|
*
|
||||||
|
* @param element the element where the new pad came up.
|
||||||
|
* @param pad the new pad
|
||||||
|
* @param self reference to the associated GstreamerPlayer object
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
newPad(GstElement * element,
|
||||||
|
GstPad * pad,
|
||||||
|
gpointer self)
|
||||||
|
throw ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event handler for the state change event on the pipeline.
|
||||||
|
* Use this to catch events like playing has ended.
|
||||||
|
*
|
||||||
|
* @param element the pipeline the event change has occured at
|
||||||
|
* @param oldState the old state
|
||||||
|
* @param newState the new state
|
||||||
|
* @param self a pointer to the associated GstreamerPlayer object.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
stateChange(GstElement * element,
|
||||||
|
gint oldState,
|
||||||
|
gint newState,
|
||||||
|
gpointer self)
|
||||||
|
throw ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to plug a matching element to the specified pad
|
||||||
|
*
|
||||||
|
* @param pad the pad to plug to
|
||||||
|
* @param caps find a matching element to these capabilities
|
||||||
|
* @exception std::logic_error if couldn't plug
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
tryToPlug(GstPad * pad,
|
||||||
|
const GstCaps * caps)
|
||||||
|
throw (std::logic_error);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the link between a source pad and a sink element
|
||||||
|
*
|
||||||
|
* @param srcpad the source pad to link up
|
||||||
|
* @param sinkelement link srcpad to this element
|
||||||
|
* @param padname use this pad from sinkelement to link to
|
||||||
|
* @param templlist use pads from these templates
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
closeLink(GstPad * srcpad,
|
||||||
|
GstElement * sinkelement,
|
||||||
|
const gchar * padname,
|
||||||
|
const GList * templlist)
|
||||||
|
throw ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the onStop event to all attached listeners.
|
||||||
|
*/
|
||||||
|
virtual void
|
||||||
|
fireOnStopEvent(void) throw ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell if the object is currently opened (has a file source to
|
||||||
|
* read.)
|
||||||
|
*
|
||||||
|
* @return true if the object is currently opened, false otherwise.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
isOpened(void) throw ();
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*/
|
||||||
|
GstreamerPlayer(void) throw ()
|
||||||
|
{
|
||||||
|
pipeline = 0;
|
||||||
|
filesrc = 0;
|
||||||
|
typefinder = 0;
|
||||||
|
decoder = 0;
|
||||||
|
decoderSrc = 0;
|
||||||
|
audiosink = 0;
|
||||||
|
initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A virtual destructor, as this class has virtual functions.
|
||||||
|
*/
|
||||||
|
virtual
|
||||||
|
~GstreamerPlayer(void) throw ()
|
||||||
|
{
|
||||||
|
deInitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the name of the XML element this object expects
|
||||||
|
* to be sent to a call to configure().
|
||||||
|
*
|
||||||
|
* @return the name of the expected XML configuration element.
|
||||||
|
*/
|
||||||
|
static const std::string
|
||||||
|
getConfigElementName(void) throw ()
|
||||||
|
{
|
||||||
|
return configElementNameStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure the object based on the XML element supplied.
|
||||||
|
*
|
||||||
|
* @param element the XML element to configure the object from.
|
||||||
|
* @exception std::invalid_argument if the supplied XML element
|
||||||
|
* contains bad configuraiton information
|
||||||
|
* @exception std::logic_error if the scheduler daemon has already
|
||||||
|
* been configured, and can not be reconfigured.
|
||||||
|
*/
|
||||||
|
virtual void
|
||||||
|
configure(const xmlpp::Element & element)
|
||||||
|
throw (std::invalid_argument,
|
||||||
|
std::logic_error);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the Helix Player object, so that it is ready to
|
||||||
|
* play audio files.
|
||||||
|
*
|
||||||
|
* @exception std::exception on initialization problems.
|
||||||
|
*/
|
||||||
|
virtual void
|
||||||
|
initialize(void) throw (std::exception);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* De-initialize the Helix Player object.
|
||||||
|
*/
|
||||||
|
virtual void
|
||||||
|
deInitialize(void) throw ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attach an event listener for this audio player.
|
||||||
|
* After this call, the supplied event will recieve all events
|
||||||
|
* related to this audio player.
|
||||||
|
*
|
||||||
|
* @param eventListener the event listener to register.
|
||||||
|
* @see #detach
|
||||||
|
*/
|
||||||
|
virtual void
|
||||||
|
attachListener(AudioPlayerEventListener* eventListener)
|
||||||
|
throw ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detach an event listener for this audio player.
|
||||||
|
*
|
||||||
|
* @param eventListener the event listener to unregister.
|
||||||
|
* @exception std::invalid_argument if the supplied event listener
|
||||||
|
* has not been previously registered.
|
||||||
|
* @see #attach
|
||||||
|
*/
|
||||||
|
virtual void
|
||||||
|
detachListener(AudioPlayerEventListener* eventListener)
|
||||||
|
throw (std::invalid_argument);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the audio device used for playback.
|
||||||
|
*
|
||||||
|
* @param deviceName the new device name, e.g., /dev/dsp or
|
||||||
|
* plughw:0,0
|
||||||
|
* @return true if successful, false if not
|
||||||
|
*/
|
||||||
|
virtual bool
|
||||||
|
setAudioDevice(const std::string &deviceName)
|
||||||
|
throw ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify which audio resource to play.
|
||||||
|
* The file may be a playlist, referencing other files, which
|
||||||
|
* will be accessed automatically.
|
||||||
|
* Note: this call will <b>not</b> start playing! You will
|
||||||
|
* have to call the start() function to begin playing.
|
||||||
|
* Always close any opened resource with a call to close().
|
||||||
|
*
|
||||||
|
* @param fileUrl a URL to a file
|
||||||
|
* @exception std::invalid_argument if the supplied fileUrl
|
||||||
|
* seems to be invalid.
|
||||||
|
* @see #close
|
||||||
|
* @see #start
|
||||||
|
*/
|
||||||
|
virtual void
|
||||||
|
open(const std::string fileUrl) throw (std::invalid_argument);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close an audio source that was opened.
|
||||||
|
*
|
||||||
|
* @see #open
|
||||||
|
*/
|
||||||
|
virtual void
|
||||||
|
close(void) throw ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start playing.
|
||||||
|
* This call will start playing the active playlist, which was
|
||||||
|
* set by a previous call to open().
|
||||||
|
* Playing can be stopped by calling stop().
|
||||||
|
*
|
||||||
|
* @exception std::logic_error if there was no previous call to
|
||||||
|
* open().
|
||||||
|
* @see #open
|
||||||
|
* @see #stop
|
||||||
|
*/
|
||||||
|
virtual void
|
||||||
|
start(void) throw (std::logic_error);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pause the player.
|
||||||
|
* Playing can be resumed by calling start().
|
||||||
|
*
|
||||||
|
* @exception std::logic_error if there was no previous call to
|
||||||
|
* open().
|
||||||
|
* @see #open
|
||||||
|
* @see #start
|
||||||
|
*/
|
||||||
|
virtual void
|
||||||
|
pause(void) throw (std::logic_error);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell if we're currently playing.
|
||||||
|
*
|
||||||
|
* @return true of the player is currently playing, false
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
virtual bool
|
||||||
|
isPlaying(void) throw ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop playing.
|
||||||
|
*
|
||||||
|
* @exception std::logic_error if there was no previous call to
|
||||||
|
* start()
|
||||||
|
*/
|
||||||
|
virtual void
|
||||||
|
stop(void) throw (std::logic_error);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the length of the currently opened audio clip.
|
||||||
|
* This function waits as long as necessary to get the length.
|
||||||
|
*
|
||||||
|
* @return the length of the currently playing audio clip, or 0,
|
||||||
|
* if nothing is openned.
|
||||||
|
*/
|
||||||
|
virtual Ptr<posix_time::time_duration>::Ref
|
||||||
|
getPlaylength(void) throw ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the volume of the player.
|
||||||
|
*
|
||||||
|
* @return the volume, from 1 to 100.
|
||||||
|
*/
|
||||||
|
virtual unsigned int
|
||||||
|
getVolume(void) throw ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the volume of the player.
|
||||||
|
*
|
||||||
|
* @param volume the new volume, from 1 to 100.
|
||||||
|
*/
|
||||||
|
virtual void
|
||||||
|
setVolume(unsigned int volume) throw ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Play a playlist, with simulated fading.
|
||||||
|
*
|
||||||
|
* This is a stopgap method, and should be replaced as soon as
|
||||||
|
* the SMIL animation issues are fixed in the Helix client.
|
||||||
|
*
|
||||||
|
* The playlist is assumed to contain a URI field, which points
|
||||||
|
* to a SMIL file containing the same audio clips, with the same
|
||||||
|
* offsets, as the playlist. This can be ensured, for example, by
|
||||||
|
* calling Storage::WebStorageClient::acquirePlaylist().
|
||||||
|
*
|
||||||
|
* @param playlist the Playlist object to be played.
|
||||||
|
* @exception std::invalid_argument playlist is invalid (e.g.,
|
||||||
|
* does not have a URI field, or there is no valid
|
||||||
|
* SMIL file at the given URI).
|
||||||
|
* @exception std::logic_error thrown by start() if open() was
|
||||||
|
* unsuccessful, but returned normally (never happens)
|
||||||
|
* @exception std::runtime_error on errors thrown by the helix player
|
||||||
|
*/
|
||||||
|
virtual void
|
||||||
|
openAndStart(Ptr<Playlist>::Ref playlist)
|
||||||
|
throw (std::invalid_argument,
|
||||||
|
std::logic_error,
|
||||||
|
std::runtime_error);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* ================================================= external data structures */
|
||||||
|
|
||||||
|
|
||||||
|
/* ====================================================== function prototypes */
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace PlaylistExecutor
|
||||||
|
} // namespace LiveSupport
|
||||||
|
|
||||||
|
|
||||||
|
#endif // GstreamerPlayer_h
|
||||||
|
|
339
livesupport/modules/playlistExecutor/src/GstreamerPlayerTest.cxx
Normal file
339
livesupport/modules/playlistExecutor/src/GstreamerPlayerTest.cxx
Normal file
|
@ -0,0 +1,339 @@
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2004 Media Development Loan Fund
|
||||||
|
|
||||||
|
This file is part of the LiveSupport project.
|
||||||
|
http://livesupport.campware.org/
|
||||||
|
To report bugs, send an e-mail to bugs@campware.org
|
||||||
|
|
||||||
|
LiveSupport is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
LiveSupport is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with LiveSupport; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
|
||||||
|
Author : $Author: maroy $
|
||||||
|
Version : $Revision: 1.1 $
|
||||||
|
Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/playlistExecutor/src/GstreamerPlayerTest.cxx,v $
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* ============================================================ include files */
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "configure.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#else
|
||||||
|
#error "Need unistd.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "LiveSupport/Core/TimeConversion.h"
|
||||||
|
|
||||||
|
#include "GstreamerPlayer.h"
|
||||||
|
#include "TestEventListener.h"
|
||||||
|
#include "GstreamerPlayerTest.h"
|
||||||
|
|
||||||
|
|
||||||
|
using namespace LiveSupport::PlaylistExecutor;
|
||||||
|
|
||||||
|
/* =================================================== local data structures */
|
||||||
|
|
||||||
|
|
||||||
|
/* ================================================ local constants & macros */
|
||||||
|
|
||||||
|
CPPUNIT_TEST_SUITE_REGISTRATION(GstreamerPlayerTest);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the configuration file for the Helix player.
|
||||||
|
*/
|
||||||
|
static const std::string configFileName = "etc/gstreamerPlayer.xml";
|
||||||
|
|
||||||
|
|
||||||
|
/* =============================================== local function prototypes */
|
||||||
|
|
||||||
|
|
||||||
|
/* ============================================================= module code */
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Set up the test environment
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
GstreamerPlayerTest :: setUp(void) throw ()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Ptr<xmlpp::DomParser>::Ref parser(
|
||||||
|
new xmlpp::DomParser(configFileName, true));
|
||||||
|
const xmlpp::Document * document = parser->get_document();
|
||||||
|
const xmlpp::Element * root = document->get_root_node();
|
||||||
|
|
||||||
|
player.reset(new GstreamerPlayer());
|
||||||
|
player->configure(*root);
|
||||||
|
|
||||||
|
} catch (std::invalid_argument &e) {
|
||||||
|
std::cerr << "semantic error in configuration file" << std::endl;
|
||||||
|
} catch (xmlpp::exception &e) {
|
||||||
|
std::cerr << e.what() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Clean up the test environment
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
GstreamerPlayerTest :: tearDown(void) throw ()
|
||||||
|
{
|
||||||
|
player.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Test to see if the GstreamerPlayer engine can be started and stopped
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
GstreamerPlayerTest :: firstTest(void)
|
||||||
|
throw (CPPUNIT_NS::Exception)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
player->initialize();
|
||||||
|
CPPUNIT_ASSERT(!player->isPlaying());
|
||||||
|
player->deInitialize();
|
||||||
|
} catch (std::exception &e) {
|
||||||
|
CPPUNIT_FAIL("failed to initialize or de-initialize GstreamerPlayer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Play something simple
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
GstreamerPlayerTest :: simplePlayTest(void)
|
||||||
|
throw (CPPUNIT_NS::Exception)
|
||||||
|
{
|
||||||
|
Ptr<time_duration>::Ref sleepT(new time_duration(microseconds(10)));
|
||||||
|
|
||||||
|
player->initialize();
|
||||||
|
try {
|
||||||
|
player->open("file:var/test.mp3");
|
||||||
|
} catch (std::invalid_argument &e) {
|
||||||
|
CPPUNIT_FAIL(e.what());
|
||||||
|
}
|
||||||
|
CPPUNIT_ASSERT(!player->isPlaying());
|
||||||
|
player->start();
|
||||||
|
CPPUNIT_ASSERT(player->isPlaying());
|
||||||
|
while (player->isPlaying()) {
|
||||||
|
TimeConversion::sleep(sleepT);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ptr<time_duration>::Ref playlength = player->getPlaylength();
|
||||||
|
CPPUNIT_ASSERT(playlength.get());
|
||||||
|
CPPUNIT_ASSERT(playlength->seconds() == 14);
|
||||||
|
CPPUNIT_ASSERT(playlength->fractional_seconds() == 785187);
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT(!player->isPlaying());
|
||||||
|
player->close();
|
||||||
|
player->deInitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Check for error conditions
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
GstreamerPlayerTest :: checkErrorConditions(void)
|
||||||
|
throw (CPPUNIT_NS::Exception)
|
||||||
|
{
|
||||||
|
player->initialize();
|
||||||
|
|
||||||
|
bool gotException;
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT(!player->isPlaying());
|
||||||
|
|
||||||
|
gotException = false;
|
||||||
|
try {
|
||||||
|
player->start();
|
||||||
|
} catch (std::logic_error &e) {
|
||||||
|
gotException = true;
|
||||||
|
}
|
||||||
|
CPPUNIT_ASSERT(gotException);
|
||||||
|
|
||||||
|
gotException = false;
|
||||||
|
try {
|
||||||
|
player->stop();
|
||||||
|
} catch (std::logic_error &e) {
|
||||||
|
gotException = true;
|
||||||
|
}
|
||||||
|
CPPUNIT_ASSERT(gotException);
|
||||||
|
|
||||||
|
gotException = false;
|
||||||
|
try {
|
||||||
|
player->open("totally/bad/URL");
|
||||||
|
} catch (std::invalid_argument &e) {
|
||||||
|
gotException = true;
|
||||||
|
}
|
||||||
|
CPPUNIT_ASSERT(gotException);
|
||||||
|
|
||||||
|
gotException = false;
|
||||||
|
try {
|
||||||
|
player->start();
|
||||||
|
} catch (std::logic_error &e) {
|
||||||
|
gotException = true;
|
||||||
|
}
|
||||||
|
CPPUNIT_ASSERT(gotException);
|
||||||
|
|
||||||
|
// check for opening a wrong URL after opening a proper one
|
||||||
|
try {
|
||||||
|
player->open("file:var/test.mp3");
|
||||||
|
} catch (std::invalid_argument &e) {
|
||||||
|
CPPUNIT_FAIL(e.what());
|
||||||
|
}
|
||||||
|
player->close();
|
||||||
|
gotException = false;
|
||||||
|
try {
|
||||||
|
player->open("totally/bad/URL");
|
||||||
|
} catch (std::invalid_argument &e) {
|
||||||
|
gotException = true;
|
||||||
|
}
|
||||||
|
CPPUNIT_ASSERT(gotException);
|
||||||
|
|
||||||
|
player->deInitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Test to see if attaching and detaching event listeners works.
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
GstreamerPlayerTest :: eventListenerAttachTest(void)
|
||||||
|
throw (CPPUNIT_NS::Exception)
|
||||||
|
{
|
||||||
|
CPPUNIT_ASSERT_NO_THROW(player->initialize());
|
||||||
|
|
||||||
|
Ptr<TestEventListener>::Ref listener1(new TestEventListener());
|
||||||
|
Ptr<TestEventListener>::Ref listener2(new TestEventListener());
|
||||||
|
|
||||||
|
// try with one listener
|
||||||
|
player->attachListener(listener1.get());
|
||||||
|
CPPUNIT_ASSERT_NO_THROW(
|
||||||
|
player->detachListener(listener1.get())
|
||||||
|
);
|
||||||
|
CPPUNIT_ASSERT_THROW(
|
||||||
|
player->detachListener(listener1.get()),
|
||||||
|
std::invalid_argument
|
||||||
|
);
|
||||||
|
|
||||||
|
// try with two listeners
|
||||||
|
player->attachListener(listener1.get());
|
||||||
|
CPPUNIT_ASSERT_THROW(
|
||||||
|
player->detachListener(listener2.get()),
|
||||||
|
std::invalid_argument
|
||||||
|
);
|
||||||
|
player->attachListener(listener2.get());
|
||||||
|
CPPUNIT_ASSERT_NO_THROW(
|
||||||
|
player->detachListener(listener1.get());
|
||||||
|
);
|
||||||
|
|
||||||
|
player->deInitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Test to see if the player event listener mechanism works.
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
GstreamerPlayerTest :: eventListenerTest(void)
|
||||||
|
throw (CPPUNIT_NS::Exception)
|
||||||
|
{
|
||||||
|
CPPUNIT_ASSERT_NO_THROW(player->initialize());
|
||||||
|
|
||||||
|
Ptr<time_duration>::Ref sleepT(new time_duration(microseconds(10)));
|
||||||
|
Ptr<TestEventListener>::Ref listener1(new TestEventListener());
|
||||||
|
player->attachListener(listener1.get());
|
||||||
|
|
||||||
|
// try with one listener
|
||||||
|
CPPUNIT_ASSERT(!listener1->stopFlag);
|
||||||
|
CPPUNIT_ASSERT_NO_THROW(
|
||||||
|
player->open("file:var/test.mp3");
|
||||||
|
);
|
||||||
|
CPPUNIT_ASSERT(!player->isPlaying());
|
||||||
|
CPPUNIT_ASSERT(!listener1->stopFlag);
|
||||||
|
player->start();
|
||||||
|
CPPUNIT_ASSERT(player->isPlaying());
|
||||||
|
CPPUNIT_ASSERT(!listener1->stopFlag);
|
||||||
|
while (player->isPlaying()) {
|
||||||
|
CPPUNIT_ASSERT(!listener1->stopFlag);
|
||||||
|
TimeConversion::sleep(sleepT);
|
||||||
|
}
|
||||||
|
CPPUNIT_ASSERT(!player->isPlaying());
|
||||||
|
CPPUNIT_ASSERT(listener1->stopFlag);
|
||||||
|
listener1->stopFlag = false;
|
||||||
|
|
||||||
|
// try with two listeners
|
||||||
|
Ptr<TestEventListener>::Ref listener2(new TestEventListener());
|
||||||
|
player->attachListener(listener2.get());
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT(!listener1->stopFlag);
|
||||||
|
CPPUNIT_ASSERT(!listener2->stopFlag);
|
||||||
|
CPPUNIT_ASSERT_NO_THROW(
|
||||||
|
player->open("file:var/test.mp3");
|
||||||
|
);
|
||||||
|
CPPUNIT_ASSERT(!player->isPlaying());
|
||||||
|
CPPUNIT_ASSERT(!listener1->stopFlag);
|
||||||
|
CPPUNIT_ASSERT(!listener2->stopFlag);
|
||||||
|
player->start();
|
||||||
|
CPPUNIT_ASSERT(player->isPlaying());
|
||||||
|
CPPUNIT_ASSERT(!listener1->stopFlag);
|
||||||
|
CPPUNIT_ASSERT(!listener2->stopFlag);
|
||||||
|
while (player->isPlaying()) {
|
||||||
|
CPPUNIT_ASSERT(!listener1->stopFlag);
|
||||||
|
CPPUNIT_ASSERT(!listener2->stopFlag);
|
||||||
|
TimeConversion::sleep(sleepT);
|
||||||
|
}
|
||||||
|
CPPUNIT_ASSERT(!player->isPlaying());
|
||||||
|
CPPUNIT_ASSERT(listener1->stopFlag);
|
||||||
|
CPPUNIT_ASSERT(listener2->stopFlag);
|
||||||
|
listener1->stopFlag = false;
|
||||||
|
listener2->stopFlag = false;
|
||||||
|
|
||||||
|
// try with only the second listener
|
||||||
|
CPPUNIT_ASSERT_NO_THROW(
|
||||||
|
player->detachListener(listener1.get());
|
||||||
|
);
|
||||||
|
CPPUNIT_ASSERT(!listener2->stopFlag);
|
||||||
|
CPPUNIT_ASSERT_NO_THROW(
|
||||||
|
player->open("file:var/test.mp3");
|
||||||
|
);
|
||||||
|
CPPUNIT_ASSERT(!player->isPlaying());
|
||||||
|
CPPUNIT_ASSERT(!listener2->stopFlag);
|
||||||
|
player->start();
|
||||||
|
CPPUNIT_ASSERT(player->isPlaying());
|
||||||
|
CPPUNIT_ASSERT(!listener2->stopFlag);
|
||||||
|
while (player->isPlaying()) {
|
||||||
|
CPPUNIT_ASSERT(!listener2->stopFlag);
|
||||||
|
TimeConversion::sleep(sleepT);
|
||||||
|
}
|
||||||
|
CPPUNIT_ASSERT(!player->isPlaying());
|
||||||
|
CPPUNIT_ASSERT(listener2->stopFlag);
|
||||||
|
listener2->stopFlag = false;
|
||||||
|
|
||||||
|
player->close();
|
||||||
|
player->deInitialize();
|
||||||
|
}
|
||||||
|
|
151
livesupport/modules/playlistExecutor/src/GstreamerPlayerTest.h
Normal file
151
livesupport/modules/playlistExecutor/src/GstreamerPlayerTest.h
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2004 Media Development Loan Fund
|
||||||
|
|
||||||
|
This file is part of the LiveSupport project.
|
||||||
|
http://livesupport.campware.org/
|
||||||
|
To report bugs, send an e-mail to bugs@campware.org
|
||||||
|
|
||||||
|
LiveSupport is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
LiveSupport is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with LiveSupport; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
|
||||||
|
Author : $Author: maroy $
|
||||||
|
Version : $Revision: 1.1 $
|
||||||
|
Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/playlistExecutor/src/GstreamerPlayerTest.h,v $
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------*/
|
||||||
|
#ifndef GstreamerPlayerTest_h
|
||||||
|
#define GstreamerPlayerTest_h
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
#error This is a C++ include file
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* ============================================================ include files */
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "configure.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <cppunit/extensions/HelperMacros.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace LiveSupport {
|
||||||
|
namespace PlaylistExecutor {
|
||||||
|
|
||||||
|
/* ================================================================ constants */
|
||||||
|
|
||||||
|
|
||||||
|
/* =================================================================== macros */
|
||||||
|
|
||||||
|
|
||||||
|
/* =============================================================== data types */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit test for the GstreamerPlayer class.
|
||||||
|
*
|
||||||
|
* @author $Author: maroy $
|
||||||
|
* @version $Revision: 1.1 $
|
||||||
|
* @see GstreamerPlayer
|
||||||
|
*/
|
||||||
|
class GstreamerPlayerTest : public CPPUNIT_NS::TestFixture
|
||||||
|
{
|
||||||
|
CPPUNIT_TEST_SUITE(GstreamerPlayerTest);
|
||||||
|
CPPUNIT_TEST(firstTest);
|
||||||
|
CPPUNIT_TEST(simplePlayTest);
|
||||||
|
CPPUNIT_TEST(checkErrorConditions);
|
||||||
|
CPPUNIT_TEST(eventListenerAttachTest);
|
||||||
|
CPPUNIT_TEST(eventListenerTest);
|
||||||
|
CPPUNIT_TEST_SUITE_END();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The player to use for the tests.
|
||||||
|
*/
|
||||||
|
Ptr<GstreamerPlayer>::Ref player;
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple test.
|
||||||
|
*
|
||||||
|
* @exception CPPUNIT_NS::Exception on test failures.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
firstTest(void) throw (CPPUNIT_NS::Exception);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple play test.
|
||||||
|
*
|
||||||
|
* @exception CPPUNIT_NS::Exception on test failures.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
simplePlayTest(void) throw (CPPUNIT_NS::Exception);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for error conditions.
|
||||||
|
*
|
||||||
|
* @exception CPPUNIT_NS::Exception on test failures.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
checkErrorConditions(void) throw (CPPUNIT_NS::Exception);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test to see if attaching and detaching event listeners works.
|
||||||
|
*
|
||||||
|
* @exception CPPUNIT_NS::Exception on test failures.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
eventListenerAttachTest(void) throw (CPPUNIT_NS::Exception);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test to see if the player event listener mechanism works.
|
||||||
|
*
|
||||||
|
* @exception CPPUNIT_NS::Exception on test failures.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
eventListenerTest(void) throw (CPPUNIT_NS::Exception);
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up the environment for the test case.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
setUp(void) throw ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean up the environment after the test case.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
tearDown(void) throw ();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* ================================================= external data structures */
|
||||||
|
|
||||||
|
|
||||||
|
/* ====================================================== function prototypes */
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace PlaylistExecutor
|
||||||
|
} // namespace LiveSupport
|
||||||
|
|
||||||
|
#endif // GstreamerPlayerTest_h
|
||||||
|
|
|
@ -0,0 +1,247 @@
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2004 Media Development Loan Fund
|
||||||
|
|
||||||
|
This file is part of the LiveSupport project.
|
||||||
|
http://livesupport.campware.org/
|
||||||
|
To report bugs, send an e-mail to bugs@campware.org
|
||||||
|
|
||||||
|
LiveSupport is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
LiveSupport is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with LiveSupport; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
|
||||||
|
Author : $Author: maroy $
|
||||||
|
Version : $Revision: 1.1 $
|
||||||
|
Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/playlistExecutor/src/TwoGstreamerPlayersTest.cxx,v $
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* ============================================================ include files */
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "configure.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#else
|
||||||
|
#error "Need unistd.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "LiveSupport/Core/TimeConversion.h"
|
||||||
|
|
||||||
|
#include "GstreamerPlayer.h"
|
||||||
|
#include "TestEventListener.h"
|
||||||
|
#include "TwoGstreamerPlayersTest.h"
|
||||||
|
|
||||||
|
|
||||||
|
using namespace LiveSupport::PlaylistExecutor;
|
||||||
|
|
||||||
|
/* =================================================== local data structures */
|
||||||
|
|
||||||
|
|
||||||
|
/* ================================================ local constants & macros */
|
||||||
|
|
||||||
|
CPPUNIT_TEST_SUITE_REGISTRATION(TwoGstreamerPlayersTest);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the configuration file for the Helix player.
|
||||||
|
*/
|
||||||
|
static const std::string configFileName = "etc/twoGstreamerPlayers.xml";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the root XML element in the configuration file.
|
||||||
|
*/
|
||||||
|
static const std::string rootElementName = "twoGstreamerPlayers";
|
||||||
|
|
||||||
|
|
||||||
|
/* =============================================== local function prototypes */
|
||||||
|
|
||||||
|
|
||||||
|
/* ============================================================= module code */
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Set up the test environment
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
TwoGstreamerPlayersTest :: setUp(void) throw ()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Ptr<xmlpp::DomParser>::Ref parser(
|
||||||
|
new xmlpp::DomParser(configFileName, true));
|
||||||
|
const xmlpp::Document * document = parser->get_document();
|
||||||
|
const xmlpp::Element * root = document->get_root_node();
|
||||||
|
|
||||||
|
xmlpp::Node::NodeList children;
|
||||||
|
const xmlpp::Element * element;
|
||||||
|
|
||||||
|
children = root->get_children(GstreamerPlayer::getConfigElementName());
|
||||||
|
|
||||||
|
element = dynamic_cast<const xmlpp::Element*> (*(children.begin()));
|
||||||
|
player1.reset(new GstreamerPlayer());
|
||||||
|
player1->configure(*element);
|
||||||
|
|
||||||
|
children.pop_front();
|
||||||
|
element = dynamic_cast<const xmlpp::Element*> (*(children.begin()));
|
||||||
|
player2.reset(new GstreamerPlayer());
|
||||||
|
player2->configure(*element);
|
||||||
|
|
||||||
|
} catch (std::invalid_argument &e) {
|
||||||
|
std::cerr << "semantic error in configuration file" << std::endl;
|
||||||
|
} catch (xmlpp::exception &e) {
|
||||||
|
std::cerr << e.what() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Clean up the test environment
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
TwoGstreamerPlayersTest :: tearDown(void) throw ()
|
||||||
|
{
|
||||||
|
player2.reset();
|
||||||
|
player1.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Test to see if the GstreamerPlayer engine can be started and stopped
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
TwoGstreamerPlayersTest :: firstTest(void)
|
||||||
|
throw (CPPUNIT_NS::Exception)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
player1->initialize();
|
||||||
|
player2->initialize();
|
||||||
|
CPPUNIT_ASSERT(!player1->isPlaying());
|
||||||
|
CPPUNIT_ASSERT(!player2->isPlaying());
|
||||||
|
player2->deInitialize();
|
||||||
|
player1->deInitialize();
|
||||||
|
} catch (std::exception &e) {
|
||||||
|
CPPUNIT_FAIL("failed to initialize or de-initialize GstreamerPlayer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Play something simple on player #1
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
TwoGstreamerPlayersTest :: simplePlay1Test(void)
|
||||||
|
throw (CPPUNIT_NS::Exception)
|
||||||
|
{
|
||||||
|
Ptr<time_duration>::Ref sleepT(new time_duration(microseconds(10)));
|
||||||
|
|
||||||
|
player1->initialize();
|
||||||
|
try {
|
||||||
|
player1->open("file:var/test10001.mp3");
|
||||||
|
} catch (std::invalid_argument &e) {
|
||||||
|
CPPUNIT_FAIL(e.what());
|
||||||
|
}
|
||||||
|
CPPUNIT_ASSERT(!player1->isPlaying());
|
||||||
|
player1->start();
|
||||||
|
CPPUNIT_ASSERT(player1->isPlaying());
|
||||||
|
while (player1->isPlaying()) {
|
||||||
|
TimeConversion::sleep(sleepT);
|
||||||
|
}
|
||||||
|
CPPUNIT_ASSERT(!player1->isPlaying());
|
||||||
|
player1->close();
|
||||||
|
player1->deInitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Play something simple on player #2
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
TwoGstreamerPlayersTest :: simplePlay2Test(void)
|
||||||
|
throw (CPPUNIT_NS::Exception)
|
||||||
|
{
|
||||||
|
Ptr<time_duration>::Ref sleepT(new time_duration(microseconds(10)));
|
||||||
|
|
||||||
|
player2->initialize();
|
||||||
|
try {
|
||||||
|
player2->open("file:var/test.mp3");
|
||||||
|
} catch (std::invalid_argument &e) {
|
||||||
|
CPPUNIT_FAIL(e.what());
|
||||||
|
}
|
||||||
|
CPPUNIT_ASSERT(!player2->isPlaying());
|
||||||
|
player2->start();
|
||||||
|
CPPUNIT_ASSERT(player2->isPlaying());
|
||||||
|
while (player2->isPlaying()) {
|
||||||
|
TimeConversion::sleep(sleepT);
|
||||||
|
}
|
||||||
|
CPPUNIT_ASSERT(!player2->isPlaying());
|
||||||
|
player2->close();
|
||||||
|
player2->deInitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Play something simple on both players
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
TwoGstreamerPlayersTest :: playBothTest(void)
|
||||||
|
throw (CPPUNIT_NS::Exception)
|
||||||
|
{
|
||||||
|
Ptr<time_duration>::Ref sleepT(new time_duration(microseconds(10)));
|
||||||
|
|
||||||
|
player1->initialize();
|
||||||
|
player2->initialize();
|
||||||
|
|
||||||
|
// start playing on player1
|
||||||
|
try {
|
||||||
|
player1->open("file:var/test10001.mp3");
|
||||||
|
} catch (std::invalid_argument &e) {
|
||||||
|
CPPUNIT_FAIL(e.what());
|
||||||
|
}
|
||||||
|
CPPUNIT_ASSERT(!player1->isPlaying());
|
||||||
|
player1->start();
|
||||||
|
CPPUNIT_ASSERT(player1->isPlaying());
|
||||||
|
|
||||||
|
// sleep some time
|
||||||
|
for (unsigned i = 0; i < 100; ++i) {
|
||||||
|
TimeConversion::sleep(sleepT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// start playing on player2
|
||||||
|
try {
|
||||||
|
player2->open("file:var/test.mp3");
|
||||||
|
} catch (std::invalid_argument &e) {
|
||||||
|
CPPUNIT_FAIL(e.what());
|
||||||
|
}
|
||||||
|
CPPUNIT_ASSERT(!player2->isPlaying());
|
||||||
|
player2->start();
|
||||||
|
CPPUNIT_ASSERT(player2->isPlaying());
|
||||||
|
|
||||||
|
// wait for both players to finish
|
||||||
|
while (player1->isPlaying() || player2->isPlaying()) {
|
||||||
|
TimeConversion::sleep(sleepT);
|
||||||
|
}
|
||||||
|
CPPUNIT_ASSERT(!player1->isPlaying());
|
||||||
|
CPPUNIT_ASSERT(!player2->isPlaying());
|
||||||
|
|
||||||
|
player2->close();
|
||||||
|
player1->close();
|
||||||
|
player2->deInitialize();
|
||||||
|
player1->deInitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,161 @@
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2004 Media Development Loan Fund
|
||||||
|
|
||||||
|
This file is part of the LiveSupport project.
|
||||||
|
http://livesupport.campware.org/
|
||||||
|
To report bugs, send an e-mail to bugs@campware.org
|
||||||
|
|
||||||
|
LiveSupport is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
LiveSupport is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with LiveSupport; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
|
||||||
|
Author : $Author: maroy $
|
||||||
|
Version : $Revision: 1.1 $
|
||||||
|
Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/playlistExecutor/src/TwoGstreamerPlayersTest.h,v $
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------*/
|
||||||
|
#ifndef TwoGstreamerPlayersTest_h
|
||||||
|
#define TwoGstreamerPlayersTest_h
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
#error This is a C++ include file
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* ============================================================ include files */
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "configure.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <cppunit/extensions/HelperMacros.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace LiveSupport {
|
||||||
|
namespace PlaylistExecutor {
|
||||||
|
|
||||||
|
/* ================================================================ constants */
|
||||||
|
|
||||||
|
|
||||||
|
/* =================================================================== macros */
|
||||||
|
|
||||||
|
|
||||||
|
/* =============================================================== data types */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit test for the GstreamerPlayer class, two see if two helix players,
|
||||||
|
* playing on two different sound cards work correctly.
|
||||||
|
*
|
||||||
|
* @author $Author: maroy $
|
||||||
|
* @version $Revision: 1.1 $
|
||||||
|
* @see GstreamerPlayer
|
||||||
|
*/
|
||||||
|
class TwoGstreamerPlayersTest : public CPPUNIT_NS::TestFixture
|
||||||
|
{
|
||||||
|
CPPUNIT_TEST_SUITE(TwoGstreamerPlayersTest);
|
||||||
|
CPPUNIT_TEST(firstTest);
|
||||||
|
CPPUNIT_TEST(simplePlay1Test);
|
||||||
|
CPPUNIT_TEST(simplePlay2Test);
|
||||||
|
CPPUNIT_TEST(playBothTest);
|
||||||
|
CPPUNIT_TEST_SUITE_END();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helix player #1 to use for the tests.
|
||||||
|
*/
|
||||||
|
Ptr<GstreamerPlayer>::Ref player1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helix player #2 to use for the tests.
|
||||||
|
*/
|
||||||
|
Ptr<GstreamerPlayer>::Ref player2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Play a specific file.
|
||||||
|
*
|
||||||
|
* @param fileName the name of the file to play.
|
||||||
|
* @param player the player to use for playing the file.
|
||||||
|
* @exception CPPUNIT_NS::Exception on playing failures
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
playFile(const std::string & fileName,
|
||||||
|
Ptr<GstreamerPlayer>::Ref player)
|
||||||
|
throw (CPPUNIT_NS::Exception);
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple test.
|
||||||
|
*
|
||||||
|
* @exception CPPUNIT_NS::Exception on test failures.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
firstTest(void) throw (CPPUNIT_NS::Exception);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Play something on player #1.
|
||||||
|
*
|
||||||
|
* @exception CPPUNIT_NS::Exception on test failures.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
simplePlay1Test(void) throw (CPPUNIT_NS::Exception);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Play something on player #2.
|
||||||
|
*
|
||||||
|
* @exception CPPUNIT_NS::Exception on test failures.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
simplePlay2Test(void) throw (CPPUNIT_NS::Exception);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Play something on both players, at the same time.
|
||||||
|
*
|
||||||
|
* @exception CPPUNIT_NS::Exception on test failures.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
playBothTest(void) throw (CPPUNIT_NS::Exception);
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up the environment for the test case.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
setUp(void) throw ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean up the environment after the test case.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
tearDown(void) throw ();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* ================================================= external data structures */
|
||||||
|
|
||||||
|
|
||||||
|
/* ====================================================== function prototypes */
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace PlaylistExecutor
|
||||||
|
} // namespace LiveSupport
|
||||||
|
|
||||||
|
#endif // TwoGstreamerPlayersTest_h
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue