1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 //_________________________________________________________________________________________________________________
25 // my own includes
26 //_________________________________________________________________________________________________________________
27
28 #ifndef __FRAMEWORK_DISPATCH_SOUNDHANDLER_HXX_
29 #include "soundhandler.hxx"
30 #endif
31
32 #ifndef __COMPHELPER_MEDIADESCRIPTOR_HXX_
33 #include <comphelper/mediadescriptor.hxx>
34 #endif
35
36 //_________________________________________________________________________________________________________________
37 // interface includes
38 //_________________________________________________________________________________________________________________
39 #include <com/sun/star/io/XInputStream.hpp>
40 #include <com/sun/star/frame/DispatchResultState.hpp>
41
42 //_________________________________________________________________________________________________________________
43 // includes of other projects
44 //_________________________________________________________________________________________________________________
45 #include <comphelper/sequenceashashmap.hxx>
46 #include <rtl/ustrbuf.hxx>
47
48 #include <cppuhelper/typeprovider.hxx>
49 #include <cppuhelper/factory.hxx>
50
51 //_________________________________________________________________________________________________________________
52 // namespace
53 //_________________________________________________________________________________________________________________
54
55 namespace avmedia{
56
57 //_________________________________________________________________________________________________________________
58 // non exported const
59 //_________________________________________________________________________________________________________________
60
61 //_________________________________________________________________________________________________________________
62 // non exported definitions
63 //_________________________________________________________________________________________________________________
64
65 //_________________________________________________________________________________________________________________
66 // declarations
67 //_________________________________________________________________________________________________________________
68
69 //*****************************************************************************************************************
70 // XInterface, XTypeProvider, XServiceInfo
71 //*****************************************************************************************************************
72
acquire()73 void SAL_CALL SoundHandler::acquire() throw()
74 {
75 /* Don't use mutex in methods of XInterface! */
76 OWeakObject::acquire();
77 }
78
release()79 void SAL_CALL SoundHandler::release() throw()
80 {
81 /* Don't use mutex in methods of XInterface! */
82 OWeakObject::release();
83 }
84
queryInterface(const css::uno::Type & aType)85 css::uno::Any SAL_CALL SoundHandler::queryInterface( const css::uno::Type& aType ) throw( css::uno::RuntimeException )
86 {
87 /* Attention: Don't use mutex or guard in this method!!! Is a method of XInterface. */
88 /* Ask for my own supported interfaces ...*/
89 css::uno::Any aReturn( ::cppu::queryInterface( aType,
90 static_cast< css::lang::XTypeProvider* >(this),
91 static_cast< css::lang::XServiceInfo* >(this),
92 static_cast< css::frame::XNotifyingDispatch* >(this),
93 static_cast< css::frame::XDispatch* >(this),
94 static_cast< css::document::XExtendedFilterDetection* >(this)));
95 /* If searched interface not supported by this class ... */
96 if ( aReturn.hasValue() == sal_False )
97 {
98 /* ... ask baseclass for interfaces! */
99 aReturn = OWeakObject::queryInterface( aType );
100 }
101 /* Return result of this search. */
102 return aReturn;
103 }
104
getImplementationId()105 css::uno::Sequence< sal_Int8 > SAL_CALL SoundHandler::getImplementationId() throw( css::uno::RuntimeException )
106 {
107 /* Create one Id for all instances of this class. */
108 /* Use ethernet address to do this! (sal_True) */
109 /* Optimize this method */
110 /* We initialize a static variable only one time. And we don't must use a mutex at every call! */
111 /* For the first call; pID is NULL - for the second call pID is different from NULL! */
112 static ::cppu::OImplementationId* pID = NULL ;
113 if ( pID == NULL )
114 {
115 /* Ready for multithreading; get global mutex for first call of this method only! see before */
116 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
117 /* Control these pointer again ... it can be, that another instance will be faster then these! */
118 if ( pID == NULL )
119 {
120 /* Create a new static ID ... */
121 static ::cppu::OImplementationId aID( sal_False );
122 /* ... and set his address to static pointer! */
123 pID = &aID ;
124 }
125 }
126 return pID->getImplementationId();
127 }
128
getTypes()129 css::uno::Sequence< css::uno::Type > SAL_CALL SoundHandler::getTypes() throw( css::uno::RuntimeException )
130 {
131 /* Optimize this method ! */
132 /* We initialize a static variable only one time. */
133 /* And we don't must use a mutex at every call! */
134 /* For the first call; pTypeCollection is NULL - */
135 /* for the second call pTypeCollection is different from NULL! */
136 static ::cppu::OTypeCollection* pTypeCollection = NULL ;
137 if ( pTypeCollection == NULL )
138 {
139 /* Ready for multithreading; get global mutex for first call of this method only! see before */
140 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
141 /* Control these pointer again ... it can be, that another instance will be faster then these! */
142 if ( pTypeCollection == NULL )
143 {
144 /* Create a static typecollection ... */
145 static ::cppu::OTypeCollection aTypeCollection
146 (
147 ::getCppuType(( const ::com::sun::star::uno::Reference< css::lang::XTypeProvider >*)NULL ),
148 ::getCppuType(( const ::com::sun::star::uno::Reference< css::lang::XServiceInfo >*)NULL ),
149 ::getCppuType(( const ::com::sun::star::uno::Reference< css::frame::XNotifyingDispatch >*)NULL ),
150 ::getCppuType(( const ::com::sun::star::uno::Reference< css::frame::XDispatch >*)NULL ),
151 ::getCppuType(( const ::com::sun::star::uno::Reference< css::document::XExtendedFilterDetection >*)NULL )
152 );
153 /* ... and set his address to static pointer! */
154 pTypeCollection = &aTypeCollection ;
155 }
156 }
157 return pTypeCollection->getTypes();
158 }
159
160 #define DECLARE_ASCII( SASCIIVALUE ) \
161 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SASCIIVALUE ) )
162
163 #define IMPLEMENTATIONNAME_SOUNDHANDLER DECLARE_ASCII("com.sun.star.comp.framework.SoundHandler")
164 #define SERVICENAME_CONTENTHANDLER DECLARE_ASCII("com.sun.star.frame.ContentHandler")
165
166 /*===========================================================================================================*/
167 /* XServiceInfo */
168 /*===========================================================================================================*/
getImplementationName()169 ::rtl::OUString SAL_CALL SoundHandler::getImplementationName() throw( css::uno::RuntimeException )
170 {
171 return impl_getStaticImplementationName();
172 }
173
174 /*===========================================================================================================*/
175 /* XServiceInfo */
176 /*===========================================================================================================*/
supportsService(const::rtl::OUString & sServiceName)177 sal_Bool SAL_CALL SoundHandler::supportsService( const ::rtl::OUString& sServiceName ) throw( css::uno::RuntimeException )
178 {
179 /* Set default return value. */
180 sal_Bool bReturn = sal_False ;
181 /* Get names of all supported servicenames. */
182 css::uno::Sequence< ::rtl::OUString > seqServiceNames = getSupportedServiceNames();
183 const ::rtl::OUString* pArray = seqServiceNames.getConstArray();
184 sal_Int32 nCounter = 0;
185 sal_Int32 nLength = seqServiceNames.getLength();
186 /* Search for right name in list. */
187 while (
188 ( nCounter < nLength ) &&
189 ( bReturn == sal_False )
190 )
191 {
192 /* Is name was found, say "YES, SERVICE IS SUPPORTED." and break loop. */
193 if ( pArray[nCounter] == sServiceName )
194 {
195 bReturn = sal_True ;
196 }
197 /* Else step to next element in list. */
198 ++nCounter;
199 }
200 /* Return state of search. */
201 return bReturn;
202 }
203
204 /*===========================================================================================================*/
205 /* XServiceInfo */
206 /*===========================================================================================================*/
getSupportedServiceNames()207 css::uno::Sequence< ::rtl::OUString > SAL_CALL SoundHandler::getSupportedServiceNames() throw( css::uno::RuntimeException )
208 {
209 return impl_getStaticSupportedServiceNames();
210 }
211
212 /*===========================================================================================================*/
213 /* Helper for XServiceInfo */
214 /*===========================================================================================================*/
impl_getStaticSupportedServiceNames()215 css::uno::Sequence< ::rtl::OUString > SoundHandler::impl_getStaticSupportedServiceNames()
216 {
217 css::uno::Sequence< ::rtl::OUString > seqServiceNames( 1 );
218 seqServiceNames.getArray() [0] = SERVICENAME_CONTENTHANDLER;
219 return seqServiceNames;
220 }
221
222 /*===========================================================================================================*/
223 /* Helper for XServiceInfo */
224 /*===========================================================================================================*/
impl_getStaticImplementationName()225 ::rtl::OUString SoundHandler::impl_getStaticImplementationName()
226 {
227 return IMPLEMENTATIONNAME_SOUNDHANDLER;
228 }
229
impl_createInstance(const css::uno::Reference<css::lang::XMultiServiceFactory> & xServiceManager)230 css::uno::Reference< css::uno::XInterface > SAL_CALL SoundHandler::impl_createInstance( const css::uno::Reference< css::lang::XMultiServiceFactory >& xServiceManager ) throw( css::uno::Exception )
231 {
232 /* create new instance of service */
233 SoundHandler* pClass = new SoundHandler( xServiceManager );
234 /* hold it alive by increasing his ref count!!! */
235 css::uno::Reference< css::uno::XInterface > xService( static_cast< ::cppu::OWeakObject* >(pClass), css::uno::UNO_QUERY );
236 /* initialize new service instance ... he can use his own refcount ... we hold it! */
237 pClass->impl_initService();
238 /* return new created service as reference */
239 return xService;
240 }
241
impl_createFactory(const css::uno::Reference<css::lang::XMultiServiceFactory> & xServiceManager)242 css::uno::Reference< css::lang::XSingleServiceFactory > SoundHandler::impl_createFactory( const css::uno::Reference< css::lang::XMultiServiceFactory >& xServiceManager )
243 {
244 css::uno::Reference< css::lang::XSingleServiceFactory > xReturn ( cppu::createSingleFactory (
245 xServiceManager,
246 SoundHandler::impl_getStaticImplementationName(),
247 SoundHandler::impl_createInstance,
248 SoundHandler::impl_getStaticSupportedServiceNames()
249 )
250 );
251 return xReturn;
252 }
253
impl_initService()254 void SAL_CALL SoundHandler::impl_initService()
255 {
256 }
257
258
259 /*-************************************************************************************************************//**
260 @short standard ctor
261 @descr These initialize a new instance of this class with needed informations for work.
262
263 @seealso using at owner
264
265 @param "xFactory", reference to service manager for creation of new services
266 @return -
267
268 @onerror Show an assertion and do nothing else.
269 @threadsafe yes
270 *//*-*************************************************************************************************************/
SoundHandler(const css::uno::Reference<css::lang::XMultiServiceFactory> & xFactory)271 SoundHandler::SoundHandler( const css::uno::Reference< css::lang::XMultiServiceFactory >& xFactory )
272 // Init baseclasses first
273 : ThreadHelpBase ( )
274 , ::cppu::OWeakObject ( )
275 // Init member
276 , m_bError ( false )
277 , m_xFactory ( xFactory )
278 {
279 m_aUpdateTimer.SetTimeoutHdl(LINK(this, SoundHandler, implts_PlayerNotify));
280 }
281
282 /*-************************************************************************************************************//**
283 @short standard dtor
284 @descr -
285
286 @seealso -
287
288 @param -
289 @return -
290
291 @onerror -
292 @threadsafe -
293 *//*-*************************************************************************************************************/
~SoundHandler()294 SoundHandler::~SoundHandler()
295 {
296 if (m_xListener.is())
297 {
298 css::frame::DispatchResultEvent aEvent;
299 aEvent.State = css::frame::DispatchResultState::FAILURE;
300 m_xListener->dispatchFinished(aEvent);
301 m_xListener = css::uno::Reference< css::frame::XDispatchResultListener >();
302 }
303 }
304
305 /*-************************************************************************************************************//**
306 @interface ::com::sun::star::frame::XDispatch
307
308 @short try to load audio file
309 @descr This method try to load given audio file by URL and play it. We use vcl/Sound class to do that.
310 Playing of sound is asynchron everytime.
311
312 @attention We must hold us alive by ourself ... because we use async. vcl sound player ... but playing is started
313 in async interface call "dispatch()" too. And caller forget us imediatly. But then our uno ref count
314 will decreased to 0 and will die. The only solution is to use own reference to our implementation.
315 But we do it for realy started jobs only and release it during call back of vcl.
316
317 @seealso class vcl/Sound
318 @seealso method implts_PlayerNotify()
319
320 @param "aURL" , URL to dispatch.
321 @param "lArguments", list of optional arguments.
322 @return -
323
324 @onerror We do nothing.
325 @threadsafe yes
326 *//*-*************************************************************************************************************/
dispatchWithNotification(const css::util::URL & aURL,const css::uno::Sequence<css::beans::PropertyValue> & lDescriptor,const css::uno::Reference<css::frame::XDispatchResultListener> & xListener)327 void SAL_CALL SoundHandler::dispatchWithNotification(const css::util::URL& aURL ,
328 const css::uno::Sequence< css::beans::PropertyValue >& lDescriptor,
329 const css::uno::Reference< css::frame::XDispatchResultListener >& xListener ) throw(css::uno::RuntimeException)
330 {
331 // SAFE {
332 const ::vos::OGuard aLock( m_aLock );
333
334 {
335 //close streams otherwise on windows we can't reopen the file in the
336 //media player when we pass the url to directx as it'll already be open
337 ::comphelper::MediaDescriptor aDescriptor(lDescriptor);
338
339 css::uno::Reference< css::io::XInputStream > xInputStream =
340 aDescriptor.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_INPUTSTREAM(),
341 css::uno::Reference< css::io::XInputStream >());
342 if (xInputStream.is()) xInputStream->closeInput();
343 }
344
345 // If player currently used for other dispatch() requests ...
346 // cancel it by calling stop()!
347 m_aUpdateTimer.Stop();
348 if (m_xPlayer.is())
349 {
350 if (m_xPlayer->isPlaying())
351 m_xPlayer->stop();
352 m_xPlayer.clear();
353 }
354
355 // Try to initialize player.
356 m_xListener = xListener;
357 try
358 {
359 m_bError = false;
360 m_xPlayer.set( avmedia::MediaWindow::createPlayer( aURL.Complete ), css::uno::UNO_QUERY_THROW );
361 // OK- we can start async playing ...
362 // Count this request and initialize self-holder against dieing by uno ref count ...
363 m_xSelfHold = css::uno::Reference< css::uno::XInterface >(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY);
364 m_xPlayer->start();
365 m_aUpdateTimer.SetTimeout( 200 );
366 m_aUpdateTimer.Start();
367 }
368 catch( css::uno::Exception& e )
369 {
370 m_bError = true;
371 (void)e;
372 m_xPlayer.clear();
373 }
374
375 // } SAFE
376 }
377
dispatch(const css::util::URL & aURL,const css::uno::Sequence<css::beans::PropertyValue> & lArguments)378 void SAL_CALL SoundHandler::dispatch( const css::util::URL& aURL ,
379 const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) throw( css::uno::RuntimeException )
380 {
381 dispatchWithNotification(aURL, lArguments, css::uno::Reference< css::frame::XDispatchResultListener >());
382 }
383
384 /*-************************************************************************************************************//**
385 @interface ::com::sun::star::document::XExtendedFilterDetection
386
387 @short try to detect file (given as argument included in "lDescriptor")
388 @descr We try to detect, if given file could be handled by this class and is a well known one.
389 If it is - we return right internal type name - otherwise we return nothing!
390 So call can search for another detect service and ask him too.
391
392 @attention a) We don't need any mutex here ... because we don't use any member!
393 b) Dont' use internal player instance "m_pPlayer" to detect given sound file!
394 It's not neccessary to do that ... and we can use temp. variable to do the same.
395 This way is easy - we don't must synchronize it with currently played sounds!
396 Another reason to do so ... We are a listener on our internal ma_Player object.
397 If you would call "IsSoundFile()" on this instance, he would call us back and
398 we make some uneccssary things ...
399
400 @seealso -
401
402 @param "lDescriptor", description of file to detect
403 @return Internal type name which match this file ... or nothing if it is unknown.
404
405 @onerror We return nothing.
406 @threadsafe yes
407 *//*-*************************************************************************************************************/
detect(css::uno::Sequence<css::beans::PropertyValue> & lDescriptor)408 ::rtl::OUString SAL_CALL SoundHandler::detect( css::uno::Sequence< css::beans::PropertyValue >& lDescriptor ) throw( css::uno::RuntimeException )
409 {
410 // Our default is "nothing". So we can return it, if detection failed or fily type is realy unknown.
411 ::rtl::OUString sTypeName;
412
413 // Analyze given descriptor to find filename or input stream or ...
414 ::comphelper::MediaDescriptor aDescriptor(lDescriptor);
415 ::rtl::OUString sURL = aDescriptor.getUnpackedValueOrDefault(::comphelper::MediaDescriptor::PROP_URL(), ::rtl::OUString());
416
417 if (
418 !sURL.isEmpty() &&
419 (avmedia::MediaWindow::isMediaURL(sURL))
420 )
421 {
422 // If the file type is supported depends on the OS, so...
423 // I think we can the following ones:
424 // a) look for given extension of url to map our type decision HARD CODED!!!
425 // b) return preferred type every time... it's easy :-)
426 sTypeName = ::rtl::OUString::createFromAscii("wav_Wave_Audio_File");
427 aDescriptor[::comphelper::MediaDescriptor::PROP_TYPENAME()] <<= sTypeName;
428 aDescriptor >> lDescriptor;
429 }
430
431 // Return our decision.
432 return sTypeName;
433 }
434
435 /*-************************************************************************************************************//**
436 @short call back of sound player
437 @descr Our player call us back to give us some informations.
438 We use this informations to callback our might existing listener.
439
440 @seealso method dispatchWithNotification()
441
442 @param -
443 @return 0 everytime ... it doesnt matter for us.
444
445 @onerror -
446 @threadsafe yes
447 *//*-*************************************************************************************************************/
IMPL_LINK(SoundHandler,implts_PlayerNotify,void *,EMPTYARG)448 IMPL_LINK( SoundHandler, implts_PlayerNotify, void*, EMPTYARG )
449 {
450 // SAFE {
451 ::vos::OClearableGuard aLock( m_aLock );
452
453 if (m_xPlayer.is() && m_xPlayer->isPlaying() && m_xPlayer->getMediaTime() < m_xPlayer->getDuration())
454 {
455 m_aUpdateTimer.Start();
456 return 0L;
457 }
458 m_xPlayer.clear();
459
460 // We use m_xSelfHold to let us die ... but we must live till real finishing of this method too!!!
461 // So we SHOULD use another "self-holder" temp. to provide that ...
462 css::uno::Reference< css::uno::XInterface > xOperationHold = m_xSelfHold;
463 m_xSelfHold = css::uno::Reference< css::uno::XInterface >();
464
465 // notify might existing listener
466 // And forget this listener!
467 // Because the corresponding dispatch was finished.
468 if (m_xListener.is())
469 {
470 css::frame::DispatchResultEvent aEvent;
471 if (!m_bError)
472 aEvent.State = css::frame::DispatchResultState::SUCCESS;
473 else
474 aEvent.State = css::frame::DispatchResultState::FAILURE;
475 m_xListener->dispatchFinished(aEvent);
476 m_xListener = css::uno::Reference< css::frame::XDispatchResultListener >();
477 }
478
479 // } SAFE
480 //release aLock before end of method at which point xOperationHold goes out of scope and pThis dies
481 aLock.clear();
482 return 0;
483 }
484
485 } // namespace framework
486
487 // ------------------------------------------
488 // - component_getImplementationEnvironment -
489 // ------------------------------------------
490
component_getImplementationEnvironment(const sal_Char ** ppEnvTypeName,uno_Environment **)491 extern "C" void SAL_CALL component_getImplementationEnvironment( const sal_Char ** ppEnvTypeName, uno_Environment ** /*ppEnv*/ )
492 {
493 *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
494 }
495
496 // ------------------------
497 // - component_getFactory -
498 // ------------------------
499
component_getFactory(const sal_Char * pImplementationName,void * pServiceManager,void *)500 extern "C" void* SAL_CALL component_getFactory(const sal_Char* pImplementationName, void* pServiceManager, void* /*pRegistryKey*/ )
501 {
502 void* pReturn = NULL;
503 if (pServiceManager != NULL )
504 {
505 /* Define variables which are used in following macros. */
506 css::uno::Reference< ::com::sun::star::lang::XSingleServiceFactory > xFactory;
507 css::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceManager;
508 xServiceManager = reinterpret_cast< ::com::sun::star::lang::XMultiServiceFactory* >( pServiceManager ) ;
509
510 if ( avmedia::SoundHandler::impl_getStaticImplementationName().equals( ::rtl::OUString::createFromAscii( pImplementationName ) ) )
511 xFactory = avmedia::SoundHandler::impl_createFactory( xServiceManager );
512
513 if ( xFactory.is() == sal_True )
514 {
515 xFactory->acquire();
516 pReturn = xFactory.get();
517 }
518 }
519 /* Return with result of this operation. */
520 return pReturn;
521 }
522