Merge changes Iae3d6f9d,I79e25d27 into pi-dev am: da74fce85a
am: 6fddec7de7
Change-Id: I1e076640ba2d4d3cc4559b8e710750d5f8c9506d
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 61fc897..2c088e6 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -579,12 +579,12 @@
break;
}
+ CHECK(buffer != NULL);
+
if (buffer->range_length() > 0) {
break;
}
- CHECK(buffer != NULL);
-
buffer->release();
buffer = NULL;
}
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index ca119d5..5f19f74 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -538,6 +538,10 @@
mTimestampMutator.push(timestamp);
}
+ virtual ExtendedTimestamp getTimestamp() const {
+ return mTimestampMutator.last();
+ }
+
// Flushes the shared ring buffer if the client had requested it using mStreaming.mFlush.
// If flush occurs then:
// cblk->u.mStreaming.mFront, ServerProxy::mFlush and ServerProxy::mFlushed will be modified
@@ -551,6 +555,9 @@
// Total count of the number of flushed frames since creation (never reset).
virtual int64_t framesFlushed() const { return mFlushed; }
+ // Safe frames ready query with no side effects.
+ virtual size_t framesReadySafe() const = 0;
+
// Get dynamic buffer size from the shared control block.
uint32_t getBufferSizeInFrames() const {
return android_atomic_acquire_load((int32_t *)&mCblk->mBufferSizeInFrames);
@@ -588,8 +595,7 @@
// which may include non-contiguous frames
virtual size_t framesReady();
- // Safe frames ready query used by dump() - this has no side effects.
- virtual size_t framesReadySafe() const;
+ size_t framesReadySafe() const override; // frames available to read by server.
// Currently AudioFlinger will call framesReady() for a fast track from two threads:
// FastMixer thread, and normal mixer thread. This is dangerous, as the proxy is intended
@@ -693,6 +699,8 @@
return mCblk->u.mStreaming.mRear; // For completeness only; mRear written by server.
}
+ size_t framesReadySafe() const override; // frames available to read by client.
+
protected:
virtual ~AudioRecordServerProxy() { }
};
diff --git a/media/OWNERS b/media/OWNERS
index 1f687a2..1e2d123 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -2,8 +2,10 @@
dwkang@google.com
elaurent@google.com
essick@google.com
+gkasten@google.com
hkuang@google.com
hunga@google.com
+jiabin@google.com
jmtrivi@google.com
krocard@google.com
lajos@google.com
diff --git a/media/audioserver/audioserver.rc b/media/audioserver/audioserver.rc
index 1f2e82f..f1e815b 100644
--- a/media/audioserver/audioserver.rc
+++ b/media/audioserver/audioserver.rc
@@ -7,6 +7,7 @@
ioprio rt 4
writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
onrestart restart vendor.audio-hal-2-0
+ onrestart restart vendor.audio-hal-4-0-msd
# Keep the original service name for backward compatibility when upgrading
# O-MR1 devices with framework-only.
onrestart restart audio-hal-2-0
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 2df37a8..6146c0e 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -49,6 +49,7 @@
"libaudiomanager",
"libmedia_helper",
"libmediametrics",
+ "libmediautils",
],
export_shared_lib_headers: ["libbinder"],
diff --git a/media/libaudioclient/AudioTrackShared.cpp b/media/libaudioclient/AudioTrackShared.cpp
index dced3c4..a018b22 100644
--- a/media/libaudioclient/AudioTrackShared.cpp
+++ b/media/libaudioclient/AudioTrackShared.cpp
@@ -1231,6 +1231,21 @@
return 0;
}
+__attribute__((no_sanitize("integer")))
+size_t AudioRecordServerProxy::framesReadySafe() const
+{
+ if (mIsShutdown) {
+ return 0;
+ }
+ const int32_t front = android_atomic_acquire_load(&mCblk->u.mStreaming.mFront);
+ const int32_t rear = mCblk->u.mStreaming.mRear;
+ const ssize_t filled = rear - front;
+ if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
+ return 0; // error condition, silently return 0.
+ }
+ return filled;
+}
+
// ---------------------------------------------------------------------------
} // namespace android
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 00af7e8..37c62a8 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -24,10 +24,8 @@
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
-#include <cutils/multiuser.h>
#include <media/TimeCheck.h>
-#include <private/android_filesystem_config.h>
-
+#include <mediautils/ServiceUtilities.h>
#include "IAudioFlinger.h"
namespace android {
@@ -912,7 +910,7 @@
case SET_MIC_MUTE:
case SET_LOW_RAM_DEVICE:
case SYSTEM_READY: {
- if (multiuser_get_app_id(IPCThreadState::self()->getCallingUid()) >= AID_APP_START) {
+ if (!isServiceUid(IPCThreadState::self()->getCallingUid())) {
ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
__func__, code, IPCThreadState::self()->getCallingPid(),
IPCThreadState::self()->getCallingUid());
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index a1236e7..316105c 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -24,11 +24,10 @@
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
-#include <cutils/multiuser.h>
#include <media/AudioEffect.h>
#include <media/IAudioPolicyService.h>
#include <media/TimeCheck.h>
-#include <private/android_filesystem_config.h>
+#include <mediautils/ServiceUtilities.h>
#include <system/audio.h>
namespace android {
@@ -936,7 +935,7 @@
case STOP_AUDIO_SOURCE:
case GET_SURROUND_FORMATS:
case SET_SURROUND_FORMAT_ENABLED: {
- if (multiuser_get_app_id(IPCThreadState::self()->getCallingUid()) >= AID_APP_START) {
+ if (!isServiceUid(IPCThreadState::self()->getCallingUid())) {
ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
__func__, code, IPCThreadState::self()->getCallingPid(),
IPCThreadState::self()->getCallingUid());
diff --git a/media/libaudioclient/include/media/AudioParameter.h b/media/libaudioclient/include/media/AudioParameter.h
index 967d895..24837e3 100644
--- a/media/libaudioclient/include/media/AudioParameter.h
+++ b/media/libaudioclient/include/media/AudioParameter.h
@@ -64,6 +64,9 @@
static const char * const keyPresentationId;
static const char * const keyProgramId;
+ // keyAudioLanguagePreferred: Preferred audio language
+ static const char * const keyAudioLanguagePreferred;
+
// keyStreamConnect / Disconnect: value is an int in audio_devices_t
static const char * const keyStreamConnect;
static const char * const keyStreamDisconnect;
diff --git a/media/libaudioclient/include/media/AudioTimestamp.h b/media/libaudioclient/include/media/AudioTimestamp.h
index 498de8e..e5925dd 100644
--- a/media/libaudioclient/include/media/AudioTimestamp.h
+++ b/media/libaudioclient/include/media/AudioTimestamp.h
@@ -135,8 +135,23 @@
return INVALID_OPERATION;
}
+ double getOutputServerLatencyMs(uint32_t sampleRate) const {
+ return getLatencyMs(sampleRate, LOCATION_SERVER, LOCATION_KERNEL);
+ }
+
+ double getLatencyMs(uint32_t sampleRate, Location location1, Location location2) const {
+ if (sampleRate > 0 && mTimeNs[location1] > 0 && mTimeNs[location2] > 0) {
+ const int64_t frameDifference =
+ mPosition[location1] - mPosition[location2];
+ const int64_t timeDifferenceNs =
+ mTimeNs[location1] - mTimeNs[location2];
+ return ((double)frameDifference * 1e9 / sampleRate - timeDifferenceNs) * 1e-6;
+ }
+ return 0.;
+ }
+
// convert fields to a printable string
- std::string toString() {
+ std::string toString() const {
std::stringstream ss;
ss << "BOOTTIME offset " << mTimebaseOffset[TIMEBASE_BOOTTIME] << "\n";
diff --git a/media/libaudiohal/2.0/DevicesFactoryHalHidl.cpp b/media/libaudiohal/2.0/DevicesFactoryHalHidl.cpp
index 5b33592..31da263 100644
--- a/media/libaudiohal/2.0/DevicesFactoryHalHidl.cpp
+++ b/media/libaudiohal/2.0/DevicesFactoryHalHidl.cpp
@@ -43,9 +43,6 @@
ALOGE("Failed to obtain IDevicesFactory service, terminating process.");
exit(1);
}
- // The MSD factory is optional
- mDevicesFactoryMsd = IDevicesFactory::getService(AUDIO_HAL_SERVICE_NAME_MSD);
- // TODO: Register death handler, and add 'restart' directive to audioserver.rc
}
DevicesFactoryHalHidl::~DevicesFactoryHalHidl() {
diff --git a/media/libaudiohal/2.0/DevicesFactoryHalHidl.h b/media/libaudiohal/2.0/DevicesFactoryHalHidl.h
index 0748849..e2f1ad1 100644
--- a/media/libaudiohal/2.0/DevicesFactoryHalHidl.h
+++ b/media/libaudiohal/2.0/DevicesFactoryHalHidl.h
@@ -39,7 +39,6 @@
friend class DevicesFactoryHalHybrid;
sp<IDevicesFactory> mDevicesFactory;
- sp<IDevicesFactory> mDevicesFactoryMsd;
static status_t nameFromHal(const char *name, IDevicesFactory::Device *device);
diff --git a/media/libaudiohal/4.0/DevicesFactoryHalHidl.cpp b/media/libaudiohal/4.0/DevicesFactoryHalHidl.cpp
index c83194e..c566728 100644
--- a/media/libaudiohal/4.0/DevicesFactoryHalHidl.cpp
+++ b/media/libaudiohal/4.0/DevicesFactoryHalHidl.cpp
@@ -15,6 +15,7 @@
*/
#include <string.h>
+#include <vector>
#define LOG_TAG "DevicesFactoryHalHidl"
//#define LOG_NDEBUG 0
@@ -35,40 +36,48 @@
namespace V4_0 {
DevicesFactoryHalHidl::DevicesFactoryHalHidl() {
- mDevicesFactory = IDevicesFactory::getService();
- if (mDevicesFactory != 0) {
- // It is assumed that DevicesFactory is owned by AudioFlinger
- // and thus have the same lifespan.
- mDevicesFactory->linkToDeath(HalDeathHandler::getInstance(), 0 /*cookie*/);
- } else {
- ALOGE("Failed to obtain IDevicesFactory service, terminating process.");
+ sp<IDevicesFactory> defaultFactory{IDevicesFactory::getService()};
+ if (!defaultFactory) {
+ ALOGE("Failed to obtain IDevicesFactory/default service, terminating process.");
exit(1);
}
+ mDeviceFactories.push_back(defaultFactory);
// The MSD factory is optional
- mDevicesFactoryMsd = IDevicesFactory::getService(AUDIO_HAL_SERVICE_NAME_MSD);
- // TODO: Register death handler, and add 'restart' directive to audioserver.rc
-}
-
-DevicesFactoryHalHidl::~DevicesFactoryHalHidl() {
+ sp<IDevicesFactory> msdFactory{IDevicesFactory::getService(AUDIO_HAL_SERVICE_NAME_MSD)};
+ if (msdFactory) {
+ mDeviceFactories.push_back(msdFactory);
+ }
+ for (const auto& factory : mDeviceFactories) {
+ // It is assumed that the DevicesFactoryHalInterface instance is owned
+ // by AudioFlinger and thus have the same lifespan.
+ factory->linkToDeath(HalDeathHandler::getInstance(), 0 /*cookie*/);
+ }
}
status_t DevicesFactoryHalHidl::openDevice(const char *name, sp<DeviceHalInterface> *device) {
- if (mDevicesFactory == 0) return NO_INIT;
+ if (mDeviceFactories.empty()) return NO_INIT;
Result retval = Result::NOT_INITIALIZED;
- Return<void> ret = mDevicesFactory->openDevice(
- name,
- [&](Result r, const sp<IDevice>& result) {
- retval = r;
- if (retval == Result::OK) {
- *device = new DeviceHalHidl(result);
- }
- });
- if (ret.isOk()) {
- if (retval == Result::OK) return OK;
- else if (retval == Result::INVALID_ARGUMENTS) return BAD_VALUE;
- else return NO_INIT;
+ for (const auto& factory : mDeviceFactories) {
+ Return<void> ret = factory->openDevice(
+ name,
+ [&](Result r, const sp<IDevice>& result) {
+ retval = r;
+ if (retval == Result::OK) {
+ *device = new DeviceHalHidl(result);
+ }
+ });
+ if (!ret.isOk()) return FAILED_TRANSACTION;
+ switch (retval) {
+ // Device was found and was initialized successfully.
+ case Result::OK: return OK;
+ // Device was found but failed to initalize.
+ case Result::NOT_INITIALIZED: return NO_INIT;
+ // Otherwise continue iterating.
+ default: ;
+ }
}
- return FAILED_TRANSACTION;
+ ALOGW("The specified device name is not recognized: \"%s\"", name);
+ return BAD_VALUE;
}
} // namespace V4_0
diff --git a/media/libaudiohal/4.0/DevicesFactoryHalHidl.h b/media/libaudiohal/4.0/DevicesFactoryHalHidl.h
index 114889b..c97178f 100644
--- a/media/libaudiohal/4.0/DevicesFactoryHalHidl.h
+++ b/media/libaudiohal/4.0/DevicesFactoryHalHidl.h
@@ -39,13 +39,12 @@
private:
friend class DevicesFactoryHalHybrid;
- sp<IDevicesFactory> mDevicesFactory;
- sp<IDevicesFactory> mDevicesFactoryMsd;
+ std::vector<sp<IDevicesFactory>> mDeviceFactories;
// Can not be constructed directly by clients.
DevicesFactoryHalHidl();
- virtual ~DevicesFactoryHalHidl();
+ virtual ~DevicesFactoryHalHidl() = default;
};
} // namespace V4_0
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 1b3a1be..a22819a 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -32,6 +32,9 @@
"libaudioclient_headers",
"libaudio_system_headers",
],
+ export_header_lib_headers: [
+ "libmedia_headers",
+ ],
clang: true,
}
diff --git a/media/libmedia/AudioParameter.cpp b/media/libmedia/AudioParameter.cpp
index 034f7c2..1c95e27 100644
--- a/media/libmedia/AudioParameter.cpp
+++ b/media/libmedia/AudioParameter.cpp
@@ -36,6 +36,8 @@
const char * const AudioParameter::keyHwAvSync = AUDIO_PARAMETER_HW_AV_SYNC;
const char * const AudioParameter::keyPresentationId = AUDIO_PARAMETER_STREAM_PRESENTATION_ID;
const char * const AudioParameter::keyProgramId = AUDIO_PARAMETER_STREAM_PROGRAM_ID;
+const char * const AudioParameter::keyAudioLanguagePreferred =
+ AUDIO_PARAMETER_KEY_AUDIO_LANGUAGE_PREFERRED;
const char * const AudioParameter::keyMonoOutput = AUDIO_PARAMETER_MONO_OUTPUT;
const char * const AudioParameter::keyStreamHwAvSync = AUDIO_PARAMETER_STREAM_HW_AV_SYNC;
const char * const AudioParameter::keyStreamConnect = AUDIO_PARAMETER_DEVICE_CONNECT;
diff --git a/media/libmedia/include/media/PatchBuilder.h b/media/libmedia/include/media/PatchBuilder.h
new file mode 100644
index 0000000..f2722a6
--- /dev/null
+++ b/media/libmedia/include/media/PatchBuilder.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_PATCH_BUILDER_H
+#define ANDROID_PATCH_BUILDER_H
+
+#include <functional>
+#include <utility>
+
+#include <system/audio.h>
+#include <utils/StrongPointer.h>
+
+// This is a header-only utility.
+
+namespace android {
+
+class PatchBuilder {
+ public:
+ using mix_usecase_t = decltype(audio_port_config_mix_ext::usecase);
+
+ PatchBuilder() = default;
+
+ // All existing methods operating on audio patches take a pointer to const.
+ // It's OK to construct a temporary PatchBuilder while preparing a parameter
+ // to such a function because the Builder will be kept alive until the code
+ // execution reaches the function call statement semicolon.
+ const struct audio_patch* patch() const { return &mPatch; }
+
+ template<typename T, typename... S>
+ PatchBuilder& addSink(T&& t, S&&... s) {
+ sinks().add(std::forward<T>(t), std::forward<S>(s)...);
+ return *this;
+ }
+ // Explicit type of the second parameter allows clients to provide the struct inline.
+ template<typename T>
+ PatchBuilder& addSink(T&& t, const mix_usecase_t& update) {
+ sinks().add(std::forward<T>(t), update);
+ return *this;
+ }
+ template<typename T, typename... S>
+ PatchBuilder& addSource(T&& t, S&&... s) {
+ sources().add(std::forward<T>(t), std::forward<S>(s)...);
+ return *this;
+ }
+ // Explicit type of the second parameter allows clients to provide the struct inline.
+ template<typename T>
+ PatchBuilder& addSource(T&& t, const mix_usecase_t& update) {
+ sources().add(std::forward<T>(t), update);
+ return *this;
+ }
+
+ private:
+ struct PortCfgs {
+ PortCfgs(unsigned int *countPtr, struct audio_port_config *portCfgs)
+ : mCountPtr(countPtr), mPortCfgs(portCfgs) {}
+ audio_port_config& add(const audio_port_config& portCfg) {
+ return *advance() = portCfg;
+ }
+ template<typename T>
+ audio_port_config& add(const sp<T>& entity) {
+ audio_port_config* added = advance();
+ entity->toAudioPortConfig(added);
+ return *added;
+ }
+ template<typename T>
+ void add(const sp<T>& entity, const mix_usecase_t& usecaseUpdate) {
+ add(entity).ext.mix.usecase = usecaseUpdate;
+ }
+ template<typename T>
+ void add(const sp<T>& entity,
+ std::function<mix_usecase_t(const mix_usecase_t&)> usecaseUpdater) {
+ mix_usecase_t* usecase = &add(entity).ext.mix.usecase;
+ *usecase = usecaseUpdater(*usecase);
+ }
+ struct audio_port_config* advance() {
+ return &mPortCfgs[(*mCountPtr)++];
+ }
+ unsigned int *mCountPtr;
+ struct audio_port_config *mPortCfgs;
+ };
+
+ PortCfgs sinks() { return PortCfgs(&mPatch.num_sinks, mPatch.sinks); }
+ PortCfgs sources() { return PortCfgs(&mPatch.num_sources, mPatch.sources); }
+
+ struct audio_patch mPatch = {};
+};
+
+} // namespace android
+
+#endif // ANDROID_PATCH_BUILDER_H
diff --git a/media/libmedia/include/media/SingleStateQueue.h b/media/libmedia/include/media/SingleStateQueue.h
index d423962..c2761cb 100644
--- a/media/libmedia/include/media/SingleStateQueue.h
+++ b/media/libmedia/include/media/SingleStateQueue.h
@@ -99,6 +99,13 @@
return mShared->mAck - sequence >= 0;
}
+ // returns the last value written (or the contents of the shared buffer after initialization
+ // if no value was written).
+ T last() const
+ { // assume no sequence check required - we are the writer.
+ return mShared->mValue;
+ }
+
private:
int32_t mSequence;
Shared * const mShared;
diff --git a/media/libmediaextractor/MediaBuffer.cpp b/media/libmediaextractor/MediaBuffer.cpp
index 39f8d6e..d197b3f 100644
--- a/media/libmediaextractor/MediaBuffer.cpp
+++ b/media/libmediaextractor/MediaBuffer.cpp
@@ -39,7 +39,7 @@
mRangeOffset(0),
mRangeLength(size),
mOwnsData(false),
- mMetaData(new MetaData),
+ mMetaData(new MetaDataBase),
mOriginal(NULL) {
}
@@ -51,7 +51,7 @@
mRangeOffset(0),
mRangeLength(size),
mOwnsData(true),
- mMetaData(new MetaData),
+ mMetaData(new MetaDataBase),
mOriginal(NULL) {
if (size < kSharedMemThreshold
|| std::atomic_load_explicit(&mUseSharedMemory, std::memory_order_seq_cst) == 0) {
@@ -84,7 +84,7 @@
mRangeLength(mSize),
mBuffer(buffer),
mOwnsData(false),
- mMetaData(new MetaData),
+ mMetaData(new MetaDataBase),
mOriginal(NULL) {
}
@@ -96,7 +96,7 @@
return;
}
- int prevCount = __sync_fetch_and_sub(&mRefCount, 1);
+ int prevCount = mRefCount.fetch_sub(1);
if (prevCount == 1) {
if (mObserver == NULL) {
delete this;
@@ -110,13 +110,13 @@
void MediaBuffer::claim() {
CHECK(mObserver != NULL);
- CHECK_EQ(mRefCount, 1);
+ CHECK_EQ(mRefCount.load(std::memory_order_relaxed), 1);
- mRefCount = 0;
+ mRefCount.store(0, std::memory_order_relaxed);
}
void MediaBuffer::add_ref() {
- (void) __sync_fetch_and_add(&mRefCount, 1);
+ (void) mRefCount.fetch_add(1);
}
void *MediaBuffer::data() const {
diff --git a/media/libmediaextractor/include/media/stagefright/MediaBuffer.h b/media/libmediaextractor/include/media/stagefright/MediaBuffer.h
index f944d51..5a25965 100644
--- a/media/libmediaextractor/include/media/stagefright/MediaBuffer.h
+++ b/media/libmediaextractor/include/media/stagefright/MediaBuffer.h
@@ -86,12 +86,14 @@
virtual MediaBufferBase *clone();
// sum of localRefcount() and remoteRefcount()
+ // Result should be treated as approximate unless the result precludes concurrent accesses.
virtual int refcount() const {
return localRefcount() + remoteRefcount();
}
+ // Result should be treated as approximate unless the result precludes concurrent accesses.
virtual int localRefcount() const {
- return mRefCount;
+ return mRefCount.load(std::memory_order_relaxed);
}
virtual int remoteRefcount() const {
@@ -146,7 +148,7 @@
void claim();
MediaBufferObserver *mObserver;
- int mRefCount;
+ std::atomic<int> mRefCount;
void *mData;
size_t mSize, mRangeOffset, mRangeLength;
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index 29a219f..1a185ab 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -498,9 +498,10 @@
return ERROR_MALFORMED;
}
- int32_t width, height;
+ int32_t width, height, stride;
CHECK(outputFormat->findInt32("width", &width));
CHECK(outputFormat->findInt32("height", &height));
+ CHECK(outputFormat->findInt32("stride", &stride));
int32_t crop_left, crop_top, crop_right, crop_bottom;
if (!outputFormat->findRect("crop", &crop_left, &crop_top, &crop_right, &crop_bottom)) {
@@ -527,11 +528,10 @@
if (converter.isValid()) {
converter.convert(
(const uint8_t *)videoFrameBuffer->data(),
- width, height,
+ width, height, stride,
crop_left, crop_top, crop_right, crop_bottom,
frame->getFlattenedData(),
- frame->mWidth,
- frame->mHeight,
+ frame->mWidth, frame->mHeight, frame->mRowBytes,
crop_left, crop_top, crop_right, crop_bottom);
return OK;
}
@@ -678,9 +678,10 @@
return ERROR_MALFORMED;
}
- int32_t width, height;
+ int32_t width, height, stride;
CHECK(outputFormat->findInt32("width", &width));
CHECK(outputFormat->findInt32("height", &height));
+ CHECK(outputFormat->findInt32("stride", &stride));
if (mFrame == NULL) {
sp<IMemory> frameMem = allocVideoFrame(
@@ -724,11 +725,10 @@
if (converter.isValid()) {
converter.convert(
(const uint8_t *)videoFrameBuffer->data(),
- width, height,
+ width, height, stride,
crop_left, crop_top, crop_right, crop_bottom,
mFrame->getFlattenedData(),
- mFrame->mWidth,
- mFrame->mHeight,
+ mFrame->mWidth, mFrame->mHeight, mFrame->mRowBytes,
dstLeft, dstTop, dstRight, dstBottom);
return OK;
}
diff --git a/media/libstagefright/colorconversion/ColorConverter.cpp b/media/libstagefright/colorconversion/ColorConverter.cpp
index 05f4104..c46a40f 100644
--- a/media/libstagefright/colorconversion/ColorConverter.cpp
+++ b/media/libstagefright/colorconversion/ColorConverter.cpp
@@ -85,9 +85,15 @@
|| mDstFormat == OMX_COLOR_Format32bitBGRA8888;
}
+/*
+ * If stride is non-zero, client's stride will be used. For planar
+ * or semi-planar YUV formats, stride must be even numbers.
+ * If stride is zero, it will be calculated based on width and bpp
+ * of the format, assuming no padding on the right edge.
+ */
ColorConverter::BitmapParams::BitmapParams(
void *bits,
- size_t width, size_t height,
+ size_t width, size_t height, size_t stride,
size_t cropLeft, size_t cropTop,
size_t cropRight, size_t cropBottom,
OMX_COLOR_FORMATTYPE colorFromat)
@@ -101,6 +107,8 @@
mCropBottom(cropBottom) {
switch(mColorFormat) {
case OMX_COLOR_Format16bitRGB565:
+ case OMX_COLOR_FormatYUV420Planar16:
+ case OMX_COLOR_FormatCbYCrY:
mBpp = 2;
mStride = 2 * mWidth;
break;
@@ -112,13 +120,7 @@
mStride = 4 * mWidth;
break;
- case OMX_COLOR_FormatYUV420Planar16:
- mBpp = 2;
- mStride = 2 * mWidth;
- break;
-
case OMX_COLOR_FormatYUV420Planar:
- case OMX_COLOR_FormatCbYCrY:
case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
case OMX_COLOR_FormatYUV420SemiPlanar:
case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
@@ -132,6 +134,10 @@
mStride = mWidth;
break;
}
+ // use client's stride if it's specified.
+ if (stride != 0) {
+ mStride = stride;
+ }
}
size_t ColorConverter::BitmapParams::cropWidth() const {
@@ -144,21 +150,21 @@
status_t ColorConverter::convert(
const void *srcBits,
- size_t srcWidth, size_t srcHeight,
+ size_t srcWidth, size_t srcHeight, size_t srcStride,
size_t srcCropLeft, size_t srcCropTop,
size_t srcCropRight, size_t srcCropBottom,
void *dstBits,
- size_t dstWidth, size_t dstHeight,
+ size_t dstWidth, size_t dstHeight, size_t dstStride,
size_t dstCropLeft, size_t dstCropTop,
size_t dstCropRight, size_t dstCropBottom) {
BitmapParams src(
const_cast<void *>(srcBits),
- srcWidth, srcHeight,
+ srcWidth, srcHeight, srcStride,
srcCropLeft, srcCropTop, srcCropRight, srcCropBottom, mSrcFormat);
BitmapParams dst(
dstBits,
- dstWidth, dstHeight,
+ dstWidth, dstHeight, dstStride,
dstCropLeft, dstCropTop, dstCropRight, dstCropBottom, mDstFormat);
if (!((src.mCropLeft & 1) == 0
@@ -792,15 +798,15 @@
uint8_t *kAdjustedClip = initClip();
- uint16_t *dst_ptr = (uint16_t *)dst.mBits
- + dst.mCropTop * dst.mWidth + dst.mCropLeft;
+ uint16_t *dst_ptr = (uint16_t *)((uint8_t *)
+ dst.mBits + dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp);
const uint8_t *src_y =
- (const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft;
+ (const uint8_t *)src.mBits + src.mCropTop * src.mStride + src.mCropLeft;
const uint8_t *src_u =
- (const uint8_t *)src_y + src.mWidth * src.mHeight
- + src.mCropTop * src.mWidth + src.mCropLeft;
+ (const uint8_t *)src.mBits + src.mHeight * src.mStride +
+ src.mCropTop * src.mStride / 2 + src.mCropLeft;
for (size_t y = 0; y < src.cropHeight(); ++y) {
for (size_t x = 0; x < src.cropWidth(); x += 2) {
@@ -842,13 +848,13 @@
}
}
- src_y += src.mWidth;
+ src_y += src.mStride;
if (y & 1) {
- src_u += src.mWidth;
+ src_u += src.mStride;
}
- dst_ptr += dst.mWidth;
+ dst_ptr = (uint16_t*)((uint8_t*)dst_ptr + dst.mStride);
}
return OK;
diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
index 657a05b..359df3d 100644
--- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp
+++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
@@ -44,6 +44,7 @@
mNativeWindow(nativeWindow),
mWidth(0),
mHeight(0),
+ mStride(0),
mCropLeft(0),
mCropTop(0),
mCropRight(0),
@@ -67,9 +68,10 @@
int32_t colorFormatNew;
CHECK(format->findInt32("color-format", &colorFormatNew));
- int32_t widthNew, heightNew;
- CHECK(format->findInt32("stride", &widthNew));
+ int32_t widthNew, heightNew, strideNew;
+ CHECK(format->findInt32("width", &widthNew));
CHECK(format->findInt32("slice-height", &heightNew));
+ CHECK(format->findInt32("stride", &strideNew));
int32_t cropLeftNew, cropTopNew, cropRightNew, cropBottomNew;
if (!format->findRect(
@@ -106,6 +108,7 @@
mColorFormat = static_cast<OMX_COLOR_FORMATTYPE>(colorFormatNew);
mWidth = widthNew;
mHeight = heightNew;
+ mStride = strideNew;
mCropLeft = cropLeftNew;
mCropTop = cropTopNew;
mCropRight = cropRightNew;
@@ -276,20 +279,15 @@
if (mConverter) {
mConverter->convert(
data,
- mWidth, mHeight,
+ mWidth, mHeight, mStride,
mCropLeft, mCropTop, mCropRight, mCropBottom,
dst,
- buf->stride, buf->height,
+ buf->stride, buf->height, 0,
0, 0, mCropWidth - 1, mCropHeight - 1);
} else if (mColorFormat == OMX_COLOR_FormatYUV420Planar) {
- const uint8_t *src_y = (const uint8_t *)data;
- const uint8_t *src_u =
- (const uint8_t *)data + mWidth * mHeight;
- const uint8_t *src_v = src_u + (mWidth / 2 * mHeight / 2);
-
- src_y +=mCropLeft + mCropTop * mWidth;
- src_u +=(mCropLeft + mCropTop * mWidth / 2)/2;
- src_v +=(mCropLeft + mCropTop * mWidth / 2)/2;
+ const uint8_t *src_y = (const uint8_t *)data + mCropTop * mStride + mCropLeft;
+ const uint8_t *src_u = (const uint8_t *)data + mStride * mHeight + mCropTop * mStride / 4;
+ const uint8_t *src_v = (const uint8_t *)src_u + mStride * mHeight / 4;
uint8_t *dst_y = (uint8_t *)dst;
size_t dst_y_size = buf->stride * buf->height;
@@ -305,7 +303,7 @@
for (int y = 0; y < mCropHeight; ++y) {
memcpy(dst_y, src_y, mCropWidth);
- src_y += mWidth;
+ src_y += mStride;
dst_y += buf->stride;
}
@@ -313,19 +311,15 @@
memcpy(dst_u, src_u, (mCropWidth + 1) / 2);
memcpy(dst_v, src_v, (mCropWidth + 1) / 2);
- src_u += mWidth / 2;
- src_v += mWidth / 2;
+ src_u += mStride / 2;
+ src_v += mStride / 2;
dst_u += dst_c_stride;
dst_v += dst_c_stride;
}
} else if (mColorFormat == OMX_COLOR_FormatYUV420Planar16) {
- const uint16_t *src_y = (const uint16_t *)data;
- const uint16_t *src_u = (const uint16_t *)data + mWidth * mHeight;
- const uint16_t *src_v = src_u + (mWidth / 2 * mHeight / 2);
-
- src_y += mCropLeft + mCropTop * mWidth;
- src_u += (mCropLeft + mCropTop * mWidth / 2) / 2;
- src_v += (mCropLeft + mCropTop * mWidth / 2) / 2;
+ const uint8_t *src_y = (const uint8_t *)data + mCropTop * mStride + mCropLeft * 2;
+ const uint8_t *src_u = (const uint8_t *)data + mStride * mHeight + mCropTop * mStride / 4;
+ const uint8_t *src_v = (const uint8_t *)src_u + mStride * mHeight / 4;
uint8_t *dst_y = (uint8_t *)dst;
size_t dst_y_size = buf->stride * buf->height;
@@ -340,21 +334,21 @@
for (int y = 0; y < mCropHeight; ++y) {
for (int x = 0; x < mCropWidth; ++x) {
- dst_y[x] = (uint8_t)(src_y[x] >> 2);
+ dst_y[x] = (uint8_t)(((uint16_t *)src_y)[x] >> 2);
}
- src_y += mWidth;
+ src_y += mStride;
dst_y += buf->stride;
}
for (int y = 0; y < (mCropHeight + 1) / 2; ++y) {
for (int x = 0; x < (mCropWidth + 1) / 2; ++x) {
- dst_u[x] = (uint8_t)(src_u[x] >> 2);
- dst_v[x] = (uint8_t)(src_v[x] >> 2);
+ dst_u[x] = (uint8_t)(((uint16_t *)src_u)[x] >> 2);
+ dst_v[x] = (uint8_t)(((uint16_t *)src_v)[x] >> 2);
}
- src_u += mWidth / 2;
- src_v += mWidth / 2;
+ src_u += mStride / 2;
+ src_v += mStride / 2;
dst_u += dst_c_stride;
dst_v += dst_c_stride;
}
diff --git a/media/libstagefright/include/SoftwareRenderer.h b/media/libstagefright/include/SoftwareRenderer.h
index c286516..64dca4e 100644
--- a/media/libstagefright/include/SoftwareRenderer.h
+++ b/media/libstagefright/include/SoftwareRenderer.h
@@ -51,7 +51,7 @@
ColorConverter *mConverter;
YUVMode mYUVMode;
sp<ANativeWindow> mNativeWindow;
- int32_t mWidth, mHeight;
+ int32_t mWidth, mHeight, mStride;
int32_t mCropLeft, mCropTop, mCropRight, mCropBottom;
int32_t mCropWidth, mCropHeight;
int32_t mRotationDegrees;
diff --git a/media/libstagefright/include/media/stagefright/ColorConverter.h b/media/libstagefright/include/media/stagefright/ColorConverter.h
index 5b3543d..2b8c7c8 100644
--- a/media/libstagefright/include/media/stagefright/ColorConverter.h
+++ b/media/libstagefright/include/media/stagefright/ColorConverter.h
@@ -37,11 +37,11 @@
status_t convert(
const void *srcBits,
- size_t srcWidth, size_t srcHeight,
+ size_t srcWidth, size_t srcHeight, size_t srcStride,
size_t srcCropLeft, size_t srcCropTop,
size_t srcCropRight, size_t srcCropBottom,
void *dstBits,
- size_t dstWidth, size_t dstHeight,
+ size_t dstWidth, size_t dstHeight, size_t dstStride,
size_t dstCropLeft, size_t dstCropTop,
size_t dstCropRight, size_t dstCropBottom);
@@ -49,7 +49,7 @@
struct BitmapParams {
BitmapParams(
void *bits,
- size_t width, size_t height,
+ size_t width, size_t height, size_t stride,
size_t cropLeft, size_t cropTop,
size_t cropRight, size_t cropBottom,
OMX_COLOR_FORMATTYPE colorFromat);
diff --git a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
index 935dc34..672a37c 100644
--- a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
@@ -154,12 +154,12 @@
outDef->format.video.nFrameWidth = outputBufferWidth();
outDef->format.video.nFrameHeight = outputBufferHeight();
outDef->format.video.eColorFormat = mOutputFormat;
- outDef->format.video.nStride = outDef->format.video.nFrameWidth;
outDef->format.video.nSliceHeight = outDef->format.video.nFrameHeight;
int32_t bpp = (mOutputFormat == OMX_COLOR_FormatYUV420Planar16) ? 2 : 1;
+ outDef->format.video.nStride = outDef->format.video.nFrameWidth * bpp;
outDef->nBufferSize =
- (outDef->format.video.nStride * outDef->format.video.nSliceHeight * bpp * 3) / 2;
+ (outDef->format.video.nStride * outDef->format.video.nSliceHeight * 3) / 2;
OMX_PARAM_PORTDEFINITIONTYPE *inDef = &editPortInfo(kInputPortIndex)->mDef;
inDef->format.video.nFrameWidth = mWidth;
diff --git a/media/utils/Android.bp b/media/utils/Android.bp
index d6dae5b..de8e46a 100644
--- a/media/utils/Android.bp
+++ b/media/utils/Android.bp
@@ -21,9 +21,11 @@
"MemoryLeakTrackUtil.cpp",
"ProcessInfo.cpp",
"SchedulingPolicyService.cpp",
+ "ServiceUtilities.cpp",
],
shared_libs: [
"libbinder",
+ "libcutils",
"liblog",
"libutils",
"libmemunreachable",
diff --git a/services/audioflinger/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
similarity index 84%
rename from services/audioflinger/ServiceUtilities.cpp
rename to media/utils/ServiceUtilities.cpp
index aa267ea..6a90bea 100644
--- a/services/audioflinger/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -18,8 +18,7 @@
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/PermissionCache.h>
-#include <private/android_filesystem_config.h>
-#include "ServiceUtilities.h"
+#include "mediautils/ServiceUtilities.h"
/* When performing permission checks we do not use permission cache for
* runtime permissions (protection level dangerous) as they may change at
@@ -32,24 +31,6 @@
static const String16 sAndroidPermissionRecordAudio("android.permission.RECORD_AUDIO");
-// Not valid until initialized by AudioFlinger constructor. It would have to be
-// re-initialized if the process containing AudioFlinger service forks (which it doesn't).
-// This is often used to validate binder interface calls within audioserver
-// (e.g. AudioPolicyManager to AudioFlinger).
-pid_t getpid_cached;
-
-// A trusted calling UID may specify the client UID as part of a binder interface call.
-// otherwise the calling UID must be equal to the client UID.
-bool isTrustedCallingUid(uid_t uid) {
- switch (uid) {
- case AID_MEDIA:
- case AID_AUDIOSERVER:
- return true;
- default:
- return false;
- }
-}
-
static String16 resolveCallingPackage(PermissionController& permissionController,
const String16& opPackageName, uid_t uid) {
if (opPackageName.size() > 0) {
@@ -71,16 +52,11 @@
return packages[0];
}
-static inline bool isAudioServerOrRoot(uid_t uid) {
- // AID_ROOT is OK for command-line tests. Native unforked audioserver always OK.
- return uid == AID_ROOT || uid == AID_AUDIOSERVER ;
-}
-
static bool checkRecordingInternal(const String16& opPackageName, pid_t pid,
uid_t uid, bool start) {
// Okay to not track in app ops as audio server is us and if
// device is rooted security model is considered compromised.
- if (isAudioServerOrRoot(uid)) return true;
+ if (isAudioServerOrRootUid(uid)) return true;
// We specify a pid and uid here as mediaserver (aka MediaRecorder or StageFrightRecorder)
// may open a record track on behalf of a client. Note that pid may be a tid.
@@ -127,7 +103,7 @@
void finishRecording(const String16& opPackageName, uid_t uid) {
// Okay to not track in app ops as audio server is us and if
// device is rooted security model is considered compromised.
- if (isAudioServerOrRoot(uid)) return;
+ if (isAudioServerOrRootUid(uid)) return;
PermissionController permissionController;
String16 resolvedOpPackageName = resolveCallingPackage(
@@ -142,7 +118,7 @@
}
bool captureAudioOutputAllowed(pid_t pid, uid_t uid) {
- if (getpid_cached == IPCThreadState::self()->getCallingPid()) return true;
+ if (isAudioServerOrRootUid(uid)) return true;
static const String16 sCaptureAudioOutput("android.permission.CAPTURE_AUDIO_OUTPUT");
bool ok = PermissionCache::checkPermission(sCaptureAudioOutput, pid, uid);
if (!ok) ALOGE("Request requires android.permission.CAPTURE_AUDIO_OUTPUT");
@@ -163,7 +139,8 @@
}
bool settingsAllowed() {
- if (getpid_cached == IPCThreadState::self()->getCallingPid()) return true;
+ // given this is a permission check, could this be isAudioServerOrRootUid()?
+ if (isAudioServerUid(IPCThreadState::self()->getCallingUid())) return true;
static const String16 sAudioSettings("android.permission.MODIFY_AUDIO_SETTINGS");
// IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
bool ok = PermissionCache::checkCallingPermission(sAudioSettings);
@@ -180,7 +157,6 @@
}
bool dumpAllowed() {
- // don't optimize for same pid, since mediaserver never dumps itself
static const String16 sDump("android.permission.DUMP");
// IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
bool ok = PermissionCache::checkCallingPermission(sDump);
diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h
new file mode 100644
index 0000000..2bdba5e
--- /dev/null
+++ b/media/utils/include/mediautils/ServiceUtilities.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <unistd.h>
+
+#include <binder/PermissionController.h>
+#include <cutils/multiuser.h>
+#include <private/android_filesystem_config.h>
+
+namespace android {
+
+// Audio permission utilities
+
+// Used for calls that should originate from system services.
+// We allow that some services might have separate processes to
+// handle multiple users, e.g. u10_system, u10_bluetooth, u10_radio.
+static inline bool isServiceUid(uid_t uid) {
+ return multiuser_get_app_id(uid) < AID_APP_START;
+}
+
+// Used for calls that should originate from audioserver.
+static inline bool isAudioServerUid(uid_t uid) {
+ return uid == AID_AUDIOSERVER;
+}
+
+// Used for some permission checks.
+// AID_ROOT is OK for command-line tests. Native audioserver always OK.
+static inline bool isAudioServerOrRootUid(uid_t uid) {
+ return uid == AID_AUDIOSERVER || uid == AID_ROOT;
+}
+
+// Used for calls that should come from system server or internal.
+// Note: system server is multiprocess for multiple users. audioserver is not.
+static inline bool isAudioServerOrSystemServerUid(uid_t uid) {
+ return multiuser_get_app_id(uid) == AID_SYSTEM || uid == AID_AUDIOSERVER;
+}
+
+// Mediaserver may forward the client PID and UID as part of a binder interface call;
+// otherwise the calling UID must be equal to the client UID.
+static inline bool isAudioServerOrMediaServerUid(uid_t uid) {
+ switch (uid) {
+ case AID_MEDIA:
+ case AID_AUDIOSERVER:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool recordingAllowed(const String16& opPackageName, pid_t pid, uid_t uid);
+bool startRecording(const String16& opPackageName, pid_t pid, uid_t uid);
+void finishRecording(const String16& opPackageName, uid_t uid);
+bool captureAudioOutputAllowed(pid_t pid, uid_t uid);
+bool captureHotwordAllowed(pid_t pid, uid_t uid);
+bool settingsAllowed();
+bool modifyAudioRoutingAllowed();
+bool dumpAllowed();
+bool modifyPhoneStateAllowed(pid_t pid, uid_t uid);
+}
diff --git a/packages/MediaComponents/Android.mk b/packages/MediaComponents/Android.mk
index def9dc5..55a5424 100644
--- a/packages/MediaComponents/Android.mk
+++ b/packages/MediaComponents/Android.mk
@@ -42,7 +42,7 @@
#
#LOCAL_MULTILIB := first
#
-#LOCAL_JAVA_LIBRARIES += android-support-annotations
+#LOCAL_JAVA_LIBRARIES += androidx.annotation_annotation
#
## To embed native libraries in package, uncomment the lines below.
##LOCAL_MODULE_TAGS := samples
@@ -60,9 +60,9 @@
#
## TODO: Remove dependency with other support libraries.
#LOCAL_STATIC_ANDROID_LIBRARIES += \
-# android-support-v4 \
-# android-support-v7-appcompat \
-# android-support-v7-palette
+# androidx.legacy_legacy-support-v4 \
+# androidx.appcompat_appcompat \
+# androidx.palette_palette
#LOCAL_USE_AAPT2 := true
#
#include $(BUILD_PACKAGE)
diff --git a/packages/MediaComponents/res/layout/mr_controller_material_dialog_b.xml b/packages/MediaComponents/res/layout/mr_controller_material_dialog_b.xml
index b304471..f6f7be5 100644
--- a/packages/MediaComponents/res/layout/mr_controller_material_dialog_b.xml
+++ b/packages/MediaComponents/res/layout/mr_controller_material_dialog_b.xml
@@ -169,7 +169,7 @@
android:layout_height="wrap_content"
android:fillViewport="true"
android:scrollIndicators="top|bottom">
- <android.support.v7.widget.ButtonBarLayout
+ <androidx.appcompat.widget.ButtonBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="bottom"
@@ -184,7 +184,7 @@
style="?android:attr/buttonBarNeutralButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
- <android.support.v4.widget.Space
+ <androidx.legacy.widget.Space
android:id="@+id/spacer"
android:layout_width="0dp"
android:layout_height="0dp"
@@ -200,7 +200,7 @@
style="?android:attr/buttonBarPositiveButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
- </android.support.v7.widget.ButtonBarLayout>
+ </androidx.appcompat.widget.ButtonBarLayout>
</ScrollView>
</LinearLayout>
</FrameLayout>
diff --git a/packages/MediaComponents/res/layout/mr_controller_volume_item.xml b/packages/MediaComponents/res/layout/mr_controller_volume_item.xml
index a89058b..12d85ae 100644
--- a/packages/MediaComponents/res/layout/mr_controller_volume_item.xml
+++ b/packages/MediaComponents/res/layout/mr_controller_volume_item.xml
@@ -40,7 +40,7 @@
android:layout_marginBottom="8dp"
android:scaleType="fitCenter"
android:src="?attr/mediaRouteAudioTrackDrawable" />
- <android.support.v7.app.MediaRouteVolumeSlider
+ <androidx.mediarouter.app.MediaRouteVolumeSlider
android:id="@+id/mr_volume_slider"
android:layout_width="fill_parent"
android:layout_height="40dp"
diff --git a/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java b/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java
index c909099..0327beb 100644
--- a/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java
@@ -19,7 +19,6 @@
import android.content.Context;
import android.media.MediaBrowser2;
import android.media.MediaBrowser2.BrowserCallback;
-import android.media.MediaController2;
import android.media.MediaItem2;
import android.media.SessionToken2;
import android.media.update.MediaBrowser2Provider;
diff --git a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java b/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
index 249365a..2883087 100644
--- a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
@@ -16,7 +16,6 @@
package com.android.media;
-import static android.media.SessionCommand2.COMMAND_CODE_SET_VOLUME;
import static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_ADD_ITEM;
import static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_REMOVE_ITEM;
import static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_REPLACE_ITEM;
@@ -30,6 +29,7 @@
import static android.media.SessionCommand2.COMMAND_CODE_SESSION_PREPARE_FROM_MEDIA_ID;
import static android.media.SessionCommand2.COMMAND_CODE_SESSION_PREPARE_FROM_SEARCH;
import static android.media.SessionCommand2.COMMAND_CODE_SESSION_PREPARE_FROM_URI;
+import static android.media.SessionCommand2.COMMAND_CODE_SET_VOLUME;
import android.app.PendingIntent;
import android.content.ComponentName;
@@ -44,11 +44,11 @@
import android.media.MediaMetadata2;
import android.media.MediaPlaylistAgent.RepeatMode;
import android.media.MediaPlaylistAgent.ShuffleMode;
-import android.media.SessionCommand2;
import android.media.MediaSession2.CommandButton;
-import android.media.SessionCommandGroup2;
import android.media.MediaSessionService2;
import android.media.Rating2;
+import android.media.SessionCommand2;
+import android.media.SessionCommandGroup2;
import android.media.SessionToken2;
import android.media.update.MediaController2Provider;
import android.net.Uri;
@@ -58,10 +58,11 @@
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.UserHandle;
-import android.support.annotation.GuardedBy;
import android.text.TextUtils;
import android.util.Log;
+import androidx.annotation.GuardedBy;
+
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
diff --git a/packages/MediaComponents/src/com/android/media/MediaController2Stub.java b/packages/MediaComponents/src/com/android/media/MediaController2Stub.java
index 2cfc5df..ece4a00 100644
--- a/packages/MediaComponents/src/com/android/media/MediaController2Stub.java
+++ b/packages/MediaComponents/src/com/android/media/MediaController2Stub.java
@@ -21,8 +21,8 @@
import android.media.MediaController2;
import android.media.MediaItem2;
import android.media.MediaMetadata2;
-import android.media.SessionCommand2;
import android.media.MediaSession2.CommandButton;
+import android.media.SessionCommand2;
import android.media.SessionCommandGroup2;
import android.os.Bundle;
import android.os.ResultReceiver;
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java b/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
index 4ec6042..72ecf54 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
@@ -44,13 +44,13 @@
import android.media.MediaPlaylistAgent.PlaylistEventCallback;
import android.media.MediaSession2;
import android.media.MediaSession2.Builder;
-import android.media.SessionCommand2;
import android.media.MediaSession2.CommandButton;
-import android.media.SessionCommandGroup2;
import android.media.MediaSession2.ControllerInfo;
import android.media.MediaSession2.OnDataSourceMissingHelper;
import android.media.MediaSession2.SessionCallback;
import android.media.MediaSessionService2;
+import android.media.SessionCommand2;
+import android.media.SessionCommandGroup2;
import android.media.SessionToken2;
import android.media.VolumeProvider2;
import android.media.session.MediaSessionManager;
@@ -60,10 +60,11 @@
import android.os.Parcelable;
import android.os.Process;
import android.os.ResultReceiver;
-import android.support.annotation.GuardedBy;
import android.text.TextUtils;
import android.util.Log;
+import androidx.annotation.GuardedBy;
+
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.util.ArrayList;
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java b/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
index ec657d7..11ccd9f 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
@@ -22,11 +22,11 @@
import android.media.MediaItem2;
import android.media.MediaLibraryService2.LibraryRoot;
import android.media.MediaMetadata2;
-import android.media.SessionCommand2;
import android.media.MediaSession2.CommandButton;
-import android.media.SessionCommandGroup2;
import android.media.MediaSession2.ControllerInfo;
import android.media.Rating2;
+import android.media.SessionCommand2;
+import android.media.SessionCommandGroup2;
import android.media.VolumeProvider2;
import android.net.Uri;
import android.os.Binder;
@@ -35,13 +35,14 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ResultReceiver;
-import android.support.annotation.GuardedBy;
-import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.util.SparseArray;
+import androidx.annotation.GuardedBy;
+import androidx.annotation.NonNull;
+
import com.android.media.MediaLibraryService2Impl.MediaLibrarySessionImpl;
import com.android.media.MediaSession2Impl.CommandButtonImpl;
import com.android.media.MediaSession2Impl.CommandGroupImpl;
diff --git a/packages/MediaComponents/src/com/android/media/MediaSessionService2Impl.java b/packages/MediaComponents/src/com/android/media/MediaSessionService2Impl.java
index c33eb65..d975839 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSessionService2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSessionService2Impl.java
@@ -20,7 +20,6 @@
import android.app.Notification;
import android.app.NotificationManager;
-import android.content.Context;
import android.content.Intent;
import android.media.MediaPlayerBase;
import android.media.MediaPlayerBase.PlayerEventCallback;
@@ -31,9 +30,10 @@
import android.media.SessionToken2.TokenType;
import android.media.update.MediaSessionService2Provider;
import android.os.IBinder;
-import android.support.annotation.GuardedBy;
import android.util.Log;
+import androidx.annotation.GuardedBy;
+
// TODO(jaewan): Need a test for session service itself.
public class MediaSessionService2Impl implements MediaSessionService2Provider {
diff --git a/packages/MediaComponents/src/com/android/media/Rating2Impl.java b/packages/MediaComponents/src/com/android/media/Rating2Impl.java
index d558129..e2b9f0a 100644
--- a/packages/MediaComponents/src/com/android/media/Rating2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/Rating2Impl.java
@@ -18,7 +18,6 @@
import static android.media.Rating2.*;
-import android.content.Context;
import android.media.Rating2;
import android.media.Rating2.Style;
import android.media.update.Rating2Provider;
diff --git a/packages/MediaComponents/src/com/android/media/RoutePlayer.java b/packages/MediaComponents/src/com/android/media/RoutePlayer.java
index 9450d34..ebff0e2 100644
--- a/packages/MediaComponents/src/com/android/media/RoutePlayer.java
+++ b/packages/MediaComponents/src/com/android/media/RoutePlayer.java
@@ -23,7 +23,8 @@
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
-import android.support.annotation.RequiresApi;
+
+import androidx.annotation.RequiresApi;
import com.android.support.mediarouter.media.MediaItemStatus;
import com.android.support.mediarouter.media.MediaRouter;
@@ -33,8 +34,6 @@
import com.android.support.mediarouter.media.RemotePlaybackClient.SessionActionCallback;
import com.android.support.mediarouter.media.RemotePlaybackClient.StatusCallback;
-import java.util.Map;
-
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class RoutePlayer extends MediaSession.Callback {
public static final long PLAYBACK_ACTIONS = PlaybackState.ACTION_PAUSE
diff --git a/packages/MediaComponents/src/com/android/media/SessionToken2Impl.java b/packages/MediaComponents/src/com/android/media/SessionToken2Impl.java
index a5cf8c4..f792712 100644
--- a/packages/MediaComponents/src/com/android/media/SessionToken2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/SessionToken2Impl.java
@@ -16,9 +16,9 @@
package com.android.media;
+import static android.media.SessionToken2.TYPE_LIBRARY_SERVICE;
import static android.media.SessionToken2.TYPE_SESSION;
import static android.media.SessionToken2.TYPE_SESSION_SERVICE;
-import static android.media.SessionToken2.TYPE_LIBRARY_SERVICE;
import android.content.Context;
import android.content.Intent;
diff --git a/packages/MediaComponents/src/com/android/media/subtitle/SubtitleController.java b/packages/MediaComponents/src/com/android/media/subtitle/SubtitleController.java
index a4d55d7..97d3927 100644
--- a/packages/MediaComponents/src/com/android/media/subtitle/SubtitleController.java
+++ b/packages/MediaComponents/src/com/android/media/subtitle/SubtitleController.java
@@ -16,12 +16,8 @@
package com.android.media.subtitle;
-import java.util.Locale;
-import java.util.Vector;
-
import android.content.Context;
import android.media.MediaFormat;
-import android.media.MediaPlayer2;
import android.media.MediaPlayer2.TrackInfo;
import android.os.Handler;
import android.os.Looper;
@@ -30,6 +26,9 @@
import com.android.media.subtitle.SubtitleTrack.RenderingWidget;
+import java.util.Locale;
+import java.util.Vector;
+
// Note: This is forked from android.media.SubtitleController since P
/**
* The subtitle controller provides the architecture to display subtitles for a
diff --git a/packages/MediaComponents/src/com/android/media/update/ApiFactory.java b/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
index d7be549..f75b75e 100644
--- a/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
+++ b/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
@@ -31,13 +31,13 @@
import android.media.MediaMetadata2;
import android.media.MediaPlaylistAgent;
import android.media.MediaSession2;
-import android.media.SessionCommand2;
-import android.media.SessionCommandGroup2;
import android.media.MediaSession2.ControllerInfo;
import android.media.MediaSession2.SessionCallback;
import android.media.MediaSessionService2;
import android.media.MediaSessionService2.MediaNotification;
import android.media.Rating2;
+import android.media.SessionCommand2;
+import android.media.SessionCommandGroup2;
import android.media.SessionToken2;
import android.media.VolumeProvider2;
import android.media.update.MediaBrowser2Provider;
@@ -59,11 +59,12 @@
import android.media.update.VolumeProvider2Provider;
import android.os.Bundle;
import android.os.IInterface;
-import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.widget.MediaControlView2;
import android.widget.VideoView2;
+import androidx.annotation.Nullable;
+
import com.android.media.IMediaController2;
import com.android.media.MediaBrowser2Impl;
import com.android.media.MediaController2Impl;
diff --git a/packages/MediaComponents/src/com/android/media/update/ApiHelper.java b/packages/MediaComponents/src/com/android/media/update/ApiHelper.java
index ad8bb48..dc5e5e2 100644
--- a/packages/MediaComponents/src/com/android/media/update/ApiHelper.java
+++ b/packages/MediaComponents/src/com/android/media/update/ApiHelper.java
@@ -18,21 +18,21 @@
import android.annotation.Nullable;
import android.content.Context;
-import android.content.ContextWrapper;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.XmlResourceParser;
-import android.support.annotation.GuardedBy;
-import android.support.v4.widget.Space;
-import android.support.v7.widget.ButtonBarLayout;
import android.util.AttributeSet;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import androidx.annotation.GuardedBy;
+import androidx.appcompat.widget.ButtonBarLayout;
+import androidx.legacy.widget.Space;
+
import com.android.support.mediarouter.app.MediaRouteButton;
import com.android.support.mediarouter.app.MediaRouteExpandCollapseButton;
import com.android.support.mediarouter.app.MediaRouteVolumeSlider;
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteActionProvider.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteActionProvider.java
index d3e8d47..98c0d17 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteActionProvider.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteActionProvider.java
@@ -19,11 +19,12 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
-import android.support.v4.view.ActionProvider;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
+import androidx.core.view.ActionProvider;
+
import com.android.support.mediarouter.media.MediaRouteSelector;
import com.android.support.mediarouter.media.MediaRouter;
@@ -48,7 +49,7 @@
* <h3>Prerequisites</h3>
* <p>
* To use the media route action provider, the activity must be a subclass of
- * {@link AppCompatActivity} from the <code>android.support.v7.appcompat</code>
+ * {@link AppCompatActivity} from the <code>androidx.appcompat.appcompat</code>
* support library. Refer to support library documentation for details.
* </p>
*
@@ -65,7 +66,7 @@
* <item android:id="@+id/media_route_menu_item"
* android:title="@string/media_route_menu_title"
* app:showAsAction="always"
- * app:actionProviderClass="android.support.v7.app.MediaRouteActionProvider"/>
+ * app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"/>
* </menu>
* </pre><p>
* Then configure the menu and set the route selector for the chooser.
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteButton.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteButton.java
index fde8a63..e82fcb9 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteButton.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteButton.java
@@ -28,14 +28,15 @@
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
-import android.support.v4.graphics.drawable.DrawableCompat;
-import android.support.v7.widget.TooltipCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
import android.view.SoundEffectConstants;
import android.view.View;
+import androidx.appcompat.widget.TooltipCompat;
+import androidx.core.graphics.drawable.DrawableCompat;
+
import com.android.media.update.ApiHelper;
import com.android.media.update.R;
import com.android.support.mediarouter.media.MediaRouteSelector;
@@ -70,7 +71,7 @@
* <h3>Prerequisites</h3>
* <p>
* To use the media route button, the activity must be a subclass of
- * {@link FragmentActivity} from the <code>android.support.v4</code>
+ * {@link FragmentActivity} from the <code>androidx.core./code>
* support library. Refer to support library documentation for details.
* </p>
*
@@ -81,9 +82,9 @@
private static final String TAG = "MediaRouteButton";
private static final String CHOOSER_FRAGMENT_TAG =
- "android.support.v7.mediarouter:MediaRouteChooserDialogFragment";
+ "androidx.mediarouter.media.outer:MediaRouteChooserDialogFragment";
private static final String CONTROLLER_FRAGMENT_TAG =
- "android.support.v7.mediarouter:MediaRouteControllerDialogFragment";
+ "androidx.mediarouter.media.outer:MediaRouteControllerDialogFragment";
private final MediaRouter mRouter;
private final MediaRouterCallback mCallback;
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteChooserDialog.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteChooserDialog.java
index cac64d9..f24028a 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteChooserDialog.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteChooserDialog.java
@@ -16,13 +16,14 @@
package com.android.support.mediarouter.app;
-import static com.android.support.mediarouter.media.MediaRouter.RouteInfo.CONNECTION_STATE_CONNECTED;
-import static com.android.support.mediarouter.media.MediaRouter.RouteInfo.CONNECTION_STATE_CONNECTING;
+import static com.android.support.mediarouter.media.MediaRouter.RouteInfo
+ .CONNECTION_STATE_CONNECTED;
+import static com.android.support.mediarouter.media.MediaRouter.RouteInfo
+ .CONNECTION_STATE_CONNECTING;
import android.annotation.NonNull;
import android.app.Dialog;
import android.content.Context;
-import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.net.Uri;
@@ -30,12 +31,10 @@
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
-import android.support.v7.app.AppCompatDialog;
import android.text.TextUtils;
import android.util.Log;
import android.view.ContextThemeWrapper;
import android.view.Gravity;
-import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteControllerDialog.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteControllerDialog.java
index 060cfca..f6c1d2f 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteControllerDialog.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteControllerDialog.java
@@ -40,9 +40,6 @@
import android.support.v4.media.session.MediaControllerCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
-import android.support.v4.util.ObjectsCompat;
-import android.support.v4.view.accessibility.AccessibilityEventCompat;
-import android.support.v7.graphics.Palette;
import android.text.TextUtils;
import android.util.Log;
import android.view.ContextThemeWrapper;
@@ -72,11 +69,15 @@
import android.widget.SeekBar;
import android.widget.TextView;
+import androidx.core.util.ObjectsCompat;
+import androidx.core.view.accessibility.AccessibilityEventCompat;
+import androidx.palette.graphics.Palette;
+
import com.android.media.update.ApiHelper;
import com.android.media.update.R;
+import com.android.support.mediarouter.app.OverlayListView.OverlayObject;
import com.android.support.mediarouter.media.MediaRouteSelector;
import com.android.support.mediarouter.media.MediaRouter;
-import com.android.support.mediarouter.app.OverlayListView.OverlayObject;
import java.io.BufferedInputStream;
import java.io.IOException;
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteDialogFactory.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteDialogFactory.java
index a9eaf39..b5ee63e 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteDialogFactory.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteDialogFactory.java
@@ -16,7 +16,7 @@
package com.android.support.mediarouter.app;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
/**
* The media route dialog factory is responsible for creating the media route
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteDiscoveryFragment.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteDiscoveryFragment.java
index 02ee118..52aecd88 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteDiscoveryFragment.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteDiscoveryFragment.java
@@ -17,10 +17,11 @@
package com.android.support.mediarouter.app;
import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import com.android.support.mediarouter.media.MediaRouter;
+import androidx.fragment.app.Fragment;
+
import com.android.support.mediarouter.media.MediaRouteSelector;
+import com.android.support.mediarouter.media.MediaRouter;
/**
* Media route discovery fragment.
@@ -34,7 +35,7 @@
* provide the {@link MediaRouter} callback to register.
* </p><p>
* Note that the discovery callback makes the application be connected with all the
- * {@link android.support.v7.media.MediaRouteProviderService media route provider services}
+ * {@link androidx.mediarouter.media.MediaRouteProviderService media route provider services}
* while it is registered.
* </p>
*/
@@ -114,7 +115,7 @@
}
/**
- * Called to create the {@link android.support.v7.media.MediaRouter.Callback callback}
+ * Called to create the {@link androidx.mediarouter.media.MediaRouter.Callback callback}
* that will be registered.
* <p>
* The default callback does nothing. The application may override this method to
@@ -129,7 +130,7 @@
/**
* Called to prepare the callback flags that will be used when the
- * {@link android.support.v7.media.MediaRouter.Callback callback} is registered.
+ * {@link androidx.mediarouter.media.MediaRouter.Callback callback} is registered.
* <p>
* The default implementation returns {@link MediaRouter#CALLBACK_FLAG_REQUEST_DISCOVERY}.
* </p>
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteExpandCollapseButton.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteExpandCollapseButton.java
index 6a0a95a..dcca6a0 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteExpandCollapseButton.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouteExpandCollapseButton.java
@@ -21,7 +21,6 @@
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.AnimationDrawable;
-import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageButton;
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouterThemeHelper.java b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouterThemeHelper.java
index 63f042f..b4bf8d1 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouterThemeHelper.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/app/MediaRouterThemeHelper.java
@@ -19,12 +19,13 @@
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
-import android.support.annotation.IntDef;
-import android.support.v4.graphics.ColorUtils;
import android.util.TypedValue;
import android.view.ContextThemeWrapper;
import android.view.View;
+import androidx.annotation.IntDef;
+import androidx.core.graphics.ColorUtils;
+
import com.android.media.update.R;
import java.lang.annotation.Retention;
@@ -170,7 +171,7 @@
private static boolean isLightTheme(Context context) {
TypedValue value = new TypedValue();
// TODO(sungsoo): Switch to com.android.internal.R.attr.isLightTheme
- return context.getTheme().resolveAttribute(android.support.v7.appcompat.R.attr.isLightTheme,
+ return context.getTheme().resolveAttribute(androidx.appcompat.R.attr.isLightTheme,
value, true) && value.data != 0;
}
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/jellybean-mr1/MediaRouterJellybeanMr1.java b/packages/MediaComponents/src/com/android/support/mediarouter/jellybean-mr1/MediaRouterJellybeanMr1.java
index f8539bd..5a0bc95 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/jellybean-mr1/MediaRouterJellybeanMr1.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/jellybean-mr1/MediaRouterJellybeanMr1.java
@@ -20,7 +20,6 @@
import android.hardware.display.DisplayManager;
import android.os.Build;
import android.os.Handler;
-import android.support.annotation.RequiresApi;
import android.util.Log;
import android.view.Display;
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaItemStatus.java b/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaItemStatus.java
index 90ea2d5..92f608b 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaItemStatus.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaItemStatus.java
@@ -19,7 +19,8 @@
import android.app.PendingIntent;
import android.os.Bundle;
import android.os.SystemClock;
-import android.support.v4.util.TimeUtils;
+
+import androidx.core.util.TimeUtils;
/**
* Describes the playback status of a media item.
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouteProvider.java b/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouteProvider.java
index 91a2e1a..7ea328c 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouteProvider.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouteProvider.java
@@ -23,7 +23,8 @@
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
-import android.support.v4.util.ObjectsCompat;
+
+import androidx.core.util.ObjectsCompat;
import com.android.support.mediarouter.media.MediaRouter.ControlRequestCallback;
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouteProviderService.java b/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouteProviderService.java
index 43cde10..a186fee 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouteProviderService.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouteProviderService.java
@@ -29,12 +29,14 @@
.CLIENT_MSG_RELEASE_ROUTE_CONTROLLER;
import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
.CLIENT_MSG_ROUTE_CONTROL_REQUEST;
-import static com.android.support.mediarouter.media.MediaRouteProviderProtocol.CLIENT_MSG_SELECT_ROUTE;
+import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
+ .CLIENT_MSG_SELECT_ROUTE;
import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
.CLIENT_MSG_SET_DISCOVERY_REQUEST;
import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
.CLIENT_MSG_SET_ROUTE_VOLUME;
-import static com.android.support.mediarouter.media.MediaRouteProviderProtocol.CLIENT_MSG_UNREGISTER;
+import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
+ .CLIENT_MSG_UNREGISTER;
import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
.CLIENT_MSG_UNSELECT_ROUTE;
import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
@@ -51,9 +53,12 @@
.SERVICE_MSG_GENERIC_FAILURE;
import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
.SERVICE_MSG_GENERIC_SUCCESS;
-import static com.android.support.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_REGISTERED;
-import static com.android.support.mediarouter.media.MediaRouteProviderProtocol.SERVICE_VERSION_CURRENT;
-import static com.android.support.mediarouter.media.MediaRouteProviderProtocol.isValidRemoteMessenger;
+import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
+ .SERVICE_MSG_REGISTERED;
+import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
+ .SERVICE_VERSION_CURRENT;
+import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
+ .isValidRemoteMessenger;
import android.app.Service;
import android.content.Intent;
@@ -65,11 +70,12 @@
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
-import android.support.annotation.VisibleForTesting;
-import android.support.v4.util.ObjectsCompat;
import android.util.Log;
import android.util.SparseArray;
+import androidx.annotation.VisibleForTesting;
+import androidx.core.util.ObjectsCompat;
+
import java.lang.ref.WeakReference;
import java.util.ArrayList;
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouteSelector.java b/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouteSelector.java
index 5669b19..f20dcc0 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouteSelector.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouteSelector.java
@@ -17,8 +17,9 @@
import android.content.IntentFilter;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouter.java b/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouter.java
index db0052e..4b56b19 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouter.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaRouter.java
@@ -33,15 +33,16 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.support.v4.app.ActivityManagerCompat;
-import android.support.v4.hardware.display.DisplayManagerCompat;
-import android.support.v4.media.VolumeProviderCompat;
import android.support.v4.media.session.MediaSessionCompat;
-import android.support.v4.util.Pair;
import android.text.TextUtils;
import android.util.Log;
import android.view.Display;
+import androidx.core.app.ActivityManagerCompat;
+import androidx.core.hardware.display.DisplayManagerCompat;
+import androidx.core.util.Pair;
+import androidx.media.VolumeProviderCompat;
+
import com.android.support.mediarouter.media.MediaRouteProvider.ProviderMetadata;
import com.android.support.mediarouter.media.MediaRouteProvider.RouteController;
@@ -81,13 +82,13 @@
static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
/**
- * Passed to {@link android.support.v7.media.MediaRouteProvider.RouteController#onUnselect(int)}
+ * Passed to {@link androidx.mediarouter.media.MediaRouteProvider.RouteController#onUnselect(int)}
* and {@link Callback#onRouteUnselected(MediaRouter, RouteInfo, int)} when the reason the route
* was unselected is unknown.
*/
public static final int UNSELECT_REASON_UNKNOWN = 0;
/**
- * Passed to {@link android.support.v7.media.MediaRouteProvider.RouteController#onUnselect(int)}
+ * Passed to {@link androidx.mediarouter.media.MediaRouteProvider.RouteController#onUnselect(int)}
* and {@link Callback#onRouteUnselected(MediaRouter, RouteInfo, int)} when the user pressed
* the disconnect button to disconnect and keep playing.
* <p>
@@ -96,13 +97,13 @@
*/
public static final int UNSELECT_REASON_DISCONNECTED = 1;
/**
- * Passed to {@link android.support.v7.media.MediaRouteProvider.RouteController#onUnselect(int)}
+ * Passed to {@link androidx.mediarouter.media.MediaRouteProvider.RouteController#onUnselect(int)}
* and {@link Callback#onRouteUnselected(MediaRouter, RouteInfo, int)} when the user pressed
* the stop casting button.
*/
public static final int UNSELECT_REASON_STOPPED = 2;
/**
- * Passed to {@link android.support.v7.media.MediaRouteProvider.RouteController#onUnselect(int)}
+ * Passed to {@link androidx.mediarouter.media.MediaRouteProvider.RouteController#onUnselect(int)}
* and {@link Callback#onRouteUnselected(MediaRouter, RouteInfo, int)} when the user selected
* a different route.
*/
@@ -174,7 +175,7 @@
* Applications should typically add a callback using this flag in the
* {@link android.app.Activity activity's} {@link android.app.Activity#onStart onStart}
* method and remove it in the {@link android.app.Activity#onStop onStop} method.
- * The {@link android.support.v7.app.MediaRouteDiscoveryFragment} fragment may
+ * The {@link androidx.mediarouter.app.MediaRouteDiscoveryFragment} fragment may
* also be used for this purpose.
* </p><p class="note">
* On {@link ActivityManager#isLowRamDevice low-RAM devices} this flag
@@ -182,7 +183,7 @@
* {@link #addCallback(MediaRouteSelector, Callback, int) addCallback} for details.
* </p>
*
- * @see android.support.v7.app.MediaRouteDiscoveryFragment
+ * @see androidx.mediarouter.app.MediaRouteDiscoveryFragment
*/
public static final int CALLBACK_FLAG_REQUEST_DISCOVERY = 1 << 2;
@@ -197,7 +198,7 @@
* {@link #addCallback(MediaRouteSelector, Callback, int) addCallback} for details.
* </p>
*
- * @see android.support.v7.app.MediaRouteDiscoveryFragment
+ * @see androidx.mediarouter.app.MediaRouteDiscoveryFragment
*/
public static final int CALLBACK_FLAG_FORCE_DISCOVERY = 1 << 3;
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaSessionStatus.java b/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaSessionStatus.java
index 3206596..0e7514c 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaSessionStatus.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/media/MediaSessionStatus.java
@@ -19,7 +19,8 @@
import android.app.PendingIntent;
import android.os.Bundle;
import android.os.SystemClock;
-import android.support.v4.util.TimeUtils;
+
+import androidx.core.util.TimeUtils;
/**
* Describes the playback status of a media session.
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/media/RegisteredMediaRouteProvider.java b/packages/MediaComponents/src/com/android/support/mediarouter/media/RegisteredMediaRouteProvider.java
index 98e4e28..eacf1c8 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/media/RegisteredMediaRouteProvider.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/media/RegisteredMediaRouteProvider.java
@@ -29,17 +29,20 @@
.CLIENT_MSG_RELEASE_ROUTE_CONTROLLER;
import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
.CLIENT_MSG_ROUTE_CONTROL_REQUEST;
-import static com.android.support.mediarouter.media.MediaRouteProviderProtocol.CLIENT_MSG_SELECT_ROUTE;
+import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
+ .CLIENT_MSG_SELECT_ROUTE;
import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
.CLIENT_MSG_SET_DISCOVERY_REQUEST;
import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
.CLIENT_MSG_SET_ROUTE_VOLUME;
-import static com.android.support.mediarouter.media.MediaRouteProviderProtocol.CLIENT_MSG_UNREGISTER;
+import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
+ .CLIENT_MSG_UNREGISTER;
import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
.CLIENT_MSG_UNSELECT_ROUTE;
import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
.CLIENT_MSG_UPDATE_ROUTE_VOLUME;
-import static com.android.support.mediarouter.media.MediaRouteProviderProtocol.CLIENT_VERSION_CURRENT;
+import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
+ .CLIENT_VERSION_CURRENT;
import static com.android.support.mediarouter.media.MediaRouteProviderProtocol.SERVICE_DATA_ERROR;
import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
.SERVICE_MSG_CONTROL_REQUEST_FAILED;
@@ -51,9 +54,11 @@
.SERVICE_MSG_GENERIC_FAILURE;
import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
.SERVICE_MSG_GENERIC_SUCCESS;
-import static com.android.support.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_REGISTERED;
+import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
+ .SERVICE_MSG_REGISTERED;
import static com.android.support.mediarouter.media.MediaRouteProviderProtocol.SERVICE_VERSION_1;
-import static com.android.support.mediarouter.media.MediaRouteProviderProtocol.isValidRemoteMessenger;
+import static com.android.support.mediarouter.media.MediaRouteProviderProtocol
+ .isValidRemoteMessenger;
import android.annotation.NonNull;
import android.content.ComponentName;
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/media/RemoteControlClientCompat.java b/packages/MediaComponents/src/com/android/support/mediarouter/media/RemoteControlClientCompat.java
index 826449b..65c5518 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/media/RemoteControlClientCompat.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/media/RemoteControlClientCompat.java
@@ -18,7 +18,6 @@
import android.content.Context;
import android.media.AudioManager;
import android.os.Build;
-import android.support.annotation.RequiresApi;
import java.lang.ref.WeakReference;
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/media/RemotePlaybackClient.java b/packages/MediaComponents/src/com/android/support/mediarouter/media/RemotePlaybackClient.java
index f6e1497..e76564e 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/media/RemotePlaybackClient.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/media/RemotePlaybackClient.java
@@ -22,9 +22,10 @@
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Bundle;
-import android.support.v4.util.ObjectsCompat;
import android.util.Log;
+import androidx.core.util.ObjectsCompat;
+
/**
* A helper class for playing media on remote routes using the remote playback protocol
* defined by {@link MediaControlIntent}.
@@ -867,11 +868,11 @@
private final class ActionReceiver extends BroadcastReceiver {
public static final String ACTION_ITEM_STATUS_CHANGED =
- "android.support.v7.media.actions.ACTION_ITEM_STATUS_CHANGED";
+ "androidx.mediarouter.media.actions.ACTION_ITEM_STATUS_CHANGED";
public static final String ACTION_SESSION_STATUS_CHANGED =
- "android.support.v7.media.actions.ACTION_SESSION_STATUS_CHANGED";
+ "androidx.mediarouter.media.actions.ACTION_SESSION_STATUS_CHANGED";
public static final String ACTION_MESSAGE_RECEIVED =
- "android.support.v7.media.actions.ACTION_MESSAGE_RECEIVED";
+ "androidx.mediarouter.media.actions.ACTION_MESSAGE_RECEIVED";
ActionReceiver() {
}
diff --git a/packages/MediaComponents/src/com/android/support/mediarouter/media/SystemMediaRouteProvider.java b/packages/MediaComponents/src/com/android/support/mediarouter/media/SystemMediaRouteProvider.java
index a38491f..53901a4 100644
--- a/packages/MediaComponents/src/com/android/support/mediarouter/media/SystemMediaRouteProvider.java
+++ b/packages/MediaComponents/src/com/android/support/mediarouter/media/SystemMediaRouteProvider.java
@@ -24,7 +24,6 @@
import android.content.res.Resources;
import android.media.AudioManager;
import android.os.Build;
-import android.support.annotation.RequiresApi;
import android.view.Display;
import com.android.media.update.ApiHelper;
diff --git a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
index 3aff150..ad85af4 100644
--- a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
@@ -20,15 +20,13 @@
import android.content.res.Resources;
import android.graphics.Point;
import android.media.MediaMetadata;
+import android.media.SessionToken2;
import android.media.session.MediaController;
import android.media.session.PlaybackState;
-import android.media.SessionToken2;
import android.media.update.MediaControlView2Provider;
import android.media.update.ViewGroupProvider;
import android.os.Bundle;
-import android.support.annotation.Nullable;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
@@ -36,27 +34,28 @@
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
-import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.MediaControlView2;
-import android.widget.ProgressBar;
import android.widget.PopupWindow;
+import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
+import androidx.annotation.Nullable;
+
import com.android.media.update.ApiHelper;
import com.android.media.update.R;
import com.android.support.mediarouter.app.MediaRouteButton;
-import com.android.support.mediarouter.media.MediaRouter;
import com.android.support.mediarouter.media.MediaRouteSelector;
+import com.android.support.mediarouter.media.MediaRouter;
-import java.util.Arrays;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Formatter;
import java.util.List;
import java.util.Locale;
diff --git a/packages/MediaComponents/src/com/android/widget/SubtitleView.java b/packages/MediaComponents/src/com/android/widget/SubtitleView.java
index 67b2cd1..db0ae33 100644
--- a/packages/MediaComponents/src/com/android/widget/SubtitleView.java
+++ b/packages/MediaComponents/src/com/android/widget/SubtitleView.java
@@ -19,10 +19,11 @@
import android.content.Context;
import android.graphics.Canvas;
import android.os.Looper;
-import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.widget.FrameLayout;
+import androidx.annotation.Nullable;
+
import com.android.media.subtitle.SubtitleController.Anchor;
import com.android.media.subtitle.SubtitleTrack.RenderingWidget;
diff --git a/packages/MediaComponents/src/com/android/widget/VideoSurfaceView.java b/packages/MediaComponents/src/com/android/widget/VideoSurfaceView.java
index fc92e85..c9869c0 100644
--- a/packages/MediaComponents/src/com/android/widget/VideoSurfaceView.java
+++ b/packages/MediaComponents/src/com/android/widget/VideoSurfaceView.java
@@ -16,17 +16,18 @@
package com.android.widget;
+import static android.widget.VideoView2.VIEW_TYPE_SURFACEVIEW;
+
import android.content.Context;
import android.graphics.Rect;
import android.media.MediaPlayer2;
-import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
-import static android.widget.VideoView2.VIEW_TYPE_SURFACEVIEW;
+import androidx.annotation.NonNull;
class VideoSurfaceView extends SurfaceView implements VideoViewInterface, SurfaceHolder.Callback {
private static final String TAG = "VideoSurfaceView";
diff --git a/packages/MediaComponents/src/com/android/widget/VideoTextureView.java b/packages/MediaComponents/src/com/android/widget/VideoTextureView.java
index 024a3aa..40fb046 100644
--- a/packages/MediaComponents/src/com/android/widget/VideoTextureView.java
+++ b/packages/MediaComponents/src/com/android/widget/VideoTextureView.java
@@ -16,18 +16,19 @@
package com.android.widget;
+import static android.widget.VideoView2.VIEW_TYPE_TEXTUREVIEW;
+
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.media.MediaPlayer2;
-import android.support.annotation.NonNull;
-import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
-import static android.widget.VideoView2.VIEW_TYPE_TEXTUREVIEW;
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
@RequiresApi(26)
class VideoTextureView extends TextureView
diff --git a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
index 97279d6..ffb145a 100644
--- a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
@@ -28,30 +28,29 @@
import android.media.AudioFocusRequest;
import android.media.AudioManager;
import android.media.DataSourceDesc;
+import android.media.MediaItem2;
import android.media.MediaMetadata;
+import android.media.MediaMetadata2;
+import android.media.MediaMetadataRetriever;
import android.media.MediaPlayer2;
import android.media.MediaPlayer2.MediaPlayer2EventCallback;
import android.media.MediaPlayer2.OnSubtitleDataListener;
import android.media.MediaPlayer2Impl;
-import android.media.SubtitleData;
-import android.media.MediaItem2;
-import android.media.MediaMetadata2;
-import android.media.MediaMetadataRetriever;
import android.media.Metadata;
import android.media.PlaybackParams;
+import android.media.SessionToken2;
+import android.media.SubtitleData;
import android.media.TimedText;
import android.media.session.MediaController;
import android.media.session.MediaController.PlaybackInfo;
import android.media.session.MediaSession;
import android.media.session.PlaybackState;
-import android.media.SessionToken2;
import android.media.update.VideoView2Provider;
import android.media.update.ViewGroupProvider;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.ResultReceiver;
-import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -66,6 +65,8 @@
import android.widget.TextView;
import android.widget.VideoView2;
+import androidx.annotation.Nullable;
+
import com.android.internal.graphics.palette.Palette;
import com.android.media.RoutePlayer;
import com.android.media.subtitle.ClosedCaptionRenderer;
@@ -73,10 +74,10 @@
import com.android.media.subtitle.SubtitleTrack;
import com.android.media.update.ApiHelper;
import com.android.media.update.R;
-import com.android.support.mediarouter.media.MediaItemStatus;
import com.android.support.mediarouter.media.MediaControlIntent;
-import com.android.support.mediarouter.media.MediaRouter;
+import com.android.support.mediarouter.media.MediaItemStatus;
import com.android.support.mediarouter.media.MediaRouteSelector;
+import com.android.support.mediarouter.media.MediaRouter;
import java.util.ArrayList;
import java.util.List;
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 7419e64..c0aa477 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -2,24 +2,6 @@
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := \
- ServiceUtilities.cpp
-
-# FIXME Move this library to frameworks/native
-LOCAL_MODULE := libserviceutility
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libutils \
- liblog \
- libbinder
-
-LOCAL_CFLAGS := -Wall -Werror
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-
LOCAL_SRC_FILES:= \
AudioFlinger.cpp \
Threads.cpp \
@@ -31,7 +13,8 @@
PatchPanel.cpp \
StateQueue.cpp \
BufLog.cpp \
- TypedLogger.cpp
+ TypedLogger.cpp \
+ NBAIO_Tee.cpp \
LOCAL_C_INCLUDES := \
frameworks/av/services/audiopolicy \
@@ -53,13 +36,13 @@
libnbaio \
libnblog \
libpowermanager \
- libserviceutility \
libmediautils \
libmemunreachable \
libmedia_helper
LOCAL_STATIC_LIBRARIES := \
libcpustats \
+ libsndfile \
LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
@@ -82,6 +65,7 @@
LOCAL_CFLAGS += -fvisibility=hidden
LOCAL_CFLAGS += -Werror -Wall
+LOCAL_SANITIZE := integer_overflow
include $(BUILD_SHARED_LIBRARY)
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index bdd39c6..13477f3 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -28,7 +28,6 @@
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
-#include <cutils/multiuser.h>
#include <utils/Log.h>
#include <utils/Trace.h>
#include <binder/Parcel.h>
@@ -47,7 +46,7 @@
#include <system/audio.h>
#include "AudioFlinger.h"
-#include "ServiceUtilities.h"
+#include "NBAIO_Tee.h"
#include <media/AudioResamplerPublic.h>
@@ -56,7 +55,6 @@
#include <system/audio_effects/effect_aec.h>
#include <audio_utils/primitives.h>
-#include <audio_utils/string.h>
#include <powermanager/PowerManager.h>
@@ -66,6 +64,7 @@
#include <media/nbaio/PipeReader.h>
#include <media/AudioParameter.h>
#include <mediautils/BatteryNotifier.h>
+#include <mediautils/ServiceUtilities.h>
#include <private/android_filesystem_config.h>
//#define BUFLOG_NDEBUG 0
@@ -100,17 +99,6 @@
uint32_t AudioFlinger::mScreenState;
-
-#ifdef TEE_SINK
-bool AudioFlinger::mTeeSinkInputEnabled = false;
-bool AudioFlinger::mTeeSinkOutputEnabled = false;
-bool AudioFlinger::mTeeSinkTrackEnabled = false;
-
-size_t AudioFlinger::mTeeSinkInputFrames = kTeeSinkInputFramesDefault;
-size_t AudioFlinger::mTeeSinkOutputFrames = kTeeSinkOutputFramesDefault;
-size_t AudioFlinger::mTeeSinkTrackFrames = kTeeSinkTrackFramesDefault;
-#endif
-
// In order to avoid invalidating offloaded tracks each time a Visualizer is turned on and off
// we define a minimum time during which a global effect is considered enabled.
static const nsecs_t kMinGlobalEffectEnabletimeNs = seconds(7200);
@@ -160,6 +148,7 @@
mTotalMemory(0),
mClientSharedHeapSize(kMinimumClientSharedHeapSizeBytes),
mGlobalEffectEnableTime(0),
+ mPatchPanel(this),
mSystemReady(false)
{
// unsigned instead of audio_unique_id_use_t, because ++ operator is unavailable for enum
@@ -168,7 +157,6 @@
mNextUniqueIds[use] = AUDIO_UNIQUE_ID_USE_MAX;
}
- getpid_cached = getpid();
const bool doLog = property_get_bool("ro.test_harness", false);
if (doLog) {
mLogMemoryDealer = new MemoryDealer(kLogMemorySize, "LogWriters",
@@ -185,27 +173,6 @@
mEffectsFactoryHal = EffectsFactoryHalInterface::create();
mMediaLogNotifier->run("MediaLogNotifier");
-
-#ifdef TEE_SINK
- char value[PROPERTY_VALUE_MAX];
- (void) property_get("ro.debuggable", value, "0");
- int debuggable = atoi(value);
- int teeEnabled = 0;
- if (debuggable) {
- (void) property_get("af.tee", value, "0");
- teeEnabled = atoi(value);
- }
- // FIXME symbolic constants here
- if (teeEnabled & 1) {
- mTeeSinkInputEnabled = true;
- }
- if (teeEnabled & 2) {
- mTeeSinkOutputEnabled = true;
- }
- if (teeEnabled & 4) {
- mTeeSinkTrackEnabled = true;
- }
-#endif
}
void AudioFlinger::onFirstRef()
@@ -226,8 +193,6 @@
}
}
- mPatchPanel = new PatchPanel(this);
-
mMode = AUDIO_MODE_NORMAL;
gAudioFlinger = this;
@@ -534,12 +499,7 @@
dev->dump(fd);
}
-#ifdef TEE_SINK
- // dump the serially shared record tee sink
- if (mRecordTeeSource != 0) {
- dumpTee(fd, mRecordTeeSource, AUDIO_IO_HANDLE_NONE, 'C');
- }
-#endif
+ mPatchPanel.dump(fd);
BUFLOG_RESET;
@@ -547,6 +507,10 @@
mLock.unlock();
}
+#ifdef TEE_SINK
+ // NBAIO_Tee dump is safe to call outside of AF lock.
+ NBAIO_Tee::dumpAll(fd, "_DUMP");
+#endif
// append a copy of media.log here by forwarding fd to it, but don't attempt
// to lookup the service if it's not running, as it will block for a second
if (sMediaLogServiceAsBinder != 0) {
@@ -666,7 +630,7 @@
bool updatePid = (input.clientInfo.clientPid == -1);
const uid_t callingUid = IPCThreadState::self()->getCallingUid();
uid_t clientUid = input.clientInfo.clientUid;
- if (!isTrustedCallingUid(callingUid)) {
+ if (!isAudioServerOrMediaServerUid(callingUid)) {
ALOGW_IF(clientUid != callingUid,
"%s uid %d tried to pass itself off as %d",
__FUNCTION__, callingUid, clientUid);
@@ -1078,9 +1042,9 @@
ALOGW("checkStreamType() invalid stream %d", stream);
return BAD_VALUE;
}
- pid_t caller = IPCThreadState::self()->getCallingPid();
- if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT && caller != getpid_cached) {
- ALOGW("checkStreamType() pid %d cannot use internal stream type %d", caller, stream);
+ const uid_t callerUid = IPCThreadState::self()->getCallingUid();
+ if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT && !isAudioServerUid(callerUid)) {
+ ALOGW("checkStreamType() uid %d cannot use internal stream type %d", callerUid, stream);
return PERMISSION_DENIED;
}
@@ -1200,9 +1164,8 @@
String8(AudioParameter::keyStreamSupportedSamplingRates),
};
- // multiuser friendly app ID check for requests coming from audioserver
- if (multiuser_get_app_id(callingUid) == AID_AUDIOSERVER) {
- return;
+ if (isAudioServerUid(callingUid)) {
+ return; // no need to filter if audioserver.
}
AudioParameter param = AudioParameter(keyValuePairs);
@@ -1636,7 +1599,7 @@
bool updatePid = (input.clientInfo.clientPid == -1);
const uid_t callingUid = IPCThreadState::self()->getCallingUid();
uid_t clientUid = input.clientInfo.clientUid;
- if (!isTrustedCallingUid(callingUid)) {
+ if (!isAudioServerOrMediaServerUid(callingUid)) {
ALOGW_IF(clientUid != callingUid,
"%s uid %d tried to pass itself off as %d",
__FUNCTION__, callingUid, clientUid);
@@ -1885,7 +1848,7 @@
status_t AudioFlinger::setLowRamDevice(bool isLowRamDevice, int64_t totalMemory)
{
uid_t uid = IPCThreadState::self()->getCallingUid();
- if (uid != AID_SYSTEM) {
+ if (!isAudioServerOrSystemServerUid(uid)) {
return PERMISSION_DENIED;
}
Mutex::Autolock _l(mLock);
@@ -1930,6 +1893,28 @@
return mClientSharedHeapSize;
}
+status_t AudioFlinger::setAudioPortConfig(const struct audio_port_config *config)
+{
+ ALOGV(__func__);
+
+ audio_module_handle_t module;
+ if (config->type == AUDIO_PORT_TYPE_DEVICE) {
+ module = config->ext.device.hw_module;
+ } else {
+ module = config->ext.mix.hw_module;
+ }
+
+ Mutex::Autolock _l(mLock);
+ ssize_t index = mAudioHwDevs.indexOfKey(module);
+ if (index < 0) {
+ ALOGW("%s() bad hw module %d", __func__, module);
+ return BAD_VALUE;
+ }
+
+ AudioHwDevice *audioHwDevice = mAudioHwDevs.valueAt(index);
+ return audioHwDevice->hwDevice()->setAudioPortConfig(config);
+}
+
audio_hw_sync_t AudioFlinger::getAudioHwSyncForSession(audio_session_t sessionId)
{
Mutex::Autolock _l(mLock);
@@ -2274,7 +2259,7 @@
delete out;
}
-void AudioFlinger::closeOutputInternal_l(const sp<PlaybackThread>& thread)
+void AudioFlinger::closeThreadInternal_l(const sp<PlaybackThread>& thread)
{
mPlaybackThreads.removeItem(thread->mId);
thread->exit();
@@ -2407,55 +2392,6 @@
thread.get());
return thread;
} else {
-#ifdef TEE_SINK
- // Try to re-use most recently used Pipe to archive a copy of input for dumpsys,
- // or (re-)create if current Pipe is idle and does not match the new format
- sp<NBAIO_Sink> teeSink;
- enum {
- TEE_SINK_NO, // don't copy input
- TEE_SINK_NEW, // copy input using a new pipe
- TEE_SINK_OLD, // copy input using an existing pipe
- } kind;
- NBAIO_Format format = Format_from_SR_C(halconfig.sample_rate,
- audio_channel_count_from_in_mask(halconfig.channel_mask), halconfig.format);
- if (!mTeeSinkInputEnabled) {
- kind = TEE_SINK_NO;
- } else if (!Format_isValid(format)) {
- kind = TEE_SINK_NO;
- } else if (mRecordTeeSink == 0) {
- kind = TEE_SINK_NEW;
- } else if (mRecordTeeSink->getStrongCount() != 1) {
- kind = TEE_SINK_NO;
- } else if (Format_isEqual(format, mRecordTeeSink->format())) {
- kind = TEE_SINK_OLD;
- } else {
- kind = TEE_SINK_NEW;
- }
- switch (kind) {
- case TEE_SINK_NEW: {
- Pipe *pipe = new Pipe(mTeeSinkInputFrames, format);
- size_t numCounterOffers = 0;
- const NBAIO_Format offers[1] = {format};
- ssize_t index = pipe->negotiate(offers, 1, NULL, numCounterOffers);
- ALOG_ASSERT(index == 0);
- PipeReader *pipeReader = new PipeReader(*pipe);
- numCounterOffers = 0;
- index = pipeReader->negotiate(offers, 1, NULL, numCounterOffers);
- ALOG_ASSERT(index == 0);
- mRecordTeeSink = pipe;
- mRecordTeeSource = pipeReader;
- teeSink = pipe;
- }
- break;
- case TEE_SINK_OLD:
- teeSink = mRecordTeeSink;
- break;
- case TEE_SINK_NO:
- default:
- break;
- }
-#endif
-
// Start record thread
// RecordThread requires both input and output device indication to forward to audio
// pre processing modules
@@ -2465,9 +2401,6 @@
primaryOutputDevice_l(),
devices,
mSystemReady
-#ifdef TEE_SINK
- , teeSink
-#endif
);
mRecordThreads.add(*input, thread);
ALOGV("openInput_l() created record thread: ID %d thread %p", *input, thread.get());
@@ -2567,7 +2500,7 @@
delete in;
}
-void AudioFlinger::closeInputInternal_l(const sp<RecordThread>& thread)
+void AudioFlinger::closeThreadInternal_l(const sp<RecordThread>& thread)
{
mRecordThreads.removeItem(thread->mId);
closeInputFinish(thread);
@@ -2605,7 +2538,8 @@
Mutex::Autolock _l(mLock);
pid_t caller = IPCThreadState::self()->getCallingPid();
ALOGV("acquiring %d from %d, for %d", audioSession, caller, pid);
- if (pid != -1 && (caller == getpid_cached)) {
+ const uid_t callerUid = IPCThreadState::self()->getCallingUid();
+ if (pid != -1 && isAudioServerUid(callerUid)) { // check must match releaseAudioSessionId()
caller = pid;
}
@@ -2639,7 +2573,8 @@
Mutex::Autolock _l(mLock);
pid_t caller = IPCThreadState::self()->getCallingPid();
ALOGV("releasing %d from %d for %d", audioSession, caller, pid);
- if (pid != -1 && (caller == getpid_cached)) {
+ const uid_t callerUid = IPCThreadState::self()->getCallingUid();
+ if (pid != -1 && isAudioServerUid(callerUid)) { // check must match acquireAudioSessionId()
caller = pid;
}
size_t num = mAudioSessionRefs.size();
@@ -2656,9 +2591,10 @@
return;
}
}
- // If the caller is mediaserver it is likely that the session being released was acquired
+ // If the caller is audioserver it is likely that the session being released was acquired
// on behalf of a process not in notification clients and we ignore the warning.
- ALOGW_IF(caller != getpid_cached, "session id %d not found for pid %d", audioSession, caller);
+ ALOGW_IF(!isAudioServerUid(callerUid),
+ "session id %d not found for pid %d", audioSession, caller);
}
bool AudioFlinger::isSessionAcquired_l(audio_session_t audioSession)
@@ -2966,7 +2902,7 @@
effect_descriptor_t desc;
const uid_t callingUid = IPCThreadState::self()->getCallingUid();
- if (pid == -1 || !isTrustedCallingUid(callingUid)) {
+ if (pid == -1 || !isAudioServerOrMediaServerUid(callingUid)) {
const pid_t callingPid = IPCThreadState::self()->getCallingPid();
ALOGW_IF(pid != -1 && pid != callingPid,
"%s uid %d pid %d tried to pass itself off as pid %d",
@@ -2989,8 +2925,8 @@
}
// Session AUDIO_SESSION_OUTPUT_STAGE is reserved for output stage effects
- // that can only be created by audio policy manager (running in same process)
- if (sessionId == AUDIO_SESSION_OUTPUT_STAGE && getpid_cached != pid) {
+ // that can only be created by audio policy manager
+ if (sessionId == AUDIO_SESSION_OUTPUT_STAGE && !isAudioServerUid(callingUid)) {
lStatus = PERMISSION_DENIED;
goto Exit;
}
@@ -3370,136 +3306,6 @@
}
-struct Entry {
-#define TEE_MAX_FILENAME 32 // %Y%m%d%H%M%S_%d.wav = 4+2+2+2+2+2+1+1+4+1 = 21
- char mFileName[TEE_MAX_FILENAME];
-};
-
-int comparEntry(const void *p1, const void *p2)
-{
- return strcmp(((const Entry *) p1)->mFileName, ((const Entry *) p2)->mFileName);
-}
-
-#ifdef TEE_SINK
-void AudioFlinger::dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_handle_t id, char suffix)
-{
- NBAIO_Source *teeSource = source.get();
- if (teeSource != NULL) {
- // .wav rotation
- // There is a benign race condition if 2 threads call this simultaneously.
- // They would both traverse the directory, but the result would simply be
- // failures at unlink() which are ignored. It's also unlikely since
- // normally dumpsys is only done by bugreport or from the command line.
- char teePath[PATH_MAX] = "/data/misc/audioserver";
- size_t teePathLen = strlen(teePath);
- DIR *dir = opendir(teePath);
- teePath[teePathLen++] = '/';
- if (dir != NULL) {
-#define TEE_MAX_SORT 20 // number of entries to sort
-#define TEE_MAX_KEEP 10 // number of entries to keep
- struct Entry entries[TEE_MAX_SORT];
- size_t entryCount = 0;
- while (entryCount < TEE_MAX_SORT) {
- errno = 0; // clear errno before readdir() to track potential errors.
- const struct dirent *result = readdir(dir);
- if (result == nullptr) {
- ALOGW_IF(errno != 0, "tee readdir() failure %s", strerror(errno));
- break;
- }
- // ignore non .wav file entries
- const size_t nameLen = strlen(result->d_name);
- if (nameLen <= 4 || nameLen >= TEE_MAX_FILENAME ||
- strcmp(&result->d_name[nameLen - 4], ".wav")) {
- continue;
- }
- (void)audio_utils_strlcpy(entries[entryCount++].mFileName, result->d_name);
- }
- (void) closedir(dir);
- if (entryCount > TEE_MAX_KEEP) {
- qsort(entries, entryCount, sizeof(Entry), comparEntry);
- for (size_t i = 0; i < entryCount - TEE_MAX_KEEP; ++i) {
- strcpy(&teePath[teePathLen], entries[i].mFileName);
- (void) unlink(teePath);
- }
- }
- } else {
- if (fd >= 0) {
- dprintf(fd, "unable to rotate tees in %.*s: %s\n", (int) teePathLen, teePath,
- strerror(errno));
- }
- }
- char teeTime[16];
- struct timeval tv;
- gettimeofday(&tv, NULL);
- struct tm tm;
- localtime_r(&tv.tv_sec, &tm);
- strftime(teeTime, sizeof(teeTime), "%Y%m%d%H%M%S", &tm);
- snprintf(&teePath[teePathLen], sizeof(teePath) - teePathLen, "%s_%d_%c.wav", teeTime, id,
- suffix);
- // if 2 dumpsys are done within 1 second, and rotation didn't work, then discard 2nd
- int teeFd = open(teePath, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, S_IRUSR | S_IWUSR);
- if (teeFd >= 0) {
- // FIXME use libsndfile
- char wavHeader[44];
- memcpy(wavHeader,
- "RIFF\0\0\0\0WAVEfmt \20\0\0\0\1\0\2\0\104\254\0\0\0\0\0\0\4\0\20\0data\0\0\0\0",
- sizeof(wavHeader));
- NBAIO_Format format = teeSource->format();
- unsigned channelCount = Format_channelCount(format);
- uint32_t sampleRate = Format_sampleRate(format);
- size_t frameSize = Format_frameSize(format);
- wavHeader[22] = channelCount; // number of channels
- wavHeader[24] = sampleRate; // sample rate
- wavHeader[25] = sampleRate >> 8;
- wavHeader[32] = frameSize; // block alignment
- wavHeader[33] = frameSize >> 8;
- write(teeFd, wavHeader, sizeof(wavHeader));
- size_t total = 0;
- bool firstRead = true;
-#define TEE_SINK_READ 1024 // frames per I/O operation
- void *buffer = malloc(TEE_SINK_READ * frameSize);
- for (;;) {
- size_t count = TEE_SINK_READ;
- ssize_t actual = teeSource->read(buffer, count);
- bool wasFirstRead = firstRead;
- firstRead = false;
- if (actual <= 0) {
- if (actual == (ssize_t) OVERRUN && wasFirstRead) {
- continue;
- }
- break;
- }
- ALOG_ASSERT(actual <= (ssize_t)count);
- write(teeFd, buffer, actual * frameSize);
- total += actual;
- }
- free(buffer);
- lseek(teeFd, (off_t) 4, SEEK_SET);
- uint32_t temp = 44 + total * frameSize - 8;
- // FIXME not big-endian safe
- write(teeFd, &temp, sizeof(temp));
- lseek(teeFd, (off_t) 40, SEEK_SET);
- temp = total * frameSize;
- // FIXME not big-endian safe
- write(teeFd, &temp, sizeof(temp));
- close(teeFd);
- // TODO Should create file with temporary name and then rename to final if non-empty.
- if (total > 0) {
- if (fd >= 0) {
- dprintf(fd, "tee copied to %s\n", teePath);
- }
- } else {
- unlink(teePath);
- }
- } else {
- if (fd >= 0) {
- dprintf(fd, "unable to create tee %s: %s\n", teePath, strerror(errno));
- }
- }
- }
-}
-#endif
-
// ----------------------------------------------------------------------------
status_t AudioFlinger::onTransact(
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 963a87d..a59c13e 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -71,6 +71,7 @@
#include "AudioStreamOut.h"
#include "SpdifStreamOut.h"
#include "AudioHwDevice.h"
+#include "NBAIO_Tee.h"
#include <powermanager/IPowerManager.h>
@@ -791,44 +792,16 @@
// for use from destructor
status_t closeOutput_nonvirtual(audio_io_handle_t output);
- void closeOutputInternal_l(const sp<PlaybackThread>& thread);
+ void closeThreadInternal_l(const sp<PlaybackThread>& thread);
status_t closeInput_nonvirtual(audio_io_handle_t input);
- void closeInputInternal_l(const sp<RecordThread>& thread);
+ void closeThreadInternal_l(const sp<RecordThread>& thread);
void setAudioHwSyncForSession_l(PlaybackThread *thread, audio_session_t sessionId);
status_t checkStreamType(audio_stream_type_t stream) const;
void filterReservedParameters(String8& keyValuePairs, uid_t callingUid);
-#ifdef TEE_SINK
- // all record threads serially share a common tee sink, which is re-created on format change
- sp<NBAIO_Sink> mRecordTeeSink;
- sp<NBAIO_Source> mRecordTeeSource;
-#endif
-
public:
-
-#ifdef TEE_SINK
- // tee sink, if enabled by property, allows dumpsys to write most recent audio to .wav file
- static void dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_handle_t id, char suffix);
-
- // whether tee sink is enabled by property
- static bool mTeeSinkInputEnabled;
- static bool mTeeSinkOutputEnabled;
- static bool mTeeSinkTrackEnabled;
-
- // runtime configured size of each tee sink pipe, in frames
- static size_t mTeeSinkInputFrames;
- static size_t mTeeSinkOutputFrames;
- static size_t mTeeSinkTrackFrames;
-
- // compile-time default size of tee sink pipes, in frames
- // 0x200000 stereo 16-bit PCM frames = 47.5 seconds at 44.1 kHz, 8 megabytes
- static const size_t kTeeSinkInputFramesDefault = 0x200000;
- static const size_t kTeeSinkOutputFramesDefault = 0x200000;
- static const size_t kTeeSinkTrackFramesDefault = 0x200000;
-#endif
-
// These methods read variables atomically without mLock,
// though the variables are updated with mLock.
bool isLowRamDevice() const { return mIsLowRamDevice; }
@@ -843,7 +816,8 @@
nsecs_t mGlobalEffectEnableTime; // when a global effect was last enabled
- sp<PatchPanel> mPatchPanel;
+ // protected by mLock
+ PatchPanel mPatchPanel;
sp<EffectsFactoryHalInterface> mEffectsFactoryHal;
bool mSystemReady;
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 2047dfd..786c4af 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -31,9 +31,9 @@
#include <media/AudioEffect.h>
#include <media/audiohal/EffectHalInterface.h>
#include <media/audiohal/EffectsFactoryHalInterface.h>
+#include <mediautils/ServiceUtilities.h>
#include "AudioFlinger.h"
-#include "ServiceUtilities.h"
// ----------------------------------------------------------------------------
@@ -1815,7 +1815,7 @@
bool locked = mCblk != NULL && AudioFlinger::dumpTryLock(mCblk->lock);
snprintf(buffer, size, "\t\t\t%5d %5d %3s %3s %5u %5u\n",
- (mClient == 0) ? getpid_cached : mClient->pid(),
+ (mClient == 0) ? getpid() : mClient->pid(),
mPriority,
mHasControl ? "yes" : "no",
locked ? "yes" : "no",
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index 79bb9fe..caeede9 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -47,7 +47,8 @@
/*static*/ const FastMixerState FastMixer::sInitial;
-FastMixer::FastMixer() : FastThread("cycle_ms", "load_us"),
+FastMixer::FastMixer(audio_io_handle_t parentIoHandle)
+ : FastThread("cycle_ms", "load_us"),
// mFastTrackNames
// mGenerations
mOutputSink(NULL),
@@ -66,8 +67,11 @@
mTotalNativeFramesWritten(0),
// timestamp
mNativeFramesWrittenButNotPresented(0), // the = 0 is to silence the compiler
- mMasterMono(false)
+ mMasterMono(false),
+ mThreadIoHandle(parentIoHandle)
{
+ (void)mThreadIoHandle; // prevent unused warning, see C++17 [[maybe_unused]]
+
// FIXME pass sInitial as parameter to base class constructor, and make it static local
mPrevious = &sInitial;
mCurrent = &sInitial;
@@ -220,6 +224,10 @@
previousTrackMask = 0;
mFastTracksGen = current->mFastTracksGen - 1;
dumpState->mFrameCount = frameCount;
+#ifdef TEE_SINK
+ mTee.set(mFormat, NBAIO_Tee::TEE_FLAG_OUTPUT_THREAD);
+ mTee.setId(std::string("_") + std::to_string(mThreadIoHandle) + "_F");
+#endif
} else {
previousTrackMask = previous->mTrackMask;
}
@@ -446,10 +454,9 @@
frameCount * Format_channelCount(mFormat));
}
// if non-NULL, then duplicate write() to this non-blocking sink
- NBAIO_Sink* teeSink;
- if ((teeSink = current->mTeeSink) != NULL) {
- (void) teeSink->write(buffer, frameCount);
- }
+#ifdef TEE_SINK
+ mTee.write(buffer, frameCount);
+#endif
// FIXME write() is non-blocking and lock-free for a properly implemented NBAIO sink,
// but this code should be modified to handle both non-blocking and blocking sinks
dumpState->mWriteSequence++;
@@ -482,6 +489,10 @@
timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL];
mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] =
timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL];
+ // We don't compensate for server - kernel time difference and
+ // only update latency if we have valid info.
+ dumpState->mLatencyMs =
+ (double)mNativeFramesWrittenButNotPresented * 1000 / mSampleRate;
} else {
// HAL reported that more frames were presented than were written
mNativeFramesWrittenButNotPresented = 0;
diff --git a/services/audioflinger/FastMixer.h b/services/audioflinger/FastMixer.h
index 235d23f..1c86d9a 100644
--- a/services/audioflinger/FastMixer.h
+++ b/services/audioflinger/FastMixer.h
@@ -22,6 +22,7 @@
#include "StateQueue.h"
#include "FastMixerState.h"
#include "FastMixerDumpState.h"
+#include "NBAIO_Tee.h"
namespace android {
@@ -32,7 +33,9 @@
class FastMixer : public FastThread {
public:
- FastMixer();
+ /** FastMixer constructor takes as param the parent MixerThread's io handle (id)
+ for purposes of identification. */
+ explicit FastMixer(audio_io_handle_t threadIoHandle);
virtual ~FastMixer();
FastMixerStateQueue* sq();
@@ -87,6 +90,11 @@
// accessed without lock between multiple threads.
std::atomic_bool mMasterMono;
std::atomic_int_fast64_t mBoottimeOffset;
+
+ const audio_io_handle_t mThreadIoHandle; // parent thread id for debugging purposes
+#ifdef TEE_SINK
+ NBAIO_Tee mTee;
+#endif
}; // class FastMixer
} // namespace android
diff --git a/services/audioflinger/FastMixerDumpState.cpp b/services/audioflinger/FastMixerDumpState.cpp
index 2e4fb8c..b3a2520 100644
--- a/services/audioflinger/FastMixerDumpState.cpp
+++ b/services/audioflinger/FastMixerDumpState.cpp
@@ -68,11 +68,11 @@
dprintf(fd, " FastMixer command=%s writeSequence=%u framesWritten=%u\n"
" numTracks=%u writeErrors=%u underruns=%u overruns=%u\n"
" sampleRate=%u frameCount=%zu measuredWarmup=%.3g ms, warmupCycles=%u\n"
- " mixPeriod=%.2f ms\n",
+ " mixPeriod=%.2f ms latency=%.2f ms\n",
FastMixerState::commandToString(mCommand), mWriteSequence, mFramesWritten,
mNumTracks, mWriteErrors, mUnderruns, mOverruns,
mSampleRate, mFrameCount, measuredWarmupMs, mWarmupCycles,
- mixPeriodSec * 1e3);
+ mixPeriodSec * 1e3, mLatencyMs);
#ifdef FAST_THREAD_STATISTICS
// find the interval of valid samples
uint32_t bounds = mBounds;
diff --git a/services/audioflinger/FastMixerDumpState.h b/services/audioflinger/FastMixerDumpState.h
index 8ef31d1..aed6bc5 100644
--- a/services/audioflinger/FastMixerDumpState.h
+++ b/services/audioflinger/FastMixerDumpState.h
@@ -66,6 +66,7 @@
void dump(int fd) const; // should only be called on a stable copy, not the original
+ double mLatencyMs = 0.; // measured latency, default of 0 if no valid timestamp read.
uint32_t mWriteSequence; // incremented before and after each write()
uint32_t mFramesWritten; // total number of frames written successfully
uint32_t mNumTracks; // total number of active fast tracks
diff --git a/services/audioflinger/FastMixerState.cpp b/services/audioflinger/FastMixerState.cpp
index 36d8eef..b98842d 100644
--- a/services/audioflinger/FastMixerState.cpp
+++ b/services/audioflinger/FastMixerState.cpp
@@ -35,7 +35,7 @@
FastMixerState::FastMixerState() : FastThreadState(),
// mFastTracks
mFastTracksGen(0), mTrackMask(0), mOutputSink(NULL), mOutputSinkGen(0),
- mFrameCount(0), mTeeSink(NULL)
+ mFrameCount(0)
{
int ok = pthread_once(&sMaxFastTracksOnce, sMaxFastTracksInit);
if (ok != 0) {
diff --git a/services/audioflinger/FastMixerState.h b/services/audioflinger/FastMixerState.h
index 2be1e91..c7fcbd8 100644
--- a/services/audioflinger/FastMixerState.h
+++ b/services/audioflinger/FastMixerState.h
@@ -77,9 +77,6 @@
WRITE = 0x10, // write to output sink
MIX_WRITE = 0x18; // mix tracks and write to output sink
- // This might be a one-time configuration rather than per-state
- NBAIO_Sink* mTeeSink; // if non-NULL, then duplicate write()s to this non-blocking sink
-
// never returns NULL; asserts if command is invalid
static const char *commandToString(Command command);
diff --git a/services/audioflinger/NBAIO_Tee.cpp b/services/audioflinger/NBAIO_Tee.cpp
new file mode 100644
index 0000000..53083d5
--- /dev/null
+++ b/services/audioflinger/NBAIO_Tee.cpp
@@ -0,0 +1,517 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "NBAIO_Tee"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+
+#include <deque>
+#include <dirent.h>
+#include <future>
+#include <list>
+#include <vector>
+
+#include <audio_utils/format.h>
+#include <audio_utils/sndfile.h>
+#include <media/nbaio/PipeReader.h>
+
+#include "Configuration.h"
+#include "NBAIO_Tee.h"
+
+// Enabled with TEE_SINK in Configuration.h
+#ifdef TEE_SINK
+
+namespace android {
+
+/*
+ Tee filenames generated as follows:
+
+ "aftee_Date_ThreadId_C_reason.wav" RecordThread
+ "aftee_Date_ThreadId_M_reason.wav" MixerThread (Normal)
+ "aftee_Date_ThreadId_F_reason.wav" MixerThread (Fast)
+ "aftee_Date_ThreadId_TrackId_R_reason.wav" RecordTrack
+ "aftee_Date_ThreadId_TrackId_TrackName_T_reason.wav" PlaybackTrack
+
+ where Date = YYYYmmdd_HHMMSS_MSEC
+
+ where Reason = [ DTOR | DUMP | REMOVE ]
+
+ Examples:
+ aftee_20180424_153811_038_13_57_2_T_REMOVE.wav
+ aftee_20180424_153811_218_13_57_2_T_REMOVE.wav
+ aftee_20180424_153811_378_13_57_2_T_REMOVE.wav
+ aftee_20180424_153825_147_62_C_DUMP.wav
+ aftee_20180424_153825_148_62_59_R_DUMP.wav
+ aftee_20180424_153825_149_13_F_DUMP.wav
+ aftee_20180424_153842_125_62_59_R_REMOVE.wav
+ aftee_20180424_153842_168_62_C_DTOR.wav
+*/
+
+static constexpr char DEFAULT_PREFIX[] = "aftee_";
+static constexpr char DEFAULT_DIRECTORY[] = "/data/misc/audioserver";
+static constexpr size_t DEFAULT_THREADPOOL_SIZE = 8;
+
+/** AudioFileHandler manages temporary audio wav files with a least recently created
+ retention policy.
+
+ The temporary filenames are systematically generated. A common filename prefix,
+ storage directory, and concurrency pool are passed in on creating the object.
+
+ Temporary files are created by "create", which returns a filename generated by
+
+ prefix + 14 char date + suffix
+
+ TODO Move to audio_utils.
+ TODO Avoid pointing two AudioFileHandlers to the same directory and prefix
+ as we don't have a prefix specific lock file. */
+
+class AudioFileHandler {
+public:
+
+ AudioFileHandler(const std::string &prefix, const std::string &directory, size_t pool)
+ : mThreadPool(pool)
+ , mPrefix(prefix)
+ {
+ (void)setDirectory(directory);
+ }
+
+ /** returns filename of created audio file, else empty string on failure. */
+ std::string create(
+ std::function<ssize_t /* frames_read */
+ (void * /* buffer */, size_t /* size_in_frames */)> reader,
+ uint32_t sampleRate,
+ uint32_t channelCount,
+ audio_format_t format,
+ const std::string &suffix);
+
+private:
+ /** sets the current directory. this is currently private to avoid confusion
+ when changing while pending operations are occurring (it's okay, but
+ weakly synchronized). */
+ status_t setDirectory(const std::string &directory);
+
+ /** cleans current directory and returns the directory name done. */
+ status_t clean(std::string *dir = nullptr);
+
+ /** creates an audio file from a reader functor passed in. */
+ status_t createInternal(
+ std::function<ssize_t /* frames_read */
+ (void * /* buffer */, size_t /* size_in_frames */)> reader,
+ uint32_t sampleRate,
+ uint32_t channelCount,
+ audio_format_t format,
+ const std::string &filename);
+
+ static bool isDirectoryValid(const std::string &directory) {
+ return directory.size() > 0 && directory[0] == '/';
+ }
+
+ std::string generateFilename(const std::string &suffix) const {
+ char fileTime[sizeof("YYYYmmdd_HHMMSS_\0")];
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ struct tm tm;
+ localtime_r(&tv.tv_sec, &tm);
+ LOG_ALWAYS_FATAL_IF(strftime(fileTime, sizeof(fileTime), "%Y%m%d_%H%M%S_", &tm) == 0,
+ "incorrect fileTime buffer");
+ char msec[4];
+ (void)snprintf(msec, sizeof(msec), "%03d", (int)(tv.tv_usec / 1000));
+ return mPrefix + fileTime + msec + suffix + ".wav";
+ }
+
+ bool isManagedFilename(const char *name) {
+ constexpr size_t FILENAME_LEN_DATE = 4 + 2 + 2 // %Y%m%d%
+ + 1 + 2 + 2 + 2 // _H%M%S
+ + 1 + 3; //_MSEC
+ const size_t prefixLen = mPrefix.size();
+ const size_t nameLen = strlen(name);
+
+ // reject on size, prefix, and .wav
+ if (nameLen < prefixLen + FILENAME_LEN_DATE + 4 /* .wav */
+ || strncmp(name, mPrefix.c_str(), prefixLen) != 0
+ || strcmp(name + nameLen - 4, ".wav") != 0) {
+ return false;
+ }
+
+ // validate date portion
+ const char *date = name + prefixLen;
+ return std::all_of(date, date + 8, isdigit)
+ && date[8] == '_'
+ && std::all_of(date + 9, date + 15, isdigit)
+ && date[15] == '_'
+ && std::all_of(date + 16, date + 19, isdigit);
+ }
+
+ // yet another ThreadPool implementation.
+ class ThreadPool {
+ public:
+ ThreadPool(size_t size)
+ : mThreadPoolSize(size)
+ { }
+
+ /** launches task "name" with associated function "func".
+ if the threadpool is exhausted, it will launch on calling function */
+ status_t launch(const std::string &name, std::function<status_t()> func);
+
+ private:
+ std::mutex mLock;
+ std::list<std::pair<
+ std::string, std::future<status_t>>> mFutures; // GUARDED_BY(mLock)
+
+ const size_t mThreadPoolSize;
+ } mThreadPool;
+
+ const std::string mPrefix;
+ std::mutex mLock;
+ std::string mDirectory; // GUARDED_BY(mLock)
+ std::deque<std::string> mFiles; // GUARDED_BY(mLock) sorted list of files by creation time
+
+ static constexpr size_t FRAMES_PER_READ = 1024;
+ static constexpr size_t MAX_FILES_READ = 1024;
+ static constexpr size_t MAX_FILES_KEEP = 32;
+};
+
+/* static */
+void NBAIO_Tee::NBAIO_TeeImpl::dumpTee(
+ int fd, const NBAIO_SinkSource &sinkSource, const std::string &suffix)
+{
+ // Singleton. Constructed thread-safe on first call, never destroyed.
+ static AudioFileHandler audioFileHandler(
+ DEFAULT_PREFIX, DEFAULT_DIRECTORY, DEFAULT_THREADPOOL_SIZE);
+
+ auto &source = sinkSource.second;
+ if (source.get() == nullptr) {
+ return;
+ }
+
+ const NBAIO_Format format = source->format();
+ bool firstRead = true;
+ std::string filename = audioFileHandler.create(
+ // this functor must not hold references to stack
+ [firstRead, sinkSource] (void *buffer, size_t frames) mutable {
+ auto &source = sinkSource.second;
+ ssize_t actualRead = source->read(buffer, frames);
+ if (actualRead == (ssize_t)OVERRUN && firstRead) {
+ // recheck once
+ actualRead = source->read(buffer, frames);
+ }
+ firstRead = false;
+ return actualRead;
+ },
+ Format_sampleRate(format),
+ Format_channelCount(format),
+ format.mFormat,
+ suffix);
+
+ if (fd >= 0 && filename.size() > 0) {
+ dprintf(fd, "tee wrote to %s\n", filename.c_str());
+ }
+}
+
+/* static */
+NBAIO_Tee::NBAIO_TeeImpl::NBAIO_SinkSource NBAIO_Tee::NBAIO_TeeImpl::makeSinkSource(
+ const NBAIO_Format &format, size_t frames, bool *enabled)
+{
+ if (Format_isValid(format) && audio_is_linear_pcm(format.mFormat)) {
+ Pipe *pipe = new Pipe(frames, format);
+ size_t numCounterOffers = 0;
+ const NBAIO_Format offers[1] = {format};
+ ssize_t index = pipe->negotiate(offers, 1, NULL, numCounterOffers);
+ if (index != 0) {
+ ALOGW("pipe failure to negotiate: %zd", index);
+ goto exit;
+ }
+ PipeReader *pipeReader = new PipeReader(*pipe);
+ numCounterOffers = 0;
+ index = pipeReader->negotiate(offers, 1, NULL, numCounterOffers);
+ if (index != 0) {
+ ALOGW("pipeReader failure to negotiate: %zd", index);
+ goto exit;
+ }
+ if (enabled != nullptr) *enabled = true;
+ return {pipe, pipeReader};
+ }
+exit:
+ if (enabled != nullptr) *enabled = false;
+ return {nullptr, nullptr};
+}
+
+std::string AudioFileHandler::create(
+ std::function<ssize_t /* frames_read */
+ (void * /* buffer */, size_t /* size_in_frames */)> reader,
+ uint32_t sampleRate,
+ uint32_t channelCount,
+ audio_format_t format,
+ const std::string &suffix)
+{
+ const std::string filename = generateFilename(suffix);
+
+ if (mThreadPool.launch(std::string("create ") + filename,
+ [=]() { return createInternal(reader, sampleRate, channelCount, format, filename); })
+ == NO_ERROR) {
+ return filename;
+ }
+ return "";
+}
+
+status_t AudioFileHandler::setDirectory(const std::string &directory)
+{
+ if (!isDirectoryValid(directory)) return BAD_VALUE;
+
+ // TODO: consider using std::filesystem in C++17
+ DIR *dir = opendir(directory.c_str());
+
+ if (dir == nullptr) {
+ ALOGW("%s: cannot open directory %s", __func__, directory.c_str());
+ return BAD_VALUE;
+ }
+
+ size_t toRemove = 0;
+ decltype(mFiles) files;
+
+ while (files.size() < MAX_FILES_READ) {
+ errno = 0;
+ const struct dirent *result = readdir(dir);
+ if (result == nullptr) {
+ ALOGW_IF(errno != 0, "%s: readdir failure %s", __func__, strerror(errno));
+ break;
+ }
+ // is it a managed filename?
+ if (!isManagedFilename(result->d_name)) {
+ continue;
+ }
+ files.emplace_back(result->d_name);
+ }
+ (void)closedir(dir);
+
+ // OPTIMIZATION: we don't need to stat each file, the filenames names are
+ // already (roughly) ordered by creation date. we use std::deque instead
+ // of std::set for faster insertion and sorting times.
+
+ if (files.size() > MAX_FILES_KEEP) {
+ // removed files can use a partition (no need to do a full sort).
+ toRemove = files.size() - MAX_FILES_KEEP;
+ std::nth_element(files.begin(), files.begin() + toRemove - 1, files.end());
+ }
+
+ // kept files must be sorted.
+ std::sort(files.begin() + toRemove, files.end());
+
+ {
+ std::lock_guard<std::mutex> _l(mLock);
+
+ mDirectory = directory;
+ mFiles = std::move(files);
+ }
+
+ if (toRemove > 0) { // launch a clean in background.
+ (void)mThreadPool.launch(
+ std::string("cleaning ") + directory, [this]() { return clean(); });
+ }
+ return NO_ERROR;
+}
+
+status_t AudioFileHandler::clean(std::string *directory)
+{
+ std::vector<std::string> filesToRemove;
+ std::string dir;
+ {
+ std::lock_guard<std::mutex> _l(mLock);
+
+ if (!isDirectoryValid(mDirectory)) return NO_INIT;
+
+ dir = mDirectory;
+ if (mFiles.size() > MAX_FILES_KEEP) {
+ size_t toRemove = mFiles.size() - MAX_FILES_KEEP;
+
+ // use move and erase to efficiently transfer std::string
+ std::move(mFiles.begin(),
+ mFiles.begin() + toRemove,
+ std::back_inserter(filesToRemove));
+ mFiles.erase(mFiles.begin(), mFiles.begin() + toRemove);
+ }
+ }
+
+ std::string dirp = dir + "/";
+ // remove files outside of lock for better concurrency.
+ for (const auto &file : filesToRemove) {
+ (void)unlink((dirp + file).c_str());
+ }
+
+ // return the directory if requested.
+ if (directory != nullptr) {
+ *directory = dir;
+ }
+ return NO_ERROR;
+}
+
+status_t AudioFileHandler::ThreadPool::launch(
+ const std::string &name, std::function<status_t()> func)
+{
+ if (mThreadPoolSize > 1) {
+ std::lock_guard<std::mutex> _l(mLock);
+ if (mFutures.size() >= mThreadPoolSize) {
+ for (auto it = mFutures.begin(); it != mFutures.end();) {
+ const std::string &filename = it->first;
+ std::future<status_t> &future = it->second;
+ if (!future.valid() ||
+ future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
+ ALOGV("%s: future %s ready", __func__, filename.c_str());
+ it = mFutures.erase(it);
+ } else {
+ ALOGV("%s: future %s not ready", __func__, filename.c_str());
+ ++it;
+ }
+ }
+ }
+ if (mFutures.size() < mThreadPoolSize) {
+ ALOGV("%s: deferred calling %s", __func__, name.c_str());
+ mFutures.emplace_back(name, std::async(std::launch::async, func));
+ return NO_ERROR;
+ }
+ }
+ ALOGV("%s: immediate calling %s", __func__, name.c_str());
+ return func();
+}
+
+status_t AudioFileHandler::createInternal(
+ std::function<ssize_t /* frames_read */
+ (void * /* buffer */, size_t /* size_in_frames */)> reader,
+ uint32_t sampleRate,
+ uint32_t channelCount,
+ audio_format_t format,
+ const std::string &filename)
+{
+ // Attempt to choose the best matching file format.
+ // We can choose any sf_format
+ // but writeFormat must be one of 16, 32, float
+ // due to sf_writef compatibility.
+ int sf_format;
+ audio_format_t writeFormat;
+ switch (format) {
+ case AUDIO_FORMAT_PCM_8_BIT:
+ case AUDIO_FORMAT_PCM_16_BIT:
+ sf_format = SF_FORMAT_PCM_16;
+ writeFormat = AUDIO_FORMAT_PCM_16_BIT;
+ ALOGV("%s: %s using PCM_16 for format %#x", __func__, filename.c_str(), format);
+ break;
+ case AUDIO_FORMAT_PCM_8_24_BIT:
+ case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+ case AUDIO_FORMAT_PCM_32_BIT:
+ sf_format = SF_FORMAT_PCM_32;
+ writeFormat = AUDIO_FORMAT_PCM_32_BIT;
+ ALOGV("%s: %s using PCM_32 for format %#x", __func__, filename.c_str(), format);
+ break;
+ case AUDIO_FORMAT_PCM_FLOAT:
+ sf_format = SF_FORMAT_FLOAT;
+ writeFormat = AUDIO_FORMAT_PCM_FLOAT;
+ ALOGV("%s: %s using PCM_FLOAT for format %#x", __func__, filename.c_str(), format);
+ break;
+ default:
+ // TODO:
+ // handle audio_has_proportional_frames() formats.
+ // handle compressed formats as single byte files.
+ return BAD_VALUE;
+ }
+
+ std::string directory;
+ status_t status = clean(&directory);
+ if (status != NO_ERROR) return status;
+ std::string dirPrefix = directory + "/";
+
+ const std::string path = dirPrefix + filename;
+
+ /* const */ SF_INFO info = {
+ .frames = 0,
+ .samplerate = (int)sampleRate,
+ .channels = (int)channelCount,
+ .format = SF_FORMAT_WAV | sf_format,
+ };
+ SNDFILE *sf = sf_open(path.c_str(), SFM_WRITE, &info);
+ if (sf == nullptr) {
+ return INVALID_OPERATION;
+ }
+
+ size_t total = 0;
+ void *buffer = malloc(FRAMES_PER_READ * std::max(
+ channelCount * audio_bytes_per_sample(writeFormat), //output framesize
+ channelCount * audio_bytes_per_sample(format))); // input framesize
+ if (buffer == nullptr) {
+ sf_close(sf);
+ return NO_MEMORY;
+ }
+
+ for (;;) {
+ const ssize_t actualRead = reader(buffer, FRAMES_PER_READ);
+ if (actualRead <= 0) {
+ break;
+ }
+
+ // Convert input format to writeFormat as needed.
+ if (format != writeFormat) {
+ memcpy_by_audio_format(
+ buffer, writeFormat, buffer, format, actualRead * info.channels);
+ }
+
+ ssize_t reallyWritten;
+ switch (writeFormat) {
+ case AUDIO_FORMAT_PCM_16_BIT:
+ reallyWritten = sf_writef_short(sf, (const int16_t *)buffer, actualRead);
+ break;
+ case AUDIO_FORMAT_PCM_32_BIT:
+ reallyWritten = sf_writef_int(sf, (const int32_t *)buffer, actualRead);
+ break;
+ case AUDIO_FORMAT_PCM_FLOAT:
+ reallyWritten = sf_writef_float(sf, (const float *)buffer, actualRead);
+ break;
+ default:
+ LOG_ALWAYS_FATAL("%s: %s writeFormat: %#x", __func__, filename.c_str(), writeFormat);
+ break;
+ }
+
+ if (reallyWritten < 0) {
+ ALOGW("%s: %s write error: %zd", __func__, filename.c_str(), reallyWritten);
+ break;
+ }
+ total += reallyWritten;
+ if (reallyWritten < actualRead) {
+ ALOGW("%s: %s write short count: %zd < %zd",
+ __func__, filename.c_str(), reallyWritten, actualRead);
+ break;
+ }
+ }
+ sf_close(sf);
+ free(buffer);
+ if (total == 0) {
+ (void)unlink(path.c_str());
+ return NOT_ENOUGH_DATA;
+ }
+
+ // Success: add our name to managed files.
+ {
+ std::lock_guard<std::mutex> _l(mLock);
+ // weak synchronization - only update mFiles if the directory hasn't changed.
+ if (mDirectory == directory) {
+ mFiles.emplace_back(filename); // add to the end to preserve sort.
+ }
+ }
+ return NO_ERROR; // return full path
+}
+
+} // namespace android
+
+#endif // TEE_SINK
diff --git a/services/audioflinger/NBAIO_Tee.h b/services/audioflinger/NBAIO_Tee.h
new file mode 100644
index 0000000..fed8cc8
--- /dev/null
+++ b/services/audioflinger/NBAIO_Tee.h
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Enabled with TEE_SINK in Configuration.h
+#ifndef ANDROID_NBAIO_TEE_H
+#define ANDROID_NBAIO_TEE_H
+
+#ifdef TEE_SINK
+
+#include <atomic>
+#include <mutex>
+#include <set>
+
+#include <cutils/properties.h>
+#include <media/nbaio/NBAIO.h>
+
+namespace android {
+
+/**
+ * The NBAIO_Tee uses the NBAIO Pipe and PipeReader for nonblocking
+ * data collection, for eventual dump to log files.
+ * See https://source.android.com/devices/audio/debugging for how to
+ * enable by ro.debuggable and af.tee properties.
+ *
+ * The write() into the NBAIO_Tee is therefore nonblocking,
+ * but changing NBAIO_Tee formats with set() cannot be done during a write();
+ * usually the caller already implements this mutual exclusion.
+ *
+ * All other calls except set() vs write() may occur at any time.
+ *
+ * dump() disruption is minimized to the caller since system calls are executed
+ * in an asynchronous thread (when possible).
+ *
+ * Currently the NBAIO_Tee is "hardwired" for AudioFlinger support.
+ *
+ * Some AudioFlinger specific notes:
+ *
+ * 1) Tees capture only linear PCM data.
+ * 2) Tees without any data written are considered empty and do not generate
+ * any output files.
+ * 2) Once a Tee dumps data, it is considered "emptied" and new data
+ * needs to be written before another Tee file is generated.
+ * 3) Tee file format is
+ * WAV integer PCM 16 bit for AUDIO_FORMAT_PCM_8_BIT, AUDIO_FORMAT_PCM_16_BIT.
+ * WAV integer PCM 32 bit for AUDIO_FORMAT_PCM_8_24_BIT, AUDIO_FORMAT_PCM_24_BIT_PACKED
+ * AUDIO_FORMAT_PCM_32_BIT.
+ * WAV float PCM 32 bit for AUDIO_FORMAT_PCM_FLOAT.
+ *
+ * Input_Thread:
+ * 1) Capture buffer is teed when read from the HAL, before resampling for the AudioRecord
+ * client.
+ *
+ * Output_Thread:
+ * 1) MixerThreads will tee at the FastMixer output (if it has one) or at the
+ * NormalMixer output (if no FastMixer).
+ * 2) DuplicatingThreads do not tee any mixed data. Apply a tee on the downstream OutputTrack
+ * or on the upstream playback Tracks.
+ * 3) DirectThreads and OffloadThreads do not tee any data. The upstream track
+ * (if linear PCM format) may be teed to discover data.
+ * 4) MmapThreads are not supported.
+ *
+ * Tracks:
+ * 1) RecordTracks and playback Tracks tee as data is being written to or
+ * read from the shared client-server track buffer by the associated Threads.
+ * 2) The mechanism is on the AudioBufferProvider release() so large static Track
+ * playback may not show any Tee data depending on when it is released.
+ * 3) When a track becomes inactive, the Thread will trigger a dump.
+ */
+
+class NBAIO_Tee {
+public:
+ /* TEE_FLAG is used in set() and must match the flags for the af.tee property
+ given in https://source.android.com/devices/audio/debugging
+ */
+ enum TEE_FLAG {
+ TEE_FLAG_NONE = 0,
+ TEE_FLAG_INPUT_THREAD = (1 << 0), // treat as a Tee for input (Capture) Threads
+ TEE_FLAG_OUTPUT_THREAD = (1 << 1), // treat as a Tee for output (Playback) Threads
+ TEE_FLAG_TRACK = (1 << 2), // treat as a Tee for tracks (Record and Playback)
+ };
+
+ NBAIO_Tee()
+ : mTee(std::make_shared<NBAIO_TeeImpl>())
+ {
+ getRunningTees().add(mTee);
+ }
+
+ ~NBAIO_Tee() {
+ getRunningTees().remove(mTee);
+ dump(-1, "_DTOR"); // log any data remaining in Tee.
+ }
+
+ /**
+ * \brief set is used for deferred configuration of Tee.
+ *
+ * May be called anytime except concurrently with write().
+ *
+ * \param format NBAIO_Format used to open NBAIO pipes
+ * \param flags (https://source.android.com/devices/audio/debugging)
+ * - TEE_FLAG_NONE to bypass af.tee property checks (default);
+ * - TEE_FLAG_INPUT_THREAD to check af.tee if input thread logging set;
+ * - TEE_FLAG_OUTPUT_THREAD to check af.tee if output thread logging set;
+ * - TEE_FLAG_TRACK to check af.tee if track logging set.
+ * \param frames number of frames to open the NBAIO pipe (set to 0 to use default).
+ *
+ * \return
+ * - NO_ERROR on success (or format unchanged)
+ * - BAD_VALUE if format or flags invalid.
+ * - PERMISSION_DENIED if flags not allowed by af.tee
+ */
+
+ status_t set(const NBAIO_Format &format,
+ TEE_FLAG flags = TEE_FLAG_NONE, size_t frames = 0) const {
+ return mTee->set(format, flags, frames);
+ }
+
+ status_t set(uint32_t sampleRate, uint32_t channelCount, audio_format_t format,
+ TEE_FLAG flags = TEE_FLAG_NONE, size_t frames = 0) const {
+ return mTee->set(Format_from_SR_C(sampleRate, channelCount, format), flags, frames);
+ }
+
+ /**
+ * \brief write data to the tee.
+ *
+ * This call is lock free (as shared pointer and NBAIO is lock free);
+ * may be called simultaneous to all methods except set().
+ *
+ * \param buffer to write to pipe.
+ * \param frameCount in frames as specified by the format passed to set()
+ */
+
+ void write(const void *buffer, size_t frameCount) const {
+ mTee->write(buffer, frameCount);
+ }
+
+ /** sets Tee id string which identifies the generated file (should be unique). */
+ void setId(const std::string &id) const {
+ mTee->setId(id);
+ }
+
+ /**
+ * \brief dump the audio content written to the Tee.
+ *
+ * \param fd file descriptor to write dumped filename for logging, use -1 to ignore.
+ * \param reason string suffix to append to the generated file.
+ */
+ void dump(int fd, const std::string &reason = "") const {
+ mTee->dump(fd, reason);
+ }
+
+ /**
+ * \brief dump all Tees currently alive.
+ *
+ * \param fd file descriptor to write dumped filename for logging, use -1 to ignore.
+ * \param reason string suffix to append to the generated file.
+ */
+ static void dumpAll(int fd, const std::string &reason = "") {
+ getRunningTees().dump(fd, reason);
+ }
+
+private:
+
+ /** The underlying implementation of the Tee - the lifetime is through
+ a shared pointer so destruction of the NBAIO_Tee container may proceed
+ even though dumping is occurring. */
+ class NBAIO_TeeImpl {
+ public:
+ status_t set(const NBAIO_Format &format, TEE_FLAG flags, size_t frames) {
+ static const int teeConfig = property_get_bool("ro.debuggable", false)
+ ? property_get_int32("af.tee", 0) : 0;
+
+ // check the type of Tee
+ const TEE_FLAG type = TEE_FLAG(
+ flags & (TEE_FLAG_INPUT_THREAD | TEE_FLAG_OUTPUT_THREAD | TEE_FLAG_TRACK));
+
+ // parameter flags can't select multiple types.
+ if (__builtin_popcount(type) > 1) {
+ return BAD_VALUE;
+ }
+
+ // if type is set, we check to see if it is permitted by configuration.
+ if (type != 0 && (type & teeConfig) == 0) {
+ return PERMISSION_DENIED;
+ }
+
+ // determine number of frames for Tee
+ if (frames == 0) {
+ // TODO: consider varying frame count based on type.
+ frames = DEFAULT_TEE_FRAMES;
+ }
+
+ // TODO: should we check minimum number of frames?
+
+ // don't do anything if format and frames are the same.
+ if (Format_isEqual(format, mFormat) && frames == mFrames) {
+ return NO_ERROR;
+ }
+
+ bool enabled = false;
+ auto sinksource = makeSinkSource(format, frames, &enabled);
+
+ // enabled is set if makeSinkSource is successful.
+ // Note: as mentioned in NBAIO_Tee::set(), don't call set() while write() is
+ // ongoing.
+ if (enabled) {
+ std::lock_guard<std::mutex> _l(mLock);
+ mFlags = flags;
+ mFormat = format; // could get this from the Sink.
+ mFrames = frames;
+ mSinkSource = std::move(sinksource);
+ mEnabled.store(true);
+ return NO_ERROR;
+ }
+ return BAD_VALUE;
+ }
+
+ void setId(const std::string &id) {
+ std::lock_guard<std::mutex> _l(mLock);
+ mId = id;
+ }
+
+ void dump(int fd, const std::string &reason) {
+ if (!mDataReady.exchange(false)) return;
+ std::string suffix;
+ NBAIO_SinkSource sinkSource;
+ {
+ std::lock_guard<std::mutex> _l(mLock);
+ suffix = mId + reason;
+ sinkSource = mSinkSource;
+ }
+ dumpTee(fd, sinkSource, suffix);
+ }
+
+ void write(const void *buffer, size_t frameCount) {
+ if (!mEnabled.load() || frameCount == 0) return;
+ (void)mSinkSource.first->write(buffer, frameCount);
+ mDataReady.store(true);
+ }
+
+ private:
+ // TRICKY: We need to keep the NBAIO_Sink and NBAIO_Source both alive at the same time
+ // because PipeReader holds a naked reference (not a strong or weak pointer) to Pipe.
+ using NBAIO_SinkSource = std::pair<sp<NBAIO_Sink>, sp<NBAIO_Source>>;
+
+ static void dumpTee(int fd, const NBAIO_SinkSource& sinkSource, const std::string& suffix);
+
+ static NBAIO_SinkSource makeSinkSource(
+ const NBAIO_Format &format, size_t frames, bool *enabled);
+
+ // 0x200000 stereo 16-bit PCM frames = 47.5 seconds at 44.1 kHz, 8 megabytes
+ static constexpr size_t DEFAULT_TEE_FRAMES = 0x200000;
+
+ // atomic status checking
+ std::atomic<bool> mEnabled{false};
+ std::atomic<bool> mDataReady{false};
+
+ // locked dump information
+ mutable std::mutex mLock;
+ std::string mId; // GUARDED_BY(mLock)
+ TEE_FLAG mFlags = TEE_FLAG_NONE; // GUARDED_BY(mLock)
+ NBAIO_Format mFormat = Format_Invalid; // GUARDED_BY(mLock)
+ size_t mFrames = 0; // GUARDED_BY(mLock)
+ NBAIO_SinkSource mSinkSource; // GUARDED_BY(mLock)
+ };
+
+ /** RunningTees tracks current running tees for dump purposes.
+ It is implemented to have minimal locked regions, to be transparent to the caller. */
+ class RunningTees {
+ public:
+ void add(const std::shared_ptr<NBAIO_TeeImpl> &tee) {
+ std::lock_guard<std::mutex> _l(mLock);
+ ALOGW_IF(!mTees.emplace(tee).second,
+ "%s: %p already exists in mTees", __func__, tee.get());
+ }
+
+ void remove(const std::shared_ptr<NBAIO_TeeImpl> &tee) {
+ std::lock_guard<std::mutex> _l(mLock);
+ ALOGW_IF(mTees.erase(tee) != 1,
+ "%s: %p doesn't exist in mTees", __func__, tee.get());
+ }
+
+ void dump(int fd, const std::string &reason) {
+ std::vector<std::shared_ptr<NBAIO_TeeImpl>> tees; // safe snapshot of tees
+ {
+ std::lock_guard<std::mutex> _l(mLock);
+ tees.insert(tees.end(), mTees.begin(), mTees.end());
+ }
+ for (const auto &tee : tees) {
+ tee->dump(fd, reason);
+ }
+ }
+
+ private:
+ std::mutex mLock;
+ std::set<std::shared_ptr<NBAIO_TeeImpl>> mTees; // GUARDED_BY(mLock)
+ };
+
+ // singleton
+ static RunningTees &getRunningTees() {
+ static RunningTees runningTees;
+ return runningTees;
+ }
+
+ // The NBAIO TeeImpl may have lifetime longer than NBAIO_Tee if
+ // RunningTees::dump() is being called simultaneous to ~NBAIO_Tee().
+ // This is allowed for maximum concurrency.
+ const std::shared_ptr<NBAIO_TeeImpl> mTee;
+}; // NBAIO_Tee
+
+} // namespace android
+
+#endif // TEE_SINK
+#endif // !ANDROID_NBAIO_TEE_H
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index e5cb8a2..c2927ba 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -24,8 +24,9 @@
#include <audio_utils/primitives.h>
#include "AudioFlinger.h"
-#include "ServiceUtilities.h"
#include <media/AudioParameter.h>
+#include <media/PatchBuilder.h>
+#include <mediautils/ServiceUtilities.h>
// ----------------------------------------------------------------------------
@@ -49,107 +50,65 @@
struct audio_port *ports)
{
Mutex::Autolock _l(mLock);
- if (mPatchPanel != 0) {
- return mPatchPanel->listAudioPorts(num_ports, ports);
- }
- return NO_INIT;
+ return mPatchPanel.listAudioPorts(num_ports, ports);
}
/* Get supported attributes for a given audio port */
status_t AudioFlinger::getAudioPort(struct audio_port *port)
{
Mutex::Autolock _l(mLock);
- if (mPatchPanel != 0) {
- return mPatchPanel->getAudioPort(port);
- }
- return NO_INIT;
+ return mPatchPanel.getAudioPort(port);
}
-
/* Connect a patch between several source and sink ports */
status_t AudioFlinger::createAudioPatch(const struct audio_patch *patch,
audio_patch_handle_t *handle)
{
Mutex::Autolock _l(mLock);
- if (mPatchPanel != 0) {
- return mPatchPanel->createAudioPatch(patch, handle);
- }
- return NO_INIT;
+ return mPatchPanel.createAudioPatch(patch, handle);
}
/* Disconnect a patch */
status_t AudioFlinger::releaseAudioPatch(audio_patch_handle_t handle)
{
Mutex::Autolock _l(mLock);
- if (mPatchPanel != 0) {
- return mPatchPanel->releaseAudioPatch(handle);
- }
- return NO_INIT;
+ return mPatchPanel.releaseAudioPatch(handle);
}
-
/* List connected audio ports and they attributes */
status_t AudioFlinger::listAudioPatches(unsigned int *num_patches,
struct audio_patch *patches)
{
Mutex::Autolock _l(mLock);
- if (mPatchPanel != 0) {
- return mPatchPanel->listAudioPatches(num_patches, patches);
- }
- return NO_INIT;
-}
-
-/* Set audio port configuration */
-status_t AudioFlinger::setAudioPortConfig(const struct audio_port_config *config)
-{
- Mutex::Autolock _l(mLock);
- if (mPatchPanel != 0) {
- return mPatchPanel->setAudioPortConfig(config);
- }
- return NO_INIT;
-}
-
-
-AudioFlinger::PatchPanel::PatchPanel(const sp<AudioFlinger>& audioFlinger)
- : mAudioFlinger(audioFlinger)
-{
-}
-
-AudioFlinger::PatchPanel::~PatchPanel()
-{
+ return mPatchPanel.listAudioPatches(num_patches, patches);
}
/* List connected audio ports and their attributes */
status_t AudioFlinger::PatchPanel::listAudioPorts(unsigned int *num_ports __unused,
struct audio_port *ports __unused)
{
- ALOGV("listAudioPorts");
+ ALOGV(__func__);
return NO_ERROR;
}
/* Get supported attributes for a given audio port */
status_t AudioFlinger::PatchPanel::getAudioPort(struct audio_port *port __unused)
{
- ALOGV("getAudioPort");
+ ALOGV(__func__);
return NO_ERROR;
}
-
/* Connect a patch between several source and sink ports */
status_t AudioFlinger::PatchPanel::createAudioPatch(const struct audio_patch *patch,
audio_patch_handle_t *handle)
{
- status_t status = NO_ERROR;
- audio_patch_handle_t halHandle = AUDIO_PATCH_HANDLE_NONE;
- sp<AudioFlinger> audioflinger = mAudioFlinger.promote();
if (handle == NULL || patch == NULL) {
return BAD_VALUE;
}
- ALOGV("createAudioPatch() num_sources %d num_sinks %d handle %d",
- patch->num_sources, patch->num_sinks, *handle);
- if (audioflinger == 0) {
- return NO_INIT;
- }
+ ALOGV("%s() num_sources %d num_sinks %d handle %d",
+ __func__, patch->num_sources, patch->num_sinks, *handle);
+ status_t status = NO_ERROR;
+ audio_patch_handle_t halHandle = AUDIO_PATCH_HANDLE_NONE;
if (patch->num_sources == 0 || patch->num_sources > AUDIO_PATCH_PORTS_MAX ||
(patch->num_sinks == 0 && patch->num_sources != 2) ||
@@ -163,81 +122,73 @@
}
if (*handle != AUDIO_PATCH_HANDLE_NONE) {
- for (size_t index = 0; *handle != 0 && index < mPatches.size(); index++) {
- if (*handle == mPatches[index]->mHandle) {
- ALOGV("createAudioPatch() removing patch handle %d", *handle);
- halHandle = mPatches[index]->mHalHandle;
- Patch *removedPatch = mPatches[index];
- // free resources owned by the removed patch if applicable
- // 1) if a software patch is present, release the playback and capture threads and
- // tracks created. This will also release the corresponding audio HAL patches
- if ((removedPatch->mRecordPatchHandle
- != AUDIO_PATCH_HANDLE_NONE) ||
- (removedPatch->mPlaybackPatchHandle !=
- AUDIO_PATCH_HANDLE_NONE)) {
- clearPatchConnections(removedPatch);
- }
- // 2) if the new patch and old patch source or sink are devices from different
- // hw modules, clear the audio HAL patches now because they will not be updated
- // by call to create_audio_patch() below which will happen on a different HW module
- if (halHandle != AUDIO_PATCH_HANDLE_NONE) {
- audio_module_handle_t hwModule = AUDIO_MODULE_HANDLE_NONE;
- if ((removedPatch->mAudioPatch.sources[0].type == AUDIO_PORT_TYPE_DEVICE) &&
- ((patch->sources[0].type != AUDIO_PORT_TYPE_DEVICE) ||
- (removedPatch->mAudioPatch.sources[0].ext.device.hw_module !=
- patch->sources[0].ext.device.hw_module))) {
- hwModule = removedPatch->mAudioPatch.sources[0].ext.device.hw_module;
- } else if ((patch->num_sinks == 0) ||
- ((removedPatch->mAudioPatch.sinks[0].type == AUDIO_PORT_TYPE_DEVICE) &&
- ((patch->sinks[0].type != AUDIO_PORT_TYPE_DEVICE) ||
- (removedPatch->mAudioPatch.sinks[0].ext.device.hw_module !=
- patch->sinks[0].ext.device.hw_module)))) {
- // Note on (patch->num_sinks == 0): this situation should not happen as
- // these special patches are only created by the policy manager but just
- // in case, systematically clear the HAL patch.
- // Note that removedPatch->mAudioPatch.num_sinks cannot be 0 here because
- // halHandle would be AUDIO_PATCH_HANDLE_NONE in this case.
- hwModule = removedPatch->mAudioPatch.sinks[0].ext.device.hw_module;
- }
- if (hwModule != AUDIO_MODULE_HANDLE_NONE) {
- ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(hwModule);
- if (index >= 0) {
- sp<DeviceHalInterface> hwDevice =
- audioflinger->mAudioHwDevs.valueAt(index)->hwDevice();
- hwDevice->releaseAudioPatch(halHandle);
- }
- }
- }
- mPatches.removeAt(index);
- delete removedPatch;
- break;
+ auto iter = mPatches.find(*handle);
+ if (iter != mPatches.end()) {
+ ALOGV("%s() removing patch handle %d", __func__, *handle);
+ Patch &removedPatch = iter->second;
+ // free resources owned by the removed patch if applicable
+ // 1) if a software patch is present, release the playback and capture threads and
+ // tracks created. This will also release the corresponding audio HAL patches
+ if (removedPatch.isSoftware()) {
+ removedPatch.clearConnections(this);
}
+ // 2) if the new patch and old patch source or sink are devices from different
+ // hw modules, clear the audio HAL patches now because they will not be updated
+ // by call to create_audio_patch() below which will happen on a different HW module
+ if (removedPatch.mHalHandle != AUDIO_PATCH_HANDLE_NONE) {
+ audio_module_handle_t hwModule = AUDIO_MODULE_HANDLE_NONE;
+ const struct audio_patch &oldPatch = removedPatch.mAudioPatch;
+ if (oldPatch.sources[0].type == AUDIO_PORT_TYPE_DEVICE &&
+ (patch->sources[0].type != AUDIO_PORT_TYPE_DEVICE ||
+ oldPatch.sources[0].ext.device.hw_module !=
+ patch->sources[0].ext.device.hw_module)) {
+ hwModule = oldPatch.sources[0].ext.device.hw_module;
+ } else if (patch->num_sinks == 0 ||
+ (oldPatch.sinks[0].type == AUDIO_PORT_TYPE_DEVICE &&
+ (patch->sinks[0].type != AUDIO_PORT_TYPE_DEVICE ||
+ oldPatch.sinks[0].ext.device.hw_module !=
+ patch->sinks[0].ext.device.hw_module))) {
+ // Note on (patch->num_sinks == 0): this situation should not happen as
+ // these special patches are only created by the policy manager but just
+ // in case, systematically clear the HAL patch.
+ // Note that removedPatch.mAudioPatch.num_sinks cannot be 0 here because
+ // removedPatch.mHalHandle would be AUDIO_PATCH_HANDLE_NONE in this case.
+ hwModule = oldPatch.sinks[0].ext.device.hw_module;
+ }
+ sp<DeviceHalInterface> hwDevice = findHwDeviceByModule(hwModule);
+ if (hwDevice != 0) {
+ hwDevice->releaseAudioPatch(removedPatch.mHalHandle);
+ }
+ }
+ mPatches.erase(iter);
}
}
- Patch *newPatch = new Patch(patch);
+ Patch newPatch{*patch};
switch (patch->sources[0].type) {
case AUDIO_PORT_TYPE_DEVICE: {
audio_module_handle_t srcModule = patch->sources[0].ext.device.hw_module;
- ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule);
+ ssize_t index = mAudioFlinger.mAudioHwDevs.indexOfKey(srcModule);
if (index < 0) {
- ALOGW("createAudioPatch() bad src hw module %d", srcModule);
+ ALOGW("%s() bad src hw module %d", __func__, srcModule);
status = BAD_VALUE;
goto exit;
}
- AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
+ AudioHwDevice *audioHwDevice = mAudioFlinger.mAudioHwDevs.valueAt(index);
for (unsigned int i = 0; i < patch->num_sinks; i++) {
// support only one sink if connection to a mix or across HW modules
if ((patch->sinks[i].type == AUDIO_PORT_TYPE_MIX ||
- patch->sinks[i].ext.mix.hw_module != srcModule) &&
+ (patch->sinks[i].type == AUDIO_PORT_TYPE_DEVICE &&
+ patch->sinks[i].ext.device.hw_module != srcModule)) &&
patch->num_sinks > 1) {
+ ALOGW("%s() multiple sinks for mix or across modules not supported", __func__);
status = INVALID_OPERATION;
goto exit;
}
// reject connection to different sink types
if (patch->sinks[i].type != patch->sinks[0].type) {
- ALOGW("createAudioPatch() different sink types in same patch not supported");
+ ALOGW("%s() different sink types in same patch not supported", __func__);
status = BAD_VALUE;
goto exit;
}
@@ -256,38 +207,42 @@
if (patch->sources[1].type != AUDIO_PORT_TYPE_MIX ||
(patch->num_sinks != 0 && patch->sinks[0].ext.device.hw_module !=
patch->sources[1].ext.mix.hw_module)) {
- ALOGW("createAudioPatch() invalid source combination");
+ ALOGW("%s() invalid source combination", __func__);
status = INVALID_OPERATION;
goto exit;
}
sp<ThreadBase> thread =
- audioflinger->checkPlaybackThread_l(patch->sources[1].ext.mix.handle);
- newPatch->mPlaybackThread = (MixerThread *)thread.get();
+ mAudioFlinger.checkPlaybackThread_l(patch->sources[1].ext.mix.handle);
if (thread == 0) {
- ALOGW("createAudioPatch() cannot get playback thread");
+ ALOGW("%s() cannot get playback thread", __func__);
status = INVALID_OPERATION;
goto exit;
}
+ // existing playback thread is reused, so it is not closed when patch is cleared
+ newPatch.mPlayback.setThread(
+ reinterpret_cast<PlaybackThread*>(thread.get()), false /*closeThread*/);
} else {
audio_config_t config = AUDIO_CONFIG_INITIALIZER;
audio_devices_t device = patch->sinks[0].ext.device.type;
String8 address = String8(patch->sinks[0].ext.device.address);
audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
- sp<ThreadBase> thread = audioflinger->openOutput_l(
+ audio_output_flags_t flags =
+ patch->sinks[0].config_mask & AUDIO_PORT_CONFIG_FLAGS ?
+ patch->sinks[0].flags.output : AUDIO_OUTPUT_FLAG_NONE;
+ sp<ThreadBase> thread = mAudioFlinger.openOutput_l(
patch->sinks[0].ext.device.hw_module,
&output,
&config,
device,
address,
- AUDIO_OUTPUT_FLAG_NONE);
- newPatch->mPlaybackThread = (PlaybackThread *)thread.get();
- ALOGV("audioflinger->openOutput_l() returned %p",
- newPatch->mPlaybackThread.get());
- if (newPatch->mPlaybackThread == 0) {
+ flags);
+ ALOGV("mAudioFlinger.openOutput_l() returned %p", thread.get());
+ if (thread == 0) {
status = NO_MEMORY;
goto exit;
}
+ newPatch.mPlayback.setThread(reinterpret_cast<PlaybackThread*>(thread.get()));
}
audio_devices_t device = patch->sources[0].ext.device.type;
String8 address = String8(patch->sources[0].ext.device.address);
@@ -297,47 +252,50 @@
if (patch->sources[0].config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
config.sample_rate = patch->sources[0].sample_rate;
} else {
- config.sample_rate = newPatch->mPlaybackThread->sampleRate();
+ config.sample_rate = newPatch.mPlayback.thread()->sampleRate();
}
if (patch->sources[0].config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
config.channel_mask = patch->sources[0].channel_mask;
} else {
- config.channel_mask =
- audio_channel_in_mask_from_count(newPatch->mPlaybackThread->channelCount());
+ config.channel_mask = audio_channel_in_mask_from_count(
+ newPatch.mPlayback.thread()->channelCount());
}
if (patch->sources[0].config_mask & AUDIO_PORT_CONFIG_FORMAT) {
config.format = patch->sources[0].format;
} else {
- config.format = newPatch->mPlaybackThread->format();
+ config.format = newPatch.mPlayback.thread()->format();
}
+ audio_input_flags_t flags =
+ patch->sources[0].config_mask & AUDIO_PORT_CONFIG_FLAGS ?
+ patch->sources[0].flags.input : AUDIO_INPUT_FLAG_NONE;
audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
- sp<ThreadBase> thread = audioflinger->openInput_l(srcModule,
+ sp<ThreadBase> thread = mAudioFlinger.openInput_l(srcModule,
&input,
&config,
device,
address,
AUDIO_SOURCE_MIC,
- AUDIO_INPUT_FLAG_NONE);
- newPatch->mRecordThread = (RecordThread *)thread.get();
- ALOGV("audioflinger->openInput_l() returned %p inChannelMask %08x",
- newPatch->mRecordThread.get(), config.channel_mask);
- if (newPatch->mRecordThread == 0) {
+ flags);
+ ALOGV("mAudioFlinger.openInput_l() returned %p inChannelMask %08x",
+ thread.get(), config.channel_mask);
+ if (thread == 0) {
status = NO_MEMORY;
goto exit;
}
- status = createPatchConnections(newPatch, patch);
+ newPatch.mRecord.setThread(reinterpret_cast<RecordThread*>(thread.get()));
+ status = newPatch.createConnections(this);
if (status != NO_ERROR) {
goto exit;
}
} else {
if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) {
- sp<ThreadBase> thread = audioflinger->checkRecordThread_l(
+ sp<ThreadBase> thread = mAudioFlinger.checkRecordThread_l(
patch->sinks[0].ext.mix.handle);
if (thread == 0) {
- thread = audioflinger->checkMmapThread_l(patch->sinks[0].ext.mix.handle);
+ thread = mAudioFlinger.checkMmapThread_l(patch->sinks[0].ext.mix.handle);
if (thread == 0) {
- ALOGW("createAudioPatch() bad capture I/O handle %d",
- patch->sinks[0].ext.mix.handle);
+ ALOGW("%s() bad capture I/O handle %d",
+ __func__, patch->sinks[0].ext.mix.handle);
status = BAD_VALUE;
goto exit;
}
@@ -356,9 +314,9 @@
} break;
case AUDIO_PORT_TYPE_MIX: {
audio_module_handle_t srcModule = patch->sources[0].ext.mix.hw_module;
- ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule);
+ ssize_t index = mAudioFlinger.mAudioHwDevs.indexOfKey(srcModule);
if (index < 0) {
- ALOGW("createAudioPatch() bad src hw module %d", srcModule);
+ ALOGW("%s() bad src hw module %d", __func__, srcModule);
status = BAD_VALUE;
goto exit;
}
@@ -366,8 +324,8 @@
audio_devices_t type = AUDIO_DEVICE_NONE;
for (unsigned int i = 0; i < patch->num_sinks; i++) {
if (patch->sinks[i].type != AUDIO_PORT_TYPE_DEVICE) {
- ALOGW("createAudioPatch() invalid sink type %d for mix source",
- patch->sinks[i].type);
+ ALOGW("%s() invalid sink type %d for mix source",
+ __func__, patch->sinks[i].type);
status = BAD_VALUE;
goto exit;
}
@@ -379,21 +337,21 @@
type |= patch->sinks[i].ext.device.type;
}
sp<ThreadBase> thread =
- audioflinger->checkPlaybackThread_l(patch->sources[0].ext.mix.handle);
+ mAudioFlinger.checkPlaybackThread_l(patch->sources[0].ext.mix.handle);
if (thread == 0) {
- thread = audioflinger->checkMmapThread_l(patch->sources[0].ext.mix.handle);
+ thread = mAudioFlinger.checkMmapThread_l(patch->sources[0].ext.mix.handle);
if (thread == 0) {
- ALOGW("createAudioPatch() bad playback I/O handle %d",
- patch->sources[0].ext.mix.handle);
+ ALOGW("%s() bad playback I/O handle %d",
+ __func__, patch->sources[0].ext.mix.handle);
status = BAD_VALUE;
goto exit;
}
}
- if (thread == audioflinger->primaryPlaybackThread_l()) {
+ if (thread == mAudioFlinger.primaryPlaybackThread_l()) {
AudioParameter param = AudioParameter();
param.addInt(String8(AudioParameter::keyRouting), (int)type);
- audioflinger->broacastParametersToRecordThreads_l(param.toString());
+ mAudioFlinger.broacastParametersToRecordThreads_l(param.toString());
}
status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);
@@ -403,72 +361,70 @@
goto exit;
}
exit:
- ALOGV("createAudioPatch() status %d", status);
+ ALOGV("%s() status %d", __func__, status);
if (status == NO_ERROR) {
- *handle = (audio_patch_handle_t) audioflinger->nextUniqueId(AUDIO_UNIQUE_ID_USE_PATCH);
- newPatch->mHandle = *handle;
- newPatch->mHalHandle = halHandle;
- mPatches.add(newPatch);
- ALOGV("createAudioPatch() added new patch handle %d halHandle %d", *handle, halHandle);
+ *handle = (audio_patch_handle_t) mAudioFlinger.nextUniqueId(AUDIO_UNIQUE_ID_USE_PATCH);
+ newPatch.mHalHandle = halHandle;
+ mPatches.insert(std::make_pair(*handle, std::move(newPatch)));
+ ALOGV("%s() added new patch handle %d halHandle %d", __func__, *handle, halHandle);
} else {
- clearPatchConnections(newPatch);
- delete newPatch;
+ newPatch.clearConnections(this);
}
return status;
}
-status_t AudioFlinger::PatchPanel::createPatchConnections(Patch *patch,
- const struct audio_patch *audioPatch)
+AudioFlinger::PatchPanel::Patch::~Patch()
+{
+ ALOGE_IF(isSoftware(), "Software patch connections leaked %d %d",
+ mRecord.handle(), mPlayback.handle());
+}
+
+status_t AudioFlinger::PatchPanel::Patch::createConnections(PatchPanel *panel)
{
// create patch from source device to record thread input
- struct audio_patch subPatch;
- subPatch.num_sources = 1;
- subPatch.sources[0] = audioPatch->sources[0];
- subPatch.num_sinks = 1;
-
- patch->mRecordThread->getAudioPortConfig(&subPatch.sinks[0]);
- subPatch.sinks[0].ext.mix.usecase.source = AUDIO_SOURCE_MIC;
-
- status_t status = createAudioPatch(&subPatch, &patch->mRecordPatchHandle);
+ status_t status = panel->createAudioPatch(
+ PatchBuilder().addSource(mAudioPatch.sources[0]).
+ addSink(mRecord.thread(), { .source = AUDIO_SOURCE_MIC }).patch(),
+ mRecord.handlePtr());
if (status != NO_ERROR) {
- patch->mRecordPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+ *mRecord.handlePtr() = AUDIO_PATCH_HANDLE_NONE;
return status;
}
// create patch from playback thread output to sink device
- if (audioPatch->num_sinks != 0) {
- patch->mPlaybackThread->getAudioPortConfig(&subPatch.sources[0]);
- subPatch.sinks[0] = audioPatch->sinks[0];
- status = createAudioPatch(&subPatch, &patch->mPlaybackPatchHandle);
+ if (mAudioPatch.num_sinks != 0) {
+ status = panel->createAudioPatch(
+ PatchBuilder().addSource(mPlayback.thread()).addSink(mAudioPatch.sinks[0]).patch(),
+ mPlayback.handlePtr());
if (status != NO_ERROR) {
- patch->mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+ *mPlayback.handlePtr() = AUDIO_PATCH_HANDLE_NONE;
return status;
}
} else {
- patch->mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+ *mPlayback.handlePtr() = AUDIO_PATCH_HANDLE_NONE;
}
// use a pseudo LCM between input and output framecount
- size_t playbackFrameCount = patch->mPlaybackThread->frameCount();
+ size_t playbackFrameCount = mPlayback.thread()->frameCount();
int playbackShift = __builtin_ctz(playbackFrameCount);
- size_t recordFramecount = patch->mRecordThread->frameCount();
+ size_t recordFramecount = mRecord.thread()->frameCount();
int shift = __builtin_ctz(recordFramecount);
if (playbackShift < shift) {
shift = playbackShift;
}
size_t frameCount = (playbackFrameCount * recordFramecount) >> shift;
- ALOGV("createPatchConnections() playframeCount %zu recordFramecount %zu frameCount %zu",
- playbackFrameCount, recordFramecount, frameCount);
+ ALOGV("%s() playframeCount %zu recordFramecount %zu frameCount %zu",
+ __func__, playbackFrameCount, recordFramecount, frameCount);
// create a special record track to capture from record thread
- uint32_t channelCount = patch->mPlaybackThread->channelCount();
+ uint32_t channelCount = mPlayback.thread()->channelCount();
audio_channel_mask_t inChannelMask = audio_channel_in_mask_from_count(channelCount);
- audio_channel_mask_t outChannelMask = patch->mPlaybackThread->channelMask();
- uint32_t sampleRate = patch->mPlaybackThread->sampleRate();
- audio_format_t format = patch->mPlaybackThread->format();
+ audio_channel_mask_t outChannelMask = mPlayback.thread()->channelMask();
+ uint32_t sampleRate = mPlayback.thread()->sampleRate();
+ audio_format_t format = mPlayback.thread()->format();
- patch->mPatchRecord = new RecordThread::PatchRecord(
- patch->mRecordThread.get(),
+ sp<RecordThread::PatchRecord> tempRecordTrack = new (std::nothrow) RecordThread::PatchRecord(
+ mRecord.thread().get(),
sampleRate,
inChannelMask,
format,
@@ -476,222 +432,202 @@
NULL,
(size_t)0 /* bufferSize */,
AUDIO_INPUT_FLAG_NONE);
- if (patch->mPatchRecord == 0) {
- return NO_MEMORY;
- }
- status = patch->mPatchRecord->initCheck();
+ status = mRecord.checkTrack(tempRecordTrack.get());
if (status != NO_ERROR) {
return status;
}
- patch->mRecordThread->addPatchRecord(patch->mPatchRecord);
// create a special playback track to render to playback thread.
// this track is given the same buffer as the PatchRecord buffer
- patch->mPatchTrack = new PlaybackThread::PatchTrack(
- patch->mPlaybackThread.get(),
- audioPatch->sources[1].ext.mix.usecase.stream,
+ sp<PlaybackThread::PatchTrack> tempPatchTrack = new (std::nothrow) PlaybackThread::PatchTrack(
+ mPlayback.thread().get(),
+ mAudioPatch.sources[1].ext.mix.usecase.stream,
sampleRate,
outChannelMask,
format,
frameCount,
- patch->mPatchRecord->buffer(),
- patch->mPatchRecord->bufferSize(),
+ tempRecordTrack->buffer(),
+ tempRecordTrack->bufferSize(),
AUDIO_OUTPUT_FLAG_NONE);
- status = patch->mPatchTrack->initCheck();
+ status = mPlayback.checkTrack(tempPatchTrack.get());
if (status != NO_ERROR) {
return status;
}
- patch->mPlaybackThread->addPatchTrack(patch->mPatchTrack);
// tie playback and record tracks together
- patch->mPatchRecord->setPeerProxy(patch->mPatchTrack.get());
- patch->mPatchTrack->setPeerProxy(patch->mPatchRecord.get());
+ mRecord.setTrackAndPeer(tempRecordTrack, tempPatchTrack.get());
+ mPlayback.setTrackAndPeer(tempPatchTrack, tempRecordTrack.get());
// start capture and playback
- patch->mPatchRecord->start(AudioSystem::SYNC_EVENT_NONE, AUDIO_SESSION_NONE);
- patch->mPatchTrack->start();
+ mRecord.track()->start(AudioSystem::SYNC_EVENT_NONE, AUDIO_SESSION_NONE);
+ mPlayback.track()->start();
return status;
}
-void AudioFlinger::PatchPanel::clearPatchConnections(Patch *patch)
+void AudioFlinger::PatchPanel::Patch::clearConnections(PatchPanel *panel)
{
- sp<AudioFlinger> audioflinger = mAudioFlinger.promote();
- if (audioflinger == 0) {
- return;
+ ALOGV("%s() mRecord.handle %d mPlayback.handle %d",
+ __func__, mRecord.handle(), mPlayback.handle());
+ mRecord.stopTrack();
+ mPlayback.stopTrack();
+ mRecord.closeConnections(panel);
+ mPlayback.closeConnections(panel);
+}
+
+status_t AudioFlinger::PatchPanel::Patch::getLatencyMs(double *latencyMs) const
+{
+ if (!isSoftware()) return INVALID_OPERATION;
+
+ auto recordTrack = mRecord.const_track();
+ if (recordTrack.get() == nullptr) return INVALID_OPERATION;
+
+ auto playbackTrack = mPlayback.const_track();
+ if (playbackTrack.get() == nullptr) return INVALID_OPERATION;
+
+ // Latency information for tracks may be called without obtaining
+ // the underlying thread lock.
+ //
+ // We use record server latency + playback track latency (generally smaller than the
+ // reverse due to internal biases).
+ //
+ // TODO: is this stable enough? Consider a PatchTrack synchronized version of this.
+ double recordServerLatencyMs;
+ if (recordTrack->getServerLatencyMs(&recordServerLatencyMs) != OK) return INVALID_OPERATION;
+
+ double playbackTrackLatencyMs;
+ if (playbackTrack->getTrackLatencyMs(&playbackTrackLatencyMs) != OK) return INVALID_OPERATION;
+
+ *latencyMs = recordServerLatencyMs + playbackTrackLatencyMs;
+ return OK;
+}
+
+String8 AudioFlinger::PatchPanel::Patch::dump(audio_patch_handle_t myHandle)
+{
+ String8 result;
+
+ // TODO: Consider table dump form for patches, just like tracks.
+ result.appendFormat("Patch %d: thread %p => thread %p",
+ myHandle, mRecord.thread().get(), mPlayback.thread().get());
+
+ // add latency if it exists
+ double latencyMs;
+ if (getLatencyMs(&latencyMs) == OK) {
+ result.appendFormat(" latency: %.2lf", latencyMs);
}
- ALOGV("clearPatchConnections() patch->mRecordPatchHandle %d patch->mPlaybackPatchHandle %d",
- patch->mRecordPatchHandle, patch->mPlaybackPatchHandle);
-
- if (patch->mPatchRecord != 0) {
- patch->mPatchRecord->stop();
- }
- if (patch->mPatchTrack != 0) {
- patch->mPatchTrack->stop();
- }
- if (patch->mRecordPatchHandle != AUDIO_PATCH_HANDLE_NONE) {
- releaseAudioPatch(patch->mRecordPatchHandle);
- patch->mRecordPatchHandle = AUDIO_PATCH_HANDLE_NONE;
- }
- if (patch->mPlaybackPatchHandle != AUDIO_PATCH_HANDLE_NONE) {
- releaseAudioPatch(patch->mPlaybackPatchHandle);
- patch->mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;
- }
- if (patch->mRecordThread != 0) {
- if (patch->mPatchRecord != 0) {
- patch->mRecordThread->deletePatchRecord(patch->mPatchRecord);
- }
- audioflinger->closeInputInternal_l(patch->mRecordThread);
- }
- if (patch->mPlaybackThread != 0) {
- if (patch->mPatchTrack != 0) {
- patch->mPlaybackThread->deletePatchTrack(patch->mPatchTrack);
- }
- // if num sources == 2 we are reusing an existing playback thread so we do not close it
- if (patch->mAudioPatch.num_sources != 2) {
- audioflinger->closeOutputInternal_l(patch->mPlaybackThread);
- }
- }
- if (patch->mRecordThread != 0) {
- if (patch->mPatchRecord != 0) {
- patch->mPatchRecord.clear();
- }
- patch->mRecordThread.clear();
- }
- if (patch->mPlaybackThread != 0) {
- if (patch->mPatchTrack != 0) {
- patch->mPatchTrack.clear();
- }
- patch->mPlaybackThread.clear();
- }
-
+ result.append("\n");
+ return result;
}
/* Disconnect a patch */
status_t AudioFlinger::PatchPanel::releaseAudioPatch(audio_patch_handle_t handle)
{
- ALOGV("releaseAudioPatch handle %d", handle);
+ ALOGV("%s handle %d", __func__, handle);
status_t status = NO_ERROR;
- size_t index;
- sp<AudioFlinger> audioflinger = mAudioFlinger.promote();
- if (audioflinger == 0) {
- return NO_INIT;
- }
-
- for (index = 0; index < mPatches.size(); index++) {
- if (handle == mPatches[index]->mHandle) {
- break;
- }
- }
- if (index == mPatches.size()) {
+ auto iter = mPatches.find(handle);
+ if (iter == mPatches.end()) {
return BAD_VALUE;
}
- Patch *removedPatch = mPatches[index];
- mPatches.removeAt(index);
+ Patch &removedPatch = iter->second;
+ const struct audio_patch &patch = removedPatch.mAudioPatch;
- struct audio_patch *patch = &removedPatch->mAudioPatch;
-
- switch (patch->sources[0].type) {
+ const struct audio_port_config &src = patch.sources[0];
+ switch (src.type) {
case AUDIO_PORT_TYPE_DEVICE: {
- audio_module_handle_t srcModule = patch->sources[0].ext.device.hw_module;
- ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule);
- if (index < 0) {
- ALOGW("releaseAudioPatch() bad src hw module %d", srcModule);
+ sp<DeviceHalInterface> hwDevice = findHwDeviceByModule(src.ext.device.hw_module);
+ if (hwDevice == 0) {
+ ALOGW("%s() bad src hw module %d", __func__, src.ext.device.hw_module);
status = BAD_VALUE;
break;
}
- if (removedPatch->mRecordPatchHandle != AUDIO_PATCH_HANDLE_NONE ||
- removedPatch->mPlaybackPatchHandle != AUDIO_PATCH_HANDLE_NONE) {
- clearPatchConnections(removedPatch);
+ if (removedPatch.isSoftware()) {
+ removedPatch.clearConnections(this);
break;
}
- if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) {
- sp<ThreadBase> thread = audioflinger->checkRecordThread_l(
- patch->sinks[0].ext.mix.handle);
+ if (patch.sinks[0].type == AUDIO_PORT_TYPE_MIX) {
+ audio_io_handle_t ioHandle = patch.sinks[0].ext.mix.handle;
+ sp<ThreadBase> thread = mAudioFlinger.checkRecordThread_l(ioHandle);
if (thread == 0) {
- thread = audioflinger->checkMmapThread_l(patch->sinks[0].ext.mix.handle);
+ thread = mAudioFlinger.checkMmapThread_l(ioHandle);
if (thread == 0) {
- ALOGW("releaseAudioPatch() bad capture I/O handle %d",
- patch->sinks[0].ext.mix.handle);
+ ALOGW("%s() bad capture I/O handle %d", __func__, ioHandle);
status = BAD_VALUE;
break;
}
}
- status = thread->sendReleaseAudioPatchConfigEvent(removedPatch->mHalHandle);
+ status = thread->sendReleaseAudioPatchConfigEvent(removedPatch.mHalHandle);
} else {
- AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
- sp<DeviceHalInterface> hwDevice = audioHwDevice->hwDevice();
- status = hwDevice->releaseAudioPatch(removedPatch->mHalHandle);
+ status = hwDevice->releaseAudioPatch(removedPatch.mHalHandle);
}
} break;
case AUDIO_PORT_TYPE_MIX: {
- audio_module_handle_t srcModule = patch->sources[0].ext.mix.hw_module;
- ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule);
- if (index < 0) {
- ALOGW("releaseAudioPatch() bad src hw module %d", srcModule);
+ if (findHwDeviceByModule(src.ext.mix.hw_module) == 0) {
+ ALOGW("%s() bad src hw module %d", __func__, src.ext.mix.hw_module);
status = BAD_VALUE;
break;
}
- sp<ThreadBase> thread =
- audioflinger->checkPlaybackThread_l(patch->sources[0].ext.mix.handle);
+ audio_io_handle_t ioHandle = src.ext.mix.handle;
+ sp<ThreadBase> thread = mAudioFlinger.checkPlaybackThread_l(ioHandle);
if (thread == 0) {
- thread = audioflinger->checkMmapThread_l(patch->sources[0].ext.mix.handle);
+ thread = mAudioFlinger.checkMmapThread_l(ioHandle);
if (thread == 0) {
- ALOGW("releaseAudioPatch() bad playback I/O handle %d",
- patch->sources[0].ext.mix.handle);
+ ALOGW("%s() bad playback I/O handle %d", __func__, ioHandle);
status = BAD_VALUE;
break;
}
}
- status = thread->sendReleaseAudioPatchConfigEvent(removedPatch->mHalHandle);
+ status = thread->sendReleaseAudioPatchConfigEvent(removedPatch.mHalHandle);
} break;
default:
status = BAD_VALUE;
- break;
}
- delete removedPatch;
+ mPatches.erase(iter);
return status;
}
-
/* List connected audio ports and they attributes */
status_t AudioFlinger::PatchPanel::listAudioPatches(unsigned int *num_patches __unused,
struct audio_patch *patches __unused)
{
- ALOGV("listAudioPatches");
+ ALOGV(__func__);
return NO_ERROR;
}
-/* Set audio port configuration */
-status_t AudioFlinger::PatchPanel::setAudioPortConfig(const struct audio_port_config *config)
+sp<DeviceHalInterface> AudioFlinger::PatchPanel::findHwDeviceByModule(audio_module_handle_t module)
{
- ALOGV("setAudioPortConfig");
-
- sp<AudioFlinger> audioflinger = mAudioFlinger.promote();
- if (audioflinger == 0) {
- return NO_INIT;
- }
-
- audio_module_handle_t module;
- if (config->type == AUDIO_PORT_TYPE_DEVICE) {
- module = config->ext.device.hw_module;
- } else {
- module = config->ext.mix.hw_module;
- }
-
- ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(module);
+ if (module == AUDIO_MODULE_HANDLE_NONE) return nullptr;
+ ssize_t index = mAudioFlinger.mAudioHwDevs.indexOfKey(module);
if (index < 0) {
- ALOGW("setAudioPortConfig() bad hw module %d", module);
- return BAD_VALUE;
+ return nullptr;
}
+ return mAudioFlinger.mAudioHwDevs.valueAt(index)->hwDevice();
+}
- AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
- return audioHwDevice->hwDevice()->setAudioPortConfig(config);
+void AudioFlinger::PatchPanel::dump(int fd)
+{
+ // Only dump software patches.
+ bool headerPrinted = false;
+ for (auto& iter : mPatches) {
+ if (iter.second.isSoftware()) {
+ if (!headerPrinted) {
+ String8 header("\nSoftware patches:\n");
+ write(fd, header.string(), header.size());
+ headerPrinted = true;
+ }
+ String8 patchDump(" ");
+ patchDump.append(iter.second.dump(iter.first));
+ write(fd, patchDump.string(), patchDump.size());
+ }
+ }
+ if (headerPrinted) {
+ String8 trailing("\n");
+ write(fd, trailing.string(), trailing.size());
+ }
}
} // namespace android
diff --git a/services/audioflinger/PatchPanel.h b/services/audioflinger/PatchPanel.h
index d37c0d3..5d6bf00 100644
--- a/services/audioflinger/PatchPanel.h
+++ b/services/audioflinger/PatchPanel.h
@@ -19,13 +19,10 @@
#error This header file should only be included from AudioFlinger.h
#endif
-class PatchPanel : public RefBase {
+// PatchPanel is concealed within AudioFlinger, their lifetimes are the same.
+class PatchPanel {
public:
-
- class Patch;
-
- explicit PatchPanel(const sp<AudioFlinger>& audioFlinger);
- virtual ~PatchPanel();
+ explicit PatchPanel(AudioFlinger* audioFlinger) : mAudioFlinger(*audioFlinger) {}
/* List connected audio ports and their attributes */
status_t listAudioPorts(unsigned int *num_ports,
@@ -45,46 +42,104 @@
status_t listAudioPatches(unsigned int *num_patches,
struct audio_patch *patches);
- /* Set audio port configuration */
- status_t setAudioPortConfig(const struct audio_port_config *config);
+ void dump(int fd);
- status_t createPatchConnections(Patch *patch,
- const struct audio_patch *audioPatch);
- void clearPatchConnections(Patch *patch);
+private:
+ template<typename ThreadType, typename TrackType>
+ class Endpoint {
+ public:
+ Endpoint() = default;
+ Endpoint(Endpoint&& other) { *this = std::move(other); }
+ Endpoint& operator=(Endpoint&& other) {
+ ALOGE_IF(mHandle != AUDIO_PATCH_HANDLE_NONE,
+ "A non empty Patch Endpoint leaked, handle %d", mHandle);
+ *this = other;
+ other.mHandle = AUDIO_PATCH_HANDLE_NONE;
+ return *this;
+ }
+
+ status_t checkTrack(TrackType *trackOrNull) const {
+ if (trackOrNull == nullptr) return NO_MEMORY;
+ return trackOrNull->initCheck();
+ }
+ audio_patch_handle_t handle() const { return mHandle; }
+ sp<ThreadType> thread() { return mThread; }
+ sp<TrackType> track() { return mTrack; }
+ sp<const TrackType> const_track() const { return mTrack; }
+
+ void closeConnections(PatchPanel *panel) {
+ if (mHandle != AUDIO_PATCH_HANDLE_NONE) {
+ panel->releaseAudioPatch(mHandle);
+ mHandle = AUDIO_PATCH_HANDLE_NONE;
+ }
+ if (mThread != 0) {
+ if (mTrack != 0) {
+ mThread->deletePatchTrack(mTrack);
+ }
+ if (mCloseThread) {
+ panel->mAudioFlinger.closeThreadInternal_l(mThread);
+ }
+ }
+ }
+ audio_patch_handle_t* handlePtr() { return &mHandle; }
+ void setThread(const sp<ThreadType>& thread, bool closeThread = true) {
+ mThread = thread;
+ mCloseThread = closeThread;
+ }
+ void setTrackAndPeer(const sp<TrackType>& track,
+ ThreadBase::PatchProxyBufferProvider *peer) {
+ mTrack = track;
+ mThread->addPatchTrack(mTrack);
+ mTrack->setPeerProxy(peer);
+ }
+ void stopTrack() { if (mTrack) mTrack->stop(); }
+
+ private:
+ Endpoint(const Endpoint&) = default;
+ Endpoint& operator=(const Endpoint&) = default;
+
+ sp<ThreadType> mThread;
+ bool mCloseThread = true;
+ audio_patch_handle_t mHandle = AUDIO_PATCH_HANDLE_NONE;
+ sp<TrackType> mTrack;
+ };
class Patch {
public:
- explicit Patch(const struct audio_patch *patch) :
- mAudioPatch(*patch), mHandle(AUDIO_PATCH_HANDLE_NONE),
- mHalHandle(AUDIO_PATCH_HANDLE_NONE), mRecordPatchHandle(AUDIO_PATCH_HANDLE_NONE),
- mPlaybackPatchHandle(AUDIO_PATCH_HANDLE_NONE) {}
- ~Patch() {}
+ explicit Patch(const struct audio_patch &patch) : mAudioPatch(patch) {}
+ ~Patch();
+ Patch(const Patch&) = delete;
+ Patch(Patch&&) = default;
+ Patch& operator=(const Patch&) = delete;
+ Patch& operator=(Patch&&) = default;
+ status_t createConnections(PatchPanel *panel);
+ void clearConnections(PatchPanel *panel);
+ bool isSoftware() const {
+ return mRecord.handle() != AUDIO_PATCH_HANDLE_NONE ||
+ mPlayback.handle() != AUDIO_PATCH_HANDLE_NONE; }
+
+ // returns the latency of the patch (from record to playback).
+ status_t getLatencyMs(double *latencyMs) const;
+
+ String8 dump(audio_patch_handle_t myHandle);
+
+ // Note that audio_patch::id is only unique within a HAL module
struct audio_patch mAudioPatch;
- audio_patch_handle_t mHandle;
// handle for audio HAL patch handle present only when the audio HAL version is >= 3.0
- audio_patch_handle_t mHalHandle;
+ audio_patch_handle_t mHalHandle = AUDIO_PATCH_HANDLE_NONE;
// below members are used by a software audio patch connecting a source device from a
// given audio HW module to a sink device on an other audio HW module.
- // playback thread created by createAudioPatch() and released by clearPatchConnections() if
- // no existing playback thread can be used by the software patch
- sp<PlaybackThread> mPlaybackThread;
- // audio track created by createPatchConnections() and released by clearPatchConnections()
- sp<PlaybackThread::PatchTrack> mPatchTrack;
- // record thread created by createAudioPatch() and released by clearPatchConnections()
- sp<RecordThread> mRecordThread;
- // audio record created by createPatchConnections() and released by clearPatchConnections()
- sp<RecordThread::PatchRecord> mPatchRecord;
- // handle for audio patch connecting source device to record thread input.
- // created by createPatchConnections() and released by clearPatchConnections()
- audio_patch_handle_t mRecordPatchHandle;
- // handle for audio patch connecting playback thread output to sink device
- // created by createPatchConnections() and released by clearPatchConnections()
- audio_patch_handle_t mPlaybackPatchHandle;
-
+ // the objects are created by createConnections() and released by clearConnections()
+ // playback thread is created if no existing playback thread can be used
+ // connects playback thread output to sink device
+ Endpoint<PlaybackThread, PlaybackThread::PatchTrack> mPlayback;
+ // connects source device to record thread input
+ Endpoint<RecordThread, RecordThread::PatchRecord> mRecord;
};
-private:
- const wp<AudioFlinger> mAudioFlinger;
- SortedVector <Patch *> mPatches;
+ sp<DeviceHalInterface> findHwDeviceByModule(audio_module_handle_t module);
+
+ AudioFlinger &mAudioFlinger;
+ std::map<audio_patch_handle_t, Patch> mPatches;
};
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index a78be99..3381e77 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -41,7 +41,7 @@
virtual ~Track();
virtual status_t initCheck() const;
- static void appendDumpHeader(String8& result);
+ void appendDumpHeader(String8& result);
void appendDump(String8& result, bool active);
virtual status_t start(AudioSystem::sync_event_t event =
AudioSystem::SYNC_EVENT_NONE,
@@ -56,6 +56,12 @@
LOG_ALWAYS_FATAL_IF(mName >= 0 && name >= 0,
"%s both old name %d and new name %d are valid", __func__, mName, name);
mName = name;
+#ifdef TEE_SINK
+ mTee.setId(std::string("_") + std::to_string(mThreadIoHandle)
+ + "_" + std::to_string(mId)
+ + "_" + std::to_string(mName)
+ + "_T");
+#endif
}
virtual uint32_t sampleRate() const;
@@ -69,6 +75,7 @@
bool isOffloadedOrDirect() const { return (mFlags
& (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD
| AUDIO_OUTPUT_FLAG_DIRECT)) != 0; }
+ bool isStatic() const { return mSharedBuffer.get() != nullptr; }
status_t setParameters(const String8& keyValuePairs);
status_t attachAuxEffect(int EffectId);
@@ -87,6 +94,10 @@
virtual bool isFastTrack() const { return (mFlags & AUDIO_OUTPUT_FLAG_FAST) != 0; }
+ double bufferLatencyMs() const override {
+ return isStatic() ? 0. : TrackBase::bufferLatencyMs();
+ }
+
// implement volume handling.
media::VolumeShaper::Status applyVolumeShaper(
const sp<media::VolumeShaper::Configuration>& configuration,
@@ -140,7 +151,7 @@
bool isResumePending();
void resumeAck();
void updateTrackFrameInfo(int64_t trackFramesReleased, int64_t sinkFramesWritten,
- const ExtendedTimestamp &timeStamp);
+ uint32_t halSampleRate, const ExtendedTimestamp &timeStamp);
sp<IMemory> sharedBuffer() const { return mSharedBuffer; }
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index fc2dbbb..43b6391 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -51,7 +51,7 @@
bool setOverflow() { bool tmp = mOverflow; mOverflow = true;
return tmp; }
- static void appendDumpHeader(String8& result);
+ void appendDumpHeader(String8& result);
void appendDump(String8& result, bool active);
void handleSyncStartEvent(const sp<SyncEvent>& event);
diff --git a/services/audioflinger/ServiceUtilities.h b/services/audioflinger/ServiceUtilities.h
deleted file mode 100644
index f45ada1..0000000
--- a/services/audioflinger/ServiceUtilities.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <unistd.h>
-
-#include <binder/PermissionController.h>
-
-namespace android {
-
-extern pid_t getpid_cached;
-bool isTrustedCallingUid(uid_t uid);
-bool recordingAllowed(const String16& opPackageName, pid_t pid, uid_t uid);
-bool startRecording(const String16& opPackageName, pid_t pid, uid_t uid);
-void finishRecording(const String16& opPackageName, uid_t uid);
-bool captureAudioOutputAllowed(pid_t pid, uid_t uid);
-bool captureHotwordAllowed(pid_t pid, uid_t uid);
-bool settingsAllowed();
-bool modifyAudioRoutingAllowed();
-bool dumpAllowed();
-bool modifyPhoneStateAllowed(pid_t pid, uid_t uid);
-}
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index dcad866..d61b1f0 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -62,8 +62,8 @@
#include "AudioFlinger.h"
#include "FastMixer.h"
#include "FastCapture.h"
-#include "ServiceUtilities.h"
-#include "mediautils/SchedulingPolicyService.h"
+#include <mediautils/SchedulingPolicyService.h>
+#include <mediautils/ServiceUtilities.h>
#ifdef ADD_BATTERY_DATA
#include <media/IMediaPlayerService.h>
@@ -769,6 +769,8 @@
if (mask & AUDIO_CHANNEL_OUT_TOP_BACK_LEFT) s.append("top-back-left, ");
if (mask & AUDIO_CHANNEL_OUT_TOP_BACK_CENTER) s.append("top-back-center, " );
if (mask & AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT) s.append("top-back-right, " );
+ if (mask & AUDIO_CHANNEL_OUT_TOP_SIDE_LEFT) s.append("top-side-left, " );
+ if (mask & AUDIO_CHANNEL_OUT_TOP_SIDE_RIGHT) s.append("top-side-right, " );
if (mask & ~AUDIO_CHANNEL_OUT_ALL) s.append("unknown, ");
} else {
if (mask & AUDIO_CHANNEL_IN_LEFT) s.append("left, ");
@@ -783,6 +785,12 @@
if (mask & AUDIO_CHANNEL_IN_X_AXIS) s.append("X, ");
if (mask & AUDIO_CHANNEL_IN_Y_AXIS) s.append("Y, ");
if (mask & AUDIO_CHANNEL_IN_Z_AXIS) s.append("Z, ");
+ if (mask & AUDIO_CHANNEL_IN_BACK_LEFT) s.append("back-left, ");
+ if (mask & AUDIO_CHANNEL_IN_BACK_RIGHT) s.append("back-right, ");
+ if (mask & AUDIO_CHANNEL_IN_CENTER) s.append("center, ");
+ if (mask & AUDIO_CHANNEL_IN_LOW_FREQUENCY) s.append("low freq, ");
+ if (mask & AUDIO_CHANNEL_IN_TOP_LEFT) s.append("top-left, " );
+ if (mask & AUDIO_CHANNEL_IN_TOP_RIGHT) s.append("top-right, " );
if (mask & AUDIO_CHANNEL_IN_VOICE_UPLINK) s.append("voice-uplink, ");
if (mask & AUDIO_CHANNEL_IN_VOICE_DNLINK) s.append("voice-dnlink, ");
if (mask & ~AUDIO_CHANNEL_IN_ALL) s.append("unknown, ");
@@ -1519,7 +1527,7 @@
}
}
-void AudioFlinger::ThreadBase::getAudioPortConfig(struct audio_port_config *config)
+void AudioFlinger::ThreadBase::toAudioPortConfig(struct audio_port_config *config)
{
config->type = AUDIO_PORT_TYPE_MIX;
config->ext.mix.handle = mId;
@@ -1571,6 +1579,9 @@
--mBatteryCounter[track->uid()].second;
// mLatestActiveTrack is not cleared even if is the same as track.
mHasChanged = true;
+#ifdef TEE_SINK
+ track->dumpTee(-1 /* fd */, "_REMOVE");
+#endif
return index;
}
@@ -1773,7 +1784,7 @@
if (numtracks) {
dprintf(fd, " of which %zu are active\n", numactive);
result.append(prefix);
- Track::appendDumpHeader(result);
+ mTracks[0]->appendDumpHeader(result);
for (size_t i = 0; i < numtracks; ++i) {
sp<Track> track = mTracks[i];
if (track != 0) {
@@ -1793,7 +1804,7 @@
result.append(" The following tracks are in the active list but"
" not in the track list\n");
result.append(prefix);
- Track::appendDumpHeader(result);
+ mActiveTracks[0]->appendDumpHeader(result);
for (size_t i = 0; i < numactive; ++i) {
sp<Track> track = mActiveTracks[i];
if (mTracks.indexOf(track) < 0) {
@@ -2845,6 +2856,9 @@
ATRACE_END();
if (framesWritten > 0) {
bytesWritten = framesWritten * mFrameSize;
+#ifdef TEE_SINK
+ mTee.write((char *)mSinkBuffer + offset, framesWritten);
+#endif
} else {
bytesWritten = framesWritten;
}
@@ -3251,6 +3265,7 @@
t->updateTrackFrameInfo(
t->mAudioTrackServerProxy->framesReleased(),
mFramesWritten,
+ mSampleRate,
mTimestamp);
}
}
@@ -3772,12 +3787,16 @@
destroyTrack_l(track);
}
-void AudioFlinger::PlaybackThread::getAudioPortConfig(struct audio_port_config *config)
+void AudioFlinger::PlaybackThread::toAudioPortConfig(struct audio_port_config *config)
{
- ThreadBase::getAudioPortConfig(config);
+ ThreadBase::toAudioPortConfig(config);
config->role = AUDIO_PORT_ROLE_SOURCE;
config->ext.mix.hw_module = mOutput->audioHwDev->handle();
config->ext.mix.usecase.stream = AUDIO_STREAM_DEFAULT;
+ if (mOutput && mOutput->flags != AUDIO_OUTPUT_FLAG_NONE) {
+ config->config_mask |= AUDIO_PORT_CONFIG_FLAGS;
+ config->flags.output = mOutput->flags;
+ }
}
// ----------------------------------------------------------------------------
@@ -3858,9 +3877,7 @@
// create a MonoPipe to connect our submix to FastMixer
NBAIO_Format format = mOutputSink->format();
-#ifdef TEE_SINK
- NBAIO_Format origformat = format;
-#endif
+
// adjust format to match that of the Fast Mixer
ALOGV("format changed from %#x to %#x", format.mFormat, fastMixerFormat);
format.mFormat = fastMixerFormat;
@@ -3872,7 +3889,7 @@
MonoPipe *monoPipe = new MonoPipe(mNormalFrameCount * 4, format, true /*writeCanBlock*/);
const NBAIO_Format offers[1] = {format};
size_t numCounterOffers = 0;
-#if !LOG_NDEBUG || defined(TEE_SINK)
+#if !LOG_NDEBUG
ssize_t index =
#else
(void)
@@ -3883,25 +3900,8 @@
(monoPipe->maxFrames() * 7) / 8 : mNormalFrameCount * 2);
mPipeSink = monoPipe;
-#ifdef TEE_SINK
- if (mTeeSinkOutputEnabled) {
- // create a Pipe to archive a copy of FastMixer's output for dumpsys
- Pipe *teeSink = new Pipe(mTeeSinkOutputFrames, origformat);
- const NBAIO_Format offers2[1] = {origformat};
- numCounterOffers = 0;
- index = teeSink->negotiate(offers2, 1, NULL, numCounterOffers);
- ALOG_ASSERT(index == 0);
- mTeeSink = teeSink;
- PipeReader *teeSource = new PipeReader(*teeSink);
- numCounterOffers = 0;
- index = teeSource->negotiate(offers2, 1, NULL, numCounterOffers);
- ALOG_ASSERT(index == 0);
- mTeeSource = teeSource;
- }
-#endif
-
// create fast mixer and configure it initially with just one fast track for our submix
- mFastMixer = new FastMixer();
+ mFastMixer = new FastMixer(mId);
FastMixerStateQueue *sq = mFastMixer->sq();
#ifdef STATE_QUEUE_DUMP
sq->setObserverDump(&mStateQueueObserverDump);
@@ -3927,9 +3927,6 @@
state->mColdFutexAddr = &mFastMixerFutex;
state->mColdGen++;
state->mDumpState = &mFastMixerDumpState;
-#ifdef TEE_SINK
- state->mTeeSink = mTeeSink.get();
-#endif
mFastMixerNBLogWriter = audioFlinger->newWriter_l(kFastMixerLogSize, "FastMixer");
state->mNBLogWriter = mFastMixerNBLogWriter.get();
sq->end();
@@ -3938,7 +3935,7 @@
// start the fast mixer
mFastMixer->run("FastMixer", PRIORITY_URGENT_AUDIO);
pid_t tid = mFastMixer->getTid();
- sendPrioConfigEvent(getpid_cached, tid, kPriorityFastMixer, false /*forApp*/);
+ sendPrioConfigEvent(getpid(), tid, kPriorityFastMixer, false /*forApp*/);
stream()->setHalThreadPriority(kPriorityFastMixer);
#ifdef AUDIO_WATCHDOG
@@ -3947,9 +3944,14 @@
mAudioWatchdog->setDump(&mAudioWatchdogDump);
mAudioWatchdog->run("AudioWatchdog", PRIORITY_URGENT_AUDIO);
tid = mAudioWatchdog->getTid();
- sendPrioConfigEvent(getpid_cached, tid, kPriorityFastMixer, false /*forApp*/);
+ sendPrioConfigEvent(getpid(), tid, kPriorityFastMixer, false /*forApp*/);
#endif
-
+ } else {
+#ifdef TEE_SINK
+ // Only use the MixerThread tee if there is no FastMixer.
+ mTee.set(mOutputSink->format(), NBAIO_Tee::TEE_FLAG_OUTPUT_THREAD);
+ mTee.setId(std::string("_") + std::to_string(mId) + "_M");
+#endif
}
switch (kUseFastMixer) {
@@ -4265,6 +4267,37 @@
mMixerBufferValid = false; // mMixerBuffer has no valid data until appropriate tracks found.
mEffectBufferValid = false; // mEffectBuffer has no valid data until tracks found.
+ // DeferredOperations handles statistics after setting mixerStatus.
+ class DeferredOperations {
+ public:
+ DeferredOperations(mixer_state *mixerStatus)
+ : mMixerStatus(mixerStatus) { }
+
+ // when leaving scope, tally frames properly.
+ ~DeferredOperations() {
+ // Tally underrun frames only if we are actually mixing (MIXER_TRACKS_READY)
+ // because that is when the underrun occurs.
+ // We do not distinguish between FastTracks and NormalTracks here.
+ if (*mMixerStatus == MIXER_TRACKS_READY) {
+ for (const auto &underrun : mUnderrunFrames) {
+ underrun.first->mAudioTrackServerProxy->tallyUnderrunFrames(
+ underrun.second);
+ }
+ }
+ }
+
+ // tallyUnderrunFrames() is called to update the track counters
+ // with the number of underrun frames for a particular mixer period.
+ // We defer tallying until we know the final mixer status.
+ void tallyUnderrunFrames(sp<Track> track, size_t underrunFrames) {
+ mUnderrunFrames.emplace_back(track, underrunFrames);
+ }
+
+ private:
+ const mixer_state * const mMixerStatus;
+ std::vector<std::pair<sp<Track>, size_t>> mUnderrunFrames;
+ } deferredOperations(&mixerStatus); // implicit nested scope for variable capture
+
for (size_t i=0 ; i<count ; i++) {
const sp<Track> t = mActiveTracks[i];
@@ -4299,13 +4332,14 @@
track->mObservedUnderruns = underruns;
// don't count underruns that occur while stopping or pausing
// or stopped which can occur when flush() is called while active
+ size_t underrunFrames = 0;
if (!(track->isStopping() || track->isPausing() || track->isStopped()) &&
recentUnderruns > 0) {
// FIXME fast mixer will pull & mix partial buffers, but we count as a full underrun
- track->mAudioTrackServerProxy->tallyUnderrunFrames(recentUnderruns * mFrameCount);
- } else {
- track->mAudioTrackServerProxy->tallyUnderrunFrames(0);
+ underrunFrames = recentUnderruns * mFrameCount;
}
+ // Immediately account for FastTrack underruns.
+ track->mAudioTrackServerProxy->tallyUnderrunFrames(underrunFrames);
// This is similar to the state machine for normal tracks,
// with a few modifications for fast tracks.
@@ -4720,13 +4754,13 @@
mixerStatus = MIXER_TRACKS_READY;
}
} else {
+ size_t underrunFrames = 0;
if (framesReady < desiredFrames && !track->isStopped() && !track->isPaused()) {
ALOGV("track(%p) underrun, framesReady(%zu) < framesDesired(%zd)",
track, framesReady, desiredFrames);
- track->mAudioTrackServerProxy->tallyUnderrunFrames(desiredFrames);
- } else {
- track->mAudioTrackServerProxy->tallyUnderrunFrames(0);
+ underrunFrames = desiredFrames;
}
+ deferredOperations.tallyUnderrunFrames(track, underrunFrames);
// clear effect chain input buffer if an active track underruns to avoid sending
// previous audio buffer again to effects
@@ -5025,6 +5059,12 @@
dprintf(fd, " Thread throttle time (msecs): %u\n", mThreadThrottleTimeMs);
dprintf(fd, " AudioMixer tracks: %s\n", mAudioMixer->trackNames().c_str());
dprintf(fd, " Master mono: %s\n", mMasterMono ? "on" : "off");
+ const double latencyMs = mTimestamp.getOutputServerLatencyMs(mSampleRate);
+ if (latencyMs != 0.) {
+ dprintf(fd, " NormalMixer latency ms: %.2lf\n", latencyMs);
+ } else {
+ dprintf(fd, " NormalMixer latency ms: unavail\n");
+ }
if (hasFastMixer()) {
dprintf(fd, " FastMixer thread %p tid=%d", mFastMixer.get(), mFastMixer->getTid());
@@ -5056,12 +5096,6 @@
} else {
dprintf(fd, " No FastMixer\n");
}
-
-#ifdef TEE_SINK
- // Write the tee output to a .wav file
- dumpTee(fd, mTeeSource, mId, 'M');
-#endif
-
}
uint32_t AudioFlinger::MixerThread::idleSleepTimeUs() const
@@ -6227,9 +6261,6 @@
audio_devices_t outDevice,
audio_devices_t inDevice,
bool systemReady
-#ifdef TEE_SINK
- , const sp<NBAIO_Sink>& teeSink
-#endif
) :
ThreadBase(audioFlinger, id, outDevice, inDevice, RECORD, systemReady),
mInput(input),
@@ -6237,9 +6268,6 @@
mRsmpInBuffer(NULL),
// mRsmpInFrames, mRsmpInFramesP2, and mRsmpInFramesOA are set by readInputParameters_l()
mRsmpInRear(0)
-#ifdef TEE_SINK
- , mTeeSink(teeSink)
-#endif
, mReadOnlyHeap(new MemoryDealer(kRecordThreadReadOnlyHeapSize,
"RecordThreadRO", MemoryHeapBase::READ_ONLY))
// mFastCapture below
@@ -6354,7 +6382,7 @@
// start the fast capture
mFastCapture->run("FastCapture", ANDROID_PRIORITY_URGENT_AUDIO);
pid_t tid = mFastCapture->getTid();
- sendPrioConfigEvent(getpid_cached, tid, kPriorityFastCapture, false /*forApp*/);
+ sendPrioConfigEvent(getpid(), tid, kPriorityFastCapture, false /*forApp*/);
stream()->setHalThreadPriority(kPriorityFastCapture);
#ifdef AUDIO_WATCHDOG
// FIXME
@@ -6362,6 +6390,10 @@
mFastTrackAvail = true;
}
+#ifdef TEE_SINK
+ mTee.set(mInputSource->format(), NBAIO_Tee::TEE_FLAG_INPUT_THREAD);
+ mTee.setId(std::string("_") + std::to_string(mId) + "_C");
+#endif
failed: ;
// FIXME mNormalSource
@@ -6704,9 +6736,9 @@
}
ALOG_ASSERT(framesRead > 0);
- if (mTeeSink != 0) {
- (void) mTeeSink->write((uint8_t*)mRsmpInBuffer + rear * mFrameSize, framesRead);
- }
+#ifdef TEE_SINK
+ (void)mTee.write((uint8_t*)mRsmpInBuffer + rear * mFrameSize, framesRead);
+#endif
// If destination is non-contiguous, we now correct for reading past end of buffer.
{
size_t part1 = mRsmpInFramesP2 - rear;
@@ -7304,6 +7336,13 @@
(void)input->stream->dump(fd);
}
+ const double latencyMs = - mTimestamp.getOutputServerLatencyMs(mSampleRate);
+ if (latencyMs != 0.) {
+ dprintf(fd, " NormalRecord latency ms: %.2lf\n", latencyMs);
+ } else {
+ dprintf(fd, " NormalRecord latency ms: unavail\n");
+ }
+
dprintf(fd, " Fast capture thread: %s\n", hasFastCapture() ? "yes" : "no");
dprintf(fd, " Fast track available: %s\n", mFastTrackAvail ? "yes" : "no");
@@ -7327,7 +7366,7 @@
if (numtracks) {
dprintf(fd, " of which %zu are active\n", numactive);
result.append(prefix);
- RecordTrack::appendDumpHeader(result);
+ mTracks[0]->appendDumpHeader(result);
for (size_t i = 0; i < numtracks ; ++i) {
sp<RecordTrack> track = mTracks[i];
if (track != 0) {
@@ -7347,7 +7386,7 @@
result.append(" The following tracks are in the active list but"
" not in the track list\n");
result.append(prefix);
- RecordTrack::appendDumpHeader(result);
+ mActiveTracks[0]->appendDumpHeader(result);
for (size_t i = 0; i < numactive; ++i) {
sp<RecordTrack> track = mActiveTracks[i];
if (mTracks.indexOf(track) < 0) {
@@ -7855,24 +7894,28 @@
return status;
}
-void AudioFlinger::RecordThread::addPatchRecord(const sp<PatchRecord>& record)
+void AudioFlinger::RecordThread::addPatchTrack(const sp<PatchRecord>& record)
{
Mutex::Autolock _l(mLock);
mTracks.add(record);
}
-void AudioFlinger::RecordThread::deletePatchRecord(const sp<PatchRecord>& record)
+void AudioFlinger::RecordThread::deletePatchTrack(const sp<PatchRecord>& record)
{
Mutex::Autolock _l(mLock);
destroyTrack_l(record);
}
-void AudioFlinger::RecordThread::getAudioPortConfig(struct audio_port_config *config)
+void AudioFlinger::RecordThread::toAudioPortConfig(struct audio_port_config *config)
{
- ThreadBase::getAudioPortConfig(config);
+ ThreadBase::toAudioPortConfig(config);
config->role = AUDIO_PORT_ROLE_SINK;
config->ext.mix.hw_module = mInput->audioHwDev->handle();
config->ext.mix.usecase.source = mAudioSource;
+ if (mInput && mInput->flags != AUDIO_INPUT_FLAG_NONE) {
+ config->config_mask |= AUDIO_PORT_CONFIG_FLAGS;
+ config->flags.input = mInput->flags;
+ }
}
// ----------------------------------------------------------------------------
@@ -8454,9 +8497,9 @@
return status;
}
-void AudioFlinger::MmapThread::getAudioPortConfig(struct audio_port_config *config)
+void AudioFlinger::MmapThread::toAudioPortConfig(struct audio_port_config *config)
{
- ThreadBase::getAudioPortConfig(config);
+ ThreadBase::toAudioPortConfig(config);
if (isOutput()) {
config->role = AUDIO_PORT_ROLE_SOURCE;
config->ext.mix.hw_module = mAudioHwDev->handle();
@@ -8840,6 +8883,15 @@
}
}
+void AudioFlinger::MmapPlaybackThread::toAudioPortConfig(struct audio_port_config *config)
+{
+ MmapThread::toAudioPortConfig(config);
+ if (mOutput && mOutput->flags != AUDIO_OUTPUT_FLAG_NONE) {
+ config->config_mask |= AUDIO_PORT_CONFIG_FLAGS;
+ config->flags.output = mOutput->flags;
+ }
+}
+
void AudioFlinger::MmapPlaybackThread::dumpInternals(int fd, const Vector<String16>& args)
{
MmapThread::dumpInternals(fd, args);
@@ -8930,4 +8982,13 @@
}
}
+void AudioFlinger::MmapCaptureThread::toAudioPortConfig(struct audio_port_config *config)
+{
+ MmapThread::toAudioPortConfig(config);
+ if (mInput && mInput->flags != AUDIO_INPUT_FLAG_NONE) {
+ config->config_mask |= AUDIO_PORT_CONFIG_FLAGS;
+ config->flags.input = mInput->flags;
+ }
+}
+
} // namespace android
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 28d4482..680e021 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -281,7 +281,7 @@
virtual status_t createAudioPatch_l(const struct audio_patch *patch,
audio_patch_handle_t *handle) = 0;
virtual status_t releaseAudioPatch_l(const audio_patch_handle_t handle) = 0;
- virtual void getAudioPortConfig(struct audio_port_config *config) = 0;
+ virtual void toAudioPortConfig(struct audio_port_config *config) = 0;
// see note at declaration of mStandby, mOutDevice and mInDevice
@@ -497,6 +497,9 @@
// we must not wait for async write callback in the thread loop before evaluating it
bool mSignalPending;
+#ifdef TEE_SINK
+ NBAIO_Tee mTee;
+#endif
// ActiveTracks is a sorted vector of track type T representing the
// active tracks of threadLoop() to be considered by the locked prepare portion.
// ActiveTracks should be accessed with the ThreadBase lock held.
@@ -782,7 +785,7 @@
void addPatchTrack(const sp<PatchTrack>& track);
void deletePatchTrack(const sp<PatchTrack>& track);
- virtual void getAudioPortConfig(struct audio_port_config *config);
+ virtual void toAudioPortConfig(struct audio_port_config *config);
// Return the asynchronous signal wait time.
virtual int64_t computeWaitTimeNs_l() const { return INT64_MAX; }
@@ -1054,11 +1057,6 @@
sp<NBAIO_Sink> mPipeSink;
// The current sink for the normal mixer to write it's (sub)mix, mOutputSink or mPipeSink
sp<NBAIO_Sink> mNormalSink;
-#ifdef TEE_SINK
- // For dumpsys
- sp<NBAIO_Sink> mTeeSink;
- sp<NBAIO_Source> mTeeSource;
-#endif
uint32_t mScreenState; // cached copy of gScreenState
// TODO: add comment and adjust size as needed
static const size_t kFastMixerLogSize = 8 * 1024;
@@ -1374,9 +1372,6 @@
audio_devices_t outDevice,
audio_devices_t inDevice,
bool systemReady
-#ifdef TEE_SINK
- , const sp<NBAIO_Sink>& teeSink
-#endif
);
virtual ~RecordThread();
@@ -1437,8 +1432,8 @@
audio_patch_handle_t *handle);
virtual status_t releaseAudioPatch_l(const audio_patch_handle_t handle);
- void addPatchRecord(const sp<PatchRecord>& record);
- void deletePatchRecord(const sp<PatchRecord>& record);
+ void addPatchTrack(const sp<PatchRecord>& record);
+ void deletePatchTrack(const sp<PatchRecord>& record);
void readInputParameters_l();
virtual uint32_t getInputFramesLost();
@@ -1459,7 +1454,7 @@
virtual size_t frameCount() const { return mFrameCount; }
bool hasFastCapture() const { return mFastCapture != 0; }
- virtual void getAudioPortConfig(struct audio_port_config *config);
+ virtual void toAudioPortConfig(struct audio_port_config *config);
virtual status_t checkEffectCompatibility_l(const effect_descriptor_t *desc,
audio_session_t sessionId);
@@ -1506,8 +1501,6 @@
int32_t mRsmpInRear; // last filled frame + 1
// For dumpsys
- const sp<NBAIO_Sink> mTeeSink;
-
const sp<MemoryDealer> mReadOnlyHeap;
// one-time initialization, no locks required
@@ -1602,7 +1595,7 @@
virtual status_t createAudioPatch_l(const struct audio_patch *patch,
audio_patch_handle_t *handle);
virtual status_t releaseAudioPatch_l(const audio_patch_handle_t handle);
- virtual void getAudioPortConfig(struct audio_port_config *config);
+ virtual void toAudioPortConfig(struct audio_port_config *config);
virtual sp<StreamHalInterface> stream() const { return mHalStream; }
virtual status_t addEffectChain_l(const sp<EffectChain>& chain);
@@ -1686,6 +1679,8 @@
void updateMetadata_l() override;
+ virtual void toAudioPortConfig(struct audio_port_config *config);
+
protected:
audio_stream_type_t mStreamType;
@@ -1714,6 +1709,8 @@
void processVolume_l() override;
void setRecordSilenced(uid_t uid, bool silenced) override;
+ virtual void toAudioPortConfig(struct audio_port_config *config);
+
protected:
AudioStreamIn* mInput;
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index ccfb69f..dafba1e 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -100,6 +100,92 @@
audio_attributes_t attributes() const { return mAttr; }
+#ifdef TEE_SINK
+ void dumpTee(int fd, const std::string &reason) const {
+ mTee.dump(fd, reason);
+ }
+#endif
+
+ /** returns the buffer contents size converted to time in milliseconds
+ * for PCM Playback or Record streaming tracks. The return value is zero for
+ * PCM static tracks and not defined for non-PCM tracks.
+ *
+ * This may be called without the thread lock.
+ */
+ virtual double bufferLatencyMs() const {
+ return mServerProxy->framesReadySafe() * 1000 / sampleRate();
+ }
+
+ /** returns whether the track supports server latency computation.
+ * This is set in the constructor and constant throughout the track lifetime.
+ */
+
+ bool isServerLatencySupported() const { return mServerLatencySupported; }
+
+ /** computes the server latency for PCM Playback or Record track
+ * to the device sink/source. This is the time for the next frame in the track buffer
+ * written or read from the server thread to the device source or sink.
+ *
+ * This may be called without the thread lock, but latencyMs and fromTrack
+ * may be not be synchronized. For example PatchPanel may not obtain the
+ * thread lock before calling.
+ *
+ * \param latencyMs on success is set to the latency in milliseconds of the
+ * next frame written/read by the server thread to/from the track buffer
+ * from the device source/sink.
+ * \param fromTrack on success is set to true if latency was computed directly
+ * from the track timestamp; otherwise set to false if latency was
+ * estimated from the server timestamp.
+ * fromTrack may be nullptr or omitted if not required.
+ *
+ * \returns OK or INVALID_OPERATION on failure.
+ */
+ status_t getServerLatencyMs(double *latencyMs, bool *fromTrack = nullptr) const {
+ if (!isServerLatencySupported()) {
+ return INVALID_OPERATION;
+ }
+
+ // if no thread lock is acquired, these atomics are not
+ // synchronized with each other, considered a benign race.
+
+ const double serverLatencyMs = mServerLatencyMs.load();
+ if (serverLatencyMs == 0.) {
+ return INVALID_OPERATION;
+ }
+ if (fromTrack != nullptr) {
+ *fromTrack = mServerLatencyFromTrack.load();
+ }
+ *latencyMs = serverLatencyMs;
+ return OK;
+ }
+
+ /** computes the total client latency for PCM Playback or Record tracks
+ * for the next client app access to the device sink/source; i.e. the
+ * server latency plus the buffer latency.
+ *
+ * This may be called without the thread lock, but latencyMs and fromTrack
+ * may be not be synchronized. For example PatchPanel may not obtain the
+ * thread lock before calling.
+ *
+ * \param latencyMs on success is set to the latency in milliseconds of the
+ * next frame written/read by the client app to/from the track buffer
+ * from the device sink/source.
+ * \param fromTrack on success is set to true if latency was computed directly
+ * from the track timestamp; otherwise set to false if latency was
+ * estimated from the server timestamp.
+ * fromTrack may be nullptr or omitted if not required.
+ *
+ * \returns OK or INVALID_OPERATION on failure.
+ */
+ status_t getTrackLatencyMs(double *latencyMs, bool *fromTrack = nullptr) const {
+ double serverLatencyMs;
+ status_t status = getServerLatencyMs(&serverLatencyMs, fromTrack);
+ if (status == OK) {
+ *latencyMs = serverLatencyMs + bufferLatencyMs();
+ }
+ return status;
+ }
+
protected:
DISALLOW_COPY_AND_ASSIGN(TrackBase);
@@ -208,13 +294,18 @@
const bool mIsOut;
sp<ServerProxy> mServerProxy;
const int mId;
- sp<NBAIO_Sink> mTeeSink;
- sp<NBAIO_Source> mTeeSource;
+#ifdef TEE_SINK
+ NBAIO_Tee mTee;
+#endif
bool mTerminated;
track_type mType; // must be one of TYPE_DEFAULT, TYPE_OUTPUT, TYPE_PATCH ...
audio_io_handle_t mThreadIoHandle; // I/O handle of the thread the track is attached to
audio_port_handle_t mPortId; // unique ID for this track used by audio policy
bool mIsInvalid; // non-resettable latch, set by invalidate()
+
+ bool mServerLatencySupported = false;
+ std::atomic<bool> mServerLatencyFromTrack{}; // latency from track or server timestamp.
+ std::atomic<double> mServerLatencyMs{}; // last latency pushed from server thread.
};
// PatchProxyBufferProvider interface is implemented by PatchTrack and PatchRecord.
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index a7c4253..5966f85 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -28,11 +28,11 @@
#include <private/media/AudioTrackShared.h>
#include "AudioFlinger.h"
-#include "ServiceUtilities.h"
#include <media/nbaio/Pipe.h>
#include <media/nbaio/PipeReader.h>
#include <media/RecordBufferConverter.h>
+#include <mediautils/ServiceUtilities.h>
#include <audio_utils/minifloat.h>
// ----------------------------------------------------------------------------
@@ -102,7 +102,7 @@
mIsInvalid(false)
{
const uid_t callingUid = IPCThreadState::self()->getCallingUid();
- if (!isTrustedCallingUid(callingUid) || clientUid == AUDIO_UID_INVALID) {
+ if (!isAudioServerOrMediaServerUid(callingUid) || clientUid == AUDIO_UID_INVALID) {
ALOGW_IF(clientUid != AUDIO_UID_INVALID && clientUid != callingUid,
"%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, clientUid);
clientUid = callingUid;
@@ -210,22 +210,7 @@
mBufferSize = bufferSize;
#ifdef TEE_SINK
- if (mTeeSinkTrackEnabled) {
- NBAIO_Format pipeFormat = Format_from_SR_C(mSampleRate, mChannelCount, mFormat);
- if (Format_isValid(pipeFormat)) {
- Pipe *pipe = new Pipe(mTeeSinkTrackFrames, pipeFormat);
- size_t numCounterOffers = 0;
- const NBAIO_Format offers[1] = {pipeFormat};
- ssize_t index = pipe->negotiate(offers, 1, NULL, numCounterOffers);
- ALOG_ASSERT(index == 0);
- PipeReader *pipeReader = new PipeReader(*pipe);
- numCounterOffers = 0;
- index = pipeReader->negotiate(offers, 1, NULL, numCounterOffers);
- ALOG_ASSERT(index == 0);
- mTeeSink = pipe;
- mTeeSource = pipeReader;
- }
- }
+ mTee.set(sampleRate, mChannelCount, format, NBAIO_Tee::TEE_FLAG_TRACK);
#endif
}
@@ -244,9 +229,6 @@
AudioFlinger::ThreadBase::TrackBase::~TrackBase()
{
-#ifdef TEE_SINK
- dumpTee(-1, mTeeSource, mId, 'T');
-#endif
// delete the proxy before deleting the shared memory it refers to, to avoid dangling reference
mServerProxy.clear();
if (mCblk != NULL) {
@@ -274,9 +256,7 @@
void AudioFlinger::ThreadBase::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
{
#ifdef TEE_SINK
- if (mTeeSink != 0) {
- (void) mTeeSink->write(buffer->raw, buffer->frameCount);
- }
+ mTee.write(buffer->raw, buffer->frameCount);
#endif
ServerProxy::Buffer buf;
@@ -454,6 +434,13 @@
thread->mFastTrackAvailMask &= ~(1 << i);
}
mName = TRACK_NAME_PENDING;
+
+ mServerLatencySupported = thread->type() == ThreadBase::MIXER;
+#ifdef TEE_SINK
+ mTee.setId(std::string("_") + std::to_string(mThreadIoHandle)
+ + "_" + std::to_string(mId) +
+ + "_PEND_T");
+#endif
}
AudioFlinger::PlaybackThread::Track::~Track()
@@ -503,13 +490,14 @@
}
}
-/*static*/ void AudioFlinger::PlaybackThread::Track::appendDumpHeader(String8& result)
+void AudioFlinger::PlaybackThread::Track::appendDumpHeader(String8& result)
{
- result.append("T Name Active Client Session S Flags "
+ result.appendFormat("T Name Active Client Session S Flags "
" Format Chn mask SRate "
"ST L dB R dB VS dB "
- " Server FrmCnt FrmRdy F Underruns Flushed "
- "Main Buf Aux Buf\n");
+ " Server FrmCnt FrmRdy F Underruns Flushed"
+ "%s\n",
+ isServerLatencySupported() ? " Latency" : "");
}
void AudioFlinger::PlaybackThread::Track::appendDump(String8& result, bool active)
@@ -518,7 +506,7 @@
switch (mType) {
case TYPE_DEFAULT:
case TYPE_OUTPUT:
- if (mSharedBuffer.get() != nullptr) {
+ if (isStatic()) {
trackType = 'S'; // static
} else {
trackType = ' '; // normal
@@ -596,17 +584,16 @@
result.appendFormat("%7s %6u %7u %2s 0x%03X "
"%08X %08X %6u "
"%2u %5.2g %5.2g %5.2g%c "
- "%08X %6zu%c %6zu %c %9u%c %7u "
- "%08zX %08zX\n",
+ "%08X %6zu%c %6zu %c %9u%c %7u",
active ? "yes" : "no",
- (mClient == 0) ? getpid_cached : mClient->pid(),
+ (mClient == 0) ? getpid() : mClient->pid(),
mSessionId,
getTrackStateString(),
mCblk->mFlags,
mFormat,
mChannelMask,
- mAudioTrackServerProxy->getSampleRate(),
+ sampleRate(),
mStreamType,
20.0 * log10(float_from_gain(gain_minifloat_unpack_left(vlr))),
@@ -621,11 +608,21 @@
fillingStatus,
mAudioTrackServerProxy->getUnderrunFrames(),
nowInUnderrun,
- (unsigned)mAudioTrackServerProxy->framesFlushed() % 10000000,
-
- (size_t)mMainBuffer, // use %zX as %p appends 0x
- (size_t)mAuxBuffer // use %zX as %p appends 0x
+ (unsigned)mAudioTrackServerProxy->framesFlushed() % 10000000
);
+
+ if (isServerLatencySupported()) {
+ double latencyMs;
+ bool fromTrack;
+ if (getTrackLatencyMs(&latencyMs, &fromTrack) == OK) {
+ // Show latency in msec, followed by 't' if from track timestamp (the most accurate)
+ // or 'k' if estimated from kernel because track frames haven't been presented yet.
+ result.appendFormat(" %7.2lf %c", latencyMs, fromTrack ? 't' : 'k');
+ } else {
+ result.appendFormat("%10s", mCblk->mServer != 0 ? "unavail" : "new");
+ }
+ }
+ result.append("\n");
}
uint32_t AudioFlinger::PlaybackThread::Track::sampleRate() const {
@@ -682,6 +679,13 @@
mAudioTrackServerProxy->setTimestamp(timestamp);
// We do not set drained here, as FastTrack timestamp may not go to very last frame.
+
+ // Compute latency.
+ // TODO: Consider whether the server latency may be passed in by FastMixer
+ // as a constant for all active FastTracks.
+ const double latencyMs = timestamp.getOutputServerLatencyMs(sampleRate());
+ mServerLatencyFromTrack.store(true);
+ mServerLatencyMs.store(latencyMs);
}
// Don't call for fast tracks; the framesReady() could result in priority inversion
@@ -1246,7 +1250,7 @@
//To be called with thread lock held
void AudioFlinger::PlaybackThread::Track::updateTrackFrameInfo(
int64_t trackFramesReleased, int64_t sinkFramesWritten,
- const ExtendedTimestamp &timeStamp) {
+ uint32_t halSampleRate, const ExtendedTimestamp &timeStamp) {
//update frame map
mFrameMap.push(trackFramesReleased, sinkFramesWritten);
@@ -1255,6 +1259,7 @@
// Our timestamps are only updated when the track is on the Thread active list.
// We need to ensure that tracks are not removed before full drain.
ExtendedTimestamp local = timeStamp;
+ bool drained = true; // default assume drained, if no server info found
bool checked = false;
for (int i = ExtendedTimestamp::LOCATION_MAX - 1;
i >= ExtendedTimestamp::LOCATION_SERVER; --i) {
@@ -1263,18 +1268,25 @@
local.mPosition[i] = mFrameMap.findX(local.mPosition[i]);
// check drain state from the latest stage in the pipeline.
if (!checked && i <= ExtendedTimestamp::LOCATION_KERNEL) {
- mAudioTrackServerProxy->setDrained(
- local.mPosition[i] >= mAudioTrackServerProxy->framesReleased());
+ drained = local.mPosition[i] >= mAudioTrackServerProxy->framesReleased();
checked = true;
}
}
}
- if (!checked) { // no server info, assume drained.
- mAudioTrackServerProxy->setDrained(true);
- }
+
+ mAudioTrackServerProxy->setDrained(drained);
// Set correction for flushed frames that are not accounted for in released.
local.mFlushed = mAudioTrackServerProxy->framesFlushed();
mServerProxy->setTimestamp(local);
+
+ // Compute latency info.
+ const bool useTrackTimestamp = !drained;
+ const double latencyMs = useTrackTimestamp
+ ? local.getOutputServerLatencyMs(sampleRate())
+ : timeStamp.getOutputServerLatencyMs(halSampleRate);
+
+ mServerLatencyFromTrack.store(useTrackTimestamp);
+ mServerLatencyMs.store(latencyMs);
}
// ----------------------------------------------------------------------------
@@ -1509,7 +1521,7 @@
audio_attributes_t{} /* currently unused for patch track */,
sampleRate, format, channelMask, frameCount,
buffer, bufferSize, nullptr /* sharedBuffer */,
- AUDIO_SESSION_NONE, getuid(), flags, TYPE_PATCH),
+ AUDIO_SESSION_NONE, AID_AUDIOSERVER, flags, TYPE_PATCH),
mProxy(new ClientProxy(mCblk, mBuffer, frameCount, mFrameSize, true, true))
{
uint64_t mixBufferNs = ((uint64_t)2 * playbackThread->frameCount() * 1000000000) /
@@ -1694,7 +1706,15 @@
if (flags & AUDIO_INPUT_FLAG_FAST) {
ALOG_ASSERT(thread->mFastTrackAvail);
thread->mFastTrackAvail = false;
+ } else {
+ // TODO: only Normal Record has timestamps (Fast Record does not).
+ mServerLatencySupported = true;
}
+#ifdef TEE_SINK
+ mTee.setId(std::string("_") + std::to_string(mThreadIoHandle)
+ + "_" + std::to_string(mId)
+ + "_R");
+#endif
}
AudioFlinger::RecordThread::RecordTrack::~RecordTrack()
@@ -1783,19 +1803,20 @@
}
-/*static*/ void AudioFlinger::RecordThread::RecordTrack::appendDumpHeader(String8& result)
+void AudioFlinger::RecordThread::RecordTrack::appendDumpHeader(String8& result)
{
- result.append("Active Client Session S Flags Format Chn mask SRate Server FrmCnt Sil\n");
+ result.appendFormat("Active Client Session S Flags Format Chn mask SRate Server"
+ " FrmCnt FrmRdy Sil%s\n", isServerLatencySupported() ? " Latency" : "");
}
void AudioFlinger::RecordThread::RecordTrack::appendDump(String8& result, bool active)
{
result.appendFormat("%c%5s %6u %7u %2s 0x%03X "
"%08X %08X %6u "
- "%08X %6zu %3c\n",
+ "%08X %6zu %6zu %3c",
isFastTrack() ? 'F' : ' ',
active ? "yes" : "no",
- (mClient == 0) ? getpid_cached : mClient->pid(),
+ (mClient == 0) ? getpid() : mClient->pid(),
mSessionId,
getTrackStateString(),
mCblk->mFlags,
@@ -1806,8 +1827,21 @@
mCblk->mServer,
mFrameCount,
+ mServerProxy->framesReadySafe(),
isSilenced() ? 's' : 'n'
);
+ if (isServerLatencySupported()) {
+ double latencyMs;
+ bool fromTrack;
+ if (getTrackLatencyMs(&latencyMs, &fromTrack) == OK) {
+ // Show latency in msec, followed by 't' if from track timestamp (the most accurate)
+ // or 'k' if estimated from kernel (usually for debugging).
+ result.appendFormat(" %7.2lf %c", latencyMs, fromTrack ? 't' : 'k');
+ } else {
+ result.appendFormat("%10s", mCblk->mServer != 0 ? "unavail" : "new");
+ }
+ }
+ result.append("\n");
}
void AudioFlinger::RecordThread::RecordTrack::handleSyncStartEvent(const sp<SyncEvent>& event)
@@ -1850,6 +1884,15 @@
}
}
mServerProxy->setTimestamp(local);
+
+ // Compute latency info.
+ const bool useTrackTimestamp = true; // use track unless debugging.
+ const double latencyMs = - (useTrackTimestamp
+ ? local.getOutputServerLatencyMs(sampleRate())
+ : timestamp.getOutputServerLatencyMs(halSampleRate));
+
+ mServerLatencyFromTrack.store(useTrackTimestamp);
+ mServerLatencyMs.store(latencyMs);
}
status_t AudioFlinger::RecordThread::RecordTrack::getActiveMicrophones(
@@ -1875,7 +1918,8 @@
: RecordTrack(recordThread, NULL,
audio_attributes_t{} /* currently unused for patch track */,
sampleRate, format, channelMask, frameCount,
- buffer, bufferSize, AUDIO_SESSION_NONE, getuid(), flags, TYPE_PATCH),
+ buffer, bufferSize, AUDIO_SESSION_NONE, AID_AUDIOSERVER,
+ flags, TYPE_PATCH),
mProxy(new ClientProxy(mCblk, mBuffer, frameCount, mFrameSize, false, true))
{
uint64_t mixBufferNs = ((uint64_t)2 * recordThread->frameCount() * 1000000000) /
diff --git a/services/audiopolicy/Android.mk b/services/audiopolicy/Android.mk
index d29cae1..b75e957 100644
--- a/services/audiopolicy/Android.mk
+++ b/services/audiopolicy/Android.mk
@@ -13,7 +13,6 @@
$(call include-path-for, audio-utils) \
frameworks/av/services/audiopolicy/common/include \
frameworks/av/services/audiopolicy/engine/interface \
- frameworks/av/services/audiopolicy/utilities
LOCAL_SHARED_LIBRARIES := \
libcutils \
@@ -22,10 +21,10 @@
libbinder \
libaudioclient \
libhardware_legacy \
- libserviceutility \
libaudiopolicymanager \
libmedia_helper \
libmediametrics \
+ libmediautils \
libeffectsconfig
LOCAL_STATIC_LIBRARIES := \
@@ -74,7 +73,6 @@
LOCAL_C_INCLUDES += \
frameworks/av/services/audiopolicy/common/include \
frameworks/av/services/audiopolicy/engine/interface \
- frameworks/av/services/audiopolicy/utilities
LOCAL_STATIC_LIBRARIES := \
libaudiopolicycomponents
diff --git a/services/audiopolicy/common/managerdefinitions/Android.mk b/services/audiopolicy/common/managerdefinitions/Android.mk
index e69e687..b3611c4 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.mk
+++ b/services/audiopolicy/common/managerdefinitions/Android.mk
@@ -35,8 +35,7 @@
$(LOCAL_PATH)/include \
frameworks/av/services/audiopolicy/common/include \
frameworks/av/services/audiopolicy \
- frameworks/av/services/audiopolicy/utilities \
- system/media/audio_utils/include \
+ $(call include-path-for, audio-utils) \
ifeq ($(USE_XML_AUDIO_POLICY_CONF), 1)
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioSessionInfoProvider.h b/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h
similarity index 67%
rename from services/audiopolicy/common/managerdefinitions/include/AudioSessionInfoProvider.h
rename to services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h
index e0037fc..9f3fc0c 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioSessionInfoProvider.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h
@@ -19,26 +19,27 @@
namespace android {
/**
- * Interface for input descriptors to implement so dependent audio sessions can query information
- * about their context
+ * Interface for I/O descriptors to implement so information about their context
+ * can be queried and updated.
*/
-class AudioSessionInfoProvider
+class AudioIODescriptorInterface
{
public:
- virtual ~AudioSessionInfoProvider() {};
+ virtual ~AudioIODescriptorInterface() {};
virtual audio_config_base_t getConfig() const = 0;
virtual audio_patch_handle_t getPatchHandle() const = 0;
+ virtual void setPatchHandle(audio_patch_handle_t handle) = 0;
};
-class AudioSessionInfoUpdateListener
+class AudioIODescriptorUpdateListener
{
public:
- virtual ~AudioSessionInfoUpdateListener() {};
+ virtual ~AudioIODescriptorUpdateListener() {};
- virtual void onSessionInfoUpdate() const = 0;;
+ virtual void onIODescriptorUpdate() const = 0;
};
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index b25d6d4..85f3b86 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -16,9 +16,9 @@
#pragma once
+#include "AudioIODescriptorInterface.h"
#include "AudioPort.h"
#include "AudioSession.h"
-#include "AudioSessionInfoProvider.h"
#include <utils/Errors.h>
#include <system/audio.h>
#include <utils/SortedVector.h>
@@ -31,7 +31,7 @@
// descriptor for audio inputs. Used to maintain current configuration of each opened audio input
// and keep track of the usage of this input.
-class AudioInputDescriptor: public AudioPortConfig, public AudioSessionInfoProvider
+class AudioInputDescriptor: public AudioPortConfig, public AudioIODescriptorInterface
{
public:
explicit AudioInputDescriptor(const sp<IOProfile>& profile,
@@ -67,11 +67,10 @@
size_t getAudioSessionCount(bool activeOnly) const;
audio_source_t getHighestPrioritySource(bool activeOnly) const;
- // implementation of AudioSessionInfoProvider
- virtual audio_config_base_t getConfig() const;
- virtual audio_patch_handle_t getPatchHandle() const;
-
- void setPatchHandle(audio_patch_handle_t handle);
+ // implementation of AudioIODescriptorInterface
+ audio_config_base_t getConfig() const override;
+ audio_patch_handle_t getPatchHandle() const override;
+ void setPatchHandle(audio_patch_handle_t handle) override;
status_t open(const audio_config_t *config,
audio_devices_t device,
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 5e5d38b..57d1cfa 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -24,6 +24,7 @@
#include <utils/Timers.h>
#include <utils/KeyedVector.h>
#include <system/audio.h>
+#include "AudioIODescriptorInterface.h"
#include "AudioSourceDescriptor.h"
namespace android {
@@ -35,7 +36,7 @@
// descriptor for audio outputs. Used to maintain current configuration of each opened audio output
// and keep track of the usage of this output by each audio stream type.
-class AudioOutputDescriptor: public AudioPortConfig
+class AudioOutputDescriptor: public AudioPortConfig, public AudioIODescriptorInterface
{
public:
AudioOutputDescriptor(const sp<AudioPort>& port,
@@ -73,8 +74,10 @@
audio_module_handle_t getModuleHandle() const;
- audio_patch_handle_t getPatchHandle() const { return mPatchHandle; };
- void setPatchHandle(audio_patch_handle_t handle) { mPatchHandle = handle; };
+ // implementation of AudioIODescriptorInterface
+ audio_config_base_t getConfig() const override;
+ audio_patch_handle_t getPatchHandle() const override;
+ void setPatchHandle(audio_patch_handle_t handle) override;
sp<AudioPort> mPort;
audio_devices_t mDevice; // current device this output is routed to
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
index 43f6ed6..f747c36 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
@@ -48,6 +48,14 @@
mIsSpeakerDrcEnabled(false)
{}
+ const std::string& getSource() const {
+ return mSource;
+ }
+
+ void setSource(const std::string& file) {
+ mSource = file;
+ }
+
void setVolumes(const VolumeCurvesCollection &volumes)
{
if (mVolumeCurves != nullptr) {
@@ -107,6 +115,7 @@
void setDefault(void)
{
+ mSource = "AudioPolicyConfig::setDefault";
mDefaultOutputDevices = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPEAKER);
sp<HwModule> module;
sp<DeviceDescriptor> defaultInputDevice = new DeviceDescriptor(AUDIO_DEVICE_IN_BUILTIN_MIC);
@@ -136,6 +145,7 @@
}
private:
+ std::string mSource;
HwModuleCollection &mHwModules; /**< Collection of Module, with Profiles, i.e. Mix Ports. */
DeviceVector &mAvailableOutputDevices;
DeviceVector &mAvailableInputDevices;
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
index 09a86dd..bd7517f 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
@@ -153,9 +153,6 @@
class AudioPortConfig : public virtual RefBase
{
public:
- AudioPortConfig();
- virtual ~AudioPortConfig() {}
-
status_t applyAudioPortConfig(const struct audio_port_config *config,
struct audio_port_config *backupConfig = NULL);
virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
@@ -165,10 +162,11 @@
return (other != 0) &&
(other->getAudioPort()->getModuleHandle() == getAudioPort()->getModuleHandle());
}
- uint32_t mSamplingRate;
- audio_format_t mFormat;
- audio_channel_mask_t mChannelMask;
- struct audio_gain_config mGain;
+ unsigned int mSamplingRate = 0u;
+ audio_format_t mFormat = AUDIO_FORMAT_INVALID;
+ audio_channel_mask_t mChannelMask = AUDIO_CHANNEL_NONE;
+ struct audio_gain_config mGain = { .index = -1 };
+ union audio_io_flags mFlags = { AUDIO_INPUT_FLAG_NONE };
};
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
index dd5247d..53e6ec9 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
@@ -23,13 +23,13 @@
#include <utils/KeyedVector.h>
#include <media/AudioPolicy.h>
#include <media/IAudioPolicyServiceClient.h>
-#include "AudioSessionInfoProvider.h"
+#include "AudioIODescriptorInterface.h"
namespace android {
class AudioPolicyClientInterface;
-class AudioSession : public RefBase, public AudioSessionInfoUpdateListener
+class AudioSession : public RefBase, public AudioIODescriptorUpdateListener
{
public:
AudioSession(audio_session_t session,
@@ -63,9 +63,9 @@
uint32_t changeOpenCount(int delta);
uint32_t changeActiveCount(int delta);
- void setInfoProvider(AudioSessionInfoProvider *provider);
- // implementation of AudioSessionInfoUpdateListener
- virtual void onSessionInfoUpdate() const;
+ void setInfoProvider(AudioIODescriptorInterface *provider);
+ // implementation of AudioIODescriptorUpdateListener
+ virtual void onIODescriptorUpdate() const;
private:
record_client_info_t mRecordClientInfo;
@@ -77,17 +77,17 @@
uint32_t mActiveCount;
AudioMix* mPolicyMix; // non NULL when used by a dynamic policy
AudioPolicyClientInterface* mClientInterface;
- const AudioSessionInfoProvider* mInfoProvider;
+ const AudioIODescriptorInterface* mInfoProvider;
};
class AudioSessionCollection :
public DefaultKeyedVector<audio_session_t, sp<AudioSession> >,
- public AudioSessionInfoUpdateListener
+ public AudioIODescriptorUpdateListener
{
public:
status_t addSession(audio_session_t session,
const sp<AudioSession>& audioSession,
- AudioSessionInfoProvider *provider);
+ AudioIODescriptorInterface *provider);
status_t removeSession(audio_session_t session);
@@ -99,8 +99,8 @@
bool isSourceActive(audio_source_t source) const;
audio_source_t getHighestPrioritySource(bool activeOnly) const;
- // implementation of AudioSessionInfoUpdateListener
- virtual void onSessionInfoUpdate() const;
+ // implementation of AudioIODescriptorUpdateListener
+ virtual void onIODescriptorUpdate() const;
status_t dump(int fd, int spaces) const;
};
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index 92a4c3e..2325e4f 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -76,11 +76,12 @@
audio_devices_t types() const { return mDeviceTypes; }
- sp<DeviceDescriptor> getDevice(audio_devices_t type, const String8& address) const;
- DeviceVector getDevicesFromType(audio_devices_t types) const;
+ // If 'address' is empty, a device with a non-empty address may be returned
+ // if there is no device with the specified 'type' and empty address.
+ sp<DeviceDescriptor> getDevice(audio_devices_t type, const String8 &address) const;
+ DeviceVector getDevicesFromTypeMask(audio_devices_t types) const;
sp<DeviceDescriptor> getDeviceFromId(audio_port_handle_t id) const;
sp<DeviceDescriptor> getDeviceFromTagName(const String8 &tagName) const;
- DeviceVector getDevicesFromTypeAddr(audio_devices_t type, const String8& address) const;
audio_devices_t getDevicesFromHwModule(audio_module_handle_t moduleHandle) const;
diff --git a/services/audiopolicy/common/managerdefinitions/include/HwModule.h b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
index cb9f49e..05cfc31 100644
--- a/services/audiopolicy/common/managerdefinitions/include/HwModule.h
+++ b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
@@ -107,7 +107,7 @@
sp<DeviceDescriptor> getDeviceDescriptor(const audio_devices_t device,
const char *device_address,
const char *device_name,
- bool matchAdress = true) const;
+ bool matchAddress = true) const;
status_t dump(int fd) const;
};
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index 92332fb..f0144db 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -164,7 +164,7 @@
status_t AudioInputDescriptor::addAudioSession(audio_session_t session,
const sp<AudioSession>& audioSession) {
- return mSessions.addSession(session, audioSession, /*AudioSessionInfoProvider*/this);
+ return mSessions.addSession(session, audioSession, /*AudioIODescriptorInterface*/this);
}
status_t AudioInputDescriptor::removeAudioSession(audio_session_t session) {
@@ -179,7 +179,7 @@
void AudioInputDescriptor::setPatchHandle(audio_patch_handle_t handle)
{
mPatchHandle = handle;
- mSessions.onSessionInfoUpdate();
+ mSessions.onIODescriptorUpdate();
}
audio_config_base_t AudioInputDescriptor::getConfig() const
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 294a2a6..3c69de5 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -55,11 +55,28 @@
}
}
+audio_config_base_t AudioOutputDescriptor::getConfig() const
+{
+ const audio_config_base_t config = { .sample_rate = mSamplingRate, .channel_mask = mChannelMask,
+ .format = mFormat };
+ return config;
+}
+
audio_module_handle_t AudioOutputDescriptor::getModuleHandle() const
{
return mPort.get() != nullptr ? mPort->getModuleHandle() : AUDIO_MODULE_HANDLE_NONE;
}
+audio_patch_handle_t AudioOutputDescriptor::getPatchHandle() const
+{
+ return mPatchHandle;
+}
+
+void AudioOutputDescriptor::setPatchHandle(audio_patch_handle_t handle)
+{
+ mPatchHandle = handle;
+}
+
audio_port_handle_t AudioOutputDescriptor::getId() const
{
return mId;
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
index a9fe48d..e78e121 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
@@ -34,51 +34,32 @@
{
}
+static String8 dumpPatchEndpoints(
+ int spaces, const char *prefix, int count, const audio_port_config *cfgs)
+{
+ String8 result;
+ for (int i = 0; i < count; ++i) {
+ const audio_port_config &cfg = cfgs[i];
+ result.appendFormat("%*s [%s %d] ", spaces, "", prefix, i + 1);
+ if (cfg.type == AUDIO_PORT_TYPE_DEVICE) {
+ std::string device;
+ deviceToString(cfg.ext.device.type, device);
+ result.appendFormat("Device ID %d %s", cfg.id, device.c_str());
+ } else {
+ result.appendFormat("Mix ID %d I/O handle %d", cfg.id, cfg.ext.mix.handle);
+ }
+ result.append("\n");
+ }
+ return result;
+}
+
status_t AudioPatch::dump(int fd, int spaces, int index) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
String8 result;
-
- snprintf(buffer, SIZE, "%*sAudio patch %d:\n", spaces, "", index+1);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- handle: %2d\n", spaces, "", mHandle);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- audio flinger handle: %2d\n", spaces, "", mAfPatchHandle);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- owner uid: %2d\n", spaces, "", mUid);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- %d sources:\n", spaces, "", mPatch.num_sources);
- result.append(buffer);
- for (size_t i = 0; i < mPatch.num_sources; i++) {
- if (mPatch.sources[i].type == AUDIO_PORT_TYPE_DEVICE) {
- std::string device;
- deviceToString(mPatch.sources[i].ext.device.type, device);
- snprintf(buffer, SIZE, "%*s- Device ID %d %s\n", spaces + 2, "",
- mPatch.sources[i].id,
- device.c_str());
- } else {
- snprintf(buffer, SIZE, "%*s- Mix ID %d I/O handle %d\n", spaces + 2, "",
- mPatch.sources[i].id, mPatch.sources[i].ext.mix.handle);
- }
- result.append(buffer);
- }
- snprintf(buffer, SIZE, "%*s- %d sinks:\n", spaces, "", mPatch.num_sinks);
- result.append(buffer);
- for (size_t i = 0; i < mPatch.num_sinks; i++) {
- if (mPatch.sinks[i].type == AUDIO_PORT_TYPE_DEVICE) {
- std::string device;
- deviceToString(mPatch.sinks[i].ext.device.type, device);
- snprintf(buffer, SIZE, "%*s- Device ID %d %s\n", spaces + 2, "",
- mPatch.sinks[i].id,
- device.c_str());
- } else {
- snprintf(buffer, SIZE, "%*s- Mix ID %d I/O handle %d\n", spaces + 2, "",
- mPatch.sinks[i].id, mPatch.sinks[i].ext.mix.handle);
- }
- result.append(buffer);
- }
-
+ result.appendFormat("%*sPatch %d: owner uid %4d, handle %2d, af handle %2d\n",
+ spaces, "", index + 1, mUid, mHandle, mAfPatchHandle);
+ result.append(dumpPatchEndpoints(spaces, "src ", mPatch.num_sources, mPatch.sources));
+ result.append(dumpPatchEndpoints(spaces, "sink", mPatch.num_sinks, mPatch.sinks));
write(fd, result.string(), result.size());
return NO_ERROR;
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
index d85562e..3fe37ab 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
@@ -386,22 +386,12 @@
// --- AudioPortConfig class implementation
-AudioPortConfig::AudioPortConfig()
-{
- mSamplingRate = 0;
- mChannelMask = AUDIO_CHANNEL_NONE;
- mFormat = AUDIO_FORMAT_INVALID;
- memset(&mGain, 0, sizeof(struct audio_gain_config));
- mGain.index = -1;
-}
-
status_t AudioPortConfig::applyAudioPortConfig(const struct audio_port_config *config,
struct audio_port_config *backupConfig)
{
- struct audio_port_config localBackupConfig;
+ struct audio_port_config localBackupConfig = { .config_mask = config->config_mask };
status_t status = NO_ERROR;
- localBackupConfig.config_mask = config->config_mask;
toAudioPortConfig(&localBackupConfig);
sp<AudioPort> audioport = getAudioPort();
@@ -425,6 +415,9 @@
if (config->config_mask & AUDIO_PORT_CONFIG_GAIN) {
mGain = config->gain;
}
+ if (config->config_mask & AUDIO_PORT_CONFIG_FLAGS) {
+ mFlags = config->flags;
+ }
exit:
if (status != NO_ERROR) {
@@ -436,33 +429,38 @@
return status;
}
+namespace {
+
+template<typename T>
+void updateField(
+ const T& portConfigField, T audio_port_config::*port_config_field,
+ struct audio_port_config *dstConfig, const struct audio_port_config *srcConfig,
+ unsigned int configMask, T defaultValue)
+{
+ if (dstConfig->config_mask & configMask) {
+ if ((srcConfig != nullptr) && (srcConfig->config_mask & configMask)) {
+ dstConfig->*port_config_field = srcConfig->*port_config_field;
+ } else {
+ dstConfig->*port_config_field = portConfigField;
+ }
+ } else {
+ dstConfig->*port_config_field = defaultValue;
+ }
+}
+
+} // namespace
+
void AudioPortConfig::toAudioPortConfig(struct audio_port_config *dstConfig,
const struct audio_port_config *srcConfig) const
{
- if (dstConfig->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
- dstConfig->sample_rate = mSamplingRate;
- if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE)) {
- dstConfig->sample_rate = srcConfig->sample_rate;
- }
- } else {
- dstConfig->sample_rate = 0;
- }
- if (dstConfig->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
- dstConfig->channel_mask = mChannelMask;
- if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK)) {
- dstConfig->channel_mask = srcConfig->channel_mask;
- }
- } else {
- dstConfig->channel_mask = AUDIO_CHANNEL_NONE;
- }
- if (dstConfig->config_mask & AUDIO_PORT_CONFIG_FORMAT) {
- dstConfig->format = mFormat;
- if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_FORMAT)) {
- dstConfig->format = srcConfig->format;
- }
- } else {
- dstConfig->format = AUDIO_FORMAT_INVALID;
- }
+ updateField(mSamplingRate, &audio_port_config::sample_rate,
+ dstConfig, srcConfig, AUDIO_PORT_CONFIG_SAMPLE_RATE, 0u);
+ updateField(mChannelMask, &audio_port_config::channel_mask,
+ dstConfig, srcConfig, AUDIO_PORT_CONFIG_CHANNEL_MASK,
+ (audio_channel_mask_t)AUDIO_CHANNEL_NONE);
+ updateField(mFormat, &audio_port_config::format,
+ dstConfig, srcConfig, AUDIO_PORT_CONFIG_FORMAT, AUDIO_FORMAT_INVALID);
+
sp<AudioPort> audioport = getAudioPort();
if ((dstConfig->config_mask & AUDIO_PORT_CONFIG_GAIN) && audioport != NULL) {
dstConfig->gain = mGain;
@@ -478,6 +476,9 @@
} else {
dstConfig->config_mask &= ~AUDIO_PORT_CONFIG_GAIN;
}
+
+ updateField(mFlags, &audio_port_config::flags,
+ dstConfig, srcConfig, AUDIO_PORT_CONFIG_FLAGS, { AUDIO_INPUT_FLAG_NONE });
}
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
index 7cda46b..91dee35 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
@@ -86,7 +86,7 @@
}
// Recording configuration callback:
- const AudioSessionInfoProvider* provider = mInfoProvider;
+ const AudioIODescriptorInterface* provider = mInfoProvider;
const audio_config_base_t deviceConfig = (provider != NULL) ? provider->getConfig() :
AUDIO_CONFIG_BASE_INITIALIZER;
const audio_patch_handle_t patchHandle = (provider != NULL) ? provider->getPatchHandle() :
@@ -114,16 +114,16 @@
return false;
}
-void AudioSession::setInfoProvider(AudioSessionInfoProvider *provider)
+void AudioSession::setInfoProvider(AudioIODescriptorInterface *provider)
{
mInfoProvider = provider;
}
-void AudioSession::onSessionInfoUpdate() const
+void AudioSession::onIODescriptorUpdate() const
{
if (mActiveCount > 0) {
// resend the callback after requerying the informations from the info provider
- const AudioSessionInfoProvider* provider = mInfoProvider;
+ const AudioIODescriptorInterface* provider = mInfoProvider;
const audio_config_base_t deviceConfig = (provider != NULL) ? provider->getConfig() :
AUDIO_CONFIG_BASE_INITIALIZER;
const audio_patch_handle_t patchHandle = (provider != NULL) ? provider->getPatchHandle() :
@@ -170,7 +170,7 @@
status_t AudioSessionCollection::addSession(audio_session_t session,
const sp<AudioSession>& audioSession,
- AudioSessionInfoProvider *provider)
+ AudioIODescriptorInterface *provider)
{
ssize_t index = indexOfKey(session);
@@ -271,10 +271,10 @@
return source;
}
-void AudioSessionCollection::onSessionInfoUpdate() const
+void AudioSessionCollection::onIODescriptorUpdate() const
{
for (size_t i = 0; i < size(); i++) {
- valueAt(i)->onSessionInfoUpdate();
+ valueAt(i)->onIODescriptorUpdate();
}
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
index 1e105f5..19eac26 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
@@ -412,6 +412,7 @@
free(data);
ALOGI("loadAudioPolicyConfig() loaded %s\n", path);
+ config.setSource(path);
return NO_ERROR;
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index 19c2062..d3cc8b9 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -145,8 +145,8 @@
}
}
}
- ALOGV("DeviceVector::getDevice() for type %08x address %s found %p",
- type, address.string(), device.get());
+ ALOGV("DeviceVector::%s() for type %08x address \"%s\" found %p",
+ __func__, type, address.string(), device.get());
return device;
}
@@ -160,7 +160,7 @@
return nullptr;
}
-DeviceVector DeviceVector::getDevicesFromType(audio_devices_t type) const
+DeviceVector DeviceVector::getDevicesFromTypeMask(audio_devices_t type) const
{
DeviceVector devices;
bool isOutput = audio_is_output_devices(type);
@@ -171,20 +171,8 @@
if ((isOutput == curIsOutput) && ((type & curType) != 0)) {
devices.add(itemAt(i));
type &= ~curType;
- ALOGV("DeviceVector::getDevicesFromType() for type %x found %p",
- itemAt(i)->type(), itemAt(i).get());
- }
- }
- return devices;
-}
-
-DeviceVector DeviceVector::getDevicesFromTypeAddr(
- audio_devices_t type, const String8& address) const
-{
- DeviceVector devices;
- for (const auto& device : *this) {
- if (device->type() == type && device->mAddress == address) {
- devices.add(device);
+ ALOGV("DeviceVector::%s() for type %08x found %p",
+ __func__, itemAt(i)->type(), itemAt(i).get());
}
}
return devices;
@@ -253,7 +241,7 @@
void DeviceDescriptor::toAudioPort(struct audio_port *port) const
{
- ALOGV("DeviceDescriptor::toAudioPort() handle %d type %x", mId, mDeviceType);
+ ALOGV("DeviceDescriptor::toAudioPort() handle %d type %08x", mId, mDeviceType);
AudioPort::toAudioPort(port);
port->id = mId;
toAudioPortConfig(&port->active_config);
@@ -305,7 +293,7 @@
{
std::string device;
deviceToString(mDeviceType, device);
- ALOGI("Device id:%d type:0x%X:%s, addr:%s", mId, mDeviceType, device.c_str(),
+ ALOGI("Device id:%d type:0x%08X:%s, addr:%s", mId, mDeviceType, device.c_str(),
mAddress.string());
AudioPort::log(" ");
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index aef7dbe..dcc0ec8 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -278,9 +278,10 @@
sp<DeviceDescriptor> HwModuleCollection::getDeviceDescriptor(const audio_devices_t device,
const char *device_address,
const char *device_name,
- bool matchAdress) const
+ bool matchAddress) const
{
- String8 address = (device_address == nullptr) ? String8("") : String8(device_address);
+ String8 address = (device_address == nullptr || !matchAddress) ?
+ String8("") : String8(device_address);
// handle legacy remote submix case where the address was not always specified
if (device_distinguishes_on_address(device) && (address.length() == 0)) {
address = String8("0");
@@ -288,15 +289,9 @@
for (const auto& hwModule : *this) {
DeviceVector declaredDevices = hwModule->getDeclaredDevices();
- DeviceVector deviceList = declaredDevices.getDevicesFromTypeAddr(device, address);
- if (!deviceList.isEmpty()) {
- return deviceList.itemAt(0);
- }
- if (!matchAdress) {
- deviceList = declaredDevices.getDevicesFromType(device);
- if (!deviceList.isEmpty()) {
- return deviceList.itemAt(0);
- }
+ sp<DeviceDescriptor> deviceDesc = declaredDevices.getDevice(device, address);
+ if (deviceDesc) {
+ return deviceDesc;
}
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp b/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp
index d34214b..38ab560 100644
--- a/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp
@@ -129,7 +129,7 @@
if (streamType == route->mStreamType && route->isActiveOrChanged()
&& route->mDeviceDescriptor != 0) {
device = route->mDeviceDescriptor->type();
- if (!availableDevices.getDevicesFromType(device).isEmpty()) {
+ if (!availableDevices.getDevicesFromTypeMask(device).isEmpty()) {
break;
}
}
diff --git a/services/audiopolicy/config/audio_policy_configuration.xml b/services/audiopolicy/config/audio_policy_configuration.xml
index a75f1cb..9381f1f 100644
--- a/services/audiopolicy/config/audio_policy_configuration.xml
+++ b/services/audiopolicy/config/audio_policy_configuration.xml
@@ -185,6 +185,9 @@
<!-- Hearing aid Audio HAL -->
<xi:include href="hearing_aid_audio_policy_configuration.xml"/>
+ <!-- MSD Audio HAL (optional) -->
+ <xi:include href="msd_audio_policy_configuration.xml"/>
+
</modules>
<!-- End of Modules section -->
diff --git a/services/audiopolicy/config/msd_audio_policy_configuration.xml b/services/audiopolicy/config/msd_audio_policy_configuration.xml
new file mode 100644
index 0000000..a84117e
--- /dev/null
+++ b/services/audiopolicy/config/msd_audio_policy_configuration.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2017-2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- Multi Stream Decoder Audio Policy Configuration file -->
+<module name="msd" halVersion="2.0">
+ <attachedDevices>
+ <item>MS12 Input</item>
+ <item>MS12 Output</item>
+ </attachedDevices>
+ <mixPorts>
+ <mixPort name="ms12 input" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="ms12 compressed input" role="source"
+ flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|AUDIO_OUTPUT_FLAG_NON_BLOCKING">
+ <profile name="" format="AUDIO_FORMAT_AC3"
+ samplingRates="32000,44100,48000"
+ channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_5POINT1"/>
+ <profile name="" format="AUDIO_FORMAT_E_AC3"
+ samplingRates="32000,44100,48000"
+ channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_5POINT1,AUDIO_CHANNEL_OUT_7POINT1"/>
+ <profile name="" format="AUDIO_FORMAT_AC4"
+ samplingRates="32000,44100,48000"
+ channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_5POINT1,AUDIO_CHANNEL_OUT_7POINT1"/>
+ </mixPort>
+ <mixPort name="ms12 output" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+ <profile name="" format="AUDIO_FORMAT_AC3"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_5POINT1"/>
+ <profile name="" format="AUDIO_FORMAT_E_AC3"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_5POINT1"/>
+ </mixPort>
+ </mixPorts>
+ <devicePorts>
+ <devicePort tagName="MS12 Input" type="AUDIO_DEVICE_OUT_BUS" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </devicePort>
+ <devicePort tagName="MS12 Output" type="AUDIO_DEVICE_IN_BUS" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+ </devicePort>
+ </devicePorts>
+ <routes>
+ <route type="mix" sink="MS12 Input" sources="ms12 input,ms12 compressed input"/>
+ <route type="mix" sink="ms12 output" sources="MS12 Output"/>
+ </routes>
+</module>
diff --git a/services/audiopolicy/engineconfigurable/wrapper/Android.mk b/services/audiopolicy/engineconfigurable/wrapper/Android.mk
index 36e0f42..b128a38 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/Android.mk
+++ b/services/audiopolicy/engineconfigurable/wrapper/Android.mk
@@ -10,7 +10,6 @@
$(LOCAL_PATH)/include \
frameworks/av/services/audiopolicy/engineconfigurable/include \
frameworks/av/services/audiopolicy/engineconfigurable/interface \
- frameworks/av/services/audiopolicy/utilities/convert \
LOCAL_SRC_FILES:= ParameterManagerWrapper.cpp
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index 3e13e50..007eea0 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -482,7 +482,7 @@
}
}
availableOutputDevices =
- availableOutputDevices.getDevicesFromType(availableOutputDevicesType);
+ availableOutputDevices.getDevicesFromTypeMask(availableOutputDevicesType);
if (outputs.isStreamActive(AUDIO_STREAM_RING) ||
outputs.isStreamActive(AUDIO_STREAM_ALARM)) {
return getDeviceForStrategyInt(
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 0318ffe..0a8bed1 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -38,6 +38,8 @@
#include <utils/Log.h>
#include <media/AudioParameter.h>
#include <media/AudioPolicyHelper.h>
+#include <media/PatchBuilder.h>
+#include <private/android_filesystem_config.h>
#include <soundtrigger/SoundTrigger.h>
#include <system/audio.h>
#include <audio_policy_conf.h>
@@ -476,20 +478,15 @@
sp<AudioPatch> AudioPolicyManager::createTelephonyPatch(
bool isRx, audio_devices_t device, uint32_t delayMs) {
- struct audio_patch patch;
- patch.num_sources = 1;
- patch.num_sinks = 1;
+ PatchBuilder patchBuilder;
sp<DeviceDescriptor> txSourceDeviceDesc;
if (isRx) {
- fillAudioPortConfigForDevice(mAvailableOutputDevices, device, &patch.sinks[0]);
- fillAudioPortConfigForDevice(
- mAvailableInputDevices, AUDIO_DEVICE_IN_TELEPHONY_RX, &patch.sources[0]);
+ patchBuilder.addSink(findDevice(mAvailableOutputDevices, device)).
+ addSource(findDevice(mAvailableInputDevices, AUDIO_DEVICE_IN_TELEPHONY_RX));
} else {
- txSourceDeviceDesc = fillAudioPortConfigForDevice(
- mAvailableInputDevices, device, &patch.sources[0]);
- fillAudioPortConfigForDevice(
- mAvailableOutputDevices, AUDIO_DEVICE_OUT_TELEPHONY_TX, &patch.sinks[0]);
+ patchBuilder.addSource(txSourceDeviceDesc = findDevice(mAvailableInputDevices, device)).
+ addSink(findDevice(mAvailableOutputDevices, AUDIO_DEVICE_OUT_TELEPHONY_TX));
}
audio_devices_t outputDevice = isRx ? device : AUDIO_DEVICE_OUT_TELEPHONY_TX;
@@ -500,9 +497,7 @@
sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
ALOG_ASSERT(!outputDesc->isDuplicated(),
"%s() %#x device output %d is duplicated", __func__, outputDevice, output);
- outputDesc->toAudioPortConfig(&patch.sources[1]);
- patch.sources[1].ext.mix.usecase.stream = AUDIO_STREAM_PATCH;
- patch.num_sources = 2;
+ patchBuilder.addSource(outputDesc, { .stream = AUDIO_STREAM_PATCH });
}
if (!isRx) {
@@ -524,26 +519,25 @@
}
audio_patch_handle_t afPatchHandle = AUDIO_PATCH_HANDLE_NONE;
- status_t status = mpClientInterface->createAudioPatch(&patch, &afPatchHandle, delayMs);
+ status_t status = mpClientInterface->createAudioPatch(
+ patchBuilder.patch(), &afPatchHandle, delayMs);
ALOGW_IF(status != NO_ERROR,
"%s() error %d creating %s audio patch", __func__, status, isRx ? "RX" : "TX");
sp<AudioPatch> audioPatch;
if (status == NO_ERROR) {
- audioPatch = new AudioPatch(&patch, mUidCached);
+ audioPatch = new AudioPatch(patchBuilder.patch(), mUidCached);
audioPatch->mAfPatchHandle = afPatchHandle;
audioPatch->mUid = mUidCached;
}
return audioPatch;
}
-sp<DeviceDescriptor> AudioPolicyManager::fillAudioPortConfigForDevice(
- const DeviceVector& devices, audio_devices_t device, audio_port_config *config) {
- DeviceVector deviceList = devices.getDevicesFromType(device);
+sp<DeviceDescriptor> AudioPolicyManager::findDevice(
+ const DeviceVector& devices, audio_devices_t device) {
+ DeviceVector deviceList = devices.getDevicesFromTypeMask(device);
ALOG_ASSERT(!deviceList.isEmpty(),
"%s() selected device type %#x is not in devices list", __func__, device);
- sp<DeviceDescriptor> deviceDesc = deviceList.itemAt(0);
- deviceDesc->toAudioPortConfig(config);
- return deviceDesc;
+ return deviceList.itemAt(0);
}
void AudioPolicyManager::setPhoneState(audio_mode_t state)
@@ -871,7 +865,7 @@
return INVALID_OPERATION;
}
- DeviceVector outputDevices = mAvailableOutputDevices.getDevicesFromType(device);
+ DeviceVector outputDevices = mAvailableOutputDevices.getDevicesFromTypeMask(device);
*selectedDeviceId = outputDevices.size() > 0 ? outputDevices.itemAt(0)->getId()
: AUDIO_PORT_HANDLE_NONE;
@@ -976,7 +970,7 @@
sp<SwAudioOutputDescriptor> outputDesc =
new SwAudioOutputDescriptor(profile, mpClientInterface);
- DeviceVector outputDevices = mAvailableOutputDevices.getDevicesFromType(device);
+ DeviceVector outputDevices = mAvailableOutputDevices.getDevicesFromTypeMask(device);
String8 address = outputDevices.size() > 0 ? outputDevices.itemAt(0)->mAddress
: String8("");
@@ -1545,7 +1539,7 @@
if (*portId == AUDIO_PORT_HANDLE_NONE) {
*portId = AudioPort::getNextUniqueId();
}
- inputDevices = mAvailableInputDevices.getDevicesFromType(inputDesc->mDevice);
+ inputDevices = mAvailableInputDevices.getDevicesFromTypeMask(inputDesc->mDevice);
*selectedDeviceId = inputDevices.size() > 0 ? inputDevices.itemAt(0)->getId()
: AUDIO_PORT_HANDLE_NONE;
ALOGI("%s reusing MMAP input %d for session %d", __FUNCTION__, *input, session);
@@ -1612,7 +1606,7 @@
goto error;
}
- inputDevices = mAvailableInputDevices.getDevicesFromType(device);
+ inputDevices = mAvailableInputDevices.getDevicesFromTypeMask(device);
*selectedDeviceId = inputDevices.size() > 0 ? inputDevices.itemAt(0)->getId()
: AUDIO_PORT_HANDLE_NONE;
@@ -1780,7 +1774,7 @@
lConfig.format = profileFormat;
if (address == "") {
- DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromType(device);
+ DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromTypeMask(device);
// the inputs vector must be of size >= 1, but we don't want to crash here
address = inputDevices.size() > 0 ? inputDevices.itemAt(0)->mAddress : String8("");
}
@@ -2627,42 +2621,24 @@
status_t AudioPolicyManager::dump(int fd)
{
- const size_t SIZE = 256;
- char buffer[SIZE];
String8 result;
-
- snprintf(buffer, SIZE, "\nAudioPolicyManager Dump: %p\n", this);
- result.append(buffer);
-
- snprintf(buffer, SIZE, " Primary Output: %d\n",
+ result.appendFormat("\nAudioPolicyManager Dump: %p\n", this);
+ result.appendFormat(" Primary Output: %d\n",
hasPrimaryOutput() ? mPrimaryOutput->mIoHandle : AUDIO_IO_HANDLE_NONE);
- result.append(buffer);
std::string stateLiteral;
AudioModeConverter::toString(mEngine->getPhoneState(), stateLiteral);
- snprintf(buffer, SIZE, " Phone state: %s\n", stateLiteral.c_str());
- result.append(buffer);
- snprintf(buffer, SIZE, " Force use for communications %d\n",
- mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION));
- result.append(buffer);
- snprintf(buffer, SIZE, " Force use for media %d\n", mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA));
- result.append(buffer);
- snprintf(buffer, SIZE, " Force use for record %d\n", mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD));
- result.append(buffer);
- snprintf(buffer, SIZE, " Force use for dock %d\n", mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_DOCK));
- result.append(buffer);
- snprintf(buffer, SIZE, " Force use for system %d\n", mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM));
- result.append(buffer);
- snprintf(buffer, SIZE, " Force use for hdmi system audio %d\n",
- mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO));
- result.append(buffer);
- snprintf(buffer, SIZE, " Force use for encoded surround output %d\n",
- mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND));
- result.append(buffer);
- snprintf(buffer, SIZE, " TTS output %s\n", mTtsOutputAvailable ? "available" : "not available");
- result.append(buffer);
- snprintf(buffer, SIZE, " Master mono: %s\n", mMasterMono ? "on" : "off");
- result.append(buffer);
-
+ result.appendFormat(" Phone state: %s\n", stateLiteral.c_str());
+ const char* forceUses[AUDIO_POLICY_FORCE_USE_CNT] = {
+ "communications", "media", "record", "dock", "system",
+ "HDMI system audio", "encoded surround output", "vibrate ringing" };
+ for (audio_policy_force_use_t i = AUDIO_POLICY_FORCE_FOR_COMMUNICATION;
+ i < AUDIO_POLICY_FORCE_USE_CNT; i = (audio_policy_force_use_t)((int)i + 1)) {
+ result.appendFormat(" Force use for %s: %d\n",
+ forceUses[i], mEngine->getForceUse(i));
+ }
+ result.appendFormat(" TTS output %savailable\n", mTtsOutputAvailable ? "" : "not ");
+ result.appendFormat(" Master mono: %s\n", mMasterMono ? "on" : "off");
+ result.appendFormat(" Config source: %s\n", getConfig().getSource().c_str());
write(fd, result.string(), result.size());
mAvailableOutputDevices.dump(fd, String8("Available output"));
@@ -3078,28 +3054,8 @@
}
// TODO: check from routing capabilities in config file and other conflicting patches
- audio_patch_handle_t afPatchHandle = AUDIO_PATCH_HANDLE_NONE;
- if (index >= 0) {
- afPatchHandle = patchDesc->mAfPatchHandle;
- }
-
- status_t status = mpClientInterface->createAudioPatch(&newPatch,
- &afPatchHandle,
- 0);
- ALOGV("createAudioPatch() patch panel returned %d patchHandle %d",
- status, afPatchHandle);
- if (status == NO_ERROR) {
- if (index < 0) {
- patchDesc = new AudioPatch(&newPatch, uid);
- addAudioPatch(patchDesc->mHandle, patchDesc);
- } else {
- patchDesc->mPatch = newPatch;
- }
- patchDesc->mAfPatchHandle = afPatchHandle;
- *handle = patchDesc->mHandle;
- nextAudioPortGeneration();
- mpClientInterface->onAudioPatchListUpdate();
- } else {
+ status_t status = installPatch(__func__, index, handle, &newPatch, 0, uid, &patchDesc);
+ if (status != NO_ERROR) {
ALOGW("createAudioPatch() patch panel could not connect device patch, error %d",
status);
return INVALID_OPERATION;
@@ -3232,10 +3188,10 @@
return BAD_VALUE;
}
- struct audio_port_config backupConfig;
+ struct audio_port_config backupConfig = {};
status_t status = audioPortConfig->applyAudioPortConfig(config, &backupConfig);
if (status == NO_ERROR) {
- struct audio_port_config newConfig;
+ struct audio_port_config newConfig = {};
audioPortConfig->toAudioPortConfig(&newConfig, config);
status = mpClientInterface->setAudioPortConfig(&newConfig, 0);
}
@@ -3383,7 +3339,7 @@
sp<AudioSourceDescriptor> sourceDesc =
new AudioSourceDescriptor(srcDeviceDesc, attributes, uid);
- struct audio_patch dummyPatch;
+ struct audio_patch dummyPatch = {};
sp<AudioPatch> patchDesc = new AudioPatch(&dummyPatch, uid);
sourceDesc->mPatchDesc = patchDesc;
@@ -3411,7 +3367,6 @@
mAvailableOutputDevices.getDevice(sinkDevice, String8(""));
audio_patch_handle_t afPatchHandle = AUDIO_PATCH_HANDLE_NONE;
- struct audio_patch *patch = &sourceDesc->mPatchDesc->mPatch;
if (srcDeviceDesc->getAudioPort()->mModule->getHandle() ==
sinkDeviceDesc->getAudioPort()->mModule->getHandle() &&
@@ -3443,16 +3398,14 @@
// be connected as well as the stream type for volume control
// - the sink is defined by whatever output device is currently selected for the output
// though which this patch is routed.
- patch->num_sinks = 0;
- patch->num_sources = 2;
- srcDeviceDesc->toAudioPortConfig(&patch->sources[0], NULL);
- outputDesc->toAudioPortConfig(&patch->sources[1], NULL);
- patch->sources[1].ext.mix.usecase.stream = stream;
- status = mpClientInterface->createAudioPatch(patch,
+ PatchBuilder patchBuilder;
+ patchBuilder.addSource(srcDeviceDesc).addSource(outputDesc, { .stream = stream });
+ status = mpClientInterface->createAudioPatch(patchBuilder.patch(),
&afPatchHandle,
0);
ALOGV("%s patch panel returned %d patchHandle %d", __FUNCTION__,
status, afPatchHandle);
+ sourceDesc->mPatchDesc->mPatch = *patchBuilder.patch();
if (status != NO_ERROR) {
ALOGW("%s patch panel could not connect device patch, error %d",
__FUNCTION__, status);
@@ -3615,7 +3568,7 @@
}
}
// Open an output to query dynamic parameters.
- DeviceVector hdmiOutputDevices = mAvailableOutputDevices.getDevicesFromType(
+ DeviceVector hdmiOutputDevices = mAvailableOutputDevices.getDevicesFromTypeMask(
AUDIO_DEVICE_OUT_HDMI);
for (size_t i = 0; i < hdmiOutputDevices.size(); i++) {
String8 address = hdmiOutputDevices[i]->mAddress;
@@ -3741,7 +3694,7 @@
sp<SwAudioOutputDescriptor> outputDesc;
bool profileUpdated = false;
- DeviceVector hdmiOutputDevices = mAvailableOutputDevices.getDevicesFromType(
+ DeviceVector hdmiOutputDevices = mAvailableOutputDevices.getDevicesFromTypeMask(
AUDIO_DEVICE_OUT_HDMI);
for (size_t i = 0; i < hdmiOutputDevices.size(); i++) {
// Simulate reconnection to update enabled surround sound formats.
@@ -3760,7 +3713,7 @@
name.c_str());
profileUpdated |= (status == NO_ERROR);
}
- DeviceVector hdmiInputDevices = mAvailableInputDevices.getDevicesFromType(
+ DeviceVector hdmiInputDevices = mAvailableInputDevices.getDevicesFromTypeMask(
AUDIO_DEVICE_IN_HDMI);
for (size_t i = 0; i < hdmiInputDevices.size(); i++) {
// Simulate reconnection to update enabled surround sound formats.
@@ -3904,6 +3857,7 @@
"%s/%s", kConfigLocationList[i], fileName);
ret = serializer.deserialize(audioPolicyXmlConfigFile, config);
if (ret == NO_ERROR) {
+ config.setSource(audioPolicyXmlConfigFile);
return ret;
}
}
@@ -3915,7 +3869,7 @@
AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface,
bool /*forTesting*/)
:
- mUidCached(getuid()),
+ mUidCached(AID_AUDIOSERVER), // no need to call getuid(), there's only one of us running.
mpClientInterface(clientInterface),
mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
mA2dpSuspended(false),
@@ -4026,7 +3980,8 @@
sp<SwAudioOutputDescriptor> outputDesc = new SwAudioOutputDescriptor(outProfile,
mpClientInterface);
const DeviceVector &supportedDevices = outProfile->getSupportedDevices();
- const DeviceVector &devicesForType = supportedDevices.getDevicesFromType(profileType);
+ const DeviceVector &devicesForType = supportedDevices.getDevicesFromTypeMask(
+ profileType);
String8 address = devicesForType.size() > 0 ? devicesForType.itemAt(0)->mAddress
: String8("");
audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
@@ -4080,7 +4035,7 @@
sp<AudioInputDescriptor> inputDesc =
new AudioInputDescriptor(inProfile, mpClientInterface);
- DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromType(profileType);
+ DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromTypeMask(profileType);
// the inputs vector must be of size >= 1, but we don't want to crash here
String8 address = inputDevices.size() > 0 ? inputDevices.itemAt(0)->mAddress
: String8("");
@@ -5245,54 +5200,20 @@
} else {
DeviceVector deviceList;
if ((address == NULL) || (strlen(address) == 0)) {
- deviceList = mAvailableOutputDevices.getDevicesFromType(device);
+ deviceList = mAvailableOutputDevices.getDevicesFromTypeMask(device);
} else {
- deviceList = mAvailableOutputDevices.getDevicesFromTypeAddr(device, String8(address));
+ sp<DeviceDescriptor> deviceDesc = mAvailableOutputDevices.getDevice(
+ device, String8(address));
+ if (deviceDesc) deviceList.add(deviceDesc);
}
if (!deviceList.isEmpty()) {
- struct audio_patch patch;
- outputDesc->toAudioPortConfig(&patch.sources[0]);
- patch.num_sources = 1;
- patch.num_sinks = 0;
+ PatchBuilder patchBuilder;
+ patchBuilder.addSource(outputDesc);
for (size_t i = 0; i < deviceList.size() && i < AUDIO_PATCH_PORTS_MAX; i++) {
- deviceList.itemAt(i)->toAudioPortConfig(&patch.sinks[i]);
- patch.num_sinks++;
+ patchBuilder.addSink(deviceList.itemAt(i));
}
- ssize_t index;
- if (patchHandle && *patchHandle != AUDIO_PATCH_HANDLE_NONE) {
- index = mAudioPatches.indexOfKey(*patchHandle);
- } else {
- index = mAudioPatches.indexOfKey(outputDesc->getPatchHandle());
- }
- sp< AudioPatch> patchDesc;
- audio_patch_handle_t afPatchHandle = AUDIO_PATCH_HANDLE_NONE;
- if (index >= 0) {
- patchDesc = mAudioPatches.valueAt(index);
- afPatchHandle = patchDesc->mAfPatchHandle;
- }
-
- status_t status = mpClientInterface->createAudioPatch(&patch,
- &afPatchHandle,
- delayMs);
- ALOGV("setOutputDevice() createAudioPatch returned %d patchHandle %d"
- "num_sources %d num_sinks %d",
- status, afPatchHandle, patch.num_sources, patch.num_sinks);
- if (status == NO_ERROR) {
- if (index < 0) {
- patchDesc = new AudioPatch(&patch, mUidCached);
- addAudioPatch(patchDesc->mHandle, patchDesc);
- } else {
- patchDesc->mPatch = patch;
- }
- patchDesc->mAfPatchHandle = afPatchHandle;
- if (patchHandle) {
- *patchHandle = patchDesc->mHandle;
- }
- outputDesc->setPatchHandle(patchDesc->mHandle);
- nextAudioPortGeneration();
- mpClientInterface->onAudioPatchListUpdate();
- }
+ installPatch(__func__, patchHandle, outputDesc.get(), patchBuilder.patch(), delayMs);
}
// inform all input as well
@@ -5350,53 +5271,21 @@
if ((device != AUDIO_DEVICE_NONE) && ((device != inputDesc->mDevice) || force)) {
inputDesc->mDevice = device;
- DeviceVector deviceList = mAvailableInputDevices.getDevicesFromType(device);
+ DeviceVector deviceList = mAvailableInputDevices.getDevicesFromTypeMask(device);
if (!deviceList.isEmpty()) {
- struct audio_patch patch;
- inputDesc->toAudioPortConfig(&patch.sinks[0]);
+ PatchBuilder patchBuilder;
+ patchBuilder.addSink(inputDesc,
// AUDIO_SOURCE_HOTWORD is for internal use only:
// handled as AUDIO_SOURCE_VOICE_RECOGNITION by the audio HAL
- if (patch.sinks[0].ext.mix.usecase.source == AUDIO_SOURCE_HOTWORD &&
- !inputDesc->isSoundTrigger()) {
- patch.sinks[0].ext.mix.usecase.source = AUDIO_SOURCE_VOICE_RECOGNITION;
- }
- patch.num_sinks = 1;
+ [inputDesc](const PatchBuilder::mix_usecase_t& usecase) {
+ auto result = usecase;
+ if (result.source == AUDIO_SOURCE_HOTWORD && !inputDesc->isSoundTrigger()) {
+ result.source = AUDIO_SOURCE_VOICE_RECOGNITION;
+ }
+ return result; }).
//only one input device for now
- deviceList.itemAt(0)->toAudioPortConfig(&patch.sources[0]);
- patch.num_sources = 1;
- ssize_t index;
- if (patchHandle && *patchHandle != AUDIO_PATCH_HANDLE_NONE) {
- index = mAudioPatches.indexOfKey(*patchHandle);
- } else {
- index = mAudioPatches.indexOfKey(inputDesc->getPatchHandle());
- }
- sp< AudioPatch> patchDesc;
- audio_patch_handle_t afPatchHandle = AUDIO_PATCH_HANDLE_NONE;
- if (index >= 0) {
- patchDesc = mAudioPatches.valueAt(index);
- afPatchHandle = patchDesc->mAfPatchHandle;
- }
-
- status_t status = mpClientInterface->createAudioPatch(&patch,
- &afPatchHandle,
- 0);
- ALOGV("setInputDevice() createAudioPatch returned %d patchHandle %d",
- status, afPatchHandle);
- if (status == NO_ERROR) {
- if (index < 0) {
- patchDesc = new AudioPatch(&patch, mUidCached);
- addAudioPatch(patchDesc->mHandle, patchDesc);
- } else {
- patchDesc->mPatch = patch;
- }
- patchDesc->mAfPatchHandle = afPatchHandle;
- if (patchHandle) {
- *patchHandle = patchDesc->mHandle;
- }
- inputDesc->setPatchHandle(patchDesc->mHandle);
- nextAudioPortGeneration();
- mpClientInterface->onAudioPatchListUpdate();
- }
+ addSource(deviceList.itemAt(0));
+ status = installPatch(__func__, patchHandle, inputDesc.get(), patchBuilder.patch(), 0);
}
}
return status;
@@ -6152,4 +6041,58 @@
}
}
+status_t AudioPolicyManager::installPatch(const char *caller,
+ audio_patch_handle_t *patchHandle,
+ AudioIODescriptorInterface *ioDescriptor,
+ const struct audio_patch *patch,
+ int delayMs)
+{
+ ssize_t index = mAudioPatches.indexOfKey(
+ patchHandle && *patchHandle != AUDIO_PATCH_HANDLE_NONE ?
+ *patchHandle : ioDescriptor->getPatchHandle());
+ sp<AudioPatch> patchDesc;
+ status_t status = installPatch(
+ caller, index, patchHandle, patch, delayMs, mUidCached, &patchDesc);
+ if (status == NO_ERROR) {
+ ioDescriptor->setPatchHandle(patchDesc->mHandle);
+ }
+ return status;
+}
+
+status_t AudioPolicyManager::installPatch(const char *caller,
+ ssize_t index,
+ audio_patch_handle_t *patchHandle,
+ const struct audio_patch *patch,
+ int delayMs,
+ uid_t uid,
+ sp<AudioPatch> *patchDescPtr)
+{
+ sp<AudioPatch> patchDesc;
+ audio_patch_handle_t afPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+ if (index >= 0) {
+ patchDesc = mAudioPatches.valueAt(index);
+ afPatchHandle = patchDesc->mAfPatchHandle;
+ }
+
+ status_t status = mpClientInterface->createAudioPatch(patch, &afPatchHandle, delayMs);
+ ALOGV("%s() AF::createAudioPatch returned %d patchHandle %d num_sources %d num_sinks %d",
+ caller, status, afPatchHandle, patch->num_sources, patch->num_sinks);
+ if (status == NO_ERROR) {
+ if (index < 0) {
+ patchDesc = new AudioPatch(patch, uid);
+ addAudioPatch(patchDesc->mHandle, patchDesc);
+ } else {
+ patchDesc->mPatch = *patch;
+ }
+ patchDesc->mAfPatchHandle = afPatchHandle;
+ if (patchHandle) {
+ *patchHandle = patchDesc->mHandle;
+ }
+ nextAudioPortGeneration();
+ mpClientInterface->onAudioPatchListUpdate();
+ }
+ if (patchDescPtr) *patchDescPtr = patchDesc;
+ return status;
+}
+
} // namespace android
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index b954714..008e1ca 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -502,8 +502,8 @@
uint32_t updateCallRouting(audio_devices_t rxDevice, uint32_t delayMs = 0);
sp<AudioPatch> createTelephonyPatch(bool isRx, audio_devices_t device, uint32_t delayMs);
- sp<DeviceDescriptor> fillAudioPortConfigForDevice(
- const DeviceVector& devices, audio_devices_t device, audio_port_config *config);
+ sp<DeviceDescriptor> findDevice(
+ const DeviceVector& devices, audio_devices_t device);
// if argument "device" is different from AUDIO_DEVICE_NONE, startSource() will force
// the re-evaluation of the output device.
@@ -540,7 +540,7 @@
static bool streamsMatchForvolume(audio_stream_type_t stream1,
audio_stream_type_t stream2);
- uid_t mUidCached;
+ const uid_t mUidCached; // AID_AUDIOSERVER
AudioPolicyClientInterface *mpClientInterface; // audio policy client interface
sp<SwAudioOutputDescriptor> mPrimaryOutput; // primary output descriptor
// list of descriptors for outputs currently opened
@@ -680,6 +680,18 @@
param.addInt(String8(AudioParameter::keyMonoOutput), (int)mMasterMono);
mpClientInterface->setParameters(output, param.toString());
}
+ status_t installPatch(const char *caller,
+ audio_patch_handle_t *patchHandle,
+ AudioIODescriptorInterface *ioDescriptor,
+ const struct audio_patch *patch,
+ int delayMs);
+ status_t installPatch(const char *caller,
+ ssize_t index,
+ audio_patch_handle_t *patchHandle,
+ const struct audio_patch *patch,
+ int delayMs,
+ uid_t uid,
+ sp<AudioPatch> *patchDescPtr);
bool soundTriggerSupportsConcurrentCapture();
bool mSoundTriggerSupportsConcurrentCapture;
diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp
index c7dfe0f..fdae23b 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.cpp
+++ b/services/audiopolicy/service/AudioPolicyEffects.cpp
@@ -24,6 +24,7 @@
#include <cutils/misc.h>
#include <media/AudioEffect.h>
#include <media/EffectsConfig.h>
+#include <mediautils/ServiceUtilities.h>
#include <system/audio.h>
#include <system/audio_effects/audio_effects_conf.h>
#include <utils/Vector.h>
@@ -31,7 +32,6 @@
#include <cutils/config_utils.h>
#include <binder/IPCThreadState.h>
#include "AudioPolicyEffects.h"
-#include "ServiceUtilities.h"
namespace android {
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 7337f04..d3a1188 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -21,7 +21,7 @@
#include <media/MediaAnalyticsItem.h>
#include "AudioPolicyService.h"
-#include "ServiceUtilities.h"
+#include <mediautils/ServiceUtilities.h>
#include "TypeConverter.h"
namespace android {
@@ -183,7 +183,7 @@
Mutex::Autolock _l(mLock);
const uid_t callingUid = IPCThreadState::self()->getCallingUid();
- if (!isTrustedCallingUid(callingUid) || uid == (uid_t)-1) {
+ if (!isAudioServerOrMediaServerUid(callingUid) || uid == (uid_t)-1) {
ALOGW_IF(uid != (uid_t)-1 && uid != callingUid,
"%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, uid);
uid = callingUid;
@@ -320,7 +320,7 @@
bool updatePid = (pid == -1);
const uid_t callingUid = IPCThreadState::self()->getCallingUid();
- if (!isTrustedCallingUid(callingUid)) {
+ if (!isAudioServerOrMediaServerUid(callingUid)) {
ALOGW_IF(uid != (uid_t)-1 && uid != callingUid,
"%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, uid);
uid = callingUid;
@@ -528,10 +528,13 @@
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);
-
+ if (client->opPackageName.size() != 0) {
+ item->setCString(kAudioPolicyRqstPkg,
+ std::string(String8(client->opPackageName).string()).c_str());
+ } else {
+ item->setCString(kAudioPolicyRqstPkg, to_string(client->uid).c_str());
+ }
item->setCString(
kAudioPolicyRqstDevice, getDeviceTypeStrForPortId(client->deviceId).c_str());
@@ -550,9 +553,13 @@
// 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->setInt32(kAudioPolicyActiveSession, other->session);
+ if (other->opPackageName.size() != 0) {
+ item->setCString(kAudioPolicyActivePkg,
+ std::string(String8(other->opPackageName).string()).c_str());
+ } else {
+ item->setCString(kAudioPolicyRqstPkg, to_string(other->uid).c_str());
+ }
item->setCString(kAudioPolicyActiveDevice,
getDeviceTypeStrForPortId(other->deviceId).c_str());
}
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index f3cddc3..1379223 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -26,7 +26,6 @@
#include <sys/time.h>
#include <binder/IServiceManager.h>
#include <utils/Log.h>
-#include <cutils/multiuser.h>
#include <cutils/properties.h>
#include <binder/IPCThreadState.h>
#include <binder/ActivityManager.h>
@@ -35,16 +34,14 @@
#include <utils/String16.h>
#include <utils/threads.h>
#include "AudioPolicyService.h"
-#include "ServiceUtilities.h"
#include <hardware_legacy/power.h>
#include <media/AudioEffect.h>
#include <media/AudioParameter.h>
+#include <mediautils/ServiceUtilities.h>
#include <system/audio.h>
#include <system/audio_policy.h>
-#include <private/android_filesystem_config.h>
-
namespace android {
static const char kDeadlockedString[] = "AudioPolicyService may be deadlocked\n";
@@ -275,7 +272,7 @@
void AudioPolicyService::NotificationClient::onDynamicPolicyMixStateUpdate(
const String8& regId, int32_t state)
{
- if (mAudioPolicyServiceClient != 0 && multiuser_get_app_id(mUid) < AID_APP_START) {
+ if (mAudioPolicyServiceClient != 0 && isServiceUid(mUid)) {
mAudioPolicyServiceClient->onDynamicPolicyMixStateUpdate(regId, state);
}
}
@@ -285,7 +282,7 @@
const audio_config_base_t *clientConfig, const audio_config_base_t *deviceConfig,
audio_patch_handle_t patchHandle)
{
- if (mAudioPolicyServiceClient != 0 && multiuser_get_app_id(mUid) < AID_APP_START) {
+ if (mAudioPolicyServiceClient != 0 && isServiceUid(mUid)) {
mAudioPolicyServiceClient->onRecordingConfigurationUpdate(event, clientInfo,
clientConfig, deviceConfig, patchHandle);
}
@@ -577,10 +574,6 @@
updateUidCache(uid, false, true);
}
-bool AudioPolicyService::UidPolicy::isServiceUid(uid_t uid) const {
- return multiuser_get_app_id(uid) < AID_APP_START;
-}
-
void AudioPolicyService::UidPolicy::notifyService(uid_t uid, bool active) {
sp<AudioPolicyService> service = mService.promote();
if (service != nullptr) {
@@ -1212,6 +1205,7 @@
patch = ((CreateAudioPatchData *)command->mParam.get())->mPatch;
} else {
handle = ((ReleaseAudioPatchData *)command->mParam.get())->mHandle;
+ memset(&patch, 0, sizeof(patch));
}
audio_patch_handle_t handle2;
struct audio_patch patch2;
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 407d7a5..02019a2 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -293,7 +293,6 @@
void removeOverrideUid(uid_t uid) { updateOverrideUid(uid, false, false); }
private:
- bool isServiceUid(uid_t uid) const;
void notifyService(uid_t uid, bool active);
void updateOverrideUid(uid_t uid, bool active, bool insert);
void updateUidCache(uid_t uid, bool active, bool insert);
diff --git a/services/audiopolicy/tests/Android.mk b/services/audiopolicy/tests/Android.mk
index a43daea..cfa9ab1 100644
--- a/services/audiopolicy/tests/Android.mk
+++ b/services/audiopolicy/tests/Android.mk
@@ -6,7 +6,6 @@
frameworks/av/services/audiopolicy \
frameworks/av/services/audiopolicy/common/include \
frameworks/av/services/audiopolicy/engine/interface \
- frameworks/av/services/audiopolicy/utilities
LOCAL_SHARED_LIBRARIES := \
libaudiopolicymanagerdefault \
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index a9593b8..2d9260e 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -19,6 +19,8 @@
#include <gtest/gtest.h>
+#include <media/PatchBuilder.h>
+
#include "AudioPolicyTestClient.h"
#include "AudioPolicyTestManager.h"
@@ -166,29 +168,14 @@
}
TEST_F(AudioPolicyManagerTest, CreateAudioPatchFromMix) {
- audio_patch patch{};
audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE;
uid_t uid = 42;
const size_t patchCountBefore = mClient->getActivePatchesCount();
- patch.num_sources = 1;
- {
- auto& src = patch.sources[0];
- src.role = AUDIO_PORT_ROLE_SOURCE;
- src.type = AUDIO_PORT_TYPE_MIX;
- src.id = mManager->getConfig().getAvailableInputDevices()[0]->getId();
- // Note: these are the parameters of the output device.
- src.sample_rate = 44100;
- src.format = AUDIO_FORMAT_PCM_16_BIT;
- src.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
- }
- patch.num_sinks = 1;
- {
- auto& sink = patch.sinks[0];
- sink.role = AUDIO_PORT_ROLE_SINK;
- sink.type = AUDIO_PORT_TYPE_DEVICE;
- sink.id = mManager->getConfig().getDefaultOutputDevice()->getId();
- }
- ASSERT_EQ(NO_ERROR, mManager->createAudioPatch(&patch, &handle, uid));
+ ASSERT_FALSE(mManager->getConfig().getAvailableInputDevices().isEmpty());
+ PatchBuilder patchBuilder;
+ patchBuilder.addSource(mManager->getConfig().getAvailableInputDevices()[0]).
+ addSink(mManager->getConfig().getDefaultOutputDevice());
+ ASSERT_EQ(NO_ERROR, mManager->createAudioPatch(patchBuilder.patch(), &handle, uid));
ASSERT_NE(AUDIO_PATCH_HANDLE_NONE, handle);
ASSERT_EQ(patchCountBefore + 1, mClient->getActivePatchesCount());
}
diff --git a/services/medialog/Android.bp b/services/medialog/Android.bp
index 29e6dfc..ca96f62 100644
--- a/services/medialog/Android.bp
+++ b/services/medialog/Android.bp
@@ -9,7 +9,9 @@
shared_libs: [
"libaudioutils",
"libbinder",
+ "libcutils",
"liblog",
+ "libmediautils",
"libnbaio",
"libnblog",
"libutils",
diff --git a/services/medialog/MediaLogService.cpp b/services/medialog/MediaLogService.cpp
index 1be5544..e58dff7 100644
--- a/services/medialog/MediaLogService.cpp
+++ b/services/medialog/MediaLogService.cpp
@@ -21,7 +21,7 @@
#include <utils/Log.h>
#include <binder/PermissionCache.h>
#include <media/nblog/NBLog.h>
-#include <private/android_filesystem_config.h>
+#include <mediautils/ServiceUtilities.h>
#include "MediaLogService.h"
namespace android {
@@ -53,7 +53,7 @@
void MediaLogService::registerWriter(const sp<IMemory>& shared, size_t size, const char *name)
{
- if (IPCThreadState::self()->getCallingUid() != AID_AUDIOSERVER || shared == 0 ||
+ if (!isAudioServerOrMediaServerUid(IPCThreadState::self()->getCallingUid()) || shared == 0 ||
size < kMinSize || size > kMaxSize || name == NULL ||
shared->size() < NBLog::Timeline::sharedSize(size)) {
return;
@@ -67,7 +67,7 @@
void MediaLogService::unregisterWriter(const sp<IMemory>& shared)
{
- if (IPCThreadState::self()->getCallingUid() != AID_AUDIOSERVER || shared == 0) {
+ if (!isAudioServerOrMediaServerUid(IPCThreadState::self()->getCallingUid()) || shared == 0) {
return;
}
Mutex::Autolock _l(mLock);
@@ -95,10 +95,8 @@
status_t MediaLogService::dump(int fd, const Vector<String16>& args __unused)
{
- // FIXME merge with similar but not identical code at services/audioflinger/ServiceUtilities.cpp
- static const String16 sDump("android.permission.DUMP");
- if (!(IPCThreadState::self()->getCallingUid() == AID_AUDIOSERVER ||
- PermissionCache::checkCallingPermission(sDump))) {
+ if (!(isAudioServerOrMediaServerUid(IPCThreadState::self()->getCallingUid())
+ || dumpAllowed())) {
dprintf(fd, "Permission Denial: can't dump media.log from pid=%d, uid=%d\n",
IPCThreadState::self()->getCallingPid(),
IPCThreadState::self()->getCallingUid());
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index 6a72e5b..94440b1 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -24,6 +24,7 @@
#include <aaudio/AAudio.h>
#include <mediautils/SchedulingPolicyService.h>
+#include <mediautils/ServiceUtilities.h>
#include <utils/String16.h>
#include "binding/AAudioServiceMessage.h"
@@ -33,7 +34,6 @@
#include "AAudioServiceStreamMMAP.h"
#include "AAudioServiceStreamShared.h"
#include "binding/IAAudioService.h"
-#include "ServiceUtilities.h"
using namespace android;
using namespace aaudio;
diff --git a/services/oboeservice/Android.mk b/services/oboeservice/Android.mk
index 584b2ef..3d5f140 100644
--- a/services/oboeservice/Android.mk
+++ b/services/oboeservice/Android.mk
@@ -53,7 +53,6 @@
libbinder \
libcutils \
libmediautils \
- libserviceutility \
libutils \
liblog
diff --git a/services/soundtrigger/Android.mk b/services/soundtrigger/Android.mk
index ad3666e..3c7d29d 100644
--- a/services/soundtrigger/Android.mk
+++ b/services/soundtrigger/Android.mk
@@ -34,8 +34,7 @@
libhardware \
libsoundtrigger \
libaudioclient \
- libserviceutility
-
+ libmediautils \
ifeq ($(USE_LEGACY_LOCAL_AUDIO_HAL),true)
# libhardware configuration
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index a7d6e83..6bf6e94 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -27,13 +27,13 @@
#include <cutils/properties.h>
#include <hardware/hardware.h>
#include <media/AudioSystem.h>
+#include <mediautils/ServiceUtilities.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <binder/IServiceManager.h>
#include <binder/MemoryBase.h>
#include <binder/MemoryHeapBase.h>
#include <system/sound_trigger.h>
-#include <ServiceUtilities.h>
#include "SoundTriggerHwService.h"
#ifdef SOUND_TRIGGER_USE_STUB_MODULE