LibreOffice Module avmedia (master) 1
soundhandler.cxx
Go to the documentation of this file.
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
23
24#include <com/sun/star/io/XInputStream.hpp>
25#include <com/sun/star/frame/DispatchResultState.hpp>
26
32
33namespace avmedia{
34
35
36// XInterface, XTypeProvider, XServiceInfo
37
38
39void SAL_CALL SoundHandler::acquire() noexcept
40{
41 /* Don't use mutex in methods of XInterface! */
42 OWeakObject::acquire();
43}
44
45void SAL_CALL SoundHandler::release() noexcept
46{
47 /* Don't use mutex in methods of XInterface! */
48 OWeakObject::release();
49}
50
51css::uno::Any SAL_CALL SoundHandler::queryInterface( const css::uno::Type& aType )
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 static_cast< css::document::XExtendedFilterDetection* >(this)));
61 /* If searched interface not supported by this class ... */
62 if ( !aReturn.hasValue() )
63 {
64 /* ... ask baseclass for interfaces! */
65 aReturn = OWeakObject::queryInterface( aType );
66 }
67 /* Return result of this search. */
68 return aReturn;
69}
70
71css::uno::Sequence< sal_Int8 > SAL_CALL SoundHandler::getImplementationId()
72{
73 return css::uno::Sequence<sal_Int8>();
74}
75
76css::uno::Sequence< css::uno::Type > SAL_CALL SoundHandler::getTypes()
77{
78 static ::cppu::OTypeCollection aTypeCollection(
84
85 return aTypeCollection.getTypes();
86}
87
88constexpr OUStringLiteral IMPLEMENTATIONNAME_SOUNDHANDLER = u"com.sun.star.comp.framework.SoundHandler";
89
90/*===========================================================================================================*/
91/* XServiceInfo */
92/*===========================================================================================================*/
94{
96}
97
98// XServiceInfo
99sal_Bool SAL_CALL SoundHandler::supportsService( const OUString& sServiceName )
100{
102}
103
104// XServiceInfo
105css::uno::Sequence< OUString > SAL_CALL SoundHandler::getSupportedServiceNames()
106{
107 return { "com.sun.star.frame.ContentHandler" };
108}
109
110/*-************************************************************************************************************
111 @short standard ctor
112 @descr These initialize a new instance of this class with needed information for work.
113
114 @seealso using at owner
115
116 @param "xFactory", reference to service manager for creation of new services
117 @onerror Show an assertion and do nothing else.
118 @threadsafe yes
119*//*-*************************************************************************************************************/
121 // Init member
122 : m_bError ( false )
123 , m_aUpdateIdle ( "avmedia SoundHandler Update" )
124{
125 m_aUpdateIdle.SetInvokeHandler(LINK(this, SoundHandler, implts_PlayerNotify));
126}
127
128/*-************************************************************************************************************
129 @short standard dtor
130*//*-*************************************************************************************************************/
132{
133 if (m_xListener.is())
134 {
135 css::frame::DispatchResultEvent aEvent;
136 aEvent.State = css::frame::DispatchResultState::FAILURE;
137 m_xListener->dispatchFinished(aEvent);
138 m_xListener.clear();
139 }
140}
141
142/*-************************************************************************************************************
143 @interface css::frame::XDispatch
144
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 asynchronous every time.
148
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.
153
154 @seealso class vcl/Sound
155 @seealso method implts_PlayerNotify()
156
157 @param "aURL" , URL to dispatch.
158 @param "lArguments", list of optional arguments.
159 @onerror We do nothing.
160 @threadsafe yes
161*//*-*************************************************************************************************************/
162void 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 )
165{
166 // SAFE {
167 const ::osl::MutexGuard aLock( m_aMutex );
168
169 utl::MediaDescriptor aDescriptor(lDescriptor);
170
171 {
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();
178 }
179
180 // If player currently used for other dispatch() requests ...
181 // cancel it by calling stop()!
183 if (m_xPlayer.is())
184 {
185 if (m_xPlayer->isPlaying())
186 m_xPlayer->stop();
187 m_xPlayer.clear();
188 }
189
190 // Try to initialize player.
191 m_xListener = xListener;
192 try
193 {
194 m_bError = false;
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(getXWeak());
199 m_xPlayer->start();
200 m_aUpdateIdle.SetPriority( TaskPriority::HIGH_IDLE );
202 }
203 catch( css::uno::Exception& )
204 {
205 m_bError = true;
206 m_xPlayer.clear();
207 }
208
209 // } SAFE
210}
211
212void SAL_CALL SoundHandler::dispatch( const css::util::URL& aURL ,
213 const css::uno::Sequence< css::beans::PropertyValue >& lArguments )
214{
215 dispatchWithNotification(aURL, lArguments, css::uno::Reference< css::frame::XDispatchResultListener >());
216}
217
218/*-************************************************************************************************************
219 @interface css::document::XExtendedFilterDetection
220
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.
225
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.
235
236 @onerror We return nothing.
237 @threadsafe yes
238*//*-*************************************************************************************************************/
239OUString SAL_CALL SoundHandler::detect( css::uno::Sequence< css::beans::PropertyValue >& lDescriptor )
240{
241 // Our default is "nothing". So we can return it, if detection failed or file type is really unknown.
242 OUString sTypeName;
243
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());
248
249 if (
250 !sURL.isEmpty() &&
251 (avmedia::MediaWindow::isMediaURL(sURL, sReferer))
252 )
253 {
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;
261 }
262
263 // Return our decision.
264 return sTypeName;
265}
266
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.
271
272 @seealso method dispatchWithNotification()
273 @return 0 every time... it doesn't matter for us.
274 @threadsafe yes
275*//*-*************************************************************************************************************/
276IMPL_LINK_NOARG(SoundHandler, implts_PlayerNotify, Timer *, void)
277{
278 // SAFE {
279 ::osl::ClearableMutexGuard aLock( m_aMutex );
280
281 if (m_xPlayer.is() && m_xPlayer->isPlaying() && m_xPlayer->getMediaTime() < m_xPlayer->getDuration())
282 {
283 m_aUpdateIdle.Start();
284 return;
285 }
286 m_xPlayer.clear();
287
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;
291 m_xSelfHold.clear();
292
293 // notify might existing listener
294 // And forget this listener!
295 // Because the corresponding dispatch was finished.
296 if (m_xListener.is())
297 {
298 css::frame::DispatchResultEvent aEvent;
299 if (!m_bError)
300 aEvent.State = css::frame::DispatchResultState::SUCCESS;
301 else
302 aEvent.State = css::frame::DispatchResultState::FAILURE;
303 m_xListener->dispatchFinished(aEvent);
304 m_xListener.clear();
305 }
306
307 // } SAFE
308 //release aLock before end of method at which point xOperationHold goes out of scope and pThis dies
309 aLock.clear();
310}
311
312} // namespace framework
313
314
315extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
317 css::uno::Sequence<css::uno::Any> const &)
318{
319 return cppu::acquire(new avmedia::SoundHandler);
320}
321
322
323/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool m_bError
constexpr OUStringLiteral sServiceName
AnyEventRef aEvent
virtual void Start(bool bStartTimer=true) override
void SetPriority(TaskPriority ePriority)
void Stop()
void SetInvokeHandler(const Link< Timer *, void > &rLink)
static css::uno::Reference< css::media::XPlayer > createPlayer(const OUString &rURL, const OUString &rReferer, const OUString *pMimeType=nullptr)
static bool isMediaURL(std::u16string_view rURL, const OUString &rReferer, bool bDeep=false, rtl::Reference< PlayerListener > xPreferredPixelSizeListener=nullptr)
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
css::uno::Reference< css::uno::XInterface > m_xSelfHold
virtual ~SoundHandler() override
virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override
virtual OUString SAL_CALL getImplementationName() override
virtual void SAL_CALL dispatchWithNotification(const css::util::URL &aURL, const css::uno::Sequence< css::beans::PropertyValue > &lArguments, const css::uno::Reference< css::frame::XDispatchResultListener > &xListener) override
virtual sal_Bool SAL_CALL supportsService(const OUString &sServiceName) override
css::uno::Reference< css::media::XPlayer > m_xPlayer
virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type &aType) override
virtual void SAL_CALL acquire() noexcept override
virtual void SAL_CALL release() noexcept override
css::uno::Reference< css::frame::XDispatchResultListener > m_xListener
virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override
virtual OUString SAL_CALL detect(css::uno::Sequence< css::beans::PropertyValue > &lDescriptor) override
virtual void SAL_CALL dispatch(const css::util::URL &aURL, const css::uno::Sequence< css::beans::PropertyValue > &lArguments) override
mutable::osl::Mutex m_aMutex
static constexpr OUStringLiteral PROP_INPUTSTREAM
static constexpr OUStringLiteral PROP_URL
static constexpr OUStringLiteral PROP_TYPENAME
static constexpr OUStringLiteral PROP_REFERRER
URL aURL
float u
Reference< XTextListener > m_xListener
std::mutex m_aMutex
IMPL_LINK_NOARG(MediaControl, implTimeEndHdl, Timer *, void)
constexpr OUStringLiteral IMPLEMENTATIONNAME_SOUNDHANDLER
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * com_sun_star_comp_framework_SoundHandler_get_implementation(css::uno::XComponentContext *, css::uno::Sequence< css::uno::Any > const &)
unsigned char sal_Bool