/* NMM - Network-Integrated Multimedia Middleware
*
* Copyright ( C ) 2002 - 2006
* NMM work group ,
* Computer Graphics Lab ,
* Saarland University , Germany
* http : //www.networkmultimedia.org
*
* Maintainer : Robert Gogolok < gogo @ graphics . cs . uni - sb . de >
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* This library 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
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Steet , Fifth Floor , Boston , MA 02110 - 1301
* USA
*/
# include "nmm_engine.h"
# include "nmm_kdeconfig.h"
# include "nmm_configdialog.h"
# include "HostListItem.h"
# include "debug.h"
# include "plugin/plugin.h"
# include <nmm/base/graph/GraphBuilder2.hpp>
# include <nmm/base/registry/NodeDescription.hpp>
# include <nmm/base/ProxyApplication.hpp>
# include <nmm/interfaces/base/sync/ISynchronizedSink.hpp>
# include <nmm/interfaces/file/ISeekable.hpp>
# include <nmm/interfaces/file/ITrack.hpp>
# include <nmm/interfaces/file/IBufferSize.hpp>
# include <nmm/interfaces/general/progress/IProgressListener.hpp>
# include <nmm/interfaces/general/progress/IProgress.hpp>
# include <nmm/interfaces/general/ITrackDuration.hpp>
# include <nmm/interfaces/device/audio/IAudioDevice.hpp>
# include <nmm/base/ProxyObject.hpp>
# include <nmm/utils/NMMConfig.hpp>
# include <tqapplication.h>
# include <tqtimer.h>
# include <tdefileitem.h>
# include <tdelocale.h>
# include <tdemessagebox.h>
# include <kmimetype.h>
# include <iostream>
# include <kurl.h>
NmmEngine * NmmEngine : : s_instance ;
AMAROK_EXPORT_PLUGIN ( NmmEngine )
NmmEngine : : NmmEngine ( )
: Engine : : Base ( ) ,
__position ( 0 ) ,
__track_length ( 0 ) ,
__state ( Engine : : Empty ) ,
__app ( NULL ) ,
__endTrack_listener ( this , & NmmEngine : : endTrack ) ,
__syncReset_listener ( this , & NmmEngine : : syncReset ) ,
__setProgress_listener ( this , & NmmEngine : : setProgress ) ,
__trackDuration_listener ( this , & NmmEngine : : trackDuration ) ,
__composite ( NULL ) ,
__playback ( NULL ) ,
__display ( NULL ) ,
__av_sync ( NULL ) ,
__synchronizer ( NULL ) ,
__with_video ( false ) ,
__seeking ( false ) ,
m_localhostonly_errordialog ( false )
{
addPluginProperty ( " HasConfigure " , " true " ) ;
}
bool NmmEngine : : init ( )
{
DEBUG_BLOCK
s_instance = this ;
// disable debug and warning streams
NamedObject : : getGlobalInstance ( ) . setDebugStream ( NULL , NamedObject : : ALL_LEVELS ) ;
NamedObject : : getGlobalInstance ( ) . setWarningStream ( NULL , NamedObject : : ALL_LEVELS ) ;
// create new NMM application object
__app = ProxyApplication : : getApplication ( 0 , 0 ) ;
createEnvironmentHostList ( ) ;
createUserHostList ( ) ;
connect ( this , TQT_SIGNAL ( hostError ( TQString , int ) ) , TQT_SLOT ( notifyHostError ( TQString , int ) ) ) ;
return true ;
}
NmmEngine : : ~ NmmEngine ( )
{
// stop all nodes
stop ( ) ;
// delete application object
if ( __app )
delete __app ;
}
void NmmEngine : : checkSecurity ( )
{
const char * home ( getenv ( " HOME " ) ) ;
NMMConfig nmmconfig ( string ( home ) + string ( " /.nmmrc " ) ) ;
bool readpaths_set = false ;
bool writepaths_set = false ;
string optionvalue ( " " ) ;
nmmconfig . getValue ( " allowedreadpaths " , optionvalue ) ;
if ( ! optionvalue . empty ( ) )
readpaths_set = true ;
optionvalue = " " ;
nmmconfig . getValue ( " allowedwritepaths " , optionvalue ) ;
if ( ! optionvalue . empty ( ) )
writepaths_set = true ;
TQString str ;
str + = " <html><body> " ;
str + = " Your current NMM setup is insecure.<br/><br/> " ;
str + = " The file <b>.nmmrc</b> in your home directory restricts read and write access for NMM to certain paths.<br/><br/> " ;
if ( ! readpaths_set )
str + = " <b>allowedreadpaths option is not set</b>. NMM plugins are therefore allowed to read every file the process running NMM is allowed.<br/> " ;
if ( ! writepaths_set )
str + = " <b>allowedwritepaths option is not set</b>. NMM plugins are therefore allowed to write every file or directory the process running NMM is allowed.<br/> " ;
str + = " <br/>See <a href= \" http://www.networkmultimedia.org/Download/ \" >http://www.networkmultimedia.org/Download/</a> for general security instructions in the correspoding <i>configure and test NMM</i> section depending on your chosen installation method. " ;
str + = " </body></html> " ;
if ( ! writepaths_set | | ! readpaths_set )
KMessageBox : : information ( 0 , str , i18n ( " Insecure NMM setup " ) , " insecureNmmSetup " , KMessageBox : : AllowLink ) ;
}
void NmmEngine : : notifyHostError ( TQString hostname , int error )
{
DEBUG_BLOCK
for ( TQValueList < NmmLocation > : : Iterator it = tmp_user_list . begin ( ) ; it ! = tmp_user_list . end ( ) ; + + it ) {
if ( ( * it ) . hostname ( ) = = hostname ) {
( * it ) . setStatus ( error ) ;
break ;
}
}
for ( TQValueList < NmmLocation > : : Iterator it = tmp_environment_list . begin ( ) ; it ! = tmp_environment_list . end ( ) ; + + it ) {
if ( ( * it ) . hostname ( ) = = hostname ) {
( * it ) . setStatus ( error ) ;
break ;
}
}
}
Engine : : State NmmEngine : : state ( ) const
{
return __state ;
}
Amarok : : PluginConfig * NmmEngine : : configure ( ) const
{
NmmConfigDialog * dialog = new NmmConfigDialog ( ) ;
connect ( this , TQT_SIGNAL ( hostError ( TQString , int ) ) , dialog , TQT_SLOT ( notifyHostError ( TQString , int ) ) ) ;
return dialog ;
}
bool NmmEngine : : load ( const KURL & url , bool stream )
{
DEBUG_BLOCK
static int error ;
error = STATUS_UNKNOWN ;
// check security options
static bool already_checked = false ;
if ( ! already_checked ) {
TQTimer : : singleShot ( 100 , this , TQT_SLOT ( checkSecurity ( ) ) ) ;
already_checked = true ;
}
// Don't play a track if 'localhost only' error dialog is being shown
if ( m_localhostonly_errordialog )
return false ;
// play only local files
if ( ! url . isLocalFile ( ) ) {
debug ( ) < < " Currently NMM engine can only play local files! " < < endl ;
return false ;
}
Engine : : Base : : load ( url , stream ) ;
cleanup ( ) ;
// make the GraphBuilder construct an appropriate graph for the given URL
try {
TQStringList hosts ;
// node for audio playback
NodeDescription playback_nd ( " PlaybackNode " ) ;
// ALSA or OSS
if ( NmmKDEConfig : : audioOutputPlugin ( ) = = " ALSAPlaybackNode " )
playback_nd = NodeDescription ( " ALSAPlaybackNode " ) ;
// TODO: currently we only support one host for audio playback
if ( ! ( hosts = getSinkHosts ( ) ) . empty ( ) )
playback_nd . setLocation ( hosts . first ( ) . ascii ( ) ) ;
// node for video playback
NodeDescription display_nd ( " XDisplayNode " ) ;
// TODO: currently we only support one host for video playback
if ( ! ( hosts = getSinkHosts ( false ) ) . empty ( ) )
display_nd . setLocation ( hosts . first ( ) . ascii ( ) ) ;
GraphBuilder2 gb ;
// convert the URL to a valid NMM url
if ( ! gb . setURL ( " file:// " + string ( url . path ( ) . ascii ( ) ) ) )
throw Exception ( " Invalid URL given " ) ;
ClientRegistry & registry = __app - > getRegistry ( ) ;
// requst playback and audio node {{{
{
//debug() << "##############> ClientRegistry " << endl;
RegistryLock lock ( registry ) ;
// get a playback node interface from the registry
try {
list < Response > playback_response = registry . initRequest ( playback_nd ) ;
if ( playback_response . empty ( ) ) // playback node not available
throw ( NMMEngineException ( playback_nd . getLocation ( ) , NmmEngine : : ERROR_PLAYBACKNODE ) ) ;
__playback = registry . requestNode ( playback_response . front ( ) ) ;
}
catch ( RegistryException ) {
error = NmmEngine : : ERROR_PLAYBACKNODE ;
throw ( NMMEngineException ( playback_nd . getLocation ( ) , NmmEngine : : ERROR_PLAYBACKNODE ) ) ;
}
catch ( . . . ) {
error = NmmEngine : : ERROR_PLAYBACKNODE ;
throw ;
}
// get a display node interface from the registry
try {
list < Response > display_response = registry . initRequest ( display_nd ) ;
if ( display_response . empty ( ) ) // Display Node not available
throw NMMEngineException ( display_nd . getLocation ( ) , NmmEngine : : ERROR_DISPLAYNODE ) ;
__display = registry . requestNode ( display_response . front ( ) ) ;
}
catch ( RegistryException ) {
error = NmmEngine : : ERROR_DISPLAYNODE ;
throw NMMEngineException ( display_nd . getLocation ( ) , NmmEngine : : ERROR_DISPLAYNODE ) ;
}
catch ( . . . ) {
error = NmmEngine : : ERROR_DISPLAYNODE ;
throw ;
}
//debug() << "##############< ClientRegistry " << endl;
} //}}}
__av_sync = new MultiAudioVideoSynchronizer ( ) ;
__synchronizer = __av_sync - > getCheckedInterface < IMultiAudioVideoSynchronizer > ( ) ;
// initialize the GraphBuilder
gb . setMultiAudioVideoSynchronizer ( __synchronizer ) ;
gb . setAudioSink ( __playback ) ;
gb . setVideoSink ( __display ) ;
gb . setDemuxAudioJackTag ( " audio " ) ;
gb . setDemuxVideoJackTag ( " video " ) ;
// create the graph represented by a composite node
__composite = gb . createGraph ( * __app ) ;
// if the display node is connected we know we will play a video TODO: what about video without audio?
__with_video = __display - > isInputConnected ( ) ;
debug ( ) < < " NMM video playback? " < < __with_video < < endl ;
// set volume for playback node
setVolume ( m_volume ) ;
// register the needed event listeners at the display node if video enabled
if ( __with_video ) {
__display - > getParentObject ( ) - > registerEventListener ( ISyncReset : : syncReset_event , & __syncReset_listener ) ;
__display - > getParentObject ( ) - > registerEventListener ( IProgressListener : : setProgress_event , & __setProgress_listener ) ;
__display - > getParentObject ( ) - > registerEventListener ( ITrack : : endTrack_event , & __endTrack_listener ) ;
}
else { // in other case at the playback node
__playback - > getParentObject ( ) - > registerEventListener ( ISyncReset : : syncReset_event , & __syncReset_listener ) ;
__playback - > getParentObject ( ) - > registerEventListener ( IProgressListener : : setProgress_event , & __setProgress_listener ) ;
__playback - > getParentObject ( ) - > registerEventListener ( ITrack : : endTrack_event , & __endTrack_listener ) ;
( __playback - > getParentObject ( ) - > getCheckedInterface < ISynchronizedSink > ( ) ) - > setSynchronized ( false ) ;
}
__playback - > getParentObject ( ) - > registerEventListener ( ITrackDuration : : trackDuration_event , & __trackDuration_listener ) ;
__display - > getParentObject ( ) - > registerEventListener ( ITrackDuration : : trackDuration_event , & __trackDuration_listener ) ;
// Tell the node that implements the IProgress interface to send progress events frequently.
IProgress_var progress ( __composite - > getInterface < IProgress > ( ) ) ;
if ( progress . get ( ) ) {
progress - > sendProgressInformation ( true ) ;
progress - > setProgressInterval ( 1 ) ;
}
// minimize the buffer size to increase the frequency of progress events
IBufferSize_var buffer_size ( __composite - > getInterface < IBufferSize > ( ) ) ;
if ( buffer_size . get ( ) ) {
buffer_size - > setBufferSize ( 1000 ) ;
}
// we don't know the track length yet - we have to wait for the trackDuration event
__track_length = 0 ;
__seeking = false ;
// finally start the graph
if ( __playback - > isActivated ( ) )
__playback - > reachStarted ( ) ;
if ( __display - > isActivated ( ) )
__display - > reachStarted ( ) ;
__composite - > reachStarted ( ) ;
return true ;
}
catch ( const NMMEngineException e ) {
TQString host = e . hostname . c_str ( ) ;
emit hostError ( host , error ) ;
emit statusText ( i18n ( " NMM engine: Stopping playback... " ) ) ;
}
catch ( const Exception & e ) {
cerr < < e < < endl ;
TQString status = e . getComment ( ) . c_str ( ) ;
emit statusText ( TQString ( i18n ( " NMM engine: " ) ) + status ) ;
}
catch ( . . . ) {
emit statusText ( i18n ( " NMM engine: Something went wrong... " ) ) ;
}
// loading failed, clean up
cleanup ( ) ;
// if 'Localhost only' playback, show user an error message
// and explanation how to test current NMM setup
if ( NmmKDEConfig : : location ( ) = = NmmKDEConfig : : EnumLocation : : LocalhostOnly )
{
m_localhostonly_errordialog = true ;
TQString detailed_status = HostListItem : : prettyStatus ( error ) ;
KMessageBox : : detailedError ( 0 , i18n ( " Local NMM playback failed. " ) , detailed_status , i18n ( " Error " ) , KMessageBox : : AllowLink ) ;
m_localhostonly_errordialog = false ;
}
return false ;
}
bool NmmEngine : : play ( uint )
{
DEBUG_BLOCK
if ( ! __composite )
return false ;
// TODO: seek to the last position if 'resume playback on startup' is enabled
__synchronizer - > wakeup ( ) ;
__state = Engine : : Playing ;
emit stateChanged ( Engine : : Playing ) ;
return true ;
}
void NmmEngine : : cleanup ( )
{
DEBUG_BLOCK
// remove all event listeners
if ( __display & & __with_video ) {
__display - > getParentObject ( ) - > removeEventListener ( & __setProgress_listener ) ;
__display - > getParentObject ( ) - > removeEventListener ( & __endTrack_listener ) ;
__display - > getParentObject ( ) - > removeEventListener ( & __syncReset_listener ) ;
if ( __playback )
__playback - > getParentObject ( ) - > removeEventListener ( & __trackDuration_listener ) ;
__display - > getParentObject ( ) - > removeEventListener ( & __trackDuration_listener ) ;
debug ( ) < < " removed event listener for __display " < < endl ;
}
else if ( __playback ) {
__playback - > getParentObject ( ) - > removeEventListener ( & __setProgress_listener ) ;
__playback - > getParentObject ( ) - > removeEventListener ( & __endTrack_listener ) ;
__playback - > getParentObject ( ) - > removeEventListener ( & __syncReset_listener ) ;
__playback - > getParentObject ( ) - > removeEventListener ( & __trackDuration_listener ) ;
if ( __display )
__display - > getParentObject ( ) - > removeEventListener ( & __trackDuration_listener ) ;
debug ( ) < < " removed event listener for __playback " < < endl ;
}
if ( __composite & & __composite - > isStarted ( ) ) {
__composite - > reachActivated ( ) ;
debug ( ) < < " __composite STARTED -> ACTIVATED " < < endl ;
}
if ( __playback & & __playback - > isStarted ( ) ) {
__playback - > reachActivated ( ) ;
debug ( ) < < " __playback STARTED -> ACTIVATED " < < endl ;
}
if ( __display & & __display - > isStarted ( ) ) {
__display - > reachActivated ( ) ;
debug ( ) < < " __display STARTED -> ACTIVATED " < < endl ;
}
if ( __composite & & __composite - > isActivated ( ) ) {
__composite - > flush ( ) ;
__composite - > reachConstructed ( ) ;
debug ( ) < < " __composite ACTIVATED -> CONSTRUCTED " < < endl ;
}
if ( __playback & & __playback - > isActivated ( ) ) {
__playback - > flush ( ) ;
__playback - > reachConstructed ( ) ;
debug ( ) < < " __playback ACTIVATED -> CONSTRUCTED " < < endl ;
}
if ( __display & & __display - > isActivated ( ) ) {
__display - > flush ( ) ;
__display - > reachConstructed ( ) ;
debug ( ) < < " __display ACTIVATED -> CONSTRUCTED " < < endl ;
}
// release the playback and video node
ClientRegistry & registry = __app - > getRegistry ( ) ;
{
RegistryLock lock ( registry ) ;
if ( __playback ) {
registry . releaseNode ( * __playback ) ;
debug ( ) < < " RELEASED __playback node " < < endl ;
}
if ( __display ) {
registry . releaseNode ( * __display ) ;
debug ( ) < < " RELEASED __display node " < < endl ;
}
}
delete __composite ;
__composite = NULL ;
delete __playback ;
__playback = NULL ;
delete __display ;
__display = NULL ;
__with_video = false ;
delete __synchronizer ;
__synchronizer = NULL ;
delete __av_sync ;
__av_sync = NULL ;
__position = 0 ;
__state = Engine : : Idle ;
}
void NmmEngine : : createEnvironmentHostList ( )
{
TQString hosts = getenv ( " AUDIO_HOSTS " ) ;
TQStringList list = TQStringList : : split ( " : " , hosts ) ;
/* merge audio hosts */
for ( TQStringList : : Iterator it = list . begin ( ) ; it ! = list . end ( ) ; + + it ) {
tmp_environment_list . append ( NmmLocation ( ( * it ) , true , false , 0 , NmmEngine : : STATUS_UNKNOWN ) ) ;
}
/* merge video hosts */
hosts = getenv ( " VIDEO_HOSTS " ) ;
list = TQStringList : : split ( " : " , hosts ) ;
bool found = false ;
for ( TQStringList : : Iterator it = list . begin ( ) ; it ! = list . end ( ) ; + + it ) {
found = false ;
for ( TQValueList < NmmLocation > : : Iterator it_t = tmp_environment_list . begin ( ) ; it_t ! = tmp_environment_list . end ( ) ; + + it_t ) {
if ( ( * it_t ) . hostname ( ) = = * it ) {
( * it_t ) . setVideo ( true ) ;
found = true ;
break ;
}
}
if ( ! found )
tmp_environment_list . append ( NmmLocation ( ( * it ) , false , true , 0 , NmmEngine : : STATUS_UNKNOWN ) ) ;
}
//debug() << "### ENVIRONMENT" << endl;
//for( TQValueList<NmmLocation>::Iterator it = tmp_environment_list.begin(); it != tmp_environment_list.end(); ++it ) {
//debug() << "### hostname " << (*it).hostname() << endl;
//debug() << "### audio " << (*it).audio() << endl;
//debug() << "### video " << (*it).video() << endl;
//debug() << "#########################" << endl;
//}
}
void NmmEngine : : createUserHostList ( )
{
TQStringList hosts = NmmKDEConfig : : hostList ( ) ;
TQStringList audio_list = NmmKDEConfig : : audioToggle ( ) ;
TQStringList video_list = NmmKDEConfig : : videoToggle ( ) ;
bool audio = false ;
bool video = false ;
unsigned int size = hosts . size ( ) ;
for ( unsigned int i = 0 ; i < size ; i + + ) {
if ( audio_list [ i ] = = " 1 " )
audio = true ;
else
audio = false ;
if ( video_list [ i ] = = " 1 " )
video = true ;
else
video = false ;
tmp_user_list . append ( NmmLocation ( hosts [ i ] , audio , video , /* TODO: volume */ 0 , NmmEngine : : STATUS_UNKNOWN ) ) ;
}
}
void NmmEngine : : stop ( )
{
DEBUG_BLOCK
cleanup ( ) ;
__state = Engine : : Empty ;
emit stateChanged ( Engine : : Empty ) ;
}
void NmmEngine : : pause ( )
{
if ( ! __composite )
return ;
debug ( ) < < " pause() " < < endl ;
if ( __state = = Engine : : Playing ) {
__synchronizer - > pause ( ) ;
__state = Engine : : Paused ;
emit stateChanged ( Engine : : Paused ) ;
}
else if ( __state = = Engine : : Paused ) {
__synchronizer - > wakeup ( ) ;
__state = Engine : : Playing ;
emit stateChanged ( Engine : : Playing ) ;
}
}
void NmmEngine : : seek ( uint ms )
{
if ( ! __track_length )
return ;
__seeking = true ;
__position = ms ;
ISeekable_var seek ( __composite - > getCheckedInterface < ISeekable > ( ) ) ;
if ( seek . get ( ) )
seek - > seekPercentTo ( Rational ( ms , __track_length ) ) ;
}
void NmmEngine : : endOfStreamReached ( )
{
DEBUG_BLOCK
emit trackEnded ( ) ;
}
uint NmmEngine : : position ( ) const
{
return __position ;
}
uint NmmEngine : : length ( ) const
{
return __track_length ;
}
bool NmmEngine : : canDecode ( const KURL & url ) const
{
static TQStringList types ;
if ( url . protocol ( ) = = " http " ) return false ;
// the following MIME types can be decoded
types + = TQString ( " audio/x-mp3 " ) ;
types + = TQString ( " audio/x-wav " ) ;
types + = TQString ( " audio/ac3 " ) ;
types + = TQString ( " audio/vorbis " ) ;
types + = TQString ( " video/mpeg " ) ;
types + = TQString ( " video/x-msvideo " ) ;
types + = TQString ( " video/x-ogm " ) ;
KFileItem fileItem ( KFileItem : : Unknown , KFileItem : : Unknown , url , false ) ; //false = determineMimeType straight away
KMimeType : : Ptr mimetype = fileItem . determineMimeType ( ) ;
return types . contains ( mimetype - > name ( ) ) ;
}
void NmmEngine : : setVolumeSW ( uint percent )
{
if ( __playback )
{
IAudioDevice_var audio ( __playback - > getParentObject ( ) - > getCheckedInterface < IAudioDevice > ( ) ) ;
audio - > setVolume ( percent ) ;
}
}
TQStringList NmmEngine : : getSinkHosts ( bool audio )
{
TQStringList hosts ;
// TODO: redundant code...
// read locations from environment variable
if ( NmmKDEConfig : : location ( ) = = NmmKDEConfig : : EnumLocation : : EnvironmentVariable )
{
for ( TQValueList < NmmLocation > : : Iterator it = tmp_environment_list . begin ( ) ; it ! = tmp_environment_list . end ( ) ; + + it ) {
if ( audio & & ( * it ) . audio ( ) )
hosts . append ( ( * it ) . hostname ( ) ) ;
else if ( ! audio & & ( * it ) . video ( ) )
hosts . append ( ( * it ) . hostname ( ) ) ;
}
//debug() << "locations from environment variable are => " << hosts << endl;
return hosts ;
}
// read locations from host list
else if ( NmmKDEConfig : : location ( ) = = NmmKDEConfig : : EnumLocation : : HostList )
{
for ( TQValueList < NmmLocation > : : Iterator it = tmp_user_list . begin ( ) ; it ! = tmp_user_list . end ( ) ; + + it ) {
if ( audio & & ( * it ) . audio ( ) )
hosts . append ( ( * it ) . hostname ( ) ) ;
else if ( ! audio & & ( * it ) . video ( ) )
hosts . append ( ( * it ) . hostname ( ) ) ;
}
return hosts ;
}
// localhost only
return hosts ;
}
Result NmmEngine : : setProgress ( u_int64_t & numerator , u_int64_t & denominator )
{
// compute the track position in milliseconds
u_int64_t position = numerator * __track_length / denominator ;
if ( __seeking )
return SUCCESS ;
__position = position ;
return SUCCESS ;
}
Result NmmEngine : : endTrack ( )
{
__state = Engine : : Idle ;
__position = 0 ;
// cleanup after this method returned
TQTimer : : singleShot ( 0 , instance ( ) , TQT_SLOT ( endOfStreamReached ( ) ) ) ;
return SUCCESS ;
}
Result NmmEngine : : syncReset ( )
{
__seeking = false ;
return SUCCESS ;
}
Result NmmEngine : : trackDuration ( Interval & duration )
{
// we got the duration of the track, so let's convert it to milliseconds
__track_length = duration . sec * 1000 + duration . nsec / 1000 ;
kdDebug ( ) < < " NmmEngine::trackDuration " < < __track_length < < endl ;
return SUCCESS ;
}
# include "nmm_engine.moc"