MediaPlayer_to_android.cpp revision 4b9966d5e0569707f23ab2b22e584f7117adc179
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "sles_allinclusive.h" 18#include "utils/RefBase.h" 19#include "android_prompts.h" 20// LocAVPlayer and StreamPlayer derive from GenericMediaPlayer, 21// so no need to #include "android_GenericMediaPlayer.h" 22#include "android_LocAVPlayer.h" 23#include "android_StreamPlayer.h" 24 25 26//----------------------------------------------------------------------------- 27static void player_handleMediaPlayerEventNotifications(int event, int data1, int data2, void* user) 28{ 29 if (NULL == user) { 30 return; 31 } 32 33 CMediaPlayer* mp = (CMediaPlayer*) user; 34 SL_LOGV("received event %d, data %d from AVPlayer", event, data1); 35 36 switch(event) { 37 38 case android::GenericPlayer::kEventPrepared: { 39 if (PLAYER_SUCCESS == data1) { 40 object_lock_exclusive(&mp->mObject); 41 SL_LOGV("Received AVPlayer::kEventPrepared from AVPlayer for CMediaPlayer %p", mp); 42 mp->mAndroidObjState = ANDROID_READY; 43 object_unlock_exclusive(&mp->mObject); 44 } 45 break; 46 } 47 48 case android::GenericPlayer::kEventHasVideoSize: { 49 SL_LOGV("Received AVPlayer::kEventHasVideoSize (%d,%d) for CMediaPlayer %p", 50 data1, data2, mp); 51 52 object_lock_exclusive(&mp->mObject); 53 54 // remove an existing video info entry (here we only have one video stream) 55 for(size_t i=0 ; i < mp->mStreamInfo.mStreamInfoTable.size() ; i++) { 56 if (XA_DOMAINTYPE_VIDEO == mp->mStreamInfo.mStreamInfoTable.itemAt(i).domain) { 57 mp->mStreamInfo.mStreamInfoTable.removeAt(i); 58 break; 59 } 60 } 61 // update the stream information with a new video info entry 62 StreamInfo streamInfo; 63 streamInfo.domain = XA_DOMAINTYPE_VIDEO; 64 streamInfo.videoInfo.codecId = 0;// unknown, we don't have that info FIXME 65 streamInfo.videoInfo.width = (XAuint32)data1; 66 streamInfo.videoInfo.height = (XAuint32)data2; 67 streamInfo.videoInfo.bitRate = 0;// unknown, we don't have that info FIXME 68 streamInfo.videoInfo.duration = XA_TIME_UNKNOWN; 69 StreamInfo &contInfo = mp->mStreamInfo.mStreamInfoTable.editItemAt(0); 70 contInfo.containerInfo.numStreams = 1; 71 ssize_t index = mp->mStreamInfo.mStreamInfoTable.add(streamInfo); 72 73 xaStreamEventChangeCallback callback = mp->mStreamInfo.mCallback; 74 void* callbackPContext = mp->mStreamInfo.mContext; 75 76 object_unlock_exclusive(&mp->mObject); 77 78 // enqueue notification (outside of lock) that the stream information has been updated 79 if ((NULL != callback) && (index >= 0)) { 80#ifdef XA_SYNCHRONOUS_STREAMCBEVENT_PROPERTYCHANGE 81 (*callback)(&mp->mStreamInfo.mItf, XA_STREAMCBEVENT_PROPERTYCHANGE /*eventId*/, 82 1 /*streamIndex, only one stream supported here, 0 is reserved*/, 83 NULL /*pEventData, always NULL in OpenMAX AL 1.0.1*/, 84 callbackPContext /*pContext*/); 85#else 86 SLresult res = EnqueueAsyncCallback_piipp(mp, callback, 87 /*p1*/ &mp->mStreamInfo.mItf, 88 /*i1*/ XA_STREAMCBEVENT_PROPERTYCHANGE /*eventId*/, 89 /*i2*/ 1 /*streamIndex, only one stream supported here, 0 is reserved*/, 90 /*p2*/ NULL /*pEventData, always NULL in OpenMAX AL 1.0.1*/, 91 /*p3*/ callbackPContext /*pContext*/); 92#endif 93 } 94 break; 95 } 96 97 case android::GenericPlayer::kEventEndOfStream: { 98 SL_LOGV("Received AVPlayer::kEventEndOfStream for CMediaPlayer %p", mp); 99 100 object_lock_exclusive(&mp->mObject); 101 // should be xaPlayCallback but we're sharing the itf between SL and AL 102 slPlayCallback playCallback = NULL; 103 void * playContext = NULL; 104 // XAPlayItf callback or no callback? 105 if (mp->mPlay.mEventFlags & XA_PLAYEVENT_HEADATEND) { 106 playCallback = mp->mPlay.mCallback; 107 playContext = mp->mPlay.mContext; 108 } 109 mp->mPlay.mState = XA_PLAYSTATE_PAUSED; 110 object_unlock_exclusive(&mp->mObject); 111 112 // enqueue callback with no lock held 113 if (NULL != playCallback) { 114#ifdef XA_SYNCHRONOUS_PLAYEVENT_HEADATEND 115 (*playCallback)(&mp->mPlay.mItf, playContext, XA_PLAYEVENT_HEADATEND); 116#else 117 SLresult res = EnqueueAsyncCallback_ppi(mp, playCallback, &mp->mPlay.mItf, playContext, 118 XA_PLAYEVENT_HEADATEND); 119 LOGW_IF(SL_RESULT_SUCCESS != res, 120 "Callback %p(%p, %p, XA_PLAYEVENT_HEADATEND) dropped", playCallback, 121 &mp->mPlay.mItf, playContext); 122#endif 123 } 124 break; 125 } 126 127 case android::GenericPlayer::kEventChannelCount: { 128 SL_LOGV("kEventChannelCount channels = %d", data1); 129 object_lock_exclusive(&mp->mObject); 130 if (UNKNOWN_NUMCHANNELS == mp->mNumChannels && UNKNOWN_NUMCHANNELS != data1) { 131 mp->mNumChannels = data1; 132 android_Player_volumeUpdate(mp); 133 } 134 object_unlock_exclusive(&mp->mObject); 135 } 136 break; 137 138 case android::GenericPlayer::kEventPrefetchFillLevelUpdate: { 139 SL_LOGV("kEventPrefetchFillLevelUpdate"); 140 } 141 break; 142 143 case android::GenericPlayer::kEventPrefetchStatusChange: { 144 SL_LOGV("kEventPrefetchStatusChange"); 145 } 146 break; 147 148 case android::GenericPlayer::kEventPlay: { 149 SL_LOGV("kEventPlay"); 150 151 interface_lock_shared(&mp->mPlay); 152 slPlayCallback callback = mp->mPlay.mCallback; 153 void* callbackPContext = mp->mPlay.mContext; 154 interface_unlock_shared(&mp->mPlay); 155 156 if (NULL != callback) { 157 (*callback)(&mp->mPlay.mItf, callbackPContext, (SLuint32) data1); // SL_PLAYEVENT_HEAD* 158 } 159 } 160 break; 161 162 default: { 163 SL_LOGE("Received unknown event %d, data %d from AVPlayer", event, data1); 164 } 165 } 166} 167 168 169//----------------------------------------------------------------------------- 170XAresult android_Player_checkSourceSink(CMediaPlayer *mp) { 171 172 XAresult result = XA_RESULT_SUCCESS; 173 174 const SLDataSource *pSrc = &mp->mDataSource.u.mSource; 175 const SLDataSink *pAudioSnk = &mp->mAudioSink.u.mSink; 176 177 // format check: 178 const SLuint32 sourceLocatorType = *(SLuint32 *)pSrc->pLocator; 179 const SLuint32 sourceFormatType = *(SLuint32 *)pSrc->pFormat; 180 const SLuint32 audioSinkLocatorType = *(SLuint32 *)pAudioSnk->pLocator; 181 //const SLuint32 sinkFormatType = *(SLuint32 *)pAudioSnk->pFormat; 182 183 // Source check 184 switch(sourceLocatorType) { 185 186 case XA_DATALOCATOR_ANDROIDBUFFERQUEUE: { 187 switch (sourceFormatType) { 188 case XA_DATAFORMAT_MIME: { 189 SLDataFormat_MIME *df_mime = (SLDataFormat_MIME *) pSrc->pFormat; 190 if (SL_CONTAINERTYPE_MPEG_TS != df_mime->containerType) { 191 SL_LOGE("Cannot create player with XA_DATALOCATOR_ANDROIDBUFFERQUEUE data source " 192 "that is not fed MPEG-2 TS data"); 193 return SL_RESULT_CONTENT_UNSUPPORTED; 194 } 195 } break; 196 default: 197 SL_LOGE("Cannot create player with XA_DATALOCATOR_ANDROIDBUFFERQUEUE data source " 198 "without SL_DATAFORMAT_MIME format"); 199 return XA_RESULT_CONTENT_UNSUPPORTED; 200 } 201 } break; 202 203 case XA_DATALOCATOR_URI: // intended fall-through 204 case XA_DATALOCATOR_ANDROIDFD: 205 break; 206 207 default: 208 SL_LOGE("Cannot create media player with data locator type 0x%x", 209 (unsigned) sourceLocatorType); 210 return SL_RESULT_PARAMETER_INVALID; 211 }// switch (locatorType) 212 213 // Audio sink check: only playback is supported here 214 switch(audioSinkLocatorType) { 215 216 case XA_DATALOCATOR_OUTPUTMIX: 217 break; 218 219 default: 220 SL_LOGE("Cannot create media player with audio sink data locator of type 0x%x", 221 (unsigned) audioSinkLocatorType); 222 return XA_RESULT_PARAMETER_INVALID; 223 }// switch (locaaudioSinkLocatorTypeorType) 224 225 return result; 226} 227 228 229//----------------------------------------------------------------------------- 230XAresult android_Player_create(CMediaPlayer *mp) { 231 232 XAresult result = XA_RESULT_SUCCESS; 233 234 // FIXME verify data source 235 const SLDataSource *pDataSrc = &mp->mDataSource.u.mSource; 236 // FIXME verify audio data sink 237 const SLDataSink *pAudioSnk = &mp->mAudioSink.u.mSink; 238 // FIXME verify image data sink 239 const SLDataSink *pVideoSnk = &mp->mImageVideoSink.u.mSink; 240 241 XAuint32 sourceLocator = *(XAuint32 *)pDataSrc->pLocator; 242 switch(sourceLocator) { 243 // FIXME support Android simple buffer queue as well 244 case XA_DATALOCATOR_ANDROIDBUFFERQUEUE: 245 mp->mAndroidObjType = AUDIOVIDEOPLAYER_FROM_TS_ANDROIDBUFFERQUEUE; 246 break; 247 case XA_DATALOCATOR_URI: // intended fall-through 248 case SL_DATALOCATOR_ANDROIDFD: 249 mp->mAndroidObjType = AUDIOVIDEOPLAYER_FROM_URIFD; 250 break; 251 case XA_DATALOCATOR_ADDRESS: // intended fall-through 252 default: 253 SL_LOGE("Unable to create MediaPlayer for data source locator 0x%x", sourceLocator); 254 result = XA_RESULT_PARAMETER_INVALID; 255 break; 256 } 257 258 // FIXME duplicates an initialization also done by higher level 259 mp->mAndroidObjState = ANDROID_UNINITIALIZED; 260 mp->mStreamType = ANDROID_DEFAULT_OUTPUT_STREAM_TYPE; 261 mp->mSessionId = android::AudioSystem::newAudioSessionId(); 262 263 return result; 264} 265 266 267//----------------------------------------------------------------------------- 268// FIXME abstract out the diff between CMediaPlayer and CAudioPlayer 269XAresult android_Player_realize(CMediaPlayer *mp, SLboolean async) { 270 SL_LOGV("android_Player_realize_l(%p)", mp); 271 XAresult result = XA_RESULT_SUCCESS; 272 273 const SLDataSource *pDataSrc = &mp->mDataSource.u.mSource; 274 const SLuint32 sourceLocator = *(SLuint32 *)pDataSrc->pLocator; 275 276 AudioPlayback_Parameters ap_params; 277 ap_params.sessionId = mp->mSessionId; 278 ap_params.streamType = mp->mStreamType; 279 ap_params.trackcb = NULL; 280 ap_params.trackcbUser = NULL; 281 282 switch(mp->mAndroidObjType) { 283 case AUDIOVIDEOPLAYER_FROM_TS_ANDROIDBUFFERQUEUE: { 284 mp->mAVPlayer = new android::StreamPlayer(&ap_params, true /*hasVideo*/); 285 mp->mAVPlayer->init(player_handleMediaPlayerEventNotifications, (void*)mp); 286 } 287 break; 288 case AUDIOVIDEOPLAYER_FROM_URIFD: { 289 mp->mAVPlayer = new android::LocAVPlayer(&ap_params, true /*hasVideo*/); 290 mp->mAVPlayer->init(player_handleMediaPlayerEventNotifications, (void*)mp); 291 switch (mp->mDataSource.mLocator.mLocatorType) { 292 case XA_DATALOCATOR_URI: 293 ((android::LocAVPlayer*)mp->mAVPlayer.get())->setDataSource( 294 (const char*)mp->mDataSource.mLocator.mURI.URI); 295 break; 296 case XA_DATALOCATOR_ANDROIDFD: { 297 int64_t offset = (int64_t)mp->mDataSource.mLocator.mFD.offset; 298 ((android::LocAVPlayer*)mp->mAVPlayer.get())->setDataSource( 299 (int)mp->mDataSource.mLocator.mFD.fd, 300 offset == SL_DATALOCATOR_ANDROIDFD_USE_FILE_SIZE ? 301 (int64_t)PLAYER_FD_FIND_FILE_SIZE : offset, 302 (int64_t)mp->mDataSource.mLocator.mFD.length); 303 } 304 break; 305 default: 306 SL_LOGE("Invalid or unsupported data locator type %u for data source", 307 mp->mDataSource.mLocator.mLocatorType); 308 result = XA_RESULT_PARAMETER_INVALID; 309 } 310 } 311 break; 312 case INVALID_TYPE: // intended fall-through 313 default: 314 SL_LOGE("Unable to realize MediaPlayer, invalid internal Android object type"); 315 result = XA_RESULT_PARAMETER_INVALID; 316 break; 317 } 318 319 if (XA_RESULT_SUCCESS == result) { 320 321 // if there is a video sink 322 if (XA_DATALOCATOR_NATIVEDISPLAY == 323 mp->mImageVideoSink.mLocator.mLocatorType) { 324 ANativeWindow *nativeWindow = (ANativeWindow *) 325 mp->mImageVideoSink.mLocator.mNativeDisplay.hWindow; 326 // we already verified earlier that hWindow is non-NULL 327 assert(nativeWindow != NULL); 328 result = android_Player_setNativeWindow(mp, nativeWindow); 329 } 330 331 } 332 333 return result; 334} 335 336//----------------------------------------------------------------------------- 337XAresult android_Player_destroy(CMediaPlayer *mp) { 338 SL_LOGV("android_Player_destroy(%p)", mp); 339 XAresult result = XA_RESULT_SUCCESS; 340 341 if (mp->mAVPlayer != 0) { 342 mp->mAVPlayer.clear(); 343 } 344 345 return result; 346} 347 348 349void android_Player_usePlayEventMask(CMediaPlayer *mp) { 350 if (mp->mAVPlayer != 0) { 351 IPlay *pPlayItf = &mp->mPlay; 352 mp->mAVPlayer->setPlayEvents((int32_t) pPlayItf->mEventFlags, 353 (int32_t) pPlayItf->mMarkerPosition, (int32_t) pPlayItf->mPositionUpdatePeriod); 354 } 355} 356 357 358XAresult android_Player_getDuration(IPlay *pPlayItf, XAmillisecond *pDurMsec) { 359 CMediaPlayer *avp = (CMediaPlayer *)pPlayItf->mThis; 360 361 switch (avp->mAndroidObjType) { 362 363 case AUDIOVIDEOPLAYER_FROM_URIFD: { 364 int dur = ANDROID_UNKNOWN_TIME; 365 if (avp->mAVPlayer != 0) { 366 avp->mAVPlayer->getDurationMsec(&dur); 367 } 368 if (dur == ANDROID_UNKNOWN_TIME) { 369 *pDurMsec = XA_TIME_UNKNOWN; 370 } else { 371 *pDurMsec = (XAmillisecond)dur; 372 } 373 } break; 374 375 case AUDIOVIDEOPLAYER_FROM_TS_ANDROIDBUFFERQUEUE: // intended fall-through 376 default: 377 *pDurMsec = XA_TIME_UNKNOWN; 378 break; 379 } 380 381 return XA_RESULT_SUCCESS; 382} 383 384 385XAresult android_Player_getPosition(IPlay *pPlayItf, XAmillisecond *pPosMsec) { 386 SL_LOGD("android_Player_getPosition()"); 387 XAresult result = XA_RESULT_SUCCESS; 388 CMediaPlayer *avp = (CMediaPlayer *)pPlayItf->mThis; 389 390 switch (avp->mAndroidObjType) { 391 392 case AUDIOVIDEOPLAYER_FROM_TS_ANDROIDBUFFERQUEUE: // intended fall-through 393 case AUDIOVIDEOPLAYER_FROM_URIFD: { 394 int pos = -1; 395 if (avp->mAVPlayer != 0) { 396 avp->mAVPlayer->getPositionMsec(&pos); 397 } 398 if (pos == ANDROID_UNKNOWN_TIME) { 399 *pPosMsec = XA_TIME_UNKNOWN; 400 } else { 401 *pPosMsec = (XAmillisecond)pos; 402 } 403 } break; 404 405 default: 406 // we shouldn't be here 407 assert(false); 408 break; 409 } 410 411 return result; 412} 413 414 415//----------------------------------------------------------------------------- 416/** 417 * pre-condition: mp != NULL 418 */ 419void android_Player_volumeUpdate(CMediaPlayer* mp) 420{ 421 android::GenericPlayer* avp = mp->mAVPlayer.get(); 422 if (avp != NULL) { 423 float volumes[2]; 424 // MediaPlayer does not currently support EffectSend or MuteSolo 425 android_player_volumeUpdate(volumes, &mp->mVolume, mp->mNumChannels, 1.0f, NULL); 426 float leftVol = volumes[0], rightVol = volumes[1]; 427 avp->setVolume(leftVol, rightVol); 428 } 429} 430 431//----------------------------------------------------------------------------- 432/** 433 * pre-condition: gp != 0 434 */ 435XAresult android_Player_setPlayState(const android::sp<android::GenericPlayer> &gp, 436 SLuint32 playState, 437 AndroidObjectState* pObjState) 438{ 439 XAresult result = XA_RESULT_SUCCESS; 440 AndroidObjectState objState = *pObjState; 441 442 switch (playState) { 443 case SL_PLAYSTATE_STOPPED: { 444 SL_LOGV("setting AVPlayer to SL_PLAYSTATE_STOPPED"); 445 gp->stop(); 446 } 447 break; 448 case SL_PLAYSTATE_PAUSED: { 449 SL_LOGV("setting AVPlayer to SL_PLAYSTATE_PAUSED"); 450 switch(objState) { 451 case ANDROID_UNINITIALIZED: 452 *pObjState = ANDROID_PREPARING; 453 gp->prepare(); 454 break; 455 case ANDROID_PREPARING: 456 break; 457 case ANDROID_READY: 458 gp->pause(); 459 break; 460 default: 461 SL_LOGE("Android object in invalid state"); 462 break; 463 } 464 } 465 break; 466 case SL_PLAYSTATE_PLAYING: { 467 SL_LOGV("setting AVPlayer to SL_PLAYSTATE_PLAYING"); 468 switch(objState) { 469 case ANDROID_UNINITIALIZED: 470 *pObjState = ANDROID_PREPARING; 471 gp->prepare(); 472 // intended fall through 473 case ANDROID_PREPARING: 474 // intended fall through 475 case ANDROID_READY: 476 gp->play(); 477 break; 478 default: 479 SL_LOGE("Android object in invalid state"); 480 break; 481 } 482 } 483 break; 484 default: 485 // checked by caller, should not happen 486 break; 487 } 488 489 return result; 490} 491 492 493/** 494 * pre-condition: mp != NULL 495 */ 496XAresult android_Player_seek(CMediaPlayer *mp, SLmillisecond posMsec) { 497 XAresult result = XA_RESULT_SUCCESS; 498 switch (mp->mAndroidObjType) { 499 case AUDIOVIDEOPLAYER_FROM_URIFD: 500 if (mp->mAVPlayer !=0) { 501 mp->mAVPlayer->seek(posMsec); 502 } 503 break; 504 case AUDIOVIDEOPLAYER_FROM_TS_ANDROIDBUFFERQUEUE: // intended fall-through 505 default: { 506 result = XA_RESULT_PARAMETER_INVALID; 507 } 508 } 509 return result; 510} 511 512 513/** 514 * pre-condition: mp != NULL 515 */ 516XAresult android_Player_loop(CMediaPlayer *mp, SLboolean loopEnable) { 517 XAresult result = XA_RESULT_SUCCESS; 518 switch (mp->mAndroidObjType) { 519 case AUDIOVIDEOPLAYER_FROM_URIFD: 520 if (mp->mAVPlayer !=0) { 521 mp->mAVPlayer->loop(loopEnable); 522 } 523 break; 524 case AUDIOVIDEOPLAYER_FROM_TS_ANDROIDBUFFERQUEUE: // intended fall-through 525 default: { 526 result = XA_RESULT_PARAMETER_INVALID; 527 } 528 } 529 return result; 530} 531 532 533//----------------------------------------------------------------------------- 534void android_Player_androidBufferQueue_registerCallback_l(CMediaPlayer *mp) { 535 if ((mp->mAndroidObjType == AUDIOVIDEOPLAYER_FROM_TS_ANDROIDBUFFERQUEUE) 536 && (mp->mAVPlayer != 0)) { 537 SL_LOGD("android_Player_androidBufferQueue_registerCallback_l"); 538 android::StreamPlayer* splr = static_cast<android::StreamPlayer*>(mp->mAVPlayer.get()); 539 splr->registerQueueCallback( 540 (const void*)mp, false /*userIsAudioPlayer*/, 541 mp->mAndroidBufferQueue.mContext, (const void*)&(mp->mAndroidBufferQueue.mItf)); 542 543 } 544} 545 546 547void android_Player_androidBufferQueue_clear_l(CMediaPlayer *mp) { 548 if ((mp->mAndroidObjType == AUDIOVIDEOPLAYER_FROM_TS_ANDROIDBUFFERQUEUE) 549 && (mp->mAVPlayer != 0)) { 550 android::StreamPlayer* splr = static_cast<android::StreamPlayer*>(mp->mAVPlayer.get()); 551 splr->appClear_l(); 552 } 553} 554 555 556void android_Player_androidBufferQueue_onRefilled_l(CMediaPlayer *mp) { 557 if ((mp->mAndroidObjType == AUDIOVIDEOPLAYER_FROM_TS_ANDROIDBUFFERQUEUE) 558 && (mp->mAVPlayer != 0)) { 559 android::StreamPlayer* splr = static_cast<android::StreamPlayer*>(mp->mAVPlayer.get()); 560 splr->queueRefilled_l(); 561 } 562} 563 564 565/* 566 * pre-conditions: 567 * mp != NULL 568 * mp->mAVPlayer != 0 (player is realized) 569 * nativeWindow can be NULL, but if NULL it is treated as an error 570 */ 571SLresult android_Player_setNativeWindow(CMediaPlayer *mp, ANativeWindow *nativeWindow) 572{ 573 assert(mp != NULL); 574 assert(mp->mAVPlayer != 0); 575 if (nativeWindow == NULL) { 576 SL_LOGE("ANativeWindow is NULL"); 577 return SL_RESULT_PARAMETER_INVALID; 578 } 579 SLresult result; 580 int err; 581 int value; 582 // this could crash if app passes in a bad parameter, but that's OK 583 err = (*nativeWindow->query)(nativeWindow, NATIVE_WINDOW_CONCRETE_TYPE, &value); 584 if (0 != err) { 585 SL_LOGE("Query NATIVE_WINDOW_CONCRETE_TYPE on ANativeWindow * %p failed; " 586 "errno %d", nativeWindow, err); 587 result = SL_RESULT_PARAMETER_INVALID; 588 } else { 589 switch (value) { 590 case NATIVE_WINDOW_SURFACE: { // Surface 591 SL_LOGV("Displaying on ANativeWindow of type NATIVE_WINDOW_SURFACE"); 592 android::sp<android::Surface> nativeSurface( 593 static_cast<android::Surface *>(nativeWindow)); 594 mp->mAVPlayer->setVideoSurface(nativeSurface); 595 result = SL_RESULT_SUCCESS; 596 } break; 597 case NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT: { // SurfaceTextureClient 598 SL_LOGV("Displaying on ANativeWindow of type NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT"); 599 android::sp<android::SurfaceTextureClient> surfaceTextureClient( 600 static_cast<android::SurfaceTextureClient *>(nativeWindow)); 601 android::sp<android::ISurfaceTexture> nativeSurfaceTexture( 602 surfaceTextureClient->getISurfaceTexture()); 603 mp->mAVPlayer->setVideoSurfaceTexture(nativeSurfaceTexture); 604 result = SL_RESULT_SUCCESS; 605 } break; 606 case NATIVE_WINDOW_FRAMEBUFFER: // FramebufferNativeWindow 607 // fall through 608 default: 609 SL_LOGE("ANativeWindow * %p has unknown or unsupported concrete type %d", 610 nativeWindow, value); 611 result = SL_RESULT_PARAMETER_INVALID; 612 break; 613 } 614 } 615 return result; 616} 617