Merge "Camera3Device: Wait for empty in-flight map when waiting for idle" into nyc-mr1-dev
diff --git a/include/media/ToneGenerator.h b/include/media/ToneGenerator.h
index c41c686..75515ac 100644
--- a/include/media/ToneGenerator.h
+++ b/include/media/ToneGenerator.h
@@ -195,6 +195,11 @@
TONE_JAPAN_RADIO_ACK, // Radio path acknowlegment: 400Hz, 1s ON, 2s OFF...
// UK Supervisory tones
TONE_UK_RINGTONE, // Ring Tone: A 400Hz + 450Hz tone repeated in a 0.4s on, 0.2s off, 0.4s on, 2.0s off pattern.
+ // AUSTRALIA Supervisory tones
+ TONE_AUSTRALIA_RINGTONE, // Ring tone: A 400Hz + 450Hz tone repeated in a 0.4s on, 0.2s off, 0.4s on, 2.0s off pattern.
+ TONE_AUSTRALIA_BUSY, // Busy tone: 425 Hz repeated in a 0.375s on, 0.375s off pattern.
+ TONE_AUSTRALIA_CALL_WAITING,// Call waiting tone: 425Hz tone repeated in a 0.2s on, 0.2s off, 0.2s on, 4.4s off pattern.
+ TONE_AUSTRALIA_CONGESTION, // Congestion tone: 425Hz tone repeated in a 0.375s on, 0.375s off pattern
NUM_ALTERNATE_TONES
};
@@ -202,6 +207,7 @@
ANSI,
JAPAN,
UK,
+ AUSTRALIA,
CEPT,
NUM_REGIONS
};
diff --git a/include/media/stagefright/MediaBuffer.h b/include/media/stagefright/MediaBuffer.h
index 55b1f58..abfe068 100644
--- a/include/media/stagefright/MediaBuffer.h
+++ b/include/media/stagefright/MediaBuffer.h
@@ -108,6 +108,14 @@
return reinterpret_cast<SharedControl *>(memory->pointer())->isDeadObject();
}
+ // Sticky on enabling of shared memory MediaBuffers. By default we don't use
+ // shared memory for MediaBuffers, but we enable this for those processes
+ // that export MediaBuffers.
+ static void useSharedMemory() {
+ std::atomic_store_explicit(
+ &mUseSharedMemory, (int_least32_t)1, std::memory_order_seq_cst);
+ }
+
protected:
// MediaBuffer remote releases are handled through a
// pending release count variable stored in a SharedControl block
@@ -161,6 +169,8 @@
MediaBuffer *mOriginal;
+ static std::atomic_int_least32_t mUseSharedMemory;
+
MediaBuffer(const MediaBuffer &);
MediaBuffer &operator=(const MediaBuffer &);
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/IMediaExtractorService.cpp b/media/libmedia/IMediaExtractorService.cpp
index dcbbde2..d170c22 100644
--- a/media/libmedia/IMediaExtractorService.cpp
+++ b/media/libmedia/IMediaExtractorService.cpp
@@ -71,6 +71,9 @@
ALOGE("Error reading source from parcel");
return ret;
}
+ // If we make an extractor through Binder, enabled shared memory
+ // for MediaBuffers for this process.
+ MediaBuffer::useSharedMemory();
sp<IDataSource> source = interface_cast<IDataSource>(b);
const char *mime = data.readCString();
sp<IMediaExtractor> ex = makeExtractor(source, mime);
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index f352d5b..2f53637 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -747,9 +747,30 @@
{ .duration = 0, .waveFreq = { 0 }, 0, 0}},
.repeatCnt = ToneGenerator::TONEGEN_INF,
.repeatSegment = 0 }, // TONE_UK_RINGTONE
-
-
-
+ { .segments = { { .duration = 400, .waveFreq = { 400, 450, 0 }, 0, 0 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 400, .waveFreq = { 400, 450, 0 }, 0, 0 },
+ { .duration = 2000, .waveFreq = { 0 }, 0, 0},
+ { .duration = 0, .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_AUSTRALIA_RINGTONE
+ { .segments = { { .duration = 375, .waveFreq = { 425, 0 }, 0, 0 },
+ { .duration = 375, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_AUSTRALIA_BUSY
+ { .segments = { { .duration = 200, .waveFreq = { 425, 0 }, 0, 0 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 200, .waveFreq = { 425, 0 }, 0, 0 },
+ { .duration = 4400, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_AUSTRALIA_CALL_WAITING
+ { .segments = { { .duration = 375, .waveFreq = { 425, 0 }, 0, 0 },
+ { .duration = 375, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_AUSTRALIA_CONGESTION
};
// Used by ToneGenerator::getToneForRegion() to convert user specified supervisory tone type
@@ -784,8 +805,17 @@
TONE_SUP_ERROR, // TONE_SUP_ERROR
TONE_SUP_CALL_WAITING, // TONE_SUP_CALL_WAITING
TONE_UK_RINGTONE // TONE_SUP_RINGTONE
+ },
+ { // AUSTRALIA
+ TONE_ANSI_DIAL, // TONE_SUP_DIAL
+ TONE_AUSTRALIA_BUSY, // TONE_SUP_BUSY
+ TONE_AUSTRALIA_CONGESTION, // TONE_SUP_CONGESTION
+ TONE_SUP_RADIO_ACK, // TONE_SUP_RADIO_ACK
+ TONE_SUP_RADIO_NOTAVAIL, // TONE_SUP_RADIO_NOTAVAIL
+ TONE_SUP_ERROR, // TONE_SUP_ERROR
+ TONE_AUSTRALIA_CALL_WAITING,// TONE_SUP_CALL_WAITING
+ TONE_AUSTRALIA_RINGTONE // TONE_SUP_RINGTONE
}
-
};
@@ -841,6 +871,8 @@
mRegion = JAPAN;
} else if (strstr(value, "uk") != NULL) {
mRegion = UK;
+ } else if (strstr(value, "au") != NULL) {
+ mRegion = AUSTRALIA;
} else {
mRegion = CEPT;
}
@@ -1063,47 +1095,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/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index d790821..3cfed5e 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1938,6 +1938,7 @@
continue;
}
callbackData->mSwitching = true; // begin track switch
+ callbackData->setOutput(NULL);
#else
// tryBeginTrackSwitch() returns false if the callback has the lock.
if (!mCallbackData->tryBeginTrackSwitch()) {
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
index c4147e1..a7c5cf4 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
@@ -229,7 +229,8 @@
sp<MetaData> meta = source->getFormat();
status_t err = convertMetaDataToMessage(meta, &format);
- if (err != OK) {
+ if (err != OK) { // format may have been cleared on error
+ format = new AMessage;
format->setInt32("err", err);
}
return format;
diff --git a/media/libstagefright/AACExtractor.cpp b/media/libstagefright/AACExtractor.cpp
index 19efc53..7449aa7 100644
--- a/media/libstagefright/AACExtractor.cpp
+++ b/media/libstagefright/AACExtractor.cpp
@@ -174,7 +174,9 @@
if (mDataSource->getSize(&streamSize) == OK) {
while (offset < streamSize) {
if ((frameSize = getAdtsFrameLength(source, offset, NULL)) == 0) {
- return;
+ ALOGW("prematured AAC stream (%lld vs %lld)",
+ (long long)offset, (long long)streamSize);
+ break;
}
mOffsetVector.push(offset);
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 3dea270..cfdc341 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -4275,8 +4275,9 @@
h264type.eProfile = static_cast<OMX_VIDEO_AVCPROFILETYPE>(profile);
h264type.eLevel = static_cast<OMX_VIDEO_AVCLEVELTYPE>(level);
} else {
- // Use largest supported profile for AVC recording if profile is not specified.
h264type.eProfile = OMX_VIDEO_AVCProfileBaseline;
+#if 0 /* DON'T YET DEFAULT TO HIGHEST PROFILE */
+ // Use largest supported profile for AVC recording if profile is not specified.
for (OMX_VIDEO_AVCPROFILETYPE profile : {
OMX_VIDEO_AVCProfileHigh, OMX_VIDEO_AVCProfileMain }) {
if (verifySupportForProfileAndLevel(profile, 0) == OK) {
@@ -4284,6 +4285,7 @@
break;
}
}
+#endif
}
ALOGI("setupAVCEncoderParameters with [profile: %s] [level: %s]",
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 66c4ffd..4681abd 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -3030,8 +3030,6 @@
mOwner->writeInt16(0x18); // depth
mOwner->writeInt16(-1); // predefined
- CHECK_LT(23 + mCodecSpecificDataSize, 128);
-
if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
writeMp4vEsdsBox();
} else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
@@ -3151,6 +3149,10 @@
void MPEG4Writer::Track::writeMp4vEsdsBox() {
CHECK(mCodecSpecificData);
CHECK_GT(mCodecSpecificDataSize, 0);
+
+ // Make sure all sizes encode to a single byte.
+ CHECK_LT(23 + mCodecSpecificDataSize, 128);
+
mOwner->beginBox("esds");
mOwner->writeInt32(0); // version=0, flags=0
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index c9c49f5..eb1f193 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -18,6 +18,8 @@
//#define LOG_NDEBUG 0
#include <utils/Log.h>
+#include <limits>
+
#include "include/SampleTable.h"
#include "include/SampleIterator.h"
@@ -45,6 +47,8 @@
////////////////////////////////////////////////////////////////////////////////
+const off64_t kMaxOffset = std::numeric_limits<off64_t>::max();
+
struct SampleTable::CompositionDeltaLookup {
CompositionDeltaLookup();
@@ -233,11 +237,11 @@
mNumSampleToChunkOffsets = U32_AT(&header[4]);
- if ((data_size - 8) / 12 < mNumSampleToChunkOffsets) {
+ if ((data_size - 8) / sizeof(SampleToChunkEntry) < mNumSampleToChunkOffsets) {
return ERROR_MALFORMED;
}
- if ((uint64_t)SIZE_MAX / sizeof(SampleToChunkEntry) <=
+ if ((uint64_t)kMaxTotalSize / sizeof(SampleToChunkEntry) <=
(uint64_t)mNumSampleToChunkOffsets) {
ALOGE("Sample-to-chunk table size too large.");
return ERROR_OUT_OF_RANGE;
@@ -269,21 +273,19 @@
return OK;
}
- if ((off64_t)(SIZE_MAX - 8 -
+ if ((off64_t)(kMaxOffset - 8 -
((mNumSampleToChunkOffsets - 1) * sizeof(SampleToChunkEntry)))
< mSampleToChunkOffset) {
return ERROR_MALFORMED;
}
for (uint32_t i = 0; i < mNumSampleToChunkOffsets; ++i) {
- uint8_t buffer[12];
-
- if ((off64_t)(SIZE_MAX - 8 - (i * 12)) < mSampleToChunkOffset) {
- return ERROR_MALFORMED;
- }
+ uint8_t buffer[sizeof(SampleToChunkEntry)];
if (mDataSource->readAt(
- mSampleToChunkOffset + 8 + i * 12, buffer, sizeof(buffer))
+ mSampleToChunkOffset + 8 + i * sizeof(SampleToChunkEntry),
+ buffer,
+ sizeof(buffer))
!= (ssize_t)sizeof(buffer)) {
return ERROR_IO;
}
@@ -384,8 +386,7 @@
}
mTimeToSampleCount = U32_AT(&header[4]);
- if ((uint64_t)mTimeToSampleCount >
- (uint64_t)UINT32_MAX / (2 * sizeof(uint32_t))) {
+ if (mTimeToSampleCount > UINT32_MAX / (2 * sizeof(uint32_t))) {
// Choose this bound because
// 1) 2 * sizeof(uint32_t) is the amount of memory needed for one
// time-to-sample entry in the time-to-sample table.
@@ -469,7 +470,7 @@
mNumCompositionTimeDeltaEntries = numEntries;
uint64_t allocSize = (uint64_t)numEntries * 2 * sizeof(int32_t);
- if (allocSize > SIZE_MAX) {
+ if (allocSize > kMaxTotalSize) {
ALOGE("Composition-time-to-sample table size too large.");
return ERROR_OUT_OF_RANGE;
}
@@ -536,7 +537,7 @@
}
uint64_t allocSize = (uint64_t)mNumSyncSamples * sizeof(uint32_t);
- if (allocSize > SIZE_MAX) {
+ if (allocSize > kMaxTotalSize) {
ALOGE("Sync sample table size too large.");
return ERROR_OUT_OF_RANGE;
}
diff --git a/media/libstagefright/SimpleDecodingSource.cpp b/media/libstagefright/SimpleDecodingSource.cpp
index 1b44a00..de21c5e 100644
--- a/media/libstagefright/SimpleDecodingSource.cpp
+++ b/media/libstagefright/SimpleDecodingSource.cpp
@@ -43,7 +43,9 @@
CHECK(meta->findCString(kKeyMIMEType, &mime));
sp<AMessage> format = new AMessage;
- convertMetaDataToMessage(source->getFormat(), &format);
+ if (convertMetaDataToMessage(source->getFormat(), &format) != OK) {
+ return NULL;
+ }
Vector<AString> matchingCodecs;
MediaCodecList::findMatchingCodecs(
diff --git a/media/libstagefright/SurfaceUtils.cpp b/media/libstagefright/SurfaceUtils.cpp
index 568837a..60ef662 100644
--- a/media/libstagefright/SurfaceUtils.cpp
+++ b/media/libstagefright/SurfaceUtils.cpp
@@ -186,6 +186,10 @@
break;
}
+ if (img == NULL) {
+ ALOGE("error pushing blank frames: lock returned NULL buffer");
+ break;
+ }
*img = 0;
err = buf->unlock();
diff --git a/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
index 0215a11..5c70387 100644
--- a/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
+++ b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
@@ -182,6 +182,48 @@
return OK;
}
+bool SoftHEVC::getVUIParams() {
+ IV_API_CALL_STATUS_T status;
+ ihevcd_cxa_ctl_get_vui_params_ip_t s_ctl_get_vui_params_ip;
+ ihevcd_cxa_ctl_get_vui_params_op_t s_ctl_get_vui_params_op;
+
+ s_ctl_get_vui_params_ip.e_cmd = IVD_CMD_VIDEO_CTL;
+ s_ctl_get_vui_params_ip.e_sub_cmd =
+ (IVD_CONTROL_API_COMMAND_TYPE_T)IHEVCD_CXA_CMD_CTL_GET_VUI_PARAMS;
+
+ s_ctl_get_vui_params_ip.u4_size =
+ sizeof(ihevcd_cxa_ctl_get_vui_params_ip_t);
+
+ s_ctl_get_vui_params_op.u4_size = sizeof(ihevcd_cxa_ctl_get_vui_params_op_t);
+
+ status = ivdec_api_function(
+ (iv_obj_t *)mCodecCtx, (void *)&s_ctl_get_vui_params_ip,
+ (void *)&s_ctl_get_vui_params_op);
+
+ if (status != IV_SUCCESS) {
+ ALOGW("Error in getting VUI params: 0x%x",
+ s_ctl_get_vui_params_op.u4_error_code);
+ return false;
+ }
+
+ int32_t primaries = s_ctl_get_vui_params_op.u1_colour_primaries;
+ int32_t transfer = s_ctl_get_vui_params_op.u1_transfer_characteristics;
+ int32_t coeffs = s_ctl_get_vui_params_op.u1_matrix_coefficients;
+ bool fullRange = s_ctl_get_vui_params_op.u1_video_full_range_flag;
+
+ 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;
+}
+
status_t SoftHEVC::resetDecoder() {
ivd_ctl_reset_ip_t s_ctl_ip;
ivd_ctl_reset_op_t s_ctl_op;
@@ -554,6 +596,8 @@
bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF));
+ getVUIParams();
+
GETTIME(&mTimeEnd, NULL);
/* Compute time taken for decode() */
TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);
@@ -589,6 +633,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;
@@ -599,6 +645,11 @@
resetDecoder();
return;
}
+ } else if (mUpdateColorAspects) {
+ notify(OMX_EventPortSettingsChanged, kOutputPortIndex,
+ kDescribeColorAspectsIndex, NULL);
+ mUpdateColorAspects = false;
+ return;
}
if (s_dec_op.u4_output_present) {
@@ -654,6 +705,10 @@
}
}
+int SoftHEVC::getColorAspectPreference() {
+ return kPreferBitstream;
+}
+
} // namespace android
android::SoftOMXComponent *createSoftOMXComponent(const char *name,
diff --git a/media/libstagefright/codecs/hevcdec/SoftHEVC.h b/media/libstagefright/codecs/hevcdec/SoftHEVC.h
index 943edfd..20a836b 100644
--- a/media/libstagefright/codecs/hevcdec/SoftHEVC.h
+++ b/media/libstagefright/codecs/hevcdec/SoftHEVC.h
@@ -61,6 +61,7 @@
virtual void onQueueFilled(OMX_U32 portIndex);
virtual void onPortFlushCompleted(OMX_U32 portIndex);
virtual void onReset();
+ virtual int getColorAspectPreference();
private:
// Number of input and output buffers
enum {
@@ -112,6 +113,8 @@
OMX_BUFFERHEADERTYPE *outHeader,
size_t timeStampIx);
+ bool getVUIParams();
+
DISALLOW_EVIL_CONSTRUCTORS (SoftHEVC);
};
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/media/libstagefright/foundation/MediaBuffer.cpp b/media/libstagefright/foundation/MediaBuffer.cpp
index 15d557d..718b7e5 100644
--- a/media/libstagefright/foundation/MediaBuffer.cpp
+++ b/media/libstagefright/foundation/MediaBuffer.cpp
@@ -30,6 +30,9 @@
namespace android {
+/* static */
+std::atomic_int_least32_t MediaBuffer::mUseSharedMemory(0);
+
MediaBuffer::MediaBuffer(void *data, size_t size)
: mObserver(NULL),
mRefCount(0),
@@ -52,7 +55,8 @@
mOwnsData(true),
mMetaData(new MetaData),
mOriginal(NULL) {
- if (size < kSharedMemThreshold) {
+ if (size < kSharedMemThreshold
+ || std::atomic_load_explicit(&mUseSharedMemory, std::memory_order_seq_cst) == 0) {
mData = malloc(size);
} else {
ALOGV("creating memoryDealer");
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 8b831f0..05dacac 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -3,7 +3,8 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
- ServiceUtilities.cpp
+ ServiceUtilities.cpp \
+ LockWatch.cpp
# FIXME Move this library to frameworks/native
LOCAL_MODULE := libserviceutility
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 79f4a66..c32eadd 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -246,7 +246,9 @@
}
mPatchPanel = new PatchPanel(this);
-
+ // FIXME: bug 30737845: trigger audioserver restart if main audioflinger lock
+ // is held continuously for more than 3 seconds
+ mLockWatch = new LockWatch(mLock, String8("AudioFlinger"));
mMode = AUDIO_MODE_NORMAL;
}
@@ -279,6 +281,7 @@
}
}
}
+ mLockWatch->requestExitAndWait();
}
static const char * const audio_interfaces[] = {
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index c56dcc1..e334d80 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -58,6 +58,7 @@
#include "SpdifStreamOut.h"
#include "AudioHwDevice.h"
#include "LinearMap.h"
+#include "LockWatch.h"
#include <powermanager/IPowerManager.h>
@@ -630,6 +631,7 @@
};
mutable Mutex mLock;
+ sp<LockWatch> mLockWatch;
// protects mClients and mNotificationClients.
// must be locked after mLock and ThreadBase::mLock if both must be locked
// avoids acquiring AudioFlinger::mLock from inside thread loop.
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index aea6b67..0be7199 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -430,7 +430,7 @@
{
ALOGV("AudioMixer::deleteTrackName(%d)", name);
name -= TRACK0;
- ALOG_ASSERT(uint32_t(name) < MAX_NUM_TRACKS, "bad track name %d", name);
+ LOG_ALWAYS_FATAL_IF(name < 0 || name >= (int)MAX_NUM_TRACKS, "bad track name %d", name);
ALOGV("deleteTrackName(%d)", name);
track_t& track(mState.tracks[ name ]);
if (track.enabled) {
diff --git a/services/audioflinger/BufferProviders.cpp b/services/audioflinger/BufferProviders.cpp
index 2ca2cac..7b6dfcb 100644
--- a/services/audioflinger/BufferProviders.cpp
+++ b/services/audioflinger/BufferProviders.cpp
@@ -474,18 +474,18 @@
ALOGV("processFrames(%zu %zu) remaining(%zu)", *dstFrames, *srcFrames, mRemaining);
// Note dstFrames is the required number of frames.
- // Ensure consumption from src is as expected.
- //TODO: add logic to track "very accurate" consumption related to speed, original sampling
- //rate, actual frames processed.
- const size_t targetSrc = *dstFrames * mPlaybackRate.mSpeed;
- if (*srcFrames < targetSrc) { // limit dst frames to that possible
- *dstFrames = *srcFrames / mPlaybackRate.mSpeed;
- } else if (*srcFrames > targetSrc + 1) {
- *srcFrames = targetSrc + 1;
- }
-
if (!mAudioPlaybackRateValid) {
//fallback mode
+ // Ensure consumption from src is as expected.
+ // TODO: add logic to track "very accurate" consumption related to speed, original sampling
+ // rate, actual frames processed.
+
+ const size_t targetSrc = *dstFrames * mPlaybackRate.mSpeed;
+ if (*srcFrames < targetSrc) { // limit dst frames to that possible
+ *dstFrames = *srcFrames / mPlaybackRate.mSpeed;
+ } else if (*srcFrames > targetSrc + 1) {
+ *srcFrames = targetSrc + 1;
+ }
if (*dstFrames > 0) {
switch(mPlaybackRate.mFallbackMode) {
case AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT:
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index e6c8abc..e3e518c 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -216,9 +216,10 @@
return mHandles.size();
}
-void AudioFlinger::EffectModule::updateState() {
+bool AudioFlinger::EffectModule::updateState() {
Mutex::Autolock _l(mLock);
+ bool started = false;
switch (mState) {
case RESTART:
reset_l();
@@ -233,6 +234,7 @@
}
if (start_l() == NO_ERROR) {
mState = ACTIVE;
+ started = true;
} else {
mState = IDLE;
}
@@ -256,6 +258,8 @@
default: //IDLE , ACTIVE, DESTROYED
break;
}
+
+ return started;
}
void AudioFlinger::EffectModule::process()
@@ -462,10 +466,22 @@
}
}
+// start() must be called with PlaybackThread::mLock or EffectChain::mLock held
status_t AudioFlinger::EffectModule::start()
{
- Mutex::Autolock _l(mLock);
- return start_l();
+ sp<EffectChain> chain;
+ status_t status;
+ {
+ Mutex::Autolock _l(mLock);
+ status = start_l();
+ if (status == NO_ERROR) {
+ chain = mChain.promote();
+ }
+ }
+ if (chain != 0) {
+ chain->resetVolume_l();
+ }
+ return status;
}
status_t AudioFlinger::EffectModule::start_l()
@@ -489,10 +505,6 @@
}
if (status == 0) {
addEffectToHal_l();
- sp<EffectChain> chain = mChain.promote();
- if (chain != 0) {
- chain->forceVolume();
- }
}
return status;
}
@@ -1349,7 +1361,7 @@
audio_session_t sessionId)
: mThread(thread), mSessionId(sessionId), mActiveTrackCnt(0), mTrackCnt(0), mTailBufferCount(0),
mOwnInBuffer(false), mVolumeCtrlIdx(-1), mLeftVolume(UINT_MAX), mRightVolume(UINT_MAX),
- mNewLeftVolume(UINT_MAX), mNewRightVolume(UINT_MAX), mForceVolume(false)
+ mNewLeftVolume(UINT_MAX), mNewRightVolume(UINT_MAX)
{
mStrategy = AudioSystem::getStrategyForStream(AUDIO_STREAM_MUSIC);
if (thread == NULL) {
@@ -1471,8 +1483,12 @@
mEffects[i]->process();
}
}
+ bool doResetVolume = false;
for (size_t i = 0; i < size; i++) {
- mEffects[i]->updateState();
+ doResetVolume = mEffects[i]->updateState() || doResetVolume;
+ }
+ if (doResetVolume) {
+ resetVolume_l();
}
}
@@ -1653,8 +1669,8 @@
}
}
-// setVolume_l() must be called with PlaybackThread::mLock held
-bool AudioFlinger::EffectChain::setVolume_l(uint32_t *left, uint32_t *right)
+// setVolume_l() must be called with PlaybackThread::mLock or EffectChain::mLock held
+bool AudioFlinger::EffectChain::setVolume_l(uint32_t *left, uint32_t *right, bool force)
{
uint32_t newLeft = *left;
uint32_t newRight = *right;
@@ -1672,7 +1688,7 @@
}
}
- if (!isVolumeForced() && ctrlIdx == mVolumeCtrlIdx &&
+ if (!force && ctrlIdx == mVolumeCtrlIdx &&
*left == mLeftVolume && *right == mRightVolume) {
if (hasControl) {
*left = mNewLeftVolume;
@@ -1714,6 +1730,16 @@
return hasControl;
}
+// resetVolume_l() must be called with PlaybackThread::mLock or EffectChain::mLock held
+void AudioFlinger::EffectChain::resetVolume_l()
+{
+ if ((mLeftVolume != UINT_MAX) && (mRightVolume != UINT_MAX)) {
+ uint32_t left = mLeftVolume;
+ uint32_t right = mRightVolume;
+ (void)setVolume_l(&left, &right, true);
+ }
+}
+
void AudioFlinger::EffectChain::syncHalEffectsState()
{
Mutex::Autolock _l(mLock);
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index 3b62652..322c06a 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -60,7 +60,7 @@
int id() const { return mId; }
void process();
- void updateState();
+ bool updateState();
status_t command(uint32_t cmdCode,
uint32_t cmdSize,
void *pCmdData,
@@ -277,7 +277,8 @@
sp<EffectModule> getEffectFromId_l(int id);
sp<EffectModule> getEffectFromType_l(const effect_uuid_t *type);
// FIXME use float to improve the dynamic range
- bool setVolume_l(uint32_t *left, uint32_t *right);
+ bool setVolume_l(uint32_t *left, uint32_t *right, bool force = false);
+ void resetVolume_l();
void setDevice_l(audio_devices_t device);
void setMode_l(audio_mode_t mode);
void setAudioSource_l(audio_source_t source);
@@ -323,13 +324,6 @@
// At least one non offloadable effect in the chain is enabled
bool isNonOffloadableEnabled();
- // use release_cas because we don't care about the observed value, just want to make sure the
- // new value is observable.
- void forceVolume() { android_atomic_release_cas(false, true, &mForceVolume); }
- // use acquire_cas because we are interested in the observed value and
- // we are the only observers.
- bool isVolumeForced() { return (android_atomic_acquire_cas(true, false, &mForceVolume) == 0); }
-
void syncHalEffectsState();
bool hasSoftwareEffect() const;
@@ -393,5 +387,4 @@
// timeLow fields among effect type UUIDs.
// Updated by updateSuspendedSessions_l() only.
KeyedVector< int, sp<SuspendedEffectDesc> > mSuspendedEffects;
- volatile int32_t mForceVolume; // force next volume command because a new effect was enabled
};
diff --git a/services/audioflinger/LockWatch.cpp b/services/audioflinger/LockWatch.cpp
new file mode 100644
index 0000000..21eed6e
--- /dev/null
+++ b/services/audioflinger/LockWatch.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LockWatch"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include "LockWatch.h"
+
+namespace android {
+
+void LockWatch::onFirstRef()
+{
+ run("lock watch", ANDROID_PRIORITY_URGENT_AUDIO);
+}
+
+bool LockWatch::threadLoop()
+{
+ while (!exitPending()) {
+ // we neglect previous lock time effect on period
+ usleep(mPeriodMs * 1000);
+ if (mLock.timedLock(milliseconds(mTimeOutMs)) != NO_ERROR) {
+ LOG_ALWAYS_FATAL("LockWatch timeout for: %s", mTag.string());
+ }
+ mLock.unlock();
+ }
+ return false;
+}
+
+} // namespace android
+
diff --git a/services/audioflinger/LockWatch.h b/services/audioflinger/LockWatch.h
new file mode 100644
index 0000000..2d30217
--- /dev/null
+++ b/services/audioflinger/LockWatch.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef LOCK_WATCH_H
+#define LOCK_WATCH_H
+
+#include <utils/String8.h>
+#include <utils/Thread.h>
+
+namespace android {
+
+// periodically checks if a mutex can be acquired and kill process otherwise
+class LockWatch : public Thread {
+
+public:
+ static const uint32_t DEFAULT_PERIOD_MS = 10000; // 10 seconds default check period
+ static const uint32_t DEFAULT_TIMEOUT_MS = 3000; // 3 seconds default lock timeout
+
+ LockWatch(Mutex& lock, const String8& tag = String8(""),
+ uint32_t periodMs = DEFAULT_PERIOD_MS, uint32_t timeoutMs = DEFAULT_TIMEOUT_MS)
+ : Thread(false /*canCallJava*/),
+ mLock(lock), mTag(tag), mPeriodMs(periodMs), mTimeOutMs(timeoutMs) {}
+
+ virtual ~LockWatch() { }
+
+ // RefBase
+ virtual void onFirstRef();
+
+private:
+ // Thread
+ virtual bool threadLoop();
+
+ Mutex& mLock; // monitored mutex
+ String8 mTag; // tag
+ uint32_t mPeriodMs; // check period in milliseconds
+ uint32_t mTimeOutMs; // mutex lock timeout in milliseconds
+};
+
+} // namespace android
+
+#endif // LOCK_WATCH_H
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index a3dcdcf..aa2561e 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;
}
@@ -5355,7 +5359,8 @@
AudioFlinger::OffloadThread::OffloadThread(const sp<AudioFlinger>& audioFlinger,
AudioStreamOut* output, audio_io_handle_t id, uint32_t device, bool systemReady)
: DirectOutputThread(audioFlinger, output, id, device, OFFLOAD, systemReady),
- mPausedWriteLength(0), mPausedBytesRemaining(0), mKeepWakeLock(true)
+ mPausedWriteLength(0), mPausedBytesRemaining(0), mKeepWakeLock(true),
+ mOffloadUnderrunPosition(~0LL)
{
//FIXME: mStandby should be set to true by ThreadBase constructor
mStandby = true;
@@ -5565,12 +5570,30 @@
// No buffers for this track. Give it a few chances to
// fill a buffer, then remove it from active list.
if (--(track->mRetryCount) <= 0) {
- ALOGV("OffloadThread: BUFFER TIMEOUT: remove(%d) from active list",
- track->name());
- tracksToRemove->add(track);
- // indicate to client process that the track was disabled because of underrun;
- // it will then automatically call start() when data is available
- track->disable();
+ bool running = false;
+ if (mOutput->stream->get_presentation_position != nullptr) {
+ uint64_t position = 0;
+ struct timespec unused;
+ // The running check restarts the retry counter at least once.
+ int ret = mOutput->stream->get_presentation_position(
+ mOutput->stream, &position, &unused);
+ if (ret == NO_ERROR && position != mOffloadUnderrunPosition) {
+ running = true;
+ mOffloadUnderrunPosition = position;
+ }
+ ALOGVV("underrun counter, running(%d): %lld vs %lld", running,
+ (long long)position, (long long)mOffloadUnderrunPosition);
+ }
+ if (running) { // still running, give us more time.
+ track->mRetryCount = kMaxTrackRetriesOffload;
+ } else {
+ ALOGV("OffloadThread: BUFFER TIMEOUT: remove(%d) from active list",
+ track->name());
+ tracksToRemove->add(track);
+ // indicate to client process that the track was disabled because of underrun;
+ // it will then automatically call start() when data is available
+ track->disable();
+ }
} else if (last){
mixerStatus = MIXER_TRACKS_ENABLED;
}
@@ -5627,6 +5650,7 @@
mPausedBytesRemaining = 0;
// reset bytes written count to reflect that DSP buffers are empty after flush.
mBytesWritten = 0;
+ mOffloadUnderrunPosition = ~0LL;
if (mUseAsyncWrite) {
// discard any pending drain or write ack by incrementing sequence
@@ -5748,12 +5772,15 @@
mChannelMask,
frameCount,
IPCThreadState::self()->getCallingUid());
- if (outputTrack->cblk() != NULL) {
- thread->setStreamVolume(AUDIO_STREAM_PATCH, 1.0f);
- mOutputTracks.add(outputTrack);
- ALOGV("addOutputTrack() track %p, on thread %p", outputTrack.get(), thread);
- updateWaitTime_l();
+ status_t status = outputTrack != 0 ? outputTrack->initCheck() : (status_t) NO_MEMORY;
+ if (status != NO_ERROR) {
+ ALOGE("addOutputTrack() initCheck failed %d", status);
+ return;
}
+ thread->setStreamVolume(AUDIO_STREAM_PATCH, 1.0f);
+ mOutputTracks.add(outputTrack);
+ ALOGV("addOutputTrack() track %p, on thread %p", outputTrack.get(), thread);
+ updateWaitTime_l();
}
void AudioFlinger::DuplicatingThread::removeOutputTrack(MixerThread *thread)
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 2fd7eeb..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,12 +1021,16 @@
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
size_t mPausedBytesRemaining; // bytes still waiting in mixbuffer after resume
bool mKeepWakeLock; // keep wake lock while waiting for write callback
+ uint64_t mOffloadUnderrunPosition; // Current frame position for offloaded playback
+ // used and valid only during underrun. ~0 if
+ // no underrun has occurred during playback and
+ // is not reset on standby.
};
class AsyncCallbackThread : public Thread {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 51066fd..b752541 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -273,6 +273,9 @@
}
closeAllInputs();
+ // As the input device list can impact the output device selection, update
+ // getDeviceForStrategy() cache
+ updateDevicesAndOutputs();
if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) {
audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/);
@@ -1167,8 +1170,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 +1193,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/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 4510d36..d0df6d1 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -2119,6 +2119,8 @@
}
finishCameraOps();
+ // Notify flashlight that a camera device is closed.
+ mCameraService->mFlashlight->deviceClosed(String8::format("%d", mCameraId));
ALOGI("%s: Disconnected client for camera %d for PID %d", __FUNCTION__, mCameraId, mClientPid);
// client shouldn't be able to call into us anymore
@@ -2216,10 +2218,6 @@
// Transition device state to CLOSED
mCameraService->updateProxyDeviceState(ICameraServiceProxy::CAMERA_STATE_CLOSED,
String8::format("%d", mCameraId));
-
- // Notify flashlight that a camera device is closed.
- mCameraService->mFlashlight->deviceClosed(
- String8::format("%d", mCameraId));
}
// Always stop watching, even if no camera op is active
if (mOpsCallback != NULL) {
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index c0d6da6..ccd1e4d 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -104,7 +104,8 @@
return res;
}
- res = mDevice->setNotifyCallback(this);
+ wp<CameraDeviceBase::NotificationListener> weakThis(this);
+ res = mDevice->setNotifyCallback(weakThis);
return OK;
}
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index 8707f2a..984d84b 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -190,7 +190,7 @@
/**
* Abstract class for HAL notification listeners
*/
- class NotificationListener {
+ class NotificationListener : public virtual RefBase {
public:
// The set of notifications is a merge of the notifications required for
// API1 and API2.
@@ -219,7 +219,7 @@
* Connect HAL notifications to a listener. Overwrites previous
* listener. Set to NULL to stop receiving notifications.
*/
- virtual status_t setNotifyCallback(NotificationListener *listener) = 0;
+ virtual status_t setNotifyCallback(wp<NotificationListener> listener) = 0;
/**
* Whether the device supports calling notifyAutofocus, notifyAutoExposure,
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index c930ac0..48a2a99 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -42,6 +42,7 @@
#include <utils/Log.h>
#include <utils/Trace.h>
#include <utils/Timers.h>
+#include <cutils/properties.h>
#include <android/hardware/camera2/ICameraDeviceUser.h>
@@ -259,7 +260,7 @@
ATRACE_CALL();
Mutex::Autolock il(mInterfaceLock);
- ALOGV("%s: E", __FUNCTION__);
+ ALOGI("%s: E", __FUNCTION__);
status_t res = OK;
@@ -336,7 +337,7 @@
internalUpdateStatusLocked(STATUS_UNINITIALIZED);
}
- ALOGV("%s: X", __FUNCTION__);
+ ALOGI("%s: X", __FUNCTION__);
return res;
}
@@ -1482,7 +1483,7 @@
}
-status_t Camera3Device::setNotifyCallback(NotificationListener *listener) {
+status_t Camera3Device::setNotifyCallback(wp<NotificationListener> listener) {
ATRACE_CALL();
Mutex::Autolock l(mOutputLock);
@@ -1615,15 +1616,9 @@
ALOGV("%s: Camera %d: Flushing all requests", __FUNCTION__, mId);
Mutex::Autolock il(mInterfaceLock);
- NotificationListener* listener;
- {
- Mutex::Autolock l(mOutputLock);
- listener = mListener;
- }
-
{
Mutex::Autolock l(mLock);
- mRequestThread->clear(listener, /*out*/frameNumber);
+ mRequestThread->clear(/*out*/frameNumber);
}
status_t res;
@@ -1749,10 +1744,11 @@
// state changes
if (mPauseStateNotify) return;
}
- NotificationListener *listener;
+
+ sp<NotificationListener> listener;
{
Mutex::Autolock l(mOutputLock);
- listener = mListener;
+ listener = mListener.promote();
}
if (idle && listener != NULL) {
listener->notifyIdle();
@@ -2045,19 +2041,20 @@
// across configure_streams() calls
mRequestThread->configurationComplete(mIsConstrainedHighSpeedConfiguration);
- // Boost priority of request thread for high speed recording to SCHED_FIFO
- if (mIsConstrainedHighSpeedConfiguration) {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("camera.fifo.disable", value, "0");
+ int32_t disableFifo = atoi(value);
+ if (disableFifo != 1) {
+ // Boost priority of request thread to SCHED_FIFO.
pid_t requestThreadTid = mRequestThread->getTid();
res = requestPriority(getpid(), requestThreadTid,
- kConstrainedHighSpeedThreadPriority, /*asynchronous*/ false);
+ kRequestThreadPriority, /*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);
}
- } else {
- // TODO: Set/restore normal priority for normal use cases
}
// Update device state
@@ -2176,8 +2173,9 @@
internalUpdateStatusLocked(STATUS_ERROR);
// Notify upstream about a device error
- if (mListener != NULL) {
- mListener->notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE,
+ sp<NotificationListener> listener = mListener.promote();
+ if (listener != NULL) {
+ listener->notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE,
CaptureResultExtras());
}
@@ -2579,10 +2577,10 @@
void Camera3Device::notify(const camera3_notify_msg *msg) {
ATRACE_CALL();
- NotificationListener *listener;
+ sp<NotificationListener> listener;
{
Mutex::Autolock l(mOutputLock);
- listener = mListener;
+ listener = mListener.promote();
}
if (msg == NULL) {
@@ -2606,7 +2604,7 @@
}
void Camera3Device::notifyError(const camera3_error_msg_t &msg,
- NotificationListener *listener) {
+ sp<NotificationListener> listener) {
// Map camera HAL error codes to ICameraDeviceCallback error codes
// Index into this with the HAL error code
@@ -2677,7 +2675,7 @@
}
void Camera3Device::notifyShutter(const camera3_shutter_msg_t &msg,
- NotificationListener *listener) {
+ sp<NotificationListener> listener) {
ssize_t idx;
// Set timestamp for the request in the in-flight tracking
@@ -2786,7 +2784,7 @@
}
void Camera3Device::RequestThread::setNotificationListener(
- NotificationListener *listener) {
+ wp<NotificationListener> listener) {
Mutex::Autolock l(mRequestLock);
mListener = listener;
}
@@ -2921,7 +2919,6 @@
}
status_t Camera3Device::RequestThread::clear(
- NotificationListener *listener,
/*out*/int64_t *lastFrameNumber) {
Mutex::Autolock l(mRequestLock);
ALOGV("RequestThread::%s:", __FUNCTION__);
@@ -2930,6 +2927,7 @@
// Send errors for all requests pending in the request queue, including
// pending repeating requests
+ sp<NotificationListener> listener = mListener.promote();
if (listener != NULL) {
for (RequestList::iterator it = mRequestQueue.begin();
it != mRequestQueue.end(); ++it) {
@@ -3069,6 +3067,7 @@
void Camera3Device::RequestThread::checkAndStopRepeatingRequest() {
bool surfaceAbandoned = false;
int64_t lastFrameNumber = 0;
+ sp<NotificationListener> listener;
{
Mutex::Autolock l(mRequestLock);
// Check all streams needed by repeating requests are still valid. Otherwise, stop
@@ -3085,9 +3084,11 @@
break;
}
}
+ listener = mListener.promote();
}
- if (surfaceAbandoned) {
- mListener->notifyRepeatingRequestError(lastFrameNumber);
+
+ if (listener != NULL && surfaceAbandoned) {
+ listener->notifyRepeatingRequestError(lastFrameNumber);
}
}
@@ -3151,7 +3152,7 @@
mFlushLock.lock();
}
- ALOGVV("%s: %d: submitting %d requests in a batch.", __FUNCTION__, __LINE__,
+ ALOGVV("%s: %d: submitting %zu requests in a batch.", __FUNCTION__, __LINE__,
mNextRequests.size());
for (auto& nextRequest : mNextRequests) {
// Submit request and block until ready for next one
@@ -3430,8 +3431,9 @@
if (sendRequestError) {
Mutex::Autolock l(mRequestLock);
- if (mListener != NULL) {
- mListener->notifyError(
+ sp<NotificationListener> listener = mListener.promote();
+ if (listener != NULL) {
+ listener->notifyError(
hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST,
captureRequest->mResultExtras);
}
@@ -3570,8 +3572,10 @@
// error
ALOGE("%s: Can't get input buffer, skipping request:"
" %s (%d)", __FUNCTION__, strerror(-res), res);
- if (mListener != NULL) {
- mListener->notifyError(
+
+ sp<NotificationListener> listener = mListener.promote();
+ if (listener != NULL) {
+ listener->notifyError(
hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST,
nextRequest->mResultExtras);
}
@@ -3851,13 +3855,14 @@
status_t res;
Mutex::Autolock l(mLock);
+ sp<NotificationListener> listener = mListener.promote();
res = stream->startPrepare(maxCount);
if (res == OK) {
// No preparation needed, fire listener right off
ALOGV("%s: Stream %d already prepared", __FUNCTION__, stream->getId());
- if (mListener) {
- mListener->notifyPrepared(stream->getId());
+ if (listener != NULL) {
+ listener->notifyPrepared(stream->getId());
}
return OK;
} else if (res != NOT_ENOUGH_DATA) {
@@ -3872,8 +3877,8 @@
res = Thread::run("C3PrepThread", PRIORITY_BACKGROUND);
if (res != OK) {
ALOGE("%s: Unable to start preparer stream: %d (%s)", __FUNCTION__, res, strerror(-res));
- if (mListener) {
- mListener->notifyPrepared(stream->getId());
+ if (listener != NULL) {
+ listener->notifyPrepared(stream->getId());
}
return res;
}
@@ -3901,7 +3906,7 @@
return OK;
}
-void Camera3Device::PreparerThread::setNotificationListener(NotificationListener *listener) {
+void Camera3Device::PreparerThread::setNotificationListener(wp<NotificationListener> listener) {
Mutex::Autolock l(mLock);
mListener = listener;
}
@@ -3948,10 +3953,11 @@
// This stream has finished, notify listener
Mutex::Autolock l(mLock);
- if (mListener) {
+ sp<NotificationListener> listener = mListener.promote();
+ if (listener != NULL) {
ALOGV("%s: Stream %d prepare done, signaling listener", __FUNCTION__,
mCurrentStream->getId());
- mListener->notifyPrepared(mCurrentStream->getId());
+ listener->notifyPrepared(mCurrentStream->getId());
}
ATRACE_ASYNC_END("stream prepare", mCurrentStream->getId());
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index ea5a4b3..17893a9 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -132,7 +132,7 @@
// Transitions to the idle state on success
virtual status_t waitUntilDrained();
- virtual status_t setNotifyCallback(NotificationListener *listener);
+ virtual status_t setNotifyCallback(wp<NotificationListener> listener);
virtual bool willNotify3A();
virtual status_t waitForNextFrame(nsecs_t timeout);
virtual status_t getNextResult(CaptureResult *frame);
@@ -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
@@ -460,7 +460,7 @@
camera3_device_t *hal3Device,
bool aeLockAvailable);
- void setNotificationListener(NotificationListener *listener);
+ void setNotificationListener(wp<NotificationListener> listener);
/**
* Call after stream (re)-configuration is completed.
@@ -485,9 +485,7 @@
/**
* Remove all queued and repeating requests, and pending triggers
*/
- status_t clear(NotificationListener *listener,
- /*out*/
- int64_t *lastFrameNumber = NULL);
+ status_t clear(/*out*/int64_t *lastFrameNumber = NULL);
/**
* Flush all pending requests in HAL.
@@ -603,7 +601,7 @@
wp<camera3::StatusTracker> mStatusTracker;
camera3_device_t *mHal3Device;
- NotificationListener *mListener;
+ wp<NotificationListener> mListener;
const int mId; // The camera ID
int mStatusId; // The RequestThread's component ID for
@@ -760,7 +758,7 @@
PreparerThread();
~PreparerThread();
- void setNotificationListener(NotificationListener *listener);
+ void setNotificationListener(wp<NotificationListener> listener);
/**
* Queue up a stream to be prepared. Streams are processed by a background thread in FIFO
@@ -781,7 +779,7 @@
// Guarded by mLock
- NotificationListener *mListener;
+ wp<NotificationListener> mListener;
List<sp<camera3::Camera3StreamInterface> > mPendingStreams;
bool mActive;
bool mCancelNow;
@@ -810,7 +808,7 @@
uint32_t mNextReprocessShutterFrameNumber;
List<CaptureResult> mResultQueue;
Condition mResultSignal;
- NotificationListener *mListener;
+ wp<NotificationListener> mListener;
/**** End scope for mOutputLock ****/
@@ -823,9 +821,9 @@
// Specific notify handlers
void notifyError(const camera3_error_msg_t &msg,
- NotificationListener *listener);
+ sp<NotificationListener> listener);
void notifyShutter(const camera3_shutter_msg_t &msg,
- NotificationListener *listener);
+ sp<NotificationListener> listener);
// helper function to return the output buffers to the streams.
void returnOutputBuffers(const camera3_stream_buffer_t *outputBuffers,
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 299435a..7229929 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -472,6 +472,12 @@
__FUNCTION__, mTransform, strerror(-res), res);
}
+ // Set dequeueBuffer/attachBuffer timeout if the consumer is not hw composer or hw texture.
+ // We need skip these cases as timeout will disable the non-blocking (async) mode.
+ if (!(isConsumedByHWComposer() || isConsumedByHWTexture())) {
+ mConsumer->setDequeueTimeout(kDequeueBufferTimeout);
+ }
+
/**
* Camera3 Buffer manager is only supported by HAL3.3 onwards, as the older HALs requires
* buffers to be statically allocated for internal static buffer registration, while the
@@ -701,6 +707,17 @@
return (usage & GRALLOC_USAGE_HW_COMPOSER) != 0;
}
+bool Camera3OutputStream::isConsumedByHWTexture() const {
+ uint32_t usage = 0;
+ status_t res = getEndpointUsage(&usage);
+ if (res != OK) {
+ ALOGE("%s: getting end point usage failed: %s (%d).", __FUNCTION__, strerror(-res), res);
+ return false;
+ }
+
+ return (usage & GRALLOC_USAGE_HW_TEXTURE) != 0;
+}
+
}; // namespace camera3
}; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 5507cfc..d450a69 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -128,6 +128,11 @@
bool isConsumedByHWComposer() const;
/**
+ * Return if this output stream is consumed by hardware texture.
+ */
+ bool isConsumedByHWTexture() const;
+
+ /**
* Return if the consumer configuration of this stream is deferred.
*/
virtual bool isConsumerConfigurationDeferred() const;
@@ -181,6 +186,9 @@
sp<Surface> mConsumer;
private:
+
+ static const nsecs_t kDequeueBufferTimeout = 1000000000; // 1 sec
+
int mTransform;
virtual status_t setTransformLocked(int transform);