Merge "NuPlayer will notify SeekComplete only when requested so." into lmp-dev
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index b87a09e..bca78b9 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -268,7 +268,7 @@
 
     static void PostReplyWithError(int32_t replyID, int32_t err);
 
-    status_t init(const char *name, bool nameIsType, bool encoder);
+    status_t init(const AString &name, bool nameIsType, bool encoder);
 
     void setState(State newState);
     void returnBuffersToCodec();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index d2caf65..ceedb40 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -157,6 +157,7 @@
       mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER),
       mAudioDecoderGeneration(0),
       mVideoDecoderGeneration(0),
+      mRendererGeneration(0),
       mAudioEOS(false),
       mVideoEOS(false),
       mScanSourcesPending(false),
@@ -637,10 +638,10 @@
                 flags |= Renderer::FLAG_OFFLOAD_AUDIO;
             }
 
-            mRenderer = new Renderer(
-                    mAudioSink,
-                    new AMessage(kWhatRendererNotify, id()),
-                    flags);
+            sp<AMessage> notify = new AMessage(kWhatRendererNotify, id());
+            ++mRendererGeneration;
+            notify->setInt32("generation", mRendererGeneration);
+            mRenderer = new Renderer(mAudioSink, notify, flags);
 
             mRendererLooper = new ALooper;
             mRendererLooper->setName("NuPlayerRenderer");
