void WordSuggest::specialPipeNotification(NotificationType notification, Layout* pLayout) { // Pipe notifications to notifier template including own data switch (notification) { case NotificationType::WORD_SUGGEST_CHOSEN: { // Notify listener method with UTF-16 string notifyListener(&WordSuggestListener::chosen, pLayout, getId(), mLastChosenSuggestion); // Convert suggestion value to UTF-8 string std::string lastChosenSuggestionValue8; convertUTF16ToUTF8(mLastChosenSuggestion, lastChosenSuggestionValue8); // Notify listener method with UTF-8 string notifyListener(&WordSuggestListener::chosen, pLayout, getId(), lastChosenSuggestionValue8); break; } default: throwWarning( OperationNotifier::Operation::BUG, "Word suggest got notification which is not thought for it."); break; } }
void AttachmentsSaveToWorker::work() { Util::LibraryLogger::setCurrentThreadName("AttSaveToW"); try { { auto session = Db::makeSession(sessionConfig_); SmartSqlite::ScopedTransaction tx(session); auto isDraft = isDraft_ ? Dao::IsDraft::Yes : Dao::IsDraft::No; auto dao = Dao::AttachmentDao::load( isDraft, convOrMsgId_, attId_, session); if (dao) { auto stream = Util::Filesystem::makeOfstream(path_); dao->saveContent(*stream); } tx.commit(); } notifyListener(convOrMsgId_, attId_, path_); } catch(std::exception &ex) { Log.e() << "AttachmentsSaveToWorker failed for path '" << path_ << "' with message:\n" << Util::formatException(ex); error(convOrMsgId_, attId_, path_, toLocalError(std::current_exception())); } }
void Button::specialPipeNotification(NotificationType notification, Layout* pLayout) { // Pipe notifications to notifier template including own data switch (notification) { case NotificationType::BUTTON_HIT: notifyListener(&ButtonListener::hit, pLayout, getId()); break; case NotificationType::BUTTON_DOWN: notifyListener(&ButtonListener::down, pLayout, getId()); break; case NotificationType::BUTTON_UP: notifyListener(&ButtonListener::up, pLayout, getId()); break; default: throwWarning( OperationNotifier::Operation::BUG, "Button got notification which is not thought for it."); break; } }
int Handler::processStreamingRequest() { if (m_streamReceiver.empty()) { int ret = m_streamReceiver.process(); if (ret < 0) return -1; } while (!m_streamReceiver.empty()) { switch (m_streamReceiver.headType()) { case StreamReceiver::COMMAND: { if (m_streamCommand != NULL) delete m_streamCommand; m_streamCommand = NULL; CommandBase* cmd; m_streamReceiver.popCommand(cmd); if ((cmd->cmdType() == CMD_INSERT) || (cmd->cmdType() == CMD_SET)) { InputBaseCommand* ibc = static_cast<InputBaseCommand*>(cmd); if (ibc->m_binding) m_streamCommand = ibc; } if (m_streamCommand == NULL) { cmd->setStreamMode(); m_commands.push_back(cmd); } break; } case StreamReceiver::DATA: { CommandBase* cmd = m_streamReceiver.popData(m_streamCommand); cmd->setStreamMode(); m_commands.push_back(cmd); break; } case StreamReceiver::FINISH: if (m_streamCommand != NULL) delete m_streamCommand; m_streamCommand = NULL; m_streamReceiver.clear(); m_mode = INTERACTIVE; break; } } if (m_commands.empty()) { notifyListener(); } else { if (!m_dedicatedThread) MainQueue::put(&m_task); } return 0; }
void ICUNotifier::notifyChanged(void) { if (listeners != NULL) { Mutex lmx(¬ifyLock); if (listeners != NULL) { for (int i = 0, e = listeners->size(); i < e; ++i) { EventListener* el = (EventListener*)listeners->elementAt(i); notifyListener(*el); } } } }
status_t DashPlayerDriver::prepareAsync() { status_t err = UNKNOWN_ERROR; if (mPlayer != NULL) { err = mPlayer->prepareAsync(); } if (err == OK) { err = prepare(); notifyListener(MEDIA_PREPARED); } else if (err == -EWOULDBLOCK) { // this case only happens for DASH return OK; } return err; }
void Sensor::specialPipeNotification(Notification notification, Layout* pLayout) { // Pipe notifications to notifier template including own data switch (notification) { case Notification::SENSOR_PENETRATED: notifyListener(&SensorListener::penetrated, pLayout, getId(), mPenetration.getValue()); break; default: throwWarning( OperationNotifier::Operation::BUG, "Sensor got notification which is not thought for it."); break; } }
int Handler::processInteractiveRequest() { int ret = m_httpReceiver.process(); if (ret < 0) return -1; if (m_httpReceiver.type() == HttpReceiver::REQ_FILE) { m_commands.push_back(new DownloadCommand(m_httpReceiver.path())); } else if (m_httpReceiver.type() == HttpReceiver::REQ_DATA) { CommandBase* cmd = makeQueryCommand(m_httpReceiver.args()); m_commands.push_back(cmd); } else if (m_httpReceiver.type() == HttpReceiver::REQ_STREAM) { m_mode = STREAMING; m_streamReceiver.process(m_httpReceiver.buffer()); // TODO: think more. there are potential // problems with partial lines in // parsed HTTP PUT content!!! } else { m_request.append(m_httpReceiver.arg(ARG_COMMAND)); Parser parser; CommandBase* cmd = parser.parse(m_request.raw()); if (cmd == NULL) THROW("Failed to parse command"); if (m_httpReceiver.command() == "HEAD") cmd->setNoResponse(); if (m_httpReceiver.command() == ">") cmd->setStreamMode(); m_commands.push_back(cmd); m_request.clear(); } if (m_commands.empty()) { notifyListener(); } else { if (!m_dedicatedThread) MainQueue::put(&m_task); } return 0; }
bool QueueManager::start() { if (mAvaiableSlots == 0 || mItemsQueue.empty()) { return false; } mRunning = true; notifyListener("Queue Start"); while (mItemsRunning.size() < mAvaiableSlots && !mItemsQueue.empty()) { NARWorker* item = mItemsQueue.dequeue(); int id = item->getId(); mItemsRunning.insert(id, item); item->startJob(); } foreach (IQueueListener* listener, mListeners) { listener->itemsRemains(mItemsQueue.size()); }
void DashPlayerDriver::notifySeekComplete() { notifyListener(MEDIA_SEEK_COMPLETE); }
void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { switch (msg->what()) { case kWhatSetDataSource: { ALOGV("kWhatSetDataSource"); CHECK(mSource == NULL); sp<RefBase> obj; CHECK(msg->findObject("source", &obj)); mSource = static_cast<Source *>(obj.get()); looper()->registerHandler(mSource); CHECK(mDriver != NULL); sp<NuPlayerDriver> driver = mDriver.promote(); if (driver != NULL) { driver->notifySetDataSourceCompleted(OK); } break; } case kWhatPrepare: { mSource->prepareAsync(); break; } case kWhatGetTrackInfo: { uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); status_t err = INVALID_OPERATION; if (mSource != NULL) { Parcel* reply; CHECK(msg->findPointer("reply", (void**)&reply)); err = mSource->getTrackInfo(reply); } sp<AMessage> response = new AMessage; response->setInt32("err", err); response->postReply(replyID); break; } case kWhatSelectTrack: { uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); status_t err = INVALID_OPERATION; if (mSource != NULL) { size_t trackIndex; int32_t select; CHECK(msg->findSize("trackIndex", &trackIndex)); CHECK(msg->findInt32("select", &select)); err = mSource->selectTrack(trackIndex, select); } sp<AMessage> response = new AMessage; response->setInt32("err", err); response->postReply(replyID); break; } case kWhatPollDuration: { int32_t generation; CHECK(msg->findInt32("generation", &generation)); if (generation != mPollDurationGeneration) { // stale break; } int64_t durationUs; if (mDriver != NULL && mSource->getDuration(&durationUs) == OK) { sp<NuPlayerDriver> driver = mDriver.promote(); if (driver != NULL) { driver->notifyDuration(durationUs); } } msg->post(1000000ll); // poll again in a second. break; } case kWhatSetVideoNativeWindow: { ALOGV("kWhatSetVideoNativeWindow"); mDeferredActions.push_back( new ShutdownDecoderAction( false /* audio */, true /* video */)); sp<RefBase> obj; CHECK(msg->findObject("native-window", &obj)); mDeferredActions.push_back( new SetSurfaceAction( static_cast<NativeWindowWrapper *>(obj.get()))); if (obj != NULL) { // If there is a new surface texture, instantiate decoders // again if possible. mDeferredActions.push_back( new SimpleAction(&NuPlayer::performScanSources)); } processDeferredActions(); break; } case kWhatSetAudioSink: { ALOGV("kWhatSetAudioSink"); sp<RefBase> obj; CHECK(msg->findObject("sink", &obj)); mAudioSink = static_cast<MediaPlayerBase::AudioSink *>(obj.get()); break; } case kWhatStart: { ALOGV("kWhatStart"); mVideoIsAVC = false; mAudioEOS = false; mVideoEOS = false; mSkipRenderingAudioUntilMediaTimeUs = -1; mSkipRenderingVideoUntilMediaTimeUs = -1; mVideoLateByUs = 0; mNumFramesTotal = 0; mNumFramesDropped = 0; mStarted = true; mSource->start(); uint32_t flags = 0; if (mSource->isRealTime()) { flags |= Renderer::FLAG_REAL_TIME; } mRenderer = new Renderer( mAudioSink, new AMessage(kWhatRendererNotify, id()), flags); looper()->registerHandler(mRenderer); postScanSources(); break; } case kWhatScanSources: { int32_t generation; CHECK(msg->findInt32("generation", &generation)); if (generation != mScanSourcesGeneration) { // Drop obsolete msg. break; } mScanSourcesPending = false; ALOGV("scanning sources haveAudio=%d, haveVideo=%d", mAudioDecoder != NULL, mVideoDecoder != NULL); bool mHadAnySourcesBefore = (mAudioDecoder != NULL) || (mVideoDecoder != NULL); if (mNativeWindow != NULL) { instantiateDecoder(false, &mVideoDecoder); } if (mAudioSink != NULL) { instantiateDecoder(true, &mAudioDecoder); } if (!mHadAnySourcesBefore && (mAudioDecoder != NULL || mVideoDecoder != NULL)) { // This is the first time we've found anything playable. if (mSourceFlags & Source::FLAG_DYNAMIC_DURATION) { schedulePollDuration(); } } status_t err; if ((err = mSource->feedMoreTSData()) != OK) { if (mAudioDecoder == NULL && mVideoDecoder == NULL) { // We're not currently decoding anything (no audio or // video tracks found) and we just ran out of input data. if (err == ERROR_END_OF_STREAM) { notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0); } else { notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); } } break; } if ((mAudioDecoder == NULL && mAudioSink != NULL) || (mVideoDecoder == NULL && mNativeWindow != NULL)) { msg->post(100000ll); mScanSourcesPending = true; } break; } case kWhatVideoNotify: case kWhatAudioNotify: { bool audio = msg->what() == kWhatAudioNotify; sp<AMessage> codecRequest; CHECK(msg->findMessage("codec-request", &codecRequest)); int32_t what; CHECK(codecRequest->findInt32("what", &what)); if (what == ACodec::kWhatFillThisBuffer) { status_t err = feedDecoderInputData( audio, codecRequest); if (err == -EWOULDBLOCK) { if (mSource->feedMoreTSData() == OK) { msg->post(10000ll); } } } else if (what == ACodec::kWhatEOS) { int32_t err; CHECK(codecRequest->findInt32("err", &err)); if (err == ERROR_END_OF_STREAM) { ALOGV("got %s decoder EOS", audio ? "audio" : "video"); } else { ALOGV("got %s decoder EOS w/ error %d", audio ? "audio" : "video", err); } mRenderer->queueEOS(audio, err); } else if (what == ACodec::kWhatFlushCompleted) { bool needShutdown; if (audio) { CHECK(IsFlushingState(mFlushingAudio, &needShutdown)); mFlushingAudio = FLUSHED; } else { CHECK(IsFlushingState(mFlushingVideo, &needShutdown)); mFlushingVideo = FLUSHED; mVideoLateByUs = 0; } ALOGV("decoder %s flush completed", audio ? "audio" : "video"); if (needShutdown) { ALOGV("initiating %s decoder shutdown", audio ? "audio" : "video"); (audio ? mAudioDecoder : mVideoDecoder)->initiateShutdown(); if (audio) { mFlushingAudio = SHUTTING_DOWN_DECODER; } else { mFlushingVideo = SHUTTING_DOWN_DECODER; } } finishFlushIfPossible(); } else if (what == ACodec::kWhatOutputFormatChanged) { if (audio) { int32_t numChannels; CHECK(codecRequest->findInt32( "channel-count", &numChannels)); int32_t sampleRate; CHECK(codecRequest->findInt32("sample-rate", &sampleRate)); ALOGV("Audio output format changed to %d Hz, %d channels", sampleRate, numChannels); mAudioSink->close(); audio_output_flags_t flags; int64_t durationUs; // FIXME: we should handle the case where the video decoder // is created after we receive the format change indication. // Current code will just make that we select deep buffer // with video which should not be a problem as it should // not prevent from keeping A/V sync. if (mVideoDecoder == NULL && mSource->getDuration(&durationUs) == OK && durationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US) { flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER; } else { flags = AUDIO_OUTPUT_FLAG_NONE; } int32_t channelMask; if (!codecRequest->findInt32("channel-mask", &channelMask)) { channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER; } CHECK_EQ(mAudioSink->open( sampleRate, numChannels, (audio_channel_mask_t)channelMask, AUDIO_FORMAT_PCM_16_BIT, 8 /* bufferCount */, NULL, NULL, flags), (status_t)OK); mAudioSink->start(); mRenderer->signalAudioSinkChanged(); } else { // video int32_t width, height; CHECK(codecRequest->findInt32("width", &width)); CHECK(codecRequest->findInt32("height", &height)); int32_t cropLeft, cropTop, cropRight, cropBottom; CHECK(codecRequest->findRect( "crop", &cropLeft, &cropTop, &cropRight, &cropBottom)); int32_t displayWidth = cropRight - cropLeft + 1; int32_t displayHeight = cropBottom - cropTop + 1; ALOGV("Video output format changed to %d x %d " "(crop: %d x %d @ (%d, %d))", width, height, displayWidth, displayHeight, cropLeft, cropTop); sp<AMessage> videoInputFormat = mSource->getFormat(false /* audio */); // Take into account sample aspect ratio if necessary: int32_t sarWidth, sarHeight; if (videoInputFormat->findInt32("sar-width", &sarWidth) && videoInputFormat->findInt32( "sar-height", &sarHeight)) { ALOGV("Sample aspect ratio %d : %d", sarWidth, sarHeight); displayWidth = (displayWidth * sarWidth) / sarHeight; ALOGV("display dimensions %d x %d", displayWidth, displayHeight); } notifyListener( MEDIA_SET_VIDEO_SIZE, displayWidth, displayHeight); } } else if (what == ACodec::kWhatShutdownCompleted) { ALOGV("%s shutdown completed", audio ? "audio" : "video"); if (audio) { mAudioDecoder.clear(); CHECK_EQ((int)mFlushingAudio, (int)SHUTTING_DOWN_DECODER); mFlushingAudio = SHUT_DOWN; } else { mVideoDecoder.clear(); CHECK_EQ((int)mFlushingVideo, (int)SHUTTING_DOWN_DECODER); mFlushingVideo = SHUT_DOWN; } finishFlushIfPossible(); } else if (what == ACodec::kWhatError) { ALOGE("Received error from %s decoder, aborting playback.", audio ? "audio" : "video"); mRenderer->queueEOS(audio, UNKNOWN_ERROR); } else if (what == ACodec::kWhatDrainThisBuffer) { renderBuffer(audio, codecRequest); } else if (what != ACodec::kWhatComponentAllocated && what != ACodec::kWhatComponentConfigured && what != ACodec::kWhatBuffersAllocated) { ALOGV("Unhandled codec notification %d '%c%c%c%c'.", what, what >> 24, (what >> 16) & 0xff, (what >> 8) & 0xff, what & 0xff); } break; } case kWhatRendererNotify: { int32_t what; CHECK(msg->findInt32("what", &what)); if (what == Renderer::kWhatEOS) { int32_t audio; CHECK(msg->findInt32("audio", &audio)); int32_t finalResult; CHECK(msg->findInt32("finalResult", &finalResult)); if (audio) { mAudioEOS = true; } else { mVideoEOS = true; } if (finalResult == ERROR_END_OF_STREAM) { ALOGV("reached %s EOS", audio ? "audio" : "video"); } else { ALOGE("%s track encountered an error (%d)", audio ? "audio" : "video", finalResult); notifyListener( MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, finalResult); } if ((mAudioEOS || mAudioDecoder == NULL) && (mVideoEOS || mVideoDecoder == NULL)) { notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0); } } else if (what == Renderer::kWhatPosition) { int64_t positionUs; CHECK(msg->findInt64("positionUs", &positionUs)); CHECK(msg->findInt64("videoLateByUs", &mVideoLateByUs)); if (mDriver != NULL) { sp<NuPlayerDriver> driver = mDriver.promote(); if (driver != NULL) { driver->notifyPosition(positionUs); driver->notifyFrameStats( mNumFramesTotal, mNumFramesDropped); } } } else if (what == Renderer::kWhatFlushComplete) { int32_t audio; CHECK(msg->findInt32("audio", &audio)); ALOGV("renderer %s flush completed.", audio ? "audio" : "video"); } else if (what == Renderer::kWhatVideoRenderingStart) { notifyListener(MEDIA_INFO, MEDIA_INFO_RENDERING_START, 0); } else if (what == Renderer::kWhatMediaRenderingStart) { ALOGV("media rendering started"); notifyListener(MEDIA_STARTED, 0, 0); } break; } case kWhatMoreDataQueued: { break; } case kWhatReset: { ALOGV("kWhatReset"); mDeferredActions.push_back( new ShutdownDecoderAction( true /* audio */, true /* video */)); mDeferredActions.push_back( new SimpleAction(&NuPlayer::performReset)); processDeferredActions(); break; } case kWhatSeek: { int64_t seekTimeUs; CHECK(msg->findInt64("seekTimeUs", &seekTimeUs)); ALOGV("kWhatSeek seekTimeUs=%lld us", seekTimeUs); mDeferredActions.push_back( new SimpleAction(&NuPlayer::performDecoderFlush)); mDeferredActions.push_back(new SeekAction(seekTimeUs)); processDeferredActions(); break; } case kWhatPause: { CHECK(mRenderer != NULL); mSource->pause(); mRenderer->pause(); break; } case kWhatResume: { CHECK(mRenderer != NULL); mSource->resume(); mRenderer->resume(); break; } case kWhatSourceNotify: { onSourceNotify(msg); break; } default: TRESPASS(); break; }
status_t NuPlayerDriver::prepareAsync() { notifyListener(MEDIA_PREPARED); return OK; }
void TimedTextPlayer::onMessageReceived(const sp<AMessage> &msg) { switch (msg->what()) { case kWhatPause: { mPaused = true; break; } case kWhatResume: { mPaused = false; if (mPendingSeekTimeUs != kInvalidTimeUs) { seekToAsync(mPendingSeekTimeUs); mPendingSeekTimeUs = kInvalidTimeUs; } else { doRead(); } break; } case kWhatStart: { sp<MediaPlayerBase> listener = mListener.promote(); if (listener == NULL) { ALOGE("Listener is NULL when kWhatStart is received."); break; } mPaused = false; mPendingSeekTimeUs = kInvalidTimeUs; int32_t positionMs = 0; listener->getCurrentPosition(&positionMs); int64_t seekTimeUs = positionMs * 1000ll; notifyListener(); mSendSubtitleGeneration++; doSeekAndRead(seekTimeUs); break; } case kWhatRetryRead: { int32_t generation = -1; CHECK(msg->findInt32("generation", &generation)); if (generation != mSendSubtitleGeneration) { // Drop obsolete msg. break; } int64_t seekTimeUs; int seekMode; if (msg->findInt64("seekTimeUs", &seekTimeUs) && msg->findInt32("seekMode", &seekMode)) { MediaSource::ReadOptions options; options.setSeekTo( seekTimeUs, static_cast<MediaSource::ReadOptions::SeekMode>(seekMode)); doRead(&options); } else { doRead(); } break; } case kWhatSeek: { int64_t seekTimeUs = kInvalidTimeUs; // Clear a displayed timed text before seeking. notifyListener(); msg->findInt64("seekTimeUs", &seekTimeUs); if (seekTimeUs == kInvalidTimeUs) { sp<MediaPlayerBase> listener = mListener.promote(); if (listener != NULL) { int32_t positionMs = 0; listener->getCurrentPosition(&positionMs); seekTimeUs = positionMs * 1000ll; } } if (mPaused) { mPendingSeekTimeUs = seekTimeUs; break; } mSendSubtitleGeneration++; doSeekAndRead(seekTimeUs); break; } case kWhatSendSubtitle: { int32_t generation; CHECK(msg->findInt32("generation", &generation)); if (generation != mSendSubtitleGeneration) { // Drop obsolete msg. break; } // If current time doesn't reach to the fire time, // re-post the message with the adjusted delay time. int64_t fireTimeUs = kInvalidTimeUs; if (msg->findInt64("fireTimeUs", &fireTimeUs)) { // TODO: check if fireTimeUs is not kInvalidTimeUs. int64_t delayUs = delayUsFromCurrentTime(fireTimeUs); if (delayUs > 0) { msg->post(delayUs); break; } } sp<RefBase> obj; if (msg->findObject("subtitle", &obj)) { sp<ParcelEvent> parcelEvent; parcelEvent = static_cast<ParcelEvent*>(obj.get()); notifyListener(&(parcelEvent->parcel)); doRead(); } else { notifyListener(); } break; } case kWhatSetSource: { mSendSubtitleGeneration++; sp<RefBase> obj; msg->findObject("source", &obj); if (mSource != NULL) { mSource->stop(); mSource.clear(); mSource = NULL; } // null source means deselect track. if (obj == NULL) { mPendingSeekTimeUs = kInvalidTimeUs; mPaused = false; notifyListener(); break; } mSource = static_cast<TimedTextSource*>(obj.get()); status_t err = mSource->start(); if (err != OK) { notifyError(err); break; } Parcel parcel; err = mSource->extractGlobalDescriptions(&parcel); if (err != OK) { notifyError(err); break; } notifyListener(&parcel); break; } } }
void TimedTextPlayer::onMessageReceived(const sp<AMessage> &msg) { switch (msg->what()) { case kWhatPause: { mSendSubtitleGeneration++; break; } case kWhatRetryRead: { int64_t seekTimeUs; int seekMode; if (msg->findInt64("seekTimeUs", &seekTimeUs) && msg->findInt32("seekMode", &seekMode)) { MediaSource::ReadOptions options; options.setSeekTo( seekTimeUs, static_cast<MediaSource::ReadOptions::SeekMode>(seekMode)); doRead(&options); } else { doRead(); } break; } case kWhatSeek: { int64_t seekTimeUs = 0; msg->findInt64("seekTimeUs", &seekTimeUs); if (seekTimeUs < 0) { sp<MediaPlayerBase> listener = mListener.promote(); if (listener != NULL) { int32_t positionMs = 0; listener->getCurrentPosition(&positionMs); seekTimeUs = positionMs * 1000ll; } } doSeekAndRead(seekTimeUs); break; } case kWhatSendSubtitle: { int32_t generation; CHECK(msg->findInt32("generation", &generation)); if (generation != mSendSubtitleGeneration) { // Drop obsolete msg. break; } sp<RefBase> obj; if (msg->findObject("subtitle", &obj)) { sp<ParcelEvent> parcelEvent; parcelEvent = static_cast<ParcelEvent*>(obj.get()); notifyListener(&(parcelEvent->parcel)); doRead(); } else { notifyListener(); } break; } case kWhatSetSource: { sp<RefBase> obj; msg->findObject("source", &obj); if (obj == NULL) break; if (mSource != NULL) { mSource->stop(); } mSource = static_cast<TimedTextSource*>(obj.get()); status_t err = mSource->start(); if (err != OK) { notifyError(err); break; } Parcel parcel; err = mSource->extractGlobalDescriptions(&parcel); if (err != OK) { notifyError(err); break; } notifyListener(&parcel); break; } } }
void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { switch (msg->what()) { case kWhatSetDataSource: { LOGV("kWhatSetDataSource"); CHECK(mSource == NULL); sp<RefBase> obj; CHECK(msg->findObject("source", &obj)); mSource = static_cast<Source *>(obj.get()); break; } case kWhatSetVideoNativeWindow: { LOGV("kWhatSetVideoNativeWindow"); sp<RefBase> obj; CHECK(msg->findObject("native-window", &obj)); mNativeWindow = static_cast<NativeWindowWrapper *>(obj.get()); break; } case kWhatSetAudioSink: { LOGV("kWhatSetAudioSink"); sp<RefBase> obj; CHECK(msg->findObject("sink", &obj)); mAudioSink = static_cast<MediaPlayerBase::AudioSink *>(obj.get()); break; } case kWhatStart: { LOGV("kWhatStart"); mVideoIsAVC = false; mAudioEOS = false; mVideoEOS = false; mSkipRenderingAudioUntilMediaTimeUs = -1; mSkipRenderingVideoUntilMediaTimeUs = -1; mVideoLateByUs = 0; mNumFramesTotal = 0; mNumFramesDropped = 0; mSource->start(); mRenderer = new Renderer( mAudioSink, new AMessage(kWhatRendererNotify, id())); looper()->registerHandler(mRenderer); postScanSources(); break; } case kWhatScanSources: { int32_t generation; CHECK(msg->findInt32("generation", &generation)); if (generation != mScanSourcesGeneration) { // Drop obsolete msg. break; } mScanSourcesPending = false; LOGV("scanning sources haveAudio=%d, haveVideo=%d", mAudioDecoder != NULL, mVideoDecoder != NULL); instantiateDecoder(false, &mVideoDecoder); if (mAudioSink != NULL) { instantiateDecoder(true, &mAudioDecoder); } status_t err; if ((err = mSource->feedMoreTSData()) != OK) { if (mAudioDecoder == NULL && mVideoDecoder == NULL) { // We're not currently decoding anything (no audio or // video tracks found) and we just ran out of input data. if (err == ERROR_END_OF_STREAM) { notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0); } else { notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); } } break; } if (mAudioDecoder == NULL || mVideoDecoder == NULL) { msg->post(100000ll); mScanSourcesPending = true; } break; } case kWhatVideoNotify: case kWhatAudioNotify: { bool audio = msg->what() == kWhatAudioNotify; sp<AMessage> codecRequest; CHECK(msg->findMessage("codec-request", &codecRequest)); int32_t what; CHECK(codecRequest->findInt32("what", &what)); if (what == ACodec::kWhatFillThisBuffer) { status_t err = feedDecoderInputData( audio, codecRequest); if (err == -EWOULDBLOCK) { if (mSource->feedMoreTSData() == OK) { msg->post(10000ll); } } } else if (what == ACodec::kWhatEOS) { int32_t err; CHECK(codecRequest->findInt32("err", &err)); if (err == ERROR_END_OF_STREAM) { LOGV("got %s decoder EOS", audio ? "audio" : "video"); } else { LOGV("got %s decoder EOS w/ error %d", audio ? "audio" : "video", err); } mRenderer->queueEOS(audio, err); } else if (what == ACodec::kWhatFlushCompleted) { bool needShutdown; if (audio) { CHECK(IsFlushingState(mFlushingAudio, &needShutdown)); mFlushingAudio = FLUSHED; } else { CHECK(IsFlushingState(mFlushingVideo, &needShutdown)); mFlushingVideo = FLUSHED; mVideoLateByUs = 0; } LOGV("decoder %s flush completed", audio ? "audio" : "video"); if (needShutdown) { LOGV("initiating %s decoder shutdown", audio ? "audio" : "video"); (audio ? mAudioDecoder : mVideoDecoder)->initiateShutdown(); if (audio) { mFlushingAudio = SHUTTING_DOWN_DECODER; } else { mFlushingVideo = SHUTTING_DOWN_DECODER; } } finishFlushIfPossible(); } else if (what == ACodec::kWhatOutputFormatChanged) { if (audio) { int32_t numChannels; CHECK(codecRequest->findInt32("channel-count", &numChannels)); int32_t sampleRate; CHECK(codecRequest->findInt32("sample-rate", &sampleRate)); LOGV("Audio output format changed to %d Hz, %d channels", sampleRate, numChannels); mAudioSink->close(); CHECK_EQ(mAudioSink->open( sampleRate, numChannels, AUDIO_FORMAT_PCM_16_BIT, 8 /* bufferCount */), (status_t)OK); mAudioSink->start(); mRenderer->signalAudioSinkChanged(); } else { // video int32_t width, height; CHECK(codecRequest->findInt32("width", &width)); CHECK(codecRequest->findInt32("height", &height)); int32_t cropLeft, cropTop, cropRight, cropBottom; CHECK(codecRequest->findRect( "crop", &cropLeft, &cropTop, &cropRight, &cropBottom)); LOGV("Video output format changed to %d x %d " "(crop: %d x %d @ (%d, %d))", width, height, (cropRight - cropLeft + 1), (cropBottom - cropTop + 1), cropLeft, cropTop); notifyListener( MEDIA_SET_VIDEO_SIZE, cropRight - cropLeft + 1, cropBottom - cropTop + 1); } } else if (what == ACodec::kWhatShutdownCompleted) { LOGV("%s shutdown completed", audio ? "audio" : "video"); if (audio) { mAudioDecoder.clear(); CHECK_EQ((int)mFlushingAudio, (int)SHUTTING_DOWN_DECODER); mFlushingAudio = SHUT_DOWN; } else { mVideoDecoder.clear(); CHECK_EQ((int)mFlushingVideo, (int)SHUTTING_DOWN_DECODER); mFlushingVideo = SHUT_DOWN; } finishFlushIfPossible(); } else if (what == ACodec::kWhatError) { LOGE("Received error from %s decoder, aborting playback.", audio ? "audio" : "video"); mRenderer->queueEOS(audio, UNKNOWN_ERROR); } else { CHECK_EQ((int)what, (int)ACodec::kWhatDrainThisBuffer); renderBuffer(audio, codecRequest); } break; } case kWhatRendererNotify: { int32_t what; CHECK(msg->findInt32("what", &what)); if (what == Renderer::kWhatEOS) { int32_t audio; CHECK(msg->findInt32("audio", &audio)); int32_t finalResult; CHECK(msg->findInt32("finalResult", &finalResult)); if (audio) { mAudioEOS = true; } else { mVideoEOS = true; } if (finalResult == ERROR_END_OF_STREAM) { LOGV("reached %s EOS", audio ? "audio" : "video"); } else { LOGE("%s track encountered an error (%d)", audio ? "audio" : "video", finalResult); notifyListener( MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, finalResult); } if ((mAudioEOS || mAudioDecoder == NULL) && (mVideoEOS || mVideoDecoder == NULL)) { notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0); } } else if (what == Renderer::kWhatPosition) { int64_t positionUs; CHECK(msg->findInt64("positionUs", &positionUs)); CHECK(msg->findInt64("videoLateByUs", &mVideoLateByUs)); if (mDriver != NULL) { sp<NuPlayerDriver> driver = mDriver.promote(); if (driver != NULL) { driver->notifyPosition(positionUs); driver->notifyFrameStats( mNumFramesTotal, mNumFramesDropped); } } } else if (what == Renderer::kWhatFlushComplete) { CHECK_EQ(what, (int32_t)Renderer::kWhatFlushComplete); int32_t audio; CHECK(msg->findInt32("audio", &audio)); LOGV("renderer %s flush completed.", audio ? "audio" : "video"); } break; } case kWhatMoreDataQueued: { break; } case kWhatReset: { LOGV("kWhatReset"); if (mRenderer != NULL) { // There's an edge case where the renderer owns all output // buffers and is paused, therefore the decoder will not read // more input data and will never encounter the matching // discontinuity. To avoid this, we resume the renderer. if (mFlushingAudio == AWAITING_DISCONTINUITY || mFlushingVideo == AWAITING_DISCONTINUITY) { mRenderer->resume(); } } if (mFlushingAudio != NONE || mFlushingVideo != NONE) { // We're currently flushing, postpone the reset until that's // completed. LOGV("postponing reset mFlushingAudio=%d, mFlushingVideo=%d", mFlushingAudio, mFlushingVideo); mResetPostponed = true; break; } if (mAudioDecoder == NULL && mVideoDecoder == NULL) { finishReset(); break; } mTimeDiscontinuityPending = true; if (mAudioDecoder != NULL) { flushDecoder(true /* audio */, true /* needShutdown */); } if (mVideoDecoder != NULL) { flushDecoder(false /* audio */, true /* needShutdown */); } mResetInProgress = true; break; } case kWhatSeek: { int64_t seekTimeUs; CHECK(msg->findInt64("seekTimeUs", &seekTimeUs)); LOGV("kWhatSeek seekTimeUs=%lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6); mSource->seekTo(seekTimeUs); if (mDriver != NULL) { sp<NuPlayerDriver> driver = mDriver.promote(); if (driver != NULL) { driver->notifySeekComplete(); } } break; } case kWhatPause: { CHECK(mRenderer != NULL); mRenderer->pause(); break; } case kWhatResume: { CHECK(mRenderer != NULL); mRenderer->resume(); break; } default: TRESPASS(); break; } }