Merge "hdr: enable VP9 profile2 in SoftVPX"
diff --git a/drm/libmediadrm/CryptoHal.cpp b/drm/libmediadrm/CryptoHal.cpp
index b9b3685..2114d40 100644
--- a/drm/libmediadrm/CryptoHal.cpp
+++ b/drm/libmediadrm/CryptoHal.cpp
@@ -332,10 +332,13 @@
return status;
}
secure = false;
- } else {
+ } else if (destination.mType == kDestinationTypeNativeHandle) {
hDestination.type = BufferType::NATIVE_HANDLE;
hDestination.secureMemory = hidl_handle(destination.mHandle);
secure = true;
+ } else {
+ android_errorWriteLog(0x534e4554, "70526702");
+ return UNKNOWN_ERROR;
}
::SharedBuffer hSource;
diff --git a/drm/libmediadrm/ICrypto.cpp b/drm/libmediadrm/ICrypto.cpp
index 37dc83b..1d70a4e 100644
--- a/drm/libmediadrm/ICrypto.cpp
+++ b/drm/libmediadrm/ICrypto.cpp
@@ -369,6 +369,10 @@
android_errorWriteLog(0x534e4554, "71389378");
return OK;
}
+ } else {
+ reply->writeInt32(BAD_VALUE);
+ android_errorWriteLog(0x534e4554, "70526702");
+ return OK;
}
AString errorDetailMsg;
diff --git a/drm/libmediadrm/PluginMetricsReporting.cpp b/drm/libmediadrm/PluginMetricsReporting.cpp
index 877cbd4..cc7fb72 100644
--- a/drm/libmediadrm/PluginMetricsReporting.cpp
+++ b/drm/libmediadrm/PluginMetricsReporting.cpp
@@ -47,7 +47,7 @@
// Report the package name.
if (metricsGroup.has_app_package_name()) {
- AString app_package_name(metricsGroup.app_package_name().c_str(),
+ std::string app_package_name(metricsGroup.app_package_name().c_str(),
metricsGroup.app_package_name().size());
analyticsItem.setPkgName(app_package_name);
}
diff --git a/media/extractors/aac/AACExtractor.cpp b/media/extractors/aac/AACExtractor.cpp
index 716fe31..dfb54e2 100644
--- a/media/extractors/aac/AACExtractor.cpp
+++ b/media/extractors/aac/AACExtractor.cpp
@@ -288,6 +288,10 @@
if (options && options->getSeekTo(&seekTimeUs, &mode)) {
if (mFrameDurationUs > 0) {
int64_t seekFrame = seekTimeUs / mFrameDurationUs;
+ if (seekFrame < 0 || seekFrame >= (int64_t)mOffsetVector.size()) {
+ android_errorWriteLog(0x534e4554, "70239507");
+ return ERROR_MALFORMED;
+ }
mCurrentTimeUs = seekFrame * mFrameDurationUs;
mOffset = mOffsetVector.itemAt(seekFrame);
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index 3c23736..00c43dc 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -137,6 +137,149 @@
};
typedef int32_t aaudio_performance_mode_t;
+/**
+ * The USAGE attribute expresses "why" you are playing a sound, what is this sound used for.
+ * This information is used by certain platforms or routing policies
+ * to make more refined volume or routing decisions.
+ *
+ * Note that these match the equivalent values in AudioAttributes in the Android Java API.
+ */
+enum {
+ /**
+ * Use this for streaming media, music performance, video, podcasts, etcetera.
+ */
+ AAUDIO_USAGE_MEDIA = 1,
+
+ /**
+ * Use this for voice over IP, telephony, etcetera.
+ */
+ AAUDIO_USAGE_VOICE_COMMUNICATION = 2,
+
+ /**
+ * Use this for sounds associated with telephony such as busy tones, DTMF, etcetera.
+ */
+ AAUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING = 3,
+
+ /**
+ * Use this to demand the users attention.
+ */
+ AAUDIO_USAGE_ALARM = 4,
+
+ /**
+ * Use this for notifying the user when a message has arrived or some
+ * other background event has occured.
+ */
+ AAUDIO_USAGE_NOTIFICATION = 5,
+
+ /**
+ * Use this when the phone rings.
+ */
+ AAUDIO_USAGE_NOTIFICATION_RINGTONE = 6,
+
+ /**
+ * Use this to attract the users attention when, for example, the battery is low.
+ */
+ AAUDIO_USAGE_NOTIFICATION_EVENT = 10,
+
+ /**
+ * Use this for screen readers, etcetera.
+ */
+ AAUDIO_USAGE_ASSISTANCE_ACCESSIBILITY = 11,
+
+ /**
+ * Use this for driving or navigation directions.
+ */
+ AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12,
+
+ /**
+ * Use this for user interface sounds, beeps, etcetera.
+ */
+ AAUDIO_USAGE_ASSISTANCE_SONIFICATION = 13,
+
+ /**
+ * Use this for game audio and sound effects.
+ */
+ AAUDIO_USAGE_GAME = 14,
+
+ /**
+ * Use this for audio responses to user queries, audio instructions or help utterances.
+ */
+ AAUDIO_USAGE_ASSISTANT = 16
+};
+typedef int32_t aaudio_usage_t;
+
+/**
+ * The CONTENT_TYPE attribute describes "what" you are playing.
+ * It expresses the general category of the content. This information is optional.
+ * But in case it is known (for instance {@link #AAUDIO_CONTENT_TYPE_MOVIE} for a
+ * movie streaming service or {@link #AAUDIO_CONTENT_TYPE_SPEECH} for
+ * an audio book application) this information might be used by the audio framework to
+ * enforce audio focus.
+ *
+ * Note that these match the equivalent values in AudioAttributes in the Android Java API.
+ */
+enum {
+
+ /**
+ * Use this for spoken voice, audio books, etcetera.
+ */
+ AAUDIO_CONTENT_TYPE_SPEECH = 1,
+
+ /**
+ * Use this for pre-recorded or live music.
+ */
+ AAUDIO_CONTENT_TYPE_MUSIC = 2,
+
+ /**
+ * Use this for a movie or video soundtrack.
+ */
+ AAUDIO_CONTENT_TYPE_MOVIE = 3,
+
+ /**
+ * Use this for sound is designed to accompany a user action,
+ * such as a click or beep sound made when the user presses a button.
+ */
+ AAUDIO_CONTENT_TYPE_SONIFICATION = 4
+};
+typedef int32_t aaudio_content_type_t;
+
+/**
+ * Defines the audio source.
+ * An audio source defines both a default physical source of audio signal, and a recording
+ * configuration.
+ *
+ * Note that these match the equivalent values in MediaRecorder.AudioSource in the Android Java API.
+ */
+enum {
+ /**
+ * Use this preset when other presets do not apply.
+ */
+ AAUDIO_INPUT_PRESET_GENERIC = 1,
+
+ /**
+ * Use this preset when recording video.
+ */
+ AAUDIO_INPUT_PRESET_CAMCORDER = 5,
+
+ /**
+ * Use this preset when doing speech recognition.
+ */
+ AAUDIO_INPUT_PRESET_VOICE_RECOGNITION = 6,
+
+ /**
+ * Use this preset when doing telephony or voice messaging.
+ */
+ AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION = 7,
+
+ /**
+ * Use this preset to obtain an input with no effects.
+ * Note that this input will not have automatic gain control
+ * so the recorded volume may be very low.
+ */
+ AAUDIO_INPUT_PRESET_UNPROCESSED = 9,
+};
+typedef int32_t aaudio_input_preset_t;
+
typedef struct AAudioStreamStruct AAudioStream;
typedef struct AAudioStreamBuilderStruct AAudioStreamBuilder;
@@ -308,6 +451,52 @@
aaudio_performance_mode_t mode);
/**
+ * Set the intended use case for the stream.
+ *
+ * The AAudio system will use this information to optimize the
+ * behavior of the stream.
+ * This could, for example, affect how volume and focus is handled for the stream.
+ *
+ * The default, if you do not call this function, is AAUDIO_USAGE_MEDIA.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder()
+ * @param usage the desired usage, eg. AAUDIO_USAGE_GAME
+ */
+AAUDIO_API void AAudioStreamBuilder_setUsage(AAudioStreamBuilder* builder,
+ aaudio_usage_t usage);
+
+/**
+ * Set the type of audio data that the stream will carry.
+ *
+ * The AAudio system will use this information to optimize the
+ * behavior of the stream.
+ * This could, for example, affect whether a stream is paused when a notification occurs.
+ *
+ * The default, if you do not call this function, is AAUDIO_CONTENT_TYPE_MUSIC.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder()
+ * @param contentType the type of audio data, eg. AAUDIO_CONTENT_TYPE_SPEECH
+ */
+AAUDIO_API void AAudioStreamBuilder_setContentType(AAudioStreamBuilder* builder,
+ aaudio_content_type_t contentType);
+
+/**
+ * Set the input (capture) preset for the stream.
+ *
+ * The AAudio system will use this information to optimize the
+ * behavior of the stream.
+ * This could, for example, affect which microphones are used and how the
+ * recorded data is processed.
+ *
+ * The default, if you do not call this function, is AAUDIO_INPUT_PRESET_GENERIC.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder()
+ * @param inputPreset the desired configuration for recording
+ */
+AAUDIO_API void AAudioStreamBuilder_setInputPreset(AAudioStreamBuilder* builder,
+ aaudio_input_preset_t inputPreset);
+
+/**
* Return one of these values from the data callback function.
*/
enum {
@@ -820,6 +1009,30 @@
int64_t *framePosition,
int64_t *timeNanoseconds);
+/**
+ * Return the use case for the stream.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return frames read
+ */
+AAUDIO_API aaudio_usage_t AAudioStream_getUsage(AAudioStream* stream);
+
+/**
+ * Return the content type for the stream.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return content type, for example AAUDIO_CONTENT_TYPE_MUSIC
+ */
+AAUDIO_API aaudio_content_type_t AAudioStream_getContentType(AAudioStream* stream);
+
+/**
+ * Return the input preset for the stream.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return input preset, for example AAUDIO_INPUT_PRESET_CAMCORDER
+ */
+AAUDIO_API aaudio_input_preset_t AAudioStream_getInputPreset(AAudioStream* stream);
+
#ifdef __cplusplus
}
#endif
diff --git a/media/libaaudio/libaaudio.map.txt b/media/libaaudio/libaaudio.map.txt
index 2ba5250..98fbb6f 100644
--- a/media/libaaudio/libaaudio.map.txt
+++ b/media/libaaudio/libaaudio.map.txt
@@ -17,6 +17,9 @@
AAudioStreamBuilder_setSharingMode;
AAudioStreamBuilder_setDirection;
AAudioStreamBuilder_setBufferCapacityInFrames;
+ AAudioStreamBuilder_setUsage; # introduced=28
+ AAudioStreamBuilder_setContentType; # introduced=28
+ AAudioStreamBuilder_setInputPreset; # introduced=28
AAudioStreamBuilder_openStream;
AAudioStreamBuilder_delete;
AAudioStream_close;
@@ -42,6 +45,9 @@
AAudioStream_getFormat;
AAudioStream_getSharingMode;
AAudioStream_getDirection;
+ AAudioStream_getUsage; # introduced=28
+ AAudioStream_getContentType; # introduced=28
+ AAudioStream_getInputPreset; # introduced=28
AAudioStream_getFramesWritten;
AAudioStream_getFramesRead;
AAudioStream_getTimestamp;
diff --git a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
index 153fce3..97672a0 100644
--- a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
@@ -50,6 +50,12 @@
if (status != NO_ERROR) goto error;
status = parcel->writeInt32(getBufferCapacity());
if (status != NO_ERROR) goto error;
+ status = parcel->writeInt32((int32_t) getUsage());
+ if (status != NO_ERROR) goto error;
+ status = parcel->writeInt32((int32_t) getContentType());
+ if (status != NO_ERROR) goto error;
+ status = parcel->writeInt32((int32_t) getInputPreset());
+ if (status != NO_ERROR) goto error;
return NO_ERROR;
error:
ALOGE("AAudioStreamConfiguration.writeToParcel(): write failed = %d", status);
@@ -69,16 +75,25 @@
setSamplesPerFrame(value);
status = parcel->readInt32(&value);
if (status != NO_ERROR) goto error;
- setSharingMode(value);
+ setSharingMode((aaudio_sharing_mode_t) value);
status = parcel->readInt32(&value);
if (status != NO_ERROR) goto error;
- setFormat(value);
+ setFormat((aaudio_format_t) value);
status = parcel->readInt32(&value);
if (status != NO_ERROR) goto error;
setDirection((aaudio_direction_t) value);
status = parcel->readInt32(&value);
if (status != NO_ERROR) goto error;
setBufferCapacity(value);
+ status = parcel->readInt32(&value);
+ if (status != NO_ERROR) goto error;
+ setUsage((aaudio_usage_t) value);
+ status = parcel->readInt32(&value);
+ if (status != NO_ERROR) goto error;
+ setContentType((aaudio_content_type_t) value);
+ status = parcel->readInt32(&value);
+ if (status != NO_ERROR) goto error;
+ setInputPreset((aaudio_input_preset_t) value);
return NO_ERROR;
error:
ALOGE("AAudioStreamConfiguration.readFromParcel(): read failed = %d", status);
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 6d5a64f..5856ec3 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -112,6 +112,10 @@
request.getConfiguration().setDirection(getDirection());
request.getConfiguration().setSharingMode(getSharingMode());
+ request.getConfiguration().setUsage(getUsage());
+ request.getConfiguration().setContentType(getContentType());
+ request.getConfiguration().setInputPreset(getInputPreset());
+
request.getConfiguration().setBufferCapacity(builder.getBufferCapacity());
mServiceStreamHandle = mServiceInterface.openStream(request, configurationOutput);
@@ -131,6 +135,10 @@
setDeviceId(configurationOutput.getDeviceId());
setSharingMode(configurationOutput.getSharingMode());
+ setUsage(configurationOutput.getUsage());
+ setContentType(configurationOutput.getContentType());
+ setInputPreset(configurationOutput.getInputPreset());
+
// Save device format so we can do format conversion and volume scaling together.
mDeviceFormat = configurationOutput.getFormat();
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index bb007ac..9e5ca8e 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -177,6 +177,24 @@
streamBuilder->setSharingMode(sharingMode);
}
+AAUDIO_API void AAudioStreamBuilder_setUsage(AAudioStreamBuilder* builder,
+ aaudio_usage_t usage) {
+ AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
+ streamBuilder->setUsage(usage);
+}
+
+AAUDIO_API void AAudioStreamBuilder_setContentType(AAudioStreamBuilder* builder,
+ aaudio_content_type_t contentType) {
+ AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
+ streamBuilder->setContentType(contentType);
+}
+
+AAUDIO_API void AAudioStreamBuilder_setInputPreset(AAudioStreamBuilder* builder,
+ aaudio_input_preset_t inputPreset) {
+ AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
+ streamBuilder->setInputPreset(inputPreset);
+}
+
AAUDIO_API void AAudioStreamBuilder_setBufferCapacityInFrames(AAudioStreamBuilder* builder,
int32_t frames)
{
@@ -447,6 +465,24 @@
return audioStream->getSharingMode();
}
+AAUDIO_API aaudio_usage_t AAudioStream_getUsage(AAudioStream* stream)
+{
+ AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+ return audioStream->getUsage();
+}
+
+AAUDIO_API aaudio_content_type_t AAudioStream_getContentType(AAudioStream* stream)
+{
+ AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+ return audioStream->getContentType();
+}
+
+AAUDIO_API aaudio_input_preset_t AAudioStream_getInputPreset(AAudioStream* stream)
+{
+ AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+ return audioStream->getInputPreset();
+}
+
AAUDIO_API int64_t AAudioStream_getFramesWritten(AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.cpp b/media/libaaudio/src/core/AAudioStreamParameters.cpp
index 6400eb4..23c4eb8 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.cpp
+++ b/media/libaaudio/src/core/AAudioStreamParameters.cpp
@@ -42,6 +42,9 @@
mAudioFormat = other.mAudioFormat;
mDirection = other.mDirection;
mBufferCapacity = other.mBufferCapacity;
+ mUsage = other.mUsage;
+ mContentType = other.mContentType;
+ mInputPreset = other.mInputPreset;
}
aaudio_result_t AAudioStreamParameters::validate() const {
@@ -98,6 +101,54 @@
// break;
}
+ switch (mUsage) {
+ case AAUDIO_UNSPECIFIED:
+ case AAUDIO_USAGE_MEDIA:
+ case AAUDIO_USAGE_VOICE_COMMUNICATION:
+ case AAUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING:
+ case AAUDIO_USAGE_ALARM:
+ case AAUDIO_USAGE_NOTIFICATION:
+ case AAUDIO_USAGE_NOTIFICATION_RINGTONE:
+ case AAUDIO_USAGE_NOTIFICATION_EVENT:
+ case AAUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
+ case AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
+ case AAUDIO_USAGE_ASSISTANCE_SONIFICATION:
+ case AAUDIO_USAGE_GAME:
+ case AAUDIO_USAGE_ASSISTANT:
+ break; // valid
+ default:
+ ALOGE("usage not valid = %d", mUsage);
+ return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+ // break;
+ }
+
+ switch (mContentType) {
+ case AAUDIO_UNSPECIFIED:
+ case AAUDIO_CONTENT_TYPE_MUSIC:
+ case AAUDIO_CONTENT_TYPE_MOVIE:
+ case AAUDIO_CONTENT_TYPE_SONIFICATION:
+ case AAUDIO_CONTENT_TYPE_SPEECH:
+ break; // valid
+ default:
+ ALOGE("content type not valid = %d", mContentType);
+ return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+ // break;
+ }
+
+ switch (mInputPreset) {
+ case AAUDIO_UNSPECIFIED:
+ case AAUDIO_INPUT_PRESET_GENERIC:
+ case AAUDIO_INPUT_PRESET_CAMCORDER:
+ case AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION:
+ case AAUDIO_INPUT_PRESET_VOICE_RECOGNITION:
+ case AAUDIO_INPUT_PRESET_UNPROCESSED:
+ break; // valid
+ default:
+ ALOGE("input preset not valid = %d", mInputPreset);
+ return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+ // break;
+ }
+
return AAUDIO_OK;
}
@@ -109,5 +160,8 @@
ALOGD("mAudioFormat = %6d", (int)mAudioFormat);
ALOGD("mDirection = %6d", mDirection);
ALOGD("mBufferCapacity = %6d", mBufferCapacity);
+ ALOGD("mUsage = %6d", mUsage);
+ ALOGD("mContentType = %6d", mContentType);
+ ALOGD("mInputPreset = %6d", mInputPreset);
}
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.h b/media/libaaudio/src/core/AAudioStreamParameters.h
index 5e67c93..0c173f5 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.h
+++ b/media/libaaudio/src/core/AAudioStreamParameters.h
@@ -88,6 +88,30 @@
mDirection = direction;
}
+ aaudio_usage_t getUsage() const {
+ return mUsage;
+ }
+
+ void setUsage(aaudio_usage_t usage) {
+ mUsage = usage;
+ }
+
+ aaudio_content_type_t getContentType() const {
+ return mContentType;
+ }
+
+ void setContentType(aaudio_content_type_t contentType) {
+ mContentType = contentType;
+ }
+
+ aaudio_input_preset_t getInputPreset() const {
+ return mInputPreset;
+ }
+
+ void setInputPreset(aaudio_input_preset_t inputPreset) {
+ mInputPreset = inputPreset;
+ }
+
int32_t calculateBytesPerFrame() const {
return getSamplesPerFrame() * AAudioConvert_formatToSizeInBytes(getFormat());
}
@@ -109,6 +133,9 @@
aaudio_sharing_mode_t mSharingMode = AAUDIO_SHARING_MODE_SHARED;
aaudio_format_t mAudioFormat = AAUDIO_FORMAT_UNSPECIFIED;
aaudio_direction_t mDirection = AAUDIO_DIRECTION_OUTPUT;
+ aaudio_usage_t mUsage = AAUDIO_UNSPECIFIED;
+ aaudio_content_type_t mContentType = AAUDIO_UNSPECIFIED;
+ aaudio_input_preset_t mInputPreset = AAUDIO_UNSPECIFIED;
int32_t mBufferCapacity = AAUDIO_UNSPECIFIED;
};
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index 8f5f5d3..1b2ca39 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -74,15 +74,28 @@
}
// Copy parameters from the Builder because the Builder may be deleted after this call.
+ // TODO AudioStream should be a subclass of AudioStreamParameters
mSamplesPerFrame = builder.getSamplesPerFrame();
mSampleRate = builder.getSampleRate();
mDeviceId = builder.getDeviceId();
mFormat = builder.getFormat();
mSharingMode = builder.getSharingMode();
mSharingModeMatchRequired = builder.isSharingModeMatchRequired();
-
mPerformanceMode = builder.getPerformanceMode();
+ mUsage = builder.getUsage();
+ if (mUsage == AAUDIO_UNSPECIFIED) {
+ mUsage = AAUDIO_USAGE_MEDIA;
+ }
+ mContentType = builder.getContentType();
+ if (mContentType == AAUDIO_UNSPECIFIED) {
+ mContentType = AAUDIO_CONTENT_TYPE_MUSIC;
+ }
+ mInputPreset = builder.getInputPreset();
+ if (mInputPreset == AAUDIO_UNSPECIFIED) {
+ mInputPreset = AAUDIO_INPUT_PRESET_GENERIC;
+ }
+
// callbacks
mFramesPerDataCallback = builder.getFramesPerDataCallback();
mDataCallbackProc = builder.getDataCallbackProc();
@@ -99,6 +112,8 @@
mDeviceId, mPerformanceMode,
(isDataCallbackSet() ? "ON" : "OFF"),
mFramesPerDataCallback);
+ ALOGI("open() usage = %d, contentType = %d, inputPreset = %d",
+ mUsage, mContentType, mInputPreset);
return AAUDIO_OK;
}
@@ -221,6 +236,17 @@
if (err != 0) {
return AAudioConvert_androidToAAudioResult(-errno);
} else {
+ // Name the thread with an increasing index, "AAudio_#", for debugging.
+ static std::atomic<uint32_t> nextThreadIndex{1};
+ char name[16]; // max length for a pthread_name
+ uint32_t index = nextThreadIndex++;
+ // Wrap the index so that we do not hit the 16 char limit
+ // and to avoid hard-to-read large numbers.
+ index = index % 100000; // arbitrary
+ snprintf(name, sizeof(name), "AAudio_%u", index);
+ err = pthread_setname_np(mThread, name);
+ ALOGW_IF((err != 0), "Could not set name of AAudio thread. err = %d", err);
+
mHasThread = true;
return AAUDIO_OK;
}
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index b5d7fd5..21fa595 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -204,6 +204,18 @@
virtual aaudio_direction_t getDirection() const = 0;
+ aaudio_usage_t getUsage() const {
+ return mUsage;
+ }
+
+ aaudio_content_type_t getContentType() const {
+ return mContentType;
+ }
+
+ aaudio_input_preset_t getInputPreset() const {
+ return mInputPreset;
+ }
+
/**
* This is only valid after setSamplesPerFrame() and setFormat() have been called.
*/
@@ -408,6 +420,7 @@
/**
* This should not be called after the open() call.
+ * TODO for multiple setters: assert(mState == AAUDIO_STREAM_STATE_UNINITIALIZED)
*/
void setSampleRate(int32_t sampleRate) {
mSampleRate = sampleRate;
@@ -456,6 +469,27 @@
return mPeriodNanoseconds.load(std::memory_order_acquire);
}
+ /**
+ * This should not be called after the open() call.
+ */
+ void setUsage(aaudio_usage_t usage) {
+ mUsage = usage;
+ }
+
+ /**
+ * This should not be called after the open() call.
+ */
+ void setContentType(aaudio_content_type_t contentType) {
+ mContentType = contentType;
+ }
+
+ /**
+ * This should not be called after the open() call.
+ */
+ void setInputPreset(aaudio_input_preset_t inputPreset) {
+ mInputPreset = inputPreset;
+ }
+
private:
std::mutex mStreamLock;
@@ -471,6 +505,9 @@
aaudio_format_t mFormat = AAUDIO_FORMAT_UNSPECIFIED;
aaudio_stream_state_t mState = AAUDIO_STREAM_STATE_UNINITIALIZED;
aaudio_performance_mode_t mPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
+ aaudio_usage_t mUsage = AAUDIO_USAGE_MEDIA;
+ aaudio_content_type_t mContentType = AAUDIO_CONTENT_TYPE_MUSIC;
+ aaudio_input_preset_t mInputPreset = AAUDIO_INPUT_PRESET_GENERIC;
// callback ----------------------------------
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index 55eed92..5f4ab9b 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -104,11 +104,24 @@
? AUDIO_PORT_HANDLE_NONE
: getDeviceId();
+ const audio_content_type_t contentType =
+ AAudioConvert_contentTypeToInternal(builder.getContentType());
+ const audio_source_t source =
+ AAudioConvert_inputPresetToAudioSource(builder.getInputPreset());
+
+ const audio_attributes_t attributes = {
+ .content_type = contentType,
+ .usage = AUDIO_USAGE_UNKNOWN, // only used for output
+ .source = source,
+ .flags = flags, // If attributes are set then the other flags parameter is ignored.
+ .tags = ""
+ };
+
mAudioRecord = new AudioRecord(
mOpPackageName // const String16& opPackageName TODO does not compile
);
mAudioRecord->set(
- AUDIO_SOURCE_VOICE_RECOGNITION,
+ AUDIO_SOURCE_DEFAULT, // ignored because we pass attributes below
getSampleRate(),
format,
channelMask,
@@ -122,7 +135,7 @@
flags,
AUDIO_UID_INVALID, // DEFAULT uid
-1, // DEFAULT pid
- NULL, // DEFAULT audio_attributes_t
+ &attributes,
selectedDeviceId
);
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 5113278..17a8d52 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -121,9 +121,22 @@
? AUDIO_PORT_HANDLE_NONE
: getDeviceId();
+ const audio_content_type_t contentType =
+ AAudioConvert_contentTypeToInternal(builder.getContentType());
+ const audio_usage_t usage =
+ AAudioConvert_usageToInternal(builder.getUsage());
+
+ const audio_attributes_t attributes = {
+ .content_type = contentType,
+ .usage = usage,
+ .source = AUDIO_SOURCE_DEFAULT, // only used for recording
+ .flags = flags, // If attributes are set then the other flags parameter is ignored.
+ .tags = ""
+ };
+
mAudioTrack = new AudioTrack();
mAudioTrack->set(
- (audio_stream_type_t) AUDIO_STREAM_MUSIC,
+ AUDIO_STREAM_DEFAULT, // ignored because we pass attributes below
getSampleRate(),
format,
channelMask,
@@ -139,7 +152,7 @@
NULL, // DEFAULT audio_offload_info_t
AUDIO_UID_INVALID, // DEFAULT uid
-1, // DEFAULT pid
- NULL, // DEFAULT audio_attributes_t
+ &attributes,
// WARNING - If doNotReconnect set true then audio stops after plugging and unplugging
// headphones a few times.
false, // DEFAULT doNotReconnect,
diff --git a/media/libaaudio/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp
index f709f41..c6adf33 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.cpp
+++ b/media/libaaudio/src/utility/AAudioUtilities.cpp
@@ -26,6 +26,7 @@
#include "aaudio/AAudio.h"
#include <aaudio/AAudioTesting.h>
#include <math.h>
+#include <system/audio-base.h>
#include "utility/AAudioUtilities.h"
@@ -283,6 +284,61 @@
return aaudioFormat;
}
+// Make a message string from the condition.
+#define STATIC_ASSERT(condition) static_assert(condition, #condition)
+
+audio_usage_t AAudioConvert_usageToInternal(aaudio_usage_t usage) {
+ // The public aaudio_content_type_t constants are supposed to have the same
+ // values as the internal audio_content_type_t values.
+ STATIC_ASSERT(AAUDIO_USAGE_MEDIA == AUDIO_USAGE_MEDIA);
+ STATIC_ASSERT(AAUDIO_USAGE_VOICE_COMMUNICATION == AUDIO_USAGE_VOICE_COMMUNICATION);
+ STATIC_ASSERT(AAUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING
+ == AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING);
+ STATIC_ASSERT(AAUDIO_USAGE_ALARM == AUDIO_USAGE_ALARM);
+ STATIC_ASSERT(AAUDIO_USAGE_NOTIFICATION == AUDIO_USAGE_NOTIFICATION);
+ STATIC_ASSERT(AAUDIO_USAGE_NOTIFICATION_RINGTONE
+ == AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE);
+ STATIC_ASSERT(AAUDIO_USAGE_NOTIFICATION_EVENT == AUDIO_USAGE_NOTIFICATION_EVENT);
+ STATIC_ASSERT(AAUDIO_USAGE_ASSISTANCE_ACCESSIBILITY == AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY);
+ STATIC_ASSERT(AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE
+ == AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE);
+ STATIC_ASSERT(AAUDIO_USAGE_ASSISTANCE_SONIFICATION == AUDIO_USAGE_ASSISTANCE_SONIFICATION);
+ STATIC_ASSERT(AAUDIO_USAGE_GAME == AUDIO_USAGE_GAME);
+ STATIC_ASSERT(AAUDIO_USAGE_ASSISTANT == AUDIO_USAGE_ASSISTANT);
+ if (usage == AAUDIO_UNSPECIFIED) {
+ usage = AAUDIO_USAGE_MEDIA;
+ }
+ return (audio_usage_t) usage; // same value
+}
+
+audio_content_type_t AAudioConvert_contentTypeToInternal(aaudio_content_type_t contentType) {
+ // The public aaudio_content_type_t constants are supposed to have the same
+ // values as the internal audio_content_type_t values.
+ STATIC_ASSERT(AAUDIO_CONTENT_TYPE_MUSIC == AUDIO_CONTENT_TYPE_MUSIC);
+ STATIC_ASSERT(AAUDIO_CONTENT_TYPE_SPEECH == AUDIO_CONTENT_TYPE_SPEECH);
+ STATIC_ASSERT(AAUDIO_CONTENT_TYPE_SONIFICATION == AUDIO_CONTENT_TYPE_SONIFICATION);
+ STATIC_ASSERT(AAUDIO_CONTENT_TYPE_MOVIE == AUDIO_CONTENT_TYPE_MOVIE);
+ if (contentType == AAUDIO_UNSPECIFIED) {
+ contentType = AAUDIO_CONTENT_TYPE_MUSIC;
+ }
+ return (audio_content_type_t) contentType; // same value
+}
+
+audio_source_t AAudioConvert_inputPresetToAudioSource(aaudio_input_preset_t preset) {
+ // The public aaudio_input_preset_t constants are supposed to have the same
+ // values as the internal audio_source_t values.
+ STATIC_ASSERT(AAUDIO_UNSPECIFIED == AUDIO_SOURCE_DEFAULT);
+ STATIC_ASSERT(AAUDIO_INPUT_PRESET_GENERIC == AUDIO_SOURCE_MIC);
+ STATIC_ASSERT(AAUDIO_INPUT_PRESET_CAMCORDER == AUDIO_SOURCE_CAMCORDER);
+ STATIC_ASSERT(AAUDIO_INPUT_PRESET_VOICE_RECOGNITION == AUDIO_SOURCE_VOICE_RECOGNITION);
+ STATIC_ASSERT(AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION == AUDIO_SOURCE_VOICE_COMMUNICATION);
+ STATIC_ASSERT(AAUDIO_INPUT_PRESET_UNPROCESSED == AUDIO_SOURCE_UNPROCESSED);
+ if (preset == AAUDIO_UNSPECIFIED) {
+ preset = AAUDIO_INPUT_PRESET_GENERIC;
+ }
+ return (audio_source_t) preset; // same value
+}
+
int32_t AAudioConvert_framesToBytes(int32_t numFrames,
int32_t bytesPerFrame,
int32_t *sizeInBytes) {
diff --git a/media/libaaudio/src/utility/AAudioUtilities.h b/media/libaaudio/src/utility/AAudioUtilities.h
index 3afa976..f2347f5 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.h
+++ b/media/libaaudio/src/utility/AAudioUtilities.h
@@ -167,6 +167,29 @@
aaudio_format_t AAudioConvert_androidToAAudioDataFormat(audio_format_t format);
+
+/**
+ * Note that this function does not validate the passed in value.
+ * That is done somewhere else.
+ * @return internal value
+ */
+
+audio_usage_t AAudioConvert_usageToInternal(aaudio_usage_t usage);
+
+/**
+ * Note that this function does not validate the passed in value.
+ * That is done somewhere else.
+ * @return internal value
+ */
+audio_content_type_t AAudioConvert_contentTypeToInternal(aaudio_content_type_t contentType);
+
+/**
+ * Note that this function does not validate the passed in value.
+ * That is done somewhere else.
+ * @return internal audio source
+ */
+audio_source_t AAudioConvert_inputPresetToAudioSource(aaudio_input_preset_t preset);
+
/**
* @return the size of a sample of the given format in bytes or AAUDIO_ERROR_ILLEGAL_ARGUMENT
*/
diff --git a/media/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp
index 9f80695..33718fc 100644
--- a/media/libaaudio/tests/Android.bp
+++ b/media/libaaudio/tests/Android.bp
@@ -124,3 +124,15 @@
"libutils",
],
}
+
+cc_test {
+ name: "test_attributes",
+ defaults: ["libaaudio_tests_defaults"],
+ srcs: ["test_attributes.cpp"],
+ shared_libs: [
+ "libaaudio",
+ "libbinder",
+ "libcutils",
+ "libutils",
+ ],
+}
diff --git a/media/libaaudio/tests/test_attributes.cpp b/media/libaaudio/tests/test_attributes.cpp
new file mode 100644
index 0000000..9cbf113
--- /dev/null
+++ b/media/libaaudio/tests/test_attributes.cpp
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+// Test AAudio attributes such as Usage, ContentType and InputPreset.
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include <aaudio/AAudio.h>
+#include <gtest/gtest.h>
+
+constexpr int64_t kNanosPerSecond = 1000000000;
+constexpr int kNumFrames = 256;
+constexpr int kChannelCount = 2;
+
+constexpr int32_t DONT_SET = -1000;
+
+static void checkAttributes(aaudio_performance_mode_t perfMode,
+ aaudio_usage_t usage,
+ aaudio_content_type_t contentType,
+ aaudio_input_preset_t preset = DONT_SET,
+ aaudio_direction_t direction = AAUDIO_DIRECTION_OUTPUT) {
+
+ float *buffer = new float[kNumFrames * kChannelCount];
+
+ AAudioStreamBuilder *aaudioBuilder = nullptr;
+ AAudioStream *aaudioStream = nullptr;
+
+ // Use an AAudioStreamBuilder to contain requested parameters.
+ ASSERT_EQ(AAUDIO_OK, AAudio_createStreamBuilder(&aaudioBuilder));
+
+ // Request stream properties.
+ AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, perfMode);
+ AAudioStreamBuilder_setDirection(aaudioBuilder, direction);
+
+ // Set the attribute in the builder.
+ if (usage != DONT_SET) {
+ AAudioStreamBuilder_setUsage(aaudioBuilder, usage);
+ }
+ if (contentType != DONT_SET) {
+ AAudioStreamBuilder_setContentType(aaudioBuilder, contentType);
+ }
+ if (preset != DONT_SET) {
+ AAudioStreamBuilder_setInputPreset(aaudioBuilder, preset);
+ }
+
+ // Create an AAudioStream using the Builder.
+ ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream));
+ AAudioStreamBuilder_delete(aaudioBuilder);
+
+ // Make sure we get the same attributes back from the stream.
+ aaudio_usage_t expectedUsage =
+ (usage == DONT_SET || usage == AAUDIO_UNSPECIFIED)
+ ? AAUDIO_USAGE_MEDIA // default
+ : usage;
+ EXPECT_EQ(expectedUsage, AAudioStream_getUsage(aaudioStream));
+
+ aaudio_content_type_t expectedContentType =
+ (contentType == DONT_SET || contentType == AAUDIO_UNSPECIFIED)
+ ? AAUDIO_CONTENT_TYPE_MUSIC // default
+ : contentType;
+ EXPECT_EQ(expectedContentType, AAudioStream_getContentType(aaudioStream));
+
+ aaudio_input_preset_t expectedPreset =
+ (preset == DONT_SET || preset == AAUDIO_UNSPECIFIED)
+ ? AAUDIO_INPUT_PRESET_GENERIC // default
+ : preset;
+ EXPECT_EQ(expectedPreset, AAudioStream_getInputPreset(aaudioStream));
+
+ EXPECT_EQ(AAUDIO_OK, AAudioStream_requestStart(aaudioStream));
+
+ if (direction == AAUDIO_DIRECTION_INPUT) {
+ EXPECT_EQ(kNumFrames,
+ AAudioStream_read(aaudioStream, buffer, kNumFrames, kNanosPerSecond));
+ } else {
+ EXPECT_EQ(kNumFrames,
+ AAudioStream_write(aaudioStream, buffer, kNumFrames, kNanosPerSecond));
+ }
+
+ EXPECT_EQ(AAUDIO_OK, AAudioStream_requestStop(aaudioStream));
+
+ EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream));
+ delete[] buffer;
+}
+
+static const aaudio_usage_t sUsages[] = {
+ DONT_SET,
+ AAUDIO_UNSPECIFIED,
+ AAUDIO_USAGE_MEDIA,
+ AAUDIO_USAGE_VOICE_COMMUNICATION,
+ AAUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING,
+ AAUDIO_USAGE_ALARM,
+ AAUDIO_USAGE_NOTIFICATION,
+ AAUDIO_USAGE_NOTIFICATION_RINGTONE,
+ AAUDIO_USAGE_NOTIFICATION_EVENT,
+ AAUDIO_USAGE_ASSISTANCE_ACCESSIBILITY,
+ AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+ AAUDIO_USAGE_ASSISTANCE_SONIFICATION,
+ AAUDIO_USAGE_GAME,
+ AAUDIO_USAGE_ASSISTANT
+};
+
+static const aaudio_content_type_t sContentypes[] = {
+ DONT_SET,
+ AAUDIO_UNSPECIFIED,
+ AAUDIO_CONTENT_TYPE_SPEECH,
+ AAUDIO_CONTENT_TYPE_MUSIC,
+ AAUDIO_CONTENT_TYPE_MOVIE,
+ AAUDIO_CONTENT_TYPE_SONIFICATION
+};
+
+static const aaudio_input_preset_t sInputPresets[] = {
+ DONT_SET,
+ AAUDIO_UNSPECIFIED,
+ AAUDIO_INPUT_PRESET_GENERIC,
+ AAUDIO_INPUT_PRESET_CAMCORDER,
+ AAUDIO_INPUT_PRESET_VOICE_RECOGNITION,
+ AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION,
+ AAUDIO_INPUT_PRESET_UNPROCESSED,
+};
+
+static void checkAttributesUsage(aaudio_performance_mode_t perfMode) {
+ for (aaudio_usage_t usage : sUsages) {
+ checkAttributes(perfMode, usage, DONT_SET);
+ }
+}
+
+static void checkAttributesContentType(aaudio_input_preset_t perfMode) {
+ for (aaudio_content_type_t contentType : sContentypes) {
+ checkAttributes(perfMode, DONT_SET, contentType);
+ }
+}
+
+static void checkAttributesInputPreset(aaudio_performance_mode_t perfMode) {
+ for (aaudio_input_preset_t inputPreset : sInputPresets) {
+ checkAttributes(perfMode,
+ DONT_SET,
+ DONT_SET,
+ inputPreset,
+ AAUDIO_DIRECTION_INPUT);
+ }
+}
+
+TEST(test_attributes, aaudio_usage_perfnone) {
+ checkAttributesUsage(AAUDIO_PERFORMANCE_MODE_NONE);
+}
+
+TEST(test_attributes, aaudio_content_type_perfnone) {
+ checkAttributesContentType(AAUDIO_PERFORMANCE_MODE_NONE);
+}
+
+TEST(test_attributes, aaudio_input_preset_perfnone) {
+ checkAttributesInputPreset(AAUDIO_PERFORMANCE_MODE_NONE);
+}
+
+TEST(test_attributes, aaudio_usage_lowlat) {
+ checkAttributesUsage(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
+}
+
+TEST(test_attributes, aaudio_content_type_lowlat) {
+ checkAttributesContentType(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
+}
+
+TEST(test_attributes, aaudio_input_preset_lowlat) {
+ checkAttributesInputPreset(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
+}
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 94253a4..2df37a8 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -49,7 +49,6 @@
"libaudiomanager",
"libmedia_helper",
"libmediametrics",
- "libstagefright_foundation",
],
export_shared_lib_headers: ["libbinder"],
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 0d4b462..bc294c5 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -26,6 +26,8 @@
#include <utils/Log.h>
#include <private/media/AudioTrackShared.h>
#include <media/IAudioFlinger.h>
+#include <media/MediaAnalyticsItem.h>
+#include <media/TypeConverter.h>
#define WAIT_PERIOD_MS 10
@@ -65,6 +67,34 @@
// ---------------------------------------------------------------------------
+static std::string audioFormatTypeString(audio_format_t value) {
+ std::string formatType;
+ if (FormatConverter::toString(value, formatType)) {
+ return formatType;
+ }
+ char rawbuffer[16]; // room for "%d"
+ snprintf(rawbuffer, sizeof(rawbuffer), "%d", value);
+ return rawbuffer;
+}
+
+void AudioRecord::MediaMetrics::gather(const AudioRecord *record)
+{
+ // key for media statistics is defined in the header
+ // attrs for media statistics
+ static constexpr char kAudioRecordChannelCount[] = "android.media.audiorecord.channels";
+ static constexpr char kAudioRecordFormat[] = "android.media.audiorecord.format";
+ static constexpr char kAudioRecordLatency[] = "android.media.audiorecord.latency";
+ static constexpr char kAudioRecordSampleRate[] = "android.media.audiorecord.samplerate";
+
+ // constructor guarantees mAnalyticsItem is valid
+
+ mAnalyticsItem->setInt32(kAudioRecordLatency, record->mLatency);
+ mAnalyticsItem->setInt32(kAudioRecordSampleRate, record->mSampleRate);
+ mAnalyticsItem->setInt32(kAudioRecordChannelCount, record->mChannelCount);
+ mAnalyticsItem->setCString(kAudioRecordFormat,
+ audioFormatTypeString(record->mFormat).c_str());
+}
+
AudioRecord::AudioRecord(const String16 &opPackageName)
: mActive(false), mStatus(NO_INIT), mOpPackageName(opPackageName),
mSessionId(AUDIO_SESSION_ALLOCATE),
@@ -105,6 +135,8 @@
AudioRecord::~AudioRecord()
{
+ mMediaMetrics.gather(this);
+
if (mStatus == NO_ERROR) {
// Make sure that callback function exits in the case where
// it is looping on buffer empty condition in obtainBuffer().
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 7670982..a3c66fe 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -189,16 +189,22 @@
static constexpr char kAudioTrackUsage[] = "android.media.audiotrack.usage";
static constexpr char kAudioTrackSampleRate[] = "android.media.audiotrack.samplerate";
static constexpr char kAudioTrackChannelMask[] = "android.media.audiotrack.channelmask";
+#if 0
+ // XXX: disabled temporarily for b/72027185
static constexpr char kAudioTrackUnderrunFrames[] = "android.media.audiotrack.underrunframes";
+#endif
static constexpr char kAudioTrackStartupGlitch[] = "android.media.audiotrack.glitch.startup";
// constructor guarantees mAnalyticsItem is valid
+#if 0
+ // XXX: disabled temporarily for b/72027185
// must gather underrun info before cleaning mProxy information.
const int32_t underrunFrames = track->getUnderrunFrames();
if (underrunFrames != 0) {
mAnalyticsItem->setInt32(kAudioTrackUnderrunFrames, underrunFrames);
}
+#endif
if (track->mTimestampStartupGlitchReported) {
mAnalyticsItem->setInt32(kAudioTrackStartupGlitch, 1);
diff --git a/media/libaudioclient/include/media/AudioRecord.h b/media/libaudioclient/include/media/AudioRecord.h
index 074e547..fea973a 100644
--- a/media/libaudioclient/include/media/AudioRecord.h
+++ b/media/libaudioclient/include/media/AudioRecord.h
@@ -21,6 +21,7 @@
#include <cutils/sched_policy.h>
#include <media/AudioSystem.h>
#include <media/AudioTimestamp.h>
+#include <media/MediaAnalyticsItem.h>
#include <media/Modulo.h>
#include <utils/RefBase.h>
#include <utils/threads.h>
@@ -688,6 +689,24 @@
// activity and connected devices
wp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
+private:
+ class MediaMetrics {
+ public:
+ MediaMetrics() : mAnalyticsItem(new MediaAnalyticsItem("audiorecord")) {
+ }
+ ~MediaMetrics() {
+ // mAnalyticsItem alloc failure will be flagged in the constructor
+ // don't log empty records
+ if (mAnalyticsItem->count() > 0) {
+ mAnalyticsItem->setFinalized(true);
+ mAnalyticsItem->selfrecord();
+ }
+ }
+ void gather(const AudioRecord *record);
+ private:
+ std::unique_ptr<MediaAnalyticsItem> mAnalyticsItem;
+ };
+ MediaMetrics mMediaMetrics;
};
}; // namespace android
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 0b4fd25..e7dc0fe 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -139,10 +139,18 @@
},
}
+filegroup {
+ name: "mediaupdateservice_aidl",
+ srcs: [
+ "aidl/android/media/IMediaExtractorUpdateService.aidl",
+ ],
+}
+
cc_library_shared {
name: "libmedia",
srcs: [
+ ":mediaupdateservice_aidl",
"IDataSource.cpp",
"BufferingSettings.cpp",
"mediaplayer.cpp",
@@ -179,6 +187,11 @@
"StringArray.cpp",
],
+ aidl: {
+ local_include_dirs: ["aidl"],
+ export_aidl_headers: true,
+ },
+
shared_libs: [
"liblog",
"libcutils",
@@ -306,6 +319,7 @@
srcs: [
"AudioParameter.cpp",
+ "JAudioTrack.cpp",
"MediaPlayer2Factory.cpp",
"MediaPlayer2Manager.cpp",
"TestPlayerStub.cpp",
@@ -314,6 +328,7 @@
],
shared_libs: [
+ "libandroid_runtime",
"libaudioclient",
"libbinder",
"libcutils",
diff --git a/media/libmedia/JAudioTrack.cpp b/media/libmedia/JAudioTrack.cpp
new file mode 100644
index 0000000..b228d8b
--- /dev/null
+++ b/media/libmedia/JAudioTrack.cpp
@@ -0,0 +1,520 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "JAudioTrack"
+
+#include "media/JAudioAttributes.h"
+#include "media/JAudioFormat.h"
+#include "media/JAudioTrack.h"
+
+#include <android_media_AudioErrors.h>
+#include <android_runtime/AndroidRuntime.h>
+
+namespace android {
+
+// TODO: Store Java class/methodID as a member variable in the class.
+// TODO: Add NULL && Exception checks after every JNI call.
+JAudioTrack::JAudioTrack( // < Usages of the arguments are below >
+ audio_stream_type_t streamType, // AudioAudioAttributes
+ uint32_t sampleRate, // AudioFormat && bufferSizeInBytes
+ audio_format_t format, // AudioFormat && bufferSizeInBytes
+ audio_channel_mask_t channelMask, // AudioFormat && bufferSizeInBytes
+ size_t frameCount, // bufferSizeInBytes
+ audio_session_t sessionId, // AudioTrack
+ const audio_attributes_t* pAttributes, // AudioAttributes
+ float maxRequiredSpeed) { // bufferSizeInBytes
+
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jclass jAudioTrackCls = env->FindClass("android/media/AudioTrack");
+ mAudioTrackCls = (jclass) env->NewGlobalRef(jAudioTrackCls);
+
+ maxRequiredSpeed = std::min(std::max(maxRequiredSpeed, 1.0f), AUDIO_TIMESTRETCH_SPEED_MAX);
+
+ int bufferSizeInBytes = 0;
+ if (sampleRate == 0 || frameCount > 0) {
+ // Manually calculate buffer size.
+ bufferSizeInBytes = audio_channel_count_from_out_mask(channelMask)
+ * audio_bytes_per_sample(format) * (frameCount > 0 ? frameCount : 1);
+ } else if (sampleRate > 0) {
+ // Call Java AudioTrack::getMinBufferSize().
+ jmethodID jGetMinBufferSize =
+ env->GetStaticMethodID(mAudioTrackCls, "getMinBufferSize", "(III)I");
+ bufferSizeInBytes = env->CallStaticIntMethod(mAudioTrackCls, jGetMinBufferSize,
+ sampleRate, outChannelMaskFromNative(channelMask), audioFormatFromNative(format));
+ }
+ bufferSizeInBytes = (int) (bufferSizeInBytes * maxRequiredSpeed);
+
+ // Create a Java AudioTrack object through its Builder.
+ jclass jBuilderCls = env->FindClass("android/media/AudioTrack$Builder");
+ jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
+ jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);
+
+ jmethodID jSetAudioAttributes = env->GetMethodID(jBuilderCls, "setAudioAttributes",
+ "(Landroid/media/AudioAttributes;)Landroid/media/AudioTrack$Builder;");
+ jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetAudioAttributes,
+ JAudioAttributes::createAudioAttributesObj(env, pAttributes, streamType));
+
+ jmethodID jSetAudioFormat = env->GetMethodID(jBuilderCls, "setAudioFormat",
+ "(Landroid/media/AudioFormat;)Landroid/media/AudioTrack$Builder;");
+ jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetAudioFormat,
+ JAudioFormat::createAudioFormatObj(env, sampleRate, format, channelMask));
+
+ jmethodID jSetBufferSizeInBytes = env->GetMethodID(jBuilderCls, "setBufferSizeInBytes",
+ "(I)Landroid/media/AudioTrack$Builder;");
+ jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetBufferSizeInBytes, bufferSizeInBytes);
+
+ // We only use streaming mode of Java AudioTrack.
+ jfieldID jModeStream = env->GetStaticFieldID(mAudioTrackCls, "MODE_STREAM", "I");
+ jint transferMode = env->GetStaticIntField(mAudioTrackCls, jModeStream);
+ jmethodID jSetTransferMode = env->GetMethodID(jBuilderCls, "setTransferMode",
+ "(I)Landroid/media/AudioTrack$Builder;");
+ jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetTransferMode,
+ transferMode /* Java AudioTrack::MODE_STREAM */);
+
+ if (sessionId != 0) {
+ jmethodID jSetSessionId = env->GetMethodID(jBuilderCls, "setSessionId",
+ "(I)Landroid/media/AudioTrack$Builder;");
+ jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetSessionId, sessionId);
+ }
+
+ jmethodID jBuild = env->GetMethodID(jBuilderCls, "build", "()Landroid/media/AudioTrack;");
+ mAudioTrackObj = env->CallObjectMethod(jBuilderObj, jBuild);
+}
+
+JAudioTrack::~JAudioTrack() {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ env->DeleteGlobalRef(mAudioTrackCls);
+}
+
+size_t JAudioTrack::frameCount() {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jmethodID jGetBufferSizeInFrames = env->GetMethodID(
+ mAudioTrackCls, "getBufferSizeInFrames", "()I");
+ return env->CallIntMethod(mAudioTrackObj, jGetBufferSizeInFrames);
+}
+
+size_t JAudioTrack::channelCount() {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jmethodID jGetChannelCount = env->GetMethodID(mAudioTrackCls, "getChannelCount", "()I");
+ return env->CallIntMethod(mAudioTrackObj, jGetChannelCount);
+}
+
+status_t JAudioTrack::getPosition(uint32_t *position) {
+ if (position == NULL) {
+ return BAD_VALUE;
+ }
+
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jmethodID jGetPlaybackHeadPosition = env->GetMethodID(
+ mAudioTrackCls, "getPlaybackHeadPosition", "()I");
+ *position = env->CallIntMethod(mAudioTrackObj, jGetPlaybackHeadPosition);
+
+ return NO_ERROR;
+}
+
+bool JAudioTrack::getTimeStamp(AudioTimestamp& timestamp) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+ jclass jAudioTimeStampCls = env->FindClass("android/media/AudioTimestamp");
+ jobject jAudioTimeStampObj = env->AllocObject(jAudioTimeStampCls);
+
+ jfieldID jFramePosition = env->GetFieldID(jAudioTimeStampCls, "framePosition", "L");
+ jfieldID jNanoTime = env->GetFieldID(jAudioTimeStampCls, "nanoTime", "L");
+
+ jmethodID jGetTimestamp = env->GetMethodID(mAudioTrackCls,
+ "getTimestamp", "(Landroid/media/AudioTimestamp)B");
+ bool success = env->CallBooleanMethod(mAudioTrackObj, jGetTimestamp, jAudioTimeStampObj);
+
+ if (!success) {
+ return false;
+ }
+
+ long long framePosition = env->GetLongField(jAudioTimeStampObj, jFramePosition);
+ long long nanoTime = env->GetLongField(jAudioTimeStampObj, jNanoTime);
+
+ struct timespec ts;
+ const long long secondToNano = 1000000000LL; // 1E9
+ ts.tv_sec = nanoTime / secondToNano;
+ ts.tv_nsec = nanoTime % secondToNano;
+ timestamp.mTime = ts;
+ timestamp.mPosition = (uint32_t) framePosition;
+
+ return true;
+}
+
+status_t JAudioTrack::setPlaybackRate(const AudioPlaybackRate &playbackRate) {
+ // TODO: existing native AudioTrack returns INVALID_OPERATION on offload/direct/fast tracks.
+ // Should we do the same thing?
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+ jclass jPlaybackParamsCls = env->FindClass("android/media/PlaybackParams");
+ jmethodID jPlaybackParamsCtor = env->GetMethodID(jPlaybackParamsCls, "<init>", "()V");
+ jobject jPlaybackParamsObj = env->NewObject(jPlaybackParamsCls, jPlaybackParamsCtor);
+
+ jmethodID jSetAudioFallbackMode = env->GetMethodID(
+ jPlaybackParamsCls, "setAudioFallbackMode", "(I)Landroid/media/PlaybackParams;");
+ jPlaybackParamsObj = env->CallObjectMethod(
+ jPlaybackParamsObj, jSetAudioFallbackMode, playbackRate.mFallbackMode);
+
+ jmethodID jSetAudioStretchMode = env->GetMethodID(
+ jPlaybackParamsCls, "setAudioStretchMode", "(I)Landroid/media/PlaybackParams;");
+ jPlaybackParamsObj = env->CallObjectMethod(
+ jPlaybackParamsObj, jSetAudioStretchMode, playbackRate.mStretchMode);
+
+ jmethodID jSetPitch = env->GetMethodID(
+ jPlaybackParamsCls, "setPitch", "(F)Landroid/media/PlaybackParams;");
+ jPlaybackParamsObj = env->CallObjectMethod(jPlaybackParamsObj, jSetPitch, playbackRate.mPitch);
+
+ jmethodID jSetSpeed = env->GetMethodID(
+ jPlaybackParamsCls, "setSpeed", "(F)Landroid/media/PlaybackParams;");
+ jPlaybackParamsObj = env->CallObjectMethod(jPlaybackParamsObj, jSetSpeed, playbackRate.mSpeed);
+
+
+ // Set this Java PlaybackParams object into Java AudioTrack.
+ jmethodID jSetPlaybackParams = env->GetMethodID(
+ mAudioTrackCls, "setPlaybackParams", "(Landroid/media/PlaybackParams;)V");
+ env->CallVoidMethod(mAudioTrackObj, jSetPlaybackParams, jPlaybackParamsObj);
+ // TODO: Should we catch the Java IllegalArgumentException?
+
+ return NO_ERROR;
+}
+
+const AudioPlaybackRate JAudioTrack::getPlaybackRate() {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+ jmethodID jGetPlaybackParams = env->GetMethodID(
+ mAudioTrackCls, "getPlaybackParams", "()Landroid/media/PlaybackParams;");
+ jobject jPlaybackParamsObj = env->CallObjectMethod(mAudioTrackObj, jGetPlaybackParams);
+
+ AudioPlaybackRate playbackRate;
+ jclass jPlaybackParamsCls = env->FindClass("android/media/PlaybackParams");
+
+ jmethodID jGetAudioFallbackMode = env->GetMethodID(
+ jPlaybackParamsCls, "getAudioFallbackMode", "()I");
+ // TODO: Should we enable passing AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT?
+ // The enum is internal only, so it is not defined in PlaybackParmas.java.
+ // TODO: Is this right way to convert an int to an enum?
+ playbackRate.mFallbackMode = static_cast<AudioTimestretchFallbackMode>(
+ env->CallIntMethod(jPlaybackParamsObj, jGetAudioFallbackMode));
+
+ jmethodID jGetAudioStretchMode = env->GetMethodID(
+ jPlaybackParamsCls, "getAudioStretchMode", "()I");
+ playbackRate.mStretchMode = static_cast<AudioTimestretchStretchMode>(
+ env->CallIntMethod(jPlaybackParamsObj, jGetAudioStretchMode));
+
+ jmethodID jGetPitch = env->GetMethodID(jPlaybackParamsCls, "getPitch", "()F");
+ playbackRate.mPitch = env->CallFloatMethod(jPlaybackParamsObj, jGetPitch);
+
+ jmethodID jGetSpeed = env->GetMethodID(jPlaybackParamsCls, "getSpeed", "()F");
+ playbackRate.mSpeed = env->CallFloatMethod(jPlaybackParamsObj, jGetSpeed);
+
+ return playbackRate;
+}
+
+media::VolumeShaper::Status JAudioTrack::applyVolumeShaper(
+ const sp<media::VolumeShaper::Configuration>& configuration,
+ const sp<media::VolumeShaper::Operation>& operation) {
+
+ jobject jConfigurationObj = createVolumeShaperConfigurationObj(configuration);
+ jobject jOperationObj = createVolumeShaperOperationObj(operation);
+
+ if (jConfigurationObj == NULL || jOperationObj == NULL) {
+ return media::VolumeShaper::Status(BAD_VALUE);
+ }
+
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+ jmethodID jCreateVolumeShaper = env->GetMethodID(mAudioTrackCls, "createVolumeShaper",
+ "(Landroid/media/VolumeShaper$Configuration;)Landroid/media/VolumeShaper;");
+ jobject jVolumeShaperObj = env->CallObjectMethod(
+ mAudioTrackObj, jCreateVolumeShaper, jConfigurationObj);
+
+ jclass jVolumeShaperCls = env->FindClass("android/media/VolumeShaper");
+ jmethodID jApply = env->GetMethodID(jVolumeShaperCls, "apply",
+ "(Landroid/media/VolumeShaper$Operation;)V");
+ env->CallVoidMethod(jVolumeShaperObj, jApply, jOperationObj);
+
+ return media::VolumeShaper::Status(NO_ERROR);
+}
+
+status_t JAudioTrack::setAuxEffectSendLevel(float level) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jmethodID jSetAuxEffectSendLevel = env->GetMethodID(
+ mAudioTrackCls, "setAuxEffectSendLevel", "(F)I");
+ int result = env->CallIntMethod(mAudioTrackObj, jSetAuxEffectSendLevel, level);
+ return javaToNativeStatus(result);
+}
+
+status_t JAudioTrack::attachAuxEffect(int effectId) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jmethodID jAttachAuxEffect = env->GetMethodID(mAudioTrackCls, "attachAuxEffect", "(I)I");
+ int result = env->CallIntMethod(mAudioTrackObj, jAttachAuxEffect, effectId);
+ return javaToNativeStatus(result);
+}
+
+status_t JAudioTrack::setVolume(float left, float right) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ // TODO: Java setStereoVolume is deprecated. Do we really need this method?
+ jmethodID jSetStereoVolume = env->GetMethodID(mAudioTrackCls, "setStereoVolume", "(FF)I");
+ int result = env->CallIntMethod(mAudioTrackObj, jSetStereoVolume, left, right);
+ return javaToNativeStatus(result);
+}
+
+status_t JAudioTrack::setVolume(float volume) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jmethodID jSetVolume = env->GetMethodID(mAudioTrackCls, "setVolume", "(F)I");
+ int result = env->CallIntMethod(mAudioTrackObj, jSetVolume, volume);
+ return javaToNativeStatus(result);
+}
+
+status_t JAudioTrack::start() {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jmethodID jPlay = env->GetMethodID(mAudioTrackCls, "play", "()V");
+ // TODO: Should we catch the Java IllegalStateException from play()?
+ env->CallVoidMethod(mAudioTrackObj, jPlay);
+ return NO_ERROR;
+}
+
+ssize_t JAudioTrack::write(const void* buffer, size_t size, bool blocking) {
+ if (buffer == NULL) {
+ return BAD_VALUE;
+ }
+
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jbyteArray jAudioData = env->NewByteArray(size);
+ env->SetByteArrayRegion(jAudioData, 0, size, (jbyte *) buffer);
+
+ jclass jByteBufferCls = env->FindClass("java/nio/ByteBuffer");
+ jmethodID jWrap = env->GetStaticMethodID(jByteBufferCls, "wrap", "([B)Ljava/nio/ByteBuffer;");
+ jobject jByteBufferObj = env->CallStaticObjectMethod(jByteBufferCls, jWrap, jAudioData);
+
+ int writeMode = 0;
+ if (blocking) {
+ jfieldID jWriteBlocking = env->GetStaticFieldID(mAudioTrackCls, "WRITE_BLOCKING", "I");
+ writeMode = env->GetStaticIntField(mAudioTrackCls, jWriteBlocking);
+ } else {
+ jfieldID jWriteNonBlocking = env->GetStaticFieldID(
+ mAudioTrackCls, "WRITE_NON_BLOCKING", "I");
+ writeMode = env->GetStaticIntField(mAudioTrackCls, jWriteNonBlocking);
+ }
+
+ jmethodID jWrite = env->GetMethodID(mAudioTrackCls, "write", "(Ljava/nio/ByteBuffer;II)I");
+ int result = env->CallIntMethod(mAudioTrackObj, jWrite, jByteBufferObj, size, writeMode);
+
+ if (result >= 0) {
+ return result;
+ } else {
+ return javaToNativeStatus(result);
+ }
+}
+
+void JAudioTrack::stop() {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jmethodID jStop = env->GetMethodID(mAudioTrackCls, "stop", "()V");
+ env->CallVoidMethod(mAudioTrackObj, jStop);
+ // TODO: Should we catch IllegalStateException?
+}
+
+// TODO: Is the right implementation?
+bool JAudioTrack::stopped() const {
+ return !isPlaying();
+}
+
+void JAudioTrack::flush() {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jmethodID jFlush = env->GetMethodID(mAudioTrackCls, "flush", "()V");
+ env->CallVoidMethod(mAudioTrackObj, jFlush);
+}
+
+void JAudioTrack::pause() {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jmethodID jPause = env->GetMethodID(mAudioTrackCls, "pause", "()V");
+ env->CallVoidMethod(mAudioTrackObj, jPause);
+ // TODO: Should we catch IllegalStateException?
+}
+
+bool JAudioTrack::isPlaying() const {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jmethodID jGetPlayState = env->GetMethodID(mAudioTrackCls, "getPlayState", "()I");
+ int currentPlayState = env->CallIntMethod(mAudioTrackObj, jGetPlayState);
+
+ // TODO: In Java AudioTrack, there is no STOPPING state.
+ // This means while stopping, isPlaying() will return different value in two class.
+ // - in existing native AudioTrack: true
+ // - in JAudioTrack: false
+ // If not okay, also modify the implementation of stopped().
+ jfieldID jPlayStatePlaying = env->GetStaticFieldID(mAudioTrackCls, "PLAYSTATE_PLAYING", "I");
+ int statePlaying = env->GetStaticIntField(mAudioTrackCls, jPlayStatePlaying);
+ return currentPlayState == statePlaying;
+}
+
+uint32_t JAudioTrack::getSampleRate() {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jmethodID jGetSampleRate = env->GetMethodID(mAudioTrackCls, "getSampleRate", "()I");
+ return env->CallIntMethod(mAudioTrackObj, jGetSampleRate);
+}
+
+status_t JAudioTrack::getBufferDurationInUs(int64_t *duration) {
+ if (duration == nullptr) {
+ return BAD_VALUE;
+ }
+
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jmethodID jGetBufferSizeInFrames = env->GetMethodID(
+ mAudioTrackCls, "getBufferSizeInFrames", "()I");
+ int bufferSizeInFrames = env->CallIntMethod(mAudioTrackObj, jGetBufferSizeInFrames);
+
+ const double secondToMicro = 1000000LL; // 1E6
+ int sampleRate = JAudioTrack::getSampleRate();
+ float speed = JAudioTrack::getPlaybackRate().mSpeed;
+
+ *duration = (int64_t) (bufferSizeInFrames * secondToMicro / (sampleRate * speed));
+ return NO_ERROR;
+}
+
+audio_format_t JAudioTrack::format() {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jmethodID jGetAudioFormat = env->GetMethodID(mAudioTrackCls, "getAudioFormat", "()I");
+ int javaFormat = env->CallIntMethod(mAudioTrackObj, jGetAudioFormat);
+ return audioFormatToNative(javaFormat);
+}
+
+jobject JAudioTrack::createVolumeShaperConfigurationObj(
+ const sp<media::VolumeShaper::Configuration>& config) {
+
+ // TODO: Java VolumeShaper's setId() / setOptionFlags() are hidden.
+ if (config == NULL || config->getType() == media::VolumeShaper::Configuration::TYPE_ID) {
+ return NULL;
+ }
+
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+ // Referenced "android_media_VolumeShaper.h".
+ jfloatArray xarray = nullptr;
+ jfloatArray yarray = nullptr;
+ if (config->getType() == media::VolumeShaper::Configuration::TYPE_SCALE) {
+ // convert curve arrays
+ xarray = env->NewFloatArray(config->size());
+ yarray = env->NewFloatArray(config->size());
+ float * const x = env->GetFloatArrayElements(xarray, nullptr /* isCopy */);
+ float * const y = env->GetFloatArrayElements(yarray, nullptr /* isCopy */);
+ float *xptr = x, *yptr = y;
+ for (const auto &pt : *config.get()) {
+ *xptr++ = pt.first;
+ *yptr++ = pt.second;
+ }
+ env->ReleaseFloatArrayElements(xarray, x, 0 /* mode */);
+ env->ReleaseFloatArrayElements(yarray, y, 0 /* mode */);
+ }
+
+ jclass jBuilderCls = env->FindClass("android/media/VolumeShaper$Configuration$Builder");
+ jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
+ jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);
+
+ jmethodID jSetDuration = env->GetMethodID(jBuilderCls, "setDuration",
+ "(L)Landroid/media/VolumeShaper$Configuration$Builder;");
+ jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetDuration, (jlong) config->getDurationMs());
+
+ jmethodID jSetInterpolatorType = env->GetMethodID(jBuilderCls, "setInterpolatorType",
+ "(I)Landroid/media/VolumeShaper$Configuration$Builder;");
+ jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetInterpolatorType,
+ config->getInterpolatorType());
+
+ jmethodID jSetCurve = env->GetMethodID(jBuilderCls, "setCurve",
+ "([F[F)Landroid/media/VolumeShaper$Configuration$Builder;");
+ jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetCurve, xarray, yarray);
+
+ jmethodID jBuild = env->GetMethodID(jBuilderCls, "build",
+ "()Landroid/media/VolumeShaper$Configuration;");
+ return env->CallObjectMethod(jBuilderObj, jBuild);
+}
+
+jobject JAudioTrack::createVolumeShaperOperationObj(
+ const sp<media::VolumeShaper::Operation>& operation) {
+
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+ jclass jBuilderCls = env->FindClass("android/media/VolumeShaper$Operation$Builder");
+ jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
+ jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);
+
+ // Set XOffset
+ jmethodID jSetXOffset = env->GetMethodID(jBuilderCls, "setXOffset",
+ "(F)Landroid/media/VolumeShaper$Operation$Builder;");
+ jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetXOffset, operation->getXOffset());
+
+ int32_t flags = operation->getFlags();
+
+ if (operation->getReplaceId() >= 0) {
+ jmethodID jReplace = env->GetMethodID(jBuilderCls, "replace",
+ "(IB)Landroid/media/VolumeShaper$Operation$Builder;");
+ bool join = (flags | media::VolumeShaper::Operation::FLAG_JOIN) != 0;
+ jBuilderObj = env->CallObjectMethod(jBuilderCls, jReplace, operation->getReplaceId(), join);
+ }
+
+ if (flags | media::VolumeShaper::Operation::FLAG_REVERSE) {
+ jmethodID jReverse = env->GetMethodID(jBuilderCls, "reverse",
+ "()Landroid/media/VolumeShaper$Operation$Builder;");
+ jBuilderObj = env->CallObjectMethod(jBuilderCls, jReverse);
+ }
+
+ // TODO: VolumeShaper Javadoc says "Do not call terminate() directly". Can we call this?
+ if (flags | media::VolumeShaper::Operation::FLAG_TERMINATE) {
+ jmethodID jTerminate = env->GetMethodID(jBuilderCls, "terminate",
+ "()Landroid/media/VolumeShaper$Operation$Builder;");
+ jBuilderObj = env->CallObjectMethod(jBuilderCls, jTerminate);
+ }
+
+ if (flags | media::VolumeShaper::Operation::FLAG_DELAY) {
+ jmethodID jDefer = env->GetMethodID(jBuilderCls, "defer",
+ "()Landroid/media/VolumeShaper$Operation$Builder;");
+ jBuilderObj = env->CallObjectMethod(jBuilderCls, jDefer);
+ }
+
+ if (flags | media::VolumeShaper::Operation::FLAG_CREATE_IF_NECESSARY) {
+ jmethodID jCreateIfNeeded = env->GetMethodID(jBuilderCls, "createIfNeeded",
+ "()Landroid/media/VolumeShaper$Operation$Builder;");
+ jBuilderObj = env->CallObjectMethod(jBuilderCls, jCreateIfNeeded);
+ }
+
+ // TODO: Handle error case (can it be NULL?)
+ jmethodID jBuild = env->GetMethodID(jBuilderCls, "build",
+ "()Landroid/media/VolumeShaper$Operation;");
+ return env->CallObjectMethod(jBuilderObj, jBuild);
+}
+
+status_t JAudioTrack::javaToNativeStatus(int javaStatus) {
+ switch (javaStatus) {
+ case AUDIO_JAVA_SUCCESS:
+ return NO_ERROR;
+ case AUDIO_JAVA_BAD_VALUE:
+ return BAD_VALUE;
+ case AUDIO_JAVA_INVALID_OPERATION:
+ return INVALID_OPERATION;
+ case AUDIO_JAVA_PERMISSION_DENIED:
+ return PERMISSION_DENIED;
+ case AUDIO_JAVA_NO_INIT:
+ return NO_INIT;
+ case AUDIO_JAVA_WOULD_BLOCK:
+ return WOULD_BLOCK;
+ case AUDIO_JAVA_DEAD_OBJECT:
+ return DEAD_OBJECT;
+ default:
+ return UNKNOWN_ERROR;
+ }
+}
+
+} // namespace android
diff --git a/media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl b/media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl
new file mode 100644
index 0000000..57b1bc9
--- /dev/null
+++ b/media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+/**
+ * Service to reload extractor plugins when update package is installed/uninstalled.
+ * @hide
+ */
+interface IMediaExtractorUpdateService {
+ void loadPlugins(@utf8InCpp String apkPath);
+}
diff --git a/media/libmedia/include/media/JAudioAttributes.h b/media/libmedia/include/media/JAudioAttributes.h
new file mode 100644
index 0000000..fb11435
--- /dev/null
+++ b/media/libmedia/include/media/JAudioAttributes.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_JAUDIOATTRIBUTES_H
+#define ANDROID_JAUDIOATTRIBUTES_H
+
+#include <jni.h>
+#include <system/audio.h>
+
+namespace android {
+
+class JAudioAttributes {
+public:
+ /* Creates a Java AudioAttributes object. */
+ static jobject createAudioAttributesObj(JNIEnv *env,
+ const audio_attributes_t* pAttributes,
+ audio_stream_type_t streamType) {
+
+ jclass jBuilderCls = env->FindClass("android/media/AudioAttributes$Builder");
+ jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
+ jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);
+
+ if (pAttributes != NULL) {
+ // If pAttributes is not null, streamType is ignored.
+ jmethodID jSetUsage = env->GetMethodID(
+ jBuilderCls, "setUsage", "(I)Landroid/media/AudioAttributes$Builder;");
+ jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetUsage, pAttributes->usage);
+
+ jmethodID jSetContentType = env->GetMethodID(jBuilderCls, "setContentType",
+ "(I)Landroid/media/AudioAttributes$Builder;");
+ jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetContentType,
+ pAttributes->content_type);
+
+ // TODO: Java AudioAttributes.Builder.setCapturePreset() is systemApi and hidden.
+ // Can we use this method?
+// jmethodID jSetCapturePreset = env->GetMethodID(jBuilderCls, "setCapturePreset",
+// "(I)Landroid/media/AudioAttributes$Builder;");
+// jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetCapturePreset,
+// pAttributes->source);
+
+ jmethodID jSetFlags = env->GetMethodID(jBuilderCls, "setFlags",
+ "(I)Landroid/media/AudioAttributes$Builder;");
+ jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetFlags, pAttributes->flags);
+
+ // TODO: Handle the 'tags' (char[] to HashSet<String>).
+ // How to parse the char[]? Is there any example of it?
+ // Also, the addTags() method is hidden.
+ } else {
+ // Call AudioAttributes.Builder.setLegacyStreamType().build()
+ jmethodID jSetLegacyStreamType = env->GetMethodID(jBuilderCls, "setLegacyStreamType",
+ "(I)Landroid/media/AudioAttributes$Builder;");
+ jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetLegacyStreamType, streamType);
+ }
+
+ jmethodID jBuild = env->GetMethodID(jBuilderCls, "build",
+ "()Landroid/media/AudioAttributes;");
+ return env->CallObjectMethod(jBuilderObj, jBuild);
+ }
+
+};
+
+} // namespace android
+
+#endif // ANDROID_JAUDIOATTRIBUTES_H
diff --git a/media/libmedia/include/media/JAudioFormat.h b/media/libmedia/include/media/JAudioFormat.h
new file mode 100644
index 0000000..00abdff
--- /dev/null
+++ b/media/libmedia/include/media/JAudioFormat.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_JAUDIOFORMAT_H
+#define ANDROID_JAUDIOFORMAT_H
+
+#include <android_media_AudioFormat.h>
+#include <jni.h>
+
+namespace android {
+
+class JAudioFormat {
+public:
+ /* Creates a Java AudioFormat object. */
+ static jobject createAudioFormatObj(JNIEnv *env,
+ uint32_t sampleRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask) {
+
+ jclass jBuilderCls = env->FindClass("android/media/AudioFormat$Builder");
+ jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
+ jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);
+
+ if (sampleRate == 0) {
+ jclass jAudioFormatCls = env->FindClass("android/media/AudioFormat");
+ jfieldID jSampleRateUnspecified =
+ env->GetStaticFieldID(jAudioFormatCls, "SAMPLE_RATE_UNSPECIFIED", "I");
+ sampleRate = env->GetStaticIntField(jAudioFormatCls, jSampleRateUnspecified);
+ }
+
+ jmethodID jSetEncoding = env->GetMethodID(jBuilderCls, "setEncoding",
+ "(I)Landroid/media/AudioFormat$Builder;");
+ jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetEncoding,
+ audioFormatFromNative(format));
+
+ jmethodID jSetSampleRate = env->GetMethodID(jBuilderCls, "setSampleRate",
+ "(I)Landroid/media/AudioFormat$Builder;");
+ jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetSampleRate, sampleRate);
+
+ jmethodID jSetChannelMask = env->GetMethodID(jBuilderCls, "setChannelMask",
+ "(I)Landroid/media/AudioFormat$Builder;");
+ jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetChannelMask,
+ outChannelMaskFromNative(channelMask));
+
+ jmethodID jBuild = env->GetMethodID(jBuilderCls, "build", "()Landroid/media/AudioFormat;");
+ return env->CallObjectMethod(jBuilderObj, jBuild);
+ }
+
+};
+
+} // namespace android
+
+#endif // ANDROID_JAUDIOFORMAT_H
diff --git a/media/libmedia/include/media/JAudioTrack.h b/media/libmedia/include/media/JAudioTrack.h
new file mode 100644
index 0000000..8af30b7
--- /dev/null
+++ b/media/libmedia/include/media/JAudioTrack.h
@@ -0,0 +1,273 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_JAUDIOTRACK_H
+#define ANDROID_JAUDIOTRACK_H
+
+#include <jni.h>
+#include <media/AudioResamplerPublic.h>
+#include <media/VolumeShaper.h>
+#include <system/audio.h>
+#include <utils/Errors.h>
+
+#include <media/AudioTimestamp.h> // It has dependency on audio.h/Errors.h, but doesn't
+ // include them in it. Therefore it is included here at last.
+
+namespace android {
+
+class JAudioTrack {
+public:
+
+ /* Creates an JAudioTrack object for non-offload mode.
+ * Once created, the track needs to be started before it can be used.
+ * Unspecified values are set to appropriate default values.
+ *
+ * Parameters:
+ *
+ * streamType: Select the type of audio stream this track is attached to
+ * (e.g. AUDIO_STREAM_MUSIC).
+ * sampleRate: Data source sampling rate in Hz. Zero means to use the sink sample rate.
+ * A non-zero value must be specified if AUDIO_OUTPUT_FLAG_DIRECT is set.
+ * 0 will not work with current policy implementation for direct output
+ * selection where an exact match is needed for sampling rate.
+ * (TODO: Check direct output after flags can be used in Java AudioTrack.)
+ * format: Audio format. For mixed tracks, any PCM format supported by server is OK.
+ * For direct and offloaded tracks, the possible format(s) depends on the
+ * output sink.
+ * (TODO: How can we check whether a format is supported?)
+ * channelMask: Channel mask, such that audio_is_output_channel(channelMask) is true.
+ * frameCount: Minimum size of track PCM buffer in frames. This defines the
+ * application's contribution to the latency of the track.
+ * The actual size selected by the JAudioTrack could be larger if the
+ * requested size is not compatible with current audio HAL configuration.
+ * Zero means to use a default value.
+ * sessionId: Specific session ID, or zero to use default.
+ * pAttributes: If not NULL, supersedes streamType for use case selection.
+ * maxRequiredSpeed: For PCM tracks, this creates an appropriate buffer size that will allow
+ * maxRequiredSpeed playback. Values less than 1.0f and greater than
+ * AUDIO_TIMESTRETCH_SPEED_MAX will be clamped. For non-PCM tracks
+ * and direct or offloaded tracks, this parameter is ignored.
+ * (TODO: Handle this after offload / direct track is supported.)
+ *
+ * TODO: Revive removed arguments after offload mode is supported.
+ */
+ JAudioTrack(audio_stream_type_t streamType,
+ uint32_t sampleRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ size_t frameCount = 0,
+ audio_session_t sessionId = AUDIO_SESSION_ALLOCATE,
+ const audio_attributes_t* pAttributes = NULL,
+ float maxRequiredSpeed = 1.0f);
+
+ /*
+ Temporarily removed constructor arguments:
+
+ // Q. Values are in audio-base.h, but where can we find explanation for them?
+ audio_output_flags_t flags,
+
+ // Q. May be used in AudioTrack.setPreferredDevice(AudioDeviceInfo)?
+ audio_port_handle_t selectedDeviceId,
+
+ // Should be deleted, since we don't use Binder anymore.
+ bool doNotReconnect,
+
+ // Do we need UID and PID?
+ uid_t uid,
+ pid_t pid,
+
+ // TODO: Uses these values when Java AudioTrack supports the offload mode.
+ callback_t cbf,
+ void* user,
+ int32_t notificationFrames,
+ const audio_offload_info_t *offloadInfo,
+
+ // Fixed to false, but what is this?
+ threadCanCallJava
+ */
+
+ virtual ~JAudioTrack();
+
+ size_t frameCount();
+ size_t channelCount();
+
+ /* Return the total number of frames played since playback start.
+ * The counter will wrap (overflow) periodically, e.g. every ~27 hours at 44.1 kHz.
+ * It is reset to zero by flush(), reload(), and stop().
+ *
+ * Parameters:
+ *
+ * position: Address where to return play head position.
+ *
+ * Returned status (from utils/Errors.h) can be:
+ * - NO_ERROR: successful operation
+ * - BAD_VALUE: position is NULL
+ */
+ status_t getPosition(uint32_t *position);
+
+ // TODO: Does this comment apply same to Java AudioTrack::getTimestamp?
+ // Changed the return type from status_t to bool, since Java AudioTrack::getTimestamp returns
+ // boolean. Will Java getTimestampWithStatus() be public?
+ /* Poll for a timestamp on demand.
+ * Use if EVENT_NEW_TIMESTAMP is not delivered often enough for your needs,
+ * or if you need to get the most recent timestamp outside of the event callback handler.
+ * Caution: calling this method too often may be inefficient;
+ * if you need a high resolution mapping between frame position and presentation time,
+ * consider implementing that at application level, based on the low resolution timestamps.
+ * Returns true if timestamp is valid.
+ * The timestamp parameter is undefined on return, if false is returned.
+ */
+ bool getTimeStamp(AudioTimestamp& timestamp);
+
+ /* Set source playback rate for timestretch
+ * 1.0 is normal speed: < 1.0 is slower, > 1.0 is faster
+ * 1.0 is normal pitch: < 1.0 is lower pitch, > 1.0 is higher pitch
+ *
+ * AUDIO_TIMESTRETCH_SPEED_MIN <= speed <= AUDIO_TIMESTRETCH_SPEED_MAX
+ * AUDIO_TIMESTRETCH_PITCH_MIN <= pitch <= AUDIO_TIMESTRETCH_PITCH_MAX
+ *
+ * Speed increases the playback rate of media, but does not alter pitch.
+ * Pitch increases the "tonal frequency" of media, but does not affect the playback rate.
+ */
+ status_t setPlaybackRate(const AudioPlaybackRate &playbackRate);
+
+ /* Return current playback rate */
+ const AudioPlaybackRate getPlaybackRate();
+
+ /* Sets the volume shaper object */
+ media::VolumeShaper::Status applyVolumeShaper(
+ const sp<media::VolumeShaper::Configuration>& configuration,
+ const sp<media::VolumeShaper::Operation>& operation);
+
+ /* Set the send level for this track. An auxiliary effect should be attached
+ * to the track with attachEffect(). Level must be >= 0.0 and <= 1.0.
+ */
+ status_t setAuxEffectSendLevel(float level);
+
+ /* Attach track auxiliary output to specified effect. Use effectId = 0
+ * to detach track from effect.
+ *
+ * Parameters:
+ *
+ * effectId: effectId obtained from AudioEffect::id().
+ *
+ * Returned status (from utils/Errors.h) can be:
+ * - NO_ERROR: successful operation
+ * - INVALID_OPERATION: The effect is not an auxiliary effect.
+ * - BAD_VALUE: The specified effect ID is invalid.
+ */
+ status_t attachAuxEffect(int effectId);
+
+ /* Set volume for this track, mostly used for games' sound effects
+ * left and right volumes. Levels must be >= 0.0 and <= 1.0.
+ * This is the older API. New applications should use setVolume(float) when possible.
+ */
+ status_t setVolume(float left, float right);
+
+ /* Set volume for all channels. This is the preferred API for new applications,
+ * especially for multi-channel content.
+ */
+ status_t setVolume(float volume);
+
+ // TODO: Does this comment equally apply to the Java AudioTrack::play()?
+ /* After it's created the track is not active. Call start() to
+ * make it active. If set, the callback will start being called.
+ * If the track was previously paused, volume is ramped up over the first mix buffer.
+ */
+ status_t start();
+
+ // TODO: Does this comment still applies? It seems not. (obtainBuffer, AudioFlinger, ...)
+ /* As a convenience we provide a write() interface to the audio buffer.
+ * Input parameter 'size' is in byte units.
+ * This is implemented on top of obtainBuffer/releaseBuffer. For best
+ * performance use callbacks. Returns actual number of bytes written >= 0,
+ * or one of the following negative status codes:
+ * INVALID_OPERATION AudioTrack is configured for static buffer or streaming mode
+ * BAD_VALUE size is invalid
+ * WOULD_BLOCK when obtainBuffer() returns same, or
+ * AudioTrack was stopped during the write
+ * DEAD_OBJECT when AudioFlinger dies or the output device changes and
+ * the track cannot be automatically restored.
+ * The application needs to recreate the AudioTrack
+ * because the audio device changed or AudioFlinger died.
+ * This typically occurs for direct or offload tracks
+ * or if mDoNotReconnect is true.
+ * or any other error code returned by IAudioTrack::start() or restoreTrack_l().
+ * Default behavior is to only return when all data has been transferred. Set 'blocking' to
+ * false for the method to return immediately without waiting to try multiple times to write
+ * the full content of the buffer.
+ */
+ ssize_t write(const void* buffer, size_t size, bool blocking = true);
+
+ // TODO: Does this comment equally apply to the Java AudioTrack::stop()?
+ /* Stop a track.
+ * In static buffer mode, the track is stopped immediately.
+ * In streaming mode, the callback will cease being called. Note that obtainBuffer() still
+ * works and will fill up buffers until the pool is exhausted, and then will return WOULD_BLOCK.
+ * In streaming mode the stop does not occur immediately: any data remaining in the buffer
+ * is first drained, mixed, and output, and only then is the track marked as stopped.
+ */
+ void stop();
+ bool stopped() const;
+
+ // TODO: Does this comment equally apply to the Java AudioTrack::flush()?
+ /* Flush a stopped or paused track. All previously buffered data is discarded immediately.
+ * This has the effect of draining the buffers without mixing or output.
+ * Flush is intended for streaming mode, for example before switching to non-contiguous content.
+ * This function is a no-op if the track is not stopped or paused, or uses a static buffer.
+ */
+ void flush();
+
+ // TODO: Does this comment equally apply to the Java AudioTrack::pause()?
+ // At least we are not using obtainBuffer.
+ /* Pause a track. After pause, the callback will cease being called and
+ * obtainBuffer returns WOULD_BLOCK. Note that obtainBuffer() still works
+ * and will fill up buffers until the pool is exhausted.
+ * Volume is ramped down over the next mix buffer following the pause request,
+ * and then the track is marked as paused. It can be resumed with ramp up by start().
+ */
+ void pause();
+
+ bool isPlaying() const;
+
+ /* Return current source sample rate in Hz.
+ * If specified as zero in constructor, this will be the sink sample rate.
+ */
+ uint32_t getSampleRate();
+
+ /* Returns the buffer duration in microseconds at current playback rate. */
+ status_t getBufferDurationInUs(int64_t *duration);
+
+ audio_format_t format();
+
+private:
+ jclass mAudioTrackCls;
+ jobject mAudioTrackObj;
+
+ /* Creates a Java VolumeShaper.Configuration object from VolumeShaper::Configuration */
+ jobject createVolumeShaperConfigurationObj(
+ const sp<media::VolumeShaper::Configuration>& config);
+
+ /* Creates a Java VolumeShaper.Operation object from VolumeShaper::Operation */
+ jobject createVolumeShaperOperationObj(
+ const sp<media::VolumeShaper::Operation>& operation);
+
+ status_t javaToNativeStatus(int javaStatus);
+};
+
+}; // namespace android
+
+#endif // ANDROID_JAUDIOTRACK_H
diff --git a/media/libmediametrics/MediaAnalyticsItem.cpp b/media/libmediametrics/MediaAnalyticsItem.cpp
index 6b063e8..423dfb8 100644
--- a/media/libmediametrics/MediaAnalyticsItem.cpp
+++ b/media/libmediametrics/MediaAnalyticsItem.cpp
@@ -29,8 +29,6 @@
#include <utils/SortedVector.h>
#include <utils/threads.h>
-#include <media/stagefright/foundation/AString.h>
-
#include <binder/IServiceManager.h>
#include <media/IMediaAnalyticsService.h>
#include <media/MediaAnalyticsItem.h>
@@ -205,15 +203,11 @@
return mUid;
}
-MediaAnalyticsItem &MediaAnalyticsItem::setPkgName(AString pkgName) {
+MediaAnalyticsItem &MediaAnalyticsItem::setPkgName(const std::string &pkgName) {
mPkgName = pkgName;
return *this;
}
-AString MediaAnalyticsItem::getPkgName() const {
- return mPkgName;
-}
-
MediaAnalyticsItem &MediaAnalyticsItem::setPkgVersionCode(int64_t pkgVersionCode) {
mPkgVersionCode = pkgVersionCode;
return *this;
@@ -727,11 +721,11 @@
}
-AString MediaAnalyticsItem::toString() {
+std::string MediaAnalyticsItem::toString() {
return toString(-1);
}
-AString MediaAnalyticsItem::toString(int version) {
+std::string MediaAnalyticsItem::toString(int version) {
// v0 : released with 'o'
// v1 : bug fix (missing pid/finalized separator),
@@ -744,7 +738,7 @@
version = PROTO_LAST;
}
- AString result;
+ std::string result;
char buffer[512];
if (version == PROTO_V0) {
@@ -841,7 +835,7 @@
bool MediaAnalyticsItem::selfrecord(bool forcenew) {
if (DEBUG_API) {
- AString p = this->toString();
+ std::string p = this->toString();
ALOGD("selfrecord of: %s [forcenew=%d]", p.c_str(), forcenew);
}
@@ -850,13 +844,13 @@
if (svc != NULL) {
MediaAnalyticsItem::SessionID_t newid = svc->submit(this, forcenew);
if (newid == SessionIDInvalid) {
- AString p = this->toString();
+ std::string p = this->toString();
ALOGW("Failed to record: %s [forcenew=%d]", p.c_str(), forcenew);
return false;
}
return true;
} else {
- AString p = this->toString();
+ std::string p = this->toString();
ALOGW("Unable to record: %s [forcenew=%d]", p.c_str(), forcenew);
return false;
}
diff --git a/media/libmediametrics/include/MediaAnalyticsItem.h b/media/libmediametrics/include/MediaAnalyticsItem.h
index ec9b660..79ff093 100644
--- a/media/libmediametrics/include/MediaAnalyticsItem.h
+++ b/media/libmediametrics/include/MediaAnalyticsItem.h
@@ -18,6 +18,7 @@
#define ANDROID_MEDIA_MEDIAANALYTICSITEM_H
#include <cutils/properties.h>
+#include <string>
#include <sys/types.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
@@ -25,13 +26,10 @@
#include <utils/StrongPointer.h>
#include <utils/Timers.h>
-#include <media/stagefright/foundation/AString.h>
-
namespace android {
-
-
class IMediaAnalyticsService;
+class Parcel;
// the class interface
//
@@ -66,7 +64,7 @@
// values can be "component/component"
// basic values: "video", "audio", "drm"
// XXX: need to better define the format
- typedef AString Key;
+ typedef std::string Key;
static const Key kKeyNone; // ""
static const Key kKeyAny; // "*"
@@ -170,8 +168,8 @@
MediaAnalyticsItem &setUid(uid_t);
uid_t getUid() const;
- MediaAnalyticsItem &setPkgName(AString);
- AString getPkgName() const;
+ MediaAnalyticsItem &setPkgName(const std::string &pkgName);
+ std::string getPkgName() const { return mPkgName; }
MediaAnalyticsItem &setPkgVersionCode(int64_t);
int64_t getPkgVersionCode() const;
@@ -180,8 +178,8 @@
int32_t writeToParcel(Parcel *);
int32_t readFromParcel(const Parcel&);
- AString toString();
- AString toString(int version);
+ std::string toString();
+ std::string toString(int version);
// are we collecting analytics data
static bool isEnabled();
@@ -204,7 +202,7 @@
// to help validate that A doesn't mess with B's records
pid_t mPid;
uid_t mUid;
- AString mPkgName;
+ std::string mPkgName;
int64_t mPkgVersionCode;
// let's reuse a binder connection
diff --git a/media/libnblog/NBLog.cpp b/media/libnblog/NBLog.cpp
index c8c7195..d6fa3e3 100644
--- a/media/libnblog/NBLog.cpp
+++ b/media/libnblog/NBLog.cpp
@@ -259,7 +259,8 @@
*(int*) (buffer + sizeof(entry) + sizeof(HistTsEntry)) = author;
// Update lengths
buffer[offsetof(entry, length)] = sizeof(HistTsEntryWithAuthor);
- buffer[sizeof(buffer) + Entry::kPreviousLengthOffset] = sizeof(HistTsEntryWithAuthor);
+ buffer[offsetof(entry, data) + sizeof(HistTsEntryWithAuthor) + offsetof(ending, length)]
+ = sizeof(HistTsEntryWithAuthor);
// Write new buffer into FIFO
dst->write(buffer, sizeof(buffer));
return EntryIterator(mEntry).next();
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 484e310..e16db00 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -112,6 +112,7 @@
"libRScpp",
"libhidlbase",
"libhidlmemory",
+ "libziparchive",
"android.hidl.allocator@1.0",
"android.hardware.cas.native@1.0",
"android.hardware.media.omx@1.0",
@@ -211,6 +212,7 @@
"libmedia_helper",
"libstagefright_foundation",
"libdl",
+ "libziparchive",
],
static_libs: [
diff --git a/media/libstagefright/InterfaceUtils.cpp b/media/libstagefright/InterfaceUtils.cpp
index cf9fdf8..f174ba4 100644
--- a/media/libstagefright/InterfaceUtils.cpp
+++ b/media/libstagefright/InterfaceUtils.cpp
@@ -38,11 +38,12 @@
return RemoteDataSource::wrap(source);
}
-sp<IMediaExtractor> CreateIMediaExtractorFromMediaExtractor(const sp<MediaExtractor> &extractor) {
+sp<IMediaExtractor> CreateIMediaExtractorFromMediaExtractor(
+ const sp<MediaExtractor> &extractor, const sp<RefBase> &plugin) {
if (extractor == nullptr) {
return nullptr;
}
- return RemoteMediaExtractor::wrap(extractor);
+ return RemoteMediaExtractor::wrap(extractor, plugin);
}
sp<MediaSource> CreateMediaSourceFromIMediaSource(const sp<IMediaSource> &source) {
@@ -52,11 +53,12 @@
return new CallbackMediaSource(source);
}
-sp<IMediaSource> CreateIMediaSourceFromMediaSource(const sp<MediaSource> &source) {
+sp<IMediaSource> CreateIMediaSourceFromMediaSource(
+ const sp<MediaSource> &source, const sp<RefBase> &plugin) {
if (source == nullptr) {
return nullptr;
}
- return RemoteMediaSource::wrap(source);
+ return RemoteMediaSource::wrap(source, plugin);
}
} // namespace android
diff --git a/media/libstagefright/MediaExtractorFactory.cpp b/media/libstagefright/MediaExtractorFactory.cpp
index 8a90e93..a777663 100644
--- a/media/libstagefright/MediaExtractorFactory.cpp
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -15,7 +15,7 @@
*/
//#define LOG_NDEBUG 0
-#define LOG_TAG "MediaExtractor"
+#define LOG_TAG "MediaExtractorFactory"
#include <utils/Log.h>
#include <binder/IServiceManager.h>
@@ -31,12 +31,15 @@
#include <media/IMediaExtractorService.h>
#include <cutils/properties.h>
#include <utils/String8.h>
+#include <ziparchive/zip_archive.h>
#include <dirent.h>
#include <dlfcn.h>
namespace android {
+static const char *kSystemApkPath = "/system/app/MediaComponents/MediaComponents.apk";
+
// static
sp<IMediaExtractor> MediaExtractorFactory::Create(
const sp<DataSource> &source, const char *mime) {
@@ -45,8 +48,7 @@
if (!property_get_bool("media.stagefright.extractremote", true)) {
// local extractor
ALOGW("creating media extractor in calling process");
- sp<MediaExtractor> extractor = CreateFromService(source, mime);
- return CreateIMediaExtractorFromMediaExtractor(extractor);
+ return CreateFromService(source, mime);
} else {
// remote extractor
ALOGV("get service manager");
@@ -103,11 +105,12 @@
return Create(*out, mime);
}
-sp<MediaExtractor> MediaExtractorFactory::CreateFromService(
+sp<IMediaExtractor> MediaExtractorFactory::CreateFromService(
const sp<DataSource> &source, const char *mime) {
- ALOGV("MediaExtractorFactory::%s %s", __func__, mime);
- RegisterDefaultSniffers();
+ ALOGV("MediaExtractorFactory::CreateFromService %s", mime);
+
+ UpdateExtractors(nullptr);
// initialize source decryption if needed
source->DrmInitialization(nullptr /* mime */);
@@ -117,7 +120,8 @@
MediaExtractor::CreatorFunc creator = NULL;
String8 tmp;
float confidence;
- creator = sniff(source, &tmp, &confidence, &meta);
+ sp<ExtractorPlugin> plugin;
+ creator = sniff(source, &tmp, &confidence, &meta, plugin);
if (!creator) {
ALOGV("FAILED to autodetect media content.");
return NULL;
@@ -128,39 +132,64 @@
mime, confidence);
MediaExtractor *ret = creator(source, meta);
- return ret;
+ return CreateIMediaExtractorFromMediaExtractor(ret, plugin);
}
-Mutex MediaExtractorFactory::gSnifferMutex;
-List<MediaExtractor::ExtractorDef> MediaExtractorFactory::gSniffers;
-bool MediaExtractorFactory::gSniffersRegistered = false;
+//static
+void MediaExtractorFactory::LoadPlugins(const ::std::string& apkPath) {
+ // TODO: Verify apk path with package manager in extractor process.
+ ALOGV("Load plugins from: %s", apkPath.c_str());
+ UpdateExtractors(apkPath.empty() ? nullptr : apkPath.c_str());
+}
+
+struct ExtractorPlugin : public RefBase {
+ MediaExtractor::ExtractorDef def;
+ void *libHandle;
+ String8 libPath;
+
+ ExtractorPlugin(MediaExtractor::ExtractorDef definition, void *handle, String8 &path)
+ : def(definition), libHandle(handle), libPath(path) { }
+ ~ExtractorPlugin() {
+ if (libHandle != nullptr) {
+ ALOGV("closing handle for %s %d", libPath.c_str(), def.extractor_version);
+ dlclose(libHandle);
+ }
+ }
+};
+
+Mutex MediaExtractorFactory::gPluginMutex;
+std::shared_ptr<List<sp<ExtractorPlugin>>> MediaExtractorFactory::gPlugins;
+bool MediaExtractorFactory::gPluginsRegistered = false;
// static
MediaExtractor::CreatorFunc MediaExtractorFactory::sniff(
- const sp<DataSource> &source, String8 *mimeType, float *confidence, sp<AMessage> *meta) {
+ const sp<DataSource> &source, String8 *mimeType, float *confidence, sp<AMessage> *meta,
+ sp<ExtractorPlugin> &plugin) {
*mimeType = "";
*confidence = 0.0f;
meta->clear();
+ std::shared_ptr<List<sp<ExtractorPlugin>>> plugins;
{
- Mutex::Autolock autoLock(gSnifferMutex);
- if (!gSniffersRegistered) {
+ Mutex::Autolock autoLock(gPluginMutex);
+ if (!gPluginsRegistered) {
return NULL;
}
+ plugins = gPlugins;
}
MediaExtractor::CreatorFunc curCreator = NULL;
MediaExtractor::CreatorFunc bestCreator = NULL;
- for (List<MediaExtractor::ExtractorDef>::iterator it = gSniffers.begin();
- it != gSniffers.end(); ++it) {
+ for (auto it = plugins->begin(); it != plugins->end(); ++it) {
String8 newMimeType;
float newConfidence;
sp<AMessage> newMeta;
- if ((curCreator = (*it).sniff(source, &newMimeType, &newConfidence, &newMeta))) {
+ if ((curCreator = (*it)->def.sniff(source, &newMimeType, &newConfidence, &newMeta))) {
if (newConfidence > *confidence) {
*mimeType = newMimeType;
*confidence = newConfidence;
*meta = newMeta;
+ plugin = *it;
bestCreator = curCreator;
}
}
@@ -170,95 +199,112 @@
}
// static
-void MediaExtractorFactory::RegisterSniffer_l(const MediaExtractor::ExtractorDef &def) {
+void MediaExtractorFactory::RegisterExtractor(const sp<ExtractorPlugin> &plugin,
+ List<sp<ExtractorPlugin>> &pluginList) {
// sanity check check struct version, uuid, name
- if (def.def_version == 0 || def.def_version > MediaExtractor::EXTRACTORDEF_VERSION) {
- ALOGE("don't understand extractor format %u, ignoring.", def.def_version);
+ if (plugin->def.def_version == 0
+ || plugin->def.def_version > MediaExtractor::EXTRACTORDEF_VERSION) {
+ ALOGE("don't understand extractor format %u, ignoring.", plugin->def.def_version);
return;
}
- if (memcmp(&def.extractor_uuid, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0) {
+ if (memcmp(&plugin->def.extractor_uuid, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0) {
ALOGE("invalid UUID, ignoring");
return;
}
- if (def.extractor_name == NULL || strlen(def.extractor_name) == 0) {
+ if (plugin->def.extractor_name == NULL || strlen(plugin->def.extractor_name) == 0) {
ALOGE("extractors should have a name, ignoring");
return;
}
- for (List<MediaExtractor::ExtractorDef>::iterator it = gSniffers.begin();
- it != gSniffers.end(); ++it) {
- if (memcmp(&((*it).extractor_uuid), &def.extractor_uuid, 16) == 0) {
+ for (auto it = pluginList.begin(); it != pluginList.end(); ++it) {
+ if (memcmp(&((*it)->def.extractor_uuid), &plugin->def.extractor_uuid, 16) == 0) {
// there's already an extractor with the same uuid
- if ((*it).extractor_version < def.extractor_version) {
+ if ((*it)->def.extractor_version < plugin->def.extractor_version) {
// this one is newer, replace the old one
ALOGW("replacing extractor '%s' version %u with version %u",
- def.extractor_name,
- (*it).extractor_version,
- def.extractor_version);
- gSniffers.erase(it);
+ plugin->def.extractor_name,
+ (*it)->def.extractor_version,
+ plugin->def.extractor_version);
+ pluginList.erase(it);
break;
} else {
ALOGW("ignoring extractor '%s' version %u in favor of version %u",
- def.extractor_name,
- def.extractor_version,
- (*it).extractor_version);
+ plugin->def.extractor_name,
+ plugin->def.extractor_version,
+ (*it)->def.extractor_version);
return;
}
}
}
- ALOGV("registering extractor for %s", def.extractor_name);
- gSniffers.push_back(def);
+ ALOGV("registering extractor for %s", plugin->def.extractor_name);
+ pluginList.push_back(plugin);
}
-// static
-void MediaExtractorFactory::RegisterDefaultSniffers() {
- Mutex::Autolock autoLock(gSnifferMutex);
- if (gSniffersRegistered) {
- return;
- }
-
- auto registerExtractors = [](const char *libDirPath) -> void {
- DIR *libDir = opendir(libDirPath);
- if (libDir) {
- struct dirent* libEntry;
- while ((libEntry = readdir(libDir))) {
- String8 libPath = String8(libDirPath) + libEntry->d_name;
+//static
+void MediaExtractorFactory::RegisterExtractors(
+ const char *apkPath, List<sp<ExtractorPlugin>> &pluginList) {
+ ALOGV("search for plugins at %s", apkPath);
+ ZipArchiveHandle zipHandle;
+ int32_t ret = OpenArchive(apkPath, &zipHandle);
+ if (ret == 0) {
+ char abi[PROPERTY_VALUE_MAX];
+ property_get("ro.product.cpu.abi", abi, "arm64-v8a");
+ ZipString prefix(String8::format("lib/%s/", abi).c_str());
+ ZipString suffix("extractor.so");
+ void* cookie;
+ ret = StartIteration(zipHandle, &cookie, &prefix, &suffix);
+ if (ret == 0) {
+ ZipEntry entry;
+ ZipString name;
+ while (Next(cookie, &entry, &name) == 0) {
+ String8 libPath = String8(apkPath) + "!/" +
+ String8(reinterpret_cast<const char*>(name.name), name.name_length);
void *libHandle = dlopen(libPath.string(), RTLD_NOW | RTLD_LOCAL);
if (libHandle) {
- MediaExtractor::GetExtractorDef getsniffer =
- (MediaExtractor::GetExtractorDef) dlsym(libHandle, "GETEXTRACTORDEF");
- if (getsniffer) {
+ MediaExtractor::GetExtractorDef getDef =
+ (MediaExtractor::GetExtractorDef) dlsym(libHandle, "GETEXTRACTORDEF");
+ if (getDef) {
ALOGV("registering sniffer for %s", libPath.string());
- RegisterSniffer_l(getsniffer());
+ RegisterExtractor(
+ new ExtractorPlugin(getDef(), libHandle, libPath), pluginList);
} else {
ALOGW("%s does not contain sniffer", libPath.string());
dlclose(libHandle);
}
} else {
- ALOGW("couldn't dlopen(%s)", libPath.string());
+ ALOGW("couldn't dlopen(%s) %s", libPath.string(), strerror(errno));
}
}
-
- closedir(libDir);
+ EndIteration(cookie);
} else {
- ALOGE("couldn't opendir(%s)", libDirPath);
+ ALOGW("couldn't find plugins from %s, %d", apkPath, ret);
}
- };
-
- registerExtractors("/system/lib"
-#ifdef __LP64__
- "64"
-#endif
- "/extractors/");
-
- registerExtractors("/vendor/lib"
-#ifdef __LP64__
- "64"
-#endif
- "/extractors/");
-
- gSniffersRegistered = true;
+ CloseArchive(zipHandle);
+ } else {
+ ALOGW("couldn't open(%s) %d", apkPath, ret);
+ }
}
+// static
+void MediaExtractorFactory::UpdateExtractors(const char *newUpdateApkPath) {
+ Mutex::Autolock autoLock(gPluginMutex);
+ if (newUpdateApkPath != nullptr) {
+ gPluginsRegistered = false;
+ }
+ if (gPluginsRegistered) {
+ return;
+ }
+
+ std::shared_ptr<List<sp<ExtractorPlugin>>> newList(new List<sp<ExtractorPlugin>>());
+
+ RegisterExtractors(kSystemApkPath, *newList);
+
+ if (newUpdateApkPath != nullptr) {
+ RegisterExtractors(newUpdateApkPath, *newList);
+ }
+
+ gPlugins = newList;
+ gPluginsRegistered = true;
+}
} // namespace android
diff --git a/media/libstagefright/RemoteMediaExtractor.cpp b/media/libstagefright/RemoteMediaExtractor.cpp
index 2a16e16..12654d9 100644
--- a/media/libstagefright/RemoteMediaExtractor.cpp
+++ b/media/libstagefright/RemoteMediaExtractor.cpp
@@ -36,8 +36,10 @@
static const char *kExtractorTracks = "android.media.mediaextractor.ntrk";
static const char *kExtractorFormat = "android.media.mediaextractor.fmt";
-RemoteMediaExtractor::RemoteMediaExtractor(const sp<MediaExtractor> &extractor)
- :mExtractor(extractor) {
+RemoteMediaExtractor::RemoteMediaExtractor(
+ const sp<MediaExtractor> &extractor, const sp<RefBase> &plugin)
+ :mExtractor(extractor),
+ mExtractorPlugin(plugin) {
mAnalyticsItem = nullptr;
if (MEDIA_LOG) {
@@ -65,6 +67,8 @@
}
RemoteMediaExtractor::~RemoteMediaExtractor() {
+ mExtractor = nullptr;
+ mExtractorPlugin = nullptr;
// log the current record, provided it has some information worth recording
if (MEDIA_LOG) {
if (mAnalyticsItem != nullptr) {
@@ -86,7 +90,8 @@
sp<IMediaSource> RemoteMediaExtractor::getTrack(size_t index) {
sp<MediaSource> source = mExtractor->getTrack(index);
- return (source.get() == nullptr) ? nullptr : CreateIMediaSourceFromMediaSource(source);
+ return (source.get() == nullptr)
+ ? nullptr : CreateIMediaSourceFromMediaSource(source, mExtractorPlugin);
}
sp<MetaData> RemoteMediaExtractor::getTrackMetaData(size_t index, uint32_t flags) {
@@ -133,11 +138,12 @@
////////////////////////////////////////////////////////////////////////////////
// static
-sp<IMediaExtractor> RemoteMediaExtractor::wrap(const sp<MediaExtractor> &extractor) {
+sp<IMediaExtractor> RemoteMediaExtractor::wrap(
+ const sp<MediaExtractor> &extractor, const sp<RefBase> &plugin) {
if (extractor.get() == nullptr) {
return nullptr;
}
- return new RemoteMediaExtractor(extractor);
+ return new RemoteMediaExtractor(extractor, plugin);
}
} // namespace android
diff --git a/media/libstagefright/RemoteMediaSource.cpp b/media/libstagefright/RemoteMediaSource.cpp
index 866d163..d97329c 100644
--- a/media/libstagefright/RemoteMediaSource.cpp
+++ b/media/libstagefright/RemoteMediaSource.cpp
@@ -19,10 +19,14 @@
namespace android {
-RemoteMediaSource::RemoteMediaSource(const sp<MediaSource> &source)
- :mSource(source) {}
+RemoteMediaSource::RemoteMediaSource(const sp<MediaSource> &source, const sp<RefBase> &plugin)
+ :mSource(source),
+ mExtractorPlugin(plugin) {}
-RemoteMediaSource::~RemoteMediaSource() {}
+RemoteMediaSource::~RemoteMediaSource() {
+ mSource = nullptr;
+ mExtractorPlugin = nullptr;
+}
status_t RemoteMediaSource::start(MetaData *params) {
return mSource->start(params);
@@ -51,11 +55,11 @@
////////////////////////////////////////////////////////////////////////////////
// static
-sp<IMediaSource> RemoteMediaSource::wrap(const sp<MediaSource> &source) {
+sp<IMediaSource> RemoteMediaSource::wrap(const sp<MediaSource> &source, const sp<RefBase> &plugin) {
if (source.get() == nullptr) {
return nullptr;
}
- return new RemoteMediaSource(source);
+ return new RemoteMediaSource(source, plugin);
}
} // namespace android
diff --git a/media/libstagefright/include/media/stagefright/InterfaceUtils.h b/media/libstagefright/include/media/stagefright/InterfaceUtils.h
index 783f109..224c1f1 100644
--- a/media/libstagefright/include/media/stagefright/InterfaceUtils.h
+++ b/media/libstagefright/include/media/stagefright/InterfaceUtils.h
@@ -31,13 +31,15 @@
sp<IDataSource> CreateIDataSourceFromDataSource(const sp<DataSource> &source);
// Creates an IMediaExtractor wrapper to the given MediaExtractor.
-sp<IMediaExtractor> CreateIMediaExtractorFromMediaExtractor(const sp<MediaExtractor> &extractor);
+sp<IMediaExtractor> CreateIMediaExtractorFromMediaExtractor(
+ const sp<MediaExtractor> &extractor, const sp<RefBase> &plugin);
// Creates a MediaSource which wraps the given IMediaSource object.
sp<MediaSource> CreateMediaSourceFromIMediaSource(const sp<IMediaSource> &source);
// Creates an IMediaSource wrapper to the given MediaSource.
-sp<IMediaSource> CreateIMediaSourceFromMediaSource(const sp<MediaSource> &source);
+sp<IMediaSource> CreateIMediaSourceFromMediaSource(
+ const sp<MediaSource> &source, const sp<RefBase> &plugin);
} // namespace android
diff --git a/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
index f216ff8..7fddf80 100644
--- a/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
+++ b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
@@ -26,6 +26,7 @@
namespace android {
class DataSource;
+struct ExtractorPlugin;
class MediaExtractorFactory {
public:
@@ -37,20 +38,25 @@
// will be alsp returned with |out|.
static sp<IMediaExtractor> CreateFromFd(
int fd, int64_t offset, int64_t length, const char *mime, sp<DataSource> *out);
- static sp<MediaExtractor> CreateFromService(
+ static sp<IMediaExtractor> CreateFromService(
const sp<DataSource> &source, const char *mime = NULL);
+ static void LoadPlugins(const ::std::string& apkPath);
private:
- static Mutex gSnifferMutex;
- static List<MediaExtractor::ExtractorDef> gSniffers;
- static bool gSniffersRegistered;
+ static Mutex gPluginMutex;
+ static std::shared_ptr<List<sp<ExtractorPlugin>>> gPlugins;
+ static bool gPluginsRegistered;
- static void RegisterSniffer_l(const MediaExtractor::ExtractorDef &def);
+ static void RegisterExtractors(
+ const char *apkPath, List<sp<ExtractorPlugin>> &pluginList);
+ static void RegisterExtractor(
+ const sp<ExtractorPlugin> &plugin, List<sp<ExtractorPlugin>> &pluginList);
static MediaExtractor::CreatorFunc sniff(const sp<DataSource> &source,
- String8 *mimeType, float *confidence, sp<AMessage> *meta);
+ String8 *mimeType, float *confidence, sp<AMessage> *meta,
+ sp<ExtractorPlugin> &plugin);
- static void RegisterDefaultSniffers();
+ static void UpdateExtractors(const char *newUpdateApkPath);
};
} // namespace android
diff --git a/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h b/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
index 98b8b4d..2bd71ee 100644
--- a/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
@@ -27,7 +27,7 @@
// IMediaExtractor wrapper to the MediaExtractor.
class RemoteMediaExtractor : public BnMediaExtractor {
public:
- static sp<IMediaExtractor> wrap(const sp<MediaExtractor> &extractor);
+ static sp<IMediaExtractor> wrap(const sp<MediaExtractor> &extractor, const sp<RefBase> &plugin);
virtual ~RemoteMediaExtractor();
virtual size_t countTracks();
@@ -44,10 +44,11 @@
private:
sp<MediaExtractor> mExtractor;
+ sp<RefBase> mExtractorPlugin;
MediaAnalyticsItem *mAnalyticsItem;
- explicit RemoteMediaExtractor(const sp<MediaExtractor> &extractor);
+ explicit RemoteMediaExtractor(const sp<MediaExtractor> &extractor, const sp<RefBase> &plugin);
DISALLOW_EVIL_CONSTRUCTORS(RemoteMediaExtractor);
};
diff --git a/media/libstagefright/include/media/stagefright/RemoteMediaSource.h b/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
index 0a446a5..cb222cc 100644
--- a/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
+++ b/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
@@ -26,7 +26,7 @@
// IMediaSrouce wrapper to the MediaSource.
class RemoteMediaSource : public BnMediaSource {
public:
- static sp<IMediaSource> wrap(const sp<MediaSource> &source);
+ static sp<IMediaSource> wrap(const sp<MediaSource> &source, const sp<RefBase> &plugin);
virtual ~RemoteMediaSource();
virtual status_t start(MetaData *params = NULL);
virtual status_t stop();
@@ -39,8 +39,9 @@
private:
sp<MediaSource> mSource;
+ sp<RefBase> mExtractorPlugin;
- explicit RemoteMediaSource(const sp<MediaSource> &source);
+ explicit RemoteMediaSource(const sp<MediaSource> &source, const sp<RefBase> &plugin);
DISALLOW_EVIL_CONSTRUCTORS(RemoteMediaSource);
};
diff --git a/packages/MediaUpdate/Android.mk b/packages/MediaComponents/Android.mk
similarity index 63%
rename from packages/MediaUpdate/Android.mk
rename to packages/MediaComponents/Android.mk
index 4a71401..2fa4a82 100644
--- a/packages/MediaUpdate/Android.mk
+++ b/packages/MediaComponents/Android.mk
@@ -18,9 +18,8 @@
include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := MediaUpdate
+LOCAL_PACKAGE_NAME := MediaComponents
LOCAL_MODULE_OWNER := google
-LOCAL_PRIVILEGED_MODULE := true
# TODO: create a separate key for this package.
LOCAL_CERTIFICATE := platform
@@ -31,4 +30,23 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PROGUARD_FLAG_FILES := proguard.cfg
+LOCAL_MULTILIB := first
+
+# Embed native libraries in package, rather than installing to /system/lib*.
+# TODO: Find a right way to include libs in the apk. b/72066556
+LOCAL_MODULE_TAGS := samples
+
+# To embed native libraries in package, uncomment the lines below.
+LOCAL_JNI_SHARED_LIBRARIES := \
+ libaacextractor \
+ libamrextractor \
+ libflacextractor \
+ libmidiextractor \
+ libmkvextractor \
+ libmp3extractor \
+ libmp4extractor \
+ libmpeg2extractor \
+ liboggextractor \
+ libwavextractor \
+
include $(BUILD_PACKAGE)
diff --git a/packages/MediaUpdate/AndroidManifest.xml b/packages/MediaComponents/AndroidManifest.xml
similarity index 100%
rename from packages/MediaUpdate/AndroidManifest.xml
rename to packages/MediaComponents/AndroidManifest.xml
diff --git a/packages/MediaUpdate/proguard.cfg b/packages/MediaComponents/proguard.cfg
similarity index 100%
rename from packages/MediaUpdate/proguard.cfg
rename to packages/MediaComponents/proguard.cfg
diff --git a/packages/MediaUpdate/src/com/android/media/update/ApiFactory.java b/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
similarity index 70%
rename from packages/MediaUpdate/src/com/android/media/update/ApiFactory.java
rename to packages/MediaComponents/src/com/android/media/update/ApiFactory.java
index 1cdd177..abff13e 100644
--- a/packages/MediaUpdate/src/com/android/media/update/ApiFactory.java
+++ b/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
@@ -18,21 +18,21 @@
import android.content.Context;
import android.media.update.MediaController2Provider;
+import android.media.update.VideoView2Provider;
import android.media.update.StaticProvider;
import android.media.update.ViewProvider;
import android.widget.MediaController2;
+import android.widget.VideoView2;
import com.android.widget.MediaController2Impl;
+import com.android.widget.VideoView2Impl;
public class ApiFactory implements StaticProvider {
- private final Context mContext;
- public ApiFactory(Context context) {
- mContext = context;
- }
-
- public static Object initialize(Context context) throws ReflectiveOperationException {
- return new ApiFactory(context);
+ public static Object initialize(Context appContext, Context libContext)
+ throws ReflectiveOperationException {
+ ApiHelper.initialize(appContext, libContext);
+ return new ApiFactory();
}
@Override
@@ -40,4 +40,9 @@
MediaController2 instance, ViewProvider superProvider) {
return new MediaController2Impl(instance, superProvider);
}
+
+ @Override
+ public VideoView2Provider createVideoView2(VideoView2 instance, ViewProvider superProvider) {
+ return new VideoView2Impl(instance, superProvider);
+ }
}
diff --git a/packages/MediaComponents/src/com/android/media/update/ApiHelper.java b/packages/MediaComponents/src/com/android/media/update/ApiHelper.java
new file mode 100644
index 0000000..550da86
--- /dev/null
+++ b/packages/MediaComponents/src/com/android/media/update/ApiHelper.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.media.update;
+
+import android.content.Context;
+import android.content.res.Resources;
+
+public class ApiHelper {
+ private static ApiHelper sInstance;
+ private final Context mAppContext;
+ private final Resources mLibResources;
+ private final Resources.Theme mLibTheme;
+
+ public static ApiHelper getInstance() {
+ return sInstance;
+ }
+
+ static void initialize(Context appContext, Context libContext) {
+ if (sInstance == null) {
+ sInstance = new ApiHelper(appContext, libContext);
+ }
+ }
+
+ private ApiHelper(Context appContext, Context libContext) {
+ mAppContext = appContext;
+ mLibResources = libContext.getResources();
+ mLibTheme = libContext.getTheme();
+ }
+
+ public Resources getLibResources() {
+ return mLibResources;
+ }
+
+ public Resources.Theme getLibTheme() {
+ return mLibTheme;
+ }
+}
diff --git a/packages/MediaUpdate/src/com/android/widget/MediaController2Impl.java b/packages/MediaComponents/src/com/android/widget/MediaController2Impl.java
similarity index 100%
rename from packages/MediaUpdate/src/com/android/widget/MediaController2Impl.java
rename to packages/MediaComponents/src/com/android/widget/MediaController2Impl.java
diff --git a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
new file mode 100644
index 0000000..66b5ed5
--- /dev/null
+++ b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.widget;
+
+import android.graphics.Canvas;
+import android.media.AudioAttributes;
+import android.media.AudioFocusRequest;
+import android.media.MediaPlayer;
+import android.media.update.VideoView2Provider;
+import android.media.update.ViewProvider;
+import android.net.Uri;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.MediaController2;
+import android.widget.VideoView2;
+
+import java.util.Map;
+
+public class VideoView2Impl implements VideoView2Provider, VideoViewInterface.SurfaceListener {
+
+ private final VideoView2 mInstance;
+ private final ViewProvider mSuperProvider;
+
+ public VideoView2Impl(VideoView2 instance, ViewProvider superProvider) {
+ mInstance = instance;
+ mSuperProvider = superProvider;
+
+ // TODO: Implement
+ }
+
+ @Override
+ public void start_impl() {
+ // TODO: Implement
+ }
+
+ @Override
+ public void pause_impl() {
+ // TODO: Implement
+ }
+
+ @Override
+ public int getDuration_impl() {
+ // TODO: Implement
+ return -1;
+ }
+
+ @Override
+ public int getCurrentPosition_impl() {
+ // TODO: Implement
+ return 0;
+ }
+
+ @Override
+ public void seekTo_impl(int msec) {
+ // TODO: Implement
+ }
+
+ @Override
+ public boolean isPlaying_impl() {
+ // TODO: Implement
+ return false;
+ }
+
+ @Override
+ public int getBufferPercentage_impl() {
+ return -1;
+ }
+
+ @Override
+ public int getAudioSessionId_impl() {
+ // TODO: Implement
+ return 0;
+ }
+
+ @Override
+ public void showSubtitle_impl() {
+ // TODO: Implement
+ }
+
+ @Override
+ public void hideSubtitle_impl() {
+ // TODO: Implement
+ }
+
+ @Override
+ public void setAudioFocusRequest_impl(int focusGain) {
+ // TODO: Implement
+ }
+
+ @Override
+ public void setAudioAttributes_impl(AudioAttributes attributes) {
+ // TODO: Implement
+ }
+
+ @Override
+ public void setVideoPath_impl(String path) {
+ // TODO: Implement
+ }
+
+ @Override
+ public void setVideoURI_impl(Uri uri) {
+ // TODO: Implement
+ }
+
+ @Override
+ public void setVideoURI_impl(Uri uri, Map<String, String> headers) {
+ // TODO: Implement
+ }
+
+ @Override
+ public void setMediaController2_impl(MediaController2 controllerView) {
+ // TODO: Implement
+ }
+
+ @Override
+ public void setViewType_impl(int viewType) {
+ // TODO: Implement
+ }
+
+ @Override
+ public int getViewType_impl() {
+ // TODO: Implement
+ return -1;
+ }
+
+ @Override
+ public void stopPlayback_impl() {
+ // TODO: Implement
+ }
+
+ @Override
+ public void setOnPreparedListener_impl(MediaPlayer.OnPreparedListener l) {
+ // TODO: Implement
+ }
+
+ @Override
+ public void setOnCompletionListener_impl(MediaPlayer.OnCompletionListener l) {
+ // TODO: Implement
+ }
+
+ @Override
+ public void setOnErrorListener_impl(MediaPlayer.OnErrorListener l) {
+ // TODO: Implement
+ }
+
+ @Override
+ public void setOnInfoListener_impl(MediaPlayer.OnInfoListener l) {
+ // TODO: Implement
+ }
+
+ @Override
+ public void setOnViewTypeChangedListener_impl(VideoView2.OnViewTypeChangedListener l) {
+ // TODO: Implement
+ }
+
+ @Override
+ public void onAttachedToWindow_impl() {
+ mSuperProvider.onAttachedToWindow_impl();
+ // TODO: Implement
+ }
+
+ @Override
+ public void onDetachedFromWindow_impl() {
+ mSuperProvider.onDetachedFromWindow_impl();
+ // TODO: Implement
+ }
+
+ @Override
+ public void onLayout_impl(boolean changed, int left, int top, int right, int bottom) {
+ mSuperProvider.onLayout_impl(changed, left, top, right, bottom);
+ // TODO: Implement
+ }
+
+ @Override
+ public void draw_impl(Canvas canvas) {
+ mSuperProvider.draw_impl(canvas);
+ // TODO: Implement
+ }
+
+ @Override
+ public CharSequence getAccessibilityClassName_impl() {
+ // TODO: Implement
+ return null;
+ }
+
+ @Override
+ public boolean onTouchEvent_impl(MotionEvent ev) {
+ // TODO: Implement
+ return false;
+ }
+
+ @Override
+ public boolean onTrackballEvent_impl(MotionEvent ev) {
+ // TODO: Implement
+ return false;
+ }
+
+ @Override
+ public boolean onKeyDown_impl(int keyCode, KeyEvent event) {
+ // TODO: Implement
+ return false;
+ }
+
+ @Override
+ public void onFinishInflate_impl() {
+ // TODO: Implement
+ }
+
+ @Override
+ public boolean dispatchKeyEvent_impl(KeyEvent event) {
+ // TODO: Implement
+ return false;
+ }
+
+ @Override
+ public void setEnabled_impl(boolean enabled) {
+ // TODO: Implement
+ }
+
+ ///////////////////////////////////////////////////
+ // Implements VideoViewInterface.SurfaceListener
+ ///////////////////////////////////////////////////
+
+ @Override
+ public void onSurfaceCreated(View view, int width, int height) {
+ // TODO: Implement
+ }
+
+ @Override
+ public void onSurfaceDestroyed(View view) {
+ // TODO: Implement
+ }
+
+ @Override
+ public void onSurfaceChanged(View view, int width, int height) {
+ // TODO: Implement
+ }
+
+ @Override
+ public void onSurfaceTakeOverDone(VideoViewInterface view) {
+ // TODO: Implement
+ }
+}
diff --git a/packages/MediaComponents/src/com/android/widget/VideoViewInterface.java b/packages/MediaComponents/src/com/android/widget/VideoViewInterface.java
new file mode 100644
index 0000000..2a5eb94
--- /dev/null
+++ b/packages/MediaComponents/src/com/android/widget/VideoViewInterface.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.widget;
+
+import android.annotation.NonNull;
+import android.media.MediaPlayer;
+import android.view.View;
+
+interface VideoViewInterface {
+ /**
+ * Assigns the view's surface to the given MediaPlayer instance.
+ *
+ * @param mp MediaPlayer
+ * @return true if the surface is successfully assigned, false if not. It will fail to assign
+ * if any of MediaPlayer or surface is unavailable.
+ */
+ boolean assignSurfaceToMediaPlayer(MediaPlayer mp);
+ void setSurfaceListener(SurfaceListener l);
+ int getViewType();
+ void setMediaPlayer(MediaPlayer mp);
+
+ /**
+ * Takes over oldView. It means that the MediaPlayer will start rendering on this view.
+ * The visibility of oldView will be set as {@link View.GONE}. If the view doesn't have a
+ * MediaPlayer instance or its surface is not available, the actual execution is deferred until
+ * a MediaPlayer instance is set by {@link #setMediaPlayer} or its surface becomes available.
+ * {@link SurfaceListener.onSurfaceTakeOverDone} will be called when the actual execution is
+ * done.
+ *
+ * @param oldView The view that MediaPlayer is currently rendering on.
+ */
+ void takeOver(@NonNull VideoViewInterface oldView);
+
+ /**
+ * Indicates if the view's surface is available.
+ *
+ * @return true if the surface is available.
+ */
+ boolean hasAvailableSurface();
+
+ /**
+ * An instance of VideoViewInterface calls these surface notification methods accordingly if
+ * a listener has been registered via {@link #setSurfaceListener(SurfaceListener)}.
+ */
+ interface SurfaceListener {
+ void onSurfaceCreated(View view, int width, int height);
+ void onSurfaceDestroyed(View view);
+ void onSurfaceChanged(View view, int width, int height);
+ void onSurfaceTakeOverDone(VideoViewInterface view);
+ }
+}
diff --git a/services/mediaanalytics/MediaAnalyticsService.cpp b/services/mediaanalytics/MediaAnalyticsService.cpp
index 7f42b1b..2954b3b 100644
--- a/services/mediaanalytics/MediaAnalyticsService.cpp
+++ b/services/mediaanalytics/MediaAnalyticsService.cpp
@@ -389,7 +389,7 @@
nsecs_t ts_since = 0;
String16 helpOption("-help");
String16 onlyOption("-only");
- AString only;
+ std::string only;
int n = args.size();
for (int i = 0; i < n; i++) {
@@ -553,7 +553,7 @@
if (only != NULL && strcmp(only, (*it)->getKey()) != 0) {
ALOGV("Told to omit '%s'", (*it)->getKey());
}
- AString distilled = (*it)->dumpSummary(slot, only);
+ std::string distilled = (*it)->dumpSummary(slot, only);
result.append(distilled.c_str());
}
}
@@ -605,7 +605,7 @@
ALOGV("Omit '%s', it's not '%s'", (*it)->getKey().c_str(), only);
continue;
}
- AString entry = (*it)->toString(mDumpProto);
+ std::string entry = (*it)->toString(mDumpProto);
result.appendFormat("%5d: %s\n", slot, entry.c_str());
slot++;
}
@@ -746,7 +746,7 @@
}
}
-static AString allowedKeys[] =
+static std::string allowedKeys[] =
{
"codec",
"extractor"
@@ -760,7 +760,7 @@
// untrusted uids can only send us a limited set of keys
if (isTrusted == false) {
// restrict to a specific set of keys
- AString key = item->getKey();
+ std::string key = item->getKey();
size_t i;
for(i = 0; i < nAllowedKeys; i++) {
@@ -854,7 +854,7 @@
return setPkgInfo(item, uid, setName, setVersion);
}
} else {
- AString pkg;
+ std::string pkg;
std::string installer = "";
int64_t versionCode = 0;
@@ -896,7 +896,7 @@
}
// strip any leading "shared:" strings that came back
- if (pkg.startsWith("shared:")) {
+ if (pkg.compare(0, 7, "shared:") == 0) {
pkg.erase(0, 7);
}
diff --git a/services/mediaanalytics/MediaAnalyticsService.h b/services/mediaanalytics/MediaAnalyticsService.h
index fce7d08..1287835 100644
--- a/services/mediaanalytics/MediaAnalyticsService.h
+++ b/services/mediaanalytics/MediaAnalyticsService.h
@@ -136,8 +136,8 @@
// mapping uids to package names
struct UidToPkgMap {
uid_t uid;
- AString pkg;
- AString installer;
+ std::string pkg;
+ std::string installer;
int64_t versionCode;
nsecs_t expiration;
};
diff --git a/services/mediaanalytics/MetricsSummarizer.cpp b/services/mediaanalytics/MetricsSummarizer.cpp
index 93fe0ec..e7c26e3 100644
--- a/services/mediaanalytics/MetricsSummarizer.cpp
+++ b/services/mediaanalytics/MetricsSummarizer.cpp
@@ -19,6 +19,7 @@
#include <stdlib.h>
#include <stdint.h>
+#include <string>
#include <inttypes.h>
#include <utils/threads.h>
@@ -87,21 +88,21 @@
{
if (mKey == NULL)
return true;
- AString itemKey = item.getKey();
+ std::string itemKey = item.getKey();
if (strcmp(mKey, itemKey.c_str()) != 0) {
return false;
}
return true;
}
-AString MetricsSummarizer::dumpSummary(int &slot)
+std::string MetricsSummarizer::dumpSummary(int &slot)
{
return dumpSummary(slot, NULL);
}
-AString MetricsSummarizer::dumpSummary(int &slot, const char *only)
+std::string MetricsSummarizer::dumpSummary(int &slot, const char *only)
{
- AString value = "";
+ std::string value;
List<MediaAnalyticsItem *>::iterator it = mSummaries->begin();
if (it != mSummaries->end()) {
@@ -110,7 +111,7 @@
if (only != NULL && strcmp(only, (*it)->getKey().c_str()) != 0) {
continue;
}
- AString entry = (*it)->toString();
+ std::string entry = (*it)->toString();
snprintf(buf, sizeof(buf), "%5d: ", slot);
value.append(buf);
value.append(entry.c_str());
diff --git a/services/mediaanalytics/MetricsSummarizer.h b/services/mediaanalytics/MetricsSummarizer.h
index a9f0786..a16c7bc 100644
--- a/services/mediaanalytics/MetricsSummarizer.h
+++ b/services/mediaanalytics/MetricsSummarizer.h
@@ -18,10 +18,10 @@
#ifndef ANDROID_METRICSSUMMARIZER_H
#define ANDROID_METRICSSUMMARIZER_H
+#include <string>
#include <utils/threads.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
-#include <utils/String8.h>
#include <utils/List.h>
#include <media/IMediaAnalyticsService.h>
@@ -49,8 +49,8 @@
virtual void mergeRecord(MediaAnalyticsItem &have, MediaAnalyticsItem &incoming);
// dump the summarized records (for dumpsys)
- AString dumpSummary(int &slot);
- AString dumpSummary(int &slot, const char *only);
+ std::string dumpSummary(int &slot);
+ std::string dumpSummary(int &slot, const char *only);
void setIgnorables(const char **);
const char **getIgnorables();
diff --git a/services/mediaextractor/Android.mk b/services/mediaextractor/Android.mk
index cd086f9..4980316 100644
--- a/services/mediaextractor/Android.mk
+++ b/services/mediaextractor/Android.mk
@@ -2,8 +2,11 @@
# service library
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := MediaExtractorService.cpp
LOCAL_CFLAGS := -Wall -Werror
+LOCAL_SRC_FILES := \
+ MediaExtractorService.cpp \
+ MediaExtractorUpdateService.cpp \
+
LOCAL_SHARED_LIBRARIES := libmedia libstagefright libbinder libutils liblog
LOCAL_MODULE:= libmediaextractorservice
include $(BUILD_SHARED_LIBRARY)
@@ -18,16 +21,7 @@
# extractor libraries
LOCAL_REQUIRED_MODULES := \
- libaacextractor \
- libamrextractor \
- libflacextractor \
- libmidiextractor \
- libmkvextractor \
- libmp3extractor \
- libmp4extractor \
- libmpeg2extractor \
- liboggextractor \
- libwavextractor \
+ MediaComponents \
LOCAL_SRC_FILES := main_extractorservice.cpp
LOCAL_SHARED_LIBRARIES := libmedia libmediaextractorservice libbinder libutils \
diff --git a/services/mediaextractor/MediaExtractorService.cpp b/services/mediaextractor/MediaExtractorService.cpp
index f09d7cf..0dc1fce 100644
--- a/services/mediaextractor/MediaExtractorService.cpp
+++ b/services/mediaextractor/MediaExtractorService.cpp
@@ -36,16 +36,15 @@
sp<DataSource> localSource = CreateDataSourceFromIDataSource(remoteSource);
- sp<MediaExtractor> extractor = MediaExtractorFactory::CreateFromService(localSource, mime);
+ sp<IMediaExtractor> extractor = MediaExtractorFactory::CreateFromService(localSource, mime);
ALOGV("extractor service created %p (%s)",
extractor.get(),
extractor == nullptr ? "" : extractor->name());
if (extractor != nullptr) {
- sp<IMediaExtractor> ret = CreateIMediaExtractorFromMediaExtractor(extractor);
- registerMediaExtractor(ret, localSource, mime);
- return ret;
+ registerMediaExtractor(extractor, localSource, mime);
+ return extractor;
}
return nullptr;
}
diff --git a/services/mediaextractor/MediaExtractorUpdateService.cpp b/services/mediaextractor/MediaExtractorUpdateService.cpp
new file mode 100644
index 0000000..473a698
--- /dev/null
+++ b/services/mediaextractor/MediaExtractorUpdateService.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "MediaExtractorUpdateService"
+#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <media/stagefright/MediaExtractorFactory.h>
+
+#include "MediaExtractorUpdateService.h"
+
+namespace android {
+namespace media {
+
+binder::Status MediaExtractorUpdateService::loadPlugins(const ::std::string& apkPath) {
+ ALOGV("loadPlugins %s", apkPath.c_str());
+ MediaExtractorFactory::LoadPlugins(apkPath);
+ return binder::Status::ok();
+}
+
+} // namespace media
+} // namespace android
diff --git a/services/mediaextractor/MediaExtractorUpdateService.h b/services/mediaextractor/MediaExtractorUpdateService.h
new file mode 100644
index 0000000..4115f6d
--- /dev/null
+++ b/services/mediaextractor/MediaExtractorUpdateService.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_EXTRACTOR_UPDATE_SERVICE_H
+#define ANDROID_MEDIA_EXTRACTOR_UPDATE_SERVICE_H
+
+#include <binder/BinderService.h>
+#include <android/media/BnMediaExtractorUpdateService.h>
+
+namespace android {
+namespace media {
+
+class MediaExtractorUpdateService
+ : public BinderService<MediaExtractorUpdateService>, public BnMediaExtractorUpdateService
+{
+ friend class BinderService<MediaExtractorUpdateService>;
+public:
+ MediaExtractorUpdateService() : BnMediaExtractorUpdateService() { }
+ virtual ~MediaExtractorUpdateService() { }
+ static const char* getServiceName() { return "media.extractor.update"; }
+ binder::Status loadPlugins(const ::std::string& apkPath);
+};
+
+} // namespace media
+} // namespace android
+
+#endif // ANDROID_MEDIA_EXTRACTOR_UPDATE_SERVICE_H
diff --git a/services/mediaextractor/main_extractorservice.cpp b/services/mediaextractor/main_extractorservice.cpp
index 6a5320d..0dc5e29 100644
--- a/services/mediaextractor/main_extractorservice.cpp
+++ b/services/mediaextractor/main_extractorservice.cpp
@@ -30,6 +30,7 @@
// from LOCAL_C_INCLUDES
#include "IcuUtils.h"
#include "MediaExtractorService.h"
+#include "MediaExtractorUpdateService.h"
#include "MediaUtils.h"
#include "minijail.h"
@@ -63,6 +64,16 @@
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
MediaExtractorService::instantiate();
+
+ // TODO: Uncomment below once sepolicy change is landed.
+ /*
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.build.type", value, "unknown");
+ if (strcmp(value, "userdebug") == 0 || strcmp(value, "eng") == 0) {
+ media::MediaExtractorUpdateService::instantiate();
+ }
+ */
+
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index f917675..01e9c6f 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -55,11 +55,15 @@
result << " Direction: " << ((getDirection() == AAUDIO_DIRECTION_OUTPUT)
? "OUTPUT" : "INPUT") << "\n";
- result << " Sample Rate: " << getSampleRate() << "\n";
- result << " Frames Per Burst: " << mFramesPerBurst << "\n";
- result << " Reference Count: " << mOpenCount << "\n";
result << " Requested Device Id: " << mRequestedDeviceId << "\n";
result << " Device Id: " << getDeviceId() << "\n";
+ result << " Sample Rate: " << getSampleRate() << "\n";
+ result << " Channel Count: " << getSamplesPerFrame() << "\n";
+ result << " Frames Per Burst: " << mFramesPerBurst << "\n";
+ result << " Usage: " << getUsage() << "\n";
+ result << " ContentType: " << getContentType() << "\n";
+ result << " InputPreset: " << getInputPreset() << "\n";
+ result << " Reference Count: " << mOpenCount << "\n";
result << " Connected: " << mConnected.load() << "\n";
result << " Registered Streams:" << "\n";
result << AAudioServiceStreamShared::dumpHeader() << "\n";
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index a61994d..541be20 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -72,13 +72,6 @@
aaudio_result_t AAudioServiceEndpointMMAP::open(const aaudio::AAudioStreamRequest &request) {
aaudio_result_t result = AAUDIO_OK;
- const audio_attributes_t attributes = {
- .content_type = AUDIO_CONTENT_TYPE_MUSIC,
- .usage = AUDIO_USAGE_MEDIA,
- .source = AUDIO_SOURCE_VOICE_RECOGNITION,
- .flags = AUDIO_FLAG_LOW_LATENCY,
- .tags = ""
- };
audio_config_base_t config;
audio_port_handle_t deviceId;
@@ -87,6 +80,27 @@
copyFrom(request.getConstantConfiguration());
+ aaudio_direction_t direction = getDirection();
+
+ const audio_content_type_t contentType =
+ AAudioConvert_contentTypeToInternal(getContentType());
+ const audio_usage_t usage = (direction == AAUDIO_DIRECTION_OUTPUT)
+ ? AAudioConvert_usageToInternal(getUsage())
+ : AUDIO_USAGE_UNKNOWN;
+ const audio_source_t source = (direction == AAUDIO_DIRECTION_INPUT)
+ ? AAudioConvert_inputPresetToAudioSource(getInputPreset())
+ : AUDIO_SOURCE_DEFAULT;
+
+ const audio_attributes_t attributes = {
+ .content_type = contentType,
+ .usage = usage,
+ .source = source,
+ .flags = AUDIO_FLAG_LOW_LATENCY,
+ .tags = ""
+ };
+ ALOGV("open() MMAP attributes.usage = %d, content_type = %d, source = %d",
+ attributes.usage, attributes.content_type, attributes.source);
+
mMmapClient.clientUid = request.getUserId();
mMmapClient.clientPid = request.getProcessId();
mMmapClient.packageName.setTo(String16(""));
@@ -108,7 +122,6 @@
int32_t aaudioSamplesPerFrame = getSamplesPerFrame();
- aaudio_direction_t direction = getDirection();
if (direction == AAUDIO_DIRECTION_OUTPUT) {
config.channel_mask = (aaudioSamplesPerFrame == AAUDIO_UNSPECIFIED)
? AUDIO_CHANNEL_OUT_STEREO
diff --git a/services/oboeservice/AAudioServiceEndpointShared.cpp b/services/oboeservice/AAudioServiceEndpointShared.cpp
index 6af9e7e..2de537a 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.cpp
+++ b/services/oboeservice/AAudioServiceEndpointShared.cpp
@@ -60,18 +60,16 @@
aaudio_result_t result = AAUDIO_OK;
const AAudioStreamConfiguration &configuration = request.getConstantConfiguration();
+ copyFrom(configuration);
mRequestedDeviceId = configuration.getDeviceId();
- setDirection(configuration.getDirection());
AudioStreamBuilder builder;
+ builder.copyFrom(configuration);
+
builder.setSharingMode(AAUDIO_SHARING_MODE_EXCLUSIVE);
// Don't fall back to SHARED because that would cause recursion.
builder.setSharingModeMatchRequired(true);
- builder.setDeviceId(mRequestedDeviceId);
- builder.setFormat(configuration.getFormat());
- builder.setSampleRate(configuration.getSampleRate());
- builder.setSamplesPerFrame(configuration.getSamplesPerFrame());
- builder.setDirection(configuration.getDirection());
+
builder.setBufferCapacity(DEFAULT_BUFFER_CAPACITY);
result = mStreamInternal->open(builder);
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index 53d2860..864fc35 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -42,7 +42,7 @@
AAudioServiceStreamBase::AAudioServiceStreamBase(AAudioService &audioService)
: mUpMessageQueue(nullptr)
- , mTimestampThread()
+ , mTimestampThread("AATime")
, mAtomicTimestamp()
, mAudioService(audioService) {
mMmapClient.clientUid = -1;
diff --git a/services/oboeservice/AAudioThread.cpp b/services/oboeservice/AAudioThread.cpp
index fbb0da4..ed7895b 100644
--- a/services/oboeservice/AAudioThread.cpp
+++ b/services/oboeservice/AAudioThread.cpp
@@ -27,12 +27,26 @@
using namespace aaudio;
+std::atomic<uint32_t> AAudioThread::mNextThreadIndex{1};
-AAudioThread::AAudioThread()
- : mRunnable(nullptr)
- , mHasThread(false) {
+AAudioThread::AAudioThread(const char *prefix) {
+ setup(prefix);
+}
+
+AAudioThread::AAudioThread() {
+ 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));
+
+ // 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
+ // and to avoid hard-to-read large numbers.
+ index = index % 100000; // arbitrary
+ snprintf(mName, sizeof(mName), "%s_%u", prefix, index);
}
void AAudioThread::dispatch() {
@@ -64,6 +78,8 @@
ALOGE("start() - pthread_create() returned %d %s", err, strerror(err));
return AAudioConvert_androidToAAudioResult(-err);
} else {
+ int err = pthread_setname_np(mThread, mName);
+ ALOGW_IF((err != 0), "Could not set name of AAudioThread. err = %d", err);
mHasThread = true;
return AAUDIO_OK;
}
diff --git a/services/oboeservice/AAudioThread.h b/services/oboeservice/AAudioThread.h
index 02f1459..ffc9b7b 100644
--- a/services/oboeservice/AAudioThread.h
+++ b/services/oboeservice/AAudioThread.h
@@ -43,7 +43,9 @@
{
public:
AAudioThread();
- AAudioThread(Runnable *runnable);
+
+ AAudioThread(const char *prefix);
+
virtual ~AAudioThread() = default;
/**
@@ -66,10 +68,15 @@
void dispatch(); // called internally from 'C' thread wrapper
private:
- Runnable *mRunnable;
- bool mHasThread;
+
+ void setup(const char *prefix);
+
+ Runnable *mRunnable = nullptr;
+ bool mHasThread = false;
pthread_t mThread; // initialized in constructor
+ static std::atomic<uint32_t> mNextThreadIndex;
+ char mName[16]; // max length for a pthread_name
};
} /* namespace aaudio */