@@ -817,11 +818,13 @@
                 ALOGV("%s shutdown completed", audio ? "audio" : "video");
                 if (audio) {
                     mAudioDecoder.clear();
+                    ++mAudioDecoderGeneration;
 
                     CHECK_EQ((int)mFlushingAudio, (int)SHUTTING_DOWN_DECODER);
                     mFlushingAudio = SHUT_DOWN;
                 } else {
                     mVideoDecoder.clear();
+                    ++mVideoDecoderGeneration;
 
                     CHECK_EQ((int)mFlushingVideo, (int)SHUTTING_DOWN_DECODER);
                     mFlushingVideo = SHUT_DOWN;
@@ -839,9 +842,11 @@
                 mRenderer->queueEOS(audio, err);
                 if (audio && mFlushingAudio != NONE) {
                     mAudioDecoder.clear();
+                    ++mAudioDecoderGeneration;
                     mFlushingAudio = SHUT_DOWN;
                 } else if (!audio && mFlushingVideo != NONE){
                     mVideoDecoder.clear();
+                    ++mVideoDecoderGeneration;
                     mFlushingVideo = SHUT_DOWN;
                 }
                 finishFlushIfPossible();
@@ -861,6 +866,14 @@
 
         case kWhatRendererNotify:
         {
+            int32_t requesterGeneration = mRendererGeneration - 1;
+            CHECK(msg->findInt32("generation", &requesterGeneration));
+            if (requesterGeneration != mRendererGeneration) {
+                ALOGV("got message from old renderer, generation(%d:%d)",
+                        requesterGeneration, mRendererGeneration);
+                return;
+            }
+
             int32_t what;
             CHECK(msg->findInt32("what", &what));
 
@@ -923,6 +936,7 @@
                 CHECK(msg->findInt64("positionUs", &positionUs));
                 closeAudioSink();
                 mAudioDecoder.clear();
+                ++mAudioDecoderGeneration;
                 mRenderer->flush(true /* audio */);
                 if (mVideoDecoder != NULL) {
                     mRenderer->flush(false /* audio */);
@@ -978,17 +992,31 @@
 
         case kWhatPause:
         {
-            CHECK(mRenderer != NULL);
-            mSource->pause();
-            mRenderer->pause();
+            if (mSource != NULL) {
+                mSource->pause();
+            } else {
+                ALOGW("pause called when source is gone or not set");
+            }
+            if (mRenderer != NULL) {
+                mRenderer->pause();
+            } else {
+                ALOGW("pause called when renderer is gone or not set");
+            }
             break;
         }
 
         case kWhatResume:
         {
-            CHECK(mRenderer != NULL);
-            mSource->resume();
-            mRenderer->resume();
+            if (mSource != NULL) {
+                mSource->resume();
+            } else {
+                ALOGW("resume called when source is gone or not set");
+            }
+            if (mRenderer != NULL) {
+                mRenderer->resume();
+            } else {
+                ALOGW("resume called when renderer is gone or not set");
+            }
             break;
         }
 
@@ -1860,9 +1888,6 @@
     ++mScanSourcesGeneration;
     mScanSourcesPending = false;
 
-    ++mAudioDecoderGeneration;
-    ++mVideoDecoderGeneration;
-
     if (mRendererLooper != NULL) {
         if (mRenderer != NULL) {
             mRendererLooper->unregisterHandler(mRenderer->id());
@@ -1871,6 +1896,7 @@
         mRendererLooper.clear();
     }
     mRenderer.clear();
+    ++mRendererGeneration;
 
     if (mSource != NULL) {
         mSource->stop();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 18cfe86..8fa7269 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -138,6 +138,7 @@
     sp<ALooper> mRendererLooper;
     int32_t mAudioDecoderGeneration;
     int32_t mVideoDecoderGeneration;
+    int32_t mRendererGeneration;
 
     List<sp<Action> > mDeferredActions;
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index a8c8818..73ac057 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -32,6 +32,10 @@
 
 namespace android {
 
+// Maximum time in paused state when offloading audio decompression. When elapsed, the AudioSink
+// is closed to allow the audio DSP to power down.
+static const int64_t kOffloadPauseMaxUs = 60000000ll;
+
 // static
 const int64_t NuPlayer::Renderer::kMinPositionUpdateDelayUs = 100000ll;
 
@@ -61,7 +65,9 @@
       mVideoRenderingStartGeneration(0),
       mAudioRenderingStartGeneration(0),
       mLastPositionUpdateUs(-1ll),
-      mVideoLateByUs(0ll) {
+      mVideoLateByUs(0ll),
+      mAudioOffloadPauseTimeoutGeneration(0),
+      mAudioOffloadTornDown(false) {
 }
 
 NuPlayer::Renderer::~Renderer() {
@@ -259,6 +265,17 @@
             break;
         }
 
+        case kWhatAudioOffloadPauseTimeout:
+        {
+            int32_t generation;
+            CHECK(msg->findInt32("generation", &generation));
+            if (generation != mAudioOffloadPauseTimeoutGeneration) {
+                break;
+            }
+            onAudioOffloadTearDown();
+            break;
+        }
+
         default:
             TRESPASS();
             break;
@@ -951,6 +968,7 @@
 
     if (mHasAudio) {
         mAudioSink->pause();
+        startAudioOffloadPauseTimeout();
     }
 
     ALOGV("now paused audio queue has %d entries, video has %d entries",
@@ -963,6 +981,7 @@
     }
 
     if (mHasAudio) {
+        cancelAudioOffloadPauseTimeout();
         mAudioSink->start();
     }
 
@@ -1051,6 +1070,11 @@
 }
 
 void NuPlayer::Renderer::onAudioOffloadTearDown() {
+    if (mAudioOffloadTornDown) {
+        return;
+    }
+    mAudioOffloadTornDown = true;
+
     int64_t firstAudioTimeUs;
     {
         Mutex::Autolock autoLock(mLock);
@@ -1069,5 +1093,19 @@
     notify->post();
 }
 
+void NuPlayer::Renderer::startAudioOffloadPauseTimeout() {
+    if (offloadingAudio()) {
+        sp<AMessage> msg = new AMessage(kWhatAudioOffloadPauseTimeout, id());
+        msg->setInt32("generation", mAudioOffloadPauseTimeoutGeneration);
+        msg->post(kOffloadPauseMaxUs);
+    }
+}
+
+void NuPlayer::Renderer::cancelAudioOffloadPauseTimeout() {
+    if (offloadingAudio()) {
+        ++mAudioOffloadPauseTimeoutGeneration;
+    }
+}
+
 }  // namespace android
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index e28071f..8e6112b 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -66,6 +66,7 @@
         kWhatVideoRenderingStart = 'vdrd',
         kWhatMediaRenderingStart = 'mdrd',
         kWhatAudioOffloadTearDown = 'aOTD',
+        kWhatAudioOffloadPauseTimeout = 'aOPT',
     };
 
 protected:
@@ -132,6 +133,9 @@
     int64_t mLastPositionUpdateUs;
     int64_t mVideoLateByUs;
 
+    int32_t mAudioOffloadPauseTimeoutGeneration;
+    bool mAudioOffloadTornDown;
+
     size_t fillAudioBuffer(void *buffer, size_t size);
 
     bool onDrainAudioQueue();
@@ -168,6 +172,9 @@
 
     bool offloadingAudio() const { return (mFlags & FLAG_OFFLOAD_AUDIO) != 0; }
 
+    void startAudioOffloadPauseTimeout();
+    void cancelAudioOffloadPauseTimeout();
+
     DISALLOW_EVIL_CONSTRUCTORS(Renderer);
 };
 
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 9d6fd78..a72cbd5 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -199,7 +199,18 @@
     } else if (!strncasecmp("http://", uri, 7)
             || !strncasecmp("https://", uri, 8)
             || isWidevine) {
-        sp<HTTPBase> httpSource = new MediaHTTP(httpService->makeHTTPConnection());
+        if (httpService == NULL) {
+            ALOGE("Invalid http service!");
+            return NULL;
+        }
+
+        sp<IMediaHTTPConnection> conn = httpService->makeHTTPConnection();
+        if (conn == NULL) {
+            ALOGE("Failed to make http connection from http service!");
+            return NULL;
+        }
+
+        sp<HTTPBase> httpSource = new MediaHTTP(conn);
 
         String8 tmp;
         if (isWidevine) {
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 0bfc6e4..6c98c52 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -179,7 +179,7 @@
     response->postReply(replyID);
 }
 
-status_t MediaCodec::init(const char *name, bool nameIsType, bool encoder) {
+status_t MediaCodec::init(const AString &name, bool nameIsType, bool encoder) {
     // save init parameters for reset
     mInitName = name;
     mInitNameIsType = nameIsType;
@@ -191,7 +191,7 @@
     // queue.
     mCodec = new ACodec;
     bool needDedicatedLooper = false;
-    if (nameIsType && !strncasecmp(name, "video/", 6)) {
+    if (nameIsType && !strncasecmp(name.c_str(), "video/", 6)) {
         needDedicatedLooper = true;
     } else {
         AString tmp = name;
@@ -357,7 +357,7 @@
     mHaveInputSurface = false;
 
     if (err == OK) {
-        err = init(mInitName.c_str(), mInitNameIsType, mInitIsEncoder);
+        err = init(mInitName, mInitNameIsType, mInitIsEncoder);
     }
     return err;
 }
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index f3dfc59..423a420 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -254,7 +254,9 @@
     static void addSDES(int s, const sp<ABuffer> &buffer) {
         struct sockaddr_in addr;
         socklen_t addrSize = sizeof(addr);
-        CHECK_EQ(0, getsockname(s, (sockaddr *)&addr, &addrSize));
+        if (getsockname(s, (sockaddr *)&addr, &addrSize) != 0) {
+            inet_aton("0.0.0.0", &(addr.sin_addr));
+        }
 
         uint8_t *data = buffer->data() + buffer->size();
         data[0] = 0x80 | 1;
diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp
index 95ac070..d51ee8e 100644
--- a/services/audiopolicy/AudioPolicyManager.cpp
+++ b/services/audiopolicy/AudioPolicyManager.cpp
@@ -112,7 +112,7 @@
     STRING_TO_ENUM(AUDIO_DEVICE_IN_LOOPBACK),
 };
 
-const StringToEnum sFlagNameToEnumTable[] = {
+const StringToEnum sOutputFlagNameToEnumTable[] = {
     STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DIRECT),
     STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_PRIMARY),
     STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_FAST),
@@ -122,6 +122,11 @@
     STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_HW_AV_SYNC),
 };
 
+const StringToEnum sInputFlagNameToEnumTable[] = {
+    STRING_TO_ENUM(AUDIO_INPUT_FLAG_FAST),
+    STRING_TO_ENUM(AUDIO_INPUT_FLAG_HW_HOTWORD),
+};
+
 const StringToEnum sFormatNameToEnumTable[] = {
     STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT),
     STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_BIT),
@@ -1292,16 +1297,41 @@
         break;
     }
 
+    audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
+    bool isSoundTrigger = false;
+    audio_source_t halInputSource = inputSource;
+    if (inputSource == AUDIO_SOURCE_HOTWORD) {
+        ssize_t index = mSoundTriggerSessions.indexOfKey(session);
+        if (index >= 0) {
+            input = mSoundTriggerSessions.valueFor(session);
+            isSoundTrigger = true;
+            flags = (audio_input_flags_t)(flags | AUDIO_INPUT_FLAG_HW_HOTWORD);
+            ALOGV("SoundTrigger capture on session %d input %d", session, input);
+        } else {
+            halInputSource = AUDIO_SOURCE_VOICE_RECOGNITION;
+        }
+    }
+
     sp<IOProfile> profile = getInputProfile(device,
                                          samplingRate,
                                          format,
                                          channelMask,
                                          flags);
     if (profile == 0) {
-        ALOGW("getInput() could not find profile for device 0x%X, samplingRate %u, format %#x, "
-                "channelMask 0x%X, flags %#x",
-                device, samplingRate, format, channelMask, flags);
-        return AUDIO_IO_HANDLE_NONE;
+        //retry without flags
+        audio_input_flags_t log_flags = flags;
+        flags = AUDIO_INPUT_FLAG_NONE;
+        profile = getInputProfile(device,
+                                 samplingRate,
+                                 format,
+                                 channelMask,
+                                 flags);
+        if (profile == 0) {
+            ALOGW("getInput() could not find profile for device 0x%X, samplingRate %u, format %#x, "
+                    "channelMask 0x%X, flags %#x",
+                    device, samplingRate, format, channelMask, log_flags);
+            return AUDIO_IO_HANDLE_NONE;
+        }
     }
 
     if (profile->mModule->mHandle == 0) {
@@ -1313,20 +1343,7 @@
     config.sample_rate = samplingRate;
     config.channel_mask = channelMask;
     config.format = format;
-    audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
 
-    bool isSoundTrigger = false;
-    audio_source_t halInputSource = inputSource;
-    if (inputSource == AUDIO_SOURCE_HOTWORD) {
-        ssize_t index = mSoundTriggerSessions.indexOfKey(session);
-        if (index >= 0) {
-            input = mSoundTriggerSessions.valueFor(session);
-            isSoundTrigger = true;
-            ALOGV("SoundTrigger capture on session %d input %d", session, input);
-        } else {
-            halInputSource = AUDIO_SOURCE_VOICE_RECOGNITION;
-        }
-    }
     status_t status = mpClientInterface->openInput(profile->mModule->mHandle,
                                                    &input,
                                                    &config,
@@ -5220,7 +5237,7 @@
         mStrategyMutedByDevice[i] = false;
     }
     if (profile != NULL) {
-        mFlags = profile->mFlags;
+        mFlags = (audio_output_flags_t)profile->mFlags;
         mSamplingRate = profile->pickSamplingRate();
         mFormat = profile->pickFormat();
         mChannelMask = profile->pickChannelMask();
@@ -5568,6 +5585,8 @@
         } else if (strcmp(node->name, DEVICES_TAG) == 0) {
             profile->mSupportedDevices.loadDevicesFromName((char *)node->value,
                                                            mDeclaredDevices);
+        } else if (strcmp(node->name, FLAGS_TAG) == 0) {
+            profile->mFlags = parseInputFlagNames((char *)node->value);
         } else if (strcmp(node->name, GAINS_TAG) == 0) {
             profile->loadGains(node);
         }
@@ -5613,7 +5632,7 @@
             profile->mSupportedDevices.loadDevicesFromName((char *)node->value,
                                                            mDeclaredDevices);
         } else if (strcmp(node->name, FLAGS_TAG) == 0) {
-            profile->mFlags = parseFlagNames((char *)node->value);
+            profile->mFlags = parseOutputFlagNames((char *)node->value);
         } else if (strcmp(node->name, GAINS_TAG) == 0) {
             profile->loadGains(node);
         }
@@ -5728,7 +5747,7 @@
 
 AudioPolicyManager::AudioPort::AudioPort(const String8& name, audio_port_type_t type,
           audio_port_role_t role, const sp<HwModule>& module) :
-    mName(name), mType(type), mRole(role), mModule(module), mFlags((audio_output_flags_t)0)
+    mName(name), mType(type), mRole(role), mModule(module), mFlags(0)
 {
     mUseInChannelMask = ((type == AUDIO_PORT_TYPE_DEVICE) && (role == AUDIO_PORT_ROLE_SOURCE)) ||
                     ((type == AUDIO_PORT_TYPE_MIX) && (role == AUDIO_PORT_ROLE_SINK));
@@ -6560,7 +6579,7 @@
                                                             uint32_t *updatedSamplingRate,
                                                             audio_format_t format,
                                                             audio_channel_mask_t channelMask,
-                                                            audio_output_flags_t flags) const
+                                                            uint32_t flags) const
 {
     const bool isPlaybackThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SOURCE;
     const bool isRecordThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK;
@@ -6602,7 +6621,7 @@
     // An existing fast stream is compatible with a normal track request.
     // An existing normal stream is compatible with a fast track request,
     // but the fast request will be denied by AudioFlinger and converted to normal track.
-    if (isRecordThread && (((audio_input_flags_t) mFlags ^ (audio_input_flags_t) flags) &
+    if (isRecordThread && ((mFlags ^ flags) &
             ~AUDIO_INPUT_FLAG_FAST)) {
         return false;
     }
@@ -6958,7 +6977,7 @@
 
 // --- audio_policy.conf file parsing
 
-audio_output_flags_t AudioPolicyManager::parseFlagNames(char *name)
+uint32_t AudioPolicyManager::parseOutputFlagNames(char *name)
 {
     uint32_t flag = 0;
 
@@ -6967,8 +6986,8 @@
     char *flagName = strtok(name, "|");
     while (flagName != NULL) {
         if (strlen(flagName) != 0) {
-            flag |= stringToEnum(sFlagNameToEnumTable,
-                               ARRAY_SIZE(sFlagNameToEnumTable),
+            flag |= stringToEnum(sOutputFlagNameToEnumTable,
+                               ARRAY_SIZE(sOutputFlagNameToEnumTable),
                                flagName);
         }
         flagName = strtok(NULL, "|");
@@ -6980,7 +6999,25 @@
         flag |= AUDIO_OUTPUT_FLAG_DIRECT;
     }
 
-    return (audio_output_flags_t)flag;
+    return flag;
+}
+
+uint32_t AudioPolicyManager::parseInputFlagNames(char *name)
+{
+    uint32_t flag = 0;
+
+    // it is OK to cast name to non const here as we are not going to use it after
+    // strtok() modifies it
+    char *flagName = strtok(name, "|");
+    while (flagName != NULL) {
+        if (strlen(flagName) != 0) {
+            flag |= stringToEnum(sInputFlagNameToEnumTable,
+                               ARRAY_SIZE(sInputFlagNameToEnumTable),
+                               flagName);
+        }
+        flagName = strtok(NULL, "|");
+    }
+    return flag;
 }
 
 audio_devices_t AudioPolicyManager::parseDeviceNames(char *name)
diff --git a/services/audiopolicy/AudioPolicyManager.h b/services/audiopolicy/AudioPolicyManager.h
index da0d95d..0ea7b97 100644
--- a/services/audiopolicy/AudioPolicyManager.h
+++ b/services/audiopolicy/AudioPolicyManager.h
@@ -283,8 +283,8 @@
             Vector <audio_format_t> mFormats; // supported audio formats
             Vector < sp<AudioGain> > mGains; // gain controllers
             sp<HwModule> mModule;                 // audio HW module exposing this I/O stream
-            audio_output_flags_t mFlags; // attribute flags (e.g primary output,
-                                                // direct output...). For outputs only.
+            uint32_t mFlags; // attribute flags (e.g primary output,
+                                                // direct output...).
         };
 
         class AudioPortConfig: public virtual RefBase
@@ -387,7 +387,7 @@
                                      uint32_t *updatedSamplingRate,
                                      audio_format_t format,
                                      audio_channel_mask_t channelMask,
-                                     audio_output_flags_t flags) const;
+                                     uint32_t flags) const;
 
             void dump(int fd);
             void log();
@@ -754,7 +754,8 @@
                                       size_t size,
                                       uint32_t value);
         static bool stringToBool(const char *value);
-        static audio_output_flags_t parseFlagNames(char *name);
+        static uint32_t parseOutputFlagNames(char *name);
+        static uint32_t parseInputFlagNames(char *name);
         static audio_devices_t parseDeviceNames(char *name);
         void loadHwModule(cnode *root);
         void loadHwModules(cnode *root);
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index fe2f299..48ec730 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -1217,6 +1217,8 @@
     {
         SharedParameters::Lock l(mParameters);
         if (l.mParameters.state < Parameters::PREVIEW) {
+            ALOGE("%s: Camera %d: Call autoFocus when preview is inactive (state = %d).",
+                    __FUNCTION__, mCameraId, l.mParameters.state);
             return INVALID_OPERATION;
         }