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