Merge "NuPlayer: update timestamp handling" into lmp-dev
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 72e51f9..b5256f0 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -580,7 +580,14 @@
      * Caution: calling this method too often may be inefficient;
      * if you need a high resolution mapping between frame position and presentation time,
      * consider implementing that at application level, based on the low resolution timestamps.
-     * Returns NO_ERROR if timestamp is valid.
+     * Returns NO_ERROR    if timestamp is valid.
+     *         WOULD_BLOCK if called in STOPPED or FLUSHED state, or if called immediately after
+     *                     start/ACTIVE, when the number of frames consumed is less than the
+     *                     overall hardware latency to physical output. In WOULD_BLOCK cases,
+     *                     one might poll again, or use getPosition(), or use 0 position and
+     *                     current time for the timestamp.
+     *         INVALID_OPERATION  if called on a FastTrack, wrong state, or some other error.
+     *
      * The timestamp parameter is undefined on return, if status is not NO_ERROR.
      */
             status_t    getTimestamp(AudioTimestamp& timestamp);
@@ -747,6 +754,8 @@
                                                     // reset by stop() but continues monotonically
                                                     // after new IAudioTrack to restore mPosition,
                                                     // and could be easily widened to uint64_t
+    int64_t                 mStartUs;               // the start time after flush or stop.
+                                                    // only used for offloaded and direct tracks.
 
     audio_output_flags_t    mFlags;
         // const after set(), except for bits AUDIO_OUTPUT_FLAG_FAST and AUDIO_OUTPUT_FLAG_OFFLOAD.
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index ff7da83..762dca5 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -37,6 +37,19 @@
 namespace android {
 // ---------------------------------------------------------------------------
 
+static int64_t convertTimespecToUs(const struct timespec &tv)
+{
+    return tv.tv_sec * 1000000ll + tv.tv_nsec / 1000;
+}
+
+// current monotonic time in microseconds.
+static int64_t getNowUs()
+{
+    struct timespec tv;
+    (void) clock_gettime(CLOCK_MONOTONIC, &tv);
+    return convertTimespecToUs(tv);
+}
+
 // static
 status_t AudioTrack::getMinFrameCount(
         size_t* frameCount,
@@ -420,6 +433,7 @@
     mServer = 0;
     mPosition = 0;
     mReleased = 0;
+    mStartUs = 0;
     AudioSystem::acquireAudioSessionId(mSessionId, mClientPid);
     mSequence = 1;
     mObservedSequence = mSequence;
@@ -451,6 +465,12 @@
         // reset current position as seen by client to 0
         mPosition = 0;
         mReleased = 0;
+        // For offloaded tracks, we don't know if the hardware counters are really zero here,
+        // since the flush is asynchronous and stop may not fully drain.
+        // We save the time when the track is started to later verify whether
+        // the counters are realistic (i.e. start from zero after this time).
+        mStartUs = getNowUs();
+
         // force refresh of remaining frames by processAudioBuffer() as last
         // write before stop could be partial.
         mRefreshRemaining = true;
@@ -587,9 +607,18 @@
 
     if (isOffloaded_l()) {
         if (mOutput != AUDIO_IO_HANDLE_NONE) {
+            // An offload output can be re-used between two audio tracks having
+            // the same configuration. A timestamp query for a paused track
+            // while the other is running would return an incorrect time.
+            // To fix this, cache the playback position on a pause() and return
+            // this time when requested until the track is resumed.
+
+            // OffloadThread sends HAL pause in its threadLoop. Time saved
+            // here can be slightly off.
+
+            // TODO: check return code for getRenderPosition.
+
             uint32_t halFrames;
-            // OffloadThread sends HAL pause in its threadLoop.. time saved
-            // here can be slightly off
             AudioSystem::getRenderPosition(mOutput, &halFrames, &mPausedPosition);
             ALOGV("AudioTrack::pause for offload, cache current position %u", mPausedPosition);
         }
@@ -825,6 +854,8 @@
             uint32_t halFrames;
             AudioSystem::getRenderPosition(mOutput, &halFrames, &dspFrames);
         }
+        // FIXME: dspFrames may not be zero in (mState == STATE_STOPPED || mState == STATE_FLUSHED)
+        // due to hardware latency. We leave this behavior for now.
         *position = dspFrames;
     } else {
         // IAudioTrack::stop() isn't synchronous; we don't know when presentation completes
@@ -1881,13 +1912,70 @@
     if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
         return INVALID_OPERATION;
     }
-    if (mState != STATE_ACTIVE && mState != STATE_PAUSED) {
-        return INVALID_OPERATION;
+
+    switch (mState) {
+    case STATE_ACTIVE:
+    case STATE_PAUSED:
+        break; // handle below
+    case STATE_FLUSHED:
+    case STATE_STOPPED:
+        return WOULD_BLOCK;
+    case STATE_STOPPING:
+    case STATE_PAUSED_STOPPING:
+        if (!isOffloaded_l()) {
+            return INVALID_OPERATION;
+        }
+        break; // offloaded tracks handled below
+    default:
+        LOG_ALWAYS_FATAL("Invalid mState in getTimestamp(): %d", mState);
+        break;
     }
+
     // The presented frame count must always lag behind the consumed frame count.
     // To avoid a race, read the presented frames first.  This ensures that presented <= consumed.
     status_t status = mAudioTrack->getTimestamp(timestamp);
-    if (status == NO_ERROR) {
+    if (status != NO_ERROR) {
+        ALOGW_IF(status != WOULD_BLOCK, "getTimestamp error:%#x", status);
+        return status;
+    }
+    if (isOffloadedOrDirect_l()) {
+        if (isOffloaded_l() && (mState == STATE_PAUSED || mState == STATE_PAUSED_STOPPING)) {
+            // use cached paused position in case another offloaded track is running.
+            timestamp.mPosition = mPausedPosition;
+            clock_gettime(CLOCK_MONOTONIC, &timestamp.mTime);
+            return NO_ERROR;
+        }
+
+        // Check whether a pending flush or stop has completed, as those commands may
+        // be asynchronous or return near finish.
+        if (mStartUs != 0 && mSampleRate != 0) {
+            static const int kTimeJitterUs = 100000; // 100 ms
+            static const int k1SecUs = 1000000;
+
+            const int64_t timeNow = getNowUs();
+
+            if (timeNow < mStartUs + k1SecUs) { // within first second of starting
+                const int64_t timestampTimeUs = convertTimespecToUs(timestamp.mTime);
+                if (timestampTimeUs < mStartUs) {
+                    return WOULD_BLOCK;  // stale timestamp time, occurs before start.
+                }
+                const int64_t deltaTimeUs = timestampTimeUs - mStartUs;
+                const int64_t deltaPositionByUs = timestamp.mPosition * 1000000LL / mSampleRate;
+
+                if (deltaPositionByUs > deltaTimeUs + kTimeJitterUs) {
+                    // Verify that the counter can't count faster than the sample rate
+                    // since the start time.  If greater, then that means we have failed
+                    // to completely flush or stop the previous playing track.
+                    ALOGW("incomplete flush or stop:"
+                            " deltaTimeUs(%lld) deltaPositionUs(%lld) tsmPosition(%u)",
+                            (long long)deltaTimeUs, (long long)deltaPositionByUs,
+                            timestamp.mPosition);
+                    return WOULD_BLOCK;
+                }
+            }
+            mStartUs = 0; // no need to check again, start timestamp has either expired or unneeded.
+        }
+    } else {
         // Update the mapping between local consumed (mPosition) and server consumed (mServer)
         (void) updateAndGetPosition_l();
         // Server consumed (mServer) and presented both use the same server time base,
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index bd67cbd..142107d 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -106,6 +106,10 @@
     return OK;
 }
 
+sp<MetaData> NuPlayer::GenericSource::getFileFormatMeta() const {
+    return mFileMeta;
+}
+
 status_t NuPlayer::GenericSource::initFromDataSource() {
     sp<MediaExtractor> extractor;
 
@@ -144,10 +148,10 @@
         checkDrmStatus(mDataSource);
     }
 
-    sp<MetaData> fileMeta = extractor->getMetaData();
-    if (fileMeta != NULL) {
+    mFileMeta = extractor->getMetaData();
+    if (mFileMeta != NULL) {
         int64_t duration;
-        if (fileMeta->findInt64(kKeyDuration, &duration)) {
+        if (mFileMeta->findInt64(kKeyDuration, &duration)) {
             mDurationUs = duration;
         }
     }
@@ -1256,6 +1260,8 @@
 
             sp<ABuffer> buffer = mediaBufferToABuffer(mbuf, trackType, actualTimeUs);
             track->mPackets->queueAccessUnit(buffer);
+            formatChange = false;
+            seeking = false;
             ++numBuffers;
         } else if (err == WOULD_BLOCK) {
             break;
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 454edeb..24bb6af 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -59,6 +59,8 @@
 
     virtual status_t feedMoreTSData();
 
+    virtual sp<MetaData> getFileFormatMeta() const;
+
     virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
 
     virtual status_t getDuration(int64_t *durationUs);
@@ -125,6 +127,7 @@
     sp<DataSource> mDataSource;
     sp<NuCachedSource2> mCachedSource;
     sp<WVMExtractor> mWVMExtractor;
+    sp<MetaData> mFileMeta;
     DrmManagerClient *mDrmManagerClient;
     sp<DecryptHandle> mDecryptHandle;
     bool mStarted;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 7c6d576..5321deb 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -1730,6 +1730,10 @@
     return err;
 }
 
+sp<MetaData> NuPlayer::getFileMeta() {
+    return mSource->getFileFormatMeta();
+}
+
 void NuPlayer::schedulePollDuration() {
     sp<AMessage> msg = new AMessage(kWhatPollDuration, id());
     msg->setInt32("generation", mPollDurationGeneration);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 2e951bd..7197e5f 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -67,6 +67,8 @@
     status_t getSelectedTrack(int32_t type, Parcel* reply) const;
     status_t selectTrack(size_t trackIndex, bool select);
 
+    sp<MetaData> getFileMeta();
+
     static const size_t kAggregateBufferSizeBytes;
 
 protected:
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index bcf8e99..7ec9876 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -45,6 +45,7 @@
       mPlayerFlags(0),
       mAtEOS(false),
       mLooping(false),
+      mAutoLoop(false),
       mStartupSeekTimeUs(-1) {
     mLooper->setName("NuPlayerDriver Looper");
 
@@ -533,6 +534,7 @@
 
 void NuPlayerDriver::setAudioSink(const sp<AudioSink> &audioSink) {
     mPlayer->setAudioSink(audioSink);
+    mAudioSink = audioSink;
 }
 
 status_t NuPlayerDriver::setParameter(
@@ -662,7 +664,8 @@
         case MEDIA_PLAYBACK_COMPLETE:
         {
             if (mState != STATE_RESET_IN_PROGRESS) {
-                if (mLooping) {
+                if (mLooping || (mAutoLoop
+                        && (mAudioSink == NULL || mAudioSink->realtime()))) {
                     mPlayer->seekToAsync(0);
                     break;
                 }
@@ -728,6 +731,13 @@
         }
     }
 
+    sp<MetaData> meta = mPlayer->getFileMeta();
+    int32_t loop;
+    if (meta != NULL
+            && meta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
+        mAutoLoop = true;
+    }
+
     mCondition.broadcast();
 }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index e81d605..f2bd431 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -114,10 +114,12 @@
 
     sp<ALooper> mLooper;
     sp<NuPlayer> mPlayer;
+    sp<AudioSink> mAudioSink;
     uint32_t mPlayerFlags;
 
     bool mAtEOS;
     bool mLooping;
+    bool mAutoLoop;
 
     int64_t mStartupSeekTimeUs;
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index 7d994fa..2f06c31 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -76,6 +76,7 @@
 
     virtual sp<AMessage> getFormat(bool audio);
     virtual sp<MetaData> getFormatMeta(bool /* audio */) { return NULL; }
+    virtual sp<MetaData> getFileFormatMeta() const { return NULL; }
 
     virtual status_t dequeueAccessUnit(
             bool audio, sp<ABuffer> *accessUnit) = 0;
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index 4569c1c..456be89 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -705,7 +705,9 @@
                     }
 
                     // Discard input buffer.
-                    inHeader->nFilledLen = 0;
+                    if (inHeader) {
+                        inHeader->nFilledLen = 0;
+                    }
 
                     aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);
 
@@ -736,7 +738,7 @@
                         notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
                         mOutputPortSettingsChange = AWAITING_DISABLED;
 
-                        if (inHeader->nFilledLen == 0) {
+                        if (inHeader && inHeader->nFilledLen == 0) {
                             inInfo->mOwnedByUs = false;
                             mInputBufferCount++;
                             inQueue.erase(inQueue.begin());
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 3720085..7786c27 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -158,9 +158,16 @@
 
     // wait for counterpart
     sp<AnotherPacketSource> otherSource;
-    if (stream == STREAMTYPE_AUDIO && (mStreamMask & STREAMTYPE_VIDEO)) {
+    uint32_t mask = mNewStreamMask & mStreamMask;
+    uint32_t fetchersMask  = 0;
+    for (size_t i = 0; i < mFetcherInfos.size(); ++i) {
+        uint32_t fetcherMask = mFetcherInfos.valueAt(i).mFetcher->getStreamTypeMask();
+        fetchersMask |= fetcherMask;
+    }
+    mask &= fetchersMask;
+    if (stream == STREAMTYPE_AUDIO && (mask & STREAMTYPE_VIDEO)) {
         otherSource = mPacketSources.valueFor(STREAMTYPE_VIDEO);
-    } else if (stream == STREAMTYPE_VIDEO && (mStreamMask & STREAMTYPE_AUDIO)) {
+    } else if (stream == STREAMTYPE_VIDEO && (mask & STREAMTYPE_AUDIO)) {
         otherSource = mPacketSources.valueFor(STREAMTYPE_AUDIO);
     }
     if (otherSource != NULL && !otherSource->hasBufferAvailable(&finalResult)) {
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index 1166762..f78f8b4 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -1009,7 +1009,16 @@
 
     // bulk extract non-ts files
     if (tsBuffer == NULL) {
-      err = extractAndQueueAccessUnits(buffer, itemMeta);
+        err = extractAndQueueAccessUnits(buffer, itemMeta);
+        if (err == -EAGAIN) {
+            // starting sequence number too low/high
+            postMonitorQueue();
+            return;
+        } else if (err == ERROR_OUT_OF_RANGE) {
+            // reached stopping point
+            stopAsync(/* clear = */false);
+            return;
+        }
     }
 
     if (err != OK) {
@@ -1552,14 +1561,52 @@
             if (startTimeUs < mStartTimeUs) {
                 continue;
             }
+
+            if (mStartTimeUsNotify != NULL) {
+                int32_t targetDurationSecs;
+                CHECK(mPlaylist->meta()->findInt32("target-duration", &targetDurationSecs));
+                int64_t targetDurationUs = targetDurationSecs * 1000000ll;
+
+                // Duplicated logic from how we handle .ts playlists.
+                if (mStartup && mSegmentStartTimeUs >= 0
+                        && timeUs - mStartTimeUs > targetDurationUs) {
+                    int32_t newSeqNumber = getSeqNumberWithAnchorTime(timeUs);
+                    if (newSeqNumber >= mSeqNumber) {
+                        --mSeqNumber;
+                    } else {
+                        mSeqNumber = newSeqNumber;
+                    }
+                    return -EAGAIN;
+                }
+
+                mStartTimeUsNotify->setInt64("timeUsAudio", timeUs);
+                mStartTimeUsNotify->setInt32("discontinuitySeq", mDiscontinuitySeq);
+                mStartTimeUsNotify->setInt32("streamMask", LiveSession::STREAMTYPE_AUDIO);
+                mStartTimeUsNotify->post();
+                mStartTimeUsNotify.clear();
+            }
+        }
+
+        if (mStopParams != NULL) {
+            // Queue discontinuity in original stream.
+            int32_t discontinuitySeq;
+            int64_t stopTimeUs;
+            if (!mStopParams->findInt32("discontinuitySeq", &discontinuitySeq)
+                    || discontinuitySeq > mDiscontinuitySeq
+                    || !mStopParams->findInt64("timeUsAudio", &stopTimeUs)
+                    || (discontinuitySeq == mDiscontinuitySeq && unitTimeUs >= stopTimeUs)) {
+                packetSource->queueAccessUnit(mSession->createFormatChangeBuffer());
+                mStreamTypeMask = 0;
+                mPacketSources.clear();
+                return ERROR_OUT_OF_RANGE;
+            }
         }
 
         sp<ABuffer> unit = new ABuffer(aac_frame_length);
         memcpy(unit->data(), adtsHeader, aac_frame_length);
 
         unit->meta()->setInt64("timeUs", unitTimeUs);
-        unit->meta()->setInt64("segmentStartTimeUs", getSegmentStartTimeUs(mSeqNumber));
-        unit->meta()->setInt32("discontinuitySeq", mDiscontinuitySeq);
+        setAccessUnitProperties(unit, packetSource);
         packetSource->queueAccessUnit(unit);
     }
 
diff --git a/media/libstagefright/httplive/PlaylistFetcher.h b/media/libstagefright/httplive/PlaylistFetcher.h
index 4ba37fa..4b09df1 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.h
+++ b/media/libstagefright/httplive/PlaylistFetcher.h
@@ -69,6 +69,10 @@
 
     void resumeUntilAsync(const sp<AMessage> &params);
 
+    uint32_t getStreamTypeMask() const {
+        return mStreamTypeMask;
+    }
+
 protected:
     virtual ~PlaylistFetcher();
     virtual void onMessageReceived(const sp<AMessage> &msg);
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 3d17c89..818bb05 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -3991,8 +3991,6 @@
             minFrames = 1;
         }
 
-        ALOGI("prepareTracks_l minFrames %d state %d frames ready %d, ",
-              minFrames, track->mState, track->framesReady());
         if ((track->framesReady() >= minFrames) && track->isReady() && !track->isPaused() &&
                 !track->isStopping_2() && !track->isStopped())
         {
diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp
index d5f6c1e..95ac070 100644
--- a/services/audiopolicy/AudioPolicyManager.cpp
+++ b/services/audiopolicy/AudioPolicyManager.cpp
@@ -2667,59 +2667,69 @@
                 continue;
             }
 
+            if ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
+                continue;
+            }
             audio_devices_t profileType = outProfile->mSupportedDevices.types();
             if ((profileType & mDefaultOutputDevice->mDeviceType) != AUDIO_DEVICE_NONE) {
                 profileType = mDefaultOutputDevice->mDeviceType;
             } else {
-                profileType = outProfile->mSupportedDevices[0]->mDeviceType;
-            }
-            if ((profileType & outputDeviceTypes) &&
-                    ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0)) {
-                sp<AudioOutputDescriptor> outputDesc = new AudioOutputDescriptor(outProfile);
-
-                outputDesc->mDevice = profileType;
-                audio_config_t config = AUDIO_CONFIG_INITIALIZER;
-                config.sample_rate = outputDesc->mSamplingRate;
-                config.channel_mask = outputDesc->mChannelMask;
-                config.format = outputDesc->mFormat;
-                audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
-                status_t status = mpClientInterface->openOutput(outProfile->mModule->mHandle,
-                                                                &output,
-                                                                &config,
-                                                                &outputDesc->mDevice,
-                                                                String8(""),
-                                                                &outputDesc->mLatency,
-                                                                outputDesc->mFlags);
-
-                if (status != NO_ERROR) {
-                    ALOGW("Cannot open output stream for device %08x on hw module %s",
-                          outputDesc->mDevice,
-                          mHwModules[i]->mName);
-                } else {
-                    outputDesc->mSamplingRate = config.sample_rate;
-                    outputDesc->mChannelMask = config.channel_mask;
-                    outputDesc->mFormat = config.format;
-
-                    for (size_t k = 0; k  < outProfile->mSupportedDevices.size(); k++) {
-                        audio_devices_t type = outProfile->mSupportedDevices[k]->mDeviceType;
-                        ssize_t index =
-                                mAvailableOutputDevices.indexOf(outProfile->mSupportedDevices[k]);
-                        // give a valid ID to an attached device once confirmed it is reachable
-                        if ((index >= 0) && (mAvailableOutputDevices[index]->mId == 0)) {
-                            mAvailableOutputDevices[index]->mId = nextUniqueId();
-                            mAvailableOutputDevices[index]->mModule = mHwModules[i];
-                        }
+                // chose first device present in mSupportedDevices also part of
+                // outputDeviceTypes
+                for (size_t k = 0; k  < outProfile->mSupportedDevices.size(); k++) {
+                    profileType = outProfile->mSupportedDevices[k]->mDeviceType;
+                    if ((profileType & outputDeviceTypes) != 0) {
+                        break;
                     }
-                    if (mPrimaryOutput == 0 &&
-                            outProfile->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY) {
-                        mPrimaryOutput = output;
-                    }
-                    addOutput(output, outputDesc);
-                    setOutputDevice(output,
-                                    outputDesc->mDevice,
-                                    true);
                 }
             }
+            if ((profileType & outputDeviceTypes) == 0) {
+                continue;
+            }
+            sp<AudioOutputDescriptor> outputDesc = new AudioOutputDescriptor(outProfile);
+
+            outputDesc->mDevice = profileType;
+            audio_config_t config = AUDIO_CONFIG_INITIALIZER;
+            config.sample_rate = outputDesc->mSamplingRate;
+            config.channel_mask = outputDesc->mChannelMask;
+            config.format = outputDesc->mFormat;
+            audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
+            status_t status = mpClientInterface->openOutput(outProfile->mModule->mHandle,
+                                                            &output,
+                                                            &config,
+                                                            &outputDesc->mDevice,
+                                                            String8(""),
+                                                            &outputDesc->mLatency,
+                                                            outputDesc->mFlags);
+
+            if (status != NO_ERROR) {
+                ALOGW("Cannot open output stream for device %08x on hw module %s",
+                      outputDesc->mDevice,
+                      mHwModules[i]->mName);
+            } else {
+                outputDesc->mSamplingRate = config.sample_rate;
+                outputDesc->mChannelMask = config.channel_mask;
+                outputDesc->mFormat = config.format;
+
+                for (size_t k = 0; k  < outProfile->mSupportedDevices.size(); k++) {
+                    audio_devices_t type = outProfile->mSupportedDevices[k]->mDeviceType;
+                    ssize_t index =
+                            mAvailableOutputDevices.indexOf(outProfile->mSupportedDevices[k]);
+                    // give a valid ID to an attached device once confirmed it is reachable
+                    if ((index >= 0) && (mAvailableOutputDevices[index]->mId == 0)) {
+                        mAvailableOutputDevices[index]->mId = nextUniqueId();
+                        mAvailableOutputDevices[index]->mModule = mHwModules[i];
+                    }
+                }
+                if (mPrimaryOutput == 0 &&
+                        outProfile->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY) {
+                    mPrimaryOutput = output;
+                }
+                addOutput(output, outputDesc);
+                setOutputDevice(output,
+                                outputDesc->mDevice,
+                                true);
+            }
         }
         // open input streams needed to access attached devices to validate
         // mAvailableInputDevices list
@@ -2731,45 +2741,53 @@
                 ALOGW("Input profile contains no device on module %s", mHwModules[i]->mName);
                 continue;
             }
-
-            audio_devices_t profileType = inProfile->mSupportedDevices[0]->mDeviceType;
-            if (profileType & inputDeviceTypes) {
-                sp<AudioInputDescriptor> inputDesc = new AudioInputDescriptor(inProfile);
-
-                inputDesc->mInputSource = AUDIO_SOURCE_MIC;
-                inputDesc->mDevice = profileType;
-
-                audio_config_t config = AUDIO_CONFIG_INITIALIZER;
-                config.sample_rate = inputDesc->mSamplingRate;
-                config.channel_mask = inputDesc->mChannelMask;
-                config.format = inputDesc->mFormat;
-                audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
-                status_t status = mpClientInterface->openInput(inProfile->mModule->mHandle,
-                                                               &input,
-                                                               &config,
-                                                               &inputDesc->mDevice,
-                                                               String8(""),
-                                                               AUDIO_SOURCE_MIC,
-                                                               AUDIO_INPUT_FLAG_NONE);
-
-                if (status == NO_ERROR) {
-                    for (size_t k = 0; k  < inProfile->mSupportedDevices.size(); k++) {
-                        audio_devices_t type = inProfile->mSupportedDevices[k]->mDeviceType;
-                        ssize_t index =
-                                mAvailableInputDevices.indexOf(inProfile->mSupportedDevices[k]);
-                        // give a valid ID to an attached device once confirmed it is reachable
-                        if ((index >= 0) && (mAvailableInputDevices[index]->mId == 0)) {
-                            mAvailableInputDevices[index]->mId = nextUniqueId();
-                            mAvailableInputDevices[index]->mModule = mHwModules[i];
-                        }
-                    }
-                    mpClientInterface->closeInput(input);
-                } else {
-                    ALOGW("Cannot open input stream for device %08x on hw module %s",
-                          inputDesc->mDevice,
-                          mHwModules[i]->mName);
+            // chose first device present in mSupportedDevices also part of
+            // inputDeviceTypes
+            audio_devices_t profileType = AUDIO_DEVICE_NONE;
+            for (size_t k = 0; k  < inProfile->mSupportedDevices.size(); k++) {
+                profileType = inProfile->mSupportedDevices[k]->mDeviceType;
+                if (profileType & inputDeviceTypes) {
+                    break;
                 }
             }
+            if ((profileType & inputDeviceTypes) == 0) {
+                continue;
+            }
+            sp<AudioInputDescriptor> inputDesc = new AudioInputDescriptor(inProfile);
+
+            inputDesc->mInputSource = AUDIO_SOURCE_MIC;
+            inputDesc->mDevice = profileType;
+
+            audio_config_t config = AUDIO_CONFIG_INITIALIZER;
+            config.sample_rate = inputDesc->mSamplingRate;
+            config.channel_mask = inputDesc->mChannelMask;
+            config.format = inputDesc->mFormat;
+            audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
+            status_t status = mpClientInterface->openInput(inProfile->mModule->mHandle,
+                                                           &input,
+                                                           &config,
+                                                           &inputDesc->mDevice,
+                                                           String8(""),
+                                                           AUDIO_SOURCE_MIC,
+                                                           AUDIO_INPUT_FLAG_NONE);
+
+            if (status == NO_ERROR) {
+                for (size_t k = 0; k  < inProfile->mSupportedDevices.size(); k++) {
+                    audio_devices_t type = inProfile->mSupportedDevices[k]->mDeviceType;
+                    ssize_t index =
+                            mAvailableInputDevices.indexOf(inProfile->mSupportedDevices[k]);
+                    // give a valid ID to an attached device once confirmed it is reachable
+                    if ((index >= 0) && (mAvailableInputDevices[index]->mId == 0)) {
+                        mAvailableInputDevices[index]->mId = nextUniqueId();
+                        mAvailableInputDevices[index]->mModule = mHwModules[i];
+                    }
+                }
+                mpClientInterface->closeInput(input);
+            } else {
+                ALOGW("Cannot open input stream for device %08x on hw module %s",
+                      inputDesc->mDevice,
+                      mHwModules[i]->mName);
+            }
         }
     }
     // make sure all attached devices have been allocated a unique ID