1 /* 2 * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #import "OSXMediaPlayer.h" 27 #import "com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer.h" 28 #import <Utils/JObjectPeers.h> 29 #import <Utils/JavaUtils.h> 30 #import <CoreAudio/CoreAudio.h> 31 #import <jni/Logger.h> 32 33 #import <objc/runtime.h> 34 35 #define USE_WEAK_REFS 0 36 37 // Don't access directly, use the OSXMediaPlayer static methods to ensure thread safe access 38 static JObjectPeers *gMediaPlayerPeers = nil; 39 static id gMediaPlayerClass = nil; 40 41 @implementation OSXMediaPlayer 42 43 + (void) initialize 44 { 45 gMediaPlayerPeers = [[JObjectPeers alloc] init]; 46 } 47 48 + (OSXMediaPlayer*) peerForPlayer:(jobject)javaPlayer andEnv:(JNIEnv*)javaEnv 49 { 50 return [gMediaPlayerPeers peerForJObject:javaPlayer javaEnv:javaEnv]; 51 } 52 53 + (void) setPeer:(OSXMediaPlayer*)player forJavaPlayer:(jobject)javaPlayer andEnv:(JNIEnv*)javaEnv 54 { 55 [gMediaPlayerPeers setPeer:player forJObject:javaPlayer javaEnv:javaEnv]; 56 } 57 58 + (void) removePlayerPeers:(OSXMediaPlayer*)player 59 { 60 [gMediaPlayerPeers removePeer:player]; 61 } 62 63 + (void) initPlayerPlatform 64 { 65 // Determine if we can use QTKMediaPlayer or not, without directly linking and pulling 66 // in unwanted dependencies 67 id klass = objc_getClass("QTKMediaPlayer"); 68 if (klass) { 69 gMediaPlayerClass = klass; 70 } 71 } 72 73 - (id) init 74 { 75 if ((self = [super init]) != nil) { 76 } 77 return self; 78 } 79 80 - (id) initWithURL:(NSURL *)source javaPlayer:(jobject)jp andEnv:(JNIEnv*)env eventHandler:(CJavaPlayerEventDispatcher*)hdlr 81 { 82 if (!gMediaPlayerClass) { 83 // No player class available, abort 84 return nil; 85 } 86 87 if ((self = [super init]) != nil) { 88 movieURL = [source retain]; 89 90 env->GetJavaVM(&javaPlayerVM); 91 #if USE_WEAK_REFS 92 javaPlayer = env->NewWeakGlobalRef(jp); 93 #else 94 javaPlayer = env->NewGlobalRef(jp); 95 #endif 96 // set up the peer association 97 [OSXMediaPlayer setPeer:self forJavaPlayer:javaPlayer andEnv:env]; 98 99 eventHandler = hdlr; 100 101 // create the movie object 102 player = [[gMediaPlayerClass alloc] initWithURL:movieURL eventHandler:eventHandler]; 103 } 104 return self; 105 } 106 107 - (void) dealloc 108 { 109 [self dispose]; // just in case 110 [movieURL release]; 111 [super dealloc]; 112 } 113 114 - (void) dispose 115 { 116 @synchronized(self) { 117 [player dispose]; 118 [player release]; 119 player = nil; 120 121 if (eventHandler) { 122 eventHandler->Dispose(); 123 delete eventHandler; 124 } 125 eventHandler = NULL; 126 127 [OSXMediaPlayer removePlayerPeers:self]; 128 if (javaPlayerVM && javaPlayer) { 129 BOOL attached = NO; 130 JNIEnv *env = GetJavaEnvironment(javaPlayerVM, &attached); 131 132 // remove peer association 133 [OSXMediaPlayer removePlayerPeers:self]; 134 #if USE_WEAK_REFS 135 env->DeleteWeakGlobalRef(javaPlayer); 136 #else 137 env->DeleteGlobalRef(javaPlayer); 138 #endif 139 if (attached) { 140 javaPlayerVM->DetachCurrentThread(); 141 } 142 } 143 javaPlayer = 0; 144 javaPlayerVM = NULL; 145 } 146 } 147 148 - (id<OSXPlayerProtocol>) player 149 { 150 return [[player retain] autorelease]; 151 } 152 153 - (int64_t) audioSyncDelay 154 { 155 return player.audioSyncDelay; 156 } 157 158 - (void) setAudioSyncDelay:(int64_t)audioSyncDelay 159 { 160 player.audioSyncDelay = audioSyncDelay; 161 } 162 163 - (double) duration 164 { 165 return player.duration; 166 } 167 168 - (float) rate 169 { 170 return player.rate; 171 } 172 173 - (void) setRate:(float)rate 174 { 175 player.rate = rate; 176 } 177 178 - (double) currentTime 179 { 180 return player.currentTime; 181 } 182 183 - (void) setCurrentTime:(double)currentTime 184 { 185 player.currentTime = currentTime; 186 } 187 188 - (BOOL) mute 189 { 190 return player.mute; 191 } 192 193 - (void) setMute:(BOOL)mute 194 { 195 player.mute = mute; 196 } 197 198 - (float) volume 199 { 200 return player.volume; 201 } 202 203 - (void) setVolume:(float)volume 204 { 205 player.volume = volume; 206 } 207 208 - (float) balance 209 { 210 return player.balance; 211 } 212 213 - (void) setBalance:(float)balance 214 { 215 player.balance = balance; 216 } 217 218 - (void) play 219 { 220 [player play]; 221 } 222 223 - (void) pause 224 { 225 [player pause]; 226 } 227 228 - (void) finish 229 { 230 [player finish]; 231 } 232 233 - (void) stop 234 { 235 [player stop]; 236 } 237 238 @end 239 240 #pragma mark - 241 #pragma mark JNI Methods 242 243 /* 244 * Class: com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer 245 * Method: osxCreatePlayer 246 * Signature: (Ljava/lang/String;)V 247 */ 248 JNIEXPORT void JNICALL Java_com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer_osxCreatePlayer 249 (JNIEnv *env, jobject playerObject, jstring sourceURI) 250 { 251 // create the event dispatcher, init later 252 CJavaPlayerEventDispatcher *eventHandler = new CJavaPlayerEventDispatcher(); 253 eventHandler->Init(env, playerObject, NULL); 254 255 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 256 NSString *sourceURIString = NSStringFromJavaString(env, sourceURI); 257 if (!sourceURIString) { 258 LOGGER_ERRORMSG("OSXMediaPlayer: Unable to create sourceURIString\n"); 259 eventHandler->SendPlayerMediaErrorEvent(ERROR_OSX_INIT); 260 return; 261 } 262 263 NSURL *mediaURL = [[NSURL alloc] initWithString:sourceURIString]; 264 if (!mediaURL) { 265 LOGGER_WARNMSG("OSXMediaPlayer: Unable to create mediaURL\n"); 266 eventHandler->SendPlayerMediaErrorEvent(ERROR_OSX_INIT); 267 return; 268 } 269 270 OSXMediaPlayer *player = [[OSXMediaPlayer alloc] initWithURL:mediaURL javaPlayer:playerObject andEnv:env eventHandler:eventHandler]; 271 if (!player) { 272 LOGGER_WARNMSG("OSXMediaPlayer: Unable to create player\n"); 273 eventHandler->SendPlayerMediaErrorEvent(ERROR_OSX_INIT); 274 return; 275 } 276 277 [player release]; // The player peer list retains for us 278 [pool drain]; 279 } 280 281 /* 282 * Class: com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer 283 * Method: osxGetAudioSyncDelay 284 * Signature: ()J 285 */ 286 JNIEXPORT jlong JNICALL Java_com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer_osxGetAudioSyncDelay 287 (JNIEnv *env, jobject playerObject) 288 { 289 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 290 OSXMediaPlayer *player = [OSXMediaPlayer peerForPlayer:playerObject andEnv:env]; 291 jlong asd = 0; 292 if (player) { 293 asd = (jlong)player.audioSyncDelay; 294 } 295 [pool drain]; 296 return asd; 297 } 298 299 /* 300 * Class: com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer 301 * Method: osxSetAudioSyncDelay 302 * Signature: (J)V 303 */ 304 JNIEXPORT void JNICALL Java_com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer_osxSetAudioSyncDelay 305 (JNIEnv *env, jobject playerObject, jlong delay) 306 { 307 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 308 OSXMediaPlayer *player = [OSXMediaPlayer peerForPlayer:playerObject andEnv:env]; 309 if (player) { 310 player.audioSyncDelay = (int64_t)delay; 311 } 312 [pool drain]; 313 } 314 315 /* 316 * Class: com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer 317 * Method: osxPlay 318 * Signature: ()V 319 */ 320 JNIEXPORT void JNICALL Java_com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer_osxPlay 321 (JNIEnv *env, jobject playerObject) 322 { 323 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 324 OSXMediaPlayer *player = [OSXMediaPlayer peerForPlayer:playerObject andEnv:env]; 325 if (player) { 326 [player play]; 327 } 328 [pool drain]; 329 } 330 331 /* 332 * Class: com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer 333 * Method: osxStop 334 * Signature: ()V 335 */ 336 JNIEXPORT void JNICALL Java_com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer_osxStop 337 (JNIEnv *env, jobject playerObject) 338 { 339 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 340 OSXMediaPlayer *player = [OSXMediaPlayer peerForPlayer:playerObject andEnv:env]; 341 if (player) { 342 [player stop]; 343 } 344 [pool drain]; 345 } 346 347 /* 348 * Class: com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer 349 * Method: osxPause 350 * Signature: ()V 351 */ 352 JNIEXPORT void JNICALL Java_com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer_osxPause 353 (JNIEnv *env, jobject playerObject) 354 { 355 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 356 OSXMediaPlayer *player = [OSXMediaPlayer peerForPlayer:playerObject andEnv:env]; 357 if (player) { 358 [player pause]; 359 } 360 [pool drain]; 361 } 362 363 /* 364 * Class: com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer 365 * Method: osxFinish 366 * Signature: ()V 367 */ 368 JNIEXPORT void JNICALL Java_com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer_osxFinish 369 (JNIEnv *env, jobject playerObject) 370 { 371 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 372 OSXMediaPlayer *player = [OSXMediaPlayer peerForPlayer:playerObject andEnv:env]; 373 if (player) { 374 [player finish]; 375 } 376 [pool drain]; 377 } 378 379 /* 380 * Class: com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer 381 * Method: osxGetRate 382 * Signature: ()F 383 */ 384 JNIEXPORT jfloat JNICALL Java_com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer_osxGetRate 385 (JNIEnv *env, jobject playerObject) 386 { 387 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 388 OSXMediaPlayer *player = [OSXMediaPlayer peerForPlayer:playerObject andEnv:env]; 389 jfloat rc = 0.0; 390 if (player) { 391 rc = (jfloat)player.rate; 392 } 393 [pool drain]; 394 return rc; 395 } 396 397 /* 398 * Class: com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer 399 * Method: osxSetRate 400 * Signature: (F)V 401 */ 402 JNIEXPORT void JNICALL Java_com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer_osxSetRate 403 (JNIEnv *env, jobject playerObject, jfloat rate) 404 { 405 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 406 OSXMediaPlayer *player = [OSXMediaPlayer peerForPlayer:playerObject andEnv:env]; 407 if (player) { 408 player.rate = (double)rate; 409 } 410 [pool drain]; 411 } 412 413 /* 414 * Class: com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer 415 * Method: osxGetPresentationTime 416 * Signature: ()D 417 */ 418 JNIEXPORT jdouble JNICALL Java_com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer_osxGetPresentationTime 419 (JNIEnv *env, jobject playerObject) 420 { 421 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 422 OSXMediaPlayer *player = [OSXMediaPlayer peerForPlayer:playerObject andEnv:env]; 423 jdouble rc = 0.0; 424 if (player) { 425 rc = player.currentTime; 426 } 427 [pool drain]; 428 return rc; 429 } 430 431 /* 432 * Class: com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer 433 * Method: osxGetMute 434 * Signature: ()Z 435 */ 436 JNIEXPORT jboolean JNICALL Java_com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer_osxGetMute 437 (JNIEnv *env, jobject playerObject) 438 { 439 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 440 OSXMediaPlayer *player = [OSXMediaPlayer peerForPlayer:playerObject andEnv:env]; 441 jboolean rc = JNI_FALSE; 442 if (player) { 443 rc = (player.mute != NO); 444 } 445 [pool drain]; 446 return rc; 447 } 448 449 /* 450 * Class: com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer 451 * Method: osxSetMute 452 * Signature: (Z)V 453 */ 454 JNIEXPORT void JNICALL Java_com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer_osxSetMute 455 (JNIEnv *env, jobject playerObject, jboolean mute) 456 { 457 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 458 OSXMediaPlayer *player = [OSXMediaPlayer peerForPlayer:playerObject andEnv:env]; 459 if (player) { 460 player.mute = (mute != JNI_FALSE); 461 } 462 [pool drain]; 463 } 464 465 /* 466 * Class: com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer 467 * Method: osxGetVolume 468 * Signature: ()F 469 */ 470 JNIEXPORT jfloat JNICALL Java_com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer_osxGetVolume 471 (JNIEnv *env, jobject playerObject) 472 { 473 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 474 OSXMediaPlayer *player = [OSXMediaPlayer peerForPlayer:playerObject andEnv:env]; 475 jfloat rc = 0.0; 476 if (player) { 477 rc = (jfloat)player.volume; 478 } 479 [pool drain]; 480 return rc; 481 } 482 483 /* 484 * Class: com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer 485 * Method: osxSetVolume 486 * Signature: (F)V 487 */ 488 JNIEXPORT void JNICALL Java_com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer_osxSetVolume 489 (JNIEnv *env, jobject playerObject, jfloat volume) 490 { 491 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 492 OSXMediaPlayer *player = [OSXMediaPlayer peerForPlayer:playerObject andEnv:env]; 493 if (player) { 494 player.volume = (double)volume; 495 } 496 [pool drain]; 497 } 498 499 /* 500 * Class: com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer 501 * Method: osxGetBalance 502 * Signature: ()F 503 */ 504 JNIEXPORT jfloat JNICALL Java_com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer_osxGetBalance 505 (JNIEnv *env, jobject playerObject) 506 { 507 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 508 OSXMediaPlayer *player = [OSXMediaPlayer peerForPlayer:playerObject andEnv:env]; 509 jfloat rc = 0.0; 510 if (player) { 511 rc = (jfloat)player.balance; 512 } 513 [pool drain]; 514 return rc; 515 } 516 517 /* 518 * Class: com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer 519 * Method: osxSetBalance 520 * Signature: (F)V 521 */ 522 JNIEXPORT void JNICALL Java_com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer_osxSetBalance 523 (JNIEnv *env, jobject playerObject, jfloat balance) 524 { 525 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 526 OSXMediaPlayer *player = [OSXMediaPlayer peerForPlayer:playerObject andEnv:env]; 527 if (player) { 528 player.balance = (double)balance; 529 } 530 [pool drain]; 531 } 532 533 /* 534 * Class: com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer 535 * Method: osxGetDuration 536 * Signature: ()D 537 */ 538 JNIEXPORT jdouble JNICALL Java_com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer_osxGetDuration 539 (JNIEnv *env, jobject playerObject) 540 { 541 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 542 OSXMediaPlayer *player = [OSXMediaPlayer peerForPlayer:playerObject andEnv:env]; 543 double duration = -1.0; 544 if (player) { 545 duration = (jdouble)player.duration; 546 } 547 [pool drain]; 548 return duration; 549 } 550 551 /* 552 * Class: com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer 553 * Method: osxSeek 554 * Signature: (D)V 555 */ 556 JNIEXPORT void JNICALL Java_com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer_osxSeek 557 (JNIEnv *env, jobject playerObject, jdouble time) 558 { 559 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 560 OSXMediaPlayer *player = [OSXMediaPlayer peerForPlayer:playerObject andEnv:env]; 561 if (player) { 562 player.currentTime = (double)time; 563 } 564 [pool drain]; 565 } 566 567 /* 568 * Class: com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer 569 * Method: osxDispose 570 * Signature: ()V 571 */ 572 JNIEXPORT void JNICALL Java_com_sun_media_jfxmediaimpl_platform_osx_OSXMediaPlayer_osxDispose 573 (JNIEnv *env, jobject playerObject) 574 { 575 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 576 OSXMediaPlayer *player = [OSXMediaPlayer peerForPlayer:playerObject andEnv:env]; 577 if (player) { 578 [player dispose]; 579 580 // This should pop the last retain, aside from the autoreleased reference... 581 [OSXMediaPlayer removePlayerPeers:player]; 582 } 583 [pool drain]; 584 }