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