Merge "stagefright/foundation: add copy and move constructor/assignment to AData" 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/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/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/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 7931176..ee16e07 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
// ----------------------------------------------------------------------------
@@ -3461,6 +3481,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 +4123,7 @@
mInputs.clear();
mHwModules.clear();
mHwModulesAll.clear();
+ mSurroundFormats.clear();
}
status_t AudioPolicyManager::initCheck()
@@ -5590,81 +5880,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;
}
}
}
@@ -5686,8 +6005,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) {
@@ -5714,7 +6034,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 0df52da..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>
@@ -237,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;
@@ -596,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..9592b6a 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -986,5 +986,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..3e179c0 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);
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;
};