1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "soundhandler.hxx"
22 #include <unotools/mediadescriptor.hxx>
24 #include <com/sun/star/io/XInputStream.hpp>
25 #include <com/sun/star/frame/DispatchResultState.hpp>
27 #include <avmedia/mediawindow.hxx>
28 #include <cppuhelper/queryinterface.hxx>
29 #include <cppuhelper/typeprovider.hxx>
30 #include <cppuhelper/factory.hxx>
31 #include <cppuhelper/supportsservice.hxx>
36 // XInterface, XTypeProvider, XServiceInfo
39 void SAL_CALL
SoundHandler::acquire() throw()
41 /* Don't use mutex in methods of XInterface! */
42 OWeakObject::acquire();
45 void SAL_CALL
SoundHandler::release() throw()
47 /* Don't use mutex in methods of XInterface! */
48 OWeakObject::release();
51 css::uno::Any SAL_CALL
SoundHandler::queryInterface( const css::uno::Type
& aType
)
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 static_cast< css::document::XExtendedFilterDetection
* >(this)));
61 /* If searched interface not supported by this class ... */
62 if ( !aReturn
.hasValue() )
64 /* ... ask baseclass for interfaces! */
65 aReturn
= OWeakObject::queryInterface( aType
);
67 /* Return result of this search. */
71 css::uno::Sequence
< sal_Int8
> SAL_CALL
SoundHandler::getImplementationId()
73 return css::uno::Sequence
<sal_Int8
>();
76 css::uno::Sequence
< css::uno::Type
> SAL_CALL
SoundHandler::getTypes()
78 static ::cppu::OTypeCollection
aTypeCollection(
79 cppu::UnoType
<css::lang::XTypeProvider
>::get(),
80 cppu::UnoType
<css::lang::XServiceInfo
>::get(),
81 cppu::UnoType
<css::frame::XNotifyingDispatch
>::get(),
82 cppu::UnoType
<css::frame::XDispatch
>::get(),
83 cppu::UnoType
<css::document::XExtendedFilterDetection
>::get());
85 return aTypeCollection
.getTypes();
88 #define IMPLEMENTATIONNAME_SOUNDHANDLER "com.sun.star.comp.framework.SoundHandler"
90 /*===========================================================================================================*/
92 /*===========================================================================================================*/
93 OUString SAL_CALL
SoundHandler::getImplementationName()
95 return IMPLEMENTATIONNAME_SOUNDHANDLER
;
99 sal_Bool SAL_CALL
SoundHandler::supportsService( const OUString
& sServiceName
)
101 return cppu::supportsService(this, sServiceName
);
105 css::uno::Sequence
< OUString
> SAL_CALL
SoundHandler::getSupportedServiceNames()
107 return { "com.sun.star.frame.ContentHandler" };
110 /*-************************************************************************************************************
112 @descr These initialize a new instance of this class with needed information for work.
114 @seealso using at owner
116 @param "xFactory", reference to service manager for creation of new services
117 @onerror Show an assertion and do nothing else.
119 *//*-*************************************************************************************************************/
120 SoundHandler::SoundHandler()
123 , m_aUpdateIdle ( "avmedia SoundHandler Update" )
125 m_aUpdateIdle
.SetInvokeHandler(LINK(this, SoundHandler
, implts_PlayerNotify
));
128 /*-************************************************************************************************************
130 *//*-*************************************************************************************************************/
131 SoundHandler::~SoundHandler()
133 if (m_xListener
.is())
135 css::frame::DispatchResultEvent aEvent
;
136 aEvent
.State
= css::frame::DispatchResultState::FAILURE
;
137 m_xListener
->dispatchFinished(aEvent
);
142 /*-************************************************************************************************************
143 @interface css::frame::XDispatch
145 @short try to load audio file
146 @descr This method try to load given audio file by URL and play it. We use vcl/Sound class to do that.
147 Playing of sound is asynchron every time.
149 @attention We must hold us alive by ourself ... because we use async. vcl sound player ... but playing is started
150 in async interface call "dispatch()" too. And caller forget us immediately. But then our uno ref count
151 will decreased to 0 and will die. The only solution is to use own reference to our implementation.
152 But we do it for really started jobs only and release it during call back of vcl.
154 @seealso class vcl/Sound
155 @seealso method implts_PlayerNotify()
157 @param "aURL" , URL to dispatch.
158 @param "lArguments", list of optional arguments.
159 @onerror We do nothing.
161 *//*-*************************************************************************************************************/
162 void SAL_CALL
SoundHandler::dispatchWithNotification(const css::util::URL
& aURL
,
163 const css::uno::Sequence
< css::beans::PropertyValue
>& lDescriptor
,
164 const css::uno::Reference
< css::frame::XDispatchResultListener
>& xListener
)
167 const ::osl::MutexGuard
aLock( GetMutex() );
169 utl::MediaDescriptor
aDescriptor(lDescriptor
);
172 //close streams otherwise on windows we can't reopen the file in the
173 //media player when we pass the url to directx as it'll already be open
174 css::uno::Reference
< css::io::XInputStream
> xInputStream
=
175 aDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_INPUTSTREAM(),
176 css::uno::Reference
< css::io::XInputStream
>());
177 if (xInputStream
.is()) xInputStream
->closeInput();
180 // If player currently used for other dispatch() requests ...
181 // cancel it by calling stop()!
182 m_aUpdateIdle
.Stop();
185 if (m_xPlayer
->isPlaying())
190 // Try to initialize player.
191 m_xListener
= xListener
;
195 m_xPlayer
.set( avmedia::MediaWindow::createPlayer( aURL
.Complete
, aDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_REFERRER(), OUString()) ), css::uno::UNO_SET_THROW
);
196 // OK- we can start async playing ...
197 // Count this request and initialize self-holder against dying by uno ref count ...
198 m_xSelfHold
.set(static_cast< ::cppu::OWeakObject
* >(this), css::uno::UNO_QUERY
);
200 m_aUpdateIdle
.SetPriority( TaskPriority::HIGH_IDLE
);
201 m_aUpdateIdle
.Start();
203 catch( css::uno::Exception
& )
212 void SAL_CALL
SoundHandler::dispatch( const css::util::URL
& aURL
,
213 const css::uno::Sequence
< css::beans::PropertyValue
>& lArguments
)
215 dispatchWithNotification(aURL
, lArguments
, css::uno::Reference
< css::frame::XDispatchResultListener
>());
218 /*-************************************************************************************************************
219 @interface css::document::XExtendedFilterDetection
221 @short try to detect file (given as argument included in "lDescriptor")
222 @descr We try to detect, if given file could be handled by this class and is a well known one.
223 If it is - we return right internal type name - otherwise we return nothing!
224 So call can search for another detect service and ask him too.
226 @attention a) We don't need any mutex here ... because we don't use any member!
227 b) Don't use internal player instance "m_pPlayer" to detect given sound file!
228 It's not necessary to do that ... and we can use temp. variable to do the same.
229 This way is easy - we don't must synchronize it with currently played sounds!
230 Another reason to do so ... We are a listener on our internal ma_Player object.
231 If you would call "IsSoundFile()" on this instance, he would call us back and
232 we make some unnecessary things ...
233 @param "lDescriptor", description of file to detect
234 @return Internal type name which match this file ... or nothing if it is unknown.
236 @onerror We return nothing.
238 *//*-*************************************************************************************************************/
239 OUString SAL_CALL
SoundHandler::detect( css::uno::Sequence
< css::beans::PropertyValue
>& lDescriptor
)
241 // Our default is "nothing". So we can return it, if detection failed or file type is really unknown.
244 // Analyze given descriptor to find filename or input stream or ...
245 utl::MediaDescriptor
aDescriptor(lDescriptor
);
246 OUString sURL
= aDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_URL(), OUString());
247 OUString sReferer
= aDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_REFERRER(), OUString());
251 (avmedia::MediaWindow::isMediaURL(sURL
, sReferer
))
254 // If the file type is supported depends on the OS, so...
255 // I think we can the following ones:
256 // a) look for given extension of url to map our type decision HARD CODED!!!
257 // b) return preferred type every time... it's easy :-)
258 sTypeName
= "wav_Wave_Audio_File";
259 aDescriptor
[utl::MediaDescriptor::PROP_TYPENAME()] <<= sTypeName
;
260 aDescriptor
>> lDescriptor
;
263 // Return our decision.
267 /*-************************************************************************************************************
268 @short call back of sound player
269 @descr Our player call us back to give us some information.
270 We use this information to callback our might existing listener.
272 @seealso method dispatchWithNotification()
273 @return 0 every time... it doesn't matter for us.
275 *//*-*************************************************************************************************************/
276 IMPL_LINK_NOARG(SoundHandler
, implts_PlayerNotify
, Timer
*, void)
279 ::osl::ClearableMutexGuard
aLock( GetMutex() );
281 if (m_xPlayer
.is() && m_xPlayer
->isPlaying() && m_xPlayer
->getMediaTime() < m_xPlayer
->getDuration())
283 m_aUpdateIdle
.Start();
288 // We use m_xSelfHold to let us die ... but we must live till real finishing of this method too!!!
289 // So we SHOULD use another "self-holder" temp. to provide that ...
290 css::uno::Reference
< css::uno::XInterface
> xOperationHold
= m_xSelfHold
;
293 // notify might existing listener
294 // And forget this listener!
295 // Because the corresponding dispatch was finished.
296 if (m_xListener
.is())
298 css::frame::DispatchResultEvent aEvent
;
300 aEvent
.State
= css::frame::DispatchResultState::SUCCESS
;
302 aEvent
.State
= css::frame::DispatchResultState::FAILURE
;
303 m_xListener
->dispatchFinished(aEvent
);
308 //release aLock before end of method at which point xOperationHold goes out of scope and pThis dies
312 } // namespace framework
315 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
316 com_sun_star_comp_framework_SoundHandler_get_implementation(css::uno::XComponentContext
*,
317 css::uno::Sequence
<css::uno::Any
> const &)
319 return cppu::acquire(new avmedia::SoundHandler
);
323 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */