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