3 ** Copyright 2007, The Android Open Source Project
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
9 ** http://www.apache.org/licenses/LICENSE-2.0
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
18 //#define LOG_NDEBUG 0
19 #define LOG_TAG "PlayerDriver"
20 #include <utils/Log.h>
22 #include <sys/prctl.h>
23 #include <sys/resource.h>
24 #include <media/mediaplayer.h>
25 #include <media/thread_init.h>
26 #include <utils/threads.h>
27 #include "playerdriver.h"
28 #include "PVPlayerExtHandler.h"
30 using namespace android;
33 # define PAGESIZE 4096
36 // library and function name to retrieve device-specific MIOs
37 static const char* MIO_LIBRARY_NAME = "libopencorehw.so";
38 static const char* VIDEO_MIO_FACTORY_NAME = "createVideoMio";
39 typedef AndroidSurfaceOutput* (*VideoMioFactory)();
44 // For the event's buffer format is:
46 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
47 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48 // | buffering percent |
49 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51 // @param buffer Pointer to the start of the buffering status data.
52 // @param size Of the buffer
53 // @param[out] percentage On return contains the amout of buffering.
54 // The value is in [0,100]
55 // @return true if a valid buffering update was found. false otherwise.
56 bool GetBufferingPercentage(const void *buffer,
61 LOGE("Invalid buffer: NULL");
64 if (sizeof(int) != size)
66 LOGE("Invalid percentage buffer size %d (expected %d)", size, sizeof(int));
69 // TODO: The PVEvent class should expose a memcopy method
70 // that does bound checking instead of having clients reaching
71 // for its internal buffer.
72 oscl_memcpy(percentage, buffer, sizeof(int));
74 // Clamp the value and complain loudly.
75 if (*percentage < 0 || *percentage > 100)
77 LOGE("Invalid percentage value %d", *percentage);
83 // Macro used in a switch statement to convert a PlayerCommand code into its
84 // string representation.
86 #error "CONSIDER_CODE already defined!!"
88 #define CONSIDER_CODE(val) case ::PlayerCommand::val: return #val
90 // Convert a command code into a string for logging purposes.
91 // @param code Of the command.
92 // @return a string representation of the command type.
93 const char *PlayerCommandCodeToString(PlayerCommand::Code code) {
95 CONSIDER_CODE(PLAYER_QUIT);
96 CONSIDER_CODE(PLAYER_SETUP);
97 CONSIDER_CODE(PLAYER_SET_DATA_SOURCE);
98 CONSIDER_CODE(PLAYER_SET_VIDEO_SURFACE);
99 CONSIDER_CODE(PLAYER_SET_AUDIO_SINK);
100 CONSIDER_CODE(PLAYER_INIT);
101 CONSIDER_CODE(PLAYER_PREPARE);
102 CONSIDER_CODE(PLAYER_START);
103 CONSIDER_CODE(PLAYER_STOP);
104 CONSIDER_CODE(PLAYER_PAUSE);
105 CONSIDER_CODE(PLAYER_RESET);
106 CONSIDER_CODE(PLAYER_SET_LOOP);
107 CONSIDER_CODE(PLAYER_SEEK);
108 CONSIDER_CODE(PLAYER_GET_POSITION);
109 CONSIDER_CODE(PLAYER_GET_DURATION);
110 CONSIDER_CODE(PLAYER_GET_STATUS);
111 CONSIDER_CODE(PLAYER_REMOVE_DATA_SOURCE);
112 CONSIDER_CODE(PLAYER_CANCEL_ALL_COMMANDS);
113 CONSIDER_CODE(PLAYER_EXTENSION_COMMAND);
114 default: return "UNKNOWN PlayerCommand code";
119 // Map a PV status code to a message type (error/info/nop)
120 // @param status PacketVideo status code as defined in pvmf_return_codes.h
121 // @return the corresponding android message type. MEDIA_NOP is used as a default.
122 ::android::media_event_type MapStatusToEventType(const PVMFStatus status) {
123 if (status <= PVMFErrFirst) {
124 return ::android::MEDIA_ERROR;
125 } else if (status >= PVMFInfoFirst) {
126 return ::android::MEDIA_INFO;
128 return ::android::MEDIA_NOP;
132 // Map a PV status to an error/info code.
133 // @param status PacketVideo status code as defined in pvmf_return_codes.h
134 // @return the corresponding android error/info code.
135 int MapStatusToEventCode(const PVMFStatus status) {
137 case PVMFErrContentInvalidForProgressivePlayback :
138 LOGE("PVMFErrContentInvalidForProgressivePlayback event recieved");
139 return ::android::MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK;
142 // Takes advantage that both error and info codes are mapped to the
144 assert(::android::MEDIA_ERROR_UNKNOWN == ::android::MEDIA_INFO_UNKNOWN);
145 return ::android::MEDIA_ERROR_UNKNOWN;
149 } // anonymous namespace
152 PlayerDriver::PlayerDriver(PVPlayer* pvPlayer) :
153 OsclActiveObject(OsclActiveObject::EPriorityNominal, "PVPlayerPlayer"),
157 mDataReadyReceived(false),
163 mIsLiveStreaming(false),
167 mSyncSem = new OsclSemaphore();
173 mAudioOutputMIO = NULL;
176 mVideoOutputMIO = NULL;
178 mPlayerCapConfig = NULL;
179 mDownloadContextData = NULL;
180 mLocalContextData = NULL;
181 mExtensionHandler = NULL;
183 // running in emulation?
185 char value[PROPERTY_VALUE_MAX];
186 if (property_get("ro.kernel.qemu", value, 0)) {
188 LOGV("Emulation mode - using software codecs");
190 // attempt to open h/w specific library
191 mLibHandle = ::dlopen(MIO_LIBRARY_NAME, RTLD_NOW);
192 if (mLibHandle != NULL) {
193 LOGV("OpenCore hardware module loaded");
195 LOGV("OpenCore hardware module not found");
199 // start player thread
200 LOGV("start player thread");
201 createThreadEtc(PlayerDriver::startPlayerThread, this, "PV player");
203 // mSyncSem will be signaled when the scheduler has started
205 mExtensionHandler = new PVPlayerExtensionHandler(*this);
206 if(!mExtensionHandler){
207 LOGV("No ExtensionHandler, Out of memory");
211 PlayerDriver::~PlayerDriver()
214 if (mLibHandle != NULL) {
215 ::dlclose(mLibHandle);
217 if(mExtensionHandler){
218 delete mExtensionHandler; mExtensionHandler=NULL;
222 PlayerCommand* PlayerDriver::dequeueCommand()
224 PlayerCommand* command;
228 // XXX should we assert here?
229 if (mCommandQueue.empty()) {
235 command = *(--mCommandQueue.end());
236 mCommandQueue.erase(--mCommandQueue.end());
237 if (mCommandQueue.size() > 0 )
250 status_t PlayerDriver::enqueueCommand(PlayerCommand* command)
252 if (mPlayer == NULL) {
253 // Only commands which can come in this use-case is PLAYER_SETUP and PLAYER_QUIT
254 // The calling function should take responsibility to delete the command and cleanup
258 OsclSemaphore *syncsemcopy = NULL;
260 // If the user didn't specify a completion callback, we
261 // are running in synchronous mode.
262 if (!command->hasCallback()) {
263 command->set(PlayerDriver::syncCompletion, this);
264 // make a copy of this semaphore for special handling of the PLAYER_QUIT code
265 syncsemcopy = mSyncSem;
268 // Add the code to the queue.
270 mCommandQueue.push_front(command);
272 // save code, since command will be deleted by the standard completion function
273 int code = command->code();
275 // AO needs to be scheduled only if this is the first cmd after queue was empty
276 if (mCommandQueue.size() == 1)
278 PendComplete(OSCL_REQUEST_ERR_NONE);
282 // If we are in synchronous mode, wait for completion.
285 if (code == PlayerCommand::PLAYER_QUIT) {
286 syncsemcopy->Close();
296 void PlayerDriver::FinishSyncCommand(PlayerCommand* command)
298 command->complete(NO_ERROR, false);
302 // The OSCL scheduler calls this when we get to run (this should happen only
303 // when a code has been enqueued for us).
304 void PlayerDriver::Run()
308 PVPPlaybackPosition begin, end;
309 begin.iIndeterminate = false;
310 begin.iPosUnit = PVPPBPOSUNIT_SEC;
311 begin.iPosValue.sec_value = 0;
312 begin.iMode = PVPPBPOS_MODE_NOW;
313 end.iIndeterminate = true;
314 mPlayer->SetPlaybackRange(begin, end, false, NULL);
319 PVPlayerState state = PVP_STATE_ERROR;
320 if ((mPlayer->GetPVPlayerStateSync(state) == PVMFSuccess))
322 if (state == PVP_STATE_ERROR)
329 PlayerCommand* command;
331 command = dequeueCommand();
333 LOGV("Send player code: %d", command->code());
335 switch (command->code()) {
336 case PlayerCommand::PLAYER_SETUP:
337 handleSetup(static_cast<PlayerSetup*>(command));
340 case PlayerCommand::PLAYER_SET_DATA_SOURCE:
341 handleSetDataSource(static_cast<PlayerSetDataSource*>(command));
344 case PlayerCommand::PLAYER_SET_VIDEO_SURFACE:
345 handleSetVideoSurface(static_cast<PlayerSetVideoSurface*>(command));
348 case PlayerCommand::PLAYER_SET_AUDIO_SINK:
349 handleSetAudioSink(static_cast<PlayerSetAudioSink*>(command));
352 case PlayerCommand::PLAYER_INIT:
353 handleInit(static_cast<PlayerInit*>(command));
356 case PlayerCommand::PLAYER_PREPARE:
357 handlePrepare(static_cast<PlayerPrepare*>(command));
360 case PlayerCommand::PLAYER_START:
361 handleStart(static_cast<PlayerStart*>(command));
364 case PlayerCommand::PLAYER_STOP:
365 handleStop(static_cast<PlayerStop*>(command));
368 case PlayerCommand::PLAYER_PAUSE:
370 if(mIsLiveStreaming) {
371 LOGW("Pause denied");
372 FinishSyncCommand(command);
375 handlePause(static_cast<PlayerPause*>(command));
379 case PlayerCommand::PLAYER_SEEK:
381 if(mIsLiveStreaming) {
383 mPvPlayer->sendEvent(MEDIA_SEEK_COMPLETE);
384 FinishSyncCommand(command);
387 handleSeek(static_cast<PlayerSeek*>(command));
391 case PlayerCommand::PLAYER_GET_POSITION:
392 handleGetPosition(static_cast<PlayerGetPosition*>(command));
393 FinishSyncCommand(command);
396 case PlayerCommand::PLAYER_GET_STATUS:
397 handleGetStatus(static_cast<PlayerGetStatus*>(command));
398 FinishSyncCommand(command);
401 case PlayerCommand::PLAYER_CHECK_LIVE_STREAMING:
402 handleCheckLiveStreaming(static_cast<PlayerCheckLiveStreaming*>(command));
405 case PlayerCommand::PLAYER_GET_DURATION:
406 handleGetDuration(static_cast<PlayerGetDuration*>(command));
409 case PlayerCommand::PLAYER_REMOVE_DATA_SOURCE:
410 handleRemoveDataSource(static_cast<PlayerRemoveDataSource*>(command));
413 case PlayerCommand::PLAYER_CANCEL_ALL_COMMANDS:
414 handleCancelAllCommands(static_cast<PlayerCancelAllCommands*>(command));
417 case PlayerCommand::PLAYER_RESET:
418 handleReset(static_cast<PlayerReset*>(command));
421 case PlayerCommand::PLAYER_QUIT:
422 handleQuit(static_cast<PlayerQuit*>(command));
425 case PlayerCommand::PLAYER_SET_LOOP:
426 mIsLooping = static_cast<PlayerSetLoop*>(command)->loop();
427 FinishSyncCommand(command);
430 case PlayerCommand::PLAYER_EXTENSION_COMMAND:
431 handleExtensionCommand(static_cast<PlayerExtensionCommand*>(command));
434 LOGE("Unexpected code %d", command->code());
441 void PlayerDriver::commandFailed(PlayerCommand* command)
443 if (command == NULL) {
444 LOGV("async code failed");
448 LOGV("Command failed: %d", command->code());
449 command->complete(UNKNOWN_ERROR, false);
453 void PlayerDriver::handleSetup(PlayerSetup* command)
457 // Make sure we have the capabilities and config interface first.
458 OSCL_TRY(error, mPlayer->QueryInterface(PVMI_CAPABILITY_AND_CONFIG_PVUUID,
459 (PVInterface *&)mPlayerCapConfig, command));
460 OSCL_FIRST_CATCH_ANY(error, commandFailed(command));
463 int PlayerDriver::setupHttpStreamPre()
465 mDataSource->SetDataSourceFormatType((char*)PVMF_MIME_DATA_SOURCE_HTTP_URL);
467 delete mDownloadContextData;
468 mDownloadContextData = NULL;
470 mDownloadContextData = new PVMFSourceContextData();
471 mDownloadContextData->EnableCommonSourceContext();
472 mDownloadContextData->EnableDownloadHTTPSourceContext();
474 mDownloadConfigFilename = _STRLIT_WCHAR("/tmp/http-stream-cfg");
475 mDownloadFilename = NULL;
476 mDownloadProxy = _STRLIT_CHAR("");
478 mDownloadContextData->DownloadHTTPData()->iMaxFileSize = 0xFFFFFFFF;
479 mDownloadContextData->DownloadHTTPData()->iPlaybackControl = PVMFSourceContextDataDownloadHTTP::ENoSaveToFile;
480 mDownloadContextData->DownloadHTTPData()->iConfigFileName = mDownloadConfigFilename;
481 mDownloadContextData->DownloadHTTPData()->iDownloadFileName = mDownloadFilename;
482 mDownloadContextData->DownloadHTTPData()->iProxyName = mDownloadProxy;
483 mDownloadContextData->DownloadHTTPData()->iProxyPort = 0;
484 mDownloadContextData->DownloadHTTPData()->bIsNewSession = true;
486 mDataSource->SetDataSourceContextData(mDownloadContextData);
491 int PlayerDriver::setupHttpStreamPost()
493 PvmiKvp iKVPSetAsync;
494 OSCL_StackString<64> iKeyStringSetAsync;
495 PvmiKvp *iErrorKVP = NULL;
499 iKeyStringSetAsync=_STRLIT_CHAR("x-pvmf/net/http-timeout;valtype=uint32");
500 iKVPSetAsync.key=iKeyStringSetAsync.get_str();
501 iKVPSetAsync.value.uint32_value=20;
503 OSCL_TRY(error, mPlayerCapConfig->setParametersSync(NULL, &iKVPSetAsync, 1, iErrorKVP));
504 OSCL_FIRST_CATCH_ANY(error, return -1);
506 iKeyStringSetAsync=_STRLIT_CHAR("x-pvmf/net/num-redirect-attempts;valtype=uint32");
507 iKVPSetAsync.key=iKeyStringSetAsync.get_str();
508 iKVPSetAsync.value.uint32_value=4;
510 OSCL_TRY(error, mPlayerCapConfig->setParametersSync(NULL, &iKVPSetAsync, 1, iErrorKVP));
511 OSCL_FIRST_CATCH_ANY(error, return -1);
513 // enable or disable HEAD request
514 iKeyStringSetAsync=_STRLIT_CHAR("x-pvmf/net/http-header-request-disabled;valtype=bool");
515 iKVPSetAsync.key=iKeyStringSetAsync.get_str();
516 iKVPSetAsync.value.bool_value=false;
518 OSCL_TRY(error, mPlayerCapConfig->setParametersSync(NULL, &iKVPSetAsync, 1, iErrorKVP));
519 OSCL_FIRST_CATCH_ANY(error, return -1);
521 iKeyStringSetAsync=_STRLIT_CHAR("x-pvmf/net/max-tcp-recv-buffer-size-download;valtype=uint32");
522 iKVPSetAsync.key=iKeyStringSetAsync.get_str();
523 iKVPSetAsync.value.uint32_value=64000;
525 OSCL_TRY(error, mPlayerCapConfig->setParametersSync(NULL, &iKVPSetAsync, 1, iErrorKVP));
526 OSCL_FIRST_CATCH_ANY(error, return -1);
531 void PlayerDriver::handleSetDataSource(PlayerSetDataSource* command)
533 LOGV("handleSetDataSource");
535 const char* url = command->url();
536 int lengthofurl = strlen(url);
537 oscl_wchar output[lengthofurl + 1];
538 OSCL_wHeapString<OsclMemAllocator> wFileName;
545 // Create a URL datasource to feed PVPlayer
546 mDataSource = new PVPlayerDataSourceURL();
547 oscl_UTF8ToUnicode(url, strlen(url), output, lengthofurl+1);
548 wFileName.set(output, oscl_strlen(output));
549 mDataSource->SetDataSourceURL(wFileName);
550 LOGV("handleSetDataSource- scanning for extension");
551 if (strncmp(url, "rtsp:", strlen("rtsp:")) == 0) {
552 mDataSource->SetDataSourceFormatType((const char*)PVMF_MIME_DATA_SOURCE_RTSP_URL);
553 } else if (strncmp(url, "http:", strlen("http:")) == 0) {
554 if (0!=setupHttpStreamPre())
556 commandFailed(command);
560 LOGV("handleSetDataSource - called with a filepath - %s",url);
561 mDataSource->SetDataSourceFormatType((const char*)PVMF_MIME_FORMAT_UNKNOWN); // Let PV figure it out
562 delete mLocalContextData;
563 mLocalContextData = NULL;
564 const char* ext = strrchr(url, '.');
565 if (ext && ( strcasecmp(ext, ".sdp") == 0) ) {
566 // For SDP files, currently there is no recognizer. So, to play from such files,
567 // there is a need to set the format type.
568 mDataSource->SetDataSourceFormatType((const char*)PVMF_MIME_DATA_SOURCE_SDP_FILE);
570 mLocalContextData = new PVMFSourceContextData();
571 mLocalContextData->EnableCommonSourceContext();
572 mDataSource->SetDataSourceContextData((OsclAny*)mLocalContextData);
574 OSCL_TRY(error, mPlayer->AddDataSource(*mDataSource, command));
575 OSCL_FIRST_CATCH_ANY(error, commandFailed(command));
578 void PlayerDriver::handleInit(PlayerInit* command)
582 if (mDownloadContextData) {
583 setupHttpStreamPost();
586 if (mLocalContextData) {
587 PvmiKvp iKVPSetAsync;
590 OSCL_StackString<64> iKeyStringSetAsync=_STRLIT_CHAR("x-pvmf/parser/mp4ff-open-file-once-per-track;valtype=bool");
591 iKVPSetAsync.key=iKeyStringSetAsync.get_str();
592 iKVPSetAsync.value.bool_value=false;
593 PvmiKvp* iErrorKVP=NULL;
594 OSCL_TRY(error, mPlayerCapConfig->setParametersSync(NULL, &iKVPSetAsync, 1, iErrorKVP));
595 OSCL_FIRST_CATCH_ANY(error, return;);
599 PvmiKvp iKVPSetAsync;
600 OSCL_StackString<64> iKeyStringSetAsync;
601 iKeyStringSetAsync=_STRLIT_CHAR("x-pvmf/net/user-agent;valtype=wchar*");
602 iKVPSetAsync.key=iKeyStringSetAsync.get_str();
603 // The CORE and OpenCORE versions are set and maintained by PV
604 OSCL_wHeapString<OsclMemAllocator> userAgent = _STRLIT_WCHAR("CORE/8.507.1.1 OpenCORE/2.07 (Linux;Android ");
606 #if (PROPERTY_VALUE_MAX < 8)
607 #error "PROPERTY_VALUE_MAX must be at least 8"
609 char value[PROPERTY_VALUE_MAX];
610 int len = property_get("ro.build.version.release", value, "Unknown");
612 LOGV("release string is %s len %d", value, len);
613 oscl_wchar output[len+ 1];
614 oscl_UTF8ToUnicode(value, len, output, len+1);
617 userAgent += _STRLIT_WCHAR(")");
619 iKVPSetAsync.value.pWChar_value=userAgent.get_str();
621 PvmiKvp *iErrorKVP = NULL;
622 OSCL_TRY(error, mPlayerCapConfig->setParametersSync(NULL, &iKVPSetAsync, 1, iErrorKVP));
623 OSCL_FIRST_CATCH_ANY(error,
624 LOGE("handleInit- setParametersSync ERROR setting useragent");
628 OSCL_TRY(error, mPlayer->Init(command));
629 OSCL_FIRST_CATCH_ANY(error, commandFailed(command));
632 void PlayerDriver::handleSetVideoSurface(PlayerSetVideoSurface* command)
635 AndroidSurfaceOutput* mio = NULL;
637 // attempt to load device-specific video MIO
638 if (mLibHandle != NULL) {
639 VideoMioFactory f = (VideoMioFactory) ::dlsym(mLibHandle, VIDEO_MIO_FACTORY_NAME);
645 // if no device-specific MIO was created, use the generic one
647 LOGW("Using generic video MIO");
648 mio = new AndroidSurfaceOutput();
651 // initialize the MIO parameters
652 status_t ret = mio->set(mPvPlayer, command->surface(), mEmulation);
653 if (ret != NO_ERROR) {
654 LOGE("Video MIO set failed");
655 commandFailed(command);
659 mVideoOutputMIO = mio;
661 mVideoNode = PVMediaOutputNodeFactory::CreateMediaOutputNode(mVideoOutputMIO);
662 mVideoSink = new PVPlayerDataSinkPVMFNode;
664 ((PVPlayerDataSinkPVMFNode *)mVideoSink)->SetDataSinkNode(mVideoNode);
666 OSCL_TRY(error, mPlayer->AddDataSink(*mVideoSink, command));
667 OSCL_FIRST_CATCH_ANY(error, commandFailed(command));
670 void PlayerDriver::handleSetAudioSink(PlayerSetAudioSink* command)
673 if (command->audioSink()->realtime()) {
674 LOGV("Create realtime output");
675 mAudioOutputMIO = new AndroidAudioOutput();
677 LOGV("Create stream output");
678 mAudioOutputMIO = new AndroidAudioStream();
680 mAudioOutputMIO->setAudioSink(command->audioSink());
682 mAudioNode = PVMediaOutputNodeFactory::CreateMediaOutputNode(mAudioOutputMIO);
683 mAudioSink = new PVPlayerDataSinkPVMFNode;
685 ((PVPlayerDataSinkPVMFNode *)mAudioSink)->SetDataSinkNode(mAudioNode);
687 OSCL_TRY(error, mPlayer->AddDataSink(*mAudioSink, command));
688 OSCL_FIRST_CATCH_ANY(error, commandFailed(command));
691 void PlayerDriver::handlePrepare(PlayerPrepare* command)
693 //Keep alive is sent during the play to prevent the firewall from closing ports while
694 //streaming long clip
695 PvmiKvp iKVPSetAsync;
696 OSCL_StackString<64> iKeyStringSetAsync;
697 PvmiKvp *iErrorKVP = NULL;
699 iKeyStringSetAsync=_STRLIT_CHAR("x-pvmf/net/keep-alive-during-play;valtype=bool");
700 iKVPSetAsync.key=iKeyStringSetAsync.get_str();
701 iKVPSetAsync.value.bool_value=true;
703 OSCL_TRY(error, mPlayerCapConfig->setParametersSync(NULL, &iKVPSetAsync, 1, iErrorKVP));
704 OSCL_TRY(error, mPlayer->Prepare(command));
705 OSCL_FIRST_CATCH_ANY(error, commandFailed(command));
707 char value[PROPERTY_VALUE_MAX] = {"0"};
708 property_get("ro.com.android.disable_rtsp_nat", value, "0");
709 LOGV("disable natpkt - %s",value);
710 if (1 == atoi(value))
712 //disable firewall packet
713 iKeyStringSetAsync=_STRLIT_CHAR("x-pvmf/net/disable-firewall-packets;valtype=bool");
714 iKVPSetAsync.key=iKeyStringSetAsync.get_str();
715 iKVPSetAsync.value.bool_value = 1; //1 - disable
717 OSCL_TRY(error,mPlayerCapConfig->setParametersSync(NULL,&iKVPSetAsync,1,iErrorKVP));
721 void PlayerDriver::handleStart(PlayerStart* command)
725 // for video, set thread priority so we don't hog CPU
726 if (mVideoOutputMIO) {
727 int ret = setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);
729 // for audio, set thread priority so audio isn't choppy
731 int ret = setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
734 // Signalling seek complete to continue obtaining the current position
735 // from PVPlayer Engine
737 // if we are paused, just resume
739 if (mPlayer->GetPVPlayerStateSync(state) == PVMFSuccess
740 && (state == PVP_STATE_PAUSED)) {
742 // if we are at the end, seek to the beginning first
744 PVPPlaybackPosition begin, end;
745 begin.iIndeterminate = false;
746 begin.iPosUnit = PVPPBPOSUNIT_SEC;
747 begin.iPosValue.sec_value = 0;
748 begin.iMode = PVPPBPOS_MODE_NOW;
749 end.iIndeterminate = true;
750 mPlayer->SetPlaybackRange(begin, end, false, NULL);
752 OSCL_TRY(error, mPlayer->Resume(command));
753 OSCL_FIRST_CATCH_ANY(error, commandFailed(command));
755 OSCL_TRY(error, mPlayer->Start(command));
756 OSCL_FIRST_CATCH_ANY(error, commandFailed(command));
760 void PlayerDriver::handleSeek(PlayerSeek* command)
765 // Cache the most recent seek request
766 mRecentSeek = command->msec();
767 // Seeking in the pause state
769 if (mPlayer->GetPVPlayerStateSync(state) == PVMFSuccess
770 && (state == PVP_STATE_PAUSED)) {
773 PVPPlaybackPosition begin, end;
774 begin.iIndeterminate = false;
775 begin.iPosUnit = PVPPBPOSUNIT_MILLISEC;
776 begin.iPosValue.millisec_value = command->msec();
777 begin.iMode = PVPPBPOS_MODE_NOW;
778 end.iIndeterminate = true;
780 OSCL_TRY(error, mPlayer->SetPlaybackRange(begin, end, false, command));
781 OSCL_FIRST_CATCH_ANY(error, commandFailed(command));
786 void PlayerDriver::handleGetPosition(PlayerGetPosition* command)
788 PVPPlaybackPosition pos;
789 pos.iPosUnit = PVPPBPOSUNIT_MILLISEC;
791 // In the pause state, get the progress bar position from the recent seek value
792 // instead of GetCurrentPosition() from PVPlayer Engine.
793 if (mPlayer->GetPVPlayerStateSync(state) == PVMFSuccess
794 && (state == PVP_STATE_PAUSED)
795 && (mSeekComp == false)) {
796 command->set(mRecentSeek);
799 if (mPlayer->GetCurrentPositionSync(pos) != PVMFSuccess) {
802 LOGV("position=%d", pos.iPosValue.millisec_value);
803 command->set((int)pos.iPosValue.millisec_value);
808 void PlayerDriver::handleGetStatus(PlayerGetStatus* command)
811 if (mPlayer->GetPVPlayerStateSync(state) != PVMFSuccess) {
815 LOGV("status=%d", state);
819 void PlayerDriver::handleExtensionCommand(PlayerExtensionCommand* command)
821 LOGV("handleExtensionCommand");
822 if(mExtensionHandler){
823 if(mExtensionHandler->callPlayerExtension(command,command->getDataParcel(),command->getReplyParcel()) != NO_ERROR){
824 LOGW("handleExtensionCommand error");
827 LOGV("mExtensionHandler == NULL");
828 command->getReplyParcel().writeInt32(INVALID_OPERATION);
829 commandFailed(command);
833 void PlayerDriver::handleCheckLiveStreaming(PlayerCheckLiveStreaming* command)
835 LOGV("handleCheckLiveStreaming ...");
836 mCheckLiveKey.clear();
837 mCheckLiveKey.push_back(OSCL_HeapString<OsclMemAllocator>("pause-denied"));
838 mCheckLiveValue.clear();
840 OSCL_TRY(error, mPlayer->GetMetadataValues(mCheckLiveKey, 0, 1, mCheckLiveMetaValues, mCheckLiveValue, command));
841 OSCL_FIRST_CATCH_ANY(error, commandFailed(command));
844 void PlayerDriver::handleGetDuration(PlayerGetDuration* command)
847 mMetaKeyList.clear();
848 mMetaKeyList.push_back(OSCL_HeapString<OsclMemAllocator>("duration"));
849 mMetaValueList.clear();
852 OSCL_TRY(error, mPlayer->GetMetadataValues(mMetaKeyList,0,-1,mNumMetaValues,mMetaValueList, command));
853 OSCL_FIRST_CATCH_ANY(error, commandFailed(command));
856 void PlayerDriver::handleStop(PlayerStop* command)
859 // setting the looping boolean to false. MediaPlayer app takes care of setting the loop again before the start.
863 if ((mPlayer->GetPVPlayerStateSync(state) == PVMFSuccess)
864 && ( (state == PVP_STATE_PAUSED) ||
865 (state == PVP_STATE_PREPARED) ||
866 (state == PVP_STATE_STARTED) ))
868 OSCL_TRY(error, mPlayer->Stop(command));
869 OSCL_FIRST_CATCH_ANY(error, commandFailed(command));
873 LOGV("handleStop - Player State = %d - Sending Reset instead of Stop\n",state);
874 // TODO: Previously this called CancelAllCommands and RemoveDataSource
875 handleReset(new PlayerReset(command->callback(), command->cookie()));
880 void PlayerDriver::handlePause(PlayerPause* command)
884 OSCL_TRY(error, mPlayer->Pause(command));
885 OSCL_FIRST_CATCH_ANY(error, commandFailed(command));
888 void PlayerDriver::handleRemoveDataSource(PlayerRemoveDataSource* command)
890 LOGV("handleRemoveDataSource");
892 OSCL_TRY(error, mPlayer->RemoveDataSource(*mDataSource, command));
893 OSCL_FIRST_CATCH_ANY(error, commandFailed(command));
896 void PlayerDriver::handleCancelAllCommands(PlayerCancelAllCommands* command)
898 LOGV("handleCancelAllCommands");
900 OSCL_TRY(error, mPlayer->CancelAllCommands(command));
901 OSCL_FIRST_CATCH_ANY(error, commandFailed(command));
904 void PlayerDriver::handleReset(PlayerReset* command)
909 // setting the looping boolean to false. MediaPlayer app takes care of setting the loop again before the start.
914 OSCL_TRY(error, mPlayer->Reset(command));
915 OSCL_FIRST_CATCH_ANY(error, commandFailed(command));
918 void PlayerDriver::handleQuit(PlayerQuit* command)
920 OsclExecScheduler *sched = OsclExecScheduler::Current();
921 sched->StopScheduler();
924 PVMFFormatType PlayerDriver::getFormatType()
926 return mDataSource->GetDataSourceFormatType();
929 /*static*/ int PlayerDriver::startPlayerThread(void *cookie)
931 LOGV("startPlayerThread");
932 PlayerDriver *ed = (PlayerDriver *)cookie;
933 return ed->playerThread();
936 int PlayerDriver::playerThread()
940 LOGV("InitializeForThread");
941 if (!InitializeForThread())
943 LOGV("InitializeForThread fail");
949 LOGV("OMX_MasterInit");
952 LOGV("OsclScheduler::Init");
953 OsclScheduler::Init("AndroidPVWrapper");
955 LOGV("CreatePlayer");
956 OSCL_TRY(error, mPlayer = PVPlayerFactory::CreatePlayer(this, this, this));
958 // Just crash the first time someone tries to use it for now?
964 LOGV("AddToScheduler");
969 LOGV("OsclActiveScheduler::Current");
970 OsclExecScheduler *sched = OsclExecScheduler::Current();
971 LOGV("StartScheduler");
972 sched->StartScheduler(mSyncSem);
974 LOGV("DeletePlayer");
975 PVPlayerFactory::DeletePlayer(mPlayer);
977 delete mDownloadContextData;
978 mDownloadContextData = NULL;
980 delete mLocalContextData;
981 mLocalContextData = NULL;
986 PVMediaOutputNodeFactory::DeleteMediaOutputNode(mAudioNode);
987 delete mAudioOutputMIO;
990 PVMediaOutputNodeFactory::DeleteMediaOutputNode(mVideoNode);
991 delete mVideoOutputMIO;
996 // note that we only signal mSyncSem. Deleting it is handled
997 // in enqueueCommand(). This is done because waiting for an
998 // already-deleted OsclSemaphore doesn't work (it blocks),
999 // and it's entirely possible for this thread to exit before
1000 // enqueueCommand() gets around to waiting for the semaphore.
1002 // do some of destructor's work here
1003 // goodbye cruel world
1006 //Moved after the delete this, as Oscl cleanup should be done in the end.
1007 //delete this was cleaning up OsclSemaphore objects, eventually causing a crash
1008 OsclScheduler::Cleanup();
1009 LOGV("OsclScheduler::Cleanup");
1011 LOGV("OMX_MasterDeinit");
1013 UninitializeForThread();
1017 /*static*/ void PlayerDriver::syncCompletion(status_t s, void *cookie, bool cancelled)
1019 PlayerDriver *ed = static_cast<PlayerDriver*>(cookie);
1020 ed->mSyncStatus = s;
1021 ed->mSyncSem->Signal();
1024 void PlayerDriver::handleCheckLiveStreamingComplete(PlayerCheckLiveStreaming* cmd)
1026 if (mCheckLiveValue.empty())
1029 const char* substr = oscl_strstr((char*)(mCheckLiveValue[0].key), _STRLIT_CHAR("pause-denied;valtype=bool"));
1031 if ( mCheckLiveValue[0].value.bool_value == true ) {
1032 LOGI("Live Streaming...");
1033 mIsLiveStreaming = true;
1038 void PlayerDriver::handleGetDurationComplete(PlayerGetDuration* cmd)
1042 if (mMetaValueList.empty())
1045 MediaClockConverter mcc;
1047 for (uint32 i = 0; i < mMetaValueList.size(); ++i) {
1048 // Search for the duration
1049 const char* substr=oscl_strstr(mMetaValueList[i].key, _STRLIT_CHAR("duration;valtype=uint32;timescale="));
1051 uint32 timescale=1000;
1052 if (PV_atoi((substr+34), 'd', timescale) == false) {
1053 // Retrieving timescale failed so default to 1000
1056 uint32 duration = mMetaValueList[i].value.uint32_value;
1057 if (duration > 0 && timescale > 0) {
1059 mcc.set_timescale(timescale);
1060 //set the clock to the duration as per the timescale
1061 mcc.set_clock(duration,0);
1062 //convert to millisec
1063 cmd->set(mcc.get_converted_ts(1000));
1069 void PlayerDriver::CommandCompleted(const PVCmdResponse& aResponse)
1071 LOGV("CommandCompleted");
1072 PVMFStatus status = aResponse.GetCmdStatus();
1080 PlayerCommand* command = static_cast<PlayerCommand*>(aResponse.GetContext());
1081 LOGV("Completed command %s status=%s", command ? command->toString(): "<null>", PVMFStatusToString(status));
1082 if (command == NULL) return;
1084 // FIXME: Ignore non-fatal seek errors because pvPlayerEngine returns these errors and retains it's state.
1086 mSeekPending = false;
1087 if ( ( (status == PVMFErrArgument) || (status == PVMFErrInvalidState) || (status == PVMFErrNotSupported) ) ) {
1088 LOGV("Ignoring error during seek");
1089 status = PVMFSuccess;
1092 if (command->code() == PlayerCommand::PLAYER_EXTENSION_COMMAND ) {
1093 // extension might want to know about command it initiated
1094 // returns true if command->complete was called by extension, else do it here
1095 if (mExtensionHandler->commandCompleted((PlayerExtensionCommand*)command, aResponse)) {
1100 if (status == PVMFSuccess) {
1101 switch (command->code()) {
1102 case PlayerCommand::PLAYER_PREPARE:
1103 LOGV("PLAYER_PREPARE complete mDownloadContextData=%p, mDataReadyReceived=%d", mDownloadContextData, mDataReadyReceived);
1104 mPrepareDone = true;
1105 // If we are streaming from the network, we
1106 // have to wait until the first PVMFInfoDataReady
1107 // is sent to notify the user that it is okay to
1108 // begin playback. If it is a local file, just
1109 // send it now at the completion of Prepare().
1110 if ((mDownloadContextData == NULL) || mDataReadyReceived) {
1111 mPvPlayer->sendEvent(MEDIA_PREPARED);
1115 case PlayerCommand::PLAYER_GET_DURATION:
1116 handleGetDurationComplete(static_cast<PlayerGetDuration*>(command));
1119 case PlayerCommand::PLAYER_CHECK_LIVE_STREAMING:
1120 handleCheckLiveStreamingComplete(static_cast<PlayerCheckLiveStreaming*>(command));
1123 case PlayerCommand::PLAYER_PAUSE:
1124 LOGV("pause complete");
1127 case PlayerCommand::PLAYER_SEEK:
1128 mPvPlayer->sendEvent(MEDIA_SEEK_COMPLETE);
1131 default: /* shut up gcc */
1135 // Call the user's requested completion function
1136 command->complete(NO_ERROR, false);
1137 } else if (status == PVMFErrCancelled) {
1138 // Ignore cancelled code return status (PVMFErrCancelled), since it is not an error.
1139 LOGE("Command (%d) was cancelled", command->code());
1140 status = PVMFSuccess;
1141 command->complete(NO_ERROR, true);
1143 // Try to map the PV error code to an Android one.
1144 LOGE("Command %s completed with an error or info %s", command->toString(), PVMFStatusToString(status));
1145 const media_event_type event_type = MapStatusToEventType(status);
1147 if (MEDIA_NOP != event_type) {
1148 mPvPlayer->sendEvent(event_type, MapStatusToEventCode(status), status);
1150 LOGE("Ignoring: %d", status);
1152 command->complete(UNKNOWN_ERROR, false);
1158 void PlayerDriver::HandleErrorEvent(const PVAsyncErrorEvent& aEvent)
1160 PVMFStatus status = aEvent.GetEventType();
1162 // Errors use negative codes (see pvmi/pvmf/include/pvmf_return_codes.h)
1163 if (status > PVMFErrFirst) {
1164 LOGE("HandleErrorEvent called with an non-error event [%d]!!", status);
1166 LOGE("HandleErrorEvent: %s", PVMFStatusToString(status));
1167 // TODO: Map more of the PV error code into the Android Media Player ones.
1168 mPvPlayer->sendEvent(MEDIA_ERROR, ::android::MEDIA_ERROR_UNKNOWN, status);
1171 void PlayerDriver::HandleInformationalEvent(const PVAsyncInformationalEvent& aEvent)
1173 PVMFStatus status = aEvent.GetEventType();
1175 // Errors use negative codes (see pvmi/pvmf/include/pvmf_return_codes.h)
1176 if (status <= PVMFErrFirst) {
1177 // Errors should go to the HandleErrorEvent handler, not the
1178 // informational one.
1179 LOGE("HandleInformationalEvent called with an error event [%d]!!", status);
1182 LOGV("HandleInformationalEvent: %s", PVMFStatusToString(status));
1185 case PVMFInfoEndOfData:
1192 mPvPlayer->sendEvent(MEDIA_PLAYBACK_COMPLETE);
1196 case PVMFInfoErrorHandlingComplete:
1197 LOGW("PVMFInfoErrorHandlingComplete");
1201 case PVMFInfoBufferingStart:
1202 mPvPlayer->sendEvent(MEDIA_BUFFERING_UPDATE, 0);
1205 case PVMFInfoBufferingStatus:
1207 const void *buffer = aEvent.GetLocalBuffer();
1208 const size_t size = aEvent.GetLocalBufferSize();
1211 if (GetBufferingPercentage(buffer, size, &percentage))
1213 LOGD("buffering (%d)", percentage);
1214 mPvPlayer->sendEvent(MEDIA_BUFFERING_UPDATE, percentage);
1219 case PVMFInfoDurationAvailable:
1221 PVUuid infomsguuid = PVMFDurationInfoMessageInterfaceUUID;
1222 PVMFDurationInfoMessageInterface* eventMsg = NULL;
1223 PVInterface* infoExtInterface = aEvent.GetEventExtensionInterface();
1224 if (infoExtInterface &&
1225 infoExtInterface->queryInterface(infomsguuid, (PVInterface*&)eventMsg))
1229 eventMsg->GetCodeUUID(infoCode, eventuuid);
1230 if (eventuuid == infomsguuid)
1232 uint32 SourceDurationInMS = eventMsg->GetDuration();
1233 LOGV(".... with duration = %u ms",SourceDurationInMS);
1239 case PVMFInfoDataReady:
1240 if (mDataReadyReceived)
1242 mDataReadyReceived = true;
1243 // If this is a network stream, we are now ready to play.
1244 if (mDownloadContextData && mPrepareDone) {
1245 mPvPlayer->sendEvent(MEDIA_PREPARED);
1249 case PVMFInfoVideoTrackFallingBehind:
1250 // TODO: This event should not be passed to the user in the ERROR channel.
1251 LOGW("Video track fell behind");
1252 mPvPlayer->sendEvent(MEDIA_INFO, ::android::MEDIA_INFO_VIDEO_TRACK_LAGGING,
1253 PVMFInfoVideoTrackFallingBehind);
1256 case PVMFInfoPoorlyInterleavedContent:
1257 // TODO: This event should not be passed to the user in the ERROR channel.
1258 LOGW("Poorly interleaved content.");
1259 mPvPlayer->sendEvent(MEDIA_INFO, ::android::MEDIA_INFO_BAD_INTERLEAVING,
1260 PVMFInfoPoorlyInterleavedContent);
1263 case PVMFInfoContentTruncated:
1264 LOGE("Content is truncated.");
1267 case PVMFInfoRemoteSourceNotification:
1269 PVInterface* infoExtInterface = aEvent.GetEventExtensionInterface();
1270 if (infoExtInterface)
1272 PVUuid infomsguuid = PVMFFileFormatEventTypesUUID;
1273 PVMFBasicErrorInfoMessage* eventMsg = OSCL_STATIC_CAST(PVMFBasicErrorInfoMessage*, infoExtInterface);
1276 eventMsg->GetCodeUUID(infoCode, eventuuid);
1277 if (eventuuid == PVMFFileFormatEventTypesUUID)
1279 if (infoCode == PVMFMP4FFParserInfoNotPseudostreamableFile)
1281 LOGE("Not valid for Progressive Playback.");
1282 mPvPlayer->sendEvent(MEDIA_ERROR, ::android::MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK, PVMFInfoRemoteSourceNotification);
1289 /* Certain events we don't really care about, but don't
1290 * want log spewage, so just no-op them here.
1292 case PVMFInfoPositionStatus:
1293 case PVMFInfoBufferingComplete:
1294 case PVMFInfoContentLength:
1295 case PVMFInfoContentType:
1296 case PVMFInfoUnderflow:
1297 case PVMFInfoDataDiscarded:
1298 case PVMFInfoActualPlaybackPosition:
1302 LOGV("HandleInformationalEvent: type=%d UNHANDLED", status);
1303 mPvPlayer->sendEvent(MEDIA_INFO, ::android::MEDIA_INFO_UNKNOWN, status);
1308 // ----------------------------------------------------------------------------
1309 // PlayerCommand implementation
1310 // ----------------------------------------------------------------------------
1311 const char* PlayerCommand::toString() const {
1312 return PlayerCommandCodeToString(code());
1318 #define LOG_TAG "PVPlayer"
1320 #ifdef MAX_OPENCORE_INSTANCES
1321 /*static*/ volatile int32_t PVPlayer::sNumInstances = 0;
1324 // ----------------------------------------------------------------------------
1325 // implement the Packet Video player
1326 // ----------------------------------------------------------------------------
1327 PVPlayer::PVPlayer()
1329 LOGV("PVPlayer constructor");
1330 mDataSourcePath = NULL;
1332 mIsDataSourceSet = false;
1334 mPlayerDriver = NULL;
1336 #ifdef MAX_OPENCORE_INSTANCES
1337 if (android_atomic_inc(&sNumInstances) >= MAX_OPENCORE_INSTANCES) {
1338 LOGW("Exceeds maximum number of OpenCore instances");
1344 LOGV("construct PlayerDriver");
1345 mPlayerDriver = new PlayerDriver(this);
1346 LOGV("send PLAYER_SETUP");
1347 PlayerSetup* setup = new PlayerSetup(0,0);
1348 mInit = mPlayerDriver->enqueueCommand(setup);
1349 if (mInit == NO_INIT) {
1354 status_t PVPlayer::initCheck()
1359 PVPlayer::~PVPlayer()
1361 LOGV("PVPlayer destructor");
1362 if (mPlayerDriver != NULL) {
1363 PlayerQuit quit = PlayerQuit(0,0);
1364 mPlayerDriver->enqueueCommand(&quit); // will wait on mSyncSem, signaled by player thread
1366 free(mDataSourcePath);
1367 if (mSharedFd >= 0) {
1370 #ifdef MAX_OPENCORE_INSTANCES
1371 android_atomic_dec(&sNumInstances);
1375 status_t PVPlayer::setDataSource(const char *url)
1377 LOGV("setDataSource(%s)", url);
1378 if (mSharedFd >= 0) {
1382 free(mDataSourcePath);
1383 mDataSourcePath = NULL;
1385 // Don't let somebody trick us in to reading some random block of memory
1386 if (strncmp("assethandle://", url, 14) == 0)
1387 return android::UNKNOWN_ERROR;
1388 mDataSourcePath = strdup(url);
1392 status_t PVPlayer::setDataSource(int fd, int64_t offset, int64_t length) {
1394 // This is all a big hack to allow PV to play from a file descriptor.
1395 // Eventually we'll fix PV to use a file descriptor directly instead
1397 LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
1398 if (mSharedFd >= 0) {
1402 free(mDataSourcePath);
1403 mDataSourcePath = NULL;
1406 mSharedFd = dup(fd);
1407 TOsclFileHandle handle = fdopen(mSharedFd,"rb");
1408 sprintf(buf, "assethandle://%ld:%lld:%lld", (long)handle, offset, length);
1409 mDataSourcePath = strdup(buf);
1413 status_t PVPlayer::setVideoSurface(const sp<ISurface>& surface)
1415 LOGV("setVideoSurface(%p)", surface.get());
1420 status_t PVPlayer::prepare()
1424 // We need to differentiate the two valid use cases for prepare():
1425 // 1. new PVPlayer/reset()->setDataSource()->prepare()
1426 // 2. new PVPlayer/reset()->setDataSource()->prepare()/prepareAsync()
1427 // ->start()->...->stop()->prepare()
1428 // If data source has already been set previously, no need to run
1429 // a sequence of commands and only the PLAYER_PREPARE code needs
1431 if (!mIsDataSourceSet) {
1434 LOGV(" data source = %s", mDataSourcePath);
1435 ret = mPlayerDriver->enqueueCommand(new PlayerSetDataSource(mDataSourcePath,0,0));
1441 ret = mPlayerDriver->enqueueCommand(new PlayerInit(0,0));
1445 // set video surface, if there is one
1446 if (mSurface != NULL) {
1447 LOGV(" set video surface");
1448 ret = mPlayerDriver->enqueueCommand(new PlayerSetVideoSurface(mSurface,0,0));
1454 // If we ever need to expose selectable audio output setup, this can be broken
1455 // out. In the meantime, however, system audio routing APIs should suffice.
1456 LOGV(" set audio sink");
1457 ret = mPlayerDriver->enqueueCommand(new PlayerSetAudioSink(mAudioSink,0,0));
1461 // New data source has been set successfully.
1462 mIsDataSourceSet = true;
1467 return mPlayerDriver->enqueueCommand(new PlayerPrepare(check_for_live_streaming, this));
1470 void PVPlayer::check_for_live_streaming(status_t s, void *cookie, bool cancelled)
1472 LOGV("check_for_live_streaming s=%d, cancelled=%d", s, cancelled);
1473 if (s == NO_ERROR && !cancelled) {
1474 PVPlayer *p = (PVPlayer*)cookie;
1475 if ( (p->mPlayerDriver->getFormatType() == PVMF_MIME_DATA_SOURCE_RTSP_URL) ||
1476 (p->mPlayerDriver->getFormatType() == PVMF_MIME_DATA_SOURCE_MS_HTTP_STREAMING_URL) ) {
1477 LOGV("check_for_live_streaming enQ PlayerCheckLiveStreaming command");
1478 p->mPlayerDriver->enqueueCommand(new PlayerCheckLiveStreaming( do_nothing, NULL));
1483 void PVPlayer::run_init(status_t s, void *cookie, bool cancelled)
1485 LOGV("run_init s=%d, cancelled=%d", s, cancelled);
1486 if (s == NO_ERROR && !cancelled) {
1487 PVPlayer *p = (PVPlayer*)cookie;
1488 p->mPlayerDriver->enqueueCommand(new PlayerInit(run_set_video_surface, cookie));
1492 void PVPlayer::run_set_video_surface(status_t s, void *cookie, bool cancelled)
1494 LOGV("run_set_video_surface s=%d, cancelled=%d", s, cancelled);
1495 if (s == NO_ERROR && !cancelled) {
1496 // If we don't have a video surface, just skip to the next step.
1497 PVPlayer *p = (PVPlayer*)cookie;
1498 if (p->mSurface == NULL) {
1499 run_set_audio_output(s, cookie, false);
1501 p->mPlayerDriver->enqueueCommand(new PlayerSetVideoSurface(p->mSurface, run_set_audio_output, cookie));
1506 void PVPlayer::run_set_audio_output(status_t s, void *cookie, bool cancelled)
1508 LOGV("run_set_audio_output s=%d, cancelled=%d", s, cancelled);
1509 if (s == NO_ERROR && !cancelled) {
1510 PVPlayer *p = (PVPlayer*)cookie;
1511 p->mPlayerDriver->enqueueCommand(new PlayerSetAudioSink(p->mAudioSink, run_prepare, cookie));
1515 void PVPlayer::run_prepare(status_t s, void *cookie, bool cancelled)
1517 LOGV("run_prepare s=%d, cancelled=%d", s, cancelled);
1518 if (s == NO_ERROR && !cancelled) {
1519 PVPlayer *p = (PVPlayer*)cookie;
1520 p->mPlayerDriver->enqueueCommand(new PlayerPrepare(check_for_live_streaming, cookie));
1524 status_t PVPlayer::prepareAsync()
1526 LOGV("prepareAsync");
1529 if (!mIsDataSourceSet) { // If data source has NOT been set.
1530 // Set our data source as cached in setDataSource() above.
1531 LOGV(" data source = %s", mDataSourcePath);
1532 ret = mPlayerDriver->enqueueCommand(new PlayerSetDataSource(mDataSourcePath,run_init,this));
1533 mIsDataSourceSet = true;
1534 } else { // If data source has been already set.
1535 // No need to run a sequence of commands.
1536 // The only code needed to run is PLAYER_PREPARE.
1537 ret = mPlayerDriver->enqueueCommand(new PlayerPrepare(do_nothing, NULL));
1543 status_t PVPlayer::start()
1546 return mPlayerDriver->enqueueCommand(new PlayerStart(0,0));
1549 status_t PVPlayer::stop()
1552 return mPlayerDriver->enqueueCommand(new PlayerStop(0,0));
1555 status_t PVPlayer::pause()
1558 return mPlayerDriver->enqueueCommand(new PlayerPause(0,0));
1561 bool PVPlayer::isPlaying()
1564 if (mPlayerDriver->enqueueCommand(new PlayerGetStatus(&status,0,0)) == NO_ERROR) {
1565 return (status == PVP_STATE_STARTED);
1570 status_t PVPlayer::getCurrentPosition(int *msec)
1572 return mPlayerDriver->enqueueCommand(new PlayerGetPosition(msec,0,0));
1575 status_t PVPlayer::getDuration(int *msec)
1577 status_t ret = mPlayerDriver->enqueueCommand(new PlayerGetDuration(msec,0,0));
1578 if (ret == NO_ERROR) mDuration = *msec;
1579 LOGI("duration = %d",mDuration);
1583 status_t PVPlayer::seekTo(int msec)
1585 LOGV("seekTo(%d)", msec);
1586 // can't always seek to end of streams - so we fudge a little
1587 if ((msec == mDuration) && (mDuration > 0)) {
1589 LOGV("Seek adjusted 1 msec from end");
1591 return mPlayerDriver->enqueueCommand(new PlayerSeek(msec,do_nothing,0));
1594 status_t PVPlayer::reset()
1597 status_t ret = mPlayerDriver->enqueueCommand(new PlayerCancelAllCommands(0,0));
1598 if (ret == NO_ERROR) {
1599 ret = mPlayerDriver->enqueueCommand(new PlayerReset(0,0));
1601 if (ret == NO_ERROR) {
1602 ret = mPlayerDriver->enqueueCommand(new PlayerRemoveDataSource(0,0));
1606 if (mSharedFd >= 0) {
1610 mIsDataSourceSet = false;
1614 status_t PVPlayer::setLooping(int loop)
1616 LOGV("setLooping(%d)", loop);
1617 return mPlayerDriver->enqueueCommand(new PlayerSetLoop(loop,0,0));
1620 // This is a stub for the direct invocation API.
1621 // From include/media/MediaPlayerInterface.h where the abstract method
1624 // Invoke a generic method on the player by using opaque parcels
1625 // for the request and reply.
1626 // @param request Parcel that must start with the media player
1628 // @param[out] reply Parcel to hold the reply data. Cannot be null.
1629 // @return OK if the invocation was made successfully.
1631 // This stub should be replaced with a concrete implementation.
1633 // Typically the request parcel will contain an opcode to identify an
1634 // operation to be executed. There might also be a handle used to
1635 // create a session between the client and the player.
1637 // The concrete implementation can then dispatch the request
1638 // internally based on the double (opcode, handle).
1639 status_t PVPlayer::invoke(const Parcel& request, Parcel *reply)
1641 return INVALID_OPERATION;
1644 status_t PVPlayer::getMetadata(const media::Metadata::Filter& ids,
1646 return UNKNOWN_ERROR;
1649 }; // namespace android