Merge "Bump apex versions"
diff --git a/apex/Android.bp b/apex/Android.bp
index ef296d6..80e751c 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -64,10 +64,9 @@
],
}
-prebuilt_etc {
+linker_config {
name: "media-linker-config",
- src: "linker.config.txt",
- filename: "linker.config.txt",
+ src: "linker.config.json",
installable: false,
}
diff --git a/apex/linker.config.json b/apex/linker.config.json
new file mode 100644
index 0000000..67c076e
--- /dev/null
+++ b/apex/linker.config.json
@@ -0,0 +1,3 @@
+{
+ "visible": true
+}
diff --git a/apex/linker.config.txt b/apex/linker.config.txt
deleted file mode 100644
index d1c815b..0000000
--- a/apex/linker.config.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-# Extra linker configurations for media APEX
-# See https://android.googlesource.com/platform/system/linkerconfig/+/master/README.md#apex_etc_linker_config_txt
-
-[properties]
-
-# Set media APEX as force visible so media APEX namespace is accessible via android_get_exported_namespace
-visible = true
diff --git a/camera/ndk/impl/ACameraMetadata.cpp b/camera/ndk/impl/ACameraMetadata.cpp
index 631f6cd..895514e 100644
--- a/camera/ndk/impl/ACameraMetadata.cpp
+++ b/camera/ndk/impl/ACameraMetadata.cpp
@@ -426,6 +426,7 @@
camera_metadata_ro_entry_t entry;
int ret = get_camera_metadata_ro_entry(rawMetadata, i, &entry);
if (ret != 0) {
+ mData->unlock(rawMetadata);
ALOGE("%s: error reading metadata index %zu", __FUNCTION__, i);
return ACAMERA_ERROR_UNKNOWN;
}
diff --git a/media/codec2/components/flac/C2SoftFlacEnc.cpp b/media/codec2/components/flac/C2SoftFlacEnc.cpp
index 408db7e..72910c5 100644
--- a/media/codec2/components/flac/C2SoftFlacEnc.cpp
+++ b/media/codec2/components/flac/C2SoftFlacEnc.cpp
@@ -262,9 +262,10 @@
work->result = C2_NO_MEMORY;
return;
}
- C2WriteView wView = mOutputBlock->map().get();
- if (wView.error()) {
- ALOGE("write view map failed %d", wView.error());
+
+ err = mOutputBlock->map().get().error();
+ if (err) {
+ ALOGE("write view map failed %d", err);
work->result = C2_CORRUPTED;
return;
}
diff --git a/media/codec2/vndk/C2AllocatorGralloc.cpp b/media/codec2/vndk/C2AllocatorGralloc.cpp
index 4d7e619..59471a2 100644
--- a/media/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/codec2/vndk/C2AllocatorGralloc.cpp
@@ -25,6 +25,7 @@
#include <hardware/gralloc.h>
#include <ui/GraphicBufferAllocator.h>
#include <ui/GraphicBufferMapper.h>
+#include <ui/Rect.h>
#include <C2AllocatorGralloc.h>
#include <C2Buffer.h>
@@ -253,7 +254,7 @@
virtual ~C2AllocationGralloc() override;
virtual c2_status_t map(
- C2Rect rect, C2MemoryUsage usage, C2Fence *fence,
+ C2Rect c2Rect, C2MemoryUsage usage, C2Fence *fence,
C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) override;
virtual c2_status_t unmap(
uint8_t **addr /* nonnull */, C2Rect rect, C2Fence *fence /* nullable */) override;
@@ -336,8 +337,12 @@
}
c2_status_t C2AllocationGralloc::map(
- C2Rect rect, C2MemoryUsage usage, C2Fence *fence,
+ C2Rect c2Rect, C2MemoryUsage usage, C2Fence *fence,
C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) {
+ const Rect rect{(int32_t)c2Rect.left, (int32_t)c2Rect.top,
+ (int32_t)(c2Rect.left + c2Rect.width) /* right */,
+ (int32_t)(c2Rect.top + c2Rect.height) /* bottom */};
+
uint64_t grallocUsage = static_cast<C2AndroidMemoryUsage>(usage).asGrallocUsage();
ALOGV("mapping buffer with usage %#llx => %#llx",
(long long)usage.expected, (long long)grallocUsage);
@@ -386,10 +391,7 @@
void *pointer = nullptr;
// TODO: fence
status_t err = GraphicBufferMapper::get().lock(
- const_cast<native_handle_t *>(mBuffer), grallocUsage,
- { (int32_t)rect.left, (int32_t)rect.top,
- (int32_t)rect.width, (int32_t)rect.height },
- &pointer);
+ const_cast<native_handle_t *>(mBuffer), grallocUsage, rect, &pointer);
if (err) {
ALOGE("failed transaction: lock(RGBA_1010102)");
return C2_CORRUPTED;
@@ -464,10 +466,7 @@
void *pointer = nullptr;
// TODO: fence
status_t err = GraphicBufferMapper::get().lock(
- const_cast<native_handle_t*>(mBuffer), grallocUsage,
- { (int32_t)rect.left, (int32_t)rect.top,
- (int32_t)rect.width, (int32_t)rect.height },
- &pointer);
+ const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, &pointer);
if (err) {
ALOGE("failed transaction: lock(RGBA_8888)");
return C2_CORRUPTED;
@@ -524,10 +523,7 @@
void *pointer = nullptr;
// TODO: fence
status_t err = GraphicBufferMapper::get().lock(
- const_cast<native_handle_t*>(mBuffer), grallocUsage,
- { (int32_t)rect.left, (int32_t)rect.top,
- (int32_t)rect.width, (int32_t)rect.height },
- &pointer);
+ const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, &pointer);
if (err) {
ALOGE("failed transaction: lock(BLOB)");
return C2_CORRUPTED;
@@ -544,10 +540,7 @@
android_ycbcr ycbcrLayout;
status_t err = GraphicBufferMapper::get().lockYCbCr(
- const_cast<native_handle_t*>(mBuffer), grallocUsage,
- { (int32_t)rect.left, (int32_t)rect.top,
- (int32_t)rect.width, (int32_t)rect.height },
- &ycbcrLayout);
+ const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, &ycbcrLayout);
if (err) {
ALOGE("failed transaction: lockYCbCr");
return C2_CORRUPTED;
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 94f10e5..c2dcd35 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -75,6 +75,7 @@
}
AudioStreamInternal::~AudioStreamInternal() {
+ ALOGD("%s() %p called", __func__, this);
}
aaudio_result_t AudioStreamInternal::open(const AudioStreamBuilder &builder) {
@@ -270,21 +271,21 @@
return result;
error:
- releaseCloseFinal();
+ safeReleaseClose();
return result;
}
// This must be called under mStreamLock.
aaudio_result_t AudioStreamInternal::release_l() {
aaudio_result_t result = AAUDIO_OK;
- ALOGV("%s(): mServiceStreamHandle = 0x%08X", __func__, mServiceStreamHandle);
+ ALOGD("%s(): mServiceStreamHandle = 0x%08X", __func__, mServiceStreamHandle);
if (mServiceStreamHandle != AAUDIO_HANDLE_INVALID) {
aaudio_stream_state_t currentState = getState();
// Don't release a stream while it is running. Stop it first.
// If DISCONNECTED then we should still try to stop in case the
// error callback is still running.
if (isActive() || currentState == AAUDIO_STREAM_STATE_DISCONNECTED) {
- requestStop();
+ requestStop_l();
}
logReleaseBufferState();
@@ -330,7 +331,7 @@
* The processing code will then save the current offset
* between client and server and apply that to any position given to the app.
*/
-aaudio_result_t AudioStreamInternal::requestStart()
+aaudio_result_t AudioStreamInternal::requestStart_l()
{
int64_t startTime;
if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
@@ -373,7 +374,7 @@
* AAUDIO_NANOS_PER_SECOND
/ getSampleRate();
mCallbackEnabled.store(true);
- result = createThread(periodNanos, aaudio_callback_thread_proc, this);
+ result = createThread_l(periodNanos, aaudio_callback_thread_proc, this);
}
if (result != AAUDIO_OK) {
setState(originalState);
@@ -399,26 +400,29 @@
}
// This must be called under mStreamLock.
-aaudio_result_t AudioStreamInternal::stopCallback()
+aaudio_result_t AudioStreamInternal::stopCallback_l()
{
if (isDataCallbackSet()
&& (isActive() || getState() == AAUDIO_STREAM_STATE_DISCONNECTED)) {
mCallbackEnabled.store(false);
- aaudio_result_t result = joinThread(NULL); // may temporarily unlock mStreamLock
+ aaudio_result_t result = joinThread_l(NULL); // may temporarily unlock mStreamLock
if (result == AAUDIO_ERROR_INVALID_HANDLE) {
ALOGD("%s() INVALID_HANDLE, stream was probably stolen", __func__);
result = AAUDIO_OK;
}
return result;
} else {
+ ALOGD("%s() skipped, isDataCallbackSet() = %d, isActive() = %d, getState() = %d", __func__,
+ isDataCallbackSet(), isActive(), getState());
return AAUDIO_OK;
}
}
// This must be called under mStreamLock.
-aaudio_result_t AudioStreamInternal::requestStop() {
- aaudio_result_t result = stopCallback();
+aaudio_result_t AudioStreamInternal::requestStop_l() {
+ aaudio_result_t result = stopCallback_l();
if (result != AAUDIO_OK) {
+ ALOGW("%s() stop callback returned %d, returning early", __func__, result);
return result;
}
// The stream may have been unlocked temporarily to let a callback finish
@@ -426,6 +430,7 @@
// Check to make sure the stream still needs to be stopped.
// See also AudioStream::safeStop().
if (!(isActive() || getState() == AAUDIO_STREAM_STATE_DISCONNECTED)) {
+ ALOGD("%s() returning early, not active or disconnected", __func__);
return AAUDIO_OK;
}
@@ -805,11 +810,15 @@
return mBufferCapacityInFrames;
}
-// This must be called under mStreamLock.
aaudio_result_t AudioStreamInternal::joinThread(void** returnArg) {
return AudioStream::joinThread(returnArg, calculateReasonableTimeout(getFramesPerBurst()));
}
+// This must be called under mStreamLock.
+aaudio_result_t AudioStreamInternal::joinThread_l(void** returnArg) {
+ return AudioStream::joinThread_l(returnArg, calculateReasonableTimeout(getFramesPerBurst()));
+}
+
bool AudioStreamInternal::isClockModelInControl() const {
return isActive() && mAudioEndpoint->isFreeRunning() && mClockModel.isRunning();
}
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index d7024cf..1838b53 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -44,9 +44,9 @@
AudioStreamInternal(AAudioServiceInterface &serviceInterface, bool inService);
virtual ~AudioStreamInternal();
- aaudio_result_t requestStart() override;
+ aaudio_result_t requestStart_l() override;
- aaudio_result_t requestStop() override;
+ aaudio_result_t requestStop_l() override;
aaudio_result_t getTimestamp(clockid_t clockId,
int64_t *framePosition,
@@ -117,7 +117,9 @@
aaudio_result_t processCommands();
- aaudio_result_t stopCallback();
+ aaudio_result_t stopCallback_l();
+
+ aaudio_result_t joinThread_l(void** returnArg);
virtual void prepareBuffersForStart() {}
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index 980592c..b81e5e4 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -56,7 +56,7 @@
getDeviceChannelCount());
if (result != AAUDIO_OK) {
- releaseCloseFinal();
+ safeReleaseClose();
}
// Sample rate is constrained to common values by now and should not overflow.
int32_t numFrames = kRampMSec * getSampleRate() / AAUDIO_MILLIS_PER_SECOND;
@@ -66,9 +66,9 @@
}
// This must be called under mStreamLock.
-aaudio_result_t AudioStreamInternalPlay::requestPause()
+aaudio_result_t AudioStreamInternalPlay::requestPause_l()
{
- aaudio_result_t result = stopCallback();
+ aaudio_result_t result = stopCallback_l();
if (result != AAUDIO_OK) {
return result;
}
@@ -83,7 +83,7 @@
return mServiceInterface.pauseStream(mServiceStreamHandle);
}
-aaudio_result_t AudioStreamInternalPlay::requestFlush() {
+aaudio_result_t AudioStreamInternalPlay::requestFlush_l() {
if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
ALOGW("%s() mServiceStreamHandle invalid", __func__);
return AAUDIO_ERROR_INVALID_STATE;
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.h b/media/libaaudio/src/client/AudioStreamInternalPlay.h
index 7b1cddc..03c957d 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.h
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.h
@@ -35,9 +35,9 @@
aaudio_result_t open(const AudioStreamBuilder &builder) override;
- aaudio_result_t requestPause() override;
+ aaudio_result_t requestPause_l() override;
- aaudio_result_t requestFlush() override;
+ aaudio_result_t requestFlush_l() override;
bool isFlushSupported() const override {
// Only implement FLUSH for OUTPUT streams.
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index ac2da57..ba86170 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -42,16 +42,20 @@
: mPlayerBase(new MyPlayerBase())
, mStreamId(AAudio_getNextStreamId())
{
- // mThread is a pthread_t of unknown size so we need memset.
- memset(&mThread, 0, sizeof(mThread));
setPeriodNanoseconds(0);
}
AudioStream::~AudioStream() {
- // Please preserve this log because there have been several bugs related to
+ // Please preserve these logs because there have been several bugs related to
// AudioStream deletion and late callbacks.
ALOGD("%s(s#%u) mPlayerBase strongCount = %d",
__func__, getId(), mPlayerBase->getStrongCount());
+
+ ALOGE_IF(pthread_equal(pthread_self(), mThread),
+ "%s() destructor running in callback", __func__);
+
+ ALOGE_IF(mHasThread, "%s() callback thread never join()ed", __func__);
+
// If the stream is deleted when OPEN or in use then audio resources will leak.
// This would indicate an internal error. So we want to find this ASAP.
LOG_ALWAYS_FATAL_IF(!(getState() == AAUDIO_STREAM_STATE_CLOSED
@@ -164,7 +168,7 @@
return AAUDIO_ERROR_INVALID_STATE;
}
- aaudio_result_t result = requestStart();
+ aaudio_result_t result = requestStart_l();
if (result == AAUDIO_OK) {
// We only call this for logging in "dumpsys audio". So ignore return code.
(void) mPlayerBase->start();
@@ -214,7 +218,7 @@
return AAUDIO_ERROR_INVALID_STATE;
}
- aaudio_result_t result = requestPause();
+ aaudio_result_t result = requestPause_l();
if (result == AAUDIO_OK) {
// We only call this for logging in "dumpsys audio". So ignore return code.
(void) mPlayerBase->pause();
@@ -239,7 +243,7 @@
return result;
}
- return requestFlush();
+ return requestFlush_l();
}
aaudio_result_t AudioStream::systemStopFromCallback() {
@@ -299,11 +303,11 @@
return AAUDIO_ERROR_INVALID_STATE;
}
- return requestStop();
+ return requestStop_l();
}
aaudio_result_t AudioStream::safeRelease() {
- // This get temporarily unlocked in the MMAP release() when joining callback threads.
+ // This may get temporarily unlocked in the MMAP release() when joining callback threads.
std::lock_guard<std::mutex> lock(mStreamLock);
if (collidesWithCallback()) {
ALOGE("%s cannot be called from a callback!", __func__);
@@ -322,7 +326,14 @@
ALOGE("%s cannot be called from a callback!", __func__);
return AAUDIO_ERROR_INVALID_STATE;
}
- releaseCloseFinal();
+ releaseCloseFinal_l();
+ return AAUDIO_OK;
+}
+
+aaudio_result_t AudioStream::safeReleaseCloseFromCallback() {
+ // This get temporarily unlocked in the MMAP release() when joining callback threads.
+ std::lock_guard<std::mutex> lock(mStreamLock);
+ releaseCloseFinal_l();
return AAUDIO_OK;
}
@@ -403,21 +414,28 @@
return procResult;
}
-// This is the entry point for the new thread created by createThread().
+
+// This is the entry point for the new thread created by createThread_l().
// It converts the 'C' function call to a C++ method call.
static void* AudioStream_internalThreadProc(void* threadArg) {
AudioStream *audioStream = (AudioStream *) threadArg;
- return audioStream->wrapUserThread();
+ // Prevent the stream from being deleted while being used.
+ // This is just for extra safety. It is probably not needed because
+ // this callback should be joined before the stream is closed.
+ android::sp<AudioStream> protectedStream(audioStream);
+ // Balance the incStrong() in createThread_l().
+ protectedStream->decStrong(nullptr);
+ return protectedStream->wrapUserThread();
}
// This is not exposed in the API.
// But it is still used internally to implement callbacks for MMAP mode.
-aaudio_result_t AudioStream::createThread(int64_t periodNanoseconds,
- aaudio_audio_thread_proc_t threadProc,
- void* threadArg)
+aaudio_result_t AudioStream::createThread_l(int64_t periodNanoseconds,
+ aaudio_audio_thread_proc_t threadProc,
+ void* threadArg)
{
if (mHasThread) {
- ALOGE("createThread() - mHasThread already true");
+ ALOGE("%s() - mHasThread already true", __func__);
return AAUDIO_ERROR_INVALID_STATE;
}
if (threadProc == nullptr) {
@@ -427,10 +445,14 @@
mThreadProc = threadProc;
mThreadArg = threadArg;
setPeriodNanoseconds(periodNanoseconds);
+ // Prevent this object from getting deleted before the thread has a chance to create
+ // its strong pointer. Assume the thread will call decStrong().
+ this->incStrong(nullptr);
int err = pthread_create(&mThread, nullptr, AudioStream_internalThreadProc, this);
if (err != 0) {
android::status_t status = -errno;
- ALOGE("createThread() - pthread_create() failed, %d", status);
+ ALOGE("%s() - pthread_create() failed, %d", __func__, status);
+ this->decStrong(nullptr); // Because the thread won't do it.
return AAudioConvert_androidToAAudioResult(status);
} else {
// TODO Use AAudioThread or maybe AndroidThread
@@ -450,17 +472,23 @@
}
}
+aaudio_result_t AudioStream::joinThread(void** returnArg, int64_t timeoutNanoseconds) {
+ // This may get temporarily unlocked in the MMAP release() when joining callback threads.
+ std::lock_guard<std::mutex> lock(mStreamLock);
+ return joinThread_l(returnArg, timeoutNanoseconds);
+}
+
// This must be called under mStreamLock.
-aaudio_result_t AudioStream::joinThread(void** returnArg, int64_t timeoutNanoseconds __unused)
+aaudio_result_t AudioStream::joinThread_l(void** returnArg, int64_t /* timeoutNanoseconds */)
{
if (!mHasThread) {
- ALOGE("joinThread() - but has no thread");
+ ALOGD("joinThread() - but has no thread");
return AAUDIO_ERROR_INVALID_STATE;
}
aaudio_result_t result = AAUDIO_OK;
// If the callback is stopping the stream because the app passed back STOP
// then we don't need to join(). The thread is already about to exit.
- if (pthread_self() != mThread) {
+ if (!pthread_equal(pthread_self(), mThread)) {
// Called from an app thread. Not the callback.
// Unlock because the callback may be trying to stop the stream but is blocked.
mStreamLock.unlock();
@@ -475,11 +503,15 @@
if (err) {
ALOGE("%s() pthread_join() returns err = %d", __func__, err);
result = AAudioConvert_androidToAAudioResult(-err);
+ } else {
+ ALOGD("%s() pthread_join succeeded", __func__);
+ // This must be set false so that the callback thread can be created
+ // when the stream is restarted.
+ mHasThread = false;
}
+ } else {
+ ALOGD("%s() pthread_join() called on itself!", __func__);
}
- // This must be set false so that the callback thread can be created
- // when the stream is restarted.
- mHasThread = false;
return (result != AAUDIO_OK) ? result : mThreadRegistrationResult;
}
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index e438477..d9a9d8e 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -60,7 +60,7 @@
/* Asynchronous requests.
* Use waitForStateChange() to wait for completion.
*/
- virtual aaudio_result_t requestStart() = 0;
+ virtual aaudio_result_t requestStart_l() = 0;
/**
* Check the state to see if Pause is currently legal.
@@ -80,18 +80,17 @@
return false;
}
- virtual aaudio_result_t requestPause()
- {
+ virtual aaudio_result_t requestPause_l() {
// Only implement this for OUTPUT streams.
return AAUDIO_ERROR_UNIMPLEMENTED;
}
- virtual aaudio_result_t requestFlush() {
+ virtual aaudio_result_t requestFlush_l() {
// Only implement this for OUTPUT streams.
return AAUDIO_ERROR_UNIMPLEMENTED;
}
- virtual aaudio_result_t requestStop() = 0;
+ virtual aaudio_result_t requestStop_l() = 0;
public:
virtual aaudio_result_t getTimestamp(clockid_t clockId,
@@ -152,17 +151,6 @@
setState(AAUDIO_STREAM_STATE_CLOSED);
}
- /**
- * Release then close the stream.
- */
- void releaseCloseFinal() {
- if (getState() != AAUDIO_STREAM_STATE_CLOSING) { // not already released?
- // Ignore result and keep closing.
- (void) release_l();
- }
- close_l();
- }
-
// This is only used to identify a stream in the logs without
// revealing any pointers.
aaudio_stream_id_t getId() {
@@ -171,9 +159,9 @@
virtual aaudio_result_t setBufferSize(int32_t requestedFrames) = 0;
- virtual aaudio_result_t createThread(int64_t periodNanoseconds,
- aaudio_audio_thread_proc_t threadProc,
- void *threadArg);
+ virtual aaudio_result_t createThread_l(int64_t periodNanoseconds,
+ aaudio_audio_thread_proc_t threadProc,
+ void *threadArg);
aaudio_result_t joinThread(void **returnArg, int64_t timeoutNanoseconds);
@@ -432,6 +420,8 @@
*/
aaudio_result_t safeReleaseClose();
+ aaudio_result_t safeReleaseCloseFromCallback();
+
protected:
// PlayerBase allows the system to control the stream volume.
@@ -543,6 +533,8 @@
mSessionId = sessionId;
}
+ aaudio_result_t joinThread_l(void **returnArg, int64_t timeoutNanoseconds);
+
std::atomic<bool> mCallbackEnabled{false};
float mDuckAndMuteVolume = 1.0f;
@@ -613,6 +605,17 @@
aaudio_result_t safeStop();
+ /**
+ * Release then close the stream.
+ */
+ void releaseCloseFinal_l() {
+ if (getState() != AAUDIO_STREAM_STATE_CLOSING) { // not already released?
+ // Ignore result and keep closing.
+ (void) release_l();
+ }
+ close_l();
+ }
+
std::mutex mStreamLock;
const android::sp<MyPlayerBase> mPlayerBase;
@@ -654,7 +657,7 @@
// background thread ----------------------------------
bool mHasThread = false;
- pthread_t mThread; // initialized in constructor
+ pthread_t mThread = {};
// These are set by the application thread and then read by the audio pthread.
std::atomic<int64_t> mPeriodNanoseconds; // for tuning SCHED_FIFO threads
diff --git a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
index 33c1bf5..fdaa2ab 100644
--- a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
@@ -226,7 +226,7 @@
ALOGD("%s() request DISCONNECT in data callback, device %d => %d",
__func__, (int) getDeviceId(), (int) deviceId);
// If the stream is stopped before the data callback has a chance to handle the
- // request then the requestStop() and requestPause() methods will handle it after
+ // request then the requestStop_l() and requestPause() methods will handle it after
// the callback has stopped.
mRequestDisconnect.request();
} else {
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index d46ef56..45b2258 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -185,7 +185,7 @@
// Did we get a valid track?
status_t status = mAudioRecord->initCheck();
if (status != OK) {
- releaseCloseFinal();
+ safeReleaseClose();
ALOGE("open(), initCheck() returned %d", status);
return AAudioConvert_androidToAAudioResult(status);
}
@@ -341,7 +341,7 @@
return;
}
-aaudio_result_t AudioStreamRecord::requestStart()
+aaudio_result_t AudioStreamRecord::requestStart_l()
{
if (mAudioRecord.get() == nullptr) {
return AAUDIO_ERROR_INVALID_STATE;
@@ -365,7 +365,7 @@
return AAUDIO_OK;
}
-aaudio_result_t AudioStreamRecord::requestStop() {
+aaudio_result_t AudioStreamRecord::requestStop_l() {
if (mAudioRecord.get() == nullptr) {
return AAUDIO_ERROR_INVALID_STATE;
}
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.h b/media/libaaudio/src/legacy/AudioStreamRecord.h
index ad8dfe4..fe9689f 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.h
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.h
@@ -41,8 +41,8 @@
aaudio_result_t release_l() override;
void close_l() override;
- aaudio_result_t requestStart() override;
- aaudio_result_t requestStop() override;
+ aaudio_result_t requestStart_l() override;
+ aaudio_result_t requestStop_l() override;
virtual aaudio_result_t getTimestamp(clockid_t clockId,
int64_t *framePosition,
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 307904e..1d036d0 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -178,7 +178,7 @@
// Did we get a valid track?
status_t status = mAudioTrack->initCheck();
if (status != NO_ERROR) {
- releaseCloseFinal();
+ safeReleaseClose();
ALOGE("open(), initCheck() returned %d", status);
return AAudioConvert_androidToAAudioResult(status);
}
@@ -293,7 +293,7 @@
return;
}
-aaudio_result_t AudioStreamTrack::requestStart() {
+aaudio_result_t AudioStreamTrack::requestStart_l() {
if (mAudioTrack.get() == nullptr) {
ALOGE("requestStart() no AudioTrack");
return AAUDIO_ERROR_INVALID_STATE;
@@ -320,7 +320,7 @@
return AAUDIO_OK;
}
-aaudio_result_t AudioStreamTrack::requestPause() {
+aaudio_result_t AudioStreamTrack::requestPause_l() {
if (mAudioTrack.get() == nullptr) {
ALOGE("%s() no AudioTrack", __func__);
return AAUDIO_ERROR_INVALID_STATE;
@@ -336,7 +336,7 @@
return checkForDisconnectRequest(false);
}
-aaudio_result_t AudioStreamTrack::requestFlush() {
+aaudio_result_t AudioStreamTrack::requestFlush_l() {
if (mAudioTrack.get() == nullptr) {
ALOGE("%s() no AudioTrack", __func__);
return AAUDIO_ERROR_INVALID_STATE;
@@ -350,7 +350,7 @@
return AAUDIO_OK;
}
-aaudio_result_t AudioStreamTrack::requestStop() {
+aaudio_result_t AudioStreamTrack::requestStop_l() {
if (mAudioTrack.get() == nullptr) {
ALOGE("%s() no AudioTrack", __func__);
return AAUDIO_ERROR_INVALID_STATE;
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.h b/media/libaaudio/src/legacy/AudioStreamTrack.h
index 5a8fb39..654ea9b 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.h
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.h
@@ -44,10 +44,10 @@
aaudio_result_t release_l() override;
void close_l() override;
- aaudio_result_t requestStart() override;
- aaudio_result_t requestPause() override;
- aaudio_result_t requestFlush() override;
- aaudio_result_t requestStop() override;
+ aaudio_result_t requestStart_l() override;
+ aaudio_result_t requestPause_l() override;
+ aaudio_result_t requestFlush_l() override;
+ aaudio_result_t requestStop_l() override;
bool isFlushSupported() const override {
// Only implement FLUSH for OUTPUT streams.
diff --git a/media/libaaudio/tests/test_stop_hang.cpp b/media/libaaudio/tests/test_stop_hang.cpp
index 2397b6c..982ff4a 100644
--- a/media/libaaudio/tests/test_stop_hang.cpp
+++ b/media/libaaudio/tests/test_stop_hang.cpp
@@ -45,7 +45,7 @@
{
// Will block if the thread is running.
// This mutex is used to close() immediately after the callback returns
- // and before the requestStop() is called.
+ // and before the requestStop_l() is called.
std::lock_guard<std::mutex> lock(doneLock);
if (done) break;
}
diff --git a/media/libaudioclient/AidlConversion.cpp b/media/libaudioclient/AidlConversion.cpp
new file mode 100644
index 0000000..95a6a4a
--- /dev/null
+++ b/media/libaudioclient/AidlConversion.cpp
@@ -0,0 +1,1223 @@
+/*
+ * Copyright (C) 2020 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 <limits>
+
+#define LOG_TAG "AidlConversion"
+//#define LOG_NDEBUG 0
+#include <system/audio.h>
+#include <utils/Log.h>
+
+#include "media/AidlConversion.h"
+
+#define VALUE_OR_RETURN(result) \
+ ({ \
+ auto _tmp = (result); \
+ if (!_tmp.ok()) return unexpected(_tmp.error()); \
+ _tmp.value(); \
+ })
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Utilities
+
+namespace android {
+
+using base::unexpected;
+
+namespace {
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// The code below establishes:
+// IntegralTypeOf<T>, which works for either integral types (in which case it evaluates to T), or
+// enum types (in which case it evaluates to std::underlying_type_T<T>).
+
+template<typename T, typename = std::enable_if_t<std::is_integral_v<T> || std::is_enum_v<T>>>
+struct IntegralTypeOfStruct {
+ using Type = T;
+};
+
+template<typename T>
+struct IntegralTypeOfStruct<T, std::enable_if_t<std::is_enum_v<T>>> {
+ using Type = std::underlying_type_t<T>;
+};
+
+template<typename T>
+using IntegralTypeOf = typename IntegralTypeOfStruct<T>::Type;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Utilities for handling bitmasks.
+
+template<typename Enum>
+Enum index2enum_index(int index) {
+ static_assert(std::is_enum_v<Enum> || std::is_integral_v<Enum>);
+ return static_cast<Enum>(index);
+}
+
+template<typename Enum>
+Enum index2enum_bitmask(int index) {
+ static_assert(std::is_enum_v<Enum> || std::is_integral_v<Enum>);
+ return static_cast<Enum>(1 << index);
+}
+
+template<typename Mask, typename Enum>
+Mask enumToMask_bitmask(Enum e) {
+ static_assert(std::is_enum_v<Enum> || std::is_integral_v<Enum>);
+ static_assert(std::is_enum_v<Mask> || std::is_integral_v<Mask>);
+ return static_cast<Mask>(e);
+}
+
+template<typename Mask, typename Enum>
+Mask enumToMask_index(Enum e) {
+ static_assert(std::is_enum_v<Enum> || std::is_integral_v<Enum>);
+ static_assert(std::is_enum_v<Mask> || std::is_integral_v<Mask>);
+ return static_cast<Mask>(static_cast<std::make_unsigned_t<IntegralTypeOf<Mask>>>(1)
+ << static_cast<int>(e));
+}
+
+template<typename DestMask, typename SrcMask, typename DestEnum, typename SrcEnum>
+ConversionResult<DestMask> convertBitmask(
+ SrcMask src, const std::function<ConversionResult<DestEnum>(SrcEnum)>& enumConversion,
+ const std::function<SrcEnum(int)>& srcIndexToEnum,
+ const std::function<DestMask(DestEnum)>& destEnumToMask) {
+ using UnsignedDestMask = std::make_unsigned_t<IntegralTypeOf<DestMask>>;
+ using UnsignedSrcMask = std::make_unsigned_t<IntegralTypeOf<SrcMask>>;
+
+ UnsignedDestMask dest = static_cast<UnsignedDestMask>(0);
+ UnsignedSrcMask usrc = static_cast<UnsignedSrcMask>(src);
+
+ int srcBitIndex = 0;
+ while (usrc != 0) {
+ if (usrc & 1) {
+ SrcEnum srcEnum = srcIndexToEnum(srcBitIndex);
+ DestEnum destEnum = VALUE_OR_RETURN(enumConversion(srcEnum));
+ DestMask destMask = destEnumToMask(destEnum);
+ dest |= destMask;
+ }
+ ++srcBitIndex;
+ usrc >>= 1;
+ }
+ return static_cast<DestMask>(dest);
+}
+
+template<typename Mask, typename Enum>
+bool bitmaskIsSet(Mask mask, Enum index) {
+ return (mask & enumToMask_index<Mask, Enum>(index)) != 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+template<typename To, typename From>
+ConversionResult<To> convertIntegral(From from) {
+ // Special handling is required for signed / vs. unsigned comparisons, since otherwise we may
+ // have the signed converted to unsigned and produce wrong results.
+ if (std::is_signed_v<From> && !std::is_signed_v<To>) {
+ if (from < 0 || from > std::numeric_limits<To>::max()) {
+ return unexpected(BAD_VALUE);
+ }
+ } else if (std::is_signed_v<To> && !std::is_signed_v<From>) {
+ if (from > std::numeric_limits<To>::max()) {
+ return unexpected(BAD_VALUE);
+ }
+ } else {
+ if (from < std::numeric_limits<To>::min() || from > std::numeric_limits<To>::max()) {
+ return unexpected(BAD_VALUE);
+ }
+ }
+ return static_cast<To>(from);
+}
+
+template<typename To, typename From>
+ConversionResult<To> convertReinterpret(From from) {
+ static_assert(sizeof(From) == sizeof(To));
+ return static_cast<To>(from);
+}
+
+enum class Direction {
+ INPUT, OUTPUT
+};
+
+ConversionResult<Direction> direction(media::AudioPortRole role, media::AudioPortType type) {
+ switch (type) {
+ case media::AudioPortType::DEVICE:
+ switch (role) {
+ case media::AudioPortRole::SOURCE:
+ return Direction::INPUT;
+ case media::AudioPortRole::SINK:
+ return Direction::OUTPUT;
+ default:
+ break;
+ }
+ break;
+ case media::AudioPortType::MIX:
+ switch (role) {
+ case media::AudioPortRole::SOURCE:
+ return Direction::OUTPUT;
+ case media::AudioPortRole::SINK:
+ return Direction::INPUT;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<Direction> direction(audio_port_role_t role, audio_port_type_t type) {
+ switch (type) {
+ case AUDIO_PORT_TYPE_DEVICE:
+ switch (role) {
+ case AUDIO_PORT_ROLE_SOURCE:
+ return Direction::INPUT;
+ case AUDIO_PORT_ROLE_SINK:
+ return Direction::OUTPUT;
+ default:
+ break;
+ }
+ break;
+ case AUDIO_PORT_TYPE_MIX:
+ switch (role) {
+ case AUDIO_PORT_ROLE_SOURCE:
+ return Direction::OUTPUT;
+ case AUDIO_PORT_ROLE_SINK:
+ return Direction::INPUT;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Converters
+
+// The legacy enum is unnamed. Thus, we use int.
+ConversionResult<int> aidl2legacy_AudioPortConfigType(media::AudioPortConfigType aidl) {
+ switch (aidl) {
+ case media::AudioPortConfigType::SAMPLE_RATE:
+ return AUDIO_PORT_CONFIG_SAMPLE_RATE;
+ case media::AudioPortConfigType::CHANNEL_MASK:
+ return AUDIO_PORT_CONFIG_CHANNEL_MASK;
+ case media::AudioPortConfigType::FORMAT:
+ return AUDIO_PORT_CONFIG_FORMAT;
+ case media::AudioPortConfigType::FLAGS:
+ return AUDIO_PORT_CONFIG_FLAGS;
+ default:
+ return unexpected(BAD_VALUE);
+ }
+}
+
+// The legacy enum is unnamed. Thus, we use int.
+ConversionResult<media::AudioPortConfigType> legacy2aidl_AudioPortConfigType(int legacy) {
+ switch (legacy) {
+ case AUDIO_PORT_CONFIG_SAMPLE_RATE:
+ return media::AudioPortConfigType::SAMPLE_RATE;
+ case AUDIO_PORT_CONFIG_CHANNEL_MASK:
+ return media::AudioPortConfigType::CHANNEL_MASK;
+ case AUDIO_PORT_CONFIG_FORMAT:
+ return media::AudioPortConfigType::FORMAT;
+ case AUDIO_PORT_CONFIG_FLAGS:
+ return media::AudioPortConfigType::FLAGS;
+ default:
+ return unexpected(BAD_VALUE);
+ }
+}
+
+ConversionResult<unsigned int> aidl2legacy_int32_t_config_mask(int32_t aidl) {
+ return convertBitmask<unsigned int, int32_t, int, media::AudioPortConfigType>(
+ aidl, aidl2legacy_AudioPortConfigType,
+ // AudioPortConfigType enum is index-based.
+ index2enum_index<media::AudioPortConfigType>,
+ // AUDIO_PORT_CONFIG_* flags are mask-based.
+ enumToMask_bitmask<unsigned int, int>);
+}
+
+ConversionResult<int32_t> legacy2aidl_config_mask_int32_t(unsigned int legacy) {
+ return convertBitmask<int32_t, unsigned int, media::AudioPortConfigType, int>(
+ legacy, legacy2aidl_AudioPortConfigType,
+ // AUDIO_PORT_CONFIG_* flags are mask-based.
+ index2enum_bitmask<unsigned>,
+ // AudioPortConfigType enum is index-based.
+ enumToMask_index<int32_t, media::AudioPortConfigType>);
+}
+
+ConversionResult<audio_channel_mask_t> aidl2legacy_int32_t_audio_channel_mask_t(int32_t aidl) {
+ // TODO(ytai): should we convert bit-by-bit?
+ // One problem here is that the representation is both opaque and is different based on the
+ // context (input vs. output). Can determine based on type and role, as per useInChannelMask().
+ return convertReinterpret<audio_channel_mask_t>(aidl);
+}
+
+ConversionResult<int32_t> legacy2aidl_audio_channel_mask_t_int32_t(audio_channel_mask_t legacy) {
+ // TODO(ytai): should we convert bit-by-bit?
+ // One problem here is that the representation is both opaque and is different based on the
+ // context (input vs. output). Can determine based on type and role, as per useInChannelMask().
+ return convertReinterpret<int32_t>(legacy);
+}
+
+ConversionResult<audio_io_config_event> aidl2legacy_AudioIoConfigEvent_audio_io_config_event(
+ media::AudioIoConfigEvent aidl) {
+ switch (aidl) {
+ case media::AudioIoConfigEvent::OUTPUT_REGISTERED:
+ return AUDIO_OUTPUT_REGISTERED;
+ case media::AudioIoConfigEvent::OUTPUT_OPENED:
+ return AUDIO_OUTPUT_OPENED;
+ case media::AudioIoConfigEvent::OUTPUT_CLOSED:
+ return AUDIO_OUTPUT_CLOSED;
+ case media::AudioIoConfigEvent::OUTPUT_CONFIG_CHANGED:
+ return AUDIO_OUTPUT_CONFIG_CHANGED;
+ case media::AudioIoConfigEvent::INPUT_REGISTERED:
+ return AUDIO_INPUT_REGISTERED;
+ case media::AudioIoConfigEvent::INPUT_OPENED:
+ return AUDIO_INPUT_OPENED;
+ case media::AudioIoConfigEvent::INPUT_CLOSED:
+ return AUDIO_INPUT_CLOSED;
+ case media::AudioIoConfigEvent::INPUT_CONFIG_CHANGED:
+ return AUDIO_INPUT_CONFIG_CHANGED;
+ case media::AudioIoConfigEvent::CLIENT_STARTED:
+ return AUDIO_CLIENT_STARTED;
+ default:
+ return unexpected(BAD_VALUE);
+ }
+}
+
+ConversionResult<media::AudioIoConfigEvent> legacy2aidl_audio_io_config_event_AudioIoConfigEvent(
+ audio_io_config_event legacy) {
+ switch (legacy) {
+ case AUDIO_OUTPUT_REGISTERED:
+ return media::AudioIoConfigEvent::OUTPUT_REGISTERED;
+ case AUDIO_OUTPUT_OPENED:
+ return media::AudioIoConfigEvent::OUTPUT_OPENED;
+ case AUDIO_OUTPUT_CLOSED:
+ return media::AudioIoConfigEvent::OUTPUT_CLOSED;
+ case AUDIO_OUTPUT_CONFIG_CHANGED:
+ return media::AudioIoConfigEvent::OUTPUT_CONFIG_CHANGED;
+ case AUDIO_INPUT_REGISTERED:
+ return media::AudioIoConfigEvent::INPUT_REGISTERED;
+ case AUDIO_INPUT_OPENED:
+ return media::AudioIoConfigEvent::INPUT_OPENED;
+ case AUDIO_INPUT_CLOSED:
+ return media::AudioIoConfigEvent::INPUT_CLOSED;
+ case AUDIO_INPUT_CONFIG_CHANGED:
+ return media::AudioIoConfigEvent::INPUT_CONFIG_CHANGED;
+ case AUDIO_CLIENT_STARTED:
+ return media::AudioIoConfigEvent::CLIENT_STARTED;
+ default:
+ return unexpected(BAD_VALUE);
+ }
+}
+
+ConversionResult<audio_port_role_t> aidl2legacy_AudioPortRole_audio_port_role_t(
+ media::AudioPortRole aidl) {
+ switch (aidl) {
+ case media::AudioPortRole::NONE:
+ return AUDIO_PORT_ROLE_NONE;
+ case media::AudioPortRole::SOURCE:
+ return AUDIO_PORT_ROLE_SOURCE;
+ case media::AudioPortRole::SINK:
+ return AUDIO_PORT_ROLE_SINK;
+ default:
+ return unexpected(BAD_VALUE);
+ }
+}
+
+ConversionResult<media::AudioPortRole> legacy2aidl_audio_port_role_t_AudioPortRole(
+ audio_port_role_t legacy) {
+ switch (legacy) {
+ case AUDIO_PORT_ROLE_NONE:
+ return media::AudioPortRole::NONE;
+ case AUDIO_PORT_ROLE_SOURCE:
+ return media::AudioPortRole::SOURCE;
+ case AUDIO_PORT_ROLE_SINK:
+ return media::AudioPortRole::SINK;
+ default:
+ return unexpected(BAD_VALUE);
+ }
+}
+
+ConversionResult<audio_port_type_t> aidl2legacy_AudioPortType_audio_port_type_t(
+ media::AudioPortType aidl) {
+ switch (aidl) {
+ case media::AudioPortType::NONE:
+ return AUDIO_PORT_TYPE_NONE;
+ case media::AudioPortType::DEVICE:
+ return AUDIO_PORT_TYPE_DEVICE;
+ case media::AudioPortType::MIX:
+ return AUDIO_PORT_TYPE_MIX;
+ case media::AudioPortType::SESSION:
+ return AUDIO_PORT_TYPE_SESSION;
+ default:
+ return unexpected(BAD_VALUE);
+ }
+}
+
+ConversionResult<media::AudioPortType> legacy2aidl_audio_port_type_t_AudioPortType(
+ audio_port_type_t legacy) {
+ switch (legacy) {
+ case AUDIO_PORT_TYPE_NONE:
+ return media::AudioPortType::NONE;
+ case AUDIO_PORT_TYPE_DEVICE:
+ return media::AudioPortType::DEVICE;
+ case AUDIO_PORT_TYPE_MIX:
+ return media::AudioPortType::MIX;
+ case AUDIO_PORT_TYPE_SESSION:
+ return media::AudioPortType::SESSION;
+ default:
+ return unexpected(BAD_VALUE);
+ }
+}
+
+ConversionResult<audio_format_t> aidl2legacy_AudioFormat_audio_format_t(
+ media::audio::common::AudioFormat aidl) {
+ // This relies on AudioFormat being kept in sync with audio_format_t.
+ static_assert(sizeof(media::audio::common::AudioFormat) == sizeof(audio_format_t));
+ return static_cast<audio_format_t>(aidl);
+}
+
+ConversionResult<media::audio::common::AudioFormat> legacy2aidl_audio_format_t_AudioFormat(
+ audio_format_t legacy) {
+ // This relies on AudioFormat being kept in sync with audio_format_t.
+ static_assert(sizeof(media::audio::common::AudioFormat) == sizeof(audio_format_t));
+ return static_cast<media::audio::common::AudioFormat>(legacy);
+}
+
+ConversionResult<int> aidl2legacy_AudioGainMode_int(media::AudioGainMode aidl) {
+ switch (aidl) {
+ case media::AudioGainMode::JOINT:
+ return AUDIO_GAIN_MODE_JOINT;
+ case media::AudioGainMode::CHANNELS:
+ return AUDIO_GAIN_MODE_CHANNELS;
+ case media::AudioGainMode::RAMP:
+ return AUDIO_GAIN_MODE_RAMP;
+ default:
+ return unexpected(BAD_VALUE);
+ }
+}
+
+ConversionResult<media::AudioGainMode> legacy2aidl_int_AudioGainMode(int legacy) {
+ switch (legacy) {
+ case AUDIO_GAIN_MODE_JOINT:
+ return media::AudioGainMode::JOINT;
+ case AUDIO_GAIN_MODE_CHANNELS:
+ return media::AudioGainMode::CHANNELS;
+ case AUDIO_GAIN_MODE_RAMP:
+ return media::AudioGainMode::RAMP;
+ default:
+ return unexpected(BAD_VALUE);
+ }
+}
+
+ConversionResult<audio_gain_mode_t> aidl2legacy_int32_t_audio_gain_mode_t(int32_t aidl) {
+ return convertBitmask<audio_gain_mode_t, int32_t, int, media::AudioGainMode>(
+ aidl, aidl2legacy_AudioGainMode_int,
+ // AudioGainMode is index-based.
+ index2enum_index<media::AudioGainMode>,
+ // AUDIO_GAIN_MODE_* constants are mask-based.
+ enumToMask_bitmask<audio_gain_mode_t, int>);
+}
+
+ConversionResult<int32_t> legacy2aidl_audio_gain_mode_t_int32_t(audio_gain_mode_t legacy) {
+ return convertBitmask<int32_t, audio_gain_mode_t, media::AudioGainMode, int>(
+ legacy, legacy2aidl_int_AudioGainMode,
+ // AUDIO_GAIN_MODE_* constants are mask-based.
+ index2enum_bitmask<int>,
+ // AudioGainMode is index-based.
+ enumToMask_index<int32_t, media::AudioGainMode>);
+}
+
+ConversionResult<audio_devices_t> aidl2legacy_int32_t_audio_devices_t(int32_t aidl) {
+ // TODO(ytai): bitfield?
+ return convertReinterpret<audio_devices_t>(aidl);
+}
+
+ConversionResult<int32_t> legacy2aidl_audio_devices_t_int32_t(audio_devices_t legacy) {
+ // TODO(ytai): bitfield?
+ return convertReinterpret<int32_t>(legacy);
+}
+
+ConversionResult<audio_gain_config> aidl2legacy_AudioGainConfig_audio_gain_config(
+ const media::AudioGainConfig& aidl, media::AudioPortRole role, media::AudioPortType type) {
+ audio_gain_config legacy;
+ legacy.index = VALUE_OR_RETURN(convertIntegral<int>(aidl.index));
+ legacy.mode = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_gain_mode_t(aidl.mode));
+ legacy.channel_mask =
+ VALUE_OR_RETURN(aidl2legacy_int32_t_audio_channel_mask_t(aidl.channelMask));
+ const bool isInput = VALUE_OR_RETURN(direction(role, type)) == Direction::INPUT;
+ const bool isJoint = bitmaskIsSet(aidl.mode, media::AudioGainMode::JOINT);
+ size_t numValues = isJoint ? 1
+ : isInput ? audio_channel_count_from_in_mask(legacy.channel_mask)
+ : audio_channel_count_from_out_mask(legacy.channel_mask);
+ if (aidl.values.size() != numValues || aidl.values.size() > std::size(legacy.values)) {
+ return unexpected(BAD_VALUE);
+ }
+ for (size_t i = 0; i < numValues; ++i) {
+ legacy.values[i] = VALUE_OR_RETURN(convertIntegral<int>(aidl.values[i]));
+ }
+ legacy.ramp_duration_ms = VALUE_OR_RETURN(convertIntegral<unsigned int>(aidl.rampDurationMs));
+ return legacy;
+}
+
+ConversionResult<media::AudioGainConfig> legacy2aidl_audio_gain_config_AudioGainConfig(
+ const audio_gain_config& legacy, audio_port_role_t role, audio_port_type_t type) {
+ media::AudioGainConfig aidl;
+ aidl.index = VALUE_OR_RETURN(convertIntegral<int32_t>(legacy.index));
+ aidl.mode = VALUE_OR_RETURN(legacy2aidl_audio_gain_mode_t_int32_t(legacy.mode));
+ aidl.channelMask =
+ VALUE_OR_RETURN(legacy2aidl_audio_channel_mask_t_int32_t(legacy.channel_mask));
+ const bool isInput = VALUE_OR_RETURN(direction(role, type)) == Direction::INPUT;
+ const bool isJoint = (legacy.mode & AUDIO_GAIN_MODE_JOINT) != 0;
+ size_t numValues = isJoint ? 1
+ : isInput ? audio_channel_count_from_in_mask(legacy.channel_mask)
+ : audio_channel_count_from_out_mask(legacy.channel_mask);
+ aidl.values.resize(numValues);
+ for (size_t i = 0; i < numValues; ++i) {
+ aidl.values[i] = VALUE_OR_RETURN(convertIntegral<int32_t>(legacy.values[i]));
+ }
+ aidl.rampDurationMs = VALUE_OR_RETURN(convertIntegral<int32_t>(legacy.ramp_duration_ms));
+ return aidl;
+}
+
+ConversionResult<audio_input_flags_t> aidl2legacy_AudioInputFlags_audio_input_flags_t(
+ media::AudioInputFlags aidl) {
+ switch (aidl) {
+ case media::AudioInputFlags::FAST:
+ return AUDIO_INPUT_FLAG_FAST;
+ case media::AudioInputFlags::HW_HOTWORD:
+ return AUDIO_INPUT_FLAG_HW_HOTWORD;
+ case media::AudioInputFlags::RAW:
+ return AUDIO_INPUT_FLAG_RAW;
+ case media::AudioInputFlags::SYNC:
+ return AUDIO_INPUT_FLAG_SYNC;
+ case media::AudioInputFlags::MMAP_NOIRQ:
+ return AUDIO_INPUT_FLAG_MMAP_NOIRQ;
+ case media::AudioInputFlags::VOIP_TX:
+ return AUDIO_INPUT_FLAG_VOIP_TX;
+ case media::AudioInputFlags::HW_AV_SYNC:
+ return AUDIO_INPUT_FLAG_HW_AV_SYNC;
+ case media::AudioInputFlags::DIRECT:
+ return AUDIO_INPUT_FLAG_DIRECT;
+ default:
+ return unexpected(BAD_VALUE);
+ }
+}
+
+ConversionResult<media::AudioInputFlags> legacy2aidl_audio_input_flags_t_AudioInputFlags(
+ audio_input_flags_t legacy) {
+ switch (legacy) {
+ case AUDIO_INPUT_FLAG_FAST:
+ return media::AudioInputFlags::FAST;
+ case AUDIO_INPUT_FLAG_HW_HOTWORD:
+ return media::AudioInputFlags::HW_HOTWORD;
+ case AUDIO_INPUT_FLAG_RAW:
+ return media::AudioInputFlags::RAW;
+ case AUDIO_INPUT_FLAG_SYNC:
+ return media::AudioInputFlags::SYNC;
+ case AUDIO_INPUT_FLAG_MMAP_NOIRQ:
+ return media::AudioInputFlags::MMAP_NOIRQ;
+ case AUDIO_INPUT_FLAG_VOIP_TX:
+ return media::AudioInputFlags::VOIP_TX;
+ case AUDIO_INPUT_FLAG_HW_AV_SYNC:
+ return media::AudioInputFlags::HW_AV_SYNC;
+ case AUDIO_INPUT_FLAG_DIRECT:
+ return media::AudioInputFlags::DIRECT;
+ default:
+ return unexpected(BAD_VALUE);
+ }
+}
+
+ConversionResult<audio_output_flags_t> aidl2legacy_AudioOutputFlags_audio_output_flags_t(
+ media::AudioOutputFlags aidl) {
+ switch (aidl) {
+ case media::AudioOutputFlags::DIRECT:
+ return AUDIO_OUTPUT_FLAG_DIRECT;
+ case media::AudioOutputFlags::PRIMARY:
+ return AUDIO_OUTPUT_FLAG_PRIMARY;
+ case media::AudioOutputFlags::FAST:
+ return AUDIO_OUTPUT_FLAG_FAST;
+ case media::AudioOutputFlags::DEEP_BUFFER:
+ return AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
+ case media::AudioOutputFlags::COMPRESS_OFFLOAD:
+ return AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
+ case media::AudioOutputFlags::NON_BLOCKING:
+ return AUDIO_OUTPUT_FLAG_NON_BLOCKING;
+ case media::AudioOutputFlags::HW_AV_SYNC:
+ return AUDIO_OUTPUT_FLAG_HW_AV_SYNC;
+ case media::AudioOutputFlags::TTS:
+ return AUDIO_OUTPUT_FLAG_TTS;
+ case media::AudioOutputFlags::RAW:
+ return AUDIO_OUTPUT_FLAG_RAW;
+ case media::AudioOutputFlags::SYNC:
+ return AUDIO_OUTPUT_FLAG_SYNC;
+ case media::AudioOutputFlags::IEC958_NONAUDIO:
+ return AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO;
+ case media::AudioOutputFlags::DIRECT_PCM:
+ return AUDIO_OUTPUT_FLAG_DIRECT_PCM;
+ case media::AudioOutputFlags::MMAP_NOIRQ:
+ return AUDIO_OUTPUT_FLAG_MMAP_NOIRQ;
+ case media::AudioOutputFlags::VOIP_RX:
+ return AUDIO_OUTPUT_FLAG_VOIP_RX;
+ case media::AudioOutputFlags::INCALL_MUSIC:
+ return AUDIO_OUTPUT_FLAG_INCALL_MUSIC;
+ default:
+ return unexpected(BAD_VALUE);
+ }
+}
+
+ConversionResult<media::AudioOutputFlags> legacy2aidl_audio_output_flags_t_AudioOutputFlags(
+ audio_output_flags_t legacy) {
+ switch (legacy) {
+ case AUDIO_OUTPUT_FLAG_DIRECT:
+ return media::AudioOutputFlags::DIRECT;
+ case AUDIO_OUTPUT_FLAG_PRIMARY:
+ return media::AudioOutputFlags::PRIMARY;
+ case AUDIO_OUTPUT_FLAG_FAST:
+ return media::AudioOutputFlags::FAST;
+ case AUDIO_OUTPUT_FLAG_DEEP_BUFFER:
+ return media::AudioOutputFlags::DEEP_BUFFER;
+ case AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD:
+ return media::AudioOutputFlags::COMPRESS_OFFLOAD;
+ case AUDIO_OUTPUT_FLAG_NON_BLOCKING:
+ return media::AudioOutputFlags::NON_BLOCKING;
+ case AUDIO_OUTPUT_FLAG_HW_AV_SYNC:
+ return media::AudioOutputFlags::HW_AV_SYNC;
+ case AUDIO_OUTPUT_FLAG_TTS:
+ return media::AudioOutputFlags::TTS;
+ case AUDIO_OUTPUT_FLAG_RAW:
+ return media::AudioOutputFlags::RAW;
+ case AUDIO_OUTPUT_FLAG_SYNC:
+ return media::AudioOutputFlags::SYNC;
+ case AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO:
+ return media::AudioOutputFlags::IEC958_NONAUDIO;
+ case AUDIO_OUTPUT_FLAG_DIRECT_PCM:
+ return media::AudioOutputFlags::DIRECT_PCM;
+ case AUDIO_OUTPUT_FLAG_MMAP_NOIRQ:
+ return media::AudioOutputFlags::MMAP_NOIRQ;
+ case AUDIO_OUTPUT_FLAG_VOIP_RX:
+ return media::AudioOutputFlags::VOIP_RX;
+ case AUDIO_OUTPUT_FLAG_INCALL_MUSIC:
+ return media::AudioOutputFlags::INCALL_MUSIC;
+ default:
+ return unexpected(BAD_VALUE);
+ }
+}
+
+ConversionResult<audio_input_flags_t> aidl2legacy_audio_input_flags_mask(int32_t aidl) {
+ using LegacyMask = std::underlying_type_t<audio_input_flags_t>;
+
+ LegacyMask converted = VALUE_OR_RETURN(
+ (convertBitmask<LegacyMask, int32_t, audio_input_flags_t, media::AudioInputFlags>(
+ aidl, aidl2legacy_AudioInputFlags_audio_input_flags_t,
+ index2enum_index<media::AudioInputFlags>,
+ enumToMask_bitmask<LegacyMask, audio_input_flags_t>)));
+ return static_cast<audio_input_flags_t>(converted);
+}
+
+ConversionResult<int32_t> legacy2aidl_audio_input_flags_mask(audio_input_flags_t legacy) {
+ using LegacyMask = std::underlying_type_t<audio_input_flags_t>;
+
+ LegacyMask legacyMask = static_cast<LegacyMask>(legacy);
+ return convertBitmask<int32_t, LegacyMask, media::AudioInputFlags, audio_input_flags_t>(
+ legacyMask, legacy2aidl_audio_input_flags_t_AudioInputFlags,
+ index2enum_bitmask<audio_input_flags_t>,
+ enumToMask_index<int32_t, media::AudioInputFlags>);
+}
+
+ConversionResult<audio_output_flags_t> aidl2legacy_audio_output_flags_mask(int32_t aidl) {
+ using LegacyMask = std::underlying_type_t<audio_output_flags_t>;
+
+ LegacyMask converted = VALUE_OR_RETURN(
+ (convertBitmask<LegacyMask, int32_t, audio_output_flags_t, media::AudioOutputFlags>(
+ aidl, aidl2legacy_AudioOutputFlags_audio_output_flags_t,
+ index2enum_index<media::AudioOutputFlags>,
+ enumToMask_bitmask<LegacyMask, audio_output_flags_t>)));
+ return convertReinterpret<audio_output_flags_t>(converted);
+}
+
+ConversionResult<int32_t> legacy2aidl_audio_output_flags_mask(audio_output_flags_t legacy) {
+ using LegacyMask = std::underlying_type_t<audio_output_flags_t>;
+
+ LegacyMask legacyMask = static_cast<LegacyMask>(legacy);
+ return convertBitmask<int32_t, LegacyMask, media::AudioOutputFlags, audio_output_flags_t>(
+ legacyMask, legacy2aidl_audio_output_flags_t_AudioOutputFlags,
+ index2enum_bitmask<audio_output_flags_t>,
+ enumToMask_index<int32_t, media::AudioOutputFlags>);
+}
+
+ConversionResult<audio_io_flags> aidl2legacy_AudioIoFlags_audio_io_flags(
+ const media::AudioIoFlags& aidl, media::AudioPortRole role, media::AudioPortType type) {
+ audio_io_flags legacy;
+ // Our way of representing a union in AIDL is to have multiple vectors and require that at most
+ // one of the them has size 1 and the rest are empty.
+ size_t totalSize = aidl.input.size() + aidl.output.size();
+ if (totalSize > 1) {
+ return unexpected(BAD_VALUE);
+ }
+
+ Direction dir = VALUE_OR_RETURN(direction(role, type));
+ switch (dir) {
+ case Direction::INPUT:
+ if (aidl.input.empty()) {
+ return unexpected(BAD_VALUE);
+ }
+ legacy.input = VALUE_OR_RETURN(aidl2legacy_audio_input_flags_mask(aidl.input[0]));
+ break;
+
+ case Direction::OUTPUT:
+ if (aidl.output.empty()) {
+ return unexpected(BAD_VALUE);
+ }
+ legacy.output = VALUE_OR_RETURN(aidl2legacy_audio_output_flags_mask(aidl.output[0]));
+ break;
+ }
+
+ return legacy;
+}
+
+ConversionResult<media::AudioIoFlags> legacy2aidl_audio_io_flags_AudioIoFlags(
+ const audio_io_flags& legacy, audio_port_role_t role, audio_port_type_t type) {
+ media::AudioIoFlags aidl;
+
+ Direction dir = VALUE_OR_RETURN(direction(role, type));
+ switch (dir) {
+ case Direction::INPUT:
+ aidl.input.push_back(VALUE_OR_RETURN(legacy2aidl_audio_input_flags_mask(legacy.input)));
+ break;
+ case Direction::OUTPUT:
+ aidl.output.push_back(
+ VALUE_OR_RETURN(legacy2aidl_audio_output_flags_mask(legacy.output)));
+ break;
+ }
+ return aidl;
+}
+
+ConversionResult<audio_port_config_device_ext> aidl2legacy_AudioPortConfigDeviceExt(
+ const media::AudioPortConfigDeviceExt& aidl) {
+ audio_port_config_device_ext legacy;
+ legacy.hw_module = VALUE_OR_RETURN(convertReinterpret<audio_module_handle_t>(aidl.hwModule));
+ legacy.type = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_devices_t(aidl.type));
+ if (aidl.address.size() > AUDIO_DEVICE_MAX_ADDRESS_LEN - 1) {
+ return unexpected(BAD_VALUE);
+ }
+ std::strcpy(legacy.address, aidl.address.c_str());
+ return legacy;
+}
+
+ConversionResult<media::AudioPortConfigDeviceExt> legacy2aidl_AudioPortConfigDeviceExt(
+ const audio_port_config_device_ext& legacy) {
+ media::AudioPortConfigDeviceExt aidl;
+ aidl.hwModule = VALUE_OR_RETURN(convertReinterpret<int32_t>(legacy.hw_module));
+ aidl.type = VALUE_OR_RETURN(legacy2aidl_audio_devices_t_int32_t(legacy.type));
+
+ if (strnlen(legacy.address, AUDIO_DEVICE_MAX_ADDRESS_LEN) == AUDIO_DEVICE_MAX_ADDRESS_LEN) {
+ // No null-terminator.
+ return unexpected(BAD_VALUE);
+ }
+ aidl.address = legacy.address;
+ return aidl;
+}
+
+ConversionResult<audio_stream_type_t> aidl2legacy_AudioStreamType_audio_stream_type_t(
+ media::AudioStreamType aidl) {
+ switch (aidl) {
+ case media::AudioStreamType::DEFAULT:
+ return AUDIO_STREAM_DEFAULT;
+ case media::AudioStreamType::VOICE_CALL:
+ return AUDIO_STREAM_VOICE_CALL;
+ case media::AudioStreamType::SYSTEM:
+ return AUDIO_STREAM_SYSTEM;
+ case media::AudioStreamType::RING:
+ return AUDIO_STREAM_RING;
+ case media::AudioStreamType::MUSIC:
+ return AUDIO_STREAM_MUSIC;
+ case media::AudioStreamType::ALARM:
+ return AUDIO_STREAM_ALARM;
+ case media::AudioStreamType::NOTIFICATION:
+ return AUDIO_STREAM_NOTIFICATION;
+ case media::AudioStreamType::BLUETOOTH_SCO:
+ return AUDIO_STREAM_BLUETOOTH_SCO;
+ case media::AudioStreamType::ENFORCED_AUDIBLE:
+ return AUDIO_STREAM_ENFORCED_AUDIBLE;
+ case media::AudioStreamType::DTMF:
+ return AUDIO_STREAM_DTMF;
+ case media::AudioStreamType::TTS:
+ return AUDIO_STREAM_TTS;
+ case media::AudioStreamType::ACCESSIBILITY:
+ return AUDIO_STREAM_ACCESSIBILITY;
+ case media::AudioStreamType::ASSISTANT:
+ return AUDIO_STREAM_ASSISTANT;
+ case media::AudioStreamType::REROUTING:
+ return AUDIO_STREAM_REROUTING;
+ case media::AudioStreamType::PATCH:
+ return AUDIO_STREAM_PATCH;
+ case media::AudioStreamType::CALL_ASSISTANT:
+ return AUDIO_STREAM_CALL_ASSISTANT;
+ default:
+ return unexpected(BAD_VALUE);
+ }
+}
+
+ConversionResult<media::AudioStreamType> legacy2aidl_audio_stream_type_t_AudioStreamType(
+ audio_stream_type_t legacy) {
+ switch (legacy) {
+ case AUDIO_STREAM_DEFAULT:
+ return media::AudioStreamType::DEFAULT;
+ case AUDIO_STREAM_VOICE_CALL:
+ return media::AudioStreamType::VOICE_CALL;
+ case AUDIO_STREAM_SYSTEM:
+ return media::AudioStreamType::SYSTEM;
+ case AUDIO_STREAM_RING:
+ return media::AudioStreamType::RING;
+ case AUDIO_STREAM_MUSIC:
+ return media::AudioStreamType::MUSIC;
+ case AUDIO_STREAM_ALARM:
+ return media::AudioStreamType::ALARM;
+ case AUDIO_STREAM_NOTIFICATION:
+ return media::AudioStreamType::NOTIFICATION;
+ case AUDIO_STREAM_BLUETOOTH_SCO:
+ return media::AudioStreamType::BLUETOOTH_SCO;
+ case AUDIO_STREAM_ENFORCED_AUDIBLE:
+ return media::AudioStreamType::ENFORCED_AUDIBLE;
+ case AUDIO_STREAM_DTMF:
+ return media::AudioStreamType::DTMF;
+ case AUDIO_STREAM_TTS:
+ return media::AudioStreamType::TTS;
+ case AUDIO_STREAM_ACCESSIBILITY:
+ return media::AudioStreamType::ACCESSIBILITY;
+ case AUDIO_STREAM_ASSISTANT:
+ return media::AudioStreamType::ASSISTANT;
+ case AUDIO_STREAM_REROUTING:
+ return media::AudioStreamType::REROUTING;
+ case AUDIO_STREAM_PATCH:
+ return media::AudioStreamType::PATCH;
+ case AUDIO_STREAM_CALL_ASSISTANT:
+ return media::AudioStreamType::CALL_ASSISTANT;
+ default:
+ return unexpected(BAD_VALUE);
+ }
+}
+
+ConversionResult<audio_source_t> aidl2legacy_AudioSourceType_audio_source_t(
+ media::AudioSourceType aidl) {
+ switch (aidl) {
+ case media::AudioSourceType::DEFAULT:
+ return AUDIO_SOURCE_DEFAULT;
+ case media::AudioSourceType::MIC:
+ return AUDIO_SOURCE_MIC;
+ case media::AudioSourceType::VOICE_UPLINK:
+ return AUDIO_SOURCE_VOICE_UPLINK;
+ case media::AudioSourceType::VOICE_DOWNLINK:
+ return AUDIO_SOURCE_VOICE_DOWNLINK;
+ case media::AudioSourceType::VOICE_CALL:
+ return AUDIO_SOURCE_VOICE_CALL;
+ case media::AudioSourceType::CAMCORDER:
+ return AUDIO_SOURCE_CAMCORDER;
+ case media::AudioSourceType::VOICE_RECOGNITION:
+ return AUDIO_SOURCE_VOICE_RECOGNITION;
+ case media::AudioSourceType::VOICE_COMMUNICATION:
+ return AUDIO_SOURCE_VOICE_COMMUNICATION;
+ case media::AudioSourceType::REMOTE_SUBMIX:
+ return AUDIO_SOURCE_REMOTE_SUBMIX;
+ case media::AudioSourceType::UNPROCESSED:
+ return AUDIO_SOURCE_UNPROCESSED;
+ case media::AudioSourceType::VOICE_PERFORMANCE:
+ return AUDIO_SOURCE_VOICE_PERFORMANCE;
+ case media::AudioSourceType::ECHO_REFERENCE:
+ return AUDIO_SOURCE_ECHO_REFERENCE;
+ case media::AudioSourceType::FM_TUNER:
+ return AUDIO_SOURCE_FM_TUNER;
+ case media::AudioSourceType::HOTWORD:
+ return AUDIO_SOURCE_HOTWORD;
+ default:
+ return unexpected(BAD_VALUE);
+ }
+}
+
+ConversionResult<media::AudioSourceType> legacy2aidl_audio_source_t_AudioSourceType(
+ audio_source_t legacy) {
+ switch (legacy) {
+ case AUDIO_SOURCE_DEFAULT:
+ return media::AudioSourceType::DEFAULT;
+ case AUDIO_SOURCE_MIC:
+ return media::AudioSourceType::MIC;
+ case AUDIO_SOURCE_VOICE_UPLINK:
+ return media::AudioSourceType::VOICE_UPLINK;
+ case AUDIO_SOURCE_VOICE_DOWNLINK:
+ return media::AudioSourceType::VOICE_DOWNLINK;
+ case AUDIO_SOURCE_VOICE_CALL:
+ return media::AudioSourceType::VOICE_CALL;
+ case AUDIO_SOURCE_CAMCORDER:
+ return media::AudioSourceType::CAMCORDER;
+ case AUDIO_SOURCE_VOICE_RECOGNITION:
+ return media::AudioSourceType::VOICE_RECOGNITION;
+ case AUDIO_SOURCE_VOICE_COMMUNICATION:
+ return media::AudioSourceType::VOICE_COMMUNICATION;
+ case AUDIO_SOURCE_REMOTE_SUBMIX:
+ return media::AudioSourceType::REMOTE_SUBMIX;
+ case AUDIO_SOURCE_UNPROCESSED:
+ return media::AudioSourceType::UNPROCESSED;
+ case AUDIO_SOURCE_VOICE_PERFORMANCE:
+ return media::AudioSourceType::VOICE_PERFORMANCE;
+ case AUDIO_SOURCE_ECHO_REFERENCE:
+ return media::AudioSourceType::ECHO_REFERENCE;
+ case AUDIO_SOURCE_FM_TUNER:
+ return media::AudioSourceType::FM_TUNER;
+ case AUDIO_SOURCE_HOTWORD:
+ return media::AudioSourceType::HOTWORD;
+ default:
+ return unexpected(BAD_VALUE);
+ }
+}
+
+ConversionResult<audio_session_t> aidl2legacy_AudioSessionType_audio_session_t(
+ media::AudioSessionType aidl) {
+ switch (aidl) {
+ case media::AudioSessionType::DEVICE:
+ return AUDIO_SESSION_DEVICE;
+ case media::AudioSessionType::OUTPUT_STAGE:
+ return AUDIO_SESSION_OUTPUT_STAGE;
+ case media::AudioSessionType::OUTPUT_MIX:
+ return AUDIO_SESSION_OUTPUT_MIX;
+ default:
+ return unexpected(BAD_VALUE);
+ }
+}
+
+ConversionResult<media::AudioSessionType> legacy2aidl_audio_session_t_AudioSessionType(
+ audio_session_t legacy) {
+ switch (legacy) {
+ case AUDIO_SESSION_DEVICE:
+ return media::AudioSessionType::DEVICE;
+ case AUDIO_SESSION_OUTPUT_STAGE:
+ return media::AudioSessionType::OUTPUT_STAGE;
+ case AUDIO_SESSION_OUTPUT_MIX:
+ return media::AudioSessionType::OUTPUT_MIX;
+ default:
+ return unexpected(BAD_VALUE);
+ }
+}
+
+// This type is unnamed in the original definition, thus we name it here.
+using audio_port_config_mix_ext_usecase = decltype(audio_port_config_mix_ext::usecase);
+
+ConversionResult<audio_port_config_mix_ext_usecase> aidl2legacy_AudioPortConfigMixExtUseCase(
+ const media::AudioPortConfigMixExtUseCase& aidl, media::AudioPortRole role) {
+ audio_port_config_mix_ext_usecase legacy;
+
+ // Our way of representing a union in AIDL is to have multiple vectors and require that exactly
+ // one of the them has size 1 and the rest are empty.
+ size_t totalSize = aidl.stream.size() + aidl.source.size();
+ if (totalSize > 1) {
+ return unexpected(BAD_VALUE);
+ }
+
+ switch (role) {
+ case media::AudioPortRole::NONE:
+ if (totalSize != 0) {
+ return unexpected(BAD_VALUE);
+ }
+ break;
+
+ case media::AudioPortRole::SOURCE:
+ // This is not a bug. A SOURCE role corresponds to the stream field.
+ if (aidl.stream.empty()) {
+ return unexpected(BAD_VALUE);
+ }
+ legacy.stream = VALUE_OR_RETURN(
+ aidl2legacy_AudioStreamType_audio_stream_type_t(aidl.stream[0]));
+ break;
+
+ case media::AudioPortRole::SINK:
+ // This is not a bug. A SINK role corresponds to the source field.
+ if (aidl.source.empty()) {
+ return unexpected(BAD_VALUE);
+ }
+ legacy.source =
+ VALUE_OR_RETURN(aidl2legacy_AudioSourceType_audio_source_t(aidl.source[0]));
+ break;
+
+ default:
+ LOG_ALWAYS_FATAL("Shouldn't get here");
+ }
+ return legacy;
+}
+
+ConversionResult<media::AudioPortConfigMixExtUseCase> legacy2aidl_AudioPortConfigMixExtUseCase(
+ const audio_port_config_mix_ext_usecase& legacy, audio_port_role_t role) {
+ media::AudioPortConfigMixExtUseCase aidl;
+
+ switch (role) {
+ case AUDIO_PORT_ROLE_NONE:
+ break;
+ case AUDIO_PORT_ROLE_SOURCE:
+ // This is not a bug. A SOURCE role corresponds to the stream field.
+ aidl.stream.push_back(VALUE_OR_RETURN(
+ legacy2aidl_audio_stream_type_t_AudioStreamType(
+ legacy.stream)));
+ break;
+ case AUDIO_PORT_ROLE_SINK:
+ // This is not a bug. A SINK role corresponds to the source field.
+ aidl.source.push_back(
+ VALUE_OR_RETURN(legacy2aidl_audio_source_t_AudioSourceType(legacy.source)));
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Shouldn't get here");
+ }
+ return aidl;
+}
+
+ConversionResult<audio_port_config_mix_ext> aidl2legacy_AudioPortConfigMixExt(
+ const media::AudioPortConfigMixExt& aidl, media::AudioPortRole role) {
+ audio_port_config_mix_ext legacy;
+ legacy.hw_module = VALUE_OR_RETURN(convertReinterpret<audio_module_handle_t>(aidl.hwModule));
+ legacy.handle = VALUE_OR_RETURN(convertReinterpret<audio_io_handle_t>(aidl.handle));
+ legacy.usecase = VALUE_OR_RETURN(aidl2legacy_AudioPortConfigMixExtUseCase(aidl.usecase, role));
+ return legacy;
+}
+
+ConversionResult<media::AudioPortConfigMixExt> legacy2aidl_AudioPortConfigMixExt(
+ const audio_port_config_mix_ext& legacy, audio_port_role_t role) {
+ media::AudioPortConfigMixExt aidl;
+ aidl.hwModule = VALUE_OR_RETURN(convertReinterpret<int32_t>(legacy.hw_module));
+ aidl.handle = VALUE_OR_RETURN(convertReinterpret<int32_t>(legacy.handle));
+ aidl.usecase = VALUE_OR_RETURN(legacy2aidl_AudioPortConfigMixExtUseCase(legacy.usecase, role));
+ return aidl;
+}
+
+ConversionResult<audio_port_config_session_ext> aidl2legacy_AudioPortConfigSessionExt(
+ const media::AudioPortConfigSessionExt& aidl) {
+ audio_port_config_session_ext legacy;
+ legacy.session = VALUE_OR_RETURN(aidl2legacy_AudioSessionType_audio_session_t(aidl.session));
+ return legacy;
+}
+
+ConversionResult<media::AudioPortConfigSessionExt> legacy2aidl_AudioPortConfigSessionExt(
+ const audio_port_config_session_ext& legacy) {
+ media::AudioPortConfigSessionExt aidl;
+ aidl.session = VALUE_OR_RETURN(legacy2aidl_audio_session_t_AudioSessionType(legacy.session));
+ return aidl;
+}
+
+// This type is unnamed in the original definition, thus we name it here.
+using audio_port_config_ext = decltype(audio_port_config::ext);
+
+ConversionResult<audio_port_config_ext> aidl2legacy_AudioPortConfigExt(
+ const media::AudioPortConfigExt& aidl, media::AudioPortType type,
+ media::AudioPortRole role) {
+ audio_port_config_ext legacy;
+ // Our way of representing a union in AIDL is to have multiple vectors and require that at most
+ // one of the them has size 1 and the rest are empty.
+ size_t totalSize = aidl.device.size() + aidl.mix.size() + aidl.session.size();
+ if (totalSize > 1) {
+ return unexpected(BAD_VALUE);
+ }
+ switch (type) {
+ case media::AudioPortType::NONE:
+ if (totalSize != 0) {
+ return unexpected(BAD_VALUE);
+ }
+ break;
+ case media::AudioPortType::DEVICE:
+ if (aidl.device.empty()) {
+ return unexpected(BAD_VALUE);
+ }
+ legacy.device = VALUE_OR_RETURN(aidl2legacy_AudioPortConfigDeviceExt(aidl.device[0]));
+ break;
+ case media::AudioPortType::MIX:
+ if (aidl.mix.empty()) {
+ return unexpected(BAD_VALUE);
+ }
+ legacy.mix = VALUE_OR_RETURN(aidl2legacy_AudioPortConfigMixExt(aidl.mix[0], role));
+ break;
+ case media::AudioPortType::SESSION:
+ if (aidl.session.empty()) {
+ return unexpected(BAD_VALUE);
+ }
+ legacy.session =
+ VALUE_OR_RETURN(aidl2legacy_AudioPortConfigSessionExt(aidl.session[0]));
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Shouldn't get here");
+ }
+ return legacy;
+}
+
+ConversionResult<media::AudioPortConfigExt> legacy2aidl_AudioPortConfigExt(
+ const audio_port_config_ext& legacy, audio_port_type_t type, audio_port_role_t role) {
+ media::AudioPortConfigExt aidl;
+
+ switch (type) {
+ case AUDIO_PORT_TYPE_NONE:
+ break;
+ case AUDIO_PORT_TYPE_DEVICE:
+ aidl.device.push_back(
+ VALUE_OR_RETURN(legacy2aidl_AudioPortConfigDeviceExt(legacy.device)));
+ break;
+ case AUDIO_PORT_TYPE_MIX:
+ aidl.mix.push_back(
+ VALUE_OR_RETURN(legacy2aidl_AudioPortConfigMixExt(legacy.mix, role)));
+ break;
+ case AUDIO_PORT_TYPE_SESSION:
+ aidl.session.push_back(
+ VALUE_OR_RETURN(legacy2aidl_AudioPortConfigSessionExt(legacy.session)));
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Shouldn't get here");
+ }
+ return aidl;
+}
+
+ConversionResult<audio_port_config> aidl2legacy_AudioPortConfig_audio_port_config(
+ const media::AudioPortConfig& aidl) {
+ audio_port_config legacy;
+ legacy.id = VALUE_OR_RETURN(convertReinterpret<audio_port_handle_t>(aidl.id));
+ legacy.role = VALUE_OR_RETURN(aidl2legacy_AudioPortRole_audio_port_role_t(aidl.role));
+ legacy.type = VALUE_OR_RETURN(aidl2legacy_AudioPortType_audio_port_type_t(aidl.type));
+ legacy.config_mask = VALUE_OR_RETURN(aidl2legacy_int32_t_config_mask(aidl.configMask));
+ if (bitmaskIsSet(aidl.configMask, media::AudioPortConfigType::SAMPLE_RATE)) {
+ legacy.sample_rate = VALUE_OR_RETURN(convertIntegral<unsigned int>(aidl.sampleRate));
+ }
+ if (bitmaskIsSet(aidl.configMask, media::AudioPortConfigType::CHANNEL_MASK)) {
+ legacy.channel_mask =
+ VALUE_OR_RETURN(aidl2legacy_int32_t_audio_channel_mask_t(aidl.channelMask));
+ }
+ if (bitmaskIsSet(aidl.configMask, media::AudioPortConfigType::FORMAT)) {
+ legacy.format = VALUE_OR_RETURN(aidl2legacy_AudioFormat_audio_format_t(aidl.format));
+ }
+ if (bitmaskIsSet(aidl.configMask, media::AudioPortConfigType::GAIN)) {
+ legacy.gain = VALUE_OR_RETURN(
+ aidl2legacy_AudioGainConfig_audio_gain_config(aidl.gain, aidl.role, aidl.type));
+ }
+ if (bitmaskIsSet(aidl.configMask, media::AudioPortConfigType::FLAGS)) {
+ legacy.flags = VALUE_OR_RETURN(
+ aidl2legacy_AudioIoFlags_audio_io_flags(aidl.flags, aidl.role, aidl.type));
+ }
+ legacy.ext = VALUE_OR_RETURN(aidl2legacy_AudioPortConfigExt(aidl.ext, aidl.type, aidl.role));
+ return legacy;
+}
+
+ConversionResult<media::AudioPortConfig> legacy2aidl_audio_port_config_AudioPortConfig(
+ const audio_port_config& legacy) {
+ media::AudioPortConfig aidl;
+ aidl.id = VALUE_OR_RETURN(convertReinterpret<audio_port_handle_t>(legacy.id));
+ aidl.role = VALUE_OR_RETURN(legacy2aidl_audio_port_role_t_AudioPortRole(legacy.role));
+ aidl.type = VALUE_OR_RETURN(legacy2aidl_audio_port_type_t_AudioPortType(legacy.type));
+ aidl.configMask = VALUE_OR_RETURN(legacy2aidl_config_mask_int32_t(legacy.config_mask));
+ if (legacy.config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
+ aidl.sampleRate = VALUE_OR_RETURN(convertIntegral<int32_t>(legacy.sample_rate));
+ }
+ if (legacy.config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
+ aidl.channelMask =
+ VALUE_OR_RETURN(legacy2aidl_audio_channel_mask_t_int32_t(legacy.channel_mask));
+ }
+ if (legacy.config_mask & AUDIO_PORT_CONFIG_FORMAT) {
+ aidl.format = VALUE_OR_RETURN(legacy2aidl_audio_format_t_AudioFormat(legacy.format));
+ }
+ if (legacy.config_mask & AUDIO_PORT_CONFIG_GAIN) {
+ aidl.gain = VALUE_OR_RETURN(legacy2aidl_audio_gain_config_AudioGainConfig(
+ legacy.gain, legacy.role, legacy.type));
+ }
+ if (legacy.config_mask & AUDIO_PORT_CONFIG_FLAGS) {
+ aidl.flags = VALUE_OR_RETURN(
+ legacy2aidl_audio_io_flags_AudioIoFlags(legacy.flags, legacy.role, legacy.type));
+ }
+ aidl.ext =
+ VALUE_OR_RETURN(legacy2aidl_AudioPortConfigExt(legacy.ext, legacy.type, legacy.role));
+ return aidl;
+}
+
+ConversionResult<struct audio_patch> aidl2legacy_AudioPatch_audio_patch(
+ const media::AudioPatch& aidl) {
+ struct audio_patch legacy;
+ legacy.id = VALUE_OR_RETURN(convertReinterpret<audio_patch_handle_t>(aidl.id));
+ legacy.num_sinks = VALUE_OR_RETURN(convertIntegral<unsigned int>(aidl.sinks.size()));
+ if (legacy.num_sinks > AUDIO_PATCH_PORTS_MAX) {
+ return unexpected(BAD_VALUE);
+ }
+ for (size_t i = 0; i < legacy.num_sinks; ++i) {
+ legacy.sinks[i] =
+ VALUE_OR_RETURN(aidl2legacy_AudioPortConfig_audio_port_config(aidl.sinks[i]));
+ }
+ legacy.num_sources = VALUE_OR_RETURN(convertIntegral<unsigned int>(aidl.sources.size()));
+ if (legacy.num_sources > AUDIO_PATCH_PORTS_MAX) {
+ return unexpected(BAD_VALUE);
+ }
+ for (size_t i = 0; i < legacy.num_sources; ++i) {
+ legacy.sources[i] =
+ VALUE_OR_RETURN(aidl2legacy_AudioPortConfig_audio_port_config(aidl.sources[i]));
+ }
+ return legacy;
+}
+
+ConversionResult<media::AudioPatch> legacy2aidl_audio_patch_AudioPatch(
+ const struct audio_patch& legacy) {
+ media::AudioPatch aidl;
+ aidl.id = VALUE_OR_RETURN(convertReinterpret<int32_t>(legacy.id));
+
+ if (legacy.num_sinks > AUDIO_PATCH_PORTS_MAX) {
+ return unexpected(BAD_VALUE);
+ }
+ for (unsigned int i = 0; i < legacy.num_sinks; ++i) {
+ aidl.sinks.push_back(
+ VALUE_OR_RETURN(legacy2aidl_audio_port_config_AudioPortConfig(legacy.sinks[i])));
+ }
+ if (legacy.num_sources > AUDIO_PATCH_PORTS_MAX) {
+ return unexpected(BAD_VALUE);
+ }
+ for (unsigned int i = 0; i < legacy.num_sources; ++i) {
+ aidl.sources.push_back(
+ VALUE_OR_RETURN(legacy2aidl_audio_port_config_AudioPortConfig(legacy.sources[i])));
+ }
+ return aidl;
+}
+
+ConversionResult<sp<AudioIoDescriptor>> aidl2legacy_AudioIoDescriptor_AudioIoDescriptor(
+ const media::AudioIoDescriptor& aidl) {
+ sp<AudioIoDescriptor> legacy(new AudioIoDescriptor());
+ legacy->mIoHandle = VALUE_OR_RETURN(convertReinterpret<audio_io_handle_t>(aidl.ioHandle));
+ legacy->mPatch = VALUE_OR_RETURN(aidl2legacy_AudioPatch_audio_patch(aidl.patch));
+ legacy->mSamplingRate = VALUE_OR_RETURN(convertIntegral<uint32_t>(aidl.samplingRate));
+ legacy->mFormat = VALUE_OR_RETURN(aidl2legacy_AudioFormat_audio_format_t(aidl.format));
+ legacy->mChannelMask =
+ VALUE_OR_RETURN(aidl2legacy_int32_t_audio_channel_mask_t(aidl.channelMask));
+ legacy->mFrameCount = VALUE_OR_RETURN(convertIntegral<size_t>(aidl.frameCount));
+ legacy->mFrameCountHAL = VALUE_OR_RETURN(convertIntegral<size_t>(aidl.frameCountHAL));
+ legacy->mLatency = VALUE_OR_RETURN(convertIntegral<uint32_t>(aidl.latency));
+ legacy->mPortId = VALUE_OR_RETURN(convertReinterpret<audio_port_handle_t>(aidl.portId));
+ return legacy;
+}
+
+ConversionResult<media::AudioIoDescriptor> legacy2aidl_AudioIoDescriptor_AudioIoDescriptor(
+ const sp<AudioIoDescriptor>& legacy) {
+ media::AudioIoDescriptor aidl;
+ aidl.ioHandle = VALUE_OR_RETURN(convertReinterpret<int32_t>(legacy->mIoHandle));
+ aidl.patch = VALUE_OR_RETURN(legacy2aidl_audio_patch_AudioPatch(legacy->mPatch));
+ aidl.samplingRate = VALUE_OR_RETURN(convertIntegral<int32_t>(legacy->mSamplingRate));
+ aidl.format = VALUE_OR_RETURN(legacy2aidl_audio_format_t_AudioFormat(legacy->mFormat));
+ aidl.channelMask = VALUE_OR_RETURN(convertReinterpret<int32_t>(legacy->mChannelMask));
+ aidl.frameCount = VALUE_OR_RETURN(convertIntegral<int64_t>(legacy->mFrameCount));
+ aidl.frameCountHAL = VALUE_OR_RETURN(convertIntegral<int64_t>(legacy->mFrameCountHAL));
+ aidl.latency = VALUE_OR_RETURN(convertIntegral<int32_t>(legacy->mLatency));
+ aidl.portId = VALUE_OR_RETURN(convertReinterpret<int32_t>(legacy->mPortId));
+ return aidl;
+}
+
+} // namespace android
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index d7e9461..fef0ca9 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -2,6 +2,7 @@
name: "libaudioclient_headers",
vendor_available: true,
min_sdk_version: "29",
+ host_supported: true,
header_libs: [
"libaudiofoundation_headers",
@@ -12,7 +13,12 @@
export_header_lib_headers: [
"libaudiofoundation_headers",
],
- host_supported: true,
+ static_libs: [
+ "audioflinger-aidl-unstable-cpp",
+ ],
+ export_static_lib_headers: [
+ "audioflinger-aidl-unstable-cpp",
+ ],
target: {
darwin: {
enabled: false,
@@ -29,6 +35,7 @@
"AudioVolumeGroup.cpp",
],
shared_libs: [
+ "audioflinger-aidl-unstable-cpp",
"capture_state_listener-aidl-cpp",
"libaudiofoundation",
"libaudioutils",
@@ -44,6 +51,7 @@
include_dirs: ["system/media/audio_utils/include"],
export_include_dirs: ["include"],
export_shared_lib_headers: [
+ "audioflinger-aidl-unstable-cpp",
"capture_state_listener-aidl-cpp",
],
}
@@ -73,7 +81,6 @@
"AudioTrack.cpp",
"AudioTrackShared.cpp",
"IAudioFlinger.cpp",
- "IAudioFlingerClient.cpp",
"IAudioPolicyService.cpp",
"IAudioPolicyServiceClient.cpp",
"IAudioTrack.cpp",
@@ -83,7 +90,9 @@
"TrackPlayerBase.cpp",
],
shared_libs: [
+ "audioflinger-aidl-unstable-cpp",
"capture_state_listener-aidl-cpp",
+ "libaudioclient_aidl_conversion",
"libaudiofoundation",
"libaudioutils",
"libaudiopolicy",
@@ -101,7 +110,10 @@
"libutils",
"libvibrator",
],
- export_shared_lib_headers: ["libbinder"],
+ export_shared_lib_headers: [
+ "audioflinger-aidl-unstable-cpp",
+ "libbinder",
+ ],
include_dirs: [
"frameworks/av/media/libnbaio/include_mono/",
@@ -140,6 +152,32 @@
},
}
+cc_library_shared {
+ name: "libaudioclient_aidl_conversion",
+ srcs: ["AidlConversion.cpp"],
+ local_include_dirs: ["include"],
+ shared_libs: [
+ "audioclient-types-aidl-unstable-cpp",
+ "libbase",
+ "liblog",
+ "libutils",
+ ],
+ export_shared_lib_headers: [
+ "audioclient-types-aidl-unstable-cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-error=deprecated-declarations",
+ ],
+ sanitize: {
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ },
+}
+
// AIDL interface between libaudioclient and framework.jar
filegroup {
name: "libaudioclient_aidl",
@@ -189,3 +227,61 @@
"shared-file-region-aidl",
],
}
+
+aidl_interface {
+ name: "audioclient-types-aidl",
+ unstable: true,
+ host_supported: true,
+ vendor_available: true,
+ double_loadable: true,
+ local_include_dir: "aidl",
+ srcs: [
+ "aidl/android/media/AudioGainConfig.aidl",
+ "aidl/android/media/AudioGainMode.aidl",
+ "aidl/android/media/AudioInputFlags.aidl",
+ "aidl/android/media/AudioIoConfigEvent.aidl",
+ "aidl/android/media/AudioIoDescriptor.aidl",
+ "aidl/android/media/AudioIoFlags.aidl",
+ "aidl/android/media/AudioOutputFlags.aidl",
+ "aidl/android/media/AudioPatch.aidl",
+ "aidl/android/media/AudioPortConfig.aidl",
+ "aidl/android/media/AudioPortConfigType.aidl",
+ "aidl/android/media/AudioPortConfigDeviceExt.aidl",
+ "aidl/android/media/AudioPortConfigExt.aidl",
+ "aidl/android/media/AudioPortConfigMixExt.aidl",
+ "aidl/android/media/AudioPortConfigMixExtUseCase.aidl",
+ "aidl/android/media/AudioPortConfigSessionExt.aidl",
+ "aidl/android/media/AudioPortRole.aidl",
+ "aidl/android/media/AudioPortType.aidl",
+ "aidl/android/media/AudioSessionType.aidl",
+ "aidl/android/media/AudioSourceType.aidl",
+ "aidl/android/media/AudioStreamType.aidl",
+ ],
+ imports: [
+ "audio_common-aidl",
+ ],
+}
+
+aidl_interface {
+ name: "audioflinger-aidl",
+ unstable: true,
+ local_include_dir: "aidl",
+ host_supported: true,
+ vendor_available: true,
+ srcs: [
+ "aidl/android/media/IAudioFlingerClient.aidl",
+ ],
+ imports: [
+ "audioclient-types-aidl",
+ ],
+ double_loadable: true,
+ backend: {
+ cpp: {
+ min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media",
+ ],
+ },
+ },
+}
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index edb0889..0507879 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -23,6 +23,7 @@
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <binder/IPCThreadState.h>
+#include <media/AidlConversion.h>
#include <media/AudioResamplerPublic.h>
#include <media/AudioSystem.h>
#include <media/IAudioFlinger.h>
@@ -32,10 +33,17 @@
#include <system/audio.h>
+#define VALUE_OR_RETURN(x) \
+ ({ auto _tmp = (x); \
+ if (!_tmp.ok()) return Status::fromStatusT(_tmp.error()); \
+ _tmp.value(); })
+
// ----------------------------------------------------------------------------
namespace android {
+using binder::Status;
+
// client singleton for AudioFlinger binder interface
Mutex AudioSystem::gLock;
Mutex AudioSystem::gLockErrorCallbacks;
@@ -521,11 +529,17 @@
ALOGW("AudioFlinger server died!");
}
-void AudioSystem::AudioFlingerClient::ioConfigChanged(audio_io_config_event event,
- const sp<AudioIoDescriptor>& ioDesc) {
+Status AudioSystem::AudioFlingerClient::ioConfigChanged(
+ media::AudioIoConfigEvent _event,
+ const media::AudioIoDescriptor& _ioDesc) {
+ audio_io_config_event event = VALUE_OR_RETURN(
+ aidl2legacy_AudioIoConfigEvent_audio_io_config_event(_event));
+ sp<AudioIoDescriptor> ioDesc(
+ VALUE_OR_RETURN(aidl2legacy_AudioIoDescriptor_AudioIoDescriptor(_ioDesc)));
+
ALOGV("ioConfigChanged() event %d", event);
- if (ioDesc == 0 || ioDesc->mIoHandle == AUDIO_IO_HANDLE_NONE) return;
+ if (ioDesc->mIoHandle == AUDIO_IO_HANDLE_NONE) return Status::ok();
audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE;
std::vector<sp<AudioDeviceCallback>> callbacksToCall;
@@ -640,6 +654,8 @@
// If callbacksToCall is not empty, it implies ioDesc->mIoHandle and deviceId are valid
cb->onAudioDeviceUpdate(ioDesc->mIoHandle, deviceId);
}
+
+ return Status::ok();
}
status_t AudioSystem::AudioFlingerClient::getInputBufferSize(
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 7c304a1..d86182e 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -373,7 +373,7 @@
return reply.readString8();
}
- virtual void registerClient(const sp<IAudioFlingerClient>& client)
+ virtual void registerClient(const sp<media::IAudioFlingerClient>& client)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
@@ -1213,7 +1213,7 @@
case REGISTER_CLIENT: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient>(
+ sp<media::IAudioFlingerClient> client = interface_cast<media::IAudioFlingerClient>(
data.readStrongBinder());
registerClient(client);
return NO_ERROR;
diff --git a/media/libaudioclient/IAudioFlingerClient.cpp b/media/libaudioclient/IAudioFlingerClient.cpp
deleted file mode 100644
index 47eb7dc..0000000
--- a/media/libaudioclient/IAudioFlingerClient.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2009 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 "IAudioFlingerClient"
-#include <utils/Log.h>
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <binder/Parcel.h>
-
-#include <media/IAudioFlingerClient.h>
-#include <media/AudioSystem.h>
-
-namespace android {
-
-enum {
- IO_CONFIG_CHANGED = IBinder::FIRST_CALL_TRANSACTION
-};
-
-class BpAudioFlingerClient : public BpInterface<IAudioFlingerClient>
-{
-public:
- explicit BpAudioFlingerClient(const sp<IBinder>& impl)
- : BpInterface<IAudioFlingerClient>(impl)
- {
- }
-
- void ioConfigChanged(audio_io_config_event event, const sp<AudioIoDescriptor>& ioDesc)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IAudioFlingerClient::getInterfaceDescriptor());
- data.writeInt32(event);
- data.writeInt32((int32_t)ioDesc->mIoHandle);
- data.write(&ioDesc->mPatch, sizeof(struct audio_patch));
- data.writeInt32(ioDesc->mSamplingRate);
- data.writeInt32(ioDesc->mFormat);
- data.writeInt32(ioDesc->mChannelMask);
- data.writeInt64(ioDesc->mFrameCount);
- data.writeInt64(ioDesc->mFrameCountHAL);
- data.writeInt32(ioDesc->mLatency);
- data.writeInt32(ioDesc->mPortId);
- remote()->transact(IO_CONFIG_CHANGED, data, &reply, IBinder::FLAG_ONEWAY);
- }
-};
-
-IMPLEMENT_META_INTERFACE(AudioFlingerClient, "android.media.IAudioFlingerClient");
-
-// ----------------------------------------------------------------------
-
-status_t BnAudioFlingerClient::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch (code) {
- case IO_CONFIG_CHANGED: {
- CHECK_INTERFACE(IAudioFlingerClient, data, reply);
- audio_io_config_event event = (audio_io_config_event)data.readInt32();
- sp<AudioIoDescriptor> ioDesc = new AudioIoDescriptor();
- ioDesc->mIoHandle = (audio_io_handle_t) data.readInt32();
- data.read(&ioDesc->mPatch, sizeof(struct audio_patch));
- ioDesc->mSamplingRate = data.readInt32();
- ioDesc->mFormat = (audio_format_t) data.readInt32();
- ioDesc->mChannelMask = (audio_channel_mask_t) data.readInt32();
- ioDesc->mFrameCount = data.readInt64();
- ioDesc->mFrameCountHAL = data.readInt64();
- ioDesc->mLatency = data.readInt32();
- ioDesc->mPortId = data.readInt32();
- ioConfigChanged(event, ioDesc);
- return NO_ERROR;
- } break;
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-// ----------------------------------------------------------------------------
-
-} // namespace android
diff --git a/media/libaudioclient/aidl/android/media/AudioGainConfig.aidl b/media/libaudioclient/aidl/android/media/AudioGainConfig.aidl
new file mode 100644
index 0000000..b93c2dc
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/AudioGainConfig.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package android.media;
+
+/**
+ * {@hide}
+ */
+parcelable AudioGainConfig {
+ /** Index of the corresponding audio_gain in the audio_port gains[] table. */
+ int index;
+
+ /** Mode requested for this command. Bitfield indexed by AudioGainMode. */
+ int mode;
+
+ /**
+ * Channels which gain value follows. N/A in joint mode.
+ * Interpreted as audio_channel_mask_t.
+ */
+ int channelMask;
+
+ /**
+ * Gain values in millibels.
+ * For each channel ordered from LSb to MSb in channel mask. The number of values is 1 in joint
+ * mode, otherwise equals the number of bits implied by channelMask.
+ */
+ int[] values;
+
+ /** Ramp duration in ms. */
+ int rampDurationMs;
+}
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl b/media/libaudioclient/aidl/android/media/AudioGainMode.aidl
similarity index 65%
copy from media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
copy to media/libaudioclient/aidl/android/media/AudioGainMode.aidl
index 1a5d81a..39395e5 100644
--- a/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioGainMode.aidl
@@ -13,25 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package android.media;
-/**
- * Priority of a transcoding job.
- *
- * {@hide}
- */
@Backing(type="int")
-enum TranscodingJobPriority {
- // TODO(hkuang): define what each priority level actually mean.
- kUnspecified = 0,
- kLow = 1,
- /**
- * 2 ~ 20 is reserved for future use.
- */
- kNormal = 21,
- /**
- * 22 ~ 30 is reserved for future use.
- */
- kHigh = 31,
-}
\ No newline at end of file
+enum AudioGainMode {
+ JOINT = 0,
+ CHANNELS = 1,
+ RAMP = 2,
+}
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl b/media/libaudioclient/aidl/android/media/AudioInputFlags.aidl
similarity index 65%
copy from media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
copy to media/libaudioclient/aidl/android/media/AudioInputFlags.aidl
index 1a5d81a..8f517e7 100644
--- a/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioInputFlags.aidl
@@ -13,25 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package android.media;
-/**
- * Priority of a transcoding job.
- *
- * {@hide}
- */
@Backing(type="int")
-enum TranscodingJobPriority {
- // TODO(hkuang): define what each priority level actually mean.
- kUnspecified = 0,
- kLow = 1,
- /**
- * 2 ~ 20 is reserved for future use.
- */
- kNormal = 21,
- /**
- * 22 ~ 30 is reserved for future use.
- */
- kHigh = 31,
-}
\ No newline at end of file
+enum AudioInputFlags {
+ FAST = 0,
+ HW_HOTWORD = 1,
+ RAW = 2,
+ SYNC = 3,
+ MMAP_NOIRQ = 4,
+ VOIP_TX = 5,
+ HW_AV_SYNC = 6,
+ DIRECT = 7,
+}
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl b/media/libaudioclient/aidl/android/media/AudioIoConfigEvent.aidl
similarity index 67%
copy from media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
copy to media/libaudioclient/aidl/android/media/AudioIoConfigEvent.aidl
index 1a5d81a..d5f23a1 100644
--- a/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioIoConfigEvent.aidl
@@ -17,21 +17,17 @@
package android.media;
/**
- * Priority of a transcoding job.
- *
* {@hide}
*/
@Backing(type="int")
-enum TranscodingJobPriority {
- // TODO(hkuang): define what each priority level actually mean.
- kUnspecified = 0,
- kLow = 1,
- /**
- * 2 ~ 20 is reserved for future use.
- */
- kNormal = 21,
- /**
- * 22 ~ 30 is reserved for future use.
- */
- kHigh = 31,
-}
\ No newline at end of file
+enum AudioIoConfigEvent {
+ OUTPUT_REGISTERED = 0,
+ OUTPUT_OPENED = 1,
+ OUTPUT_CLOSED = 2,
+ OUTPUT_CONFIG_CHANGED = 3,
+ INPUT_REGISTERED = 4,
+ INPUT_OPENED = 5,
+ INPUT_CLOSED = 6,
+ INPUT_CONFIG_CHANGED = 7,
+ CLIENT_STARTED = 8,
+}
diff --git a/media/libaudioclient/aidl/android/media/AudioIoDescriptor.aidl b/media/libaudioclient/aidl/android/media/AudioIoDescriptor.aidl
new file mode 100644
index 0000000..876ef9b
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/AudioIoDescriptor.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package android.media;
+
+import android.media.AudioPatch;
+import android.media.audio.common.AudioFormat;
+
+/**
+ * {@hide}
+ */
+parcelable AudioIoDescriptor {
+ /** Interpreted as audio_io_handle_t. */
+ int ioHandle;
+ AudioPatch patch;
+ int samplingRate;
+ AudioFormat format;
+ /** Interpreted as audio_channel_mask_t. */
+ int channelMask;
+ long frameCount;
+ long frameCountHAL;
+ /** Only valid for output. */
+ int latency;
+ /**
+ * Interpreted as audio_port_handle_t.
+ * valid for event AUDIO_CLIENT_STARTED.
+ */
+ int portId;
+}
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl b/media/libaudioclient/aidl/android/media/AudioIoFlags.aidl
similarity index 65%
copy from media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
copy to media/libaudioclient/aidl/android/media/AudioIoFlags.aidl
index 1a5d81a..1fe2acc 100644
--- a/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioIoFlags.aidl
@@ -17,21 +17,14 @@
package android.media;
/**
- * Priority of a transcoding job.
- *
* {@hide}
*/
-@Backing(type="int")
-enum TranscodingJobPriority {
- // TODO(hkuang): define what each priority level actually mean.
- kUnspecified = 0,
- kLow = 1,
- /**
- * 2 ~ 20 is reserved for future use.
- */
- kNormal = 21,
- /**
- * 22 ~ 30 is reserved for future use.
- */
- kHigh = 31,
-}
\ No newline at end of file
+// TODO(b/150948558): This should be a union. In the meantime, we require
+// that exactly one of the below arrays has a single element and the rest
+// are empty.
+parcelable AudioIoFlags {
+ /** Bitmask indexed by AudioInputFlags. */
+ int[] input;
+ /** Bitmask indexed by AudioOutputFlags. */
+ int[] output;
+}
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl b/media/libaudioclient/aidl/android/media/AudioOutputFlags.aidl
similarity index 60%
copy from media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
copy to media/libaudioclient/aidl/android/media/AudioOutputFlags.aidl
index 1a5d81a..aebf871 100644
--- a/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioOutputFlags.aidl
@@ -13,25 +13,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package android.media;
-/**
- * Priority of a transcoding job.
- *
- * {@hide}
- */
@Backing(type="int")
-enum TranscodingJobPriority {
- // TODO(hkuang): define what each priority level actually mean.
- kUnspecified = 0,
- kLow = 1,
- /**
- * 2 ~ 20 is reserved for future use.
- */
- kNormal = 21,
- /**
- * 22 ~ 30 is reserved for future use.
- */
- kHigh = 31,
-}
\ No newline at end of file
+enum AudioOutputFlags {
+ DIRECT = 0,
+ PRIMARY = 1,
+ FAST = 2,
+ DEEP_BUFFER = 3,
+ COMPRESS_OFFLOAD = 4,
+ NON_BLOCKING = 5,
+ HW_AV_SYNC = 6,
+ TTS = 7,
+ RAW = 8,
+ SYNC = 9,
+ IEC958_NONAUDIO = 10,
+ DIRECT_PCM = 11,
+ MMAP_NOIRQ = 12,
+ VOIP_RX = 13,
+ INCALL_MUSIC = 14,
+}
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl b/media/libaudioclient/aidl/android/media/AudioPatch.aidl
similarity index 67%
copy from media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
copy to media/libaudioclient/aidl/android/media/AudioPatch.aidl
index 1a5d81a..8519faf 100644
--- a/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioPatch.aidl
@@ -16,22 +16,17 @@
package android.media;
+import android.media.AudioPortConfig;
+
/**
- * Priority of a transcoding job.
- *
* {@hide}
*/
-@Backing(type="int")
-enum TranscodingJobPriority {
- // TODO(hkuang): define what each priority level actually mean.
- kUnspecified = 0,
- kLow = 1,
+parcelable AudioPatch {
/**
- * 2 ~ 20 is reserved for future use.
+ * Patch unique ID.
+ * Interpreted as audio_patch_handle_t.
*/
- kNormal = 21,
- /**
- * 22 ~ 30 is reserved for future use.
- */
- kHigh = 31,
-}
\ No newline at end of file
+ int id;
+ AudioPortConfig[] sources;
+ AudioPortConfig[] sinks;
+}
diff --git a/media/libaudioclient/aidl/android/media/AudioPortConfig.aidl b/media/libaudioclient/aidl/android/media/AudioPortConfig.aidl
new file mode 100644
index 0000000..2dd30a4
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/AudioPortConfig.aidl
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package android.media;
+
+import android.media.AudioGainConfig;
+import android.media.AudioIoFlags;
+import android.media.AudioPortConfigExt;
+import android.media.AudioPortConfigType;
+import android.media.AudioPortRole;
+import android.media.AudioPortType;
+import android.media.audio.common.AudioFormat;
+
+/**
+ * {@hide}
+ */
+parcelable AudioPortConfig {
+ /**
+ * Port unique ID.
+ * Interpreted as audio_port_handle_t.
+ */
+ int id;
+ /** Sink or source. */
+ AudioPortRole role;
+ /** Device, mix ... */
+ AudioPortType type;
+ /** Bitmask, indexed by AudioPortConfigType. */
+ int configMask;
+ /** Sampling rate in Hz. */
+ int sampleRate;
+ /**
+ * Channel mask, if applicable.
+ * Interpreted as audio_channel_mask_t.
+ * TODO: bitmask?
+ */
+ int channelMask;
+ /**
+ * Format, if applicable.
+ */
+ AudioFormat format;
+ /** Gain to apply, if applicable. */
+ AudioGainConfig gain;
+ /** Framework only: HW_AV_SYNC, DIRECT, ... */
+ AudioIoFlags flags;
+ AudioPortConfigExt ext;
+}
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl b/media/libaudioclient/aidl/android/media/AudioPortConfigDeviceExt.aidl
similarity index 64%
copy from media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
copy to media/libaudioclient/aidl/android/media/AudioPortConfigDeviceExt.aidl
index 1a5d81a..a99aa9b 100644
--- a/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioPortConfigDeviceExt.aidl
@@ -17,21 +17,20 @@
package android.media;
/**
- * Priority of a transcoding job.
- *
* {@hide}
*/
-@Backing(type="int")
-enum TranscodingJobPriority {
- // TODO(hkuang): define what each priority level actually mean.
- kUnspecified = 0,
- kLow = 1,
+parcelable AudioPortConfigDeviceExt {
/**
- * 2 ~ 20 is reserved for future use.
+ * Module the device is attached to.
+ * Interpreted as audio_module_handle_t.
*/
- kNormal = 21,
+ int hwModule;
/**
- * 22 ~ 30 is reserved for future use.
+ * Device type (e.g AUDIO_DEVICE_OUT_SPEAKER).
+ * Interpreted as audio_devices_t.
+ * TODO: Convert to a standalone AIDL representation.
*/
- kHigh = 31,
-}
\ No newline at end of file
+ int type;
+ /** Device address. "" if N/A. */
+ @utf8InCpp String address;
+}
diff --git a/media/libaudioclient/aidl/android/media/AudioPortConfigExt.aidl b/media/libaudioclient/aidl/android/media/AudioPortConfigExt.aidl
new file mode 100644
index 0000000..83e985e
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/AudioPortConfigExt.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package android.media;
+
+import android.media.AudioPortConfigDeviceExt;
+import android.media.AudioPortConfigMixExt;
+import android.media.AudioPortConfigSessionExt;
+
+/**
+ * {@hide}
+ */
+parcelable AudioPortConfigExt {
+ // TODO(b/150948558): This should be a union. In the meantime, we require
+ // that exactly one of the below arrays has a single element and the rest
+ // are empty.
+
+ /** Device specific info. */
+ AudioPortConfigDeviceExt[] device;
+ /** Mix specific info. */
+ AudioPortConfigMixExt[] mix;
+ /** Session specific info. */
+ AudioPortConfigSessionExt[] session;
+}
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl b/media/libaudioclient/aidl/android/media/AudioPortConfigMixExt.aidl
similarity index 66%
copy from media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
copy to media/libaudioclient/aidl/android/media/AudioPortConfigMixExt.aidl
index 1a5d81a..d3226f2 100644
--- a/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioPortConfigMixExt.aidl
@@ -16,22 +16,21 @@
package android.media;
+import android.media.AudioPortConfigMixExtUseCase;
+
/**
- * Priority of a transcoding job.
- *
* {@hide}
*/
-@Backing(type="int")
-enum TranscodingJobPriority {
- // TODO(hkuang): define what each priority level actually mean.
- kUnspecified = 0,
- kLow = 1,
+parcelable AudioPortConfigMixExt {
/**
- * 2 ~ 20 is reserved for future use.
+ * Module the stream is attached to.
+ * Interpreted as audio_module_handle_t.
*/
- kNormal = 21,
+ int hwModule;
/**
- * 22 ~ 30 is reserved for future use.
+ * I/O handle of the input/output stream.
+ * Interpreted as audio_io_handle_t.
*/
- kHigh = 31,
-}
\ No newline at end of file
+ int handle;
+ AudioPortConfigMixExtUseCase usecase;
+}
diff --git a/media/libaudioclient/aidl/android/media/AudioPortConfigMixExtUseCase.aidl b/media/libaudioclient/aidl/android/media/AudioPortConfigMixExtUseCase.aidl
new file mode 100644
index 0000000..675daf8
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/AudioPortConfigMixExtUseCase.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package android.media;
+
+import android.media.AudioSourceType;
+import android.media.AudioStreamType;
+
+/**
+ * {@hide}
+ */
+parcelable AudioPortConfigMixExtUseCase {
+ // TODO(b/150948558): This should be a union. In the meantime, we require
+ // that exactly one of the below arrays has a single element and the rest
+ // are empty.
+
+ /** This to be set if the containing config has the AudioPortRole::SOURCE role. */
+ AudioStreamType[] stream;
+ /** This to be set if the containing config has the AudioPortRole::SINK role. */
+ AudioSourceType[] source;
+}
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl b/media/libaudioclient/aidl/android/media/AudioPortConfigSessionExt.aidl
similarity index 65%
copy from media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
copy to media/libaudioclient/aidl/android/media/AudioPortConfigSessionExt.aidl
index 1a5d81a..d3261d9 100644
--- a/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioPortConfigSessionExt.aidl
@@ -16,22 +16,11 @@
package android.media;
+import android.media.AudioSessionType;
+
/**
- * Priority of a transcoding job.
- *
* {@hide}
*/
-@Backing(type="int")
-enum TranscodingJobPriority {
- // TODO(hkuang): define what each priority level actually mean.
- kUnspecified = 0,
- kLow = 1,
- /**
- * 2 ~ 20 is reserved for future use.
- */
- kNormal = 21,
- /**
- * 22 ~ 30 is reserved for future use.
- */
- kHigh = 31,
-}
\ No newline at end of file
+parcelable AudioPortConfigSessionExt {
+ AudioSessionType session;
+}
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl b/media/libaudioclient/aidl/android/media/AudioPortConfigType.aidl
similarity index 65%
copy from media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
copy to media/libaudioclient/aidl/android/media/AudioPortConfigType.aidl
index 1a5d81a..c7bb4d8 100644
--- a/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioPortConfigType.aidl
@@ -13,25 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package android.media;
-/**
- * Priority of a transcoding job.
- *
- * {@hide}
- */
@Backing(type="int")
-enum TranscodingJobPriority {
- // TODO(hkuang): define what each priority level actually mean.
- kUnspecified = 0,
- kLow = 1,
- /**
- * 2 ~ 20 is reserved for future use.
- */
- kNormal = 21,
- /**
- * 22 ~ 30 is reserved for future use.
- */
- kHigh = 31,
-}
\ No newline at end of file
+enum AudioPortConfigType {
+ SAMPLE_RATE = 0,
+ CHANNEL_MASK = 1,
+ FORMAT = 2,
+ GAIN = 3,
+ FLAGS = 4,
+}
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl b/media/libaudioclient/aidl/android/media/AudioPortRole.aidl
similarity index 65%
copy from media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
copy to media/libaudioclient/aidl/android/media/AudioPortRole.aidl
index 1a5d81a..3212325 100644
--- a/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioPortRole.aidl
@@ -13,25 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package android.media;
-/**
- * Priority of a transcoding job.
- *
- * {@hide}
- */
@Backing(type="int")
-enum TranscodingJobPriority {
- // TODO(hkuang): define what each priority level actually mean.
- kUnspecified = 0,
- kLow = 1,
- /**
- * 2 ~ 20 is reserved for future use.
- */
- kNormal = 21,
- /**
- * 22 ~ 30 is reserved for future use.
- */
- kHigh = 31,
-}
\ No newline at end of file
+enum AudioPortRole {
+ NONE = 0,
+ SOURCE = 1,
+ SINK = 2,
+}
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl b/media/libaudioclient/aidl/android/media/AudioPortType.aidl
similarity index 65%
copy from media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
copy to media/libaudioclient/aidl/android/media/AudioPortType.aidl
index 1a5d81a..90eea9a 100644
--- a/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioPortType.aidl
@@ -13,25 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package android.media;
-/**
- * Priority of a transcoding job.
- *
- * {@hide}
- */
@Backing(type="int")
-enum TranscodingJobPriority {
- // TODO(hkuang): define what each priority level actually mean.
- kUnspecified = 0,
- kLow = 1,
- /**
- * 2 ~ 20 is reserved for future use.
- */
- kNormal = 21,
- /**
- * 22 ~ 30 is reserved for future use.
- */
- kHigh = 31,
-}
\ No newline at end of file
+enum AudioPortType {
+ NONE = 0,
+ DEVICE = 1,
+ MIX = 2,
+ SESSION = 3,
+}
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl b/media/libaudioclient/aidl/android/media/AudioSessionType.aidl
similarity index 65%
copy from media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
copy to media/libaudioclient/aidl/android/media/AudioSessionType.aidl
index 1a5d81a..d305c29 100644
--- a/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioSessionType.aidl
@@ -13,25 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package android.media;
-/**
- * Priority of a transcoding job.
- *
- * {@hide}
- */
@Backing(type="int")
-enum TranscodingJobPriority {
- // TODO(hkuang): define what each priority level actually mean.
- kUnspecified = 0,
- kLow = 1,
- /**
- * 2 ~ 20 is reserved for future use.
- */
- kNormal = 21,
- /**
- * 22 ~ 30 is reserved for future use.
- */
- kHigh = 31,
-}
\ No newline at end of file
+enum AudioSessionType {
+ DEVICE = -2,
+ OUTPUT_STAGE = -1,
+ OUTPUT_MIX = 0,
+ ALLOCATE = 0,
+ NONE = 0,
+}
diff --git a/media/libaudioclient/aidl/android/media/AudioSourceType.aidl b/media/libaudioclient/aidl/android/media/AudioSourceType.aidl
new file mode 100644
index 0000000..f6ecc46
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/AudioSourceType.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+package android.media;
+
+@Backing(type="int")
+enum AudioSourceType {
+ DEFAULT = 0,
+ MIC = 1,
+ VOICE_UPLINK = 2,
+ VOICE_DOWNLINK = 3,
+ VOICE_CALL = 4,
+ CAMCORDER = 5,
+ VOICE_RECOGNITION = 6,
+ VOICE_COMMUNICATION = 7,
+ REMOTE_SUBMIX = 8,
+ UNPROCESSED = 9,
+ VOICE_PERFORMANCE = 10,
+ ECHO_REFERENCE = 1997,
+ FM_TUNER = 1998,
+ /**
+ * A low-priority, preemptible audio source for for background software
+ * hotword detection. Same tuning as VOICE_RECOGNITION.
+ * Used only internally by the framework.
+ */
+ HOTWORD = 1999,
+}
diff --git a/media/libaudioclient/aidl/android/media/AudioStreamType.aidl b/media/libaudioclient/aidl/android/media/AudioStreamType.aidl
new file mode 100644
index 0000000..803b87b
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/AudioStreamType.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+package android.media;
+
+@Backing(type="int")
+enum AudioStreamType {
+ DEFAULT = -1,
+ VOICE_CALL = 0,
+ SYSTEM = 1,
+ RING = 2,
+ MUSIC = 3,
+ ALARM = 4,
+ NOTIFICATION = 5,
+ BLUETOOTH_SCO = 6,
+ ENFORCED_AUDIBLE = 7,
+ DTMF = 8,
+ TTS = 9,
+ ACCESSIBILITY = 10,
+ ASSISTANT = 11,
+ /** For dynamic policy output mixes. Only used by the audio policy */
+ REROUTING = 12,
+ /** For audio flinger tracks volume. Only used by the audioflinger */
+ PATCH = 13,
+ /** stream for corresponding to AUDIO_USAGE_CALL_ASSISTANT */
+ CALL_ASSISTANT = 14,
+}
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl b/media/libaudioclient/aidl/android/media/IAudioFlingerClient.aidl
similarity index 65%
copy from media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
copy to media/libaudioclient/aidl/android/media/IAudioFlingerClient.aidl
index 1a5d81a..421c31c 100644
--- a/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioFlingerClient.aidl
@@ -16,22 +16,15 @@
package android.media;
+import android.media.AudioIoConfigEvent;
+import android.media.AudioIoDescriptor;
+
/**
- * Priority of a transcoding job.
+ * A callback interface for AudioFlinger.
*
* {@hide}
*/
-@Backing(type="int")
-enum TranscodingJobPriority {
- // TODO(hkuang): define what each priority level actually mean.
- kUnspecified = 0,
- kLow = 1,
- /**
- * 2 ~ 20 is reserved for future use.
- */
- kNormal = 21,
- /**
- * 22 ~ 30 is reserved for future use.
- */
- kHigh = 31,
-}
\ No newline at end of file
+interface IAudioFlingerClient {
+ oneway void ioConfigChanged(AudioIoConfigEvent event,
+ in AudioIoDescriptor ioDesc);
+}
diff --git a/media/libaudioclient/include/media/AidlConversion.h b/media/libaudioclient/include/media/AidlConversion.h
new file mode 100644
index 0000000..a1b9b82
--- /dev/null
+++ b/media/libaudioclient/include/media/AidlConversion.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <system/audio.h>
+
+#include <android-base/result.h>
+#include <android/media/AudioGainMode.h>
+#include <android/media/AudioInputFlags.h>
+#include <android/media/AudioIoConfigEvent.h>
+#include <android/media/AudioIoDescriptor.h>
+#include <android/media/AudioOutputFlags.h>
+#include <android/media/AudioPortConfigType.h>
+
+#include <media/AudioIoDescriptor.h>
+
+namespace android {
+
+template <typename T>
+using ConversionResult = base::expected<T, status_t>;
+
+// The legacy enum is unnamed. Thus, we use int.
+ConversionResult<int> aidl2legacy_AudioPortConfigType(media::AudioPortConfigType aidl);
+// The legacy enum is unnamed. Thus, we use int.
+ConversionResult<media::AudioPortConfigType> legacy2aidl_AudioPortConfigType(int legacy);
+
+ConversionResult<unsigned int> aidl2legacy_int32_t_config_mask(int32_t aidl);
+ConversionResult<int32_t> legacy2aidl_config_mask_int32_t(unsigned int legacy);
+
+ConversionResult<audio_channel_mask_t> aidl2legacy_int32_t_audio_channel_mask_t(int32_t aidl);
+ConversionResult<int32_t> legacy2aidl_audio_channel_mask_t_int32_t(audio_channel_mask_t legacy);
+
+ConversionResult<audio_io_config_event> aidl2legacy_AudioIoConfigEvent_audio_io_config_event(
+ media::AudioIoConfigEvent aidl);
+ConversionResult<media::AudioIoConfigEvent> legacy2aidl_audio_io_config_event_AudioIoConfigEvent(
+ audio_io_config_event legacy);
+
+ConversionResult<audio_port_role_t> aidl2legacy_AudioPortRole_audio_port_role_t(
+ media::AudioPortRole aidl);
+ConversionResult<media::AudioPortRole> legacy2aidl_audio_port_role_t_AudioPortRole(
+ audio_port_role_t legacy);
+
+ConversionResult<audio_port_type_t> aidl2legacy_AudioPortType_audio_port_type_t(
+ media::AudioPortType aidl);
+ConversionResult<media::AudioPortType> legacy2aidl_audio_port_type_t_AudioPortType(
+ audio_port_type_t legacy);
+
+ConversionResult<audio_format_t> aidl2legacy_AudioFormat_audio_format_t(
+ media::audio::common::AudioFormat aidl);
+ConversionResult<media::audio::common::AudioFormat> legacy2aidl_audio_format_t_AudioFormat(
+ audio_format_t legacy);
+
+ConversionResult<int> aidl2legacy_AudioGainMode_int(media::AudioGainMode aidl);
+ConversionResult<media::AudioGainMode> legacy2aidl_int_AudioGainMode(int legacy);
+
+ConversionResult<audio_gain_mode_t> aidl2legacy_int32_t_audio_gain_mode_t(int32_t aidl);
+ConversionResult<int32_t> legacy2aidl_audio_gain_mode_t_int32_t(audio_gain_mode_t legacy);
+
+ConversionResult<audio_devices_t> aidl2legacy_int32_t_audio_devices_t(int32_t aidl);
+ConversionResult<int32_t> legacy2aidl_audio_devices_t_int32_t(audio_devices_t legacy);
+
+ConversionResult<audio_gain_config> aidl2legacy_AudioGainConfig_audio_gain_config(
+ const media::AudioGainConfig& aidl, media::AudioPortRole role, media::AudioPortType type);
+ConversionResult<media::AudioGainConfig> legacy2aidl_audio_gain_config_AudioGainConfig(
+ const audio_gain_config& legacy, audio_port_role_t role, audio_port_type_t type);
+
+ConversionResult<audio_input_flags_t> aidl2legacy_AudioInputFlags_audio_input_flags_t(
+ media::AudioInputFlags aidl);
+ConversionResult<media::AudioInputFlags> legacy2aidl_audio_input_flags_t_AudioInputFlags(
+ audio_input_flags_t legacy);
+
+ConversionResult<audio_output_flags_t> aidl2legacy_AudioOutputFlags_audio_output_flags_t(
+ media::AudioOutputFlags aidl);
+ConversionResult<media::AudioOutputFlags> legacy2aidl_audio_output_flags_t_AudioOutputFlags(
+ audio_output_flags_t legacy);
+
+ConversionResult<audio_input_flags_t> aidl2legacy_audio_input_flags_mask(int32_t aidl);
+ConversionResult<int32_t> legacy2aidl_audio_input_flags_mask(audio_input_flags_t legacy);
+
+ConversionResult<audio_output_flags_t> aidl2legacy_audio_output_flags_mask(int32_t aidl);
+ConversionResult<int32_t> legacy2aidl_audio_output_flags_mask(audio_output_flags_t legacy);
+
+ConversionResult<audio_io_flags> aidl2legacy_AudioIoFlags_audio_io_flags(
+ const media::AudioIoFlags& aidl, media::AudioPortRole role, media::AudioPortType type);
+ConversionResult<media::AudioIoFlags> legacy2aidl_audio_io_flags_AudioIoFlags(
+ const audio_io_flags& legacy, audio_port_role_t role, audio_port_type_t type);
+
+ConversionResult<audio_port_config_device_ext> aidl2legacy_AudioPortConfigDeviceExt(
+ const media::AudioPortConfigDeviceExt& aidl);
+ConversionResult<media::AudioPortConfigDeviceExt> legacy2aidl_AudioPortConfigDeviceExt(
+ const audio_port_config_device_ext& legacy);
+
+ConversionResult<audio_stream_type_t> aidl2legacy_AudioStreamType_audio_stream_type_t(
+ media::AudioStreamType aidl);
+ConversionResult<media::AudioStreamType> legacy2aidl_audio_stream_type_t_AudioStreamType(
+ audio_stream_type_t legacy);
+
+ConversionResult<audio_source_t> aidl2legacy_AudioSourceType_audio_source_t(
+ media::AudioSourceType aidl);
+ConversionResult<media::AudioSourceType> legacy2aidl_audio_source_t_AudioSourceType(
+ audio_source_t legacy);
+
+ConversionResult<audio_session_t> aidl2legacy_AudioSessionType_audio_session_t(
+ media::AudioSessionType aidl);
+ConversionResult<media::AudioSessionType> legacy2aidl_audio_session_t_AudioSessionType(
+ audio_session_t legacy);
+
+ConversionResult<audio_port_config_mix_ext> aidl2legacy_AudioPortConfigMixExt(
+ const media::AudioPortConfigMixExt& aidl, media::AudioPortRole role);
+ConversionResult<media::AudioPortConfigMixExt> legacy2aidl_AudioPortConfigMixExt(
+ const audio_port_config_mix_ext& legacy, audio_port_role_t role);
+
+ConversionResult<audio_port_config_session_ext> aidl2legacy_AudioPortConfigSessionExt(
+ const media::AudioPortConfigSessionExt& aidl);
+ConversionResult<media::AudioPortConfigSessionExt> legacy2aidl_AudioPortConfigSessionExt(
+ const audio_port_config_session_ext& legacy);
+
+ConversionResult<audio_port_config> aidl2legacy_AudioPortConfig_audio_port_config(
+ const media::AudioPortConfig& aidl);
+ConversionResult<media::AudioPortConfig> legacy2aidl_audio_port_config_AudioPortConfig(
+ const audio_port_config& legacy);
+
+ConversionResult<struct audio_patch> aidl2legacy_AudioPatch_audio_patch(
+ const media::AudioPatch& aidl);
+ConversionResult<media::AudioPatch> legacy2aidl_audio_patch_AudioPatch(
+ const struct audio_patch& legacy);
+
+ConversionResult<sp<AudioIoDescriptor>> aidl2legacy_AudioIoDescriptor_AudioIoDescriptor(
+ const media::AudioIoDescriptor& aidl);
+ConversionResult<media::AudioIoDescriptor> legacy2aidl_AudioIoDescriptor_AudioIoDescriptor(
+ const sp<AudioIoDescriptor>& legacy);
+
+} // namespace android
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 848743a..dfc1982 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -19,12 +19,12 @@
#include <sys/types.h>
+#include <android/media/BnAudioFlingerClient.h>
#include <media/AudioDeviceTypeAddr.h>
#include <media/AudioPolicy.h>
#include <media/AudioProductStrategy.h>
#include <media/AudioVolumeGroup.h>
#include <media/AudioIoDescriptor.h>
-#include <media/IAudioFlingerClient.h>
#include <media/IAudioPolicyServiceClient.h>
#include <media/MicrophoneInfo.h>
#include <set>
@@ -531,7 +531,7 @@
private:
- class AudioFlingerClient: public IBinder::DeathRecipient, public BnAudioFlingerClient
+ class AudioFlingerClient: public IBinder::DeathRecipient, public media::BnAudioFlingerClient
{
public:
AudioFlingerClient() :
@@ -551,9 +551,9 @@
// indicate a change in the configuration of an output or input: keeps the cached
// values for output/input parameters up-to-date in client process
- virtual void ioConfigChanged(audio_io_config_event event,
- const sp<AudioIoDescriptor>& ioDesc);
-
+ binder::Status ioConfigChanged(
+ media::AudioIoConfigEvent event,
+ const media::AudioIoDescriptor& ioDesc) override;
status_t addAudioDeviceCallback(const wp<AudioDeviceCallback>& callback,
audio_io_handle_t audioIo,
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index a01b681..413db71 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -29,7 +29,6 @@
#include <media/AudioClient.h>
#include <media/DeviceDescriptorBase.h>
#include <media/IAudioTrack.h>
-#include <media/IAudioFlingerClient.h>
#include <system/audio.h>
#include <system/audio_effect.h>
#include <system/audio_policy.h>
@@ -39,6 +38,7 @@
#include <vector>
#include "android/media/IAudioRecord.h"
+#include "android/media/IAudioFlingerClient.h"
#include "android/media/IAudioTrackCallback.h"
#include "android/media/IEffect.h"
#include "android/media/IEffectClient.h"
@@ -420,7 +420,7 @@
// Register an object to receive audio input/output change and track notifications.
// For a given calling pid, AudioFlinger disregards any registrations after the first.
// Thus the IAudioFlingerClient must be a singleton per process.
- virtual void registerClient(const sp<IAudioFlingerClient>& client) = 0;
+ virtual void registerClient(const sp<media::IAudioFlingerClient>& client) = 0;
// retrieve the audio recording buffer size in bytes
// FIXME This API assumes a route, and so should be deprecated.
diff --git a/media/libaudioclient/include/media/IAudioFlingerClient.h b/media/libaudioclient/include/media/IAudioFlingerClient.h
deleted file mode 100644
index 0080bc9..0000000
--- a/media/libaudioclient/include/media/IAudioFlingerClient.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2009 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_IAUDIOFLINGERCLIENT_H
-#define ANDROID_IAUDIOFLINGERCLIENT_H
-
-
-#include <utils/RefBase.h>
-#include <binder/IInterface.h>
-#include <utils/KeyedVector.h>
-#include <system/audio.h>
-#include <media/AudioIoDescriptor.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-class IAudioFlingerClient : public IInterface
-{
-public:
- DECLARE_META_INTERFACE(AudioFlingerClient);
-
- // Notifies a change of audio input/output configuration.
- virtual void ioConfigChanged(audio_io_config_event event,
- const sp<AudioIoDescriptor>& ioDesc) = 0;
-
-};
-
-
-// ----------------------------------------------------------------------------
-
-class BnAudioFlingerClient : public BnInterface<IAudioFlingerClient>
-{
-public:
- virtual status_t onTransact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_IAUDIOFLINGERCLIENT_H
diff --git a/media/libmediatranscoding/Android.bp b/media/libmediatranscoding/Android.bp
index 128d0d8..7329c63 100644
--- a/media/libmediatranscoding/Android.bp
+++ b/media/libmediatranscoding/Android.bp
@@ -21,12 +21,12 @@
"aidl/android/media/ITranscodingClient.aidl",
"aidl/android/media/ITranscodingClientCallback.aidl",
"aidl/android/media/TranscodingErrorCode.aidl",
- "aidl/android/media/TranscodingJobPriority.aidl",
- "aidl/android/media/TranscodingJobStats.aidl",
+ "aidl/android/media/TranscodingSessionPriority.aidl",
+ "aidl/android/media/TranscodingSessionStats.aidl",
"aidl/android/media/TranscodingType.aidl",
"aidl/android/media/TranscodingVideoCodecType.aidl",
"aidl/android/media/TranscodingVideoTrackFormat.aidl",
- "aidl/android/media/TranscodingJobParcel.aidl",
+ "aidl/android/media/TranscodingSessionParcel.aidl",
"aidl/android/media/TranscodingRequestParcel.aidl",
"aidl/android/media/TranscodingResultParcel.aidl",
"aidl/android/media/TranscodingTestConfig.aidl",
@@ -53,7 +53,7 @@
srcs: [
"TranscodingClientManager.cpp",
- "TranscodingJobScheduler.cpp",
+ "TranscodingSessionController.cpp",
"TranscodingResourcePolicy.cpp",
"TranscodingUidPolicy.cpp",
"TranscoderWrapper.cpp",
diff --git a/media/libmediatranscoding/TranscoderWrapper.cpp b/media/libmediatranscoding/TranscoderWrapper.cpp
index 8062fcf..fffbfe9 100644
--- a/media/libmediatranscoding/TranscoderWrapper.cpp
+++ b/media/libmediatranscoding/TranscoderWrapper.cpp
@@ -117,7 +117,7 @@
return "(unknown)";
}
std::string result;
- result = "job {" + std::to_string(event.clientId) + "," + std::to_string(event.jobId) +
+ result = "session {" + std::to_string(event.clientId) + "," + std::to_string(event.sessionId) +
"}: " + typeStr;
if (event.type == Event::Error || event.type == Event::Progress) {
result += " " + std::to_string(event.arg);
@@ -128,13 +128,13 @@
class TranscoderWrapper::CallbackImpl : public MediaTranscoder::CallbackInterface {
public:
CallbackImpl(const std::shared_ptr<TranscoderWrapper>& owner, ClientIdType clientId,
- JobIdType jobId)
- : mOwner(owner), mClientId(clientId), mJobId(jobId) {}
+ SessionIdType sessionId)
+ : mOwner(owner), mClientId(clientId), mSessionId(sessionId) {}
virtual void onFinished(const MediaTranscoder* transcoder __unused) override {
auto owner = mOwner.lock();
if (owner != nullptr) {
- owner->onFinish(mClientId, mJobId);
+ owner->onFinish(mClientId, mSessionId);
}
}
@@ -142,7 +142,7 @@
media_status_t error) override {
auto owner = mOwner.lock();
if (owner != nullptr) {
- owner->onError(mClientId, mJobId, error);
+ owner->onError(mClientId, mSessionId, error);
}
}
@@ -150,23 +150,23 @@
int32_t progress) override {
auto owner = mOwner.lock();
if (owner != nullptr) {
- owner->onProgress(mClientId, mJobId, progress);
+ owner->onProgress(mClientId, mSessionId, progress);
}
}
virtual void onCodecResourceLost(const MediaTranscoder* transcoder __unused,
- const std::shared_ptr<const Parcel>& pausedState
+ const std::shared_ptr<ndk::ScopedAParcel>& pausedState
__unused) override {
- ALOGV("%s: job {%lld, %d}", __FUNCTION__, (long long)mClientId, mJobId);
+ ALOGV("%s: session {%lld, %d}", __FUNCTION__, (long long)mClientId, mSessionId);
}
private:
std::weak_ptr<TranscoderWrapper> mOwner;
ClientIdType mClientId;
- JobIdType mJobId;
+ SessionIdType mSessionId;
};
-TranscoderWrapper::TranscoderWrapper() : mCurrentClientId(0), mCurrentJobId(-1) {
+TranscoderWrapper::TranscoderWrapper() : mCurrentClientId(0), mCurrentSessionId(-1) {
std::thread(&TranscoderWrapper::threadLoop, this).detach();
}
@@ -178,83 +178,85 @@
return err == AMEDIACODEC_ERROR_RECLAIMED || err == AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE;
}
-void TranscoderWrapper::reportError(ClientIdType clientId, JobIdType jobId, media_status_t err) {
+void TranscoderWrapper::reportError(ClientIdType clientId, SessionIdType sessionId,
+ media_status_t err) {
auto callback = mCallback.lock();
if (callback != nullptr) {
if (isResourceError(err)) {
// Add a placeholder pause state to mPausedStateMap. This is required when resuming.
// TODO: remove this when transcoder pause/resume logic is ready. New logic will
// no longer use the pause states.
- auto it = mPausedStateMap.find(JobKeyType(clientId, jobId));
+ auto it = mPausedStateMap.find(SessionKeyType(clientId, sessionId));
if (it == mPausedStateMap.end()) {
- mPausedStateMap.emplace(JobKeyType(clientId, jobId),
- std::shared_ptr<const Parcel>());
+ mPausedStateMap.emplace(SessionKeyType(clientId, sessionId),
+ new ndk::ScopedAParcel());
}
callback->onResourceLost();
} else {
- callback->onError(clientId, jobId, toTranscodingError(err));
+ callback->onError(clientId, sessionId, toTranscodingError(err));
}
}
}
-void TranscoderWrapper::start(ClientIdType clientId, JobIdType jobId,
+void TranscoderWrapper::start(ClientIdType clientId, SessionIdType sessionId,
const TranscodingRequestParcel& request,
const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
- queueEvent(Event::Start, clientId, jobId, [=] {
- media_status_t err = handleStart(clientId, jobId, request, clientCb);
+ queueEvent(Event::Start, clientId, sessionId, [=] {
+ media_status_t err = handleStart(clientId, sessionId, request, clientCb);
if (err != AMEDIA_OK) {
cleanup();
- reportError(clientId, jobId, err);
+ reportError(clientId, sessionId, err);
} else {
auto callback = mCallback.lock();
if (callback != nullptr) {
- callback->onStarted(clientId, jobId);
+ callback->onStarted(clientId, sessionId);
}
}
});
}
-void TranscoderWrapper::pause(ClientIdType clientId, JobIdType jobId) {
- queueEvent(Event::Pause, clientId, jobId, [=] {
- media_status_t err = handlePause(clientId, jobId);
+void TranscoderWrapper::pause(ClientIdType clientId, SessionIdType sessionId) {
+ queueEvent(Event::Pause, clientId, sessionId, [=] {
+ media_status_t err = handlePause(clientId, sessionId);
cleanup();
if (err != AMEDIA_OK) {
- reportError(clientId, jobId, err);
+ reportError(clientId, sessionId, err);
} else {
auto callback = mCallback.lock();
if (callback != nullptr) {
- callback->onPaused(clientId, jobId);
+ callback->onPaused(clientId, sessionId);
}
}
});
}
-void TranscoderWrapper::resume(ClientIdType clientId, JobIdType jobId,
+void TranscoderWrapper::resume(ClientIdType clientId, SessionIdType sessionId,
const TranscodingRequestParcel& request,
const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
- queueEvent(Event::Resume, clientId, jobId, [=] {
- media_status_t err = handleResume(clientId, jobId, request, clientCb);
+ queueEvent(Event::Resume, clientId, sessionId, [=] {
+ media_status_t err = handleResume(clientId, sessionId, request, clientCb);
if (err != AMEDIA_OK) {
cleanup();
- reportError(clientId, jobId, err);
+ reportError(clientId, sessionId, err);
} else {
auto callback = mCallback.lock();
if (callback != nullptr) {
- callback->onResumed(clientId, jobId);
+ callback->onResumed(clientId, sessionId);
}
}
});
}
-void TranscoderWrapper::stop(ClientIdType clientId, JobIdType jobId) {
- queueEvent(Event::Stop, clientId, jobId, [=] {
- if (mTranscoder != nullptr && clientId == mCurrentClientId && jobId == mCurrentJobId) {
- // Cancelling the currently running job.
+void TranscoderWrapper::stop(ClientIdType clientId, SessionIdType sessionId) {
+ queueEvent(Event::Stop, clientId, sessionId, [=] {
+ if (mTranscoder != nullptr && clientId == mCurrentClientId &&
+ sessionId == mCurrentSessionId) {
+ // Cancelling the currently running session.
media_status_t err = mTranscoder->cancel();
if (err != AMEDIA_OK) {
ALOGW("failed to stop transcoder: %d", err);
@@ -263,55 +265,58 @@
}
cleanup();
} else {
- // For jobs that's not currently running, release any pausedState for the job.
- mPausedStateMap.erase(JobKeyType(clientId, jobId));
+ // For sessions that's not currently running, release any pausedState for the session.
+ mPausedStateMap.erase(SessionKeyType(clientId, sessionId));
}
// No callback needed for stop.
});
}
-void TranscoderWrapper::onFinish(ClientIdType clientId, JobIdType jobId) {
- queueEvent(Event::Finish, clientId, jobId, [=] {
- if (mTranscoder != nullptr && clientId == mCurrentClientId && jobId == mCurrentJobId) {
+void TranscoderWrapper::onFinish(ClientIdType clientId, SessionIdType sessionId) {
+ queueEvent(Event::Finish, clientId, sessionId, [=] {
+ if (mTranscoder != nullptr && clientId == mCurrentClientId &&
+ sessionId == mCurrentSessionId) {
cleanup();
}
auto callback = mCallback.lock();
if (callback != nullptr) {
- callback->onFinish(clientId, jobId);
+ callback->onFinish(clientId, sessionId);
}
});
}
-void TranscoderWrapper::onError(ClientIdType clientId, JobIdType jobId, media_status_t error) {
+void TranscoderWrapper::onError(ClientIdType clientId, SessionIdType sessionId,
+ media_status_t error) {
queueEvent(
- Event::Error, clientId, jobId,
+ Event::Error, clientId, sessionId,
[=] {
if (mTranscoder != nullptr && clientId == mCurrentClientId &&
- jobId == mCurrentJobId) {
+ sessionId == mCurrentSessionId) {
cleanup();
}
- reportError(clientId, jobId, error);
+ reportError(clientId, sessionId, error);
},
error);
}
-void TranscoderWrapper::onProgress(ClientIdType clientId, JobIdType jobId, int32_t progress) {
+void TranscoderWrapper::onProgress(ClientIdType clientId, SessionIdType sessionId,
+ int32_t progress) {
queueEvent(
- Event::Progress, clientId, jobId,
+ Event::Progress, clientId, sessionId,
[=] {
auto callback = mCallback.lock();
if (callback != nullptr) {
- callback->onProgressUpdate(clientId, jobId, progress);
+ callback->onProgressUpdate(clientId, sessionId, progress);
}
},
progress);
}
media_status_t TranscoderWrapper::setupTranscoder(
- ClientIdType clientId, JobIdType jobId, const TranscodingRequestParcel& request,
+ ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& request,
const std::shared_ptr<ITranscodingClientCallback>& clientCb,
- const std::shared_ptr<const Parcel>& pausedState) {
+ const std::shared_ptr<ndk::ScopedAParcel>& pausedState) {
if (clientCb == nullptr) {
ALOGE("client callback is null");
return AMEDIA_ERROR_INVALID_PARAMETER;
@@ -340,8 +345,8 @@
}
mCurrentClientId = clientId;
- mCurrentJobId = jobId;
- mTranscoderCb = std::make_shared<CallbackImpl>(shared_from_this(), clientId, jobId);
+ mCurrentSessionId = sessionId;
+ mTranscoderCb = std::make_shared<CallbackImpl>(shared_from_this(), clientId, sessionId);
mTranscoder = MediaTranscoder::create(mTranscoderCb, pausedState);
if (mTranscoder == nullptr) {
ALOGE("failed to create transcoder");
@@ -389,10 +394,10 @@
}
media_status_t TranscoderWrapper::handleStart(
- ClientIdType clientId, JobIdType jobId, const TranscodingRequestParcel& request,
+ ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& request,
const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
ALOGI("%s: setting up transcoder for start", __FUNCTION__);
- media_status_t err = setupTranscoder(clientId, jobId, request, clientCb);
+ media_status_t err = setupTranscoder(clientId, sessionId, request, clientCb);
if (err != AMEDIA_OK) {
ALOGI("%s: failed to setup transcoder", __FUNCTION__);
return err;
@@ -408,36 +413,36 @@
return AMEDIA_OK;
}
-media_status_t TranscoderWrapper::handlePause(ClientIdType clientId, JobIdType jobId) {
+media_status_t TranscoderWrapper::handlePause(ClientIdType clientId, SessionIdType sessionId) {
if (mTranscoder == nullptr) {
ALOGE("%s: transcoder is not running", __FUNCTION__);
return AMEDIA_ERROR_INVALID_OPERATION;
}
- if (clientId != mCurrentClientId || jobId != mCurrentJobId) {
- ALOGW("%s: stopping job {%lld, %d} that's not current job {%lld, %d}", __FUNCTION__,
- (long long)clientId, jobId, (long long)mCurrentClientId, mCurrentJobId);
+ if (clientId != mCurrentClientId || sessionId != mCurrentSessionId) {
+ ALOGW("%s: stopping session {%lld, %d} that's not current session {%lld, %d}", __FUNCTION__,
+ (long long)clientId, sessionId, (long long)mCurrentClientId, mCurrentSessionId);
}
ALOGI("%s: pausing transcoder", __FUNCTION__);
- std::shared_ptr<const Parcel> pauseStates;
+ std::shared_ptr<ndk::ScopedAParcel> pauseStates;
media_status_t err = mTranscoder->pause(&pauseStates);
if (err != AMEDIA_OK) {
ALOGE("%s: failed to pause transcoder: %d", __FUNCTION__, err);
return err;
}
- mPausedStateMap[JobKeyType(clientId, jobId)] = pauseStates;
+ mPausedStateMap[SessionKeyType(clientId, sessionId)] = pauseStates;
ALOGI("%s: transcoder paused", __FUNCTION__);
return AMEDIA_OK;
}
media_status_t TranscoderWrapper::handleResume(
- ClientIdType clientId, JobIdType jobId, const TranscodingRequestParcel& request,
+ ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& request,
const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
- std::shared_ptr<const Parcel> pausedState;
- auto it = mPausedStateMap.find(JobKeyType(clientId, jobId));
+ std::shared_ptr<ndk::ScopedAParcel> pausedState;
+ auto it = mPausedStateMap.find(SessionKeyType(clientId, sessionId));
if (it != mPausedStateMap.end()) {
pausedState = it->second;
mPausedStateMap.erase(it);
@@ -447,7 +452,7 @@
}
ALOGI("%s: setting up transcoder for resume", __FUNCTION__);
- media_status_t err = setupTranscoder(clientId, jobId, request, clientCb, pausedState);
+ media_status_t err = setupTranscoder(clientId, sessionId, request, clientCb, pausedState);
if (err != AMEDIA_OK) {
ALOGE("%s: failed to setup transcoder: %d", __FUNCTION__, err);
return err;
@@ -465,16 +470,16 @@
void TranscoderWrapper::cleanup() {
mCurrentClientId = 0;
- mCurrentJobId = -1;
+ mCurrentSessionId = -1;
mTranscoderCb = nullptr;
mTranscoder = nullptr;
}
-void TranscoderWrapper::queueEvent(Event::Type type, ClientIdType clientId, JobIdType jobId,
+void TranscoderWrapper::queueEvent(Event::Type type, ClientIdType clientId, SessionIdType sessionId,
const std::function<void()> runnable, int32_t arg) {
std::scoped_lock lock{mLock};
- mQueue.push_back({type, clientId, jobId, runnable, arg});
+ mQueue.push_back({type, clientId, sessionId, runnable, arg});
mCondition.notify_one();
}
diff --git a/media/libmediatranscoding/TranscodingClientManager.cpp b/media/libmediatranscoding/TranscodingClientManager.cpp
index 82a6dde..ae1f7a5 100644
--- a/media/libmediatranscoding/TranscodingClientManager.cpp
+++ b/media/libmediatranscoding/TranscodingClientManager.cpp
@@ -31,12 +31,15 @@
static_assert(sizeof(ClientIdType) == sizeof(void*), "ClientIdType should be pointer-sized");
-static constexpr const char* MEDIA_PROVIDER_PKG_NAME = "com.google.android.providers.media.module";
+static constexpr const char* MEDIA_PROVIDER_PKG_NAMES[] = {
+ "com.android.providers.media.module",
+ "com.google.android.providers.media.module",
+};
using ::aidl::android::media::BnTranscodingClient;
using ::aidl::android::media::IMediaTranscodingService; // For service error codes
-using ::aidl::android::media::TranscodingJobParcel;
using ::aidl::android::media::TranscodingRequestParcel;
+using ::aidl::android::media::TranscodingSessionParcel;
using Status = ::ndk::ScopedAStatus;
using ::ndk::SpAIBinder;
@@ -74,8 +77,8 @@
std::string mClientName;
std::string mClientOpPackageName;
- // Next jobId to assign.
- std::atomic<int32_t> mNextJobId;
+ // Next sessionId to assign.
+ std::atomic<int32_t> mNextSessionId;
// Whether this client has been unregistered already.
std::atomic<bool> mAbandoned;
// Weak pointer to the client manager for this client.
@@ -86,12 +89,13 @@
const std::weak_ptr<TranscodingClientManager>& owner);
Status submitRequest(const TranscodingRequestParcel& /*in_request*/,
- TranscodingJobParcel* /*out_job*/, bool* /*_aidl_return*/) override;
+ TranscodingSessionParcel* /*out_session*/,
+ bool* /*_aidl_return*/) override;
- Status cancelJob(int32_t /*in_jobId*/, bool* /*_aidl_return*/) override;
+ Status cancelSession(int32_t /*in_sessionId*/, bool* /*_aidl_return*/) override;
- Status getJobWithId(int32_t /*in_jobId*/, TranscodingJobParcel* /*out_job*/,
- bool* /*_aidl_return*/) override;
+ Status getSessionWithId(int32_t /*in_sessionId*/, TranscodingSessionParcel* /*out_session*/,
+ bool* /*_aidl_return*/) override;
Status unregister() override;
};
@@ -104,12 +108,12 @@
mClientId(sCookieCounter.fetch_add(1, std::memory_order_relaxed)),
mClientName(clientName),
mClientOpPackageName(opPackageName),
- mNextJobId(0),
+ mNextSessionId(0),
mAbandoned(false),
mOwner(owner) {}
Status TranscodingClientManager::ClientImpl::submitRequest(
- const TranscodingRequestParcel& in_request, TranscodingJobParcel* out_job,
+ const TranscodingRequestParcel& in_request, TranscodingSessionParcel* out_session,
bool* _aidl_return) {
*_aidl_return = false;
@@ -161,23 +165,24 @@
in_clientPid, in_clientUid, callingUid);
}
- int32_t jobId = mNextJobId.fetch_add(1);
+ int32_t sessionId = mNextSessionId.fetch_add(1);
- *_aidl_return = owner->mJobScheduler->submit(mClientId, jobId, in_clientUid, in_request,
- mClientCallback);
+ *_aidl_return = owner->mSessionController->submit(mClientId, sessionId, in_clientUid,
+ in_request, mClientCallback);
if (*_aidl_return) {
- out_job->jobId = jobId;
+ out_session->sessionId = sessionId;
- // TODO(chz): is some of this coming from JobScheduler?
- *(TranscodingRequest*)&out_job->request = in_request;
- out_job->awaitNumberOfJobs = 0;
+ // TODO(chz): is some of this coming from SessionController?
+ *(TranscodingRequest*)&out_session->request = in_request;
+ out_session->awaitNumberOfSessions = 0;
}
return Status::ok();
}
-Status TranscodingClientManager::ClientImpl::cancelJob(int32_t in_jobId, bool* _aidl_return) {
+Status TranscodingClientManager::ClientImpl::cancelSession(int32_t in_sessionId,
+ bool* _aidl_return) {
*_aidl_return = false;
std::shared_ptr<TranscodingClientManager> owner;
@@ -185,17 +190,17 @@
return Status::fromServiceSpecificError(IMediaTranscodingService::ERROR_DISCONNECTED);
}
- if (in_jobId < 0) {
+ if (in_sessionId < 0) {
return Status::ok();
}
- *_aidl_return = owner->mJobScheduler->cancel(mClientId, in_jobId);
+ *_aidl_return = owner->mSessionController->cancel(mClientId, in_sessionId);
return Status::ok();
}
-Status TranscodingClientManager::ClientImpl::getJobWithId(int32_t in_jobId,
- TranscodingJobParcel* out_job,
- bool* _aidl_return) {
+Status TranscodingClientManager::ClientImpl::getSessionWithId(int32_t in_sessionId,
+ TranscodingSessionParcel* out_session,
+ bool* _aidl_return) {
*_aidl_return = false;
std::shared_ptr<TranscodingClientManager> owner;
@@ -203,15 +208,16 @@
return Status::fromServiceSpecificError(IMediaTranscodingService::ERROR_DISCONNECTED);
}
- if (in_jobId < 0) {
+ if (in_sessionId < 0) {
return Status::ok();
}
- *_aidl_return = owner->mJobScheduler->getJob(mClientId, in_jobId, &out_job->request);
+ *_aidl_return =
+ owner->mSessionController->getSession(mClientId, in_sessionId, &out_session->request);
if (*_aidl_return) {
- out_job->jobId = in_jobId;
- out_job->awaitNumberOfJobs = 0;
+ out_session->sessionId = in_sessionId;
+ out_session->awaitNumberOfSessions = 0;
}
return Status::ok();
}
@@ -224,8 +230,8 @@
return Status::fromServiceSpecificError(IMediaTranscodingService::ERROR_DISCONNECTED);
}
- // Use jobId == -1 to cancel all realtime jobs for this client with the scheduler.
- owner->mJobScheduler->cancel(mClientId, -1);
+ // Use sessionId == -1 to cancel all realtime sessions for this client with the controller.
+ owner->mSessionController->cancel(mClientId, -1);
owner->removeClient(mClientId);
return Status::ok();
@@ -256,18 +262,18 @@
}
TranscodingClientManager::TranscodingClientManager(
- const std::shared_ptr<SchedulerClientInterface>& scheduler)
+ const std::shared_ptr<ControllerClientInterface>& controller)
: mDeathRecipient(AIBinder_DeathRecipient_new(BinderDiedCallback)),
- mJobScheduler(scheduler),
- mMediaProviderUid(-1) {
+ mSessionController(controller) {
ALOGD("TranscodingClientManager started");
uid_t mpuid;
- if (TranscodingUidPolicy::getUidForPackage(String16(MEDIA_PROVIDER_PKG_NAME), mpuid) ==
- NO_ERROR) {
- ALOGI("Found MediaProvider uid: %d", mpuid);
- mMediaProviderUid = mpuid;
- } else {
- ALOGW("Couldn't get uid for MediaProvider.");
+ for (const char* pkgName : MEDIA_PROVIDER_PKG_NAMES) {
+ if (TranscodingUidPolicy::getUidForPackage(String16(pkgName), mpuid) == NO_ERROR) {
+ ALOGI("Found %s's uid: %d", pkgName, mpuid);
+ mMediaProviderUid.insert(mpuid);
+ } else {
+ ALOGW("Couldn't get uid for %s.", pkgName);
+ }
}
}
@@ -300,7 +306,7 @@
}
bool TranscodingClientManager::isTrustedCallingUid(uid_t uid) {
- if (uid > 0 && uid == mMediaProviderUid) {
+ if (uid > 0 && mMediaProviderUid.count(uid) > 0) {
return true;
}
diff --git a/media/libmediatranscoding/TranscodingJobScheduler.cpp b/media/libmediatranscoding/TranscodingJobScheduler.cpp
deleted file mode 100644
index d3a1836..0000000
--- a/media/libmediatranscoding/TranscodingJobScheduler.cpp
+++ /dev/null
@@ -1,567 +0,0 @@
-/*
- * Copyright (C) 2020 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_NDEBUG 0
-#define LOG_TAG "TranscodingJobScheduler"
-
-#define VALIDATE_STATE 1
-
-#include <inttypes.h>
-#include <media/TranscodingJobScheduler.h>
-#include <media/TranscodingUidPolicy.h>
-#include <utils/Log.h>
-
-#include <utility>
-
-namespace android {
-
-static_assert((JobIdType)-1 < 0, "JobIdType should be signed");
-
-constexpr static uid_t OFFLINE_UID = -1;
-
-//static
-String8 TranscodingJobScheduler::jobToString(const JobKeyType& jobKey) {
- return String8::format("{client:%lld, job:%d}", (long long)jobKey.first, jobKey.second);
-}
-
-//static
-const char* TranscodingJobScheduler::jobStateToString(const Job::State jobState) {
- switch (jobState) {
- case Job::State::NOT_STARTED:
- return "NOT_STARTED";
- case Job::State::RUNNING:
- return "RUNNING";
- case Job::State::PAUSED:
- return "PAUSED";
- default:
- break;
- }
- return "(unknown)";
-}
-
-TranscodingJobScheduler::TranscodingJobScheduler(
- const std::shared_ptr<TranscoderInterface>& transcoder,
- const std::shared_ptr<UidPolicyInterface>& uidPolicy,
- const std::shared_ptr<ResourcePolicyInterface>& resourcePolicy)
- : mTranscoder(transcoder),
- mUidPolicy(uidPolicy),
- mResourcePolicy(resourcePolicy),
- mCurrentJob(nullptr),
- mResourceLost(false) {
- // Only push empty offline queue initially. Realtime queues are added when requests come in.
- mUidSortedList.push_back(OFFLINE_UID);
- mOfflineUidIterator = mUidSortedList.begin();
- mJobQueues.emplace(OFFLINE_UID, JobQueueType());
-}
-
-TranscodingJobScheduler::~TranscodingJobScheduler() {}
-
-void TranscodingJobScheduler::dumpAllJobs(int fd, const Vector<String16>& args __unused) {
- String8 result;
-
- const size_t SIZE = 256;
- char buffer[SIZE];
- std::scoped_lock lock{mLock};
-
- snprintf(buffer, SIZE, "\n========== Dumping all jobs queues =========\n");
- result.append(buffer);
- snprintf(buffer, SIZE, " Total num of Jobs: %zu\n", mJobMap.size());
- result.append(buffer);
-
- std::vector<int32_t> uids(mUidSortedList.begin(), mUidSortedList.end());
- // Exclude last uid, which is for offline queue
- uids.pop_back();
- std::vector<std::string> packageNames;
- if (TranscodingUidPolicy::getNamesForUids(uids, &packageNames)) {
- uids.push_back(OFFLINE_UID);
- packageNames.push_back("(offline)");
- }
-
- for (int32_t i = 0; i < uids.size(); i++) {
- const uid_t uid = uids[i];
-
- if (mJobQueues[uid].empty()) {
- continue;
- }
- snprintf(buffer, SIZE, " Uid: %d, pkg: %s\n", uid,
- packageNames.empty() ? "(unknown)" : packageNames[i].c_str());
- result.append(buffer);
- snprintf(buffer, SIZE, " Num of jobs: %zu\n", mJobQueues[uid].size());
- result.append(buffer);
- for (auto& jobKey : mJobQueues[uid]) {
- auto jobIt = mJobMap.find(jobKey);
- if (jobIt == mJobMap.end()) {
- snprintf(buffer, SIZE, "Failed to look up Job %s \n", jobToString(jobKey).c_str());
- result.append(buffer);
- continue;
- }
- Job& job = jobIt->second;
- TranscodingRequestParcel& request = job.request;
- snprintf(buffer, SIZE, " Job: %s, %s, %d%%\n", jobToString(jobKey).c_str(),
- jobStateToString(job.state), job.lastProgress);
- result.append(buffer);
- snprintf(buffer, SIZE, " Src: %s\n", request.sourceFilePath.c_str());
- result.append(buffer);
- snprintf(buffer, SIZE, " Dst: %s\n", request.destinationFilePath.c_str());
- result.append(buffer);
- }
- }
-
- write(fd, result.string(), result.size());
-}
-
-TranscodingJobScheduler::Job* TranscodingJobScheduler::getTopJob_l() {
- if (mJobMap.empty()) {
- return nullptr;
- }
- uid_t topUid = *mUidSortedList.begin();
- JobKeyType topJobKey = *mJobQueues[topUid].begin();
- return &mJobMap[topJobKey];
-}
-
-void TranscodingJobScheduler::updateCurrentJob_l() {
- Job* topJob = getTopJob_l();
- Job* curJob = mCurrentJob;
- ALOGV("updateCurrentJob: topJob is %s, curJob is %s",
- topJob == nullptr ? "null" : jobToString(topJob->key).c_str(),
- curJob == nullptr ? "null" : jobToString(curJob->key).c_str());
-
- // If we found a topJob that should be run, and it's not already running,
- // take some actions to ensure it's running.
- if (topJob != nullptr && (topJob != curJob || topJob->state != Job::RUNNING)) {
- // If another job is currently running, pause it first.
- if (curJob != nullptr && curJob->state == Job::RUNNING) {
- mTranscoder->pause(curJob->key.first, curJob->key.second);
- curJob->state = Job::PAUSED;
- }
- // If we are not experiencing resource loss, we can start or resume
- // the topJob now.
- if (!mResourceLost) {
- if (topJob->state == Job::NOT_STARTED) {
- mTranscoder->start(topJob->key.first, topJob->key.second, topJob->request,
- topJob->callback.lock());
- } else if (topJob->state == Job::PAUSED) {
- mTranscoder->resume(topJob->key.first, topJob->key.second, topJob->request,
- topJob->callback.lock());
- }
- topJob->state = Job::RUNNING;
- }
- }
- mCurrentJob = topJob;
-}
-
-void TranscodingJobScheduler::removeJob_l(const JobKeyType& jobKey) {
- ALOGV("%s: job %s", __FUNCTION__, jobToString(jobKey).c_str());
-
- if (mJobMap.count(jobKey) == 0) {
- ALOGE("job %s doesn't exist", jobToString(jobKey).c_str());
- return;
- }
-
- // Remove job from uid's queue.
- const uid_t uid = mJobMap[jobKey].uid;
- JobQueueType& jobQueue = mJobQueues[uid];
- auto it = std::find(jobQueue.begin(), jobQueue.end(), jobKey);
- if (it == jobQueue.end()) {
- ALOGE("couldn't find job %s in queue for uid %d", jobToString(jobKey).c_str(), uid);
- return;
- }
- jobQueue.erase(it);
-
- // If this is the last job in a real-time queue, remove this uid's queue.
- if (uid != OFFLINE_UID && jobQueue.empty()) {
- mUidSortedList.remove(uid);
- mJobQueues.erase(uid);
- mUidPolicy->unregisterMonitorUid(uid);
-
- std::unordered_set<uid_t> topUids = mUidPolicy->getTopUids();
- moveUidsToTop_l(topUids, false /*preserveTopUid*/);
- }
-
- // Clear current job.
- if (mCurrentJob == &mJobMap[jobKey]) {
- mCurrentJob = nullptr;
- }
-
- // Remove job from job map.
- mJobMap.erase(jobKey);
-}
-
-/**
- * Moves the set of uids to the front of mUidSortedList (which is used to pick
- * the next job to run).
- *
- * This is called when 1) we received a onTopUidsChanged() callbcak from UidPolicy,
- * or 2) we removed the job queue for a uid because it becomes empty.
- *
- * In case of 1), if there are multiple uids in the set, and the current front
- * uid in mUidSortedList is still in the set, we try to keep that uid at front
- * so that current job run is not interrupted. (This is not a concern for case 2)
- * because the queue for a uid was just removed entirely.)
- */
-void TranscodingJobScheduler::moveUidsToTop_l(const std::unordered_set<uid_t>& uids,
- bool preserveTopUid) {
- // If uid set is empty, nothing to do. Do not change the queue status.
- if (uids.empty()) {
- return;
- }
-
- // Save the current top uid.
- uid_t curTopUid = *mUidSortedList.begin();
- bool pushCurTopToFront = false;
- int32_t numUidsMoved = 0;
-
- // Go through the sorted uid list once, and move the ones in top set to front.
- for (auto it = mUidSortedList.begin(); it != mUidSortedList.end();) {
- uid_t uid = *it;
-
- if (uid != OFFLINE_UID && uids.count(uid) > 0) {
- it = mUidSortedList.erase(it);
-
- // If this is the top we're preserving, don't push it here, push
- // it after the for-loop.
- if (uid == curTopUid && preserveTopUid) {
- pushCurTopToFront = true;
- } else {
- mUidSortedList.push_front(uid);
- }
-
- // If we found all uids in the set, break out.
- if (++numUidsMoved == uids.size()) {
- break;
- }
- } else {
- ++it;
- }
- }
-
- if (pushCurTopToFront) {
- mUidSortedList.push_front(curTopUid);
- }
-}
-
-bool TranscodingJobScheduler::submit(ClientIdType clientId, JobIdType jobId, uid_t uid,
- const TranscodingRequestParcel& request,
- const std::weak_ptr<ITranscodingClientCallback>& callback) {
- JobKeyType jobKey = std::make_pair(clientId, jobId);
-
- ALOGV("%s: job %s, uid %d, prioirty %d", __FUNCTION__, jobToString(jobKey).c_str(), uid,
- (int32_t)request.priority);
-
- std::scoped_lock lock{mLock};
-
- if (mJobMap.count(jobKey) > 0) {
- ALOGE("job %s already exists", jobToString(jobKey).c_str());
- return false;
- }
-
- // TODO(chz): only support offline vs real-time for now. All kUnspecified jobs
- // go to offline queue.
- if (request.priority == TranscodingJobPriority::kUnspecified) {
- uid = OFFLINE_UID;
- }
-
- // Add job to job map.
- mJobMap[jobKey].key = jobKey;
- mJobMap[jobKey].uid = uid;
- mJobMap[jobKey].state = Job::NOT_STARTED;
- mJobMap[jobKey].lastProgress = 0;
- mJobMap[jobKey].request = request;
- mJobMap[jobKey].callback = callback;
-
- // If it's an offline job, the queue was already added in constructor.
- // If it's a real-time jobs, check if a queue is already present for the uid,
- // and add a new queue if needed.
- if (uid != OFFLINE_UID) {
- if (mJobQueues.count(uid) == 0) {
- mUidPolicy->registerMonitorUid(uid);
- if (mUidPolicy->isUidOnTop(uid)) {
- mUidSortedList.push_front(uid);
- } else {
- // Shouldn't be submitting real-time requests from non-top app,
- // put it in front of the offline queue.
- mUidSortedList.insert(mOfflineUidIterator, uid);
- }
- } else if (uid != *mUidSortedList.begin()) {
- if (mUidPolicy->isUidOnTop(uid)) {
- mUidSortedList.remove(uid);
- mUidSortedList.push_front(uid);
- }
- }
- }
- // Append this job to the uid's queue.
- mJobQueues[uid].push_back(jobKey);
-
- updateCurrentJob_l();
-
- validateState_l();
- return true;
-}
-
-bool TranscodingJobScheduler::cancel(ClientIdType clientId, JobIdType jobId) {
- JobKeyType jobKey = std::make_pair(clientId, jobId);
-
- ALOGV("%s: job %s", __FUNCTION__, jobToString(jobKey).c_str());
-
- std::list<JobKeyType> jobsToRemove;
-
- std::scoped_lock lock{mLock};
-
- if (jobId < 0) {
- for (auto it = mJobMap.begin(); it != mJobMap.end(); ++it) {
- if (it->first.first == clientId && it->second.uid != OFFLINE_UID) {
- jobsToRemove.push_back(it->first);
- }
- }
- } else {
- if (mJobMap.count(jobKey) == 0) {
- ALOGE("job %s doesn't exist", jobToString(jobKey).c_str());
- return false;
- }
- jobsToRemove.push_back(jobKey);
- }
-
- for (auto it = jobsToRemove.begin(); it != jobsToRemove.end(); ++it) {
- // If the job has ever been started, stop it now.
- // Note that stop() is needed even if the job is currently paused. This instructs
- // the transcoder to discard any states for the job, otherwise the states may
- // never be discarded.
- if (mJobMap[*it].state != Job::NOT_STARTED) {
- mTranscoder->stop(it->first, it->second);
- }
-
- // Remove the job.
- removeJob_l(*it);
- }
-
- // Start next job.
- updateCurrentJob_l();
-
- validateState_l();
- return true;
-}
-
-bool TranscodingJobScheduler::getJob(ClientIdType clientId, JobIdType jobId,
- TranscodingRequestParcel* request) {
- JobKeyType jobKey = std::make_pair(clientId, jobId);
-
- std::scoped_lock lock{mLock};
-
- if (mJobMap.count(jobKey) == 0) {
- ALOGE("job %s doesn't exist", jobToString(jobKey).c_str());
- return false;
- }
-
- *(TranscodingRequest*)request = mJobMap[jobKey].request;
- return true;
-}
-
-void TranscodingJobScheduler::notifyClient(ClientIdType clientId, JobIdType jobId,
- const char* reason,
- std::function<void(const JobKeyType&)> func) {
- JobKeyType jobKey = std::make_pair(clientId, jobId);
-
- std::scoped_lock lock{mLock};
-
- if (mJobMap.count(jobKey) == 0) {
- ALOGW("%s: ignoring %s for job %s that doesn't exist", __FUNCTION__, reason,
- jobToString(jobKey).c_str());
- return;
- }
-
- // Only ignore if job was never started. In particular, propagate the status
- // to client if the job is paused. Transcoder could have posted finish when
- // we're pausing it, and the finish arrived after we changed current job.
- if (mJobMap[jobKey].state == Job::NOT_STARTED) {
- ALOGW("%s: ignoring %s for job %s that was never started", __FUNCTION__, reason,
- jobToString(jobKey).c_str());
- return;
- }
-
- ALOGV("%s: job %s %s", __FUNCTION__, jobToString(jobKey).c_str(), reason);
- func(jobKey);
-}
-
-void TranscodingJobScheduler::onStarted(ClientIdType clientId, JobIdType jobId) {
- notifyClient(clientId, jobId, "started", [=](const JobKeyType& jobKey) {
- auto callback = mJobMap[jobKey].callback.lock();
- if (callback != nullptr) {
- callback->onTranscodingStarted(jobId);
- }
- });
-}
-
-void TranscodingJobScheduler::onPaused(ClientIdType clientId, JobIdType jobId) {
- notifyClient(clientId, jobId, "paused", [=](const JobKeyType& jobKey) {
- auto callback = mJobMap[jobKey].callback.lock();
- if (callback != nullptr) {
- callback->onTranscodingPaused(jobId);
- }
- });
-}
-
-void TranscodingJobScheduler::onResumed(ClientIdType clientId, JobIdType jobId) {
- notifyClient(clientId, jobId, "resumed", [=](const JobKeyType& jobKey) {
- auto callback = mJobMap[jobKey].callback.lock();
- if (callback != nullptr) {
- callback->onTranscodingResumed(jobId);
- }
- });
-}
-
-void TranscodingJobScheduler::onFinish(ClientIdType clientId, JobIdType jobId) {
- notifyClient(clientId, jobId, "finish", [=](const JobKeyType& jobKey) {
- {
- auto clientCallback = mJobMap[jobKey].callback.lock();
- if (clientCallback != nullptr) {
- clientCallback->onTranscodingFinished(
- jobId, TranscodingResultParcel({jobId, -1 /*actualBitrateBps*/,
- std::nullopt /*jobStats*/}));
- }
- }
-
- // Remove the job.
- removeJob_l(jobKey);
-
- // Start next job.
- updateCurrentJob_l();
-
- validateState_l();
- });
-}
-
-void TranscodingJobScheduler::onError(ClientIdType clientId, JobIdType jobId,
- TranscodingErrorCode err) {
- notifyClient(clientId, jobId, "error", [=](const JobKeyType& jobKey) {
- {
- auto clientCallback = mJobMap[jobKey].callback.lock();
- if (clientCallback != nullptr) {
- clientCallback->onTranscodingFailed(jobId, err);
- }
- }
-
- // Remove the job.
- removeJob_l(jobKey);
-
- // Start next job.
- updateCurrentJob_l();
-
- validateState_l();
- });
-}
-
-void TranscodingJobScheduler::onProgressUpdate(ClientIdType clientId, JobIdType jobId,
- int32_t progress) {
- notifyClient(clientId, jobId, "progress", [=](const JobKeyType& jobKey) {
- auto callback = mJobMap[jobKey].callback.lock();
- if (callback != nullptr) {
- callback->onProgressUpdate(jobId, progress);
- }
- mJobMap[jobKey].lastProgress = progress;
- });
-}
-
-void TranscodingJobScheduler::onResourceLost() {
- ALOGI("%s", __FUNCTION__);
-
- std::scoped_lock lock{mLock};
-
- if (mResourceLost) {
- return;
- }
-
- // If we receive a resource loss event, the TranscoderLibrary already paused
- // the transcoding, so we don't need to call onPaused to notify it to pause.
- // Only need to update the job state here.
- if (mCurrentJob != nullptr && mCurrentJob->state == Job::RUNNING) {
- mCurrentJob->state = Job::PAUSED;
- // Notify the client as a paused event.
- auto clientCallback = mCurrentJob->callback.lock();
- if (clientCallback != nullptr) {
- clientCallback->onTranscodingPaused(mCurrentJob->key.second);
- }
- }
- mResourceLost = true;
-
- validateState_l();
-}
-
-void TranscodingJobScheduler::onTopUidsChanged(const std::unordered_set<uid_t>& uids) {
- if (uids.empty()) {
- ALOGW("%s: ignoring empty uids", __FUNCTION__);
- return;
- }
-
- std::string uidStr;
- for (auto it = uids.begin(); it != uids.end(); it++) {
- if (!uidStr.empty()) {
- uidStr += ", ";
- }
- uidStr += std::to_string(*it);
- }
-
- ALOGD("%s: topUids: size %zu, uids: %s", __FUNCTION__, uids.size(), uidStr.c_str());
-
- std::scoped_lock lock{mLock};
-
- moveUidsToTop_l(uids, true /*preserveTopUid*/);
-
- updateCurrentJob_l();
-
- validateState_l();
-}
-
-void TranscodingJobScheduler::onResourceAvailable() {
- std::scoped_lock lock{mLock};
-
- if (!mResourceLost) {
- return;
- }
-
- ALOGI("%s", __FUNCTION__);
-
- mResourceLost = false;
- updateCurrentJob_l();
-
- validateState_l();
-}
-
-void TranscodingJobScheduler::validateState_l() {
-#ifdef VALIDATE_STATE
- LOG_ALWAYS_FATAL_IF(mJobQueues.count(OFFLINE_UID) != 1,
- "mJobQueues offline queue number is not 1");
- LOG_ALWAYS_FATAL_IF(*mOfflineUidIterator != OFFLINE_UID,
- "mOfflineUidIterator not pointing to offline uid");
- LOG_ALWAYS_FATAL_IF(mUidSortedList.size() != mJobQueues.size(),
- "mUidList and mJobQueues size mismatch");
-
- int32_t totalJobs = 0;
- for (auto uid : mUidSortedList) {
- LOG_ALWAYS_FATAL_IF(mJobQueues.count(uid) != 1, "mJobQueues count for uid %d is not 1",
- uid);
- for (auto& jobKey : mJobQueues[uid]) {
- LOG_ALWAYS_FATAL_IF(mJobMap.count(jobKey) != 1, "mJobs count for job %s is not 1",
- jobToString(jobKey).c_str());
- }
-
- totalJobs += mJobQueues[uid].size();
- }
- LOG_ALWAYS_FATAL_IF(mJobMap.size() != totalJobs,
- "mJobs size doesn't match total jobs counted from uid queues");
-#endif // VALIDATE_STATE
-}
-
-} // namespace android
diff --git a/media/libmediatranscoding/TranscodingSessionController.cpp b/media/libmediatranscoding/TranscodingSessionController.cpp
new file mode 100644
index 0000000..2306395
--- /dev/null
+++ b/media/libmediatranscoding/TranscodingSessionController.cpp
@@ -0,0 +1,574 @@
+/*
+ * Copyright (C) 2020 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_NDEBUG 0
+#define LOG_TAG "TranscodingSessionController"
+
+#define VALIDATE_STATE 1
+
+#include <inttypes.h>
+#include <media/TranscodingSessionController.h>
+#include <media/TranscodingUidPolicy.h>
+#include <utils/Log.h>
+
+#include <utility>
+
+namespace android {
+
+static_assert((SessionIdType)-1 < 0, "SessionIdType should be signed");
+
+constexpr static uid_t OFFLINE_UID = -1;
+
+//static
+String8 TranscodingSessionController::sessionToString(const SessionKeyType& sessionKey) {
+ return String8::format("{client:%lld, session:%d}", (long long)sessionKey.first,
+ sessionKey.second);
+}
+
+//static
+const char* TranscodingSessionController::sessionStateToString(const Session::State sessionState) {
+ switch (sessionState) {
+ case Session::State::NOT_STARTED:
+ return "NOT_STARTED";
+ case Session::State::RUNNING:
+ return "RUNNING";
+ case Session::State::PAUSED:
+ return "PAUSED";
+ default:
+ break;
+ }
+ return "(unknown)";
+}
+
+TranscodingSessionController::TranscodingSessionController(
+ const std::shared_ptr<TranscoderInterface>& transcoder,
+ const std::shared_ptr<UidPolicyInterface>& uidPolicy,
+ const std::shared_ptr<ResourcePolicyInterface>& resourcePolicy)
+ : mTranscoder(transcoder),
+ mUidPolicy(uidPolicy),
+ mResourcePolicy(resourcePolicy),
+ mCurrentSession(nullptr),
+ mResourceLost(false) {
+ // Only push empty offline queue initially. Realtime queues are added when requests come in.
+ mUidSortedList.push_back(OFFLINE_UID);
+ mOfflineUidIterator = mUidSortedList.begin();
+ mSessionQueues.emplace(OFFLINE_UID, SessionQueueType());
+}
+
+TranscodingSessionController::~TranscodingSessionController() {}
+
+void TranscodingSessionController::dumpAllSessions(int fd, const Vector<String16>& args __unused) {
+ String8 result;
+
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ std::scoped_lock lock{mLock};
+
+ snprintf(buffer, SIZE, "\n========== Dumping all sessions queues =========\n");
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Total num of Sessions: %zu\n", mSessionMap.size());
+ result.append(buffer);
+
+ std::vector<int32_t> uids(mUidSortedList.begin(), mUidSortedList.end());
+ // Exclude last uid, which is for offline queue
+ uids.pop_back();
+ std::vector<std::string> packageNames;
+ if (TranscodingUidPolicy::getNamesForUids(uids, &packageNames)) {
+ uids.push_back(OFFLINE_UID);
+ packageNames.push_back("(offline)");
+ }
+
+ for (int32_t i = 0; i < uids.size(); i++) {
+ const uid_t uid = uids[i];
+
+ if (mSessionQueues[uid].empty()) {
+ continue;
+ }
+ snprintf(buffer, SIZE, " Uid: %d, pkg: %s\n", uid,
+ packageNames.empty() ? "(unknown)" : packageNames[i].c_str());
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Num of sessions: %zu\n", mSessionQueues[uid].size());
+ result.append(buffer);
+ for (auto& sessionKey : mSessionQueues[uid]) {
+ auto sessionIt = mSessionMap.find(sessionKey);
+ if (sessionIt == mSessionMap.end()) {
+ snprintf(buffer, SIZE, "Failed to look up Session %s \n",
+ sessionToString(sessionKey).c_str());
+ result.append(buffer);
+ continue;
+ }
+ Session& session = sessionIt->second;
+ TranscodingRequestParcel& request = session.request;
+ snprintf(buffer, SIZE, " Session: %s, %s, %d%%\n",
+ sessionToString(sessionKey).c_str(), sessionStateToString(session.state),
+ session.lastProgress);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Src: %s\n", request.sourceFilePath.c_str());
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Dst: %s\n", request.destinationFilePath.c_str());
+ result.append(buffer);
+ }
+ }
+
+ write(fd, result.string(), result.size());
+}
+
+TranscodingSessionController::Session* TranscodingSessionController::getTopSession_l() {
+ if (mSessionMap.empty()) {
+ return nullptr;
+ }
+ uid_t topUid = *mUidSortedList.begin();
+ SessionKeyType topSessionKey = *mSessionQueues[topUid].begin();
+ return &mSessionMap[topSessionKey];
+}
+
+void TranscodingSessionController::updateCurrentSession_l() {
+ Session* topSession = getTopSession_l();
+ Session* curSession = mCurrentSession;
+ ALOGV("updateCurrentSession: topSession is %s, curSession is %s",
+ topSession == nullptr ? "null" : sessionToString(topSession->key).c_str(),
+ curSession == nullptr ? "null" : sessionToString(curSession->key).c_str());
+
+ // If we found a topSession that should be run, and it's not already running,
+ // take some actions to ensure it's running.
+ if (topSession != nullptr &&
+ (topSession != curSession || topSession->state != Session::RUNNING)) {
+ // If another session is currently running, pause it first.
+ if (curSession != nullptr && curSession->state == Session::RUNNING) {
+ mTranscoder->pause(curSession->key.first, curSession->key.second);
+ curSession->state = Session::PAUSED;
+ }
+ // If we are not experiencing resource loss, we can start or resume
+ // the topSession now.
+ if (!mResourceLost) {
+ if (topSession->state == Session::NOT_STARTED) {
+ mTranscoder->start(topSession->key.first, topSession->key.second,
+ topSession->request, topSession->callback.lock());
+ } else if (topSession->state == Session::PAUSED) {
+ mTranscoder->resume(topSession->key.first, topSession->key.second,
+ topSession->request, topSession->callback.lock());
+ }
+ topSession->state = Session::RUNNING;
+ }
+ }
+ mCurrentSession = topSession;
+}
+
+void TranscodingSessionController::removeSession_l(const SessionKeyType& sessionKey) {
+ ALOGV("%s: session %s", __FUNCTION__, sessionToString(sessionKey).c_str());
+
+ if (mSessionMap.count(sessionKey) == 0) {
+ ALOGE("session %s doesn't exist", sessionToString(sessionKey).c_str());
+ return;
+ }
+
+ // Remove session from uid's queue.
+ const uid_t uid = mSessionMap[sessionKey].uid;
+ SessionQueueType& sessionQueue = mSessionQueues[uid];
+ auto it = std::find(sessionQueue.begin(), sessionQueue.end(), sessionKey);
+ if (it == sessionQueue.end()) {
+ ALOGE("couldn't find session %s in queue for uid %d", sessionToString(sessionKey).c_str(),
+ uid);
+ return;
+ }
+ sessionQueue.erase(it);
+
+ // If this is the last session in a real-time queue, remove this uid's queue.
+ if (uid != OFFLINE_UID && sessionQueue.empty()) {
+ mUidSortedList.remove(uid);
+ mSessionQueues.erase(uid);
+ mUidPolicy->unregisterMonitorUid(uid);
+
+ std::unordered_set<uid_t> topUids = mUidPolicy->getTopUids();
+ moveUidsToTop_l(topUids, false /*preserveTopUid*/);
+ }
+
+ // Clear current session.
+ if (mCurrentSession == &mSessionMap[sessionKey]) {
+ mCurrentSession = nullptr;
+ }
+
+ // Remove session from session map.
+ mSessionMap.erase(sessionKey);
+}
+
+/**
+ * Moves the set of uids to the front of mUidSortedList (which is used to pick
+ * the next session to run).
+ *
+ * This is called when 1) we received a onTopUidsChanged() callback from UidPolicy,
+ * or 2) we removed the session queue for a uid because it becomes empty.
+ *
+ * In case of 1), if there are multiple uids in the set, and the current front
+ * uid in mUidSortedList is still in the set, we try to keep that uid at front
+ * so that current session run is not interrupted. (This is not a concern for case 2)
+ * because the queue for a uid was just removed entirely.)
+ */
+void TranscodingSessionController::moveUidsToTop_l(const std::unordered_set<uid_t>& uids,
+ bool preserveTopUid) {
+ // If uid set is empty, nothing to do. Do not change the queue status.
+ if (uids.empty()) {
+ return;
+ }
+
+ // Save the current top uid.
+ uid_t curTopUid = *mUidSortedList.begin();
+ bool pushCurTopToFront = false;
+ int32_t numUidsMoved = 0;
+
+ // Go through the sorted uid list once, and move the ones in top set to front.
+ for (auto it = mUidSortedList.begin(); it != mUidSortedList.end();) {
+ uid_t uid = *it;
+
+ if (uid != OFFLINE_UID && uids.count(uid) > 0) {
+ it = mUidSortedList.erase(it);
+
+ // If this is the top we're preserving, don't push it here, push
+ // it after the for-loop.
+ if (uid == curTopUid && preserveTopUid) {
+ pushCurTopToFront = true;
+ } else {
+ mUidSortedList.push_front(uid);
+ }
+
+ // If we found all uids in the set, break out.
+ if (++numUidsMoved == uids.size()) {
+ break;
+ }
+ } else {
+ ++it;
+ }
+ }
+
+ if (pushCurTopToFront) {
+ mUidSortedList.push_front(curTopUid);
+ }
+}
+
+bool TranscodingSessionController::submit(
+ ClientIdType clientId, SessionIdType sessionId, uid_t uid,
+ const TranscodingRequestParcel& request,
+ const std::weak_ptr<ITranscodingClientCallback>& callback) {
+ SessionKeyType sessionKey = std::make_pair(clientId, sessionId);
+
+ ALOGV("%s: session %s, uid %d, prioirty %d", __FUNCTION__, sessionToString(sessionKey).c_str(),
+ uid, (int32_t)request.priority);
+
+ std::scoped_lock lock{mLock};
+
+ if (mSessionMap.count(sessionKey) > 0) {
+ ALOGE("session %s already exists", sessionToString(sessionKey).c_str());
+ return false;
+ }
+
+ // TODO(chz): only support offline vs real-time for now. All kUnspecified sessions
+ // go to offline queue.
+ if (request.priority == TranscodingSessionPriority::kUnspecified) {
+ uid = OFFLINE_UID;
+ }
+
+ // Add session to session map.
+ mSessionMap[sessionKey].key = sessionKey;
+ mSessionMap[sessionKey].uid = uid;
+ mSessionMap[sessionKey].state = Session::NOT_STARTED;
+ mSessionMap[sessionKey].lastProgress = 0;
+ mSessionMap[sessionKey].request = request;
+ mSessionMap[sessionKey].callback = callback;
+
+ // If it's an offline session, the queue was already added in constructor.
+ // If it's a real-time sessions, check if a queue is already present for the uid,
+ // and add a new queue if needed.
+ if (uid != OFFLINE_UID) {
+ if (mSessionQueues.count(uid) == 0) {
+ mUidPolicy->registerMonitorUid(uid);
+ if (mUidPolicy->isUidOnTop(uid)) {
+ mUidSortedList.push_front(uid);
+ } else {
+ // Shouldn't be submitting real-time requests from non-top app,
+ // put it in front of the offline queue.
+ mUidSortedList.insert(mOfflineUidIterator, uid);
+ }
+ } else if (uid != *mUidSortedList.begin()) {
+ if (mUidPolicy->isUidOnTop(uid)) {
+ mUidSortedList.remove(uid);
+ mUidSortedList.push_front(uid);
+ }
+ }
+ }
+ // Append this session to the uid's queue.
+ mSessionQueues[uid].push_back(sessionKey);
+
+ updateCurrentSession_l();
+
+ validateState_l();
+ return true;
+}
+
+bool TranscodingSessionController::cancel(ClientIdType clientId, SessionIdType sessionId) {
+ SessionKeyType sessionKey = std::make_pair(clientId, sessionId);
+
+ ALOGV("%s: session %s", __FUNCTION__, sessionToString(sessionKey).c_str());
+
+ std::list<SessionKeyType> sessionsToRemove;
+
+ std::scoped_lock lock{mLock};
+
+ if (sessionId < 0) {
+ for (auto it = mSessionMap.begin(); it != mSessionMap.end(); ++it) {
+ if (it->first.first == clientId && it->second.uid != OFFLINE_UID) {
+ sessionsToRemove.push_back(it->first);
+ }
+ }
+ } else {
+ if (mSessionMap.count(sessionKey) == 0) {
+ ALOGE("session %s doesn't exist", sessionToString(sessionKey).c_str());
+ return false;
+ }
+ sessionsToRemove.push_back(sessionKey);
+ }
+
+ for (auto it = sessionsToRemove.begin(); it != sessionsToRemove.end(); ++it) {
+ // If the session has ever been started, stop it now.
+ // Note that stop() is needed even if the session is currently paused. This instructs
+ // the transcoder to discard any states for the session, otherwise the states may
+ // never be discarded.
+ if (mSessionMap[*it].state != Session::NOT_STARTED) {
+ mTranscoder->stop(it->first, it->second);
+ }
+
+ // Remove the session.
+ removeSession_l(*it);
+ }
+
+ // Start next session.
+ updateCurrentSession_l();
+
+ validateState_l();
+ return true;
+}
+
+bool TranscodingSessionController::getSession(ClientIdType clientId, SessionIdType sessionId,
+ TranscodingRequestParcel* request) {
+ SessionKeyType sessionKey = std::make_pair(clientId, sessionId);
+
+ std::scoped_lock lock{mLock};
+
+ if (mSessionMap.count(sessionKey) == 0) {
+ ALOGE("session %s doesn't exist", sessionToString(sessionKey).c_str());
+ return false;
+ }
+
+ *(TranscodingRequest*)request = mSessionMap[sessionKey].request;
+ return true;
+}
+
+void TranscodingSessionController::notifyClient(ClientIdType clientId, SessionIdType sessionId,
+ const char* reason,
+ std::function<void(const SessionKeyType&)> func) {
+ SessionKeyType sessionKey = std::make_pair(clientId, sessionId);
+
+ std::scoped_lock lock{mLock};
+
+ if (mSessionMap.count(sessionKey) == 0) {
+ ALOGW("%s: ignoring %s for session %s that doesn't exist", __FUNCTION__, reason,
+ sessionToString(sessionKey).c_str());
+ return;
+ }
+
+ // Only ignore if session was never started. In particular, propagate the status
+ // to client if the session is paused. Transcoder could have posted finish when
+ // we're pausing it, and the finish arrived after we changed current session.
+ if (mSessionMap[sessionKey].state == Session::NOT_STARTED) {
+ ALOGW("%s: ignoring %s for session %s that was never started", __FUNCTION__, reason,
+ sessionToString(sessionKey).c_str());
+ return;
+ }
+
+ ALOGV("%s: session %s %s", __FUNCTION__, sessionToString(sessionKey).c_str(), reason);
+ func(sessionKey);
+}
+
+void TranscodingSessionController::onStarted(ClientIdType clientId, SessionIdType sessionId) {
+ notifyClient(clientId, sessionId, "started", [=](const SessionKeyType& sessionKey) {
+ auto callback = mSessionMap[sessionKey].callback.lock();
+ if (callback != nullptr) {
+ callback->onTranscodingStarted(sessionId);
+ }
+ });
+}
+
+void TranscodingSessionController::onPaused(ClientIdType clientId, SessionIdType sessionId) {
+ notifyClient(clientId, sessionId, "paused", [=](const SessionKeyType& sessionKey) {
+ auto callback = mSessionMap[sessionKey].callback.lock();
+ if (callback != nullptr) {
+ callback->onTranscodingPaused(sessionId);
+ }
+ });
+}
+
+void TranscodingSessionController::onResumed(ClientIdType clientId, SessionIdType sessionId) {
+ notifyClient(clientId, sessionId, "resumed", [=](const SessionKeyType& sessionKey) {
+ auto callback = mSessionMap[sessionKey].callback.lock();
+ if (callback != nullptr) {
+ callback->onTranscodingResumed(sessionId);
+ }
+ });
+}
+
+void TranscodingSessionController::onFinish(ClientIdType clientId, SessionIdType sessionId) {
+ notifyClient(clientId, sessionId, "finish", [=](const SessionKeyType& sessionKey) {
+ {
+ auto clientCallback = mSessionMap[sessionKey].callback.lock();
+ if (clientCallback != nullptr) {
+ clientCallback->onTranscodingFinished(
+ sessionId, TranscodingResultParcel({sessionId, -1 /*actualBitrateBps*/,
+ std::nullopt /*sessionStats*/}));
+ }
+ }
+
+ // Remove the session.
+ removeSession_l(sessionKey);
+
+ // Start next session.
+ updateCurrentSession_l();
+
+ validateState_l();
+ });
+}
+
+void TranscodingSessionController::onError(ClientIdType clientId, SessionIdType sessionId,
+ TranscodingErrorCode err) {
+ notifyClient(clientId, sessionId, "error", [=](const SessionKeyType& sessionKey) {
+ {
+ auto clientCallback = mSessionMap[sessionKey].callback.lock();
+ if (clientCallback != nullptr) {
+ clientCallback->onTranscodingFailed(sessionId, err);
+ }
+ }
+
+ // Remove the session.
+ removeSession_l(sessionKey);
+
+ // Start next session.
+ updateCurrentSession_l();
+
+ validateState_l();
+ });
+}
+
+void TranscodingSessionController::onProgressUpdate(ClientIdType clientId, SessionIdType sessionId,
+ int32_t progress) {
+ notifyClient(clientId, sessionId, "progress", [=](const SessionKeyType& sessionKey) {
+ auto callback = mSessionMap[sessionKey].callback.lock();
+ if (callback != nullptr) {
+ callback->onProgressUpdate(sessionId, progress);
+ }
+ mSessionMap[sessionKey].lastProgress = progress;
+ });
+}
+
+void TranscodingSessionController::onResourceLost() {
+ ALOGI("%s", __FUNCTION__);
+
+ std::scoped_lock lock{mLock};
+
+ if (mResourceLost) {
+ return;
+ }
+
+ // If we receive a resource loss event, the TranscoderLibrary already paused
+ // the transcoding, so we don't need to call onPaused to notify it to pause.
+ // Only need to update the session state here.
+ if (mCurrentSession != nullptr && mCurrentSession->state == Session::RUNNING) {
+ mCurrentSession->state = Session::PAUSED;
+ // Notify the client as a paused event.
+ auto clientCallback = mCurrentSession->callback.lock();
+ if (clientCallback != nullptr) {
+ clientCallback->onTranscodingPaused(mCurrentSession->key.second);
+ }
+ }
+ mResourceLost = true;
+
+ validateState_l();
+}
+
+void TranscodingSessionController::onTopUidsChanged(const std::unordered_set<uid_t>& uids) {
+ if (uids.empty()) {
+ ALOGW("%s: ignoring empty uids", __FUNCTION__);
+ return;
+ }
+
+ std::string uidStr;
+ for (auto it = uids.begin(); it != uids.end(); it++) {
+ if (!uidStr.empty()) {
+ uidStr += ", ";
+ }
+ uidStr += std::to_string(*it);
+ }
+
+ ALOGD("%s: topUids: size %zu, uids: %s", __FUNCTION__, uids.size(), uidStr.c_str());
+
+ std::scoped_lock lock{mLock};
+
+ moveUidsToTop_l(uids, true /*preserveTopUid*/);
+
+ updateCurrentSession_l();
+
+ validateState_l();
+}
+
+void TranscodingSessionController::onResourceAvailable() {
+ std::scoped_lock lock{mLock};
+
+ if (!mResourceLost) {
+ return;
+ }
+
+ ALOGI("%s", __FUNCTION__);
+
+ mResourceLost = false;
+ updateCurrentSession_l();
+
+ validateState_l();
+}
+
+void TranscodingSessionController::validateState_l() {
+#ifdef VALIDATE_STATE
+ LOG_ALWAYS_FATAL_IF(mSessionQueues.count(OFFLINE_UID) != 1,
+ "mSessionQueues offline queue number is not 1");
+ LOG_ALWAYS_FATAL_IF(*mOfflineUidIterator != OFFLINE_UID,
+ "mOfflineUidIterator not pointing to offline uid");
+ LOG_ALWAYS_FATAL_IF(mUidSortedList.size() != mSessionQueues.size(),
+ "mUidList and mSessionQueues size mismatch");
+
+ int32_t totalSessions = 0;
+ for (auto uid : mUidSortedList) {
+ LOG_ALWAYS_FATAL_IF(mSessionQueues.count(uid) != 1,
+ "mSessionQueues count for uid %d is not 1", uid);
+ for (auto& sessionKey : mSessionQueues[uid]) {
+ LOG_ALWAYS_FATAL_IF(mSessionMap.count(sessionKey) != 1,
+ "mSessions count for session %s is not 1",
+ sessionToString(sessionKey).c_str());
+ }
+
+ totalSessions += mSessionQueues[uid].size();
+ }
+ LOG_ALWAYS_FATAL_IF(mSessionMap.size() != totalSessions,
+ "mSessions size doesn't match total sessions counted from uid queues");
+#endif // VALIDATE_STATE
+}
+
+} // namespace android
diff --git a/media/libmediatranscoding/aidl/android/media/IMediaTranscodingService.aidl b/media/libmediatranscoding/aidl/android/media/IMediaTranscodingService.aidl
index 7fc7748..ad2358e 100644
--- a/media/libmediatranscoding/aidl/android/media/IMediaTranscodingService.aidl
+++ b/media/libmediatranscoding/aidl/android/media/IMediaTranscodingService.aidl
@@ -18,7 +18,7 @@
import android.media.ITranscodingClient;
import android.media.ITranscodingClientCallback;
-import android.media.TranscodingJobParcel;
+import android.media.TranscodingSessionParcel;
import android.media.TranscodingRequestParcel;
/**
diff --git a/media/libmediatranscoding/aidl/android/media/ITranscodingClient.aidl b/media/libmediatranscoding/aidl/android/media/ITranscodingClient.aidl
index 37b5147..151e3d0 100644
--- a/media/libmediatranscoding/aidl/android/media/ITranscodingClient.aidl
+++ b/media/libmediatranscoding/aidl/android/media/ITranscodingClient.aidl
@@ -16,7 +16,7 @@
package android.media;
-import android.media.TranscodingJobParcel;
+import android.media.TranscodingSessionParcel;
import android.media.TranscodingRequestParcel;
/**
@@ -31,28 +31,28 @@
* Submits a transcoding request to MediaTranscodingService.
*
* @param request a TranscodingRequest contains transcoding configuration.
- * @param job(output variable) a TranscodingJob generated by the MediaTranscodingService.
+ * @param session(output variable) a TranscodingSession generated by MediaTranscodingService.
* @return true if success, false otherwise.
*/
boolean submitRequest(in TranscodingRequestParcel request,
- out TranscodingJobParcel job);
+ out TranscodingSessionParcel session);
/**
- * Cancels a transcoding job.
+ * Cancels a transcoding session.
*
- * @param jobId a TranscodingJob generated by the MediaTranscodingService.
+ * @param sessionId a TranscodingSession generated by the MediaTranscodingService.
* @return true if succeeds, false otherwise.
*/
- boolean cancelJob(in int jobId);
+ boolean cancelSession(in int sessionId);
/**
- * Queries the job detail associated with a jobId.
+ * Queries the session detail associated with a sessionId.
*
- * @param jobId a TranscodingJob generated by the MediaTranscodingService.
- * @param job(output variable) the TranscodingJob associated with the jobId.
+ * @param sessionId a TranscodingSession generated by the MediaTranscodingService.
+ * @param session(output variable) the TranscodingSession associated with the sessionId.
* @return true if succeeds, false otherwise.
*/
- boolean getJobWithId(in int jobId, out TranscodingJobParcel job);
+ boolean getSessionWithId(in int sessionId, out TranscodingSessionParcel session);
/**
* Unregister the client with the MediaTranscodingService.
diff --git a/media/libmediatranscoding/aidl/android/media/ITranscodingClientCallback.aidl b/media/libmediatranscoding/aidl/android/media/ITranscodingClientCallback.aidl
index 73edb95..d7d9b6f 100644
--- a/media/libmediatranscoding/aidl/android/media/ITranscodingClientCallback.aidl
+++ b/media/libmediatranscoding/aidl/android/media/ITranscodingClientCallback.aidl
@@ -17,7 +17,7 @@
package android.media;
import android.media.TranscodingErrorCode;
-import android.media.TranscodingJobParcel;
+import android.media.TranscodingSessionParcel;
import android.media.TranscodingResultParcel;
import android.os.ParcelFileDescriptor;
@@ -40,68 +40,68 @@
in @utf8InCpp String mode);
/**
- * Called when the transcoding associated with the jobId finished.
- * This will only be called if client request to get all the status of the job.
+ * Called when the transcoding associated with the sessionId finished.
+ * This will only be called if client request to get all the status of the session.
*
- * @param jobId jobId assigned by the MediaTranscodingService upon receiving request.
+ * @param sessionId sessionId assigned by the MediaTranscodingService upon receiving request.
*/
- oneway void onTranscodingStarted(in int jobId);
+ oneway void onTranscodingStarted(in int sessionId);
/**
- * Called when the transcoding associated with the jobId is paused.
- * This will only be called if client request to get all the status of the job.
+ * Called when the transcoding associated with the sessionId is paused.
+ * This will only be called if client request to get all the status of the session.
*
- * @param jobId jobId assigned by the MediaTranscodingService upon receiving request.
+ * @param sessionId sessionId assigned by the MediaTranscodingService upon receiving request.
*/
- oneway void onTranscodingPaused(in int jobId);
+ oneway void onTranscodingPaused(in int sessionId);
/**
- * Called when the transcoding associated with the jobId is resumed.
- * This will only be called if client request to get all the status of the job.
+ * Called when the transcoding associated with the sessionId is resumed.
+ * This will only be called if client request to get all the status of the session.
*
- * @param jobId jobId assigned by the MediaTranscodingService upon receiving request.
+ * @param sessionId sessionId assigned by the MediaTranscodingService upon receiving request.
*/
- oneway void onTranscodingResumed(in int jobId);
+ oneway void onTranscodingResumed(in int sessionId);
/**
- * Called when the transcoding associated with the jobId finished.
+ * Called when the transcoding associated with the sessionId finished.
*
- * @param jobId jobId assigned by the MediaTranscodingService upon receiving request.
+ * @param sessionId sessionId assigned by the MediaTranscodingService upon receiving request.
* @param result contains the transcoded file stats and other transcoding metrics if requested.
*/
- oneway void onTranscodingFinished(in int jobId, in TranscodingResultParcel result);
+ oneway void onTranscodingFinished(in int sessionId, in TranscodingResultParcel result);
/**
- * Called when the transcoding associated with the jobId failed.
+ * Called when the transcoding associated with the sessionId failed.
*
- * @param jobId jobId assigned by the MediaTranscodingService upon receiving request.
+ * @param sessionId sessionId assigned by the MediaTranscodingService upon receiving request.
* @param errorCode error code that indicates the error.
*/
- oneway void onTranscodingFailed(in int jobId, in TranscodingErrorCode errorCode);
+ oneway void onTranscodingFailed(in int sessionId, in TranscodingErrorCode errorCode);
/**
- * Called when the transcoding configuration associated with the jobId gets updated, i.e. wait
- * number in the job queue.
+ * Called when the transcoding configuration associated with the sessionId gets updated, i.e. wait
+ * number in the session queue.
*
* <p> This will only be called if client set requestUpdate to be true in the TranscodingRequest
* submitted to the MediaTranscodingService.
*
- * @param jobId jobId assigned by the MediaTranscodingService upon receiving request.
- * @param oldAwaitNumber previous number of jobs ahead of current job.
- * @param newAwaitNumber updated number of jobs ahead of current job.
+ * @param sessionId sessionId assigned by the MediaTranscodingService upon receiving request.
+ * @param oldAwaitNumber previous number of sessions ahead of current session.
+ * @param newAwaitNumber updated number of sessions ahead of current session.
*/
- oneway void onAwaitNumberOfJobsChanged(in int jobId,
+ oneway void onAwaitNumberOfSessionsChanged(in int sessionId,
in int oldAwaitNumber,
in int newAwaitNumber);
/**
- * Called when there is an update on the progress of the TranscodingJob.
+ * Called when there is an update on the progress of the TranscodingSession.
*
* <p> This will only be called if client set requestUpdate to be true in the TranscodingRequest
* submitted to the MediaTranscodingService.
*
- * @param jobId jobId assigned by the MediaTranscodingService upon receiving request.
+ * @param sessionId sessionId assigned by the MediaTranscodingService upon receiving request.
* @param progress an integer number ranging from 0 ~ 100 inclusive.
*/
- oneway void onProgressUpdate(in int jobId, in int progress);
+ oneway void onProgressUpdate(in int sessionId, in int progress);
}
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingRequestParcel.aidl b/media/libmediatranscoding/aidl/android/media/TranscodingRequestParcel.aidl
index 14d19ba..03c24f0 100644
--- a/media/libmediatranscoding/aidl/android/media/TranscodingRequestParcel.aidl
+++ b/media/libmediatranscoding/aidl/android/media/TranscodingRequestParcel.aidl
@@ -16,7 +16,7 @@
package android.media;
-import android.media.TranscodingJobPriority;
+import android.media.TranscodingSessionPriority;
import android.media.TranscodingTestConfig;
import android.media.TranscodingType;
import android.media.TranscodingVideoTrackFormat;
@@ -61,26 +61,26 @@
* Requested video track format for the transcoding.
* Note that the transcoding service will try to fulfill the requested format as much as
* possbile, while subject to hardware and software limitation. The final video track format
- * will be available in the TranscodingJobParcel when the job is finished.
+ * will be available in the TranscodingSessionParcel when the session is finished.
*/
@nullable TranscodingVideoTrackFormat requestedVideoTrackFormat;
/**
* Priority of this transcoding. Service will schedule the transcoding based on the priority.
*/
- TranscodingJobPriority priority;
+ TranscodingSessionPriority priority;
/**
- * Whether to receive update on progress and change of awaitNumJobs.
+ * Whether to receive update on progress and change of awaitNumSessions.
* Default to false.
*/
boolean requestProgressUpdate = false;
/**
- * Whether to receive update on job's start/stop/pause/resume.
+ * Whether to receive update on session's start/stop/pause/resume.
* Default to false.
*/
- boolean requestJobEventUpdate = false;
+ boolean requestSessionEventUpdate = false;
/**
* Whether this request is for testing.
@@ -94,7 +94,7 @@
/**
* Whether to get the stats of the transcoding.
- * If this is enabled, the TranscodingJobStats will be returned in TranscodingResultParcel
+ * If this is enabled, the TranscodingSessionStats will be returned in TranscodingResultParcel
* upon transcoding finishes.
*/
boolean enableStats = false;
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingResultParcel.aidl b/media/libmediatranscoding/aidl/android/media/TranscodingResultParcel.aidl
index a20c8b1..7826e25 100644
--- a/media/libmediatranscoding/aidl/android/media/TranscodingResultParcel.aidl
+++ b/media/libmediatranscoding/aidl/android/media/TranscodingResultParcel.aidl
@@ -16,7 +16,7 @@
package android.media;
-import android.media.TranscodingJobStats;
+import android.media.TranscodingSessionStats;
/**
* Result of the transcoding.
@@ -26,9 +26,9 @@
//TODO(hkuang): Implement the parcelable.
parcelable TranscodingResultParcel {
/**
- * The jobId associated with the TranscodingResult.
+ * The sessionId associated with the TranscodingResult.
*/
- int jobId;
+ int sessionId;
/**
* Actual bitrate of the transcoded video in bits per second. This will only present for video
@@ -37,8 +37,8 @@
int actualBitrateBps;
/**
- * Stats of the transcoding job. This will only be available when client requests to get the
+ * Stats of the transcoding session. This will only be available when client requests to get the
* stats in TranscodingRequestParcel.
*/
- @nullable TranscodingJobStats jobStats;
+ @nullable TranscodingSessionStats sessionStats;
}
\ No newline at end of file
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingJobParcel.aidl b/media/libmediatranscoding/aidl/android/media/TranscodingSessionParcel.aidl
similarity index 61%
rename from media/libmediatranscoding/aidl/android/media/TranscodingJobParcel.aidl
rename to media/libmediatranscoding/aidl/android/media/TranscodingSessionParcel.aidl
index baf4381..3a4a500 100644
--- a/media/libmediatranscoding/aidl/android/media/TranscodingJobParcel.aidl
+++ b/media/libmediatranscoding/aidl/android/media/TranscodingSessionParcel.aidl
@@ -20,34 +20,34 @@
import android.media.TranscodingVideoTrackFormat;
/**
- * TranscodingJob is generated by the MediaTranscodingService upon receiving a TranscodingRequest.
- * It contains all the necessary configuration generated by the MediaTranscodingService for the
- * TranscodingRequest.
+ * TranscodingSession is generated by the MediaTranscodingService upon receiving a
+ * TranscodingRequest. It contains all the necessary configuration generated by the
+ * MediaTranscodingService for the TranscodingRequest.
*
* {@hide}
*/
//TODO(hkuang): Implement the parcelable.
-parcelable TranscodingJobParcel {
+parcelable TranscodingSessionParcel {
/**
* A unique positive Id generated by the MediaTranscodingService.
*/
- int jobId;
+ int sessionId;
/**
- * The request associated with the TranscodingJob.
+ * The request associated with the TranscodingSession.
*/
TranscodingRequestParcel request;
/**
* Output video track's format. This will only be avaiable for video transcoding and it will
- * be avaiable when the job is finished.
+ * be avaiable when the session is finished.
*/
@nullable TranscodingVideoTrackFormat videoTrackFormat;
/**
- * Current number of jobs ahead of this job. The service schedules the job based on the priority
- * passed from the client. Client could specify whether to receive updates when the
- * awaitNumberOfJobs changes through setting requestProgressUpdate in the TranscodingRequest.
+ * Current number of sessions ahead of this session. The service schedules the session based on
+ * the priority passed from the client. Client could specify whether to receive updates when the
+ * awaitNumberOfSessions changes through setting requestProgressUpdate in the TranscodingRequest.
*/
- int awaitNumberOfJobs;
+ int awaitNumberOfSessions;
}
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl b/media/libmediatranscoding/aidl/android/media/TranscodingSessionPriority.aidl
similarity index 92%
rename from media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
rename to media/libmediatranscoding/aidl/android/media/TranscodingSessionPriority.aidl
index 1a5d81a..f001484 100644
--- a/media/libmediatranscoding/aidl/android/media/TranscodingJobPriority.aidl
+++ b/media/libmediatranscoding/aidl/android/media/TranscodingSessionPriority.aidl
@@ -17,12 +17,12 @@
package android.media;
/**
- * Priority of a transcoding job.
+ * Priority of a transcoding session.
*
* {@hide}
*/
@Backing(type="int")
-enum TranscodingJobPriority {
+enum TranscodingSessionPriority {
// TODO(hkuang): define what each priority level actually mean.
kUnspecified = 0,
kLow = 1,
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingJobStats.aidl b/media/libmediatranscoding/aidl/android/media/TranscodingSessionStats.aidl
similarity index 65%
rename from media/libmediatranscoding/aidl/android/media/TranscodingJobStats.aidl
rename to media/libmediatranscoding/aidl/android/media/TranscodingSessionStats.aidl
index 1b41b87..b3e7eea 100644
--- a/media/libmediatranscoding/aidl/android/media/TranscodingJobStats.aidl
+++ b/media/libmediatranscoding/aidl/android/media/TranscodingSessionStats.aidl
@@ -17,20 +17,20 @@
package android.media;
/**
- * TranscodingJobStats encapsulated the stats of the a TranscodingJob.
+ * TranscodingSessionStats encapsulated the stats of the a TranscodingSession.
*
* {@hide}
*/
-parcelable TranscodingJobStats {
+parcelable TranscodingSessionStats {
/**
- * System time of when the job is created.
+ * System time of when the session is created.
*/
- long jobCreatedTimeUs;
+ long sessionCreatedTimeUs;
/**
- * System time of when the job is finished.
+ * System time of when the session is finished.
*/
- long jobFinishedTimeUs;
+ long sessionFinishedTimeUs;
/**
* Total time spend on transcoding, exclude the time in pause.
@@ -38,8 +38,8 @@
long totalProcessingTimeUs;
/**
- * Total time spend on handling the job, include the time in pause.
- * The totaltimeUs is actually the same as jobFinishedTimeUs - jobCreatedTimeUs.
+ * Total time spend on handling the session, include the time in pause.
+ * The totaltimeUs is actually the same as sessionFinishedTimeUs - sessionCreatedTimeUs.
*/
long totalTimeUs;
}
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingTestConfig.aidl b/media/libmediatranscoding/aidl/android/media/TranscodingTestConfig.aidl
index a564799..12e0e94 100644
--- a/media/libmediatranscoding/aidl/android/media/TranscodingTestConfig.aidl
+++ b/media/libmediatranscoding/aidl/android/media/TranscodingTestConfig.aidl
@@ -24,7 +24,7 @@
parcelable TranscodingTestConfig {
/**
* Whether to use SimulatedTranscoder for testing. Note that SimulatedTranscoder does not send
- * transcoding jobs to real MediaTranscoder.
+ * transcoding sessions to real MediaTranscoder.
*/
boolean useSimulatedTranscoder = false;
@@ -35,9 +35,10 @@
boolean passThroughMode = false;
/**
- * Time of processing the job in milliseconds. Service will return the job result at least after
- * processingTotalTimeMs from the time it starts to process the job. Note that if service uses
- * real MediaTranscoder to do transcoding, the time spent on transcoding may be more than that.
+ * Time of processing the session in milliseconds. Service will return the session result at
+ * least after processingTotalTimeMs from the time it starts to process the session. Note that
+ * if service uses real MediaTranscoder to do transcoding, the time spent on transcoding may be
+ * more than that.
*/
int processingTotalTimeMs = 0;
}
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingVideoTrackFormat.aidl b/media/libmediatranscoding/aidl/android/media/TranscodingVideoTrackFormat.aidl
index 90502cd..8ed241a 100644
--- a/media/libmediatranscoding/aidl/android/media/TranscodingVideoTrackFormat.aidl
+++ b/media/libmediatranscoding/aidl/android/media/TranscodingVideoTrackFormat.aidl
@@ -25,13 +25,13 @@
* aidl_interface
*
* Note that TranscodingVideoTrackFormat is used in TranscodingRequestParcel for the client to
- * specify the desired transcoded video format, and is also used in TranscodingJobParcel for the
+ * specify the desired transcoded video format, and is also used in TranscodingSessionParcel for the
* service to notify client of the final video format for transcoding.
* When used as input in TranscodingRequestParcel, the client only needs to specify the config that
* they want to change, e.g. codec or resolution, and all the missing configs will be extracted
* from the source video and applied to the destination video.
- * When used as output in TranscodingJobParcel, all the configs will be populated to indicate the
- * final encoder configs used for transcoding.
+ * When used as output in TranscodingSessionParcel, all the configs will be populated to indicate
+ * the final encoder configs used for transcoding.
*
* {@hide}
*/
diff --git a/media/libmediatranscoding/include/media/AdjustableMaxPriorityQueue.h b/media/libmediatranscoding/include/media/AdjustableMaxPriorityQueue.h
index 9ca2ee9..5ba1ee2 100644
--- a/media/libmediatranscoding/include/media/AdjustableMaxPriorityQueue.h
+++ b/media/libmediatranscoding/include/media/AdjustableMaxPriorityQueue.h
@@ -26,7 +26,7 @@
namespace android {
/*
- * AdjustableMaxPriorityQueue is a custom max priority queue that helps managing jobs for
+ * AdjustableMaxPriorityQueue is a custom max priority queue that helps managing sessions for
* MediaTranscodingService.
*
* AdjustableMaxPriorityQueue is a wrapper template around the STL's *_heap() functions.
diff --git a/media/libmediatranscoding/include/media/ControllerClientInterface.h b/media/libmediatranscoding/include/media/ControllerClientInterface.h
new file mode 100644
index 0000000..3fd4f0c
--- /dev/null
+++ b/media/libmediatranscoding/include/media/ControllerClientInterface.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2020 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_MEDIA_CONTROLLER_CLIENT_INTERFACE_H
+#define ANDROID_MEDIA_CONTROLLER_CLIENT_INTERFACE_H
+
+#include <aidl/android/media/ITranscodingClientCallback.h>
+#include <aidl/android/media/TranscodingRequestParcel.h>
+#include <media/TranscodingDefs.h>
+
+namespace android {
+
+using ::aidl::android::media::ITranscodingClientCallback;
+using ::aidl::android::media::TranscodingRequestParcel;
+
+// Interface for a client to call the controller to schedule or retrieve
+// the status of a session.
+class ControllerClientInterface {
+public:
+ /**
+ * Submits one request to the controller.
+ *
+ * Returns true on success and false on failure. This call will fail is a session identified
+ * by <clientId, sessionId> already exists.
+ */
+ virtual bool submit(ClientIdType clientId, SessionIdType sessionId, uid_t uid,
+ const TranscodingRequestParcel& request,
+ const std::weak_ptr<ITranscodingClientCallback>& clientCallback) = 0;
+
+ /**
+ * Cancels a session identified by <clientId, sessionId>.
+ *
+ * If sessionId is negative (<0), all sessions with a specified priority (that's not
+ * TranscodingSessionPriority::kUnspecified) will be cancelled. Otherwise, only the single
+ * session <clientId, sessionId> will be cancelled.
+ *
+ * Returns false if a single session is being cancelled but it doesn't exist. Returns
+ * true otherwise.
+ */
+ virtual bool cancel(ClientIdType clientId, SessionIdType sessionId) = 0;
+
+ /**
+ * Retrieves information about a session.
+ *
+ * Returns true and the session if it exists, and false otherwise.
+ */
+ virtual bool getSession(ClientIdType clientId, SessionIdType sessionId,
+ TranscodingRequestParcel* request) = 0;
+
+protected:
+ virtual ~ControllerClientInterface() = default;
+};
+
+} // namespace android
+#endif // ANDROID_MEDIA_CONTROLLER_CLIENT_INTERFACE_H
diff --git a/media/libmediatranscoding/include/media/ResourcePolicyInterface.h b/media/libmediatranscoding/include/media/ResourcePolicyInterface.h
index 8bd7d6b..4a92af8 100644
--- a/media/libmediatranscoding/include/media/ResourcePolicyInterface.h
+++ b/media/libmediatranscoding/include/media/ResourcePolicyInterface.h
@@ -21,7 +21,7 @@
class ResourcePolicyCallbackInterface;
-// Interface for the JobScheduler to control the resource status updates.
+// Interface for the SessionController to control the resource status updates.
class ResourcePolicyInterface {
public:
// Set the associated callback interface to send the events when resource
@@ -32,11 +32,11 @@
virtual ~ResourcePolicyInterface() = default;
};
-// Interface for notifying the JobScheduler of a change in resource status.
+// Interface for notifying the SessionController of a change in resource status.
class ResourcePolicyCallbackInterface {
public:
- // Called when codec resources become available. The scheduler may use this
- // as a signal to attempt restart transcoding jobs that were previously
+ // Called when codec resources become available. The controller may use this
+ // as a signal to attempt restart transcoding sessions that were previously
// paused due to temporary resource loss.
virtual void onResourceAvailable() = 0;
diff --git a/media/libmediatranscoding/include/media/SchedulerClientInterface.h b/media/libmediatranscoding/include/media/SchedulerClientInterface.h
deleted file mode 100644
index e00cfb2..0000000
--- a/media/libmediatranscoding/include/media/SchedulerClientInterface.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2020 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_MEDIA_SCHEDULER_CLIENT_INTERFACE_H
-#define ANDROID_MEDIA_SCHEDULER_CLIENT_INTERFACE_H
-
-#include <aidl/android/media/ITranscodingClientCallback.h>
-#include <aidl/android/media/TranscodingRequestParcel.h>
-#include <media/TranscodingDefs.h>
-
-namespace android {
-
-using ::aidl::android::media::ITranscodingClientCallback;
-using ::aidl::android::media::TranscodingRequestParcel;
-
-// Interface for a client to call the scheduler to schedule or retrieve
-// the status of a job.
-class SchedulerClientInterface {
-public:
- /**
- * Submits one request to the scheduler.
- *
- * Returns true on success and false on failure. This call will fail is a job identified
- * by <clientId, jobId> already exists.
- */
- virtual bool submit(ClientIdType clientId, JobIdType jobId, uid_t uid,
- const TranscodingRequestParcel& request,
- const std::weak_ptr<ITranscodingClientCallback>& clientCallback) = 0;
-
- /**
- * Cancels a job identified by <clientId, jobId>.
- *
- * If jobId is negative (<0), all jobs with a specified priority (that's not
- * TranscodingJobPriority::kUnspecified) will be cancelled. Otherwise, only the single job
- * <clientId, jobId> will be cancelled.
- *
- * Returns false if a single job is being cancelled but it doesn't exist. Returns
- * true otherwise.
- */
- virtual bool cancel(ClientIdType clientId, JobIdType jobId) = 0;
-
- /**
- * Retrieves information about a job.
- *
- * Returns true and the job if it exists, and false otherwise.
- */
- virtual bool getJob(ClientIdType clientId, JobIdType jobId,
- TranscodingRequestParcel* request) = 0;
-
-protected:
- virtual ~SchedulerClientInterface() = default;
-};
-
-} // namespace android
-#endif // ANDROID_MEDIA_SCHEDULER_CLIENT_INTERFACE_H
diff --git a/media/libmediatranscoding/include/media/TranscoderInterface.h b/media/libmediatranscoding/include/media/TranscoderInterface.h
index 1a3f505..e17cd5a 100644
--- a/media/libmediatranscoding/include/media/TranscoderInterface.h
+++ b/media/libmediatranscoding/include/media/TranscoderInterface.h
@@ -29,39 +29,41 @@
using ::aidl::android::media::TranscodingRequestParcel;
class TranscoderCallbackInterface;
-// Interface for the scheduler to call the transcoder to take actions.
+// Interface for the controller to call the transcoder to take actions.
class TranscoderInterface {
public:
virtual void setCallback(const std::shared_ptr<TranscoderCallbackInterface>& cb) = 0;
- virtual void start(ClientIdType clientId, JobIdType jobId,
+ virtual void start(ClientIdType clientId, SessionIdType sessionId,
const TranscodingRequestParcel& request,
const std::shared_ptr<ITranscodingClientCallback>& clientCallback) = 0;
- virtual void pause(ClientIdType clientId, JobIdType jobId) = 0;
- virtual void resume(ClientIdType clientId, JobIdType jobId,
+ virtual void pause(ClientIdType clientId, SessionIdType sessionId) = 0;
+ virtual void resume(ClientIdType clientId, SessionIdType sessionId,
const TranscodingRequestParcel& request,
const std::shared_ptr<ITranscodingClientCallback>& clientCallback) = 0;
- virtual void stop(ClientIdType clientId, JobIdType jobId) = 0;
+ virtual void stop(ClientIdType clientId, SessionIdType sessionId) = 0;
protected:
virtual ~TranscoderInterface() = default;
};
-// Interface for the transcoder to notify the scheduler of the status of
-// the currently running job, or temporary loss of transcoding resources.
+// Interface for the transcoder to notify the controller of the status of
+// the currently running session, or temporary loss of transcoding resources.
class TranscoderCallbackInterface {
public:
// TODO(chz): determine what parameters are needed here.
- virtual void onStarted(ClientIdType clientId, JobIdType jobId) = 0;
- virtual void onPaused(ClientIdType clientId, JobIdType jobId) = 0;
- virtual void onResumed(ClientIdType clientId, JobIdType jobId) = 0;
- virtual void onFinish(ClientIdType clientId, JobIdType jobId) = 0;
- virtual void onError(ClientIdType clientId, JobIdType jobId, TranscodingErrorCode err) = 0;
- virtual void onProgressUpdate(ClientIdType clientId, JobIdType jobId, int32_t progress) = 0;
+ virtual void onStarted(ClientIdType clientId, SessionIdType sessionId) = 0;
+ virtual void onPaused(ClientIdType clientId, SessionIdType sessionId) = 0;
+ virtual void onResumed(ClientIdType clientId, SessionIdType sessionId) = 0;
+ virtual void onFinish(ClientIdType clientId, SessionIdType sessionId) = 0;
+ virtual void onError(ClientIdType clientId, SessionIdType sessionId,
+ TranscodingErrorCode err) = 0;
+ virtual void onProgressUpdate(ClientIdType clientId, SessionIdType sessionId,
+ int32_t progress) = 0;
// Called when transcoding becomes temporarily inaccessible due to loss of resource.
- // If there is any job currently running, it will be paused. When resource contention
- // is solved, the scheduler should call TranscoderInterface's to either start a new job,
- // or resume a paused job.
+ // If there is any session currently running, it will be paused. When resource contention
+ // is solved, the controller should call TranscoderInterface's to either start a new session,
+ // or resume a paused session.
virtual void onResourceLost() = 0;
protected:
diff --git a/media/libmediatranscoding/include/media/TranscoderWrapper.h b/media/libmediatranscoding/include/media/TranscoderWrapper.h
index c956042..9ec32d7 100644
--- a/media/libmediatranscoding/include/media/TranscoderWrapper.h
+++ b/media/libmediatranscoding/include/media/TranscoderWrapper.h
@@ -32,7 +32,7 @@
/*
* Wrapper class around MediaTranscoder.
- * Implements TranscoderInterface for TranscodingJobScheduler to use.
+ * Implements TranscoderInterface for TranscodingSessionController to use.
*/
class TranscoderWrapper : public TranscoderInterface,
public std::enable_shared_from_this<TranscoderWrapper> {
@@ -40,25 +40,25 @@
TranscoderWrapper();
virtual void setCallback(const std::shared_ptr<TranscoderCallbackInterface>& cb) override;
- virtual void start(ClientIdType clientId, JobIdType jobId,
+ virtual void start(ClientIdType clientId, SessionIdType sessionId,
const TranscodingRequestParcel& request,
const std::shared_ptr<ITranscodingClientCallback>& clientCallback) override;
- virtual void pause(ClientIdType clientId, JobIdType jobId) override;
- virtual void resume(ClientIdType clientId, JobIdType jobId,
+ virtual void pause(ClientIdType clientId, SessionIdType sessionId) override;
+ virtual void resume(ClientIdType clientId, SessionIdType sessionId,
const TranscodingRequestParcel& request,
const std::shared_ptr<ITranscodingClientCallback>& clientCallback) override;
- virtual void stop(ClientIdType clientId, JobIdType jobId) override;
+ virtual void stop(ClientIdType clientId, SessionIdType sessionId) override;
private:
class CallbackImpl;
struct Event {
enum Type { NoEvent, Start, Pause, Resume, Stop, Finish, Error, Progress } type;
ClientIdType clientId;
- JobIdType jobId;
+ SessionIdType sessionId;
std::function<void()> runnable;
int32_t arg;
};
- using JobKeyType = std::pair<ClientIdType, JobIdType>;
+ using SessionKeyType = std::pair<ClientIdType, SessionIdType>;
std::shared_ptr<CallbackImpl> mTranscoderCb;
std::shared_ptr<MediaTranscoder> mTranscoder;
@@ -66,30 +66,30 @@
std::mutex mLock;
std::condition_variable mCondition;
std::list<Event> mQueue; // GUARDED_BY(mLock);
- std::map<JobKeyType, std::shared_ptr<const Parcel>> mPausedStateMap;
+ std::map<SessionKeyType, std::shared_ptr<ndk::ScopedAParcel>> mPausedStateMap;
ClientIdType mCurrentClientId;
- JobIdType mCurrentJobId;
+ SessionIdType mCurrentSessionId;
static std::string toString(const Event& event);
- void onFinish(ClientIdType clientId, JobIdType jobId);
- void onError(ClientIdType clientId, JobIdType jobId, media_status_t status);
- void onProgress(ClientIdType clientId, JobIdType jobId, int32_t progress);
+ void onFinish(ClientIdType clientId, SessionIdType sessionId);
+ void onError(ClientIdType clientId, SessionIdType sessionId, media_status_t status);
+ void onProgress(ClientIdType clientId, SessionIdType sessionId, int32_t progress);
- media_status_t handleStart(ClientIdType clientId, JobIdType jobId,
+ media_status_t handleStart(ClientIdType clientId, SessionIdType sessionId,
const TranscodingRequestParcel& request,
const std::shared_ptr<ITranscodingClientCallback>& callback);
- media_status_t handlePause(ClientIdType clientId, JobIdType jobId);
- media_status_t handleResume(ClientIdType clientId, JobIdType jobId,
+ media_status_t handlePause(ClientIdType clientId, SessionIdType sessionId);
+ media_status_t handleResume(ClientIdType clientId, SessionIdType sessionId,
const TranscodingRequestParcel& request,
const std::shared_ptr<ITranscodingClientCallback>& callback);
- media_status_t setupTranscoder(ClientIdType clientId, JobIdType jobId,
- const TranscodingRequestParcel& request,
- const std::shared_ptr<ITranscodingClientCallback>& callback,
- const std::shared_ptr<const Parcel>& pausedState = nullptr);
+ media_status_t setupTranscoder(
+ ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& request,
+ const std::shared_ptr<ITranscodingClientCallback>& callback,
+ const std::shared_ptr<ndk::ScopedAParcel>& pausedState = nullptr);
void cleanup();
- void reportError(ClientIdType clientId, JobIdType jobId, media_status_t err);
- void queueEvent(Event::Type type, ClientIdType clientId, JobIdType jobId,
+ void reportError(ClientIdType clientId, SessionIdType sessionId, media_status_t err);
+ void queueEvent(Event::Type type, ClientIdType clientId, SessionIdType sessionId,
const std::function<void()> runnable, int32_t arg = 0);
void threadLoop();
};
diff --git a/media/libmediatranscoding/include/media/TranscodingClientManager.h b/media/libmediatranscoding/include/media/TranscodingClientManager.h
index be03bc4..451f993 100644
--- a/media/libmediatranscoding/include/media/TranscodingClientManager.h
+++ b/media/libmediatranscoding/include/media/TranscodingClientManager.h
@@ -29,7 +29,7 @@
#include <unordered_map>
#include <unordered_set>
-#include "SchedulerClientInterface.h"
+#include "ControllerClientInterface.h"
namespace android {
@@ -84,9 +84,9 @@
struct ClientImpl;
// Only allow MediaTranscodingService and unit tests to instantiate.
- TranscodingClientManager(const std::shared_ptr<SchedulerClientInterface>& scheduler);
+ TranscodingClientManager(const std::shared_ptr<ControllerClientInterface>& controller);
- // Checks if a user is trusted (and allowed to submit jobs on behalf of other uids)
+ // Checks if a user is trusted (and allowed to submit sessions on behalf of other uids)
bool isTrustedCallingUid(uid_t uid);
/**
@@ -108,8 +108,8 @@
::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
- std::shared_ptr<SchedulerClientInterface> mJobScheduler;
- uid_t mMediaProviderUid;
+ std::shared_ptr<ControllerClientInterface> mSessionController;
+ std::unordered_set<uid_t> mMediaProviderUid;
static std::atomic<ClientIdType> sCookieCounter;
static std::mutex sCookie2ClientLock;
diff --git a/media/libmediatranscoding/include/media/TranscodingDefs.h b/media/libmediatranscoding/include/media/TranscodingDefs.h
index 31d83ac..8e02dd2 100644
--- a/media/libmediatranscoding/include/media/TranscodingDefs.h
+++ b/media/libmediatranscoding/include/media/TranscodingDefs.h
@@ -23,7 +23,7 @@
namespace android {
using ClientIdType = uintptr_t;
-using JobIdType = int32_t;
+using SessionIdType = int32_t;
} // namespace android
#endif // ANDROID_MEDIA_TRANSCODING_DEFS_H
diff --git a/media/libmediatranscoding/include/media/TranscodingJobScheduler.h b/media/libmediatranscoding/include/media/TranscodingJobScheduler.h
deleted file mode 100644
index 7a656d5..0000000
--- a/media/libmediatranscoding/include/media/TranscodingJobScheduler.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2020 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_MEDIA_TRANSCODING_JOB_SCHEDULER_H
-#define ANDROID_MEDIA_TRANSCODING_JOB_SCHEDULER_H
-
-#include <aidl/android/media/TranscodingJobPriority.h>
-#include <media/ResourcePolicyInterface.h>
-#include <media/SchedulerClientInterface.h>
-#include <media/TranscoderInterface.h>
-#include <media/TranscodingRequest.h>
-#include <media/UidPolicyInterface.h>
-#include <utils/String8.h>
-#include <utils/Vector.h>
-
-#include <list>
-#include <map>
-#include <mutex>
-
-namespace android {
-using ::aidl::android::media::TranscodingJobPriority;
-using ::aidl::android::media::TranscodingResultParcel;
-
-class TranscodingJobScheduler : public UidPolicyCallbackInterface,
- public SchedulerClientInterface,
- public TranscoderCallbackInterface,
- public ResourcePolicyCallbackInterface {
-public:
- virtual ~TranscodingJobScheduler();
-
- // SchedulerClientInterface
- bool submit(ClientIdType clientId, JobIdType jobId, uid_t uid,
- const TranscodingRequestParcel& request,
- const std::weak_ptr<ITranscodingClientCallback>& clientCallback) override;
- bool cancel(ClientIdType clientId, JobIdType jobId) override;
- bool getJob(ClientIdType clientId, JobIdType jobId, TranscodingRequestParcel* request) override;
- // ~SchedulerClientInterface
-
- // TranscoderCallbackInterface
- void onStarted(ClientIdType clientId, JobIdType jobId) override;
- void onPaused(ClientIdType clientId, JobIdType jobId) override;
- void onResumed(ClientIdType clientId, JobIdType jobId) override;
- void onFinish(ClientIdType clientId, JobIdType jobId) override;
- void onError(ClientIdType clientId, JobIdType jobId, TranscodingErrorCode err) override;
- void onProgressUpdate(ClientIdType clientId, JobIdType jobId, int32_t progress) override;
- void onResourceLost() override;
- // ~TranscoderCallbackInterface
-
- // UidPolicyCallbackInterface
- void onTopUidsChanged(const std::unordered_set<uid_t>& uids) override;
- // ~UidPolicyCallbackInterface
-
- // ResourcePolicyCallbackInterface
- void onResourceAvailable() override;
- // ~ResourcePolicyCallbackInterface
-
- /**
- * Dump all the job information to the fd.
- */
- void dumpAllJobs(int fd, const Vector<String16>& args);
-
-private:
- friend class MediaTranscodingService;
- friend class TranscodingJobSchedulerTest;
-
- using JobKeyType = std::pair<ClientIdType, JobIdType>;
- using JobQueueType = std::list<JobKeyType>;
-
- struct Job {
- JobKeyType key;
- uid_t uid;
- enum State {
- NOT_STARTED,
- RUNNING,
- PAUSED,
- } state;
- int32_t lastProgress;
- TranscodingRequest request;
- std::weak_ptr<ITranscodingClientCallback> callback;
- };
-
- // TODO(chz): call transcoder without global lock.
- // Use mLock for all entrypoints for now.
- mutable std::mutex mLock;
-
- std::map<JobKeyType, Job> mJobMap;
-
- // uid->JobQueue map (uid == -1: offline queue)
- std::map<uid_t, JobQueueType> mJobQueues;
-
- // uids, with the head being the most-recently-top app, 2nd item is the
- // previous top app, etc.
- std::list<uid_t> mUidSortedList;
- std::list<uid_t>::iterator mOfflineUidIterator;
-
- std::shared_ptr<TranscoderInterface> mTranscoder;
- std::shared_ptr<UidPolicyInterface> mUidPolicy;
- std::shared_ptr<ResourcePolicyInterface> mResourcePolicy;
-
- Job* mCurrentJob;
- bool mResourceLost;
-
- // Only allow MediaTranscodingService and unit tests to instantiate.
- TranscodingJobScheduler(const std::shared_ptr<TranscoderInterface>& transcoder,
- const std::shared_ptr<UidPolicyInterface>& uidPolicy,
- const std::shared_ptr<ResourcePolicyInterface>& resourcePolicy);
-
- Job* getTopJob_l();
- void updateCurrentJob_l();
- void removeJob_l(const JobKeyType& jobKey);
- void moveUidsToTop_l(const std::unordered_set<uid_t>& uids, bool preserveTopUid);
- void notifyClient(ClientIdType clientId, JobIdType jobId, const char* reason,
- std::function<void(const JobKeyType&)> func);
- // Internal state verifier (debug only)
- void validateState_l();
-
- static String8 jobToString(const JobKeyType& jobKey);
- static const char* jobStateToString(const Job::State jobState);
-};
-
-} // namespace android
-#endif // ANDROID_MEDIA_TRANSCODING_JOB_SCHEDULER_H
diff --git a/media/libmediatranscoding/include/media/TranscodingRequest.h b/media/libmediatranscoding/include/media/TranscodingRequest.h
index a6cfed2..aae621f 100644
--- a/media/libmediatranscoding/include/media/TranscodingRequest.h
+++ b/media/libmediatranscoding/include/media/TranscodingRequest.h
@@ -43,7 +43,7 @@
requestedVideoTrackFormat = parcel.requestedVideoTrackFormat;
priority = parcel.priority;
requestProgressUpdate = parcel.requestProgressUpdate;
- requestJobEventUpdate = parcel.requestJobEventUpdate;
+ requestSessionEventUpdate = parcel.requestSessionEventUpdate;
isForTesting = parcel.isForTesting;
testConfig = parcel.testConfig;
}
diff --git a/media/libmediatranscoding/include/media/TranscodingSessionController.h b/media/libmediatranscoding/include/media/TranscodingSessionController.h
new file mode 100644
index 0000000..9ab3518
--- /dev/null
+++ b/media/libmediatranscoding/include/media/TranscodingSessionController.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2020 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_MEDIA_TRANSCODING_SESSION_CONTROLLER_H
+#define ANDROID_MEDIA_TRANSCODING_SESSION_CONTROLLER_H
+
+#include <aidl/android/media/TranscodingSessionPriority.h>
+#include <media/ControllerClientInterface.h>
+#include <media/ResourcePolicyInterface.h>
+#include <media/TranscoderInterface.h>
+#include <media/TranscodingRequest.h>
+#include <media/UidPolicyInterface.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+#include <list>
+#include <map>
+#include <mutex>
+
+namespace android {
+using ::aidl::android::media::TranscodingResultParcel;
+using ::aidl::android::media::TranscodingSessionPriority;
+
+class TranscodingSessionController : public UidPolicyCallbackInterface,
+ public ControllerClientInterface,
+ public TranscoderCallbackInterface,
+ public ResourcePolicyCallbackInterface {
+public:
+ virtual ~TranscodingSessionController();
+
+ // ControllerClientInterface
+ bool submit(ClientIdType clientId, SessionIdType sessionId, uid_t uid,
+ const TranscodingRequestParcel& request,
+ const std::weak_ptr<ITranscodingClientCallback>& clientCallback) override;
+ bool cancel(ClientIdType clientId, SessionIdType sessionId) override;
+ bool getSession(ClientIdType clientId, SessionIdType sessionId,
+ TranscodingRequestParcel* request) override;
+ // ~ControllerClientInterface
+
+ // TranscoderCallbackInterface
+ void onStarted(ClientIdType clientId, SessionIdType sessionId) override;
+ void onPaused(ClientIdType clientId, SessionIdType sessionId) override;
+ void onResumed(ClientIdType clientId, SessionIdType sessionId) override;
+ void onFinish(ClientIdType clientId, SessionIdType sessionId) override;
+ void onError(ClientIdType clientId, SessionIdType sessionId, TranscodingErrorCode err) override;
+ void onProgressUpdate(ClientIdType clientId, SessionIdType sessionId,
+ int32_t progress) override;
+ void onResourceLost() override;
+ // ~TranscoderCallbackInterface
+
+ // UidPolicyCallbackInterface
+ void onTopUidsChanged(const std::unordered_set<uid_t>& uids) override;
+ // ~UidPolicyCallbackInterface
+
+ // ResourcePolicyCallbackInterface
+ void onResourceAvailable() override;
+ // ~ResourcePolicyCallbackInterface
+
+ /**
+ * Dump all the session information to the fd.
+ */
+ void dumpAllSessions(int fd, const Vector<String16>& args);
+
+private:
+ friend class MediaTranscodingService;
+ friend class TranscodingSessionControllerTest;
+
+ using SessionKeyType = std::pair<ClientIdType, SessionIdType>;
+ using SessionQueueType = std::list<SessionKeyType>;
+
+ struct Session {
+ SessionKeyType key;
+ uid_t uid;
+ enum State {
+ NOT_STARTED,
+ RUNNING,
+ PAUSED,
+ } state;
+ int32_t lastProgress;
+ TranscodingRequest request;
+ std::weak_ptr<ITranscodingClientCallback> callback;
+ };
+
+ // TODO(chz): call transcoder without global lock.
+ // Use mLock for all entrypoints for now.
+ mutable std::mutex mLock;
+
+ std::map<SessionKeyType, Session> mSessionMap;
+
+ // uid->SessionQueue map (uid == -1: offline queue)
+ std::map<uid_t, SessionQueueType> mSessionQueues;
+
+ // uids, with the head being the most-recently-top app, 2nd item is the
+ // previous top app, etc.
+ std::list<uid_t> mUidSortedList;
+ std::list<uid_t>::iterator mOfflineUidIterator;
+
+ std::shared_ptr<TranscoderInterface> mTranscoder;
+ std::shared_ptr<UidPolicyInterface> mUidPolicy;
+ std::shared_ptr<ResourcePolicyInterface> mResourcePolicy;
+
+ Session* mCurrentSession;
+ bool mResourceLost;
+
+ // Only allow MediaTranscodingService and unit tests to instantiate.
+ TranscodingSessionController(const std::shared_ptr<TranscoderInterface>& transcoder,
+ const std::shared_ptr<UidPolicyInterface>& uidPolicy,
+ const std::shared_ptr<ResourcePolicyInterface>& resourcePolicy);
+
+ Session* getTopSession_l();
+ void updateCurrentSession_l();
+ void removeSession_l(const SessionKeyType& sessionKey);
+ void moveUidsToTop_l(const std::unordered_set<uid_t>& uids, bool preserveTopUid);
+ void notifyClient(ClientIdType clientId, SessionIdType sessionId, const char* reason,
+ std::function<void(const SessionKeyType&)> func);
+ // Internal state verifier (debug only)
+ void validateState_l();
+
+ static String8 sessionToString(const SessionKeyType& sessionKey);
+ static const char* sessionStateToString(const Session::State sessionState);
+};
+
+} // namespace android
+#endif // ANDROID_MEDIA_TRANSCODING_SESSION_CONTROLLER_H
diff --git a/media/libmediatranscoding/include/media/TranscodingUidPolicy.h b/media/libmediatranscoding/include/media/TranscodingUidPolicy.h
index f02b591..946770c 100644
--- a/media/libmediatranscoding/include/media/TranscodingUidPolicy.h
+++ b/media/libmediatranscoding/include/media/TranscodingUidPolicy.h
@@ -35,7 +35,7 @@
class ActivityManager;
// Observer for UID lifecycle and provide information about the uid's app
-// priority used by the job scheduler.
+// priority used by the session controller.
class TranscodingUidPolicy : public UidPolicyInterface {
public:
explicit TranscodingUidPolicy();
diff --git a/media/libmediatranscoding/include/media/UidPolicyInterface.h b/media/libmediatranscoding/include/media/UidPolicyInterface.h
index f88c1ed..05d8db0 100644
--- a/media/libmediatranscoding/include/media/UidPolicyInterface.h
+++ b/media/libmediatranscoding/include/media/UidPolicyInterface.h
@@ -23,7 +23,7 @@
class UidPolicyCallbackInterface;
-// Interface for the scheduler to query a uid's info.
+// Interface for the controller to query a uid's info.
class UidPolicyInterface {
public:
// Instruct the uid policy to start monitoring a uid.
@@ -41,7 +41,7 @@
virtual ~UidPolicyInterface() = default;
};
-// Interface for notifying the scheduler of a change in uid states.
+// Interface for notifying the controller of a change in uid states.
class UidPolicyCallbackInterface {
public:
// Called when the set of uids that's top priority among the uids of interest
diff --git a/media/libmediatranscoding/tests/AdjustableMaxPriorityQueue_tests.cpp b/media/libmediatranscoding/tests/AdjustableMaxPriorityQueue_tests.cpp
index 2e49f32..a35ca53 100644
--- a/media/libmediatranscoding/tests/AdjustableMaxPriorityQueue_tests.cpp
+++ b/media/libmediatranscoding/tests/AdjustableMaxPriorityQueue_tests.cpp
@@ -223,19 +223,19 @@
}
// Test the heap property and make sure it is the same as std::priority_queue.
-TEST(AdjustableMaxPriorityQueueTest, TranscodingJobTest) {
- // Test data structure that mimics the Transcoding job.
- struct TranscodingJob {
+TEST(AdjustableMaxPriorityQueueTest, TranscodingSessionTest) {
+ // Test data structure that mimics the Transcoding session.
+ struct TranscodingSession {
int32_t priority;
int64_t createTimeUs;
};
- // The job is arranging according to priority with highest priority comes first.
- // For the job with the same priority, the job with early createTime will come first.
- class TranscodingJobComp {
+ // The session is arranging according to priority with highest priority comes first.
+ // For the session with the same priority, the session with early createTime will come first.
+ class TranscodingSessionComp {
public:
- bool operator()(const std::unique_ptr<TranscodingJob>& lhs,
- const std::unique_ptr<TranscodingJob>& rhs) const {
+ bool operator()(const std::unique_ptr<TranscodingSession>& lhs,
+ const std::unique_ptr<TranscodingSession>& rhs) const {
if (lhs->priority != rhs->priority) {
return lhs->priority < rhs->priority;
}
@@ -244,46 +244,47 @@
};
// Map to save each value's position in the heap.
- std::unordered_map<int, TranscodingJob*> jobIdToJobMap;
+ std::unordered_map<int, TranscodingSession*> sessionIdToSessionMap;
- TranscodingJob testJobs[] = {
- {1 /*priority*/, 66 /*createTimeUs*/}, // First job,
- {2 /*priority*/, 67 /*createTimeUs*/}, // Second job,
- {2 /*priority*/, 66 /*createTimeUs*/}, // Third job,
- {3 /*priority*/, 68 /*createTimeUs*/}, // Fourth job.
+ TranscodingSession testSessions[] = {
+ {1 /*priority*/, 66 /*createTimeUs*/}, // First session,
+ {2 /*priority*/, 67 /*createTimeUs*/}, // Second session,
+ {2 /*priority*/, 66 /*createTimeUs*/}, // Third session,
+ {3 /*priority*/, 68 /*createTimeUs*/}, // Fourth session.
};
- AdjustableMaxPriorityQueue<std::unique_ptr<TranscodingJob>, TranscodingJobComp> jobQueue;
+ AdjustableMaxPriorityQueue<std::unique_ptr<TranscodingSession>, TranscodingSessionComp>
+ sessionQueue;
- // Pushes all the jobs into the heap.
- for (int jobId = 0; jobId < 4; ++jobId) {
- auto newJob = std::make_unique<TranscodingJob>(testJobs[jobId]);
- jobIdToJobMap[jobId] = newJob.get();
- EXPECT_TRUE(jobQueue.push(std::move(newJob)));
+ // Pushes all the sessions into the heap.
+ for (int sessionId = 0; sessionId < 4; ++sessionId) {
+ auto newSession = std::make_unique<TranscodingSession>(testSessions[sessionId]);
+ sessionIdToSessionMap[sessionId] = newSession.get();
+ EXPECT_TRUE(sessionQueue.push(std::move(newSession)));
}
- // Check the job queue size.
- EXPECT_EQ(4, jobQueue.size());
+ // Check the session queue size.
+ EXPECT_EQ(4, sessionQueue.size());
- // Check the top and it should be Forth job: (3, 68)
- const std::unique_ptr<TranscodingJob>& topJob = jobQueue.top();
- EXPECT_EQ(3, topJob->priority);
- EXPECT_EQ(68, topJob->createTimeUs);
+ // Check the top and it should be Forth session: (3, 68)
+ const std::unique_ptr<TranscodingSession>& topSession = sessionQueue.top();
+ EXPECT_EQ(3, topSession->priority);
+ EXPECT_EQ(68, topSession->createTimeUs);
// Consume the top.
- std::unique_ptr<TranscodingJob> consumeJob = jobQueue.consume_top();
+ std::unique_ptr<TranscodingSession> consumeSession = sessionQueue.consume_top();
- // Check the top and it should be Third Job (2, 66)
- const std::unique_ptr<TranscodingJob>& topJob2 = jobQueue.top();
- EXPECT_EQ(2, topJob2->priority);
- EXPECT_EQ(66, topJob2->createTimeUs);
+ // Check the top and it should be Third Session (2, 66)
+ const std::unique_ptr<TranscodingSession>& topSession2 = sessionQueue.top();
+ EXPECT_EQ(2, topSession2->priority);
+ EXPECT_EQ(66, topSession2->createTimeUs);
- // Change the Second job's priority to 4 from (2, 67) -> (4, 67). It should becomes top of the
- // queue.
- jobIdToJobMap[1]->priority = 4;
- jobQueue.rebuild();
- const std::unique_ptr<TranscodingJob>& topJob3 = jobQueue.top();
- EXPECT_EQ(4, topJob3->priority);
- EXPECT_EQ(67, topJob3->createTimeUs);
+ // Change the Second session's priority to 4 from (2, 67) -> (4, 67). It should becomes
+ // top of the queue.
+ sessionIdToSessionMap[1]->priority = 4;
+ sessionQueue.rebuild();
+ const std::unique_ptr<TranscodingSession>& topSession3 = sessionQueue.top();
+ EXPECT_EQ(4, topSession3->priority);
+ EXPECT_EQ(67, topSession3->createTimeUs);
}
} // namespace android
\ No newline at end of file
diff --git a/media/libmediatranscoding/tests/Android.bp b/media/libmediatranscoding/tests/Android.bp
index b54022a..7b15b1b 100644
--- a/media/libmediatranscoding/tests/Android.bp
+++ b/media/libmediatranscoding/tests/Android.bp
@@ -38,13 +38,13 @@
}
//
-// TranscodingJobScheduler unit test
+// TranscodingSessionController unit test
//
cc_test {
- name: "TranscodingJobScheduler_tests",
+ name: "TranscodingSessionController_tests",
defaults: ["libmediatranscoding_test_defaults"],
- srcs: ["TranscodingJobScheduler_tests.cpp"],
+ srcs: ["TranscodingSessionController_tests.cpp"],
}
//
diff --git a/media/libmediatranscoding/tests/TranscodingClientManager_tests.cpp b/media/libmediatranscoding/tests/TranscodingClientManager_tests.cpp
index c2ca9b4..1a50923 100644
--- a/media/libmediatranscoding/tests/TranscodingClientManager_tests.cpp
+++ b/media/libmediatranscoding/tests/TranscodingClientManager_tests.cpp
@@ -25,7 +25,7 @@
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <gtest/gtest.h>
-#include <media/SchedulerClientInterface.h>
+#include <media/ControllerClientInterface.h>
#include <media/TranscodingClientManager.h>
#include <media/TranscodingRequest.h>
#include <utils/Log.h>
@@ -38,10 +38,10 @@
using ::aidl::android::media::BnTranscodingClientCallback;
using ::aidl::android::media::IMediaTranscodingService;
using ::aidl::android::media::TranscodingErrorCode;
-using ::aidl::android::media::TranscodingJobParcel;
-using ::aidl::android::media::TranscodingJobPriority;
using ::aidl::android::media::TranscodingRequestParcel;
using ::aidl::android::media::TranscodingResultParcel;
+using ::aidl::android::media::TranscodingSessionParcel;
+using ::aidl::android::media::TranscodingSessionPriority;
constexpr pid_t kInvalidClientPid = -5;
constexpr pid_t kInvalidClientUid = -10;
@@ -51,7 +51,7 @@
constexpr const char* kClientName = "TestClientName";
constexpr const char* kClientPackage = "TestClientPackage";
-#define JOB(n) (n)
+#define SESSION(n) (n)
struct TestClientCallback : public BnTranscodingClientCallback {
TestClientCallback() { ALOGI("TestClientCallback Created"); }
@@ -63,30 +63,32 @@
return Status::ok();
}
- Status onTranscodingStarted(int32_t /*in_jobId*/) override { return Status::ok(); }
+ Status onTranscodingStarted(int32_t /*in_sessionId*/) override { return Status::ok(); }
- Status onTranscodingPaused(int32_t /*in_jobId*/) override { return Status::ok(); }
+ Status onTranscodingPaused(int32_t /*in_sessionId*/) override { return Status::ok(); }
- Status onTranscodingResumed(int32_t /*in_jobId*/) override { return Status::ok(); }
+ Status onTranscodingResumed(int32_t /*in_sessionId*/) override { return Status::ok(); }
- Status onTranscodingFinished(int32_t in_jobId,
+ Status onTranscodingFinished(int32_t in_sessionId,
const TranscodingResultParcel& in_result) override {
- EXPECT_EQ(in_jobId, in_result.jobId);
- mEventQueue.push_back(Finished(in_jobId));
+ EXPECT_EQ(in_sessionId, in_result.sessionId);
+ mEventQueue.push_back(Finished(in_sessionId));
return Status::ok();
}
- Status onTranscodingFailed(int32_t in_jobId, TranscodingErrorCode /*in_errorCode */) override {
- mEventQueue.push_back(Failed(in_jobId));
+ Status onTranscodingFailed(int32_t in_sessionId,
+ TranscodingErrorCode /*in_errorCode */) override {
+ mEventQueue.push_back(Failed(in_sessionId));
return Status::ok();
}
- Status onAwaitNumberOfJobsChanged(int32_t /* in_jobId */, int32_t /* in_oldAwaitNumber */,
- int32_t /* in_newAwaitNumber */) override {
+ Status onAwaitNumberOfSessionsChanged(int32_t /* in_sessionId */,
+ int32_t /* in_oldAwaitNumber */,
+ int32_t /* in_newAwaitNumber */) override {
return Status::ok();
}
- Status onProgressUpdate(int32_t /* in_jobId */, int32_t /* in_progress */) override {
+ Status onProgressUpdate(int32_t /* in_sessionId */, int32_t /* in_progress */) override {
return Status::ok();
}
@@ -96,12 +98,12 @@
Finished,
Failed,
} type;
- JobIdType jobId;
+ SessionIdType sessionId;
};
static constexpr Event NoEvent = {Event::NoEvent, 0};
#define DECLARE_EVENT(action) \
- static Event action(JobIdType jobId) { return {Event::action, jobId}; }
+ static Event action(SessionIdType sessionId) { return {Event::action, sessionId}; }
DECLARE_EVENT(Finished);
DECLARE_EVENT(Failed);
@@ -125,102 +127,102 @@
};
bool operator==(const TestClientCallback::Event& lhs, const TestClientCallback::Event& rhs) {
- return lhs.type == rhs.type && lhs.jobId == rhs.jobId;
+ return lhs.type == rhs.type && lhs.sessionId == rhs.sessionId;
}
-struct TestScheduler : public SchedulerClientInterface {
- TestScheduler() { ALOGI("TestScheduler Created"); }
+struct TestController : public ControllerClientInterface {
+ TestController() { ALOGI("TestController Created"); }
- virtual ~TestScheduler() { ALOGI("TestScheduler Destroyed"); }
+ virtual ~TestController() { ALOGI("TestController Destroyed"); }
- bool submit(ClientIdType clientId, JobIdType jobId, uid_t /*uid*/,
+ bool submit(ClientIdType clientId, SessionIdType sessionId, uid_t /*uid*/,
const TranscodingRequestParcel& request,
const std::weak_ptr<ITranscodingClientCallback>& clientCallback) override {
- JobKeyType jobKey = std::make_pair(clientId, jobId);
- if (mJobs.count(jobKey) > 0) {
+ SessionKeyType sessionKey = std::make_pair(clientId, sessionId);
+ if (mSessions.count(sessionKey) > 0) {
return false;
}
// This is the secret name we'll check, to test error propagation from
- // the scheduler back to client.
+ // the controller back to client.
if (request.sourceFilePath == "bad_source_file") {
return false;
}
- mJobs[jobKey].request = request;
- mJobs[jobKey].callback = clientCallback;
+ mSessions[sessionKey].request = request;
+ mSessions[sessionKey].callback = clientCallback;
- mLastJob = jobKey;
+ mLastSession = sessionKey;
return true;
}
- bool cancel(ClientIdType clientId, JobIdType jobId) override {
- JobKeyType jobKey = std::make_pair(clientId, jobId);
+ bool cancel(ClientIdType clientId, SessionIdType sessionId) override {
+ SessionKeyType sessionKey = std::make_pair(clientId, sessionId);
- if (mJobs.count(jobKey) == 0) {
+ if (mSessions.count(sessionKey) == 0) {
return false;
}
- mJobs.erase(jobKey);
+ mSessions.erase(sessionKey);
return true;
}
- bool getJob(ClientIdType clientId, JobIdType jobId,
- TranscodingRequestParcel* request) override {
- JobKeyType jobKey = std::make_pair(clientId, jobId);
- if (mJobs.count(jobKey) == 0) {
+ bool getSession(ClientIdType clientId, SessionIdType sessionId,
+ TranscodingRequestParcel* request) override {
+ SessionKeyType sessionKey = std::make_pair(clientId, sessionId);
+ if (mSessions.count(sessionKey) == 0) {
return false;
}
- *(TranscodingRequest*)request = mJobs[jobKey].request;
+ *(TranscodingRequest*)request = mSessions[sessionKey].request;
return true;
}
- void finishLastJob() {
- auto it = mJobs.find(mLastJob);
- if (it == mJobs.end()) {
+ void finishLastSession() {
+ auto it = mSessions.find(mLastSession);
+ if (it == mSessions.end()) {
return;
}
{
auto clientCallback = it->second.callback.lock();
if (clientCallback != nullptr) {
clientCallback->onTranscodingFinished(
- mLastJob.second,
- TranscodingResultParcel({mLastJob.second, 0, std::nullopt}));
+ mLastSession.second,
+ TranscodingResultParcel({mLastSession.second, 0, std::nullopt}));
}
}
- mJobs.erase(it);
+ mSessions.erase(it);
}
- void abortLastJob() {
- auto it = mJobs.find(mLastJob);
- if (it == mJobs.end()) {
+ void abortLastSession() {
+ auto it = mSessions.find(mLastSession);
+ if (it == mSessions.end()) {
return;
}
{
auto clientCallback = it->second.callback.lock();
if (clientCallback != nullptr) {
- clientCallback->onTranscodingFailed(mLastJob.second,
+ clientCallback->onTranscodingFailed(mLastSession.second,
TranscodingErrorCode::kUnknown);
}
}
- mJobs.erase(it);
+ mSessions.erase(it);
}
- struct Job {
+ struct Session {
TranscodingRequest request;
std::weak_ptr<ITranscodingClientCallback> callback;
};
- typedef std::pair<ClientIdType, JobIdType> JobKeyType;
- std::map<JobKeyType, Job> mJobs;
- JobKeyType mLastJob;
+ typedef std::pair<ClientIdType, SessionIdType> SessionKeyType;
+ std::map<SessionKeyType, Session> mSessions;
+ SessionKeyType mLastSession;
};
class TranscodingClientManagerTest : public ::testing::Test {
public:
TranscodingClientManagerTest()
- : mScheduler(new TestScheduler()),
- mClientManager(new TranscodingClientManager(mScheduler)) {
+ : mController(new TestController()),
+ mClientManager(new TranscodingClientManager(mController)) {
ALOGD("TranscodingClientManagerTest created");
}
@@ -260,7 +262,7 @@
EXPECT_EQ(mClientManager->getNumOfClients(), 0);
}
- std::shared_ptr<TestScheduler> mScheduler;
+ std::shared_ptr<TestController> mController;
std::shared_ptr<TranscodingClientManager> mClientManager;
std::shared_ptr<ITranscodingClient> mClient1;
std::shared_ptr<ITranscodingClient> mClient2;
@@ -349,36 +351,36 @@
unregisterMultipleClients();
}
-TEST_F(TranscodingClientManagerTest, TestSubmitCancelGetJobs) {
+TEST_F(TranscodingClientManagerTest, TestSubmitCancelGetSessions) {
addMultipleClients();
- // Test jobId assignment.
+ // Test sessionId assignment.
TranscodingRequestParcel request;
request.sourceFilePath = "test_source_file_0";
request.destinationFilePath = "test_desintaion_file_0";
- TranscodingJobParcel job;
+ TranscodingSessionParcel session;
bool result;
- EXPECT_TRUE(mClient1->submitRequest(request, &job, &result).isOk());
+ EXPECT_TRUE(mClient1->submitRequest(request, &session, &result).isOk());
EXPECT_TRUE(result);
- EXPECT_EQ(job.jobId, JOB(0));
+ EXPECT_EQ(session.sessionId, SESSION(0));
request.sourceFilePath = "test_source_file_1";
request.destinationFilePath = "test_desintaion_file_1";
- EXPECT_TRUE(mClient1->submitRequest(request, &job, &result).isOk());
+ EXPECT_TRUE(mClient1->submitRequest(request, &session, &result).isOk());
EXPECT_TRUE(result);
- EXPECT_EQ(job.jobId, JOB(1));
+ EXPECT_EQ(session.sessionId, SESSION(1));
request.sourceFilePath = "test_source_file_2";
request.destinationFilePath = "test_desintaion_file_2";
- EXPECT_TRUE(mClient1->submitRequest(request, &job, &result).isOk());
+ EXPECT_TRUE(mClient1->submitRequest(request, &session, &result).isOk());
EXPECT_TRUE(result);
- EXPECT_EQ(job.jobId, JOB(2));
+ EXPECT_EQ(session.sessionId, SESSION(2));
// Test submit bad request (no valid sourceFilePath) fails.
TranscodingRequestParcel badRequest;
badRequest.sourceFilePath = "bad_source_file";
badRequest.destinationFilePath = "bad_destination_file";
- EXPECT_TRUE(mClient1->submitRequest(badRequest, &job, &result).isOk());
+ EXPECT_TRUE(mClient1->submitRequest(badRequest, &session, &result).isOk());
EXPECT_FALSE(result);
// Test submit with bad pid/uid.
@@ -386,49 +388,49 @@
badRequest.destinationFilePath = "test_desintaion_file_3";
badRequest.clientPid = kInvalidClientPid;
badRequest.clientUid = kInvalidClientUid;
- EXPECT_TRUE(mClient1->submitRequest(badRequest, &job, &result).isOk());
+ EXPECT_TRUE(mClient1->submitRequest(badRequest, &session, &result).isOk());
EXPECT_FALSE(result);
- // Test get jobs by id.
- EXPECT_TRUE(mClient1->getJobWithId(JOB(2), &job, &result).isOk());
- EXPECT_EQ(job.jobId, JOB(2));
- EXPECT_EQ(job.request.sourceFilePath, "test_source_file_2");
+ // Test get sessions by id.
+ EXPECT_TRUE(mClient1->getSessionWithId(SESSION(2), &session, &result).isOk());
+ EXPECT_EQ(session.sessionId, SESSION(2));
+ EXPECT_EQ(session.request.sourceFilePath, "test_source_file_2");
EXPECT_TRUE(result);
- // Test get jobs by invalid id fails.
- EXPECT_TRUE(mClient1->getJobWithId(JOB(100), &job, &result).isOk());
+ // Test get sessions by invalid id fails.
+ EXPECT_TRUE(mClient1->getSessionWithId(SESSION(100), &session, &result).isOk());
EXPECT_FALSE(result);
- // Test cancel non-existent job fail.
- EXPECT_TRUE(mClient2->cancelJob(JOB(100), &result).isOk());
+ // Test cancel non-existent session fail.
+ EXPECT_TRUE(mClient2->cancelSession(SESSION(100), &result).isOk());
EXPECT_FALSE(result);
- // Test cancel valid jobId in arbitrary order.
- EXPECT_TRUE(mClient1->cancelJob(JOB(2), &result).isOk());
+ // Test cancel valid sessionId in arbitrary order.
+ EXPECT_TRUE(mClient1->cancelSession(SESSION(2), &result).isOk());
EXPECT_TRUE(result);
- EXPECT_TRUE(mClient1->cancelJob(JOB(0), &result).isOk());
+ EXPECT_TRUE(mClient1->cancelSession(SESSION(0), &result).isOk());
EXPECT_TRUE(result);
- EXPECT_TRUE(mClient1->cancelJob(JOB(1), &result).isOk());
+ EXPECT_TRUE(mClient1->cancelSession(SESSION(1), &result).isOk());
EXPECT_TRUE(result);
- // Test cancel job again fails.
- EXPECT_TRUE(mClient1->cancelJob(JOB(1), &result).isOk());
+ // Test cancel session again fails.
+ EXPECT_TRUE(mClient1->cancelSession(SESSION(1), &result).isOk());
EXPECT_FALSE(result);
- // Test get job after cancel fails.
- EXPECT_TRUE(mClient1->getJobWithId(JOB(2), &job, &result).isOk());
+ // Test get session after cancel fails.
+ EXPECT_TRUE(mClient1->getSessionWithId(SESSION(2), &session, &result).isOk());
EXPECT_FALSE(result);
- // Test jobId independence for each client.
- EXPECT_TRUE(mClient2->submitRequest(request, &job, &result).isOk());
+ // Test sessionId independence for each client.
+ EXPECT_TRUE(mClient2->submitRequest(request, &session, &result).isOk());
EXPECT_TRUE(result);
- EXPECT_EQ(job.jobId, JOB(0));
+ EXPECT_EQ(session.sessionId, SESSION(0));
- EXPECT_TRUE(mClient2->submitRequest(request, &job, &result).isOk());
+ EXPECT_TRUE(mClient2->submitRequest(request, &session, &result).isOk());
EXPECT_TRUE(result);
- EXPECT_EQ(job.jobId, JOB(1));
+ EXPECT_EQ(session.sessionId, SESSION(1));
unregisterMultipleClients();
}
@@ -439,32 +441,32 @@
TranscodingRequestParcel request;
request.sourceFilePath = "test_source_file_name";
request.destinationFilePath = "test_destination_file_name";
- TranscodingJobParcel job;
+ TranscodingSessionParcel session;
bool result;
- EXPECT_TRUE(mClient1->submitRequest(request, &job, &result).isOk());
+ EXPECT_TRUE(mClient1->submitRequest(request, &session, &result).isOk());
EXPECT_TRUE(result);
- EXPECT_EQ(job.jobId, JOB(0));
+ EXPECT_EQ(session.sessionId, SESSION(0));
- mScheduler->finishLastJob();
- EXPECT_EQ(mClientCallback1->popEvent(), TestClientCallback::Finished(job.jobId));
+ mController->finishLastSession();
+ EXPECT_EQ(mClientCallback1->popEvent(), TestClientCallback::Finished(session.sessionId));
- EXPECT_TRUE(mClient1->submitRequest(request, &job, &result).isOk());
+ EXPECT_TRUE(mClient1->submitRequest(request, &session, &result).isOk());
EXPECT_TRUE(result);
- EXPECT_EQ(job.jobId, JOB(1));
+ EXPECT_EQ(session.sessionId, SESSION(1));
- mScheduler->abortLastJob();
- EXPECT_EQ(mClientCallback1->popEvent(), TestClientCallback::Failed(job.jobId));
+ mController->abortLastSession();
+ EXPECT_EQ(mClientCallback1->popEvent(), TestClientCallback::Failed(session.sessionId));
- EXPECT_TRUE(mClient1->submitRequest(request, &job, &result).isOk());
+ EXPECT_TRUE(mClient1->submitRequest(request, &session, &result).isOk());
EXPECT_TRUE(result);
- EXPECT_EQ(job.jobId, JOB(2));
+ EXPECT_EQ(session.sessionId, SESSION(2));
- EXPECT_TRUE(mClient2->submitRequest(request, &job, &result).isOk());
+ EXPECT_TRUE(mClient2->submitRequest(request, &session, &result).isOk());
EXPECT_TRUE(result);
- EXPECT_EQ(job.jobId, JOB(0));
+ EXPECT_EQ(session.sessionId, SESSION(0));
- mScheduler->finishLastJob();
- EXPECT_EQ(mClientCallback2->popEvent(), TestClientCallback::Finished(job.jobId));
+ mController->finishLastSession();
+ EXPECT_EQ(mClientCallback2->popEvent(), TestClientCallback::Finished(session.sessionId));
unregisterMultipleClients();
}
@@ -479,20 +481,20 @@
// Submit 2 requests, 1 offline and 1 realtime.
TranscodingRequestParcel request;
- TranscodingJobParcel job;
+ TranscodingSessionParcel session;
bool result;
request.sourceFilePath = "test_source_file_0";
request.destinationFilePath = "test_destination_file_0";
- request.priority = TranscodingJobPriority::kUnspecified;
- EXPECT_TRUE(client->submitRequest(request, &job, &result).isOk() && result);
- EXPECT_EQ(job.jobId, JOB(0));
+ request.priority = TranscodingSessionPriority::kUnspecified;
+ EXPECT_TRUE(client->submitRequest(request, &session, &result).isOk() && result);
+ EXPECT_EQ(session.sessionId, SESSION(0));
request.sourceFilePath = "test_source_file_1";
request.destinationFilePath = "test_destination_file_1";
- request.priority = TranscodingJobPriority::kNormal;
- EXPECT_TRUE(client->submitRequest(request, &job, &result).isOk() && result);
- EXPECT_EQ(job.jobId, JOB(1));
+ request.priority = TranscodingSessionPriority::kNormal;
+ EXPECT_TRUE(client->submitRequest(request, &session, &result).isOk() && result);
+ EXPECT_EQ(session.sessionId, SESSION(1));
// Unregister client, should succeed.
Status status = client->unregister();
@@ -501,36 +503,36 @@
// Test submit new request after unregister, should fail with ERROR_DISCONNECTED.
request.sourceFilePath = "test_source_file_2";
request.destinationFilePath = "test_destination_file_2";
- request.priority = TranscodingJobPriority::kNormal;
- status = client->submitRequest(request, &job, &result);
+ request.priority = TranscodingSessionPriority::kNormal;
+ status = client->submitRequest(request, &session, &result);
EXPECT_FALSE(status.isOk());
EXPECT_EQ(status.getServiceSpecificError(), IMediaTranscodingService::ERROR_DISCONNECTED);
- // Test cancel jobs after unregister, should fail with ERROR_DISCONNECTED
- // regardless of realtime or offline job, or whether the jobId is valid.
- status = client->cancelJob(JOB(0), &result);
+ // Test cancel sessions after unregister, should fail with ERROR_DISCONNECTED
+ // regardless of realtime or offline session, or whether the sessionId is valid.
+ status = client->cancelSession(SESSION(0), &result);
EXPECT_FALSE(status.isOk());
EXPECT_EQ(status.getServiceSpecificError(), IMediaTranscodingService::ERROR_DISCONNECTED);
- status = client->cancelJob(JOB(1), &result);
+ status = client->cancelSession(SESSION(1), &result);
EXPECT_FALSE(status.isOk());
EXPECT_EQ(status.getServiceSpecificError(), IMediaTranscodingService::ERROR_DISCONNECTED);
- status = client->cancelJob(JOB(2), &result);
+ status = client->cancelSession(SESSION(2), &result);
EXPECT_FALSE(status.isOk());
EXPECT_EQ(status.getServiceSpecificError(), IMediaTranscodingService::ERROR_DISCONNECTED);
- // Test get jobs, should fail with ERROR_DISCONNECTED regardless of realtime
- // or offline job, or whether the jobId is valid.
- status = client->getJobWithId(JOB(0), &job, &result);
+ // Test get sessions, should fail with ERROR_DISCONNECTED regardless of realtime
+ // or offline session, or whether the sessionId is valid.
+ status = client->getSessionWithId(SESSION(0), &session, &result);
EXPECT_FALSE(status.isOk());
EXPECT_EQ(status.getServiceSpecificError(), IMediaTranscodingService::ERROR_DISCONNECTED);
- status = client->getJobWithId(JOB(1), &job, &result);
+ status = client->getSessionWithId(SESSION(1), &session, &result);
EXPECT_FALSE(status.isOk());
EXPECT_EQ(status.getServiceSpecificError(), IMediaTranscodingService::ERROR_DISCONNECTED);
- status = client->getJobWithId(JOB(2), &job, &result);
+ status = client->getSessionWithId(SESSION(2), &session, &result);
EXPECT_FALSE(status.isOk());
EXPECT_EQ(status.getServiceSpecificError(), IMediaTranscodingService::ERROR_DISCONNECTED);
}
diff --git a/media/libmediatranscoding/tests/TranscodingJobScheduler_tests.cpp b/media/libmediatranscoding/tests/TranscodingJobScheduler_tests.cpp
deleted file mode 100644
index 9b9df87..0000000
--- a/media/libmediatranscoding/tests/TranscodingJobScheduler_tests.cpp
+++ /dev/null
@@ -1,603 +0,0 @@
-/*
- * Copyright (C) 2020 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.
- */
-
-// Unit Test for TranscodingJobScheduler
-
-// #define LOG_NDEBUG 0
-#define LOG_TAG "TranscodingJobSchedulerTest"
-
-#include <aidl/android/media/BnTranscodingClientCallback.h>
-#include <aidl/android/media/IMediaTranscodingService.h>
-#include <aidl/android/media/ITranscodingClient.h>
-#include <aidl/android/media/ITranscodingClientCallback.h>
-#include <android-base/logging.h>
-#include <android/binder_manager.h>
-#include <android/binder_process.h>
-#include <gtest/gtest.h>
-#include <media/TranscodingClientManager.h>
-#include <media/TranscodingJobScheduler.h>
-#include <utils/Log.h>
-
-#include <unordered_set>
-
-namespace android {
-
-using Status = ::ndk::ScopedAStatus;
-using aidl::android::media::BnTranscodingClientCallback;
-using aidl::android::media::IMediaTranscodingService;
-using aidl::android::media::ITranscodingClient;
-using aidl::android::media::TranscodingRequestParcel;
-
-constexpr ClientIdType kClientId = 1000;
-constexpr JobIdType kClientJobId = 0;
-constexpr uid_t kClientUid = 5000;
-constexpr uid_t kInvalidUid = (uid_t)-1;
-
-#define CLIENT(n) (kClientId + (n))
-#define JOB(n) (kClientJobId + (n))
-#define UID(n) (kClientUid + (n))
-
-class TestUidPolicy : public UidPolicyInterface {
-public:
- TestUidPolicy() = default;
- virtual ~TestUidPolicy() = default;
-
- // UidPolicyInterface
- void registerMonitorUid(uid_t /*uid*/) override {}
- void unregisterMonitorUid(uid_t /*uid*/) override {}
- bool isUidOnTop(uid_t uid) override { return mTopUids.count(uid) > 0; }
- std::unordered_set<uid_t> getTopUids() const override { return mTopUids; }
- void setCallback(const std::shared_ptr<UidPolicyCallbackInterface>& cb) override {
- mUidPolicyCallback = cb;
- }
- void setTop(uid_t uid) {
- std::unordered_set<uid_t> uids = {uid};
- setTop(uids);
- }
- void setTop(const std::unordered_set<uid_t>& uids) {
- mTopUids = uids;
- auto uidPolicyCb = mUidPolicyCallback.lock();
- if (uidPolicyCb != nullptr) {
- uidPolicyCb->onTopUidsChanged(mTopUids);
- }
- }
-
- std::unordered_set<uid_t> mTopUids;
- std::weak_ptr<UidPolicyCallbackInterface> mUidPolicyCallback;
-};
-
-class TestTranscoder : public TranscoderInterface {
-public:
- TestTranscoder() : mLastError(TranscodingErrorCode::kUnknown) {}
- virtual ~TestTranscoder() {}
-
- // TranscoderInterface
- void setCallback(const std::shared_ptr<TranscoderCallbackInterface>& /*cb*/) override {}
-
- void start(ClientIdType clientId, JobIdType jobId, const TranscodingRequestParcel& /*request*/,
- const std::shared_ptr<ITranscodingClientCallback>& /*clientCallback*/) override {
- mEventQueue.push_back(Start(clientId, jobId));
- }
- void pause(ClientIdType clientId, JobIdType jobId) override {
- mEventQueue.push_back(Pause(clientId, jobId));
- }
- void resume(ClientIdType clientId, JobIdType jobId, const TranscodingRequestParcel& /*request*/,
- const std::shared_ptr<ITranscodingClientCallback>& /*clientCallback*/) override {
- mEventQueue.push_back(Resume(clientId, jobId));
- }
- void stop(ClientIdType clientId, JobIdType jobId) override {
- mEventQueue.push_back(Stop(clientId, jobId));
- }
-
- void onFinished(ClientIdType clientId, JobIdType jobId) {
- mEventQueue.push_back(Finished(clientId, jobId));
- }
-
- void onFailed(ClientIdType clientId, JobIdType jobId, TranscodingErrorCode err) {
- mLastError = err;
- mEventQueue.push_back(Failed(clientId, jobId));
- }
-
- TranscodingErrorCode getLastError() {
- TranscodingErrorCode result = mLastError;
- mLastError = TranscodingErrorCode::kUnknown;
- return result;
- }
-
- struct Event {
- enum { NoEvent, Start, Pause, Resume, Stop, Finished, Failed } type;
- ClientIdType clientId;
- JobIdType jobId;
- };
-
- static constexpr Event NoEvent = {Event::NoEvent, 0, 0};
-
-#define DECLARE_EVENT(action) \
- static Event action(ClientIdType clientId, JobIdType jobId) { \
- return {Event::action, clientId, jobId}; \
- }
-
- DECLARE_EVENT(Start);
- DECLARE_EVENT(Pause);
- DECLARE_EVENT(Resume);
- DECLARE_EVENT(Stop);
- DECLARE_EVENT(Finished);
- DECLARE_EVENT(Failed);
-
- const Event& popEvent() {
- if (mEventQueue.empty()) {
- mPoppedEvent = NoEvent;
- } else {
- mPoppedEvent = *mEventQueue.begin();
- mEventQueue.pop_front();
- }
- return mPoppedEvent;
- }
-
-private:
- Event mPoppedEvent;
- std::list<Event> mEventQueue;
- TranscodingErrorCode mLastError;
-};
-
-bool operator==(const TestTranscoder::Event& lhs, const TestTranscoder::Event& rhs) {
- return lhs.type == rhs.type && lhs.clientId == rhs.clientId && lhs.jobId == rhs.jobId;
-}
-
-struct TestClientCallback : public BnTranscodingClientCallback {
- TestClientCallback(TestTranscoder* owner, int64_t clientId)
- : mOwner(owner), mClientId(clientId) {
- ALOGD("TestClient Created");
- }
-
- Status openFileDescriptor(const std::string& /*in_fileUri*/, const std::string& /*in_mode*/,
- ::ndk::ScopedFileDescriptor* /*_aidl_return*/) override {
- return Status::ok();
- }
-
- Status onTranscodingStarted(int32_t /*in_jobId*/) override { return Status::ok(); }
-
- Status onTranscodingPaused(int32_t /*in_jobId*/) override { return Status::ok(); }
-
- Status onTranscodingResumed(int32_t /*in_jobId*/) override { return Status::ok(); }
-
- Status onTranscodingFinished(int32_t in_jobId,
- const TranscodingResultParcel& in_result) override {
- EXPECT_EQ(in_jobId, in_result.jobId);
- ALOGD("TestClientCallback: received onTranscodingFinished");
- mOwner->onFinished(mClientId, in_jobId);
- return Status::ok();
- }
-
- Status onTranscodingFailed(int32_t in_jobId, TranscodingErrorCode in_errorCode) override {
- mOwner->onFailed(mClientId, in_jobId, in_errorCode);
- return Status::ok();
- }
-
- Status onAwaitNumberOfJobsChanged(int32_t /* in_jobId */, int32_t /* in_oldAwaitNumber */,
- int32_t /* in_newAwaitNumber */) override {
- return Status::ok();
- }
-
- Status onProgressUpdate(int32_t /* in_jobId */, int32_t /* in_progress */) override {
- return Status::ok();
- }
-
- virtual ~TestClientCallback() { ALOGI("TestClient destroyed"); };
-
-private:
- TestTranscoder* mOwner;
- int64_t mClientId;
- TestClientCallback(const TestClientCallback&) = delete;
- TestClientCallback& operator=(const TestClientCallback&) = delete;
-};
-
-class TranscodingJobSchedulerTest : public ::testing::Test {
-public:
- TranscodingJobSchedulerTest() { ALOGI("TranscodingJobSchedulerTest created"); }
-
- void SetUp() override {
- ALOGI("TranscodingJobSchedulerTest set up");
- mTranscoder.reset(new TestTranscoder());
- mUidPolicy.reset(new TestUidPolicy());
- mScheduler.reset(
- new TranscodingJobScheduler(mTranscoder, mUidPolicy, nullptr /*resourcePolicy*/));
- mUidPolicy->setCallback(mScheduler);
-
- // Set priority only, ignore other fields for now.
- mOfflineRequest.priority = TranscodingJobPriority::kUnspecified;
- mRealtimeRequest.priority = TranscodingJobPriority::kHigh;
- mClientCallback0 =
- ::ndk::SharedRefBase::make<TestClientCallback>(mTranscoder.get(), CLIENT(0));
- mClientCallback1 =
- ::ndk::SharedRefBase::make<TestClientCallback>(mTranscoder.get(), CLIENT(1));
- mClientCallback2 =
- ::ndk::SharedRefBase::make<TestClientCallback>(mTranscoder.get(), CLIENT(2));
- mClientCallback3 =
- ::ndk::SharedRefBase::make<TestClientCallback>(mTranscoder.get(), CLIENT(3));
- }
-
- void TearDown() override { ALOGI("TranscodingJobSchedulerTest tear down"); }
-
- ~TranscodingJobSchedulerTest() { ALOGD("TranscodingJobSchedulerTest destroyed"); }
-
- std::shared_ptr<TestTranscoder> mTranscoder;
- std::shared_ptr<TestUidPolicy> mUidPolicy;
- std::shared_ptr<TranscodingJobScheduler> mScheduler;
- TranscodingRequestParcel mOfflineRequest;
- TranscodingRequestParcel mRealtimeRequest;
- std::shared_ptr<TestClientCallback> mClientCallback0;
- std::shared_ptr<TestClientCallback> mClientCallback1;
- std::shared_ptr<TestClientCallback> mClientCallback2;
- std::shared_ptr<TestClientCallback> mClientCallback3;
-};
-
-TEST_F(TranscodingJobSchedulerTest, TestSubmitJob) {
- ALOGD("TestSubmitJob");
-
- // Start with UID(1) on top.
- mUidPolicy->setTop(UID(1));
-
- // Submit offline job to CLIENT(0) in UID(0).
- // Should start immediately (because this is the only job).
- mScheduler->submit(CLIENT(0), JOB(0), UID(0), mOfflineRequest, mClientCallback0);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), 0));
-
- // Submit real-time job to CLIENT(0).
- // Should pause offline job and start new job, even if UID(0) is not on top.
- mScheduler->submit(CLIENT(0), JOB(1), UID(0), mRealtimeRequest, mClientCallback0);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(1)));
-
- // Submit real-time job to CLIENT(0), should be queued after the previous job.
- mScheduler->submit(CLIENT(0), JOB(2), UID(0), mRealtimeRequest, mClientCallback0);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
-
- // Submit real-time job to CLIENT(1) in same uid, should be queued after the previous job.
- mScheduler->submit(CLIENT(1), JOB(0), UID(0), mRealtimeRequest, mClientCallback1);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
-
- // Submit real-time job to CLIENT(2) in UID(1).
- // Should pause previous job and start new job, because UID(1) is (has been) top.
- mScheduler->submit(CLIENT(2), JOB(0), UID(1), mRealtimeRequest, mClientCallback2);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(1)));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), JOB(0)));
-
- // Submit offline job, shouldn't generate any event.
- mScheduler->submit(CLIENT(2), JOB(1), UID(1), mOfflineRequest, mClientCallback2);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
-
- // Bring UID(0) to top.
- mUidPolicy->setTop(UID(0));
- // Should pause current job, and resume last job in UID(0).
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(2), JOB(0)));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(1)));
-}
-
-TEST_F(TranscodingJobSchedulerTest, TestCancelJob) {
- ALOGD("TestCancelJob");
-
- // Submit real-time job JOB(0), should start immediately.
- mScheduler->submit(CLIENT(0), JOB(0), UID(0), mRealtimeRequest, mClientCallback0);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
-
- // Submit real-time job JOB(1), should not start.
- mScheduler->submit(CLIENT(0), JOB(1), UID(0), mRealtimeRequest, mClientCallback0);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
-
- // Submit offline job JOB(2), should not start.
- mScheduler->submit(CLIENT(0), JOB(2), UID(0), mOfflineRequest, mClientCallback0);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
-
- // Cancel queued real-time job.
- // Cancel real-time job JOB(1), should be cancelled.
- EXPECT_TRUE(mScheduler->cancel(CLIENT(0), JOB(1)));
-
- // Cancel queued offline job.
- // Cancel offline job JOB(2), should be cancelled.
- EXPECT_TRUE(mScheduler->cancel(CLIENT(0), JOB(2)));
-
- // Submit offline job JOB(3), shouldn't cause any event.
- mScheduler->submit(CLIENT(0), JOB(3), UID(0), mOfflineRequest, mClientCallback0);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
-
- // Cancel running real-time job JOB(0).
- // - Should be stopped first then cancelled.
- // - Should also start offline job JOB(2) because real-time queue is empty.
- EXPECT_TRUE(mScheduler->cancel(CLIENT(0), JOB(0)));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Stop(CLIENT(0), JOB(0)));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(3)));
-
- // Submit real-time job JOB(4), offline JOB(3) should pause and JOB(4) should start.
- mScheduler->submit(CLIENT(0), JOB(4), UID(0), mRealtimeRequest, mClientCallback0);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(3)));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(4)));
-
- // Cancel paused JOB(3). JOB(3) should be stopped.
- EXPECT_TRUE(mScheduler->cancel(CLIENT(0), JOB(3)));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Stop(CLIENT(0), JOB(3)));
-}
-
-TEST_F(TranscodingJobSchedulerTest, TestFinishJob) {
- ALOGD("TestFinishJob");
-
- // Start with unspecified top UID.
- // Finish without any jobs submitted, should be ignored.
- mScheduler->onFinish(CLIENT(0), JOB(0));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
-
- // Submit offline job JOB(0), should start immediately.
- mScheduler->submit(CLIENT(0), JOB(0), UID(0), mOfflineRequest, mClientCallback0);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
-
- // Submit real-time job JOB(1), should pause offline job and start immediately.
- mScheduler->submit(CLIENT(0), JOB(1), UID(0), mRealtimeRequest, mClientCallback0);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(1)));
-
- // Submit real-time job JOB(2), should not start.
- mScheduler->submit(CLIENT(0), JOB(2), UID(0), mRealtimeRequest, mClientCallback0);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
-
- // Finish when the job never started, should be ignored.
- mScheduler->onFinish(CLIENT(0), JOB(2));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
-
- // UID(1) moves to top.
- mUidPolicy->setTop(UID(1));
- // Submit real-time job to CLIENT(1) in UID(1), should pause previous job and start new job.
- mScheduler->submit(CLIENT(1), JOB(0), UID(1), mRealtimeRequest, mClientCallback1);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(1)));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), JOB(0)));
-
- // Simulate Finish that arrived late, after pause issued by scheduler.
- // Should still be propagated to client, but shouldn't trigger any new start.
- mScheduler->onFinish(CLIENT(0), JOB(1));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), JOB(1)));
-
- // Finish running real-time job, should start next real-time job in queue.
- mScheduler->onFinish(CLIENT(1), JOB(0));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(1), JOB(0)));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(2)));
-
- // Finish running real-time job, should resume next job (offline job) in queue.
- mScheduler->onFinish(CLIENT(0), JOB(2));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), JOB(2)));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
-
- // Finish running offline job.
- mScheduler->onFinish(CLIENT(0), JOB(0));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), JOB(0)));
-
- // Duplicate finish for last job, should be ignored.
- mScheduler->onFinish(CLIENT(0), JOB(0));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
-}
-
-TEST_F(TranscodingJobSchedulerTest, TestFailJob) {
- ALOGD("TestFailJob");
-
- // Start with unspecified top UID.
- // Fail without any jobs submitted, should be ignored.
- mScheduler->onError(CLIENT(0), JOB(0), TranscodingErrorCode::kUnknown);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
-
- // Submit offline job JOB(0), should start immediately.
- mScheduler->submit(CLIENT(0), JOB(0), UID(0), mOfflineRequest, mClientCallback0);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
-
- // Submit real-time job JOB(1), should pause offline job and start immediately.
- mScheduler->submit(CLIENT(0), JOB(1), UID(0), mRealtimeRequest, mClientCallback0);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(1)));
-
- // Submit real-time job JOB(2), should not start.
- mScheduler->submit(CLIENT(0), JOB(2), UID(0), mRealtimeRequest, mClientCallback0);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
-
- // Fail when the job never started, should be ignored.
- mScheduler->onError(CLIENT(0), JOB(2), TranscodingErrorCode::kUnknown);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
-
- // UID(1) moves to top.
- mUidPolicy->setTop(UID(1));
- // Submit real-time job to CLIENT(1) in UID(1), should pause previous job and start new job.
- mScheduler->submit(CLIENT(1), JOB(0), UID(1), mRealtimeRequest, mClientCallback1);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(1)));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), JOB(0)));
-
- // Simulate Fail that arrived late, after pause issued by scheduler.
- // Should still be propagated to client, but shouldn't trigger any new start.
- mScheduler->onError(CLIENT(0), JOB(1), TranscodingErrorCode::kUnknown);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(0), JOB(1)));
-
- // Fail running real-time job, should start next real-time job in queue.
- mScheduler->onError(CLIENT(1), JOB(0), TranscodingErrorCode::kUnknown);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(1), JOB(0)));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(2)));
-
- // Fail running real-time job, should resume next job (offline job) in queue.
- mScheduler->onError(CLIENT(0), JOB(2), TranscodingErrorCode::kUnknown);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(0), JOB(2)));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
-
- // Fail running offline job, and test error code propagation.
- mScheduler->onError(CLIENT(0), JOB(0), TranscodingErrorCode::kInvalidOperation);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(0), JOB(0)));
- EXPECT_EQ(mTranscoder->getLastError(), TranscodingErrorCode::kInvalidOperation);
-
- // Duplicate fail for last job, should be ignored.
- mScheduler->onError(CLIENT(0), JOB(0), TranscodingErrorCode::kUnknown);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
-}
-
-TEST_F(TranscodingJobSchedulerTest, TestTopUidChanged) {
- ALOGD("TestTopUidChanged");
-
- // Start with unspecified top UID.
- // Submit real-time job to CLIENT(0), job should start immediately.
- mScheduler->submit(CLIENT(0), JOB(0), UID(0), mRealtimeRequest, mClientCallback0);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
-
- // Submit offline job to CLIENT(0), should not start.
- mScheduler->submit(CLIENT(1), JOB(0), UID(0), mOfflineRequest, mClientCallback1);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
-
- // Move UID(1) to top.
- mUidPolicy->setTop(UID(1));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
-
- // Submit real-time job to CLIENT(2) in different uid UID(1).
- // Should pause previous job and start new job.
- mScheduler->submit(CLIENT(2), JOB(0), UID(1), mRealtimeRequest, mClientCallback2);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), JOB(0)));
-
- // Bring UID(0) back to top.
- mUidPolicy->setTop(UID(0));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(2), JOB(0)));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
-
- // Bring invalid uid to top.
- mUidPolicy->setTop(kInvalidUid);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
-
- // Finish job, next real-time job should resume.
- mScheduler->onFinish(CLIENT(0), JOB(0));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), JOB(0)));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(2), JOB(0)));
-
- // Finish job, offline job should start.
- mScheduler->onFinish(CLIENT(2), JOB(0));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(2), JOB(0)));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), JOB(0)));
-}
-
-TEST_F(TranscodingJobSchedulerTest, TestTopUidSetChanged) {
- ALOGD("TestTopUidChanged_MultipleUids");
-
- // Start with unspecified top UID.
- // Submit real-time job to CLIENT(0), job should start immediately.
- mScheduler->submit(CLIENT(0), JOB(0), UID(0), mRealtimeRequest, mClientCallback0);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
-
- // Submit offline job to CLIENT(0), should not start.
- mScheduler->submit(CLIENT(1), JOB(0), UID(0), mOfflineRequest, mClientCallback1);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
-
- // Set UID(0), UID(1) to top set.
- // UID(0) should continue to run.
- mUidPolicy->setTop({UID(0), UID(1)});
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
-
- // Submit real-time job to CLIENT(2) in different uid UID(1).
- // UID(0) should pause and UID(1) should start.
- mScheduler->submit(CLIENT(2), JOB(0), UID(1), mRealtimeRequest, mClientCallback2);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), JOB(0)));
-
- // Remove UID(0) from top set, and only leave UID(1) in the set.
- // UID(1) should continue to run.
- mUidPolicy->setTop(UID(1));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
-
- // Set UID(0), UID(2) to top set.
- // UID(1) should continue to run.
- mUidPolicy->setTop({UID(1), UID(2)});
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
-
- // Bring UID(0) back to top.
- mUidPolicy->setTop(UID(0));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(2), JOB(0)));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
-
- // Bring invalid uid to top.
- mUidPolicy->setTop(kInvalidUid);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
-
- // Finish job, next real-time job from UID(1) should resume, even if UID(1) no longer top.
- mScheduler->onFinish(CLIENT(0), JOB(0));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), JOB(0)));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(2), JOB(0)));
-
- // Finish job, offline job should start.
- mScheduler->onFinish(CLIENT(2), JOB(0));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(2), JOB(0)));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), JOB(0)));
-}
-
-TEST_F(TranscodingJobSchedulerTest, TestResourceLost) {
- ALOGD("TestResourceLost");
-
- // Start with unspecified top UID.
- // Submit real-time job to CLIENT(0), job should start immediately.
- mScheduler->submit(CLIENT(0), JOB(0), UID(0), mRealtimeRequest, mClientCallback0);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
-
- // Submit offline job to CLIENT(0), should not start.
- mScheduler->submit(CLIENT(1), JOB(0), UID(0), mOfflineRequest, mClientCallback1);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
-
- // Move UID(1) to top.
- mUidPolicy->setTop(UID(1));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
-
- // Submit real-time job to CLIENT(2) in different uid UID(1).
- // Should pause previous job and start new job.
- mScheduler->submit(CLIENT(2), JOB(0), UID(1), mRealtimeRequest, mClientCallback2);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), JOB(0)));
-
- // Test 1: No queue change during resource loss.
- // Signal resource lost.
- mScheduler->onResourceLost();
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
-
- // Signal resource available, CLIENT(2) should resume.
- mScheduler->onResourceAvailable();
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(2), JOB(0)));
-
- // Test 2: Change of queue order during resource loss.
- // Signal resource lost.
- mScheduler->onResourceLost();
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
-
- // Move UID(0) back to top, should have no resume due to no resource.
- mUidPolicy->setTop(UID(0));
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
-
- // Signal resource available, CLIENT(0) should resume.
- mScheduler->onResourceAvailable();
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
-
- // Test 3: Adding new queue during resource loss.
- // Signal resource lost.
- mScheduler->onResourceLost();
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
-
- // Move UID(2) to top.
- mUidPolicy->setTop(UID(2));
-
- // Submit real-time job to CLIENT(3) in UID(2), job shouldn't start due to no resource.
- mScheduler->submit(CLIENT(3), JOB(0), UID(2), mRealtimeRequest, mClientCallback3);
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
-
- // Signal resource available, CLIENT(3)'s job should start.
- mScheduler->onResourceAvailable();
- EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(3), JOB(0)));
-}
-
-} // namespace android
diff --git a/media/libmediatranscoding/tests/TranscodingSessionController_tests.cpp b/media/libmediatranscoding/tests/TranscodingSessionController_tests.cpp
new file mode 100644
index 0000000..4809d7a
--- /dev/null
+++ b/media/libmediatranscoding/tests/TranscodingSessionController_tests.cpp
@@ -0,0 +1,611 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+// Unit Test for TranscodingSessionController
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "TranscodingSessionControllerTest"
+
+#include <aidl/android/media/BnTranscodingClientCallback.h>
+#include <aidl/android/media/IMediaTranscodingService.h>
+#include <aidl/android/media/ITranscodingClient.h>
+#include <aidl/android/media/ITranscodingClientCallback.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <gtest/gtest.h>
+#include <media/TranscodingClientManager.h>
+#include <media/TranscodingSessionController.h>
+#include <utils/Log.h>
+
+#include <unordered_set>
+
+namespace android {
+
+using Status = ::ndk::ScopedAStatus;
+using aidl::android::media::BnTranscodingClientCallback;
+using aidl::android::media::IMediaTranscodingService;
+using aidl::android::media::ITranscodingClient;
+using aidl::android::media::TranscodingRequestParcel;
+
+constexpr ClientIdType kClientId = 1000;
+constexpr SessionIdType kClientSessionId = 0;
+constexpr uid_t kClientUid = 5000;
+constexpr uid_t kInvalidUid = (uid_t)-1;
+
+#define CLIENT(n) (kClientId + (n))
+#define SESSION(n) (kClientSessionId + (n))
+#define UID(n) (kClientUid + (n))
+
+class TestUidPolicy : public UidPolicyInterface {
+public:
+ TestUidPolicy() = default;
+ virtual ~TestUidPolicy() = default;
+
+ // UidPolicyInterface
+ void registerMonitorUid(uid_t /*uid*/) override {}
+ void unregisterMonitorUid(uid_t /*uid*/) override {}
+ bool isUidOnTop(uid_t uid) override { return mTopUids.count(uid) > 0; }
+ std::unordered_set<uid_t> getTopUids() const override { return mTopUids; }
+ void setCallback(const std::shared_ptr<UidPolicyCallbackInterface>& cb) override {
+ mUidPolicyCallback = cb;
+ }
+ void setTop(uid_t uid) {
+ std::unordered_set<uid_t> uids = {uid};
+ setTop(uids);
+ }
+ void setTop(const std::unordered_set<uid_t>& uids) {
+ mTopUids = uids;
+ auto uidPolicyCb = mUidPolicyCallback.lock();
+ if (uidPolicyCb != nullptr) {
+ uidPolicyCb->onTopUidsChanged(mTopUids);
+ }
+ }
+
+ std::unordered_set<uid_t> mTopUids;
+ std::weak_ptr<UidPolicyCallbackInterface> mUidPolicyCallback;
+};
+
+class TestTranscoder : public TranscoderInterface {
+public:
+ TestTranscoder() : mLastError(TranscodingErrorCode::kUnknown) {}
+ virtual ~TestTranscoder() {}
+
+ // TranscoderInterface
+ void setCallback(const std::shared_ptr<TranscoderCallbackInterface>& /*cb*/) override {}
+
+ void start(ClientIdType clientId, SessionIdType sessionId,
+ const TranscodingRequestParcel& /*request*/,
+ const std::shared_ptr<ITranscodingClientCallback>& /*clientCallback*/) override {
+ mEventQueue.push_back(Start(clientId, sessionId));
+ }
+ void pause(ClientIdType clientId, SessionIdType sessionId) override {
+ mEventQueue.push_back(Pause(clientId, sessionId));
+ }
+ void resume(ClientIdType clientId, SessionIdType sessionId,
+ const TranscodingRequestParcel& /*request*/,
+ const std::shared_ptr<ITranscodingClientCallback>& /*clientCallback*/) override {
+ mEventQueue.push_back(Resume(clientId, sessionId));
+ }
+ void stop(ClientIdType clientId, SessionIdType sessionId) override {
+ mEventQueue.push_back(Stop(clientId, sessionId));
+ }
+
+ void onFinished(ClientIdType clientId, SessionIdType sessionId) {
+ mEventQueue.push_back(Finished(clientId, sessionId));
+ }
+
+ void onFailed(ClientIdType clientId, SessionIdType sessionId, TranscodingErrorCode err) {
+ mLastError = err;
+ mEventQueue.push_back(Failed(clientId, sessionId));
+ }
+
+ TranscodingErrorCode getLastError() {
+ TranscodingErrorCode result = mLastError;
+ mLastError = TranscodingErrorCode::kUnknown;
+ return result;
+ }
+
+ struct Event {
+ enum { NoEvent, Start, Pause, Resume, Stop, Finished, Failed } type;
+ ClientIdType clientId;
+ SessionIdType sessionId;
+ };
+
+ static constexpr Event NoEvent = {Event::NoEvent, 0, 0};
+
+#define DECLARE_EVENT(action) \
+ static Event action(ClientIdType clientId, SessionIdType sessionId) { \
+ return {Event::action, clientId, sessionId}; \
+ }
+
+ DECLARE_EVENT(Start);
+ DECLARE_EVENT(Pause);
+ DECLARE_EVENT(Resume);
+ DECLARE_EVENT(Stop);
+ DECLARE_EVENT(Finished);
+ DECLARE_EVENT(Failed);
+
+ const Event& popEvent() {
+ if (mEventQueue.empty()) {
+ mPoppedEvent = NoEvent;
+ } else {
+ mPoppedEvent = *mEventQueue.begin();
+ mEventQueue.pop_front();
+ }
+ return mPoppedEvent;
+ }
+
+private:
+ Event mPoppedEvent;
+ std::list<Event> mEventQueue;
+ TranscodingErrorCode mLastError;
+};
+
+bool operator==(const TestTranscoder::Event& lhs, const TestTranscoder::Event& rhs) {
+ return lhs.type == rhs.type && lhs.clientId == rhs.clientId && lhs.sessionId == rhs.sessionId;
+}
+
+struct TestClientCallback : public BnTranscodingClientCallback {
+ TestClientCallback(TestTranscoder* owner, int64_t clientId)
+ : mOwner(owner), mClientId(clientId) {
+ ALOGD("TestClient Created");
+ }
+
+ Status openFileDescriptor(const std::string& /*in_fileUri*/, const std::string& /*in_mode*/,
+ ::ndk::ScopedFileDescriptor* /*_aidl_return*/) override {
+ return Status::ok();
+ }
+
+ Status onTranscodingStarted(int32_t /*in_sessionId*/) override { return Status::ok(); }
+
+ Status onTranscodingPaused(int32_t /*in_sessionId*/) override { return Status::ok(); }
+
+ Status onTranscodingResumed(int32_t /*in_sessionId*/) override { return Status::ok(); }
+
+ Status onTranscodingFinished(int32_t in_sessionId,
+ const TranscodingResultParcel& in_result) override {
+ EXPECT_EQ(in_sessionId, in_result.sessionId);
+ ALOGD("TestClientCallback: received onTranscodingFinished");
+ mOwner->onFinished(mClientId, in_sessionId);
+ return Status::ok();
+ }
+
+ Status onTranscodingFailed(int32_t in_sessionId, TranscodingErrorCode in_errorCode) override {
+ mOwner->onFailed(mClientId, in_sessionId, in_errorCode);
+ return Status::ok();
+ }
+
+ Status onAwaitNumberOfSessionsChanged(int32_t /* in_sessionId */,
+ int32_t /* in_oldAwaitNumber */,
+ int32_t /* in_newAwaitNumber */) override {
+ return Status::ok();
+ }
+
+ Status onProgressUpdate(int32_t /* in_sessionId */, int32_t /* in_progress */) override {
+ return Status::ok();
+ }
+
+ virtual ~TestClientCallback() { ALOGI("TestClient destroyed"); };
+
+private:
+ TestTranscoder* mOwner;
+ int64_t mClientId;
+ TestClientCallback(const TestClientCallback&) = delete;
+ TestClientCallback& operator=(const TestClientCallback&) = delete;
+};
+
+class TranscodingSessionControllerTest : public ::testing::Test {
+public:
+ TranscodingSessionControllerTest() { ALOGI("TranscodingSessionControllerTest created"); }
+
+ void SetUp() override {
+ ALOGI("TranscodingSessionControllerTest set up");
+ mTranscoder.reset(new TestTranscoder());
+ mUidPolicy.reset(new TestUidPolicy());
+ mController.reset(new TranscodingSessionController(mTranscoder, mUidPolicy,
+ nullptr /*resourcePolicy*/));
+ mUidPolicy->setCallback(mController);
+
+ // Set priority only, ignore other fields for now.
+ mOfflineRequest.priority = TranscodingSessionPriority::kUnspecified;
+ mRealtimeRequest.priority = TranscodingSessionPriority::kHigh;
+ mClientCallback0 =
+ ::ndk::SharedRefBase::make<TestClientCallback>(mTranscoder.get(), CLIENT(0));
+ mClientCallback1 =
+ ::ndk::SharedRefBase::make<TestClientCallback>(mTranscoder.get(), CLIENT(1));
+ mClientCallback2 =
+ ::ndk::SharedRefBase::make<TestClientCallback>(mTranscoder.get(), CLIENT(2));
+ mClientCallback3 =
+ ::ndk::SharedRefBase::make<TestClientCallback>(mTranscoder.get(), CLIENT(3));
+ }
+
+ void TearDown() override { ALOGI("TranscodingSessionControllerTest tear down"); }
+
+ ~TranscodingSessionControllerTest() { ALOGD("TranscodingSessionControllerTest destroyed"); }
+
+ std::shared_ptr<TestTranscoder> mTranscoder;
+ std::shared_ptr<TestUidPolicy> mUidPolicy;
+ std::shared_ptr<TranscodingSessionController> mController;
+ TranscodingRequestParcel mOfflineRequest;
+ TranscodingRequestParcel mRealtimeRequest;
+ std::shared_ptr<TestClientCallback> mClientCallback0;
+ std::shared_ptr<TestClientCallback> mClientCallback1;
+ std::shared_ptr<TestClientCallback> mClientCallback2;
+ std::shared_ptr<TestClientCallback> mClientCallback3;
+};
+
+TEST_F(TranscodingSessionControllerTest, TestSubmitSession) {
+ ALOGD("TestSubmitSession");
+
+ // Start with UID(1) on top.
+ mUidPolicy->setTop(UID(1));
+
+ // Submit offline session to CLIENT(0) in UID(0).
+ // Should start immediately (because this is the only session).
+ mController->submit(CLIENT(0), SESSION(0), UID(0), mOfflineRequest, mClientCallback0);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), 0));
+
+ // Submit real-time session to CLIENT(0).
+ // Should pause offline session and start new session, even if UID(0) is not on top.
+ mController->submit(CLIENT(0), SESSION(1), UID(0), mRealtimeRequest, mClientCallback0);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(0)));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(1)));
+
+ // Submit real-time session to CLIENT(0), should be queued after the previous session.
+ mController->submit(CLIENT(0), SESSION(2), UID(0), mRealtimeRequest, mClientCallback0);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
+
+ // Submit real-time session to CLIENT(1) in same uid, should be queued after the previous
+ // session.
+ mController->submit(CLIENT(1), SESSION(0), UID(0), mRealtimeRequest, mClientCallback1);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
+
+ // Submit real-time session to CLIENT(2) in UID(1).
+ // Should pause previous session and start new session, because UID(1) is (has been) top.
+ mController->submit(CLIENT(2), SESSION(0), UID(1), mRealtimeRequest, mClientCallback2);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(1)));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), SESSION(0)));
+
+ // Submit offline session, shouldn't generate any event.
+ mController->submit(CLIENT(2), SESSION(1), UID(1), mOfflineRequest, mClientCallback2);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
+
+ // Bring UID(0) to top.
+ mUidPolicy->setTop(UID(0));
+ // Should pause current session, and resume last session in UID(0).
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(2), SESSION(0)));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), SESSION(1)));
+}
+
+TEST_F(TranscodingSessionControllerTest, TestCancelSession) {
+ ALOGD("TestCancelSession");
+
+ // Submit real-time session SESSION(0), should start immediately.
+ mController->submit(CLIENT(0), SESSION(0), UID(0), mRealtimeRequest, mClientCallback0);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(0)));
+
+ // Submit real-time session SESSION(1), should not start.
+ mController->submit(CLIENT(0), SESSION(1), UID(0), mRealtimeRequest, mClientCallback0);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
+
+ // Submit offline session SESSION(2), should not start.
+ mController->submit(CLIENT(0), SESSION(2), UID(0), mOfflineRequest, mClientCallback0);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
+
+ // Cancel queued real-time session.
+ // Cancel real-time session SESSION(1), should be cancelled.
+ EXPECT_TRUE(mController->cancel(CLIENT(0), SESSION(1)));
+
+ // Cancel queued offline session.
+ // Cancel offline session SESSION(2), should be cancelled.
+ EXPECT_TRUE(mController->cancel(CLIENT(0), SESSION(2)));
+
+ // Submit offline session SESSION(3), shouldn't cause any event.
+ mController->submit(CLIENT(0), SESSION(3), UID(0), mOfflineRequest, mClientCallback0);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
+
+ // Cancel running real-time session SESSION(0).
+ // - Should be stopped first then cancelled.
+ // - Should also start offline session SESSION(2) because real-time queue is empty.
+ EXPECT_TRUE(mController->cancel(CLIENT(0), SESSION(0)));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Stop(CLIENT(0), SESSION(0)));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(3)));
+
+ // Submit real-time session SESSION(4), offline SESSION(3) should pause and SESSION(4)
+ // should start.
+ mController->submit(CLIENT(0), SESSION(4), UID(0), mRealtimeRequest, mClientCallback0);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(3)));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(4)));
+
+ // Cancel paused SESSION(3). SESSION(3) should be stopped.
+ EXPECT_TRUE(mController->cancel(CLIENT(0), SESSION(3)));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Stop(CLIENT(0), SESSION(3)));
+}
+
+TEST_F(TranscodingSessionControllerTest, TestFinishSession) {
+ ALOGD("TestFinishSession");
+
+ // Start with unspecified top UID.
+ // Finish without any sessions submitted, should be ignored.
+ mController->onFinish(CLIENT(0), SESSION(0));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
+
+ // Submit offline session SESSION(0), should start immediately.
+ mController->submit(CLIENT(0), SESSION(0), UID(0), mOfflineRequest, mClientCallback0);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(0)));
+
+ // Submit real-time session SESSION(1), should pause offline session and start immediately.
+ mController->submit(CLIENT(0), SESSION(1), UID(0), mRealtimeRequest, mClientCallback0);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(0)));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(1)));
+
+ // Submit real-time session SESSION(2), should not start.
+ mController->submit(CLIENT(0), SESSION(2), UID(0), mRealtimeRequest, mClientCallback0);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
+
+ // Finish when the session never started, should be ignored.
+ mController->onFinish(CLIENT(0), SESSION(2));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
+
+ // UID(1) moves to top.
+ mUidPolicy->setTop(UID(1));
+ // Submit real-time session to CLIENT(1) in UID(1), should pause previous session and start
+ // new session.
+ mController->submit(CLIENT(1), SESSION(0), UID(1), mRealtimeRequest, mClientCallback1);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(1)));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), SESSION(0)));
+
+ // Simulate Finish that arrived late, after pause issued by controller.
+ // Should still be propagated to client, but shouldn't trigger any new start.
+ mController->onFinish(CLIENT(0), SESSION(1));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), SESSION(1)));
+
+ // Finish running real-time session, should start next real-time session in queue.
+ mController->onFinish(CLIENT(1), SESSION(0));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(1), SESSION(0)));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(2)));
+
+ // Finish running real-time session, should resume next session (offline session) in queue.
+ mController->onFinish(CLIENT(0), SESSION(2));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), SESSION(2)));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), SESSION(0)));
+
+ // Finish running offline session.
+ mController->onFinish(CLIENT(0), SESSION(0));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), SESSION(0)));
+
+ // Duplicate finish for last session, should be ignored.
+ mController->onFinish(CLIENT(0), SESSION(0));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
+}
+
+TEST_F(TranscodingSessionControllerTest, TestFailSession) {
+ ALOGD("TestFailSession");
+
+ // Start with unspecified top UID.
+ // Fail without any sessions submitted, should be ignored.
+ mController->onError(CLIENT(0), SESSION(0), TranscodingErrorCode::kUnknown);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
+
+ // Submit offline session SESSION(0), should start immediately.
+ mController->submit(CLIENT(0), SESSION(0), UID(0), mOfflineRequest, mClientCallback0);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(0)));
+
+ // Submit real-time session SESSION(1), should pause offline session and start immediately.
+ mController->submit(CLIENT(0), SESSION(1), UID(0), mRealtimeRequest, mClientCallback0);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(0)));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(1)));
+
+ // Submit real-time session SESSION(2), should not start.
+ mController->submit(CLIENT(0), SESSION(2), UID(0), mRealtimeRequest, mClientCallback0);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
+
+ // Fail when the session never started, should be ignored.
+ mController->onError(CLIENT(0), SESSION(2), TranscodingErrorCode::kUnknown);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
+
+ // UID(1) moves to top.
+ mUidPolicy->setTop(UID(1));
+ // Submit real-time session to CLIENT(1) in UID(1), should pause previous session and start
+ // new session.
+ mController->submit(CLIENT(1), SESSION(0), UID(1), mRealtimeRequest, mClientCallback1);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(1)));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), SESSION(0)));
+
+ // Simulate Fail that arrived late, after pause issued by controller.
+ // Should still be propagated to client, but shouldn't trigger any new start.
+ mController->onError(CLIENT(0), SESSION(1), TranscodingErrorCode::kUnknown);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(0), SESSION(1)));
+
+ // Fail running real-time session, should start next real-time session in queue.
+ mController->onError(CLIENT(1), SESSION(0), TranscodingErrorCode::kUnknown);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(1), SESSION(0)));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(2)));
+
+ // Fail running real-time session, should resume next session (offline session) in queue.
+ mController->onError(CLIENT(0), SESSION(2), TranscodingErrorCode::kUnknown);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(0), SESSION(2)));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), SESSION(0)));
+
+ // Fail running offline session, and test error code propagation.
+ mController->onError(CLIENT(0), SESSION(0), TranscodingErrorCode::kInvalidOperation);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(0), SESSION(0)));
+ EXPECT_EQ(mTranscoder->getLastError(), TranscodingErrorCode::kInvalidOperation);
+
+ // Duplicate fail for last session, should be ignored.
+ mController->onError(CLIENT(0), SESSION(0), TranscodingErrorCode::kUnknown);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
+}
+
+TEST_F(TranscodingSessionControllerTest, TestTopUidChanged) {
+ ALOGD("TestTopUidChanged");
+
+ // Start with unspecified top UID.
+ // Submit real-time session to CLIENT(0), session should start immediately.
+ mController->submit(CLIENT(0), SESSION(0), UID(0), mRealtimeRequest, mClientCallback0);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(0)));
+
+ // Submit offline session to CLIENT(0), should not start.
+ mController->submit(CLIENT(1), SESSION(0), UID(0), mOfflineRequest, mClientCallback1);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
+
+ // Move UID(1) to top.
+ mUidPolicy->setTop(UID(1));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
+
+ // Submit real-time session to CLIENT(2) in different uid UID(1).
+ // Should pause previous session and start new session.
+ mController->submit(CLIENT(2), SESSION(0), UID(1), mRealtimeRequest, mClientCallback2);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(0)));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), SESSION(0)));
+
+ // Bring UID(0) back to top.
+ mUidPolicy->setTop(UID(0));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(2), SESSION(0)));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), SESSION(0)));
+
+ // Bring invalid uid to top.
+ mUidPolicy->setTop(kInvalidUid);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
+
+ // Finish session, next real-time session should resume.
+ mController->onFinish(CLIENT(0), SESSION(0));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), SESSION(0)));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(2), SESSION(0)));
+
+ // Finish session, offline session should start.
+ mController->onFinish(CLIENT(2), SESSION(0));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(2), SESSION(0)));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), SESSION(0)));
+}
+
+TEST_F(TranscodingSessionControllerTest, TestTopUidSetChanged) {
+ ALOGD("TestTopUidChanged_MultipleUids");
+
+ // Start with unspecified top UID.
+ // Submit real-time session to CLIENT(0), session should start immediately.
+ mController->submit(CLIENT(0), SESSION(0), UID(0), mRealtimeRequest, mClientCallback0);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(0)));
+
+ // Submit offline session to CLIENT(0), should not start.
+ mController->submit(CLIENT(1), SESSION(0), UID(0), mOfflineRequest, mClientCallback1);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
+
+ // Set UID(0), UID(1) to top set.
+ // UID(0) should continue to run.
+ mUidPolicy->setTop({UID(0), UID(1)});
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
+
+ // Submit real-time session to CLIENT(2) in different uid UID(1).
+ // UID(0) should pause and UID(1) should start.
+ mController->submit(CLIENT(2), SESSION(0), UID(1), mRealtimeRequest, mClientCallback2);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(0)));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), SESSION(0)));
+
+ // Remove UID(0) from top set, and only leave UID(1) in the set.
+ // UID(1) should continue to run.
+ mUidPolicy->setTop(UID(1));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
+
+ // Set UID(0), UID(2) to top set.
+ // UID(1) should continue to run.
+ mUidPolicy->setTop({UID(1), UID(2)});
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
+
+ // Bring UID(0) back to top.
+ mUidPolicy->setTop(UID(0));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(2), SESSION(0)));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), SESSION(0)));
+
+ // Bring invalid uid to top.
+ mUidPolicy->setTop(kInvalidUid);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
+
+ // Finish session, next real-time session from UID(1) should resume, even if UID(1)
+ // no longer top.
+ mController->onFinish(CLIENT(0), SESSION(0));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), SESSION(0)));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(2), SESSION(0)));
+
+ // Finish session, offline session should start.
+ mController->onFinish(CLIENT(2), SESSION(0));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(2), SESSION(0)));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), SESSION(0)));
+}
+
+TEST_F(TranscodingSessionControllerTest, TestResourceLost) {
+ ALOGD("TestResourceLost");
+
+ // Start with unspecified top UID.
+ // Submit real-time session to CLIENT(0), session should start immediately.
+ mController->submit(CLIENT(0), SESSION(0), UID(0), mRealtimeRequest, mClientCallback0);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(0)));
+
+ // Submit offline session to CLIENT(0), should not start.
+ mController->submit(CLIENT(1), SESSION(0), UID(0), mOfflineRequest, mClientCallback1);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
+
+ // Move UID(1) to top.
+ mUidPolicy->setTop(UID(1));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
+
+ // Submit real-time session to CLIENT(2) in different uid UID(1).
+ // Should pause previous session and start new session.
+ mController->submit(CLIENT(2), SESSION(0), UID(1), mRealtimeRequest, mClientCallback2);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(0)));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), SESSION(0)));
+
+ // Test 1: No queue change during resource loss.
+ // Signal resource lost.
+ mController->onResourceLost();
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
+
+ // Signal resource available, CLIENT(2) should resume.
+ mController->onResourceAvailable();
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(2), SESSION(0)));
+
+ // Test 2: Change of queue order during resource loss.
+ // Signal resource lost.
+ mController->onResourceLost();
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
+
+ // Move UID(0) back to top, should have no resume due to no resource.
+ mUidPolicy->setTop(UID(0));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
+
+ // Signal resource available, CLIENT(0) should resume.
+ mController->onResourceAvailable();
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), SESSION(0)));
+
+ // Test 3: Adding new queue during resource loss.
+ // Signal resource lost.
+ mController->onResourceLost();
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
+
+ // Move UID(2) to top.
+ mUidPolicy->setTop(UID(2));
+
+ // Submit real-time session to CLIENT(3) in UID(2), session shouldn't start due to no resource.
+ mController->submit(CLIENT(3), SESSION(0), UID(2), mRealtimeRequest, mClientCallback3);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
+
+ // Signal resource available, CLIENT(3)'s session should start.
+ mController->onResourceAvailable();
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(3), SESSION(0)));
+}
+
+} // namespace android
diff --git a/media/libmediatranscoding/tests/build_and_run_all_unit_tests.sh b/media/libmediatranscoding/tests/build_and_run_all_unit_tests.sh
index ff6df2c..5db9258 100644
--- a/media/libmediatranscoding/tests/build_and_run_all_unit_tests.sh
+++ b/media/libmediatranscoding/tests/build_and_run_all_unit_tests.sh
@@ -29,6 +29,6 @@
#adb shell /data/nativetest64/AdjustableMaxPriorityQueue_tests/AdjustableMaxPriorityQueue_tests
adb shell /data/nativetest/AdjustableMaxPriorityQueue_tests/AdjustableMaxPriorityQueue_tests
-echo "testing TranscodingJobScheduler"
-#adb shell /data/nativetest64/TranscodingJobScheduler_tests/TranscodingJobScheduler_tests
-adb shell /data/nativetest/TranscodingJobScheduler_tests/TranscodingJobScheduler_tests
+echo "testing TranscodingSessionController"
+#adb shell /data/nativetest64/TranscodingSessionController_tests/TranscodingSessionController_tests
+adb shell /data/nativetest/TranscodingSessionController_tests/TranscodingSessionController_tests
diff --git a/media/libmediatranscoding/transcoder/Android.bp b/media/libmediatranscoding/transcoder/Android.bp
index 258ed9a..1896412 100644
--- a/media/libmediatranscoding/transcoder/Android.bp
+++ b/media/libmediatranscoding/transcoder/Android.bp
@@ -34,8 +34,7 @@
"libmediandk",
"libnativewindow",
"libutils",
- // TODO: Use libbinder_ndk
- "libbinder",
+ "libbinder_ndk",
],
export_include_dirs: [
diff --git a/media/libmediatranscoding/transcoder/MediaTranscoder.cpp b/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
index cdb8368..d89b58f 100644
--- a/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
@@ -18,7 +18,6 @@
#define LOG_TAG "MediaTranscoder"
#include <android-base/logging.h>
-#include <binder/Parcel.h>
#include <fcntl.h>
#include <media/MediaSampleReaderNDK.h>
#include <media/MediaSampleWriter.h>
@@ -160,7 +159,7 @@
std::shared_ptr<MediaTranscoder> MediaTranscoder::create(
const std::shared_ptr<CallbackInterface>& callbacks,
- const std::shared_ptr<const Parcel>& pausedState) {
+ const std::shared_ptr<ndk::ScopedAParcel>& pausedState) {
if (pausedState != nullptr) {
LOG(INFO) << "Initializing from paused state.";
}
@@ -325,9 +324,9 @@
return AMEDIA_OK;
}
-media_status_t MediaTranscoder::pause(std::shared_ptr<const Parcel>* pausedState) {
+media_status_t MediaTranscoder::pause(std::shared_ptr<ndk::ScopedAParcel>* pausedState) {
// TODO: write internal states to parcel.
- *pausedState = std::make_shared<Parcel>();
+ *pausedState = std::shared_ptr<::ndk::ScopedAParcel>(new ::ndk::ScopedAParcel());
return cancel();
}
diff --git a/media/libmediatranscoding/transcoder/NdkCommon.cpp b/media/libmediatranscoding/transcoder/NdkCommon.cpp
index e58330f..a7b79dc 100644
--- a/media/libmediatranscoding/transcoder/NdkCommon.cpp
+++ b/media/libmediatranscoding/transcoder/NdkCommon.cpp
@@ -73,4 +73,18 @@
}
}
}
+
+#define DEFINE_SET_DEFAULT_FORMAT_VALUE_FUNC(_type, _typeName) \
+ bool SetDefaultFormatValue##_typeName(const char* key, AMediaFormat* format, _type value) { \
+ _type tmp; \
+ if (!AMediaFormat_get##_typeName(format, key, &tmp)) { \
+ AMediaFormat_set##_typeName(format, key, value); \
+ return true; \
+ } \
+ return false; \
+ }
+
+DEFINE_SET_DEFAULT_FORMAT_VALUE_FUNC(float, Float);
+DEFINE_SET_DEFAULT_FORMAT_VALUE_FUNC(int32_t, Int32);
+
} // namespace AMediaFormatUtils
\ No newline at end of file
diff --git a/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp b/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
index 0713eb8..4cf54f1 100644
--- a/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
@@ -22,6 +22,8 @@
#include <media/VideoTrackTranscoder.h>
#include <utils/AndroidThreads.h>
+using namespace AMediaFormatUtils;
+
namespace android {
// Check that the codec sample flags have the expected NDK meaning.
@@ -36,6 +38,12 @@
static constexpr int32_t kColorFormatSurface = 0x7f000789;
// Default key frame interval in seconds.
static constexpr float kDefaultKeyFrameIntervalSeconds = 1.0f;
+// Default codec operating rate.
+static constexpr int32_t kDefaultCodecOperatingRate = 240;
+// Default codec priority.
+static constexpr int32_t kDefaultCodecPriority = 1;
+// Default bitrate, in case source estimation fails.
+static constexpr int32_t kDefaultBitrateMbps = 10 * 1000 * 1000;
template <typename T>
void VideoTrackTranscoder::BlockingQueue<T>::push(T const& value, bool front) {
@@ -176,8 +184,6 @@
// Creates and configures the codecs.
media_status_t VideoTrackTranscoder::configureDestinationFormat(
const std::shared_ptr<AMediaFormat>& destinationFormat) {
- static constexpr int32_t kDefaultBitrateMbps = 10 * 1000 * 1000;
-
media_status_t status = AMEDIA_OK;
if (destinationFormat == nullptr) {
@@ -203,11 +209,12 @@
AMediaFormat_setInt32(encoderFormat, AMEDIAFORMAT_KEY_BIT_RATE, bitrate);
}
- float tmp;
- if (!AMediaFormat_getFloat(encoderFormat, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, &tmp)) {
- AMediaFormat_setFloat(encoderFormat, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL,
- kDefaultKeyFrameIntervalSeconds);
- }
+ SetDefaultFormatValueFloat(AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, encoderFormat,
+ kDefaultKeyFrameIntervalSeconds);
+ SetDefaultFormatValueInt32(AMEDIAFORMAT_KEY_OPERATING_RATE, encoderFormat,
+ kDefaultCodecOperatingRate);
+ SetDefaultFormatValueInt32(AMEDIAFORMAT_KEY_PRIORITY, encoderFormat, kDefaultCodecPriority);
+
AMediaFormat_setInt32(encoderFormat, AMEDIAFORMAT_KEY_COLOR_FORMAT, kColorFormatSurface);
// Always encode without rotation. The rotation degree will be transferred directly to
@@ -271,13 +278,13 @@
AMediaFormat_setInt32(decoderFormat.get(), TBD_AMEDIACODEC_PARAMETER_KEY_ALLOW_FRAME_DROP, 0);
// Copy over configurations that apply to both encoder and decoder.
- static const AMediaFormatUtils::EntryCopier kEncoderEntriesToCopy[] = {
+ static const EntryCopier kEncoderEntriesToCopy[] = {
ENTRY_COPIER2(AMEDIAFORMAT_KEY_OPERATING_RATE, Float, Int32),
ENTRY_COPIER(AMEDIAFORMAT_KEY_PRIORITY, Int32),
};
const size_t entryCount = sizeof(kEncoderEntriesToCopy) / sizeof(kEncoderEntriesToCopy[0]);
- AMediaFormatUtils::CopyFormatEntries(mDestinationFormat.get(), decoderFormat.get(),
- kEncoderEntriesToCopy, entryCount);
+ CopyFormatEntries(mDestinationFormat.get(), decoderFormat.get(), kEncoderEntriesToCopy,
+ entryCount);
status = AMediaCodec_configure(mDecoder, decoderFormat.get(), mSurface, NULL /* crypto */,
0 /* flags */);
@@ -480,7 +487,7 @@
androidSetThreadPriority(0 /* tid (0 = current) */, ANDROID_PRIORITY_VIDEO);
// Push start decoder and encoder as two messages, so that these are subject to the
- // stop request as well. If the job is cancelled (or paused) immediately after start,
+ // stop request as well. If the session is cancelled (or paused) immediately after start,
// we don't need to waste time start then stop the codecs.
mCodecMessageQueue.push([this] {
media_status_t status = AMediaCodec_start(mDecoder);
diff --git a/media/libmediatranscoding/transcoder/benchmark/MediaTrackTranscoderBenchmark.cpp b/media/libmediatranscoding/transcoder/benchmark/MediaTrackTranscoderBenchmark.cpp
index c695ed9..aee0ed6 100644
--- a/media/libmediatranscoding/transcoder/benchmark/MediaTrackTranscoderBenchmark.cpp
+++ b/media/libmediatranscoding/transcoder/benchmark/MediaTrackTranscoderBenchmark.cpp
@@ -192,7 +192,7 @@
auto& p = mSamples[mCurrentSampleIndex % mSamples.size()];
if (bufferSize < p.second.size) return AMEDIA_ERROR_INVALID_PARAMETER;
- memcpy(buffer, p.first.get(), bufferSize);
+ memcpy(buffer, p.first.get(), p.second.size);
advanceTrack(trackIndex);
return AMEDIA_OK;
diff --git a/media/libmediatranscoding/transcoder/benchmark/MediaTranscoderBenchmark.cpp b/media/libmediatranscoding/transcoder/benchmark/MediaTranscoderBenchmark.cpp
index f985a28..ede86cf 100644
--- a/media/libmediatranscoding/transcoder/benchmark/MediaTranscoderBenchmark.cpp
+++ b/media/libmediatranscoding/transcoder/benchmark/MediaTranscoderBenchmark.cpp
@@ -55,7 +55,7 @@
int32_t progress __unused) override {}
virtual void onCodecResourceLost(const MediaTranscoder* transcoder __unused,
- const std::shared_ptr<const Parcel>& pausedState
+ const std::shared_ptr<ndk::ScopedAParcel>& pausedState
__unused) override {}
bool waitForTranscodingFinished() {
diff --git a/media/libmediatranscoding/transcoder/include/media/MediaTranscoder.h b/media/libmediatranscoding/transcoder/include/media/MediaTranscoder.h
index 9a367ca..555cfce 100644
--- a/media/libmediatranscoding/transcoder/include/media/MediaTranscoder.h
+++ b/media/libmediatranscoding/transcoder/include/media/MediaTranscoder.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_MEDIA_TRANSCODER_H
#define ANDROID_MEDIA_TRANSCODER_H
+#include <android/binder_auto_utils.h>
#include <media/MediaSampleWriter.h>
#include <media/MediaTrackTranscoderCallback.h>
#include <media/NdkMediaError.h>
@@ -31,7 +32,6 @@
namespace android {
class MediaSampleReader;
-class Parcel;
class MediaTranscoder : public std::enable_shared_from_this<MediaTranscoder>,
public MediaTrackTranscoderCallback,
@@ -56,8 +56,9 @@
* 2) Creating a new MediaTranscoding instance with the paused state and then calling
* resume.
*/
- virtual void onCodecResourceLost(const MediaTranscoder* transcoder,
- const std::shared_ptr<const Parcel>& pausedState) = 0;
+ virtual void onCodecResourceLost(
+ const MediaTranscoder* transcoder,
+ const std::shared_ptr<ndk::ScopedAParcel>& pausedState) = 0;
virtual ~CallbackInterface() = default;
};
@@ -69,7 +70,7 @@
*/
static std::shared_ptr<MediaTranscoder> create(
const std::shared_ptr<CallbackInterface>& callbacks,
- const std::shared_ptr<const Parcel>& pausedState = nullptr);
+ const std::shared_ptr<ndk::ScopedAParcel>& pausedState = nullptr);
/** Configures source from path fd. */
media_status_t configureSource(int fd);
@@ -102,12 +103,8 @@
* release the transcoder instance, clear the paused state and delete the partial destination
* file. The caller can optionally call cancel to let the transcoder clean up the partial
* destination file.
- *
- * TODO: use NDK AParcel instead
- * libbinder shouldn't be used by mainline modules. When transcoding goes mainline
- * it needs to be replaced by stable AParcel.
*/
- media_status_t pause(std::shared_ptr<const Parcel>* pausedState);
+ media_status_t pause(std::shared_ptr<ndk::ScopedAParcel>* pausedState);
/** Resumes a paused transcoding. */
media_status_t resume();
diff --git a/media/libmediatranscoding/transcoder/include/media/NdkCommon.h b/media/libmediatranscoding/transcoder/include/media/NdkCommon.h
index 5e24049..1a72be3 100644
--- a/media/libmediatranscoding/transcoder/include/media/NdkCommon.h
+++ b/media/libmediatranscoding/transcoder/include/media/NdkCommon.h
@@ -78,5 +78,8 @@
void CopyFormatEntries(AMediaFormat* from, AMediaFormat* to, const EntryCopier* entries,
size_t entryCount);
+bool SetDefaultFormatValueFloat(const char* key, AMediaFormat* format, float value);
+bool SetDefaultFormatValueInt32(const char* key, AMediaFormat* format, int32_t value);
+
} // namespace AMediaFormatUtils
#endif // ANDROID_MEDIA_TRANSCODING_NDK_COMMON_H
diff --git a/media/libmediatranscoding/transcoder/tests/MediaTranscoderTests.cpp b/media/libmediatranscoding/transcoder/tests/MediaTranscoderTests.cpp
index 7a968eb..1bf2d8c 100644
--- a/media/libmediatranscoding/transcoder/tests/MediaTranscoderTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/MediaTranscoderTests.cpp
@@ -82,7 +82,7 @@
}
virtual void onCodecResourceLost(const MediaTranscoder* transcoder __unused,
- const std::shared_ptr<const Parcel>& pausedState
+ const std::shared_ptr<ndk::ScopedAParcel>& pausedState
__unused) override {}
void waitForTranscodingFinished() {
diff --git a/media/libshmem/Android.bp b/media/libshmem/Android.bp
index fae98ed..c8d2284 100644
--- a/media/libshmem/Android.bp
+++ b/media/libshmem/Android.bp
@@ -41,6 +41,7 @@
srcs: ["ShmemTest.cpp"],
shared_libs: [
"libbinder",
+ "libcutils",
"libshmemcompat",
"libshmemutil",
"libutils",
diff --git a/media/libshmem/ShmemCompat.cpp b/media/libshmem/ShmemCompat.cpp
index 5dd83f4..44fe39c 100644
--- a/media/libshmem/ShmemCompat.cpp
+++ b/media/libshmem/ShmemCompat.cpp
@@ -24,15 +24,12 @@
bool convertSharedFileRegionToIMemory(const SharedFileRegion& shmem,
sp<IMemory>* result) {
+ assert(result != nullptr);
+
if (!validateSharedFileRegion(shmem)) {
return false;
}
- if (shmem.fd.get() < 0) {
- *result = nullptr;
- return true;
- }
-
// Heap offset and size must be page aligned.
const size_t pageSize = getpagesize();
const size_t pageMask = ~(pageSize - 1);
@@ -62,16 +59,19 @@
bool convertIMemoryToSharedFileRegion(const sp<IMemory>& mem,
SharedFileRegion* result) {
+ assert(mem != nullptr);
+ assert(result != nullptr);
+
*result = SharedFileRegion();
- if (mem == nullptr) {
- return true;
- }
ssize_t offset;
size_t size;
sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
- if (heap != nullptr) {
+ if (size > 0) {
+ if (heap == nullptr) {
+ return false;
+ }
// Make sure the offset and size do not overflow from int64 boundaries.
if (size > std::numeric_limits<int64_t>::max() ||
offset > std::numeric_limits<int64_t>::max() ||
@@ -90,9 +90,33 @@
result->size = size;
result->offset = heap->getOffset() + offset;
}
-
return true;
}
+bool convertNullableSharedFileRegionToIMemory(const std::optional<SharedFileRegion>& shmem,
+ sp<IMemory>* result) {
+ assert(result != nullptr);
+
+ if (!shmem.has_value()) {
+ result->clear();
+ return true;
+ }
+
+ return convertSharedFileRegionToIMemory(shmem.value(), result);
+}
+
+bool convertNullableIMemoryToSharedFileRegion(const sp<IMemory>& mem,
+ std::optional<SharedFileRegion>* result) {
+ assert(result != nullptr);
+
+ if (mem == nullptr) {
+ result->reset();
+ return true;
+ }
+
+ result->emplace();
+ return convertIMemoryToSharedFileRegion(mem, &result->value());
+}
+
} // namespace media
} // namespace android
diff --git a/media/libshmem/ShmemTest.cpp b/media/libshmem/ShmemTest.cpp
index 4f11b51..d076ad0 100644
--- a/media/libshmem/ShmemTest.cpp
+++ b/media/libshmem/ShmemTest.cpp
@@ -17,6 +17,7 @@
#include "binder/MemoryBase.h"
#include "binder/MemoryHeapBase.h"
+#include "cutils/ashmem.h"
#include "media/ShmemCompat.h"
#include "media/ShmemUtil.h"
@@ -24,11 +25,22 @@
namespace media {
namespace {
-// Creates a SharedFileRegion instance with a null FD.
+// Creates a SharedFileRegion instance.
SharedFileRegion makeSharedFileRegion(int64_t offset, int64_t size) {
SharedFileRegion shmem;
shmem.offset = offset;
shmem.size = size;
+ int fd = ashmem_create_region("", size + offset);
+ assert(fd >= 0);
+ shmem.fd = os::ParcelFileDescriptor(base::unique_fd(fd));
+ return shmem;
+}
+
+// Creates a SharedFileRegion instance with an invalid FD.
+SharedFileRegion makeInvalidSharedFileRegion(int64_t offset, int64_t size) {
+ SharedFileRegion shmem;
+ shmem.offset = offset;
+ shmem.size = size;
return shmem;
}
@@ -46,9 +58,7 @@
EXPECT_TRUE(validateSharedFileRegion(makeSharedFileRegion(1, 2)));
EXPECT_FALSE(validateSharedFileRegion(makeSharedFileRegion(-1, 2)));
EXPECT_FALSE(validateSharedFileRegion(makeSharedFileRegion(2, -1)));
- EXPECT_TRUE(validateSharedFileRegion(makeSharedFileRegion(
- std::numeric_limits<int64_t>::max(),
- std::numeric_limits<int64_t>::max())));
+ EXPECT_FALSE(validateSharedFileRegion(makeInvalidSharedFileRegion(1, 2)));
}
TEST(ShmemTest, Conversion) {
@@ -72,12 +82,11 @@
TEST(ShmemTest, NullConversion) {
sp<IMemory> reconstructed;
{
- SharedFileRegion shmem;
+ std::optional<SharedFileRegion> shmem;
sp<IMemory> imem;
- ASSERT_TRUE(convertIMemoryToSharedFileRegion(imem, &shmem));
- ASSERT_EQ(0, shmem.size);
- ASSERT_LT(shmem.fd.get(), 0);
- ASSERT_TRUE(convertSharedFileRegionToIMemory(shmem, &reconstructed));
+ ASSERT_TRUE(convertNullableIMemoryToSharedFileRegion(imem, &shmem));
+ ASSERT_FALSE(shmem.has_value());
+ ASSERT_TRUE(convertNullableSharedFileRegionToIMemory(shmem, &reconstructed));
}
ASSERT_EQ(nullptr, reconstructed);
}
diff --git a/media/libshmem/ShmemUtil.cpp b/media/libshmem/ShmemUtil.cpp
index a6d047f..e075346 100644
--- a/media/libshmem/ShmemUtil.cpp
+++ b/media/libshmem/ShmemUtil.cpp
@@ -19,6 +19,11 @@
namespace media {
bool validateSharedFileRegion(const SharedFileRegion& shmem) {
+ // FD must be valid.
+ if (shmem.fd.get() < 0) {
+ return false;
+ }
+
// Size and offset must be non-negative.
if (shmem.size < 0 || shmem.offset < 0) {
return false;
diff --git a/media/libshmem/aidl/android/media/SharedFileRegion.aidl b/media/libshmem/aidl/android/media/SharedFileRegion.aidl
index c99ad95..a910e69 100644
--- a/media/libshmem/aidl/android/media/SharedFileRegion.aidl
+++ b/media/libshmem/aidl/android/media/SharedFileRegion.aidl
@@ -20,13 +20,15 @@
* A shared file region.
*
* This type contains the required information to share a region of a file between processes over
- * AIDL. An invalid (null) region may be represented using a negative file descriptor.
+ * AIDL.
+ * An instance of this type represents a valid FD. For representing a null SharedFileRegion, use a
+ * @nullable SharedFileRegion.
* Primarily, this is intended for shared memory blocks.
*
* @hide
*/
parcelable SharedFileRegion {
- /** File descriptor of the region. */
+ /** File descriptor of the region. Must be valid. */
ParcelFileDescriptor fd;
/** Offset, in bytes within the file of the start of the region. Must be non-negative. */
long offset;
diff --git a/media/libshmem/include/media/ShmemCompat.h b/media/libshmem/include/media/ShmemCompat.h
index 3bf7f67..ba59f25 100644
--- a/media/libshmem/include/media/ShmemCompat.h
+++ b/media/libshmem/include/media/ShmemCompat.h
@@ -19,6 +19,8 @@
// This module contains utilities for interfacing between legacy code that is using IMemory and new
// code that is using android.os.SharedFileRegion.
+#include <optional>
+
#include "android/media/SharedFileRegion.h"
#include "binder/IMemory.h"
#include "utils/StrongPointer.h"
@@ -29,8 +31,7 @@
/**
* Converts a SharedFileRegion parcelable to an IMemory instance.
* @param shmem The SharedFileRegion instance.
- * @param result The resulting IMemory instance, or null of the SharedFileRegion is null (has a
- * negative FD).
+ * @param result The resulting IMemory instance. May not be null.
* @return true if the conversion is successful (should always succeed under normal circumstances,
* failure usually means corrupt data).
*/
@@ -38,8 +39,19 @@
sp<IMemory>* result);
/**
+ * Converts a nullable SharedFileRegion parcelable to an IMemory instance.
+ * @param shmem The SharedFileRegion instance.
+ * @param result The resulting IMemory instance. May not be null. Pointee assigned to null,
+ * if the input is null.
+ * @return true if the conversion is successful (should always succeed under normal circumstances,
+ * failure usually means corrupt data).
+ */
+bool convertNullableSharedFileRegionToIMemory(const std::optional<SharedFileRegion>& shmem,
+ sp<IMemory>* result);
+
+/**
* Converts an IMemory instance to SharedFileRegion.
- * @param mem The IMemory instance. May be null.
+ * @param mem The IMemory instance. May not be null.
* @param result The resulting SharedFileRegion instance.
* @return true if the conversion is successful (should always succeed under normal circumstances,
* failure usually means corrupt data).
@@ -47,5 +59,16 @@
bool convertIMemoryToSharedFileRegion(const sp<IMemory>& mem,
SharedFileRegion* result);
+/**
+ * Converts a nullable IMemory instance to a nullable SharedFileRegion.
+ * @param mem The IMemory instance. May be null.
+ * @param result The resulting SharedFileRegion instance. May not be null. Assigned to empty,
+ * if the input is null.
+ * @return true if the conversion is successful (should always succeed under normal circumstances,
+ * failure usually means corrupt data).
+ */
+bool convertNullableIMemoryToSharedFileRegion(const sp<IMemory>& mem,
+ std::optional<SharedFileRegion>* result);
+
} // namespace media
} // namespace android
diff --git a/media/libshmem/include/media/ShmemUtil.h b/media/libshmem/include/media/ShmemUtil.h
index 563cb71..3a7a5a5 100644
--- a/media/libshmem/include/media/ShmemUtil.h
+++ b/media/libshmem/include/media/ShmemUtil.h
@@ -25,7 +25,6 @@
/**
* Checks whether a SharedFileRegion instance is valid (all the fields have sane values).
- * A null SharedFileRegion (having a negative FD) is considered valid.
*/
bool validateSharedFileRegion(const SharedFileRegion& shmem);
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 050d7c2..6245014 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -312,6 +312,27 @@
(*format)->setBuffer("pssh", buf);
}
+ // Copy over the slow-motion related metadata
+ const void *slomoMarkers;
+ size_t slomoMarkersSize;
+ if (meta->findData(kKeySlowMotionMarkers, &type, &slomoMarkers, &slomoMarkersSize)
+ && slomoMarkersSize > 0) {
+ sp<ABuffer> buf = new ABuffer(slomoMarkersSize);
+ memcpy(buf->data(), slomoMarkers, slomoMarkersSize);
+ (*format)->setBuffer("slow-motion-markers", buf);
+ }
+
+ int32_t temporalLayerCount;
+ if (meta->findInt32(kKeyTemporalLayerCount, &temporalLayerCount)
+ && temporalLayerCount > 0) {
+ (*format)->setInt32("temporal-layer-count", temporalLayerCount);
+ }
+
+ float captureFps;
+ if (meta->findFloat(kKeyCaptureFramerate, &captureFps) && captureFps > 0.0f) {
+ (*format)->setFloat("capture-rate", captureFps);
+ }
+
return OK;
}
diff --git a/media/libstagefright/codecs/amrnb/enc/Android.bp b/media/libstagefright/codecs/amrnb/enc/Android.bp
index 73a1d4b..ff9a720 100644
--- a/media/libstagefright/codecs/amrnb/enc/Android.bp
+++ b/media/libstagefright/codecs/amrnb/enc/Android.bp
@@ -81,6 +81,13 @@
//},
shared_libs: ["libstagefright_amrnb_common"],
+
+ host_supported: true,
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
}
//###############################################################################
diff --git a/media/libstagefright/codecs/amrwbenc/Android.bp b/media/libstagefright/codecs/amrwbenc/Android.bp
index 64f302c..70c672d 100644
--- a/media/libstagefright/codecs/amrwbenc/Android.bp
+++ b/media/libstagefright/codecs/amrwbenc/Android.bp
@@ -138,6 +138,12 @@
cfi: true,
},
+ host_supported: true,
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
}
//###############################################################################
diff --git a/media/libstagefright/codecs/amrwbenc/src/preemph.c b/media/libstagefright/codecs/amrwbenc/src/preemph.c
index 70c8650..a43841a 100644
--- a/media/libstagefright/codecs/amrwbenc/src/preemph.c
+++ b/media/libstagefright/codecs/amrwbenc/src/preemph.c
@@ -24,6 +24,7 @@
#include "typedef.h"
#include "basic_op.h"
+#include <stdint.h>
void Preemph(
Word16 x[], /* (i/o) : input signal overwritten by the output */
diff --git a/media/libstagefright/codecs/amrwbenc/src/q_pulse.c b/media/libstagefright/codecs/amrwbenc/src/q_pulse.c
index fe0bdda..657b6fe 100644
--- a/media/libstagefright/codecs/amrwbenc/src/q_pulse.c
+++ b/media/libstagefright/codecs/amrwbenc/src/q_pulse.c
@@ -27,6 +27,7 @@
#include "q_pulse.h"
#define NB_POS 16 /* pos in track, mask for sign bit */
+#define UNUSED_VAR __attribute__((unused))
Word32 quant_1p_N1( /* (o) return N+1 bits */
Word16 pos, /* (i) position of the pulse */
@@ -188,7 +189,7 @@
Word16 pos[], /* (i) position of the pulse 1..4 */
Word16 N) /* (i) number of bits for position */
{
- Word16 nb_pos, mask __unused, n_1, tmp;
+ Word16 nb_pos, mask UNUSED_VAR, n_1, tmp;
Word16 posA[4], posB[4];
Word32 i, j, k, index;
diff --git a/media/libstagefright/codecs/common/Android.bp b/media/libstagefright/codecs/common/Android.bp
index 260a60a..2290722 100644
--- a/media/libstagefright/codecs/common/Android.bp
+++ b/media/libstagefright/codecs/common/Android.bp
@@ -14,4 +14,11 @@
export_include_dirs: ["include"],
cflags: ["-Werror"],
+
+ host_supported: true,
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
}
diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/idct_vca.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/idct_vca.cpp
index 0ba4944..dbaf5d1 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/src/idct_vca.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/src/idct_vca.cpp
@@ -37,6 +37,7 @@
return ;
}
+__attribute__((no_sanitize("signed-integer-overflow")))
void idctrow1(int16 *blk, uint8 *pred, uint8 *dst, int width)
{
/* shortcut */
@@ -156,6 +157,7 @@
return ;
}
+__attribute__((no_sanitize("signed-integer-overflow")))
void idctcol2(int16 *blk)
{
int32 x0, x1, x3, x5, x7;//, x8;
@@ -256,6 +258,7 @@
return ;
}
+__attribute__((no_sanitize("signed-integer-overflow")))
void idctcol3(int16 *blk)
{
int32 x0, x1, x2, x3, x4, x5, x6, x7, x8;
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_framedecoder.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_framedecoder.cpp
index c64cf46..a5c7f5e 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_framedecoder.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_framedecoder.cpp
@@ -219,11 +219,6 @@
if (info->error_protection)
{
- if (bitsAvailable(&pVars->inputStream, 16))
- {
- return SIDE_INFO_ERROR;
- }
-
/*
* Get crc content
*/
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_get_side_info.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_get_side_info.cpp
index 1a3fca5..d644207 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_get_side_info.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_get_side_info.cpp
@@ -73,7 +73,6 @@
#include "pvmp3_get_side_info.h"
#include "pvmp3_crc.h"
-#include "pvmp3_getbits.h"
/*----------------------------------------------------------------------------
@@ -126,22 +125,12 @@
{
if (stereo == 1)
{
- if (!bitsAvailable(inputStream, 14))
- {
- return SIDE_INFO_ERROR;
- }
-
tmp = getbits_crc(inputStream, 14, crc, info->error_protection);
si->main_data_begin = (tmp << 18) >> 23; /* 9 */
si->private_bits = (tmp << 27) >> 27; /* 5 */
}
else
{
- if (!bitsAvailable(inputStream, 12))
- {
- return SIDE_INFO_ERROR;
- }
-
tmp = getbits_crc(inputStream, 12, crc, info->error_protection);
si->main_data_begin = (tmp << 20) >> 23; /* 9 */
si->private_bits = (tmp << 29) >> 29; /* 3 */
@@ -150,11 +139,6 @@
for (ch = 0; ch < stereo; ch++)
{
- if (!bitsAvailable(inputStream, 4))
- {
- return SIDE_INFO_ERROR;
- }
-
tmp = getbits_crc(inputStream, 4, crc, info->error_protection);
si->ch[ch].scfsi[0] = (tmp << 28) >> 31; /* 1 */
si->ch[ch].scfsi[1] = (tmp << 29) >> 31; /* 1 */
@@ -166,11 +150,6 @@
{
for (ch = 0; ch < stereo; ch++)
{
- if (!bitsAvailable(inputStream, 34))
- {
- return SIDE_INFO_ERROR;
- }
-
si->ch[ch].gran[gr].part2_3_length = getbits_crc(inputStream, 12, crc, info->error_protection);
tmp = getbits_crc(inputStream, 22, crc, info->error_protection);
@@ -181,11 +160,6 @@
if (si->ch[ch].gran[gr].window_switching_flag)
{
- if (!bitsAvailable(inputStream, 22))
- {
- return SIDE_INFO_ERROR;
- }
-
tmp = getbits_crc(inputStream, 22, crc, info->error_protection);
si->ch[ch].gran[gr].block_type = (tmp << 10) >> 30; /* 2 */;
@@ -218,11 +192,6 @@
}
else
{
- if (!bitsAvailable(inputStream, 22))
- {
- return SIDE_INFO_ERROR;
- }
-
tmp = getbits_crc(inputStream, 22, crc, info->error_protection);
si->ch[ch].gran[gr].table_select[0] = (tmp << 10) >> 27; /* 5 */;
@@ -235,11 +204,6 @@
si->ch[ch].gran[gr].block_type = 0;
}
- if (!bitsAvailable(inputStream, 3))
- {
- return SIDE_INFO_ERROR;
- }
-
tmp = getbits_crc(inputStream, 3, crc, info->error_protection);
si->ch[ch].gran[gr].preflag = (tmp << 29) >> 31; /* 1 */
si->ch[ch].gran[gr].scalefac_scale = (tmp << 30) >> 31; /* 1 */
@@ -249,21 +213,11 @@
}
else /* Layer 3 LSF */
{
- if (!bitsAvailable(inputStream, 8 + stereo))
- {
- return SIDE_INFO_ERROR;
- }
-
si->main_data_begin = getbits_crc(inputStream, 8, crc, info->error_protection);
si->private_bits = getbits_crc(inputStream, stereo, crc, info->error_protection);
for (ch = 0; ch < stereo; ch++)
{
- if (!bitsAvailable(inputStream, 39))
- {
- return SIDE_INFO_ERROR;
- }
-
tmp = getbits_crc(inputStream, 21, crc, info->error_protection);
si->ch[ch].gran[0].part2_3_length = (tmp << 11) >> 20; /* 12 */
si->ch[ch].gran[0].big_values = (tmp << 23) >> 23; /* 9 */
@@ -276,11 +230,6 @@
if (si->ch[ch].gran[0].window_switching_flag)
{
- if (!bitsAvailable(inputStream, 22))
- {
- return SIDE_INFO_ERROR;
- }
-
tmp = getbits_crc(inputStream, 22, crc, info->error_protection);
si->ch[ch].gran[0].block_type = (tmp << 10) >> 30; /* 2 */;
@@ -313,11 +262,6 @@
}
else
{
- if (!bitsAvailable(inputStream, 22))
- {
- return SIDE_INFO_ERROR;
- }
-
tmp = getbits_crc(inputStream, 22, crc, info->error_protection);
si->ch[ch].gran[0].table_select[0] = (tmp << 10) >> 27; /* 5 */;
@@ -330,11 +274,6 @@
si->ch[ch].gran[0].block_type = 0;
}
- if (!bitsAvailable(inputStream, 2))
- {
- return SIDE_INFO_ERROR;
- }
-
tmp = getbits_crc(inputStream, 2, crc, info->error_protection);
si->ch[ch].gran[0].scalefac_scale = tmp >> 1; /* 1 */
si->ch[ch].gran[0].count1table_select = tmp & 1; /* 1 */
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_getbits.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_getbits.cpp
index 4d252ef..8ff7953 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_getbits.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_getbits.cpp
@@ -113,11 +113,10 @@
uint32 offset;
uint32 bitIndex;
- uint32 bytesToFetch;
- uint8 Elem = 0; /* Needs to be same type as pInput->pBuffer */
- uint8 Elem1 = 0;
- uint8 Elem2 = 0;
- uint8 Elem3 = 0;
+ uint8 Elem; /* Needs to be same type as pInput->pBuffer */
+ uint8 Elem1;
+ uint8 Elem2;
+ uint8 Elem3;
uint32 returnValue = 0;
if (!neededBits)
@@ -127,25 +126,10 @@
offset = (ptBitStream->usedBits) >> INBUF_ARRAY_INDEX_SHIFT;
- /* Remove extra high bits by shifting up */
- bitIndex = module(ptBitStream->usedBits, INBUF_BIT_WIDTH);
-
- bytesToFetch = (bitIndex + neededBits + 7 ) >> 3 ;
-
- switch (bytesToFetch)
- {
- case 4:
- Elem3 = *(ptBitStream->pBuffer + module(offset + 3, BUFSIZE));
- [[fallthrough]];
- case 3:
- Elem2 = *(ptBitStream->pBuffer + module(offset + 2, BUFSIZE));
- [[fallthrough]];
- case 2:
- Elem1 = *(ptBitStream->pBuffer + module(offset + 1, BUFSIZE));
- [[fallthrough]];
- case 1:
- Elem = *(ptBitStream->pBuffer + module(offset, BUFSIZE));
- }
+ Elem = *(ptBitStream->pBuffer + module(offset , BUFSIZE));
+ Elem1 = *(ptBitStream->pBuffer + module(offset + 1, BUFSIZE));
+ Elem2 = *(ptBitStream->pBuffer + module(offset + 2, BUFSIZE));
+ Elem3 = *(ptBitStream->pBuffer + module(offset + 3, BUFSIZE));
returnValue = (((uint32)(Elem)) << 24) |
@@ -153,6 +137,9 @@
(((uint32)(Elem2)) << 8) |
((uint32)(Elem3));
+ /* Remove extra high bits by shifting up */
+ bitIndex = module(ptBitStream->usedBits, INBUF_BIT_WIDTH);
+
/* This line is faster than to mask off the high bits. */
returnValue <<= bitIndex;
@@ -174,32 +161,22 @@
uint32 offset;
uint32 bitIndex;
- uint32 bytesToFetch;
- uint8 Elem = 0; /* Needs to be same type as pInput->pBuffer */
- uint8 Elem1 = 0;
+ uint8 Elem; /* Needs to be same type as pInput->pBuffer */
+ uint8 Elem1;
uint16 returnValue;
offset = (ptBitStream->usedBits) >> INBUF_ARRAY_INDEX_SHIFT;
- /* Remove extra high bits by shifting up */
- bitIndex = module(ptBitStream->usedBits, INBUF_BIT_WIDTH);
-
- bytesToFetch = (bitIndex + neededBits + 7 ) >> 3 ;
-
- if (bytesToFetch > 1)
- {
- Elem = *(ptBitStream->pBuffer + module(offset, BUFSIZE));
- Elem1 = *(ptBitStream->pBuffer + module(offset + 1, BUFSIZE));
- }
- else if (bytesToFetch > 0)
- {
- Elem = *(ptBitStream->pBuffer + module(offset, BUFSIZE));
- }
+ Elem = *(ptBitStream->pBuffer + module(offset , BUFSIZE));
+ Elem1 = *(ptBitStream->pBuffer + module(offset + 1, BUFSIZE));
returnValue = (((uint16)(Elem)) << 8) |
((uint16)(Elem1));
+ /* Remove extra high bits by shifting up */
+ bitIndex = module(ptBitStream->usedBits, INBUF_BIT_WIDTH);
+
ptBitStream->usedBits += neededBits;
/* This line is faster than to mask off the high bits. */
returnValue = (returnValue << (bitIndex));
@@ -220,40 +197,25 @@
uint32 offset;
uint32 bitIndex;
- uint32 bytesToFetch;
- uint8 Elem = 0; /* Needs to be same type as pInput->pBuffer */
- uint8 Elem1 = 0;
- uint8 Elem2 = 0;
+ uint8 Elem; /* Needs to be same type as pInput->pBuffer */
+ uint8 Elem1;
+ uint8 Elem2;
uint32 returnValue;
offset = (ptBitStream->usedBits) >> INBUF_ARRAY_INDEX_SHIFT;
- /* Remove extra high bits by shifting up */
- bitIndex = module(ptBitStream->usedBits, INBUF_BIT_WIDTH);
-
- bytesToFetch = (bitIndex + neededBits + 7 ) >> 3 ;
-
- if (bytesToFetch > 2)
- {
- Elem = *(ptBitStream->pBuffer + module(offset, BUFSIZE));
- Elem1 = *(ptBitStream->pBuffer + module(offset + 1, BUFSIZE));
- Elem2 = *(ptBitStream->pBuffer + module(offset + 2, BUFSIZE));
- }
- else if (bytesToFetch > 1)
- {
- Elem = *(ptBitStream->pBuffer + module(offset, BUFSIZE));
- Elem1 = *(ptBitStream->pBuffer + module(offset + 1, BUFSIZE));
- }
- else if (bytesToFetch > 0)
- {
- Elem = *(ptBitStream->pBuffer + module(offset, BUFSIZE));
- }
+ Elem = *(ptBitStream->pBuffer + module(offset , BUFSIZE));
+ Elem1 = *(ptBitStream->pBuffer + module(offset + 1, BUFSIZE));
+ Elem2 = *(ptBitStream->pBuffer + module(offset + 2, BUFSIZE));
returnValue = (((uint32)(Elem)) << 16) |
(((uint32)(Elem1)) << 8) |
((uint32)(Elem2));
+ /* Remove extra high bits by shifting up */
+ bitIndex = module(ptBitStream->usedBits, INBUF_BIT_WIDTH);
+
ptBitStream->usedBits += neededBits;
/* This line is faster than to mask off the high bits. */
returnValue = 0xFFFFFF & (returnValue << (bitIndex));
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_getbits.h b/media/libstagefright/codecs/mp3dec/src/pvmp3_getbits.h
index b04fe6d..b058b00 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_getbits.h
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_getbits.h
@@ -104,11 +104,6 @@
; Function Prototype declaration
----------------------------------------------------------------------------*/
-static inline bool bitsAvailable(tmp3Bits *inputStream, uint32 neededBits)
-{
- return (inputStream->inputBufferCurrentLength << 3) >= (neededBits + inputStream->usedBits);
-}
-
/*----------------------------------------------------------------------------
; END
----------------------------------------------------------------------------*/
diff --git a/media/libstagefright/codecs/mp3dec/test/AndroidTest.xml b/media/libstagefright/codecs/mp3dec/test/AndroidTest.xml
index 233f9bb..29952eb 100644
--- a/media/libstagefright/codecs/mp3dec/test/AndroidTest.xml
+++ b/media/libstagefright/codecs/mp3dec/test/AndroidTest.xml
@@ -19,7 +19,7 @@
<option name="cleanup" value="true" />
<option name="push" value="Mp3DecoderTest->/data/local/tmp/Mp3DecoderTest" />
<option name="push-file"
- key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/mp3dec/test/Mp3DecoderTest-1.1.zip?unzip=true"
+ key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/mp3dec/test/Mp3DecoderTest-1.2.zip?unzip=true"
value="/data/local/tmp/Mp3DecoderTestRes/" />
</target_preparer>
diff --git a/media/libstagefright/codecs/mp3dec/test/Mp3DecoderTest.cpp b/media/libstagefright/codecs/mp3dec/test/Mp3DecoderTest.cpp
index 0784c0c..91326a8 100644
--- a/media/libstagefright/codecs/mp3dec/test/Mp3DecoderTest.cpp
+++ b/media/libstagefright/codecs/mp3dec/test/Mp3DecoderTest.cpp
@@ -186,6 +186,7 @@
::testing::Values(("bbb_44100hz_2ch_128kbps_mp3_30sec.mp3"),
("bbb_44100hz_2ch_128kbps_mp3_5mins.mp3"),
("bug_136053885.mp3"),
+ ("bbb_2ch_44kHz_lame_crc.mp3"),
("bbb_mp3_stereo_192kbps_48000hz.mp3")));
int main(int argc, char **argv) {
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 801dba1..192ba77 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -1430,7 +1430,13 @@
if (mSampleDecryptor != NULL && (nalType == 1 || nalType == 5)) {
uint8_t *nalData = mBuffer->data() + pos.nalOffset;
size_t newSize = mSampleDecryptor->processNal(nalData, pos.nalSize);
- // Note: the data can shrink due to unescaping
+ // Note: the data can shrink due to unescaping, but it can never grow
+ if (newSize > pos.nalSize) {
+ // don't log unless verbose, since this can get called a lot if
+ // the caller is trying to resynchronize
+ ALOGV("expected sample size < %u, got %zu", pos.nalSize, newSize);
+ return NULL;
+ }
memcpy(accessUnit->data() + dstOffset + 4,
nalData,
newSize);
diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp
index 316732b..58e2d2a 100644
--- a/media/mediaserver/main_mediaserver.cpp
+++ b/media/mediaserver/main_mediaserver.cpp
@@ -18,7 +18,6 @@
#define LOG_TAG "mediaserver"
//#define LOG_NDEBUG 0
-#include <aicu/AIcu.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
@@ -39,7 +38,6 @@
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm(defaultServiceManager());
ALOGI("ServiceManager: %p", sm.get());
- AIcu_initializeIcuOrDie();
MediaPlayerService::instantiate();
ResourceManagerService::instantiate();
registerExtensions();
diff --git a/services/audioflinger/Android.bp b/services/audioflinger/Android.bp
index 12f6eba..261af5a 100644
--- a/services/audioflinger/Android.bp
+++ b/services/audioflinger/Android.bp
@@ -35,6 +35,9 @@
],
shared_libs: [
+ "audioflinger-aidl-unstable-cpp",
+ "audioclient-types-aidl-unstable-cpp",
+ "libaudioclient_aidl_conversion",
"libaudiofoundation",
"libaudiohal",
"libaudioprocessing",
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index eae9437..e589eb9 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -22,6 +22,13 @@
// Define AUDIO_ARRAYS_STATIC_CHECK to check all audio arrays are correct
#define AUDIO_ARRAYS_STATIC_CHECK 1
+#define VALUE_OR_FATAL(result) \
+ ({ auto _tmp = (result); \
+ LOG_ALWAYS_FATAL_IF(!_tmp.ok(), \
+ "Failed result (%d)", \
+ _tmp.error()); \
+ _tmp.value(); })
+
#include "Configuration.h"
#include <dirent.h>
#include <math.h>
@@ -68,6 +75,7 @@
#include <powermanager/PowerManager.h>
#include <media/IMediaLogService.h>
+#include <media/AidlConversion.h>
#include <media/nbaio/Pipe.h>
#include <media/nbaio/PipeReader.h>
#include <mediautils/BatteryNotifier.h>
@@ -1774,7 +1782,7 @@
return BAD_VALUE;
}
-void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)
+void AudioFlinger::registerClient(const sp<media::IAudioFlingerClient>& client)
{
Mutex::Autolock _l(mLock);
if (client == 0) {
@@ -1849,13 +1857,18 @@
void AudioFlinger::ioConfigChanged(audio_io_config_event event,
const sp<AudioIoDescriptor>& ioDesc,
- pid_t pid)
-{
+ pid_t pid) {
+ media::AudioIoDescriptor descAidl = VALUE_OR_FATAL(
+ legacy2aidl_AudioIoDescriptor_AudioIoDescriptor(ioDesc));
+ media::AudioIoConfigEvent eventAidl = VALUE_OR_FATAL(
+ legacy2aidl_audio_io_config_event_AudioIoConfigEvent(event));
+
Mutex::Autolock _l(mClientLock);
size_t size = mNotificationClients.size();
for (size_t i = 0; i < size; i++) {
if ((pid == 0) || (mNotificationClients.keyAt(i) == pid)) {
- mNotificationClients.valueAt(i)->audioFlingerClient()->ioConfigChanged(event, ioDesc);
+ mNotificationClients.valueAt(i)->audioFlingerClient()->ioConfigChanged(eventAidl,
+ descAidl);
}
}
}
@@ -1929,7 +1942,7 @@
// ----------------------------------------------------------------------------
AudioFlinger::NotificationClient::NotificationClient(const sp<AudioFlinger>& audioFlinger,
- const sp<IAudioFlingerClient>& client,
+ const sp<media::IAudioFlingerClient>& client,
pid_t pid,
uid_t uid)
: mAudioFlinger(audioFlinger), mPid(pid), mUid(uid), mAudioFlingerClient(client)
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 14a4df7..65d672a 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -33,16 +33,16 @@
#include <sys/types.h>
#include <limits.h>
+#include <android/media/IAudioFlingerClient.h>
#include <android/media/IAudioTrackCallback.h>
#include <android/os/BnExternalVibrationController.h>
-#include <android-base/macros.h>
+#include <android-base/macros.h>
#include <cutils/atomic.h>
#include <cutils/compiler.h>
-#include <cutils/properties.h>
+#include <cutils/properties.h>
#include <media/IAudioFlinger.h>
-#include <media/IAudioFlingerClient.h>
#include <media/IAudioTrack.h>
#include <media/AudioSystem.h>
#include <media/AudioTrack.h>
@@ -177,7 +177,7 @@
virtual status_t setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs);
virtual String8 getParameters(audio_io_handle_t ioHandle, const String8& keys) const;
- virtual void registerClient(const sp<IAudioFlingerClient>& client);
+ virtual void registerClient(const sp<media::IAudioFlingerClient>& client);
virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format,
audio_channel_mask_t channelMask) const;
@@ -490,12 +490,12 @@
class NotificationClient : public IBinder::DeathRecipient {
public:
NotificationClient(const sp<AudioFlinger>& audioFlinger,
- const sp<IAudioFlingerClient>& client,
+ const sp<media::IAudioFlingerClient>& client,
pid_t pid,
uid_t uid);
virtual ~NotificationClient();
- sp<IAudioFlingerClient> audioFlingerClient() const { return mAudioFlingerClient; }
+ sp<media::IAudioFlingerClient> audioFlingerClient() const { return mAudioFlingerClient; }
pid_t getPid() const { return mPid; }
uid_t getUid() const { return mUid; }
@@ -508,7 +508,7 @@
const sp<AudioFlinger> mAudioFlinger;
const pid_t mPid;
const uid_t mUid;
- const sp<IAudioFlingerClient> mAudioFlingerClient;
+ const sp<media::IAudioFlingerClient> mAudioFlingerClient;
};
// --- MediaLogNotifier ---
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 39d1140..1d9223e 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -498,11 +498,6 @@
*/
bool isA2dpOffloadedOnPrimary() const;
- /**
- * returns true if A2DP is supported (either via hardware offload or software encoding)
- */
- bool isA2dpSupported() const;
-
sp<SwAudioOutputDescriptor> getOutputFromId(audio_port_handle_t id) const;
sp<SwAudioOutputDescriptor> getPrimaryOutput() const;
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
index 395bc70..cf1f64c 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
@@ -33,6 +33,15 @@
namespace android {
+// This class gathers together various bits of AudioPolicyManager
+// configuration, which are usually filled out as a result of parsing
+// the audio_policy_configuration.xml file.
+//
+// Note that AudioPolicyConfig doesn't own some of the data,
+// it simply proxies access to the fields of AudioPolicyManager
+// class. Be careful about the fields that are references,
+// e.g. 'mOutputDevices'. This also means that it's impossible
+// to implement "deep copying" of this class without re-designing it.
class AudioPolicyConfig
{
public:
@@ -40,14 +49,24 @@
DeviceVector &outputDevices,
DeviceVector &inputDevices,
sp<DeviceDescriptor> &defaultOutputDevice)
- : mEngineLibraryNameSuffix(kDefaultEngineLibraryNameSuffix),
- mHwModules(hwModules),
+ : mHwModules(hwModules),
mOutputDevices(outputDevices),
mInputDevices(inputDevices),
- mDefaultOutputDevice(defaultOutputDevice),
- mIsSpeakerDrcEnabled(false),
- mIsCallScreenModeSupported(false)
- {}
+ mDefaultOutputDevice(defaultOutputDevice) {
+ clear();
+ }
+
+ void clear() {
+ mSource = {};
+ mEngineLibraryNameSuffix = kDefaultEngineLibraryNameSuffix;
+ mHwModules.clear();
+ mOutputDevices.clear();
+ mInputDevices.clear();
+ mDefaultOutputDevice.clear();
+ mIsSpeakerDrcEnabled = false;
+ mIsCallScreenModeSupported = false;
+ mSurroundFormats.clear();
+ }
const std::string& getSource() const {
return mSource;
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index a2e2eec..25f7c27 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -764,11 +764,6 @@
return false;
}
-bool SwAudioOutputCollection::isA2dpSupported() const
-{
- return (isA2dpOffloadedOnPrimary() || (getA2dpOutput() != 0));
-}
-
sp<SwAudioOutputDescriptor> SwAudioOutputCollection::getPrimaryOutput() const
{
for (size_t i = 0; i < size(); i++) {
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index 889f031..333b6fe 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -254,9 +254,8 @@
constexpr void (*xmlDeleter)(T* t);
template <>
constexpr auto xmlDeleter<xmlDoc> = xmlFreeDoc;
-// http://b/111067277 - Add back constexpr when we switch to C++17.
template <>
-auto xmlDeleter<xmlChar> = [](xmlChar *s) { xmlFree(s); };
+constexpr auto xmlDeleter<xmlChar> = [](xmlChar *s) { xmlFree(s); };
/** @return a unique_ptr with the correct deleter for the libxml2 object. */
template <class T>
@@ -804,7 +803,9 @@
status_t deserializeAudioPolicyFile(const char *fileName, AudioPolicyConfig *config)
{
PolicySerializer serializer;
- return serializer.deserialize(fileName, config);
+ status_t status = serializer.deserialize(fileName, config);
+ if (status != OK) config->clear();
+ return status;
}
} // namespace android
diff --git a/services/audiopolicy/engine/common/src/EngineBase.cpp b/services/audiopolicy/engine/common/src/EngineBase.cpp
index 1875c10..8c7fb97 100644
--- a/services/audiopolicy/engine/common/src/EngineBase.cpp
+++ b/services/audiopolicy/engine/common/src/EngineBase.cpp
@@ -19,7 +19,6 @@
#include "EngineBase.h"
#include "EngineDefaultConfig.h"
-#include "../include/EngineBase.h"
#include <TypeConverter.h>
namespace android {
diff --git a/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp b/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp
index 87b6aaf..96cc140 100644
--- a/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp
+++ b/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp
@@ -69,6 +69,11 @@
case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
+ // TODO (b/122931261): remove when preferred device for strategy media will be used instead of
+ // AUDIO_POLICY_FORCE_NO_BT_A2DP.
+ case AUDIO_DEVICE_OUT_HEARING_AID:
+ case AUDIO_DEVICE_OUT_BLE_HEADSET:
+ case AUDIO_DEVICE_OUT_BLE_SPEAKER:
return GROUP_BT_A2DP;
default:
return GROUP_NONE;
diff --git a/services/audiopolicy/engine/config/TEST_MAPPING b/services/audiopolicy/engine/config/TEST_MAPPING
new file mode 100644
index 0000000..06ce111
--- /dev/null
+++ b/services/audiopolicy/engine/config/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "audiopolicy_engineconfig_tests"
+ }
+ ]
+}
diff --git a/services/audiopolicy/engine/config/include/EngineConfig.h b/services/audiopolicy/engine/config/include/EngineConfig.h
index 5d22c24..c565926 100644
--- a/services/audiopolicy/engine/config/include/EngineConfig.h
+++ b/services/audiopolicy/engine/config/include/EngineConfig.h
@@ -111,6 +111,8 @@
*/
ParsingResult parse(const char* path = DEFAULT_PATH);
android::status_t parseLegacyVolumes(VolumeGroups &volumeGroups);
+// Exposed for testing.
+android::status_t parseLegacyVolumeFile(const char* path, VolumeGroups &volumeGroups);
} // namespace engineConfig
} // namespace android
diff --git a/services/audiopolicy/engine/config/src/EngineConfig.cpp b/services/audiopolicy/engine/config/src/EngineConfig.cpp
index daf6418..7cfef5b 100644
--- a/services/audiopolicy/engine/config/src/EngineConfig.cpp
+++ b/services/audiopolicy/engine/config/src/EngineConfig.cpp
@@ -589,6 +589,7 @@
}
}
}
+ VolumeGroups tempVolumeGroups = volumeGroups;
for (const auto &volumeMapIter : legacyVolumeMap) {
// In order to let AudioService setting the min and max (compatibility), set Min and Max
// to -1 except for private streams
@@ -599,8 +600,10 @@
}
int indexMin = streamType >= AUDIO_STREAM_PUBLIC_CNT ? 0 : -1;
int indexMax = streamType >= AUDIO_STREAM_PUBLIC_CNT ? 100 : -1;
- volumeGroups.push_back({ volumeMapIter.first, indexMin, indexMax, volumeMapIter.second });
+ tempVolumeGroups.push_back(
+ { volumeMapIter.first, indexMin, indexMax, volumeMapIter.second });
}
+ std::swap(tempVolumeGroups, volumeGroups);
return NO_ERROR;
}
@@ -695,35 +698,14 @@
return deserializeLegacyVolumeCollection(doc, cur, volumeGroups, nbSkippedElements);
}
-static const int gApmXmlConfigFilePathMaxLength = 128;
-
-static constexpr const char *apmXmlConfigFileName = "audio_policy_configuration.xml";
-static constexpr const char *apmA2dpOffloadDisabledXmlConfigFileName =
- "audio_policy_configuration_a2dp_offload_disabled.xml";
-
android::status_t parseLegacyVolumes(VolumeGroups &volumeGroups) {
- char audioPolicyXmlConfigFile[gApmXmlConfigFilePathMaxLength];
- std::vector<const char *> fileNames;
- status_t ret;
-
- if (property_get_bool("ro.bluetooth.a2dp_offload.supported", false) &&
- property_get_bool("persist.bluetooth.a2dp_offload.disabled", false)) {
- // A2DP offload supported but disabled: try to use special XML file
- fileNames.push_back(apmA2dpOffloadDisabledXmlConfigFileName);
+ if (std::string audioPolicyXmlConfigFile = audio_get_audio_policy_config_file();
+ !audioPolicyXmlConfigFile.empty()) {
+ return parseLegacyVolumeFile(audioPolicyXmlConfigFile.c_str(), volumeGroups);
+ } else {
+ ALOGE("No readable audio policy config file found");
+ return BAD_VALUE;
}
- fileNames.push_back(apmXmlConfigFileName);
-
- for (const char* fileName : fileNames) {
- for (const auto& path : audio_get_configuration_paths()) {
- snprintf(audioPolicyXmlConfigFile, sizeof(audioPolicyXmlConfigFile),
- "%s/%s", path.c_str(), fileName);
- ret = parseLegacyVolumeFile(audioPolicyXmlConfigFile, volumeGroups);
- if (ret == NO_ERROR) {
- return ret;
- }
- }
- }
- return BAD_VALUE;
}
} // namespace engineConfig
diff --git a/services/audiopolicy/engine/config/tests/Android.bp b/services/audiopolicy/engine/config/tests/Android.bp
new file mode 100644
index 0000000..6b0774f
--- /dev/null
+++ b/services/audiopolicy/engine/config/tests/Android.bp
@@ -0,0 +1,25 @@
+cc_test {
+ name: "audiopolicy_engineconfig_tests",
+
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libmedia_helper",
+ "libutils",
+ "libxml2",
+ ],
+ static_libs: [
+ "libaudiopolicyengine_config",
+ ],
+
+ srcs: ["engineconfig_tests.cpp"],
+
+ data: [":audiopolicy_engineconfig_files"],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ test_suites: ["device-tests"],
+}
diff --git a/services/audiopolicy/engine/config/tests/engineconfig_tests.cpp b/services/audiopolicy/engine/config/tests/engineconfig_tests.cpp
new file mode 100644
index 0000000..f61e02f
--- /dev/null
+++ b/services/audiopolicy/engine/config/tests/engineconfig_tests.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 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 <gtest/gtest.h>
+
+#define LOG_TAG "APM_Test"
+#include <android-base/file.h>
+#include <log/log.h>
+
+#include "EngineConfig.h"
+
+using namespace android;
+
+TEST(EngineConfigTestInit, LegacyVolumeGroupsLoadingIsTransactional) {
+ engineConfig::VolumeGroups groups;
+ ASSERT_TRUE(groups.empty());
+ status_t status = engineConfig::parseLegacyVolumeFile(
+ (base::GetExecutableDirectory() + "/test_invalid_apm_volume_tables.xml").c_str(),
+ groups);
+ ASSERT_NE(NO_ERROR, status);
+ EXPECT_TRUE(groups.empty());
+ status = engineConfig::parseLegacyVolumeFile(
+ (base::GetExecutableDirectory() + "/test_apm_volume_tables.xml").c_str(),
+ groups);
+ ASSERT_EQ(NO_ERROR, status);
+ EXPECT_FALSE(groups.empty());
+}
diff --git a/services/audiopolicy/engine/config/tests/resources/Android.bp b/services/audiopolicy/engine/config/tests/resources/Android.bp
new file mode 100644
index 0000000..0aee0e9
--- /dev/null
+++ b/services/audiopolicy/engine/config/tests/resources/Android.bp
@@ -0,0 +1,7 @@
+filegroup {
+ name: "audiopolicy_engineconfig_files",
+ srcs: [
+ "test_apm_volume_tables.xml",
+ "test_invalid_apm_volume_tables.xml",
+ ],
+}
diff --git a/services/audiopolicy/engine/config/tests/resources/test_apm_volume_tables.xml b/services/audiopolicy/engine/config/tests/resources/test_apm_volume_tables.xml
new file mode 100644
index 0000000..16126b6
--- /dev/null
+++ b/services/audiopolicy/engine/config/tests/resources/test_apm_volume_tables.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- Copyright (C) 2020 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.
+-->
+
+<audioPolicyConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <globalConfiguration speaker_drc_enabled="true"/>
+ <volumes>
+ <volume stream="AUDIO_STREAM_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_HEADSET">
+ <point>0,-4200</point>
+ <point>33,-2800</point>
+ <point>66,-1400</point>
+ <point>100,0</point>
+ </volume>
+ <volume stream="AUDIO_STREAM_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>0,-2400</point>
+ <point>33,-1600</point>
+ <point>66,-800</point>
+ <point>100,0</point>
+ </volume>
+ <volume stream="AUDIO_STREAM_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_HEARING_AID"
+ ref="FULL_SCALE_VOLUME_CURVE"/>
+ </volumes>
+ <volumes>
+ <reference name="FULL_SCALE_VOLUME_CURVE">
+ <!-- Full Scale reference Volume Curve -->
+ <point>0,0</point>
+ <point>100,0</point>
+ </reference>
+ </volumes>
+</audioPolicyConfiguration>
diff --git a/services/audiopolicy/engine/config/tests/resources/test_invalid_apm_volume_tables.xml b/services/audiopolicy/engine/config/tests/resources/test_invalid_apm_volume_tables.xml
new file mode 100644
index 0000000..3ec5d10
--- /dev/null
+++ b/services/audiopolicy/engine/config/tests/resources/test_invalid_apm_volume_tables.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- Copyright (C) 2020 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.
+-->
+
+<!-- This file uses a non-existent audio stream name. -->
+<audioPolicyConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <globalConfiguration speaker_drc_enabled="true"/>
+ <volumes>
+ <volume stream="AUDIO_STREAM_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_HEADSET">
+ <point>0,-4200</point>
+ <point>33,-2800</point>
+ <point>66,-1400</point>
+ <point>100,0</point>
+ </volume>
+ <volume stream="AUDIO_STREAM_NON_EXISTING" deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>0,-2400</point>
+ <point>33,-1600</point>
+ <point>66,-800</point>
+ <point>100,0</point>
+ </volume>
+ <volume stream="AUDIO_STREAM_RING" deviceCategory="DEVICE_CATEGORY_HEADSET"
+ ref="FULL_SCALE_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_HEADSET"
+ ref="FULL_SCALE_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_ALARM" deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>0,-2970</point>
+ <point>33,-2010</point>
+ <point>66,-1020</point>
+ <point>100,0</point>
+ </volume>
+ <volume stream="AUDIO_STREAM_NOTIFICATION" deviceCategory="DEVICE_CATEGORY_HEADSET"
+ ref="FULL_SCALE_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_BLUETOOTH_SCO" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
+ ref="FULL_SCALE_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_ENFORCED_AUDIBLE" deviceCategory="DEVICE_CATEGORY_HEARING_AID"
+ ref="FULL_SCALE_VOLUME_CURVE"/>
+ <volume stream="AUDIO_STREAM_DTMF" deviceCategory="DEVICE_CATEGORY_SPEAKER"
+ ref="FULL_SCALE_VOLUME_CURVE"/>
+ </volumes>
+ <volumes>
+ <reference name="FULL_SCALE_VOLUME_CURVE">
+ <!-- Full Scale reference Volume Curve -->
+ <point>0,0</point>
+ <point>100,0</point>
+ </reference>
+ </volumes>
+</audioPolicyConfiguration>
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index ec50b14..eccde7b 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -241,10 +241,15 @@
default: // FORCE_NONE
devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_HEARING_AID);
if (!devices.isEmpty()) break;
+
+ // TODO (b/161358428): remove when preferred device
+ // for strategy phone will be used instead of AUDIO_POLICY_FORCE_FOR_COMMUNICATION
+ devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_BLE_HEADSET);
+ if (!devices.isEmpty()) break;
+
// when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP
if (!isInCall() &&
- (getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
- outputs.isA2dpSupported()) {
+ (getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP)) {
devices = availableOutputDevices.getFirstDevicesFromTypes({
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES});
@@ -267,12 +272,16 @@
case AUDIO_POLICY_FORCE_SPEAKER:
// when not in a phone call, phone strategy should route STREAM_VOICE_CALL to
// A2DP speaker when forcing to speaker output
- if (!isInCall() &&
- (getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
- outputs.isA2dpSupported()) {
+ if (!isInCall()) {
devices = availableOutputDevices.getDevicesFromType(
- AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER);
+ AUDIO_DEVICE_OUT_BLE_SPEAKER);
if (!devices.isEmpty()) break;
+
+ if ((getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP)) {
+ devices = availableOutputDevices.getDevicesFromType(
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER);
+ if (!devices.isEmpty()) break;
+ }
}
if (!isInCall()) {
devices = availableOutputDevices.getFirstDevicesFromTypes({
@@ -386,18 +395,13 @@
STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs);
break;
}
- // FIXME: Find a better solution to prevent routing to BT hearing aid(b/122931261).
- if ((devices2.isEmpty()) &&
- (getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP)) {
- devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_HEARING_AID);
- }
+
if ((devices2.isEmpty()) &&
(getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) == AUDIO_POLICY_FORCE_SPEAKER)) {
devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
}
if (devices2.isEmpty() && (getLastRemovableMediaDevices().size() > 0)) {
- if ((getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
- outputs.isA2dpSupported()) {
+ if ((getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP)) {
// Get the last connected device of wired and bluetooth a2dp
devices2 = availableOutputDevices.getFirstDevicesFromTypes(
getLastRemovableMediaDevices());
@@ -518,8 +522,9 @@
if (device != nullptr) break;
}
device = availableDevices.getFirstExistingDevice({
- AUDIO_DEVICE_IN_WIRED_HEADSET, AUDIO_DEVICE_IN_USB_HEADSET,
- AUDIO_DEVICE_IN_USB_DEVICE, AUDIO_DEVICE_IN_BUILTIN_MIC});
+ AUDIO_DEVICE_IN_BLE_HEADSET, AUDIO_DEVICE_IN_WIRED_HEADSET,
+ AUDIO_DEVICE_IN_USB_HEADSET, AUDIO_DEVICE_IN_USB_DEVICE,
+ AUDIO_DEVICE_IN_BUILTIN_MIC});
break;
case AUDIO_SOURCE_VOICE_COMMUNICATION:
@@ -543,9 +548,13 @@
FALLTHROUGH_INTENDED;
default: // FORCE_NONE
+ // TODO (b/161358428): remove AUDIO_DEVICE_IN_BLE_HEADSET from the list
+ // when preferred device for strategy phone will be used instead of
+ // AUDIO_POLICY_FORCE_FOR_COMMUNICATION.
device = availableDevices.getFirstExistingDevice({
- AUDIO_DEVICE_IN_WIRED_HEADSET, AUDIO_DEVICE_IN_USB_HEADSET,
- AUDIO_DEVICE_IN_USB_DEVICE, AUDIO_DEVICE_IN_BUILTIN_MIC});
+ AUDIO_DEVICE_IN_BLE_HEADSET, AUDIO_DEVICE_IN_WIRED_HEADSET,
+ AUDIO_DEVICE_IN_USB_HEADSET, AUDIO_DEVICE_IN_USB_DEVICE,
+ AUDIO_DEVICE_IN_BUILTIN_MIC});
break;
case AUDIO_POLICY_FORCE_SPEAKER:
@@ -570,8 +579,9 @@
if (device != nullptr) break;
}
device = availableDevices.getFirstExistingDevice({
- AUDIO_DEVICE_IN_WIRED_HEADSET, AUDIO_DEVICE_IN_USB_HEADSET,
- AUDIO_DEVICE_IN_USB_DEVICE, AUDIO_DEVICE_IN_BUILTIN_MIC});
+ AUDIO_DEVICE_IN_BLE_HEADSET, AUDIO_DEVICE_IN_WIRED_HEADSET,
+ AUDIO_DEVICE_IN_USB_HEADSET, AUDIO_DEVICE_IN_USB_DEVICE,
+ AUDIO_DEVICE_IN_BUILTIN_MIC});
break;
case AUDIO_SOURCE_CAMCORDER:
// For a device without built-in mic, adding usb device
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index d9a5fa2..ad1f147 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -29,31 +29,26 @@
#define ALOGVV(a...) do { } while(0)
#endif
-#define AUDIO_POLICY_XML_CONFIG_FILE_PATH_MAX_LENGTH 128
-#define AUDIO_POLICY_XML_CONFIG_FILE_NAME "audio_policy_configuration.xml"
-#define AUDIO_POLICY_A2DP_OFFLOAD_DISABLED_XML_CONFIG_FILE_NAME \
- "audio_policy_configuration_a2dp_offload_disabled.xml"
-#define AUDIO_POLICY_BLUETOOTH_LEGACY_HAL_XML_CONFIG_FILE_NAME \
- "audio_policy_configuration_bluetooth_legacy_hal.xml"
-
#include <algorithm>
#include <inttypes.h>
#include <math.h>
#include <set>
#include <unordered_set>
#include <vector>
+
+#include <Serializer.h>
#include <cutils/bitops.h>
#include <cutils/properties.h>
-#include <utils/Log.h>
#include <media/AudioParameter.h>
+#include <policy.h>
#include <private/android_filesystem_config.h>
#include <system/audio.h>
#include <system/audio_config.h>
#include <system/audio_effects/effect_hapticgenerator.h>
+#include <utils/Log.h>
+
#include "AudioPolicyManager.h"
-#include <Serializer.h>
#include "TypeConverter.h"
-#include <policy.h>
namespace android {
@@ -4539,37 +4534,15 @@
}
static status_t deserializeAudioPolicyXmlConfig(AudioPolicyConfig &config) {
- char audioPolicyXmlConfigFile[AUDIO_POLICY_XML_CONFIG_FILE_PATH_MAX_LENGTH];
- std::vector<const char*> fileNames;
- status_t ret;
-
- if (property_get_bool("ro.bluetooth.a2dp_offload.supported", false)) {
- if (property_get_bool("persist.bluetooth.bluetooth_audio_hal.disabled", false) &&
- property_get_bool("persist.bluetooth.a2dp_offload.disabled", false)) {
- // Both BluetoothAudio@2.0 and BluetoothA2dp@1.0 (Offlaod) are disabled, and uses
- // the legacy hardware module for A2DP and hearing aid.
- fileNames.push_back(AUDIO_POLICY_BLUETOOTH_LEGACY_HAL_XML_CONFIG_FILE_NAME);
- } else if (property_get_bool("persist.bluetooth.a2dp_offload.disabled", false)) {
- // A2DP offload supported but disabled: try to use special XML file
- fileNames.push_back(AUDIO_POLICY_A2DP_OFFLOAD_DISABLED_XML_CONFIG_FILE_NAME);
+ if (std::string audioPolicyXmlConfigFile = audio_get_audio_policy_config_file();
+ !audioPolicyXmlConfigFile.empty()) {
+ status_t ret = deserializeAudioPolicyFile(audioPolicyXmlConfigFile.c_str(), &config);
+ if (ret == NO_ERROR) {
+ config.setSource(audioPolicyXmlConfigFile);
}
- } else if (property_get_bool("persist.bluetooth.bluetooth_audio_hal.disabled", false)) {
- fileNames.push_back(AUDIO_POLICY_BLUETOOTH_LEGACY_HAL_XML_CONFIG_FILE_NAME);
+ return ret;
}
- fileNames.push_back(AUDIO_POLICY_XML_CONFIG_FILE_NAME);
-
- for (const char* fileName : fileNames) {
- for (const auto& path : audio_get_configuration_paths()) {
- snprintf(audioPolicyXmlConfigFile, sizeof(audioPolicyXmlConfigFile),
- "%s/%s", path.c_str(), fileName);
- ret = deserializeAudioPolicyFile(audioPolicyXmlConfigFile, &config);
- if (ret == NO_ERROR) {
- config.setSource(audioPolicyXmlConfigFile);
- return ret;
- }
- }
- }
- return ret;
+ return BAD_VALUE;
}
AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface,
@@ -6251,9 +6224,8 @@
float volumeDb = computeVolume(curves, volumeSource, index, deviceTypes);
if (outputDesc->isFixedVolume(deviceTypes) ||
- // Force VoIP volume to max for bluetooth SCO
-
- ((isVoiceVolSrc || isBtScoVolSrc) &&
+ // Force VoIP volume to max for bluetooth SCO device except if muted
+ (index != 0 && (isVoiceVolSrc || isBtScoVolSrc) &&
isSingleDeviceType(deviceTypes, audio_is_bluetooth_out_sco_device))) {
volumeDb = 0.0f;
}
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index ca2164b..7972dbf 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -58,6 +58,34 @@
ASSERT_EQ(NO_INIT, manager.initCheck());
}
+// Verifies that a failure while loading a config doesn't leave
+// APM config in a "dirty" state. Since AudioPolicyConfig object
+// is a proxy for the data hosted by APM, it isn't possible
+// to "deep copy" it, and thus we have to test its elements
+// individually.
+TEST(AudioPolicyManagerTestInit, ConfigLoadingIsTransactional) {
+ AudioPolicyTestClient client;
+ AudioPolicyTestManager manager(&client);
+ ASSERT_TRUE(manager.getConfig().getHwModules().isEmpty());
+ ASSERT_TRUE(manager.getConfig().getInputDevices().isEmpty());
+ ASSERT_TRUE(manager.getConfig().getOutputDevices().isEmpty());
+ status_t status = deserializeAudioPolicyFile(
+ (base::GetExecutableDirectory() +
+ "/test_invalid_audio_policy_configuration.xml").c_str(),
+ &manager.getConfig());
+ ASSERT_NE(NO_ERROR, status);
+ EXPECT_TRUE(manager.getConfig().getHwModules().isEmpty());
+ EXPECT_TRUE(manager.getConfig().getInputDevices().isEmpty());
+ EXPECT_TRUE(manager.getConfig().getOutputDevices().isEmpty());
+ status = deserializeAudioPolicyFile(
+ (base::GetExecutableDirectory() + "/test_audio_policy_configuration.xml").c_str(),
+ &manager.getConfig());
+ ASSERT_EQ(NO_ERROR, status);
+ EXPECT_FALSE(manager.getConfig().getHwModules().isEmpty());
+ EXPECT_FALSE(manager.getConfig().getInputDevices().isEmpty());
+ EXPECT_FALSE(manager.getConfig().getOutputDevices().isEmpty());
+}
+
class PatchCountCheck {
public:
diff --git a/services/audiopolicy/tests/resources/Android.bp b/services/audiopolicy/tests/resources/Android.bp
index d9476d9..4f50dad 100644
--- a/services/audiopolicy/tests/resources/Android.bp
+++ b/services/audiopolicy/tests/resources/Android.bp
@@ -3,6 +3,7 @@
srcs: [
"test_audio_policy_configuration.xml",
"test_audio_policy_primary_only_configuration.xml",
+ "test_invalid_audio_policy_configuration.xml",
"test_tv_apm_configuration.xml",
],
}
diff --git a/services/audiopolicy/tests/resources/test_invalid_audio_policy_configuration.xml b/services/audiopolicy/tests/resources/test_invalid_audio_policy_configuration.xml
new file mode 100644
index 0000000..25641d5
--- /dev/null
+++ b/services/audiopolicy/tests/resources/test_invalid_audio_policy_configuration.xml
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- Copyright (C) 2020 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.
+-->
+
+<!-- This file contains an unnamed device port in the "r_submix" module section. -->
+<audioPolicyConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <globalConfiguration speaker_drc_enabled="true"/>
+
+ <modules>
+ <!-- Primary module -->
+ <module name="primary" halVersion="2.0">
+ <attachedDevices>
+ <item>Speaker</item>
+ <item>Built-In Mic</item>
+ </attachedDevices>
+ <defaultOutputDevice>Speaker</defaultOutputDevice>
+ <mixPorts>
+ <mixPort name="primary output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="primary input" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000"
+ channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+ </mixPort>
+ <mixPort name="mixport_bt_hfp_output" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="mixport_bt_hfp_input" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="8000,11025,16000,44100,48000"
+ channelMasks="AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_MONO"/>
+ </mixPort>
+ </mixPorts>
+ <devicePorts>
+ <devicePort tagName="Speaker" type="AUDIO_DEVICE_OUT_SPEAKER" role="sink">
+ </devicePort>
+ <devicePort tagName="Built-In Mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" role="source">
+ </devicePort>
+ <devicePort tagName="Hdmi" type="AUDIO_DEVICE_OUT_HDMI" role="sink">
+ </devicePort>
+ <devicePort tagName="Hdmi-In Mic" type="AUDIO_DEVICE_IN_HDMI" role="source">
+ </devicePort>
+ <devicePort tagName="BT SCO" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO"
+ role="sink" address="hfp_client_out">
+ </devicePort>
+ <devicePort tagName="BT SCO Headset Mic" type="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET"
+ role="source" address="hfp_client_in">
+ </devicePort>
+ </devicePorts>
+ <routes>
+ <route type="mix" sink="Speaker"
+ sources="primary output"/>
+ <route type="mix" sink="primary input"
+ sources="Built-In Mic,Hdmi-In Mic"/>
+ <route type="mix" sink="Hdmi"
+ sources="primary output"/>
+ <route type="mix" sink="BT SCO"
+ sources="mixport_bt_hfp_output"/>
+ <route type="mix" sink="mixport_bt_hfp_input"
+ sources="BT SCO Headset Mic"/>
+ </routes>
+ </module>
+
+ <!-- Remote Submix module -->
+ <module name="r_submix" halVersion="2.0">
+ <attachedDevices>
+ <item>Remote Submix In</item>
+ </attachedDevices>
+ <mixPorts>
+ <mixPort name="r_submix output" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="r_submix input" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+ </mixPort>
+ </mixPorts>
+ <devicePorts>
+ <!-- This port is missing "tagName" attribute. -->
+ <devicePort type="AUDIO_DEVICE_OUT_REMOTE_SUBMIX" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </devicePort>
+ <devicePort tagName="Remote Submix In" type="AUDIO_DEVICE_IN_REMOTE_SUBMIX" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+ </devicePort>
+ </devicePorts>
+ <routes>
+ <route type="mix" sink="Remote Submix Out"
+ sources="r_submix output"/>
+ <route type="mix" sink="r_submix input"
+ sources="Remote Submix In"/>
+ </routes>
+ </module>
+ </modules>
+</audioPolicyConfiguration>
diff --git a/services/mediatranscoding/MediaTranscodingService.cpp b/services/mediatranscoding/MediaTranscodingService.cpp
index 9639c55..56f327e 100644
--- a/services/mediatranscoding/MediaTranscodingService.cpp
+++ b/services/mediatranscoding/MediaTranscodingService.cpp
@@ -24,8 +24,8 @@
#include <cutils/properties.h>
#include <media/TranscoderWrapper.h>
#include <media/TranscodingClientManager.h>
-#include <media/TranscodingJobScheduler.h>
#include <media/TranscodingResourcePolicy.h>
+#include <media/TranscodingSessionController.h>
#include <media/TranscodingUidPolicy.h>
#include <utils/Log.h>
#include <utils/Vector.h>
@@ -44,12 +44,13 @@
const std::shared_ptr<TranscoderInterface>& transcoder)
: mUidPolicy(new TranscodingUidPolicy()),
mResourcePolicy(new TranscodingResourcePolicy()),
- mJobScheduler(new TranscodingJobScheduler(transcoder, mUidPolicy, mResourcePolicy)),
- mClientManager(new TranscodingClientManager(mJobScheduler)) {
+ mSessionController(
+ new TranscodingSessionController(transcoder, mUidPolicy, mResourcePolicy)),
+ mClientManager(new TranscodingClientManager(mSessionController)) {
ALOGV("MediaTranscodingService is created");
- transcoder->setCallback(mJobScheduler);
- mUidPolicy->setCallback(mJobScheduler);
- mResourcePolicy->setCallback(mJobScheduler);
+ transcoder->setCallback(mSessionController);
+ mUidPolicy->setCallback(mSessionController);
+ mResourcePolicy->setCallback(mSessionController);
}
MediaTranscodingService::~MediaTranscodingService() {
@@ -78,7 +79,7 @@
Vector<String16> args;
mClientManager->dumpAllClients(fd, args);
- mJobScheduler->dumpAllJobs(fd, args);
+ mSessionController->dumpAllSessions(fd, args);
return OK;
}
diff --git a/services/mediatranscoding/MediaTranscodingService.h b/services/mediatranscoding/MediaTranscodingService.h
index 0fe6864..428f777 100644
--- a/services/mediatranscoding/MediaTranscodingService.h
+++ b/services/mediatranscoding/MediaTranscodingService.h
@@ -26,17 +26,17 @@
using ::aidl::android::media::BnMediaTranscodingService;
using ::aidl::android::media::ITranscodingClient;
using ::aidl::android::media::ITranscodingClientCallback;
-using ::aidl::android::media::TranscodingJobParcel;
using ::aidl::android::media::TranscodingRequestParcel;
+using ::aidl::android::media::TranscodingSessionParcel;
class TranscodingClientManager;
-class TranscodingJobScheduler;
+class TranscodingSessionController;
class TranscoderInterface;
class UidPolicyInterface;
class ResourcePolicyInterface;
class MediaTranscodingService : public BnMediaTranscodingService {
public:
- static constexpr int32_t kInvalidJobId = -1;
+ static constexpr int32_t kInvalidSessionId = -1;
static constexpr int32_t kInvalidClientId = -1;
MediaTranscodingService(const std::shared_ptr<TranscoderInterface>& transcoder);
@@ -61,7 +61,7 @@
std::shared_ptr<UidPolicyInterface> mUidPolicy;
std::shared_ptr<ResourcePolicyInterface> mResourcePolicy;
- std::shared_ptr<TranscodingJobScheduler> mJobScheduler;
+ std::shared_ptr<TranscodingSessionController> mSessionController;
std::shared_ptr<TranscodingClientManager> mClientManager;
};
diff --git a/services/mediatranscoding/SimulatedTranscoder.cpp b/services/mediatranscoding/SimulatedTranscoder.cpp
index 97d5f5f..03ee886 100644
--- a/services/mediatranscoding/SimulatedTranscoder.cpp
+++ b/services/mediatranscoding/SimulatedTranscoder.cpp
@@ -48,58 +48,59 @@
}
void SimulatedTranscoder::start(
- ClientIdType clientId, JobIdType jobId, const TranscodingRequestParcel& request,
+ ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& request,
const std::shared_ptr<ITranscodingClientCallback>& /*clientCallback*/) {
if (request.testConfig.has_value() && request.testConfig->processingTotalTimeMs > 0) {
- mJobProcessingTimeMs = request.testConfig->processingTotalTimeMs;
+ mSessionProcessingTimeMs = request.testConfig->processingTotalTimeMs;
}
- ALOGV("%s: job {%d}: processingTime: %lld", __FUNCTION__, jobId,
- (long long)mJobProcessingTimeMs);
- queueEvent(Event::Start, clientId, jobId, [=] {
+ ALOGV("%s: session {%d}: processingTime: %lld", __FUNCTION__, sessionId,
+ (long long)mSessionProcessingTimeMs);
+ queueEvent(Event::Start, clientId, sessionId, [=] {
auto callback = mCallback.lock();
if (callback != nullptr) {
- callback->onStarted(clientId, jobId);
+ callback->onStarted(clientId, sessionId);
}
});
}
-void SimulatedTranscoder::pause(ClientIdType clientId, JobIdType jobId) {
- queueEvent(Event::Pause, clientId, jobId, [=] {
+void SimulatedTranscoder::pause(ClientIdType clientId, SessionIdType sessionId) {
+ queueEvent(Event::Pause, clientId, sessionId, [=] {
auto callback = mCallback.lock();
if (callback != nullptr) {
- callback->onPaused(clientId, jobId);
+ callback->onPaused(clientId, sessionId);
}
});
}
void SimulatedTranscoder::resume(
- ClientIdType clientId, JobIdType jobId, const TranscodingRequestParcel& /*request*/,
+ ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& /*request*/,
const std::shared_ptr<ITranscodingClientCallback>& /*clientCallback*/) {
- queueEvent(Event::Resume, clientId, jobId, [=] {
+ queueEvent(Event::Resume, clientId, sessionId, [=] {
auto callback = mCallback.lock();
if (callback != nullptr) {
- callback->onResumed(clientId, jobId);
+ callback->onResumed(clientId, sessionId);
}
});
}
-void SimulatedTranscoder::stop(ClientIdType clientId, JobIdType jobId) {
- queueEvent(Event::Stop, clientId, jobId, nullptr);
+void SimulatedTranscoder::stop(ClientIdType clientId, SessionIdType sessionId) {
+ queueEvent(Event::Stop, clientId, sessionId, nullptr);
}
-void SimulatedTranscoder::queueEvent(Event::Type type, ClientIdType clientId, JobIdType jobId,
- std::function<void()> runnable) {
- ALOGV("%s: job {%lld, %d}: %s", __FUNCTION__, (long long)clientId, jobId, toString(type));
+void SimulatedTranscoder::queueEvent(Event::Type type, ClientIdType clientId,
+ SessionIdType sessionId, std::function<void()> runnable) {
+ ALOGV("%s: session {%lld, %d}: %s", __FUNCTION__, (long long)clientId, sessionId,
+ toString(type));
auto lock = std::scoped_lock(mLock);
- mQueue.push_back({type, clientId, jobId, runnable});
+ mQueue.push_back({type, clientId, sessionId, runnable});
mCondition.notify_one();
}
void SimulatedTranscoder::threadLoop() {
bool running = false;
- std::chrono::microseconds remainingUs(kJobDurationUs);
+ std::chrono::microseconds remainingUs(kSessionDurationUs);
std::chrono::system_clock::time_point lastRunningTime;
Event lastRunningEvent;
@@ -113,7 +114,7 @@
mCondition.wait(lock);
continue;
}
- // If running, wait for the remaining life of this job. Report finish if timed out.
+ // If running, wait for the remaining life of this session. Report finish if timed out.
std::cv_status status = mCondition.wait_for(lock, remainingUs);
if (status == std::cv_status::timeout) {
running = false;
@@ -121,7 +122,7 @@
auto callback = mCallback.lock();
if (callback != nullptr) {
lock.unlock();
- callback->onFinish(lastRunningEvent.clientId, lastRunningEvent.jobId);
+ callback->onFinish(lastRunningEvent.clientId, lastRunningEvent.sessionId);
lock.lock();
}
} else {
@@ -139,22 +140,22 @@
Event event = *mQueue.begin();
mQueue.pop_front();
- ALOGV("%s: job {%lld, %d}: %s", __FUNCTION__, (long long)event.clientId, event.jobId,
- toString(event.type));
+ ALOGV("%s: session {%lld, %d}: %s", __FUNCTION__, (long long)event.clientId,
+ event.sessionId, toString(event.type));
if (!running && (event.type == Event::Start || event.type == Event::Resume)) {
running = true;
lastRunningTime = std::chrono::system_clock::now();
lastRunningEvent = event;
if (event.type == Event::Start) {
- remainingUs = std::chrono::milliseconds(mJobProcessingTimeMs);
+ remainingUs = std::chrono::milliseconds(mSessionProcessingTimeMs);
}
} else if (running && (event.type == Event::Pause || event.type == Event::Stop)) {
running = false;
remainingUs -= (std::chrono::system_clock::now() - lastRunningTime);
} else {
- ALOGW("%s: discarding bad event: job {%lld, %d}: %s", __FUNCTION__,
- (long long)event.clientId, event.jobId, toString(event.type));
+ ALOGW("%s: discarding bad event: session {%lld, %d}: %s", __FUNCTION__,
+ (long long)event.clientId, event.sessionId, toString(event.type));
continue;
}
diff --git a/services/mediatranscoding/SimulatedTranscoder.h b/services/mediatranscoding/SimulatedTranscoder.h
index 1c359dd..ba2bba0 100644
--- a/services/mediatranscoding/SimulatedTranscoder.h
+++ b/services/mediatranscoding/SimulatedTranscoder.h
@@ -32,8 +32,8 @@
* SimulatedTranscoder is used when useSimulatedTranscoder in TranscodingTestConfig
* is set to true.
*
- * SimulatedTranscoder simulates job execution by reporting finish after kJobDurationUs.
- * Job lifecycle events are reported via progress updates with special progress
+ * SimulatedTranscoder simulates session execution by reporting finish after kSessionDurationUs.
+ * Session lifecycle events are reported via progress updates with special progress
* numbers (equal to the Event's type).
*/
class SimulatedTranscoder : public TranscoderInterface {
@@ -41,22 +41,24 @@
struct Event {
enum Type { NoEvent, Start, Pause, Resume, Stop, Finished, Failed } type;
ClientIdType clientId;
- JobIdType jobId;
+ SessionIdType sessionId;
std::function<void()> runnable;
};
- static constexpr int64_t kJobDurationUs = 1000000;
+ static constexpr int64_t kSessionDurationUs = 1000000;
SimulatedTranscoder();
// TranscoderInterface
void setCallback(const std::shared_ptr<TranscoderCallbackInterface>& cb) override;
- void start(ClientIdType clientId, JobIdType jobId, const TranscodingRequestParcel& request,
+ void start(ClientIdType clientId, SessionIdType sessionId,
+ const TranscodingRequestParcel& request,
const std::shared_ptr<ITranscodingClientCallback>& clientCallback) override;
- void pause(ClientIdType clientId, JobIdType jobId) override;
- void resume(ClientIdType clientId, JobIdType jobId, const TranscodingRequestParcel& request,
+ void pause(ClientIdType clientId, SessionIdType sessionId) override;
+ void resume(ClientIdType clientId, SessionIdType sessionId,
+ const TranscodingRequestParcel& request,
const std::shared_ptr<ITranscodingClientCallback>& clientCallback) override;
- void stop(ClientIdType clientId, JobIdType jobId) override;
+ void stop(ClientIdType clientId, SessionIdType sessionId) override;
// ~TranscoderInterface
private:
@@ -66,10 +68,10 @@
std::list<Event> mQueue GUARDED_BY(mLock);
// Minimum time spent on transcode the video. This is used just for testing.
- int64_t mJobProcessingTimeMs = kJobDurationUs / 1000;
+ int64_t mSessionProcessingTimeMs = kSessionDurationUs / 1000;
static const char* toString(Event::Type type);
- void queueEvent(Event::Type type, ClientIdType clientId, JobIdType jobId,
+ void queueEvent(Event::Type type, ClientIdType clientId, SessionIdType sessionId,
std::function<void()> runnable);
void threadLoop();
};
diff --git a/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h b/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h
index 6d0b99e..5f4f645 100644
--- a/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h
+++ b/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h
@@ -20,9 +20,9 @@
#include <aidl/android/media/IMediaTranscodingService.h>
#include <aidl/android/media/ITranscodingClient.h>
#include <aidl/android/media/ITranscodingClientCallback.h>
-#include <aidl/android/media/TranscodingJobParcel.h>
-#include <aidl/android/media/TranscodingJobPriority.h>
#include <aidl/android/media/TranscodingRequestParcel.h>
+#include <aidl/android/media/TranscodingSessionParcel.h>
+#include <aidl/android/media/TranscodingSessionPriority.h>
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
@@ -48,9 +48,9 @@
using aidl::android::media::IMediaTranscodingService;
using aidl::android::media::ITranscodingClient;
using aidl::android::media::ITranscodingClientCallback;
-using aidl::android::media::TranscodingJobParcel;
-using aidl::android::media::TranscodingJobPriority;
using aidl::android::media::TranscodingRequestParcel;
+using aidl::android::media::TranscodingSessionParcel;
+using aidl::android::media::TranscodingSessionPriority;
using aidl::android::media::TranscodingVideoTrackFormat;
constexpr int32_t kClientUseCallingPid = IMediaTranscodingService::USE_CALLING_PID;
@@ -112,12 +112,12 @@
struct Event {
enum { NoEvent, Start, Pause, Resume, Finished, Failed } type;
int64_t clientId;
- int32_t jobId;
+ int32_t sessionId;
};
-#define DECLARE_EVENT(action) \
- static Event action(int32_t clientId, int32_t jobId) { \
- return {Event::action, clientId, jobId}; \
+#define DECLARE_EVENT(action) \
+ static Event action(int32_t clientId, int32_t sessionId) { \
+ return {Event::action, clientId, sessionId}; \
}
DECLARE_EVENT(Start);
@@ -149,8 +149,8 @@
default:
return "NoEvent";
}
- return "job {" + std::to_string(event.clientId) + ", " + std::to_string(event.jobId) +
- "}: " + eventStr;
+ return "session {" + std::to_string(event.clientId) + ", " +
+ std::to_string(event.sessionId) + "}: " + eventStr;
}
// Pop 1 event from front, wait for up to timeoutUs if empty.
@@ -238,7 +238,7 @@
// Operators for GTest macros.
bool operator==(const EventTracker::Event& lhs, const EventTracker::Event& rhs) {
- return lhs.type == rhs.type && lhs.clientId == rhs.clientId && lhs.jobId == rhs.jobId;
+ return lhs.type == rhs.type && lhs.clientId == rhs.clientId && lhs.sessionId == rhs.sessionId;
}
std::ostream& operator<<(std::ostream& str, const EventTracker::Event& v) {
@@ -288,40 +288,41 @@
return Status::ok();
}
- Status onTranscodingStarted(int32_t in_jobId) override {
- append(EventTracker::Start(mClientId, in_jobId));
+ Status onTranscodingStarted(int32_t in_sessionId) override {
+ append(EventTracker::Start(mClientId, in_sessionId));
return Status::ok();
}
- Status onTranscodingPaused(int32_t in_jobId) override {
- append(EventTracker::Pause(mClientId, in_jobId));
+ Status onTranscodingPaused(int32_t in_sessionId) override {
+ append(EventTracker::Pause(mClientId, in_sessionId));
return Status::ok();
}
- Status onTranscodingResumed(int32_t in_jobId) override {
- append(EventTracker::Resume(mClientId, in_jobId));
+ Status onTranscodingResumed(int32_t in_sessionId) override {
+ append(EventTracker::Resume(mClientId, in_sessionId));
return Status::ok();
}
Status onTranscodingFinished(
- int32_t in_jobId,
+ int32_t in_sessionId,
const ::aidl::android::media::TranscodingResultParcel& /* in_result */) override {
- append(Finished(mClientId, in_jobId));
+ append(Finished(mClientId, in_sessionId));
return Status::ok();
}
- Status onTranscodingFailed(int32_t in_jobId,
+ Status onTranscodingFailed(int32_t in_sessionId,
::aidl::android::media::TranscodingErrorCode in_errorCode) override {
- append(Failed(mClientId, in_jobId), in_errorCode);
+ append(Failed(mClientId, in_sessionId), in_errorCode);
return Status::ok();
}
- Status onAwaitNumberOfJobsChanged(int32_t /* in_jobId */, int32_t /* in_oldAwaitNumber */,
- int32_t /* in_newAwaitNumber */) override {
+ Status onAwaitNumberOfSessionsChanged(int32_t /* in_sessionId */,
+ int32_t /* in_oldAwaitNumber */,
+ int32_t /* in_newAwaitNumber */) override {
return Status::ok();
}
- Status onProgressUpdate(int32_t /* in_jobId */, int32_t in_progress) override {
+ Status onProgressUpdate(int32_t /* in_sessionId */, int32_t in_progress) override {
updateProgress(in_progress);
return Status::ok();
}
@@ -354,13 +355,13 @@
}
template <bool expectation = success>
- bool submit(int32_t jobId, const char* sourceFilePath, const char* destinationFilePath,
- TranscodingJobPriority priority = TranscodingJobPriority::kNormal,
+ bool submit(int32_t sessionId, const char* sourceFilePath, const char* destinationFilePath,
+ TranscodingSessionPriority priority = TranscodingSessionPriority::kNormal,
int bitrateBps = -1, int overridePid = -1, int overrideUid = -1) {
constexpr bool shouldSucceed = (expectation == success);
bool result;
TranscodingRequestParcel request;
- TranscodingJobParcel job;
+ TranscodingSessionParcel session;
request.sourceFilePath = sourceFilePath;
request.destinationFilePath = destinationFilePath;
@@ -371,22 +372,23 @@
request.requestedVideoTrackFormat.emplace(TranscodingVideoTrackFormat());
request.requestedVideoTrackFormat->bitrateBps = bitrateBps;
}
- Status status = mClient->submitRequest(request, &job, &result);
+ Status status = mClient->submitRequest(request, &session, &result);
EXPECT_TRUE(status.isOk());
EXPECT_EQ(result, shouldSucceed);
if (shouldSucceed) {
- EXPECT_EQ(job.jobId, jobId);
+ EXPECT_EQ(session.sessionId, sessionId);
}
- return status.isOk() && (result == shouldSucceed) && (!shouldSucceed || job.jobId == jobId);
+ return status.isOk() && (result == shouldSucceed) &&
+ (!shouldSucceed || session.sessionId == sessionId);
}
template <bool expectation = success>
- bool cancel(int32_t jobId) {
+ bool cancel(int32_t sessionId) {
constexpr bool shouldSucceed = (expectation == success);
bool result;
- Status status = mClient->cancelJob(jobId, &result);
+ Status status = mClient->cancelSession(sessionId, &result);
EXPECT_TRUE(status.isOk());
EXPECT_EQ(result, shouldSucceed);
@@ -395,23 +397,24 @@
}
template <bool expectation = success>
- bool getJob(int32_t jobId, const char* sourceFilePath, const char* destinationFilePath) {
+ bool getSession(int32_t sessionId, const char* sourceFilePath,
+ const char* destinationFilePath) {
constexpr bool shouldSucceed = (expectation == success);
bool result;
- TranscodingJobParcel job;
- Status status = mClient->getJobWithId(jobId, &job, &result);
+ TranscodingSessionParcel session;
+ Status status = mClient->getSessionWithId(sessionId, &session, &result);
EXPECT_TRUE(status.isOk());
EXPECT_EQ(result, shouldSucceed);
if (shouldSucceed) {
- EXPECT_EQ(job.jobId, jobId);
- EXPECT_EQ(job.request.sourceFilePath, sourceFilePath);
+ EXPECT_EQ(session.sessionId, sessionId);
+ EXPECT_EQ(session.request.sourceFilePath, sourceFilePath);
}
return status.isOk() && (result == shouldSucceed) &&
- (!shouldSucceed ||
- (job.jobId == jobId && job.request.sourceFilePath == sourceFilePath &&
- job.request.destinationFilePath == destinationFilePath));
+ (!shouldSucceed || (session.sessionId == sessionId &&
+ session.request.sourceFilePath == sourceFilePath &&
+ session.request.destinationFilePath == destinationFilePath));
}
int32_t mClientId;
diff --git a/services/mediatranscoding/tests/mediatranscodingservice_real_tests.cpp b/services/mediatranscoding/tests/mediatranscodingservice_real_tests.cpp
index 381bbf5..0550d77 100644
--- a/services/mediatranscoding/tests/mediatranscodingservice_real_tests.cpp
+++ b/services/mediatranscoding/tests/mediatranscodingservice_real_tests.cpp
@@ -34,7 +34,7 @@
namespace media {
constexpr int64_t kPaddingUs = 400000;
-constexpr int64_t kJobWithPaddingUs = 10000000 + kPaddingUs;
+constexpr int64_t kSessionWithPaddingUs = 10000000 + kPaddingUs;
constexpr int32_t kBitRate = 8 * 1000 * 1000; // 8Mbs
constexpr const char* kShortSrcPath =
@@ -59,8 +59,9 @@
const char* dstPath = OUTPATH(TestInvalidSource);
deleteFile(dstPath);
- // Submit one job.
- EXPECT_TRUE(mClient1->submit(0, srcPath, dstPath, TranscodingJobPriority::kNormal, kBitRate));
+ // Submit one session.
+ EXPECT_TRUE(
+ mClient1->submit(0, srcPath, dstPath, TranscodingSessionPriority::kNormal, kBitRate));
// Check expected error.
EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Failed(CLIENT(1), 0));
@@ -75,12 +76,12 @@
const char* dstPath = OUTPATH(TestPassthru);
deleteFile(dstPath);
- // Submit one job.
+ // Submit one session.
EXPECT_TRUE(mClient1->submit(0, kShortSrcPath, dstPath));
- // Wait for job to finish.
+ // Wait for session to finish.
EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
- EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+ EXPECT_EQ(mClient1->pop(kSessionWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
unregisterMultipleClients();
}
@@ -91,13 +92,13 @@
const char* dstPath = OUTPATH(TestTranscodeVideo);
deleteFile(dstPath);
- // Submit one job.
- EXPECT_TRUE(
- mClient1->submit(0, kShortSrcPath, dstPath, TranscodingJobPriority::kNormal, kBitRate));
+ // Submit one session.
+ EXPECT_TRUE(mClient1->submit(0, kShortSrcPath, dstPath, TranscodingSessionPriority::kNormal,
+ kBitRate));
- // Wait for job to finish.
+ // Wait for session to finish.
EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
- EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+ EXPECT_EQ(mClient1->pop(kSessionWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
unregisterMultipleClients();
}
@@ -108,13 +109,13 @@
const char* dstPath = OUTPATH(TestTranscodeVideoProgress);
deleteFile(dstPath);
- // Submit one job.
- EXPECT_TRUE(
- mClient1->submit(0, kLongSrcPath, dstPath, TranscodingJobPriority::kNormal, kBitRate));
+ // Submit one session.
+ EXPECT_TRUE(mClient1->submit(0, kLongSrcPath, dstPath, TranscodingSessionPriority::kNormal,
+ kBitRate));
- // Wait for job to finish.
+ // Wait for session to finish.
EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
- EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+ EXPECT_EQ(mClient1->pop(kSessionWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
// Check the progress update messages are received. For this clip (around ~15 second long),
// expect at least 10 updates, and the last update should be 100.
@@ -133,24 +134,26 @@
const char* srcPath0 = kLongSrcPath;
const char* srcPath1 = kShortSrcPath;
- const char* dstPath0 = OUTPATH(TestCancelImmediately_Job0);
- const char* dstPath1 = OUTPATH(TestCancelImmediately_Job1);
+ const char* dstPath0 = OUTPATH(TestCancelImmediately_Session0);
+ const char* dstPath1 = OUTPATH(TestCancelImmediately_Session1);
deleteFile(dstPath0);
deleteFile(dstPath1);
- // Submit one job, should start immediately.
- EXPECT_TRUE(mClient1->submit(0, srcPath0, dstPath0, TranscodingJobPriority::kNormal, kBitRate));
+ // Submit one session, should start immediately.
+ EXPECT_TRUE(
+ mClient1->submit(0, srcPath0, dstPath0, TranscodingSessionPriority::kNormal, kBitRate));
EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
- EXPECT_TRUE(mClient1->getJob(0, srcPath0, dstPath0));
+ EXPECT_TRUE(mClient1->getSession(0, srcPath0, dstPath0));
- // Test cancel job immediately, getJob should fail after cancel.
+ // Test cancel session immediately, getSession should fail after cancel.
EXPECT_TRUE(mClient1->cancel(0));
- EXPECT_TRUE(mClient1->getJob<fail>(0, "", ""));
+ EXPECT_TRUE(mClient1->getSession<fail>(0, "", ""));
- // Submit new job, new job should start immediately and finish.
- EXPECT_TRUE(mClient1->submit(1, srcPath1, dstPath1, TranscodingJobPriority::kNormal, kBitRate));
+ // Submit new session, new session should start immediately and finish.
+ EXPECT_TRUE(
+ mClient1->submit(1, srcPath1, dstPath1, TranscodingSessionPriority::kNormal, kBitRate));
EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
- EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 1));
+ EXPECT_EQ(mClient1->pop(kSessionWithPaddingUs), EventTracker::Finished(CLIENT(1), 1));
unregisterMultipleClients();
}
@@ -163,26 +166,28 @@
const char* srcPath0 = kLongSrcPath;
const char* srcPath1 = kShortSrcPath;
- const char* dstPath0 = OUTPATH(TestCancelWhileRunning_Job0);
- const char* dstPath1 = OUTPATH(TestCancelWhileRunning_Job1);
+ const char* dstPath0 = OUTPATH(TestCancelWhileRunning_Session0);
+ const char* dstPath1 = OUTPATH(TestCancelWhileRunning_Session1);
deleteFile(dstPath0);
deleteFile(dstPath1);
- // Submit two jobs, job 0 should start immediately, job 1 should be queued.
- EXPECT_TRUE(mClient1->submit(0, srcPath0, dstPath0, TranscodingJobPriority::kNormal, kBitRate));
- EXPECT_TRUE(mClient1->submit(1, srcPath1, dstPath1, TranscodingJobPriority::kNormal, kBitRate));
+ // Submit two sessions, session 0 should start immediately, session 1 should be queued.
+ EXPECT_TRUE(
+ mClient1->submit(0, srcPath0, dstPath0, TranscodingSessionPriority::kNormal, kBitRate));
+ EXPECT_TRUE(
+ mClient1->submit(1, srcPath1, dstPath1, TranscodingSessionPriority::kNormal, kBitRate));
EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
- EXPECT_TRUE(mClient1->getJob(0, srcPath0, dstPath0));
- EXPECT_TRUE(mClient1->getJob(1, srcPath1, dstPath1));
+ EXPECT_TRUE(mClient1->getSession(0, srcPath0, dstPath0));
+ EXPECT_TRUE(mClient1->getSession(1, srcPath1, dstPath1));
- // Job 0 (longtest) shouldn't finish in 1 seconds.
+ // Session 0 (longtest) shouldn't finish in 1 seconds.
EXPECT_EQ(mClient1->pop(1000000), EventTracker::NoEvent);
- // Now cancel job 0. Job 1 should start immediately and finish.
+ // Now cancel session 0. Session 1 should start immediately and finish.
EXPECT_TRUE(mClient1->cancel(0));
- EXPECT_TRUE(mClient1->getJob<fail>(0, "", ""));
+ EXPECT_TRUE(mClient1->getSession<fail>(0, "", ""));
EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
- EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 1));
+ EXPECT_EQ(mClient1->pop(kSessionWithPaddingUs), EventTracker::Finished(CLIENT(1), 1));
unregisterMultipleClients();
}
@@ -192,48 +197,49 @@
const char* srcPath0 = kLongSrcPath;
const char* srcPath1 = kShortSrcPath;
- const char* dstPath0 = OUTPATH(TestPauseResumeSingleClient_Job0);
- const char* dstPath1 = OUTPATH(TestPauseResumeSingleClient_Job1);
+ const char* dstPath0 = OUTPATH(TestPauseResumeSingleClient_Session0);
+ const char* dstPath1 = OUTPATH(TestPauseResumeSingleClient_Session1);
deleteFile(dstPath0);
deleteFile(dstPath1);
- // Submit one offline job, should start immediately.
- EXPECT_TRUE(mClient1->submit(0, srcPath0, dstPath0, TranscodingJobPriority::kUnspecified,
+ // Submit one offline session, should start immediately.
+ EXPECT_TRUE(mClient1->submit(0, srcPath0, dstPath0, TranscodingSessionPriority::kUnspecified,
kBitRate));
EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
- // Test get job after starts.
- EXPECT_TRUE(mClient1->getJob(0, srcPath0, dstPath0));
+ // Test get session after starts.
+ EXPECT_TRUE(mClient1->getSession(0, srcPath0, dstPath0));
- // Submit one realtime job.
- EXPECT_TRUE(mClient1->submit(1, srcPath1, dstPath1, TranscodingJobPriority::kNormal, kBitRate));
+ // Submit one realtime session.
+ EXPECT_TRUE(
+ mClient1->submit(1, srcPath1, dstPath1, TranscodingSessionPriority::kNormal, kBitRate));
- // Offline job should pause.
+ // Offline session should pause.
EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Pause(CLIENT(1), 0));
- EXPECT_TRUE(mClient1->getJob(0, srcPath0, dstPath0));
+ EXPECT_TRUE(mClient1->getSession(0, srcPath0, dstPath0));
- // Realtime job should start immediately, and run to finish.
+ // Realtime session should start immediately, and run to finish.
EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
- EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 1));
+ EXPECT_EQ(mClient1->pop(kSessionWithPaddingUs), EventTracker::Finished(CLIENT(1), 1));
- // Test get job after finish fails.
- EXPECT_TRUE(mClient1->getJob<fail>(1, "", ""));
+ // Test get session after finish fails.
+ EXPECT_TRUE(mClient1->getSession<fail>(1, "", ""));
- // Then offline job should resume.
+ // Then offline session should resume.
EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Resume(CLIENT(1), 0));
- // Test get job after resume.
- EXPECT_TRUE(mClient1->getJob(0, srcPath0, dstPath0));
+ // Test get session after resume.
+ EXPECT_TRUE(mClient1->getSession(0, srcPath0, dstPath0));
- // Offline job should finish.
- EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
- // Test get job after finish fails.
- EXPECT_TRUE(mClient1->getJob<fail>(0, "", ""));
+ // Offline session should finish.
+ EXPECT_EQ(mClient1->pop(kSessionWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+ // Test get session after finish fails.
+ EXPECT_TRUE(mClient1->getSession<fail>(0, "", ""));
unregisterMultipleClients();
}
/*
- * Basic test for pause/resume with two clients, with one job each.
- * Top app's job should preempt the other app's job.
+ * Basic test for pause/resume with two clients, with one session each.
+ * Top app's session should preempt the other app's session.
*/
TEST_F(MediaTranscodingServiceRealTest, TestPauseResumeMultiClients) {
ALOGD("TestPauseResumeMultiClients starting...");
@@ -256,33 +262,35 @@
ALOGD("Moving app A to top...");
EXPECT_TRUE(ShellHelper::Start(kClientPackageA, kTestActivityName));
- // Submit job to Client1.
- ALOGD("Submitting job to client1 (app A) ...");
- EXPECT_TRUE(mClient1->submit(0, srcPath0, dstPath0, TranscodingJobPriority::kNormal, kBitRate));
+ // Submit session to Client1.
+ ALOGD("Submitting session to client1 (app A) ...");
+ EXPECT_TRUE(
+ mClient1->submit(0, srcPath0, dstPath0, TranscodingSessionPriority::kNormal, kBitRate));
- // Client1's job should start immediately.
+ // Client1's session should start immediately.
EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
ALOGD("Moving app B to top...");
EXPECT_TRUE(ShellHelper::Start(kClientPackageB, kTestActivityName));
- // Client1's job should continue to run, since Client2 (app B) doesn't have any job.
+ // Client1's session should continue to run, since Client2 (app B) doesn't have any session.
EXPECT_EQ(mClient1->pop(1000000), EventTracker::NoEvent);
- // Submit job to Client2.
- ALOGD("Submitting job to client2 (app B) ...");
- EXPECT_TRUE(mClient2->submit(0, srcPath1, dstPath1, TranscodingJobPriority::kNormal, kBitRate));
+ // Submit session to Client2.
+ ALOGD("Submitting session to client2 (app B) ...");
+ EXPECT_TRUE(
+ mClient2->submit(0, srcPath1, dstPath1, TranscodingSessionPriority::kNormal, kBitRate));
- // Client1's job should pause, client2's job should start.
+ // Client1's session should pause, client2's session should start.
EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Pause(CLIENT(1), 0));
EXPECT_EQ(mClient2->pop(kPaddingUs), EventTracker::Start(CLIENT(2), 0));
- // Client2's job should finish, then Client1's job should resume.
- EXPECT_EQ(mClient2->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(2), 0));
+ // Client2's session should finish, then Client1's session should resume.
+ EXPECT_EQ(mClient2->pop(kSessionWithPaddingUs), EventTracker::Finished(CLIENT(2), 0));
EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Resume(CLIENT(1), 0));
- // Client1's job should finish.
- EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+ // Client1's session should finish.
+ EXPECT_EQ(mClient1->pop(kSessionWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
unregisterMultipleClients();
diff --git a/services/mediatranscoding/tests/mediatranscodingservice_resource_tests.cpp b/services/mediatranscoding/tests/mediatranscodingservice_resource_tests.cpp
index 31697d5..bf99efc 100644
--- a/services/mediatranscoding/tests/mediatranscodingservice_resource_tests.cpp
+++ b/services/mediatranscoding/tests/mediatranscodingservice_resource_tests.cpp
@@ -55,13 +55,13 @@
/**
* Basic testing for handling resource lost.
*
- * This test starts a transcoding job (that's somewhat long and takes several seconds),
+ * This test starts a transcoding session (that's somewhat long and takes several seconds),
* then launches an activity that allocates video codec instances until it hits insufficient
* resource error. Because the activity is running in foreground,
* ResourceManager would reclaim codecs from transcoding service which should
- * cause the job to be paused. The activity will hold the codecs for a few seconds
+ * cause the session to be paused. The activity will hold the codecs for a few seconds
* before releasing them, and the transcoding service should be able to resume
- * and complete the job.
+ * and complete the session.
*/
TEST_F(MediaTranscodingServiceResourceTest, TestResourceLost) {
ALOGD("TestResourceLost starting...");
@@ -79,21 +79,22 @@
ALOGD("Moving app A to top...");
EXPECT_TRUE(ShellHelper::Start(kClientPackageA, kTestActivityName));
- // Submit job to Client1.
- ALOGD("Submitting job to client1 (app A) ...");
- EXPECT_TRUE(mClient1->submit(0, srcPath0, dstPath0, TranscodingJobPriority::kNormal, kBitRate));
+ // Submit session to Client1.
+ ALOGD("Submitting session to client1 (app A) ...");
+ EXPECT_TRUE(
+ mClient1->submit(0, srcPath0, dstPath0, TranscodingSessionPriority::kNormal, kBitRate));
- // Client1's job should start immediately.
+ // Client1's session should start immediately.
EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
// Launch ResourcePolicyTestActivity, which will try to allocate up to 32
// instances, which should trigger insufficient resources on most devices.
// (Note that it's possible that the device supports a very high number of
- // resource instances, in which case we'll simply require that the job completes.)
+ // resource instances, in which case we'll simply require that the session completes.)
ALOGD("Launch ResourcePolicyTestActivity...");
EXPECT_TRUE(ShellHelper::Start(kClientPackageA, kResourcePolicyTestActivity));
- // The basic requirement is that the job should complete. Wait for finish
+ // The basic requirement is that the session should complete. Wait for finish
// event to come and pop up all events received.
std::list<EventTracker::Event> events;
EXPECT_TRUE(mClient1->waitForSpecificEventAndPop(EventTracker::Finished(CLIENT(1), 0), &events,
diff --git a/services/mediatranscoding/tests/mediatranscodingservice_simulated_tests.cpp b/services/mediatranscoding/tests/mediatranscodingservice_simulated_tests.cpp
index 789b493..7dfda44 100644
--- a/services/mediatranscoding/tests/mediatranscodingservice_simulated_tests.cpp
+++ b/services/mediatranscoding/tests/mediatranscodingservice_simulated_tests.cpp
@@ -23,9 +23,9 @@
#include <aidl/android/media/IMediaTranscodingService.h>
#include <aidl/android/media/ITranscodingClient.h>
#include <aidl/android/media/ITranscodingClientCallback.h>
-#include <aidl/android/media/TranscodingJobParcel.h>
-#include <aidl/android/media/TranscodingJobPriority.h>
#include <aidl/android/media/TranscodingRequestParcel.h>
+#include <aidl/android/media/TranscodingSessionParcel.h>
+#include <aidl/android/media/TranscodingSessionPriority.h>
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
@@ -44,15 +44,15 @@
namespace media {
-// Note that -1 is valid and means using calling pid/uid for the service. But only privilege caller could
-// use them. This test is not a privilege caller.
+// Note that -1 is valid and means using calling pid/uid for the service. But only privilege caller
+// could use them. This test is not a privilege caller.
constexpr int32_t kInvalidClientPid = -5;
constexpr int32_t kInvalidClientUid = -10;
constexpr const char* kInvalidClientName = "";
constexpr const char* kInvalidClientOpPackageName = "";
constexpr int64_t kPaddingUs = 1000000;
-constexpr int64_t kJobWithPaddingUs = SimulatedTranscoder::kJobDurationUs + kPaddingUs;
+constexpr int64_t kSessionWithPaddingUs = SimulatedTranscoder::kSessionDurationUs + kPaddingUs;
constexpr const char* kClientOpPackageName = "TestClientPackage";
@@ -135,18 +135,18 @@
unregisterMultipleClients();
}
-TEST_F(MediaTranscodingServiceSimulatedTest, TestJobIdIndependence) {
+TEST_F(MediaTranscodingServiceSimulatedTest, TestSessionIdIndependence) {
registerMultipleClients();
// Submit 2 requests on client1 first.
EXPECT_TRUE(mClient1->submit(0, "test_source_file", "test_destination_file"));
EXPECT_TRUE(mClient1->submit(1, "test_source_file", "test_destination_file"));
- // Submit 2 requests on client2, jobId should be independent for each client.
+ // Submit 2 requests on client2, sessionId should be independent for each client.
EXPECT_TRUE(mClient2->submit(0, "test_source_file", "test_destination_file"));
EXPECT_TRUE(mClient2->submit(1, "test_source_file", "test_destination_file"));
- // Cancel all jobs.
+ // Cancel all sessions.
EXPECT_TRUE(mClient1->cancel(0));
EXPECT_TRUE(mClient1->cancel(1));
EXPECT_TRUE(mClient2->cancel(0));
@@ -155,10 +155,10 @@
unregisterMultipleClients();
}
-TEST_F(MediaTranscodingServiceSimulatedTest, TestSubmitCancelJobs) {
+TEST_F(MediaTranscodingServiceSimulatedTest, TestSubmitCancelSessions) {
registerMultipleClients();
- // Test jobId assignment.
+ // Test sessionId assignment.
EXPECT_TRUE(mClient1->submit(0, "test_source_file_0", "test_destination_file"));
EXPECT_TRUE(mClient1->submit(1, "test_source_file_1", "test_destination_file"));
EXPECT_TRUE(mClient1->submit(2, "test_source_file_2", "test_destination_file"));
@@ -167,33 +167,33 @@
EXPECT_TRUE(mClient1->submit<fail>(0, "", ""));
// Test submit bad request (no valid sourceFilePath) fails.
- EXPECT_TRUE(mClient1->submit<fail>(0, "src", "dst", TranscodingJobPriority::kNormal, 1000000,
- kInvalidClientPid, kInvalidClientUid));
+ EXPECT_TRUE(mClient1->submit<fail>(0, "src", "dst", TranscodingSessionPriority::kNormal,
+ 1000000, kInvalidClientPid, kInvalidClientUid));
- // Test cancel non-existent job fails.
+ // Test cancel non-existent session fails.
EXPECT_TRUE(mClient1->cancel<fail>(100));
- // Job 0 should start immediately and finish in 2 seconds, followed by Job 1 start.
+ // Session 0 should start immediately and finish in 2 seconds, followed by Session 1 start.
EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
- EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+ EXPECT_EQ(mClient1->pop(kSessionWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
- // Test cancel valid jobId in random order.
- // Test cancel finished job fails.
+ // Test cancel valid sessionId in random order.
+ // Test cancel finished session fails.
EXPECT_TRUE(mClient1->cancel(2));
EXPECT_TRUE(mClient1->cancel<fail>(0));
EXPECT_TRUE(mClient1->cancel(1));
- // Test cancel job again fails.
+ // Test cancel session again fails.
EXPECT_TRUE(mClient1->cancel<fail>(1));
// Test no more events arriving after cancel.
- EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::NoEvent);
+ EXPECT_EQ(mClient1->pop(kSessionWithPaddingUs), EventTracker::NoEvent);
unregisterMultipleClients();
}
-TEST_F(MediaTranscodingServiceSimulatedTest, TestGetJobs) {
+TEST_F(MediaTranscodingServiceSimulatedTest, TestGetSessions) {
registerMultipleClients();
// Submit 3 requests.
@@ -201,69 +201,69 @@
EXPECT_TRUE(mClient1->submit(1, "test_source_file_1", "test_destination_file_1"));
EXPECT_TRUE(mClient1->submit(2, "test_source_file_2", "test_destination_file_2"));
- // Test get jobs by id.
- EXPECT_TRUE(mClient1->getJob(2, "test_source_file_2", "test_destination_file_2"));
- EXPECT_TRUE(mClient1->getJob(1, "test_source_file_1", "test_destination_file_1"));
- EXPECT_TRUE(mClient1->getJob(0, "test_source_file_0", "test_destination_file_0"));
+ // Test get sessions by id.
+ EXPECT_TRUE(mClient1->getSession(2, "test_source_file_2", "test_destination_file_2"));
+ EXPECT_TRUE(mClient1->getSession(1, "test_source_file_1", "test_destination_file_1"));
+ EXPECT_TRUE(mClient1->getSession(0, "test_source_file_0", "test_destination_file_0"));
- // Test get job by invalid id fails.
- EXPECT_TRUE(mClient1->getJob<fail>(100, "", ""));
- EXPECT_TRUE(mClient1->getJob<fail>(-1, "", ""));
+ // Test get session by invalid id fails.
+ EXPECT_TRUE(mClient1->getSession<fail>(100, "", ""));
+ EXPECT_TRUE(mClient1->getSession<fail>(-1, "", ""));
- // Test get job after cancel fails.
+ // Test get session after cancel fails.
EXPECT_TRUE(mClient1->cancel(2));
- EXPECT_TRUE(mClient1->getJob<fail>(2, "", ""));
+ EXPECT_TRUE(mClient1->getSession<fail>(2, "", ""));
- // Job 0 should start immediately and finish in 2 seconds, followed by Job 1 start.
+ // Session 0 should start immediately and finish in 2 seconds, followed by Session 1 start.
EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
- EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+ EXPECT_EQ(mClient1->pop(kSessionWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
- // Test get job after finish fails.
- EXPECT_TRUE(mClient1->getJob<fail>(0, "", ""));
+ // Test get session after finish fails.
+ EXPECT_TRUE(mClient1->getSession<fail>(0, "", ""));
- // Test get the remaining job 1.
- EXPECT_TRUE(mClient1->getJob(1, "test_source_file_1", "test_destination_file_1"));
+ // Test get the remaining session 1.
+ EXPECT_TRUE(mClient1->getSession(1, "test_source_file_1", "test_destination_file_1"));
- // Cancel remaining job 1.
+ // Cancel remaining session 1.
EXPECT_TRUE(mClient1->cancel(1));
unregisterMultipleClients();
}
-TEST_F(MediaTranscodingServiceSimulatedTest, TestSubmitCancelWithOfflineJobs) {
+TEST_F(MediaTranscodingServiceSimulatedTest, TestSubmitCancelWithOfflineSessions) {
registerMultipleClients();
- // Submit some offline jobs first.
+ // Submit some offline sessions first.
EXPECT_TRUE(mClient1->submit(0, "test_source_file_0", "test_destination_file_0",
- TranscodingJobPriority::kUnspecified));
+ TranscodingSessionPriority::kUnspecified));
EXPECT_TRUE(mClient1->submit(1, "test_source_file_1", "test_destination_file_1",
- TranscodingJobPriority::kUnspecified));
+ TranscodingSessionPriority::kUnspecified));
- // Job 0 should start immediately.
+ // Session 0 should start immediately.
EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
- // Submit more real-time jobs.
+ // Submit more real-time sessions.
EXPECT_TRUE(mClient1->submit(2, "test_source_file_2", "test_destination_file_2"));
EXPECT_TRUE(mClient1->submit(3, "test_source_file_3", "test_destination_file_3"));
- // Job 0 should pause immediately and job 2 should start.
+ // Session 0 should pause immediately and session 2 should start.
EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Pause(CLIENT(1), 0));
EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 2));
- // Job 2 should finish in 2 seconds and job 3 should start.
- EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 2));
+ // Session 2 should finish in 2 seconds and session 3 should start.
+ EXPECT_EQ(mClient1->pop(kSessionWithPaddingUs), EventTracker::Finished(CLIENT(1), 2));
EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 3));
- // Cancel job 3 now
+ // Cancel session 3 now
EXPECT_TRUE(mClient1->cancel(3));
- // Job 0 should resume and finish in 2 seconds, followed by job 1 start.
+ // Session 0 should resume and finish in 2 seconds, followed by session 1 start.
EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Resume(CLIENT(1), 0));
- EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+ EXPECT_EQ(mClient1->pop(kSessionWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
- // Cancel remaining job 1.
+ // Cancel remaining session 1.
EXPECT_TRUE(mClient1->cancel(1));
unregisterMultipleClients();
@@ -280,16 +280,16 @@
EXPECT_TRUE(status.isOk());
// Test various operations on the client, should fail with ERROR_DISCONNECTED.
- TranscodingJobParcel job;
+ TranscodingSessionParcel session;
bool result;
- status = client->getJobWithId(0, &job, &result);
+ status = client->getSessionWithId(0, &session, &result);
EXPECT_EQ(status.getServiceSpecificError(), IMediaTranscodingService::ERROR_DISCONNECTED);
- status = client->cancelJob(0, &result);
+ status = client->cancelSession(0, &result);
EXPECT_EQ(status.getServiceSpecificError(), IMediaTranscodingService::ERROR_DISCONNECTED);
TranscodingRequestParcel request;
- status = client->submitRequest(request, &job, &result);
+ status = client->submitRequest(request, &session, &result);
EXPECT_EQ(status.getServiceSpecificError(), IMediaTranscodingService::ERROR_DISCONNECTED);
}
@@ -308,41 +308,41 @@
EXPECT_TRUE(ShellHelper::Start(kClientPackageA, kTestActivityName));
// Submit 3 requests.
- ALOGD("Submitting job to client1 (app A) ...");
+ ALOGD("Submitting session to client1 (app A) ...");
EXPECT_TRUE(mClient1->submit(0, "test_source_file_0", "test_destination_file_0"));
EXPECT_TRUE(mClient1->submit(1, "test_source_file_1", "test_destination_file_1"));
EXPECT_TRUE(mClient1->submit(2, "test_source_file_2", "test_destination_file_2"));
- // Job 0 should start immediately.
+ // Session 0 should start immediately.
EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 0));
ALOGD("Moving app B to top...");
EXPECT_TRUE(ShellHelper::Start(kClientPackageB, kTestActivityName));
- // Job 0 should continue and finish in 2 seconds, then job 1 should start.
- EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
+ // Session 0 should continue and finish in 2 seconds, then session 1 should start.
+ EXPECT_EQ(mClient1->pop(kSessionWithPaddingUs), EventTracker::Finished(CLIENT(1), 0));
EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 1));
- ALOGD("Submitting job to client2 (app B) ...");
+ ALOGD("Submitting session to client2 (app B) ...");
EXPECT_TRUE(mClient2->submit(0, "test_source_file_0", "test_destination_file_0"));
- // Client1's job should pause, client2's job should start.
+ // Client1's session should pause, client2's session should start.
EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Pause(CLIENT(1), 1));
EXPECT_EQ(mClient2->pop(kPaddingUs), EventTracker::Start(CLIENT(2), 0));
ALOGD("Moving app A back to top...");
EXPECT_TRUE(ShellHelper::Start(kClientPackageA, kTestActivityName));
- // Client2's job should pause, client1's job 1 should resume.
+ // Client2's session should pause, client1's session 1 should resume.
EXPECT_EQ(mClient2->pop(kPaddingUs), EventTracker::Pause(CLIENT(2), 0));
EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Resume(CLIENT(1), 1));
- // Client2's job 1 should finish in 2 seconds, then its job 2 should start.
- EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 1));
+ // Client2's session 1 should finish in 2 seconds, then its session 2 should start.
+ EXPECT_EQ(mClient1->pop(kSessionWithPaddingUs), EventTracker::Finished(CLIENT(1), 1));
EXPECT_EQ(mClient1->pop(kPaddingUs), EventTracker::Start(CLIENT(1), 2));
- // After client2's jobs finish, client1's job should resume.
- EXPECT_EQ(mClient1->pop(kJobWithPaddingUs), EventTracker::Finished(CLIENT(1), 2));
+ // After client2's sessions finish, client1's session should resume.
+ EXPECT_EQ(mClient1->pop(kSessionWithPaddingUs), EventTracker::Finished(CLIENT(1), 2));
EXPECT_EQ(mClient2->pop(kPaddingUs), EventTracker::Resume(CLIENT(2), 0));
unregisterMultipleClients();
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index 9f34153..483a264 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -306,6 +306,7 @@
mSharedStreams.end());
serviceEndpoint->close();
+
mSharedCloseCount++;
ALOGV("%s(%p) closed for device %d",
__func__, serviceEndpoint.get(), serviceEndpoint->getDeviceId());
diff --git a/services/oboeservice/AAudioServiceEndpointCapture.cpp b/services/oboeservice/AAudioServiceEndpointCapture.cpp
index b86fe9d..bc769f0 100644
--- a/services/oboeservice/AAudioServiceEndpointCapture.cpp
+++ b/services/oboeservice/AAudioServiceEndpointCapture.cpp
@@ -65,7 +65,9 @@
result = getStreamInternal()->read(mDistributionBuffer.get(),
getFramesPerBurst(), timeoutNanos);
if (result == AAUDIO_ERROR_DISCONNECTED) {
- ALOGV("%s() read() returned AAUDIO_ERROR_DISCONNECTED, break", __func__);
+ ALOGD("%s() read() returned AAUDIO_ERROR_DISCONNECTED", __func__);
+ // We do not need the returned vector.
+ (void) AAudioServiceEndpointShared::disconnectRegisteredStreams();
break;
} else if (result != getFramesPerBurst()) {
ALOGW("callbackLoop() read %d / %d",
diff --git a/services/oboeservice/AAudioServiceEndpointPlay.cpp b/services/oboeservice/AAudioServiceEndpointPlay.cpp
index 53cb70b..6ddc30b 100644
--- a/services/oboeservice/AAudioServiceEndpointPlay.cpp
+++ b/services/oboeservice/AAudioServiceEndpointPlay.cpp
@@ -145,7 +145,9 @@
result = getStreamInternal()->write(mMixer.getOutputBuffer(),
getFramesPerBurst(), timeoutNanos);
if (result == AAUDIO_ERROR_DISCONNECTED) {
- ALOGV("%s() write() returned AAUDIO_ERROR_DISCONNECTED, break", __func__);
+ ALOGD("%s() write() returned AAUDIO_ERROR_DISCONNECTED", __func__);
+ // We do not need the returned vector.
+ (void) AAudioServiceEndpointShared::disconnectRegisteredStreams();
break;
} else if (result != getFramesPerBurst()) {
ALOGW("callbackLoop() wrote %d / %d",
diff --git a/services/oboeservice/AAudioServiceEndpointShared.cpp b/services/oboeservice/AAudioServiceEndpointShared.cpp
index f5de59f..caf6139 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.cpp
+++ b/services/oboeservice/AAudioServiceEndpointShared.cpp
@@ -88,23 +88,30 @@
}
void AAudioServiceEndpointShared::close() {
- getStreamInternal()->releaseCloseFinal();
+ stopSharingThread();
+ getStreamInternal()->safeReleaseClose();
}
// Glue between C and C++ callbacks.
static void *aaudio_endpoint_thread_proc(void *arg) {
assert(arg != nullptr);
+ ALOGD("%s() called", __func__);
- // The caller passed in a smart pointer to prevent the endpoint from getting deleted
- // while the thread was launching.
- sp<AAudioServiceEndpointShared> *endpointForThread =
- static_cast<sp<AAudioServiceEndpointShared> *>(arg);
- sp<AAudioServiceEndpointShared> endpoint = *endpointForThread;
- delete endpointForThread; // Just use scoped smart pointer. Don't need this anymore.
+ // Prevent the stream from being deleted while being used.
+ // This is just for extra safety. It is probably not needed because
+ // this callback should be joined before the stream is closed.
+ AAudioServiceEndpointShared *endpointPtr =
+ static_cast<AAudioServiceEndpointShared *>(arg);
+ android::sp<AAudioServiceEndpointShared> endpoint(endpointPtr);
+ // Balance the incStrong() in startSharingThread_l().
+ endpoint->decStrong(nullptr);
+
void *result = endpoint->callbackLoop();
// Close now so that the HW resource is freed and we can open a new device.
if (!endpoint->isConnected()) {
- endpoint->close();
+ ALOGD("%s() call safeReleaseCloseFromCallback()", __func__);
+ // Release and close under a lock with no check for callback collisions.
+ endpoint->getStreamInternal()->safeReleaseCloseFromCallback();
}
return result;
@@ -116,14 +123,14 @@
* AAUDIO_NANOS_PER_SECOND
/ getSampleRate();
mCallbackEnabled.store(true);
- // Pass a smart pointer so the thread can hold a reference.
- sp<AAudioServiceEndpointShared> *endpointForThread = new sp<AAudioServiceEndpointShared>(this);
- aaudio_result_t result = getStreamInternal()->createThread(periodNanos,
- aaudio_endpoint_thread_proc,
- endpointForThread);
+ // Prevent this object from getting deleted before the thread has a chance to create
+ // its strong pointer. Assume the thread will call decStrong().
+ this->incStrong(nullptr);
+ aaudio_result_t result = getStreamInternal()->createThread_l(periodNanos,
+ aaudio_endpoint_thread_proc,
+ this);
if (result != AAUDIO_OK) {
- // The thread can't delete it so we have to do it here.
- delete endpointForThread;
+ this->decStrong(nullptr); // Because the thread won't do it.
}
return result;
}
@@ -141,13 +148,13 @@
{
std::lock_guard<std::mutex> lock(mLockStreams);
if (++mRunningStreamCount == 1) { // atomic
- result = getStreamInternal()->requestStart();
+ result = getStreamInternal()->requestStart_l();
if (result != AAUDIO_OK) {
--mRunningStreamCount;
} else {
result = startSharingThread_l();
if (result != AAUDIO_OK) {
- getStreamInternal()->requestStop();
+ getStreamInternal()->requestStop_l();
--mRunningStreamCount;
}
}
@@ -161,7 +168,7 @@
if (result != AAUDIO_OK) {
if (--mRunningStreamCount == 0) { // atomic
stopSharingThread();
- getStreamInternal()->requestStop();
+ getStreamInternal()->requestStop_l();
}
}
}
@@ -176,7 +183,7 @@
if (--mRunningStreamCount == 0) { // atomic
stopSharingThread(); // the sharing thread locks mLockStreams
- getStreamInternal()->requestStop();
+ getStreamInternal()->requestStop_l();
}
return AAUDIO_OK;
}
diff --git a/services/oboeservice/AAudioServiceEndpointShared.h b/services/oboeservice/AAudioServiceEndpointShared.h
index 020b926..91a86c1 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.h
+++ b/services/oboeservice/AAudioServiceEndpointShared.h
@@ -37,6 +37,8 @@
public:
explicit AAudioServiceEndpointShared(AudioStreamInternal *streamInternal);
+ virtual ~AAudioServiceEndpointShared() = default;
+
std::string dump() const override;
aaudio_result_t open(const aaudio::AAudioStreamRequest &request) override;
@@ -55,12 +57,12 @@
virtual void *callbackLoop() = 0;
-protected:
-
AudioStreamInternal *getStreamInternal() const {
return mStreamInternal.get();
};
+protected:
+
aaudio_result_t startSharingThread_l();
aaudio_result_t stopSharingThread();
diff --git a/services/oboeservice/AAudioThread.cpp b/services/oboeservice/AAudioThread.cpp
index ed7895b..68496ac 100644
--- a/services/oboeservice/AAudioThread.cpp
+++ b/services/oboeservice/AAudioThread.cpp
@@ -37,10 +37,13 @@
setup("AAudio");
}
-void AAudioThread::setup(const char *prefix) {
- // mThread is a pthread_t of unknown size so we need memset().
- memset(&mThread, 0, sizeof(mThread));
+AAudioThread::~AAudioThread() {
+ ALOGE_IF(pthread_equal(pthread_self(), mThread),
+ "%s() destructor running in thread", __func__);
+ ALOGE_IF(mHasThread, "%s() thread never joined", __func__);
+}
+void AAudioThread::setup(const char *prefix) {
// Name the thread with an increasing index, "prefix_#", for debugging.
uint32_t index = mNextThreadIndex++;
// Wrap the index so that we do not hit the 16 char limit
@@ -57,7 +60,7 @@
}
}
-// This is the entry point for the new thread created by createThread().
+// This is the entry point for the new thread created by createThread_l().
// It converts the 'C' function call to a C++ method call.
static void * AAudioThread_internalThreadProc(void *arg) {
AAudioThread *aaudioThread = (AAudioThread *) arg;
@@ -90,13 +93,18 @@
ALOGE("stop() but no thread running");
return AAUDIO_ERROR_INVALID_STATE;
}
+ // Check to see if the thread is trying to stop itself.
+ if (pthread_equal(pthread_self(), mThread)) {
+ ALOGE("%s() attempt to pthread_join() from launched thread!", __func__);
+ return AAUDIO_ERROR_INTERNAL;
+ }
+
int err = pthread_join(mThread, nullptr);
- mHasThread = false;
if (err != 0) {
ALOGE("stop() - pthread_join() returned %d %s", err, strerror(err));
return AAudioConvert_androidToAAudioResult(-err);
} else {
+ mHasThread = false;
return AAUDIO_OK;
}
}
-
diff --git a/services/oboeservice/AAudioThread.h b/services/oboeservice/AAudioThread.h
index dcce68a..08a8a98 100644
--- a/services/oboeservice/AAudioThread.h
+++ b/services/oboeservice/AAudioThread.h
@@ -46,7 +46,7 @@
explicit AAudioThread(const char *prefix);
- virtual ~AAudioThread() = default;
+ virtual ~AAudioThread();
/**
* Start the thread running.
@@ -73,7 +73,7 @@
Runnable *mRunnable = nullptr;
bool mHasThread = false;
- pthread_t mThread; // initialized in constructor
+ pthread_t mThread = {};
static std::atomic<uint32_t> mNextThreadIndex;
char mName[16]; // max length for a pthread_name