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 <rtl/ustrbuf.hxx>
29 #include <cppuhelper/queryinterface.hxx>
30 #include <cppuhelper/typeprovider.hxx>
31 #include <cppuhelper/factory.hxx>
32 #include <cppuhelper/supportsservice.hxx>
37 // XInterface, XTypeProvider, XServiceInfo
40 void SAL_CALL
SoundHandler::acquire() throw()
42 /* Don't use mutex in methods of XInterface! */
43 OWeakObject::acquire();
46 void SAL_CALL
SoundHandler::release() throw()
48 /* Don't use mutex in methods of XInterface! */
49 OWeakObject::release();
52 css::uno::Any SAL_CALL
SoundHandler::queryInterface( const css::uno::Type
& aType
)
54 /* Attention: Don't use mutex or guard in this method!!! Is a method of XInterface. */
55 /* Ask for my own supported interfaces ...*/
56 css::uno::Any
aReturn( ::cppu::queryInterface( aType
,
57 static_cast< css::lang::XTypeProvider
* >(this),
58 static_cast< css::lang::XServiceInfo
* >(this),
59 static_cast< css::frame::XNotifyingDispatch
* >(this),
60 static_cast< css::frame::XDispatch
* >(this),
61 static_cast< css::document::XExtendedFilterDetection
* >(this)));
62 /* If searched interface not supported by this class ... */
63 if ( !aReturn
.hasValue() )
65 /* ... ask baseclass for interfaces! */
66 aReturn
= OWeakObject::queryInterface( aType
);
68 /* Return result of this search. */
72 css::uno::Sequence
< sal_Int8
> SAL_CALL
SoundHandler::getImplementationId()
74 return css::uno::Sequence
<sal_Int8
>();
77 css::uno::Sequence
< css::uno::Type
> SAL_CALL
SoundHandler::getTypes()
79 static ::cppu::OTypeCollection
aTypeCollection(
80 cppu::UnoType
<css::lang::XTypeProvider
>::get(),
81 cppu::UnoType
<css::lang::XServiceInfo
>::get(),
82 cppu::UnoType
<css::frame::XNotifyingDispatch
>::get(),
83 cppu::UnoType
<css::frame::XDispatch
>::get(),
84 cppu::UnoType
<css::document::XExtendedFilterDetection
>::get());
86 return aTypeCollection
.getTypes();
89 #define IMPLEMENTATIONNAME_SOUNDHANDLER OUString("com.sun.star.comp.framework.SoundHandler")
91 /*===========================================================================================================*/
93 /*===========================================================================================================*/
94 OUString SAL_CALL
SoundHandler::getImplementationName()
96 return IMPLEMENTATIONNAME_SOUNDHANDLER
;
100 sal_Bool SAL_CALL
SoundHandler::supportsService( const OUString
& sServiceName
)
102 return cppu::supportsService(this, sServiceName
);
106 css::uno::Sequence
< OUString
> SAL_CALL
SoundHandler::getSupportedServiceNames()
108 return { "com.sun.star.frame.ContentHandler" };
111 /*-************************************************************************************************************
113 @descr These initialize a new instance of this class with needed information for work.
115 @seealso using at owner
117 @param "xFactory", reference to service manager for creation of new services
118 @onerror Show an assertion and do nothing else.
120 *//*-*************************************************************************************************************/
121 SoundHandler::SoundHandler()
122 // Init baseclasses first
124 , ::cppu::OWeakObject ( )
127 , m_aUpdateIdle ( "avmedia SoundHandler Update" )
129 m_aUpdateIdle
.SetInvokeHandler(LINK(this, SoundHandler
, implts_PlayerNotify
));
132 /*-************************************************************************************************************
134 *//*-*************************************************************************************************************/
135 SoundHandler::~SoundHandler()
137 if (m_xListener
.is())
139 css::frame::DispatchResultEvent aEvent
;
140 aEvent
.State
= css::frame::DispatchResultState::FAILURE
;
141 m_xListener
->dispatchFinished(aEvent
);
146 /*-************************************************************************************************************
147 @interface css::frame::XDispatch
149 @short try to load audio file
150 @descr This method try to load given audio file by URL and play it. We use vcl/Sound class to do that.
151 Playing of sound is asynchron every time.
153 @attention We must hold us alive by ourself ... because we use async. vcl sound player ... but playing is started
154 in async interface call "dispatch()" too. And caller forget us immediately. But then our uno ref count
155 will decreased to 0 and will die. The only solution is to use own reference to our implementation.
156 But we do it for really started jobs only and release it during call back of vcl.
158 @seealso class vcl/Sound
159 @seealso method implts_PlayerNotify()
161 @param "aURL" , URL to dispatch.
162 @param "lArguments", list of optional arguments.
163 @onerror We do nothing.
165 *//*-*************************************************************************************************************/
166 void SAL_CALL
SoundHandler::dispatchWithNotification(const css::util::URL
& aURL
,
167 const css::uno::Sequence
< css::beans::PropertyValue
>& lDescriptor
,
168 const css::uno::Reference
< css::frame::XDispatchResultListener
>& xListener
)
171 const ::osl::MutexGuard
aLock( m_aLock
);
173 utl::MediaDescriptor
aDescriptor(lDescriptor
);
176 //close streams otherwise on windows we can't reopen the file in the
177 //media player when we pass the url to directx as it'll already be open
178 css::uno::Reference
< css::io::XInputStream
> xInputStream
=
179 aDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_INPUTSTREAM(),
180 css::uno::Reference
< css::io::XInputStream
>());
181 if (xInputStream
.is()) xInputStream
->closeInput();
184 // If player currently used for other dispatch() requests ...
185 // cancel it by calling stop()!
186 m_aUpdateIdle
.Stop();
189 if (m_xPlayer
->isPlaying())
194 // Try to initialize player.
195 m_xListener
= xListener
;
199 m_xPlayer
.set( avmedia::MediaWindow::createPlayer( aURL
.Complete
, aDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_REFERRER(), OUString()) ), css::uno::UNO_SET_THROW
);
200 // OK- we can start async playing ...
201 // Count this request and initialize self-holder against dying by uno ref count ...
202 m_xSelfHold
.set(static_cast< ::cppu::OWeakObject
* >(this), css::uno::UNO_QUERY
);
204 m_aUpdateIdle
.SetPriority( TaskPriority::HIGH_IDLE
);
205 m_aUpdateIdle
.Start();
207 catch( css::uno::Exception
& )
216 void SAL_CALL
SoundHandler::dispatch( const css::util::URL
& aURL
,
217 const css::uno::Sequence
< css::beans::PropertyValue
>& lArguments
)
219 dispatchWithNotification(aURL
, lArguments
, css::uno::Reference
< css::frame::XDispatchResultListener
>());
222 /*-************************************************************************************************************
223 @interface css::document::XExtendedFilterDetection
225 @short try to detect file (given as argument included in "lDescriptor")
226 @descr We try to detect, if given file could be handled by this class and is a well known one.
227 If it is - we return right internal type name - otherwise we return nothing!
228 So call can search for another detect service and ask him too.
230 @attention a) We don't need any mutex here ... because we don't use any member!
231 b) Don't use internal player instance "m_pPlayer" to detect given sound file!
232 It's not necessary to do that ... and we can use temp. variable to do the same.
233 This way is easy - we don't must synchronize it with currently played sounds!
234 Another reason to do so ... We are a listener on our internal ma_Player object.
235 If you would call "IsSoundFile()" on this instance, he would call us back and
236 we make some unnecessary things ...
237 @param "lDescriptor", description of file to detect
238 @return Internal type name which match this file ... or nothing if it is unknown.
240 @onerror We return nothing.
242 *//*-*************************************************************************************************************/
243 OUString SAL_CALL
SoundHandler::detect( css::uno::Sequence
< css::beans::PropertyValue
>& lDescriptor
)
245 // Our default is "nothing". So we can return it, if detection failed or file type is really unknown.
248 // Analyze given descriptor to find filename or input stream or ...
249 utl::MediaDescriptor
aDescriptor(lDescriptor
);
250 OUString sURL
= aDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_URL(), OUString());
251 OUString sReferer
= aDescriptor
.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_REFERRER(), OUString());
255 (avmedia::MediaWindow::isMediaURL(sURL
, sReferer
))
258 // If the file type is supported depends on the OS, so...
259 // I think we can the following ones:
260 // a) look for given extension of url to map our type decision HARD CODED!!!
261 // b) return preferred type every time... it's easy :-)
262 sTypeName
= "wav_Wave_Audio_File";
263 aDescriptor
[utl::MediaDescriptor::PROP_TYPENAME()] <<= sTypeName
;
264 aDescriptor
>> lDescriptor
;
267 // Return our decision.
271 /*-************************************************************************************************************
272 @short call back of sound player
273 @descr Our player call us back to give us some information.
274 We use this information to callback our might existing listener.
276 @seealso method dispatchWithNotification()
277 @return 0 every time... it doesn't matter for us.
279 *//*-*************************************************************************************************************/
280 IMPL_LINK_NOARG(SoundHandler
, implts_PlayerNotify
, Timer
*, void)
283 ::osl::ClearableMutexGuard
aLock( m_aLock
);
285 if (m_xPlayer
.is() && m_xPlayer
->isPlaying() && m_xPlayer
->getMediaTime() < m_xPlayer
->getDuration())
287 m_aUpdateIdle
.Start();
292 // We use m_xSelfHold to let us die ... but we must live till real finishing of this method too!!!
293 // So we SHOULD use another "self-holder" temp. to provide that ...
294 css::uno::Reference
< css::uno::XInterface
> xOperationHold
= m_xSelfHold
;
297 // notify might existing listener
298 // And forget this listener!
299 // Because the corresponding dispatch was finished.
300 if (m_xListener
.is())
302 css::frame::DispatchResultEvent aEvent
;
304 aEvent
.State
= css::frame::DispatchResultState::SUCCESS
;
306 aEvent
.State
= css::frame::DispatchResultState::FAILURE
;
307 m_xListener
->dispatchFinished(aEvent
);
312 //release aLock before end of method at which point xOperationHold goes out of scope and pThis dies
316 } // namespace framework
319 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
320 com_sun_star_comp_framework_SoundHandler_get_implementation(css::uno::XComponentContext
*,
321 css::uno::Sequence
<css::uno::Any
> const &)
323 return cppu::acquire(new avmedia::SoundHandler
);
327 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */