Merge "Add offload support for aaudio." into main
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index 136edcc..6c41198 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -119,8 +119,42 @@
*
* Available since API level 34.
*/
- AAUDIO_FORMAT_IEC61937
+ AAUDIO_FORMAT_IEC61937,
+ /**
+ * This format is used for audio compressed in MP3 format.
+ */
+ AAUDIO_FORMAT_MP3,
+
+ /**
+ * This format is used for audio compressed in AAC LC format.
+ */
+ AAUDIO_FORMAT_AAC_LC,
+
+ /**
+ * This format is used for audio compressed in AAC HE V1 format.
+ */
+ AAUDIO_FORMAT_AAC_HE_V1,
+
+ /**
+ * This format is used for audio compressed in AAC HE V2 format.
+ */
+ AAUDIO_FORMAT_AAC_HE_V2,
+
+ /**
+ * This format is used for audio compressed in AAC ELD format.
+ */
+ AAUDIO_FORMAT_AAC_ELD,
+
+ /**
+ * This format is used for audio compressed in AAC XHE format.
+ */
+ AAUDIO_FORMAT_AAC_XHE,
+
+ /**
+ * This format is used for audio compressed in OPUS.
+ */
+ AAUDIO_FORMAT_OPUS
};
typedef int32_t aaudio_format_t;
@@ -335,7 +369,23 @@
/**
* Reducing latency is more important than battery life.
*/
- AAUDIO_PERFORMANCE_MODE_LOW_LATENCY
+ AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
+
+ /**
+ * Extending battery life is more important than low latency.
+ *
+ * This mode is not supported in input streams.
+ * This mode will play through the offloaded audio path to save battery life.
+ *
+ * Comparing to mode {@link #AAUDIO_PERFORMANCE_MODE_POWER_SAVING}, the stream at
+ * this mode will be able to write a large amount(several seconds) of data within a
+ * short time. The written data will be queued in a hardware buffer. After that, the
+ * app can suspend its thread/process that playing audio, the audio framework's data
+ * pipe will be suspended automatically and the CPU will be allowed to sleep for
+ * power saving. When all queued data are played, the apps will be able to get callback
+ * to feed more data.
+ */
+ AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED
};
typedef int32_t aaudio_performance_mode_t;
@@ -1090,7 +1140,8 @@
* Set the requested performance mode.
*
* Supported modes are {@link #AAUDIO_PERFORMANCE_MODE_NONE},
- * {@link #AAUDIO_PERFORMANCE_MODE_POWER_SAVING} * and {@link #AAUDIO_PERFORMANCE_MODE_LOW_LATENCY}.
+ * {@link #AAUDIO_PERFORMANCE_MODE_POWER_SAVING}, {@link #AAUDIO_PERFORMANCE_MODE_LOW_LATENCY} and
+ * {@link #AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED}.
*
* The default, if you do not call this function, is {@link #AAUDIO_PERFORMANCE_MODE_NONE}.
*
@@ -1475,6 +1526,44 @@
__INTRODUCED_IN(26);
/**
+ * Prototype for the callback function that is passed to
+ * AAudioStreamBuilder_setPresentationEndCallback().
+ *
+ * This will be called when all the buffers of an offloaded stream that were queued in the audio
+ * system (e.g. the combination of the Android audio framework and the device's audio hardware)
+ * have been played after AudioStream_requestStop() has been called.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream(), which must be an
+ * output stream as the offloaded mode is only supported for output stream
+ * @param userData the same address that was passed to
+ * AAudioStreamBuilder_setPresentationEndCallback().
+ */
+typedef void (*AAudioStream_presentationEndCallback)(AAudioStream* _Nonnull stream,
+ void* _Null_unspecified userData);
+
+/**
+ * Request that AAudio call this function when all the buffers of an offloaded stream that were
+ * queued in the audio system (e.g. the combination of the Android audio framework and the device's
+ * audio hardware) have been played.
+ *
+ * The presentation end callback must be used together with the data callback.
+ * The presentation edn callback won't be called if the stream is closed before all the data
+ * is played.
+ *
+ * Available since API level 36.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder()
+ * @param callback pointer to a function that will be called when all the buffers of an offloaded
+ * stream that were queued have been played.
+ * @param userData pointer to an application data structure that will be passed
+ * to the callback functions.
+ */
+AAUDIO_API void AAudioStreamBuilder_setPresentationEndCallback(
+ AAudioStreamBuilder* _Nonnull builder,
+ AAudioStream_presentationEndCallback _Nonnull callback,
+ void* _Nullable userData) __INTRODUCED_IN(36);
+
+/**
* Open a stream based on the options in the StreamBuilder.
*
* AAudioStream_close() must be called when finished with the stream to recover
@@ -2188,6 +2277,72 @@
AAUDIO_API aaudio_channel_mask_t AAudioStream_getChannelMask(AAudioStream* _Nonnull stream)
__INTRODUCED_IN(32);
+/**
+ * Configures the delay and padding values for the current stream playing in offload mode.
+ * This should only be used on a stream whose performance mode is
+ * {@link #AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED} and the format is compressed format.
+ * The unit is frames, where a frame includes samples for all audio channels, e.g. 100 frames
+ * for a stereo stream corresponds to 200 interleaved PCM samples.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @param delayInFrames number of frames to be ignored at the beginning of the stream. A value
+ * of 0 indicates no delay is to be applied.
+ * @param paddingInFrames number of frames to be ignored at the end of the stream. A value of 0
+ * of 0 indicates no padding is to be applied.
+ * @return {@link #AAUDIO_OK} if the delay and padding values are set successfully,
+ * or {@link #AAUDIO_ERROR_ILLEGAL_ARGUMENT} if delayInFrames or paddingInFrames
+ * is less than 0,
+ * or {@link #AAUDIO_ERROR_UNIMPLEMENTED} if the stream is not an output stream whose
+ * performance mode is {@link #AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED},
+ * or {@link #AAUDIO_ERROR_INVALID_STATE} if the stream is not yet initialized.
+ */
+AAUDIO_API aaudio_result_t AAudioStream_setOffloadDelayPadding(
+ AAudioStream* _Nonnull stream, int32_t delayInFrames, int32_t paddingInFrames)
+ __INTRODUCED_IN(36);
+
+/**
+ * Return the decoder delay of an offloaded stream in frames.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return the offload delay in frames that previously set with
+ * {@link #AAudioStream_setOffloadDelayPadding},
+ * or 0 if it was never modified,
+ * or {@link #AAUDIO_ERROR_UNIMPLEMENTED} if the stream is not an output stream whose
+ * performance mode is {@link #AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED},
+ * or {@link #AAUDIO_ERROR_INVALID_STATE} if the stream is not yet initialized.
+ */
+AAUDIO_API int32_t AAudioStream_getOffloadDelay(AAudioStream* _Nonnull stream) __INTRODUCED_IN(36);
+
+/**
+ * Return the decoder padding of an offloaded stream in frames.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return the offload padding in frames that previously set with
+ * {@link #AAudioStream_setOffloadDelayPadding},
+ * or 0 if it was never modified,
+ * or {@link #AAUDIO_ERROR_UNIMPLEMENTED} if the stream is not an output stream whose
+ * performance mode is {@link #AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED},
+ * or {@link #AAUDIO_ERROR_INVALID_STATE} if the stream is not yet initialized.
+ */
+AAUDIO_API int32_t AAudioStream_getOffloadPadding(AAudioStream* _Nonnull stream)
+ __INTRODUCED_IN(36);
+
+/**
+ * Declares that the last data writing operation on this stream provided the last buffer of this
+ * stream.
+ * After the end of stream, previously set padding and delay values are ignored. That indicates
+ * all written data will be played.
+ * Use this method in the same thread as any data writing operation.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return {@link #AAUDIO_OK} on success,
+ * or {@link #AAUDIO_ERROR_UNIMPLEMENTED} if the stream is not an output stream whose
+ * performance mode is {@link #AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED},
+ * or {@link #AAUDIO_ERROR_INVALID_STATE} if the stream is not yet initialized.
+ */
+AAUDIO_API aaudio_result_t AAudioStream_setOffloadEndOfStream(AAudioStream* _Nonnull stream)
+ __INTRODUCED_IN(36);
+
#ifdef __cplusplus
}
#endif
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index 64152f0..de82471 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -255,6 +255,16 @@
streamBuilder->setErrorCallbackUserData(userData);
}
+AAUDIO_API void AAudioStreamBuilder_setPresentationEndCallback(AAudioStreamBuilder* builder,
+ AAudioStream_presentationEndCallback callback, void* userData) {
+ AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
+ if (streamBuilder == nullptr) {
+ return;
+ }
+ streamBuilder->setPresentationEndCallbackProc(callback)
+ ->setPresentationEndCallbackUserData(userData);
+}
+
AAUDIO_API void AAudioStreamBuilder_setFramesPerDataCallback(AAudioStreamBuilder* builder,
int32_t frames)
{
@@ -693,3 +703,27 @@
// Do not return channel index masks as they are not public.
return AAudio_isChannelIndexMask(channelMask) ? AAUDIO_UNSPECIFIED : channelMask;
}
+
+AAUDIO_API aaudio_result_t AAudioStream_setOffloadDelayPadding(
+ AAudioStream* stream, int32_t delayInFrames, int32_t paddingInFrames) {
+ if (delayInFrames < 0 || paddingInFrames < 0) {
+ return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+ }
+ AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+ return audioStream->setOffloadDelayPadding(delayInFrames, paddingInFrames);
+}
+
+AAUDIO_API int32_t AAudioStream_getOffloadDelay(AAudioStream* stream) {
+ AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+ return audioStream->getOffloadDelay();
+}
+
+AAUDIO_API int32_t AAudioStream_getOffloadPadding(AAudioStream* stream) {
+ AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+ return audioStream->getOffloadPadding();
+}
+
+AAUDIO_API aaudio_result_t AAudioStream_setOffloadEndOfStream(AAudioStream* stream) {
+ AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+ return audioStream->setOffloadEndOfStream();
+}
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.cpp b/media/libaaudio/src/core/AAudioStreamParameters.cpp
index f504fa9..ed20d12 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.cpp
+++ b/media/libaaudio/src/core/AAudioStreamParameters.cpp
@@ -58,6 +58,13 @@
case AUDIO_FORMAT_PCM_24_BIT_PACKED:
case AUDIO_FORMAT_PCM_8_24_BIT:
case AUDIO_FORMAT_IEC61937:
+ case AUDIO_FORMAT_MP3:
+ case AUDIO_FORMAT_AAC_LC:
+ case AUDIO_FORMAT_AAC_HE_V1:
+ case AUDIO_FORMAT_AAC_HE_V2:
+ case AUDIO_FORMAT_AAC_ELD:
+ case AUDIO_FORMAT_AAC_XHE:
+ case AUDIO_FORMAT_OPUS:
break; // valid
default:
ALOGD("audioFormat not valid, audio_format_t = 0x%08x", format);
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index 8e3bcf7..468bcfa 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -116,6 +116,8 @@
mErrorCallbackProc = builder.getErrorCallbackProc();
mDataCallbackUserData = builder.getDataCallbackUserData();
mErrorCallbackUserData = builder.getErrorCallbackUserData();
+ setPresentationEndCallbackUserData(builder.getPresentationEndCallbackUserData());
+ setPresentationEndCallbackProc(builder.getPresentationEndCallbackProc());
return AAUDIO_OK;
}
@@ -285,6 +287,10 @@
aaudio_result_t AudioStream::systemStopInternal() {
std::lock_guard<std::mutex> lock(mStreamLock);
+ return systemStopInternal_l();
+}
+
+aaudio_result_t AudioStream::systemStopInternal_l() {
aaudio_result_t result = safeStop_l();
if (result == AAUDIO_OK) {
// We only call this for logging in "dumpsys audio". So ignore return code.
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index 3354adf..0ddc8ed 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -332,7 +332,7 @@
* have been called.
*/
int32_t getBytesPerFrame() const {
- return mSamplesPerFrame * getBytesPerSample();
+ return audio_bytes_per_frame(mSamplesPerFrame, mFormat);
}
/**
@@ -346,7 +346,7 @@
* This is only valid after setDeviceSamplesPerFrame() and setDeviceFormat() have been called.
*/
int32_t getBytesPerDeviceFrame() const {
- return getDeviceSamplesPerFrame() * audio_bytes_per_sample(getDeviceFormat());
+ return audio_bytes_per_frame(getDeviceSamplesPerFrame(), getDeviceFormat());
}
virtual int64_t getFramesWritten() = 0;
@@ -390,6 +390,24 @@
mDeviceSamplesPerFrame = deviceSamplesPerFrame;
}
+ virtual aaudio_result_t setOffloadDelayPadding(int32_t delayInFrames, int32_t paddingInFrames) {
+ return AAUDIO_ERROR_UNIMPLEMENTED;
+ }
+
+ virtual int32_t getOffloadDelay() {
+ return AAUDIO_ERROR_UNIMPLEMENTED;
+ }
+
+ virtual int32_t getOffloadPadding() {
+ return AAUDIO_ERROR_UNIMPLEMENTED;
+ }
+
+ virtual aaudio_result_t setOffloadEndOfStream() EXCLUDES(mStreamLock) {
+ return AAUDIO_ERROR_UNIMPLEMENTED;
+ }
+
+ virtual void setPresentationEndCallbackProc(AAudioStream_presentationEndCallback proc) { }
+ virtual void setPresentationEndCallbackUserData(void* userData) { }
/**
* @return true if data callback has been specified
@@ -408,7 +426,7 @@
/**
* @return true if called from the same thread as the callback
*/
- bool collidesWithCallback() const;
+ virtual bool collidesWithCallback() const;
// Implement AudioDeviceCallback
void onAudioDeviceUpdate(audio_io_handle_t audioIo,
@@ -649,6 +667,8 @@
aaudio_result_t joinThread_l(void **returnArg) REQUIRES(mStreamLock);
+ virtual aaudio_result_t systemStopInternal_l() REQUIRES(mStreamLock);
+
std::atomic<bool> mCallbackEnabled{false};
float mDuckAndMuteVolume = 1.0f;
@@ -742,6 +762,8 @@
mAudioBalance = audioBalance;
}
+ aaudio_result_t safeStop_l() REQUIRES(mStreamLock);
+
std::string mMetricsId; // set once during open()
std::mutex mStreamLock;
@@ -750,8 +772,6 @@
private:
- aaudio_result_t safeStop_l() REQUIRES(mStreamLock);
-
/**
* Release then close the stream.
*/
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index 73bd69f..61881cb 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -174,6 +174,11 @@
__func__);
allowMMap = false;
}
+ if (!audio_is_linear_pcm(getFormat())) {
+ ALOGD("%s() MMAP not used because the requested format(%#x) is not pcm",
+ __func__, getFormat());
+ allowMMap = false;
+ }
// SessionID and Effects are only supported in Legacy mode.
if (getSessionId() != AAUDIO_SESSION_ID_NONE) {
@@ -261,6 +266,14 @@
case AAUDIO_PERFORMANCE_MODE_POWER_SAVING:
case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
break;
+ case AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED:
+ if (getDirection() != AAUDIO_DIRECTION_OUTPUT ||
+ getFormat() == AUDIO_FORMAT_DEFAULT ||
+ getSampleRate() == 0 ||
+ getChannelMask() == AAUDIO_UNSPECIFIED) {
+ return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+ }
+ break;
default:
ALOGE("illegal performanceMode = %d", mPerformanceMode);
return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.h b/media/libaaudio/src/core/AudioStreamBuilder.h
index f91c25a..d0678ae 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.h
+++ b/media/libaaudio/src/core/AudioStreamBuilder.h
@@ -89,6 +89,24 @@
return mErrorCallbackUserData;
}
+ AudioStreamBuilder* setPresentationEndCallbackProc(AAudioStream_presentationEndCallback proc) {
+ mPresentationEndCallbackProc = proc;
+ return this;
+ }
+
+ AAudioStream_presentationEndCallback getPresentationEndCallbackProc() const {
+ return mPresentationEndCallbackProc;
+ }
+
+ AudioStreamBuilder* setPresentationEndCallbackUserData(void *userData) {
+ mPresentationEndCallbackUserData = userData;
+ return this;
+ }
+
+ void *getPresentationEndCallbackUserData() const {
+ return mPresentationEndCallbackUserData;
+ }
+
int32_t getFramesPerDataCallback() const {
return mFramesPerDataCallback;
}
@@ -128,6 +146,9 @@
AAudioStream_errorCallback mErrorCallbackProc = nullptr;
void *mErrorCallbackUserData = nullptr;
+ AAudioStream_presentationEndCallback mPresentationEndCallbackProc = nullptr;
+ void *mPresentationEndCallbackUserData = nullptr;
+
enum {
PRIVACY_SENSITIVE_DEFAULT = -1,
PRIVACY_SENSITIVE_DISABLED = 0,
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 2e57f0d..da15563 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -22,6 +22,7 @@
#include <media/AudioTrack.h>
#include <aaudio/AAudio.h>
+#include <com_android_media_aaudio.h>
#include <system/audio.h>
#include "core/AudioGlobal.h"
@@ -56,6 +57,10 @@
aaudio_result_t AudioStreamTrack::open(const AudioStreamBuilder& builder)
{
+ if (!com::android::media::aaudio::offload_support() &&
+ builder.getPerformanceMode() == AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED) {
+ return AAUDIO_ERROR_UNIMPLEMENTED;
+ }
aaudio_result_t result = AAUDIO_OK;
result = AudioStream::open(builder);
@@ -152,6 +157,34 @@
if (tags.has_value() && !tags.value().empty()) {
strcpy(attributes.tags, tags.value().c_str());
}
+
+ audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER;
+ if (getPerformanceMode() == AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED) {
+ audio_config_t config = AUDIO_CONFIG_INITIALIZER;
+ config.format = format;
+ config.channel_mask = channelMask;
+ config.sample_rate = getSampleRate();
+ audio_direct_mode_t directMode = AUDIO_DIRECT_NOT_SUPPORTED;
+ if (status_t status = AudioSystem::getDirectPlaybackSupport(
+ &attributes, &config, &directMode);
+ status != NO_ERROR) {
+ ALOGE("%s, failed to query direct support, error=%d", __func__, status);
+ return status;
+ }
+ static const audio_direct_mode_t offloadMode = static_cast<audio_direct_mode_t>(
+ AUDIO_DIRECT_OFFLOAD_SUPPORTED | AUDIO_DIRECT_OFFLOAD_GAPLESS_SUPPORTED);
+ if ((directMode & offloadMode) == AUDIO_DIRECT_NOT_SUPPORTED) {
+ return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+ }
+ flags = AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
+ frameCount = 0;
+ offloadInfo.format = format;
+ offloadInfo.sample_rate = getSampleRate();
+ offloadInfo.channel_mask = channelMask;
+ offloadInfo.has_video = false;
+ offloadInfo.stream_type = AUDIO_STREAM_MUSIC;
+ }
+
mAudioTrack = new AudioTrack();
// TODO b/182392769: use attribution source util
mAudioTrack->set(
@@ -167,7 +200,8 @@
false, // DEFAULT threadCanCallJava
sessionId,
streamTransferType,
- nullptr, // DEFAULT audio_offload_info_t
+ getPerformanceMode() == AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED
+ ? &offloadInfo : nullptr,
AttributionSourceState(), // DEFAULT uid and pid
&attributes,
// WARNING - If doNotReconnect set true then audio stops after plugging and unplugging
@@ -247,7 +281,9 @@
audio_output_flags_t actualFlags = mAudioTrack->getFlags();
aaudio_performance_mode_t actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
// We may not get the RAW flag. But as long as we get the FAST flag we can call it LOW_LATENCY.
- if ((actualFlags & AUDIO_OUTPUT_FLAG_FAST) != 0) {
+ if ((actualFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != AUDIO_OUTPUT_FLAG_NONE) {
+ actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED;
+ } else if ((actualFlags & AUDIO_OUTPUT_FLAG_FAST) != 0) {
actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
} else if ((actualFlags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) != 0) {
actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING;
@@ -347,6 +383,7 @@
setState(originalState);
return AAudioConvert_androidToAAudioResult(err);
}
+ mOffloadEosPending = false;
return AAUDIO_OK;
}
@@ -430,6 +467,12 @@
break;
case AAUDIO_STREAM_STATE_STOPPING:
if (mAudioTrack->stopped()) {
+ if (getPerformanceMode() == AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED) {
+ std::lock_guard<std::mutex> lock(mStreamLock);
+ if (!mOffloadEosPending) {
+ break;
+ }
+ }
setState(AAUDIO_STREAM_STATE_STOPPED);
}
break;
@@ -579,6 +622,104 @@
mAudioTrack->setPlayerIId(mPlayerBase->getPlayerIId());
}
+aaudio_result_t AudioStreamTrack::systemStopInternal_l() {
+ if (aaudio_result_t result = AudioStream::systemStopInternal_l(); result != AAUDIO_OK) {
+ return result;
+ }
+ mOffloadEosPending = false;
+ return AAUDIO_OK;
+}
+
+aaudio_result_t AudioStreamTrack::setOffloadDelayPadding(
+ int32_t delayInFrames, int32_t paddingInFrames) {
+ if (getPerformanceMode() != AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED ||
+ audio_is_linear_pcm(getFormat())) {
+ return AAUDIO_ERROR_UNIMPLEMENTED;
+ }
+ if (mAudioTrack == nullptr) {
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ AudioParameter param = AudioParameter();
+ param.addInt(String8(AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES), delayInFrames);
+ param.addInt(String8(AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES), paddingInFrames);
+ mAudioTrack->setParameters(param.toString());
+ mOffloadDelayFrames.store(delayInFrames);
+ mOffloadPaddingFrames.store(paddingInFrames);
+ return AAUDIO_OK;
+}
+
+int32_t AudioStreamTrack::getOffloadDelay() {
+ if (getPerformanceMode() != AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED ||
+ audio_is_linear_pcm(getFormat())) {
+ return AAUDIO_ERROR_UNIMPLEMENTED;
+ }
+ if (mAudioTrack == nullptr) {
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ return mOffloadDelayFrames.load();
+}
+
+int32_t AudioStreamTrack::getOffloadPadding() {
+ if (getPerformanceMode() != AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED ||
+ audio_is_linear_pcm(getFormat())) {
+ return AAUDIO_ERROR_UNIMPLEMENTED;
+ }
+ if (mAudioTrack == nullptr) {
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ return mOffloadPaddingFrames.load();
+}
+
+aaudio_result_t AudioStreamTrack::setOffloadEndOfStream() {
+ if (getPerformanceMode() != AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED) {
+ return AAUDIO_ERROR_UNIMPLEMENTED;
+ }
+ if (mAudioTrack == nullptr) {
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ std::lock_guard<std::mutex> lock(mStreamLock);
+ if (aaudio_result_t result = safeStop_l(); result != AAUDIO_OK) {
+ return result;
+ }
+ mOffloadEosPending = true;
+ return AAUDIO_OK;
+}
+
+bool AudioStreamTrack::collidesWithCallback() const {
+ if (AudioStream::collidesWithCallback()) {
+ return true;
+ }
+ pid_t thisThread = gettid();
+ return mPresentationEndCallbackThread.load() == thisThread;
+}
+
+void AudioStreamTrack::onStreamEnd() {
+ if (getPerformanceMode() != AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED) {
+ return;
+ }
+ if (getState() == AAUDIO_STREAM_STATE_STOPPING) {
+ std::lock_guard<std::mutex> lock(mStreamLock);
+ if (mOffloadEosPending) {
+ requestStart_l();
+ }
+ mOffloadEosPending = false;
+ }
+ maybeCallPresentationEndCallback();
+}
+
+void AudioStreamTrack::maybeCallPresentationEndCallback() {
+ if (mPresentationEndCallbackProc != nullptr) {
+ pid_t expected = CALLBACK_THREAD_NONE;
+ if (mPresentationEndCallbackThread.compare_exchange_strong(expected, gettid())) {
+ (*mPresentationEndCallbackProc)(
+ (AAudioStream *) this, mPresentationEndCallbackUserData);
+ mPresentationEndCallbackThread.store(CALLBACK_THREAD_NONE);
+ } else {
+ ALOGW("%s() error callback already running!", __func__);
+ }
+ }
+}
+
#if AAUDIO_USE_VOLUME_SHAPER
using namespace android::media::VolumeShaper;
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.h b/media/libaaudio/src/legacy/AudioStreamTrack.h
index 05609c4..82ba772 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.h
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.h
@@ -49,6 +49,11 @@
aaudio_result_t requestPause_l() REQUIRES(mStreamLock) override;
aaudio_result_t requestFlush_l() REQUIRES(mStreamLock) override;
aaudio_result_t requestStop_l() REQUIRES(mStreamLock) override;
+ aaudio_result_t systemStopInternal_l() REQUIRES(mStreamLock) final;
+
+ bool collidesWithCallback() const final;
+
+ void onStreamEnd() final;
public:
bool isFlushSupported() const override {
@@ -89,6 +94,26 @@
void registerPlayerBase() override;
+ // Offload begin --------------------------------------
+ aaudio_result_t setOffloadDelayPadding(int32_t delayInFrames, int32_t paddingInFrames) final;
+
+ int32_t getOffloadDelay() final;
+
+ int32_t getOffloadPadding() final;
+
+ aaudio_result_t setOffloadEndOfStream() EXCLUDES(mStreamLock) final;
+
+ void setPresentationEndCallbackProc(AAudioStream_presentationEndCallback proc) final {
+ mPresentationEndCallbackProc = proc;
+ }
+
+ virtual void setPresentationEndCallbackUserData(void *userData) final {
+ mPresentationEndCallbackUserData = userData;
+ }
+
+ void maybeCallPresentationEndCallback();
+ // Offload end ----------------------------------------
+
#if AAUDIO_USE_VOLUME_SHAPER
virtual android::binder::Status applyVolumeShaper(
const android::media::VolumeShaper::Configuration& configuration,
@@ -110,6 +135,15 @@
// TODO add 64-bit position reporting to AudioTrack and use it.
aaudio_wrapping_frames_t mPositionWhenPausing = 0;
+
+ // Offload --------------------------------------------
+ std::atomic<int32_t> mOffloadDelayFrames = 0;
+ std::atomic<int32_t> mOffloadPaddingFrames = 0;
+ bool mOffloadEosPending GUARDED_BY(mStreamLock) = false;
+
+ AAudioStream_presentationEndCallback mPresentationEndCallbackProc = nullptr;
+ void *mPresentationEndCallbackUserData = nullptr;
+ std::atomic<pid_t> mPresentationEndCallbackThread{CALLBACK_THREAD_NONE};
};
} /* namespace aaudio */
diff --git a/media/libaaudio/src/libaaudio.map.txt b/media/libaaudio/src/libaaudio.map.txt
index 36d76aa..44bb4c6 100644
--- a/media/libaaudio/src/libaaudio.map.txt
+++ b/media/libaaudio/src/libaaudio.map.txt
@@ -28,6 +28,7 @@
AAudioStreamBuilder_setChannelMask; # introduced=32
AAudioStreamBuilder_setSpatializationBehavior; # introduced=32
AAudioStreamBuilder_setIsContentSpatialized; # introduced=32
+ AAudioStreamBuilder_setPresentationEndCallback; #introduced=36
AAudioStreamBuilder_openStream;
AAudioStreamBuilder_delete;
AAudioStream_close;
@@ -73,6 +74,10 @@
AAudio_getPlatformMMapPolicy; # introduced=36
AAudio_getPlatformMMapExclusivePolicy; #introduced=36
AAudioStream_getDeviceIds; # introduced=36
+ AAudioStream_setOffloadDelayPadding; #introduced=36
+ AAudioStream_getOffloadDelay; #introduced=36
+ AAudioStream_getOffloadPadding; #introduced=36
+ AAudioStream_setOffloadEndOfStream; #introduced=36
AAudioStreamBuilder_setTags; # systemapi
AAudioStream_getTags; # systemapi
diff --git a/media/libaaudio/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp
index c741946..873fcba 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.cpp
+++ b/media/libaaudio/src/utility/AAudioUtilities.cpp
@@ -147,6 +147,27 @@
case AAUDIO_FORMAT_IEC61937:
androidFormat = AUDIO_FORMAT_IEC61937;
break;
+ case AAUDIO_FORMAT_MP3:
+ androidFormat = AUDIO_FORMAT_MP3;
+ break;
+ case AAUDIO_FORMAT_AAC_LC:
+ androidFormat = AUDIO_FORMAT_AAC_LC;
+ break;
+ case AAUDIO_FORMAT_AAC_HE_V1:
+ androidFormat = AUDIO_FORMAT_AAC_HE_V1;
+ break;
+ case AAUDIO_FORMAT_AAC_HE_V2:
+ androidFormat = AUDIO_FORMAT_AAC_HE_V2;
+ break;
+ case AAUDIO_FORMAT_AAC_ELD:
+ androidFormat = AUDIO_FORMAT_AAC_ELD;
+ break;
+ case AAUDIO_FORMAT_AAC_XHE:
+ androidFormat = AUDIO_FORMAT_AAC_XHE;
+ break;
+ case AAUDIO_FORMAT_OPUS:
+ androidFormat = AUDIO_FORMAT_OPUS;
+ break;
default:
androidFormat = AUDIO_FORMAT_INVALID;
ALOGE("%s() 0x%08X unrecognized", __func__, aaudioFormat);
@@ -176,6 +197,27 @@
case AUDIO_FORMAT_IEC61937:
aaudioFormat = AAUDIO_FORMAT_IEC61937;
break;
+ case AUDIO_FORMAT_MP3:
+ aaudioFormat = AAUDIO_FORMAT_MP3;
+ break;
+ case AUDIO_FORMAT_AAC_LC:
+ aaudioFormat = AAUDIO_FORMAT_AAC_LC;
+ break;
+ case AUDIO_FORMAT_AAC_HE_V1:
+ aaudioFormat = AAUDIO_FORMAT_AAC_HE_V1;
+ break;
+ case AUDIO_FORMAT_AAC_HE_V2:
+ aaudioFormat = AAUDIO_FORMAT_AAC_HE_V2;
+ break;
+ case AUDIO_FORMAT_AAC_ELD:
+ aaudioFormat = AAUDIO_FORMAT_AAC_ELD;
+ break;
+ case AUDIO_FORMAT_AAC_XHE:
+ aaudioFormat = AAUDIO_FORMAT_AAC_XHE;
+ break;
+ case AUDIO_FORMAT_OPUS:
+ aaudioFormat = AAUDIO_FORMAT_OPUS;
+ break;
default:
aaudioFormat = AAUDIO_FORMAT_INVALID;
ALOGE("%s() 0x%08X unrecognized", __func__, androidFormat);
diff --git a/media/libaaudio/src/utility/AAudioUtilities.h b/media/libaaudio/src/utility/AAudioUtilities.h
index d5069f5..940e4b5 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.h
+++ b/media/libaaudio/src/utility/AAudioUtilities.h
@@ -373,4 +373,6 @@
aaudio_policy_t AAudioConvert_androidToAAudioMMapPolicy(
android::media::audio::common::AudioMMapPolicy policy);
+bool AAudio_isCompressedFormat(audio_format_t format);
+
#endif //UTILITY_AAUDIO_UTILITIES_H