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, ×tamp.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> ¶ms);
+ 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