Merge "Write Exif data block for HEIF files" into pi-dev
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 39ee437..c072901 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -1286,6 +1286,24 @@
return af->getMicrophones(microphones);
}
+status_t AudioSystem::getSurroundFormats(unsigned int *numSurroundFormats,
+ audio_format_t *surroundFormats,
+ bool *surroundFormatsEnabled,
+ bool reported)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ return aps->getSurroundFormats(
+ numSurroundFormats, surroundFormats, surroundFormatsEnabled, reported);
+}
+
+status_t AudioSystem::setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ return aps->setSurroundFormatEnabled(audioFormat, enabled);
+}
+
// ---------------------------------------------------------------------------
int AudioSystem::AudioPolicyServiceClient::addAudioPortCallback(
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index eca6fee..a1236e7 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -80,7 +80,9 @@
SET_AUDIO_PORT_CALLBACK_ENABLED,
SET_MASTER_MONO,
GET_MASTER_MONO,
- GET_STREAM_VOLUME_DB
+ GET_STREAM_VOLUME_DB,
+ GET_SURROUND_FORMATS,
+ SET_SURROUND_FORMAT_ENABLED
};
#define MAX_ITEMS_PER_LIST 1024
@@ -829,6 +831,54 @@
}
return reply.readFloat();
}
+
+ virtual status_t getSurroundFormats(unsigned int *numSurroundFormats,
+ audio_format_t *surroundFormats,
+ bool *surroundFormatsEnabled,
+ bool reported)
+ {
+ if (numSurroundFormats == NULL || (*numSurroundFormats != 0 &&
+ (surroundFormats == NULL || surroundFormatsEnabled == NULL))) {
+ return BAD_VALUE;
+ }
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ unsigned int numSurroundFormatsReq = *numSurroundFormats;
+ data.writeUint32(numSurroundFormatsReq);
+ data.writeBool(reported);
+ status_t status = remote()->transact(GET_SURROUND_FORMATS, data, &reply);
+ if (status == NO_ERROR && (status = (status_t)reply.readInt32()) == NO_ERROR) {
+ *numSurroundFormats = reply.readUint32();
+ }
+ if (status == NO_ERROR) {
+ if (numSurroundFormatsReq > *numSurroundFormats) {
+ numSurroundFormatsReq = *numSurroundFormats;
+ }
+ if (numSurroundFormatsReq > 0) {
+ status = reply.read(surroundFormats,
+ numSurroundFormatsReq * sizeof(audio_format_t));
+ if (status != NO_ERROR) {
+ return status;
+ }
+ status = reply.read(surroundFormatsEnabled,
+ numSurroundFormatsReq * sizeof(bool));
+ }
+ }
+ return status;
+ }
+
+ virtual status_t setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(audioFormat);
+ data.writeBool(enabled);
+ status_t status = remote()->transact(SET_SURROUND_FORMAT_ENABLED, data, &reply);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ return reply.readInt32();
+ }
};
IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService");
@@ -883,7 +933,9 @@
case REGISTER_POLICY_MIXES:
case SET_MASTER_MONO:
case START_AUDIO_SOURCE:
- case STOP_AUDIO_SOURCE: {
+ case STOP_AUDIO_SOURCE:
+ case GET_SURROUND_FORMATS:
+ case SET_SURROUND_FORMAT_ENABLED: {
if (multiuser_get_app_id(IPCThreadState::self()->getCallingUid()) >= AID_APP_START) {
ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
__func__, code, IPCThreadState::self()->getCallingPid(),
@@ -1489,6 +1541,50 @@
return NO_ERROR;
}
+ case GET_SURROUND_FORMATS: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ unsigned int numSurroundFormatsReq = data.readUint32();
+ if (numSurroundFormatsReq > MAX_ITEMS_PER_LIST) {
+ numSurroundFormatsReq = MAX_ITEMS_PER_LIST;
+ }
+ bool reported = data.readBool();
+ unsigned int numSurroundFormats = numSurroundFormatsReq;
+ audio_format_t *surroundFormats = (audio_format_t *)calloc(
+ numSurroundFormats, sizeof(audio_format_t));
+ bool *surroundFormatsEnabled = (bool *)calloc(numSurroundFormats, sizeof(bool));
+ if (numSurroundFormatsReq > 0 &&
+ (surroundFormats == NULL || surroundFormatsEnabled == NULL)) {
+ free(surroundFormats);
+ free(surroundFormatsEnabled);
+ reply->writeInt32(NO_MEMORY);
+ return NO_ERROR;
+ }
+ status_t status = getSurroundFormats(
+ &numSurroundFormats, surroundFormats, surroundFormatsEnabled, reported);
+ reply->writeInt32(status);
+
+ if (status == NO_ERROR) {
+ reply->writeUint32(numSurroundFormats);
+ if (numSurroundFormatsReq > numSurroundFormats) {
+ numSurroundFormatsReq = numSurroundFormats;
+ }
+ reply->write(surroundFormats, numSurroundFormatsReq * sizeof(audio_format_t));
+ reply->write(surroundFormatsEnabled, numSurroundFormatsReq * sizeof(bool));
+ }
+ free(surroundFormats);
+ free(surroundFormatsEnabled);
+ return NO_ERROR;
+ }
+
+ case SET_SURROUND_FORMAT_ENABLED: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ audio_format_t audioFormat = (audio_format_t) data.readInt32();
+ bool enabled = data.readBool();
+ status_t status = setSurroundFormatEnabled(audioFormat, enabled);
+ reply->writeInt32(status);
+ return NO_ERROR;
+ }
+
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/media/libaudioclient/include/media/AudioParameter.h b/media/libaudioclient/include/media/AudioParameter.h
index 59ac1db..967d895 100644
--- a/media/libaudioclient/include/media/AudioParameter.h
+++ b/media/libaudioclient/include/media/AudioParameter.h
@@ -81,6 +81,11 @@
static const char * const valueListSeparator;
+ // keyReconfigA2dp: Ask HwModule to reconfigure A2DP offloaded codec
+ // keyReconfigA2dpSupported: Query if HwModule supports A2DP offload codec config
+ static const char * const keyReconfigA2dp;
+ static const char * const keyReconfigA2dpSupported;
+
String8 toString() const { return toStringImpl(true); }
String8 keysToString() const { return toStringImpl(false); }
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 0c4d6ee..4c0f796 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -340,6 +340,15 @@
static status_t getMicrophones(std::vector<media::MicrophoneInfo> *microphones);
+ // numSurroundFormats holds the maximum number of formats and bool value allowed in the array.
+ // When numSurroundFormats is 0, surroundFormats and surroundFormatsEnabled will not be
+ // populated. The actual number of surround formats should be returned at numSurroundFormats.
+ static status_t getSurroundFormats(unsigned int *numSurroundFormats,
+ audio_format_t *surroundFormats,
+ bool *surroundFormatsEnabled,
+ bool reported);
+ static status_t setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled);
+
// ----------------------------------------------------------------------------
class AudioPortCallback : public RefBase
diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h
index 1114eeb..c3876af 100644
--- a/media/libaudioclient/include/media/IAudioPolicyService.h
+++ b/media/libaudioclient/include/media/IAudioPolicyService.h
@@ -166,6 +166,12 @@
virtual status_t getMasterMono(bool *mono) = 0;
virtual float getStreamVolumeDB(
audio_stream_type_t stream, int index, audio_devices_t device) = 0;
+
+ virtual status_t getSurroundFormats(unsigned int *numSurroundFormats,
+ audio_format_t *surroundFormats,
+ bool *surroundFormatsEnabled,
+ bool reported) = 0;
+ virtual status_t setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled) = 0;
};
diff --git a/media/libeffects/config/Android.bp b/media/libeffects/config/Android.bp
index 3e88c7c..5fa9da9 100644
--- a/media/libeffects/config/Android.bp
+++ b/media/libeffects/config/Android.bp
@@ -1,5 +1,5 @@
// Effect configuration
-cc_library_shared {
+cc_library {
name: "libeffectsconfig",
vendor_available: true,
diff --git a/media/libmedia/AudioParameter.cpp b/media/libmedia/AudioParameter.cpp
index cb0e927..034f7c2 100644
--- a/media/libmedia/AudioParameter.cpp
+++ b/media/libmedia/AudioParameter.cpp
@@ -47,6 +47,8 @@
const char * const AudioParameter::valueOn = AUDIO_PARAMETER_VALUE_ON;
const char * const AudioParameter::valueOff = AUDIO_PARAMETER_VALUE_OFF;
const char * const AudioParameter::valueListSeparator = AUDIO_PARAMETER_VALUE_LIST_SEPARATOR;
+const char * const AudioParameter::keyReconfigA2dp = AUDIO_PARAMETER_RECONFIG_A2DP;
+const char * const AudioParameter::keyReconfigA2dpSupported = AUDIO_PARAMETER_A2DP_RECONFIG_SUPPORTED;
AudioParameter::AudioParameter(const String8& keyValuePairs)
{
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 0a1bdfe..a5f5fc6 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -1447,6 +1447,29 @@
break;
}
+ case kWhatGetStats:
+ {
+ ALOGV("kWhatGetStats");
+
+ Vector<sp<AMessage>> *trackStats;
+ CHECK(msg->findPointer("trackstats", (void**)&trackStats));
+
+ trackStats->clear();
+ if (mVideoDecoder != NULL) {
+ trackStats->push_back(mVideoDecoder->getStats());
+ }
+ if (mAudioDecoder != NULL) {
+ trackStats->push_back(mAudioDecoder->getStats());
+ }
+
+ // respond for synchronization
+ sp<AMessage> response = new AMessage;
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+ response->postReply(replyID);
+ break;
+ }
+
default:
TRESPASS();
break;
@@ -2210,16 +2233,16 @@
return renderer->getCurrentPosition(mediaUs);
}
-void NuPlayer::getStats(Vector<sp<AMessage> > *mTrackStats) {
- CHECK(mTrackStats != NULL);
+void NuPlayer::getStats(Vector<sp<AMessage> > *trackStats) {
+ CHECK(trackStats != NULL);
- mTrackStats->clear();
- if (mVideoDecoder != NULL) {
- mTrackStats->push_back(mVideoDecoder->getStats());
- }
- if (mAudioDecoder != NULL) {
- mTrackStats->push_back(mAudioDecoder->getStats());
- }
+ ALOGV("NuPlayer::getStats()");
+ sp<AMessage> msg = new AMessage(kWhatGetStats, this);
+ msg->setPointer("trackstats", trackStats);
+
+ sp<AMessage> response;
+ (void) msg->postAndAwaitResponse(&response);
+ // response is for synchronization, ignore contents
}
sp<MetaData> NuPlayer::getFileMeta() {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 3a7ef4e..e400d16 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -88,7 +88,7 @@
status_t getSelectedTrack(int32_t type, Parcel* reply) const;
status_t selectTrack(size_t trackIndex, bool select, int64_t timeUs);
status_t getCurrentPosition(int64_t *mediaUs);
- void getStats(Vector<sp<AMessage> > *mTrackStats);
+ void getStats(Vector<sp<AMessage> > *trackStats);
sp<MetaData> getFileMeta();
float getFrameRate();
@@ -159,6 +159,7 @@
kWhatPrepareDrm = 'pDrm',
kWhatReleaseDrm = 'rDrm',
kWhatMediaClockNotify = 'mckN',
+ kWhatGetStats = 'gSts',
};
wp<NuPlayerDriver> mDriver;
diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp
index 738f066..43304aa 100644
--- a/media/libstagefright/foundation/AMessage.cpp
+++ b/media/libstagefright/foundation/AMessage.cpp
@@ -116,6 +116,7 @@
default:
break;
}
+ item->mType = kTypeInt32; // clear type
}
#ifdef DUMP_STATS
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h
index 5acc6d6..85e4378 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h
@@ -437,6 +437,94 @@
};
/**
+ * Helper template that copy assigns an object of a specific type (member) in an
+ * AUnion.
+ *
+ * \param Flagger type flagger class (see AData)
+ * \param U AUnion object in which the member should be copy assigned
+ * \param Ts types to consider for the member
+ */
+template<typename Flagger, typename U, typename ...Ts>
+struct HIDE _AData_copy_assigner;
+
+/**
+ * Template specialization when there are still types to consider (T and rest)
+ */
+template<typename Flagger, typename U, typename T, typename ...Ts>
+struct HIDE _AData_copy_assigner<Flagger, U, T, Ts...> {
+ static bool assign(typename Flagger::type flags, U &dst, const U &src) {
+ static_assert(std::is_copy_constructible<T>::value, "T must be copy constructible");
+ // if we can delete as, we can also assign as
+ if (Flagger::canDeleteAs(flags, Flagger::flagFor((T*)0))) {
+ dst.template emplace<T>(src.template get<T>());
+ return true;
+ }
+ return _AData_copy_assigner<Flagger, U, Ts...>::assign(flags, dst, src);
+ }
+};
+
+/**
+ * Template specialization when there are no more types to consider.
+ */
+template<typename Flagger, typename U>
+struct HIDE _AData_copy_assigner<Flagger, U> {
+ inline static bool assign(typename Flagger::type, U &, const U &) {
+ return false;
+ }
+};
+
+/**
+ * Helper template that move assigns an object of a specific type (member) in an
+ * AUnion.
+ *
+ * \param Flagger type flagger class (see AData)
+ * \param U AUnion object in which the member should be copy assigned
+ * \param Ts types to consider for the member
+ */
+template<typename Flagger, typename U, typename ...Ts>
+struct HIDE _AData_move_assigner;
+
+/**
+ * Template specialization when there are still types to consider (T and rest)
+ */
+template<typename Flagger, typename U, typename T, typename ...Ts>
+struct HIDE _AData_move_assigner<Flagger, U, T, Ts...> {
+ template<typename V = T>
+ static typename std::enable_if<std::is_move_constructible<V>::value, bool>::type
+ assign(typename Flagger::type flags, U &dst, U &src) {
+ // if we can delete as, we can also assign as
+ if (Flagger::canDeleteAs(flags, Flagger::flagFor((T*)0))) {
+ dst.template emplace<T>(std::move(src.template get<T>()));
+ return true;
+ }
+ return _AData_move_assigner<Flagger, U, Ts...>::assign(flags, dst, src);
+ }
+
+ // Fall back to copy construction if T is not move constructible
+ template<typename V = T>
+ static typename std::enable_if<!std::is_move_constructible<V>::value, bool>::type
+ assign(typename Flagger::type flags, U &dst, U &src) {
+ static_assert(std::is_copy_constructible<T>::value, "T must be copy constructible");
+ // if we can delete as, we can also assign as
+ if (Flagger::canDeleteAs(flags, Flagger::flagFor((T*)0))) {
+ dst.template emplace<T>(src.template get<T>());
+ return true;
+ }
+ return _AData_move_assigner<Flagger, U, Ts...>::assign(flags, dst, src);
+ }
+};
+
+/**
+ * Template specialization when there are no more types to consider.
+ */
+template<typename Flagger, typename U>
+struct HIDE _AData_move_assigner<Flagger, U> {
+ inline static bool assign(typename Flagger::type, U &, U &) {
+ return false;
+ }
+};
+
+/**
* Container that can store an arbitrary object of a set of specified types.
*
* This struct is an outer class that contains various inner classes based on desired type
@@ -657,6 +745,61 @@
Custom() : base_t(Flagger::flagFor((void*)0)) { }
/**
+ * Copy assignment operator.
+ */
+ Custom& operator=(const Custom &o) {
+ if (&o != this) {
+ if (this->used() && !this->clear()) {
+ __builtin_trap();
+ }
+ if (o.used()) {
+ if (_AData_copy_assigner<Flagger, data_t, Ts...>::assign(
+ o.flags(), this->get(), o.get())) {
+ this->setFlags(o.flags());
+ } else {
+ __builtin_trap();
+ }
+ }
+ }
+ return *this;
+ }
+
+ /**
+ * Copy constructor.
+ */
+ Custom(const Custom &o) : Custom() {
+ *this = o;
+ }
+
+ /**
+ * Move assignment operator.
+ */
+ Custom& operator=(Custom &&o) {
+ if (&o != this) {
+ if (this->used() && !this->clear()) {
+ __builtin_trap();
+ }
+ if (o.used()) {
+ if (_AData_move_assigner<Flagger, data_t, Ts...>::assign(
+ o.flags(), this->get(), o.get())) {
+ this->setFlags(o.flags());
+ o.clear();
+ } else {
+ __builtin_trap();
+ }
+ }
+ }
+ return *this;
+ }
+
+ /**
+ * Move constructor.
+ */
+ Custom(Custom &&o) : Custom() {
+ *this = std::move(o);
+ }
+
+ /**
* Removes the contained object, if any.
*/
~Custom() {
diff --git a/media/libstagefright/foundation/tests/AData_test.cpp b/media/libstagefright/foundation/tests/AData_test.cpp
index f014c25..2628a47 100644
--- a/media/libstagefright/foundation/tests/AData_test.cpp
+++ b/media/libstagefright/foundation/tests/AData_test.cpp
@@ -978,4 +978,63 @@
}
};
+TEST_F(ADataTest, AData_AssignmentTest) {
+ typedef AData<sp<ABuffer>, int32_t>::Basic Data;
+
+ sp<ABuffer> buf1 = new ABuffer((void *)"hello", 6);
+ wp<ABuffer> buf1w = buf1;
+
+ Data obj1;
+ obj1.set(buf1);
+ EXPECT_NE(buf1w.promote(), nullptr);
+ buf1.clear();
+ EXPECT_NE(buf1w.promote(), nullptr);
+ obj1.clear();
+ EXPECT_EQ(buf1w.promote(), nullptr);
+
+ buf1 = new ABuffer((void *)"again", 6);
+ buf1w = buf1;
+
+ obj1.set(buf1);
+ EXPECT_TRUE(obj1.used());
+ Data obj2 = obj1;
+
+ sp<ABuffer> buf2;
+ EXPECT_TRUE(obj2.find(&buf2));
+ EXPECT_EQ(buf2, buf1);
+ buf1.clear();
+ buf2.clear();
+ EXPECT_NE(buf1w.promote(), nullptr);
+ obj1.clear();
+ EXPECT_NE(buf1w.promote(), nullptr);
+ obj2.clear();
+ EXPECT_EQ(buf1w.promote(), nullptr);
+
+ buf1 = new ABuffer((void *)"still", 6);
+ buf1w = buf1;
+
+ obj1.set(buf1);
+ EXPECT_TRUE(obj1.used());
+ obj2 = std::move(obj1);
+ EXPECT_FALSE(obj1.used());
+
+ EXPECT_TRUE(obj2.find(&buf2));
+ EXPECT_EQ(buf2, buf1);
+ buf1.clear();
+ buf2.clear();
+ EXPECT_NE(buf1w.promote(), nullptr);
+ obj2.clear();
+ EXPECT_EQ(buf1w.promote(), nullptr);
+
+ typedef AData<sp<ABuffer>, std::unique_ptr<int32_t>>::Basic Data2;
+ Data2 obj3, obj4;
+
+ buf1 = new ABuffer((void *)"hence", 6);
+ obj3.set(buf1);
+ obj4 = std::move(obj3);
+ EXPECT_FALSE(obj3.used());
+ EXPECT_TRUE(obj4.find(&buf2));
+ EXPECT_EQ(buf2, buf1);
+}
+
} // namespace android
diff --git a/media/mtp/MtpFfsHandle.cpp b/media/mtp/MtpFfsHandle.cpp
index 952b907..f25fc71 100644
--- a/media/mtp/MtpFfsHandle.cpp
+++ b/media/mtp/MtpFfsHandle.cpp
@@ -127,27 +127,45 @@
mControl.reset();
}
-int MtpFfsHandle::doAsync(void* data, size_t len, bool read) {
- struct io_event ioevs[1];
- if (len > AIO_BUF_LEN) {
- LOG(ERROR) << "Mtp read/write too large " << len;
- errno = EINVAL;
- return -1;
+int MtpFfsHandle::doAsync(void* data, size_t len, bool read, bool zero_packet) {
+ struct io_event ioevs[AIO_BUFS_MAX];
+ size_t total = 0;
+
+ while (total < len) {
+ size_t this_len = std::min(len - total, static_cast<size_t>(AIO_BUF_LEN * AIO_BUFS_MAX));
+ int num_bufs = this_len / AIO_BUF_LEN + (this_len % AIO_BUF_LEN == 0 ? 0 : 1);
+ for (int i = 0; i < num_bufs; i++) {
+ mIobuf[0].buf[i] = reinterpret_cast<unsigned char*>(data) + total + i * AIO_BUF_LEN;
+ }
+ int ret = iobufSubmit(&mIobuf[0], read ? mBulkOut : mBulkIn, this_len, read);
+ if (ret < 0) return -1;
+ ret = waitEvents(&mIobuf[0], ret, ioevs, nullptr);
+ if (ret < 0) return -1;
+ total += ret;
+ if (static_cast<size_t>(ret) < this_len) break;
}
- mIobuf[0].buf[0] = reinterpret_cast<unsigned char*>(data);
- if (iobufSubmit(&mIobuf[0], read ? mBulkOut : mBulkIn, len, read) == -1)
- return -1;
- int ret = waitEvents(&mIobuf[0], 1, ioevs, nullptr);
- mIobuf[0].buf[0] = mIobuf[0].bufs.data();
- return ret;
+
+ int packet_size = getPacketSize(read ? mBulkOut : mBulkIn);
+ if (len % packet_size == 0 && zero_packet) {
+ int ret = iobufSubmit(&mIobuf[0], read ? mBulkOut : mBulkIn, 0, read);
+ if (ret < 0) return -1;
+ ret = waitEvents(&mIobuf[0], ret, ioevs, nullptr);
+ if (ret < 0) return -1;
+ }
+
+ for (unsigned i = 0; i < AIO_BUFS_MAX; i++) {
+ mIobuf[0].buf[i] = mIobuf[0].bufs.data() + i * AIO_BUF_LEN;
+ }
+ return total;
}
int MtpFfsHandle::read(void* data, size_t len) {
- return doAsync(data, len, true);
+ // Zero packets are handled by receiveFile()
+ return doAsync(data, len, true, false);
}
int MtpFfsHandle::write(const void* data, size_t len) {
- return doAsync(const_cast<void*>(data), len, false);
+ return doAsync(const_cast<void*>(data), len, false, true);
}
int MtpFfsHandle::handleEvent() {
@@ -570,7 +588,8 @@
if (TEMP_FAILURE_RETRY(pread(mfr.fd, mIobuf[0].bufs.data() +
sizeof(mtp_data_header), init_read_len, offset))
!= init_read_len) return -1;
- if (write(mIobuf[0].bufs.data(), sizeof(mtp_data_header) + init_read_len) == -1)
+ if (doAsync(mIobuf[0].bufs.data(), sizeof(mtp_data_header) + init_read_len,
+ false, false /* zlps are handled below */) == -1)
return -1;
file_length -= init_read_len;
offset += init_read_len;
diff --git a/media/mtp/MtpFfsHandle.h b/media/mtp/MtpFfsHandle.h
index 24a8bd5..fe343f7 100644
--- a/media/mtp/MtpFfsHandle.h
+++ b/media/mtp/MtpFfsHandle.h
@@ -48,7 +48,7 @@
void closeEndpoints();
void advise(int fd);
int handleControlRequest(const struct usb_ctrlrequest *request);
- int doAsync(void* data, size_t len, bool read);
+ int doAsync(void* data, size_t len, bool read, bool zero_packet);
int handleEvent();
void cancelTransaction();
void doSendEvent(mtp_event me);
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 86d59dd..ccddd6e 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -809,7 +809,7 @@
uint64_t finalsize = sstat.st_size;
ALOGV("Sent a file over MTP. Time: %f s, Size: %" PRIu64 ", Rate: %f bytes/s",
diff.count(), finalsize, ((double) finalsize) / diff.count());
- close(mfr.fd);
+ closeObjFd(mfr.fd, filePath);
return result;
}
@@ -887,7 +887,7 @@
else
result = MTP_RESPONSE_GENERAL_ERROR;
}
- close(mfr.fd);
+ closeObjFd(mfr.fd, filePath);
return result;
}
@@ -1043,7 +1043,7 @@
if (info.mStorageID == storageID) {
ALOGV("Moving file from %s to %s", (const char*)fromPath, (const char*)path);
- if (rename(fromPath, path)) {
+ if (renameTo(fromPath, path)) {
PLOG(ERROR) << "rename() failed from " << fromPath << " to " << path;
result = MTP_RESPONSE_GENERAL_ERROR;
}
@@ -1226,7 +1226,7 @@
}
fstat(mfr.fd, &sstat);
- close(mfr.fd);
+ closeObjFd(mfr.fd, mSendObjectFilePath);
if (ret < 0) {
ALOGE("Mtp receive file got error %s", strerror(errno));
diff --git a/media/mtp/MtpUtils.cpp b/media/mtp/MtpUtils.cpp
index 51cfd7d..8564576 100644
--- a/media/mtp/MtpUtils.cpp
+++ b/media/mtp/MtpUtils.cpp
@@ -36,6 +36,13 @@
constexpr unsigned long FILE_COPY_SIZE = 262144;
+static void access_ok(const char *path) {
+ if (access(path, F_OK) == -1) {
+ // Ignore. Failure could be common in cases of delete where
+ // the metadata was updated through other paths.
+ }
+}
+
/*
DateTime strings follow a compatible subset of the definition found in ISO 8601, and
take the form of a Unicode string formatted as: "YYYYMMDDThhmmss.s". In this
@@ -101,6 +108,7 @@
} else {
chown((const char *)path, getuid(), FILE_GROUP);
}
+ access_ok(path);
return ret;
}
@@ -181,6 +189,7 @@
LOG(DEBUG) << "Copied a file with MTP. Time: " << diff.count() << " s, Size: " << length <<
", Rate: " << ((double) length) / diff.count() << " bytes/s";
chown(toPath, getuid(), FILE_GROUP);
+ access_ok(toPath);
return ret == -1 ? -1 : 0;
}
@@ -212,6 +221,7 @@
} else {
success = unlink(childPath.c_str());
}
+ access_ok(childPath.c_str());
if (success == -1)
PLOG(ERROR) << "Deleting path " << childPath << " failed";
}
@@ -236,7 +246,22 @@
}
if (success == -1)
PLOG(ERROR) << "Deleting path " << path << " failed";
+ access_ok(path);
return success == 0;
}
+int renameTo(const char *oldPath, const char *newPath) {
+ int ret = rename(oldPath, newPath);
+ access_ok(oldPath);
+ access_ok(newPath);
+ return ret;
+}
+
+// Calls access(2) on the path to update underlying filesystems,
+// then closes the fd.
+void closeObjFd(int fd, const char *path) {
+ close(fd);
+ access_ok(path);
+}
+
} // namespace android
diff --git a/media/mtp/MtpUtils.h b/media/mtp/MtpUtils.h
index 744546b..21f5df0 100644
--- a/media/mtp/MtpUtils.h
+++ b/media/mtp/MtpUtils.h
@@ -34,7 +34,9 @@
int copyRecursive(const char *fromPath, const char *toPath);
int copyFile(const char *fromPath, const char *toPath);
bool deletePath(const char* path);
+int renameTo(const char *oldPath, const char *newPath);
+void closeObjFd(int fd, const char *path);
}; // namespace android
#endif // _MTP_UTILS_H
diff --git a/media/mtp/tests/MtpFfsHandle_test.cpp b/media/mtp/tests/MtpFfsHandle_test.cpp
index d11fe07..c9c9e62 100644
--- a/media/mtp/tests/MtpFfsHandle_test.cpp
+++ b/media/mtp/tests/MtpFfsHandle_test.cpp
@@ -123,6 +123,21 @@
EXPECT_STREQ(buf, dummyDataStr.c_str());
}
+TYPED_TEST(MtpFfsHandleTest, testReadLarge) {
+ std::stringstream ss;
+ int size = TEST_PACKET_SIZE * MED_MULT;
+ char buf[size + 1];
+ buf[size] = '\0';
+
+ for (int i = 0; i < MED_MULT; i++)
+ ss << dummyDataStr;
+
+ EXPECT_EQ(write(this->bulk_out, ss.str().c_str(), size), size);
+ EXPECT_EQ(this->handle->read(buf, size), size);
+
+ EXPECT_STREQ(buf, ss.str().c_str());
+}
+
TYPED_TEST(MtpFfsHandleTest, testWrite) {
char buf[TEST_PACKET_SIZE + 1];
buf[TEST_PACKET_SIZE] = '\0';
@@ -131,6 +146,21 @@
EXPECT_STREQ(buf, dummyDataStr.c_str());
}
+TYPED_TEST(MtpFfsHandleTest, testWriteLarge) {
+ std::stringstream ss;
+ int size = TEST_PACKET_SIZE * MED_MULT;
+ char buf[size + 1];
+ buf[size] = '\0';
+
+ for (int i = 0; i < MED_MULT; i++)
+ ss << dummyDataStr;
+
+ EXPECT_EQ(this->handle->write(ss.str().c_str(), size), size);
+ EXPECT_EQ(read(this->bulk_in, buf, size), size);
+
+ EXPECT_STREQ(buf, ss.str().c_str());
+}
+
TYPED_TEST(MtpFfsHandleTest, testReceiveFileEmpty) {
std::stringstream ss;
mtp_file_range mfr;
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 76b29c9..bdd39c6 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1690,6 +1690,7 @@
recordTrack.clear();
AudioSystem::releaseInput(portId);
output.inputId = AUDIO_IO_HANDLE_NONE;
+ output.selectedDeviceId = input.selectedDeviceId;
portId = AUDIO_PORT_HANDLE_NONE;
}
lStatus = AudioSystem::getInputForAttr(&input.attr, &output.inputId,
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index dcf223c..2047dfd 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -595,7 +595,8 @@
(mConfig.inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO
|| mConfig.outputCfg.channels != AUDIO_CHANNEL_OUT_STEREO)) {
// Older effects may require exact STEREO position mask.
- if (mConfig.inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO) {
+ if (mConfig.inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO
+ && (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_AUXILIARY) {
ALOGV("Overriding effect input channels %#x as STEREO", mConfig.inputCfg.channels);
mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
}
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 923c091..4812b1f 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -245,6 +245,12 @@
virtual float getStreamVolumeDB(
audio_stream_type_t stream, int index, audio_devices_t device) = 0;
+ virtual status_t getSurroundFormats(unsigned int *numSurroundFormats,
+ audio_format_t *surroundFormats,
+ bool *surroundFormatsEnabled,
+ bool reported) = 0;
+ virtual status_t setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled) = 0;
+
virtual void setRecordSilenced(uid_t uid, bool silenced);
};
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index 83aec3b..23c020d 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -148,7 +148,8 @@
case AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND:
if (config != AUDIO_POLICY_FORCE_NONE &&
config != AUDIO_POLICY_FORCE_ENCODED_SURROUND_NEVER &&
- config != AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS) {
+ config != AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS &&
+ config != AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL) {
ALOGW("setForceUse() invalid config %d for ENCODED_SURROUND", config);
return BAD_VALUE;
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index d1d7530..1e5f9ae 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -60,6 +60,26 @@
// media / notification / system volume.
constexpr float IN_CALL_EARPIECE_HEADROOM_DB = 3.f;
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+// Array of all surround formats.
+static const audio_format_t SURROUND_FORMATS[] = {
+ AUDIO_FORMAT_AC3,
+ AUDIO_FORMAT_E_AC3,
+ AUDIO_FORMAT_DTS,
+ AUDIO_FORMAT_DTS_HD,
+ AUDIO_FORMAT_AAC_LC,
+ AUDIO_FORMAT_DOLBY_TRUEHD,
+ AUDIO_FORMAT_E_AC3_JOC,
+};
+// Array of all AAC formats. When AAC is enabled by users, all AAC formats should be enabled.
+static const audio_format_t AAC_FORMATS[] = {
+ AUDIO_FORMAT_AAC_LC,
+ AUDIO_FORMAT_AAC_HE_V1,
+ AUDIO_FORMAT_AAC_HE_V2,
+ AUDIO_FORMAT_AAC_ELD,
+ AUDIO_FORMAT_AAC_XHE,
+};
+
// ----------------------------------------------------------------------------
// AudioPolicyInterface implementation
// ----------------------------------------------------------------------------
@@ -348,6 +368,9 @@
const char *device_name)
{
status_t status;
+ String8 reply;
+ AudioParameter param;
+ int isReconfigA2dpSupported = 0;
ALOGV("handleDeviceConfigChange(() device: 0x%X, address %s name %s",
device, device_address, device_name);
@@ -364,6 +387,26 @@
return NO_ERROR;
}
+ // For offloaded A2DP, Hw modules may have the capability to
+ // configure codecs. Check if any of the loaded hw modules
+ // supports this.
+ // If supported, send a set parameter to configure A2DP codecs
+ // and return. No need to toggle device state.
+ if (device & AUDIO_DEVICE_OUT_ALL_A2DP) {
+ reply = mpClientInterface->getParameters(
+ AUDIO_IO_HANDLE_NONE,
+ String8(AudioParameter::keyReconfigA2dpSupported));
+ AudioParameter repliedParameters(reply);
+ repliedParameters.getInt(
+ String8(AudioParameter::keyReconfigA2dpSupported), isReconfigA2dpSupported);
+ if (isReconfigA2dpSupported) {
+ const String8 key(AudioParameter::keyReconfigA2dp);
+ param.add(key, String8("true"));
+ mpClientInterface->setParameters(AUDIO_IO_HANDLE_NONE, param.toString());
+ return NO_ERROR;
+ }
+ }
+
// Toggle the device state: UNAVAILABLE -> AVAILABLE
// This will force reading again the device configuration
status = setDeviceConnectionState(device,
@@ -2768,9 +2811,32 @@
return NO_ERROR;
}
-status_t AudioPolicyManager::getAudioPort(struct audio_port *port __unused)
+status_t AudioPolicyManager::getAudioPort(struct audio_port *port)
{
- return NO_ERROR;
+ if (port == nullptr || port->id == AUDIO_PORT_HANDLE_NONE) {
+ return BAD_VALUE;
+ }
+ sp<DeviceDescriptor> dev = mAvailableOutputDevices.getDeviceFromId(port->id);
+ if (dev != 0) {
+ dev->toAudioPort(port);
+ return NO_ERROR;
+ }
+ dev = mAvailableInputDevices.getDeviceFromId(port->id);
+ if (dev != 0) {
+ dev->toAudioPort(port);
+ return NO_ERROR;
+ }
+ sp<SwAudioOutputDescriptor> out = mOutputs.getOutputFromId(port->id);
+ if (out != 0) {
+ out->toAudioPort(port);
+ return NO_ERROR;
+ }
+ sp<AudioInputDescriptor> in = mInputs.getInputFromId(port->id);
+ if (in != 0) {
+ in->toAudioPort(port);
+ return NO_ERROR;
+ }
+ return BAD_VALUE;
}
status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch,
@@ -3461,6 +3527,275 @@
return computeVolume(stream, index, device);
}
+status_t AudioPolicyManager::getSupportedFormats(audio_io_handle_t ioHandle,
+ FormatVector& formats) {
+ if (ioHandle == AUDIO_IO_HANDLE_NONE) {
+ return BAD_VALUE;
+ }
+ String8 reply;
+ reply = mpClientInterface->getParameters(
+ ioHandle, String8(AudioParameter::keyStreamSupportedFormats));
+ ALOGV("%s: supported formats %s", __FUNCTION__, reply.string());
+ AudioParameter repliedParameters(reply);
+ if (repliedParameters.get(
+ String8(AudioParameter::keyStreamSupportedFormats), reply) != NO_ERROR) {
+ ALOGE("%s: failed to retrieve format, bailing out", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ for (auto format : formatsFromString(reply.string())) {
+ // Only AUDIO_FORMAT_AAC_LC will be used in Settings UI for all AAC formats.
+ for (size_t i = 0; i < ARRAY_SIZE(AAC_FORMATS); i++) {
+ if (format == AAC_FORMATS[i]) {
+ format = AUDIO_FORMAT_AAC_LC;
+ break;
+ }
+ }
+ bool exist = false;
+ for (size_t i = 0; i < formats.size(); i++) {
+ if (format == formats[i]) {
+ exist = true;
+ break;
+ }
+ }
+ bool isSurroundFormat = false;
+ for (size_t i = 0; i < ARRAY_SIZE(SURROUND_FORMATS); i++) {
+ if (SURROUND_FORMATS[i] == format) {
+ isSurroundFormat = true;
+ break;
+ }
+ }
+ if (!exist && isSurroundFormat) {
+ formats.add(format);
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManager::getSurroundFormats(unsigned int *numSurroundFormats,
+ audio_format_t *surroundFormats,
+ bool *surroundFormatsEnabled,
+ bool reported)
+{
+ if (numSurroundFormats == NULL || (*numSurroundFormats != 0 &&
+ (surroundFormats == NULL || surroundFormatsEnabled == NULL))) {
+ return BAD_VALUE;
+ }
+ ALOGV("getSurroundFormats() numSurroundFormats %d surroundFormats %p surroundFormatsEnabled %p",
+ *numSurroundFormats, surroundFormats, surroundFormatsEnabled);
+
+ // Only return value if there is HDMI output.
+ if ((mAvailableOutputDevices.types() & AUDIO_DEVICE_OUT_HDMI) == 0) {
+ return INVALID_OPERATION;
+ }
+
+ size_t formatsWritten = 0;
+ size_t formatsMax = *numSurroundFormats;
+ *numSurroundFormats = 0;
+ FormatVector formats;
+ if (reported) {
+ // Only get surround formats which are reported by device.
+ // First list already open outputs that can be routed to this device
+ audio_devices_t device = AUDIO_DEVICE_OUT_HDMI;
+ SortedVector<audio_io_handle_t> outputs;
+ bool reportedFormatFound = false;
+ status_t status;
+ sp<SwAudioOutputDescriptor> desc;
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ desc = mOutputs.valueAt(i);
+ if (!desc->isDuplicated() && (desc->supportedDevices() & device)) {
+ outputs.add(mOutputs.keyAt(i));
+ }
+ }
+ // Open an output to query dynamic parameters.
+ DeviceVector hdmiOutputDevices = mAvailableOutputDevices.getDevicesFromType(
+ AUDIO_DEVICE_OUT_HDMI);
+ for (size_t i = 0; i < hdmiOutputDevices.size(); i++) {
+ String8 address = hdmiOutputDevices[i]->mAddress;
+ for (const auto& hwModule : mHwModules) {
+ for (size_t i = 0; i < hwModule->getOutputProfiles().size(); i++) {
+ sp<IOProfile> profile = hwModule->getOutputProfiles()[i];
+ if (profile->supportDevice(AUDIO_DEVICE_OUT_HDMI) &&
+ profile->supportDeviceAddress(address)) {
+ size_t j;
+ for (j = 0; j < outputs.size(); j++) {
+ desc = mOutputs.valueFor(outputs.itemAt(j));
+ if (!desc->isDuplicated() && desc->mProfile == profile) {
+ break;
+ }
+ }
+ if (j != outputs.size()) {
+ status = getSupportedFormats(outputs.itemAt(j), formats);
+ reportedFormatFound |= (status == NO_ERROR);
+ continue;
+ }
+
+ if (!profile->canOpenNewIo()) {
+ ALOGW("Max Output number %u already opened for this profile %s",
+ profile->maxOpenCount, profile->getTagName().c_str());
+ continue;
+ }
+
+ ALOGV("opening output for device %08x with params %s profile %p name %s",
+ device, address.string(), profile.get(), profile->getName().string());
+ desc = new SwAudioOutputDescriptor(profile, mpClientInterface);
+ audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
+ status_t status = desc->open(nullptr, device, address,
+ AUDIO_STREAM_DEFAULT, AUDIO_OUTPUT_FLAG_NONE,
+ &output);
+
+ if (status == NO_ERROR) {
+ status = getSupportedFormats(output, formats);
+ reportedFormatFound |= (status == NO_ERROR);
+ desc->close();
+ output = AUDIO_IO_HANDLE_NONE;
+ }
+ }
+ }
+ }
+ }
+
+ if (!reportedFormatFound) {
+ return UNKNOWN_ERROR;
+ }
+ } else {
+ for (size_t i = 0; i < ARRAY_SIZE(SURROUND_FORMATS); i++) {
+ formats.add(SURROUND_FORMATS[i]);
+ }
+ }
+ for (size_t i = 0; i < formats.size(); i++) {
+ if (formatsWritten < formatsMax) {
+ surroundFormats[formatsWritten] = formats[i];
+ bool formatEnabled = false;
+ if (formats[i] == AUDIO_FORMAT_AAC_LC) {
+ for (size_t j = 0; j < ARRAY_SIZE(AAC_FORMATS); j++) {
+ formatEnabled =
+ mSurroundFormats.find(AAC_FORMATS[i]) != mSurroundFormats.end();
+ break;
+ }
+ } else {
+ formatEnabled = mSurroundFormats.find(formats[i]) != mSurroundFormats.end();
+ }
+ surroundFormatsEnabled[formatsWritten++] = formatEnabled;
+ }
+ (*numSurroundFormats)++;
+ }
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManager::setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled)
+{
+ // Check if audio format is a surround formats.
+ bool isSurroundFormat = false;
+ for (size_t i = 0; i < ARRAY_SIZE(SURROUND_FORMATS); i++) {
+ if (audioFormat == SURROUND_FORMATS[i]) {
+ isSurroundFormat = true;
+ break;
+ }
+ }
+ if (!isSurroundFormat) {
+ return BAD_VALUE;
+ }
+
+ // Should only be called when MANUAL.
+ audio_policy_forced_cfg_t forceUse = mEngine->getForceUse(
+ AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND);
+ if (forceUse != AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL) {
+ return INVALID_OPERATION;
+ }
+
+ if ((mSurroundFormats.find(audioFormat) != mSurroundFormats.end() && enabled)
+ || (mSurroundFormats.find(audioFormat) == mSurroundFormats.end() && !enabled)) {
+ return NO_ERROR;
+ }
+
+ // The operation is valid only when there is HDMI output available.
+ if ((mAvailableOutputDevices.types() & AUDIO_DEVICE_OUT_HDMI) == 0) {
+ return INVALID_OPERATION;
+ }
+
+ if (enabled) {
+ if (audioFormat == AUDIO_FORMAT_AAC_LC) {
+ for (size_t i = 0; i < ARRAY_SIZE(AAC_FORMATS); i++) {
+ mSurroundFormats.insert(AAC_FORMATS[i]);
+ }
+ } else {
+ mSurroundFormats.insert(audioFormat);
+ }
+ } else {
+ if (audioFormat == AUDIO_FORMAT_AAC_LC) {
+ for (size_t i = 0; i < ARRAY_SIZE(AAC_FORMATS); i++) {
+ mSurroundFormats.erase(AAC_FORMATS[i]);
+ }
+ } else {
+ mSurroundFormats.erase(audioFormat);
+ }
+ }
+
+ sp<SwAudioOutputDescriptor> outputDesc;
+ bool profileUpdated = false;
+ DeviceVector hdmiOutputDevices = mAvailableOutputDevices.getDevicesFromType(
+ AUDIO_DEVICE_OUT_HDMI);
+ for (size_t i = 0; i < hdmiOutputDevices.size(); i++) {
+ // Simulate reconnection to update enabled surround sound formats.
+ String8 address = hdmiOutputDevices[i]->mAddress;
+ String8 name = hdmiOutputDevices[i]->getName();
+ status_t status = setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_HDMI,
+ AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ address.c_str(),
+ name.c_str());
+ if (status != NO_ERROR) {
+ continue;
+ }
+ status = setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_HDMI,
+ AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ address.c_str(),
+ name.c_str());
+ profileUpdated |= (status == NO_ERROR);
+ }
+ DeviceVector hdmiInputDevices = mAvailableInputDevices.getDevicesFromType(
+ AUDIO_DEVICE_IN_HDMI);
+ for (size_t i = 0; i < hdmiInputDevices.size(); i++) {
+ // Simulate reconnection to update enabled surround sound formats.
+ String8 address = hdmiInputDevices[i]->mAddress;
+ String8 name = hdmiInputDevices[i]->getName();
+ status_t status = setDeviceConnectionStateInt(AUDIO_DEVICE_IN_HDMI,
+ AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ address.c_str(),
+ name.c_str());
+ if (status != NO_ERROR) {
+ continue;
+ }
+ status = setDeviceConnectionStateInt(AUDIO_DEVICE_IN_HDMI,
+ AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ address.c_str(),
+ name.c_str());
+ profileUpdated |= (status == NO_ERROR);
+ }
+
+ // Undo the surround formats change due to no audio profiles updated.
+ if (!profileUpdated) {
+ if (enabled) {
+ if (audioFormat == AUDIO_FORMAT_AAC_LC) {
+ for (size_t i = 0; i < ARRAY_SIZE(AAC_FORMATS); i++) {
+ mSurroundFormats.erase(AAC_FORMATS[i]);
+ }
+ } else {
+ mSurroundFormats.erase(audioFormat);
+ }
+ } else {
+ if (audioFormat == AUDIO_FORMAT_AAC_LC) {
+ for (size_t i = 0; i < ARRAY_SIZE(AAC_FORMATS); i++) {
+ mSurroundFormats.insert(AAC_FORMATS[i]);
+ }
+ } else {
+ mSurroundFormats.insert(audioFormat);
+ }
+ }
+ }
+
+ return profileUpdated ? NO_ERROR : INVALID_OPERATION;
+}
+
void AudioPolicyManager::setRecordSilenced(uid_t uid, bool silenced)
{
ALOGV("AudioPolicyManager:setRecordSilenced(uid:%d, silenced:%d)", uid, silenced);
@@ -3834,6 +4169,7 @@
mInputs.clear();
mHwModules.clear();
mHwModulesAll.clear();
+ mSurroundFormats.clear();
}
status_t AudioPolicyManager::initCheck()
@@ -4382,14 +4718,23 @@
}
if (!vectorsEqual(srcOutputs,dstOutputs)) {
+ // get maximum latency of all source outputs to determine the minimum mute time guaranteeing
+ // audio from invalidated tracks will be rendered when unmuting
+ uint32_t maxLatency = 0;
+ for (audio_io_handle_t srcOut : srcOutputs) {
+ sp<SwAudioOutputDescriptor> desc = mPreviousOutputs.valueFor(srcOut);
+ if (desc != 0 && maxLatency < desc->latency()) {
+ maxLatency = desc->latency();
+ }
+ }
ALOGV("checkOutputForStrategy() strategy %d, moving from output %d to output %d",
strategy, srcOutputs[0], dstOutputs[0]);
// mute strategy while moving tracks from one output to another
for (audio_io_handle_t srcOut : srcOutputs) {
- sp<SwAudioOutputDescriptor> desc = mOutputs.valueFor(srcOut);
- if (isStrategyActive(desc, strategy)) {
+ sp<SwAudioOutputDescriptor> desc = mPreviousOutputs.valueFor(srcOut);
+ if (desc != 0 && isStrategyActive(desc, strategy)) {
setStrategyMute(strategy, true, desc);
- setStrategyMute(strategy, false, desc, MUTE_TIME_MS, newDevice);
+ setStrategyMute(strategy, false, desc, maxLatency * LATENCY_MUTE_FACTOR, newDevice);
}
sp<AudioSourceDescriptor> source =
getSourceForStrategyOnOutput(srcOut, strategy);
@@ -5581,81 +5926,110 @@
AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND);
ALOGD("%s: forced use = %d", __FUNCTION__, forceUse);
- // Analyze original support for various formats.
- bool supportsAC3 = false;
- bool supportsOtherSurround = false;
- bool supportsIEC61937 = false;
- for (ssize_t formatIndex = 0; formatIndex < (ssize_t)formats.size(); formatIndex++) {
- audio_format_t format = formats[formatIndex];
- switch (format) {
- case AUDIO_FORMAT_AC3:
- supportsAC3 = true;
- break;
- case AUDIO_FORMAT_E_AC3:
- case AUDIO_FORMAT_DTS:
- case AUDIO_FORMAT_DTS_HD:
- // If ALWAYS, remove all other surround formats here since we will add them later.
- if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS) {
- formats.removeAt(formatIndex);
- formatIndex--;
- }
- supportsOtherSurround = true;
- break;
- case AUDIO_FORMAT_IEC61937:
- supportsIEC61937 = true;
- break;
- default:
- break;
+ // If MANUAL, keep the supported surround sound formats as current enabled ones.
+ if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL) {
+ formats.clear();
+ for (auto it = mSurroundFormats.begin(); it != mSurroundFormats.end(); it++) {
+ formats.add(*it);
}
- }
+ // Always enable IEC61937 when in MANUAL mode.
+ formats.add(AUDIO_FORMAT_IEC61937);
+ } else { // NEVER, AUTO or ALWAYS
+ // Analyze original support for various formats.
+ bool supportsAC3 = false;
+ bool supportsOtherSurround = false;
+ bool supportsIEC61937 = false;
+ mSurroundFormats.clear();
+ for (ssize_t formatIndex = 0; formatIndex < (ssize_t)formats.size(); formatIndex++) {
+ audio_format_t format = formats[formatIndex];
+ switch (format) {
+ case AUDIO_FORMAT_AC3:
+ supportsAC3 = true;
+ break;
+ case AUDIO_FORMAT_E_AC3:
+ case AUDIO_FORMAT_DTS:
+ case AUDIO_FORMAT_DTS_HD:
+ // If ALWAYS, remove all other surround formats here
+ // since we will add them later.
+ if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS) {
+ formats.removeAt(formatIndex);
+ formatIndex--;
+ }
+ supportsOtherSurround = true;
+ break;
+ case AUDIO_FORMAT_IEC61937:
+ supportsIEC61937 = true;
+ break;
+ default:
+ break;
+ }
+ }
- // Modify formats based on surround preferences.
- // If NEVER, remove support for surround formats.
- if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_NEVER) {
- if (supportsAC3 || supportsOtherSurround || supportsIEC61937) {
- // Remove surround sound related formats.
- for (size_t formatIndex = 0; formatIndex < formats.size(); ) {
+ // Modify formats based on surround preferences.
+ // If NEVER, remove support for surround formats.
+ if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_NEVER) {
+ if (supportsAC3 || supportsOtherSurround || supportsIEC61937) {
+ // Remove surround sound related formats.
+ for (size_t formatIndex = 0; formatIndex < formats.size(); ) {
+ audio_format_t format = formats[formatIndex];
+ switch(format) {
+ case AUDIO_FORMAT_AC3:
+ case AUDIO_FORMAT_E_AC3:
+ case AUDIO_FORMAT_DTS:
+ case AUDIO_FORMAT_DTS_HD:
+ case AUDIO_FORMAT_IEC61937:
+ formats.removeAt(formatIndex);
+ break;
+ default:
+ formatIndex++; // keep it
+ break;
+ }
+ }
+ supportsAC3 = false;
+ supportsOtherSurround = false;
+ supportsIEC61937 = false;
+ }
+ } else { // AUTO or ALWAYS
+ // Most TVs support AC3 even if they do not report it in the EDID.
+ if ((alwaysForceAC3 || (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS))
+ && !supportsAC3) {
+ formats.add(AUDIO_FORMAT_AC3);
+ supportsAC3 = true;
+ }
+
+ // If ALWAYS, add support for raw surround formats if all are missing.
+ // This assumes that if any of these formats are reported by the HAL
+ // then the report is valid and should not be modified.
+ if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS) {
+ formats.add(AUDIO_FORMAT_E_AC3);
+ formats.add(AUDIO_FORMAT_DTS);
+ formats.add(AUDIO_FORMAT_DTS_HD);
+ supportsOtherSurround = true;
+ }
+
+ // Add support for IEC61937 if any raw surround supported.
+ // The HAL could do this but add it here, just in case.
+ if ((supportsAC3 || supportsOtherSurround) && !supportsIEC61937) {
+ formats.add(AUDIO_FORMAT_IEC61937);
+ supportsIEC61937 = true;
+ }
+
+ // Add reported surround sound formats to enabled surround formats.
+ for (size_t formatIndex = 0; formatIndex < formats.size(); formatIndex++) {
audio_format_t format = formats[formatIndex];
switch(format) {
case AUDIO_FORMAT_AC3:
case AUDIO_FORMAT_E_AC3:
case AUDIO_FORMAT_DTS:
case AUDIO_FORMAT_DTS_HD:
- case AUDIO_FORMAT_IEC61937:
- formats.removeAt(formatIndex);
- break;
+ case AUDIO_FORMAT_AAC_LC:
+ case AUDIO_FORMAT_DOLBY_TRUEHD:
+ case AUDIO_FORMAT_E_AC3_JOC:
+ mSurroundFormats.insert(format);
default:
- formatIndex++; // keep it
break;
}
}
- supportsAC3 = false;
- supportsOtherSurround = false;
- supportsIEC61937 = false;
- }
- } else { // AUTO or ALWAYS
- // Most TVs support AC3 even if they do not report it in the EDID.
- if ((alwaysForceAC3 || (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS))
- && !supportsAC3) {
- formats.add(AUDIO_FORMAT_AC3);
- supportsAC3 = true;
- }
-
- // If ALWAYS, add support for raw surround formats if all are missing.
- // This assumes that if any of these formats are reported by the HAL
- // then the report is valid and should not be modified.
- if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS) {
- formats.add(AUDIO_FORMAT_E_AC3);
- formats.add(AUDIO_FORMAT_DTS);
- formats.add(AUDIO_FORMAT_DTS_HD);
- supportsOtherSurround = true;
- }
-
- // Add support for IEC61937 if any raw surround supported.
- // The HAL could do this but add it here, just in case.
- if ((supportsAC3 || supportsOtherSurround) && !supportsIEC61937) {
- formats.add(AUDIO_FORMAT_IEC61937);
- supportsIEC61937 = true;
}
}
}
@@ -5677,8 +6051,9 @@
maskIndex++;
}
}
- // If ALWAYS, then make sure we at least support 5.1
- } else if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS) {
+ // If ALWAYS or MANUAL, then make sure we at least support 5.1
+ } else if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS
+ || forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL) {
bool supports5dot1 = false;
// Are there any channel masks that can be considered "surround"?
for (audio_channel_mask_t channelMask : channelMasks) {
@@ -5705,7 +6080,7 @@
if (profiles.hasDynamicFormat()) {
reply = mpClientInterface->getParameters(
ioHandle, String8(AudioParameter::keyStreamSupportedFormats));
- ALOGV("%s: supported formats %s", __FUNCTION__, reply.string());
+ ALOGV("%s: supported formats %d, %s", __FUNCTION__, ioHandle, reply.string());
AudioParameter repliedParameters(reply);
if (repliedParameters.get(
String8(AudioParameter::keyStreamSupportedFormats), reply) != NO_ERROR) {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 2b68882..b954714 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -18,6 +18,7 @@
#include <atomic>
#include <memory>
+#include <unordered_set>
#include <stdint.h>
#include <sys/types.h>
@@ -67,6 +68,10 @@
// is switched
#define MUTE_TIME_MS 2000
+// multiplication factor applied to output latency when calculating a safe mute delay when
+// invalidating tracks
+#define LATENCY_MUTE_FACTOR 4
+
#define NUM_TEST_OUTPUTS 5
#define NUM_VOL_CURVE_KNEES 2
@@ -233,6 +238,12 @@
virtual float getStreamVolumeDB(
audio_stream_type_t stream, int index, audio_devices_t device);
+ virtual status_t getSurroundFormats(unsigned int *numSurroundFormats,
+ audio_format_t *surroundFormats,
+ bool *surroundFormatsEnabled,
+ bool reported);
+ virtual status_t setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled);
+
// return the strategy corresponding to a given stream type
routing_strategy getStrategy(audio_stream_type_t stream) const;
@@ -592,11 +603,16 @@
// Audio Policy Engine Interface.
AudioPolicyManagerInterface *mEngine;
+
+ // Surround formats that are enabled.
+ std::unordered_set<audio_format_t> mSurroundFormats;
private:
// Add or remove AC3 DTS encodings based on user preferences.
void filterSurroundFormats(FormatVector *formatsPtr);
void filterSurroundChannelMasks(ChannelsVector *channelMasksPtr);
+ status_t getSupportedFormats(audio_io_handle_t ioHandle, FormatVector& formats);
+
// If any, resolve any "dynamic" fields of an Audio Profiles collection
void updateAudioProfiles(audio_devices_t device, audio_io_handle_t ioHandle,
AudioProfileVector &profiles);
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index f6d407f..66ac050 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -408,6 +408,7 @@
client->active = false;
client->isConcurrent = false;
client->isVirtualDevice = false; //TODO : update from APM->getInputForAttr()
+ client->deviceId = *selectedDeviceId;
mAudioRecordClients.add(*portId, client);
}
@@ -434,7 +435,8 @@
return rawbuffer;
}
-static std::string audioConcurrencyString(AudioPolicyInterface::concurrency_type__mask_t concurrency)
+static std::string audioConcurrencyString(
+ AudioPolicyInterface::concurrency_type__mask_t concurrency)
{
char buffer[64]; // oversized
if (concurrency & AudioPolicyInterface::API_INPUT_CONCURRENCY_ALL) {
@@ -450,6 +452,17 @@
return &buffer[1];
}
+std::string AudioPolicyService::getDeviceTypeStrForPortId(audio_port_handle_t portId) {
+ std::string typeStr;
+ struct audio_port port = {};
+ port.id = portId;
+ status_t status = mAudioPolicyManager->getAudioPort(&port);
+ if (status == NO_ERROR && port.type == AUDIO_PORT_TYPE_DEVICE) {
+ deviceToString(port.ext.device.type, typeStr);
+ }
+ return typeStr;
+}
+
status_t AudioPolicyService::startInput(audio_port_handle_t portId, bool *silenced)
{
if (mAudioPolicyManager == NULL) {
@@ -498,9 +511,14 @@
static constexpr char kAudioPolicyRqstSrc[] = "android.media.audiopolicy.rqst.src";
static constexpr char kAudioPolicyRqstPkg[] = "android.media.audiopolicy.rqst.pkg";
static constexpr char kAudioPolicyRqstSession[] = "android.media.audiopolicy.rqst.session";
+ static constexpr char kAudioPolicyRqstDevice[] =
+ "android.media.audiopolicy.rqst.device";
static constexpr char kAudioPolicyActiveSrc[] = "android.media.audiopolicy.active.src";
static constexpr char kAudioPolicyActivePkg[] = "android.media.audiopolicy.active.pkg";
- static constexpr char kAudioPolicyActiveSession[] = "android.media.audiopolicy.active.session";
+ static constexpr char kAudioPolicyActiveSession[] =
+ "android.media.audiopolicy.active.session";
+ static constexpr char kAudioPolicyActiveDevice[] =
+ "android.media.audiopolicy.active.device";
MediaAnalyticsItem *item = new MediaAnalyticsItem(kAudioPolicy);
if (item != NULL) {
@@ -508,10 +526,15 @@
item->setCString(kAudioPolicyReason, audioConcurrencyString(concurrency).c_str());
item->setInt32(kAudioPolicyStatus, status);
- item->setCString(kAudioPolicyRqstSrc, audioSourceString(client->attributes.source).c_str());
- item->setCString(kAudioPolicyRqstPkg, std::string(String8(client->opPackageName).string()).c_str());
+ item->setCString(kAudioPolicyRqstSrc,
+ audioSourceString(client->attributes.source).c_str());
+ item->setCString(kAudioPolicyRqstPkg,
+ std::string(String8(client->opPackageName).string()).c_str());
item->setInt32(kAudioPolicyRqstSession, client->session);
+ item->setCString(
+ kAudioPolicyRqstDevice, getDeviceTypeStrForPortId(client->deviceId).c_str());
+
// figure out who is active
// NB: might the other party have given up the microphone since then? how sure.
// perhaps could have given up on it.
@@ -527,8 +550,11 @@
// keeps the last of the clients marked active
item->setCString(kAudioPolicyActiveSrc,
audioSourceString(other->attributes.source).c_str());
- item->setCString(kAudioPolicyActivePkg, std::string(String8(other->opPackageName).string()).c_str());
+ item->setCString(kAudioPolicyActivePkg,
+ std::string(String8(other->opPackageName).string()).c_str());
item->setInt32(kAudioPolicyActiveSession, other->session);
+ item->setCString(kAudioPolicyActiveDevice,
+ getDeviceTypeStrForPortId(other->deviceId).c_str());
}
}
}
@@ -986,5 +1012,28 @@
return mAudioPolicyManager->getStreamVolumeDB(stream, index, device);
}
+status_t AudioPolicyService::getSurroundFormats(unsigned int *numSurroundFormats,
+ audio_format_t *surroundFormats,
+ bool *surroundFormatsEnabled,
+ bool reported)
+{
+ if (mAudioPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ Mutex::Autolock _l(mLock);
+ AutoCallerClear acc;
+ return mAudioPolicyManager->getSurroundFormats(numSurroundFormats, surroundFormats,
+ surroundFormatsEnabled, reported);
+}
+
+status_t AudioPolicyService::setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled)
+{
+ if (mAudioPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ Mutex::Autolock _l(mLock);
+ AutoCallerClear acc;
+ return mAudioPolicyManager->setSurroundFormatEnabled(audioFormat, enabled);
+}
} // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index d8dd797..407d7a5 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -203,6 +203,12 @@
virtual float getStreamVolumeDB(
audio_stream_type_t stream, int index, audio_devices_t device);
+ virtual status_t getSurroundFormats(unsigned int *numSurroundFormats,
+ audio_format_t *surroundFormats,
+ bool *surroundFormatsEnabled,
+ bool reported);
+ virtual status_t setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled);
+
status_t doStopOutput(audio_io_handle_t output,
audio_stream_type_t stream,
audio_session_t session);
@@ -257,6 +263,8 @@
// Prints the shell command help
status_t printHelp(int out);
+ std::string getDeviceTypeStrForPortId(audio_port_handle_t portId);
+
// If recording we need to make sure the UID is allowed to do that. If the UID is idle
// then it cannot record and gets buffers with zeros - silence. As soon as the UID
// transitions to an active state we will start reporting buffers with data. This approach
@@ -637,7 +645,8 @@
const audio_session_t session; // audio session ID
bool active; // Capture is active or inactive
bool isConcurrent; // is allowed to concurrent capture
- bool isVirtualDevice; // uses vitual device: updated by APM::getInputForAttr()
+ bool isVirtualDevice; // uses virtual device: updated by APM::getInputForAttr()
+ audio_port_handle_t deviceId; // selected input device port ID
};
// A class automatically clearing and restoring binder caller identity inside
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 6b958a8..9acbf0a 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -4045,6 +4045,7 @@
mRepeatingLastFrameNumber(
hardware::camera2::ICameraDeviceUser::NO_IN_FLIGHT_REPEATING_FRAMES),
mPrepareVideoStream(false),
+ mConstrainedMode(false),
mRequestLatency(kRequestLatencyBinSize),
mSessionParamKeys(sessionParamKeys),
mLatestSessionParams(sessionParamKeys.size()) {
@@ -4068,6 +4069,7 @@
mLatestSessionParams = sessionParams;
// Prepare video stream for high speed recording.
mPrepareVideoStream = isConstrainedHighSpeed;
+ mConstrainedMode = isConstrainedHighSpeed;
}
status_t Camera3Device::RequestThread::queueRequestList(
@@ -4482,6 +4484,17 @@
return maxExpectedDuration;
}
+bool Camera3Device::RequestThread::skipHFRTargetFPSUpdate(int32_t tag,
+ const camera_metadata_ro_entry_t& newEntry, const camera_metadata_entry_t& currentEntry) {
+ if (mConstrainedMode && (ANDROID_CONTROL_AE_TARGET_FPS_RANGE == tag) &&
+ (newEntry.count == currentEntry.count) && (currentEntry.count == 2) &&
+ (currentEntry.data.i32[1] == newEntry.data.i32[1])) {
+ return true;
+ }
+
+ return false;
+}
+
bool Camera3Device::RequestThread::updateSessionParameters(const CameraMetadata& settings) {
ATRACE_CALL();
bool updatesDetected = false;
@@ -4514,8 +4527,10 @@
if (isDifferent) {
ALOGV("%s: Session parameter tag id %d changed", __FUNCTION__, tag);
+ if (!skipHFRTargetFPSUpdate(tag, entry, lastEntry)) {
+ updatesDetected = true;
+ }
mLatestSessionParams.update(entry);
- updatesDetected = true;
}
} else if (lastEntry.count > 0) {
// Value has been removed
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 13b83ba..5372407 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -861,6 +861,11 @@
// Check and update latest session parameters based on the current request settings.
bool updateSessionParameters(const CameraMetadata& settings);
+ // Check whether FPS range session parameter re-configuration is needed in constrained
+ // high speed recording camera sessions.
+ bool skipHFRTargetFPSUpdate(int32_t tag, const camera_metadata_ro_entry_t& newEntry,
+ const camera_metadata_entry_t& currentEntry);
+
// Re-configure camera using the latest session parameters.
bool reconfigureCamera();
@@ -919,6 +924,8 @@
// Flag indicating if we should prepare video stream for video requests.
bool mPrepareVideoStream;
+ bool mConstrainedMode;
+
static const int32_t kRequestLatencyBinSize = 40; // in ms
CameraLatencyHistogram mRequestLatency;
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index 5675b0b..6a72e5b 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -144,15 +144,14 @@
// If a close request is pending then close the stream
bool AAudioService::releaseStream(const sp<AAudioServiceStreamBase> &serviceStream) {
bool closed = false;
- if ((serviceStream->decrementServiceReferenceCount() == 0) && serviceStream->isCloseNeeded()) {
- // removeStreamByHandle() uses a lock so that if there are two simultaneous closes
- // then only one will get the pointer and do the close.
- sp<AAudioServiceStreamBase> foundStream = mStreamTracker.removeStreamByHandle(serviceStream->getHandle());
- if (foundStream.get() != nullptr) {
- foundStream->close();
- pid_t pid = foundStream->getOwnerProcessId();
- AAudioClientTracker::getInstance().unregisterClientStream(pid, foundStream);
- }
+ // decrementAndRemoveStreamByHandle() uses a lock so that if there are two simultaneous closes
+ // then only one will get the pointer and do the close.
+ sp<AAudioServiceStreamBase> foundStream = mStreamTracker.decrementAndRemoveStreamByHandle(
+ serviceStream->getHandle());
+ if (foundStream.get() != nullptr) {
+ foundStream->close();
+ pid_t pid = foundStream->getOwnerProcessId();
+ AAudioClientTracker::getInstance().unregisterClientStream(pid, foundStream);
closed = true;
}
return closed;
@@ -175,14 +174,15 @@
pid_t pid = serviceStream->getOwnerProcessId();
AAudioClientTracker::getInstance().unregisterClientStream(pid, serviceStream);
- serviceStream->setCloseNeeded(true);
+ serviceStream->markCloseNeeded();
(void) releaseStream(serviceStream);
return AAUDIO_OK;
}
sp<AAudioServiceStreamBase> AAudioService::convertHandleToServiceStream(
aaudio_handle_t streamHandle) {
- sp<AAudioServiceStreamBase> serviceStream = mStreamTracker.getStreamByHandle(streamHandle);
+ sp<AAudioServiceStreamBase> serviceStream = mStreamTracker.getStreamByHandleAndIncrement(
+ streamHandle);
if (serviceStream.get() != nullptr) {
// Only allow owner or the aaudio service to access the stream.
const uid_t callingUserId = IPCThreadState::self()->getCallingUid();
@@ -194,9 +194,9 @@
if (!allowed) {
ALOGE("AAudioService: calling uid %d cannot access stream 0x%08X owned by %d",
callingUserId, streamHandle, ownerUserId);
+ // We incremented the reference count so we must check if it needs to be closed.
+ checkForPendingClose(serviceStream, AAUDIO_OK);
serviceStream.clear();
- } else {
- serviceStream->incrementServiceReferenceCount();
}
}
return serviceStream;
@@ -328,12 +328,11 @@
aaudio_result_t AAudioService::disconnectStreamByPortHandle(audio_port_handle_t portHandle) {
ALOGD("%s(%d) called", __func__, portHandle);
sp<AAudioServiceStreamBase> serviceStream =
- mStreamTracker.findStreamByPortHandle(portHandle);
+ mStreamTracker.findStreamByPortHandleAndIncrement(portHandle);
if (serviceStream.get() == nullptr) {
ALOGE("%s(), could not find stream with portHandle = %d", __func__, portHandle);
return AAUDIO_ERROR_INVALID_HANDLE;
}
- serviceStream->incrementServiceReferenceCount();
aaudio_result_t result = serviceStream->stop();
serviceStream->disconnect();
return checkForPendingClose(serviceStream, result);
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index 48d8002..9af8af3 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -414,12 +414,13 @@
sendServiceEvent(AAUDIO_SERVICE_EVENT_VOLUME, volume);
}
-int32_t AAudioServiceStreamBase::incrementServiceReferenceCount() {
- std::lock_guard<std::mutex> lock(mCallingCountLock);
+int32_t AAudioServiceStreamBase::incrementServiceReferenceCount_l() {
return ++mCallingCount;
}
-int32_t AAudioServiceStreamBase::decrementServiceReferenceCount() {
- std::lock_guard<std::mutex> lock(mCallingCountLock);
- return --mCallingCount;
+int32_t AAudioServiceStreamBase::decrementServiceReferenceCount_l() {
+ int32_t count = --mCallingCount;
+ // Each call to increment should be balanced with one call to decrement.
+ assert(count >= 0);
+ return count;
}
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index 0ad015e..a1815d0 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -205,22 +205,33 @@
/**
* Atomically increment the number of active references to the stream by AAudioService.
+ *
+ * This is called under a global lock in AAudioStreamTracker.
+ *
* @return value after the increment
*/
- int32_t incrementServiceReferenceCount();
+ int32_t incrementServiceReferenceCount_l();
/**
* Atomically decrement the number of active references to the stream by AAudioService.
+ * This should only be called after incrementServiceReferenceCount_l().
+ *
+ * This is called under a global lock in AAudioStreamTracker.
+ *
* @return value after the decrement
*/
- int32_t decrementServiceReferenceCount();
+ int32_t decrementServiceReferenceCount_l();
bool isCloseNeeded() const {
return mCloseNeeded.load();
}
- void setCloseNeeded(bool needed) {
- mCloseNeeded.store(needed);
+ /**
+ * Mark this stream as needing to be closed.
+ * Once marked for closing, it cannot be unmarked.
+ */
+ void markCloseNeeded() {
+ mCloseNeeded.store(true);
}
virtual const char *getTypeText() const { return "Base"; }
@@ -290,8 +301,9 @@
aaudio_handle_t mHandle = -1;
bool mFlowing = false;
- std::mutex mCallingCountLock;
- std::atomic<int32_t> mCallingCount{0};
+ // This is modified under a global lock in AAudioStreamTracker.
+ int32_t mCallingCount = 0;
+
std::atomic<bool> mCloseNeeded{false};
};
diff --git a/services/oboeservice/AAudioStreamTracker.cpp b/services/oboeservice/AAudioStreamTracker.cpp
index 9d5d8fc..3328159 100644
--- a/services/oboeservice/AAudioStreamTracker.cpp
+++ b/services/oboeservice/AAudioStreamTracker.cpp
@@ -30,34 +30,40 @@
using namespace android;
using namespace aaudio;
-sp<AAudioServiceStreamBase> AAudioStreamTracker::removeStreamByHandle(
+sp<AAudioServiceStreamBase> AAudioStreamTracker::decrementAndRemoveStreamByHandle(
+ aaudio_handle_t streamHandle) {
+ std::lock_guard<std::mutex> lock(mHandleLock);
+ sp<AAudioServiceStreamBase> serviceStream;
+ auto it = mStreamsByHandle.find(streamHandle);
+ if (it != mStreamsByHandle.end()) {
+ sp<AAudioServiceStreamBase> tempStream = it->second;
+ // Does the caller need to close the stream?
+ // The reference count should never be negative.
+ // But it is safer to check for <= 0 than == 0.
+ if ((tempStream->decrementServiceReferenceCount_l() <= 0) && tempStream->isCloseNeeded()) {
+ serviceStream = tempStream; // Only return stream if ready to be closed.
+ mStreamsByHandle.erase(it);
+ }
+ }
+ return serviceStream;
+}
+
+sp<AAudioServiceStreamBase> AAudioStreamTracker::getStreamByHandleAndIncrement(
aaudio_handle_t streamHandle) {
std::lock_guard<std::mutex> lock(mHandleLock);
sp<AAudioServiceStreamBase> serviceStream;
auto it = mStreamsByHandle.find(streamHandle);
if (it != mStreamsByHandle.end()) {
serviceStream = it->second;
- mStreamsByHandle.erase(it);
+ serviceStream->incrementServiceReferenceCount_l();
}
return serviceStream;
}
-sp<AAudioServiceStreamBase> AAudioStreamTracker::getStreamByHandle(
- aaudio_handle_t streamHandle) {
- std::lock_guard<std::mutex> lock(mHandleLock);
- sp<AAudioServiceStreamBase> serviceStream;
- auto it = mStreamsByHandle.find(streamHandle);
- if (it != mStreamsByHandle.end()) {
- serviceStream = it->second;
- }
- return serviceStream;
-}
-
-
// The port handle is only available when the stream is started.
// So we have to iterate over all the streams.
// Luckily this rarely happens.
-sp<AAudioServiceStreamBase> AAudioStreamTracker::findStreamByPortHandle(
+sp<AAudioServiceStreamBase> AAudioStreamTracker::findStreamByPortHandleAndIncrement(
audio_port_handle_t portHandle) {
std::lock_guard<std::mutex> lock(mHandleLock);
sp<AAudioServiceStreamBase> serviceStream;
@@ -66,6 +72,7 @@
auto candidate = it->second;
if (candidate->getPortHandle() == portHandle) {
serviceStream = candidate;
+ serviceStream->incrementServiceReferenceCount_l();
break;
}
it++;
@@ -86,7 +93,7 @@
aaudio_handle_t AAudioStreamTracker::addStreamForHandle(sp<AAudioServiceStreamBase> serviceStream) {
std::lock_guard<std::mutex> lock(mHandleLock);
- aaudio_handle_t handle = mPreviousHandle.load();
+ aaudio_handle_t handle = mPreviousHandle;
// Assign a unique handle.
while (true) {
handle = bumpHandle(handle);
@@ -98,7 +105,7 @@
break;
}
}
- mPreviousHandle.store(handle);
+ mPreviousHandle = handle;
return handle;
}
diff --git a/services/oboeservice/AAudioStreamTracker.h b/services/oboeservice/AAudioStreamTracker.h
index 54e46ca..57ec426 100644
--- a/services/oboeservice/AAudioStreamTracker.h
+++ b/services/oboeservice/AAudioStreamTracker.h
@@ -32,25 +32,35 @@
public:
/**
- * Remove the stream associated with the handle.
+ * Find the stream associated with the handle.
+ * Decrement its reference counter. If zero and the stream needs
+ * to be closed then remove the stream and return a pointer to the stream.
+ * Otherwise return null if it does not need to be closed.
+ *
* @param streamHandle
- * @return strong pointer to the stream if found or to nullptr
+ * @return strong pointer to the stream if it needs to be closed, or nullptr
*/
- android::sp<AAudioServiceStreamBase> removeStreamByHandle(aaudio_handle_t streamHandle);
+ android::sp<AAudioServiceStreamBase> decrementAndRemoveStreamByHandle(
+ aaudio_handle_t streamHandle);
/**
* Look up a stream based on the handle.
+ * Increment its service reference count if found.
+ *
* @param streamHandle
- * @return strong pointer to the stream if found or to nullptr
+ * @return strong pointer to the stream if found, or nullptr
*/
- android::sp<aaudio::AAudioServiceStreamBase> getStreamByHandle(aaudio_handle_t streamHandle);
+ android::sp<aaudio::AAudioServiceStreamBase> getStreamByHandleAndIncrement(
+ aaudio_handle_t streamHandle);
/**
* Look up a stream based on the AudioPolicy portHandle.
+ * Increment its service reference count if found.
+ *
* @param portHandle
- * @return strong pointer to the stream if found or to nullptr
+ * @return strong pointer to the stream if found, or nullptr
*/
- android::sp<aaudio::AAudioServiceStreamBase> findStreamByPortHandle(
+ android::sp<aaudio::AAudioServiceStreamBase> findStreamByPortHandleAndIncrement(
audio_port_handle_t portHandle);
/**
@@ -71,7 +81,9 @@
// Track stream using a unique handle that wraps. Only use positive half.
mutable std::mutex mHandleLock;
- std::atomic<aaudio_handle_t> mPreviousHandle{0};
+ // protected by mHandleLock
+ aaudio_handle_t mPreviousHandle = 0;
+ // protected by mHandleLock
std::map<aaudio_handle_t, android::sp<aaudio::AAudioServiceStreamBase>> mStreamsByHandle;
};