Merge "MediaControlView2: Add UX for ad mode"
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
index bf97db9..ec75896 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
@@ -210,16 +210,16 @@
std::string name(propertyName.c_str());
std::string value;
- if (name == "vendor") {
- value = "Google";
- } else if (name == "version") {
- value = "1.1";
- } else if (name == "description") {
- value = "ClearKey CDM";
- } else if (name == "algorithms") {
- value = "";
- } else if (name == "listenerTestSupport") {
- value = mStringProperties[name];
+ if (name == kVendorKey) {
+ value = mStringProperties[kVendorKey];
+ } else if (name == kVersionKey) {
+ value = mStringProperties[kVersionKey];
+ } else if (name == kPluginDescriptionKey) {
+ value = mStringProperties[kPluginDescriptionKey];
+ } else if (name == kAlgorithmsKey) {
+ value = mStringProperties[kAlgorithmsKey];
+ } else if (name == kListenerTestSupportKey) {
+ value = mStringProperties[kListenerTestSupportKey];
} else {
ALOGE("App requested unknown string property %s", name.c_str());
_hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, "");
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h b/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h
index 7731b14..d65b25c 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h
@@ -28,7 +28,7 @@
static const std::string kVendorKey("vendor");
static const std::string kVendorValue("Google");
static const std::string kVersionKey("version");
-static const std::string kVersionValue("1.0");
+static const std::string kVersionValue("1.1");
static const std::string kPluginDescriptionKey("description");
static const std::string kPluginDescriptionValue("ClearKey CDM");
static const std::string kAlgorithmsKey("algorithms");
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index f7ae7d7..28158e2 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -113,7 +113,7 @@
.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.
+ .flags = AUDIO_FLAG_NONE, // Different than the AUDIO_INPUT_FLAGS
.tags = ""
};
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index ee069ee..023e8af 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -22,6 +22,7 @@
#include <media/AudioTrack.h>
#include <aaudio/AAudio.h>
+#include <system/audio.h>
#include "utility/AudioClock.h"
#include "legacy/AudioStreamLegacy.h"
#include "legacy/AudioStreamTrack.h"
@@ -130,7 +131,7 @@
.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.
+ .flags = AUDIO_FLAG_NONE, // Different than the AUDIO_OUTPUT_FLAGS
.tags = ""
};
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 6b3a8f0..21d3fa6 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -91,11 +91,14 @@
{
// key for media statistics is defined in the header
// attrs for media statistics
- static constexpr char kAudioRecordChannelCount[] = "android.media.audiorecord.channels";
+ // NB: these are matched with public Java API constants defined
+ // in frameworks/base/media/java/android/media/AudioRecord.java
+ // These must be kept synchronized with the constants there.
static constexpr char kAudioRecordEncoding[] = "android.media.audiorecord.encoding";
+ static constexpr char kAudioRecordSource[] = "android.media.audiorecord.source";
static constexpr char kAudioRecordLatency[] = "android.media.audiorecord.latency";
static constexpr char kAudioRecordSampleRate[] = "android.media.audiorecord.samplerate";
- static constexpr char kAudioRecordSource[] = "android.media.audiotrack.source";
+ static constexpr char kAudioRecordChannelCount[] = "android.media.audiorecord.channels";
// constructor guarantees mAnalyticsItem is valid
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 9dfb514..1c4a80e 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -904,6 +904,7 @@
audio_session_t session,
pid_t pid,
uid_t uid,
+ const String16& opPackageName,
const audio_config_base_t *config,
audio_input_flags_t flags,
audio_port_handle_t *selectedDeviceId,
@@ -912,35 +913,29 @@
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return NO_INIT;
return aps->getInputForAttr(
- attr, input, session, pid, uid,
+ attr, input, session, pid, uid, opPackageName,
config, flags, selectedDeviceId, portId);
}
-status_t AudioSystem::startInput(audio_io_handle_t input,
- audio_session_t session,
- audio_devices_t device,
- uid_t uid,
- bool *silenced)
+status_t AudioSystem::startInput(audio_port_handle_t portId, bool *silenced)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return PERMISSION_DENIED;
- return aps->startInput(input, session, device, uid, silenced);
+ return aps->startInput(portId, silenced);
}
-status_t AudioSystem::stopInput(audio_io_handle_t input,
- audio_session_t session)
+status_t AudioSystem::stopInput(audio_port_handle_t portId)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return PERMISSION_DENIED;
- return aps->stopInput(input, session);
+ return aps->stopInput(portId);
}
-void AudioSystem::releaseInput(audio_io_handle_t input,
- audio_session_t session)
+void AudioSystem::releaseInput(audio_port_handle_t portId)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return;
- aps->releaseInput(input, session);
+ aps->releaseInput(portId);
}
status_t AudioSystem::initStreamVolume(audio_stream_type_t stream,
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 55954f2..50c1295 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -56,8 +56,6 @@
return x > y ? x : y;
}
-static const int32_t NANOS_PER_SECOND = 1000000000;
-
static inline nsecs_t framesToNanoseconds(ssize_t frames, uint32_t sampleRate, float speed)
{
return ((double)frames * 1000000000) / ((double)sampleRate * speed);
@@ -185,11 +183,16 @@
// key for media statistics is defined in the header
// attrs for media statistics
+ // NB: these are matched with public Java API constants defined
+ // in frameworks/base/media/java/android/media/AudioTrack.java
+ // These must be kept synchronized with the constants there.
static constexpr char kAudioTrackStreamType[] = "android.media.audiotrack.streamtype";
static constexpr char kAudioTrackContentType[] = "android.media.audiotrack.type";
static constexpr char kAudioTrackUsage[] = "android.media.audiotrack.usage";
static constexpr char kAudioTrackSampleRate[] = "android.media.audiotrack.samplerate";
static constexpr char kAudioTrackChannelMask[] = "android.media.audiotrack.channelmask";
+
+ // NB: These are not yet exposed as public Java API constants.
static constexpr char kAudioTrackUnderrunFrames[] = "android.media.audiotrack.underrunframes";
static constexpr char kAudioTrackStartupGlitch[] = "android.media.audiotrack.glitch.startup";
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index a24a099..8f5ff30 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -285,6 +285,7 @@
audio_session_t session,
pid_t pid,
uid_t uid,
+ const String16& opPackageName,
const audio_config_base_t *config,
audio_input_flags_t flags,
audio_port_handle_t *selectedDeviceId,
@@ -313,6 +314,7 @@
data.writeInt32(session);
data.writeInt32(pid);
data.writeInt32(uid);
+ data.writeString16(opPackageName);
data.write(config, sizeof(audio_config_base_t));
data.writeInt32(flags);
data.writeInt32(*selectedDeviceId);
@@ -331,18 +333,12 @@
return NO_ERROR;
}
- virtual status_t startInput(audio_io_handle_t input,
- audio_session_t session,
- audio_devices_t device,
- uid_t uid,
+ virtual status_t startInput(audio_port_handle_t portId,
bool *silenced)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
- data.writeInt32(input);
- data.writeInt32(session);
- data.writeInt32(device);
- data.writeInt32(uid);
+ data.writeInt32(portId);
data.writeInt32(*silenced ? 1 : 0);
remote()->transact(START_INPUT, data, &reply);
status_t status = static_cast <status_t> (reply.readInt32());
@@ -350,24 +346,20 @@
return status;
}
- virtual status_t stopInput(audio_io_handle_t input,
- audio_session_t session)
+ virtual status_t stopInput(audio_port_handle_t portId)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
- data.writeInt32(input);
- data.writeInt32(session);
+ data.writeInt32(portId);
remote()->transact(STOP_INPUT, data, &reply);
return static_cast <status_t> (reply.readInt32());
}
- virtual void releaseInput(audio_io_handle_t input,
- audio_session_t session)
+ virtual void releaseInput(audio_port_handle_t portId)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
- data.writeInt32(input);
- data.writeInt32(session);
+ data.writeInt32(portId);
remote()->transact(RELEASE_INPUT, data, &reply);
}
@@ -1055,6 +1047,7 @@
audio_session_t session = (audio_session_t)data.readInt32();
pid_t pid = (pid_t)data.readInt32();
uid_t uid = (uid_t)data.readInt32();
+ const String16 opPackageName = data.readString16();
audio_config_base_t config;
memset(&config, 0, sizeof(audio_config_base_t));
data.read(&config, sizeof(audio_config_base_t));
@@ -1062,7 +1055,7 @@
audio_port_handle_t selectedDeviceId = (audio_port_handle_t) data.readInt32();
audio_port_handle_t portId = (audio_port_handle_t)data.readInt32();
status_t status = getInputForAttr(&attr, &input, session, pid, uid,
- &config,
+ opPackageName, &config,
flags, &selectedDeviceId, &portId);
reply->writeInt32(status);
if (status == NO_ERROR) {
@@ -1075,12 +1068,9 @@
case START_INPUT: {
CHECK_INTERFACE(IAudioPolicyService, data, reply);
- audio_io_handle_t input = static_cast <audio_io_handle_t>(data.readInt32());
- audio_session_t session = static_cast <audio_session_t>(data.readInt32());
- audio_devices_t device = static_cast <audio_devices_t>(data.readInt32());
- uid_t uid = static_cast <uid_t>(data.readInt32());
+ audio_port_handle_t portId = static_cast <audio_port_handle_t>(data.readInt32());
bool silenced = data.readInt32() == 1;
- status_t status = startInput(input, session, device, uid, &silenced);
+ status_t status = startInput(portId, &silenced);
reply->writeInt32(static_cast <uint32_t>(status));
reply->writeInt32(silenced ? 1 : 0);
return NO_ERROR;
@@ -1088,17 +1078,15 @@
case STOP_INPUT: {
CHECK_INTERFACE(IAudioPolicyService, data, reply);
- audio_io_handle_t input = static_cast <audio_io_handle_t>(data.readInt32());
- audio_session_t session = static_cast <audio_session_t>(data.readInt32());
- reply->writeInt32(static_cast <uint32_t>(stopInput(input, session)));
+ audio_port_handle_t portId = static_cast <audio_port_handle_t>(data.readInt32());
+ reply->writeInt32(static_cast <uint32_t>(stopInput(portId)));
return NO_ERROR;
} break;
case RELEASE_INPUT: {
CHECK_INTERFACE(IAudioPolicyService, data, reply);
- audio_io_handle_t input = static_cast <audio_io_handle_t>(data.readInt32());
- audio_session_t session = static_cast <audio_session_t>(data.readInt32());
- releaseInput(input, session);
+ audio_port_handle_t portId = static_cast <audio_port_handle_t>(data.readInt32());
+ releaseInput(portId);
return NO_ERROR;
} break;
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 3c8e7bc..22b700d 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -241,20 +241,16 @@
audio_session_t session,
pid_t pid,
uid_t uid,
+ const String16& opPackageName,
const audio_config_base_t *config,
audio_input_flags_t flags,
audio_port_handle_t *selectedDeviceId,
audio_port_handle_t *portId);
- static status_t startInput(audio_io_handle_t input,
- audio_session_t session,
- audio_devices_t device,
- uid_t uid,
+ static status_t startInput(audio_port_handle_t portId,
bool *silenced);
- static status_t stopInput(audio_io_handle_t input,
- audio_session_t session);
- static void releaseInput(audio_io_handle_t input,
- audio_session_t session);
+ static status_t stopInput(audio_port_handle_t portId);
+ static void releaseInput(audio_port_handle_t portId);
static status_t initStreamVolume(audio_stream_type_t stream,
int indexMin,
int indexMax);
diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h
index 5338927..949d593 100644
--- a/media/libaudioclient/include/media/IAudioPolicyService.h
+++ b/media/libaudioclient/include/media/IAudioPolicyService.h
@@ -80,19 +80,15 @@
audio_session_t session,
pid_t pid,
uid_t uid,
+ const String16& opPackageName,
const audio_config_base_t *config,
audio_input_flags_t flags,
audio_port_handle_t *selectedDeviceId,
audio_port_handle_t *portId) = 0;
- virtual status_t startInput(audio_io_handle_t input,
- audio_session_t session,
- audio_devices_t device,
- uid_t uid,
+ virtual status_t startInput(audio_port_handle_t portId,
bool *silenced) = 0;
- virtual status_t stopInput(audio_io_handle_t input,
- audio_session_t session) = 0;
- virtual void releaseInput(audio_io_handle_t input,
- audio_session_t session) = 0;
+ virtual status_t stopInput(audio_port_handle_t portId) = 0;
+ virtual void releaseInput(audio_port_handle_t portId) = 0;
virtual status_t initStreamVolume(audio_stream_type_t stream,
int indexMin,
int indexMax) = 0;
diff --git a/media/libmediaplayer2/MediaPlayer2Manager.cpp b/media/libmediaplayer2/MediaPlayer2Manager.cpp
index c642d89..44df2ac 100644
--- a/media/libmediaplayer2/MediaPlayer2Manager.cpp
+++ b/media/libmediaplayer2/MediaPlayer2Manager.cpp
@@ -512,7 +512,7 @@
}
bool MediaPlayer2Manager::Client::init() {
- sp<MediaPlayer2Interface> p = new NuPlayer2Driver(mPid);
+ sp<MediaPlayer2Interface> p = new NuPlayer2Driver(mPid, mUid);
status_t init_result = p->initCheck();
if (init_result != NO_ERROR) {
ALOGE("Failed to create player object, initCheck failed(%d)", init_result);
@@ -520,7 +520,6 @@
}
p->setNotifyCallback(this, notify);
- p->setUID(mUid);
mAudioDeviceUpdatedListener = new AudioDeviceUpdatedNotifier(p);
mAudioOutput = new AudioOutput(mAudioSessionId, mUid,
mPid, mAudioAttributes, mAudioDeviceUpdatedListener);
@@ -581,7 +580,7 @@
audio_port_handle_t deviceId) {
sp<MediaPlayer2Interface> listener = mListener.promote();
if (listener != NULL) {
- listener->sendEvent(MEDIA2_AUDIO_ROUTING_CHANGED, audioIo, deviceId);
+ listener->sendEvent(0, MEDIA2_AUDIO_ROUTING_CHANGED, audioIo, deviceId);
} else {
ALOGW("listener for process %d death is gone", MEDIA2_AUDIO_ROUTING_CHANGED);
}
@@ -1032,7 +1031,8 @@
}
void MediaPlayer2Manager::Client::notify(
- const wp<MediaPlayer2Engine> &listener, int msg, int ext1, int ext2, const Parcel *obj)
+ const wp<MediaPlayer2Engine> &listener, int64_t srcId,
+ int msg, int ext1, int ext2, const Parcel *obj)
{
sp<MediaPlayer2Engine> spListener = listener.promote();
if (spListener == NULL) {
@@ -1064,9 +1064,9 @@
}
if (nc != NULL) {
if (errStartNext == NO_ERROR) {
- nc->notify(MEDIA2_INFO, MEDIA2_INFO_STARTED_AS_NEXT, 0, obj);
+ nc->notify(srcId, MEDIA2_INFO, MEDIA2_INFO_STARTED_AS_NEXT, 0, obj);
} else {
- nc->notify(MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN , 0, obj);
+ nc->notify(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN , 0, obj);
ALOGE("gapless:start playback for next track failed, err(%d)", errStartNext);
}
}
@@ -1086,8 +1086,9 @@
}
if (c != NULL) {
- ALOGV("[%d] notify (%p, %d, %d, %d)", client->mConnId, spListener.get(), msg, ext1, ext2);
- c->notify(msg, ext1, ext2, obj);
+ ALOGV("[%d] notify (%p, %lld, %d, %d, %d)", client->mConnId, spListener.get(),
+ (long long)srcId, msg, ext1, ext2);
+ c->notify(srcId, msg, ext1, ext2, obj);
}
}
diff --git a/media/libmediaplayer2/MediaPlayer2Manager.h b/media/libmediaplayer2/MediaPlayer2Manager.h
index fde1381..7e6f0de 100644
--- a/media/libmediaplayer2/MediaPlayer2Manager.h
+++ b/media/libmediaplayer2/MediaPlayer2Manager.h
@@ -276,8 +276,8 @@
virtual status_t setDataSource(const sp<DataSourceDesc> &dsd);
- static void notify(const wp<MediaPlayer2Engine> &listener, int msg,
- int ext1, int ext2, const Parcel *obj);
+ static void notify(const wp<MediaPlayer2Engine> &listener, int64_t srcId,
+ int msg, int ext1, int ext2, const Parcel *obj);
pid_t pid() const { return mPid; }
virtual status_t dump(int fd, const Vector<String16>& args);
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2EngineClient.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2EngineClient.h
index 22df095..0b066aa 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2EngineClient.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2EngineClient.h
@@ -25,7 +25,7 @@
class MediaPlayer2EngineClient: public RefBase
{
public:
- virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) = 0;
+ virtual void notify(int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj) = 0;
};
}; // namespace android
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
index bee5175..b1cdf96 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
@@ -64,7 +64,7 @@
public:
// callback mechanism for passing messages to MediaPlayer2 object
typedef void (*NotifyCallback)(const wp<MediaPlayer2Engine> &listener,
- int msg, int ext1, int ext2, const Parcel *obj);
+ int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj);
// AudioSink: abstraction layer for audio output
class AudioSink : public RefBase {
@@ -148,10 +148,6 @@
virtual ~MediaPlayer2Interface() { }
virtual status_t initCheck() = 0;
- virtual status_t setUID(uid_t /* uid */) {
- return INVALID_OPERATION;
- }
-
virtual void setAudioSink(const sp<AudioSink>& audioSink) { mAudioSink = audioSink; }
virtual status_t setDataSource(const sp<DataSourceDesc>& /* dsd */) {
@@ -244,7 +240,7 @@
mClient = client; mNotify = notifyFunc;
}
- void sendEvent(int msg, int ext1=0, int ext2=0,
+ void sendEvent(int64_t srcId, int msg, int ext1=0, int ext2=0,
const Parcel *obj=NULL) {
NotifyCallback notifyCB;
wp<MediaPlayer2Engine> client;
@@ -254,7 +250,7 @@
client = mClient;
}
- if (notifyCB) notifyCB(client, msg, ext1, ext2, obj);
+ if (notifyCB) notifyCB(client, srcId, msg, ext1, ext2, obj);
}
virtual status_t dump(int /* fd */, const Vector<String16>& /* args */) const {
diff --git a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
index 35186ed..e9d6f84 100644
--- a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
+++ b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
@@ -83,10 +83,11 @@
// 0xx
MEDIA2_ERROR_UNKNOWN = 1,
// 1xx
- MEDIA2_ERROR_SERVER_DIED = 100,
+ // MEDIA2_ERROR_SERVER_DIED = 100,
// 2xx
MEDIA2_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200,
// 3xx
+ MEDIA2_ERROR_FAILED_TO_SET_DATA_SOURCE = 300,
};
@@ -193,7 +194,7 @@
class MediaPlayer2Listener: virtual public RefBase
{
public:
- virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) = 0;
+ virtual void notify(int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj) = 0;
};
class MediaPlayer2 : public MediaPlayer2EngineClient
@@ -203,6 +204,7 @@
~MediaPlayer2();
void disconnect();
+ status_t getSrcId(int64_t *srcId);
status_t setDataSource(const sp<DataSourceDesc> &dsd);
status_t setVideoSurfaceTexture(const sp<ANativeWindowWrapper>& nww);
status_t setListener(const sp<MediaPlayer2Listener>& listener);
@@ -234,7 +236,8 @@
status_t setLooping(int loop);
bool isLooping();
status_t setVolume(float leftVolume, float rightVolume);
- void notify(int msg, int ext1, int ext2, const Parcel *obj = NULL);
+ void notify(int64_t srcId, int msg, int ext1, int ext2,
+ const Parcel *obj = NULL);
status_t invoke(const Parcel& request, Parcel *reply);
status_t setMetadataFilter(const Parcel& filter);
status_t getMetadata(bool update_only, bool apply_filter, Parcel *metadata);
@@ -259,11 +262,12 @@
status_t seekTo_l(int msec, MediaPlayer2SeekMode mode);
status_t prepareAsync_l();
status_t getDuration_l(int *msec);
- status_t attachNewPlayer(const sp<MediaPlayer2Engine>& player);
+ status_t attachNewPlayer(const sp<MediaPlayer2Engine>& player, long srcId);
status_t reset_l();
status_t checkStateForKeySet_l(int key);
sp<MediaPlayer2Engine> mPlayer;
+ int64_t mSrcId;
thread_id_t mLockThreadId;
Mutex mLock;
Mutex mNotifyLock;
diff --git a/media/libmediaplayer2/mediaplayer2.cpp b/media/libmediaplayer2/mediaplayer2.cpp
index b858783..ab30273 100644
--- a/media/libmediaplayer2/mediaplayer2.cpp
+++ b/media/libmediaplayer2/mediaplayer2.cpp
@@ -53,6 +53,7 @@
MediaPlayer2::MediaPlayer2()
{
ALOGV("constructor");
+ mSrcId = 0;
mListener = NULL;
mCookie = NULL;
mStreamType = AUDIO_STREAM_MUSIC;
@@ -118,8 +119,17 @@
return NO_ERROR;
}
+status_t MediaPlayer2::getSrcId(int64_t *srcId) {
+ if (srcId == NULL) {
+ return BAD_VALUE;
+ }
-status_t MediaPlayer2::attachNewPlayer(const sp<MediaPlayer2Engine>& player)
+ Mutex::Autolock _l(mLock);
+ *srcId = mSrcId;
+ return OK;
+}
+
+status_t MediaPlayer2::attachNewPlayer(const sp<MediaPlayer2Engine>& player, long srcId)
{
status_t err = UNKNOWN_ERROR;
sp<MediaPlayer2Engine> p;
@@ -135,6 +145,7 @@
clear_l();
p = mPlayer;
mPlayer = player;
+ mSrcId = srcId;
if (player != 0) {
mCurrentState = MEDIA_PLAYER2_INITIALIZED;
err = NO_ERROR;
@@ -161,7 +172,7 @@
if (NO_ERROR != player->setDataSource(dsd)) {
player.clear();
}
- err = attachNewPlayer(player);
+ err = attachNewPlayer(player, dsd->mId);
return err;
}
@@ -763,9 +774,10 @@
return INVALID_OPERATION;
}
-void MediaPlayer2::notify(int msg, int ext1, int ext2, const Parcel *obj)
+void MediaPlayer2::notify(int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj)
{
- ALOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
+ ALOGV("message received srcId=%lld, msg=%d, ext1=%d, ext2=%d",
+ (long long)srcId, msg, ext1, ext2);
bool send = true;
bool locked = false;
@@ -784,7 +796,8 @@
// Allows calls from JNI in idle state to notify errors
if (!(msg == MEDIA2_ERROR && mCurrentState == MEDIA_PLAYER2_IDLE) && mPlayer == 0) {
- ALOGV("notify(%d, %d, %d) callback on disconnected mediaplayer", msg, ext1, ext2);
+ ALOGV("notify(%lld, %d, %d, %d) callback on disconnected mediaplayer",
+ (long long)srcId, msg, ext1, ext2);
if (locked) mLock.unlock(); // release the lock when done.
return;
}
@@ -803,7 +816,8 @@
}
break;
case MEDIA2_DRM_INFO:
- ALOGV("MediaPlayer2::notify() MEDIA2_DRM_INFO(%d, %d, %d, %p)", msg, ext1, ext2, obj);
+ ALOGV("MediaPlayer2::notify() MEDIA2_DRM_INFO(%lld, %d, %d, %d, %p)",
+ (long long)srcId, msg, ext1, ext2, obj);
break;
case MEDIA2_PLAYBACK_COMPLETE:
ALOGV("playback complete");
@@ -882,7 +896,7 @@
if ((listener != 0) && send) {
Mutex::Autolock _l(mNotifyLock);
ALOGV("callback application");
- listener->notify(msg, ext1, ext2, obj);
+ listener->notify(srcId, msg, ext1, ext2, obj);
ALOGV("back from callback");
}
}
diff --git a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
index 0351a76..4700660 100644
--- a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
+++ b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
@@ -54,7 +54,6 @@
NuPlayer2::GenericSource2::GenericSource2(
const sp<AMessage> ¬ify,
- bool uidValid,
uid_t uid,
const sp<MediaClock> &mediaClock)
: Source(notify),
@@ -73,7 +72,6 @@
mAudioIsVorbis(false),
mIsSecure(false),
mIsStreaming(false),
- mUIDValid(uidValid),
mUID(uid),
mMediaClock(mediaClock),
mFd(-1),
diff --git a/media/libmediaplayer2/nuplayer2/GenericSource2.h b/media/libmediaplayer2/nuplayer2/GenericSource2.h
index bc13eb7..1a5409a 100644
--- a/media/libmediaplayer2/nuplayer2/GenericSource2.h
+++ b/media/libmediaplayer2/nuplayer2/GenericSource2.h
@@ -43,7 +43,7 @@
struct NuPlayer2::GenericSource2 : public NuPlayer2::Source,
public MediaBufferObserver // Modular DRM
{
- GenericSource2(const sp<AMessage> ¬ify, bool uidValid, uid_t uid,
+ GenericSource2(const sp<AMessage> ¬ify, uid_t uid,
const sp<MediaClock> &mediaClock);
status_t setDataSource(
@@ -150,7 +150,6 @@
// Secure codec is required.
bool mIsSecure;
bool mIsStreaming;
- bool mUIDValid;
uid_t mUID;
const sp<MediaClock> mMediaClock;
sp<MediaHTTPService> mHTTPService;
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
index 65e0957..c414f23 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
@@ -208,9 +208,9 @@
////////////////////////////////////////////////////////////////////////////////
-NuPlayer2::NuPlayer2(pid_t pid, const sp<MediaClock> &mediaClock)
- : mUIDValid(false),
- mPID(pid),
+NuPlayer2::NuPlayer2(pid_t pid, uid_t uid, const sp<MediaClock> &mediaClock)
+ : mPID(pid),
+ mUID(uid),
mMediaClock(mediaClock),
mSourceFlags(0),
mOffloadAudio(false),
@@ -249,11 +249,6 @@
NuPlayer2::~NuPlayer2() {
}
-void NuPlayer2::setUID(uid_t uid) {
- mUIDValid = true;
- mUID = uid;
-}
-
void NuPlayer2::setDriver(const wp<NuPlayer2Driver> &driver) {
mDriver = driver;
}
@@ -275,10 +270,12 @@
return false;
}
-void NuPlayer2::setDataSourceAsync(const sp<DataSourceDesc> &dsd) {
- sp<AMessage> msg = new AMessage(kWhatSetDataSource, this);
+status_t NuPlayer2::createNuPlayer2Source(const sp<DataSourceDesc> &dsd,
+ sp<Source> *source,
+ DATA_SOURCE_TYPE *dataSourceType) {
+ status_t err = NO_ERROR;
sp<AMessage> notify = new AMessage(kWhatSourceNotify, this);
- sp<Source> source;
+ notify->setInt64("srcId", dsd->mId);
switch (dsd->mType) {
case DataSourceDesc::TYPE_URL:
@@ -290,38 +287,39 @@
KeyedVector<String8, String8> *headers = &(dsd->mHeaders);
if (IsHTTPLiveURL(url)) {
- source = new HTTPLiveSource2(notify, httpService, url, headers);
- ALOGV("setDataSourceAsync HTTPLiveSource2 %s", url);
- mDataSourceType = DATA_SOURCE_TYPE_HTTP_LIVE;
+ *source = new HTTPLiveSource2(notify, httpService, url, headers);
+ ALOGV("createNuPlayer2Source HTTPLiveSource2 %s", url);
+ *dataSourceType = DATA_SOURCE_TYPE_HTTP_LIVE;
} else if (!strncasecmp(url, "rtsp://", 7)) {
- source = new RTSPSource2(
- notify, httpService, url, headers, mUIDValid, mUID);
- ALOGV("setDataSourceAsync RTSPSource2 %s", url);
- mDataSourceType = DATA_SOURCE_TYPE_RTSP;
+ *source = new RTSPSource2(
+ notify, httpService, url, headers, mUID);
+ ALOGV("createNuPlayer2Source RTSPSource2 %s", url);
+ *dataSourceType = DATA_SOURCE_TYPE_RTSP;
} else if ((!strncasecmp(url, "http://", 7)
|| !strncasecmp(url, "https://", 8))
&& ((len >= 4 && !strcasecmp(".sdp", &url[len - 4]))
|| strstr(url, ".sdp?"))) {
- source = new RTSPSource2(
- notify, httpService, url, headers, mUIDValid, mUID, true);
- ALOGV("setDataSourceAsync RTSPSource2 http/https/.sdp %s", url);
- mDataSourceType = DATA_SOURCE_TYPE_RTSP;
+ *source = new RTSPSource2(
+ notify, httpService, url, headers, mUID, true);
+ ALOGV("createNuPlayer2Source RTSPSource2 http/https/.sdp %s", url);
+ *dataSourceType = DATA_SOURCE_TYPE_RTSP;
} else {
- ALOGV("setDataSourceAsync GenericSource2 %s", url);
+ ALOGV("createNuPlayer2Source GenericSource2 %s", url);
sp<GenericSource2> genericSource =
- new GenericSource2(notify, mUIDValid, mUID, mMediaClock);
+ new GenericSource2(notify, mUID, mMediaClock);
- status_t err = genericSource->setDataSource(httpService, url, headers);
+ err = genericSource->setDataSource(httpService, url, headers);
if (err == OK) {
- source = genericSource;
+ *source = genericSource;
} else {
- ALOGE("Failed to set data source!");
+ *source = NULL;
+ ALOGE("Failed to create NuPlayer2Source!");
}
// regardless of success/failure
- mDataSourceType = DATA_SOURCE_TYPE_GENERIC_URL;
+ *dataSourceType = DATA_SOURCE_TYPE_GENERIC_URL;
}
break;
}
@@ -329,47 +327,99 @@
case DataSourceDesc::TYPE_FD:
{
sp<GenericSource2> genericSource =
- new GenericSource2(notify, mUIDValid, mUID, mMediaClock);
+ new GenericSource2(notify, mUID, mMediaClock);
- ALOGV("setDataSourceAsync fd %d/%lld/%lld source: %p",
- dsd->mFD, (long long)dsd->mFDOffset, (long long)dsd->mFDLength, source.get());
+ ALOGV("createNuPlayer2Source fd %d/%lld/%lld source: %p",
+ dsd->mFD, (long long)dsd->mFDOffset, (long long)dsd->mFDLength,
+ genericSource.get());
- status_t err = genericSource->setDataSource(dsd->mFD, dsd->mFDOffset, dsd->mFDLength);
+ err = genericSource->setDataSource(dsd->mFD, dsd->mFDOffset, dsd->mFDLength);
if (err != OK) {
- ALOGE("Failed to set data source!");
- source = NULL;
+ ALOGE("Failed to create NuPlayer2Source!");
+ *source = NULL;
} else {
- source = genericSource;
+ *source = genericSource;
}
- mDataSourceType = DATA_SOURCE_TYPE_GENERIC_FD;
+ *dataSourceType = DATA_SOURCE_TYPE_GENERIC_FD;
break;
}
case DataSourceDesc::TYPE_CALLBACK:
{
sp<GenericSource2> genericSource =
- new GenericSource2(notify, mUIDValid, mUID, mMediaClock);
- status_t err = genericSource->setDataSource(dsd->mCallbackSource);
+ new GenericSource2(notify, mUID, mMediaClock);
+ err = genericSource->setDataSource(dsd->mCallbackSource);
if (err != OK) {
- ALOGE("Failed to set data source!");
- source = NULL;
+ ALOGE("Failed to create NuPlayer2Source!");
+ *source = NULL;
} else {
- source = genericSource;
+ *source = genericSource;
}
- mDataSourceType = DATA_SOURCE_TYPE_MEDIA;
+ *dataSourceType = DATA_SOURCE_TYPE_MEDIA;
break;
}
default:
+ err = BAD_TYPE;
+ *source = NULL;
+ *dataSourceType = DATA_SOURCE_TYPE_NONE;
ALOGE("invalid data source type!");
break;
}
+ return err;
+}
+
+void NuPlayer2::setDataSourceAsync(const sp<DataSourceDesc> &dsd) {
+ DATA_SOURCE_TYPE dataSourceType;
+ sp<Source> source;
+ createNuPlayer2Source(dsd, &source, &dataSourceType);
+
+ // TODO: currently NuPlayer2Driver makes blocking call to setDataSourceAsync
+ // and expects notifySetDataSourceCompleted regardless of success or failure.
+ // This will be changed since setDataSource should be asynchronous at JAVA level.
+ // When it succeeds, app will get onInfo notification. Otherwise, onError
+ // will be called.
+ /*
+ if (err != OK) {
+ notifyListener(dsd->mId, MEDIA2_ERROR, MEDIA2_ERROR_FAILED_TO_SET_DATA_SOURCE, err);
+ return;
+ }
+
+ // Now, source != NULL.
+ */
+
+ mDataSourceType = dataSourceType;
+
+ sp<AMessage> msg = new AMessage(kWhatSetDataSource, this);
msg->setObject("source", source);
+ msg->setInt64("srcId", dsd->mId);
+ msg->post();
+}
+
+void NuPlayer2::prepareNextDataSourceAsync(const sp<DataSourceDesc> &dsd) {
+ DATA_SOURCE_TYPE dataSourceType;
+ sp<Source> source;
+ createNuPlayer2Source(dsd, &source, &dataSourceType);
+
+ /*
+ if (err != OK) {
+ notifyListener(dsd->mId, MEDIA2_ERROR, MEDIA2_ERROR_FAILED_TO_SET_DATA_SOURCE, err);
+ return;
+ }
+
+ // Now, source != NULL.
+ */
+
+ mNextDataSourceType = dataSourceType;
+
+ sp<AMessage> msg = new AMessage(kWhatPrepareNextDataSource, this);
+ msg->setObject("source", source);
+ msg->setInt64("srcId", dsd->mId);
msg->post();
}
@@ -587,6 +637,7 @@
CHECK(msg->findObject("source", &obj));
if (obj != NULL) {
Mutex::Autolock autoLock(mSourceLock);
+ CHECK(msg->findInt64("srcId", &mSrcId));
mSource = static_cast<Source *>(obj.get());
} else {
err = UNKNOWN_ERROR;
@@ -595,11 +646,30 @@
CHECK(mDriver != NULL);
sp<NuPlayer2Driver> driver = mDriver.promote();
if (driver != NULL) {
- driver->notifySetDataSourceCompleted(err);
+ driver->notifySetDataSourceCompleted(mSrcId, err);
}
break;
}
+ case kWhatPrepareNextDataSource:
+ {
+ ALOGV("kWhatPrepareNextDataSource");
+
+ status_t err = OK;
+ sp<RefBase> obj;
+ CHECK(msg->findObject("source", &obj));
+ if (obj != NULL) {
+ Mutex::Autolock autoLock(mSourceLock);
+ CHECK(msg->findInt64("srcId", &mNextSrcId));
+ mNextSource = static_cast<Source *>(obj.get());
+ mNextSource->prepareAsync();
+ } else {
+ err = UNKNOWN_ERROR;
+ }
+
+ break;
+ }
+
case kWhatGetBufferingSettings:
{
sp<AReplyToken> replyID;
@@ -775,7 +845,7 @@
if (mDriver != NULL && mSource->getDuration(&durationUs) == OK) {
sp<NuPlayer2Driver> driver = mDriver.promote();
if (driver != NULL) {
- driver->notifyDuration(durationUs);
+ driver->notifyDuration(mSrcId, durationUs);
}
}
@@ -865,6 +935,7 @@
onStart();
}
mPausedByClient = false;
+ notifyListener(mSrcId, MEDIA2_STARTED, 0, 0);
break;
}
@@ -904,6 +975,7 @@
if (err == OK) {
if (rate.mSpeed == 0.f) {
onPause();
+ notifyListener(mSrcId, MEDIA2_PAUSED, 0, 0);
mPausedByClient = true;
// save all other settings (using non-paused speed)
// so we can restore them on start
@@ -1058,9 +1130,9 @@
// video tracks found) and we just ran out of input data.
if (err == ERROR_END_OF_STREAM) {
- notifyListener(MEDIA2_PLAYBACK_COMPLETE, 0, 0);
+ notifyListener(mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
} else {
- notifyListener(MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+ notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
}
}
break;
@@ -1145,7 +1217,7 @@
mSource->getFormat(false /* audio */);
setVideoScalingMode(mVideoScalingMode);
- updateVideoSize(inputFormat, format);
+ updateVideoSize(mSrcId, inputFormat, format);
} else if (what == DecoderBase::kWhatShutdownCompleted) {
ALOGV("%s shutdown completed", audio ? "audio" : "video");
if (audio) {
@@ -1219,10 +1291,10 @@
|| mVideoDecoder == NULL) {
// When both audio and video have error, or this stream has only audio
// which has error, notify client of error.
- notifyListener(MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+ notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
} else {
// Only audio track has error. Video track could be still good to play.
- notifyListener(MEDIA2_INFO, MEDIA2_INFO_PLAY_AUDIO_ERROR, err);
+ notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_PLAY_AUDIO_ERROR, err);
}
mAudioDecoderError = true;
} else {
@@ -1230,10 +1302,10 @@
|| mAudioSink == NULL || mAudioDecoder == NULL) {
// When both audio and video have error, or this stream has only video
// which has error, notify client of error.
- notifyListener(MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+ notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
} else {
// Only video track has error. Audio track could be still good to play.
- notifyListener(MEDIA2_INFO, MEDIA2_INFO_PLAY_VIDEO_ERROR, err);
+ notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_PLAY_VIDEO_ERROR, err);
}
mVideoDecoderError = true;
}
@@ -1283,12 +1355,12 @@
audio ? "audio" : "video", finalResult);
notifyListener(
- MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, finalResult);
+ mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, finalResult);
}
if ((mAudioEOS || mAudioDecoder == NULL)
&& (mVideoEOS || mVideoDecoder == NULL)) {
- notifyListener(MEDIA2_PLAYBACK_COMPLETE, 0, 0);
+ notifyListener(mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
}
} else if (what == Renderer::kWhatFlushComplete) {
int32_t audio;
@@ -1309,10 +1381,10 @@
handleFlushComplete(audio, false /* isDecoder */);
finishFlushIfPossible();
} else if (what == Renderer::kWhatVideoRenderingStart) {
- notifyListener(MEDIA2_INFO, MEDIA2_INFO_RENDERING_START, 0);
+ notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_RENDERING_START, 0);
} else if (what == Renderer::kWhatMediaRenderingStart) {
ALOGV("media rendering started");
- notifyListener(MEDIA2_STARTED, 0, 0);
+ notifyListener(mSrcId, MEDIA2_STARTED, 0, 0);
} else if (what == Renderer::kWhatAudioTearDown) {
int32_t reason;
CHECK(msg->findInt32("reason", &reason));
@@ -1365,7 +1437,7 @@
int64_t timerUs;
CHECK(msg->findInt64("timerUs", &timerUs));
- notifyListener(MEDIA2_NOTIFY_TIME, timerUs, 0);
+ notifyListener(mSrcId, MEDIA2_NOTIFY_TIME, timerUs, 0);
break;
}
@@ -1381,6 +1453,9 @@
ALOGV("kWhatSeek seekTimeUs=%lld us, mode=%d, needNotify=%d",
(long long)seekTimeUs, mode, needNotify);
+ // seeks can take a while, so we essentially paused
+ notifyListener(mSrcId, MEDIA2_PAUSED, 0, 0);
+
if (!mStarted) {
// Seek before the player is started. In order to preview video,
// need to start the player and pause it. This branch is called
@@ -1393,7 +1468,7 @@
mPausedByClient = true;
}
if (needNotify) {
- notifyDriverSeekComplete();
+ notifyDriverSeekComplete(mSrcId);
}
break;
}
@@ -1418,6 +1493,7 @@
case kWhatPause:
{
onPause();
+ notifyListener(mSrcId, MEDIA2_PAUSED, 0, 0);
mPausedByClient = true;
break;
}
@@ -1489,35 +1565,6 @@
startPlaybackTimer("onresume");
}
-status_t NuPlayer2::onInstantiateSecureDecoders() {
- status_t err;
- if (!(mSourceFlags & Source::FLAG_SECURE)) {
- return BAD_TYPE;
- }
-
- if (mRenderer != NULL) {
- ALOGE("renderer should not be set when instantiating secure decoders");
- return UNKNOWN_ERROR;
- }
-
- // TRICKY: We rely on mRenderer being null, so that decoder does not start requesting
- // data on instantiation.
- if (mNativeWindow != NULL && mNativeWindow->getANativeWindow() != NULL) {
- err = instantiateDecoder(false, &mVideoDecoder);
- if (err != OK) {
- return err;
- }
- }
-
- if (mAudioSink != NULL) {
- err = instantiateDecoder(true, &mAudioDecoder);
- if (err != OK) {
- return err;
- }
- }
- return OK;
-}
-
void NuPlayer2::onStart(int64_t startPositionUs, MediaPlayer2SeekMode mode) {
ALOGV("onStart: mCrypto: %p", mCrypto.get());
@@ -1550,7 +1597,7 @@
ALOGE("no metadata for either audio or video source");
mSource->stop();
mSourceStarted = false;
- notifyListener(MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, ERROR_MALFORMED);
+ notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, ERROR_MALFORMED);
return;
}
ALOGV_IF(!hasAudio, "no metadata for audio source"); // video only stream
@@ -1589,7 +1636,7 @@
if (err != OK) {
mSource->stop();
mSourceStarted = false;
- notifyListener(MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+ notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
return;
}
@@ -1631,7 +1678,7 @@
ALOGV("stopPlaybackTimer() log %20" PRId64 "", played);
if (played > 0) {
- driver->notifyMorePlayingTimeUs((played+500)/1000);
+ driver->notifyMorePlayingTimeUs(mSrcId, (played+500)/1000);
}
}
mLastStartedPlayingTimeNs = 0;
@@ -1659,9 +1706,9 @@
ALOGV("stopRebufferingTimer() log %20" PRId64 "", rebuffered);
if (rebuffered > 0) {
- driver->notifyMoreRebufferingTimeUs((rebuffered+500)/1000);
+ driver->notifyMoreRebufferingTimeUs(mSrcId, (rebuffered+500)/1000);
if (exitingPlayback) {
- driver->notifyRebufferingWhenExit(true);
+ driver->notifyRebufferingWhenExit(mSrcId, true);
}
}
}
@@ -1978,11 +2025,12 @@
}
void NuPlayer2::updateVideoSize(
+ int64_t srcId,
const sp<AMessage> &inputFormat,
const sp<AMessage> &outputFormat) {
if (inputFormat == NULL) {
ALOGW("Unknown video size, reporting 0x0!");
- notifyListener(MEDIA2_SET_VIDEO_SIZE, 0, 0);
+ notifyListener(srcId, MEDIA2_SET_VIDEO_SIZE, 0, 0);
return;
}
int32_t err = OK;
@@ -2061,12 +2109,13 @@
}
notifyListener(
+ srcId,
MEDIA2_SET_VIDEO_SIZE,
displayWidth,
displayHeight);
}
-void NuPlayer2::notifyListener(int msg, int ext1, int ext2, const Parcel *in) {
+void NuPlayer2::notifyListener(int64_t srcId, int msg, int ext1, int ext2, const Parcel *in) {
if (mDriver == NULL) {
return;
}
@@ -2077,7 +2126,7 @@
return;
}
- driver->notifyListener(msg, ext1, ext2, in);
+ driver->notifyListener(srcId, msg, ext1, ext2, in);
}
void NuPlayer2::flushDecoder(bool audio, bool needShutdown) {
@@ -2342,7 +2391,7 @@
if (mDriver != NULL) {
sp<NuPlayer2Driver> driver = mDriver.promote();
if (driver != NULL) {
- driver->notifyResetComplete();
+ driver->notifyResetComplete(mSrcId);
}
}
@@ -2384,7 +2433,7 @@
if (mDriver != NULL) {
sp<NuPlayer2Driver> driver = mDriver.promote();
if (driver != NULL) {
- driver->notifySetSurfaceComplete();
+ driver->notifySetSurfaceComplete(mSrcId);
}
}
}
@@ -2416,15 +2465,15 @@
void NuPlayer2::finishResume() {
if (mResumePending) {
mResumePending = false;
- notifyDriverSeekComplete();
+ notifyDriverSeekComplete(mSrcId);
}
}
-void NuPlayer2::notifyDriverSeekComplete() {
+void NuPlayer2::notifyDriverSeekComplete(int64_t srcId) {
if (mDriver != NULL) {
sp<NuPlayer2Driver> driver = mDriver.promote();
if (driver != NULL) {
- driver->notifySeekComplete();
+ driver->notifySeekComplete(srcId);
}
}
}
@@ -2433,24 +2482,9 @@
int32_t what;
CHECK(msg->findInt32("what", &what));
+ int64_t srcId;
+ CHECK(msg->findInt64("srcId", &srcId));
switch (what) {
- case Source::kWhatInstantiateSecureDecoders:
- {
- if (mSource == NULL) {
- // This is a stale notification from a source that was
- // asynchronously preparing when the client called reset().
- // We handled the reset, the source is gone.
- break;
- }
-
- sp<AMessage> reply;
- CHECK(msg->findMessage("reply", &reply));
- status_t err = onInstantiateSecureDecoders();
- reply->setInt32("err", err);
- reply->post();
- break;
- }
-
case Source::kWhatPrepared:
{
ALOGV("NuPlayer2::onSourceNotify Source::kWhatPrepared source: %p", mSource.get());
@@ -2480,9 +2514,9 @@
// the app received the "prepare complete" callback.
int64_t durationUs;
if (mSource->getDuration(&durationUs) == OK) {
- driver->notifyDuration(durationUs);
+ driver->notifyDuration(srcId, durationUs);
}
- driver->notifyPrepareCompleted(err);
+ driver->notifyPrepareCompleted(srcId, err);
}
break;
@@ -2499,7 +2533,7 @@
ALOGV("onSourceNotify() kWhatDrmInfo MEDIA2_DRM_INFO drmInfo: %p parcel size: %zu",
drmInfo.get(), parcel.dataSize());
- notifyListener(MEDIA2_DRM_INFO, 0 /* ext1 */, 0 /* ext2 */, &parcel);
+ notifyListener(srcId, MEDIA2_DRM_INFO, 0 /* ext1 */, 0 /* ext2 */, &parcel);
break;
}
@@ -2526,9 +2560,9 @@
if ((flags & NuPlayer2::Source::FLAG_CAN_SEEK) == 0) {
driver->notifyListener(
- MEDIA2_INFO, MEDIA2_INFO_NOT_SEEKABLE, 0);
+ srcId, MEDIA2_INFO, MEDIA2_INFO_NOT_SEEKABLE, 0);
}
- driver->notifyFlagsChanged(flags);
+ driver->notifyFlagsChanged(srcId, flags);
}
if ((mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
@@ -2549,7 +2583,7 @@
sp<AMessage> format;
CHECK(msg->findMessage("format", &format));
- updateVideoSize(format);
+ updateVideoSize(srcId, format);
break;
}
@@ -2558,7 +2592,7 @@
int32_t percentage;
CHECK(msg->findInt32("percentage", &percentage));
- notifyListener(MEDIA2_BUFFERING_UPDATE, percentage, 0);
+ notifyListener(srcId, MEDIA2_BUFFERING_UPDATE, percentage, 0);
break;
}
@@ -2572,7 +2606,7 @@
mPausedForBuffering = true;
onPause();
}
- notifyListener(MEDIA2_INFO, MEDIA2_INFO_BUFFERING_START, 0);
+ notifyListener(srcId, MEDIA2_INFO, MEDIA2_INFO_BUFFERING_START, 0);
break;
}
@@ -2590,7 +2624,7 @@
onResume();
}
}
- notifyListener(MEDIA2_INFO, MEDIA2_INFO_BUFFERING_END, 0);
+ notifyListener(srcId, MEDIA2_INFO, MEDIA2_INFO_BUFFERING_END, 0);
break;
}
@@ -2599,7 +2633,7 @@
int32_t kbps;
CHECK(msg->findInt32("bandwidth", &kbps));
- notifyListener(MEDIA2_INFO, MEDIA2_INFO_NETWORK_BANDWIDTH, kbps);
+ notifyListener(srcId, MEDIA2_INFO, MEDIA2_INFO_NETWORK_BANDWIDTH, kbps);
break;
}
@@ -2616,7 +2650,7 @@
{
sp<ABuffer> buffer;
if (!msg->findBuffer("buffer", &buffer)) {
- notifyListener(MEDIA2_INFO, MEDIA2_INFO_METADATA_UPDATE, 0);
+ notifyListener(srcId, MEDIA2_INFO, MEDIA2_INFO_METADATA_UPDATE, 0);
} else {
sendTimedMetaData(buffer);
}
@@ -2671,7 +2705,7 @@
case Source::kWhatDrmNoLicense:
{
- notifyListener(MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
+ notifyListener(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
break;
}
@@ -2701,7 +2735,7 @@
case NuPlayer2::CCDecoder::kWhatTrackAdded:
{
- notifyListener(MEDIA2_INFO, MEDIA2_INFO_METADATA_UPDATE, 0);
+ notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_METADATA_UPDATE, 0);
break;
}
@@ -2728,7 +2762,7 @@
in.writeInt32(buffer->size());
in.write(buffer->data(), buffer->size());
- notifyListener(MEDIA2_SUBTITLE_DATA, 0, 0, &in);
+ notifyListener(mSrcId, MEDIA2_SUBTITLE_DATA, 0, 0, &in);
}
void NuPlayer2::sendTimedMetaData(const sp<ABuffer> &buffer) {
@@ -2741,7 +2775,7 @@
in.writeInt32(buffer->size());
in.write(buffer->data(), buffer->size());
- notifyListener(MEDIA2_META_DATA, 0, 0, &in);
+ notifyListener(mSrcId, MEDIA2_META_DATA, 0, 0, &in);
}
void NuPlayer2::sendTimedTextData(const sp<ABuffer> &buffer) {
@@ -2771,9 +2805,9 @@
}
if ((parcel.dataSize() > 0)) {
- notifyListener(MEDIA2_TIMED_TEXT, 0, 0, &parcel);
+ notifyListener(mSrcId, MEDIA2_TIMED_TEXT, 0, 0, &parcel);
} else { // send an empty timed text
- notifyListener(MEDIA2_TIMED_TEXT, 0, 0);
+ notifyListener(mSrcId, MEDIA2_TIMED_TEXT, 0, 0);
}
}
@@ -2794,9 +2828,6 @@
case DATA_SOURCE_TYPE_MEDIA:
return "Media";
- case DATA_SOURCE_TYPE_STREAM:
- return "Stream";
-
case DATA_SOURCE_TYPE_NONE:
default:
return "None";
@@ -2984,13 +3015,6 @@
notify->post();
}
-void NuPlayer2::Source::notifyInstantiateSecureDecoders(const sp<AMessage> &reply) {
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatInstantiateSecureDecoders);
- notify->setMessage("reply", reply);
- notify->post();
-}
-
void NuPlayer2::Source::onMessageReceived(const sp<AMessage> & /* msg */) {
TRESPASS();
}
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.h b/media/libmediaplayer2/nuplayer2/NuPlayer2.h
index 594525c..e884b92 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.h
@@ -32,20 +32,18 @@
struct AudioPlaybackRate;
struct AVSyncSettings;
struct DataSourceDesc;
-class IDataSource;
struct MediaClock;
struct MediaHTTPService;
class MetaData;
struct NuPlayer2Driver;
struct NuPlayer2 : public AHandler {
- explicit NuPlayer2(pid_t pid, const sp<MediaClock> &mediaClock);
-
- void setUID(uid_t uid);
+ explicit NuPlayer2(pid_t pid, uid_t uid, const sp<MediaClock> &mediaClock);
void setDriver(const wp<NuPlayer2Driver> &driver);
void setDataSourceAsync(const sp<DataSourceDesc> &dsd);
+ void prepareNextDataSourceAsync(const sp<DataSourceDesc> &dsd);
status_t getBufferingSettings(BufferingSettings* buffering /* nonnull */);
status_t setBufferingSettings(const BufferingSettings& buffering);
@@ -122,6 +120,7 @@
enum {
kWhatSetDataSource = '=DaS',
kWhatPrepare = 'prep',
+ kWhatPrepareNextDataSource = 'pNDS',
kWhatSetVideoSurface = '=VSu',
kWhatSetAudioSink = '=AuS',
kWhatMoreDataQueued = 'more',
@@ -152,13 +151,16 @@
};
wp<NuPlayer2Driver> mDriver;
- bool mUIDValid;
- uid_t mUID;
pid_t mPID;
+ uid_t mUID;
const sp<MediaClock> mMediaClock;
Mutex mSourceLock; // guard |mSource|.
sp<Source> mSource;
+ int64_t mSrcId;
uint32_t mSourceFlags;
+ sp<Source> mNextSource;
+ int64_t mNextSrcId;
+ uint32_t mNextSourceFlags;
sp<ANativeWindowWrapper> mNativeWindow;
sp<MediaPlayer2Interface::AudioSink> mAudioSink;
sp<DecoderBase> mVideoDecoder;
@@ -251,10 +253,10 @@
DATA_SOURCE_TYPE_GENERIC_URL,
DATA_SOURCE_TYPE_GENERIC_FD,
DATA_SOURCE_TYPE_MEDIA,
- DATA_SOURCE_TYPE_STREAM,
} DATA_SOURCE_TYPE;
std::atomic<DATA_SOURCE_TYPE> mDataSourceType;
+ std::atomic<DATA_SOURCE_TYPE> mNextDataSourceType;
inline const sp<DecoderBase> &getDecoder(bool audio) {
return audio ? mAudioDecoder : mVideoDecoder;
@@ -267,6 +269,10 @@
mFlushComplete[1][1] = false;
}
+ status_t createNuPlayer2Source(const sp<DataSourceDesc> &dsd,
+ sp<Source> *source,
+ DATA_SOURCE_TYPE *dataSourceType);
+
void tryOpenAudioSinkForOffload(
const sp<AMessage> &format, const sp<MetaData> &audioMeta, bool hasVideo);
void closeAudioSink();
@@ -277,13 +283,12 @@
status_t instantiateDecoder(
bool audio, sp<DecoderBase> *decoder, bool checkAudioModeChange = true);
- status_t onInstantiateSecureDecoders();
-
void updateVideoSize(
+ int64_t srcId,
const sp<AMessage> &inputFormat,
const sp<AMessage> &outputFormat = NULL);
- void notifyListener(int msg, int ext1, int ext2, const Parcel *in = NULL);
+ void notifyListener(int64_t srcId, int msg, int ext1, int ext2, const Parcel *in = NULL);
void handleFlushComplete(bool audio, bool isDecoder);
void finishFlushIfPossible();
@@ -299,7 +304,7 @@
void flushDecoder(bool audio, bool needShutdown);
void finishResume();
- void notifyDriverSeekComplete();
+ void notifyDriverSeekComplete(int64_t srcId);
void postScanSources();
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
index 6137fd1..60a07a3 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
@@ -25,6 +25,7 @@
#include "NuPlayer2.h"
#include "NuPlayer2Source.h"
+#include <media/DataSourceDesc.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AUtils.h>
@@ -79,6 +80,9 @@
// key for media statistics
static const char *kKeyPlayer = "nuplayer";
// attrs for media statistics
+ // NB: these are matched with public Java API constants defined
+ // in frameworks/base/media/java/android/media/MediaPlayer2.java
+ // These must be kept synchronized with the constants there.
static const char *kPlayerVMime = "android.media.mediaplayer.video.mime";
static const char *kPlayerVCodec = "android.media.mediaplayer.video.codec";
static const char *kPlayerWidth = "android.media.mediaplayer.width";
@@ -91,6 +95,8 @@
static const char *kPlayerPlaying = "android.media.mediaplayer.playingMs";
static const char *kPlayerError = "android.media.mediaplayer.err";
static const char *kPlayerErrorCode = "android.media.mediaplayer.errcode";
+
+// NB: These are not yet exposed as public Java API constants.
static const char *kPlayerErrorState = "android.media.mediaplayer.errstate";
static const char *kPlayerDataSourceType = "android.media.mediaplayer.dataSource";
//
@@ -99,10 +105,11 @@
static const char *kPlayerRebufferingAtExit = "android.media.mediaplayer.rebufferExit";
-NuPlayer2Driver::NuPlayer2Driver(pid_t pid)
+NuPlayer2Driver::NuPlayer2Driver(pid_t pid, uid_t uid)
: mState(STATE_IDLE),
mIsAsyncPrepare(false),
mAsyncResult(UNKNOWN_ERROR),
+ mSrcId(0),
mSetSurfaceInProgress(false),
mDurationUs(-1),
mPositionUs(-1),
@@ -114,10 +121,10 @@
mLooper(new ALooper),
mNuPlayer2Looper(new ALooper),
mMediaClock(new MediaClock),
- mPlayer(new NuPlayer2(pid, mMediaClock)),
+ mPlayer(new NuPlayer2(pid, uid, mMediaClock)),
mPlayerFlags(0),
mAnalyticsItem(NULL),
- mClientUid(-1),
+ mClientUid(uid),
mAtEOS(false),
mLooping(false),
mAutoLoop(false) {
@@ -129,6 +136,7 @@
// set up an analytics record
mAnalyticsItem = new MediaAnalyticsItem(kKeyPlayer);
+ mAnalyticsItem->setUid(mClientUid);
mNuPlayer2Looper->start(
false, /* runOnCallingThread */
@@ -165,16 +173,6 @@
return OK;
}
-status_t NuPlayer2Driver::setUID(uid_t uid) {
- mPlayer->setUID(uid);
- mClientUid = uid;
- if (mAnalyticsItem) {
- mAnalyticsItem->setUid(mClientUid);
- }
-
- return OK;
-}
-
status_t NuPlayer2Driver::setDataSource(const sp<DataSourceDesc> &dsd) {
ALOGV("setDataSource(%p) callback source", this);
Mutex::Autolock autoLock(mLock);
@@ -183,6 +181,7 @@
return INVALID_OPERATION;
}
+ mSrcId = dsd->mId;
mState = STATE_SET_DATASOURCE_PENDING;
mPlayer->setDataSourceAsync(dsd);
@@ -365,7 +364,7 @@
case STATE_PAUSED:
mState = STATE_STOPPED;
- notifyListener_l(MEDIA2_STOPPED);
+ //notifyListener_l(MEDIA2_STOPPED);
break;
case STATE_PREPARED:
@@ -400,7 +399,6 @@
case STATE_RUNNING:
mState = STATE_PAUSED;
- notifyListener_l(MEDIA2_PAUSED);
mPlayer->pause();
break;
@@ -424,7 +422,6 @@
Mutex::Autolock autoLock(mLock);
if (rate.mSpeed == 0.f && mState == STATE_RUNNING) {
mState = STATE_PAUSED;
- notifyListener_l(MEDIA2_PAUSED);
} else if (rate.mSpeed != 0.f
&& (mState == STATE_PAUSED
|| mState == STATE_STOPPED_AND_PREPARED
@@ -461,8 +458,6 @@
{
mAtEOS = false;
mSeekInProgress = true;
- // seeks can take a while, so we essentially paused
- notifyListener_l(MEDIA2_PAUSED);
mPlayer->seekToAsync(seekTimeUs, mode, true /* needNotify */);
break;
}
@@ -633,7 +628,7 @@
{
CHECK(mIsAsyncPrepare);
- notifyListener_l(MEDIA2_PREPARED);
+ notifyListener_l(mSrcId, MEDIA2_PREPARED);
break;
}
@@ -642,7 +637,7 @@
}
if (mState != STATE_STOPPED) {
- notifyListener_l(MEDIA2_STOPPED);
+ // notifyListener_l(MEDIA2_STOPPED);
}
mState = STATE_RESET_IN_PROGRESS;
@@ -776,7 +771,7 @@
return OK;
}
-void NuPlayer2Driver::notifyResetComplete() {
+void NuPlayer2Driver::notifyResetComplete(int64_t /* srcId */) {
ALOGD("notifyResetComplete(%p)", this);
Mutex::Autolock autoLock(mLock);
@@ -785,7 +780,7 @@
mCondition.broadcast();
}
-void NuPlayer2Driver::notifySetSurfaceComplete() {
+void NuPlayer2Driver::notifySetSurfaceComplete(int64_t /* srcId */) {
ALOGV("notifySetSurfaceComplete(%p)", this);
Mutex::Autolock autoLock(mLock);
@@ -795,35 +790,35 @@
mCondition.broadcast();
}
-void NuPlayer2Driver::notifyDuration(int64_t durationUs) {
+void NuPlayer2Driver::notifyDuration(int64_t /* srcId */, int64_t durationUs) {
Mutex::Autolock autoLock(mLock);
mDurationUs = durationUs;
}
-void NuPlayer2Driver::notifyMorePlayingTimeUs(int64_t playingUs) {
+void NuPlayer2Driver::notifyMorePlayingTimeUs(int64_t /* srcId */, int64_t playingUs) {
Mutex::Autolock autoLock(mLock);
mPlayingTimeUs += playingUs;
}
-void NuPlayer2Driver::notifyMoreRebufferingTimeUs(int64_t rebufferingUs) {
+void NuPlayer2Driver::notifyMoreRebufferingTimeUs(int64_t /* srcId */, int64_t rebufferingUs) {
Mutex::Autolock autoLock(mLock);
mRebufferingTimeUs += rebufferingUs;
mRebufferingEvents++;
}
-void NuPlayer2Driver::notifyRebufferingWhenExit(bool status) {
+void NuPlayer2Driver::notifyRebufferingWhenExit(int64_t /* srcId */, bool status) {
Mutex::Autolock autoLock(mLock);
mRebufferingAtExit = status;
}
-void NuPlayer2Driver::notifySeekComplete() {
+void NuPlayer2Driver::notifySeekComplete(int64_t srcId) {
ALOGV("notifySeekComplete(%p)", this);
Mutex::Autolock autoLock(mLock);
mSeekInProgress = false;
- notifySeekComplete_l();
+ notifySeekComplete_l(srcId);
}
-void NuPlayer2Driver::notifySeekComplete_l() {
+void NuPlayer2Driver::notifySeekComplete_l(int64_t srcId) {
bool wasSeeking = true;
if (mState == STATE_STOPPED_AND_PREPARING) {
wasSeeking = false;
@@ -837,7 +832,7 @@
// no need to notify listener
return;
}
- notifyListener_l(wasSeeking ? MEDIA2_SEEK_COMPLETE : MEDIA2_PREPARED);
+ notifyListener_l(srcId, wasSeeking ? MEDIA2_SEEK_COMPLETE : MEDIA2_PREPARED);
}
status_t NuPlayer2Driver::dump(
@@ -920,9 +915,11 @@
void NuPlayer2Driver::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case kWhatNotifyListener: {
+ int64_t srcId;
int32_t msgId;
int32_t ext1 = 0;
int32_t ext2 = 0;
+ CHECK(msg->findInt64("srcId", &srcId));
CHECK(msg->findInt32("messageId", &msgId));
msg->findInt32("ext1", &ext1);
msg->findInt32("ext2", &ext2);
@@ -931,7 +928,7 @@
if (msg->findObject("parcel", &obj) && obj != NULL) {
in = static_cast<ParcelWrapper *>(obj.get());
}
- sendEvent(msgId, ext1, ext2, (in == NULL ? NULL : in->getParcel()));
+ sendEvent(srcId, msgId, ext1, ext2, (in == NULL ? NULL : in->getParcel()));
break;
}
default:
@@ -940,15 +937,16 @@
}
void NuPlayer2Driver::notifyListener(
- int msg, int ext1, int ext2, const Parcel *in) {
+ int64_t srcId, int msg, int ext1, int ext2, const Parcel *in) {
Mutex::Autolock autoLock(mLock);
- notifyListener_l(msg, ext1, ext2, in);
+ notifyListener_l(srcId, msg, ext1, ext2, in);
}
void NuPlayer2Driver::notifyListener_l(
- int msg, int ext1, int ext2, const Parcel *in) {
- ALOGD("notifyListener_l(%p), (%d, %d, %d, %d), loop setting(%d, %d)",
- this, msg, ext1, ext2, (in == NULL ? -1 : (int)in->dataSize()), mAutoLoop, mLooping);
+ int64_t srcId, int msg, int ext1, int ext2, const Parcel *in) {
+ ALOGD("notifyListener_l(%p), (%lld, %d, %d, %d, %d), loop setting(%d, %d)",
+ this, (long long)srcId, msg, ext1, ext2,
+ (in == NULL ? -1 : (int)in->dataSize()), mAutoLoop, mLooping);
switch (msg) {
case MEDIA2_PLAYBACK_COMPLETE:
{
@@ -1004,6 +1002,7 @@
}
sp<AMessage> notify = new AMessage(kWhatNotifyListener, this);
+ notify->setInt64("srcId", srcId);
notify->setInt32("messageId", msg);
notify->setInt32("ext1", ext1);
notify->setInt32("ext2", ext2);
@@ -1011,7 +1010,7 @@
notify->post();
}
-void NuPlayer2Driver::notifySetDataSourceCompleted(status_t err) {
+void NuPlayer2Driver::notifySetDataSourceCompleted(int64_t /* srcId */, status_t err) {
Mutex::Autolock autoLock(mLock);
CHECK_EQ(mState, STATE_SET_DATASOURCE_PENDING);
@@ -1021,7 +1020,7 @@
mCondition.broadcast();
}
-void NuPlayer2Driver::notifyPrepareCompleted(status_t err) {
+void NuPlayer2Driver::notifyPrepareCompleted(int64_t srcId, status_t err) {
ALOGV("notifyPrepareCompleted %d", err);
Mutex::Autolock autoLock(mLock);
@@ -1043,12 +1042,12 @@
// in response, NuPlayer2Driver has the right state
mState = STATE_PREPARED;
if (mIsAsyncPrepare) {
- notifyListener_l(MEDIA2_PREPARED);
+ notifyListener_l(srcId, MEDIA2_PREPARED);
}
} else {
mState = STATE_UNPREPARED;
if (mIsAsyncPrepare) {
- notifyListener_l(MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+ notifyListener_l(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
}
}
@@ -1062,7 +1061,7 @@
mCondition.broadcast();
}
-void NuPlayer2Driver::notifyFlagsChanged(uint32_t flags) {
+void NuPlayer2Driver::notifyFlagsChanged(int64_t /* srcId */, uint32_t flags) {
Mutex::Autolock autoLock(mLock);
mPlayerFlags = flags;
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h
index 7156813..4c57cfd 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h
@@ -26,12 +26,10 @@
struct NuPlayer2;
struct NuPlayer2Driver : public MediaPlayer2Interface {
- explicit NuPlayer2Driver(pid_t pid);
+ explicit NuPlayer2Driver(pid_t pid, uid_t uid);
virtual status_t initCheck();
- virtual status_t setUID(uid_t uid);
-
virtual status_t setDataSource(const sp<DataSourceDesc> &dsd) override;
virtual status_t setVideoSurfaceTexture(const sp<ANativeWindowWrapper> &nww);
@@ -69,18 +67,19 @@
virtual void onMessageReceived(const sp<AMessage> &msg) override;
- void notifySetDataSourceCompleted(status_t err);
- void notifyPrepareCompleted(status_t err);
- void notifyResetComplete();
- void notifySetSurfaceComplete();
- void notifyDuration(int64_t durationUs);
- void notifyMorePlayingTimeUs(int64_t timeUs);
- void notifyMoreRebufferingTimeUs(int64_t timeUs);
- void notifyRebufferingWhenExit(bool status);
- void notifySeekComplete();
- void notifySeekComplete_l();
- void notifyListener(int msg, int ext1 = 0, int ext2 = 0, const Parcel *in = NULL);
- void notifyFlagsChanged(uint32_t flags);
+ void notifySetDataSourceCompleted(int64_t srcId, status_t err);
+ void notifyPrepareCompleted(int64_t srcId, status_t err);
+ void notifyResetComplete(int64_t srcId);
+ void notifySetSurfaceComplete(int64_t srcId);
+ void notifyDuration(int64_t srcId, int64_t durationUs);
+ void notifyMorePlayingTimeUs(int64_t srcId, int64_t timeUs);
+ void notifyMoreRebufferingTimeUs(int64_t srcId, int64_t timeUs);
+ void notifyRebufferingWhenExit(int64_t srcId, bool status);
+ void notifySeekComplete(int64_t srcId);
+ void notifySeekComplete_l(int64_t srcId);
+ void notifyListener(int64_t srcId, int msg, int ext1 = 0, int ext2 = 0,
+ const Parcel *in = NULL);
+ void notifyFlagsChanged(int64_t srcId, uint32_t flags);
// Modular DRM
virtual status_t prepareDrm(const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId);
@@ -120,6 +119,7 @@
// The following are protected through "mLock"
// >>>
+ int64_t mSrcId;
bool mSetSurfaceInProgress;
int64_t mDurationUs;
int64_t mPositionUs;
@@ -149,7 +149,8 @@
status_t prepare_l();
status_t start_l();
- void notifyListener_l(int msg, int ext1 = 0, int ext2 = 0, const Parcel *in = NULL);
+ void notifyListener_l(int64_t srcId, int msg, int ext1 = 0, int ext2 = 0,
+ const Parcel *in = NULL);
DISALLOW_EVIL_CONSTRUCTORS(NuPlayer2Driver);
};
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h
index ef57bc0..662235f 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h
@@ -55,7 +55,6 @@
kWhatTimedMetaData,
kWhatQueueDecoderShutdown,
kWhatDrmNoLicense,
- kWhatInstantiateSecureDecoders,
// Modular DRM
kWhatDrmInfo,
};
@@ -151,7 +150,6 @@
void notifyFlagsChanged(uint32_t flags);
void notifyVideoSizeChanged(const sp<AMessage> &format = NULL);
- void notifyInstantiateSecureDecoders(const sp<AMessage> &reply);
void notifyPrepared(status_t err = OK);
// Modular DRM
void notifyDrmInfo(const sp<ABuffer> &buffer);
diff --git a/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp b/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp
index 8b67ae5..1dfe383 100644
--- a/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp
+++ b/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp
@@ -43,13 +43,11 @@
const sp<MediaHTTPService> &httpService,
const char *url,
const KeyedVector<String8, String8> *headers,
- bool uidValid,
uid_t uid,
bool isSDP)
: Source(notify),
mHTTPService(httpService),
mURL(url),
- mUIDValid(uidValid),
mUID(uid),
mFlags(0),
mIsSDP(isSDP),
@@ -128,7 +126,7 @@
mSDPLoader->load(
mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
} else {
- mHandler = new MyHandler(mURL.c_str(), notify, mUIDValid, mUID);
+ mHandler = new MyHandler(mURL.c_str(), notify, true /* uidValid */, mUID);
mLooper->registerHandler(mHandler);
mHandler->connect();
@@ -793,7 +791,7 @@
} else {
sp<AMessage> notify = new AMessage(kWhatNotify, this);
- mHandler = new MyHandler(rtspUri.c_str(), notify, mUIDValid, mUID);
+ mHandler = new MyHandler(rtspUri.c_str(), notify, true /* uidValid */, mUID);
mLooper->registerHandler(mHandler);
mHandler->loadSDP(desc);
diff --git a/media/libmediaplayer2/nuplayer2/RTSPSource2.h b/media/libmediaplayer2/nuplayer2/RTSPSource2.h
index 739bd53..712c3e5 100644
--- a/media/libmediaplayer2/nuplayer2/RTSPSource2.h
+++ b/media/libmediaplayer2/nuplayer2/RTSPSource2.h
@@ -36,7 +36,6 @@
const sp<MediaHTTPService> &httpService,
const char *url,
const KeyedVector<String8, String8> *headers,
- bool uidValid = false,
uid_t uid = 0,
bool isSDP = false);
@@ -97,7 +96,6 @@
sp<MediaHTTPService> mHTTPService;
AString mURL;
KeyedVector<String8, String8> mExtraHeaders;
- bool mUIDValid;
uid_t mUID;
uint32_t mFlags;
bool mIsSDP;
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
index 3209c6d..1376ccc 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -126,8 +126,7 @@
sp<MediaPlayerBase> MediaPlayerFactory::createPlayer(
player_type playerType,
- const wp<IMediaPlayer> &client,
- notify_callback_f notifyFunc,
+ const sp<MediaPlayerBase::Listener> &listener,
pid_t pid) {
sp<MediaPlayerBase> p;
IFactory* factory;
@@ -152,7 +151,7 @@
init_result = p->initCheck();
if (init_result == NO_ERROR) {
- p->setNotifyCallback(client, notifyFunc);
+ p->setNotifyCallback(listener);
} else {
ALOGE("Failed to create player object of type %d, initCheck failed"
" (res = %d)", playerType, init_result);
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.h b/media/libmediaplayerservice/MediaPlayerFactory.h
index 6aedeb2..e88700c 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.h
+++ b/media/libmediaplayerservice/MediaPlayerFactory.h
@@ -65,8 +65,7 @@
const sp<DataSource> &source);
static sp<MediaPlayerBase> createPlayer(player_type playerType,
- const wp<IMediaPlayer> &client,
- notify_callback_f notifyFunc,
+ const sp<MediaPlayerBase::Listener> &listener,
pid_t pid);
static void registerBuiltinFactories();
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 88221ed..9bcfc83 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -572,10 +572,11 @@
mUid = uid;
mRetransmitEndpointValid = false;
mAudioAttributes = NULL;
+ mListener = new Listener(this);
#if CALLBACK_ANTAGONIZER
ALOGD("create Antagonizer");
- mAntagonizer = new Antagonizer(notify, this);
+ mAntagonizer = new Antagonizer(mListener);
#endif
}
@@ -610,7 +611,7 @@
// and reset the player. We assume the player will serialize
// access to itself if necessary.
if (p != 0) {
- p->setNotifyCallback(0, 0);
+ p->setNotifyCallback(0);
#if CALLBACK_ANTAGONIZER
ALOGD("kill Antagonizer");
mAntagonizer->kill();
@@ -635,7 +636,7 @@
p.clear();
}
if (p == NULL) {
- p = MediaPlayerFactory::createPlayer(playerType, this, notify, mPid);
+ p = MediaPlayerFactory::createPlayer(playerType, mListener, mPid);
}
if (p != NULL) {
@@ -1421,25 +1422,19 @@
}
void MediaPlayerService::Client::notify(
- const wp<IMediaPlayer> &listener, int msg, int ext1, int ext2, const Parcel *obj)
+ int msg, int ext1, int ext2, const Parcel *obj)
{
- sp<IMediaPlayer> spListener = listener.promote();
- if (spListener == NULL) {
- return;
- }
- Client* client = static_cast<Client*>(spListener.get());
-
sp<IMediaPlayerClient> c;
sp<Client> nextClient;
status_t errStartNext = NO_ERROR;
{
- Mutex::Autolock l(client->mLock);
- c = client->mClient;
- if (msg == MEDIA_PLAYBACK_COMPLETE && client->mNextClient != NULL) {
- nextClient = client->mNextClient;
+ Mutex::Autolock l(mLock);
+ c = mClient;
+ if (msg == MEDIA_PLAYBACK_COMPLETE && mNextClient != NULL) {
+ nextClient = mNextClient;
- if (client->mAudioOutput != NULL)
- client->mAudioOutput->switchToNextOutput();
+ if (mAudioOutput != NULL)
+ mAudioOutput->switchToNextOutput();
errStartNext = nextClient->start();
}
@@ -1465,17 +1460,17 @@
MEDIA_INFO_METADATA_UPDATE == ext1) {
const media::Metadata::Type metadata_type = ext2;
- if(client->shouldDropMetadata(metadata_type)) {
+ if(shouldDropMetadata(metadata_type)) {
return;
}
// Update the list of metadata that have changed. getMetadata
// also access mMetadataUpdated and clears it.
- client->addNewMetadataUpdate(metadata_type);
+ addNewMetadataUpdate(metadata_type);
}
if (c != NULL) {
- ALOGV("[%d] notify (%p, %d, %d, %d)", client->mConnId, spListener.get(), msg, ext1, ext2);
+ ALOGV("[%d] notify (%d, %d, %d)", mConnId, msg, ext1, ext2);
c->notify(msg, ext1, ext2, obj);
}
}
@@ -1569,8 +1564,8 @@
#if CALLBACK_ANTAGONIZER
const int Antagonizer::interval = 10000; // 10 msecs
-Antagonizer::Antagonizer(notify_callback_f cb, const wp<IMediaPlayer> &client) :
- mExit(false), mActive(false), mClient(client), mCb(cb)
+Antagonizer::Antagonizer(const sp<MediaPlayerBase::Listener> &listener) :
+ mExit(false), mActive(false), mListener(listener)
{
createThread(callbackThread, this);
}
@@ -1590,7 +1585,7 @@
while (!p->mExit) {
if (p->mActive) {
ALOGV("send event");
- p->mCb(p->mClient, 0, 0, 0);
+ p->mListener->notify(0, 0, 0, 0);
}
usleep(interval);
}
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 58efa8c..bfb7cc2 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -51,7 +51,7 @@
#if CALLBACK_ANTAGONIZER
class Antagonizer {
public:
- Antagonizer(notify_callback_f cb, const wp<IMediaPlayer> &client);
+ Antagonizer(const sp<MediaPlayerBase::Listener> &listener);
void start() { mActive = true; }
void stop() { mActive = false; }
void kill();
@@ -59,12 +59,11 @@
static const int interval;
Antagonizer();
static int callbackThread(void* cookie);
- Mutex mLock;
- Condition mCondition;
- bool mExit;
- bool mActive;
- wp<IMediaPlayer> mClient;
- notify_callback_f mCb;
+ Mutex mLock;
+ Condition mCondition;
+ bool mExit;
+ bool mActive;
+ sp<MediaPlayerBase::Listener> mListener;
};
#endif
@@ -228,7 +227,6 @@
}; // AudioOutput
-
public:
static void instantiate();
@@ -377,8 +375,7 @@
status_t setDataSource_post(const sp<MediaPlayerBase>& p,
status_t status);
- static void notify(const wp<IMediaPlayer> &cookie, int msg,
- int ext1, int ext2, const Parcel *obj);
+ void notify(int msg, int ext1, int ext2, const Parcel *obj);
pid_t pid() const { return mPid; }
virtual status_t dump(int fd, const Vector<String16>& args);
@@ -468,23 +465,38 @@
status_t setAudioAttributes_l(const Parcel &request);
- mutable Mutex mLock;
- sp<MediaPlayerBase> mPlayer;
- sp<MediaPlayerService> mService;
- sp<IMediaPlayerClient> mClient;
- sp<AudioOutput> mAudioOutput;
- pid_t mPid;
- status_t mStatus;
- bool mLoop;
- int32_t mConnId;
- audio_session_t mAudioSessionId;
- audio_attributes_t * mAudioAttributes;
- uid_t mUid;
- sp<ANativeWindow> mConnectedWindow;
- sp<IBinder> mConnectedWindowBinder;
- struct sockaddr_in mRetransmitEndpoint;
- bool mRetransmitEndpointValid;
- sp<Client> mNextClient;
+ class Listener : public MediaPlayerBase::Listener {
+ public:
+ Listener(const wp<Client> &client) : mClient(client) {}
+ virtual ~Listener() {}
+ virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) {
+ sp<Client> client = mClient.promote();
+ if (client != NULL) {
+ client->notify(msg, ext1, ext2, obj);
+ }
+ }
+ private:
+ wp<Client> mClient;
+ };
+
+ mutable Mutex mLock;
+ sp<MediaPlayerBase> mPlayer;
+ sp<MediaPlayerService> mService;
+ sp<IMediaPlayerClient> mClient;
+ sp<AudioOutput> mAudioOutput;
+ pid_t mPid;
+ status_t mStatus;
+ bool mLoop;
+ int32_t mConnId;
+ audio_session_t mAudioSessionId;
+ audio_attributes_t * mAudioAttributes;
+ uid_t mUid;
+ sp<ANativeWindow> mConnectedWindow;
+ sp<IBinder> mConnectedWindowBinder;
+ struct sockaddr_in mRetransmitEndpoint;
+ bool mRetransmitEndpointValid;
+ sp<Client> mNextClient;
+ sp<MediaPlayerBase::Listener> mListener;
// Metadata filters.
media::Metadata::Filter mMetadataAllow; // protected by mLock
@@ -500,7 +512,7 @@
sp<ServiceDeathNotifier> mCodecDeathListener;
sp<AudioDeviceUpdatedNotifier> mAudioDeviceUpdatedListener;
#if CALLBACK_ANTAGONIZER
- Antagonizer* mAntagonizer;
+ Antagonizer* mAntagonizer;
#endif
}; // Client
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index bc8d8c8..5cbf976 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -69,22 +69,26 @@
// key for media statistics
static const char *kKeyRecorder = "recorder";
// attrs for media statistics
-static const char *kRecorderHeight = "android.media.mediarecorder.height";
-static const char *kRecorderWidth = "android.media.mediarecorder.width";
-static const char *kRecorderFrameRate = "android.media.mediarecorder.frame-rate";
-static const char *kRecorderVideoBitrate = "android.media.mediarecorder.video-bitrate";
-static const char *kRecorderAudioSampleRate = "android.media.mediarecorder.audio-samplerate";
-static const char *kRecorderAudioChannels = "android.media.mediarecorder.audio-channels";
+// NB: these are matched with public Java API constants defined
+// in frameworks/base/media/java/android/media/MediaRecorder.java
+// These must be kept synchronized with the constants there.
static const char *kRecorderAudioBitrate = "android.media.mediarecorder.audio-bitrate";
-static const char *kRecorderVideoIframeInterval = "android.media.mediarecorder.video-iframe-interval";
-static const char *kRecorderMovieTimescale = "android.media.mediarecorder.movie-timescale";
+static const char *kRecorderAudioChannels = "android.media.mediarecorder.audio-channels";
+static const char *kRecorderAudioSampleRate = "android.media.mediarecorder.audio-samplerate";
static const char *kRecorderAudioTimescale = "android.media.mediarecorder.audio-timescale";
-static const char *kRecorderVideoTimescale = "android.media.mediarecorder.video-timescale";
-static const char *kRecorderVideoProfile = "android.media.mediarecorder.video-encoder-profile";
-static const char *kRecorderVideoLevel = "android.media.mediarecorder.video-encoder-level";
-static const char *kRecorderCaptureFpsEnable = "android.media.mediarecorder.capture-fpsenable";
static const char *kRecorderCaptureFps = "android.media.mediarecorder.capture-fps";
+static const char *kRecorderCaptureFpsEnable = "android.media.mediarecorder.capture-fpsenable";
+static const char *kRecorderFrameRate = "android.media.mediarecorder.frame-rate";
+static const char *kRecorderHeight = "android.media.mediarecorder.height";
+static const char *kRecorderMovieTimescale = "android.media.mediarecorder.movie-timescale";
static const char *kRecorderRotation = "android.media.mediarecorder.rotation";
+static const char *kRecorderVideoBitrate = "android.media.mediarecorder.video-bitrate";
+static const char *kRecorderVideoIframeInterval = "android.media.mediarecorder.video-iframe-interval";
+static const char *kRecorderVideoLevel = "android.media.mediarecorder.video-encoder-level";
+static const char *kRecorderVideoProfile = "android.media.mediarecorder.video-encoder-profile";
+static const char *kRecorderVideoTimescale = "android.media.mediarecorder.video-timescale";
+static const char *kRecorderWidth = "android.media.mediarecorder.width";
+
// To collect the encoder usage for the battery app
static void addBatteryData(uint32_t params) {
diff --git a/media/libmediaplayerservice/include/MediaPlayerInterface.h b/media/libmediaplayerservice/include/MediaPlayerInterface.h
index 4b33e61..3119950 100644
--- a/media/libmediaplayerservice/include/MediaPlayerInterface.h
+++ b/media/libmediaplayerservice/include/MediaPlayerInterface.h
@@ -66,14 +66,17 @@
// duration below which we do not allow deep audio buffering
#define AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US 5000000
-// callback mechanism for passing messages to MediaPlayer object
-typedef void (*notify_callback_f)(const wp<IMediaPlayer> &listener,
- int msg, int ext1, int ext2, const Parcel *obj);
-
// abstract base class - use MediaPlayerInterface
class MediaPlayerBase : public RefBase
{
public:
+ // callback mechanism for passing messages to MediaPlayer object
+ class Listener : public RefBase {
+ public:
+ virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) = 0;
+ virtual ~Listener() {}
+ };
+
// AudioSink: abstraction layer for audio output
class AudioSink : public RefBase {
public:
@@ -157,7 +160,7 @@
virtual status_t enableAudioDeviceCallback(bool enabled);
};
- MediaPlayerBase() : mClient(0), mNotify(0) {}
+ MediaPlayerBase() {}
virtual ~MediaPlayerBase() {}
virtual status_t initCheck() = 0;
virtual bool hardwareOutput() = 0;
@@ -271,22 +274,22 @@
};
void setNotifyCallback(
- const wp<IMediaPlayer> &client, notify_callback_f notifyFunc) {
+ const sp<Listener> &listener) {
Mutex::Autolock autoLock(mNotifyLock);
- mClient = client; mNotify = notifyFunc;
+ mListener = listener;
}
void sendEvent(int msg, int ext1=0, int ext2=0,
const Parcel *obj=NULL) {
- notify_callback_f notifyCB;
- wp<IMediaPlayer> client;
+ sp<Listener> listener;
{
Mutex::Autolock autoLock(mNotifyLock);
- notifyCB = mNotify;
- client = mClient;
+ listener = mListener;
}
- if (notifyCB) notifyCB(client, msg, ext1, ext2, obj);
+ if (listener != NULL) {
+ listener->notify(msg, ext1, ext2, obj);
+ }
}
virtual status_t dump(int /* fd */, const Vector<String16>& /* args */) const {
@@ -305,8 +308,7 @@
friend class MediaPlayerService;
Mutex mNotifyLock;
- wp<IMediaPlayer> mClient;
- notify_callback_f mNotify;
+ sp<Listener> mListener;
};
// Implement this class for media players that use the AudioFlinger software mixer
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index b3fd00a..c455951 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -43,6 +43,9 @@
// key for media statistics
static const char *kKeyPlayer = "nuplayer";
// attrs for media statistics
+ // NB: these are matched with public Java API constants defined
+ // in frameworks/base/media/java/android/media/MediaPlayer.java
+ // These must be kept synchronized with the constants there.
static const char *kPlayerVMime = "android.media.mediaplayer.video.mime";
static const char *kPlayerVCodec = "android.media.mediaplayer.video.codec";
static const char *kPlayerWidth = "android.media.mediaplayer.width";
@@ -55,6 +58,8 @@
static const char *kPlayerPlaying = "android.media.mediaplayer.playingMs";
static const char *kPlayerError = "android.media.mediaplayer.err";
static const char *kPlayerErrorCode = "android.media.mediaplayer.errcode";
+
+ // NB: These are not yet exposed as public Java API constants.
static const char *kPlayerErrorState = "android.media.mediaplayer.errstate";
static const char *kPlayerDataSourceType = "android.media.mediaplayer.dataSource";
//
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 2ec30dd..08b2775 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -130,10 +130,10 @@
"libui",
"libutils",
"libmedia_helper",
+ "libstagefright_bufferqueue_helper",
"libstagefright_codec2",
"libstagefright_codec2_vndk",
"libstagefright_foundation",
- "libstagefright_gbs",
"libstagefright_omx",
"libstagefright_omx_utils",
"libstagefright_xmlparser",
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 56ac3ed..2b33708 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -64,16 +64,22 @@
// key for media statistics
static const char *kCodecKeyName = "codec";
// attrs for media statistics
+// NB: these are matched with public Java API constants defined
+// in frameworks/base/media/java/android/media/MediaCodec.java
+// These must be kept synchronized with the constants there.
static const char *kCodecCodec = "android.media.mediacodec.codec"; /* e.g. OMX.google.aac.decoder */
static const char *kCodecMime = "android.media.mediacodec.mime"; /* e.g. audio/mime */
static const char *kCodecMode = "android.media.mediacodec.mode"; /* audio, video */
-static const char *kCodecSecure = "android.media.mediacodec.secure"; /* 0, 1 */
-static const char *kCodecHeight = "android.media.mediacodec.height"; /* 0..n */
-static const char *kCodecWidth = "android.media.mediacodec.width"; /* 0..n */
-static const char *kCodecRotation = "android.media.mediacodec.rotation-degrees"; /* 0/90/180/270 */
-static const char *kCodecCrypto = "android.media.mediacodec.crypto"; /* 0,1 */
+static const char *kCodecModeVideo = "video"; /* values returned for kCodecMode */
+static const char *kCodecModeAudio = "audio";
static const char *kCodecEncoder = "android.media.mediacodec.encoder"; /* 0,1 */
+static const char *kCodecSecure = "android.media.mediacodec.secure"; /* 0, 1 */
+static const char *kCodecWidth = "android.media.mediacodec.width"; /* 0..n */
+static const char *kCodecHeight = "android.media.mediacodec.height"; /* 0..n */
+static const char *kCodecRotation = "android.media.mediacodec.rotation-degrees"; /* 0/90/180/270 */
+// NB: These are not yet exposed as public Java API constants.
+static const char *kCodecCrypto = "android.media.mediacodec.crypto"; /* 0,1 */
static const char *kCodecBytesIn = "android.media.mediacodec.bytesin"; /* 0..n */
static const char *kCodecProfile = "android.media.mediacodec.profile"; /* 0..n */
static const char *kCodecLevel = "android.media.mediacodec.level"; /* 0..n */
@@ -645,7 +651,7 @@
} else {
mAnalyticsItem->setCString(kCodecCodec, name.c_str());
}
- mAnalyticsItem->setCString(kCodecMode, mIsVideo ? "video" : "audio");
+ mAnalyticsItem->setCString(kCodecMode, mIsVideo ? kCodecModeVideo : kCodecModeAudio);
if (nameIsType)
mAnalyticsItem->setInt32(kCodecEncoder, encoder);
}
@@ -2949,8 +2955,8 @@
if (mSoftRenderer != NULL) {
std::list<FrameRenderTracker::Info> doneFrames = mSoftRenderer->render(
- buffer->data(), buffer->size(),
- mediaTimeUs, renderTimeNs, NULL, buffer->format());
+ buffer->data(), buffer->size(), mediaTimeUs, renderTimeNs,
+ mPortBuffers[kPortIndexOutput].size(), buffer->format());
// if we are running, notify rendered frames
if (!doneFrames.empty() && mState == STARTED && mOnFrameRenderedNotification != NULL) {
diff --git a/media/libstagefright/RemoteMediaExtractor.cpp b/media/libstagefright/RemoteMediaExtractor.cpp
index d190780..5bb0953 100644
--- a/media/libstagefright/RemoteMediaExtractor.cpp
+++ b/media/libstagefright/RemoteMediaExtractor.cpp
@@ -32,9 +32,12 @@
static const char *kKeyExtractor = "extractor";
// attrs for media statistics
+// NB: these are matched with public Java API constants defined
+// in frameworks/base/media/java/android/media/MediaExtractor.java
+// These must be kept synchronized with the constants there.
+static const char *kExtractorFormat = "android.media.mediaextractor.fmt";
static const char *kExtractorMime = "android.media.mediaextractor.mime";
static const char *kExtractorTracks = "android.media.mediaextractor.ntrk";
-static const char *kExtractorFormat = "android.media.mediaextractor.fmt";
RemoteMediaExtractor::RemoteMediaExtractor(
MediaExtractor *extractor,
diff --git a/media/libstagefright/gbs/Android.bp b/media/libstagefright/bqhelper/Android.bp
similarity index 82%
rename from media/libstagefright/gbs/Android.bp
rename to media/libstagefright/bqhelper/Android.bp
index a53b7b7..b5b4a2a 100644
--- a/media/libstagefright/gbs/Android.bp
+++ b/media/libstagefright/bqhelper/Android.bp
@@ -1,5 +1,5 @@
cc_library_shared {
- name: "libstagefright_gbs",
+ name: "libstagefright_bufferqueue_helper",
vendor_available: true,
vndk: {
enabled: true,
@@ -8,6 +8,7 @@
srcs: [
"FrameDropper.cpp",
"GraphicBufferSource.cpp",
+ "WProducerListener.cpp",
],
export_include_dirs: [
@@ -25,12 +26,18 @@
shared_libs: [
"libbase",
"libbinder",
- "libutils",
- "liblog",
- "libui",
- "libgui",
"libcutils",
+ "libgui",
+ "libhidlbase",
+ "libhidlmemory",
+ "libhidltransport",
+ "liblog",
"libstagefright_foundation",
+ "libui",
+ "libutils",
+
+ "android.hardware.graphics.bufferqueue@1.0",
+
"libnativewindow", // TODO(b/62923479): use header library
],
diff --git a/media/libstagefright/gbs/FrameDropper.cpp b/media/libstagefright/bqhelper/FrameDropper.cpp
similarity index 97%
rename from media/libstagefright/gbs/FrameDropper.cpp
rename to media/libstagefright/bqhelper/FrameDropper.cpp
index 9f0b8cc..7afe837 100644
--- a/media/libstagefright/gbs/FrameDropper.cpp
+++ b/media/libstagefright/bqhelper/FrameDropper.cpp
@@ -18,7 +18,7 @@
#define LOG_TAG "FrameDropper"
#include <utils/Log.h>
-#include <media/stagefright/gbs/FrameDropper.h>
+#include <media/stagefright/bqhelper/FrameDropper.h>
#include <media/stagefright/foundation/ADebug.h>
namespace android {
diff --git a/media/libstagefright/gbs/GraphicBufferSource.cpp b/media/libstagefright/bqhelper/GraphicBufferSource.cpp
similarity index 99%
rename from media/libstagefright/gbs/GraphicBufferSource.cpp
rename to media/libstagefright/bqhelper/GraphicBufferSource.cpp
index 139c916..87d2555 100644
--- a/media/libstagefright/gbs/GraphicBufferSource.cpp
+++ b/media/libstagefright/bqhelper/GraphicBufferSource.cpp
@@ -22,8 +22,8 @@
#define STRINGIFY_ENUMS // for asString in HardwareAPI.h/VideoAPI.h
-#include <media/stagefright/gbs/GraphicBufferSource.h>
-#include <media/stagefright/gbs/FrameDropper.h>
+#include <media/stagefright/bqhelper/GraphicBufferSource.h>
+#include <media/stagefright/bqhelper/FrameDropper.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/ColorUtils.h>
diff --git a/media/libstagefright/omx/1.0/WProducerListener.cpp b/media/libstagefright/bqhelper/WProducerListener.cpp
similarity index 82%
rename from media/libstagefright/omx/1.0/WProducerListener.cpp
rename to media/libstagefright/bqhelper/WProducerListener.cpp
index bdc3aa1..2ca13be 100644
--- a/media/libstagefright/omx/1.0/WProducerListener.cpp
+++ b/media/libstagefright/bqhelper/WProducerListener.cpp
@@ -14,14 +14,9 @@
* limitations under the License.
*/
-#include <media/stagefright/omx/1.0/WProducerListener.h>
+#include <media/stagefright/bqhelper/WProducerListener.h>
namespace android {
-namespace hardware {
-namespace media {
-namespace omx {
-namespace V1_0 {
-namespace implementation {
// TWProducerListener
TWProducerListener::TWProducerListener(
@@ -52,9 +47,4 @@
return static_cast<bool>(mBase->needsReleaseNotify());
}
-} // namespace implementation
-} // namespace V1_0
-} // namespace omx
-} // namespace media
-} // namespace hardware
} // namespace android
diff --git a/media/libstagefright/gbs/include/media/stagefright/gbs/ComponentWrapper.h b/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/ComponentWrapper.h
similarity index 100%
rename from media/libstagefright/gbs/include/media/stagefright/gbs/ComponentWrapper.h
rename to media/libstagefright/bqhelper/include/media/stagefright/bqhelper/ComponentWrapper.h
diff --git a/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/Conversion.h b/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/Conversion.h
new file mode 100644
index 0000000..c15fafa
--- /dev/null
+++ b/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/Conversion.h
@@ -0,0 +1,1590 @@
+/*
+ * Copyright 2016, 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 MEDIA_STAGEFRIGHT_CONVERSION_H_
+#define MEDIA_STAGEFRIGHT_CONVERSION_H_
+
+#include <vector>
+#include <list>
+
+#include <unistd.h>
+
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <hidlmemory/mapping.h>
+
+#include <binder/Binder.h>
+#include <binder/Status.h>
+#include <ui/FenceTime.h>
+#include <cutils/native_handle.h>
+#include <gui/IGraphicBufferProducer.h>
+
+#include <media/hardware/VideoAPI.h>
+
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <android/hardware/graphics/bufferqueue/1.0/IProducerListener.h>
+
+namespace android {
+namespace conversion {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+using ::android::status_t;
+
+using ::android::String8;
+
+using ::android::hardware::media::V1_0::Rect;
+using ::android::hardware::media::V1_0::Region;
+
+using ::android::hardware::graphics::common::V1_0::Dataspace;
+
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+
+using ::android::hardware::media::V1_0::AnwBuffer;
+using ::android::GraphicBuffer;
+
+typedef ::android::hardware::graphics::bufferqueue::V1_0::IGraphicBufferProducer
+ HGraphicBufferProducer;
+typedef ::android::IGraphicBufferProducer
+ BGraphicBufferProducer;
+
+// native_handle_t helper functions.
+
+/**
+ * \brief Take an fd and create a native handle containing only the given fd.
+ * The created handle will need to be deleted manually with
+ * `native_handle_delete()`.
+ *
+ * \param[in] fd The source file descriptor (of type `int`).
+ * \return The create `native_handle_t*` that contains the given \p fd. If the
+ * supplied \p fd is negative, the created native handle will contain no file
+ * descriptors.
+ *
+ * If the native handle cannot be created, the return value will be
+ * `nullptr`.
+ *
+ * This function does not duplicate the file descriptor.
+ */
+inline native_handle_t* native_handle_create_from_fd(int fd) {
+ if (fd < 2) {
+ return native_handle_create(0, 0);
+ }
+ native_handle_t* nh = native_handle_create(1, 0);
+ if (nh == nullptr) {
+ return nullptr;
+ }
+ nh->data[0] = fd;
+ return nh;
+}
+
+/**
+ * \brief Extract a file descriptor from a native handle.
+ *
+ * \param[in] nh The source `native_handle_t*`.
+ * \param[in] index The index of the file descriptor in \p nh to read from. This
+ * input has the default value of `0`.
+ * \return The `index`-th file descriptor in \p nh. If \p nh does not have
+ * enough file descriptors, the returned value will be `-1`.
+ *
+ * This function does not duplicate the file descriptor.
+ */
+inline int native_handle_read_fd(native_handle_t const* nh, int index = 0) {
+ return ((nh == nullptr) || (nh->numFds == 0) ||
+ (nh->numFds <= index) || (index < 0)) ?
+ -1 : nh->data[index];
+}
+
+/**
+ * Conversion functions
+ * ====================
+ *
+ * There are two main directions of conversion:
+ * - `inTargetType(...)`: Create a wrapper whose lifetime depends on the
+ * input. The wrapper has type `TargetType`.
+ * - `toTargetType(...)`: Create a standalone object of type `TargetType` that
+ * corresponds to the input. The lifetime of the output does not depend on the
+ * lifetime of the input.
+ * - `wrapIn(TargetType*, ...)`: Same as `inTargetType()`, but for `TargetType`
+ * that cannot be copied and/or moved efficiently, or when there are multiple
+ * output arguments.
+ * - `convertTo(TargetType*, ...)`: Same as `toTargetType()`, but for
+ * `TargetType` that cannot be copied and/or moved efficiently, or when there
+ * are multiple output arguments.
+ *
+ * `wrapIn()` and `convertTo()` functions will take output arguments before
+ * input arguments. Some of these functions might return a value to indicate
+ * success or error.
+ *
+ * In converting or wrapping something as a Treble type that contains a
+ * `hidl_handle`, `native_handle_t*` will need to be created and returned as
+ * an additional output argument, hence only `wrapIn()` or `convertTo()` would
+ * be available. The caller must call `native_handle_delete()` to deallocate the
+ * returned native handle when it is no longer needed.
+ *
+ * For types that contain file descriptors, `inTargetType()` and `wrapAs()` do
+ * not perform duplication of file descriptors, while `toTargetType()` and
+ * `convertTo()` do.
+ */
+
+/**
+ * \brief Convert `Return<void>` to `binder::Status`.
+ *
+ * \param[in] t The source `Return<void>`.
+ * \return The corresponding `binder::Status`.
+ */
+// convert: Return<void> -> ::android::binder::Status
+inline ::android::binder::Status toBinderStatus(
+ Return<void> const& t) {
+ return ::android::binder::Status::fromExceptionCode(
+ t.isOk() ? OK : UNKNOWN_ERROR,
+ t.description().c_str());
+}
+
+/**
+ * \brief Convert `Return<void>` to `status_t`. This is for legacy binder calls.
+ *
+ * \param[in] t The source `Return<void>`.
+ * \return The corresponding `status_t`.
+ */
+// convert: Return<void> -> status_t
+inline status_t toStatusT(Return<void> const& t) {
+ return t.isOk() ? OK : UNKNOWN_ERROR;
+}
+
+/**
+ * \brief Wrap `native_handle_t*` in `hidl_handle`.
+ *
+ * \param[in] nh The source `native_handle_t*`.
+ * \return The `hidl_handle` that points to \p nh.
+ */
+// wrap: native_handle_t* -> hidl_handle
+inline hidl_handle inHidlHandle(native_handle_t const* nh) {
+ return hidl_handle(nh);
+}
+
+/**
+ * \brief Convert `int32_t` to `Dataspace`.
+ *
+ * \param[in] l The source `int32_t`.
+ * \result The corresponding `Dataspace`.
+ */
+// convert: int32_t -> Dataspace
+inline Dataspace toHardwareDataspace(int32_t l) {
+ return static_cast<Dataspace>(l);
+}
+
+/**
+ * \brief Convert `Dataspace` to `int32_t`.
+ *
+ * \param[in] t The source `Dataspace`.
+ * \result The corresponding `int32_t`.
+ */
+// convert: Dataspace -> int32_t
+inline int32_t toRawDataspace(Dataspace const& t) {
+ return static_cast<int32_t>(t);
+}
+
+/**
+ * \brief Wrap an opaque buffer inside a `hidl_vec<uint8_t>`.
+ *
+ * \param[in] l The pointer to the beginning of the opaque buffer.
+ * \param[in] size The size of the buffer.
+ * \return A `hidl_vec<uint8_t>` that points to the buffer.
+ */
+// wrap: void*, size_t -> hidl_vec<uint8_t>
+inline hidl_vec<uint8_t> inHidlBytes(void const* l, size_t size) {
+ hidl_vec<uint8_t> t;
+ t.setToExternal(static_cast<uint8_t*>(const_cast<void*>(l)), size, false);
+ return t;
+}
+
+/**
+ * \brief Create a `hidl_vec<uint8_t>` that is a copy of an opaque buffer.
+ *
+ * \param[in] l The pointer to the beginning of the opaque buffer.
+ * \param[in] size The size of the buffer.
+ * \return A `hidl_vec<uint8_t>` that is a copy of the input buffer.
+ */
+// convert: void*, size_t -> hidl_vec<uint8_t>
+inline hidl_vec<uint8_t> toHidlBytes(void const* l, size_t size) {
+ hidl_vec<uint8_t> t;
+ t.resize(size);
+ uint8_t const* src = static_cast<uint8_t const*>(l);
+ std::copy(src, src + size, t.data());
+ return t;
+}
+
+/**
+ * \brief Wrap `GraphicBuffer` in `AnwBuffer`.
+ *
+ * \param[out] t The wrapper of type `AnwBuffer`.
+ * \param[in] l The source `GraphicBuffer`.
+ */
+// wrap: GraphicBuffer -> AnwBuffer
+inline void wrapAs(AnwBuffer* t, GraphicBuffer const& l) {
+ t->attr.width = l.getWidth();
+ t->attr.height = l.getHeight();
+ t->attr.stride = l.getStride();
+ t->attr.format = static_cast<PixelFormat>(l.getPixelFormat());
+ t->attr.layerCount = l.getLayerCount();
+ t->attr.usage = l.getUsage();
+ t->attr.id = l.getId();
+ t->attr.generationNumber = l.getGenerationNumber();
+ t->nativeHandle = hidl_handle(l.handle);
+}
+
+/**
+ * \brief Convert `AnwBuffer` to `GraphicBuffer`.
+ *
+ * \param[out] l The destination `GraphicBuffer`.
+ * \param[in] t The source `AnwBuffer`.
+ *
+ * This function will duplicate all file descriptors in \p t.
+ */
+// convert: AnwBuffer -> GraphicBuffer
+// Ref: frameworks/native/libs/ui/GraphicBuffer.cpp: GraphicBuffer::flatten
+inline bool convertTo(GraphicBuffer* l, AnwBuffer const& t) {
+ native_handle_t* handle = t.nativeHandle == nullptr ?
+ nullptr : native_handle_clone(t.nativeHandle);
+
+ size_t const numInts = 12 + (handle ? handle->numInts : 0);
+ int32_t* ints = new int32_t[numInts];
+
+ size_t numFds = static_cast<size_t>(handle ? handle->numFds : 0);
+ int* fds = new int[numFds];
+
+ ints[0] = 'GBFR';
+ ints[1] = static_cast<int32_t>(t.attr.width);
+ ints[2] = static_cast<int32_t>(t.attr.height);
+ ints[3] = static_cast<int32_t>(t.attr.stride);
+ ints[4] = static_cast<int32_t>(t.attr.format);
+ ints[5] = static_cast<int32_t>(t.attr.layerCount);
+ ints[6] = static_cast<int32_t>(t.attr.usage);
+ ints[7] = static_cast<int32_t>(t.attr.id >> 32);
+ ints[8] = static_cast<int32_t>(t.attr.id & 0xFFFFFFFF);
+ ints[9] = static_cast<int32_t>(t.attr.generationNumber);
+ ints[10] = 0;
+ ints[11] = 0;
+ if (handle) {
+ ints[10] = static_cast<int32_t>(handle->numFds);
+ ints[11] = static_cast<int32_t>(handle->numInts);
+ int* intsStart = handle->data + handle->numFds;
+ std::copy(handle->data, intsStart, fds);
+ std::copy(intsStart, intsStart + handle->numInts, &ints[12]);
+ }
+
+ void const* constBuffer = static_cast<void const*>(ints);
+ size_t size = numInts * sizeof(int32_t);
+ int const* constFds = static_cast<int const*>(fds);
+ status_t status = l->unflatten(constBuffer, size, constFds, numFds);
+
+ delete [] fds;
+ delete [] ints;
+ native_handle_delete(handle);
+ return status == NO_ERROR;
+}
+
+/**
+ * Conversion functions for types outside media
+ * ============================================
+ *
+ * Some objects in libui and libgui that were made to go through binder calls do
+ * not expose ways to read or write their fields to the public. To pass an
+ * object of this kind through the HIDL boundary, translation functions need to
+ * work around the access restriction by using the publicly available
+ * `flatten()` and `unflatten()` functions.
+ *
+ * All `flatten()` and `unflatten()` overloads follow the same convention as
+ * follows:
+ *
+ * status_t flatten(ObjectType const& object,
+ * [OtherType const& other, ...]
+ * void*& buffer, size_t& size,
+ * int*& fds, size_t& numFds)
+ *
+ * status_t unflatten(ObjectType* object,
+ * [OtherType* other, ...,]
+ * void*& buffer, size_t& size,
+ * int*& fds, size_t& numFds)
+ *
+ * The number of `other` parameters varies depending on the `ObjectType`. For
+ * example, in the process of unflattening an object that contains
+ * `hidl_handle`, `other` is needed to hold `native_handle_t` objects that will
+ * be created.
+ *
+ * The last four parameters always work the same way in all overloads of
+ * `flatten()` and `unflatten()`:
+ * - For `flatten()`, `buffer` is the pointer to the non-fd buffer to be filled,
+ * `size` is the size (in bytes) of the non-fd buffer pointed to by `buffer`,
+ * `fds` is the pointer to the fd buffer to be filled, and `numFds` is the
+ * size (in ints) of the fd buffer pointed to by `fds`.
+ * - For `unflatten()`, `buffer` is the pointer to the non-fd buffer to be read
+ * from, `size` is the size (in bytes) of the non-fd buffer pointed to by
+ * `buffer`, `fds` is the pointer to the fd buffer to be read from, and
+ * `numFds` is the size (in ints) of the fd buffer pointed to by `fds`.
+ * - After a successful call to `flatten()` or `unflatten()`, `buffer` and `fds`
+ * will be advanced, while `size` and `numFds` will be decreased to reflect
+ * how much storage/data of the two buffers (fd and non-fd) have been used.
+ * - After an unsuccessful call, the values of `buffer`, `size`, `fds` and
+ * `numFds` are invalid.
+ *
+ * The return value of a successful `flatten()` or `unflatten()` call will be
+ * `OK` (also aliased as `NO_ERROR`). Any other values indicate a failure.
+ *
+ * For each object type that supports flattening, there will be two accompanying
+ * functions: `getFlattenedSize()` and `getFdCount()`. `getFlattenedSize()` will
+ * return the size of the non-fd buffer that the object will need for
+ * flattening. `getFdCount()` will return the size of the fd buffer that the
+ * object will need for flattening.
+ *
+ * The set of these four functions, `getFlattenedSize()`, `getFdCount()`,
+ * `flatten()` and `unflatten()`, are similar to functions of the same name in
+ * the abstract class `Flattenable`. The only difference is that functions in
+ * this file are not member functions of the object type. For example, we write
+ *
+ * flatten(x, buffer, size, fds, numFds)
+ *
+ * instead of
+ *
+ * x.flatten(buffer, size, fds, numFds)
+ *
+ * because we cannot modify the type of `x`.
+ *
+ * There is one exception to the naming convention: `hidl_handle` that
+ * represents a fence. The four functions for this "Fence" type have the word
+ * "Fence" attched to their names because the object type, which is
+ * `hidl_handle`, does not carry the special meaning that the object itself can
+ * only contain zero or one file descriptor.
+ */
+
+// Ref: frameworks/native/libs/ui/Fence.cpp
+
+/**
+ * \brief Return the size of the non-fd buffer required to flatten a fence.
+ *
+ * \param[in] fence The input fence of type `hidl_handle`.
+ * \return The required size of the flat buffer.
+ *
+ * The current version of this function always returns 4, which is the number of
+ * bytes required to store the number of file descriptors contained in the fd
+ * part of the flat buffer.
+ */
+inline size_t getFenceFlattenedSize(hidl_handle const& /* fence */) {
+ return 4;
+};
+
+/**
+ * \brief Return the number of file descriptors contained in a fence.
+ *
+ * \param[in] fence The input fence of type `hidl_handle`.
+ * \return `0` if \p fence does not contain a valid file descriptor, or `1`
+ * otherwise.
+ */
+inline size_t getFenceFdCount(hidl_handle const& fence) {
+ return native_handle_read_fd(fence) == -1 ? 0 : 1;
+}
+
+/**
+ * \brief Unflatten `Fence` to `hidl_handle`.
+ *
+ * \param[out] fence The destination `hidl_handle`.
+ * \param[out] nh The underlying native handle.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * If the return value is `NO_ERROR`, \p nh will point to a newly created
+ * native handle, which needs to be deleted with `native_handle_delete()`
+ * afterwards.
+ */
+inline status_t unflattenFence(hidl_handle* fence, native_handle_t** nh,
+ void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
+ if (size < 4) {
+ return NO_MEMORY;
+ }
+
+ uint32_t numFdsInHandle;
+ FlattenableUtils::read(buffer, size, numFdsInHandle);
+
+ if (numFdsInHandle > 1) {
+ return BAD_VALUE;
+ }
+
+ if (numFds < numFdsInHandle) {
+ return NO_MEMORY;
+ }
+
+ if (numFdsInHandle) {
+ *nh = native_handle_create_from_fd(*fds);
+ if (*nh == nullptr) {
+ return NO_MEMORY;
+ }
+ *fence = *nh;
+ ++fds;
+ --numFds;
+ } else {
+ *nh = nullptr;
+ *fence = hidl_handle();
+ }
+
+ return NO_ERROR;
+}
+
+/**
+ * \brief Flatten `hidl_handle` as `Fence`.
+ *
+ * \param[in] t The source `hidl_handle`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ */
+inline status_t flattenFence(hidl_handle const& fence,
+ void*& buffer, size_t& size, int*& fds, size_t& numFds) {
+ if (size < getFenceFlattenedSize(fence) ||
+ numFds < getFenceFdCount(fence)) {
+ return NO_MEMORY;
+ }
+ // Cast to uint32_t since the size of a size_t can vary between 32- and
+ // 64-bit processes
+ FlattenableUtils::write(buffer, size,
+ static_cast<uint32_t>(getFenceFdCount(fence)));
+ int fd = native_handle_read_fd(fence);
+ if (fd != -1) {
+ *fds = fd;
+ ++fds;
+ --numFds;
+ }
+ return NO_ERROR;
+}
+
+/**
+ * \brief Wrap `Fence` in `hidl_handle`.
+ *
+ * \param[out] t The wrapper of type `hidl_handle`.
+ * \param[out] nh The native handle pointed to by \p t.
+ * \param[in] l The source `Fence`.
+ *
+ * On success, \p nh will hold a newly created native handle, which must be
+ * deleted manually with `native_handle_delete()` afterwards.
+ */
+// wrap: Fence -> hidl_handle
+inline bool wrapAs(hidl_handle* t, native_handle_t** nh, Fence const& l) {
+ size_t const baseSize = l.getFlattenedSize();
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ return false;
+ }
+
+ size_t const baseNumFds = l.getFdCount();
+ std::unique_ptr<int[]> baseFds(
+ new (std::nothrow) int[baseNumFds]);
+ if (!baseFds) {
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ int* fds = static_cast<int*>(baseFds.get());
+ size_t numFds = baseNumFds;
+ if (l.flatten(buffer, size, fds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ int const* constFds = static_cast<int const*>(baseFds.get());
+ numFds = baseNumFds;
+ if (unflattenFence(t, nh, constBuffer, size, constFds, numFds)
+ != NO_ERROR) {
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * \brief Convert `hidl_handle` to `Fence`.
+ *
+ * \param[out] l The destination `Fence`. `l` must not have been used
+ * (`l->isValid()` must return `false`) before this function is called.
+ * \param[in] t The source `hidl_handle`.
+ *
+ * If \p t contains a valid file descriptor, it will be duplicated.
+ */
+// convert: hidl_handle -> Fence
+inline bool convertTo(Fence* l, hidl_handle const& t) {
+ int fd = native_handle_read_fd(t);
+ if (fd != -1) {
+ fd = dup(fd);
+ if (fd == -1) {
+ return false;
+ }
+ }
+ native_handle_t* nh = native_handle_create_from_fd(fd);
+ if (nh == nullptr) {
+ if (fd != -1) {
+ close(fd);
+ }
+ return false;
+ }
+
+ size_t const baseSize = getFenceFlattenedSize(t);
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ native_handle_delete(nh);
+ return false;
+ }
+
+ size_t const baseNumFds = getFenceFdCount(t);
+ std::unique_ptr<int[]> baseFds(
+ new (std::nothrow) int[baseNumFds]);
+ if (!baseFds) {
+ native_handle_delete(nh);
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ int* fds = static_cast<int*>(baseFds.get());
+ size_t numFds = baseNumFds;
+ if (flattenFence(hidl_handle(nh), buffer, size, fds, numFds) != NO_ERROR) {
+ native_handle_delete(nh);
+ return false;
+ }
+ native_handle_delete(nh);
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ int const* constFds = static_cast<int const*>(baseFds.get());
+ numFds = baseNumFds;
+ if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ return true;
+}
+
+// Ref: frameworks/native/libs/ui/FenceTime.cpp: FenceTime::Snapshot
+
+/**
+ * \brief Return the size of the non-fd buffer required to flatten
+ * `FenceTimeSnapshot`.
+ *
+ * \param[in] t The input `FenceTimeSnapshot`.
+ * \return The required size of the flat buffer.
+ */
+inline size_t getFlattenedSize(
+ HGraphicBufferProducer::FenceTimeSnapshot const& t) {
+ constexpr size_t min = sizeof(t.state);
+ switch (t.state) {
+ case HGraphicBufferProducer::FenceTimeSnapshot::State::EMPTY:
+ return min;
+ case HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE:
+ return min + getFenceFlattenedSize(t.fence);
+ case HGraphicBufferProducer::FenceTimeSnapshot::State::SIGNAL_TIME:
+ return min + sizeof(
+ ::android::FenceTime::Snapshot::signalTime);
+ }
+ return 0;
+}
+
+/**
+ * \brief Return the number of file descriptors contained in
+ * `FenceTimeSnapshot`.
+ *
+ * \param[in] t The input `FenceTimeSnapshot`.
+ * \return The number of file descriptors contained in \p snapshot.
+ */
+inline size_t getFdCount(
+ HGraphicBufferProducer::FenceTimeSnapshot const& t) {
+ return t.state ==
+ HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE ?
+ getFenceFdCount(t.fence) : 0;
+}
+
+/**
+ * \brief Flatten `FenceTimeSnapshot`.
+ *
+ * \param[in] t The source `FenceTimeSnapshot`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * This function will duplicate the file descriptor in `t.fence` if `t.state ==
+ * FENCE`.
+ */
+inline status_t flatten(HGraphicBufferProducer::FenceTimeSnapshot const& t,
+ void*& buffer, size_t& size, int*& fds, size_t& numFds) {
+ if (size < getFlattenedSize(t)) {
+ return NO_MEMORY;
+ }
+
+ switch (t.state) {
+ case HGraphicBufferProducer::FenceTimeSnapshot::State::EMPTY:
+ FlattenableUtils::write(buffer, size,
+ ::android::FenceTime::Snapshot::State::EMPTY);
+ return NO_ERROR;
+ case HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE:
+ FlattenableUtils::write(buffer, size,
+ ::android::FenceTime::Snapshot::State::FENCE);
+ return flattenFence(t.fence, buffer, size, fds, numFds);
+ case HGraphicBufferProducer::FenceTimeSnapshot::State::SIGNAL_TIME:
+ FlattenableUtils::write(buffer, size,
+ ::android::FenceTime::Snapshot::State::SIGNAL_TIME);
+ FlattenableUtils::write(buffer, size, t.signalTimeNs);
+ return NO_ERROR;
+ }
+ return NO_ERROR;
+}
+
+/**
+ * \brief Unflatten `FenceTimeSnapshot`.
+ *
+ * \param[out] t The destination `FenceTimeSnapshot`.
+ * \param[out] nh The underlying native handle.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * If the return value is `NO_ERROR` and the constructed snapshot contains a
+ * file descriptor, \p nh will be created to hold that file descriptor. In this
+ * case, \p nh needs to be deleted with `native_handle_delete()` afterwards.
+ */
+inline status_t unflatten(
+ HGraphicBufferProducer::FenceTimeSnapshot* t, native_handle_t** nh,
+ void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
+ if (size < sizeof(t->state)) {
+ return NO_MEMORY;
+ }
+
+ *nh = nullptr;
+ ::android::FenceTime::Snapshot::State state;
+ FlattenableUtils::read(buffer, size, state);
+ switch (state) {
+ case ::android::FenceTime::Snapshot::State::EMPTY:
+ t->state = HGraphicBufferProducer::FenceTimeSnapshot::State::EMPTY;
+ return NO_ERROR;
+ case ::android::FenceTime::Snapshot::State::FENCE:
+ t->state = HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE;
+ return unflattenFence(&t->fence, nh, buffer, size, fds, numFds);
+ case ::android::FenceTime::Snapshot::State::SIGNAL_TIME:
+ t->state = HGraphicBufferProducer::FenceTimeSnapshot::State::SIGNAL_TIME;
+ if (size < sizeof(t->signalTimeNs)) {
+ return NO_MEMORY;
+ }
+ FlattenableUtils::read(buffer, size, t->signalTimeNs);
+ return NO_ERROR;
+ }
+ return NO_ERROR;
+}
+
+// Ref: frameworks/native/libs/gui/FrameTimestamps.cpp: FrameEventsDelta
+
+/**
+ * \brief Return a lower bound on the size of the non-fd buffer required to
+ * flatten `FrameEventsDelta`.
+ *
+ * \param[in] t The input `FrameEventsDelta`.
+ * \return A lower bound on the size of the flat buffer.
+ */
+constexpr size_t minFlattenedSize(
+ HGraphicBufferProducer::FrameEventsDelta const& /* t */) {
+ return sizeof(uint64_t) + // mFrameNumber
+ sizeof(uint8_t) + // mIndex
+ sizeof(uint8_t) + // mAddPostCompositeCalled
+ sizeof(uint8_t) + // mAddRetireCalled
+ sizeof(uint8_t) + // mAddReleaseCalled
+ sizeof(nsecs_t) + // mPostedTime
+ sizeof(nsecs_t) + // mRequestedPresentTime
+ sizeof(nsecs_t) + // mLatchTime
+ sizeof(nsecs_t) + // mFirstRefreshStartTime
+ sizeof(nsecs_t); // mLastRefreshStartTime
+}
+
+/**
+ * \brief Return the size of the non-fd buffer required to flatten
+ * `FrameEventsDelta`.
+ *
+ * \param[in] t The input `FrameEventsDelta`.
+ * \return The required size of the flat buffer.
+ */
+inline size_t getFlattenedSize(
+ HGraphicBufferProducer::FrameEventsDelta const& t) {
+ return minFlattenedSize(t) +
+ getFlattenedSize(t.gpuCompositionDoneFence) +
+ getFlattenedSize(t.displayPresentFence) +
+ getFlattenedSize(t.displayRetireFence) +
+ getFlattenedSize(t.releaseFence);
+};
+
+/**
+ * \brief Return the number of file descriptors contained in
+ * `FrameEventsDelta`.
+ *
+ * \param[in] t The input `FrameEventsDelta`.
+ * \return The number of file descriptors contained in \p t.
+ */
+inline size_t getFdCount(
+ HGraphicBufferProducer::FrameEventsDelta const& t) {
+ return getFdCount(t.gpuCompositionDoneFence) +
+ getFdCount(t.displayPresentFence) +
+ getFdCount(t.displayRetireFence) +
+ getFdCount(t.releaseFence);
+};
+
+/**
+ * \brief Unflatten `FrameEventsDelta`.
+ *
+ * \param[out] t The destination `FrameEventsDelta`.
+ * \param[out] nh The underlying array of native handles.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * If the return value is `NO_ERROR`, \p nh will have length 4, and it will be
+ * populated with `nullptr` or newly created handles. Each non-null slot in \p
+ * nh will need to be deleted manually with `native_handle_delete()`.
+ */
+inline status_t unflatten(HGraphicBufferProducer::FrameEventsDelta* t,
+ std::vector<native_handle_t*>* nh,
+ void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
+ if (size < minFlattenedSize(*t)) {
+ return NO_MEMORY;
+ }
+ FlattenableUtils::read(buffer, size, t->frameNumber);
+
+ // These were written as uint8_t for alignment.
+ uint8_t temp = 0;
+ FlattenableUtils::read(buffer, size, temp);
+ size_t index = static_cast<size_t>(temp);
+ if (index >= ::android::FrameEventHistory::MAX_FRAME_HISTORY) {
+ return BAD_VALUE;
+ }
+ t->index = static_cast<uint32_t>(index);
+
+ FlattenableUtils::read(buffer, size, temp);
+ t->addPostCompositeCalled = static_cast<bool>(temp);
+ FlattenableUtils::read(buffer, size, temp);
+ t->addRetireCalled = static_cast<bool>(temp);
+ FlattenableUtils::read(buffer, size, temp);
+ t->addReleaseCalled = static_cast<bool>(temp);
+
+ FlattenableUtils::read(buffer, size, t->postedTimeNs);
+ FlattenableUtils::read(buffer, size, t->requestedPresentTimeNs);
+ FlattenableUtils::read(buffer, size, t->latchTimeNs);
+ FlattenableUtils::read(buffer, size, t->firstRefreshStartTimeNs);
+ FlattenableUtils::read(buffer, size, t->lastRefreshStartTimeNs);
+ FlattenableUtils::read(buffer, size, t->dequeueReadyTime);
+
+ // Fences
+ HGraphicBufferProducer::FenceTimeSnapshot* tSnapshot[4];
+ tSnapshot[0] = &t->gpuCompositionDoneFence;
+ tSnapshot[1] = &t->displayPresentFence;
+ tSnapshot[2] = &t->displayRetireFence;
+ tSnapshot[3] = &t->releaseFence;
+ nh->resize(4);
+ for (size_t snapshotIndex = 0; snapshotIndex < 4; ++snapshotIndex) {
+ status_t status = unflatten(
+ tSnapshot[snapshotIndex], &((*nh)[snapshotIndex]),
+ buffer, size, fds, numFds);
+ if (status != NO_ERROR) {
+ while (snapshotIndex > 0) {
+ --snapshotIndex;
+ if ((*nh)[snapshotIndex] != nullptr) {
+ native_handle_delete((*nh)[snapshotIndex]);
+ }
+ }
+ return status;
+ }
+ }
+ return NO_ERROR;
+}
+
+/**
+ * \brief Flatten `FrameEventsDelta`.
+ *
+ * \param[in] t The source `FrameEventsDelta`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * This function will duplicate file descriptors contained in \p t.
+ */
+// Ref: frameworks/native/libs/gui/FrameTimestamp.cpp:
+// FrameEventsDelta::flatten
+inline status_t flatten(HGraphicBufferProducer::FrameEventsDelta const& t,
+ void*& buffer, size_t& size, int*& fds, size_t numFds) {
+ // Check that t.index is within a valid range.
+ if (t.index >= static_cast<uint32_t>(FrameEventHistory::MAX_FRAME_HISTORY)
+ || t.index > std::numeric_limits<uint8_t>::max()) {
+ return BAD_VALUE;
+ }
+
+ FlattenableUtils::write(buffer, size, t.frameNumber);
+
+ // These are static_cast to uint8_t for alignment.
+ FlattenableUtils::write(buffer, size, static_cast<uint8_t>(t.index));
+ FlattenableUtils::write(
+ buffer, size, static_cast<uint8_t>(t.addPostCompositeCalled));
+ FlattenableUtils::write(
+ buffer, size, static_cast<uint8_t>(t.addRetireCalled));
+ FlattenableUtils::write(
+ buffer, size, static_cast<uint8_t>(t.addReleaseCalled));
+
+ FlattenableUtils::write(buffer, size, t.postedTimeNs);
+ FlattenableUtils::write(buffer, size, t.requestedPresentTimeNs);
+ FlattenableUtils::write(buffer, size, t.latchTimeNs);
+ FlattenableUtils::write(buffer, size, t.firstRefreshStartTimeNs);
+ FlattenableUtils::write(buffer, size, t.lastRefreshStartTimeNs);
+ FlattenableUtils::write(buffer, size, t.dequeueReadyTime);
+
+ // Fences
+ HGraphicBufferProducer::FenceTimeSnapshot const* tSnapshot[4];
+ tSnapshot[0] = &t.gpuCompositionDoneFence;
+ tSnapshot[1] = &t.displayPresentFence;
+ tSnapshot[2] = &t.displayRetireFence;
+ tSnapshot[3] = &t.releaseFence;
+ for (size_t snapshotIndex = 0; snapshotIndex < 4; ++snapshotIndex) {
+ status_t status = flatten(
+ *(tSnapshot[snapshotIndex]), buffer, size, fds, numFds);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ }
+ return NO_ERROR;
+}
+
+// Ref: frameworks/native/libs/gui/FrameTimestamps.cpp: FrameEventHistoryDelta
+
+/**
+ * \brief Return the size of the non-fd buffer required to flatten
+ * `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ *
+ * \param[in] t The input `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ * \return The required size of the flat buffer.
+ */
+inline size_t getFlattenedSize(
+ HGraphicBufferProducer::FrameEventHistoryDelta const& t) {
+ size_t size = 4 + // mDeltas.size()
+ sizeof(t.compositorTiming);
+ for (size_t i = 0; i < t.deltas.size(); ++i) {
+ size += getFlattenedSize(t.deltas[i]);
+ }
+ return size;
+}
+
+/**
+ * \brief Return the number of file descriptors contained in
+ * `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ *
+ * \param[in] t The input `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ * \return The number of file descriptors contained in \p t.
+ */
+inline size_t getFdCount(
+ HGraphicBufferProducer::FrameEventHistoryDelta const& t) {
+ size_t numFds = 0;
+ for (size_t i = 0; i < t.deltas.size(); ++i) {
+ numFds += getFdCount(t.deltas[i]);
+ }
+ return numFds;
+}
+
+/**
+ * \brief Unflatten `FrameEventHistoryDelta`.
+ *
+ * \param[out] t The destination `FrameEventHistoryDelta`.
+ * \param[out] nh The underlying array of arrays of native handles.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * If the return value is `NO_ERROR`, \p nh will be populated with `nullptr` or
+ * newly created handles. The second dimension of \p nh will be 4. Each non-null
+ * slot in \p nh will need to be deleted manually with `native_handle_delete()`.
+ */
+inline status_t unflatten(
+ HGraphicBufferProducer::FrameEventHistoryDelta* t,
+ std::vector<std::vector<native_handle_t*> >* nh,
+ void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
+ if (size < 4) {
+ return NO_MEMORY;
+ }
+
+ FlattenableUtils::read(buffer, size, t->compositorTiming);
+
+ uint32_t deltaCount = 0;
+ FlattenableUtils::read(buffer, size, deltaCount);
+ if (static_cast<size_t>(deltaCount) >
+ ::android::FrameEventHistory::MAX_FRAME_HISTORY) {
+ return BAD_VALUE;
+ }
+ t->deltas.resize(deltaCount);
+ nh->resize(deltaCount);
+ for (size_t deltaIndex = 0; deltaIndex < deltaCount; ++deltaIndex) {
+ status_t status = unflatten(
+ &(t->deltas[deltaIndex]), &((*nh)[deltaIndex]),
+ buffer, size, fds, numFds);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ }
+ return NO_ERROR;
+}
+
+/**
+ * \brief Flatten `FrameEventHistoryDelta`.
+ *
+ * \param[in] t The source `FrameEventHistoryDelta`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * This function will duplicate file descriptors contained in \p t.
+ */
+inline status_t flatten(
+ HGraphicBufferProducer::FrameEventHistoryDelta const& t,
+ void*& buffer, size_t& size, int*& fds, size_t& numFds) {
+ if (t.deltas.size() > ::android::FrameEventHistory::MAX_FRAME_HISTORY) {
+ return BAD_VALUE;
+ }
+ if (size < getFlattenedSize(t)) {
+ return NO_MEMORY;
+ }
+
+ FlattenableUtils::write(buffer, size, t.compositorTiming);
+
+ FlattenableUtils::write(buffer, size, static_cast<uint32_t>(t.deltas.size()));
+ for (size_t deltaIndex = 0; deltaIndex < t.deltas.size(); ++deltaIndex) {
+ status_t status = flatten(t.deltas[deltaIndex], buffer, size, fds, numFds);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ }
+ return NO_ERROR;
+}
+
+/**
+ * \brief Wrap `::android::FrameEventHistoryData` in
+ * `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ *
+ * \param[out] t The wrapper of type
+ * `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ * \param[out] nh The array of array of native handles that are referred to by
+ * members of \p t.
+ * \param[in] l The source `::android::FrameEventHistoryDelta`.
+ *
+ * On success, each member of \p nh will be either `nullptr` or a newly created
+ * native handle. All the non-`nullptr` elements must be deleted individually
+ * with `native_handle_delete()`.
+ */
+inline bool wrapAs(HGraphicBufferProducer::FrameEventHistoryDelta* t,
+ std::vector<std::vector<native_handle_t*> >* nh,
+ ::android::FrameEventHistoryDelta const& l) {
+
+ size_t const baseSize = l.getFlattenedSize();
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ return false;
+ }
+
+ size_t const baseNumFds = l.getFdCount();
+ std::unique_ptr<int[]> baseFds(
+ new (std::nothrow) int[baseNumFds]);
+ if (!baseFds) {
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ int* fds = baseFds.get();
+ size_t numFds = baseNumFds;
+ if (l.flatten(buffer, size, fds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ int const* constFds = static_cast<int const*>(baseFds.get());
+ numFds = baseNumFds;
+ if (unflatten(t, nh, constBuffer, size, constFds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * \brief Convert `HGraphicBufferProducer::FrameEventHistoryDelta` to
+ * `::android::FrameEventHistoryDelta`.
+ *
+ * \param[out] l The destination `::android::FrameEventHistoryDelta`.
+ * \param[in] t The source `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ *
+ * This function will duplicate all file descriptors contained in \p t.
+ */
+inline bool convertTo(
+ ::android::FrameEventHistoryDelta* l,
+ HGraphicBufferProducer::FrameEventHistoryDelta const& t) {
+
+ size_t const baseSize = getFlattenedSize(t);
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ return false;
+ }
+
+ size_t const baseNumFds = getFdCount(t);
+ std::unique_ptr<int[]> baseFds(
+ new (std::nothrow) int[baseNumFds]);
+ if (!baseFds) {
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ int* fds = static_cast<int*>(baseFds.get());
+ size_t numFds = baseNumFds;
+ if (flatten(t, buffer, size, fds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ int const* constFds = static_cast<int const*>(baseFds.get());
+ numFds = baseNumFds;
+ if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ return true;
+}
+
+// Ref: frameworks/native/libs/ui/Region.cpp
+
+/**
+ * \brief Return the size of the buffer required to flatten `Region`.
+ *
+ * \param[in] t The input `Region`.
+ * \return The required size of the flat buffer.
+ */
+inline size_t getFlattenedSize(Region const& t) {
+ return sizeof(uint32_t) + t.size() * sizeof(::android::Rect);
+}
+
+/**
+ * \brief Unflatten `Region`.
+ *
+ * \param[out] t The destination `Region`.
+ * \param[in,out] buffer The pointer to the flat buffer.
+ * \param[in,out] size The size of the flat buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ */
+inline status_t unflatten(Region* t, void const*& buffer, size_t& size) {
+ if (size < sizeof(uint32_t)) {
+ return NO_MEMORY;
+ }
+
+ uint32_t numRects = 0;
+ FlattenableUtils::read(buffer, size, numRects);
+ if (size < numRects * sizeof(Rect)) {
+ return NO_MEMORY;
+ }
+ if (numRects > (UINT32_MAX / sizeof(Rect))) {
+ return NO_MEMORY;
+ }
+
+ t->resize(numRects);
+ for (size_t r = 0; r < numRects; ++r) {
+ ::android::Rect rect(::android::Rect::EMPTY_RECT);
+ status_t status = rect.unflatten(buffer, size);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ FlattenableUtils::advance(buffer, size, sizeof(rect));
+ (*t)[r] = Rect{
+ static_cast<int32_t>(rect.left),
+ static_cast<int32_t>(rect.top),
+ static_cast<int32_t>(rect.right),
+ static_cast<int32_t>(rect.bottom)};
+ }
+ return NO_ERROR;
+}
+
+/**
+ * \brief Flatten `Region`.
+ *
+ * \param[in] t The source `Region`.
+ * \param[in,out] buffer The pointer to the flat buffer.
+ * \param[in,out] size The size of the flat buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ */
+inline status_t flatten(Region const& t, void*& buffer, size_t& size) {
+ if (size < getFlattenedSize(t)) {
+ return NO_MEMORY;
+ }
+
+ FlattenableUtils::write(buffer, size, static_cast<uint32_t>(t.size()));
+ for (size_t r = 0; r < t.size(); ++r) {
+ ::android::Rect rect(
+ static_cast<int32_t>(t[r].left),
+ static_cast<int32_t>(t[r].top),
+ static_cast<int32_t>(t[r].right),
+ static_cast<int32_t>(t[r].bottom));
+ status_t status = rect.flatten(buffer, size);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ FlattenableUtils::advance(buffer, size, sizeof(rect));
+ }
+ return NO_ERROR;
+}
+
+/**
+ * \brief Convert `::android::Region` to `Region`.
+ *
+ * \param[out] t The destination `Region`.
+ * \param[in] l The source `::android::Region`.
+ */
+// convert: ::android::Region -> Region
+inline bool convertTo(Region* t, ::android::Region const& l) {
+ size_t const baseSize = l.getFlattenedSize();
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ if (l.flatten(buffer, size) != NO_ERROR) {
+ return false;
+ }
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ if (unflatten(t, constBuffer, size) != NO_ERROR) {
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * \brief Convert `Region` to `::android::Region`.
+ *
+ * \param[out] l The destination `::android::Region`.
+ * \param[in] t The source `Region`.
+ */
+// convert: Region -> ::android::Region
+inline bool convertTo(::android::Region* l, Region const& t) {
+ size_t const baseSize = getFlattenedSize(t);
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ if (flatten(t, buffer, size) != NO_ERROR) {
+ return false;
+ }
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ if (l->unflatten(constBuffer, size) != NO_ERROR) {
+ return false;
+ }
+
+ return true;
+}
+
+// Ref: frameworks/native/libs/gui/BGraphicBufferProducer.cpp:
+// BGraphicBufferProducer::QueueBufferInput
+
+/**
+ * \brief Return a lower bound on the size of the buffer required to flatten
+ * `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[in] t The input `HGraphicBufferProducer::QueueBufferInput`.
+ * \return A lower bound on the size of the flat buffer.
+ */
+constexpr size_t minFlattenedSize(
+ HGraphicBufferProducer::QueueBufferInput const& /* t */) {
+ return sizeof(int64_t) + // timestamp
+ sizeof(int) + // isAutoTimestamp
+ sizeof(android_dataspace) + // dataSpace
+ sizeof(::android::Rect) + // crop
+ sizeof(int) + // scalingMode
+ sizeof(uint32_t) + // transform
+ sizeof(uint32_t) + // stickyTransform
+ sizeof(bool); // getFrameTimestamps
+}
+
+/**
+ * \brief Return the size of the buffer required to flatten
+ * `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[in] t The input `HGraphicBufferProducer::QueueBufferInput`.
+ * \return The required size of the flat buffer.
+ */
+inline size_t getFlattenedSize(HGraphicBufferProducer::QueueBufferInput const& t) {
+ return minFlattenedSize(t) +
+ getFenceFlattenedSize(t.fence) +
+ getFlattenedSize(t.surfaceDamage) +
+ sizeof(HdrMetadata::validTypes);
+}
+
+/**
+ * \brief Return the number of file descriptors contained in
+ * `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[in] t The input `HGraphicBufferProducer::QueueBufferInput`.
+ * \return The number of file descriptors contained in \p t.
+ */
+inline size_t getFdCount(
+ HGraphicBufferProducer::QueueBufferInput const& t) {
+ return getFenceFdCount(t.fence);
+}
+
+/**
+ * \brief Flatten `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[in] t The source `HGraphicBufferProducer::QueueBufferInput`.
+ * \param[out] nh The native handle cloned from `t.fence`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * This function will duplicate the file descriptor in `t.fence`. */
+inline status_t flatten(HGraphicBufferProducer::QueueBufferInput const& t,
+ native_handle_t** nh,
+ void*& buffer, size_t& size, int*& fds, size_t& numFds) {
+ if (size < getFlattenedSize(t)) {
+ return NO_MEMORY;
+ }
+
+ FlattenableUtils::write(buffer, size, t.timestamp);
+ FlattenableUtils::write(buffer, size, static_cast<int>(t.isAutoTimestamp));
+ FlattenableUtils::write(buffer, size,
+ static_cast<android_dataspace_t>(t.dataSpace));
+ FlattenableUtils::write(buffer, size, ::android::Rect(
+ static_cast<int32_t>(t.crop.left),
+ static_cast<int32_t>(t.crop.top),
+ static_cast<int32_t>(t.crop.right),
+ static_cast<int32_t>(t.crop.bottom)));
+ FlattenableUtils::write(buffer, size, static_cast<int>(t.scalingMode));
+ FlattenableUtils::write(buffer, size, t.transform);
+ FlattenableUtils::write(buffer, size, t.stickyTransform);
+ FlattenableUtils::write(buffer, size, t.getFrameTimestamps);
+
+ *nh = t.fence.getNativeHandle() == nullptr ?
+ nullptr : native_handle_clone(t.fence);
+ status_t status = flattenFence(hidl_handle(*nh), buffer, size, fds, numFds);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ status = flatten(t.surfaceDamage, buffer, size);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ FlattenableUtils::write(buffer, size, decltype(HdrMetadata::validTypes)(0));
+ return NO_ERROR;
+}
+
+/**
+ * \brief Unflatten `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[out] t The destination `HGraphicBufferProducer::QueueBufferInput`.
+ * \param[out] nh The underlying native handle for `t->fence`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * If the return value is `NO_ERROR` and `t->fence` contains a valid file
+ * descriptor, \p nh will be a newly created native handle holding that file
+ * descriptor. \p nh needs to be deleted with `native_handle_delete()`
+ * afterwards.
+ */
+inline status_t unflatten(
+ HGraphicBufferProducer::QueueBufferInput* t, native_handle_t** nh,
+ void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
+ if (size < minFlattenedSize(*t)) {
+ return NO_MEMORY;
+ }
+
+ FlattenableUtils::read(buffer, size, t->timestamp);
+ int lIsAutoTimestamp;
+ FlattenableUtils::read(buffer, size, lIsAutoTimestamp);
+ t->isAutoTimestamp = static_cast<int32_t>(lIsAutoTimestamp);
+ android_dataspace_t lDataSpace;
+ FlattenableUtils::read(buffer, size, lDataSpace);
+ t->dataSpace = static_cast<Dataspace>(lDataSpace);
+ Rect lCrop;
+ FlattenableUtils::read(buffer, size, lCrop);
+ t->crop = Rect{
+ static_cast<int32_t>(lCrop.left),
+ static_cast<int32_t>(lCrop.top),
+ static_cast<int32_t>(lCrop.right),
+ static_cast<int32_t>(lCrop.bottom)};
+ int lScalingMode;
+ FlattenableUtils::read(buffer, size, lScalingMode);
+ t->scalingMode = static_cast<int32_t>(lScalingMode);
+ FlattenableUtils::read(buffer, size, t->transform);
+ FlattenableUtils::read(buffer, size, t->stickyTransform);
+ FlattenableUtils::read(buffer, size, t->getFrameTimestamps);
+
+ status_t status = unflattenFence(&(t->fence), nh,
+ buffer, size, fds, numFds);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ // HdrMetadata ignored
+ return unflatten(&(t->surfaceDamage), buffer, size);
+}
+
+/**
+ * \brief Wrap `BGraphicBufferProducer::QueueBufferInput` in
+ * `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[out] t The wrapper of type
+ * `HGraphicBufferProducer::QueueBufferInput`.
+ * \param[out] nh The underlying native handle for `t->fence`.
+ * \param[in] l The source `BGraphicBufferProducer::QueueBufferInput`.
+ *
+ * If the return value is `true` and `t->fence` contains a valid file
+ * descriptor, \p nh will be a newly created native handle holding that file
+ * descriptor. \p nh needs to be deleted with `native_handle_delete()`
+ * afterwards.
+ */
+inline bool wrapAs(
+ HGraphicBufferProducer::QueueBufferInput* t,
+ native_handle_t** nh,
+ BGraphicBufferProducer::QueueBufferInput const& l) {
+
+ size_t const baseSize = l.getFlattenedSize();
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ return false;
+ }
+
+ size_t const baseNumFds = l.getFdCount();
+ std::unique_ptr<int[]> baseFds(
+ new (std::nothrow) int[baseNumFds]);
+ if (!baseFds) {
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ int* fds = baseFds.get();
+ size_t numFds = baseNumFds;
+ if (l.flatten(buffer, size, fds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ int const* constFds = static_cast<int const*>(baseFds.get());
+ numFds = baseNumFds;
+ if (unflatten(t, nh, constBuffer, size, constFds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * \brief Convert `HGraphicBufferProducer::QueueBufferInput` to
+ * `BGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[out] l The destination `BGraphicBufferProducer::QueueBufferInput`.
+ * \param[in] t The source `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * If `t.fence` has a valid file descriptor, it will be duplicated.
+ */
+inline bool convertTo(
+ BGraphicBufferProducer::QueueBufferInput* l,
+ HGraphicBufferProducer::QueueBufferInput const& t) {
+
+ size_t const baseSize = getFlattenedSize(t);
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ return false;
+ }
+
+ size_t const baseNumFds = getFdCount(t);
+ std::unique_ptr<int[]> baseFds(
+ new (std::nothrow) int[baseNumFds]);
+ if (!baseFds) {
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ int* fds = baseFds.get();
+ size_t numFds = baseNumFds;
+ native_handle_t* nh;
+ if (flatten(t, &nh, buffer, size, fds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ int const* constFds = static_cast<int const*>(baseFds.get());
+ numFds = baseNumFds;
+ if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
+ if (nh != nullptr) {
+ native_handle_close(nh);
+ native_handle_delete(nh);
+ }
+ return false;
+ }
+
+ native_handle_delete(nh);
+ return true;
+}
+
+// Ref: frameworks/native/libs/gui/BGraphicBufferProducer.cpp:
+// BGraphicBufferProducer::QueueBufferOutput
+
+/**
+ * \brief Wrap `BGraphicBufferProducer::QueueBufferOutput` in
+ * `HGraphicBufferProducer::QueueBufferOutput`.
+ *
+ * \param[out] t The wrapper of type
+ * `HGraphicBufferProducer::QueueBufferOutput`.
+ * \param[out] nh The array of array of native handles that are referred to by
+ * members of \p t.
+ * \param[in] l The source `BGraphicBufferProducer::QueueBufferOutput`.
+ *
+ * On success, each member of \p nh will be either `nullptr` or a newly created
+ * native handle. All the non-`nullptr` elements must be deleted individually
+ * with `native_handle_delete()`.
+ */
+// wrap: BGraphicBufferProducer::QueueBufferOutput ->
+// HGraphicBufferProducer::QueueBufferOutput
+inline bool wrapAs(HGraphicBufferProducer::QueueBufferOutput* t,
+ std::vector<std::vector<native_handle_t*> >* nh,
+ BGraphicBufferProducer::QueueBufferOutput const& l) {
+ if (!wrapAs(&(t->frameTimestamps), nh, l.frameTimestamps)) {
+ return false;
+ }
+ t->width = l.width;
+ t->height = l.height;
+ t->transformHint = l.transformHint;
+ t->numPendingBuffers = l.numPendingBuffers;
+ t->nextFrameNumber = l.nextFrameNumber;
+ t->bufferReplaced = l.bufferReplaced;
+ return true;
+}
+
+/**
+ * \brief Convert `HGraphicBufferProducer::QueueBufferOutput` to
+ * `BGraphicBufferProducer::QueueBufferOutput`.
+ *
+ * \param[out] l The destination `BGraphicBufferProducer::QueueBufferOutput`.
+ * \param[in] t The source `HGraphicBufferProducer::QueueBufferOutput`.
+ *
+ * This function will duplicate all file descriptors contained in \p t.
+ */
+// convert: HGraphicBufferProducer::QueueBufferOutput ->
+// BGraphicBufferProducer::QueueBufferOutput
+inline bool convertTo(
+ BGraphicBufferProducer::QueueBufferOutput* l,
+ HGraphicBufferProducer::QueueBufferOutput const& t) {
+ if (!convertTo(&(l->frameTimestamps), t.frameTimestamps)) {
+ return false;
+ }
+ l->width = t.width;
+ l->height = t.height;
+ l->transformHint = t.transformHint;
+ l->numPendingBuffers = t.numPendingBuffers;
+ l->nextFrameNumber = t.nextFrameNumber;
+ l->bufferReplaced = t.bufferReplaced;
+ return true;
+}
+
+/**
+ * \brief Convert `BGraphicBufferProducer::DisconnectMode` to
+ * `HGraphicBufferProducer::DisconnectMode`.
+ *
+ * \param[in] l The source `BGraphicBufferProducer::DisconnectMode`.
+ * \return The corresponding `HGraphicBufferProducer::DisconnectMode`.
+ */
+inline HGraphicBufferProducer::DisconnectMode toHidlDisconnectMode(
+ BGraphicBufferProducer::DisconnectMode l) {
+ switch (l) {
+ case BGraphicBufferProducer::DisconnectMode::Api:
+ return HGraphicBufferProducer::DisconnectMode::API;
+ case BGraphicBufferProducer::DisconnectMode::AllLocal:
+ return HGraphicBufferProducer::DisconnectMode::ALL_LOCAL;
+ }
+ return HGraphicBufferProducer::DisconnectMode::API;
+}
+
+/**
+ * \brief Convert `HGraphicBufferProducer::DisconnectMode` to
+ * `BGraphicBufferProducer::DisconnectMode`.
+ *
+ * \param[in] l The source `HGraphicBufferProducer::DisconnectMode`.
+ * \return The corresponding `BGraphicBufferProducer::DisconnectMode`.
+ */
+inline BGraphicBufferProducer::DisconnectMode toGuiDisconnectMode(
+ HGraphicBufferProducer::DisconnectMode t) {
+ switch (t) {
+ case HGraphicBufferProducer::DisconnectMode::API:
+ return BGraphicBufferProducer::DisconnectMode::Api;
+ case HGraphicBufferProducer::DisconnectMode::ALL_LOCAL:
+ return BGraphicBufferProducer::DisconnectMode::AllLocal;
+ }
+ return BGraphicBufferProducer::DisconnectMode::Api;
+}
+
+} // namespace conversion
+} // namespace android
+
+#endif // MEDIA_STAGEFRIGHT_CONVERSION_H_
diff --git a/media/libstagefright/gbs/include/media/stagefright/gbs/FrameDropper.h b/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/FrameDropper.h
similarity index 100%
rename from media/libstagefright/gbs/include/media/stagefright/gbs/FrameDropper.h
rename to media/libstagefright/bqhelper/include/media/stagefright/bqhelper/FrameDropper.h
diff --git a/media/libstagefright/gbs/include/media/stagefright/gbs/GraphicBufferSource.h b/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/GraphicBufferSource.h
similarity index 99%
rename from media/libstagefright/gbs/include/media/stagefright/gbs/GraphicBufferSource.h
rename to media/libstagefright/bqhelper/include/media/stagefright/bqhelper/GraphicBufferSource.h
index 89f6cf8..5af9556 100644
--- a/media/libstagefright/gbs/include/media/stagefright/gbs/GraphicBufferSource.h
+++ b/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/GraphicBufferSource.h
@@ -27,7 +27,7 @@
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/foundation/AHandlerReflector.h>
#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/gbs/ComponentWrapper.h>
+#include <media/stagefright/bqhelper/ComponentWrapper.h>
namespace android {
diff --git a/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/WGraphicBufferProducer.h b/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/WGraphicBufferProducer.h
new file mode 100644
index 0000000..6f594fd
--- /dev/null
+++ b/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/WGraphicBufferProducer.h
@@ -0,0 +1,372 @@
+/*
+ * Copyright 2016, 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 MEDIA_STAGEFRIGHT_WGRAPHICBUFFERPRODUCER_H_
+#define MEDIA_STAGEFRIGHT_WGRAPHICBUFFERPRODUCER_H_
+
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <android-base/logging.h>
+#include <binder/Binder.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/IProducerListener.h>
+#include <media/stagefright/bqhelper/Conversion.h>
+#include <media/stagefright/bqhelper/WProducerListener.h>
+#include <system/window.h>
+
+#include <android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h>
+
+namespace android {
+
+using ::android::hardware::media::V1_0::AnwBuffer;
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+typedef ::android::hardware::graphics::bufferqueue::V1_0::
+ IGraphicBufferProducer HGraphicBufferProducer;
+typedef ::android::hardware::graphics::bufferqueue::V1_0::
+ IProducerListener HProducerListener;
+
+typedef ::android::IGraphicBufferProducer BGraphicBufferProducer;
+typedef ::android::IProducerListener BProducerListener;
+using ::android::BnGraphicBufferProducer;
+
+// Instantiate only if HGraphicBufferProducer is base of BASE.
+template <typename BASE,
+ typename = typename std::enable_if<std::is_base_of<HGraphicBufferProducer, BASE>::value>::type>
+struct TWGraphicBufferProducer : public BASE {
+ TWGraphicBufferProducer(sp<BGraphicBufferProducer> const& base) : mBase(base) {}
+ Return<void> requestBuffer(int32_t slot, HGraphicBufferProducer::requestBuffer_cb _hidl_cb) override {
+ sp<GraphicBuffer> buf;
+ status_t status = mBase->requestBuffer(slot, &buf);
+ AnwBuffer anwBuffer;
+ if (buf != nullptr) {
+ ::android::conversion::wrapAs(&anwBuffer, *buf);
+ }
+ _hidl_cb(static_cast<int32_t>(status), anwBuffer);
+ return Void();
+ }
+
+ Return<int32_t> setMaxDequeuedBufferCount(int32_t maxDequeuedBuffers) override {
+ return static_cast<int32_t>(mBase->setMaxDequeuedBufferCount(
+ static_cast<int>(maxDequeuedBuffers)));
+ }
+
+ Return<int32_t> setAsyncMode(bool async) override {
+ return static_cast<int32_t>(mBase->setAsyncMode(async));
+ }
+
+ Return<void> dequeueBuffer(
+ uint32_t width, uint32_t height,
+ ::android::hardware::graphics::common::V1_0::PixelFormat format, uint32_t usage,
+ bool getFrameTimestamps, HGraphicBufferProducer::dequeueBuffer_cb _hidl_cb) override {
+ int slot;
+ sp<Fence> fence;
+ ::android::FrameEventHistoryDelta outTimestamps;
+ status_t status = mBase->dequeueBuffer(
+ &slot, &fence, width, height,
+ static_cast<::android::PixelFormat>(format), usage, nullptr,
+ getFrameTimestamps ? &outTimestamps : nullptr);
+ hidl_handle tFence;
+ HGraphicBufferProducer::FrameEventHistoryDelta tOutTimestamps;
+
+ native_handle_t* nh = nullptr;
+ if ((fence == nullptr) || !::android::conversion::wrapAs(&tFence, &nh, *fence)) {
+ LOG(ERROR) << "TWGraphicBufferProducer::dequeueBuffer - "
+ "Invalid output fence";
+ _hidl_cb(static_cast<int32_t>(status),
+ static_cast<int32_t>(slot),
+ tFence,
+ tOutTimestamps);
+ return Void();
+ }
+ std::vector<std::vector<native_handle_t*> > nhAA;
+ if (getFrameTimestamps && !::android::conversion::wrapAs(&tOutTimestamps, &nhAA, outTimestamps)) {
+ LOG(ERROR) << "TWGraphicBufferProducer::dequeueBuffer - "
+ "Invalid output timestamps";
+ _hidl_cb(static_cast<int32_t>(status),
+ static_cast<int32_t>(slot),
+ tFence,
+ tOutTimestamps);
+ native_handle_delete(nh);
+ return Void();
+ }
+
+ _hidl_cb(static_cast<int32_t>(status),
+ static_cast<int32_t>(slot),
+ tFence,
+ tOutTimestamps);
+ native_handle_delete(nh);
+ if (getFrameTimestamps) {
+ for (auto& nhA : nhAA) {
+ for (auto& handle : nhA) {
+ native_handle_delete(handle);
+ }
+ }
+ }
+ return Void();
+ }
+
+ Return<int32_t> detachBuffer(int32_t slot) override {
+ return static_cast<int32_t>(mBase->detachBuffer(slot));
+ }
+
+ Return<void> detachNextBuffer(HGraphicBufferProducer::detachNextBuffer_cb _hidl_cb) override {
+ sp<GraphicBuffer> outBuffer;
+ sp<Fence> outFence;
+ status_t status = mBase->detachNextBuffer(&outBuffer, &outFence);
+ AnwBuffer tBuffer;
+ hidl_handle tFence;
+
+ if (outBuffer == nullptr) {
+ LOG(ERROR) << "TWGraphicBufferProducer::detachNextBuffer - "
+ "Invalid output buffer";
+ _hidl_cb(static_cast<int32_t>(status), tBuffer, tFence);
+ return Void();
+ }
+ ::android::conversion::wrapAs(&tBuffer, *outBuffer);
+ native_handle_t* nh = nullptr;
+ if ((outFence != nullptr) && !::android::conversion::wrapAs(&tFence, &nh, *outFence)) {
+ LOG(ERROR) << "TWGraphicBufferProducer::detachNextBuffer - "
+ "Invalid output fence";
+ _hidl_cb(static_cast<int32_t>(status), tBuffer, tFence);
+ return Void();
+ }
+
+ _hidl_cb(static_cast<int32_t>(status), tBuffer, tFence);
+ native_handle_delete(nh);
+ return Void();
+ }
+
+ Return<void> attachBuffer(const AnwBuffer& buffer, HGraphicBufferProducer::attachBuffer_cb _hidl_cb) override {
+ int outSlot;
+ sp<GraphicBuffer> lBuffer = new GraphicBuffer();
+ if (!::android::conversion::convertTo(lBuffer.get(), buffer)) {
+ LOG(ERROR) << "TWGraphicBufferProducer::attachBuffer - "
+ "Invalid input native window buffer";
+ _hidl_cb(static_cast<int32_t>(BAD_VALUE), -1);
+ return Void();
+ }
+ status_t status = mBase->attachBuffer(&outSlot, lBuffer);
+
+ _hidl_cb(static_cast<int32_t>(status), static_cast<int32_t>(outSlot));
+ return Void();
+ }
+
+ Return<void> queueBuffer(
+ int32_t slot, const HGraphicBufferProducer::QueueBufferInput& input,
+ HGraphicBufferProducer::queueBuffer_cb _hidl_cb) override {
+ HGraphicBufferProducer::QueueBufferOutput tOutput;
+ BGraphicBufferProducer::QueueBufferInput lInput(
+ 0, false, HAL_DATASPACE_UNKNOWN,
+ ::android::Rect(0, 0, 1, 1),
+ NATIVE_WINDOW_SCALING_MODE_FREEZE,
+ 0, ::android::Fence::NO_FENCE);
+ if (!::android::conversion::convertTo(&lInput, input)) {
+ LOG(ERROR) << "TWGraphicBufferProducer::queueBuffer - "
+ "Invalid input";
+ _hidl_cb(static_cast<int32_t>(BAD_VALUE), tOutput);
+ return Void();
+ }
+ BGraphicBufferProducer::QueueBufferOutput lOutput;
+ status_t status = mBase->queueBuffer(
+ static_cast<int>(slot), lInput, &lOutput);
+
+ std::vector<std::vector<native_handle_t*> > nhAA;
+ if (!::android::conversion::wrapAs(&tOutput, &nhAA, lOutput)) {
+ LOG(ERROR) << "TWGraphicBufferProducer::queueBuffer - "
+ "Invalid output";
+ _hidl_cb(static_cast<int32_t>(BAD_VALUE), tOutput);
+ return Void();
+ }
+
+ _hidl_cb(static_cast<int32_t>(status), tOutput);
+ for (auto& nhA : nhAA) {
+ for (auto& nh : nhA) {
+ native_handle_delete(nh);
+ }
+ }
+ return Void();
+ }
+
+ Return<int32_t> cancelBuffer(int32_t slot, const hidl_handle& fence) override {
+ sp<Fence> lFence = new Fence();
+ if (!::android::conversion::convertTo(lFence.get(), fence)) {
+ LOG(ERROR) << "TWGraphicBufferProducer::cancelBuffer - "
+ "Invalid input fence";
+ return static_cast<int32_t>(BAD_VALUE);
+ }
+ return static_cast<int32_t>(mBase->cancelBuffer(static_cast<int>(slot), lFence));
+ }
+
+ Return<void> query(int32_t what, HGraphicBufferProducer::query_cb _hidl_cb) override {
+ int lValue;
+ int lReturn = mBase->query(static_cast<int>(what), &lValue);
+ _hidl_cb(static_cast<int32_t>(lReturn), static_cast<int32_t>(lValue));
+ return Void();
+ }
+
+ Return<void> connect(const sp<HProducerListener>& listener,
+ int32_t api, bool producerControlledByApp,
+ HGraphicBufferProducer::connect_cb _hidl_cb) override {
+ sp<BProducerListener> lListener = listener == nullptr ?
+ nullptr : new LWProducerListener(listener);
+ BGraphicBufferProducer::QueueBufferOutput lOutput;
+ status_t status = mBase->connect(lListener,
+ static_cast<int>(api),
+ producerControlledByApp,
+ &lOutput);
+
+ HGraphicBufferProducer::QueueBufferOutput tOutput;
+ std::vector<std::vector<native_handle_t*> > nhAA;
+ if (!::android::conversion::wrapAs(&tOutput, &nhAA, lOutput)) {
+ LOG(ERROR) << "TWGraphicBufferProducer::connect - "
+ "Invalid output";
+ _hidl_cb(static_cast<int32_t>(status), tOutput);
+ return Void();
+ }
+
+ _hidl_cb(static_cast<int32_t>(status), tOutput);
+ for (auto& nhA : nhAA) {
+ for (auto& nh : nhA) {
+ native_handle_delete(nh);
+ }
+ }
+ return Void();
+ }
+
+ Return<int32_t> disconnect(
+ int32_t api,
+ HGraphicBufferProducer::DisconnectMode mode) override {
+ return static_cast<int32_t>(mBase->disconnect(
+ static_cast<int>(api),
+ ::android::conversion::toGuiDisconnectMode(mode)));
+ }
+
+ Return<int32_t> setSidebandStream(const hidl_handle& stream) override {
+ return static_cast<int32_t>(mBase->setSidebandStream(NativeHandle::create(
+ stream ? native_handle_clone(stream) : NULL, true)));
+ }
+
+ Return<void> allocateBuffers(
+ uint32_t width, uint32_t height,
+ ::android::hardware::graphics::common::V1_0::PixelFormat format,
+ uint32_t usage) override {
+ mBase->allocateBuffers(
+ width, height,
+ static_cast<::android::PixelFormat>(format),
+ usage);
+ return Void();
+ }
+
+ Return<int32_t> allowAllocation(bool allow) override {
+ return static_cast<int32_t>(mBase->allowAllocation(allow));
+ }
+
+ Return<int32_t> setGenerationNumber(uint32_t generationNumber) override {
+ return static_cast<int32_t>(mBase->setGenerationNumber(generationNumber));
+ }
+
+ Return<void> getConsumerName(HGraphicBufferProducer::getConsumerName_cb _hidl_cb) override {
+ _hidl_cb(mBase->getConsumerName().string());
+ return Void();
+ }
+
+ Return<int32_t> setSharedBufferMode(bool sharedBufferMode) override {
+ return static_cast<int32_t>(mBase->setSharedBufferMode(sharedBufferMode));
+ }
+
+ Return<int32_t> setAutoRefresh(bool autoRefresh) override {
+ return static_cast<int32_t>(mBase->setAutoRefresh(autoRefresh));
+ }
+
+ Return<int32_t> setDequeueTimeout(int64_t timeoutNs) override {
+ return static_cast<int32_t>(mBase->setDequeueTimeout(timeoutNs));
+ }
+
+ Return<void> getLastQueuedBuffer(HGraphicBufferProducer::getLastQueuedBuffer_cb _hidl_cb) override {
+ sp<GraphicBuffer> lOutBuffer = new GraphicBuffer();
+ sp<Fence> lOutFence = new Fence();
+ float lOutTransformMatrix[16];
+ status_t status = mBase->getLastQueuedBuffer(
+ &lOutBuffer, &lOutFence, lOutTransformMatrix);
+
+ AnwBuffer tOutBuffer;
+ if (lOutBuffer != nullptr) {
+ ::android::conversion::wrapAs(&tOutBuffer, *lOutBuffer);
+ }
+ hidl_handle tOutFence;
+ native_handle_t* nh = nullptr;
+ if ((lOutFence == nullptr) || !::android::conversion::wrapAs(&tOutFence, &nh, *lOutFence)) {
+ LOG(ERROR) << "TWGraphicBufferProducer::getLastQueuedBuffer - "
+ "Invalid output fence";
+ _hidl_cb(static_cast<int32_t>(status),
+ tOutBuffer,
+ tOutFence,
+ hidl_array<float, 16>());
+ return Void();
+ }
+ hidl_array<float, 16> tOutTransformMatrix(lOutTransformMatrix);
+
+ _hidl_cb(static_cast<int32_t>(status), tOutBuffer, tOutFence, tOutTransformMatrix);
+ native_handle_delete(nh);
+ return Void();
+ }
+
+ Return<void> getFrameTimestamps(HGraphicBufferProducer::getFrameTimestamps_cb _hidl_cb) override {
+ ::android::FrameEventHistoryDelta lDelta;
+ mBase->getFrameTimestamps(&lDelta);
+
+ HGraphicBufferProducer::FrameEventHistoryDelta tDelta;
+ std::vector<std::vector<native_handle_t*> > nhAA;
+ if (!::android::conversion::wrapAs(&tDelta, &nhAA, lDelta)) {
+ LOG(ERROR) << "TWGraphicBufferProducer::getFrameTimestamps - "
+ "Invalid output frame timestamps";
+ _hidl_cb(tDelta);
+ return Void();
+ }
+
+ _hidl_cb(tDelta);
+ for (auto& nhA : nhAA) {
+ for (auto& nh : nhA) {
+ native_handle_delete(nh);
+ }
+ }
+ return Void();
+ }
+
+ Return<void> getUniqueId(HGraphicBufferProducer::getUniqueId_cb _hidl_cb) override {
+ uint64_t outId;
+ status_t status = mBase->getUniqueId(&outId);
+ _hidl_cb(static_cast<int32_t>(status), outId);
+ return Void();
+ }
+
+private:
+ sp<BGraphicBufferProducer> mBase;
+};
+
+} // namespace android
+
+#endif // MEDIA_STAGEFRIGHT_WGRAPHICBUFFERPRODUCER_H_
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/1.0/WProducerListener.h b/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/WProducerListener.h
similarity index 81%
rename from media/libstagefright/omx/include/media/stagefright/omx/1.0/WProducerListener.h
rename to media/libstagefright/bqhelper/include/media/stagefright/bqhelper/WProducerListener.h
index a75e48a..febba87 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/1.0/WProducerListener.h
+++ b/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/WProducerListener.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXPRODUCERLISTENER_H
-#define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXPRODUCERLISTENER_H
+#ifndef MEDIA_STAGEFRIGHT_WPRODUCERLISTENER_H_
+#define MEDIA_STAGEFRIGHT_WPRODUCERLISTENER_H_
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
@@ -26,11 +26,6 @@
#include <android/hardware/graphics/bufferqueue/1.0/IProducerListener.h>
namespace android {
-namespace hardware {
-namespace media {
-namespace omx {
-namespace V1_0 {
-namespace implementation {
using ::android::hidl::base::V1_0::IBase;
using ::android::hardware::hidl_array;
@@ -62,11 +57,6 @@
bool needsReleaseNotify() override;
};
-} // namespace implementation
-} // namespace V1_0
-} // namespace omx
-} // namespace media
-} // namespace hardware
} // namespace android
-#endif // ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXPRODUCERLISTENER_H
+#endif // MEDIA_STAGEFRIGHT_WPRODUCERLISTENER_H_
diff --git a/media/libstagefright/gbs/tests/Android.bp b/media/libstagefright/bqhelper/tests/Android.bp
similarity index 80%
rename from media/libstagefright/gbs/tests/Android.bp
rename to media/libstagefright/bqhelper/tests/Android.bp
index 1463e73..2fbc3d6 100644
--- a/media/libstagefright/gbs/tests/Android.bp
+++ b/media/libstagefright/bqhelper/tests/Android.bp
@@ -4,7 +4,7 @@
srcs: ["FrameDropper_test.cpp"],
shared_libs: [
- "libstagefright_gbs",
+ "libstagefright_bufferqueue_helper",
"libutils",
],
diff --git a/media/libstagefright/gbs/tests/FrameDropper_test.cpp b/media/libstagefright/bqhelper/tests/FrameDropper_test.cpp
similarity index 98%
rename from media/libstagefright/gbs/tests/FrameDropper_test.cpp
rename to media/libstagefright/bqhelper/tests/FrameDropper_test.cpp
index 54a84d3..55ae77c 100644
--- a/media/libstagefright/gbs/tests/FrameDropper_test.cpp
+++ b/media/libstagefright/bqhelper/tests/FrameDropper_test.cpp
@@ -20,7 +20,7 @@
#include <gtest/gtest.h>
-#include <media/stagefright/gbs/FrameDropper.h>
+#include <media/stagefright/bqhelper/FrameDropper.h>
#include <media/stagefright/foundation/ADebug.h>
namespace android {
diff --git a/media/libstagefright/codecs/on2/dec/SoftVPX.h b/media/libstagefright/codecs/on2/dec/SoftVPX.h
index a01a4f3..9ac2791 100644
--- a/media/libstagefright/codecs/on2/dec/SoftVPX.h
+++ b/media/libstagefright/codecs/on2/dec/SoftVPX.h
@@ -44,7 +44,7 @@
private:
enum {
- kNumBuffers = 4
+ kNumBuffers = 16
};
enum {
diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
index c9ebbdc..838bc5f 100644
--- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp
+++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
@@ -60,7 +60,8 @@
mConverter = NULL;
}
-void SoftwareRenderer::resetFormatIfChanged(const sp<AMessage> &format) {
+void SoftwareRenderer::resetFormatIfChanged(
+ const sp<AMessage> &format, size_t numOutputBuffers) {
CHECK(format != NULL);
int32_t colorFormatNew;
@@ -168,7 +169,7 @@
CHECK_EQ(0,
native_window_set_usage(
mNativeWindow.get(),
- GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_OFTEN
+ GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_RARELY
| GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP));
CHECK_EQ(0,
@@ -184,6 +185,11 @@
CHECK_EQ(0, native_window_set_buffers_format(
mNativeWindow.get(),
halFormat));
+ if (OK != native_window_set_buffer_count(
+ mNativeWindow.get(), numOutputBuffers + 4)) {
+ ALOGE("Failed to set native window buffer count to (%zu + 4)",
+ numOutputBuffers);
+ }
// NOTE: native window uses extended right-bottom coordinate
android_native_rect_t crop;
@@ -219,8 +225,8 @@
std::list<FrameRenderTracker::Info> SoftwareRenderer::render(
const void *data, size_t , int64_t mediaTimeUs, nsecs_t renderTimeNs,
- void* /*platformPrivate*/, const sp<AMessage>& format) {
- resetFormatIfChanged(format);
+ size_t numOutputBuffers, const sp<AMessage>& format) {
+ resetFormatIfChanged(format, numOutputBuffers);
FrameRenderTracker::Info *info = NULL;
ANativeWindowBuffer *buf;
@@ -243,8 +249,9 @@
Rect bounds(mCropWidth, mCropHeight);
void *dst;
- CHECK_EQ(0, mapper.lock(
- buf->handle, GRALLOC_USAGE_SW_WRITE_OFTEN, bounds, &dst));
+ CHECK_EQ(0, mapper.lock(buf->handle,
+ GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_RARELY,
+ bounds, &dst));
// TODO move the other conversions also into ColorConverter, and
// fix cropping issues (when mCropLeft/Top != 0 or mWidth != mCropWidth)
diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
index bc3e57c..8f349fc 100644
--- a/media/libstagefright/httplive/M3UParser.cpp
+++ b/media/libstagefright/httplive/M3UParser.cpp
@@ -659,10 +659,13 @@
}
if (!line.startsWith("#")) {
+ if (itemMeta == NULL) {
+ ALOGV("itemMeta == NULL");
+ return ERROR_MALFORMED;
+ }
if (!mIsVariantPlaylist) {
int64_t durationUs;
- if (itemMeta == NULL
- || !itemMeta->findInt64("durationUs", &durationUs)) {
+ if (!itemMeta->findInt64("durationUs", &durationUs)) {
return ERROR_MALFORMED;
}
itemMeta->setInt32("discontinuity-sequence",
diff --git a/media/libstagefright/include/CCodecBufferChannel.h b/media/libstagefright/include/CCodecBufferChannel.h
index 57a1374..e64f984 100644
--- a/media/libstagefright/include/CCodecBufferChannel.h
+++ b/media/libstagefright/include/CCodecBufferChannel.h
@@ -27,7 +27,7 @@
#include <C2Component.h>
#include <media/stagefright/foundation/Mutexed.h>
-#include <media/stagefright/gbs/GraphicBufferSource.h>
+#include <media/stagefright/bqhelper/GraphicBufferSource.h>
#include <media/stagefright/CodecBase.h>
#include <media/ICrypto.h>
diff --git a/media/libstagefright/include/SoftwareRenderer.h b/media/libstagefright/include/SoftwareRenderer.h
index e04b59f..c286516 100644
--- a/media/libstagefright/include/SoftwareRenderer.h
+++ b/media/libstagefright/include/SoftwareRenderer.h
@@ -39,7 +39,7 @@
std::list<FrameRenderTracker::Info> render(
const void *data, size_t size, int64_t mediaTimeUs, nsecs_t renderTimeNs,
- void *platformPrivate, const sp<AMessage> &format);
+ size_t numOutputBuffers, const sp<AMessage> &format);
void clearTracker();
private:
@@ -59,10 +59,11 @@
HDRStaticInfo mHDRStaticInfo;
FrameRenderTracker mRenderTracker;
+ void resetFormatIfChanged(
+ const sp<AMessage> &format, size_t numOutputBuffers);
+
SoftwareRenderer(const SoftwareRenderer &);
SoftwareRenderer &operator=(const SoftwareRenderer &);
-
- void resetFormatIfChanged(const sp<AMessage> &format);
};
} // namespace android
diff --git a/media/libstagefright/include/media/stagefright/CCodec.h b/media/libstagefright/include/media/stagefright/CCodec.h
index fa19c6e..9307f3f 100644
--- a/media/libstagefright/include/media/stagefright/CCodec.h
+++ b/media/libstagefright/include/media/stagefright/CCodec.h
@@ -24,7 +24,7 @@
#include <android/native_window.h>
#include <media/hardware/MetadataBufferType.h>
#include <media/stagefright/foundation/Mutexed.h>
-#include <media/stagefright/gbs/GraphicBufferSource.h>
+#include <media/stagefright/bqhelper/GraphicBufferSource.h>
#include <media/stagefright/CodecBase.h>
#include <media/stagefright/FrameRenderTracker.h>
#include <media/stagefright/MediaDefs.h>
diff --git a/media/libstagefright/omx/1.0/WGraphicBufferProducer.cpp b/media/libstagefright/omx/1.0/WGraphicBufferProducer.cpp
deleted file mode 100644
index c4499dc..0000000
--- a/media/libstagefright/omx/1.0/WGraphicBufferProducer.cpp
+++ /dev/null
@@ -1,355 +0,0 @@
-/*
- * Copyright 2016, 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 "WGraphicBufferProducer-impl"
-
-#include <android-base/logging.h>
-
-#include <media/stagefright/omx/1.0/WGraphicBufferProducer.h>
-#include <media/stagefright/omx/1.0/WProducerListener.h>
-#include <media/stagefright/omx/1.0/Conversion.h>
-#include <system/window.h>
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace omx {
-namespace V1_0 {
-namespace implementation {
-
-// TWGraphicBufferProducer
-TWGraphicBufferProducer::TWGraphicBufferProducer(
- sp<BGraphicBufferProducer> const& base):
- mBase(base) {
-}
-
-Return<void> TWGraphicBufferProducer::requestBuffer(
- int32_t slot, requestBuffer_cb _hidl_cb) {
- sp<GraphicBuffer> buf;
- status_t status = mBase->requestBuffer(slot, &buf);
- AnwBuffer anwBuffer;
- if (buf != nullptr) {
- wrapAs(&anwBuffer, *buf);
- }
- _hidl_cb(static_cast<int32_t>(status), anwBuffer);
- return Void();
-}
-
-Return<int32_t> TWGraphicBufferProducer::setMaxDequeuedBufferCount(
- int32_t maxDequeuedBuffers) {
- return static_cast<int32_t>(mBase->setMaxDequeuedBufferCount(
- static_cast<int>(maxDequeuedBuffers)));
-}
-
-Return<int32_t> TWGraphicBufferProducer::setAsyncMode(bool async) {
- return static_cast<int32_t>(mBase->setAsyncMode(async));
-}
-
-Return<void> TWGraphicBufferProducer::dequeueBuffer(
- uint32_t width, uint32_t height,
- PixelFormat format, uint32_t usage,
- bool getFrameTimestamps, dequeueBuffer_cb _hidl_cb) {
- int slot;
- sp<Fence> fence;
- ::android::FrameEventHistoryDelta outTimestamps;
- status_t status = mBase->dequeueBuffer(
- &slot, &fence, width, height,
- static_cast<::android::PixelFormat>(format), usage, nullptr,
- getFrameTimestamps ? &outTimestamps : nullptr);
- hidl_handle tFence;
- FrameEventHistoryDelta tOutTimestamps;
-
- native_handle_t* nh = nullptr;
- if ((fence == nullptr) || !wrapAs(&tFence, &nh, *fence)) {
- LOG(ERROR) << "TWGraphicBufferProducer::dequeueBuffer - "
- "Invalid output fence";
- _hidl_cb(static_cast<int32_t>(status),
- static_cast<int32_t>(slot),
- tFence,
- tOutTimestamps);
- return Void();
- }
- std::vector<std::vector<native_handle_t*> > nhAA;
- if (getFrameTimestamps && !wrapAs(&tOutTimestamps, &nhAA, outTimestamps)) {
- LOG(ERROR) << "TWGraphicBufferProducer::dequeueBuffer - "
- "Invalid output timestamps";
- _hidl_cb(static_cast<int32_t>(status),
- static_cast<int32_t>(slot),
- tFence,
- tOutTimestamps);
- native_handle_delete(nh);
- return Void();
- }
-
- _hidl_cb(static_cast<int32_t>(status),
- static_cast<int32_t>(slot),
- tFence,
- tOutTimestamps);
- native_handle_delete(nh);
- if (getFrameTimestamps) {
- for (auto& nhA : nhAA) {
- for (auto& handle : nhA) {
- native_handle_delete(handle);
- }
- }
- }
- return Void();
-}
-
-Return<int32_t> TWGraphicBufferProducer::detachBuffer(int32_t slot) {
- return static_cast<int32_t>(mBase->detachBuffer(slot));
-}
-
-Return<void> TWGraphicBufferProducer::detachNextBuffer(
- detachNextBuffer_cb _hidl_cb) {
- sp<GraphicBuffer> outBuffer;
- sp<Fence> outFence;
- status_t status = mBase->detachNextBuffer(&outBuffer, &outFence);
- AnwBuffer tBuffer;
- hidl_handle tFence;
-
- if (outBuffer == nullptr) {
- LOG(ERROR) << "TWGraphicBufferProducer::detachNextBuffer - "
- "Invalid output buffer";
- _hidl_cb(static_cast<int32_t>(status), tBuffer, tFence);
- return Void();
- }
- wrapAs(&tBuffer, *outBuffer);
- native_handle_t* nh = nullptr;
- if ((outFence != nullptr) && !wrapAs(&tFence, &nh, *outFence)) {
- LOG(ERROR) << "TWGraphicBufferProducer::detachNextBuffer - "
- "Invalid output fence";
- _hidl_cb(static_cast<int32_t>(status), tBuffer, tFence);
- return Void();
- }
-
- _hidl_cb(static_cast<int32_t>(status), tBuffer, tFence);
- native_handle_delete(nh);
- return Void();
-}
-
-Return<void> TWGraphicBufferProducer::attachBuffer(
- const AnwBuffer& buffer,
- attachBuffer_cb _hidl_cb) {
- int outSlot;
- sp<GraphicBuffer> lBuffer = new GraphicBuffer();
- if (!convertTo(lBuffer.get(), buffer)) {
- LOG(ERROR) << "TWGraphicBufferProducer::attachBuffer - "
- "Invalid input native window buffer";
- _hidl_cb(static_cast<int32_t>(BAD_VALUE), -1);
- return Void();
- }
- status_t status = mBase->attachBuffer(&outSlot, lBuffer);
-
- _hidl_cb(static_cast<int32_t>(status), static_cast<int32_t>(outSlot));
- return Void();
-}
-
-Return<void> TWGraphicBufferProducer::queueBuffer(
- int32_t slot, const QueueBufferInput& input,
- queueBuffer_cb _hidl_cb) {
- QueueBufferOutput tOutput;
- BGraphicBufferProducer::QueueBufferInput lInput(
- 0, false, HAL_DATASPACE_UNKNOWN,
- ::android::Rect(0, 0, 1, 1),
- NATIVE_WINDOW_SCALING_MODE_FREEZE,
- 0, ::android::Fence::NO_FENCE);
- if (!convertTo(&lInput, input)) {
- LOG(ERROR) << "TWGraphicBufferProducer::queueBuffer - "
- "Invalid input";
- _hidl_cb(static_cast<int32_t>(BAD_VALUE), tOutput);
- return Void();
- }
- BGraphicBufferProducer::QueueBufferOutput lOutput;
- status_t status = mBase->queueBuffer(
- static_cast<int>(slot), lInput, &lOutput);
-
- std::vector<std::vector<native_handle_t*> > nhAA;
- if (!wrapAs(&tOutput, &nhAA, lOutput)) {
- LOG(ERROR) << "TWGraphicBufferProducer::queueBuffer - "
- "Invalid output";
- _hidl_cb(static_cast<int32_t>(BAD_VALUE), tOutput);
- return Void();
- }
-
- _hidl_cb(static_cast<int32_t>(status), tOutput);
- for (auto& nhA : nhAA) {
- for (auto& nh : nhA) {
- native_handle_delete(nh);
- }
- }
- return Void();
-}
-
-Return<int32_t> TWGraphicBufferProducer::cancelBuffer(
- int32_t slot, const hidl_handle& fence) {
- sp<Fence> lFence = new Fence();
- if (!convertTo(lFence.get(), fence)) {
- LOG(ERROR) << "TWGraphicBufferProducer::cancelBuffer - "
- "Invalid input fence";
- return static_cast<int32_t>(BAD_VALUE);
- }
- return static_cast<int32_t>(mBase->cancelBuffer(static_cast<int>(slot), lFence));
-}
-
-Return<void> TWGraphicBufferProducer::query(int32_t what, query_cb _hidl_cb) {
- int lValue;
- int lReturn = mBase->query(static_cast<int>(what), &lValue);
- _hidl_cb(static_cast<int32_t>(lReturn), static_cast<int32_t>(lValue));
- return Void();
-}
-
-Return<void> TWGraphicBufferProducer::connect(
- const sp<HProducerListener>& listener,
- int32_t api, bool producerControlledByApp, connect_cb _hidl_cb) {
- sp<BProducerListener> lListener = listener == nullptr ?
- nullptr : new LWProducerListener(listener);
- BGraphicBufferProducer::QueueBufferOutput lOutput;
- status_t status = mBase->connect(lListener,
- static_cast<int>(api),
- producerControlledByApp,
- &lOutput);
-
- QueueBufferOutput tOutput;
- std::vector<std::vector<native_handle_t*> > nhAA;
- if (!wrapAs(&tOutput, &nhAA, lOutput)) {
- LOG(ERROR) << "TWGraphicBufferProducer::connect - "
- "Invalid output";
- _hidl_cb(static_cast<int32_t>(status), tOutput);
- return Void();
- }
-
- _hidl_cb(static_cast<int32_t>(status), tOutput);
- for (auto& nhA : nhAA) {
- for (auto& nh : nhA) {
- native_handle_delete(nh);
- }
- }
- return Void();
-}
-
-Return<int32_t> TWGraphicBufferProducer::disconnect(
- int32_t api, DisconnectMode mode) {
- return static_cast<int32_t>(mBase->disconnect(
- static_cast<int>(api),
- toGuiDisconnectMode(mode)));
-}
-
-Return<int32_t> TWGraphicBufferProducer::setSidebandStream(const hidl_handle& stream) {
- return static_cast<int32_t>(mBase->setSidebandStream(NativeHandle::create(
- stream ? native_handle_clone(stream) : NULL, true)));
-}
-
-Return<void> TWGraphicBufferProducer::allocateBuffers(
- uint32_t width, uint32_t height, PixelFormat format, uint32_t usage) {
- mBase->allocateBuffers(
- width, height,
- static_cast<::android::PixelFormat>(format),
- usage);
- return Void();
-}
-
-Return<int32_t> TWGraphicBufferProducer::allowAllocation(bool allow) {
- return static_cast<int32_t>(mBase->allowAllocation(allow));
-}
-
-Return<int32_t> TWGraphicBufferProducer::setGenerationNumber(uint32_t generationNumber) {
- return static_cast<int32_t>(mBase->setGenerationNumber(generationNumber));
-}
-
-Return<void> TWGraphicBufferProducer::getConsumerName(getConsumerName_cb _hidl_cb) {
- _hidl_cb(mBase->getConsumerName().string());
- return Void();
-}
-
-Return<int32_t> TWGraphicBufferProducer::setSharedBufferMode(bool sharedBufferMode) {
- return static_cast<int32_t>(mBase->setSharedBufferMode(sharedBufferMode));
-}
-
-Return<int32_t> TWGraphicBufferProducer::setAutoRefresh(bool autoRefresh) {
- return static_cast<int32_t>(mBase->setAutoRefresh(autoRefresh));
-}
-
-Return<int32_t> TWGraphicBufferProducer::setDequeueTimeout(int64_t timeoutNs) {
- return static_cast<int32_t>(mBase->setDequeueTimeout(timeoutNs));
-}
-
-Return<void> TWGraphicBufferProducer::getLastQueuedBuffer(
- getLastQueuedBuffer_cb _hidl_cb) {
- sp<GraphicBuffer> lOutBuffer = new GraphicBuffer();
- sp<Fence> lOutFence = new Fence();
- float lOutTransformMatrix[16];
- status_t status = mBase->getLastQueuedBuffer(
- &lOutBuffer, &lOutFence, lOutTransformMatrix);
-
- AnwBuffer tOutBuffer;
- if (lOutBuffer != nullptr) {
- wrapAs(&tOutBuffer, *lOutBuffer);
- }
- hidl_handle tOutFence;
- native_handle_t* nh = nullptr;
- if ((lOutFence == nullptr) || !wrapAs(&tOutFence, &nh, *lOutFence)) {
- LOG(ERROR) << "TWGraphicBufferProducer::getLastQueuedBuffer - "
- "Invalid output fence";
- _hidl_cb(static_cast<int32_t>(status),
- tOutBuffer,
- tOutFence,
- hidl_array<float, 16>());
- return Void();
- }
- hidl_array<float, 16> tOutTransformMatrix(lOutTransformMatrix);
-
- _hidl_cb(static_cast<int32_t>(status), tOutBuffer, tOutFence, tOutTransformMatrix);
- native_handle_delete(nh);
- return Void();
-}
-
-Return<void> TWGraphicBufferProducer::getFrameTimestamps(
- getFrameTimestamps_cb _hidl_cb) {
- ::android::FrameEventHistoryDelta lDelta;
- mBase->getFrameTimestamps(&lDelta);
-
- FrameEventHistoryDelta tDelta;
- std::vector<std::vector<native_handle_t*> > nhAA;
- if (!wrapAs(&tDelta, &nhAA, lDelta)) {
- LOG(ERROR) << "TWGraphicBufferProducer::getFrameTimestamps - "
- "Invalid output frame timestamps";
- _hidl_cb(tDelta);
- return Void();
- }
-
- _hidl_cb(tDelta);
- for (auto& nhA : nhAA) {
- for (auto& nh : nhA) {
- native_handle_delete(nh);
- }
- }
- return Void();
-}
-
-Return<void> TWGraphicBufferProducer::getUniqueId(getUniqueId_cb _hidl_cb) {
- uint64_t outId;
- status_t status = mBase->getUniqueId(&outId);
- _hidl_cb(static_cast<int32_t>(status), outId);
- return Void();
-}
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace omx
-} // namespace media
-} // namespace hardware
-} // namespace android
diff --git a/media/libstagefright/omx/Android.bp b/media/libstagefright/omx/Android.bp
index 306a8eb..3eb98f3 100644
--- a/media/libstagefright/omx/Android.bp
+++ b/media/libstagefright/omx/Android.bp
@@ -18,8 +18,6 @@
"SoftVideoEncoderOMXComponent.cpp",
"1.0/Omx.cpp",
"1.0/OmxStore.cpp",
- "1.0/WGraphicBufferProducer.cpp",
- "1.0/WProducerListener.cpp",
"1.0/WGraphicBufferSource.cpp",
"1.0/WOmxNode.cpp",
"1.0/WOmxObserver.cpp",
@@ -48,7 +46,7 @@
"libgui",
"libcutils",
"libstagefright_foundation",
- "libstagefright_gbs",
+ "libstagefright_bufferqueue_helper",
"libstagefright_xmlparser",
"libdl",
"libhidlbase",
diff --git a/media/libstagefright/omx/OmxGraphicBufferSource.cpp b/media/libstagefright/omx/OmxGraphicBufferSource.cpp
index 83feac8..8de1f4f 100644
--- a/media/libstagefright/omx/OmxGraphicBufferSource.cpp
+++ b/media/libstagefright/omx/OmxGraphicBufferSource.cpp
@@ -20,8 +20,8 @@
//#define LOG_NDEBUG 0
#include <utils/Log.h>
-#include <media/stagefright/gbs/ComponentWrapper.h>
-#include <media/stagefright/gbs/GraphicBufferSource.h>
+#include <media/stagefright/bqhelper/ComponentWrapper.h>
+#include <media/stagefright/bqhelper/GraphicBufferSource.h>
#include <media/stagefright/omx/OmxGraphicBufferSource.h>
namespace android {
diff --git a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
index 1ba5852..d650224 100644
--- a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
+++ b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
@@ -41,7 +41,7 @@
mLooper->start(
false, // runOnCallingThread
false, // canCallJava
- ANDROID_PRIORITY_FOREGROUND);
+ ANDROID_PRIORITY_AUDIO);
}
void SimpleSoftOMXComponent::prepareForDestruction() {
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/1.0/Conversion.h b/media/libstagefright/omx/include/media/stagefright/omx/1.0/Conversion.h
index a79d403..903a2b6 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/1.0/Conversion.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/1.0/Conversion.h
@@ -35,6 +35,7 @@
#include <media/OMXFenceParcelable.h>
#include <media/OMXBuffer.h>
#include <media/hardware/VideoAPI.h>
+#include <media/stagefright/bqhelper/Conversion.h>
#include <android/hidl/memory/1.0/IMemory.h>
#include <android/hardware/graphics/bufferqueue/1.0/IProducerListener.h>
@@ -99,51 +100,13 @@
typedef ::android::IGraphicBufferProducer
BGraphicBufferProducer;
-// native_handle_t helper functions.
+// We want to use all functions declared in ::android::conversion
+using namespace ::android::conversion;
-/**
- * \brief Take an fd and create a native handle containing only the given fd.
- * The created handle will need to be deleted manually with
- * `native_handle_delete()`.
- *
- * \param[in] fd The source file descriptor (of type `int`).
- * \return The create `native_handle_t*` that contains the given \p fd. If the
- * supplied \p fd is negative, the created native handle will contain no file
- * descriptors.
- *
- * If the native handle cannot be created, the return value will be
- * `nullptr`.
- *
- * This function does not duplicate the file descriptor.
- */
-inline native_handle_t* native_handle_create_from_fd(int fd) {
- if (fd < 0) {
- return native_handle_create(0, 0);
- }
- native_handle_t* nh = native_handle_create(1, 0);
- if (nh == nullptr) {
- return nullptr;
- }
- nh->data[0] = fd;
- return nh;
-}
-
-/**
- * \brief Extract a file descriptor from a native handle.
- *
- * \param[in] nh The source `native_handle_t*`.
- * \param[in] index The index of the file descriptor in \p nh to read from. This
- * input has the default value of `0`.
- * \return The `index`-th file descriptor in \p nh. If \p nh does not have
- * enough file descriptors, the returned value will be `-1`.
- *
- * This function does not duplicate the file descriptor.
- */
-inline int native_handle_read_fd(native_handle_t const* nh, int index = 0) {
- return ((nh == nullptr) || (nh->numFds == 0) ||
- (nh->numFds <= index) || (index < 0)) ?
- -1 : nh->data[index];
-}
+// Now specifically inject these two functions here, because we're going to
+// declare functions with the same name in this namespace.
+using ::android::conversion::convertTo;
+using ::android::conversion::toStatusT;
/**
* Conversion functions
@@ -178,20 +141,6 @@
*/
/**
- * \brief Convert `Return<void>` to `binder::Status`.
- *
- * \param[in] t The source `Return<void>`.
- * \return The corresponding `binder::Status`.
- */
-// convert: Return<void> -> ::android::binder::Status
-inline ::android::binder::Status toBinderStatus(
- Return<void> const& t) {
- return ::android::binder::Status::fromExceptionCode(
- t.isOk() ? OK : UNKNOWN_ERROR,
- t.description().c_str());
-}
-
-/**
* \brief Convert `Return<Status>` to `status_t`. This is for legacy binder
* calls.
*
@@ -212,17 +161,6 @@
}
/**
- * \brief Convert `Return<void>` to `status_t`. This is for legacy binder calls.
- *
- * \param[in] t The source `Return<void>`.
- * \return The corresponding `status_t`.
- */
-// convert: Return<void> -> status_t
-inline status_t toStatusT(Return<void> const& t) {
- return t.isOk() ? OK : UNKNOWN_ERROR;
-}
-
-/**
* \brief Convert `Status` to `status_t`. This is for legacy binder calls.
*
* \param[in] t The source `Status`.
@@ -245,17 +183,6 @@
}
/**
- * \brief Wrap `native_handle_t*` in `hidl_handle`.
- *
- * \param[in] nh The source `native_handle_t*`.
- * \return The `hidl_handle` that points to \p nh.
- */
-// wrap: native_handle_t* -> hidl_handle
-inline hidl_handle inHidlHandle(native_handle_t const* nh) {
- return hidl_handle(nh);
-}
-
-/**
* \brief Wrap an `omx_message` and construct the corresponding `Message`.
*
* \param[out] t The wrapper of type `Message`.
@@ -490,128 +417,6 @@
}
/**
- * \brief Convert `int32_t` to `Dataspace`.
- *
- * \param[in] l The source `int32_t`.
- * \result The corresponding `Dataspace`.
- */
-// convert: int32_t -> Dataspace
-inline Dataspace toHardwareDataspace(int32_t l) {
- return static_cast<Dataspace>(l);
-}
-
-/**
- * \brief Convert `Dataspace` to `int32_t`.
- *
- * \param[in] t The source `Dataspace`.
- * \result The corresponding `int32_t`.
- */
-// convert: Dataspace -> int32_t
-inline int32_t toRawDataspace(Dataspace const& t) {
- return static_cast<int32_t>(t);
-}
-
-/**
- * \brief Wrap an opaque buffer inside a `hidl_vec<uint8_t>`.
- *
- * \param[in] l The pointer to the beginning of the opaque buffer.
- * \param[in] size The size of the buffer.
- * \return A `hidl_vec<uint8_t>` that points to the buffer.
- */
-// wrap: void*, size_t -> hidl_vec<uint8_t>
-inline hidl_vec<uint8_t> inHidlBytes(void const* l, size_t size) {
- hidl_vec<uint8_t> t;
- t.setToExternal(static_cast<uint8_t*>(const_cast<void*>(l)), size, false);
- return t;
-}
-
-/**
- * \brief Create a `hidl_vec<uint8_t>` that is a copy of an opaque buffer.
- *
- * \param[in] l The pointer to the beginning of the opaque buffer.
- * \param[in] size The size of the buffer.
- * \return A `hidl_vec<uint8_t>` that is a copy of the input buffer.
- */
-// convert: void*, size_t -> hidl_vec<uint8_t>
-inline hidl_vec<uint8_t> toHidlBytes(void const* l, size_t size) {
- hidl_vec<uint8_t> t;
- t.resize(size);
- uint8_t const* src = static_cast<uint8_t const*>(l);
- std::copy(src, src + size, t.data());
- return t;
-}
-
-/**
- * \brief Wrap `GraphicBuffer` in `AnwBuffer`.
- *
- * \param[out] t The wrapper of type `AnwBuffer`.
- * \param[in] l The source `GraphicBuffer`.
- */
-// wrap: GraphicBuffer -> AnwBuffer
-inline void wrapAs(AnwBuffer* t, GraphicBuffer const& l) {
- t->attr.width = l.getWidth();
- t->attr.height = l.getHeight();
- t->attr.stride = l.getStride();
- t->attr.format = static_cast<PixelFormat>(l.getPixelFormat());
- t->attr.layerCount = l.getLayerCount();
- t->attr.usage = l.getUsage();
- t->attr.id = l.getId();
- t->attr.generationNumber = l.getGenerationNumber();
- t->nativeHandle = hidl_handle(l.handle);
-}
-
-/**
- * \brief Convert `AnwBuffer` to `GraphicBuffer`.
- *
- * \param[out] l The destination `GraphicBuffer`.
- * \param[in] t The source `AnwBuffer`.
- *
- * This function will duplicate all file descriptors in \p t.
- */
-// convert: AnwBuffer -> GraphicBuffer
-// Ref: frameworks/native/libs/ui/GraphicBuffer.cpp: GraphicBuffer::flatten
-inline bool convertTo(GraphicBuffer* l, AnwBuffer const& t) {
- native_handle_t* handle = t.nativeHandle == nullptr ?
- nullptr : native_handle_clone(t.nativeHandle);
-
- size_t const numInts = 12 + (handle ? handle->numInts : 0);
- int32_t* ints = new int32_t[numInts];
-
- size_t numFds = static_cast<size_t>(handle ? handle->numFds : 0);
- int* fds = new int[numFds];
-
- ints[0] = 'GBFR';
- ints[1] = static_cast<int32_t>(t.attr.width);
- ints[2] = static_cast<int32_t>(t.attr.height);
- ints[3] = static_cast<int32_t>(t.attr.stride);
- ints[4] = static_cast<int32_t>(t.attr.format);
- ints[5] = static_cast<int32_t>(t.attr.layerCount);
- ints[6] = static_cast<int32_t>(t.attr.usage);
- ints[7] = static_cast<int32_t>(t.attr.id >> 32);
- ints[8] = static_cast<int32_t>(t.attr.id & 0xFFFFFFFF);
- ints[9] = static_cast<int32_t>(t.attr.generationNumber);
- ints[10] = 0;
- ints[11] = 0;
- if (handle) {
- ints[10] = static_cast<int32_t>(handle->numFds);
- ints[11] = static_cast<int32_t>(handle->numInts);
- int* intsStart = handle->data + handle->numFds;
- std::copy(handle->data, intsStart, fds);
- std::copy(intsStart, intsStart + handle->numInts, &ints[12]);
- }
-
- void const* constBuffer = static_cast<void const*>(ints);
- size_t size = numInts * sizeof(int32_t);
- int const* constFds = static_cast<int const*>(fds);
- status_t status = l->unflatten(constBuffer, size, constFds, numFds);
-
- delete [] fds;
- delete [] ints;
- native_handle_delete(handle);
- return status == NO_ERROR;
-}
-
-/**
* \brief Wrap `GraphicBuffer` in `CodecBuffer`.
*
* \param[out] t The wrapper of type `CodecBuffer`.
@@ -896,1288 +701,6 @@
#endif
}
-/**
- * Conversion functions for types outside media
- * ============================================
- *
- * Some objects in libui and libgui that were made to go through binder calls do
- * not expose ways to read or write their fields to the public. To pass an
- * object of this kind through the HIDL boundary, translation functions need to
- * work around the access restriction by using the publicly available
- * `flatten()` and `unflatten()` functions.
- *
- * All `flatten()` and `unflatten()` overloads follow the same convention as
- * follows:
- *
- * status_t flatten(ObjectType const& object,
- * [OtherType const& other, ...]
- * void*& buffer, size_t& size,
- * int*& fds, size_t& numFds)
- *
- * status_t unflatten(ObjectType* object,
- * [OtherType* other, ...,]
- * void*& buffer, size_t& size,
- * int*& fds, size_t& numFds)
- *
- * The number of `other` parameters varies depending on the `ObjectType`. For
- * example, in the process of unflattening an object that contains
- * `hidl_handle`, `other` is needed to hold `native_handle_t` objects that will
- * be created.
- *
- * The last four parameters always work the same way in all overloads of
- * `flatten()` and `unflatten()`:
- * - For `flatten()`, `buffer` is the pointer to the non-fd buffer to be filled,
- * `size` is the size (in bytes) of the non-fd buffer pointed to by `buffer`,
- * `fds` is the pointer to the fd buffer to be filled, and `numFds` is the
- * size (in ints) of the fd buffer pointed to by `fds`.
- * - For `unflatten()`, `buffer` is the pointer to the non-fd buffer to be read
- * from, `size` is the size (in bytes) of the non-fd buffer pointed to by
- * `buffer`, `fds` is the pointer to the fd buffer to be read from, and
- * `numFds` is the size (in ints) of the fd buffer pointed to by `fds`.
- * - After a successful call to `flatten()` or `unflatten()`, `buffer` and `fds`
- * will be advanced, while `size` and `numFds` will be decreased to reflect
- * how much storage/data of the two buffers (fd and non-fd) have been used.
- * - After an unsuccessful call, the values of `buffer`, `size`, `fds` and
- * `numFds` are invalid.
- *
- * The return value of a successful `flatten()` or `unflatten()` call will be
- * `OK` (also aliased as `NO_ERROR`). Any other values indicate a failure.
- *
- * For each object type that supports flattening, there will be two accompanying
- * functions: `getFlattenedSize()` and `getFdCount()`. `getFlattenedSize()` will
- * return the size of the non-fd buffer that the object will need for
- * flattening. `getFdCount()` will return the size of the fd buffer that the
- * object will need for flattening.
- *
- * The set of these four functions, `getFlattenedSize()`, `getFdCount()`,
- * `flatten()` and `unflatten()`, are similar to functions of the same name in
- * the abstract class `Flattenable`. The only difference is that functions in
- * this file are not member functions of the object type. For example, we write
- *
- * flatten(x, buffer, size, fds, numFds)
- *
- * instead of
- *
- * x.flatten(buffer, size, fds, numFds)
- *
- * because we cannot modify the type of `x`.
- *
- * There is one exception to the naming convention: `hidl_handle` that
- * represents a fence. The four functions for this "Fence" type have the word
- * "Fence" attched to their names because the object type, which is
- * `hidl_handle`, does not carry the special meaning that the object itself can
- * only contain zero or one file descriptor.
- */
-
-// Ref: frameworks/native/libs/ui/Fence.cpp
-
-/**
- * \brief Return the size of the non-fd buffer required to flatten a fence.
- *
- * \param[in] fence The input fence of type `hidl_handle`.
- * \return The required size of the flat buffer.
- *
- * The current version of this function always returns 4, which is the number of
- * bytes required to store the number of file descriptors contained in the fd
- * part of the flat buffer.
- */
-inline size_t getFenceFlattenedSize(hidl_handle const& /* fence */) {
- return 4;
-};
-
-/**
- * \brief Return the number of file descriptors contained in a fence.
- *
- * \param[in] fence The input fence of type `hidl_handle`.
- * \return `0` if \p fence does not contain a valid file descriptor, or `1`
- * otherwise.
- */
-inline size_t getFenceFdCount(hidl_handle const& fence) {
- return native_handle_read_fd(fence) == -1 ? 0 : 1;
-}
-
-/**
- * \brief Unflatten `Fence` to `hidl_handle`.
- *
- * \param[out] fence The destination `hidl_handle`.
- * \param[out] nh The underlying native handle.
- * \param[in,out] buffer The pointer to the flat non-fd buffer.
- * \param[in,out] size The size of the flat non-fd buffer.
- * \param[in,out] fds The pointer to the flat fd buffer.
- * \param[in,out] numFds The size of the flat fd buffer.
- * \return `NO_ERROR` on success; other value on failure.
- *
- * If the return value is `NO_ERROR`, \p nh will point to a newly created
- * native handle, which needs to be deleted with `native_handle_delete()`
- * afterwards.
- */
-inline status_t unflattenFence(hidl_handle* fence, native_handle_t** nh,
- void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
- if (size < 4) {
- return NO_MEMORY;
- }
-
- uint32_t numFdsInHandle;
- FlattenableUtils::read(buffer, size, numFdsInHandle);
-
- if (numFdsInHandle > 1) {
- return BAD_VALUE;
- }
-
- if (numFds < numFdsInHandle) {
- return NO_MEMORY;
- }
-
- if (numFdsInHandle) {
- *nh = native_handle_create_from_fd(*fds);
- if (*nh == nullptr) {
- return NO_MEMORY;
- }
- *fence = *nh;
- ++fds;
- --numFds;
- } else {
- *nh = nullptr;
- *fence = hidl_handle();
- }
-
- return NO_ERROR;
-}
-
-/**
- * \brief Flatten `hidl_handle` as `Fence`.
- *
- * \param[in] t The source `hidl_handle`.
- * \param[in,out] buffer The pointer to the flat non-fd buffer.
- * \param[in,out] size The size of the flat non-fd buffer.
- * \param[in,out] fds The pointer to the flat fd buffer.
- * \param[in,out] numFds The size of the flat fd buffer.
- * \return `NO_ERROR` on success; other value on failure.
- */
-inline status_t flattenFence(hidl_handle const& fence,
- void*& buffer, size_t& size, int*& fds, size_t& numFds) {
- if (size < getFenceFlattenedSize(fence) ||
- numFds < getFenceFdCount(fence)) {
- return NO_MEMORY;
- }
- // Cast to uint32_t since the size of a size_t can vary between 32- and
- // 64-bit processes
- FlattenableUtils::write(buffer, size,
- static_cast<uint32_t>(getFenceFdCount(fence)));
- int fd = native_handle_read_fd(fence);
- if (fd != -1) {
- *fds = fd;
- ++fds;
- --numFds;
- }
- return NO_ERROR;
-}
-
-/**
- * \brief Wrap `Fence` in `hidl_handle`.
- *
- * \param[out] t The wrapper of type `hidl_handle`.
- * \param[out] nh The native handle pointed to by \p t.
- * \param[in] l The source `Fence`.
- *
- * On success, \p nh will hold a newly created native handle, which must be
- * deleted manually with `native_handle_delete()` afterwards.
- */
-// wrap: Fence -> hidl_handle
-inline bool wrapAs(hidl_handle* t, native_handle_t** nh, Fence const& l) {
- size_t const baseSize = l.getFlattenedSize();
- std::unique_ptr<uint8_t[]> baseBuffer(
- new (std::nothrow) uint8_t[baseSize]);
- if (!baseBuffer) {
- return false;
- }
-
- size_t const baseNumFds = l.getFdCount();
- std::unique_ptr<int[]> baseFds(
- new (std::nothrow) int[baseNumFds]);
- if (!baseFds) {
- return false;
- }
-
- void* buffer = static_cast<void*>(baseBuffer.get());
- size_t size = baseSize;
- int* fds = static_cast<int*>(baseFds.get());
- size_t numFds = baseNumFds;
- if (l.flatten(buffer, size, fds, numFds) != NO_ERROR) {
- return false;
- }
-
- void const* constBuffer = static_cast<void const*>(baseBuffer.get());
- size = baseSize;
- int const* constFds = static_cast<int const*>(baseFds.get());
- numFds = baseNumFds;
- if (unflattenFence(t, nh, constBuffer, size, constFds, numFds)
- != NO_ERROR) {
- return false;
- }
-
- return true;
-}
-
-/**
- * \brief Convert `hidl_handle` to `Fence`.
- *
- * \param[out] l The destination `Fence`. `l` must not have been used
- * (`l->isValid()` must return `false`) before this function is called.
- * \param[in] t The source `hidl_handle`.
- *
- * If \p t contains a valid file descriptor, it will be duplicated.
- */
-// convert: hidl_handle -> Fence
-inline bool convertTo(Fence* l, hidl_handle const& t) {
- int fd = native_handle_read_fd(t);
- if (fd != -1) {
- fd = dup(fd);
- if (fd == -1) {
- return false;
- }
- }
- native_handle_t* nh = native_handle_create_from_fd(fd);
- if (nh == nullptr) {
- if (fd != -1) {
- close(fd);
- }
- return false;
- }
-
- size_t const baseSize = getFenceFlattenedSize(t);
- std::unique_ptr<uint8_t[]> baseBuffer(
- new (std::nothrow) uint8_t[baseSize]);
- if (!baseBuffer) {
- native_handle_delete(nh);
- return false;
- }
-
- size_t const baseNumFds = getFenceFdCount(t);
- std::unique_ptr<int[]> baseFds(
- new (std::nothrow) int[baseNumFds]);
- if (!baseFds) {
- native_handle_delete(nh);
- return false;
- }
-
- void* buffer = static_cast<void*>(baseBuffer.get());
- size_t size = baseSize;
- int* fds = static_cast<int*>(baseFds.get());
- size_t numFds = baseNumFds;
- if (flattenFence(hidl_handle(nh), buffer, size, fds, numFds) != NO_ERROR) {
- native_handle_delete(nh);
- return false;
- }
- native_handle_delete(nh);
-
- void const* constBuffer = static_cast<void const*>(baseBuffer.get());
- size = baseSize;
- int const* constFds = static_cast<int const*>(baseFds.get());
- numFds = baseNumFds;
- if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
- return false;
- }
-
- return true;
-}
-
-// Ref: frameworks/native/libs/ui/FenceTime.cpp: FenceTime::Snapshot
-
-/**
- * \brief Return the size of the non-fd buffer required to flatten
- * `FenceTimeSnapshot`.
- *
- * \param[in] t The input `FenceTimeSnapshot`.
- * \return The required size of the flat buffer.
- */
-inline size_t getFlattenedSize(
- HGraphicBufferProducer::FenceTimeSnapshot const& t) {
- constexpr size_t min = sizeof(t.state);
- switch (t.state) {
- case HGraphicBufferProducer::FenceTimeSnapshot::State::EMPTY:
- return min;
- case HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE:
- return min + getFenceFlattenedSize(t.fence);
- case HGraphicBufferProducer::FenceTimeSnapshot::State::SIGNAL_TIME:
- return min + sizeof(
- ::android::FenceTime::Snapshot::signalTime);
- }
- return 0;
-}
-
-/**
- * \brief Return the number of file descriptors contained in
- * `FenceTimeSnapshot`.
- *
- * \param[in] t The input `FenceTimeSnapshot`.
- * \return The number of file descriptors contained in \p snapshot.
- */
-inline size_t getFdCount(
- HGraphicBufferProducer::FenceTimeSnapshot const& t) {
- return t.state ==
- HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE ?
- getFenceFdCount(t.fence) : 0;
-}
-
-/**
- * \brief Flatten `FenceTimeSnapshot`.
- *
- * \param[in] t The source `FenceTimeSnapshot`.
- * \param[in,out] buffer The pointer to the flat non-fd buffer.
- * \param[in,out] size The size of the flat non-fd buffer.
- * \param[in,out] fds The pointer to the flat fd buffer.
- * \param[in,out] numFds The size of the flat fd buffer.
- * \return `NO_ERROR` on success; other value on failure.
- *
- * This function will duplicate the file descriptor in `t.fence` if `t.state ==
- * FENCE`.
- */
-inline status_t flatten(HGraphicBufferProducer::FenceTimeSnapshot const& t,
- void*& buffer, size_t& size, int*& fds, size_t& numFds) {
- if (size < getFlattenedSize(t)) {
- return NO_MEMORY;
- }
-
- switch (t.state) {
- case HGraphicBufferProducer::FenceTimeSnapshot::State::EMPTY:
- FlattenableUtils::write(buffer, size,
- ::android::FenceTime::Snapshot::State::EMPTY);
- return NO_ERROR;
- case HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE:
- FlattenableUtils::write(buffer, size,
- ::android::FenceTime::Snapshot::State::FENCE);
- return flattenFence(t.fence, buffer, size, fds, numFds);
- case HGraphicBufferProducer::FenceTimeSnapshot::State::SIGNAL_TIME:
- FlattenableUtils::write(buffer, size,
- ::android::FenceTime::Snapshot::State::SIGNAL_TIME);
- FlattenableUtils::write(buffer, size, t.signalTimeNs);
- return NO_ERROR;
- }
- return NO_ERROR;
-}
-
-/**
- * \brief Unflatten `FenceTimeSnapshot`.
- *
- * \param[out] t The destination `FenceTimeSnapshot`.
- * \param[out] nh The underlying native handle.
- * \param[in,out] buffer The pointer to the flat non-fd buffer.
- * \param[in,out] size The size of the flat non-fd buffer.
- * \param[in,out] fds The pointer to the flat fd buffer.
- * \param[in,out] numFds The size of the flat fd buffer.
- * \return `NO_ERROR` on success; other value on failure.
- *
- * If the return value is `NO_ERROR` and the constructed snapshot contains a
- * file descriptor, \p nh will be created to hold that file descriptor. In this
- * case, \p nh needs to be deleted with `native_handle_delete()` afterwards.
- */
-inline status_t unflatten(
- HGraphicBufferProducer::FenceTimeSnapshot* t, native_handle_t** nh,
- void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
- if (size < sizeof(t->state)) {
- return NO_MEMORY;
- }
-
- *nh = nullptr;
- ::android::FenceTime::Snapshot::State state;
- FlattenableUtils::read(buffer, size, state);
- switch (state) {
- case ::android::FenceTime::Snapshot::State::EMPTY:
- t->state = HGraphicBufferProducer::FenceTimeSnapshot::State::EMPTY;
- return NO_ERROR;
- case ::android::FenceTime::Snapshot::State::FENCE:
- t->state = HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE;
- return unflattenFence(&t->fence, nh, buffer, size, fds, numFds);
- case ::android::FenceTime::Snapshot::State::SIGNAL_TIME:
- t->state = HGraphicBufferProducer::FenceTimeSnapshot::State::SIGNAL_TIME;
- if (size < sizeof(t->signalTimeNs)) {
- return NO_MEMORY;
- }
- FlattenableUtils::read(buffer, size, t->signalTimeNs);
- return NO_ERROR;
- }
- return NO_ERROR;
-}
-
-// Ref: frameworks/native/libs/gui/FrameTimestamps.cpp: FrameEventsDelta
-
-/**
- * \brief Return a lower bound on the size of the non-fd buffer required to
- * flatten `FrameEventsDelta`.
- *
- * \param[in] t The input `FrameEventsDelta`.
- * \return A lower bound on the size of the flat buffer.
- */
-constexpr size_t minFlattenedSize(
- HGraphicBufferProducer::FrameEventsDelta const& /* t */) {
- return sizeof(uint64_t) + // mFrameNumber
- sizeof(uint8_t) + // mIndex
- sizeof(uint8_t) + // mAddPostCompositeCalled
- sizeof(uint8_t) + // mAddRetireCalled
- sizeof(uint8_t) + // mAddReleaseCalled
- sizeof(nsecs_t) + // mPostedTime
- sizeof(nsecs_t) + // mRequestedPresentTime
- sizeof(nsecs_t) + // mLatchTime
- sizeof(nsecs_t) + // mFirstRefreshStartTime
- sizeof(nsecs_t); // mLastRefreshStartTime
-}
-
-/**
- * \brief Return the size of the non-fd buffer required to flatten
- * `FrameEventsDelta`.
- *
- * \param[in] t The input `FrameEventsDelta`.
- * \return The required size of the flat buffer.
- */
-inline size_t getFlattenedSize(
- HGraphicBufferProducer::FrameEventsDelta const& t) {
- return minFlattenedSize(t) +
- getFlattenedSize(t.gpuCompositionDoneFence) +
- getFlattenedSize(t.displayPresentFence) +
- getFlattenedSize(t.displayRetireFence) +
- getFlattenedSize(t.releaseFence);
-};
-
-/**
- * \brief Return the number of file descriptors contained in
- * `FrameEventsDelta`.
- *
- * \param[in] t The input `FrameEventsDelta`.
- * \return The number of file descriptors contained in \p t.
- */
-inline size_t getFdCount(
- HGraphicBufferProducer::FrameEventsDelta const& t) {
- return getFdCount(t.gpuCompositionDoneFence) +
- getFdCount(t.displayPresentFence) +
- getFdCount(t.displayRetireFence) +
- getFdCount(t.releaseFence);
-};
-
-/**
- * \brief Unflatten `FrameEventsDelta`.
- *
- * \param[out] t The destination `FrameEventsDelta`.
- * \param[out] nh The underlying array of native handles.
- * \param[in,out] buffer The pointer to the flat non-fd buffer.
- * \param[in,out] size The size of the flat non-fd buffer.
- * \param[in,out] fds The pointer to the flat fd buffer.
- * \param[in,out] numFds The size of the flat fd buffer.
- * \return `NO_ERROR` on success; other value on failure.
- *
- * If the return value is `NO_ERROR`, \p nh will have length 4, and it will be
- * populated with `nullptr` or newly created handles. Each non-null slot in \p
- * nh will need to be deleted manually with `native_handle_delete()`.
- */
-inline status_t unflatten(HGraphicBufferProducer::FrameEventsDelta* t,
- std::vector<native_handle_t*>* nh,
- void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
- if (size < minFlattenedSize(*t)) {
- return NO_MEMORY;
- }
- FlattenableUtils::read(buffer, size, t->frameNumber);
-
- // These were written as uint8_t for alignment.
- uint8_t temp = 0;
- FlattenableUtils::read(buffer, size, temp);
- size_t index = static_cast<size_t>(temp);
- if (index >= ::android::FrameEventHistory::MAX_FRAME_HISTORY) {
- return BAD_VALUE;
- }
- t->index = static_cast<uint32_t>(index);
-
- FlattenableUtils::read(buffer, size, temp);
- t->addPostCompositeCalled = static_cast<bool>(temp);
- FlattenableUtils::read(buffer, size, temp);
- t->addRetireCalled = static_cast<bool>(temp);
- FlattenableUtils::read(buffer, size, temp);
- t->addReleaseCalled = static_cast<bool>(temp);
-
- FlattenableUtils::read(buffer, size, t->postedTimeNs);
- FlattenableUtils::read(buffer, size, t->requestedPresentTimeNs);
- FlattenableUtils::read(buffer, size, t->latchTimeNs);
- FlattenableUtils::read(buffer, size, t->firstRefreshStartTimeNs);
- FlattenableUtils::read(buffer, size, t->lastRefreshStartTimeNs);
- FlattenableUtils::read(buffer, size, t->dequeueReadyTime);
-
- // Fences
- HGraphicBufferProducer::FenceTimeSnapshot* tSnapshot[4];
- tSnapshot[0] = &t->gpuCompositionDoneFence;
- tSnapshot[1] = &t->displayPresentFence;
- tSnapshot[2] = &t->displayRetireFence;
- tSnapshot[3] = &t->releaseFence;
- nh->resize(4);
- for (size_t snapshotIndex = 0; snapshotIndex < 4; ++snapshotIndex) {
- status_t status = unflatten(
- tSnapshot[snapshotIndex], &((*nh)[snapshotIndex]),
- buffer, size, fds, numFds);
- if (status != NO_ERROR) {
- while (snapshotIndex > 0) {
- --snapshotIndex;
- if ((*nh)[snapshotIndex] != nullptr) {
- native_handle_delete((*nh)[snapshotIndex]);
- }
- }
- return status;
- }
- }
- return NO_ERROR;
-}
-
-/**
- * \brief Flatten `FrameEventsDelta`.
- *
- * \param[in] t The source `FrameEventsDelta`.
- * \param[in,out] buffer The pointer to the flat non-fd buffer.
- * \param[in,out] size The size of the flat non-fd buffer.
- * \param[in,out] fds The pointer to the flat fd buffer.
- * \param[in,out] numFds The size of the flat fd buffer.
- * \return `NO_ERROR` on success; other value on failure.
- *
- * This function will duplicate file descriptors contained in \p t.
- */
-// Ref: frameworks/native/libs/gui/FrameTimestamp.cpp:
-// FrameEventsDelta::flatten
-inline status_t flatten(HGraphicBufferProducer::FrameEventsDelta const& t,
- void*& buffer, size_t& size, int*& fds, size_t numFds) {
- // Check that t.index is within a valid range.
- if (t.index >= static_cast<uint32_t>(FrameEventHistory::MAX_FRAME_HISTORY)
- || t.index > std::numeric_limits<uint8_t>::max()) {
- return BAD_VALUE;
- }
-
- FlattenableUtils::write(buffer, size, t.frameNumber);
-
- // These are static_cast to uint8_t for alignment.
- FlattenableUtils::write(buffer, size, static_cast<uint8_t>(t.index));
- FlattenableUtils::write(
- buffer, size, static_cast<uint8_t>(t.addPostCompositeCalled));
- FlattenableUtils::write(
- buffer, size, static_cast<uint8_t>(t.addRetireCalled));
- FlattenableUtils::write(
- buffer, size, static_cast<uint8_t>(t.addReleaseCalled));
-
- FlattenableUtils::write(buffer, size, t.postedTimeNs);
- FlattenableUtils::write(buffer, size, t.requestedPresentTimeNs);
- FlattenableUtils::write(buffer, size, t.latchTimeNs);
- FlattenableUtils::write(buffer, size, t.firstRefreshStartTimeNs);
- FlattenableUtils::write(buffer, size, t.lastRefreshStartTimeNs);
- FlattenableUtils::write(buffer, size, t.dequeueReadyTime);
-
- // Fences
- HGraphicBufferProducer::FenceTimeSnapshot const* tSnapshot[4];
- tSnapshot[0] = &t.gpuCompositionDoneFence;
- tSnapshot[1] = &t.displayPresentFence;
- tSnapshot[2] = &t.displayRetireFence;
- tSnapshot[3] = &t.releaseFence;
- for (size_t snapshotIndex = 0; snapshotIndex < 4; ++snapshotIndex) {
- status_t status = flatten(
- *(tSnapshot[snapshotIndex]), buffer, size, fds, numFds);
- if (status != NO_ERROR) {
- return status;
- }
- }
- return NO_ERROR;
-}
-
-// Ref: frameworks/native/libs/gui/FrameTimestamps.cpp: FrameEventHistoryDelta
-
-/**
- * \brief Return the size of the non-fd buffer required to flatten
- * `HGraphicBufferProducer::FrameEventHistoryDelta`.
- *
- * \param[in] t The input `HGraphicBufferProducer::FrameEventHistoryDelta`.
- * \return The required size of the flat buffer.
- */
-inline size_t getFlattenedSize(
- HGraphicBufferProducer::FrameEventHistoryDelta const& t) {
- size_t size = 4 + // mDeltas.size()
- sizeof(t.compositorTiming);
- for (size_t i = 0; i < t.deltas.size(); ++i) {
- size += getFlattenedSize(t.deltas[i]);
- }
- return size;
-}
-
-/**
- * \brief Return the number of file descriptors contained in
- * `HGraphicBufferProducer::FrameEventHistoryDelta`.
- *
- * \param[in] t The input `HGraphicBufferProducer::FrameEventHistoryDelta`.
- * \return The number of file descriptors contained in \p t.
- */
-inline size_t getFdCount(
- HGraphicBufferProducer::FrameEventHistoryDelta const& t) {
- size_t numFds = 0;
- for (size_t i = 0; i < t.deltas.size(); ++i) {
- numFds += getFdCount(t.deltas[i]);
- }
- return numFds;
-}
-
-/**
- * \brief Unflatten `FrameEventHistoryDelta`.
- *
- * \param[out] t The destination `FrameEventHistoryDelta`.
- * \param[out] nh The underlying array of arrays of native handles.
- * \param[in,out] buffer The pointer to the flat non-fd buffer.
- * \param[in,out] size The size of the flat non-fd buffer.
- * \param[in,out] fds The pointer to the flat fd buffer.
- * \param[in,out] numFds The size of the flat fd buffer.
- * \return `NO_ERROR` on success; other value on failure.
- *
- * If the return value is `NO_ERROR`, \p nh will be populated with `nullptr` or
- * newly created handles. The second dimension of \p nh will be 4. Each non-null
- * slot in \p nh will need to be deleted manually with `native_handle_delete()`.
- */
-inline status_t unflatten(
- HGraphicBufferProducer::FrameEventHistoryDelta* t,
- std::vector<std::vector<native_handle_t*> >* nh,
- void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
- if (size < 4) {
- return NO_MEMORY;
- }
-
- FlattenableUtils::read(buffer, size, t->compositorTiming);
-
- uint32_t deltaCount = 0;
- FlattenableUtils::read(buffer, size, deltaCount);
- if (static_cast<size_t>(deltaCount) >
- ::android::FrameEventHistory::MAX_FRAME_HISTORY) {
- return BAD_VALUE;
- }
- t->deltas.resize(deltaCount);
- nh->resize(deltaCount);
- for (size_t deltaIndex = 0; deltaIndex < deltaCount; ++deltaIndex) {
- status_t status = unflatten(
- &(t->deltas[deltaIndex]), &((*nh)[deltaIndex]),
- buffer, size, fds, numFds);
- if (status != NO_ERROR) {
- return status;
- }
- }
- return NO_ERROR;
-}
-
-/**
- * \brief Flatten `FrameEventHistoryDelta`.
- *
- * \param[in] t The source `FrameEventHistoryDelta`.
- * \param[in,out] buffer The pointer to the flat non-fd buffer.
- * \param[in,out] size The size of the flat non-fd buffer.
- * \param[in,out] fds The pointer to the flat fd buffer.
- * \param[in,out] numFds The size of the flat fd buffer.
- * \return `NO_ERROR` on success; other value on failure.
- *
- * This function will duplicate file descriptors contained in \p t.
- */
-inline status_t flatten(
- HGraphicBufferProducer::FrameEventHistoryDelta const& t,
- void*& buffer, size_t& size, int*& fds, size_t& numFds) {
- if (t.deltas.size() > ::android::FrameEventHistory::MAX_FRAME_HISTORY) {
- return BAD_VALUE;
- }
- if (size < getFlattenedSize(t)) {
- return NO_MEMORY;
- }
-
- FlattenableUtils::write(buffer, size, t.compositorTiming);
-
- FlattenableUtils::write(buffer, size, static_cast<uint32_t>(t.deltas.size()));
- for (size_t deltaIndex = 0; deltaIndex < t.deltas.size(); ++deltaIndex) {
- status_t status = flatten(t.deltas[deltaIndex], buffer, size, fds, numFds);
- if (status != NO_ERROR) {
- return status;
- }
- }
- return NO_ERROR;
-}
-
-/**
- * \brief Wrap `::android::FrameEventHistoryData` in
- * `HGraphicBufferProducer::FrameEventHistoryDelta`.
- *
- * \param[out] t The wrapper of type
- * `HGraphicBufferProducer::FrameEventHistoryDelta`.
- * \param[out] nh The array of array of native handles that are referred to by
- * members of \p t.
- * \param[in] l The source `::android::FrameEventHistoryDelta`.
- *
- * On success, each member of \p nh will be either `nullptr` or a newly created
- * native handle. All the non-`nullptr` elements must be deleted individually
- * with `native_handle_delete()`.
- */
-inline bool wrapAs(HGraphicBufferProducer::FrameEventHistoryDelta* t,
- std::vector<std::vector<native_handle_t*> >* nh,
- ::android::FrameEventHistoryDelta const& l) {
-
- size_t const baseSize = l.getFlattenedSize();
- std::unique_ptr<uint8_t[]> baseBuffer(
- new (std::nothrow) uint8_t[baseSize]);
- if (!baseBuffer) {
- return false;
- }
-
- size_t const baseNumFds = l.getFdCount();
- std::unique_ptr<int[]> baseFds(
- new (std::nothrow) int[baseNumFds]);
- if (!baseFds) {
- return false;
- }
-
- void* buffer = static_cast<void*>(baseBuffer.get());
- size_t size = baseSize;
- int* fds = baseFds.get();
- size_t numFds = baseNumFds;
- if (l.flatten(buffer, size, fds, numFds) != NO_ERROR) {
- return false;
- }
-
- void const* constBuffer = static_cast<void const*>(baseBuffer.get());
- size = baseSize;
- int const* constFds = static_cast<int const*>(baseFds.get());
- numFds = baseNumFds;
- if (unflatten(t, nh, constBuffer, size, constFds, numFds) != NO_ERROR) {
- return false;
- }
-
- return true;
-}
-
-/**
- * \brief Convert `HGraphicBufferProducer::FrameEventHistoryDelta` to
- * `::android::FrameEventHistoryDelta`.
- *
- * \param[out] l The destination `::android::FrameEventHistoryDelta`.
- * \param[in] t The source `HGraphicBufferProducer::FrameEventHistoryDelta`.
- *
- * This function will duplicate all file descriptors contained in \p t.
- */
-inline bool convertTo(
- ::android::FrameEventHistoryDelta* l,
- HGraphicBufferProducer::FrameEventHistoryDelta const& t) {
-
- size_t const baseSize = getFlattenedSize(t);
- std::unique_ptr<uint8_t[]> baseBuffer(
- new (std::nothrow) uint8_t[baseSize]);
- if (!baseBuffer) {
- return false;
- }
-
- size_t const baseNumFds = getFdCount(t);
- std::unique_ptr<int[]> baseFds(
- new (std::nothrow) int[baseNumFds]);
- if (!baseFds) {
- return false;
- }
-
- void* buffer = static_cast<void*>(baseBuffer.get());
- size_t size = baseSize;
- int* fds = static_cast<int*>(baseFds.get());
- size_t numFds = baseNumFds;
- if (flatten(t, buffer, size, fds, numFds) != NO_ERROR) {
- return false;
- }
-
- void const* constBuffer = static_cast<void const*>(baseBuffer.get());
- size = baseSize;
- int const* constFds = static_cast<int const*>(baseFds.get());
- numFds = baseNumFds;
- if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
- return false;
- }
-
- return true;
-}
-
-// Ref: frameworks/native/libs/ui/Region.cpp
-
-/**
- * \brief Return the size of the buffer required to flatten `Region`.
- *
- * \param[in] t The input `Region`.
- * \return The required size of the flat buffer.
- */
-inline size_t getFlattenedSize(Region const& t) {
- return sizeof(uint32_t) + t.size() * sizeof(::android::Rect);
-}
-
-/**
- * \brief Unflatten `Region`.
- *
- * \param[out] t The destination `Region`.
- * \param[in,out] buffer The pointer to the flat buffer.
- * \param[in,out] size The size of the flat buffer.
- * \return `NO_ERROR` on success; other value on failure.
- */
-inline status_t unflatten(Region* t, void const*& buffer, size_t& size) {
- if (size < sizeof(uint32_t)) {
- return NO_MEMORY;
- }
-
- uint32_t numRects = 0;
- FlattenableUtils::read(buffer, size, numRects);
- if (size < numRects * sizeof(Rect)) {
- return NO_MEMORY;
- }
- if (numRects > (UINT32_MAX / sizeof(Rect))) {
- return NO_MEMORY;
- }
-
- t->resize(numRects);
- for (size_t r = 0; r < numRects; ++r) {
- ::android::Rect rect(::android::Rect::EMPTY_RECT);
- status_t status = rect.unflatten(buffer, size);
- if (status != NO_ERROR) {
- return status;
- }
- FlattenableUtils::advance(buffer, size, sizeof(rect));
- (*t)[r] = Rect{
- static_cast<int32_t>(rect.left),
- static_cast<int32_t>(rect.top),
- static_cast<int32_t>(rect.right),
- static_cast<int32_t>(rect.bottom)};
- }
- return NO_ERROR;
-}
-
-/**
- * \brief Flatten `Region`.
- *
- * \param[in] t The source `Region`.
- * \param[in,out] buffer The pointer to the flat buffer.
- * \param[in,out] size The size of the flat buffer.
- * \return `NO_ERROR` on success; other value on failure.
- */
-inline status_t flatten(Region const& t, void*& buffer, size_t& size) {
- if (size < getFlattenedSize(t)) {
- return NO_MEMORY;
- }
-
- FlattenableUtils::write(buffer, size, static_cast<uint32_t>(t.size()));
- for (size_t r = 0; r < t.size(); ++r) {
- ::android::Rect rect(
- static_cast<int32_t>(t[r].left),
- static_cast<int32_t>(t[r].top),
- static_cast<int32_t>(t[r].right),
- static_cast<int32_t>(t[r].bottom));
- status_t status = rect.flatten(buffer, size);
- if (status != NO_ERROR) {
- return status;
- }
- FlattenableUtils::advance(buffer, size, sizeof(rect));
- }
- return NO_ERROR;
-}
-
-/**
- * \brief Convert `::android::Region` to `Region`.
- *
- * \param[out] t The destination `Region`.
- * \param[in] l The source `::android::Region`.
- */
-// convert: ::android::Region -> Region
-inline bool convertTo(Region* t, ::android::Region const& l) {
- size_t const baseSize = l.getFlattenedSize();
- std::unique_ptr<uint8_t[]> baseBuffer(
- new (std::nothrow) uint8_t[baseSize]);
- if (!baseBuffer) {
- return false;
- }
-
- void* buffer = static_cast<void*>(baseBuffer.get());
- size_t size = baseSize;
- if (l.flatten(buffer, size) != NO_ERROR) {
- return false;
- }
-
- void const* constBuffer = static_cast<void const*>(baseBuffer.get());
- size = baseSize;
- if (unflatten(t, constBuffer, size) != NO_ERROR) {
- return false;
- }
-
- return true;
-}
-
-/**
- * \brief Convert `Region` to `::android::Region`.
- *
- * \param[out] l The destination `::android::Region`.
- * \param[in] t The source `Region`.
- */
-// convert: Region -> ::android::Region
-inline bool convertTo(::android::Region* l, Region const& t) {
- size_t const baseSize = getFlattenedSize(t);
- std::unique_ptr<uint8_t[]> baseBuffer(
- new (std::nothrow) uint8_t[baseSize]);
- if (!baseBuffer) {
- return false;
- }
-
- void* buffer = static_cast<void*>(baseBuffer.get());
- size_t size = baseSize;
- if (flatten(t, buffer, size) != NO_ERROR) {
- return false;
- }
-
- void const* constBuffer = static_cast<void const*>(baseBuffer.get());
- size = baseSize;
- if (l->unflatten(constBuffer, size) != NO_ERROR) {
- return false;
- }
-
- return true;
-}
-
-// Ref: frameworks/native/libs/gui/BGraphicBufferProducer.cpp:
-// BGraphicBufferProducer::QueueBufferInput
-
-/**
- * \brief Return a lower bound on the size of the buffer required to flatten
- * `HGraphicBufferProducer::QueueBufferInput`.
- *
- * \param[in] t The input `HGraphicBufferProducer::QueueBufferInput`.
- * \return A lower bound on the size of the flat buffer.
- */
-constexpr size_t minFlattenedSize(
- HGraphicBufferProducer::QueueBufferInput const& /* t */) {
- return sizeof(int64_t) + // timestamp
- sizeof(int) + // isAutoTimestamp
- sizeof(android_dataspace) + // dataSpace
- sizeof(::android::Rect) + // crop
- sizeof(int) + // scalingMode
- sizeof(uint32_t) + // transform
- sizeof(uint32_t) + // stickyTransform
- sizeof(bool); // getFrameTimestamps
-}
-
-/**
- * \brief Return the size of the buffer required to flatten
- * `HGraphicBufferProducer::QueueBufferInput`.
- *
- * \param[in] t The input `HGraphicBufferProducer::QueueBufferInput`.
- * \return The required size of the flat buffer.
- */
-inline size_t getFlattenedSize(HGraphicBufferProducer::QueueBufferInput const& t) {
- return minFlattenedSize(t) +
- getFenceFlattenedSize(t.fence) +
- getFlattenedSize(t.surfaceDamage) +
- sizeof(HdrMetadata::validTypes);
-}
-
-/**
- * \brief Return the number of file descriptors contained in
- * `HGraphicBufferProducer::QueueBufferInput`.
- *
- * \param[in] t The input `HGraphicBufferProducer::QueueBufferInput`.
- * \return The number of file descriptors contained in \p t.
- */
-inline size_t getFdCount(
- HGraphicBufferProducer::QueueBufferInput const& t) {
- return getFenceFdCount(t.fence);
-}
-
-/**
- * \brief Flatten `HGraphicBufferProducer::QueueBufferInput`.
- *
- * \param[in] t The source `HGraphicBufferProducer::QueueBufferInput`.
- * \param[out] nh The native handle cloned from `t.fence`.
- * \param[in,out] buffer The pointer to the flat non-fd buffer.
- * \param[in,out] size The size of the flat non-fd buffer.
- * \param[in,out] fds The pointer to the flat fd buffer.
- * \param[in,out] numFds The size of the flat fd buffer.
- * \return `NO_ERROR` on success; other value on failure.
- *
- * This function will duplicate the file descriptor in `t.fence`. */
-inline status_t flatten(HGraphicBufferProducer::QueueBufferInput const& t,
- native_handle_t** nh,
- void*& buffer, size_t& size, int*& fds, size_t& numFds) {
- if (size < getFlattenedSize(t)) {
- return NO_MEMORY;
- }
-
- FlattenableUtils::write(buffer, size, t.timestamp);
- FlattenableUtils::write(buffer, size, static_cast<int>(t.isAutoTimestamp));
- FlattenableUtils::write(buffer, size,
- static_cast<android_dataspace_t>(t.dataSpace));
- FlattenableUtils::write(buffer, size, ::android::Rect(
- static_cast<int32_t>(t.crop.left),
- static_cast<int32_t>(t.crop.top),
- static_cast<int32_t>(t.crop.right),
- static_cast<int32_t>(t.crop.bottom)));
- FlattenableUtils::write(buffer, size, static_cast<int>(t.scalingMode));
- FlattenableUtils::write(buffer, size, t.transform);
- FlattenableUtils::write(buffer, size, t.stickyTransform);
- FlattenableUtils::write(buffer, size, t.getFrameTimestamps);
-
- *nh = t.fence.getNativeHandle() == nullptr ?
- nullptr : native_handle_clone(t.fence);
- status_t status = flattenFence(hidl_handle(*nh), buffer, size, fds, numFds);
- if (status != NO_ERROR) {
- return status;
- }
- status = flatten(t.surfaceDamage, buffer, size);
- if (status != NO_ERROR) {
- return status;
- }
- FlattenableUtils::write(buffer, size, decltype(HdrMetadata::validTypes)(0));
- return NO_ERROR;
-}
-
-/**
- * \brief Unflatten `HGraphicBufferProducer::QueueBufferInput`.
- *
- * \param[out] t The destination `HGraphicBufferProducer::QueueBufferInput`.
- * \param[out] nh The underlying native handle for `t->fence`.
- * \param[in,out] buffer The pointer to the flat non-fd buffer.
- * \param[in,out] size The size of the flat non-fd buffer.
- * \param[in,out] fds The pointer to the flat fd buffer.
- * \param[in,out] numFds The size of the flat fd buffer.
- * \return `NO_ERROR` on success; other value on failure.
- *
- * If the return value is `NO_ERROR` and `t->fence` contains a valid file
- * descriptor, \p nh will be a newly created native handle holding that file
- * descriptor. \p nh needs to be deleted with `native_handle_delete()`
- * afterwards.
- */
-inline status_t unflatten(
- HGraphicBufferProducer::QueueBufferInput* t, native_handle_t** nh,
- void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
- if (size < minFlattenedSize(*t)) {
- return NO_MEMORY;
- }
-
- FlattenableUtils::read(buffer, size, t->timestamp);
- int lIsAutoTimestamp;
- FlattenableUtils::read(buffer, size, lIsAutoTimestamp);
- t->isAutoTimestamp = static_cast<int32_t>(lIsAutoTimestamp);
- android_dataspace_t lDataSpace;
- FlattenableUtils::read(buffer, size, lDataSpace);
- t->dataSpace = static_cast<Dataspace>(lDataSpace);
- Rect lCrop;
- FlattenableUtils::read(buffer, size, lCrop);
- t->crop = Rect{
- static_cast<int32_t>(lCrop.left),
- static_cast<int32_t>(lCrop.top),
- static_cast<int32_t>(lCrop.right),
- static_cast<int32_t>(lCrop.bottom)};
- int lScalingMode;
- FlattenableUtils::read(buffer, size, lScalingMode);
- t->scalingMode = static_cast<int32_t>(lScalingMode);
- FlattenableUtils::read(buffer, size, t->transform);
- FlattenableUtils::read(buffer, size, t->stickyTransform);
- FlattenableUtils::read(buffer, size, t->getFrameTimestamps);
-
- status_t status = unflattenFence(&(t->fence), nh,
- buffer, size, fds, numFds);
- if (status != NO_ERROR) {
- return status;
- }
- // HdrMetadata ignored
- return unflatten(&(t->surfaceDamage), buffer, size);
-}
-
-/**
- * \brief Wrap `BGraphicBufferProducer::QueueBufferInput` in
- * `HGraphicBufferProducer::QueueBufferInput`.
- *
- * \param[out] t The wrapper of type
- * `HGraphicBufferProducer::QueueBufferInput`.
- * \param[out] nh The underlying native handle for `t->fence`.
- * \param[in] l The source `BGraphicBufferProducer::QueueBufferInput`.
- *
- * If the return value is `true` and `t->fence` contains a valid file
- * descriptor, \p nh will be a newly created native handle holding that file
- * descriptor. \p nh needs to be deleted with `native_handle_delete()`
- * afterwards.
- */
-inline bool wrapAs(
- HGraphicBufferProducer::QueueBufferInput* t,
- native_handle_t** nh,
- BGraphicBufferProducer::QueueBufferInput const& l) {
-
- size_t const baseSize = l.getFlattenedSize();
- std::unique_ptr<uint8_t[]> baseBuffer(
- new (std::nothrow) uint8_t[baseSize]);
- if (!baseBuffer) {
- return false;
- }
-
- size_t const baseNumFds = l.getFdCount();
- std::unique_ptr<int[]> baseFds(
- new (std::nothrow) int[baseNumFds]);
- if (!baseFds) {
- return false;
- }
-
- void* buffer = static_cast<void*>(baseBuffer.get());
- size_t size = baseSize;
- int* fds = baseFds.get();
- size_t numFds = baseNumFds;
- if (l.flatten(buffer, size, fds, numFds) != NO_ERROR) {
- return false;
- }
-
- void const* constBuffer = static_cast<void const*>(baseBuffer.get());
- size = baseSize;
- int const* constFds = static_cast<int const*>(baseFds.get());
- numFds = baseNumFds;
- if (unflatten(t, nh, constBuffer, size, constFds, numFds) != NO_ERROR) {
- return false;
- }
-
- return true;
-}
-
-/**
- * \brief Convert `HGraphicBufferProducer::QueueBufferInput` to
- * `BGraphicBufferProducer::QueueBufferInput`.
- *
- * \param[out] l The destination `BGraphicBufferProducer::QueueBufferInput`.
- * \param[in] t The source `HGraphicBufferProducer::QueueBufferInput`.
- *
- * If `t.fence` has a valid file descriptor, it will be duplicated.
- */
-inline bool convertTo(
- BGraphicBufferProducer::QueueBufferInput* l,
- HGraphicBufferProducer::QueueBufferInput const& t) {
-
- size_t const baseSize = getFlattenedSize(t);
- std::unique_ptr<uint8_t[]> baseBuffer(
- new (std::nothrow) uint8_t[baseSize]);
- if (!baseBuffer) {
- return false;
- }
-
- size_t const baseNumFds = getFdCount(t);
- std::unique_ptr<int[]> baseFds(
- new (std::nothrow) int[baseNumFds]);
- if (!baseFds) {
- return false;
- }
-
- void* buffer = static_cast<void*>(baseBuffer.get());
- size_t size = baseSize;
- int* fds = baseFds.get();
- size_t numFds = baseNumFds;
- native_handle_t* nh;
- if (flatten(t, &nh, buffer, size, fds, numFds) != NO_ERROR) {
- return false;
- }
-
- void const* constBuffer = static_cast<void const*>(baseBuffer.get());
- size = baseSize;
- int const* constFds = static_cast<int const*>(baseFds.get());
- numFds = baseNumFds;
- if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
- if (nh != nullptr) {
- native_handle_close(nh);
- native_handle_delete(nh);
- }
- return false;
- }
-
- native_handle_delete(nh);
- return true;
-}
-
-// Ref: frameworks/native/libs/gui/BGraphicBufferProducer.cpp:
-// BGraphicBufferProducer::QueueBufferOutput
-
-/**
- * \brief Wrap `BGraphicBufferProducer::QueueBufferOutput` in
- * `HGraphicBufferProducer::QueueBufferOutput`.
- *
- * \param[out] t The wrapper of type
- * `HGraphicBufferProducer::QueueBufferOutput`.
- * \param[out] nh The array of array of native handles that are referred to by
- * members of \p t.
- * \param[in] l The source `BGraphicBufferProducer::QueueBufferOutput`.
- *
- * On success, each member of \p nh will be either `nullptr` or a newly created
- * native handle. All the non-`nullptr` elements must be deleted individually
- * with `native_handle_delete()`.
- */
-// wrap: BGraphicBufferProducer::QueueBufferOutput ->
-// HGraphicBufferProducer::QueueBufferOutput
-inline bool wrapAs(HGraphicBufferProducer::QueueBufferOutput* t,
- std::vector<std::vector<native_handle_t*> >* nh,
- BGraphicBufferProducer::QueueBufferOutput const& l) {
- if (!wrapAs(&(t->frameTimestamps), nh, l.frameTimestamps)) {
- return false;
- }
- t->width = l.width;
- t->height = l.height;
- t->transformHint = l.transformHint;
- t->numPendingBuffers = l.numPendingBuffers;
- t->nextFrameNumber = l.nextFrameNumber;
- t->bufferReplaced = l.bufferReplaced;
- return true;
-}
-
-/**
- * \brief Convert `HGraphicBufferProducer::QueueBufferOutput` to
- * `BGraphicBufferProducer::QueueBufferOutput`.
- *
- * \param[out] l The destination `BGraphicBufferProducer::QueueBufferOutput`.
- * \param[in] t The source `HGraphicBufferProducer::QueueBufferOutput`.
- *
- * This function will duplicate all file descriptors contained in \p t.
- */
-// convert: HGraphicBufferProducer::QueueBufferOutput ->
-// BGraphicBufferProducer::QueueBufferOutput
-inline bool convertTo(
- BGraphicBufferProducer::QueueBufferOutput* l,
- HGraphicBufferProducer::QueueBufferOutput const& t) {
- if (!convertTo(&(l->frameTimestamps), t.frameTimestamps)) {
- return false;
- }
- l->width = t.width;
- l->height = t.height;
- l->transformHint = t.transformHint;
- l->numPendingBuffers = t.numPendingBuffers;
- l->nextFrameNumber = t.nextFrameNumber;
- l->bufferReplaced = t.bufferReplaced;
- return true;
-}
-
-/**
- * \brief Convert `BGraphicBufferProducer::DisconnectMode` to
- * `HGraphicBufferProducer::DisconnectMode`.
- *
- * \param[in] l The source `BGraphicBufferProducer::DisconnectMode`.
- * \return The corresponding `HGraphicBufferProducer::DisconnectMode`.
- */
-inline HGraphicBufferProducer::DisconnectMode toOmxDisconnectMode(
- BGraphicBufferProducer::DisconnectMode l) {
- switch (l) {
- case BGraphicBufferProducer::DisconnectMode::Api:
- return HGraphicBufferProducer::DisconnectMode::API;
- case BGraphicBufferProducer::DisconnectMode::AllLocal:
- return HGraphicBufferProducer::DisconnectMode::ALL_LOCAL;
- }
- return HGraphicBufferProducer::DisconnectMode::API;
-}
-
-/**
- * \brief Convert `HGraphicBufferProducer::DisconnectMode` to
- * `BGraphicBufferProducer::DisconnectMode`.
- *
- * \param[in] l The source `HGraphicBufferProducer::DisconnectMode`.
- * \return The corresponding `BGraphicBufferProducer::DisconnectMode`.
- */
-inline BGraphicBufferProducer::DisconnectMode toGuiDisconnectMode(
- HGraphicBufferProducer::DisconnectMode t) {
- switch (t) {
- case HGraphicBufferProducer::DisconnectMode::API:
- return BGraphicBufferProducer::DisconnectMode::Api;
- case HGraphicBufferProducer::DisconnectMode::ALL_LOCAL:
- return BGraphicBufferProducer::DisconnectMode::AllLocal;
- }
- return BGraphicBufferProducer::DisconnectMode::Api;
-}
-
} // namespace implementation
} // namespace V1_0
} // namespace omx
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/1.0/WGraphicBufferProducer.h b/media/libstagefright/omx/include/media/stagefright/omx/1.0/WGraphicBufferProducer.h
index 4a3fe0c..322a699 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/1.0/WGraphicBufferProducer.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/1.0/WGraphicBufferProducer.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2016, The Android Open Source Project
+ * 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.
@@ -17,14 +17,7 @@
#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WGRAPHICBUFFERPRODUCER_H
#define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WGRAPHICBUFFERPRODUCER_H
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-
-#include <binder/Binder.h>
-#include <gui/IGraphicBufferProducer.h>
-#include <gui/IProducerListener.h>
-
-#include <android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h>
+#include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
namespace android {
namespace hardware {
@@ -33,67 +26,8 @@
namespace V1_0 {
namespace implementation {
-using ::android::hardware::graphics::common::V1_0::PixelFormat;
-using ::android::hardware::media::V1_0::AnwBuffer;
-using ::android::hidl::base::V1_0::IBase;
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::sp;
-
-typedef ::android::hardware::graphics::bufferqueue::V1_0::
- IGraphicBufferProducer HGraphicBufferProducer;
-typedef ::android::hardware::graphics::bufferqueue::V1_0::
- IProducerListener HProducerListener;
-
-typedef ::android::IGraphicBufferProducer BGraphicBufferProducer;
-typedef ::android::IProducerListener BProducerListener;
-using ::android::BnGraphicBufferProducer;
-
-struct TWGraphicBufferProducer : public HGraphicBufferProducer {
- sp<BGraphicBufferProducer> mBase;
- TWGraphicBufferProducer(sp<BGraphicBufferProducer> const& base);
- Return<void> requestBuffer(int32_t slot, requestBuffer_cb _hidl_cb)
- override;
- Return<int32_t> setMaxDequeuedBufferCount(int32_t maxDequeuedBuffers)
- override;
- Return<int32_t> setAsyncMode(bool async) override;
- Return<void> dequeueBuffer(
- uint32_t width, uint32_t height, PixelFormat format, uint32_t usage,
- bool getFrameTimestamps, dequeueBuffer_cb _hidl_cb) override;
- Return<int32_t> detachBuffer(int32_t slot) override;
- Return<void> detachNextBuffer(detachNextBuffer_cb _hidl_cb) override;
- Return<void> attachBuffer(const AnwBuffer& buffer, attachBuffer_cb _hidl_cb)
- override;
- Return<void> queueBuffer(
- int32_t slot, const HGraphicBufferProducer::QueueBufferInput& input,
- queueBuffer_cb _hidl_cb) override;
- Return<int32_t> cancelBuffer(int32_t slot, const hidl_handle& fence)
- override;
- Return<void> query(int32_t what, query_cb _hidl_cb) override;
- Return<void> connect(const sp<HProducerListener>& listener,
- int32_t api, bool producerControlledByApp,
- connect_cb _hidl_cb) override;
- Return<int32_t> disconnect(
- int32_t api,
- HGraphicBufferProducer::DisconnectMode mode) override;
- Return<int32_t> setSidebandStream(const hidl_handle& stream) override;
- Return<void> allocateBuffers(
- uint32_t width, uint32_t height,
- PixelFormat format, uint32_t usage) override;
- Return<int32_t> allowAllocation(bool allow) override;
- Return<int32_t> setGenerationNumber(uint32_t generationNumber) override;
- Return<void> getConsumerName(getConsumerName_cb _hidl_cb) override;
- Return<int32_t> setSharedBufferMode(bool sharedBufferMode) override;
- Return<int32_t> setAutoRefresh(bool autoRefresh) override;
- Return<int32_t> setDequeueTimeout(int64_t timeoutNs) override;
- Return<void> getLastQueuedBuffer(getLastQueuedBuffer_cb _hidl_cb) override;
- Return<void> getFrameTimestamps(getFrameTimestamps_cb _hidl_cb) override;
- Return<void> getUniqueId(getUniqueId_cb _hidl_cb) override;
-};
+using TWGraphicBufferProducer = ::android::TWGraphicBufferProducer<
+ ::android::hardware::graphics::bufferqueue::V1_0::IGraphicBufferProducer>;
} // namespace implementation
} // namespace V1_0
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/OmxGraphicBufferSource.h b/media/libstagefright/omx/include/media/stagefright/omx/OmxGraphicBufferSource.h
index 4b0f3d2..518e0cb 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/OmxGraphicBufferSource.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/OmxGraphicBufferSource.h
@@ -18,7 +18,7 @@
#define OMX_GRAPHIC_BUFFER_SOURCE_H_
-#include <media/stagefright/gbs/GraphicBufferSource.h>
+#include <media/stagefright/bqhelper/GraphicBufferSource.h>
#include <media/stagefright/foundation/ABase.h>
#include <android/BnGraphicBufferSource.h>
@@ -34,7 +34,7 @@
* This class is used to feed OMX codecs from a Surface via BufferQueue or
* HW producer.
*
- * See media/stagefright/gbs/GraphicBufferSource.h for documentation.
+ * See media/stagefright/bqhelper/GraphicBufferSource.h for documentation.
*/
class OmxGraphicBufferSource : public GraphicBufferSource {
public:
diff --git a/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java b/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java
index 3e6d98f..7e928d7 100644
--- a/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java
@@ -91,10 +91,4 @@
mCallback.onGetRootResult(rootHints, rootMediaId, rootExtra);
});
}
-
- public void onCustomLayoutChanged(final List<CommandButton> layout) {
- getCallbackExecutor().execute(() -> {
- mCallback.onCustomLayoutChanged(layout);
- });
- }
}
diff --git a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java b/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
index a477d1d..5ae37ee 100644
--- a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.media.AudioAttributes;
import android.media.MediaController2.PlaybackInfo;
import android.media.MediaItem2;
import android.media.MediaSession2;
@@ -43,9 +44,6 @@
import android.support.annotation.GuardedBy;
import android.util.Log;
-import com.android.media.MediaSession2Impl.CommandButtonImpl;
-
-import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
@@ -219,7 +217,11 @@
}
Context getContext() {
- return mContext;
+ return mContext;
+ }
+
+ MediaController2 getInstance() {
+ return mInstance;
}
@Override
@@ -502,10 +504,7 @@
sendTransportControlCommand(MediaSession2.COMMAND_CODE_PLAYBACK_SET_PLAYLIST_PARAMS, args);
}
- ///////////////////////////////////////////////////
- // Protected or private methods
- ///////////////////////////////////////////////////
- private void pushPlaybackStateChanges(final PlaybackState2 state) {
+ void pushPlaybackStateChanges(final PlaybackState2 state) {
synchronized (mLock) {
mPlaybackState = state;
}
@@ -517,7 +516,7 @@
});
}
- private void pushPlaylistParamsChanges(final PlaylistParams params) {
+ void pushPlaylistParamsChanges(final PlaylistParams params) {
synchronized (mLock) {
mPlaylistParams = params;
}
@@ -529,7 +528,7 @@
});
}
- private void pushPlaybackInfoChanges(final PlaybackInfo info) {
+ void pushPlaybackInfoChanges(final PlaybackInfo info) {
synchronized (mLock) {
mPlaybackInfo = info;
}
@@ -541,7 +540,7 @@
});
}
- private void pushPlaylistChanges(final List<Bundle> list) {
+ void pushPlaylistChanges(final List<Bundle> list) {
final List<MediaItem2> playlist = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
MediaItem2 item = MediaItem2.fromBundle(mContext, list.get(i));
@@ -562,7 +561,7 @@
}
// Should be used without a lock to prevent potential deadlock.
- private void onConnectedNotLocked(IMediaSession2 sessionBinder,
+ void onConnectedNotLocked(IMediaSession2 sessionBinder,
final CommandGroup commandGroup, final PlaybackState2 state, final PlaybackInfo info,
final PlaylistParams params, final List<MediaItem2> playlist, final int ratingType,
final PendingIntent sessionActivity) {
@@ -623,7 +622,7 @@
}
}
- private void onCustomCommand(final Command command, final Bundle args,
+ void onCustomCommand(final Command command, final Bundle args,
final ResultReceiver receiver) {
if (DEBUG) {
Log.d(TAG, "onCustomCommand cmd=" + command);
@@ -634,193 +633,10 @@
});
}
- // TODO(jaewan): Pull out this from the controller2, and rename it to the MediaController2Stub
- // or MediaBrowser2Stub.
- static class MediaSession2CallbackStub extends IMediaSession2Callback.Stub {
- private final WeakReference<MediaController2Impl> mController;
-
- private MediaSession2CallbackStub(MediaController2Impl controller) {
- mController = new WeakReference<>(controller);
- }
-
- private MediaController2Impl getController() throws IllegalStateException {
- final MediaController2Impl controller = mController.get();
- if (controller == null) {
- throw new IllegalStateException("Controller is released");
- }
- return controller;
- }
-
- // TODO(jaewan): Refactor code to get rid of these pattern.
- private MediaBrowser2Impl getBrowser() throws IllegalStateException {
- final MediaController2Impl controller = getController();
- if (controller instanceof MediaBrowser2Impl) {
- return (MediaBrowser2Impl) controller;
- }
- return null;
- }
-
- public void destroy() {
- mController.clear();
- }
-
- @Override
- public void onPlaybackStateChanged(Bundle state) throws RuntimeException {
- final MediaController2Impl controller;
- try {
- controller = getController();
- } catch (IllegalStateException e) {
- Log.w(TAG, "Don't fail silently here. Highly likely a bug");
- return;
- }
- controller.pushPlaybackStateChanges(
- PlaybackState2.fromBundle(controller.getContext(), state));
- }
-
- @Override
- public void onPlaylistChanged(List<Bundle> playlist) throws RuntimeException {
- final MediaController2Impl controller;
- try {
- controller = getController();
- } catch (IllegalStateException e) {
- Log.w(TAG, "Don't fail silently here. Highly likely a bug");
- return;
- }
- if (playlist == null) {
- return;
- }
- controller.pushPlaylistChanges(playlist);
- }
-
- @Override
- public void onPlaylistParamsChanged(Bundle params) throws RuntimeException {
- final MediaController2Impl controller;
- try {
- controller = getController();
- } catch (IllegalStateException e) {
- Log.w(TAG, "Don't fail silently here. Highly likely a bug");
- return;
- }
- controller.pushPlaylistParamsChanges(
- PlaylistParams.fromBundle(controller.getContext(), params));
- }
-
- @Override
- public void onPlaybackInfoChanged(Bundle playbackInfo) throws RuntimeException {
- if (DEBUG) {
- Log.d(TAG, "onPlaybackInfoChanged");
- }
- final MediaController2Impl controller;
- try {
- controller = getController();
- } catch (IllegalStateException e) {
- Log.w(TAG, "Don't fail silently here. Highly likely a bug");
- return;
- }
- controller.pushPlaybackInfoChanges(
- PlaybackInfoImpl.fromBundle(controller.getContext(), playbackInfo));
- }
-
- @Override
- public void onConnected(IMediaSession2 sessionBinder, Bundle commandGroup,
- Bundle playbackState, Bundle playbackInfo, Bundle playlistParams, List<Bundle>
- playlist, int ratingType, PendingIntent sessionActivity) {
- final MediaController2Impl controller = mController.get();
- if (controller == null) {
- if (DEBUG) {
- Log.d(TAG, "onConnected after MediaController2.close()");
- }
- return;
- }
- final Context context = controller.getContext();
- List<MediaItem2> list = new ArrayList<>();
- for (int i = 0; i < playlist.size(); i++) {
- MediaItem2 item = MediaItem2.fromBundle(context, playlist.get(i));
- if (item != null) {
- list.add(item);
- }
- }
- controller.onConnectedNotLocked(sessionBinder,
- CommandGroup.fromBundle(context, commandGroup),
- PlaybackState2.fromBundle(context, playbackState),
- PlaybackInfoImpl.fromBundle(context, playbackInfo),
- PlaylistParams.fromBundle(context, playlistParams),
- list, ratingType, sessionActivity);
- }
-
- @Override
- public void onDisconnected() {
- final MediaController2Impl controller = mController.get();
- if (controller == null) {
- if (DEBUG) {
- Log.d(TAG, "onDisconnected after MediaController2.close()");
- }
- return;
- }
- controller.mInstance.close();
- }
-
- @Override
- public void onGetRootResult(Bundle rootHints, String rootMediaId, Bundle rootExtra)
- throws RuntimeException {
- final MediaBrowser2Impl browser;
- try {
- browser = getBrowser();
- } catch (IllegalStateException e) {
- Log.w(TAG, "Don't fail silently here. Highly likely a bug");
- return;
- }
- if (browser == null) {
- // TODO(jaewan): Revisit here. Could be a bug
- return;
- }
- browser.onGetRootResult(rootHints, rootMediaId, rootExtra);
- }
-
- @Override
- public void onCustomLayoutChanged(List<Bundle> commandButtonlist) {
- if (commandButtonlist == null) {
- // Illegal call. Ignore
- return;
- }
- // TODO(jaewan): Fix here. It's controller feature so shouldn't use browser
- final MediaBrowser2Impl browser;
- try {
- browser = getBrowser();
- } catch (IllegalStateException e) {
- Log.w(TAG, "Don't fail silently here. Highly likely a bug");
- return;
- }
- if (browser == null) {
- // TODO(jaewan): Revisit here. Could be a bug
- return;
- }
- List<CommandButton> layout = new ArrayList<>();
- for (int i = 0; i < commandButtonlist.size(); i++) {
- CommandButton button = CommandButtonImpl.fromBundle(
- browser.getContext(), commandButtonlist.get(i));
- if (button != null) {
- layout.add(button);
- }
- }
- browser.onCustomLayoutChanged(layout);
- }
-
- @Override
- public void sendCustomCommand(Bundle commandBundle, Bundle args, ResultReceiver receiver) {
- final MediaController2Impl controller;
- try {
- controller = getController();
- } catch (IllegalStateException e) {
- Log.w(TAG, "Don't fail silently here. Highly likely a bug");
- return;
- }
- Command command = Command.fromBundle(controller.getContext(), commandBundle);
- if (command == null) {
- return;
- }
- controller.onCustomCommand(command, args, receiver);
- }
+ void onCustomLayoutChanged(final List<CommandButton> layout) {
+ mCallbackExecutor.execute(() -> {
+ mCallback.onCustomLayoutChanged(layout);
+ });
}
// This will be called on the main thread.
@@ -859,4 +675,97 @@
mInstance.close();
}
}
+
+ public static final class PlaybackInfoImpl implements PlaybackInfoProvider {
+
+ private static final String KEY_PLAYBACK_TYPE =
+ "android.media.playbackinfo_impl.playback_type";
+ private static final String KEY_CONTROL_TYPE =
+ "android.media.playbackinfo_impl.control_type";
+ private static final String KEY_MAX_VOLUME =
+ "android.media.playbackinfo_impl.max_volume";
+ private static final String KEY_CURRENT_VOLUME =
+ "android.media.playbackinfo_impl.current_volume";
+ private static final String KEY_AUDIO_ATTRIBUTES =
+ "android.media.playbackinfo_impl.audio_attrs";
+
+ private final Context mContext;
+ private final PlaybackInfo mInstance;
+
+ private final int mPlaybackType;
+ private final int mControlType;
+ private final int mMaxVolume;
+ private final int mCurrentVolume;
+ private final AudioAttributes mAudioAttrs;
+
+ private PlaybackInfoImpl(Context context, int playbackType, AudioAttributes attrs,
+ int controlType, int max, int current) {
+ mContext = context;
+ mPlaybackType = playbackType;
+ mAudioAttrs = attrs;
+ mControlType = controlType;
+ mMaxVolume = max;
+ mCurrentVolume = current;
+ mInstance = new PlaybackInfo(this);
+ }
+
+ @Override
+ public int getPlaybackType_impl() {
+ return mPlaybackType;
+ }
+
+ @Override
+ public AudioAttributes getAudioAttributes_impl() {
+ return mAudioAttrs;
+ }
+
+ @Override
+ public int getControlType_impl() {
+ return mControlType;
+ }
+
+ @Override
+ public int getMaxVolume_impl() {
+ return mMaxVolume;
+ }
+
+ @Override
+ public int getCurrentVolume_impl() {
+ return mCurrentVolume;
+ }
+
+ public PlaybackInfo getInstance() {
+ return mInstance;
+ }
+
+ public Bundle toBundle() {
+ Bundle bundle = new Bundle();
+ bundle.putInt(KEY_PLAYBACK_TYPE, mPlaybackType);
+ bundle.putInt(KEY_CONTROL_TYPE, mControlType);
+ bundle.putInt(KEY_MAX_VOLUME, mMaxVolume);
+ bundle.putInt(KEY_CURRENT_VOLUME, mCurrentVolume);
+ bundle.putParcelable(KEY_AUDIO_ATTRIBUTES, mAudioAttrs);
+ return bundle;
+ }
+
+ public static PlaybackInfo createPlaybackInfo(Context context, int playbackType,
+ AudioAttributes attrs, int controlType, int max, int current) {
+ return new PlaybackInfoImpl(context, playbackType, attrs, controlType, max, current)
+ .getInstance();
+ }
+
+ public static PlaybackInfo fromBundle(Context context, Bundle bundle) {
+ if (bundle == null) {
+ return null;
+ }
+ final int volumeType = bundle.getInt(KEY_PLAYBACK_TYPE);
+ final int volumeControl = bundle.getInt(KEY_CONTROL_TYPE);
+ final int maxVolume = bundle.getInt(KEY_MAX_VOLUME);
+ final int currentVolume = bundle.getInt(KEY_CURRENT_VOLUME);
+ final AudioAttributes attrs = bundle.getParcelable(KEY_AUDIO_ATTRIBUTES);
+
+ return createPlaybackInfo(
+ context, volumeType, attrs, volumeControl, maxVolume, currentVolume);
+ }
+ }
}
diff --git a/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java b/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
index 77bd334..b9dffcf 100644
--- a/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
@@ -26,6 +26,7 @@
import android.media.MediaPlayerInterface;
import android.media.MediaSession2;
import android.media.MediaSession2.ControllerInfo;
+import android.media.MediaSession2.SessionCallback;
import android.media.MediaSessionService2;
import android.media.SessionToken2;
import android.media.VolumeProvider2;
@@ -87,6 +88,12 @@
}
@Override
+ MediaLibrarySessionCallback getCallback() {
+ // Equivalent to the (MediaLibrarySessionCallback) super.getCallback().
+ return mCallback;
+ }
+
+ @Override
public void notifyChildrenChanged_impl(ControllerInfo controller, String parentId,
Bundle options) {
// TODO(jaewan): Implements
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2CallbackStub.java b/packages/MediaComponents/src/com/android/media/MediaSession2CallbackStub.java
new file mode 100644
index 0000000..07edf7e
--- /dev/null
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2CallbackStub.java
@@ -0,0 +1,227 @@
+/*
+ * 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;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.media.MediaItem2;
+import android.media.MediaSession2.Command;
+import android.media.MediaSession2.CommandButton;
+import android.media.MediaSession2.CommandGroup;
+import android.media.MediaSession2.PlaylistParams;
+import android.media.PlaybackState2;
+import android.os.Bundle;
+import android.os.ResultReceiver;
+import android.util.Log;
+
+import com.android.media.MediaController2Impl.PlaybackInfoImpl;
+import com.android.media.MediaSession2Impl.CommandButtonImpl;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+
+public class MediaSession2CallbackStub extends IMediaSession2Callback.Stub {
+ private static final String TAG = "MS2CallbackStub";
+ private static final boolean DEBUG = true; // TODO(jaewan): Change
+
+ private final WeakReference<MediaController2Impl> mController;
+
+ MediaSession2CallbackStub(MediaController2Impl controller) {
+ mController = new WeakReference<>(controller);
+ }
+
+ private MediaController2Impl getController() throws IllegalStateException {
+ final MediaController2Impl controller = mController.get();
+ if (controller == null) {
+ throw new IllegalStateException("Controller is released");
+ }
+ return controller;
+ }
+
+ private MediaBrowser2Impl getBrowser() throws IllegalStateException {
+ final MediaController2Impl controller = getController();
+ if (controller instanceof MediaBrowser2Impl) {
+ return (MediaBrowser2Impl) controller;
+ }
+ return null;
+ }
+
+ public void destroy() {
+ mController.clear();
+ }
+
+ @Override
+ public void onPlaybackStateChanged(Bundle state) throws RuntimeException {
+ final MediaController2Impl controller;
+ try {
+ controller = getController();
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Don't fail silently here. Highly likely a bug");
+ return;
+ }
+ controller.pushPlaybackStateChanges(
+ PlaybackState2.fromBundle(controller.getContext(), state));
+ }
+
+ @Override
+ public void onPlaylistChanged(List<Bundle> playlist) throws RuntimeException {
+ final MediaController2Impl controller;
+ try {
+ controller = getController();
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Don't fail silently here. Highly likely a bug");
+ return;
+ }
+ if (playlist == null) {
+ return;
+ }
+ controller.pushPlaylistChanges(playlist);
+ }
+
+ @Override
+ public void onPlaylistParamsChanged(Bundle params) throws RuntimeException {
+ final MediaController2Impl controller;
+ try {
+ controller = getController();
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Don't fail silently here. Highly likely a bug");
+ return;
+ }
+ controller.pushPlaylistParamsChanges(
+ PlaylistParams.fromBundle(controller.getContext(), params));
+ }
+
+ @Override
+ public void onPlaybackInfoChanged(Bundle playbackInfo) throws RuntimeException {
+ if (DEBUG) {
+ Log.d(TAG, "onPlaybackInfoChanged");
+ }
+ final MediaController2Impl controller;
+ try {
+ controller = getController();
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Don't fail silently here. Highly likely a bug");
+ return;
+ }
+ controller.pushPlaybackInfoChanges(
+ PlaybackInfoImpl.fromBundle(controller.getContext(), playbackInfo));
+ }
+
+ @Override
+ public void onConnected(IMediaSession2 sessionBinder, Bundle commandGroup,
+ Bundle playbackState, Bundle playbackInfo, Bundle playlistParams, List<Bundle>
+ playlist, int ratingType, PendingIntent sessionActivity) {
+ final MediaController2Impl controller = mController.get();
+ if (controller == null) {
+ if (DEBUG) {
+ Log.d(TAG, "onConnected after MediaController2.close()");
+ }
+ return;
+ }
+ final Context context = controller.getContext();
+ List<MediaItem2> list = new ArrayList<>();
+ for (int i = 0; i < playlist.size(); i++) {
+ MediaItem2 item = MediaItem2.fromBundle(context, playlist.get(i));
+ if (item != null) {
+ list.add(item);
+ }
+ }
+ controller.onConnectedNotLocked(sessionBinder,
+ CommandGroup.fromBundle(context, commandGroup),
+ PlaybackState2.fromBundle(context, playbackState),
+ PlaybackInfoImpl.fromBundle(context, playbackInfo),
+ PlaylistParams.fromBundle(context, playlistParams),
+ list, ratingType, sessionActivity);
+ }
+
+ @Override
+ public void onDisconnected() {
+ final MediaController2Impl controller = mController.get();
+ if (controller == null) {
+ if (DEBUG) {
+ Log.d(TAG, "onDisconnected after MediaController2.close()");
+ }
+ return;
+ }
+ controller.getInstance().close();
+ }
+
+ @Override
+ public void onCustomLayoutChanged(List<Bundle> commandButtonlist) {
+ if (commandButtonlist == null) {
+ // Illegal call. Ignore
+ return;
+ }
+ final MediaController2Impl controller;
+ try {
+ controller = getController();
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Don't fail silently here. Highly likely a bug");
+ return;
+ }
+ if (controller == null) {
+ // TODO(jaewan): Revisit here. Could be a bug
+ return;
+ }
+ List<CommandButton> layout = new ArrayList<>();
+ for (int i = 0; i < commandButtonlist.size(); i++) {
+ CommandButton button = CommandButtonImpl.fromBundle(
+ controller.getContext(), commandButtonlist.get(i));
+ if (button != null) {
+ layout.add(button);
+ }
+ }
+ controller.onCustomLayoutChanged(layout);
+ }
+
+ @Override
+ public void sendCustomCommand(Bundle commandBundle, Bundle args, ResultReceiver receiver) {
+ final MediaController2Impl controller;
+ try {
+ controller = getController();
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Don't fail silently here. Highly likely a bug");
+ return;
+ }
+ Command command = Command.fromBundle(controller.getContext(), commandBundle);
+ if (command == null) {
+ return;
+ }
+ controller.onCustomCommand(command, args, receiver);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ // MediaBrowser specific
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ @Override
+ public void onGetRootResult(Bundle rootHints, String rootMediaId, Bundle rootExtra)
+ throws RuntimeException {
+ final MediaBrowser2Impl browser;
+ try {
+ browser = getBrowser();
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Don't fail silently here. Highly likely a bug");
+ return;
+ }
+ if (browser == null) {
+ // TODO(jaewan): Revisit here. Could be a bug
+ return;
+ }
+ browser.onGetRootResult(rootHints, rootMediaId, rootExtra);
+ }
+}
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java b/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
index f323a17..74ac5b3 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
@@ -252,7 +252,7 @@
stream = AudioManager.STREAM_MUSIC;
}
}
- info = PlaybackInfoImpl.createPlaybackInfo(
+ info = MediaController2Impl.PlaybackInfoImpl.createPlaybackInfo(
mContext,
PlaybackInfo.PLAYBACK_TYPE_LOCAL,
attrs,
@@ -262,7 +262,7 @@
mAudioManager.getStreamMaxVolume(stream),
mAudioManager.getStreamVolume(stream));
} else {
- info = PlaybackInfoImpl.createPlaybackInfo(
+ info = MediaController2Impl.PlaybackInfoImpl.createPlaybackInfo(
mContext,
PlaybackInfo.PLAYBACK_TYPE_REMOTE /* ControlType */,
attrs,
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java b/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
index 2380fc0..43ad49d 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
@@ -19,10 +19,8 @@
import android.app.PendingIntent;
import android.content.Context;
import android.media.MediaController2;
-import android.media.MediaController2.PlaybackInfo;
import android.media.MediaItem2;
import android.media.MediaLibraryService2.LibraryRoot;
-import android.media.MediaLibraryService2.MediaLibrarySessionCallback;
import android.media.MediaSession2;
import android.media.MediaSession2.Command;
import android.media.MediaSession2.CommandButton;
@@ -31,7 +29,6 @@
import android.media.MediaSession2.PlaylistParams;
import android.media.PlaybackState2;
import android.media.VolumeProvider2;
-import android.media.update.MediaSession2Provider.CommandButtonProvider;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -42,6 +39,7 @@
import android.util.ArrayMap;
import android.util.Log;
+import com.android.media.MediaLibraryService2Impl.MediaLibrarySessionImpl;
import com.android.media.MediaSession2Impl.CommandButtonImpl;
import com.android.media.MediaSession2Impl.ControllerInfoImpl;
@@ -96,6 +94,27 @@
return session;
}
+ private MediaLibrarySessionImpl getLibrarySession() throws IllegalStateException {
+ final MediaSession2Impl session = getSession();
+ if (!(session instanceof MediaLibrarySessionImpl)) {
+ throw new RuntimeException("Session isn't a library session");
+ }
+ return (MediaLibrarySessionImpl) session;
+ }
+
+ private ControllerInfo getController(IMediaSession2Callback caller) {
+ // TODO(jaewan): Find a way to return connection-in-progress-controller
+ // to be included here, because session owner may want to send some datas
+ // while onConnected() hasn't returned.
+ synchronized (mLock) {
+ return mControllers.get(caller.asBinder());
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ // AIDL methods for session overrides
+ //////////////////////////////////////////////////////////////////////////////////////////////
+
@Override
public void connect(String callingPackage, final IMediaSession2Callback callback)
throws RuntimeException {
@@ -136,7 +155,7 @@
final PlaybackState2 state = session.getInstance().getPlaybackState();
final Bundle playbackStateBundle = (state != null) ? state.toBundle() : null;
final Bundle playbackInfoBundle =
- ((PlaybackInfoImpl) session.getPlaybackInfo().getProvider()).toBundle();
+ ((MediaController2Impl.PlaybackInfoImpl) session.getPlaybackInfo().getProvider()).toBundle();
final PlaylistParams params = session.getInstance().getPlaylistParams();
final Bundle paramsBundle = (params != null) ? params.toBundle() : null;
final int ratingType = session.getRatingType();
@@ -487,32 +506,28 @@
});
}
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ // AIDL methods for LibrarySession overrides
+ //////////////////////////////////////////////////////////////////////////////////////////////
+
@Override
public void getBrowserRoot(IMediaSession2Callback caller, Bundle rootHints)
throws RuntimeException {
- final MediaSession2Impl sessionImpl = getSession();
- if (!(sessionImpl.getCallback() instanceof MediaLibrarySessionCallback)) {
- if (DEBUG) {
- Log.d(TAG, "Session cannot hand getLibraryRoot()");
- }
- return;
- }
+ final MediaLibrarySessionImpl sessionImpl = getLibrarySession();
final ControllerInfo controller = getController(caller);
if (controller == null) {
if (DEBUG) {
- Log.d(TAG, "getBrowerRoot from a controller that hasn't connected. Ignore");
+ Log.d(TAG, "getBrowerRoot() from a controller that hasn't connected. Ignore");
}
return;
}
sessionImpl.getCallbackExecutor().execute(() -> {
- final MediaSession2Impl session = mSession.get();
+ final MediaLibrarySessionImpl session = getLibrarySession();
if (session == null) {
return;
}
- final MediaLibrarySessionCallback libraryCallback =
- (MediaLibrarySessionCallback) session.getCallback();
final ControllerInfoImpl controllerImpl = ControllerInfoImpl.from(controller);
- LibraryRoot root = libraryCallback.onGetRoot(controller, rootHints);
+ LibraryRoot root = session.getCallback().onGetRoot(controller, rootHints);
try {
controllerImpl.getControllerBinder().onGetRootResult(rootHints,
root == null ? null : root.getRootId(),
@@ -524,15 +539,9 @@
});
}
- private ControllerInfo getController(IMediaSession2Callback caller) {
- // TODO(jaewan): Device a way to return connection-in-progress-controller
- // to be included here, because session owner may want to send some datas
- // while onConnected() hasn't returned.
- synchronized (mLock) {
- return mControllers.get(caller.asBinder());
- }
- }
-
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ // APIs for MediaSession2Impl
+ //////////////////////////////////////////////////////////////////////////////////////////////
// TODO(jaewan): Need a way to get controller with permissions
public List<ControllerInfo> getControllers() {
ArrayList<ControllerInfo> controllers = new ArrayList<>();
@@ -627,7 +636,7 @@
ControllerInfoImpl.from(list.get(i)).getControllerBinder();
try {
callbackBinder.onPlaybackInfoChanged(
- ((PlaybackInfoImpl) playbackInfo.getProvider()).toBundle());
+ ((MediaController2Impl.PlaybackInfoImpl) playbackInfo.getProvider()).toBundle());
} catch (RemoteException e) {
Log.w(TAG, "Controller is gone", e);
// TODO(jaewan): What to do when the controller is gone?
diff --git a/packages/MediaComponents/src/com/android/media/PlaybackInfoImpl.java b/packages/MediaComponents/src/com/android/media/PlaybackInfoImpl.java
deleted file mode 100644
index 0782cf1..0000000
--- a/packages/MediaComponents/src/com/android/media/PlaybackInfoImpl.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * 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;
-
-import android.content.Context;
-import android.media.AudioAttributes;
-import android.media.MediaController2.PlaybackInfo;
-import android.media.update.PlaybackInfoProvider;
-import android.os.Bundle;
-
-public final class PlaybackInfoImpl implements PlaybackInfoProvider {
-
- private static final String KEY_PLAYBACK_TYPE =
- "android.media.playbackinfo_impl.playback_type";
- private static final String KEY_CONTROL_TYPE =
- "android.media.playbackinfo_impl.control_type";
- private static final String KEY_MAX_VOLUME =
- "android.media.playbackinfo_impl.max_volume";
- private static final String KEY_CURRENT_VOLUME =
- "android.media.playbackinfo_impl.current_volume";
- private static final String KEY_AUDIO_ATTRIBUTES =
- "android.media.playbackinfo_impl.audio_attrs";
-
- private final Context mContext;
- private final PlaybackInfo mInstance;
-
- private final int mPlaybackType;
- private final int mControlType;
- private final int mMaxVolume;
- private final int mCurrentVolume;
- private final AudioAttributes mAudioAttrs;
-
- private PlaybackInfoImpl(Context context, int playbackType, AudioAttributes attrs,
- int controlType, int max, int current) {
- mContext = context;
- mPlaybackType = playbackType;
- mAudioAttrs = attrs;
- mControlType = controlType;
- mMaxVolume = max;
- mCurrentVolume = current;
- mInstance = new PlaybackInfo(this);
- }
-
- @Override
- public int getPlaybackType_impl() {
- return mPlaybackType;
- }
-
- @Override
- public AudioAttributes getAudioAttributes_impl() {
- return mAudioAttrs;
- }
-
- @Override
- public int getControlType_impl() {
- return mControlType;
- }
-
- @Override
- public int getMaxVolume_impl() {
- return mMaxVolume;
- }
-
- @Override
- public int getCurrentVolume_impl() {
- return mCurrentVolume;
- }
-
- public PlaybackInfo getInstance() {
- return mInstance;
- }
-
- public Bundle toBundle() {
- Bundle bundle = new Bundle();
- bundle.putInt(KEY_PLAYBACK_TYPE, mPlaybackType);
- bundle.putInt(KEY_CONTROL_TYPE, mControlType);
- bundle.putInt(KEY_MAX_VOLUME, mMaxVolume);
- bundle.putInt(KEY_CURRENT_VOLUME, mCurrentVolume);
- bundle.putParcelable(KEY_AUDIO_ATTRIBUTES, mAudioAttrs);
- return bundle;
- }
-
- public static PlaybackInfo createPlaybackInfo(Context context, int playbackType,
- AudioAttributes attrs, int controlType, int max, int current) {
- return new PlaybackInfoImpl(context, playbackType, attrs, controlType, max, current)
- .getInstance();
- }
-
- public static PlaybackInfo fromBundle(Context context, Bundle bundle) {
- if (bundle == null) {
- return null;
- }
- final int volumeType = bundle.getInt(KEY_PLAYBACK_TYPE);
- final int volumeControl = bundle.getInt(KEY_CONTROL_TYPE);
- final int maxVolume = bundle.getInt(KEY_MAX_VOLUME);
- final int currentVolume = bundle.getInt(KEY_CURRENT_VOLUME);
- final AudioAttributes attrs = bundle.getParcelable(KEY_AUDIO_ATTRIBUTES);
-
- return createPlaybackInfo(
- context, volumeType, attrs, volumeControl, maxVolume, currentVolume);
- }
-}
diff --git a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
index dfc0792..318cbf9 100644
--- a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
@@ -54,6 +54,7 @@
static final String ARGUMENT_KEY_FULLSCREEN = "fullScreen";
+ // TODO: Move these constants to public api to support custom video view.
static final String KEY_STATE_CONTAINS_SUBTITLE = "StateContainsSubtitle";
static final String EVENT_UPDATE_SUBTITLE_STATUS = "UpdateSubtitleStatus";
@@ -72,9 +73,7 @@
private TextView mTitleView;
private int mDuration;
private int mPrevState;
- private int mCurrentVisibility;
private long mPlaybackActions;
- private boolean mShowing;
private boolean mDragging;
private boolean mIsFullScreen;
private boolean mOverflowExpanded;
@@ -233,6 +232,7 @@
public void setEnabled_impl(boolean enabled) {
super.setEnabled_impl(enabled);
+ // TODO: Merge the below code with disableUnsupportedButtons().
if (mPlayPauseButton != null) {
mPlayPauseButton.setEnabled(enabled);
}
@@ -255,24 +255,15 @@
}
@Override
- public void onVisibilityAggregated_impl(boolean invisible) {
- super.onVisibilityAggregated_impl(invisible);
+ public void onVisibilityAggregated_impl(boolean isVisible) {
+ super.onVisibilityAggregated_impl(isVisible);
- int visibility = mInstance.getVisibility();
- if (mCurrentVisibility != visibility) {
- mInstance.setVisibility(visibility);
- mCurrentVisibility = visibility;
-
- if (visibility == View.VISIBLE) {
- setProgress();
- disableUnsupportedButtons();
- // cause the progress bar to be updated even if mShowing
- // was already true. This happens, for example, if we're
- // paused with the progress bar showing the user hits play.
- mInstance.post(mShowProgress);
- } else if (visibility == View.GONE) {
- mInstance.removeCallbacks(mShowProgress);
- }
+ if (isVisible) {
+ disableUnsupportedButtons();
+ mInstance.removeCallbacks(mUpdateProgress);
+ mInstance.post(mUpdateProgress);
+ } else {
+ mInstance.removeCallbacks(mUpdateProgress);
}
}
@@ -465,12 +456,13 @@
}
}
- private final Runnable mShowProgress = new Runnable() {
+ private final Runnable mUpdateProgress = new Runnable() {
@Override
public void run() {
int pos = setProgress();
- if (!mDragging && mShowing && isPlaying()) {
- mInstance.postDelayed(mShowProgress,
+ boolean isShowing = mInstance.getVisibility() == View.VISIBLE;
+ if (!mDragging && isShowing && isPlaying()) {
+ mInstance.postDelayed(mUpdateProgress,
DEFAULT_PROGRESS_UPDATE_TIME_MS - (pos % DEFAULT_PROGRESS_UPDATE_TIME_MS));
}
}
@@ -557,7 +549,7 @@
// the seekbar and b) once the user is done dragging the thumb
// we will post one of these messages to the queue again and
// this ensures that there will be exactly one message queued up.
- mInstance.removeCallbacks(mShowProgress);
+ mInstance.removeCallbacks(mUpdateProgress);
// Check if playback is currently stopped. In this case, update the pause button to
// show the play image instead of the replay image.
@@ -602,7 +594,7 @@
// Ensure that progress is properly updated in the future,
// the call to show() does not guarantee this because it is a
// no-op if we are already showing.
- mInstance.post(mShowProgress);
+ mInstance.post(mUpdateProgress);
}
};
@@ -735,6 +727,8 @@
ApiHelper.getLibResources().getDrawable(
R.drawable.ic_pause_circle_filled, null));
mPlayPauseButton.setContentDescription(mPauseDescription);
+ mInstance.removeCallbacks(mUpdateProgress);
+ mInstance.post(mUpdateProgress);
break;
case PlaybackState.STATE_PAUSED:
mPlayPauseButton.setImageDrawable(
diff --git a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
index 256003f..ea7e714 100644
--- a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
@@ -31,7 +31,9 @@
import android.media.ClosedCaptionRenderer;
import android.media.Metadata;
import android.media.PlaybackParams;
+import android.media.SRTRenderer;
import android.media.SubtitleController;
+import android.media.TimedText;
import android.media.TtmlRenderer;
import android.media.WebVttRenderer;
import android.media.session.MediaController;
@@ -122,6 +124,7 @@
private int mVideoWidth;
private int mVideoHeight;
+ private ArrayList<Integer> mSubtitleTrackIndices;
private SubtitleView mSubtitleView;
private boolean mSubtitleEnabled;
private int mSelectedTrackIndex; // selected subtitle track index as MediaPlayer2 returns
@@ -191,13 +194,11 @@
if (enableControlView) {
mMediaControlView = new MediaControlView2(mInstance.getContext());
}
- boolean enableSubtitle = (attrs == null) || attrs.getAttributeBooleanValue(
+
+ mSubtitleEnabled = (attrs == null) || attrs.getAttributeBooleanValue(
"http://schemas.android.com/apk/res/android",
- "enableSubtitle", true);
- if (enableSubtitle) {
- Log.d(TAG, "enableSubtitle attribute is true.");
- // TODO: implement
- }
+ "enableSubtitle", false);
+
int viewType = (attrs == null) ? VideoView2.VIEW_TYPE_SURFACEVIEW
: attrs.getAttributeIntValue(
"http://schemas.android.com/apk/res/android",
@@ -240,27 +241,8 @@
@Override
public void setSubtitleEnabled_impl(boolean enable) {
- if (enable) {
- // Retrieve all tracks that belong to the current video.
- MediaPlayer.TrackInfo[] trackInfos = mMediaPlayer.getTrackInfo();
-
- List<Integer> subtitleTrackIndices = new ArrayList<>();
- for (int i = 0; i < trackInfos.length; ++i) {
- int trackType = trackInfos[i].getTrackType();
- if (trackType == MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
- subtitleTrackIndices.add(i);
- }
- }
- if (subtitleTrackIndices.size() > 0) {
- // Select first subtitle track
- mSelectedTrackIndex = subtitleTrackIndices.get(0);
- mMediaPlayer.selectTrack(mSelectedTrackIndex);
- }
- } else {
- if (mSelectedTrackIndex != INVALID_TRACK_INDEX) {
- mMediaPlayer.deselectTrack(mSelectedTrackIndex);
- mSelectedTrackIndex = INVALID_TRACK_INDEX;
- }
+ if (enable != mSubtitleEnabled) {
+ selectOrDeselectSubtitle(enable);
}
mSubtitleEnabled = enable;
}
@@ -572,7 +554,13 @@
controller.registerRenderer(new TtmlRenderer(context));
controller.registerRenderer(new Cea708CaptionRenderer(context));
controller.registerRenderer(new ClosedCaptionRenderer(context));
- mMediaPlayer.setSubtitleAnchor(controller, (SubtitleController.Anchor) mSubtitleView);
+ controller.registerRenderer(new SRTRenderer(context));
+ mMediaPlayer.setSubtitleAnchor(
+ controller, (SubtitleController.Anchor) mSubtitleView);
+ // TODO: Remove timed text related code later once relevant Renderer is defined.
+ // This is just for debugging purpose.
+ mMediaPlayer.setOnTimedTextListener(mTimedTextListener);
+
mMediaPlayer.setOnPreparedListener(mPreparedListener);
mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
mMediaPlayer.setOnCompletionListener(mCompletionListener);
@@ -622,7 +610,6 @@
/*
* Reset the media player in any state
*/
- // TODO: Figure out if the legacy code's boolean parameter: cleartargetstate is necessary.
private void resetPlayer() {
if (mMediaPlayer != null) {
mMediaPlayer.reset();
@@ -774,7 +761,58 @@
return false;
}
PlaybackInfo playbackInfo = mMediaController.getPlaybackInfo();
- return (playbackInfo != null) && (playbackInfo.getPlaybackType() == PlaybackInfo.PLAYBACK_TYPE_REMOTE);
+ return (playbackInfo != null)
+ && (playbackInfo.getPlaybackType() == PlaybackInfo.PLAYBACK_TYPE_REMOTE);
+ }
+
+ private void selectOrDeselectSubtitle(boolean select) {
+ if (!isInPlaybackState()) {
+ return;
+ }
+ if (select) {
+ if (mSubtitleTrackIndices.size() > 0) {
+ // Select first subtitle track
+ mSelectedTrackIndex = mSubtitleTrackIndices.get(0);
+ mMediaPlayer.selectTrack(mSelectedTrackIndex);
+ mSubtitleView.setVisibility(View.VISIBLE);
+ }
+ } else {
+ if (mSelectedTrackIndex != INVALID_TRACK_INDEX) {
+ mMediaPlayer.deselectTrack(mSelectedTrackIndex);
+ mSelectedTrackIndex = INVALID_TRACK_INDEX;
+ mSubtitleView.setVisibility(View.GONE);
+ }
+ }
+ }
+
+ private void extractSubtitleTracks() {
+ MediaPlayer.TrackInfo[] trackInfos = mMediaPlayer.getTrackInfo();
+ boolean previouslyNoTracks = mSubtitleTrackIndices == null
+ || mSubtitleTrackIndices.size() == 0;
+ mSubtitleTrackIndices = new ArrayList<>();
+ for (int i = 0; i < trackInfos.length; ++i) {
+ int trackType = trackInfos[i].getTrackType();
+ if (trackType == MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE
+ || trackType == MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT) {
+ mSubtitleTrackIndices.add(i);
+ }
+ }
+ if (mSubtitleTrackIndices.size() > 0) {
+ if (previouslyNoTracks) {
+ selectOrDeselectSubtitle(mSubtitleEnabled);
+ // Notify MediaControlView that subtitle track exists
+ // TODO: Send the subtitle track list to MediaSession for MCV2.
+ Bundle data = new Bundle();
+ data.putBoolean(MediaControlView2Impl.KEY_STATE_CONTAINS_SUBTITLE, true);
+ mMediaSession.sendSessionEvent(
+ MediaControlView2Impl.EVENT_UPDATE_SUBTITLE_STATUS, data);
+ }
+ } else {
+ Bundle data = new Bundle();
+ data.putBoolean(MediaControlView2Impl.KEY_STATE_CONTAINS_SUBTITLE, false);
+ mMediaSession.sendSessionEvent(
+ MediaControlView2Impl.EVENT_UPDATE_SUBTITLE_STATUS, data);
+ }
}
MediaPlayer.OnVideoSizeChangedListener mSizeChangedListener =
@@ -805,6 +843,7 @@
mCurrentState = STATE_PREPARED;
// Create and set playback state for MediaControlView2
updatePlaybackState();
+ extractSubtitleTracks();
if (mOnPreparedListener != null) {
mOnPreparedListener.onPrepared(mInstance);
@@ -884,6 +923,10 @@
if (mOnInfoListener != null) {
mOnInfoListener.onInfo(mInstance, what, extra);
}
+
+ if (what == MediaPlayer.MEDIA_INFO_METADATA_UPDATE) {
+ extractSubtitleTracks();
+ }
return true;
}
};
@@ -954,6 +997,15 @@
}
};
+ // TODO: Remove timed text related code later once relevant Renderer is defined.
+ // This is just for debugging purpose.
+ private MediaPlayer.OnTimedTextListener mTimedTextListener =
+ new MediaPlayer.OnTimedTextListener() {
+ public void onTimedText(MediaPlayer mp, TimedText text) {
+ Log.d(TAG, "TimedText: " + text.getText());
+ }
+ };
+
private class MediaSessionCallback extends MediaSession.Callback {
@Override
public void onCommand(String command, Bundle args, ResultReceiver receiver) {
diff --git a/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java b/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java
index 4cd8177..eff4c3b 100644
--- a/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java
+++ b/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java
@@ -24,6 +24,7 @@
import android.content.Context;
import android.media.MediaBrowser2.BrowserCallback;
import android.media.MediaSession2.Command;
+import android.media.MediaSession2.CommandButton;
import android.media.MediaSession2.CommandGroup;
import android.media.MediaSession2.PlaylistParams;
import android.os.Bundle;
@@ -36,6 +37,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -104,42 +106,41 @@
@CallSuper
@Override
public void onConnected(CommandGroup commands) {
- super.onConnected(commands);
connectLatch.countDown();
}
@CallSuper
@Override
public void onDisconnected() {
- super.onDisconnected();
disconnectLatch.countDown();
}
@Override
public void onPlaybackStateChanged(PlaybackState2 state) {
- super.onPlaybackStateChanged(state);
mCallbackProxy.onPlaybackStateChanged(state);
}
@Override
public void onPlaylistParamsChanged(PlaylistParams params) {
- super.onPlaylistParamsChanged(params);
mCallbackProxy.onPlaylistParamsChanged(params);
}
@Override
public void onPlaybackInfoChanged(MediaController2.PlaybackInfo info) {
- if (mCallbackProxy != null) {
- mCallbackProxy.onPlaybackInfoChanged(info);
- }
+ mCallbackProxy.onPlaybackInfoChanged(info);
}
@Override
public void onCustomCommand(Command command, Bundle args, ResultReceiver receiver) {
- super.onCustomCommand(command, args, receiver);
mCallbackProxy.onCustomCommand(command, args, receiver);
}
+
+ @Override
+ public void onCustomLayoutChanged(List<CommandButton> layout) {
+ mCallbackProxy.onCustomLayoutChanged(layout);
+ }
+
@Override
public void onGetRootResult(Bundle rootHints, String rootMediaId, Bundle rootExtra) {
super.onGetRootResult(rootHints, rootMediaId, rootExtra);
diff --git a/packages/MediaComponents/test/src/android/media/MediaSession2Test.java b/packages/MediaComponents/test/src/android/media/MediaSession2Test.java
index b00633b..f5ac6aa 100644
--- a/packages/MediaComponents/test/src/android/media/MediaSession2Test.java
+++ b/packages/MediaComponents/test/src/android/media/MediaSession2Test.java
@@ -33,6 +33,8 @@
import android.media.MediaPlayerInterface.PlaybackListener;
import android.media.MediaSession2.Builder;
import android.media.MediaSession2.Command;
+import android.media.MediaSession2.CommandButton;
+import android.media.MediaSession2.CommandGroup;
import android.media.MediaSession2.ControllerInfo;
import android.media.MediaSession2.PlaylistParams;
import android.media.MediaSession2.SessionCallback;
@@ -353,6 +355,45 @@
}
@Test
+ public void testSetCustomLayout() throws InterruptedException {
+ final List<CommandButton> buttons = new ArrayList<>();
+ buttons.add(new CommandButton.Builder(mContext)
+ .setCommand(new Command(mContext, MediaSession2.COMMAND_CODE_PLAYBACK_PLAY))
+ .setDisplayName("button").build());
+ final CountDownLatch latch = new CountDownLatch(1);
+ final SessionCallback sessionCallback = new SessionCallback(mContext) {
+ @Override
+ public CommandGroup onConnect(ControllerInfo controller) {
+ if (mContext.getPackageName().equals(controller.getPackageName())) {
+ mSession.setCustomLayout(controller, buttons);
+ }
+ return super.onConnect(controller);
+ }
+ };
+
+ try (final MediaSession2 session = new MediaSession2.Builder(mContext, mPlayer)
+ .setId("testSetCustomLayout")
+ .setSessionCallback(sHandlerExecutor, sessionCallback)
+ .build()) {
+ final TestControllerCallbackInterface callback = new TestControllerCallbackInterface() {
+ @Override
+ public void onCustomLayoutChanged(List<CommandButton> layout) {
+ assertEquals(layout.size(), buttons.size());
+ for (int i = 0; i < layout.size(); i++) {
+ assertEquals(layout.get(i).getCommand(), buttons.get(i).getCommand());
+ assertEquals(layout.get(i).getDisplayName(),
+ buttons.get(i).getDisplayName());
+ }
+ latch.countDown();
+ }
+ };
+ final MediaController2 controller =
+ createController(session.getToken(), true, callback);
+ assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+ }
+ }
+
+ @Test
public void testSendCustomAction() throws InterruptedException {
final Command testCommand =
new Command(mContext, MediaSession2.COMMAND_CODE_PLAYBACK_PREPARE);
diff --git a/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java b/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java
index 513fa29..f5abfff 100644
--- a/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java
+++ b/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java
@@ -22,6 +22,7 @@
import android.content.Context;
import android.media.MediaController2.ControllerCallback;
import android.media.MediaSession2.Command;
+import android.media.MediaSession2.CommandButton;
import android.media.MediaSession2.CommandGroup;
import android.os.Bundle;
import android.os.HandlerThread;
@@ -59,15 +60,15 @@
ControllerCallback getCallback();
}
+ // Any change here should be also reflected to the TestControllerCallback and
+ // TestBrowserCallback
interface TestControllerCallbackInterface {
- // Add methods in ControllerCallback/BrowserCallback that you want to test.
+ // Add methods in ControllerCallback that you want to test.
default void onPlaylistChanged(List<MediaItem2> playlist) {}
default void onPlaylistParamsChanged(MediaSession2.PlaylistParams params) {}
default void onPlaybackInfoChanged(MediaController2.PlaybackInfo info) {}
-
- // Currently empty. Add methods in ControllerCallback/BrowserCallback that you want to test.
- default void onPlaybackStateChanged(PlaybackState2 state) { }
-
+ default void onPlaybackStateChanged(PlaybackState2 state) {}
+ default void onCustomLayoutChanged(List<CommandButton> layout) {}
default void onCustomCommand(Command command, Bundle args, ResultReceiver receiver) {}
}
@@ -188,26 +189,22 @@
@CallSuper
@Override
public void onConnected(CommandGroup commands) {
- super.onConnected(commands);
connectLatch.countDown();
}
@CallSuper
@Override
public void onDisconnected() {
- super.onDisconnected();
disconnectLatch.countDown();
}
@Override
public void onPlaybackStateChanged(PlaybackState2 state) {
- super.onPlaybackStateChanged(state);
mCallbackProxy.onPlaybackStateChanged(state);
}
@Override
public void onCustomCommand(Command command, Bundle args, ResultReceiver receiver) {
- super.onCustomCommand(command, args, receiver);
mCallbackProxy.onCustomCommand(command, args, receiver);
}
@@ -231,23 +228,22 @@
@Override
public void onPlaylistChanged(List<MediaItem2> params) {
- if (mCallbackProxy != null) {
- mCallbackProxy.onPlaylistChanged(params);
- }
+ mCallbackProxy.onPlaylistChanged(params);
}
@Override
public void onPlaylistParamsChanged(MediaSession2.PlaylistParams params) {
- if (mCallbackProxy != null) {
- mCallbackProxy.onPlaylistParamsChanged(params);
- }
+ mCallbackProxy.onPlaylistParamsChanged(params);
}
@Override
public void onPlaybackInfoChanged(MediaController2.PlaybackInfo info) {
- if (mCallbackProxy != null) {
- mCallbackProxy.onPlaybackInfoChanged(info);
- }
+ mCallbackProxy.onPlaybackInfoChanged(info);
+ }
+
+ @Override
+ public void onCustomLayoutChanged(List<CommandButton> layout) {
+ mCallbackProxy.onCustomLayoutChanged(layout);
}
}
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index e7140c2..a3ce1f6 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -321,6 +321,7 @@
actualSessionId,
client.clientPid,
client.clientUid,
+ client.packageName,
config,
AUDIO_INPUT_FLAG_MMAP_NOIRQ, deviceId, &portId);
}
@@ -340,7 +341,7 @@
if (direction == MmapStreamInterface::DIRECTION_OUTPUT) {
AudioSystem::releaseOutput(io, streamType, actualSessionId);
} else {
- AudioSystem::releaseInput(io, actualSessionId);
+ AudioSystem::releaseInput(portId);
}
ret = NO_INIT;
}
@@ -658,7 +659,7 @@
sp<Client> client;
status_t lStatus;
audio_stream_type_t streamType;
- audio_port_handle_t portId;
+ audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
bool updatePid = (input.clientInfo.clientPid == -1);
const uid_t callingUid = IPCThreadState::self()->getCallingUid();
@@ -1596,7 +1597,7 @@
sp<Client> client;
status_t lStatus;
audio_session_t sessionId = input.sessionId;
- audio_port_handle_t portId;
+ audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
output.cblk.clear();
output.buffers.clear();
@@ -1621,12 +1622,6 @@
clientPid = callingPid;
}
- // check calling permissions
- if (!recordingAllowed(input.opPackageName, input.clientInfo.clientTid, clientUid)) {
- ALOGE("createRecord() permission denied: recording not allowed");
- lStatus = PERMISSION_DENIED;
- goto Exit;
- }
// we don't yet support anything other than linear PCM
if (!audio_is_valid_format(input.config.format) || !audio_is_linear_pcm(input.config.format)) {
ALOGE("createRecord() invalid format %#x", input.config.format);
@@ -1663,14 +1658,16 @@
// release previously opened input if retrying.
if (output.inputId != AUDIO_IO_HANDLE_NONE) {
recordTrack.clear();
- AudioSystem::releaseInput(output.inputId, sessionId);
+ AudioSystem::releaseInput(portId);
output.inputId = AUDIO_IO_HANDLE_NONE;
+ portId = AUDIO_PORT_HANDLE_NONE;
}
lStatus = AudioSystem::getInputForAttr(&input.attr, &output.inputId,
sessionId,
// FIXME compare to AudioTrack
clientPid,
clientUid,
+ input.opPackageName,
&input.config,
output.flags, &output.selectedDeviceId, &portId);
@@ -1739,7 +1736,7 @@
}
recordTrack.clear();
if (output.inputId != AUDIO_IO_HANDLE_NONE) {
- AudioSystem::releaseInput(output.inputId, sessionId);
+ AudioSystem::releaseInput(portId);
}
}
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 24d862f..d6021b3 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -6936,8 +6936,7 @@
if (recordTrack->isExternalTrack()) {
mLock.unlock();
bool silenced;
- status = AudioSystem::startInput(mId, recordTrack->sessionId(),
- mInDevice, recordTrack->uid(), &silenced);
+ status = AudioSystem::startInput(recordTrack->portId(), &silenced);
mLock.lock();
// FIXME should verify that recordTrack is still in mActiveTracks
if (status != NO_ERROR) {
@@ -6969,7 +6968,7 @@
startError:
if (recordTrack->isExternalTrack()) {
- AudioSystem::stopInput(mId, recordTrack->sessionId());
+ AudioSystem::stopInput(recordTrack->portId());
}
recordTrack->clearSyncStartEvent();
// FIXME I wonder why we do not reset the state here?
@@ -7785,7 +7784,7 @@
if (isOutput()) {
AudioSystem::releaseOutput(mId, streamType(), mSessionId);
} else {
- AudioSystem::releaseInput(mId, mSessionId);
+ AudioSystem::releaseInput(mPortId);
}
}
@@ -7845,10 +7844,6 @@
return NO_ERROR;
}
- if (!isOutput() && !recordingAllowed(client.packageName, client.clientPid, client.clientUid)) {
- return PERMISSION_DENIED;
- }
-
audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
audio_io_handle_t io = mId;
@@ -7880,6 +7875,7 @@
mSessionId,
client.clientPid,
client.clientUid,
+ client.packageName,
&config,
AUDIO_INPUT_FLAG_MMAP_NOIRQ,
&deviceId,
@@ -7898,7 +7894,7 @@
} else {
// TODO: Block recording for idle UIDs (b/72134552)
bool silenced;
- ret = AudioSystem::startInput(mId, mSessionId, mInDevice, client.clientUid, &silenced);
+ ret = AudioSystem::startInput(portId, &silenced);
}
// abort if start is rejected by audio policy manager
@@ -7908,7 +7904,7 @@
if (isOutput()) {
AudioSystem::releaseOutput(mId, streamType(), mSessionId);
} else {
- AudioSystem::releaseInput(mId, mSessionId);
+ AudioSystem::releaseInput(portId);
}
} else {
mHalStream->stop();
@@ -7965,8 +7961,8 @@
AudioSystem::stopOutput(mId, streamType(), track->sessionId());
AudioSystem::releaseOutput(mId, streamType(), track->sessionId());
} else {
- AudioSystem::stopInput(mId, track->sessionId());
- AudioSystem::releaseInput(mId, track->sessionId());
+ AudioSystem::stopInput(track->portId());
+ AudioSystem::releaseInput(track->portId());
}
sp<EffectChain> chain = getEffectChain_l(track->sessionId());
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index ce5c53b..67f27d0 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1694,7 +1694,7 @@
if (thread != 0) {
RecordThread *recordThread = (RecordThread *)thread.get();
if (recordThread->stop(this) && isExternalTrack()) {
- AudioSystem::stopInput(mThreadIoHandle, mSessionId);
+ AudioSystem::stopInput(mPortId);
}
}
}
@@ -1706,9 +1706,9 @@
{
if (isExternalTrack()) {
if (mState == ACTIVE || mState == RESUMING) {
- AudioSystem::stopInput(mThreadIoHandle, mSessionId);
+ AudioSystem::stopInput(mPortId);
}
- AudioSystem::releaseInput(mThreadIoHandle, mSessionId);
+ AudioSystem::releaseInput(mPortId);
}
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 40e0199..54bfcbc 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1158,12 +1158,6 @@
bool force = !outputDesc->isActive() &&
(outputDesc->getPatchHandle() == AUDIO_PATCH_HANDLE_NONE);
- // requiresMuteCheck is false when we can bypass mute strategy.
- // It covers a common case when there is no materially active audio
- // and muting would result in unnecessary delay and dropped audio.
- const uint32_t outputLatencyMs = outputDesc->latency();
- bool requiresMuteCheck = outputDesc->isActive(outputLatencyMs * 2); // account for drain
-
// increment usage count for this stream on the requested output:
// NOTE that the usage count is the same for duplicated output and hardware output which is
// necessary for a correct control of hardware output routing by startOutput() and stopOutput()
@@ -1187,44 +1181,29 @@
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i);
if (desc != outputDesc) {
- // An output has a shared device if
- // - managed by the same hw module
- // - supports the currently selected device
- const bool sharedDevice = outputDesc->sharesHwModuleWith(desc)
- && (desc->supportedDevices() & device) != AUDIO_DEVICE_NONE;
-
// force a device change if any other output is:
// - managed by the same hw module
- // - supports currently selected device
// - has a current device selection that differs from selected device.
+ // - supports currently selected device
// - has an active audio patch
// In this case, the audio HAL must receive the new device selection so that it can
- // change the device currently selected by the other output.
- if (sharedDevice &&
+ // change the device currently selected by the other active output.
+ if (outputDesc->sharesHwModuleWith(desc) &&
desc->device() != device &&
+ desc->supportedDevices() & device &&
desc->getPatchHandle() != AUDIO_PATCH_HANDLE_NONE) {
force = true;
}
// wait for audio on other active outputs to be presented when starting
// a notification so that audio focus effect can propagate, or that a mute/unmute
// event occurred for beacon
- const uint32_t latencyMs = desc->latency();
- const bool isActive = desc->isActive(latencyMs * 2); // account for drain
-
- if (shouldWait && isActive && (waitMs < latencyMs)) {
- waitMs = latencyMs;
+ uint32_t latency = desc->latency();
+ if (shouldWait && desc->isActive(latency * 2) && (waitMs < latency)) {
+ waitMs = latency;
}
-
- // Require mute check if another output is on a shared device
- // and currently active to have proper drain and avoid pops.
- // Note restoring AudioTracks onto this output needs to invoke
- // a volume ramp if there is no mute.
- requiresMuteCheck |= sharedDevice && isActive;
}
}
-
- const uint32_t muteWaitMs =
- setOutputDevice(outputDesc, device, force, 0, NULL, address, requiresMuteCheck);
+ uint32_t muteWaitMs = setOutputDevice(outputDesc, device, force, 0, NULL, address);
// handle special case for sonification while in call
if (isInCall()) {
@@ -1249,14 +1228,6 @@
if (waitMs > muteWaitMs) {
*delayMs = waitMs - muteWaitMs;
}
-
- // FIXME: A device change (muteWaitMs > 0) likely introduces a volume change.
- // A volume change enacted by APM with 0 delay is not synchronous, as it goes
- // via AudioCommandThread to AudioFlinger. Hence it is possible that the volume
- // change occurs after the MixerThread starts and causes a stream volume
- // glitch.
- //
- // We do not introduce additional delay here.
}
return NO_ERROR;
@@ -4771,24 +4742,21 @@
bool force,
int delayMs,
audio_patch_handle_t *patchHandle,
- const char *address,
- bool requiresMuteCheck)
+ const char* address)
{
ALOGV("setOutputDevice() device %04x delayMs %d", device, delayMs);
AudioParameter param;
uint32_t muteWaitMs;
if (outputDesc->isDuplicated()) {
- muteWaitMs = setOutputDevice(outputDesc->subOutput1(), device, force, delayMs,
- nullptr /* patchHandle */, nullptr /* address */, requiresMuteCheck);
- muteWaitMs += setOutputDevice(outputDesc->subOutput2(), device, force, delayMs,
- nullptr /* patchHandle */, nullptr /* address */, requiresMuteCheck);
+ muteWaitMs = setOutputDevice(outputDesc->subOutput1(), device, force, delayMs);
+ muteWaitMs += setOutputDevice(outputDesc->subOutput2(), device, force, delayMs);
return muteWaitMs;
}
// no need to proceed if new device is not AUDIO_DEVICE_NONE and not supported by current
// output profile
if ((device != AUDIO_DEVICE_NONE) &&
- ((device & outputDesc->supportedDevices()) == AUDIO_DEVICE_NONE)) {
+ ((device & outputDesc->supportedDevices()) == 0)) {
return 0;
}
@@ -4802,14 +4770,7 @@
if (device != AUDIO_DEVICE_NONE) {
outputDesc->mDevice = device;
}
-
- // if the outputs are not materially active, there is no need to mute.
- if (requiresMuteCheck) {
- muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
- } else {
- ALOGV("%s: suppressing checkDeviceMuteStrategies", __func__);
- muteWaitMs = 0;
- }
+ muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
// Do not change the routing if:
// the requested device is AUDIO_DEVICE_NONE
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 2b68882..ee339e7 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -317,8 +317,7 @@
bool force = false,
int delayMs = 0,
audio_patch_handle_t *patchHandle = NULL,
- const char *address = nullptr,
- bool requiresMuteCheck = true);
+ const char* address = NULL);
status_t resetOutputDevice(const sp<AudioOutputDescriptor>& outputDesc,
int delayMs = 0,
audio_patch_handle_t *patchHandle = NULL);
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index f1d7d86..306de3f 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -287,6 +287,7 @@
audio_session_t session,
pid_t pid,
uid_t uid,
+ const String16& opPackageName,
const audio_config_base_t *config,
audio_input_flags_t flags,
audio_port_handle_t *selectedDeviceId,
@@ -295,6 +296,7 @@
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
+
// already checked by client, but double-check in case the client wrapper is bypassed
if (attr->source < AUDIO_SOURCE_DEFAULT && attr->source >= AUDIO_SOURCE_CNT &&
attr->source != AUDIO_SOURCE_HOTWORD && attr->source != AUDIO_SOURCE_FM_TUNER) {
@@ -318,6 +320,13 @@
pid = callingPid;
}
+ // check calling permissions
+ if (!recordingAllowed(opPackageName, pid, uid)) {
+ ALOGE("%s permission denied: recording not allowed for uid %d pid %d",
+ __func__, uid, pid);
+ return PERMISSION_DENIED;
+ }
+
if ((attr->source == AUDIO_SOURCE_HOTWORD) && !captureHotwordAllowed(pid, uid)) {
return BAD_VALUE;
}
@@ -367,6 +376,13 @@
}
return status;
}
+
+ sp<AudioRecordClient> client =
+ new AudioRecordClient(*attr, *input, uid, pid, opPackageName, session);
+ client->active = false;
+ client->isConcurrent = false;
+ client->isVirtualDevice = false; //TODO : update from APM->getInputForAttr()
+ mAudioRecordClients.add(*portId, client);
}
if (audioPolicyEffects != 0) {
@@ -379,23 +395,38 @@
return NO_ERROR;
}
-status_t AudioPolicyService::startInput(audio_io_handle_t input,
- audio_session_t session,
- audio_devices_t device,
- uid_t uid,
- bool *silenced)
+status_t AudioPolicyService::startInput(audio_port_handle_t portId, bool *silenced)
{
- // If UID inactive it records silence until becoming active
- *silenced = !mUidPolicy->isUidActive(uid) && !is_virtual_input_device(device);
-
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
+ sp<AudioRecordClient> client;
+ {
+ Mutex::Autolock _l(mLock);
+
+ ssize_t index = mAudioRecordClients.indexOfKey(portId);
+ if (index < 0) {
+ return INVALID_OPERATION;
+ }
+ client = mAudioRecordClients.valueAt(index);
+ }
+
+ // check calling permissions
+ if (!recordingAllowed(client->opPackageName, client->pid, client->uid)) {
+ ALOGE("%s permission denied: recording not allowed for uid %d pid %d",
+ __func__, client->uid, client->pid);
+ return PERMISSION_DENIED;
+ }
+
+ // If UID inactive it records silence until becoming active
+ *silenced = !mUidPolicy->isUidActive(client->uid) && !client->isVirtualDevice;
Mutex::Autolock _l(mLock);
AudioPolicyInterface::concurrency_type__mask_t concurrency =
AudioPolicyInterface::API_INPUT_CONCURRENCY_NONE;
- status_t status = mAudioPolicyManager->startInput(input, session, *silenced, &concurrency);
+
+ status_t status = mAudioPolicyManager->startInput(
+ client->input, client->session, *silenced, &concurrency);
if (status == NO_ERROR) {
LOG_ALWAYS_FATAL_IF(concurrency & ~AudioPolicyInterface::API_INPUT_CONCURRENCY_ALL,
@@ -413,38 +444,52 @@
return status;
}
-status_t AudioPolicyService::stopInput(audio_io_handle_t input,
- audio_session_t session)
+status_t AudioPolicyService::stopInput(audio_port_handle_t portId)
{
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
Mutex::Autolock _l(mLock);
- return mAudioPolicyManager->stopInput(input, session);
+ ssize_t index = mAudioRecordClients.indexOfKey(portId);
+ if (index < 0) {
+ return INVALID_OPERATION;
+ }
+ sp<AudioRecordClient> client = mAudioRecordClients.valueAt(index);
+
+ return mAudioPolicyManager->stopInput(client->input, client->session);
}
-void AudioPolicyService::releaseInput(audio_io_handle_t input,
- audio_session_t session)
+void AudioPolicyService::releaseInput(audio_port_handle_t portId)
{
if (mAudioPolicyManager == NULL) {
return;
}
sp<AudioPolicyEffects>audioPolicyEffects;
+ sp<AudioRecordClient> client;
{
Mutex::Autolock _l(mLock);
audioPolicyEffects = mAudioPolicyEffects;
+ ssize_t index = mAudioRecordClients.indexOfKey(portId);
+ if (index < 0) {
+ return;
+ }
+ client = mAudioRecordClients.valueAt(index);
+ mAudioRecordClients.removeItem(portId);
+ }
+ if (client == 0) {
+ return;
}
if (audioPolicyEffects != 0) {
// release audio processors from the input
- status_t status = audioPolicyEffects->releaseInputEffects(input, session);
+ status_t status = audioPolicyEffects->releaseInputEffects(client->input, client->session);
if(status != NO_ERROR) {
- ALOGW("Failed to release effects on input %d", input);
+ ALOGW("Failed to release effects on input %d", client->input);
}
}
{
Mutex::Autolock _l(mLock);
- mAudioPolicyManager->releaseInput(input, session);
+ mAudioPolicyManager->releaseInput(client->input, client->session);
}
}
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index c21aa58..bfa3ef4 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -98,19 +98,15 @@
audio_session_t session,
pid_t pid,
uid_t uid,
+ const String16& opPackageName,
const audio_config_base_t *config,
audio_input_flags_t flags,
audio_port_handle_t *selectedDeviceId = NULL,
audio_port_handle_t *portId = NULL);
- virtual status_t startInput(audio_io_handle_t input,
- audio_session_t session,
- audio_devices_t device,
- uid_t uid,
+ virtual status_t startInput(audio_port_handle_t portId,
bool *silenced);
- virtual status_t stopInput(audio_io_handle_t input,
- audio_session_t session);
- virtual void releaseInput(audio_io_handle_t input,
- audio_session_t session);
+ virtual status_t stopInput(audio_port_handle_t portId);
+ virtual void releaseInput(audio_port_handle_t portId);
virtual status_t initStreamVolume(audio_stream_type_t stream,
int indexMin,
int indexMax);
@@ -611,6 +607,31 @@
bool mAudioPortCallbacksEnabled;
};
+ // --- AudioRecordClient ---
+ // Information about each registered AudioRecord client
+ // (between calls to getInputForAttr() and releaseInput())
+ class AudioRecordClient : public RefBase {
+ public:
+ AudioRecordClient(const audio_attributes_t attributes,
+ const audio_io_handle_t input, uid_t uid, pid_t pid,
+ const String16& opPackageName, const audio_session_t session) :
+ attributes(attributes),
+ input(input), uid(uid), pid(pid),
+ opPackageName(opPackageName), session(session),
+ active(false), isConcurrent(false), isVirtualDevice(false) {}
+ virtual ~AudioRecordClient() {}
+
+ const audio_attributes_t attributes; // source, flags ...
+ const audio_io_handle_t input; // audio HAL input IO handle
+ const uid_t uid; // client UID
+ const pid_t pid; // client PID
+ const String16 opPackageName; // client package name
+ const audio_session_t session; // audio session ID
+ bool active; // Capture is active or inactive
+ bool isConcurrent; // is allowed to concurrent capture
+ bool isVirtualDevice; // uses vitual device: updated by APM::getInputForAttr()
+ };
+
// Internal dump utilities.
status_t dumpPermissionDenial(int fd);
@@ -636,6 +657,7 @@
audio_mode_t mPhoneState;
sp<UidPolicy> mUidPolicy;
+ DefaultKeyedVector< audio_port_handle_t, sp<AudioRecordClient> > mAudioRecordClients;
};
} // namespace android
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 02a7616..050c3f7 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -1324,8 +1324,8 @@
{
const char *fpsRange, *fpsSingle;
- fpsRange = newParams.get(CameraParameters::KEY_PREVIEW_FRAME_RATE);
- fpsSingle = newParams.get(CameraParameters::KEY_PREVIEW_FPS_RANGE);
+ fpsSingle = newParams.get(CameraParameters::KEY_PREVIEW_FRAME_RATE);
+ fpsRange = newParams.get(CameraParameters::KEY_PREVIEW_FPS_RANGE);
/**
* Pick either the range or the single key if only one was set.
diff --git a/services/mediacodec/Android.mk b/services/mediacodec/Android.mk
index 97eaf77..8631c39 100644
--- a/services/mediacodec/Android.mk
+++ b/services/mediacodec/Android.mk
@@ -27,6 +27,7 @@
include $(CLEAR_VARS)
# seccomp is not required for coverage build.
ifneq ($(NATIVE_COVERAGE),true)
+LOCAL_REQUIRED_MODULES := crash_dump.policy
LOCAL_REQUIRED_MODULES_arm := mediacodec.policy
LOCAL_REQUIRED_MODULES_x86 := mediacodec.policy
endif
@@ -53,7 +54,7 @@
# Since this is 32-bit-only module, only 32-bit version of the codecs are installed.
# TODO(b/72343507): eliminate the need for manually adding .vendor suffix. This should be done
# by the build system.
-LOCAL_REQUIRED_MODULES := \
+LOCAL_REQUIRED_MODULES += \
$(foreach codec,$(_software_codecs),\
$(eval _vendor_suffix := $(if $(BOARD_VNDK_VERSION),.vendor))\
$(codec)$(_vendor_suffix)\
@@ -72,7 +73,11 @@
# mediacodec runs in 32-bit combatibility mode. For 64 bit architectures,
# use the 32 bit policy
ifdef TARGET_2ND_ARCH
+ ifneq ($(TARGET_TRANSLATE_2ND_ARCH),true)
LOCAL_SRC_FILES := seccomp_policy/mediacodec-$(TARGET_2ND_ARCH).policy
+ else
+ LOCAL_SRC_FILES := seccomp_policy/mediacodec-$(TARGET_ARCH).policy
+ endif
else
LOCAL_SRC_FILES := seccomp_policy/mediacodec-$(TARGET_ARCH).policy
endif
diff --git a/services/mediacodec/seccomp_policy/mediacodec-arm.policy b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
index a751b4c..6ec8895 100644
--- a/services/mediacodec/seccomp_policy/mediacodec-arm.policy
+++ b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
@@ -55,18 +55,4 @@
getdents64: 1
getrandom: 1
-# for attaching to debuggerd on process crash
-sigaction: 1
-tgkill: 1
-socket: 1
-connect: 1
-fcntl64: 1
-rt_tgsigqueueinfo: 1
-geteuid32: 1
-getgid32: 1
-getegid32: 1
-getgroups32: 1
-recvmsg: 1
-getpid: 1
-gettid: 1
-process_vm_readv: 1
+@include /system/etc/seccomp_policy/crash_dump.arm.policy
diff --git a/services/mediacodec/seccomp_policy/mediacodec-x86.policy b/services/mediacodec/seccomp_policy/mediacodec-x86.policy
index dc2c04f..1553ec7 100644
--- a/services/mediacodec/seccomp_policy/mediacodec-x86.policy
+++ b/services/mediacodec/seccomp_policy/mediacodec-x86.policy
@@ -47,23 +47,10 @@
write: 1
nanosleep: 1
-# for attaching to debuggerd on process crash
-socketcall: 1
-sigaction: 1
-tgkill: 1
-rt_sigprocmask: 1
-fcntl64: 1
-rt_tgsigqueueinfo: 1
-geteuid32: 1
-getgid32: 1
-getegid32: 1
-getgroups32: 1
-getdents64: 1
-pipe2: 1
-ppoll: 1
-
# Required by AddressSanitizer
gettid: 1
sched_yield: 1
getpid: 1
gettid: 1
+
+@include /system/etc/seccomp_policy/crash_dump.x86.policy
diff --git a/services/mediaextractor/Android.mk b/services/mediaextractor/Android.mk
index 9f3746f..5b7571c 100644
--- a/services/mediaextractor/Android.mk
+++ b/services/mediaextractor/Android.mk
@@ -15,12 +15,13 @@
# service executable
include $(CLEAR_VARS)
# seccomp filters are defined for the following architectures:
+LOCAL_REQUIRED_MODULES := crash_dump.policy
LOCAL_REQUIRED_MODULES_arm := mediaextractor.policy
LOCAL_REQUIRED_MODULES_arm64 := mediaextractor.policy
LOCAL_REQUIRED_MODULES_x86 := mediaextractor.policy
# extractor libraries
-LOCAL_REQUIRED_MODULES := \
+LOCAL_REQUIRED_MODULES += \
libaacextractor \
libamrextractor \
libflacextractor \
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
index a9ee98d..87018ed 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
@@ -48,21 +48,4 @@
readlinkat: 1
_llseek: 1
-# for attaching to debuggerd on process crash
-sigaction: 1
-tgkill: 1
-socket: 1
-connect: 1
-recvmsg: 1
-fcntl64: 1
-rt_tgsigqueueinfo: 1
-geteuid32: 1
-getgid32: 1
-getegid32: 1
-getgroups32: 1
-getdents64: 1
-pipe2: 1
-ppoll: 1
-getpid: 1
-gettid: 1
-process_vm_readv: 1
+@include /system/etc/seccomp_policy/crash_dump.arm.policy
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
index dd71ed7..d70e27b 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
@@ -40,23 +40,4 @@
pread64: 1
mremap: 1
-# for attaching to debuggerd on process crash
-tgkill: 1
-rt_sigprocmask: 1
-rt_sigaction: 1
-# socket: arg0 == AF_LOCAL
-socket: arg0 == 1
-connect: 1
-recvmsg: 1
-rt_tgsigqueueinfo: 1
-writev: 1
-geteuid: 1
-getgid: 1
-getegid: 1
-getgroups: 1
-getdents64: 1
-pipe2: 1
-ppoll: 1
-getpid: 1
-gettid: 1
-process_vm_readv: 1
+@include /system/etc/seccomp_policy/crash_dump.arm64.policy
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy b/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
index ede108e..d739ba1 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
@@ -49,24 +49,10 @@
readlinkat: 1
_llseek: 1
-# for attaching to debuggerd on process crash
-socketcall: 1
-sigaction: 1
-tgkill: 1
-rt_sigprocmask: 1
-fcntl64: 1
-rt_tgsigqueueinfo: 1
-geteuid32: 1
-getgid32: 1
-getegid32: 1
-getgroups32: 1
-getdents64: 1
-pipe2: 1
-ppoll: 1
-process_vm_readv: 1
-
# Required by AddressSanitizer
gettid: 1
sched_yield: 1
getpid: 1
gettid: 1
+
+@include /system/etc/seccomp_policy/crash_dump.x86.policy