Merge "AudioFlinger: Prevent offload underrun during active playback" into nyc-mr1-dev
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 9a87023..b172747 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -891,6 +891,9 @@
if (read > 0) {
break;
}
+ if (err == TIMED_OUT || err == -EINTR) {
+ err = WOULD_BLOCK;
+ }
return ssize_t(err);
}
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index fad8350..68a47a3 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -1739,6 +1739,9 @@
if (written > 0) {
break;
}
+ if (err == TIMED_OUT || err == -EINTR) {
+ err = WOULD_BLOCK;
+ }
return ssize_t(err);
}
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index f352d5b..ffe896e 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -1063,47 +1063,37 @@
//
////////////////////////////////////////////////////////////////////////////////
bool ToneGenerator::initAudioTrack() {
-
- // Open audio track in mono, PCM 16bit, default sampling rate, default buffer size
+ // Open audio track in mono, PCM 16bit, default sampling rate.
mpAudioTrack = new AudioTrack();
- ALOGV("Create Track: %p", mpAudioTrack.get());
+ ALOGV("AudioTrack(%p) created", mpAudioTrack.get());
- mpAudioTrack->set(mStreamType,
- 0, // sampleRate
- AUDIO_FORMAT_PCM_16_BIT,
- AUDIO_CHANNEL_OUT_MONO,
- 0, // frameCount
- AUDIO_OUTPUT_FLAG_FAST,
- audioCallback,
- this, // user
- 0, // notificationFrames
- 0, // sharedBuffer
- mThreadCanCallJava,
- AUDIO_SESSION_ALLOCATE,
- AudioTrack::TRANSFER_CALLBACK);
+ const size_t frameCount = mProcessSize;
+ status_t status = mpAudioTrack->set(
+ mStreamType,
+ 0, // sampleRate
+ AUDIO_FORMAT_PCM_16_BIT,
+ AUDIO_CHANNEL_OUT_MONO,
+ frameCount,
+ AUDIO_OUTPUT_FLAG_FAST,
+ audioCallback,
+ this, // user
+ 0, // notificationFrames
+ 0, // sharedBuffer
+ mThreadCanCallJava,
+ AUDIO_SESSION_ALLOCATE,
+ AudioTrack::TRANSFER_CALLBACK);
- if (mpAudioTrack->initCheck() != NO_ERROR) {
- ALOGE("AudioTrack->initCheck failed");
- goto initAudioTrack_exit;
+ if (status != NO_ERROR) {
+ ALOGE("AudioTrack(%p) set failed with error %d", mpAudioTrack.get(), status);
+ mpAudioTrack.clear();
+ return false;
}
mpAudioTrack->setVolume(mVolume);
-
mState = TONE_INIT;
-
return true;
-
-initAudioTrack_exit:
-
- ALOGV("Init failed: %p", mpAudioTrack.get());
-
- // Cleanup
- mpAudioTrack.clear();
-
- return false;
}
-
////////////////////////////////////////////////////////////////////////////////
//
// Method: ToneGenerator::audioCallback()
diff --git a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
index 5210683..5ed037a 100644
--- a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
+++ b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
@@ -460,6 +460,47 @@
resetPlugin();
}
+bool SoftMPEG2::getSeqInfo() {
+ IV_API_CALL_STATUS_T status;
+ impeg2d_ctl_get_seq_info_ip_t s_ctl_get_seq_info_ip;
+ impeg2d_ctl_get_seq_info_op_t s_ctl_get_seq_info_op;
+
+ s_ctl_get_seq_info_ip.e_cmd = IVD_CMD_VIDEO_CTL;
+ s_ctl_get_seq_info_ip.e_sub_cmd =
+ (IVD_CONTROL_API_COMMAND_TYPE_T)IMPEG2D_CMD_CTL_GET_SEQ_INFO;
+
+ s_ctl_get_seq_info_ip.u4_size = sizeof(impeg2d_ctl_get_seq_info_ip_t);
+ s_ctl_get_seq_info_op.u4_size = sizeof(impeg2d_ctl_get_seq_info_op_t);
+
+ status = ivdec_api_function(
+ (iv_obj_t *)mCodecCtx, (void *)&s_ctl_get_seq_info_ip,
+ (void *)&s_ctl_get_seq_info_op);
+
+ if (status != IV_SUCCESS) {
+ ALOGW("Error in getting Sequence info: 0x%x",
+ s_ctl_get_seq_info_op.u4_error_code);
+ return false;
+ }
+
+
+ int32_t primaries = s_ctl_get_seq_info_op.u1_colour_primaries;
+ int32_t transfer = s_ctl_get_seq_info_op.u1_transfer_characteristics;
+ int32_t coeffs = s_ctl_get_seq_info_op.u1_matrix_coefficients;
+ bool fullRange = false; // mpeg2 video has limited range.
+
+ ColorAspects colorAspects;
+ ColorUtils::convertIsoColorAspectsToCodecAspects(
+ primaries, transfer, coeffs, fullRange, colorAspects);
+
+ // Update color aspects if necessary.
+ if (colorAspectsDiffer(colorAspects, mBitstreamColorAspects)) {
+ mBitstreamColorAspects = colorAspects;
+ status_t err = handleColorAspectsChange();
+ CHECK(err == OK);
+ }
+ return true;
+}
+
OMX_ERRORTYPE SoftMPEG2::internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params) {
const uint32_t oldWidth = mWidth;
const uint32_t oldHeight = mHeight;
@@ -650,6 +691,8 @@
bool unsupportedDimensions = (IMPEG2D_UNSUPPORTED_DIMENSIONS == s_dec_op.u4_error_code);
bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF));
+ getSeqInfo();
+
GETTIME(&mTimeEnd, NULL);
/* Compute time taken for decode() */
TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);
@@ -705,6 +748,8 @@
continue;
}
+ // Combine the resolution change and coloraspects change in one PortSettingChange event
+ // if necessary.
if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) {
uint32_t width = s_dec_op.u4_pic_wd;
uint32_t height = s_dec_op.u4_pic_ht;
@@ -715,6 +760,11 @@
resetDecoder();
return;
}
+ } else if (mUpdateColorAspects) {
+ notify(OMX_EventPortSettingsChanged, kOutputPortIndex,
+ kDescribeColorAspectsIndex, NULL);
+ mUpdateColorAspects = false;
+ return;
}
if (s_dec_op.u4_output_present) {
@@ -783,6 +833,10 @@
}
}
+int SoftMPEG2::getColorAspectPreference() {
+ return kPreferBitstream;
+}
+
} // namespace android
android::SoftOMXComponent *createSoftOMXComponent(
diff --git a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h
index 025e9a0..700ef5f 100644
--- a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h
+++ b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.h
@@ -63,6 +63,7 @@
virtual void onQueueFilled(OMX_U32 portIndex);
virtual void onPortFlushCompleted(OMX_U32 portIndex);
virtual void onReset();
+ virtual int getColorAspectPreference();
virtual OMX_ERRORTYPE internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params);
private:
// Number of input and output buffers
@@ -125,6 +126,8 @@
OMX_BUFFERHEADERTYPE *outHeader,
size_t timeStampIx);
+ bool getSeqInfo();
+
DISALLOW_EVIL_CONSTRUCTORS(SoftMPEG2);
};
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index fb034e3..d093c32 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1662,6 +1662,7 @@
mEffectBufferValid(false),
mSuspended(0), mBytesWritten(0),
mFramesWritten(0),
+ mSuspendedFrames(0),
mActiveTracksGeneration(0),
// mStreamTypes[] initialized in constructor body
mOutput(output),
@@ -3055,7 +3056,8 @@
// copy over kernel info
mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL] =
- timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL];
+ timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL]
+ + mSuspendedFrames; // add frames discarded when suspended
mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] =
timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL];
}
@@ -3219,10 +3221,12 @@
mBytesRemaining = mCurrentWriteLength;
if (isSuspended()) {
- mSleepTimeUs = suspendSleepTimeUs();
- // simulate write to HAL when suspended
- mBytesWritten += mSinkBufferSize;
- mFramesWritten += mSinkBufferSize / mFrameSize;
+ // Simulate write to HAL when suspended (e.g. BT SCO phone call).
+ mSleepTimeUs = suspendSleepTimeUs(); // assumes full buffer.
+ const size_t framesRemaining = mBytesRemaining / mFrameSize;
+ mBytesWritten += mBytesRemaining;
+ mFramesWritten += framesRemaining;
+ mSuspendedFrames += framesRemaining; // to adjust kernel HAL position
mBytesRemaining = 0;
}
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index ba6ae5b..1d5d3c8 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -721,6 +721,7 @@
int64_t mBytesWritten;
int64_t mFramesWritten; // not reset on standby
+ int64_t mSuspendedFrames; // not reset on standby
private:
// mMasterMute is in both PlaybackThread and in AudioFlinger. When a
// PlaybackThread needs to find out if master-muted, it checks it's local
@@ -1020,7 +1021,7 @@
virtual bool waitingAsyncCallback_l();
virtual void invalidateTracks(audio_stream_type_t streamType);
- virtual bool keepWakeLock() const { return mKeepWakeLock; }
+ virtual bool keepWakeLock() const { return (mKeepWakeLock || (mDrainSequence & 1)); }
private:
size_t mPausedWriteLength; // length in bytes of write interrupted by pause
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 51066fd..c0bb4e7 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1167,8 +1167,10 @@
beaconMuteLatency = handleEventForBeacon(STARTING_OUTPUT);
}
+ // force device change if the output is inactive and no audio patch is already present.
// check active before incrementing usage count
- bool force = !outputDesc->isActive();
+ bool force = !outputDesc->isActive() &&
+ (outputDesc->getPatchHandle() == AUDIO_PATCH_HANDLE_NONE);
// increment usage count for this stream on the requested output:
// NOTE that the usage count is the same for duplicated output and hardware output which is
@@ -1188,12 +1190,17 @@
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i);
if (desc != outputDesc) {
- // force a device change if any other output is managed by the same hw
- // module and has a current device selection that differs from selected device.
+ // force a device change if any other output is:
+ // - managed by the same hw module
+ // - has a current device selection that differs from selected device.
+ // - supports currently selected device
+ // - has an active audio patch
// In this case, the audio HAL must receive the new device selection so that it can
// change the device currently selected by the other active output.
if (outputDesc->sharesHwModuleWith(desc) &&
- desc->device() != device) {
+ desc->device() != device &&
+ desc->supportedDevices() & device &&
+ desc->getPatchHandle() != AUDIO_PATCH_HANDLE_NONE) {
force = true;
}
// wait for audio on other active outputs to be presented when starting
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index f6e24e4..d24e9a0 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -987,6 +987,18 @@
delayMs = 1;
} break;
+ case SET_VOICE_VOLUME: {
+ VoiceVolumeData *data = (VoiceVolumeData *)command->mParam.get();
+ VoiceVolumeData *data2 = (VoiceVolumeData *)command2->mParam.get();
+ ALOGV("Filtering out voice volume command value %f replaced by %f",
+ data2->mVolume, data->mVolume);
+ removedCommands.add(command2);
+ command->mTime = command2->mTime;
+ // force delayMs to non 0 so that code below does not request to wait for
+ // command status as the command is now delayed
+ delayMs = 1;
+ } break;
+
case CREATE_AUDIO_PATCH:
case RELEASE_AUDIO_PATCH: {
audio_patch_handle_t handle;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 3b51239..bf94aca 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -2042,19 +2042,15 @@
// across configure_streams() calls
mRequestThread->configurationComplete(mIsConstrainedHighSpeedConfiguration);
- // Boost priority of request thread for high speed recording to SCHED_FIFO
- if (mIsConstrainedHighSpeedConfiguration) {
- pid_t requestThreadTid = mRequestThread->getTid();
- res = requestPriority(getpid(), requestThreadTid,
- kConstrainedHighSpeedThreadPriority, /*asynchronous*/ false);
- if (res != OK) {
- ALOGW("Can't set realtime priority for request processing thread: %s (%d)",
- strerror(-res), res);
- } else {
- ALOGD("Set real time priority for request queue thread (tid %d)", requestThreadTid);
- }
+ // Boost priority of request thread to SCHED_FIFO.
+ pid_t requestThreadTid = mRequestThread->getTid();
+ res = requestPriority(getpid(), requestThreadTid,
+ kRequestThreadPriority, /*asynchronous*/ false);
+ if (res != OK) {
+ ALOGW("Can't set realtime priority for request processing thread: %s (%d)",
+ strerror(-res), res);
} else {
- // TODO: Set/restore normal priority for normal use cases
+ ALOGD("Set real time priority for request queue thread (tid %d)", requestThreadTid);
}
// Update device state
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index bbb6563..430ee6c 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -178,7 +178,7 @@
static const size_t kInFlightWarnLimit = 20;
static const size_t kInFlightWarnLimitHighSpeed = 256; // batch size 32 * pipe depth 8
// SCHED_FIFO priority for request submission thread in HFR mode
- static const int kConstrainedHighSpeedThreadPriority = 1;
+ static const int kRequestThreadPriority = 1;
struct RequestTrigger;
// minimal jpeg buffer size: 256KB + blob header