1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: soundhandler.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 //_________________________________________________________________________________________________________________
33 //_________________________________________________________________________________________________________________
35 #ifndef __FRAMEWORK_DISPATCH_SOUNDHANDLER_HXX_
36 #include "soundhandler.hxx"
39 #ifndef __COMPHELPER_MEDIADESCRIPTOR_HXX_
40 #include <comphelper/mediadescriptor.hxx>
43 //_________________________________________________________________________________________________________________
45 //_________________________________________________________________________________________________________________
46 #include <com/sun/star/io/XInputStream.hpp>
47 #include <com/sun/star/frame/DispatchResultState.hpp>
49 //_________________________________________________________________________________________________________________
50 // includes of other projects
51 //_________________________________________________________________________________________________________________
52 #include <comphelper/sequenceashashmap.hxx>
53 #include <rtl/ustrbuf.hxx>
55 #include <cppuhelper/typeprovider.hxx>
56 #include <cppuhelper/factory.hxx>
58 //_________________________________________________________________________________________________________________
60 //_________________________________________________________________________________________________________________
64 //_________________________________________________________________________________________________________________
66 //_________________________________________________________________________________________________________________
68 //_________________________________________________________________________________________________________________
69 // non exported definitions
70 //_________________________________________________________________________________________________________________
72 //_________________________________________________________________________________________________________________
74 //_________________________________________________________________________________________________________________
76 //*****************************************************************************************************************
77 // XInterface, XTypeProvider, XServiceInfo
78 //*****************************************************************************************************************
80 void SAL_CALL
SoundHandler::acquire() throw()
82 /* Don't use mutex in methods of XInterface! */
83 OWeakObject::acquire();
86 void SAL_CALL
SoundHandler::release() throw()
88 /* Don't use mutex in methods of XInterface! */
89 OWeakObject::release();
92 css::uno::Any SAL_CALL
SoundHandler::queryInterface( const css::uno::Type
& aType
) throw( css::uno::RuntimeException
)
94 /* Attention: Don't use mutex or guard in this method!!! Is a method of XInterface. */
95 /* Ask for my own supported interfaces ...*/
96 css::uno::Any
aReturn( ::cppu::queryInterface( aType
,
97 static_cast< css::lang::XTypeProvider
* >(this),
98 static_cast< css::lang::XServiceInfo
* >(this),
99 static_cast< css::frame::XNotifyingDispatch
* >(this),
100 static_cast< css::frame::XDispatch
* >(this),
101 static_cast< css::document::XExtendedFilterDetection
* >(this)));
102 /* If searched interface not supported by this class ... */
103 if ( aReturn
.hasValue() == sal_False
)
105 /* ... ask baseclass for interfaces! */
106 aReturn
= OWeakObject::queryInterface( aType
);
108 /* Return result of this search. */
112 css::uno::Sequence
< sal_Int8
> SAL_CALL
SoundHandler::getImplementationId() throw( css::uno::RuntimeException
)
114 /* Create one Id for all instances of this class. */
115 /* Use ethernet address to do this! (sal_True) */
116 /* Optimize this method */
117 /* We initialize a static variable only one time. And we don't must use a mutex at every call! */
118 /* For the first call; pID is NULL - for the second call pID is different from NULL! */
119 static ::cppu::OImplementationId
* pID
= NULL
;
122 /* Ready for multithreading; get global mutex for first call of this method only! see before */
123 ::osl::MutexGuard
aGuard( ::osl::Mutex::getGlobalMutex() );
124 /* Control these pointer again ... it can be, that another instance will be faster then these! */
127 /* Create a new static ID ... */
128 static ::cppu::OImplementationId
aID( sal_False
);
129 /* ... and set his address to static pointer! */
133 return pID
->getImplementationId();
136 css::uno::Sequence
< css::uno::Type
> SAL_CALL
SoundHandler::getTypes() throw( css::uno::RuntimeException
)
138 /* Optimize this method ! */
139 /* We initialize a static variable only one time. */
140 /* And we don't must use a mutex at every call! */
141 /* For the first call; pTypeCollection is NULL - */
142 /* for the second call pTypeCollection is different from NULL! */
143 static ::cppu::OTypeCollection
* pTypeCollection
= NULL
;
144 if ( pTypeCollection
== NULL
)
146 /* Ready for multithreading; get global mutex for first call of this method only! see before */
147 ::osl::MutexGuard
aGuard( ::osl::Mutex::getGlobalMutex() );
148 /* Control these pointer again ... it can be, that another instance will be faster then these! */
149 if ( pTypeCollection
== NULL
)
151 /* Create a static typecollection ... */
152 static ::cppu::OTypeCollection aTypeCollection
154 ::getCppuType(( const ::com::sun::star::uno::Reference
< css::lang::XTypeProvider
>*)NULL
),
155 ::getCppuType(( const ::com::sun::star::uno::Reference
< css::lang::XServiceInfo
>*)NULL
),
156 ::getCppuType(( const ::com::sun::star::uno::Reference
< css::frame::XNotifyingDispatch
>*)NULL
),
157 ::getCppuType(( const ::com::sun::star::uno::Reference
< css::frame::XDispatch
>*)NULL
),
158 ::getCppuType(( const ::com::sun::star::uno::Reference
< css::document::XExtendedFilterDetection
>*)NULL
)
160 /* ... and set his address to static pointer! */
161 pTypeCollection
= &aTypeCollection
;
164 return pTypeCollection
->getTypes();
167 #define DECLARE_ASCII( SASCIIVALUE ) \
168 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SASCIIVALUE ) )
170 #define IMPLEMENTATIONNAME_SOUNDHANDLER DECLARE_ASCII("com.sun.star.comp.framework.SoundHandler")
171 #define SERVICENAME_CONTENTHANDLER DECLARE_ASCII("com.sun.star.frame.ContentHandler")
173 /*===========================================================================================================*/
175 /*===========================================================================================================*/
176 ::rtl::OUString SAL_CALL
SoundHandler::getImplementationName() throw( css::uno::RuntimeException
)
178 return impl_getStaticImplementationName();
181 /*===========================================================================================================*/
183 /*===========================================================================================================*/
184 sal_Bool SAL_CALL
SoundHandler::supportsService( const ::rtl::OUString
& sServiceName
) throw( css::uno::RuntimeException
)
186 /* Set default return value. */
187 sal_Bool bReturn
= sal_False
;
188 /* Get names of all supported servicenames. */
189 css::uno::Sequence
< ::rtl::OUString
> seqServiceNames
= getSupportedServiceNames();
190 const ::rtl::OUString
* pArray
= seqServiceNames
.getConstArray();
191 sal_Int32 nCounter
= 0;
192 sal_Int32 nLength
= seqServiceNames
.getLength();
193 /* Search for right name in list. */
195 ( nCounter
< nLength
) &&
196 ( bReturn
== sal_False
)
199 /* Is name was found, say "YES, SERVICE IS SUPPORTED." and break loop. */
200 if ( pArray
[nCounter
] == sServiceName
)
204 /* Else step to next element in list. */
207 /* Return state of search. */
211 /*===========================================================================================================*/
213 /*===========================================================================================================*/
214 css::uno::Sequence
< ::rtl::OUString
> SAL_CALL
SoundHandler::getSupportedServiceNames() throw( css::uno::RuntimeException
)
216 return impl_getStaticSupportedServiceNames();
219 /*===========================================================================================================*/
220 /* Helper for XServiceInfo */
221 /*===========================================================================================================*/
222 css::uno::Sequence
< ::rtl::OUString
> SoundHandler::impl_getStaticSupportedServiceNames()
224 css::uno::Sequence
< ::rtl::OUString
> seqServiceNames( 1 );
225 seqServiceNames
.getArray() [0] = SERVICENAME_CONTENTHANDLER
;
226 return seqServiceNames
;
229 /*===========================================================================================================*/
230 /* Helper for XServiceInfo */
231 /*===========================================================================================================*/
232 ::rtl::OUString
SoundHandler::impl_getStaticImplementationName()
234 return IMPLEMENTATIONNAME_SOUNDHANDLER
;
237 css::uno::Reference
< css::uno::XInterface
> SAL_CALL
SoundHandler::impl_createInstance( const css::uno::Reference
< css::lang::XMultiServiceFactory
>& xServiceManager
) throw( css::uno::Exception
)
239 /* create new instance of service */
240 SoundHandler
* pClass
= new SoundHandler( xServiceManager
);
241 /* hold it alive by increasing his ref count!!! */
242 css::uno::Reference
< css::uno::XInterface
> xService( static_cast< ::cppu::OWeakObject
* >(pClass
), css::uno::UNO_QUERY
);
243 /* initialize new service instance ... he can use his own refcount ... we hold it! */
244 pClass
->impl_initService();
245 /* return new created service as reference */
249 css::uno::Reference
< css::lang::XSingleServiceFactory
> SoundHandler::impl_createFactory( const css::uno::Reference
< css::lang::XMultiServiceFactory
>& xServiceManager
)
251 css::uno::Reference
< css::lang::XSingleServiceFactory
> xReturn ( cppu::createSingleFactory (
253 SoundHandler::impl_getStaticImplementationName(),
254 SoundHandler::impl_createInstance
,
255 SoundHandler::impl_getStaticSupportedServiceNames()
261 void SAL_CALL
SoundHandler::impl_initService()
266 /*-************************************************************************************************************//**
268 @descr These initialize a new instance of this class with needed informations for work.
270 @seealso using at owner
272 @param "xFactory", reference to service manager for creation of new services
275 @onerror Show an assertion and do nothing else.
277 *//*-*************************************************************************************************************/
278 SoundHandler::SoundHandler( const css::uno::Reference
< css::lang::XMultiServiceFactory
>& xFactory
)
279 // Init baseclasses first
281 , ::cppu::OWeakObject ( )
284 , m_xFactory ( xFactory
)
286 m_aUpdateTimer
.SetTimeoutHdl(LINK(this, SoundHandler
, implts_PlayerNotify
));
289 /*-************************************************************************************************************//**
300 *//*-*************************************************************************************************************/
301 SoundHandler::~SoundHandler()
303 if (m_xListener
.is())
305 css::frame::DispatchResultEvent aEvent
;
306 aEvent
.State
= css::frame::DispatchResultState::FAILURE
;
307 m_xListener
->dispatchFinished(aEvent
);
308 m_xListener
= css::uno::Reference
< css::frame::XDispatchResultListener
>();
312 /*-************************************************************************************************************//**
313 @interface ::com::sun::star::frame::XDispatch
315 @short try to load audio file
316 @descr This method try to load given audio file by URL and play it. We use vcl/Sound class to do that.
317 Playing of sound is asynchron everytime.
319 @attention We must hold us alive by ourself ... because we use async. vcl sound player ... but playing is started
320 in async interface call "dispatch()" too. And caller forget us imediatly. But then our uno ref count
321 will decreased to 0 and will die. The only solution is to use own reference to our implementation.
322 But we do it for realy started jobs only and release it during call back of vcl.
324 @seealso class vcl/Sound
325 @seealso method implts_PlayerNotify()
327 @param "aURL" , URL to dispatch.
328 @param "lArguments", list of optional arguments.
331 @onerror We do nothing.
333 *//*-*************************************************************************************************************/
334 void SAL_CALL
SoundHandler::dispatchWithNotification(const css::util::URL
& aURL
,
335 const css::uno::Sequence
< css::beans::PropertyValue
>& lDescriptor
,
336 const css::uno::Reference
< css::frame::XDispatchResultListener
>& xListener
) throw(css::uno::RuntimeException
)
339 const ::vos::OGuard
aLock( m_aLock
);
342 //close streams otherwise on windows we can't reopen the file in the
343 //media player when we pass the url to directx as it'll already be open
344 ::comphelper::MediaDescriptor
aDescriptor(lDescriptor
);
346 css::uno::Reference
< css::io::XInputStream
> xInputStream
=
347 aDescriptor
.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_INPUTSTREAM(),
348 css::uno::Reference
< css::io::XInputStream
>());
349 if (xInputStream
.is()) xInputStream
->closeInput();
352 // If player currently used for other dispatch() requests ...
353 // cancel it by calling stop()!
354 m_aUpdateTimer
.Stop();
357 if (m_xPlayer
->isPlaying())
362 // Try to initialize player.
363 m_xListener
= xListener
;
367 m_xPlayer
.set( avmedia::MediaWindow::createPlayer( aURL
.Complete
), css::uno::UNO_QUERY_THROW
);
368 // OK- we can start async playing ...
369 // Count this request and initialize self-holder against dieing by uno ref count ...
370 m_xSelfHold
= css::uno::Reference
< css::uno::XInterface
>(static_cast< ::cppu::OWeakObject
* >(this), css::uno::UNO_QUERY
);
372 m_aUpdateTimer
.SetTimeout( 200 );
373 m_aUpdateTimer
.Start();
375 catch( css::uno::Exception
& e
)
385 void SAL_CALL
SoundHandler::dispatch( const css::util::URL
& aURL
,
386 const css::uno::Sequence
< css::beans::PropertyValue
>& lArguments
) throw( css::uno::RuntimeException
)
388 dispatchWithNotification(aURL
, lArguments
, css::uno::Reference
< css::frame::XDispatchResultListener
>());
391 /*-************************************************************************************************************//**
392 @interface ::com::sun::star::document::XExtendedFilterDetection
394 @short try to detect file (given as argument included in "lDescriptor")
395 @descr We try to detect, if given file could be handled by this class and is a well known one.
396 If it is - we return right internal type name - otherwise we return nothing!
397 So call can search for another detect service and ask him too.
399 @attention a) We don't need any mutex here ... because we don't use any member!
400 b) Dont' use internal player instance "m_pPlayer" to detect given sound file!
401 It's not neccessary to do that ... and we can use temp. variable to do the same.
402 This way is easy - we don't must synchronize it with currently played sounds!
403 Another reason to do so ... We are a listener on our internal ma_Player object.
404 If you would call "IsSoundFile()" on this instance, he would call us back and
405 we make some uneccssary things ...
409 @param "lDescriptor", description of file to detect
410 @return Internal type name which match this file ... or nothing if it is unknown.
412 @onerror We return nothing.
414 *//*-*************************************************************************************************************/
415 ::rtl::OUString SAL_CALL
SoundHandler::detect( css::uno::Sequence
< css::beans::PropertyValue
>& lDescriptor
) throw( css::uno::RuntimeException
)
417 // Our default is "nothing". So we can return it, if detection failed or fily type is realy unknown.
418 ::rtl::OUString sTypeName
;
420 // Analyze given descriptor to find filename or input stream or ...
421 ::comphelper::MediaDescriptor
aDescriptor(lDescriptor
);
422 ::rtl::OUString sURL
= aDescriptor
.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_URL(), ::rtl::OUString());
425 (sURL
.getLength() ) &&
426 (avmedia::MediaWindow::isMediaURL(sURL
))
429 // If the file type is supported depends on the OS, so...
430 // I think we can the following ones:
431 // a) look for given extension of url to map our type decision HARD CODED!!!
432 // b) return preferred type every time... it's easy :-)
433 sTypeName
= ::rtl::OUString::createFromAscii("wav_Wave_Audio_File");
434 aDescriptor
[::comphelper::MediaDescriptor::PROP_TYPENAME()] <<= sTypeName
;
435 aDescriptor
>> lDescriptor
;
438 // Return our decision.
442 /*-************************************************************************************************************//**
443 @short call back of sound player
444 @descr Our player call us back to give us some informations.
445 We use this informations to callback our might existing listener.
447 @seealso method dispatchWithNotification()
450 @return 0 everytime ... it doesnt matter for us.
454 *//*-*************************************************************************************************************/
455 IMPL_LINK( SoundHandler
, implts_PlayerNotify
, void*, EMPTYARG
)
458 ::vos::OClearableGuard
aLock( m_aLock
);
460 if (m_xPlayer
.is() && m_xPlayer
->isPlaying() && m_xPlayer
->getMediaTime() < m_xPlayer
->getDuration())
462 m_aUpdateTimer
.Start();
467 // We use m_xSelfHold to let us die ... but we must live till real finishing of this method too!!!
468 // So we SHOULD use another "self-holder" temp. to provide that ...
469 css::uno::Reference
< css::uno::XInterface
> xOperationHold
= m_xSelfHold
;
470 m_xSelfHold
= css::uno::Reference
< css::uno::XInterface
>();
472 // notify might existing listener
473 // And forget this listener!
474 // Because the corresponding dispatch was finished.
475 if (m_xListener
.is())
477 css::frame::DispatchResultEvent aEvent
;
479 aEvent
.State
= css::frame::DispatchResultState::SUCCESS
;
481 aEvent
.State
= css::frame::DispatchResultState::FAILURE
;
482 m_xListener
->dispatchFinished(aEvent
);
483 m_xListener
= css::uno::Reference
< css::frame::XDispatchResultListener
>();
487 //release aLock before end of method at which point xOperationHold goes out of scope and pThis dies
492 } // namespace framework
494 // ------------------------------------------
495 // - component_getImplementationEnvironment -
496 // ------------------------------------------
498 extern "C" void SAL_CALL
component_getImplementationEnvironment( const sal_Char
** ppEnvTypeName
, uno_Environment
** /*ppEnv*/ )
500 *ppEnvTypeName
= CPPU_CURRENT_LANGUAGE_BINDING_NAME
;
503 // -----------------------
504 // - component_writeInfo -
505 // -----------------------
507 extern "C" sal_Bool SAL_CALL
component_writeInfo( void* /*pServiceManager*/, void* pRegistryKey
)
509 sal_Bool bRet
= sal_False
;
515 rtl::OUString sKeyName
= DECLARE_ASCII( "/" );
516 sKeyName
+= avmedia::SoundHandler::impl_getStaticImplementationName();
517 sKeyName
+= DECLARE_ASCII( "/UNO/SERVICES" );
518 css::uno::Reference
< css::registry::XRegistryKey
> xNewKey(
519 static_cast< css::registry::XRegistryKey
* >( pRegistryKey
)->createKey(sKeyName
));
521 if ( xNewKey
.is() == sal_True
)
523 css::uno::Sequence
< ::rtl::OUString
> seqServiceNames
= avmedia::SoundHandler::impl_getStaticSupportedServiceNames();
524 const ::rtl::OUString
* pArray
= seqServiceNames
.getArray();
525 sal_Int32 nLength
= seqServiceNames
.getLength();
526 for ( sal_Int32 nCounter
= 0; nCounter
< nLength
; ++nCounter
)
527 xNewKey
->createKey( pArray
[nCounter
] );
532 catch( css::registry::InvalidRegistryException
& )
534 OSL_ENSURE( sal_False
, "### InvalidRegistryException!" );
541 // ------------------------
542 // - component_getFactory -
543 // ------------------------
545 extern "C" void* SAL_CALL
component_getFactory(const sal_Char
* pImplementationName
, void* pServiceManager
, void* /*pRegistryKey*/ )
547 void* pReturn
= NULL
;
548 if (pServiceManager
!= NULL
)
550 /* Define variables which are used in following macros. */
551 css::uno::Reference
< ::com::sun::star::lang::XSingleServiceFactory
> xFactory
;
552 css::uno::Reference
< ::com::sun::star::lang::XMultiServiceFactory
> xServiceManager
;
553 xServiceManager
= reinterpret_cast< ::com::sun::star::lang::XMultiServiceFactory
* >( pServiceManager
) ;
555 if ( avmedia::SoundHandler::impl_getStaticImplementationName().equals( ::rtl::OUString::createFromAscii( pImplementationName
) ) )
556 xFactory
= avmedia::SoundHandler::impl_createFactory( xServiceManager
);
558 if ( xFactory
.is() == sal_True
)
561 pReturn
= xFactory
.get();
564 /* Return with result of this operation. */