Merge "AudioPolicy: fix volume curve query for min/max index" into pi-dev
diff --git a/include/media/MmapStreamCallback.h b/include/media/MmapStreamCallback.h
index 8098e79..31b8eb5 100644
--- a/include/media/MmapStreamCallback.h
+++ b/include/media/MmapStreamCallback.h
@@ -31,8 +31,9 @@
* The mmap stream should be torn down because conditions that permitted its creation with
* the requested parameters have changed and do not allow it to operate with the requested
* constraints any more.
+ * \param[in] handle handle for the client stream to tear down.
*/
- virtual void onTearDown() = 0;
+ virtual void onTearDown(audio_port_handle_t handle) = 0;
/**
* The volume to be applied to the use case specified when opening the stream has changed
diff --git a/media/extractors/mp4/ItemTable.cpp b/media/extractors/mp4/ItemTable.cpp
index 26b8251..a1f6e9a 100644
--- a/media/extractors/mp4/ItemTable.cpp
+++ b/media/extractors/mp4/ItemTable.cpp
@@ -1591,10 +1591,9 @@
ssize_t thumbItemIndex = mItemIdToItemMap.indexOfKey(masterImage.thumbnails[0]);
if (thumbItemIndex < 0) {
- ALOGW("%s: Thumbnail item id %d not found, use master instead",
- __FUNCTION__, masterImage.thumbnails[0]);
- *itemIndex = masterItemIndex;
- return OK;
+ // Do not return the master image in this case, fail it so that the
+ // thumbnail extraction code knows we really don't have it.
+ return INVALID_OPERATION;
}
*itemIndex = thumbItemIndex;
diff --git a/media/libaaudio/src/Android.bp b/media/libaaudio/src/Android.bp
index 788833b..b9e28a0 100644
--- a/media/libaaudio/src/Android.bp
+++ b/media/libaaudio/src/Android.bp
@@ -57,6 +57,7 @@
shared_libs: [
"libaudioclient",
+ "libaudioutils",
"liblog",
"libcutils",
"libutils",
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 2a3e668..0bdfeac 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -156,7 +156,7 @@
setInputPreset(configurationOutput.getInputPreset());
// Save device format so we can do format conversion and volume scaling together.
- mDeviceFormat = configurationOutput.getFormat();
+ setDeviceFormat(configurationOutput.getFormat());
result = mServiceInterface.getStreamDescription(mServiceStreamHandle, mEndPointParcelable);
if (result != AAUDIO_OK) {
@@ -501,9 +501,9 @@
ALOGW("%s - AAUDIO_SERVICE_EVENT_DISCONNECTED - FIFO cleared", __func__);
break;
case AAUDIO_SERVICE_EVENT_VOLUME:
+ ALOGD("%s - AAUDIO_SERVICE_EVENT_VOLUME %lf", __func__, message->event.dataDouble);
mStreamVolume = (float)message->event.dataDouble;
doSetVolume();
- ALOGD("%s - AAUDIO_SERVICE_EVENT_VOLUME %lf", __func__, message->event.dataDouble);
break;
case AAUDIO_SERVICE_EVENT_XRUN:
mXRunCount = static_cast<int32_t>(message->event.dataLong);
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index 0e0724b..0425cd5 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -138,8 +138,6 @@
// Calculate timeout for an operation involving framesPerOperation.
int64_t calculateReasonableTimeout(int32_t framesPerOperation);
- aaudio_format_t getDeviceFormat() const { return mDeviceFormat; }
-
int32_t getDeviceChannelCount() const { return mDeviceChannelCount; }
/**
@@ -195,9 +193,6 @@
int64_t mServiceLatencyNanos = 0;
- // Sometimes the hardware is operating with a different format or channel count from the app.
- // Then we require conversion in AAudio.
- aaudio_format_t mDeviceFormat = AAUDIO_FORMAT_UNSPECIFIED;
int32_t mDeviceChannelCount = 0;
};
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index 0c3b1fa..795ba2c 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -117,7 +117,7 @@
// Still haven't got any timestamps from server.
// Keep waiting until we get some valid timestamps then start writing to the
// current buffer position.
- ALOGD("%s() wait for valid timestamps", __func__);
+ ALOGV("%s() wait for valid timestamps", __func__);
// Sleep very briefly and hope we get a timestamp soon.
*wakeTimePtr = currentNanoTime + (2000 * AAUDIO_NANOS_PER_MICROSECOND);
ATRACE_END();
@@ -310,6 +310,9 @@
//------------------------------------------------------------------------------
// Implementation of PlayerBase
status_t AudioStreamInternalPlay::doSetVolume() {
- mVolumeRamp.setTarget(mStreamVolume * getDuckAndMuteVolume());
+ float combinedVolume = mStreamVolume * getDuckAndMuteVolume();
+ ALOGD("%s() mStreamVolume * duckAndMuteVolume = %f * %f = %f",
+ __func__, mStreamVolume, getDuckAndMuteVolume(), combinedVolume);
+ mVolumeRamp.setTarget(combinedVolume);
return android::NO_ERROR;
}
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index 61e03db..358021b 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -367,7 +367,6 @@
return err ? AAudioConvert_androidToAAudioResult(-errno) : mThreadRegistrationResult;
}
-
aaudio_data_callback_result_t AudioStream::maybeCallDataCallback(void *audioData,
int32_t numFrames) {
aaudio_data_callback_result_t result = AAUDIO_CALLBACK_RESULT_STOP;
@@ -429,6 +428,12 @@
}
#endif
+void AudioStream::setDuckAndMuteVolume(float duckAndMuteVolume) {
+ ALOGD("%s() to %f", __func__, duckAndMuteVolume);
+ mDuckAndMuteVolume = duckAndMuteVolume;
+ doSetVolume(); // apply this change
+}
+
AudioStream::MyPlayerBase::MyPlayerBase(AudioStream *parent) : mParent(parent) {
}
@@ -450,7 +455,6 @@
}
}
-
void AudioStream::MyPlayerBase::destroy() {
unregisterWithAudioManager();
}
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index 5273e36..31b895c 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -252,6 +252,20 @@
return AAudioConvert_formatToSizeInBytes(mFormat);
}
+ /**
+ * This is only valid after setSamplesPerFrame() and setDeviceFormat() have been called.
+ */
+ int32_t getBytesPerDeviceFrame() const {
+ return mSamplesPerFrame * getBytesPerDeviceSample();
+ }
+
+ /**
+ * This is only valid after setDeviceFormat() has been called.
+ */
+ int32_t getBytesPerDeviceSample() const {
+ return AAudioConvert_formatToSizeInBytes(getDeviceFormat());
+ }
+
virtual int64_t getFramesWritten() = 0;
virtual int64_t getFramesRead() = 0;
@@ -314,10 +328,7 @@
}
// This is used by the AudioManager to duck and mute the stream when changing audio focus.
- void setDuckAndMuteVolume(float duckAndMuteVolume) {
- mDuckAndMuteVolume = duckAndMuteVolume;
- doSetVolume(); // apply this change
- }
+ void setDuckAndMuteVolume(float duckAndMuteVolume);
float getDuckAndMuteVolume() const {
return mDuckAndMuteVolume;
@@ -471,6 +482,17 @@
mFormat = format;
}
+ /**
+ * This should not be called after the open() call.
+ */
+ void setDeviceFormat(aaudio_format_t format) {
+ mDeviceFormat = format;
+ }
+
+ aaudio_format_t getDeviceFormat() const {
+ return mDeviceFormat;
+ }
+
void setState(aaudio_stream_state_t state);
void setDeviceId(int32_t deviceId) {
@@ -485,9 +507,23 @@
float mDuckAndMuteVolume = 1.0f;
-
protected:
+ /**
+ * Either convert the data from device format to app format and return a pointer
+ * to the conversion buffer,
+ * OR just pass back the original pointer.
+ *
+ * Note that this is only used for the INPUT path.
+ *
+ * @param audioData
+ * @param numFrames
+ * @return original pointer or the conversion buffer
+ */
+ virtual const void * maybeConvertDeviceData(const void *audioData, int32_t numFrames) {
+ return audioData;
+ }
+
void setPeriodNanoseconds(int64_t periodNanoseconds) {
mPeriodNanoseconds.store(periodNanoseconds, std::memory_order_release);
}
@@ -539,6 +575,10 @@
int32_t mSessionId = AAUDIO_UNSPECIFIED;
+ // Sometimes the hardware is operating with a different format from the app.
+ // Then we require conversion in AAudio.
+ aaudio_format_t mDeviceFormat = AAUDIO_FORMAT_UNSPECIFIED;
+
// callback ----------------------------------
AAudioStream_dataCallback mDataCallbackProc = nullptr; // external callback functions
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index 293a6a8..3a7a578 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -87,7 +87,7 @@
break;
default:
- ALOGE("bad direction = %d", direction);
+ ALOGE("%s() bad direction = %d", __func__, direction);
result = AAUDIO_ERROR_ILLEGAL_ARGUMENT;
}
return result;
@@ -99,7 +99,7 @@
aaudio_result_t AudioStreamBuilder::build(AudioStream** streamPtr) {
AudioStream *audioStream = nullptr;
if (streamPtr == nullptr) {
- ALOGE("build() streamPtr is null");
+ ALOGE("%s() streamPtr is null", __func__);
return AAUDIO_ERROR_NULL;
}
*streamPtr = nullptr;
@@ -124,13 +124,11 @@
if (mapExclusivePolicy == AAUDIO_UNSPECIFIED) {
mapExclusivePolicy = AAUDIO_MMAP_EXCLUSIVE_POLICY_DEFAULT;
}
- ALOGD("mmapPolicy = %d, mapExclusivePolicy = %d",
- mmapPolicy, mapExclusivePolicy);
aaudio_sharing_mode_t sharingMode = getSharingMode();
if ((sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE)
&& (mapExclusivePolicy == AAUDIO_POLICY_NEVER)) {
- ALOGW("EXCLUSIVE sharing mode not supported. Use SHARED.");
+ ALOGD("%s() EXCLUSIVE sharing mode not supported. Use SHARED.", __func__);
sharingMode = AAUDIO_SHARING_MODE_SHARED;
setSharingMode(sharingMode);
}
@@ -141,13 +139,14 @@
// TODO Support other performance settings in MMAP mode.
// Disable MMAP if low latency not requested.
if (getPerformanceMode() != AAUDIO_PERFORMANCE_MODE_LOW_LATENCY) {
- ALOGD("build() MMAP not available because AAUDIO_PERFORMANCE_MODE_LOW_LATENCY not used.");
+ ALOGD("%s() MMAP not available because AAUDIO_PERFORMANCE_MODE_LOW_LATENCY not used.",
+ __func__);
allowMMap = false;
}
// SessionID and Effects are only supported in Legacy mode.
if (getSessionId() != AAUDIO_SESSION_ID_NONE) {
- ALOGD("build() MMAP not available because sessionId used.");
+ ALOGD("%s() MMAP not available because sessionId used.", __func__);
allowMMap = false;
}
@@ -163,7 +162,7 @@
audioStream = nullptr;
if (isMMap && allowLegacy) {
- ALOGD("build() MMAP stream did not open so try Legacy path");
+ ALOGV("%s() MMAP stream did not open so try Legacy path", __func__);
// If MMAP stream failed to open then TRY using a legacy stream.
result = builder_createStream(getDirection(), sharingMode,
false, &audioStream);
diff --git a/media/libaaudio/src/fifo/FifoBuffer.cpp b/media/libaaudio/src/fifo/FifoBuffer.cpp
index e6e7c8e..9b9744e 100644
--- a/media/libaaudio/src/fifo/FifoBuffer.cpp
+++ b/media/libaaudio/src/fifo/FifoBuffer.cpp
@@ -43,7 +43,7 @@
int32_t bytesPerBuffer = bytesPerFrame * capacityInFrames;
mStorage = new uint8_t[bytesPerBuffer];
mStorageOwned = true;
- ALOGD("capacityInFrames = %d, bytesPerFrame = %d",
+ ALOGV("capacityInFrames = %d, bytesPerFrame = %d",
capacityInFrames, bytesPerFrame);
}
diff --git a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
index 8bbb9d9..a6b9f5d 100644
--- a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
@@ -19,10 +19,12 @@
#include <utils/Log.h>
#include <stdint.h>
-#include <utils/String16.h>
+
+#include <aaudio/AAudio.h>
+#include <audio_utils/primitives.h>
#include <media/AudioTrack.h>
#include <media/AudioTimestamp.h>
-#include <aaudio/AAudio.h>
+#include <utils/String16.h>
#include "core/AudioStream.h"
#include "legacy/AudioStreamLegacy.h"
@@ -48,14 +50,17 @@
return AudioStreamLegacy_callback;
}
-aaudio_data_callback_result_t AudioStreamLegacy::callDataCallbackFrames(uint8_t *buffer, int32_t numFrames) {
+aaudio_data_callback_result_t AudioStreamLegacy::callDataCallbackFrames(uint8_t *buffer,
+ int32_t numFrames) {
+ void *finalAudioData = buffer;
if (getDirection() == AAUDIO_DIRECTION_INPUT) {
// Increment before because we already got the data from the device.
incrementFramesRead(numFrames);
+ finalAudioData = (void *) maybeConvertDeviceData(buffer, numFrames);
}
// Call using the AAudio callback interface.
- aaudio_data_callback_result_t callbackResult = maybeCallDataCallback(buffer, numFrames);
+ aaudio_data_callback_result_t callbackResult = maybeCallDataCallback(finalAudioData, numFrames);
if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE
&& getDirection() == AAUDIO_DIRECTION_OUTPUT) {
@@ -67,15 +72,15 @@
// Implement FixedBlockProcessor
int32_t AudioStreamLegacy::onProcessFixedBlock(uint8_t *buffer, int32_t numBytes) {
- int32_t numFrames = numBytes / getBytesPerFrame();
+ int32_t numFrames = numBytes / getBytesPerDeviceFrame();
return (int32_t) callDataCallbackFrames(buffer, numFrames);
}
void AudioStreamLegacy::processCallbackCommon(aaudio_callback_operation_t opcode, void *info) {
aaudio_data_callback_result_t callbackResult;
- // This illegal size can be used to AudioFlinger to stop calling us.
+ // This illegal size can be used to tell AudioFlinger to stop calling us.
// This takes advantage of AudioFlinger killing the stream.
- // TODO need API change in AudioRecord and AudioTrack
+ // TODO add to API in AudioRecord and AudioTrack
const size_t SIZE_STOP_CALLBACKS = SIZE_MAX;
switch (opcode) {
@@ -100,7 +105,7 @@
// If the caller specified an exact size then use a block size adapter.
if (mBlockAdapter != nullptr) {
- int32_t byteCount = audioBuffer->frameCount * getBytesPerFrame();
+ int32_t byteCount = audioBuffer->frameCount * getBytesPerDeviceFrame();
callbackResult = mBlockAdapter->processVariableBlock(
(uint8_t *) audioBuffer->raw, byteCount);
} else {
@@ -109,7 +114,7 @@
audioBuffer->frameCount);
}
if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) {
- audioBuffer->size = audioBuffer->frameCount * getBytesPerFrame();
+ audioBuffer->size = audioBuffer->frameCount * getBytesPerDeviceFrame();
} else { // STOP or invalid result
ALOGW("%s() callback requested stop, fake an error", __func__);
audioBuffer->size = SIZE_STOP_CALLBACKS;
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index 28158e2..1981ba3 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -19,13 +19,15 @@
#include <utils/Log.h>
#include <stdint.h>
-#include <utils/String16.h>
-#include <media/AudioRecord.h>
-#include <aaudio/AAudio.h>
-#include "AudioClock.h"
+#include <aaudio/AAudio.h>
+#include <audio_utils/primitives.h>
+#include <media/AudioRecord.h>
+#include <utils/String16.h>
+
#include "legacy/AudioStreamLegacy.h"
#include "legacy/AudioStreamRecord.h"
+#include "utility/AudioClock.h"
#include "utility/FixedBlockWriter.h"
using namespace android;
@@ -63,10 +65,6 @@
size_t frameCount = (builder.getBufferCapacity() == AAUDIO_UNSPECIFIED) ? 0
: builder.getBufferCapacity();
- // TODO implement an unspecified Android format then use that.
- audio_format_t format = (getFormat() == AAUDIO_FORMAT_UNSPECIFIED)
- ? AUDIO_FORMAT_PCM_FLOAT
- : AAudioConvert_aaudioToAndroidDataFormat(getFormat());
audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE;
aaudio_performance_mode_t perfMode = getPerformanceMode();
@@ -82,6 +80,35 @@
break;
}
+ // Preserve behavior of API 26
+ if (getFormat() == AAUDIO_FORMAT_UNSPECIFIED) {
+ setFormat(AAUDIO_FORMAT_PCM_FLOAT);
+ }
+
+ // Maybe change device format to get a FAST path.
+ // AudioRecord does not support FAST mode for FLOAT data.
+ // TODO AudioRecord should allow FLOAT data paths for FAST tracks.
+ // So IF the user asks for low latency FLOAT
+ // AND the sampleRate is likely to be compatible with FAST
+ // THEN request I16 and convert to FLOAT when passing to user.
+ // Note that hard coding 48000 Hz is not ideal because the sampleRate
+ // for a FAST path might not be 48000 Hz.
+ // It normally is but there is a chance that it is not.
+ // And there is no reliable way to know that in advance.
+ // Luckily the consequences of a wrong guess are minor.
+ // We just may not get a FAST track.
+ // But we wouldn't have anyway without this hack.
+ constexpr int32_t kMostLikelySampleRateForFast = 48000;
+ if (getFormat() == AAUDIO_FORMAT_PCM_FLOAT
+ && perfMode == AAUDIO_PERFORMANCE_MODE_LOW_LATENCY
+ && (samplesPerFrame <= 2) // FAST only for mono and stereo
+ && (getSampleRate() == kMostLikelySampleRateForFast
+ || getSampleRate() == AAUDIO_UNSPECIFIED)) {
+ setDeviceFormat(AAUDIO_FORMAT_PCM_I16);
+ } else {
+ setDeviceFormat(getFormat());
+ }
+
uint32_t notificationFrames = 0;
// Setup the callback if there is one.
@@ -96,9 +123,6 @@
}
mCallbackBufferSize = builder.getFramesPerDataCallback();
- ALOGD("open(), request notificationFrames = %u, frameCount = %u",
- notificationFrames, (uint)frameCount);
-
// Don't call mAudioRecord->setInputDevice() because it will be overwritten by set()!
audio_port_handle_t selectedDeviceId = (getDeviceId() == AAUDIO_UNSPECIFIED)
? AUDIO_PORT_HANDLE_NONE
@@ -120,39 +144,59 @@
aaudio_session_id_t requestedSessionId = builder.getSessionId();
audio_session_t sessionId = AAudioConvert_aaudioToAndroidSessionId(requestedSessionId);
- mAudioRecord = new AudioRecord(
- mOpPackageName // const String16& opPackageName TODO does not compile
- );
- mAudioRecord->set(
- AUDIO_SOURCE_DEFAULT, // ignored because we pass attributes below
- getSampleRate(),
- format,
- channelMask,
- frameCount,
- callback,
- callbackData,
- notificationFrames,
- false /*threadCanCallJava*/,
- sessionId,
- streamTransferType,
- flags,
- AUDIO_UID_INVALID, // DEFAULT uid
- -1, // DEFAULT pid
- &attributes,
- selectedDeviceId
- );
+ // ----------- open the AudioRecord ---------------------
+ // Might retry, but never more than once.
+ for (int i = 0; i < 2; i ++) {
+ audio_format_t requestedInternalFormat =
+ AAudioConvert_aaudioToAndroidDataFormat(getDeviceFormat());
- // Did we get a valid track?
- status_t status = mAudioRecord->initCheck();
- if (status != OK) {
- close();
- ALOGE("open(), initCheck() returned %d", status);
- return AAudioConvert_androidToAAudioResult(status);
+ mAudioRecord = new AudioRecord(
+ mOpPackageName // const String16& opPackageName TODO does not compile
+ );
+ mAudioRecord->set(
+ AUDIO_SOURCE_DEFAULT, // ignored because we pass attributes below
+ getSampleRate(),
+ requestedInternalFormat,
+ channelMask,
+ frameCount,
+ callback,
+ callbackData,
+ notificationFrames,
+ false /*threadCanCallJava*/,
+ sessionId,
+ streamTransferType,
+ flags,
+ AUDIO_UID_INVALID, // DEFAULT uid
+ -1, // DEFAULT pid
+ &attributes,
+ selectedDeviceId
+ );
+
+ // Did we get a valid track?
+ status_t status = mAudioRecord->initCheck();
+ if (status != OK) {
+ close();
+ ALOGE("open(), initCheck() returned %d", status);
+ return AAudioConvert_androidToAAudioResult(status);
+ }
+
+ // Check to see if it was worth hacking the deviceFormat.
+ bool gotFastPath = (mAudioRecord->getFlags() & AUDIO_INPUT_FLAG_FAST)
+ == AUDIO_INPUT_FLAG_FAST;
+ if (getFormat() != getDeviceFormat() && !gotFastPath) {
+ // We tried to get a FAST path by switching the device format.
+ // But it didn't work. So we might as well reopen using the same
+ // format for device and for app.
+ ALOGD("%s() used a different device format but no FAST path, reopen", __func__);
+ mAudioRecord.clear();
+ setDeviceFormat(getFormat());
+ } else {
+ break; // Keep the one we just opened.
+ }
}
// Get the actual values from the AudioRecord.
setSamplesPerFrame(mAudioRecord->channelCount());
- setFormat(AAudioConvert_androidToAAudioDataFormat(mAudioRecord->format()));
int32_t actualSampleRate = mAudioRecord->getSampleRate();
ALOGW_IF(actualSampleRate != getSampleRate(),
@@ -169,6 +213,29 @@
mBlockAdapter = nullptr;
}
+ // Allocate format conversion buffer if needed.
+ if (getDeviceFormat() == AAUDIO_FORMAT_PCM_I16
+ && getFormat() == AAUDIO_FORMAT_PCM_FLOAT) {
+
+ if (builder.getDataCallbackProc() != nullptr) {
+ // If we have a callback then we need to convert the data into an internal float
+ // array and then pass that entire array to the app.
+ mFormatConversionBufferSizeInFrames =
+ (mCallbackBufferSize != AAUDIO_UNSPECIFIED)
+ ? mCallbackBufferSize : getFramesPerBurst();
+ int32_t numSamples = mFormatConversionBufferSizeInFrames * getSamplesPerFrame();
+ mFormatConversionBufferFloat = std::make_unique<float[]>(numSamples);
+ } else {
+ // If we don't have a callback then we will read into an internal short array
+ // and then convert into the app float array in read().
+ mFormatConversionBufferSizeInFrames = getFramesPerBurst();
+ int32_t numSamples = mFormatConversionBufferSizeInFrames * getSamplesPerFrame();
+ mFormatConversionBufferI16 = std::make_unique<int16_t[]>(numSamples);
+ }
+ ALOGD("%s() setup I16>FLOAT conversion buffer with %d frames",
+ __func__, mFormatConversionBufferSizeInFrames);
+ }
+
// Update performance mode based on the actual stream.
// For example, if the sample rate does not match native then you won't get a FAST track.
audio_input_flags_t actualFlags = mAudioRecord->getFlags();
@@ -216,6 +283,24 @@
return AudioStream::close();
}
+const void * AudioStreamRecord::maybeConvertDeviceData(const void *audioData, int32_t numFrames) {
+ if (mFormatConversionBufferFloat.get() != nullptr) {
+ LOG_ALWAYS_FATAL_IF(numFrames > mFormatConversionBufferSizeInFrames,
+ "%s() conversion size %d too large for buffer %d",
+ __func__, numFrames, mFormatConversionBufferSizeInFrames);
+
+ int32_t numSamples = numFrames * getSamplesPerFrame();
+ // Only conversion supported is I16 to FLOAT
+ memcpy_to_float_from_i16(
+ mFormatConversionBufferFloat.get(),
+ (const int16_t *) audioData,
+ numSamples);
+ return mFormatConversionBufferFloat.get();
+ } else {
+ return audioData;
+ }
+}
+
void AudioStreamRecord::processCallback(int event, void *info) {
switch (event) {
case AudioRecord::EVENT_MORE_DATA:
@@ -302,9 +387,10 @@
int32_t numFrames,
int64_t timeoutNanoseconds)
{
- int32_t bytesPerFrame = getBytesPerFrame();
+ int32_t bytesPerDeviceFrame = getBytesPerDeviceFrame();
int32_t numBytes;
- aaudio_result_t result = AAudioConvert_framesToBytes(numFrames, bytesPerFrame, &numBytes);
+ // This will detect out of range values for numFrames.
+ aaudio_result_t result = AAudioConvert_framesToBytes(numFrames, bytesPerDeviceFrame, &numBytes);
if (result != AAUDIO_OK) {
return result;
}
@@ -315,19 +401,49 @@
// TODO add timeout to AudioRecord
bool blocking = (timeoutNanoseconds > 0);
- ssize_t bytesRead = mAudioRecord->read(buffer, numBytes, blocking);
- if (bytesRead == WOULD_BLOCK) {
+
+ ssize_t bytesActuallyRead = 0;
+ ssize_t totalBytesRead = 0;
+ if (mFormatConversionBufferI16.get() != nullptr) {
+ // Convert I16 data to float using an intermediate buffer.
+ float *floatBuffer = (float *) buffer;
+ int32_t framesLeft = numFrames;
+ // Perform conversion using multiple read()s if necessary.
+ while (framesLeft > 0) {
+ // Read into short internal buffer.
+ int32_t framesToRead = std::min(framesLeft, mFormatConversionBufferSizeInFrames);
+ size_t bytesToRead = framesToRead * bytesPerDeviceFrame;
+ bytesActuallyRead = mAudioRecord->read(mFormatConversionBufferI16.get(), bytesToRead, blocking);
+ if (bytesActuallyRead <= 0) {
+ break;
+ }
+ totalBytesRead += bytesActuallyRead;
+ int32_t framesToConvert = bytesActuallyRead / bytesPerDeviceFrame;
+ // Convert into app float buffer.
+ size_t numSamples = framesToConvert * getSamplesPerFrame();
+ memcpy_to_float_from_i16(
+ floatBuffer,
+ mFormatConversionBufferI16.get(),
+ numSamples);
+ floatBuffer += numSamples;
+ framesLeft -= framesToConvert;
+ }
+ } else {
+ bytesActuallyRead = mAudioRecord->read(buffer, numBytes, blocking);
+ totalBytesRead = bytesActuallyRead;
+ }
+ if (bytesActuallyRead == WOULD_BLOCK) {
return 0;
- } else if (bytesRead < 0) {
- // in this context, a DEAD_OBJECT is more likely to be a disconnect notification due to
- // AudioRecord invalidation
- if (bytesRead == DEAD_OBJECT) {
+ } else if (bytesActuallyRead < 0) {
+ // In this context, a DEAD_OBJECT is more likely to be a disconnect notification due to
+ // AudioRecord invalidation.
+ if (bytesActuallyRead == DEAD_OBJECT) {
setState(AAUDIO_STREAM_STATE_DISCONNECTED);
return AAUDIO_ERROR_DISCONNECTED;
}
- return AAudioConvert_androidToAAudioResult(bytesRead);
+ return AAudioConvert_androidToAAudioResult(bytesActuallyRead);
}
- int32_t framesRead = (int32_t)(bytesRead / bytesPerFrame);
+ int32_t framesRead = (int32_t)(totalBytesRead / bytesPerDeviceFrame);
incrementFramesRead(framesRead);
result = updateStateMachine();
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.h b/media/libaaudio/src/legacy/AudioStreamRecord.h
index c1723ba..2f41d34 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.h
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.h
@@ -76,6 +76,8 @@
return incrementFramesRead(frames);
}
+ const void * maybeConvertDeviceData(const void *audioData, int32_t numFrames) override;
+
private:
android::sp<android::AudioRecord> mAudioRecord;
// adapts between variable sized blocks and fixed size blocks
@@ -83,6 +85,11 @@
// TODO add 64-bit position reporting to AudioRecord and use it.
android::String16 mOpPackageName;
+
+ // Only one type of conversion buffer is used.
+ std::unique_ptr<float[]> mFormatConversionBufferFloat;
+ std::unique_ptr<int16_t[]> mFormatConversionBufferI16;
+ int32_t mFormatConversionBufferSizeInFrames = 0;
};
} /* namespace aaudio */
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 023e8af..9653601 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -181,6 +181,7 @@
aaudio_format_t aaudioFormat =
AAudioConvert_androidToAAudioDataFormat(mAudioTrack->format());
setFormat(aaudioFormat);
+ setDeviceFormat(aaudioFormat);
int32_t actualSampleRate = mAudioTrack->getSampleRate();
ALOGW_IF(actualSampleRate != getSampleRate(),
diff --git a/media/libaudiohal/2.0/DevicesFactoryHalHybrid.cpp b/media/libaudiohal/2.0/DevicesFactoryHalHybrid.cpp
index 77df6b5..1c4be74 100644
--- a/media/libaudiohal/2.0/DevicesFactoryHalHybrid.cpp
+++ b/media/libaudiohal/2.0/DevicesFactoryHalHybrid.cpp
@@ -32,7 +32,8 @@
}
status_t DevicesFactoryHalHybrid::openDevice(const char *name, sp<DeviceHalInterface> *device) {
- if (mHidlFactory != 0 && strcmp(AUDIO_HARDWARE_MODULE_ID_A2DP, name) != 0) {
+ if (mHidlFactory != 0 && strcmp(AUDIO_HARDWARE_MODULE_ID_A2DP, name) != 0 &&
+ strcmp(AUDIO_HARDWARE_MODULE_ID_HEARING_AID, name) != 0) {
return mHidlFactory->openDevice(name, device);
}
return mLocalFactory->openDevice(name, device);
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index f725c97..214117b 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -166,15 +166,16 @@
return interface_cast<IMemory>(reply.readStrongBinder());
}
- sp<IMemory> getImageAtIndex(int index, int colorFormat, bool metaOnly)
+ sp<IMemory> getImageAtIndex(int index, int colorFormat, bool metaOnly, bool thumbnail)
{
- ALOGV("getImageAtIndex: index %d, colorFormat(%d) metaOnly(%d)",
- index, colorFormat, metaOnly);
+ ALOGV("getImageAtIndex: index %d, colorFormat(%d) metaOnly(%d) thumbnail(%d)",
+ index, colorFormat, metaOnly, thumbnail);
Parcel data, reply;
data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
data.writeInt32(index);
data.writeInt32(colorFormat);
data.writeInt32(metaOnly);
+ data.writeInt32(thumbnail);
#ifndef DISABLE_GROUP_SCHEDULE_HACK
sendSchedPolicy(data);
#endif
@@ -356,12 +357,13 @@
int index = data.readInt32();
int colorFormat = data.readInt32();
bool metaOnly = (data.readInt32() != 0);
- ALOGV("getImageAtIndex: index(%d), colorFormat(%d), metaOnly(%d)",
- index, colorFormat, metaOnly);
+ bool thumbnail = (data.readInt32() != 0);
+ ALOGV("getImageAtIndex: index(%d), colorFormat(%d), metaOnly(%d), thumbnail(%d)",
+ index, colorFormat, metaOnly, thumbnail);
#ifndef DISABLE_GROUP_SCHEDULE_HACK
setSchedPolicy(data);
#endif
- sp<IMemory> bitmap = getImageAtIndex(index, colorFormat, metaOnly);
+ sp<IMemory> bitmap = getImageAtIndex(index, colorFormat, metaOnly, thumbnail);
if (bitmap != 0) { // Don't send NULL across the binder interface
reply->writeInt32(NO_ERROR);
reply->writeStrongBinder(IInterface::asBinder(bitmap));
diff --git a/media/libmedia/include/media/IMediaMetadataRetriever.h b/media/libmedia/include/media/IMediaMetadataRetriever.h
index 5491535..1a04552 100644
--- a/media/libmedia/include/media/IMediaMetadataRetriever.h
+++ b/media/libmedia/include/media/IMediaMetadataRetriever.h
@@ -45,7 +45,7 @@
virtual sp<IMemory> getFrameAtTime(
int64_t timeUs, int option, int colorFormat, bool metaOnly) = 0;
virtual sp<IMemory> getImageAtIndex(
- int index, int colorFormat, bool metaOnly) = 0;
+ int index, int colorFormat, bool metaOnly, bool thumbnail) = 0;
virtual status_t getFrameAtIndex(
std::vector<sp<IMemory> > *frames,
int frameIndex, int numFrames, int colorFormat, bool metaOnly) = 0;
diff --git a/media/libmedia/include/media/MediaMetadataRetrieverInterface.h b/media/libmedia/include/media/MediaMetadataRetrieverInterface.h
index 116b548..c45a964 100644
--- a/media/libmedia/include/media/MediaMetadataRetrieverInterface.h
+++ b/media/libmedia/include/media/MediaMetadataRetrieverInterface.h
@@ -46,7 +46,7 @@
virtual VideoFrame* getFrameAtTime(
int64_t timeUs, int option, int colorFormat, bool metaOnly) = 0;
virtual VideoFrame* getImageAtIndex(
- int index, int colorFormat, bool metaOnly) = 0;
+ int index, int colorFormat, bool metaOnly, bool thumbnail) = 0;
virtual status_t getFrameAtIndex(
std::vector<VideoFrame*>* frames,
int frameIndex, int numFrames, int colorFormat, bool metaOnly) = 0;
@@ -65,7 +65,7 @@
int64_t /*timeUs*/, int /*option*/, int /*colorFormat*/, bool /*metaOnly*/)
{ return NULL; }
virtual VideoFrame* getImageAtIndex(
- int /*index*/, int /*colorFormat*/, bool /*metaOnly*/)
+ int /*index*/, int /*colorFormat*/, bool /*metaOnly*/, bool /*thumbnail*/)
{ return NULL; }
virtual status_t getFrameAtIndex(
std::vector<VideoFrame*>* /*frames*/,
diff --git a/media/libmedia/include/media/mediametadataretriever.h b/media/libmedia/include/media/mediametadataretriever.h
index b41da80..4cdeeb7 100644
--- a/media/libmedia/include/media/mediametadataretriever.h
+++ b/media/libmedia/include/media/mediametadataretriever.h
@@ -90,7 +90,7 @@
sp<IMemory> getFrameAtTime(int64_t timeUs, int option,
int colorFormat = HAL_PIXEL_FORMAT_RGB_565, bool metaOnly = false);
sp<IMemory> getImageAtIndex(int index,
- int colorFormat = HAL_PIXEL_FORMAT_RGB_565, bool metaOnly = false);
+ int colorFormat = HAL_PIXEL_FORMAT_RGB_565, bool metaOnly = false, bool thumbnail = false);
status_t getFrameAtIndex(
std::vector<sp<IMemory> > *frames, int frameIndex, int numFrames = 1,
int colorFormat = HAL_PIXEL_FORMAT_RGB_565, bool metaOnly = false);
diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp
index 6a4204b..c10a907 100644
--- a/media/libmedia/mediametadataretriever.cpp
+++ b/media/libmedia/mediametadataretriever.cpp
@@ -155,15 +155,15 @@
}
sp<IMemory> MediaMetadataRetriever::getImageAtIndex(
- int index, int colorFormat, bool metaOnly) {
- ALOGV("getImageAtIndex: index(%d) colorFormat(%d) metaOnly(%d)",
- index, colorFormat, metaOnly);
+ int index, int colorFormat, bool metaOnly, bool thumbnail) {
+ ALOGV("getImageAtIndex: index(%d) colorFormat(%d) metaOnly(%d) thumbnail(%d)",
+ index, colorFormat, metaOnly, thumbnail);
Mutex::Autolock _l(mLock);
if (mRetriever == 0) {
ALOGE("retriever is not initialized");
return NULL;
}
- return mRetriever->getImageAtIndex(index, colorFormat, metaOnly);
+ return mRetriever->getImageAtIndex(index, colorFormat, metaOnly, thumbnail);
}
status_t MediaMetadataRetriever::getFrameAtIndex(
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index 16ed530..3b3ac29 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -234,9 +234,9 @@
}
sp<IMemory> MetadataRetrieverClient::getImageAtIndex(
- int index, int colorFormat, bool metaOnly) {
- ALOGV("getFrameAtTime: index(%d) colorFormat(%d), metaOnly(%d)",
- index, colorFormat, metaOnly);
+ int index, int colorFormat, bool metaOnly, bool thumbnail) {
+ ALOGV("getFrameAtTime: index(%d) colorFormat(%d), metaOnly(%d) thumbnail(%d)",
+ index, colorFormat, metaOnly, thumbnail);
Mutex::Autolock lock(mLock);
Mutex::Autolock glock(sLock);
mThumbnail.clear();
@@ -244,7 +244,7 @@
ALOGE("retriever is not initialized");
return NULL;
}
- VideoFrame *frame = mRetriever->getImageAtIndex(index, colorFormat, metaOnly);
+ VideoFrame *frame = mRetriever->getImageAtIndex(index, colorFormat, metaOnly, thumbnail);
if (frame == NULL) {
ALOGE("failed to extract image");
return NULL;
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.h b/media/libmediaplayerservice/MetadataRetrieverClient.h
index f71891a..e774c8f 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.h
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.h
@@ -53,7 +53,7 @@
virtual sp<IMemory> getFrameAtTime(
int64_t timeUs, int option, int colorFormat, bool metaOnly);
virtual sp<IMemory> getImageAtIndex(
- int index, int colorFormat, bool metaOnly);
+ int index, int colorFormat, bool metaOnly, bool thumbnail);
virtual status_t getFrameAtIndex(
std::vector<sp<IMemory> > *frames,
int frameIndex, int numFrames, int colorFormat, bool metaOnly);
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index 3d0aad1..a00d13a 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -42,30 +42,30 @@
static const int64_t kBufferTimeOutUs = 30000ll; // 30 msec
static const size_t kRetryCount = 20; // must be >0
-VideoFrame *FrameDecoder::allocVideoFrame(
- int32_t width, int32_t height, bool metaOnly) {
+//static
+VideoFrame *allocVideoFrame(const sp<MetaData> &trackMeta,
+ int32_t width, int32_t height, int32_t dstBpp, bool metaOnly = false) {
int32_t rotationAngle;
- if (!mTrackMeta->findInt32(kKeyRotation, &rotationAngle)) {
+ if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
rotationAngle = 0; // By default, no rotation
}
-
uint32_t type;
const void *iccData;
size_t iccSize;
- if (!mTrackMeta->findData(kKeyIccProfile, &type, &iccData, &iccSize)){
+ if (!trackMeta->findData(kKeyIccProfile, &type, &iccData, &iccSize)){
iccData = NULL;
iccSize = 0;
}
int32_t sarWidth, sarHeight;
int32_t displayWidth, displayHeight;
- if (mTrackMeta->findInt32(kKeySARWidth, &sarWidth)
- && mTrackMeta->findInt32(kKeySARHeight, &sarHeight)
+ if (trackMeta->findInt32(kKeySARWidth, &sarWidth)
+ && trackMeta->findInt32(kKeySARHeight, &sarHeight)
&& sarHeight != 0) {
displayWidth = (width * sarWidth) / sarHeight;
displayHeight = height;
- } else if (mTrackMeta->findInt32(kKeyDisplayWidth, &displayWidth)
- && mTrackMeta->findInt32(kKeyDisplayHeight, &displayHeight)
+ } else if (trackMeta->findInt32(kKeyDisplayWidth, &displayWidth)
+ && trackMeta->findInt32(kKeyDisplayHeight, &displayHeight)
&& displayWidth > 0 && displayHeight > 0
&& width > 0 && height > 0) {
ALOGV("found display size %dx%d", displayWidth, displayHeight);
@@ -75,27 +75,66 @@
}
return new VideoFrame(width, height, displayWidth, displayHeight,
- rotationAngle, mDstBpp, !metaOnly, iccData, iccSize);
+ rotationAngle, dstBpp, !metaOnly, iccData, iccSize);
}
-bool FrameDecoder::setDstColorFormat(android_pixel_format_t colorFormat) {
+//static
+bool findThumbnailInfo(
+ const sp<MetaData> &trackMeta, int32_t *width, int32_t *height,
+ uint32_t *type = NULL, const void **data = NULL, size_t *size = NULL) {
+ uint32_t dummyType;
+ const void *dummyData;
+ size_t dummySize;
+ return trackMeta->findInt32(kKeyThumbnailWidth, width)
+ && trackMeta->findInt32(kKeyThumbnailHeight, height)
+ && trackMeta->findData(kKeyThumbnailHVCC,
+ type ?: &dummyType, data ?: &dummyData, size ?: &dummySize);
+}
+
+//static
+VideoFrame* FrameDecoder::getMetadataOnly(
+ const sp<MetaData> &trackMeta, int colorFormat, bool thumbnail) {
+ OMX_COLOR_FORMATTYPE dstFormat;
+ int32_t dstBpp;
+ if (!getDstColorFormat(
+ (android_pixel_format_t)colorFormat, &dstFormat, &dstBpp)) {
+ return NULL;
+ }
+
+ int32_t width, height;
+ if (thumbnail) {
+ if (!findThumbnailInfo(trackMeta, &width, &height)) {
+ return NULL;
+ }
+ } else {
+ CHECK(trackMeta->findInt32(kKeyWidth, &width));
+ CHECK(trackMeta->findInt32(kKeyHeight, &height));
+ }
+ return allocVideoFrame(trackMeta, width, height, dstBpp, true /*metaOnly*/);
+}
+
+//static
+bool FrameDecoder::getDstColorFormat(
+ android_pixel_format_t colorFormat,
+ OMX_COLOR_FORMATTYPE *dstFormat,
+ int32_t *dstBpp) {
switch (colorFormat) {
case HAL_PIXEL_FORMAT_RGB_565:
{
- mDstFormat = OMX_COLOR_Format16bitRGB565;
- mDstBpp = 2;
+ *dstFormat = OMX_COLOR_Format16bitRGB565;
+ *dstBpp = 2;
return true;
}
case HAL_PIXEL_FORMAT_RGBA_8888:
{
- mDstFormat = OMX_COLOR_Format32BitRGBA8888;
- mDstBpp = 4;
+ *dstFormat = OMX_COLOR_Format32BitRGBA8888;
+ *dstBpp = 4;
return true;
}
case HAL_PIXEL_FORMAT_BGRA_8888:
{
- mDstFormat = OMX_COLOR_Format32bitBGRA8888;
- mDstBpp = 4;
+ *dstFormat = OMX_COLOR_Format32bitBGRA8888;
+ *dstBpp = 4;
return true;
}
default:
@@ -108,18 +147,12 @@
}
VideoFrame* FrameDecoder::extractFrame(
- int64_t frameTimeUs, int option, int colorFormat, bool metaOnly) {
- if (!setDstColorFormat((android_pixel_format_t)colorFormat)) {
+ int64_t frameTimeUs, int option, int colorFormat) {
+ if (!getDstColorFormat(
+ (android_pixel_format_t)colorFormat, &mDstFormat, &mDstBpp)) {
return NULL;
}
- if (metaOnly) {
- int32_t width, height;
- CHECK(trackMeta()->findInt32(kKeyWidth, &width));
- CHECK(trackMeta()->findInt32(kKeyHeight, &height));
- return allocVideoFrame(width, height, true);
- }
-
status_t err = extractInternal(frameTimeUs, 1, option);
if (err != OK) {
return NULL;
@@ -131,7 +164,8 @@
status_t FrameDecoder::extractFrames(
int64_t frameTimeUs, size_t numFrames, int option, int colorFormat,
std::vector<VideoFrame*>* frames) {
- if (!setDstColorFormat((android_pixel_format_t)colorFormat)) {
+ if (!getDstColorFormat(
+ (android_pixel_format_t)colorFormat, &mDstFormat, &mDstBpp)) {
return ERROR_UNSUPPORTED;
}
@@ -435,9 +469,10 @@
}
VideoFrame *frame = allocVideoFrame(
+ trackMeta(),
(crop_right - crop_left + 1),
(crop_bottom - crop_top + 1),
- false /*metaOnly*/);
+ dstBpp());
addFrame(frame);
int32_t srcFormat;
@@ -466,28 +501,28 @@
int64_t frameTimeUs, size_t /*numFrames*/,
int /*seekMode*/, MediaSource::ReadOptions *options) {
sp<MetaData> overrideMeta;
+ mThumbnail = false;
if (frameTimeUs < 0) {
uint32_t type;
const void *data;
size_t size;
- int64_t thumbNailTime = 0;
- int32_t thumbnailWidth, thumbnailHeight;
+ int32_t thumbWidth, thumbHeight;
// if we have a stand-alone thumbnail, set up the override meta,
// and set seekTo time to -1.
- if (trackMeta()->findInt32(kKeyThumbnailWidth, &thumbnailWidth)
- && trackMeta()->findInt32(kKeyThumbnailHeight, &thumbnailHeight)
- && trackMeta()->findData(kKeyThumbnailHVCC, &type, &data, &size)){
- overrideMeta = new MetaData(*(trackMeta()));
- overrideMeta->remove(kKeyDisplayWidth);
- overrideMeta->remove(kKeyDisplayHeight);
- overrideMeta->setInt32(kKeyWidth, thumbnailWidth);
- overrideMeta->setInt32(kKeyHeight, thumbnailHeight);
- overrideMeta->setData(kKeyHVCC, type, data, size);
- thumbNailTime = -1ll;
- ALOGV("thumbnail: %dx%d", thumbnailWidth, thumbnailHeight);
+ if (!findThumbnailInfo(trackMeta(),
+ &thumbWidth, &thumbHeight, &type, &data, &size)) {
+ ALOGE("Thumbnail not available");
+ return NULL;
}
- options->setSeekTo(thumbNailTime);
+ overrideMeta = new MetaData(*(trackMeta()));
+ overrideMeta->remove(kKeyDisplayWidth);
+ overrideMeta->remove(kKeyDisplayHeight);
+ overrideMeta->setInt32(kKeyWidth, thumbWidth);
+ overrideMeta->setInt32(kKeyHeight, thumbHeight);
+ overrideMeta->setData(kKeyHVCC, type, data, size);
+ options->setSeekTo(-1);
+ mThumbnail = true;
} else {
options->setSeekTo(frameTimeUs);
}
@@ -552,11 +587,16 @@
CHECK(outputFormat->findInt32("height", &height));
int32_t imageWidth, imageHeight;
- CHECK(trackMeta()->findInt32(kKeyWidth, &imageWidth));
- CHECK(trackMeta()->findInt32(kKeyHeight, &imageHeight));
+ if (mThumbnail) {
+ CHECK(trackMeta()->findInt32(kKeyThumbnailWidth, &imageWidth));
+ CHECK(trackMeta()->findInt32(kKeyThumbnailHeight, &imageHeight));
+ } else {
+ CHECK(trackMeta()->findInt32(kKeyWidth, &imageWidth));
+ CHECK(trackMeta()->findInt32(kKeyHeight, &imageHeight));
+ }
if (mFrame == NULL) {
- mFrame = allocVideoFrame(imageWidth, imageHeight, false /*metaOnly*/);
+ mFrame = allocVideoFrame(trackMeta(), imageWidth, imageHeight, dstBpp());
addFrame(mFrame);
}
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 5ae5644..6ad6004 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -125,10 +125,10 @@
}
VideoFrame* StagefrightMetadataRetriever::getImageAtIndex(
- int index, int colorFormat, bool metaOnly) {
+ int index, int colorFormat, bool metaOnly, bool thumbnail) {
- ALOGV("getImageAtIndex: index: %d colorFormat: %d, metaOnly: %d",
- index, colorFormat, metaOnly);
+ ALOGV("getImageAtIndex: index(%d) colorFormat(%d) metaOnly(%d) thumbnail(%d)",
+ index, colorFormat, metaOnly, thumbnail);
if (mExtractor.get() == NULL) {
ALOGE("no extractor.");
@@ -163,6 +163,10 @@
sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i);
+ if (metaOnly) {
+ return FrameDecoder::getMetadataOnly(trackMeta, colorFormat, thumbnail);
+ }
+
sp<IMediaSource> source = mExtractor->getTrack(i);
if (source.get() == NULL) {
@@ -190,7 +194,7 @@
const AString &componentName = matchingCodecs[i];
ImageDecoder decoder(componentName, trackMeta, source);
VideoFrame* frame = decoder.extractFrame(
- 0 /*frameTimeUs*/, 0 /*seekMode*/, colorFormat, metaOnly);
+ thumbnail ? -1 : 0 /*frameTimeUs*/, 0 /*seekMode*/, colorFormat);
if (frame != NULL) {
return frame;
@@ -265,6 +269,16 @@
sp<MetaData> trackMeta = mExtractor->getTrackMetaData(
i, MediaExtractor::kIncludeExtensiveMetaData);
+ if (metaOnly) {
+ if (outFrame != NULL) {
+ *outFrame = FrameDecoder::getMetadataOnly(trackMeta, colorFormat);
+ if (*outFrame != NULL) {
+ return OK;
+ }
+ }
+ return UNKNOWN_ERROR;
+ }
+
sp<IMediaSource> source = mExtractor->getTrack(i);
if (source.get() == NULL) {
@@ -294,8 +308,7 @@
const AString &componentName = matchingCodecs[i];
VideoFrameDecoder decoder(componentName, trackMeta, source);
if (outFrame != NULL) {
- *outFrame = decoder.extractFrame(
- timeUs, option, colorFormat, metaOnly);
+ *outFrame = decoder.extractFrame(timeUs, option, colorFormat);
if (*outFrame != NULL) {
return OK;
}
diff --git a/media/libstagefright/include/FrameDecoder.h b/media/libstagefright/include/FrameDecoder.h
index dfbe2cd..b67e928 100644
--- a/media/libstagefright/include/FrameDecoder.h
+++ b/media/libstagefright/include/FrameDecoder.h
@@ -44,11 +44,7 @@
mDstFormat(OMX_COLOR_Format16bitRGB565),
mDstBpp(2) {}
- VideoFrame* extractFrame(
- int64_t frameTimeUs,
- int option,
- int colorFormat,
- bool metaOnly);
+ VideoFrame* extractFrame(int64_t frameTimeUs, int option, int colorFormat);
status_t extractFrames(
int64_t frameTimeUs,
@@ -57,6 +53,9 @@
int colorFormat,
std::vector<VideoFrame*>* frames);
+ static VideoFrame* getMetadataOnly(
+ const sp<MetaData> &trackMeta, int colorFormat, bool thumbnail = false);
+
protected:
virtual ~FrameDecoder() {}
@@ -78,8 +77,6 @@
int64_t timeUs,
bool *done) = 0;
- VideoFrame *allocVideoFrame(int32_t width, int32_t height, bool metaOnly);
-
sp<MetaData> trackMeta() const { return mTrackMeta; }
OMX_COLOR_FORMATTYPE dstFormat() const { return mDstFormat; }
int32_t dstBpp() const { return mDstBpp; }
@@ -96,7 +93,11 @@
int32_t mDstBpp;
std::vector<std::unique_ptr<VideoFrame> > mFrames;
- bool setDstColorFormat(android_pixel_format_t colorFormat);
+ static bool getDstColorFormat(
+ android_pixel_format_t colorFormat,
+ OMX_COLOR_FORMATTYPE *dstFormat,
+ int32_t *dstBpp);
+
status_t extractInternal(int64_t frameTimeUs, size_t numFrames, int option);
DISALLOW_EVIL_CONSTRUCTORS(FrameDecoder);
@@ -147,7 +148,8 @@
const sp<MetaData> &trackMeta,
const sp<IMediaSource> &source) :
FrameDecoder(componentName, trackMeta, source),
- mFrame(NULL), mGridRows(1), mGridCols(1), mTilesDecoded(0) {}
+ mFrame(NULL), mGridRows(1), mGridCols(1),
+ mTilesDecoded(0), mThumbnail(false) {}
protected:
virtual sp<AMessage> onGetFormatAndSeekOptions(
@@ -173,6 +175,7 @@
int32_t mGridRows;
int32_t mGridCols;
int32_t mTilesDecoded;
+ bool mThumbnail;
};
} // namespace android
diff --git a/media/libstagefright/include/StagefrightMetadataRetriever.h b/media/libstagefright/include/StagefrightMetadataRetriever.h
index 58442fe..8443fbe 100644
--- a/media/libstagefright/include/StagefrightMetadataRetriever.h
+++ b/media/libstagefright/include/StagefrightMetadataRetriever.h
@@ -43,7 +43,7 @@
virtual VideoFrame* getFrameAtTime(
int64_t timeUs, int option, int colorFormat, bool metaOnly);
virtual VideoFrame* getImageAtIndex(
- int index, int colorFormat, bool metaOnly);
+ int index, int colorFormat, bool metaOnly, bool thumbnail);
virtual status_t getFrameAtIndex(
std::vector<VideoFrame*>* frames,
int frameIndex, int numFrames, int colorFormat, bool metaOnly);
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index ff58eb6..7f4d819 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -131,22 +131,34 @@
static_cast<void*>(mHidlMemory->getPointer())) : nullptr;
}
- void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header) {
+ void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header, OMXNodeInstance::SecureBufferType type) {
if (!mCopyFromOmx) {
return;
}
+ if (type != OMXNodeInstance::kSecureBufferTypeUnknown) {
+ ALOGE("b/77486542");
+ android_errorWriteLog(0x534e4554, "77486542");
+ return;
+ }
+
// check component returns proper range
sp<ABuffer> codec = getBuffer(header, true /* limit */);
memcpy(getPointer() + header->nOffset, codec->data(), codec->size());
}
- void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) {
+ void CopyToOMX(const OMX_BUFFERHEADERTYPE *header, OMXNodeInstance::SecureBufferType type) {
if (!mCopyToOmx) {
return;
}
+ if (type != OMXNodeInstance::kSecureBufferTypeUnknown) {
+ ALOGE("b/77486542");
+ android_errorWriteLog(0x534e4554, "77486542");
+ return;
+ }
+
memcpy(header->pBuffer + header->nOffset,
getPointer() + header->nOffset,
header->nFilledLen);
@@ -1693,7 +1705,7 @@
header->nFilledLen = rangeLength;
header->nOffset = rangeOffset;
- buffer_meta->CopyToOMX(header);
+ buffer_meta->CopyToOMX(header, mSecureBufferType[kPortIndexInput]);
}
return emptyBuffer_l(header, flags, timestamp, (intptr_t)buffer, fenceFd);
@@ -1981,7 +1993,7 @@
CLOG_ERROR(onFillBufferDone, OMX_ErrorBadParameter,
FULL_BUFFER(NULL, buffer, msg.fenceFd));
}
- buffer_meta->CopyFromOMX(buffer);
+ buffer_meta->CopyFromOMX(buffer, mSecureBufferType[kPortIndexOutput]);
// fix up the buffer info (especially timestamp) if needed
codecBufferFilled(msg);
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h b/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h
index c436121..2d022ad 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h
@@ -117,6 +117,12 @@
static OMX_CALLBACKTYPE kCallbacks;
+ enum SecureBufferType {
+ kSecureBufferTypeUnknown,
+ kSecureBufferTypeOpaque,
+ kSecureBufferTypeNativeHandle,
+ };
+
private:
struct CallbackDispatcherThread;
struct CallbackDispatcher;
@@ -155,11 +161,6 @@
IOMX::PortMode mPortMode[2];
// metadata and secure buffer types and graphic buffer mode tracking
MetadataBufferType mMetadataType[2];
- enum SecureBufferType {
- kSecureBufferTypeUnknown,
- kSecureBufferTypeOpaque,
- kSecureBufferTypeNativeHandle,
- };
SecureBufferType mSecureBufferType[2];
bool mGraphicBufferEnabled[2];
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index b38d37f..54121cd 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1000,14 +1000,12 @@
{
ALOGV("AudioFlinger::setRecordSilenced(uid:%d, silenced:%d)", uid, silenced);
- // TODO: Notify MmapThreads
-
AutoMutex lock(mLock);
for (size_t i = 0; i < mRecordThreads.size(); i++) {
- sp<RecordThread> thread = mRecordThreads.valueAt(i);
- if (thread != 0) {
- thread->setRecordSilenced(uid, silenced);
- }
+ mRecordThreads[i]->setRecordSilenced(uid, silenced);
+ }
+ for (size_t i = 0; i < mMmapThreads.size(); i++) {
+ mMmapThreads[i]->setRecordSilenced(uid, silenced);
}
}
diff --git a/services/audioflinger/MmapTracks.h b/services/audioflinger/MmapTracks.h
index a210a1b..6f546c3 100644
--- a/services/audioflinger/MmapTracks.h
+++ b/services/audioflinger/MmapTracks.h
@@ -43,6 +43,15 @@
static void appendDumpHeader(String8& result);
void appendDump(String8& result, bool active);
+ // protected by MMapThread::mLock
+ void setSilenced_l(bool silenced) { mSilenced = silenced;
+ mSilencedNotified = false;}
+ // protected by MMapThread::mLock
+ bool isSilenced_l() const { return mSilenced; }
+ // protected by MMapThread::mLock
+ bool getAndSetSilencedNotified_l() { bool silencedNotified = mSilencedNotified;
+ mSilencedNotified = true;
+ return silencedNotified; }
private:
friend class MmapThread;
@@ -58,5 +67,7 @@
virtual void onTimestamp(const ExtendedTimestamp ×tamp);
pid_t mPid;
+ bool mSilenced; // protected by MMapThread::mLock
+ bool mSilencedNotified; // protected by MMapThread::mLock
}; // end of Track
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index ab65601..1517d11 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -7898,7 +7898,7 @@
mSessionId(AUDIO_SESSION_NONE),
mDeviceId(AUDIO_PORT_HANDLE_NONE), mPortId(AUDIO_PORT_HANDLE_NONE),
mHalStream(stream), mHalDevice(hwDev->hwDevice()), mAudioHwDev(hwDev),
- mActiveTracks(&this->mLocalLog)
+ mActiveTracks(&this->mLocalLog), mNoCallbackWarningCount(0)
{
mStandby = true;
readHalParameters_l();
@@ -7916,7 +7916,14 @@
void AudioFlinger::MmapThread::disconnect()
{
- for (const sp<MmapTrack> &t : mActiveTracks) {
+ ActiveTracks<MmapTrack> activeTracks;
+ {
+ Mutex::Autolock _l(mLock);
+ for (const sp<MmapTrack> &t : mActiveTracks) {
+ activeTracks.add(t);
+ }
+ }
+ for (const sp<MmapTrack> &t : activeTracks) {
stop(t->portId());
}
// This will decrement references and may cause the destruction of this thread.
@@ -7961,6 +7968,17 @@
return mHalStream->getMmapPosition(position);
}
+status_t AudioFlinger::MmapThread::exitStandby()
+{
+ status_t ret = mHalStream->start();
+ if (ret != NO_ERROR) {
+ ALOGE("%s: error mHalStream->start() = %d for first track", __FUNCTION__, ret);
+ return ret;
+ }
+ mStandby = false;
+ return NO_ERROR;
+}
+
status_t AudioFlinger::MmapThread::start(const AudioClient& client,
audio_port_handle_t *handle)
{
@@ -7974,13 +7992,7 @@
if (*handle == mPortId) {
// for the first track, reuse portId and session allocated when the stream was opened
- ret = mHalStream->start();
- if (ret != NO_ERROR) {
- ALOGE("%s: error mHalStream->start() = %d for first track", __FUNCTION__, ret);
- return ret;
- }
- mStandby = false;
- return NO_ERROR;
+ return exitStandby();
}
audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
@@ -8028,33 +8040,43 @@
return BAD_VALUE;
}
+ bool silenced = false;
if (isOutput()) {
ret = AudioSystem::startOutput(mId, streamType(), mSessionId);
} else {
- // TODO: Block recording for idle UIDs (b/72134552)
- bool silenced;
ret = AudioSystem::startInput(portId, &silenced);
}
+ Mutex::Autolock _l(mLock);
// abort if start is rejected by audio policy manager
if (ret != NO_ERROR) {
ALOGE("%s: error start rejected by AudioPolicyManager = %d", __FUNCTION__, ret);
if (mActiveTracks.size() != 0) {
+ mLock.unlock();
if (isOutput()) {
AudioSystem::releaseOutput(mId, streamType(), mSessionId);
} else {
AudioSystem::releaseInput(portId);
}
+ mLock.lock();
} else {
mHalStream->stop();
}
return PERMISSION_DENIED;
}
+ if (!isOutput() && !silenced) {
+ for (const sp<MmapTrack> &track : mActiveTracks) {
+ if (track->isSilenced_l() && track->uid() != client.clientUid)
+ track->invalidate();
+ }
+ }
+
// Given that MmapThread::mAttr is mutable, should a MmapTrack have attributes ?
sp<MmapTrack> track = new MmapTrack(this, mAttr, mSampleRate, mFormat, mChannelMask, mSessionId,
client.clientUid, client.clientPid, portId);
+ track->setSilenced_l(silenced);
mActiveTracks.add(track);
sp<EffectChain> chain = getEffectChain_l(mSessionId);
if (chain != 0) {
@@ -8084,6 +8106,8 @@
return NO_ERROR;
}
+ Mutex::Autolock _l(mLock);
+
sp<MmapTrack> track;
for (const sp<MmapTrack> &t : mActiveTracks) {
if (handle == t->portId()) {
@@ -8097,6 +8121,7 @@
mActiveTracks.remove(track);
+ mLock.unlock();
if (isOutput()) {
AudioSystem::stopOutput(mId, streamType(), track->sessionId());
AudioSystem::releaseOutput(mId, streamType(), track->sessionId());
@@ -8104,6 +8129,7 @@
AudioSystem::stopInput(track->portId());
AudioSystem::releaseInput(track->portId());
}
+ mLock.lock();
sp<EffectChain> chain = getEffectChain_l(track->sessionId());
if (chain != 0) {
@@ -8530,9 +8556,11 @@
if (track->isInvalid()) {
sp<MmapStreamCallback> callback = mCallback.promote();
if (callback != 0) {
- callback->onTearDown();
+ callback->onTearDown(track->portId());
+ } else if (mNoCallbackWarningCount < kMaxNoCallbackWarnings) {
+ ALOGW("Could not notify MMAP stream tear down: no onTearDown callback!");
+ mNoCallbackWarningCount++;
}
- break;
}
}
}
@@ -8587,7 +8615,6 @@
mStreamVolume(1.0),
mStreamMute(false),
mHalVolFloat(-1.0f), // Initialize to illegal value so it always gets set properly later.
- mNoCallbackWarningCount(0),
mOutput(output)
{
snprintf(mThreadName, kThreadNameLength, "AudioMmapOut_%X", id);
@@ -8792,6 +8819,12 @@
mChannelCount = audio_channel_count_from_in_mask(mChannelMask);
}
+status_t AudioFlinger::MmapCaptureThread::exitStandby()
+{
+ mInput->stream->setGain(1.0f);
+ return MmapThread::exitStandby();
+}
+
AudioFlinger::AudioStreamIn* AudioFlinger::MmapCaptureThread::clearInput()
{
Mutex::Autolock _l(mLock);
@@ -8800,6 +8833,34 @@
return input;
}
+
+void AudioFlinger::MmapCaptureThread::processVolume_l()
+{
+ bool changed = false;
+ bool silenced = false;
+
+ sp<MmapStreamCallback> callback = mCallback.promote();
+ if (callback == 0) {
+ if (mNoCallbackWarningCount < kMaxNoCallbackWarnings) {
+ ALOGW("Could not set MMAP stream silenced: no onStreamSilenced callback!");
+ mNoCallbackWarningCount++;
+ }
+ }
+
+ // After a change occurred in track silenced state, mute capture in audio DSP if at least one
+ // track is silenced and unmute otherwise
+ for (size_t i = 0; i < mActiveTracks.size() && !silenced; i++) {
+ if (!mActiveTracks[i]->getAndSetSilencedNotified_l()) {
+ changed = true;
+ silenced = mActiveTracks[i]->isSilenced_l();
+ }
+ }
+
+ if (changed) {
+ mInput->stream->setGain(silenced ? 0.0f: 1.0f);
+ }
+}
+
void AudioFlinger::MmapCaptureThread::updateMetadata_l()
{
if (mInput == nullptr || mInput->stream == nullptr ||
@@ -8817,4 +8878,15 @@
mInput->stream->updateSinkMetadata(metadata);
}
+void AudioFlinger::MmapCaptureThread::setRecordSilenced(uid_t uid, bool silenced)
+{
+ Mutex::Autolock _l(mLock);
+ for (size_t i = 0; i < mActiveTracks.size() ; i++) {
+ if (mActiveTracks[i]->uid() == uid) {
+ mActiveTracks[i]->setSilenced_l(silenced);
+ broadcast_l();
+ }
+ }
+}
+
} // namespace android
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 5a5961a..bc4a534 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1589,6 +1589,7 @@
virtual void threadLoop_exit();
virtual void threadLoop_standby();
virtual bool shouldStandby_l() { return false; }
+ virtual status_t exitStandby();
virtual status_t initCheck() const { return (mHalStream == 0) ? NO_INIT : NO_ERROR; }
virtual size_t frameCount() const { return mFrameCount; }
@@ -1621,6 +1622,9 @@
virtual void invalidateTracks(audio_stream_type_t streamType __unused) {}
+ // Sets the UID records silence
+ virtual void setRecordSilenced(uid_t uid __unused, bool silenced __unused) {}
+
void dump(int fd, const Vector<String16>& args);
virtual void dumpInternals(int fd, const Vector<String16>& args);
void dumpTracks(int fd, const Vector<String16>& args);
@@ -1637,6 +1641,9 @@
sp<DeviceHalInterface> mHalDevice;
AudioHwDevice* const mAudioHwDev;
ActiveTracks<MmapTrack> mActiveTracks;
+
+ int32_t mNoCallbackWarningCount;
+ static constexpr int32_t kMaxNoCallbackWarnings = 5;
};
class MmapPlaybackThread : public MmapThread, public VolumeInterface
@@ -1670,7 +1677,7 @@
virtual audio_stream_type_t streamType() { return mStreamType; }
virtual void checkSilentMode_l();
- virtual void processVolume_l();
+ void processVolume_l() override;
virtual void dumpInternals(int fd, const Vector<String16>& args);
@@ -1686,8 +1693,6 @@
bool mMasterMute;
bool mStreamMute;
float mHalVolFloat;
- int32_t mNoCallbackWarningCount;
- static constexpr int32_t kMaxNoCallbackWarnings = 5;
AudioStreamOut* mOutput;
};
@@ -1702,9 +1707,12 @@
AudioStreamIn* clearInput();
+ status_t exitStandby() override;
virtual bool isOutput() const override { return false; }
void updateMetadata_l() override;
+ void processVolume_l() override;
+ void setRecordSilenced(uid_t uid, bool silenced) override;
protected:
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 3fe41d8..aff1239 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1946,7 +1946,7 @@
sessionId, uid, false /* isOut */,
ALLOC_NONE,
TYPE_DEFAULT, portId),
- mPid(pid)
+ mPid(pid), mSilenced(false), mSilencedNotified(false)
{
}
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index 08bcf4d..83aec3b 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -613,6 +613,23 @@
uint32_t device = AUDIO_DEVICE_NONE;
+ // when a call is active, force device selection to match source VOICE_COMMUNICATION
+ // for most other input sources to avoid rerouting call TX audio
+ if (isInCall()) {
+ switch (inputSource) {
+ case AUDIO_SOURCE_DEFAULT:
+ case AUDIO_SOURCE_MIC:
+ case AUDIO_SOURCE_VOICE_RECOGNITION:
+ case AUDIO_SOURCE_UNPROCESSED:
+ case AUDIO_SOURCE_HOTWORD:
+ case AUDIO_SOURCE_CAMCORDER:
+ inputSource = AUDIO_SOURCE_VOICE_COMMUNICATION;
+ break;
+ default:
+ break;
+ }
+ }
+
switch (inputSource) {
case AUDIO_SOURCE_VOICE_UPLINK:
if (availableDeviceTypes & AUDIO_DEVICE_IN_VOICE_CALL) {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 29ec961..0d36266 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1468,14 +1468,19 @@
}
// For MMAP mode, the first call to getInputForAttr() is made on behalf of audioflinger.
// The second call is for the first active client and sets the UID. Any further call
- // corresponds to a new client and is only permitted from the same UId.
+ // corresponds to a new client and is only permitted from the same UID.
+ // If the first UID is silenced, allow a new UID connection and replace with new UID
if (audioSession->openCount() == 1) {
audioSession->setUid(uid);
} else if (audioSession->uid() != uid) {
- ALOGW("getInputForAttr() bad uid %d for session %d uid %d",
- uid, session, audioSession->uid());
- status = INVALID_OPERATION;
- goto error;
+ if (!audioSession->isSilenced()) {
+ ALOGW("getInputForAttr() bad uid %d for session %d uid %d",
+ uid, session, audioSession->uid());
+ status = INVALID_OPERATION;
+ goto error;
+ }
+ audioSession->setUid(uid);
+ audioSession->setSilenced(false);
}
audioSession->changeOpenCount(1);
*inputType = API_INPUT_LEGACY;
@@ -4530,10 +4535,13 @@
}
}
+ // If we are not in call and no client is active on this input, this methods returns
+ // AUDIO_DEVICE_NONE, causing the patch on the input stream to be released.
audio_source_t source = inputDesc->getHighestPrioritySource(true /*activeOnly*/);
- if (isInCall()) {
- device = getDeviceAndMixForInputSource(AUDIO_SOURCE_VOICE_COMMUNICATION);
- } else if (source != AUDIO_SOURCE_DEFAULT) {
+ if (source == AUDIO_SOURCE_DEFAULT && isInCall()) {
+ source = AUDIO_SOURCE_VOICE_COMMUNICATION;
+ }
+ if (source != AUDIO_SOURCE_DEFAULT) {
device = getDeviceAndMixForInputSource(source);
}
diff --git a/services/oboeservice/AAudioClientTracker.cpp b/services/oboeservice/AAudioClientTracker.cpp
index 549a4e9..7264a9b 100644
--- a/services/oboeservice/AAudioClientTracker.cpp
+++ b/services/oboeservice/AAudioClientTracker.cpp
@@ -21,6 +21,8 @@
#include <assert.h>
#include <binder/IPCThreadState.h>
+#include <iomanip>
+#include <iostream>
#include <map>
#include <mutex>
#include <utils/Singleton.h>
@@ -39,7 +41,6 @@
: Singleton<AAudioClientTracker>() {
}
-
std::string AAudioClientTracker::dump() const {
std::stringstream result;
const bool isLocked = AAudio_tryUntilTrue(
@@ -198,7 +199,9 @@
result << " client: pid = " << mProcessId << " has " << mStreams.size() << " streams\n";
for (const auto& serviceStream : mStreams) {
- result << " stream: 0x" << std::hex << serviceStream->getHandle() << std::dec << "\n";
+ result << " stream: 0x" << std::setfill('0') << std::setw(8) << std::hex
+ << serviceStream->getHandle()
+ << std::dec << std::setfill(' ') << "\n";
}
if (isLocked) {
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index 11fd9f6..ab8f4ed 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -67,11 +67,17 @@
result << "Exclusive MMAP Endpoints: " << mExclusiveStreams.size() << "\n";
index = 0;
- for (const auto &output : mExclusiveStreams) {
+ for (const auto &stream : mExclusiveStreams) {
result << " #" << index++ << ":";
- result << output->dump() << "\n";
+ result << stream->dump() << "\n";
}
+ result << " ExclusiveSearchCount: " << mExclusiveSearchCount << "\n";
+ result << " ExclusiveFoundCount: " << mExclusiveFoundCount << "\n";
+ result << " ExclusiveOpenCount: " << mExclusiveOpenCount << "\n";
+ result << " ExclusiveCloseCount: " << mExclusiveCloseCount << "\n";
+ result << "\n";
+
if (isExclusiveLocked) {
mExclusiveLock.unlock();
}
@@ -79,11 +85,17 @@
result << "Shared Endpoints: " << mSharedStreams.size() << "\n";
index = 0;
- for (const auto &input : mSharedStreams) {
+ for (const auto &stream : mSharedStreams) {
result << " #" << index++ << ":";
- result << input->dump() << "\n";
+ result << stream->dump() << "\n";
}
+ result << " SharedSearchCount: " << mSharedSearchCount << "\n";
+ result << " SharedFoundCount: " << mSharedFoundCount << "\n";
+ result << " SharedOpenCount: " << mSharedOpenCount << "\n";
+ result << " SharedCloseCount: " << mSharedCloseCount << "\n";
+ result << "\n";
+
if (isSharedLocked) {
mSharedLock.unlock();
}
@@ -95,8 +107,10 @@
sp<AAudioServiceEndpoint> AAudioEndpointManager::findExclusiveEndpoint_l(
const AAudioStreamConfiguration &configuration) {
sp<AAudioServiceEndpoint> endpoint;
+ mExclusiveSearchCount++;
for (const auto ep : mExclusiveStreams) {
if (ep->matches(configuration)) {
+ mExclusiveFoundCount++;
endpoint = ep;
break;
}
@@ -111,8 +125,10 @@
sp<AAudioServiceEndpointShared> AAudioEndpointManager::findSharedEndpoint_l(
const AAudioStreamConfiguration &configuration) {
sp<AAudioServiceEndpointShared> endpoint;
+ mSharedSearchCount++;
for (const auto ep : mSharedStreams) {
if (ep->matches(configuration)) {
+ mSharedFoundCount++;
endpoint = ep;
break;
}
@@ -146,21 +162,21 @@
// If we find an existing one then this one cannot be exclusive.
if (endpoint.get() != nullptr) {
- ALOGE("openExclusiveEndpoint() already in use");
+ ALOGW("openExclusiveEndpoint() already in use");
// Already open so do not allow a second stream.
return nullptr;
} else {
sp<AAudioServiceEndpointMMAP> endpointMMap = new AAudioServiceEndpointMMAP();
- ALOGD("openExclusiveEndpoint(), no match so try to open MMAP %p for dev %d",
+ ALOGV("openExclusiveEndpoint(), no match so try to open MMAP %p for dev %d",
endpointMMap.get(), configuration.getDeviceId());
endpoint = endpointMMap;
aaudio_result_t result = endpoint->open(request);
if (result != AAUDIO_OK) {
- ALOGE("openExclusiveEndpoint(), open failed");
endpoint.clear();
} else {
mExclusiveStreams.push_back(endpointMMap);
+ mExclusiveOpenCount++;
}
}
@@ -201,13 +217,13 @@
if (endpoint.get() != nullptr) {
aaudio_result_t result = endpoint->open(request);
if (result != AAUDIO_OK) {
- ALOGE("%s(), open failed", __func__);
endpoint.clear();
} else {
mSharedStreams.push_back(endpoint);
+ mSharedOpenCount++;
}
}
- ALOGD("%s(), created endpoint %p, requested device = %d, dir = %d",
+ ALOGV("%s(), created endpoint %p, requested device = %d, dir = %d",
__func__, endpoint.get(), configuration.getDeviceId(), (int)direction);
IPCThreadState::self()->restoreCallingIdentity(token);
}
@@ -244,7 +260,8 @@
mExclusiveStreams.end());
serviceEndpoint->close();
- ALOGD("%s() %p for device %d",
+ mExclusiveCloseCount++;
+ ALOGV("%s() %p for device %d",
__func__, serviceEndpoint.get(), serviceEndpoint->getDeviceId());
}
}
@@ -266,7 +283,8 @@
mSharedStreams.end());
serviceEndpoint->close();
- ALOGD("%s() %p for device %d",
+ mSharedCloseCount++;
+ ALOGV("%s() %p for device %d",
__func__, serviceEndpoint.get(), serviceEndpoint->getDeviceId());
}
}
diff --git a/services/oboeservice/AAudioEndpointManager.h b/services/oboeservice/AAudioEndpointManager.h
index f6aeb5a..193bdee 100644
--- a/services/oboeservice/AAudioEndpointManager.h
+++ b/services/oboeservice/AAudioEndpointManager.h
@@ -87,8 +87,17 @@
mutable std::mutex mExclusiveLock;
std::vector<android::sp<AAudioServiceEndpointMMAP>> mExclusiveStreams;
+ // Modified under a lock.
+ int32_t mExclusiveSearchCount = 0; // number of times we SEARCHED for an exclusive endpoint
+ int32_t mExclusiveFoundCount = 0; // number of times we FOUND an exclusive endpoint
+ int32_t mExclusiveOpenCount = 0; // number of times we OPENED an exclusive endpoint
+ int32_t mExclusiveCloseCount = 0; // number of times we CLOSED an exclusive endpoint
+ // Same as above but for SHARED endpoints.
+ int32_t mSharedSearchCount = 0;
+ int32_t mSharedFoundCount = 0;
+ int32_t mSharedOpenCount = 0;
+ int32_t mSharedCloseCount = 0;
};
-
} /* namespace aaudio */
#endif //AAUDIO_AAUDIO_ENDPOINT_MANAGER_H
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index 52990da..5f1de76 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -84,6 +84,7 @@
const audio_content_type_t contentType =
AAudioConvert_contentTypeToInternal(getContentType());
+ // Usage only used for OUTPUT
const audio_usage_t usage = (direction == AAUDIO_DIRECTION_OUTPUT)
? AAudioConvert_usageToInternal(getUsage())
: AUDIO_USAGE_UNKNOWN;
@@ -343,8 +344,9 @@
}
-void AAudioServiceEndpointMMAP::onTearDown() {
+void AAudioServiceEndpointMMAP::onTearDown(audio_port_handle_t handle __unused) {
ALOGD("%s(%p) called", __func__, this);
+ //TODO: disconnect only stream corresponding to handle received
disconnectRegisteredStreams();
};
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.h b/services/oboeservice/AAudioServiceEndpointMMAP.h
index 16b6269..c4c943d 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.h
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.h
@@ -68,7 +68,7 @@
aaudio_result_t getTimestamp(int64_t *positionFrames, int64_t *timeNanos) override;
// -------------- Callback functions for MmapStreamCallback ---------------------
- void onTearDown() override;
+ void onTearDown(audio_port_handle_t handle) override;
void onVolumeChanged(audio_channel_mask_t channels,
android::Vector<float> values) override;
diff --git a/services/oboeservice/AAudioServiceEndpointShared.cpp b/services/oboeservice/AAudioServiceEndpointShared.cpp
index f08a52f..63b9983 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.cpp
+++ b/services/oboeservice/AAudioServiceEndpointShared.cpp
@@ -78,7 +78,6 @@
setSamplesPerFrame(mStreamInternal->getSamplesPerFrame());
setDeviceId(mStreamInternal->getDeviceId());
setSessionId(mStreamInternal->getSessionId());
- ALOGD("open() deviceId = %d, sessionId = %d", getDeviceId(), getSessionId());
mFramesPerBurst = mStreamInternal->getFramesPerBurst();
return result;
diff --git a/services/oboeservice/AAudioServiceStreamShared.cpp b/services/oboeservice/AAudioServiceStreamShared.cpp
index 75d88cf..864a008 100644
--- a/services/oboeservice/AAudioServiceStreamShared.cpp
+++ b/services/oboeservice/AAudioServiceStreamShared.cpp
@@ -122,19 +122,18 @@
aaudio_result_t result = AAudioServiceStreamBase::open(request, AAUDIO_SHARING_MODE_SHARED);
if (result != AAUDIO_OK) {
- ALOGE("open() returned %d", result);
+ ALOGE("%s() returned %d", __func__, result);
return result;
}
const AAudioStreamConfiguration &configurationInput = request.getConstantConfiguration();
-
// Is the request compatible with the shared endpoint?
setFormat(configurationInput.getFormat());
if (getFormat() == AAUDIO_FORMAT_UNSPECIFIED) {
setFormat(AAUDIO_FORMAT_PCM_FLOAT);
} else if (getFormat() != AAUDIO_FORMAT_PCM_FLOAT) {
- ALOGE("open() mAudioFormat = %d, need FLOAT", getFormat());
+ ALOGD("%s() mAudioFormat = %d, need FLOAT", __func__, getFormat());
result = AAUDIO_ERROR_INVALID_FORMAT;
goto error;
}
@@ -143,8 +142,8 @@
if (getSampleRate() == AAUDIO_UNSPECIFIED) {
setSampleRate(mServiceEndpoint->getSampleRate());
} else if (getSampleRate() != mServiceEndpoint->getSampleRate()) {
- ALOGE("open() mSampleRate = %d, need %d",
- getSampleRate(), mServiceEndpoint->getSampleRate());
+ ALOGD("%s() mSampleRate = %d, need %d",
+ __func__, getSampleRate(), mServiceEndpoint->getSampleRate());
result = AAUDIO_ERROR_INVALID_RATE;
goto error;
}
@@ -153,8 +152,8 @@
if (getSamplesPerFrame() == AAUDIO_UNSPECIFIED) {
setSamplesPerFrame(mServiceEndpoint->getSamplesPerFrame());
} else if (getSamplesPerFrame() != mServiceEndpoint->getSamplesPerFrame()) {
- ALOGE("open() mSamplesPerFrame = %d, need %d",
- getSamplesPerFrame(), mServiceEndpoint->getSamplesPerFrame());
+ ALOGD("%s() mSamplesPerFrame = %d, need %d",
+ __func__, getSamplesPerFrame(), mServiceEndpoint->getSamplesPerFrame());
result = AAUDIO_ERROR_OUT_OF_RANGE;
goto error;
}
@@ -173,16 +172,13 @@
mAudioDataQueue = new SharedRingBuffer();
result = mAudioDataQueue->allocate(calculateBytesPerFrame(), getBufferCapacity());
if (result != AAUDIO_OK) {
- ALOGE("open() could not allocate FIFO with %d frames",
- getBufferCapacity());
+ ALOGE("%s() could not allocate FIFO with %d frames",
+ __func__, getBufferCapacity());
result = AAUDIO_ERROR_NO_MEMORY;
goto error;
}
}
- ALOGD("open() actual rate = %d, channels = %d, deviceId = %d",
- getSampleRate(), getSamplesPerFrame(), mServiceEndpoint->getDeviceId());
-
result = mServiceEndpoint->registerStream(keep);
if (result != AAUDIO_OK) {
goto error;
@@ -217,7 +213,7 @@
{
std::lock_guard<std::mutex> lock(mAudioDataQueueLock);
if (mAudioDataQueue == nullptr) {
- ALOGE("getAudioDataDescription(): mUpMessageQueue null! - stream not open");
+ ALOGE("%s(): mUpMessageQueue null! - stream not open", __func__);
return AAUDIO_ERROR_NULL;
}
// Gather information on the data queue.
@@ -255,8 +251,8 @@
int64_t offset = mTimestampPositionOffset.load();
// TODO, do not go below starting value
position -= offset; // Offset from shared MMAP stream
- ALOGV("getHardwareTimestamp() %8lld = %8lld - %8lld",
- (long long) position, (long long) (position + offset), (long long) offset);
+ ALOGV("%s() %8lld = %8lld - %8lld",
+ __func__, (long long) position, (long long) (position + offset), (long long) offset);
}
*positionFrames = position;
return result;