Merge "Camera: Heic: Wait for first output tile callback before muxer start"
diff --git a/apex/ld.config.txt b/apex/ld.config.txt
index af8ec06..8f60bb2 100644
--- a/apex/ld.config.txt
+++ b/apex/ld.config.txt
@@ -38,9 +38,14 @@
namespace.platform.isolated = true
namespace.platform.search.paths = /system/${LIB}
-namespace.platform.search.paths += /apex/com.android.runtime/${LIB}
namespace.platform.asan.search.paths = /data/asan/system/${LIB}
namespace.platform.asan.search.paths += /system/${LIB}
+
+# TODO(b/140790209): These directories are wrong in R and later because they
+# only contain Bionic internal libraries dependencies that should not be
+# accessed from the outside. However, they may be necessary for APEX builds that
+# are pushed to Q. Remove them as soon as Q compatibility is no longer required.
+namespace.platform.search.paths += /apex/com.android.runtime/${LIB}
namespace.platform.asan.search.paths += /apex/com.android.runtime/${LIB}
# /system/lib/libc.so, etc are symlinks to /apex/com.android.lib/lib/bionic/libc.so, etc.
diff --git a/camera/cameraserver/Android.bp b/camera/cameraserver/Android.bp
index 334f879..320c499 100644
--- a/camera/cameraserver/Android.bp
+++ b/camera/cameraserver/Android.bp
@@ -17,6 +17,10 @@
srcs: ["main_cameraserver.cpp"],
+ header_libs: [
+ "libmedia_headers",
+ ],
+
shared_libs: [
"libcameraservice",
"liblog",
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index d24cb81..46a8dae 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -29,7 +29,7 @@
#include "ACameraCaptureSession.inc"
ACameraDevice::~ACameraDevice() {
- mDevice->stopLooper();
+ mDevice->stopLooperAndDisconnect();
}
namespace android {
@@ -112,19 +112,7 @@
}
}
-// Device close implementaiton
-CameraDevice::~CameraDevice() {
- sp<ACameraCaptureSession> session = mCurrentSession.promote();
- {
- Mutex::Autolock _l(mDeviceLock);
- if (!isClosed()) {
- disconnectLocked(session);
- }
- LOG_ALWAYS_FATAL_IF(mCbLooper != nullptr,
- "CameraDevice looper should've been stopped before ~CameraDevice");
- mCurrentSession = nullptr;
- }
-}
+CameraDevice::~CameraDevice() { }
void
CameraDevice::postSessionMsgAndCleanup(sp<AMessage>& msg) {
@@ -892,8 +880,14 @@
return;
}
-void CameraDevice::stopLooper() {
+void CameraDevice::stopLooperAndDisconnect() {
Mutex::Autolock _l(mDeviceLock);
+ sp<ACameraCaptureSession> session = mCurrentSession.promote();
+ if (!isClosed()) {
+ disconnectLocked(session);
+ }
+ mCurrentSession = nullptr;
+
if (mCbLooper != nullptr) {
mCbLooper->unregisterHandler(mHandler->id());
mCbLooper->stop();
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index 7a35bf0..6c2ceb3 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -40,6 +40,7 @@
#include <camera/NdkCameraManager.h>
#include <camera/NdkCameraCaptureSession.h>
+
#include "ACameraMetadata.h"
namespace android {
@@ -110,7 +111,7 @@
inline ACameraDevice* getWrapper() const { return mWrapper; };
// Stop the looper thread and unregister the handler
- void stopLooper();
+ void stopLooperAndDisconnect();
private:
friend ACameraCaptureSession;
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
index 35c8355..e511a3f 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
@@ -45,7 +45,7 @@
using namespace android;
ACameraDevice::~ACameraDevice() {
- mDevice->stopLooper();
+ mDevice->stopLooperAndDisconnect();
}
namespace android {
@@ -125,19 +125,7 @@
}
}
-// Device close implementaiton
-CameraDevice::~CameraDevice() {
- sp<ACameraCaptureSession> session = mCurrentSession.promote();
- {
- Mutex::Autolock _l(mDeviceLock);
- if (!isClosed()) {
- disconnectLocked(session);
- }
- mCurrentSession = nullptr;
- LOG_ALWAYS_FATAL_IF(mCbLooper != nullptr,
- "CameraDevice looper should've been stopped before ~CameraDevice");
- }
-}
+CameraDevice::~CameraDevice() { }
void
CameraDevice::postSessionMsgAndCleanup(sp<AMessage>& msg) {
@@ -1388,6 +1376,7 @@
// before cbh goes out of scope and causing we call the session
// destructor while holding device lock
cbh.mSession.clear();
+
postSessionMsgAndCleanup(msg);
}
@@ -1400,8 +1389,13 @@
}
}
-void CameraDevice::stopLooper() {
+void CameraDevice::stopLooperAndDisconnect() {
Mutex::Autolock _l(mDeviceLock);
+ sp<ACameraCaptureSession> session = mCurrentSession.promote();
+ if (!isClosed()) {
+ disconnectLocked(session);
+ }
+ mCurrentSession = nullptr;
if (mCbLooper != nullptr) {
mCbLooper->unregisterHandler(mHandler->id());
mCbLooper->stop();
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.h b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
index 9e034c4..7fc699e 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
@@ -36,6 +36,7 @@
#include <camera/NdkCameraManager.h>
#include <camera/NdkCameraCaptureSession.h>
+
#include "ACameraMetadata.h"
#include "utils.h"
@@ -134,7 +135,7 @@
inline ACameraDevice* getWrapper() const { return mWrapper; };
// Stop the looper thread and unregister the handler
- void stopLooper();
+ void stopLooperAndDisconnect();
private:
friend ACameraCaptureSession;
diff --git a/cmds/screenrecord/Android.bp b/cmds/screenrecord/Android.bp
index 86476cd..6bdbab1 100644
--- a/cmds/screenrecord/Android.bp
+++ b/cmds/screenrecord/Android.bp
@@ -24,6 +24,10 @@
"Program.cpp",
],
+ header_libs: [
+ "libmediadrm_headers",
+ ],
+
shared_libs: [
"libstagefright",
"libmedia",
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
index e39f885..4a24b96 100644
--- a/cmds/screenrecord/screenrecord.cpp
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -53,7 +53,7 @@
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaMuxer.h>
#include <media/stagefright/PersistentSurface.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/MediaCodecBuffer.h>
#include "screenrecord.h"
@@ -74,6 +74,7 @@
using android::MediaMuxer;
using android::Overlay;
using android::PersistentSurface;
+using android::PhysicalDisplayId;
using android::ProcessState;
using android::Rect;
using android::String8;
@@ -116,7 +117,7 @@
static uint32_t gBitRate = 20000000; // 20Mbps
static uint32_t gTimeLimitSec = kMaxTimeLimitSec;
static uint32_t gBframes = 0;
-
+static PhysicalDisplayId gPhysicalDisplayId;
// Set by signal handler to stop recording.
static volatile bool gStopRequested = false;
@@ -269,14 +270,14 @@
static status_t setDisplayProjection(
SurfaceComposerClient::Transaction& t,
const sp<IBinder>& dpy,
- const DisplayInfo& mainDpyInfo) {
+ const DisplayInfo& displayInfo) {
// Set the region of the layer stack we're interested in, which in our
// case is "all of it".
- Rect layerStackRect(mainDpyInfo.viewportW, mainDpyInfo.viewportH);
+ Rect layerStackRect(displayInfo.viewportW, displayInfo.viewportH);
// We need to preserve the aspect ratio of the display.
- float displayAspect = (float) mainDpyInfo.viewportH / (float) mainDpyInfo.viewportW;
+ float displayAspect = (float) displayInfo.viewportH / (float) displayInfo.viewportW;
// Set the way we map the output onto the display surface (which will
@@ -335,16 +336,15 @@
* Configures the virtual display. When this completes, virtual display
* frames will start arriving from the buffer producer.
*/
-static status_t prepareVirtualDisplay(const DisplayInfo& mainDpyInfo,
+static status_t prepareVirtualDisplay(const DisplayInfo& displayInfo,
const sp<IGraphicBufferProducer>& bufferProducer,
sp<IBinder>* pDisplayHandle) {
sp<IBinder> dpy = SurfaceComposerClient::createDisplay(
String8("ScreenRecorder"), false /*secure*/);
-
SurfaceComposerClient::Transaction t;
t.setDisplaySurface(dpy, bufferProducer);
- setDisplayProjection(t, dpy, mainDpyInfo);
- t.setDisplayLayerStack(dpy, 0); // default stack
+ setDisplayProjection(t, dpy, displayInfo);
+ t.setDisplayLayerStack(dpy, displayInfo.layerStack);
t.apply();
*pDisplayHandle = dpy;
@@ -406,7 +406,7 @@
* The muxer must *not* have been started before calling.
*/
static status_t runEncoder(const sp<MediaCodec>& encoder,
- const sp<MediaMuxer>& muxer, FILE* rawFp, const sp<IBinder>& mainDpy,
+ const sp<MediaMuxer>& muxer, FILE* rawFp, const sp<IBinder>& display,
const sp<IBinder>& virtualDpy, uint8_t orientation) {
static int kTimeout = 250000; // be responsive on signal
status_t err;
@@ -415,7 +415,7 @@
uint32_t debugNumFrames = 0;
int64_t startWhenNsec = systemTime(CLOCK_MONOTONIC);
int64_t endWhenNsec = startWhenNsec + seconds_to_nanoseconds(gTimeLimitSec);
- DisplayInfo mainDpyInfo;
+ DisplayInfo displayInfo;
Vector<int64_t> timestamps;
bool firstFrame = true;
@@ -472,16 +472,16 @@
//
// Polling for changes is inefficient and wrong, but the
// useful stuff is hard to get at without a Dalvik VM.
- err = SurfaceComposerClient::getDisplayInfo(mainDpy,
- &mainDpyInfo);
+ err = SurfaceComposerClient::getDisplayInfo(display,
+ &displayInfo);
if (err != NO_ERROR) {
ALOGW("getDisplayInfo(main) failed: %d", err);
- } else if (orientation != mainDpyInfo.orientation) {
- ALOGD("orientation changed, now %d", mainDpyInfo.orientation);
+ } else if (orientation != displayInfo.orientation) {
+ ALOGD("orientation changed, now %d", displayInfo.orientation);
SurfaceComposerClient::Transaction t;
- setDisplayProjection(t, virtualDpy, mainDpyInfo);
+ setDisplayProjection(t, virtualDpy, displayInfo);
t.apply();
- orientation = mainDpyInfo.orientation;
+ orientation = displayInfo.orientation;
}
}
@@ -661,32 +661,33 @@
self->startThreadPool();
// Get main display parameters.
- const sp<IBinder> mainDpy = SurfaceComposerClient::getInternalDisplayToken();
- if (mainDpy == nullptr) {
+ sp<IBinder> display = SurfaceComposerClient::getPhysicalDisplayToken(
+ gPhysicalDisplayId);
+ if (display == nullptr) {
fprintf(stderr, "ERROR: no display\n");
return NAME_NOT_FOUND;
}
- DisplayInfo mainDpyInfo;
- err = SurfaceComposerClient::getDisplayInfo(mainDpy, &mainDpyInfo);
+ DisplayInfo displayInfo;
+ err = SurfaceComposerClient::getDisplayInfo(display, &displayInfo);
if (err != NO_ERROR) {
fprintf(stderr, "ERROR: unable to get display characteristics\n");
return err;
}
if (gVerbose) {
- printf("Main display is %dx%d @%.2ffps (orientation=%u)\n",
- mainDpyInfo.viewportW, mainDpyInfo.viewportH, mainDpyInfo.fps,
- mainDpyInfo.orientation);
+ printf("Display is %dx%d @%.2ffps (orientation=%u), layerStack=%u\n",
+ displayInfo.viewportW, displayInfo.viewportH, displayInfo.fps,
+ displayInfo.orientation, displayInfo.layerStack);
fflush(stdout);
}
// Encoder can't take odd number as config
if (gVideoWidth == 0) {
- gVideoWidth = floorToEven(mainDpyInfo.viewportW);
+ gVideoWidth = floorToEven(displayInfo.viewportW);
}
if (gVideoHeight == 0) {
- gVideoHeight = floorToEven(mainDpyInfo.viewportH);
+ gVideoHeight = floorToEven(displayInfo.viewportH);
}
// Configure and start the encoder.
@@ -694,7 +695,7 @@
sp<FrameOutput> frameOutput;
sp<IGraphicBufferProducer> encoderInputSurface;
if (gOutputFormat != FORMAT_FRAMES && gOutputFormat != FORMAT_RAW_FRAMES) {
- err = prepareEncoder(mainDpyInfo.fps, &encoder, &encoderInputSurface);
+ err = prepareEncoder(displayInfo.fps, &encoder, &encoderInputSurface);
if (err != NO_ERROR && !gSizeSpecified) {
// fallback is defined for landscape; swap if we're in portrait
@@ -707,7 +708,7 @@
gVideoWidth, gVideoHeight, newWidth, newHeight);
gVideoWidth = newWidth;
gVideoHeight = newHeight;
- err = prepareEncoder(mainDpyInfo.fps, &encoder,
+ err = prepareEncoder(displayInfo.fps, &encoder,
&encoderInputSurface);
}
}
@@ -755,7 +756,7 @@
// Configure virtual display.
sp<IBinder> dpy;
- err = prepareVirtualDisplay(mainDpyInfo, bufferProducer, &dpy);
+ err = prepareVirtualDisplay(displayInfo, bufferProducer, &dpy);
if (err != NO_ERROR) {
if (encoder != NULL) encoder->release();
return err;
@@ -838,8 +839,8 @@
}
} else {
// Main encoder loop.
- err = runEncoder(encoder, muxer, rawFp, mainDpy, dpy,
- mainDpyInfo.orientation);
+ err = runEncoder(encoder, muxer, rawFp, display, dpy,
+ displayInfo.orientation);
if (err != NO_ERROR) {
fprintf(stderr, "Encoder failed (err=%d)\n", err);
// fall through to cleanup
@@ -1005,6 +1006,9 @@
" in videos captured to illustrate bugs.\n"
"--time-limit TIME\n"
" Set the maximum recording time, in seconds. Default / maximum is %d.\n"
+ "--display-id ID\n"
+ " specify the physical display ID to record. Default is the primary display.\n"
+ " see \"dumpsys SurfaceFlinger --display-id\" for valid display IDs.\n"
"--verbose\n"
" Display interesting information on stdout.\n"
"--help\n"
@@ -1036,9 +1040,18 @@
{ "monotonic-time", no_argument, NULL, 'm' },
{ "persistent-surface", no_argument, NULL, 'p' },
{ "bframes", required_argument, NULL, 'B' },
+ { "display-id", required_argument, NULL, 'd' },
{ NULL, 0, NULL, 0 }
};
+ std::optional<PhysicalDisplayId> displayId = SurfaceComposerClient::getInternalDisplayId();
+ if (!displayId) {
+ fprintf(stderr, "Failed to get token for internal display\n");
+ return 1;
+ }
+
+ gPhysicalDisplayId = *displayId;
+
while (true) {
int optionIndex = 0;
int ic = getopt_long(argc, argv, "", longOptions, &optionIndex);
@@ -1133,6 +1146,18 @@
return 2;
}
break;
+ case 'd':
+ gPhysicalDisplayId = atoll(optarg);
+ if (gPhysicalDisplayId == 0) {
+ fprintf(stderr, "Please specify a valid physical display id\n");
+ return 2;
+ } else if (SurfaceComposerClient::
+ getPhysicalDisplayToken(gPhysicalDisplayId) == nullptr) {
+ fprintf(stderr, "Invalid physical display id: %"
+ ANDROID_PHYSICAL_DISPLAY_ID_FORMAT "\n", gPhysicalDisplayId);
+ return 2;
+ }
+ break;
default:
if (ic != '?') {
fprintf(stderr, "getopt_long returned unexpected value 0x%x\n", ic);
diff --git a/cmds/screenrecord/screenrecord.h b/cmds/screenrecord/screenrecord.h
index 9b058c2..cec7c13 100644
--- a/cmds/screenrecord/screenrecord.h
+++ b/cmds/screenrecord/screenrecord.h
@@ -18,6 +18,6 @@
#define SCREENRECORD_SCREENRECORD_H
#define kVersionMajor 1
-#define kVersionMinor 2
+#define kVersionMinor 3
#endif /*SCREENRECORD_SCREENRECORD_H*/
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 0c8d44a..defc94f 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -3,14 +3,15 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ AudioPlayer.cpp \
stagefright.cpp \
jpeg.cpp \
SineSource.cpp
LOCAL_SHARED_LIBRARIES := \
- libstagefright libmedia libmedia_omx libutils libbinder \
+ libstagefright libmedia libmedia_codeclist libutils libbinder \
libstagefright_foundation libjpeg libui libgui libcutils liblog \
- libhidlbase \
+ libhidlbase libdatasource libaudioclient \
android.hardware.media.omx@1.0 \
LOCAL_C_INCLUDES:= \
@@ -31,14 +32,16 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ AudioPlayer.cpp \
SineSource.cpp \
record.cpp
LOCAL_SHARED_LIBRARIES := \
libstagefright libmedia liblog libutils libbinder \
- libstagefright_foundation
+ libstagefright_foundation libdatasource libaudioclient
LOCAL_C_INCLUDES:= \
+ frameworks/av/camera/include \
frameworks/av/media/libstagefright \
frameworks/native/include/media/openmax \
frameworks/native/include/media/hardware
@@ -56,12 +59,12 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- SineSource.cpp \
+ AudioPlayer.cpp \
recordvideo.cpp
LOCAL_SHARED_LIBRARIES := \
libstagefright libmedia liblog libutils libbinder \
- libstagefright_foundation
+ libstagefright_foundation libaudioclient
LOCAL_C_INCLUDES:= \
frameworks/av/media/libstagefright \
@@ -82,12 +85,13 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ AudioPlayer.cpp \
SineSource.cpp \
audioloop.cpp
LOCAL_SHARED_LIBRARIES := \
libstagefright libmedia liblog libutils libbinder \
- libstagefright_foundation
+ libstagefright_foundation libaudioclient
LOCAL_C_INCLUDES:= \
frameworks/av/media/libstagefright \
@@ -110,7 +114,7 @@
LOCAL_SHARED_LIBRARIES := \
libstagefright liblog libutils libbinder libui libgui \
- libstagefright_foundation libmedia libcutils
+ libstagefright_foundation libmedia libcutils libdatasource
LOCAL_C_INCLUDES:= \
frameworks/av/media/libstagefright \
@@ -132,6 +136,9 @@
codec.cpp \
SimplePlayer.cpp \
+LOCAL_HEADER_LIBRARIES := \
+ libmediadrm_headers \
+
LOCAL_SHARED_LIBRARIES := \
libstagefright liblog libutils libbinder libstagefright_foundation \
libmedia libmedia_omx libaudioclient libui libgui libcutils
@@ -158,17 +165,18 @@
filters/saturation.rscript \
mediafilter.cpp \
+LOCAL_HEADER_LIBRARIES := \
+ libmediadrm_headers \
+
LOCAL_SHARED_LIBRARIES := \
libstagefright \
liblog \
libutils \
libbinder \
libstagefright_foundation \
- libmedia \
libmedia_omx \
libui \
libgui \
- libcutils \
libRScpp \
LOCAL_C_INCLUDES:= \
diff --git a/media/libstagefright/AudioPlayer.cpp b/cmds/stagefright/AudioPlayer.cpp
similarity index 99%
rename from media/libstagefright/AudioPlayer.cpp
rename to cmds/stagefright/AudioPlayer.cpp
index 199b57b..208713d 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/cmds/stagefright/AudioPlayer.cpp
@@ -28,12 +28,13 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALookup.h>
#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
+#include "AudioPlayer.h"
+
namespace android {
AudioPlayer::AudioPlayer(
diff --git a/media/libstagefright/include/media/stagefright/AudioPlayer.h b/cmds/stagefright/AudioPlayer.h
similarity index 100%
rename from media/libstagefright/include/media/stagefright/AudioPlayer.h
rename to cmds/stagefright/AudioPlayer.h
diff --git a/cmds/stagefright/SimplePlayer.cpp b/cmds/stagefright/SimplePlayer.cpp
index afb7db3..f4b8164 100644
--- a/cmds/stagefright/SimplePlayer.cpp
+++ b/cmds/stagefright/SimplePlayer.cpp
@@ -23,7 +23,7 @@
#include <gui/Surface.h>
#include <media/AudioTrack.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/IMediaHTTPService.h>
#include <media/MediaCodecBuffer.h>
#include <media/stagefright/foundation/ABuffer.h>
diff --git a/cmds/stagefright/audioloop.cpp b/cmds/stagefright/audioloop.cpp
index d4f2e8d..bd274d8 100644
--- a/cmds/stagefright/audioloop.cpp
+++ b/cmds/stagefright/audioloop.cpp
@@ -29,11 +29,11 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/AMRWriter.h>
-#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/AudioSource.h>
#include <media/stagefright/MediaCodecSource.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/SimpleDecodingSource.h>
+#include "AudioPlayer.h"
#include "SineSource.h"
using namespace android;
diff --git a/cmds/stagefright/codec.cpp b/cmds/stagefright/codec.cpp
index e5a4337..f2d1c29 100644
--- a/cmds/stagefright/codec.cpp
+++ b/cmds/stagefright/codec.cpp
@@ -23,7 +23,7 @@
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/IMediaHTTPService.h>
#include <media/IMediaPlayerService.h>
#include <media/MediaCodecBuffer.h>
diff --git a/cmds/stagefright/mediafilter.cpp b/cmds/stagefright/mediafilter.cpp
index 2cf6955..66302b0 100644
--- a/cmds/stagefright/mediafilter.cpp
+++ b/cmds/stagefright/mediafilter.cpp
@@ -24,9 +24,9 @@
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/Surface.h>
-#include <media/ICrypto.h>
#include <media/IMediaHTTPService.h>
#include <media/MediaCodecBuffer.h>
+#include <mediadrm/ICrypto.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 95a16f3..37091c4 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -17,12 +17,11 @@
#include "SineSource.h"
#include <binder/ProcessState.h>
+#include <datasource/FileSource.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/CameraSource.h>
-#include <media/stagefright/FileSource.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaCodecSource.h>
@@ -33,6 +32,8 @@
#include <media/stagefright/SimpleDecodingSource.h>
#include <media/MediaPlayerInterface.h>
+#include "AudioPlayer.h"
+
using namespace android;
static const int32_t kAudioBitRate = 12200;
diff --git a/cmds/stagefright/recordvideo.cpp b/cmds/stagefright/recordvideo.cpp
index a63b9b9..01a178e 100644
--- a/cmds/stagefright/recordvideo.cpp
+++ b/cmds/stagefright/recordvideo.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#include "SineSource.h"
-
#include <inttypes.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -25,8 +23,8 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaCodecSource.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index cf9efe0..9ae87d8 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -31,18 +31,15 @@
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
+#include <datasource/DataSourceFactory.h>
#include <media/DataSource.h>
#include <media/MediaSource.h>
-#include <media/ICrypto.h>
#include <media/IMediaHTTPService.h>
#include <media/IMediaPlayerService.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AUtils.h>
-#include "include/NuCachedSource2.h"
-#include <media/stagefright/AudioPlayer.h>
-#include <media/stagefright/DataSourceFactory.h>
#include <media/stagefright/JPEGSource.h>
#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/MediaCodec.h>
@@ -69,6 +66,8 @@
#include <android/hardware/media/omx/1.0/IOmx.h>
+#include "AudioPlayer.h"
+
using namespace android;
static long gNumRepetitions;
@@ -1086,7 +1085,7 @@
const char *filename = argv[k];
sp<DataSource> dataSource =
- DataSourceFactory::CreateFromURI(NULL /* httpService */, filename);
+ DataSourceFactory::getInstance()->CreateFromURI(NULL /* httpService */, filename);
if (strncasecmp(filename, "sine:", 5) && dataSource == NULL) {
fprintf(stderr, "Unable to create data source.\n");
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
index 59b5f9f..fe613a8 100644
--- a/cmds/stagefright/stream.cpp
+++ b/cmds/stagefright/stream.cpp
@@ -21,6 +21,7 @@
#include <binder/ProcessState.h>
#include <cutils/properties.h> // for property_get
+#include <datasource/DataSourceFactory.h>
#include <media/DataSource.h>
#include <media/IMediaHTTPService.h>
#include <media/IStreamSource.h>
@@ -28,7 +29,6 @@
#include <media/MediaSource.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSourceFactory.h>
#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/MPEG2TSWriter.h>
#include <media/stagefright/MediaExtractor.h>
@@ -164,7 +164,7 @@
: mCurrentBufferIndex(-1),
mCurrentBufferOffset(0) {
sp<DataSource> dataSource =
- DataSourceFactory::CreateFromURI(NULL /* httpService */, filename);
+ DataSourceFactory::getInstance()->CreateFromURI(NULL /* httpService */, filename);
CHECK(dataSource != NULL);
diff --git a/drm/drmserver/DrmManager.cpp b/drm/drmserver/DrmManager.cpp
index 66610b3..e2ea83a 100644
--- a/drm/drmserver/DrmManager.cpp
+++ b/drm/drmserver/DrmManager.cpp
@@ -59,7 +59,6 @@
IDrmEngine& engine = mPlugInManager.getPlugIn(plugInId);
std::unique_ptr<MediaAnalyticsItem> item(MediaAnalyticsItem::create("drmmanager"));
- item->generateSessionID();
item->setUid(IPCThreadState::self()->getCallingUid());
item->setCString("function_name", func);
item->setCString("plugin_id", plugInId.getPathLeaf().getBasePath().c_str());
diff --git a/drm/libmediadrm/Android.bp b/drm/libmediadrm/Android.bp
index 6dce472..52c7438 100644
--- a/drm/libmediadrm/Android.bp
+++ b/drm/libmediadrm/Android.bp
@@ -2,9 +2,16 @@
// libmediadrm
//
-// TODO: change it back to cc_library_shared when MediaPlayer2 switches to
-// using NdkMediaDrm, instead of MediaDrm.java.
-cc_library {
+cc_library_headers {
+ name: "libmediadrm_headers",
+
+ export_include_dirs: [
+ "interface"
+ ],
+
+}
+
+cc_library_shared {
name: "libmediadrm",
srcs: [
@@ -19,14 +26,29 @@
"CryptoHal.cpp",
],
+ local_include_dirs: [
+ "include",
+ "interface"
+ ],
+
+ export_include_dirs: [
+ "include"
+ ],
+
+ header_libs: [
+ "libmedia_headers",
+ ],
+
shared_libs: [
"libbinder",
"libcutils",
"libdl",
"liblog",
+ "libmedia",
"libmediadrmmetrics_lite",
"libmediametrics",
"libmediautils",
+ "libresourcemanagerservice",
"libstagefright_foundation",
"libutils",
"android.hardware.drm@1.0",
@@ -51,10 +73,17 @@
"protos/metrics.proto",
],
+ local_include_dirs: [
+ "include"
+ ],
+
proto: {
export_proto_headers: true,
type: "lite",
},
+ header_libs: [
+ "libmedia_headers",
+ ],
shared_libs: [
"android.hardware.drm@1.0",
"android.hardware.drm@1.1",
@@ -82,10 +111,17 @@
"protos/metrics.proto",
],
+ local_include_dirs: [
+ "include"
+ ],
+
proto: {
export_proto_headers: true,
type: "full",
},
+ header_libs: [
+ "libmedia_headers",
+ ],
shared_libs: [
"android.hardware.drm@1.0",
"android.hardware.drm@1.1",
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index 7cfe900..8a08a7b 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -25,6 +25,7 @@
#include <android/hardware/drm/1.2/types.h>
#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <android/media/BnResourceManagerClient.h>
#include <hidl/ServiceManagement.h>
#include <media/EventMetric.h>
#include <media/PluginMetricsReporting.h>
@@ -293,28 +294,20 @@
}
}
-
Mutex DrmHal::mLock;
-struct DrmSessionClient : public DrmSessionClientInterface {
- explicit DrmSessionClient(DrmHal* drm) : mDrm(drm) {}
+struct DrmHal::DrmSessionClient : public android::media::BnResourceManagerClient {
+ explicit DrmSessionClient(DrmHal* drm, const Vector<uint8_t>& sessionId)
+ : mSessionId(sessionId),
+ mDrm(drm) {}
- virtual bool reclaimSession(const Vector<uint8_t>& sessionId) {
- sp<DrmHal> drm = mDrm.promote();
- if (drm == NULL) {
- return true;
- }
- status_t err = drm->closeSession(sessionId);
- if (err != OK) {
- return false;
- }
- drm->sendEvent(EventType::SESSION_RECLAIMED,
- toHidlVec(sessionId), hidl_vec<uint8_t>());
- return true;
- }
+ ::android::binder::Status reclaimResource(bool* _aidl_return) override;
+ ::android::binder::Status getName(::std::string* _aidl_return) override;
+
+ const Vector<uint8_t> mSessionId;
protected:
- virtual ~DrmSessionClient() {}
+ virtual ~DrmSessionClient();
private:
wp<DrmHal> mDrm;
@@ -322,9 +315,47 @@
DISALLOW_EVIL_CONSTRUCTORS(DrmSessionClient);
};
+::android::binder::Status DrmHal::DrmSessionClient::reclaimResource(bool* _aidl_return) {
+ sp<DrmHal> drm = mDrm.promote();
+ if (drm == NULL) {
+ *_aidl_return = true;
+ return ::android::binder::Status::ok();
+ }
+ status_t err = drm->closeSession(mSessionId);
+ if (err != OK) {
+ *_aidl_return = false;
+ return ::android::binder::Status::ok();
+ }
+ drm->sendEvent(EventType::SESSION_RECLAIMED,
+ toHidlVec(mSessionId), hidl_vec<uint8_t>());
+ *_aidl_return = true;
+ return ::android::binder::Status::ok();
+}
+
+::android::binder::Status DrmHal::DrmSessionClient::getName(::std::string* _aidl_return) {
+ String8 name;
+ sp<DrmHal> drm = mDrm.promote();
+ if (drm == NULL) {
+ name.append("<deleted>");
+ } else if (drm->getPropertyStringInternal(String8("vendor"), name) != OK
+ || name.isEmpty()) {
+ name.append("<Get vendor failed or is empty>");
+ }
+ name.append("[");
+ for (size_t i = 0; i < mSessionId.size(); ++i) {
+ name.appendFormat("%02x", mSessionId[i]);
+ }
+ name.append("]");
+ *_aidl_return = name;
+ return ::android::binder::Status::ok();
+}
+
+DrmHal::DrmSessionClient::~DrmSessionClient() {
+ DrmSessionManager::Instance()->removeSession(mSessionId);
+}
+
DrmHal::DrmHal()
- : mDrmSessionClient(new DrmSessionClient(this)),
- mFactories(makeDrmFactories()),
+ : mFactories(makeDrmFactories()),
mInitCheck((mFactories.size() == 0) ? ERROR_UNSUPPORTED : NO_INIT) {
}
@@ -333,14 +364,13 @@
auto openSessions = mOpenSessions;
for (size_t i = 0; i < openSessions.size(); i++) {
mLock.unlock();
- closeSession(openSessions[i]);
+ closeSession(openSessions[i]->mSessionId);
mLock.lock();
}
mOpenSessions.clear();
}
DrmHal::~DrmHal() {
- DrmSessionManager::Instance()->removeDrm(mDrmSessionClient);
}
void DrmHal::cleanup() {
@@ -746,9 +776,9 @@
} while (retry);
if (err == OK) {
- DrmSessionManager::Instance()->addSession(getCallingPid(),
- mDrmSessionClient, sessionId);
- mOpenSessions.push(sessionId);
+ sp<DrmSessionClient> client(new DrmSessionClient(this, sessionId));
+ DrmSessionManager::Instance()->addSession(getCallingPid(), client, sessionId);
+ mOpenSessions.push(client);
mMetrics.SetSessionStart(sessionId);
}
@@ -765,7 +795,7 @@
if (status == Status::OK) {
DrmSessionManager::Instance()->removeSession(sessionId);
for (size_t i = 0; i < mOpenSessions.size(); i++) {
- if (mOpenSessions[i] == sessionId) {
+ if (isEqualSessionId(mOpenSessions[i]->mSessionId, sessionId)) {
mOpenSessions.removeAt(i);
break;
}
@@ -893,9 +923,8 @@
status_t DrmHal::provideKeyResponse(Vector<uint8_t> const &sessionId,
Vector<uint8_t> const &response, Vector<uint8_t> &keySetId) {
Mutex::Autolock autoLock(mLock);
- EventTimer<status_t> keyResponseTimer(&mMetrics.mProvideKeyResponseTimeUs);
-
INIT_CHECK();
+ EventTimer<status_t> keyResponseTimer(&mMetrics.mProvideKeyResponseTimeUs);
DrmSessionManager::Instance()->useSession(sessionId);
@@ -1569,7 +1598,6 @@
void DrmHal::reportFrameworkMetrics() const
{
std::unique_ptr<MediaAnalyticsItem> item(MediaAnalyticsItem::create("mediadrm"));
- item->generateSessionID();
item->setPkgName(mMetrics.GetAppPackageName().c_str());
String8 vendor;
String8 description;
diff --git a/drm/libmediadrm/DrmSessionManager.cpp b/drm/libmediadrm/DrmSessionManager.cpp
index 375644c..0b91b85 100644
--- a/drm/libmediadrm/DrmSessionManager.cpp
+++ b/drm/libmediadrm/DrmSessionManager.cpp
@@ -18,16 +18,23 @@
#define LOG_TAG "DrmSessionManager"
#include <utils/Log.h>
+#include <android/media/IResourceManagerClient.h>
+#include <android/media/IResourceManagerService.h>
#include <binder/IPCThreadState.h>
#include <binder/IProcessInfoService.h>
#include <binder/IServiceManager.h>
-#include <media/stagefright/ProcessInfo.h>
-#include <mediadrm/DrmSessionClientInterface.h>
+#include <cutils/properties.h>
+#include <media/MediaResource.h>
#include <mediadrm/DrmSessionManager.h>
#include <unistd.h>
#include <utils/String8.h>
+#include <vector>
+
+#include "ResourceManagerService.h"
+
namespace android {
+using android::binder::Status;
static String8 GetSessionIdString(const Vector<uint8_t> &sessionId) {
String8 sessionIdStr;
@@ -37,6 +44,35 @@
return sessionIdStr;
}
+static std::vector<uint8_t> toStdVec(const Vector<uint8_t> &vector) {
+ const uint8_t *v = vector.array();
+ std::vector<uint8_t> vec(v, v + vector.size());
+ return vec;
+}
+
+static uint64_t toClientId(const sp<IResourceManagerClient>& drm) {
+ return reinterpret_cast<int64_t>(drm.get());
+}
+
+static std::vector<MediaResourceParcel> toResourceVec(
+ const Vector<uint8_t> &sessionId, int64_t value) {
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(MediaResource::DrmSessionResource(toStdVec(sessionId), value));
+ return resources;
+}
+
+static sp<IResourceManagerService> getResourceManagerService() {
+ if (property_get_bool("persist.device_config.media_native.mediadrmserver", 1)) {
+ return new android::media::ResourceManagerService();
+ }
+ sp<IServiceManager> sm = defaultServiceManager();
+ if (sm == NULL) {
+ return NULL;
+ }
+ sp<IBinder> binder = sm->getService(String16("media.resource_manager"));
+ return interface_cast<IResourceManagerService>(binder);
+}
+
bool isEqualSessionId(const Vector<uint8_t> &sessionId1, const Vector<uint8_t> &sessionId2) {
if (sessionId1.size() != sessionId2.size()) {
return false;
@@ -51,189 +87,116 @@
sp<DrmSessionManager> DrmSessionManager::Instance() {
static sp<DrmSessionManager> drmSessionManager = new DrmSessionManager();
+ drmSessionManager->init();
return drmSessionManager;
}
DrmSessionManager::DrmSessionManager()
- : mProcessInfo(new ProcessInfo()),
- mTime(0) {}
+ : DrmSessionManager(getResourceManagerService()) {
+}
-DrmSessionManager::DrmSessionManager(sp<ProcessInfoInterface> processInfo)
- : mProcessInfo(processInfo),
- mTime(0) {}
+DrmSessionManager::DrmSessionManager(const sp<IResourceManagerService> &service)
+ : mService(service),
+ mInitialized(false) {
+ if (mService == NULL) {
+ ALOGE("Failed to init ResourceManagerService");
+ }
+}
-DrmSessionManager::~DrmSessionManager() {}
+DrmSessionManager::~DrmSessionManager() {
+ if (mService != NULL) {
+ IInterface::asBinder(mService)->unlinkToDeath(this);
+ }
+}
-void DrmSessionManager::addSession(
- int pid, const sp<DrmSessionClientInterface>& drm, const Vector<uint8_t> &sessionId) {
- ALOGV("addSession(pid %d, drm %p, sessionId %s)", pid, drm.get(),
+void DrmSessionManager::init() {
+ Mutex::Autolock lock(mLock);
+ if (mInitialized) {
+ return;
+ }
+ mInitialized = true;
+ if (mService != NULL) {
+ IInterface::asBinder(mService)->linkToDeath(this);
+ }
+}
+
+void DrmSessionManager::addSession(int pid,
+ const sp<IResourceManagerClient>& drm, const Vector<uint8_t> &sessionId) {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ ALOGV("addSession(pid %d, uid %d, drm %p, sessionId %s)", pid, uid, drm.get(),
GetSessionIdString(sessionId).string());
Mutex::Autolock lock(mLock);
- SessionInfo info;
- info.drm = drm;
- info.sessionId = sessionId;
- info.timeStamp = getTime_l();
- ssize_t index = mSessionMap.indexOfKey(pid);
- if (index < 0) {
- // new pid
- SessionInfos infosForPid;
- infosForPid.push_back(info);
- mSessionMap.add(pid, infosForPid);
- } else {
- mSessionMap.editValueAt(index).push_back(info);
+ if (mService == NULL) {
+ return;
}
+
+ int64_t clientId = toClientId(drm);
+ mSessionMap[toStdVec(sessionId)] = (SessionInfo){pid, uid, clientId};
+ mService->addResource(pid, uid, clientId, drm, toResourceVec(sessionId, INT64_MAX));
}
void DrmSessionManager::useSession(const Vector<uint8_t> &sessionId) {
ALOGV("useSession(%s)", GetSessionIdString(sessionId).string());
Mutex::Autolock lock(mLock);
- for (size_t i = 0; i < mSessionMap.size(); ++i) {
- SessionInfos& infos = mSessionMap.editValueAt(i);
- for (size_t j = 0; j < infos.size(); ++j) {
- SessionInfo& info = infos.editItemAt(j);
- if (isEqualSessionId(sessionId, info.sessionId)) {
- info.timeStamp = getTime_l();
- return;
- }
- }
+ auto it = mSessionMap.find(toStdVec(sessionId));
+ if (mService == NULL || it == mSessionMap.end()) {
+ return;
}
+
+ auto info = it->second;
+ mService->addResource(info.pid, info.uid, info.clientId, NULL, toResourceVec(sessionId, -1));
}
void DrmSessionManager::removeSession(const Vector<uint8_t> &sessionId) {
ALOGV("removeSession(%s)", GetSessionIdString(sessionId).string());
Mutex::Autolock lock(mLock);
- for (size_t i = 0; i < mSessionMap.size(); ++i) {
- SessionInfos& infos = mSessionMap.editValueAt(i);
- for (size_t j = 0; j < infos.size(); ++j) {
- if (isEqualSessionId(sessionId, infos[j].sessionId)) {
- infos.removeAt(j);
- return;
- }
- }
+ auto it = mSessionMap.find(toStdVec(sessionId));
+ if (mService == NULL || it == mSessionMap.end()) {
+ return;
}
-}
-void DrmSessionManager::removeDrm(const sp<DrmSessionClientInterface>& drm) {
- ALOGV("removeDrm(%p)", drm.get());
-
- Mutex::Autolock lock(mLock);
- bool found = false;
- for (size_t i = 0; i < mSessionMap.size(); ++i) {
- SessionInfos& infos = mSessionMap.editValueAt(i);
- for (size_t j = 0; j < infos.size();) {
- if (infos[j].drm == drm) {
- ALOGV("removed session (%s)", GetSessionIdString(infos[j].sessionId).string());
- j = infos.removeAt(j);
- found = true;
- } else {
- ++j;
- }
- }
- if (found) {
- break;
- }
- }
+ auto info = it->second;
+ mService->removeResource(info.pid, info.clientId, toResourceVec(sessionId, INT64_MAX));
+ mSessionMap.erase(it);
}
bool DrmSessionManager::reclaimSession(int callingPid) {
ALOGV("reclaimSession(%d)", callingPid);
- sp<DrmSessionClientInterface> drm;
- Vector<uint8_t> sessionId;
- int lowestPriorityPid;
- int lowestPriority;
- {
- Mutex::Autolock lock(mLock);
- int callingPriority;
- if (!mProcessInfo->getPriority(callingPid, &callingPriority)) {
- return false;
- }
- if (!getLowestPriority_l(&lowestPriorityPid, &lowestPriority)) {
- return false;
- }
- if (lowestPriority <= callingPriority) {
- return false;
- }
+ // unlock early because reclaimResource might callback into removeSession
+ mLock.lock();
+ sp<IResourceManagerService> service(mService);
+ mLock.unlock();
- if (!getLeastUsedSession_l(lowestPriorityPid, &drm, &sessionId)) {
- return false;
- }
- }
-
- if (drm == NULL) {
+ if (service == NULL) {
return false;
}
- ALOGV("reclaim session(%s) opened by pid %d",
- GetSessionIdString(sessionId).string(), lowestPriorityPid);
-
- return drm->reclaimSession(sessionId);
+ // cannot update mSessionMap because we do not know which sessionId is reclaimed;
+ // we rely on IResourceManagerClient to removeSession in reclaimResource
+ Vector<uint8_t> dummy;
+ bool success;
+ Status status = service->reclaimResource(callingPid, toResourceVec(dummy, INT64_MAX), &success);
+ return status.isOk() && success;
}
-int64_t DrmSessionManager::getTime_l() {
- return mTime++;
+size_t DrmSessionManager::getSessionCount() const {
+ Mutex::Autolock lock(mLock);
+ return mSessionMap.size();
}
-bool DrmSessionManager::getLowestPriority_l(int* lowestPriorityPid, int* lowestPriority) {
- int pid = -1;
- int priority = -1;
- for (size_t i = 0; i < mSessionMap.size(); ++i) {
- if (mSessionMap.valueAt(i).size() == 0) {
- // no opened session by this process.
- continue;
- }
- int tempPid = mSessionMap.keyAt(i);
- int tempPriority;
- if (!mProcessInfo->getPriority(tempPid, &tempPriority)) {
- // shouldn't happen.
- return false;
- }
- if (pid == -1) {
- pid = tempPid;
- priority = tempPriority;
- } else {
- if (tempPriority > priority) {
- pid = tempPid;
- priority = tempPriority;
- }
- }
- }
- if (pid != -1) {
- *lowestPriorityPid = pid;
- *lowestPriority = priority;
- }
- return (pid != -1);
+bool DrmSessionManager::containsSession(const Vector<uint8_t>& sessionId) const {
+ Mutex::Autolock lock(mLock);
+ return mSessionMap.count(toStdVec(sessionId));
}
-bool DrmSessionManager::getLeastUsedSession_l(
- int pid, sp<DrmSessionClientInterface>* drm, Vector<uint8_t>* sessionId) {
- ssize_t index = mSessionMap.indexOfKey(pid);
- if (index < 0) {
- return false;
- }
-
- int leastUsedIndex = -1;
- int64_t minTs = LLONG_MAX;
- const SessionInfos& infos = mSessionMap.valueAt(index);
- for (size_t j = 0; j < infos.size(); ++j) {
- if (leastUsedIndex == -1) {
- leastUsedIndex = j;
- minTs = infos[j].timeStamp;
- } else {
- if (infos[j].timeStamp < minTs) {
- leastUsedIndex = j;
- minTs = infos[j].timeStamp;
- }
- }
- }
- if (leastUsedIndex != -1) {
- *drm = infos[leastUsedIndex].drm;
- *sessionId = infos[leastUsedIndex].sessionId;
- }
- return (leastUsedIndex != -1);
+void DrmSessionManager::binderDied(const wp<IBinder>& /*who*/) {
+ ALOGW("ResourceManagerService died.");
+ Mutex::Autolock lock(mLock);
+ mService.clear();
}
} // namespace android
diff --git a/drm/libmediadrm/PluginMetricsReporting.cpp b/drm/libmediadrm/PluginMetricsReporting.cpp
index 8cd6f96..098f07b 100644
--- a/drm/libmediadrm/PluginMetricsReporting.cpp
+++ b/drm/libmediadrm/PluginMetricsReporting.cpp
@@ -35,8 +35,6 @@
const String8& name,
const String8& appPackageName) {
std::unique_ptr<MediaAnalyticsItem> analyticsItem(MediaAnalyticsItem::create(name.c_str()));
- analyticsItem->generateSessionID();
-
std::string app_package_name(appPackageName.c_str(), appPackageName.size());
analyticsItem->setPkgName(app_package_name);
if (metrics.size() > 0) {
@@ -44,7 +42,7 @@
}
if (!analyticsItem->selfrecord()) {
- ALOGE("selfrecord() returned false. sessioId %" PRId64, analyticsItem->getSessionID());
+ ALOGE("%s: selfrecord() returned false", __func__);
}
return OK;
diff --git a/drm/libmediadrm/TEST_MAPPING b/drm/libmediadrm/TEST_MAPPING
new file mode 100644
index 0000000..bc15879
--- /dev/null
+++ b/drm/libmediadrm/TEST_MAPPING
@@ -0,0 +1,26 @@
+{
+ "presubmit": [
+ {
+ "name": "GtsMediaTestCases",
+ "options" : [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "include-filter": "com.google.android.media.gts.WidevineGenericOpsTests"
+ },
+ {
+ "include-filter": "com.google.android.media.gts.MediaDrmTest"
+ },
+ {
+ "include-filter": "com.google.android.media.gts.WidevineDashPolicyTests"
+ }
+ ]
+ }
+ ],
+ "imports": [
+ {
+ "path": "frameworks/av/drm/mediadrm/plugins"
+ }
+ ]
+}
diff --git a/media/libmedia/include/media/CryptoHal.h b/drm/libmediadrm/include/mediadrm/CryptoHal.h
similarity index 100%
rename from media/libmedia/include/media/CryptoHal.h
rename to drm/libmediadrm/include/mediadrm/CryptoHal.h
diff --git a/media/libmedia/include/media/DrmHal.h b/drm/libmediadrm/include/mediadrm/DrmHal.h
similarity index 98%
rename from media/libmedia/include/media/DrmHal.h
rename to drm/libmediadrm/include/mediadrm/DrmHal.h
index bdf1b30..0431c93 100644
--- a/media/libmedia/include/media/DrmHal.h
+++ b/drm/libmediadrm/include/mediadrm/DrmHal.h
@@ -28,6 +28,7 @@
#include <media/MediaAnalyticsItem.h>
#include <mediadrm/DrmMetrics.h>
+#include <mediadrm/DrmSessionManager.h>
#include <mediadrm/IDrm.h>
#include <mediadrm/IDrmClient.h>
#include <utils/threads.h>
@@ -59,6 +60,9 @@
struct DrmHal : public BnDrm,
public IBinder::DeathRecipient,
public IDrmPluginListener_V1_2 {
+
+ struct DrmSessionClient;
+
DrmHal();
virtual ~DrmHal();
@@ -193,8 +197,6 @@
private:
static Mutex mLock;
- sp<DrmSessionClientInterface> mDrmSessionClient;
-
sp<IDrmClient> mListener;
mutable Mutex mEventLock;
mutable Mutex mNotifyLock;
@@ -208,7 +210,7 @@
// Mutable to allow modification within GetPropertyByteArray.
mutable MediaDrmMetrics mMetrics;
- Vector<Vector<uint8_t>> mOpenSessions;
+ Vector<sp<DrmSessionClient>> mOpenSessions;
void closeOpenSessions();
void cleanup();
diff --git a/media/libmedia/include/media/DrmMetrics.h b/drm/libmediadrm/include/mediadrm/DrmMetrics.h
similarity index 100%
rename from media/libmedia/include/media/DrmMetrics.h
rename to drm/libmediadrm/include/mediadrm/DrmMetrics.h
diff --git a/media/libmedia/include/media/DrmPluginPath.h b/drm/libmediadrm/include/mediadrm/DrmPluginPath.h
similarity index 100%
rename from media/libmedia/include/media/DrmPluginPath.h
rename to drm/libmediadrm/include/mediadrm/DrmPluginPath.h
diff --git a/media/libmedia/include/media/DrmSessionClientInterface.h b/drm/libmediadrm/include/mediadrm/DrmSessionClientInterface.h
similarity index 100%
rename from media/libmedia/include/media/DrmSessionClientInterface.h
rename to drm/libmediadrm/include/mediadrm/DrmSessionClientInterface.h
diff --git a/media/libmedia/include/media/DrmSessionManager.h b/drm/libmediadrm/include/mediadrm/DrmSessionManager.h
similarity index 60%
rename from media/libmedia/include/media/DrmSessionManager.h
rename to drm/libmediadrm/include/mediadrm/DrmSessionManager.h
index ba27199..3258f7a 100644
--- a/media/libmedia/include/media/DrmSessionManager.h
+++ b/drm/libmediadrm/include/mediadrm/DrmSessionManager.h
@@ -18,56 +18,66 @@
#define DRM_SESSION_MANAGER_H_
+#include <binder/IBinder.h>
#include <media/stagefright/foundation/ABase.h>
#include <utils/RefBase.h>
#include <utils/KeyedVector.h>
#include <utils/threads.h>
#include <utils/Vector.h>
+#include <map>
+#include <utility>
+#include <vector>
+
namespace android {
class DrmSessionManagerTest;
-struct DrmSessionClientInterface;
-struct ProcessInfoInterface;
+
+namespace media {
+class IResourceManagerClient;
+class IResourceManagerService;
+}
+using android::media::IResourceManagerClient;
+using android::media::IResourceManagerService;
bool isEqualSessionId(const Vector<uint8_t> &sessionId1, const Vector<uint8_t> &sessionId2);
struct SessionInfo {
- sp<DrmSessionClientInterface> drm;
- Vector<uint8_t> sessionId;
- int64_t timeStamp;
+ pid_t pid;
+ uid_t uid;
+ int64_t clientId;
};
-typedef Vector<SessionInfo > SessionInfos;
-typedef KeyedVector<int, SessionInfos > PidSessionInfosMap;
+typedef std::map<std::vector<uint8_t>, SessionInfo> SessionInfoMap;
-struct DrmSessionManager : public RefBase {
+struct DrmSessionManager : public IBinder::DeathRecipient {
static sp<DrmSessionManager> Instance();
DrmSessionManager();
- explicit DrmSessionManager(sp<ProcessInfoInterface> processInfo);
+ explicit DrmSessionManager(const sp<IResourceManagerService> &service);
- void addSession(int pid, const sp<DrmSessionClientInterface>& drm, const Vector<uint8_t>& sessionId);
+ void addSession(int pid, const sp<IResourceManagerClient>& drm, const Vector<uint8_t>& sessionId);
void useSession(const Vector<uint8_t>& sessionId);
void removeSession(const Vector<uint8_t>& sessionId);
- void removeDrm(const sp<DrmSessionClientInterface>& drm);
bool reclaimSession(int callingPid);
+ // sanity check APIs
+ size_t getSessionCount() const;
+ bool containsSession(const Vector<uint8_t>& sessionId) const;
+
+ // implements DeathRecipient
+ virtual void binderDied(const wp<IBinder>& /*who*/);
+
protected:
virtual ~DrmSessionManager();
private:
- friend class DrmSessionManagerTest;
+ void init();
- int64_t getTime_l();
- bool getLowestPriority_l(int* lowestPriorityPid, int* lowestPriority);
- bool getLeastUsedSession_l(
- int pid, sp<DrmSessionClientInterface>* drm, Vector<uint8_t>* sessionId);
-
- sp<ProcessInfoInterface> mProcessInfo;
+ sp<IResourceManagerService> mService;
mutable Mutex mLock;
- PidSessionInfosMap mSessionMap;
- int64_t mTime;
+ SessionInfoMap mSessionMap;
+ bool mInitialized;
DISALLOW_EVIL_CONSTRUCTORS(DrmSessionManager);
};
diff --git a/media/libmedia/include/media/IDrm.h b/drm/libmediadrm/include/mediadrm/IDrm.h
similarity index 100%
rename from media/libmedia/include/media/IDrm.h
rename to drm/libmediadrm/include/mediadrm/IDrm.h
diff --git a/media/libmedia/include/media/IDrmClient.h b/drm/libmediadrm/include/mediadrm/IDrmClient.h
similarity index 100%
rename from media/libmedia/include/media/IDrmClient.h
rename to drm/libmediadrm/include/mediadrm/IDrmClient.h
diff --git a/media/libmedia/include/media/IMediaDrmService.h b/drm/libmediadrm/include/mediadrm/IMediaDrmService.h
similarity index 100%
rename from media/libmedia/include/media/IMediaDrmService.h
rename to drm/libmediadrm/include/mediadrm/IMediaDrmService.h
diff --git a/media/libmedia/include/media/SharedLibrary.h b/drm/libmediadrm/include/mediadrm/SharedLibrary.h
similarity index 100%
rename from media/libmedia/include/media/SharedLibrary.h
rename to drm/libmediadrm/include/mediadrm/SharedLibrary.h
diff --git a/media/libmedia/include/media/ICrypto.h b/drm/libmediadrm/interface/mediadrm/ICrypto.h
similarity index 100%
rename from media/libmedia/include/media/ICrypto.h
rename to drm/libmediadrm/interface/mediadrm/ICrypto.h
diff --git a/drm/libmediadrm/tests/Android.bp b/drm/libmediadrm/tests/Android.bp
index 9e0115e..2e39943 100644
--- a/drm/libmediadrm/tests/Android.bp
+++ b/drm/libmediadrm/tests/Android.bp
@@ -3,8 +3,8 @@
cc_test {
name: "CounterMetric_test",
srcs: ["CounterMetric_test.cpp"],
+ header_libs: ["libmedia_headers"],
shared_libs: ["libmediadrm"],
- include_dirs: ["frameworks/av/include/media"],
cflags: [
"-Werror",
"-Wall",
@@ -14,6 +14,9 @@
cc_test {
name: "DrmMetrics_test",
srcs: ["DrmMetrics_test.cpp"],
+ header_libs: [
+ "libmedia_headers"
+ ],
shared_libs: [
"android.hardware.drm@1.0",
"android.hardware.drm@1.1",
@@ -28,7 +31,7 @@
],
static_libs: ["libgmock"],
include_dirs: [
- "frameworks/av/include/media",
+ "frameworks/av/drm/libmediadrm/include",
],
cflags: [
// Suppress unused parameter and no error options. These cause problems
@@ -40,12 +43,14 @@
cc_test {
name: "EventMetric_test",
srcs: ["EventMetric_test.cpp"],
+ header_libs: [
+ "libmedia_headers"
+ ],
shared_libs: [
"liblog",
"libmediadrm",
"libutils",
],
- include_dirs: ["frameworks/av/include/media"],
cflags: [
"-Werror",
"-Wall",
diff --git a/drm/libmediadrm/tests/CounterMetric_test.cpp b/drm/libmediadrm/tests/CounterMetric_test.cpp
index 6bca0da..c2becb4 100644
--- a/drm/libmediadrm/tests/CounterMetric_test.cpp
+++ b/drm/libmediadrm/tests/CounterMetric_test.cpp
@@ -16,7 +16,7 @@
#include <gtest/gtest.h>
-#include "CounterMetric.h"
+#include <media/CounterMetric.h>
namespace android {
diff --git a/drm/libmediadrm/tests/EventMetric_test.cpp b/drm/libmediadrm/tests/EventMetric_test.cpp
index eb6c4f6..b3c3f62 100644
--- a/drm/libmediadrm/tests/EventMetric_test.cpp
+++ b/drm/libmediadrm/tests/EventMetric_test.cpp
@@ -16,7 +16,7 @@
#include <gtest/gtest.h>
-#include "EventMetric.h"
+#include <media/EventMetric.h>
namespace android {
diff --git a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
index bf35224..af7c367 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
+++ b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
@@ -97,7 +97,8 @@
///////////////////////////////////////////////////////////////////////////////
ClearKeyCasPlugin::ClearKeyCasPlugin(
void *appData, CasPluginCallback callback)
- : mCallback(callback), mCallbackExt(NULL), mAppData(appData) {
+ : mCallback(callback), mCallbackExt(NULL), mStatusCallback(NULL),
+ mAppData(appData) {
ALOGV("CTOR");
}
@@ -112,6 +113,13 @@
ClearKeySessionLibrary::get()->destroyPlugin(this);
}
+status_t ClearKeyCasPlugin::setStatusCallback(
+ CasPluginStatusCallback callback) {
+ ALOGV("setStatusCallback");
+ mStatusCallback = callback;
+ return OK;
+}
+
status_t ClearKeyCasPlugin::setPrivateData(const CasData &/*data*/) {
ALOGV("setPrivateData");
@@ -135,6 +143,19 @@
return ClearKeySessionLibrary::get()->addSession(this, sessionId);
}
+status_t ClearKeyCasPlugin::openSession(uint32_t intent, uint32_t mode,
+ CasSessionId* sessionId) {
+ ALOGV("openSession with intent=%d, mode=%d", intent, mode);
+ // Echo the received information to the callback.
+ // Clear key plugin doesn't use any event, echo'ing for testing only.
+ if (mStatusCallback != NULL) {
+ mStatusCallback((void*)mAppData, intent, mode);
+ }
+
+ // Clear key plugin doesn't use intent and mode.
+ return ClearKeySessionLibrary::get()->addSession(this, sessionId);
+}
+
status_t ClearKeyCasPlugin::closeSession(const CasSessionId &sessionId) {
ALOGV("closeSession: sessionId=%s", sessionIdToString(sessionId).string());
std::shared_ptr<ClearKeyCasSession> session =
diff --git a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h
index f48d5b1..c6938e6 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h
+++ b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h
@@ -71,11 +71,17 @@
ClearKeyCasPlugin(void *appData, CasPluginCallbackExt callback);
virtual ~ClearKeyCasPlugin();
+ virtual status_t setStatusCallback(
+ CasPluginStatusCallback callback) override;
+
virtual status_t setPrivateData(
const CasData &data) override;
virtual status_t openSession(CasSessionId *sessionId) override;
+ virtual status_t openSession(uint32_t intent, uint32_t mode,
+ CasSessionId *sessionId) override;
+
virtual status_t closeSession(
const CasSessionId &sessionId) override;
@@ -105,6 +111,7 @@
std::unique_ptr<KeyFetcher> mKeyFetcher;
CasPluginCallback mCallback;
CasPluginCallbackExt mCallbackExt;
+ CasPluginStatusCallback mStatusCallback;
void* mAppData;
};
diff --git a/drm/mediacas/plugins/mock/MockCasPlugin.cpp b/drm/mediacas/plugins/mock/MockCasPlugin.cpp
index 2964791..f8bab0a 100644
--- a/drm/mediacas/plugins/mock/MockCasPlugin.cpp
+++ b/drm/mediacas/plugins/mock/MockCasPlugin.cpp
@@ -111,6 +111,12 @@
MockSessionLibrary::get()->destroyPlugin(this);
}
+status_t MockCasPlugin::setStatusCallback(
+ CasPluginStatusCallback /*callback*/) {
+ ALOGV("setStatusCallback");
+ return OK;
+}
+
status_t MockCasPlugin::setPrivateData(const CasData& /*data*/) {
ALOGV("setPrivateData");
return OK;
@@ -121,6 +127,13 @@
return MockSessionLibrary::get()->addSession(this, sessionId);
}
+status_t MockCasPlugin::openSession(uint32_t intent, uint32_t mode,
+ CasSessionId* sessionId) {
+ ALOGV("openSession with intent=%d, mode=%d", intent, mode);
+ // Clear key plugin doesn't use intent and mode.
+ return MockSessionLibrary::get()->addSession(this, sessionId);
+}
+
status_t MockCasPlugin::closeSession(const CasSessionId &sessionId) {
ALOGV("closeSession: sessionId=%s", arrayToString(sessionId).string());
Mutex::Autolock lock(mLock);
diff --git a/drm/mediacas/plugins/mock/MockCasPlugin.h b/drm/mediacas/plugins/mock/MockCasPlugin.h
index 74b540c..660fd44 100644
--- a/drm/mediacas/plugins/mock/MockCasPlugin.h
+++ b/drm/mediacas/plugins/mock/MockCasPlugin.h
@@ -65,11 +65,17 @@
MockCasPlugin();
virtual ~MockCasPlugin();
+ virtual status_t setStatusCallback(
+ CasPluginStatusCallback callback) override;
+
virtual status_t setPrivateData(
const CasData &data) override;
virtual status_t openSession(CasSessionId *sessionId) override;
+ virtual status_t openSession(uint32_t intent, uint32_t mode,
+ CasSessionId *sessionId) override;
+
virtual status_t closeSession(
const CasSessionId &sessionId) override;
diff --git a/drm/mediadrm/plugins/TEST_MAPPING b/drm/mediadrm/plugins/TEST_MAPPING
new file mode 100644
index 0000000..7bd1568
--- /dev/null
+++ b/drm/mediadrm/plugins/TEST_MAPPING
@@ -0,0 +1,18 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsMediaTestCases",
+ "options" : [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "include-filter": "android.media.cts.MediaDrmClearkeyTest"
+ },
+ {
+ "include-filter": "android.media.cts.MediaDrmMetricsTest"
+ }
+ ]
+ }
+ ]
+}
diff --git a/drm/mediadrm/plugins/clearkey/default/InitDataParser.cpp b/drm/mediadrm/plugins/clearkey/default/InitDataParser.cpp
index caff393..121a4e2 100644
--- a/drm/mediadrm/plugins/clearkey/default/InitDataParser.cpp
+++ b/drm/mediadrm/plugins/clearkey/default/InitDataParser.cpp
@@ -76,10 +76,21 @@
android::status_t InitDataParser::parsePssh(const Vector<uint8_t>& initData,
Vector<const uint8_t*>* keyIds) {
+ // Description of PSSH format:
+ // https://w3c.github.io/encrypted-media/format-registry/initdata/cenc.html
size_t readPosition = 0;
- // Validate size field
uint32_t expectedSize = initData.size();
+ const char psshIdentifier[4] = {'p', 's', 's', 'h'};
+ const uint8_t psshVersion1[4] = {1, 0, 0, 0};
+ uint32_t keyIdCount = 0;
+ size_t headerSize = sizeof(expectedSize) + sizeof(psshIdentifier) +
+ sizeof(psshVersion1) + kSystemIdSize + sizeof(keyIdCount);
+ if (initData.size() < headerSize) {
+ return android::ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ // Validate size field
expectedSize = htonl(expectedSize);
if (memcmp(&initData[readPosition], &expectedSize,
sizeof(expectedSize)) != 0) {
@@ -88,7 +99,6 @@
readPosition += sizeof(expectedSize);
// Validate PSSH box identifier
- const char psshIdentifier[4] = {'p', 's', 's', 'h'};
if (memcmp(&initData[readPosition], psshIdentifier,
sizeof(psshIdentifier)) != 0) {
return android::ERROR_DRM_CANNOT_HANDLE;
@@ -96,7 +106,6 @@
readPosition += sizeof(psshIdentifier);
// Validate EME version number
- const uint8_t psshVersion1[4] = {1, 0, 0, 0};
if (memcmp(&initData[readPosition], psshVersion1,
sizeof(psshVersion1)) != 0) {
return android::ERROR_DRM_CANNOT_HANDLE;
@@ -110,12 +119,14 @@
readPosition += kSystemIdSize;
// Read key ID count
- uint32_t keyIdCount;
memcpy(&keyIdCount, &initData[readPosition], sizeof(keyIdCount));
keyIdCount = ntohl(keyIdCount);
readPosition += sizeof(keyIdCount);
- if (readPosition + ((uint64_t)keyIdCount * kKeyIdSize) !=
- initData.size() - sizeof(uint32_t)) {
+
+ uint64_t psshSize = 0;
+ if (__builtin_mul_overflow(keyIdCount, kKeyIdSize, &psshSize) ||
+ __builtin_add_overflow(readPosition, psshSize, &psshSize) ||
+ psshSize != initData.size() - sizeof(uint32_t) /* DataSize(0) */) {
return android::ERROR_DRM_CANNOT_HANDLE;
}
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
index 0c74a6c..942ea7d 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
@@ -111,6 +111,8 @@
// The content in this secure stop is implementation dependent, the clearkey
// secureStop does not serve as a reference implementation.
void DrmPlugin::installSecureStop(const hidl_vec<uint8_t>& sessionId) {
+ Mutex::Autolock lock(mSecureStopLock);
+
ClearkeySecureStop clearkeySecureStop;
clearkeySecureStop.id = uint32ToVector(++mNextSecureStopId);
clearkeySecureStop.data.assign(sessionId.begin(), sessionId.end());
@@ -744,6 +746,7 @@
}
Return<void> DrmPlugin::getSecureStops(getSecureStops_cb _hidl_cb) {
+ mSecureStopLock.lock();
std::vector<SecureStop> stops;
for (auto itr = mSecureStops.begin(); itr != mSecureStops.end(); ++itr) {
ClearkeySecureStop clearkeyStop = itr->second;
@@ -755,26 +758,32 @@
stop.opaqueData = toHidlVec(stopVec);
stops.push_back(stop);
}
+ mSecureStopLock.unlock();
+
_hidl_cb(Status::OK, stops);
return Void();
}
Return<void> DrmPlugin::getSecureStop(const hidl_vec<uint8_t>& secureStopId,
getSecureStop_cb _hidl_cb) {
- SecureStop stop;
+ std::vector<uint8_t> stopVec;
+
+ mSecureStopLock.lock();
auto itr = mSecureStops.find(toVector(secureStopId));
if (itr != mSecureStops.end()) {
ClearkeySecureStop clearkeyStop = itr->second;
- std::vector<uint8_t> stopVec;
stopVec.insert(stopVec.end(), clearkeyStop.id.begin(), clearkeyStop.id.end());
stopVec.insert(stopVec.end(), clearkeyStop.data.begin(), clearkeyStop.data.end());
+ }
+ mSecureStopLock.unlock();
+ SecureStop stop;
+ if (!stopVec.empty()) {
stop.opaqueData = toHidlVec(stopVec);
_hidl_cb(Status::OK, stop);
} else {
_hidl_cb(Status::BAD_VALUE, stop);
}
-
return Void();
}
@@ -787,52 +796,73 @@
}
Return<void> DrmPlugin::getSecureStopIds(getSecureStopIds_cb _hidl_cb) {
+ mSecureStopLock.lock();
std::vector<SecureStopId> ids;
for (auto itr = mSecureStops.begin(); itr != mSecureStops.end(); ++itr) {
ids.push_back(itr->first);
}
+ mSecureStopLock.unlock();
_hidl_cb(Status::OK, toHidlVec(ids));
return Void();
}
Return<Status> DrmPlugin::releaseSecureStops(const SecureStopRelease& ssRelease) {
- // minimum opaqueData contains the uint32_t count, see comment below
- if (ssRelease.opaqueData.size() < sizeof(uint32_t)) {
+ // OpaqueData starts with 4 byte decimal integer string
+ const size_t kFourBytesOffset = 4;
+ if (ssRelease.opaqueData.size() < kFourBytesOffset) {
+ ALOGE("Invalid secureStopRelease length");
return Status::BAD_VALUE;
}
Status status = Status::OK;
std::vector<uint8_t> input = toVector(ssRelease.opaqueData);
+ if (input.size() < kSecureStopIdSize + kFourBytesOffset) {
+ // The minimum size of SecureStopRelease has to contain
+ // a 4 bytes count and one secureStop id
+ ALOGE("Total size of secureStops is too short");
+ return Status::BAD_VALUE;
+ }
+
// The format of opaqueData is shared between the server
// and the drm service. The clearkey implementation consists of:
// count - number of secure stops
// list of fixed length secure stops
- size_t countBufferSize = sizeof(uint32_t);
uint32_t count = 0;
sscanf(reinterpret_cast<char*>(input.data()), "%04" PRIu32, &count);
// Avoid divide by 0 below.
if (count == 0) {
+ ALOGE("Invalid 0 secureStop count");
return Status::BAD_VALUE;
}
- size_t secureStopSize = (input.size() - countBufferSize) / count;
- uint8_t buffer[secureStopSize];
- size_t offset = countBufferSize; // skip the count
+ // Computes the fixed length secureStop size
+ size_t secureStopSize = (input.size() - kFourBytesOffset) / count;
+ if (secureStopSize < kSecureStopIdSize) {
+ // A valid secureStop contains the id plus data
+ ALOGE("Invalid secureStop size");
+ return Status::BAD_VALUE;
+ }
+ uint8_t* buffer = new uint8_t[secureStopSize];
+ size_t offset = kFourBytesOffset; // skip the count
for (size_t i = 0; i < count; ++i, offset += secureStopSize) {
memcpy(buffer, input.data() + offset, secureStopSize);
- std::vector<uint8_t> id(buffer, buffer + kSecureStopIdSize);
+ // A secureStop contains id+data, we only use the id for removal
+ std::vector<uint8_t> id(buffer, buffer + kSecureStopIdSize);
status = removeSecureStop(toHidlVec(id));
if (Status::OK != status) break;
}
+ delete[] buffer;
return status;
}
Return<Status> DrmPlugin::removeSecureStop(const hidl_vec<uint8_t>& secureStopId) {
+ Mutex::Autolock lock(mSecureStopLock);
+
if (1 != mSecureStops.erase(toVector(secureStopId))) {
return Status::BAD_VALUE;
}
@@ -840,6 +870,8 @@
}
Return<Status> DrmPlugin::removeAllSecureStops() {
+ Mutex::Autolock lock(mSecureStopLock);
+
mSecureStops.clear();
mNextSecureStopId = kSecureStopIdStart;
return Status::OK;
diff --git a/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp b/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp
index b988ce0..8513434 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp
@@ -85,10 +85,21 @@
Status InitDataParser::parsePssh(const std::vector<uint8_t>& initData,
std::vector<const uint8_t*>* keyIds) {
+ // Description of PSSH format:
+ // https://w3c.github.io/encrypted-media/format-registry/initdata/cenc.html
size_t readPosition = 0;
- // Validate size field
uint32_t expectedSize = initData.size();
+ const char psshIdentifier[4] = {'p', 's', 's', 'h'};
+ const uint8_t psshVersion1[4] = {1, 0, 0, 0};
+ uint32_t keyIdCount = 0;
+ size_t headerSize = sizeof(expectedSize) + sizeof(psshIdentifier) +
+ sizeof(psshVersion1) + kSystemIdSize + sizeof(keyIdCount);
+ if (initData.size() < headerSize) {
+ return Status::ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ // Validate size field
expectedSize = htonl(expectedSize);
if (memcmp(&initData[readPosition], &expectedSize,
sizeof(expectedSize)) != 0) {
@@ -97,7 +108,6 @@
readPosition += sizeof(expectedSize);
// Validate PSSH box identifier
- const char psshIdentifier[4] = {'p', 's', 's', 'h'};
if (memcmp(&initData[readPosition], psshIdentifier,
sizeof(psshIdentifier)) != 0) {
return Status::ERROR_DRM_CANNOT_HANDLE;
@@ -105,7 +115,6 @@
readPosition += sizeof(psshIdentifier);
// Validate EME version number
- const uint8_t psshVersion1[4] = {1, 0, 0, 0};
if (memcmp(&initData[readPosition], psshVersion1,
sizeof(psshVersion1)) != 0) {
return Status::ERROR_DRM_CANNOT_HANDLE;
@@ -119,12 +128,14 @@
readPosition += kSystemIdSize;
// Read key ID count
- uint32_t keyIdCount;
memcpy(&keyIdCount, &initData[readPosition], sizeof(keyIdCount));
keyIdCount = ntohl(keyIdCount);
readPosition += sizeof(keyIdCount);
- if (readPosition + ((uint64_t)keyIdCount * kKeyIdSize) !=
- initData.size() - sizeof(uint32_t)) {
+
+ uint64_t psshSize = 0;
+ if (__builtin_mul_overflow(keyIdCount, kKeyIdSize, &psshSize) ||
+ __builtin_add_overflow(readPosition, psshSize, &psshSize) ||
+ psshSize != initData.size() - sizeof(uint32_t) /* DataSize(0) */) {
return Status::ERROR_DRM_CANNOT_HANDLE;
}
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
index f294d4d..3de7589 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
@@ -416,6 +416,7 @@
}
DeviceFiles mFileHandle;
+ Mutex mSecureStopLock;
CLEARKEY_DISALLOW_COPY_AND_ASSIGN_AND_NEW(DrmPlugin);
};
diff --git a/include/camera b/include/camera
deleted file mode 120000
index 00848e3..0000000
--- a/include/camera
+++ /dev/null
@@ -1 +0,0 @@
-../camera/include/camera/
\ No newline at end of file
diff --git a/include/cpustats b/include/cpustats
deleted file mode 120000
index 4a02d41..0000000
--- a/include/cpustats
+++ /dev/null
@@ -1 +0,0 @@
-../media/libcpustats/include/cpustats/
\ No newline at end of file
diff --git a/include/media/AVSyncSettings.h b/include/media/AVSyncSettings.h
deleted file mode 120000
index bbe211f..0000000
--- a/include/media/AVSyncSettings.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/AVSyncSettings.h
\ No newline at end of file
diff --git a/include/media/AudioAttributes.h b/include/media/AudioAttributes.h
deleted file mode 120000
index 27ba471..0000000
--- a/include/media/AudioAttributes.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioAttributes.h
\ No newline at end of file
diff --git a/include/media/AudioBufferProvider.h b/include/media/AudioBufferProvider.h
deleted file mode 120000
index c4d6e79..0000000
--- a/include/media/AudioBufferProvider.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioBufferProvider.h
\ No newline at end of file
diff --git a/include/media/AudioClient.h b/include/media/AudioClient.h
deleted file mode 120000
index a0530e4..0000000
--- a/include/media/AudioClient.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioClient.h
\ No newline at end of file
diff --git a/include/media/AudioCommonTypes.h b/include/media/AudioCommonTypes.h
deleted file mode 120000
index ae7c99a..0000000
--- a/include/media/AudioCommonTypes.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioCommonTypes.h
\ No newline at end of file
diff --git a/include/media/AudioEffect.h b/include/media/AudioEffect.h
deleted file mode 120000
index bf52955..0000000
--- a/include/media/AudioEffect.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioEffect.h
\ No newline at end of file
diff --git a/include/media/AudioIoDescriptor.h b/include/media/AudioIoDescriptor.h
deleted file mode 120000
index 68f54c9..0000000
--- a/include/media/AudioIoDescriptor.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioIoDescriptor.h
\ No newline at end of file
diff --git a/include/media/AudioMixer.h b/include/media/AudioMixer.h
deleted file mode 120000
index 85ee950..0000000
--- a/include/media/AudioMixer.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioprocessing/include/media/AudioMixer.h
\ No newline at end of file
diff --git a/include/media/AudioParameter.h b/include/media/AudioParameter.h
deleted file mode 120000
index a5889e5..0000000
--- a/include/media/AudioParameter.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioParameter.h
\ No newline at end of file
diff --git a/include/media/AudioPolicy.h b/include/media/AudioPolicy.h
deleted file mode 120000
index dd4cd53..0000000
--- a/include/media/AudioPolicy.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioPolicy.h
\ No newline at end of file
diff --git a/include/media/AudioProductStrategy.h b/include/media/AudioProductStrategy.h
deleted file mode 120000
index 6bfaf11..0000000
--- a/include/media/AudioProductStrategy.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioProductStrategy.h
\ No newline at end of file
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
deleted file mode 120000
index 7939dd3..0000000
--- a/include/media/AudioRecord.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioRecord.h
\ No newline at end of file
diff --git a/include/media/AudioResampler.h b/include/media/AudioResampler.h
deleted file mode 120000
index 771f1b8..0000000
--- a/include/media/AudioResampler.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioprocessing/include/media/AudioResampler.h
\ No newline at end of file
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
deleted file mode 120000
index 9fad2b7..0000000
--- a/include/media/AudioSystem.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioSystem.h
\ No newline at end of file
diff --git a/include/media/AudioTimestamp.h b/include/media/AudioTimestamp.h
deleted file mode 120000
index b6b9278..0000000
--- a/include/media/AudioTimestamp.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioTimestamp.h
\ No newline at end of file
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
deleted file mode 120000
index 303bfcd..0000000
--- a/include/media/AudioTrack.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioTrack.h
\ No newline at end of file
diff --git a/include/media/AudioVolumeGroup.h b/include/media/AudioVolumeGroup.h
deleted file mode 120000
index d6f1c99..0000000
--- a/include/media/AudioVolumeGroup.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioVolumeGroup.h
\ No newline at end of file
diff --git a/include/media/BufferProviders.h b/include/media/BufferProviders.h
deleted file mode 120000
index 778e1d8..0000000
--- a/include/media/BufferProviders.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioprocessing/include/media/BufferProviders.h
\ No newline at end of file
diff --git a/include/media/BufferingSettings.h b/include/media/BufferingSettings.h
deleted file mode 120000
index 409203f..0000000
--- a/include/media/BufferingSettings.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/BufferingSettings.h
\ No newline at end of file
diff --git a/include/media/CharacterEncodingDetector.h b/include/media/CharacterEncodingDetector.h
deleted file mode 120000
index 2b28387..0000000
--- a/include/media/CharacterEncodingDetector.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/CharacterEncodingDetector.h
\ No newline at end of file
diff --git a/include/media/CounterMetric.h b/include/media/CounterMetric.h
deleted file mode 120000
index baba043..0000000
--- a/include/media/CounterMetric.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/CounterMetric.h
\ No newline at end of file
diff --git a/include/media/EventLog.h b/include/media/EventLog.h
deleted file mode 120000
index 9b2c4bf..0000000
--- a/include/media/EventLog.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/utils/include/mediautils/EventLog.h
\ No newline at end of file
diff --git a/include/media/EventMetric.h b/include/media/EventMetric.h
deleted file mode 120000
index 5707d9a..0000000
--- a/include/media/EventMetric.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/EventMetric.h
\ No newline at end of file
diff --git a/include/media/ExtendedAudioBufferProvider.h b/include/media/ExtendedAudioBufferProvider.h
deleted file mode 120000
index 99d3c13..0000000
--- a/include/media/ExtendedAudioBufferProvider.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/ExtendedAudioBufferProvider.h
\ No newline at end of file
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
deleted file mode 120000
index ef6f5be..0000000
--- a/include/media/IAudioFlinger.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/IAudioFlinger.h
\ No newline at end of file
diff --git a/include/media/IAudioFlingerClient.h b/include/media/IAudioFlingerClient.h
deleted file mode 120000
index dc481e8..0000000
--- a/include/media/IAudioFlingerClient.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/IAudioFlingerClient.h
\ No newline at end of file
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
deleted file mode 120000
index 08101fc..0000000
--- a/include/media/IAudioPolicyService.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/IAudioPolicyService.h
\ No newline at end of file
diff --git a/include/media/IAudioPolicyServiceClient.h b/include/media/IAudioPolicyServiceClient.h
deleted file mode 120000
index 0d4b3e7..0000000
--- a/include/media/IAudioPolicyServiceClient.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/IAudioPolicyServiceClient.h
\ No newline at end of file
diff --git a/include/media/IAudioTrack.h b/include/media/IAudioTrack.h
deleted file mode 120000
index 7bab1fd..0000000
--- a/include/media/IAudioTrack.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/IAudioTrack.h
\ No newline at end of file
diff --git a/include/media/IDataSource.h b/include/media/IDataSource.h
deleted file mode 120000
index 41cdd8b..0000000
--- a/include/media/IDataSource.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IDataSource.h
\ No newline at end of file
diff --git a/include/media/IEffect.h b/include/media/IEffect.h
deleted file mode 120000
index 2fb8bfb..0000000
--- a/include/media/IEffect.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/IEffect.h
\ No newline at end of file
diff --git a/include/media/IEffectClient.h b/include/media/IEffectClient.h
deleted file mode 120000
index b4e39cf..0000000
--- a/include/media/IEffectClient.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/IEffectClient.h
\ No newline at end of file
diff --git a/include/media/IMediaCodecList.h b/include/media/IMediaCodecList.h
deleted file mode 120000
index 2186312..0000000
--- a/include/media/IMediaCodecList.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaCodecList.h
\ No newline at end of file
diff --git a/include/media/IMediaDeathNotifier.h b/include/media/IMediaDeathNotifier.h
deleted file mode 120000
index ce3b8f0..0000000
--- a/include/media/IMediaDeathNotifier.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaDeathNotifier.h
\ No newline at end of file
diff --git a/include/media/IMediaExtractor.h b/include/media/IMediaExtractor.h
deleted file mode 120000
index 8708c8c..0000000
--- a/include/media/IMediaExtractor.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaExtractor.h
\ No newline at end of file
diff --git a/include/media/IMediaExtractorService.h b/include/media/IMediaExtractorService.h
deleted file mode 120000
index 3ee9f1e..0000000
--- a/include/media/IMediaExtractorService.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaExtractorService.h
\ No newline at end of file
diff --git a/include/media/IMediaHTTPConnection.h b/include/media/IMediaHTTPConnection.h
deleted file mode 120000
index 0970c15..0000000
--- a/include/media/IMediaHTTPConnection.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaHTTPConnection.h
\ No newline at end of file
diff --git a/include/media/IMediaHTTPService.h b/include/media/IMediaHTTPService.h
deleted file mode 120000
index b90c34f..0000000
--- a/include/media/IMediaHTTPService.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaHTTPService.h
\ No newline at end of file
diff --git a/include/media/IMediaLogService.h b/include/media/IMediaLogService.h
deleted file mode 120000
index 245a29d..0000000
--- a/include/media/IMediaLogService.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaLogService.h
\ No newline at end of file
diff --git a/include/media/IMediaMetadataRetriever.h b/include/media/IMediaMetadataRetriever.h
deleted file mode 120000
index 959df1a..0000000
--- a/include/media/IMediaMetadataRetriever.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaMetadataRetriever.h
\ No newline at end of file
diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h
deleted file mode 120000
index 9414d37..0000000
--- a/include/media/IMediaPlayer.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaPlayer.h
\ No newline at end of file
diff --git a/include/media/IMediaPlayerClient.h b/include/media/IMediaPlayerClient.h
deleted file mode 120000
index b6547ce..0000000
--- a/include/media/IMediaPlayerClient.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaPlayerClient.h
\ No newline at end of file
diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h
deleted file mode 120000
index 89c96cd..0000000
--- a/include/media/IMediaPlayerService.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaPlayerService.h
\ No newline at end of file
diff --git a/include/media/IMediaRecorder.h b/include/media/IMediaRecorder.h
deleted file mode 120000
index 57d192c..0000000
--- a/include/media/IMediaRecorder.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaRecorder.h
\ No newline at end of file
diff --git a/include/media/IMediaRecorderClient.h b/include/media/IMediaRecorderClient.h
deleted file mode 120000
index 89f4359..0000000
--- a/include/media/IMediaRecorderClient.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaRecorderClient.h
\ No newline at end of file
diff --git a/include/media/IMediaSource.h b/include/media/IMediaSource.h
deleted file mode 120000
index 1330ad3..0000000
--- a/include/media/IMediaSource.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaSource.h
\ No newline at end of file
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
deleted file mode 120000
index 6d5b375..0000000
--- a/include/media/IOMX.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IOMX.h
\ No newline at end of file
diff --git a/include/media/IRemoteDisplay.h b/include/media/IRemoteDisplay.h
deleted file mode 120000
index 4b0cf10..0000000
--- a/include/media/IRemoteDisplay.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IRemoteDisplay.h
\ No newline at end of file
diff --git a/include/media/IRemoteDisplayClient.h b/include/media/IRemoteDisplayClient.h
deleted file mode 120000
index f29a2ee..0000000
--- a/include/media/IRemoteDisplayClient.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IRemoteDisplayClient.h
\ No newline at end of file
diff --git a/include/media/IResourceManagerClient.h b/include/media/IResourceManagerClient.h
deleted file mode 120000
index 100af9b..0000000
--- a/include/media/IResourceManagerClient.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IResourceManagerClient.h
\ No newline at end of file
diff --git a/include/media/IResourceManagerService.h b/include/media/IResourceManagerService.h
deleted file mode 120000
index 9b389c6..0000000
--- a/include/media/IResourceManagerService.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IResourceManagerService.h
\ No newline at end of file
diff --git a/include/media/IStreamSource.h b/include/media/IStreamSource.h
deleted file mode 120000
index 4943af9..0000000
--- a/include/media/IStreamSource.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IStreamSource.h
\ No newline at end of file
diff --git a/include/media/JetPlayer.h b/include/media/JetPlayer.h
deleted file mode 120000
index 5483fda..0000000
--- a/include/media/JetPlayer.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/JetPlayer.h
\ No newline at end of file
diff --git a/include/media/LinearMap.h b/include/media/LinearMap.h
deleted file mode 120000
index 30d4ca8..0000000
--- a/include/media/LinearMap.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/LinearMap.h
\ No newline at end of file
diff --git a/include/media/MediaCodecBuffer.h b/include/media/MediaCodecBuffer.h
deleted file mode 120000
index 8c9aa76..0000000
--- a/include/media/MediaCodecBuffer.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/MediaCodecBuffer.h
\ No newline at end of file
diff --git a/include/media/MediaCodecInfo.h b/include/media/MediaCodecInfo.h
deleted file mode 120000
index ff44ce4..0000000
--- a/include/media/MediaCodecInfo.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/MediaCodecInfo.h
\ No newline at end of file
diff --git a/include/media/MediaMetadataRetrieverInterface.h b/include/media/MediaMetadataRetrieverInterface.h
deleted file mode 120000
index 1c53511..0000000
--- a/include/media/MediaMetadataRetrieverInterface.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/MediaMetadataRetrieverInterface.h
\ No newline at end of file
diff --git a/include/media/MediaProfiles.h b/include/media/MediaProfiles.h
deleted file mode 120000
index 651c6e6..0000000
--- a/include/media/MediaProfiles.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/MediaProfiles.h
\ No newline at end of file
diff --git a/include/media/MediaRecorderBase.h b/include/media/MediaRecorderBase.h
deleted file mode 120000
index e40f992..0000000
--- a/include/media/MediaRecorderBase.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/MediaRecorderBase.h
\ No newline at end of file
diff --git a/include/media/MediaResource.h b/include/media/MediaResource.h
deleted file mode 120000
index 91346aa..0000000
--- a/include/media/MediaResource.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/MediaResource.h
\ No newline at end of file
diff --git a/include/media/MediaResourcePolicy.h b/include/media/MediaResourcePolicy.h
deleted file mode 120000
index 5d165ee..0000000
--- a/include/media/MediaResourcePolicy.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/MediaResourcePolicy.h
\ No newline at end of file
diff --git a/include/media/MemoryLeakTrackUtil.h b/include/media/MemoryLeakTrackUtil.h
deleted file mode 120000
index 504173e..0000000
--- a/include/media/MemoryLeakTrackUtil.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/MemoryLeakTrackUtil.h
\ No newline at end of file
diff --git a/include/media/Metadata.h b/include/media/Metadata.h
deleted file mode 120000
index e421168..0000000
--- a/include/media/Metadata.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/Metadata.h
\ No newline at end of file
diff --git a/include/media/MidiDeviceInfo.h b/include/media/MidiDeviceInfo.h
deleted file mode 120000
index 95da7cf..0000000
--- a/include/media/MidiDeviceInfo.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/MidiDeviceInfo.h
\ No newline at end of file
diff --git a/include/media/MidiIoWrapper.h b/include/media/MidiIoWrapper.h
deleted file mode 120000
index 786ec3d..0000000
--- a/include/media/MidiIoWrapper.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/MidiIoWrapper.h
\ No newline at end of file
diff --git a/include/media/Modulo.h b/include/media/Modulo.h
deleted file mode 120000
index 989c4cb..0000000
--- a/include/media/Modulo.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/Modulo.h
\ No newline at end of file
diff --git a/include/media/OMXBuffer.h b/include/media/OMXBuffer.h
deleted file mode 120000
index 00db207..0000000
--- a/include/media/OMXBuffer.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/OMXBuffer.h
\ No newline at end of file
diff --git a/include/media/OMXFenceParcelable.h b/include/media/OMXFenceParcelable.h
deleted file mode 120000
index c4c1b0a..0000000
--- a/include/media/OMXFenceParcelable.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/OMXFenceParcelable.h
\ No newline at end of file
diff --git a/include/media/PluginLoader.h b/include/media/PluginLoader.h
deleted file mode 120000
index 9101735..0000000
--- a/include/media/PluginLoader.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/PluginLoader.h
\ No newline at end of file
diff --git a/include/media/PluginMetricsReporting.h b/include/media/PluginMetricsReporting.h
deleted file mode 120000
index 7d9a7a0..0000000
--- a/include/media/PluginMetricsReporting.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/PluginMetricsReporting.h
\ No newline at end of file
diff --git a/include/media/RecordBufferConverter.h b/include/media/RecordBufferConverter.h
deleted file mode 120000
index 2d7bc0c..0000000
--- a/include/media/RecordBufferConverter.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/RecordBufferConverter.h
\ No newline at end of file
diff --git a/include/media/RingBuffer.h b/include/media/RingBuffer.h
deleted file mode 120000
index 9af28d5..0000000
--- a/include/media/RingBuffer.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/RingBuffer.h
\ No newline at end of file
diff --git a/include/media/StringArray.h b/include/media/StringArray.h
deleted file mode 120000
index 616ce6c..0000000
--- a/include/media/StringArray.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/StringArray.h
\ No newline at end of file
diff --git a/include/media/TimeCheck.h b/include/media/TimeCheck.h
deleted file mode 120000
index 85e17f9..0000000
--- a/include/media/TimeCheck.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/utils/include/mediautils/TimeCheck.h
\ No newline at end of file
diff --git a/include/media/ToneGenerator.h b/include/media/ToneGenerator.h
deleted file mode 120000
index 33df0e3..0000000
--- a/include/media/ToneGenerator.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/ToneGenerator.h
\ No newline at end of file
diff --git a/include/media/TypeConverter.h b/include/media/TypeConverter.h
deleted file mode 120000
index 837af44..0000000
--- a/include/media/TypeConverter.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/TypeConverter.h
\ No newline at end of file
diff --git a/include/media/Visualizer.h b/include/media/Visualizer.h
deleted file mode 120000
index ed2ec15..0000000
--- a/include/media/Visualizer.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/Visualizer.h
\ No newline at end of file
diff --git a/include/media/convert.h b/include/media/convert.h
deleted file mode 120000
index cb0d00d..0000000
--- a/include/media/convert.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/convert.h
\ No newline at end of file
diff --git a/include/media/mediametadataretriever.h b/include/media/mediametadataretriever.h
deleted file mode 120000
index b401bab..0000000
--- a/include/media/mediametadataretriever.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/mediametadataretriever.h
\ No newline at end of file
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
deleted file mode 120000
index 06d537b..0000000
--- a/include/media/mediaplayer.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/mediaplayer.h
\ No newline at end of file
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
deleted file mode 120000
index a24deb3..0000000
--- a/include/media/mediarecorder.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/mediarecorder.h
\ No newline at end of file
diff --git a/include/media/mediascanner.h b/include/media/mediascanner.h
deleted file mode 120000
index 91479e0..0000000
--- a/include/media/mediascanner.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/mediascanner.h
\ No newline at end of file
diff --git a/include/media/nbaio/AudioBufferProviderSource.h b/include/media/nbaio/AudioBufferProviderSource.h
deleted file mode 120000
index 55841e7..0000000
--- a/include/media/nbaio/AudioBufferProviderSource.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../media/libnbaio/include/media/nbaio/AudioBufferProviderSource.h
\ No newline at end of file
diff --git a/include/media/nbaio/AudioStreamInSource.h b/include/media/nbaio/AudioStreamInSource.h
deleted file mode 120000
index f5bcc76..0000000
--- a/include/media/nbaio/AudioStreamInSource.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../media/libnbaio/include/media/nbaio/AudioStreamInSource.h
\ No newline at end of file
diff --git a/include/media/nbaio/LibsndfileSink.h b/include/media/nbaio/LibsndfileSink.h
deleted file mode 120000
index 8a13b6c..0000000
--- a/include/media/nbaio/LibsndfileSink.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../media/libnbaio/include/media/nbaio/LibsndfileSink.h
\ No newline at end of file
diff --git a/include/media/nbaio/LibsndfileSource.h b/include/media/nbaio/LibsndfileSource.h
deleted file mode 120000
index 2750fde..0000000
--- a/include/media/nbaio/LibsndfileSource.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../media/libnbaio/include/media/nbaio/LibsndfileSource.h
\ No newline at end of file
diff --git a/include/media/nbaio/MonoPipe.h b/include/media/nbaio/MonoPipe.h
deleted file mode 120000
index 4ea43be..0000000
--- a/include/media/nbaio/MonoPipe.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../media/libnbaio/include_mono/media/nbaio/MonoPipe.h
\ No newline at end of file
diff --git a/include/media/nbaio/MonoPipeReader.h b/include/media/nbaio/MonoPipeReader.h
deleted file mode 120000
index 30f426c..0000000
--- a/include/media/nbaio/MonoPipeReader.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../media/libnbaio/include_mono/media/nbaio/MonoPipeReader.h
\ No newline at end of file
diff --git a/include/media/nbaio/Pipe.h b/include/media/nbaio/Pipe.h
deleted file mode 120000
index a4bbbc9..0000000
--- a/include/media/nbaio/Pipe.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../media/libnbaio/include/media/nbaio/Pipe.h
\ No newline at end of file
diff --git a/include/media/nbaio/PipeReader.h b/include/media/nbaio/PipeReader.h
deleted file mode 120000
index 64b21cf..0000000
--- a/include/media/nbaio/PipeReader.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../media/libnbaio/include/media/nbaio/PipeReader.h
\ No newline at end of file
diff --git a/include/media/nbaio/SourceAudioBufferProvider.h b/include/media/nbaio/SourceAudioBufferProvider.h
deleted file mode 120000
index 74a3b06..0000000
--- a/include/media/nbaio/SourceAudioBufferProvider.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../media/libnbaio/include/media/nbaio/SourceAudioBufferProvider.h
\ No newline at end of file
diff --git a/include/media/nblog/NBLog.h b/include/media/nblog/NBLog.h
deleted file mode 120000
index 3cc366c..0000000
--- a/include/media/nblog/NBLog.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../media/libnblog/include/media/nblog/NBLog.h
\ No newline at end of file
diff --git a/include/media/nblog/PerformanceAnalysis.h b/include/media/nblog/PerformanceAnalysis.h
deleted file mode 120000
index 6ead3bc..0000000
--- a/include/media/nblog/PerformanceAnalysis.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../media/libnblog/include/media/nblog/PerformanceAnalysis.h
\ No newline at end of file
diff --git a/include/media/nblog/ReportPerformance.h b/include/media/nblog/ReportPerformance.h
deleted file mode 120000
index e9b8e80..0000000
--- a/include/media/nblog/ReportPerformance.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../media/libnblog/include/media/nblog/ReportPerformance.h
\ No newline at end of file
diff --git a/include/mediadrm/CryptoHal.h b/include/mediadrm/CryptoHal.h
deleted file mode 120000
index 92f3137..0000000
--- a/include/mediadrm/CryptoHal.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/CryptoHal.h
\ No newline at end of file
diff --git a/include/mediadrm/DrmHal.h b/include/mediadrm/DrmHal.h
deleted file mode 120000
index 17bb667..0000000
--- a/include/mediadrm/DrmHal.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/DrmHal.h
\ No newline at end of file
diff --git a/include/mediadrm/DrmMetrics.h b/include/mediadrm/DrmMetrics.h
deleted file mode 120000
index abc966b..0000000
--- a/include/mediadrm/DrmMetrics.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/DrmMetrics.h
\ No newline at end of file
diff --git a/include/mediadrm/DrmPluginPath.h b/include/mediadrm/DrmPluginPath.h
deleted file mode 120000
index 9e05194..0000000
--- a/include/mediadrm/DrmPluginPath.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/DrmPluginPath.h
\ No newline at end of file
diff --git a/include/mediadrm/DrmSessionClientInterface.h b/include/mediadrm/DrmSessionClientInterface.h
deleted file mode 120000
index f4e3211..0000000
--- a/include/mediadrm/DrmSessionClientInterface.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/DrmSessionClientInterface.h
\ No newline at end of file
diff --git a/include/mediadrm/DrmSessionManager.h b/include/mediadrm/DrmSessionManager.h
deleted file mode 120000
index f0a47bf..0000000
--- a/include/mediadrm/DrmSessionManager.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/DrmSessionManager.h
\ No newline at end of file
diff --git a/include/mediadrm/ICrypto.h b/include/mediadrm/ICrypto.h
deleted file mode 120000
index b250e07..0000000
--- a/include/mediadrm/ICrypto.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/ICrypto.h
\ No newline at end of file
diff --git a/include/mediadrm/IDrm.h b/include/mediadrm/IDrm.h
deleted file mode 120000
index 841bb1b..0000000
--- a/include/mediadrm/IDrm.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IDrm.h
\ No newline at end of file
diff --git a/include/mediadrm/IDrmClient.h b/include/mediadrm/IDrmClient.h
deleted file mode 120000
index 10aa5c0..0000000
--- a/include/mediadrm/IDrmClient.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IDrmClient.h
\ No newline at end of file
diff --git a/include/mediadrm/IMediaDrmService.h b/include/mediadrm/IMediaDrmService.h
deleted file mode 120000
index f3c260f..0000000
--- a/include/mediadrm/IMediaDrmService.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaDrmService.h
\ No newline at end of file
diff --git a/include/mediadrm/SharedLibrary.h b/include/mediadrm/SharedLibrary.h
deleted file mode 120000
index 9f8f5a4..0000000
--- a/include/mediadrm/SharedLibrary.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/SharedLibrary.h
\ No newline at end of file
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 1b1f149..8aec80d 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -575,7 +575,7 @@
class AudioTrackServerProxy : public ServerProxy {
public:
AudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
- size_t frameSize, bool clientInServer = false, uint32_t sampleRate = 0)
+ size_t frameSize, bool clientInServer, uint32_t sampleRate)
: ServerProxy(cblk, buffers, frameCount, frameSize, true /*isOut*/, clientInServer),
mPlaybackRateObserver(&cblk->mPlaybackRateQueue),
mUnderrunCount(0), mUnderrunning(false), mDrained(true) {
@@ -651,7 +651,7 @@
class StaticAudioTrackServerProxy : public AudioTrackServerProxy {
public:
StaticAudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
- size_t frameSize);
+ size_t frameSize, uint32_t sampleRate);
protected:
virtual ~StaticAudioTrackServerProxy() { }
diff --git a/media/audioserver/audioserver.rc b/media/audioserver/audioserver.rc
index 3f3ef69..5484613 100644
--- a/media/audioserver/audioserver.rc
+++ b/media/audioserver/audioserver.rc
@@ -6,10 +6,10 @@
capabilities BLOCK_SUSPEND
ioprio rt 4
writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
- onrestart restart vendor.audio-hal-2-0
+ onrestart restart vendor.audio-hal
onrestart restart vendor.audio-hal-4-0-msd
- # Keep the original service name for backward compatibility when upgrading
- # O-MR1 devices with framework-only.
+ # Keep the original service names for backward compatibility
+ onrestart restart vendor.audio-hal-2-0
onrestart restart audio-hal-2-0
on property:vts.native_server.on=1
diff --git a/media/bufferpool/1.0/AccessorImpl.cpp b/media/bufferpool/1.0/AccessorImpl.cpp
index 09006ca..0d7e92f 100644
--- a/media/bufferpool/1.0/AccessorImpl.cpp
+++ b/media/bufferpool/1.0/AccessorImpl.cpp
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-#define LOG_TAG "BufferPoolAccessor"
+#define LOG_TAG "BufferPoolAccessor1.0"
//#define LOG_NDEBUG 0
#include <sys/types.h>
+#include <stdint.h>
#include <time.h>
#include <unistd.h>
#include <utils/Log.h>
@@ -127,7 +128,6 @@
return false;
}
-int32_t Accessor::Impl::sPid = getpid();
uint32_t Accessor::Impl::sSeqId = time(nullptr);
Accessor::Impl::Impl(
@@ -145,14 +145,19 @@
{
std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
if (newConnection) {
- ConnectionId id = (int64_t)sPid << 32 | sSeqId;
+ int32_t pid = getpid();
+ ConnectionId id = (int64_t)pid << 32 | sSeqId;
status = mBufferPool.mObserver.open(id, fmqDescPtr);
if (status == ResultStatus::OK) {
newConnection->initialize(accessor, id);
*connection = newConnection;
*pConnectionId = id;
mBufferPool.mConnectionIds.insert(id);
- ++sSeqId;
+ if (sSeqId == UINT32_MAX) {
+ sSeqId = 0;
+ } else {
+ ++sSeqId;
+ }
}
}
mBufferPool.processStatusMessages();
diff --git a/media/bufferpool/1.0/AccessorImpl.h b/media/bufferpool/1.0/AccessorImpl.h
index 84cb685..a09cbe2 100644
--- a/media/bufferpool/1.0/AccessorImpl.h
+++ b/media/bufferpool/1.0/AccessorImpl.h
@@ -61,7 +61,6 @@
// ConnectionId = pid : (timestamp_created + seqId)
// in order to guarantee uniqueness for each connection
static uint32_t sSeqId;
- static int32_t sPid;
const std::shared_ptr<BufferPoolAllocator> mAllocator;
diff --git a/media/bufferpool/2.0/AccessorImpl.cpp b/media/bufferpool/2.0/AccessorImpl.cpp
index 929a20e..84ce172 100644
--- a/media/bufferpool/2.0/AccessorImpl.cpp
+++ b/media/bufferpool/2.0/AccessorImpl.cpp
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-#define LOG_TAG "BufferPoolAccessor"
+#define LOG_TAG "BufferPoolAccessor2.0"
//#define LOG_NDEBUG 0
#include <sys/types.h>
+#include <stdint.h>
#include <time.h>
#include <unistd.h>
#include <utils/Log.h>
@@ -134,7 +135,6 @@
return false;
}
-int32_t Accessor::Impl::sPid = getpid();
uint32_t Accessor::Impl::sSeqId = time(nullptr);
Accessor::Impl::Impl(
@@ -156,7 +156,8 @@
{
std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
if (newConnection) {
- ConnectionId id = (int64_t)sPid << 32 | sSeqId;
+ int32_t pid = getpid();
+ ConnectionId id = (int64_t)pid << 32 | sSeqId;
status = mBufferPool.mObserver.open(id, statusDescPtr);
if (status == ResultStatus::OK) {
newConnection->initialize(accessor, id);
@@ -166,7 +167,11 @@
mBufferPool.mConnectionIds.insert(id);
mBufferPool.mInvalidationChannel.getDesc(invDescPtr);
mBufferPool.mInvalidation.onConnect(id, observer);
- ++sSeqId;
+ if (sSeqId == UINT32_MAX) {
+ sSeqId = 0;
+ } else {
+ ++sSeqId;
+ }
}
}
diff --git a/media/bufferpool/2.0/AccessorImpl.h b/media/bufferpool/2.0/AccessorImpl.h
index 807e0f1..9888be5 100644
--- a/media/bufferpool/2.0/AccessorImpl.h
+++ b/media/bufferpool/2.0/AccessorImpl.h
@@ -75,7 +75,6 @@
// ConnectionId = pid : (timestamp_created + seqId)
// in order to guarantee uniqueness for each connection
static uint32_t sSeqId;
- static int32_t sPid;
const std::shared_ptr<BufferPoolAllocator> mAllocator;
diff --git a/media/codec2/components/aac/C2SoftAacEnc.cpp b/media/codec2/components/aac/C2SoftAacEnc.cpp
index a8f39d5..be52a1d 100644
--- a/media/codec2/components/aac/C2SoftAacEnc.cpp
+++ b/media/codec2/components/aac/C2SoftAacEnc.cpp
@@ -521,16 +521,14 @@
mInputSize += outargs.numInSamples * sizeof(int16_t);
}
- if (outargs.numInSamples > 0) {
- inBuffer[0] = (int16_t *)inBuffer[0] + outargs.numInSamples;
- inBufferSize[0] -= outargs.numInSamples * sizeof(int16_t);
- inargs.numInSamples -= outargs.numInSamples;
- }
-
if (inBuffer[0] == mRemainder) {
inBuffer[0] = const_cast<uint8_t *>(data);
inBufferSize[0] = capacity;
inargs.numInSamples = capacity / sizeof(int16_t);
+ } else if (outargs.numInSamples > 0) {
+ inBuffer[0] = (int16_t *)inBuffer[0] + outargs.numInSamples;
+ inBufferSize[0] -= outargs.numInSamples * sizeof(int16_t);
+ inargs.numInSamples -= outargs.numInSamples;
}
}
ALOGV("encoderErr = %d mInputSize = %zu "
diff --git a/media/codec2/components/cmds/Android.bp b/media/codec2/components/cmds/Android.bp
index 35f689e..a081e28 100644
--- a/media/codec2/components/cmds/Android.bp
+++ b/media/codec2/components/cmds/Android.bp
@@ -9,10 +9,15 @@
include_dirs: [
],
+ header_libs: [
+ "libmediadrm_headers",
+ ],
+
shared_libs: [
"libbase",
"libbinder",
"libcutils",
+ "libdatasource",
"libgui",
"liblog",
"libstagefright",
diff --git a/media/codec2/components/cmds/codec2.cpp b/media/codec2/components/cmds/codec2.cpp
index f2cf545..38eaf88 100644
--- a/media/codec2/components/cmds/codec2.cpp
+++ b/media/codec2/components/cmds/codec2.cpp
@@ -30,15 +30,15 @@
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
+#include <datasource/DataSourceFactory.h>
#include <media/DataSource.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/IMediaHTTPService.h>
#include <media/MediaSource.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AUtils.h>
-#include <media/stagefright/DataSourceFactory.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaExtractorFactory.h>
@@ -418,7 +418,7 @@
const char *filename = argv[k];
sp<DataSource> dataSource =
- DataSourceFactory::CreateFromURI(nullptr /* httpService */, filename);
+ DataSourceFactory::getInstance()->CreateFromURI(nullptr /* httpService */, filename);
if (strncasecmp(filename, "sine:", 5) && dataSource == nullptr) {
fprintf(stderr, "Unable to create data source.\n");
diff --git a/media/codec2/components/hevc/C2SoftHevcEnc.cpp b/media/codec2/components/hevc/C2SoftHevcEnc.cpp
index b129b1b..19ccbf9 100644
--- a/media/codec2/components/hevc/C2SoftHevcEnc.cpp
+++ b/media/codec2/components/hevc/C2SoftHevcEnc.cpp
@@ -42,6 +42,36 @@
constexpr char COMPONENT_NAME[] = "c2.android.hevc.encoder";
+void ParseGop(
+ const C2StreamGopTuning::output &gop,
+ uint32_t *syncInterval, uint32_t *iInterval, uint32_t *maxBframes) {
+ uint32_t syncInt = 1;
+ uint32_t iInt = 1;
+ for (size_t i = 0; i < gop.flexCount(); ++i) {
+ const C2GopLayerStruct &layer = gop.m.values[i];
+ if (layer.count == UINT32_MAX) {
+ syncInt = 0;
+ } else if (syncInt <= UINT32_MAX / (layer.count + 1)) {
+ syncInt *= (layer.count + 1);
+ }
+ if ((layer.type_ & I_FRAME) == 0) {
+ if (layer.count == UINT32_MAX) {
+ iInt = 0;
+ } else if (iInt <= UINT32_MAX / (layer.count + 1)) {
+ iInt *= (layer.count + 1);
+ }
+ }
+ if (layer.type_ == C2Config::picture_type_t(P_FRAME | B_FRAME) && maxBframes) {
+ *maxBframes = layer.count;
+ }
+ }
+ if (syncInterval) {
+ *syncInterval = syncInt;
+ }
+ if (iInterval) {
+ *iInterval = iInt;
+ }
+}
} // namepsace
class C2SoftHevcEnc::IntfImpl : public SimpleInterface<void>::BaseParams {
@@ -60,13 +90,21 @@
setDerivedInstance(this);
addParameter(
+ DefineParam(mGop, C2_PARAMKEY_GOP)
+ .withDefault(C2StreamGopTuning::output::AllocShared(
+ 0 /* flexCount */, 0u /* stream */))
+ .withFields({C2F(mGop, m.values[0].type_).any(),
+ C2F(mGop, m.values[0].count).any()})
+ .withSetter(GopSetter)
+ .build());
+
+ addParameter(
DefineParam(mActualInputDelay, C2_PARAMKEY_INPUT_DELAY)
.withDefault(new C2PortActualDelayTuning::input(
DEFAULT_B_FRAMES + DEFAULT_RC_LOOKAHEAD))
.withFields({C2F(mActualInputDelay, value).inRange(
0, MAX_B_FRAMES + MAX_RC_LOOKAHEAD)})
- .withSetter(
- Setter<decltype(*mActualInputDelay)>::StrictValueWithNoDeps)
+ .calculatedAs(InputDelaySetter, mGop)
.build());
addParameter(
@@ -172,6 +210,17 @@
.build());
}
+ static C2R InputDelaySetter(
+ bool mayBlock,
+ C2P<C2PortActualDelayTuning::input> &me,
+ const C2P<C2StreamGopTuning::output> &gop) {
+ (void)mayBlock;
+ uint32_t maxBframes = 0;
+ ParseGop(gop.v, nullptr, nullptr, &maxBframes);
+ me.set().value = maxBframes + DEFAULT_RC_LOOKAHEAD;
+ return C2R::Ok();
+ }
+
static C2R BitrateSetter(bool mayBlock,
C2P<C2StreamBitrateInfo::output>& me) {
(void)mayBlock;
@@ -270,6 +319,18 @@
return C2R::Ok();
}
+ static C2R GopSetter(bool mayBlock, C2P<C2StreamGopTuning::output> &me) {
+ (void)mayBlock;
+ for (size_t i = 0; i < me.v.flexCount(); ++i) {
+ const C2GopLayerStruct &layer = me.v.m.values[0];
+ if (layer.type_ == C2Config::picture_type_t(P_FRAME | B_FRAME)
+ && layer.count > MAX_B_FRAMES) {
+ me.set().m.values[i].count = MAX_B_FRAMES;
+ }
+ }
+ return C2R::Ok();
+ }
+
UWORD32 getProfile_l() const {
switch (mProfileLevel->profile) {
case PROFILE_HEVC_MAIN: [[fallthrough]];
@@ -338,6 +399,9 @@
std::shared_ptr<C2StreamQualityTuning::output> getQuality_l() const {
return mQuality;
}
+ std::shared_ptr<C2StreamGopTuning::output> getGop_l() const {
+ return mGop;
+ }
private:
std::shared_ptr<C2StreamUsageTuning::input> mUsage;
@@ -350,6 +414,7 @@
std::shared_ptr<C2StreamQualityTuning::output> mQuality;
std::shared_ptr<C2StreamProfileLevelInfo::output> mProfileLevel;
std::shared_ptr<C2StreamSyncFrameIntervalTuning::output> mSyncFramePeriod;
+ std::shared_ptr<C2StreamGopTuning::output> mGop;
};
static size_t GetCPUCoreCount() {
@@ -449,7 +514,25 @@
ALOGE("HEVC default init failed : 0x%x", err);
return C2_CORRUPTED;
}
-
+ mBframes = 0;
+ if (mGop && mGop->flexCount() > 0) {
+ uint32_t syncInterval = 1;
+ uint32_t iInterval = 1;
+ uint32_t maxBframes = 0;
+ ParseGop(*mGop, &syncInterval, &iInterval, &maxBframes);
+ if (syncInterval > 0) {
+ ALOGD("Updating IDR interval from GOP: old %u new %u", mIDRInterval, syncInterval);
+ mIDRInterval = syncInterval;
+ }
+ if (iInterval > 0) {
+ ALOGD("Updating I interval from GOP: old %u new %u", mIInterval, iInterval);
+ mIInterval = iInterval;
+ }
+ if (mBframes != maxBframes) {
+ ALOGD("Updating max B frames from GOP: old %u new %u", mBframes, maxBframes);
+ mBframes = maxBframes;
+ }
+ }
// update configuration
mEncParams.s_src_prms.i4_width = mSize->width;
mEncParams.s_src_prms.i4_height = mSize->height;
@@ -463,12 +546,20 @@
mBitrate->value << 1;
mEncParams.s_tgt_lyr_prms.as_tgt_params[0].i4_codec_level = mHevcEncLevel;
mEncParams.s_coding_tools_prms.i4_max_i_open_gop_period = mIDRInterval;
- mEncParams.s_coding_tools_prms.i4_max_cra_open_gop_period = mIDRInterval;
+ mEncParams.s_coding_tools_prms.i4_max_cra_open_gop_period = mIInterval;
mIvVideoColorFormat = IV_YUV_420P;
mEncParams.s_multi_thrd_prms.i4_max_num_cores = mNumCores;
mEncParams.s_out_strm_prms.i4_codec_profile = mHevcEncProfile;
mEncParams.s_lap_prms.i4_rc_look_ahead_pics = DEFAULT_RC_LOOKAHEAD;
- mEncParams.s_coding_tools_prms.i4_max_temporal_layers = DEFAULT_B_FRAMES;
+ if (mBframes == 0) {
+ mEncParams.s_coding_tools_prms.i4_max_temporal_layers = 0;
+ } else if (mBframes <= 2) {
+ mEncParams.s_coding_tools_prms.i4_max_temporal_layers = 1;
+ } else if (mBframes <= 6) {
+ mEncParams.s_coding_tools_prms.i4_max_temporal_layers = 2;
+ } else {
+ mEncParams.s_coding_tools_prms.i4_max_temporal_layers = 3;
+ }
switch (mBitrateMode->value) {
case C2Config::BITRATE_IGNORE:
@@ -523,6 +614,7 @@
c2_status_t C2SoftHevcEnc::initEncoder() {
CHECK(!mCodecCtx);
+
{
IntfImpl::Lock lock = mIntf->lock();
mSize = mIntf->getSize_l();
@@ -532,8 +624,10 @@
mHevcEncProfile = mIntf->getProfile_l();
mHevcEncLevel = mIntf->getLevel_l();
mIDRInterval = mIntf->getSyncFramePeriod_l();
+ mIInterval = mIntf->getSyncFramePeriod_l();
mComplexity = mIntf->getComplexity_l();
mQuality = mIntf->getQuality_l();
+ mGop = mIntf->getGop_l();
}
c2_status_t status = initEncParams();
diff --git a/media/codec2/components/hevc/C2SoftHevcEnc.h b/media/codec2/components/hevc/C2SoftHevcEnc.h
index f2c7642..140b4a9 100644
--- a/media/codec2/components/hevc/C2SoftHevcEnc.h
+++ b/media/codec2/components/hevc/C2SoftHevcEnc.h
@@ -67,6 +67,8 @@
ihevce_static_cfg_params_t mEncParams;
size_t mNumCores;
UWORD32 mIDRInterval;
+ UWORD32 mIInterval;
+ UWORD32 mBframes;
IV_COLOR_FORMAT_T mIvVideoColorFormat;
UWORD32 mHevcEncProfile;
UWORD32 mHevcEncLevel;
@@ -85,7 +87,7 @@
std::shared_ptr<C2StreamBitrateModeTuning::output> mBitrateMode;
std::shared_ptr<C2StreamComplexityTuning::output> mComplexity;
std::shared_ptr<C2StreamQualityTuning::output> mQuality;
-
+ std::shared_ptr<C2StreamGopTuning::output> mGop;
#ifdef FILE_DUMP_ENABLE
char mInFile[200];
char mOutFile[200];
diff --git a/media/codec2/core/include/C2Config.h b/media/codec2/core/include/C2Config.h
index 3820f90..f9eb2fa 100644
--- a/media/codec2/core/include/C2Config.h
+++ b/media/codec2/core/include/C2Config.h
@@ -243,6 +243,9 @@
kParamIndexTimestampGapAdjustment, // input-surface, struct
kParamIndexSurfaceAllocator, // u32
+
+ // low latency mode for decoders
+ kParamIndexLowLatencyMode, // bool
};
}
@@ -521,6 +524,7 @@
PROFILE_DV_HE_07 = _C2_PL_DV_BASE + 7, ///< Dolby Vision dvhe.07 profile
PROFILE_DV_HE_08 = _C2_PL_DV_BASE + 8, ///< Dolby Vision dvhe.08 profile
PROFILE_DV_AV_09 = _C2_PL_DV_BASE + 9, ///< Dolby Vision dvav.09 profile
+ PROFILE_DV_AV1_10 = _C2_PL_DV_BASE + 10, ///< Dolby Vision dav1.10 profile
// AV1 profiles
PROFILE_AV1_0 = _C2_PL_AV1_BASE, ///< AV1 Profile 0 (4:2:0, 8 to 10 bit)
@@ -804,6 +808,15 @@
constexpr char C2_PARAMKEY_PIPELINE_DELAY[] = "algo.delay";
/**
+ * Enable/disable low latency decoding mode.
+ * If true, low latency decoding mode is enabled, and the decoder doesn't hold input and output
+ * data more than required by the codec standards.
+ */
+typedef C2GlobalParam<C2Tuning, C2EasyBoolValue, kParamIndexLowLatencyMode>
+ C2GlobalLowLatencyModeTuning;
+constexpr char C2_PARAMKEY_LOW_LATENCY_MODE[] = "algo.low-latency";
+
+/**
* Reference characteristics.
*
* The component may hold onto input and output buffers even after completing the corresponding
diff --git a/media/codec2/hidl/client/client.cpp b/media/codec2/hidl/client/client.cpp
index c620bad..c747190 100644
--- a/media/codec2/hidl/client/client.cpp
+++ b/media/codec2/hidl/client/client.cpp
@@ -125,6 +125,9 @@
if (!mClient) {
mClient = Codec2Client::_CreateFromIndex(mIndex);
}
+ CHECK(mClient) << "Failed to create Codec2Client to service \""
+ << GetServiceNames()[mIndex] << "\". (Index = "
+ << mIndex << ").";
return mClient;
}
@@ -832,6 +835,7 @@
c2_status_t Codec2Client::ForAllServices(
const std::string &key,
+ size_t numberOfAttempts,
std::function<c2_status_t(const std::shared_ptr<Codec2Client>&)>
predicate) {
c2_status_t status = C2_NO_INIT; // no IComponentStores present
@@ -860,23 +864,31 @@
for (size_t index : indices) {
Cache& cache = Cache::List()[index];
- std::shared_ptr<Codec2Client> client{cache.getClient()};
- if (client) {
+ for (size_t tries = numberOfAttempts; tries > 0; --tries) {
+ std::shared_ptr<Codec2Client> client{cache.getClient()};
status = predicate(client);
if (status == C2_OK) {
std::scoped_lock lock{key2IndexMutex};
key2Index[key] = index; // update last known client index
return C2_OK;
+ } else if (status == C2_TRANSACTION_FAILED) {
+ LOG(WARNING) << "\"" << key << "\" failed for service \""
+ << client->getName()
+ << "\" due to transaction failure. "
+ << "(Service may have crashed.)"
+ << (tries > 1 ? " Retrying..." : "");
+ cache.invalidate();
+ continue;
}
- }
- if (wasMapped) {
- LOG(INFO) << "Could not find \"" << key << "\""
- " in the last instance. Retrying...";
- wasMapped = false;
- cache.invalidate();
+ if (wasMapped) {
+ LOG(INFO) << "\"" << key << "\" became invalid in service \""
+ << client->getName() << "\". Retrying...";
+ wasMapped = false;
+ }
+ break;
}
}
- return status; // return the last status from a valid client
+ return status; // return the last status from a valid client
}
std::shared_ptr<Codec2Client::Component>
@@ -885,35 +897,37 @@
const std::shared_ptr<Listener>& listener,
std::shared_ptr<Codec2Client>* owner,
size_t numberOfAttempts) {
- while (true) {
- std::shared_ptr<Component> component;
- c2_status_t status = ForAllServices(
- componentName,
- [owner, &component, componentName, &listener](
- const std::shared_ptr<Codec2Client> &client)
- -> c2_status_t {
- c2_status_t status = client->createComponent(componentName,
- listener,
- &component);
- if (status == C2_OK) {
- if (owner) {
- *owner = client;
- }
- } else if (status != C2_NOT_FOUND) {
- LOG(DEBUG) << "IComponentStore("
- << client->getServiceName()
- << ")::createComponent(\"" << componentName
- << "\") returned status = "
- << status << ".";
+ std::string key{"create:"};
+ key.append(componentName);
+ std::shared_ptr<Component> component;
+ c2_status_t status = ForAllServices(
+ key,
+ numberOfAttempts,
+ [owner, &component, componentName, &listener](
+ const std::shared_ptr<Codec2Client> &client)
+ -> c2_status_t {
+ c2_status_t status = client->createComponent(componentName,
+ listener,
+ &component);
+ if (status == C2_OK) {
+ if (owner) {
+ *owner = client;
}
- return status;
- });
- if (numberOfAttempts > 0 && status == C2_TRANSACTION_FAILED) {
- --numberOfAttempts;
- continue;
- }
- return component;
+ } else if (status != C2_NOT_FOUND) {
+ LOG(DEBUG) << "IComponentStore("
+ << client->getServiceName()
+ << ")::createComponent(\"" << componentName
+ << "\") returned status = "
+ << status << ".";
+ }
+ return status;
+ });
+ if (status != C2_OK) {
+ LOG(DEBUG) << "Failed to create component \"" << componentName
+ << "\" from all known services. "
+ "Last returned status = " << status << ".";
}
+ return component;
}
std::shared_ptr<Codec2Client::Interface>
@@ -921,34 +935,36 @@
const char* interfaceName,
std::shared_ptr<Codec2Client>* owner,
size_t numberOfAttempts) {
- while (true) {
- std::shared_ptr<Interface> interface;
- c2_status_t status = ForAllServices(
- interfaceName,
- [owner, &interface, interfaceName](
- const std::shared_ptr<Codec2Client> &client)
- -> c2_status_t {
- c2_status_t status = client->createInterface(interfaceName,
- &interface);
- if (status == C2_OK) {
- if (owner) {
- *owner = client;
- }
- } else if (status != C2_NOT_FOUND) {
- LOG(DEBUG) << "IComponentStore("
- << client->getServiceName()
- << ")::createInterface(\"" << interfaceName
- << "\") returned status = "
- << status << ".";
+ std::string key{"create:"};
+ key.append(interfaceName);
+ std::shared_ptr<Interface> interface;
+ c2_status_t status = ForAllServices(
+ key,
+ numberOfAttempts,
+ [owner, &interface, interfaceName](
+ const std::shared_ptr<Codec2Client> &client)
+ -> c2_status_t {
+ c2_status_t status = client->createInterface(interfaceName,
+ &interface);
+ if (status == C2_OK) {
+ if (owner) {
+ *owner = client;
}
- return status;
- });
- if (numberOfAttempts > 0 && status == C2_TRANSACTION_FAILED) {
- --numberOfAttempts;
- continue;
- }
- return interface;
+ } else if (status != C2_NOT_FOUND) {
+ LOG(DEBUG) << "IComponentStore("
+ << client->getServiceName()
+ << ")::createInterface(\"" << interfaceName
+ << "\") returned status = "
+ << status << ".";
+ }
+ return status;
+ });
+ if (status != C2_OK) {
+ LOG(DEBUG) << "Failed to create interface \"" << interfaceName
+ << "\" from all known services. "
+ "Last returned status = " << status << ".";
}
+ return interface;
}
std::vector<C2Component::Traits> const& Codec2Client::ListComponents() {
diff --git a/media/codec2/hidl/client/include/codec2/hidl/client.h b/media/codec2/hidl/client/include/codec2/hidl/client.h
index 848901d..c37407f 100644
--- a/media/codec2/hidl/client/include/codec2/hidl/client.h
+++ b/media/codec2/hidl/client/include/codec2/hidl/client.h
@@ -208,11 +208,25 @@
protected:
sp<Base> mBase;
- // Finds the first store where the predicate returns OK, and returns the last
- // predicate result. Uses key to remember the last store found, and if cached,
- // it tries that store before trying all stores (one retry).
+ // Finds the first store where the predicate returns C2_OK and returns the
+ // last predicate result. The predicate will be tried on all stores. The
+ // function will return C2_OK the first time the predicate returns C2_OK,
+ // or it will return the value from the last time that predicate is tried.
+ // (The latter case corresponds to a failure on every store.) The order of
+ // the stores to try is the same as the return value of GetServiceNames().
+ //
+ // key is used to remember the last store with which the predicate last
+ // succeeded. If the last successful store is cached, it will be tried
+ // first before all the stores are tried. Note that the last successful
+ // store will be tried twice---first before all the stores, and another time
+ // with all the stores.
+ //
+ // If an attempt to evaluate the predicate results in a transaction failure,
+ // repeated attempts will be made until the predicate returns without a
+ // transaction failure or numberOfAttempts attempts have been made.
static c2_status_t ForAllServices(
const std::string& key,
+ size_t numberOfAttempts,
std::function<c2_status_t(std::shared_ptr<Codec2Client> const&)>
predicate);
diff --git a/media/codec2/sfplugin/Android.bp b/media/codec2/sfplugin/Android.bp
index 591088e..e174751 100644
--- a/media/codec2/sfplugin/Android.bp
+++ b/media/codec2/sfplugin/Android.bp
@@ -9,7 +9,6 @@
"CCodecConfig.cpp",
"Codec2Buffer.cpp",
"Codec2InfoBuilder.cpp",
- "Omx2IGraphicBufferSource.cpp",
"PipelineWatcher.cpp",
"ReflectedParamUpdater.cpp",
"SkipCutBuffer.cpp",
@@ -22,6 +21,7 @@
header_libs: [
"libcodec2_internal",
+ "libmediadrm_headers",
"media_ndk_headers",
],
@@ -38,7 +38,7 @@
"libhidlallocatorutils",
"libhidlbase",
"liblog",
- "libmedia",
+ "libmedia_codeclist",
"libmedia_omx",
"libsfplugin_ccodec_utils",
"libstagefright_bufferqueue_helper",
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 4a31953..1cbbbb8 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -26,7 +26,6 @@
#include <C2ParamInternal.h>
#include <C2PlatformSupport.h>
-#include <android/IGraphicBufferSource.h>
#include <android/IOMXBufferSource.h>
#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
#include <android/hardware/media/omx/1.0/IOmx.h>
@@ -35,8 +34,11 @@
#include <gui/IGraphicBufferProducer.h>
#include <gui/Surface.h>
#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
-#include <media/omx/1.0/WGraphicBufferSource.h>
+#include <media/omx/1.0/WOmxNode.h>
+#include <media/openmax/OMX_Core.h>
#include <media/openmax/OMX_IndexExt.h>
+#include <media/stagefright/omx/1.0/WGraphicBufferSource.h>
+#include <media/stagefright/omx/OmxGraphicBufferSource.h>
#include <media/stagefright/BufferProducerWrapper.h>
#include <media/stagefright/MediaCodecConstants.h>
#include <media/stagefright/PersistentSurface.h>
@@ -45,7 +47,6 @@
#include "CCodec.h"
#include "CCodecBufferChannel.h"
#include "InputSurfaceWrapper.h"
-#include "Omx2IGraphicBufferSource.h"
extern "C" android::PersistentSurface *CreateInputSurface();
@@ -54,9 +55,10 @@
using namespace std::chrono_literals;
using ::android::hardware::graphics::bufferqueue::V1_0::utils::H2BGraphicBufferProducer;
using android::base::StringPrintf;
-using BGraphicBufferSource = ::android::IGraphicBufferSource;
using ::android::hardware::media::c2::V1_0::IInputSurface;
+typedef hardware::media::omx::V1_0::IGraphicBufferSource HGraphicBufferSource;
+
namespace {
class CCodecWatchdog : public AHandler {
@@ -180,9 +182,10 @@
class GraphicBufferSourceWrapper : public InputSurfaceWrapper {
public:
-// explicit GraphicBufferSourceWrapper(const sp<BGraphicBufferSource> &source) : mSource(source) {}
+ typedef hardware::media::omx::V1_0::Status OmxStatus;
+
GraphicBufferSourceWrapper(
- const sp<BGraphicBufferSource> &source,
+ const sp<HGraphicBufferSource> &source,
uint32_t width,
uint32_t height,
uint64_t usage)
@@ -194,6 +197,7 @@
status_t connect(const std::shared_ptr<Codec2Client::Component> &comp) override {
mNode = new C2OMXNode(comp);
+ mOmxNode = new hardware::media::omx::V1_0::utils::TWOmxNode(mNode);
mNode->setFrameSize(mWidth, mHeight);
// Usage is queried during configure(), so setting it beforehand.
@@ -204,7 +208,8 @@
// NOTE: we do not use/pass through color aspects from GraphicBufferSource as we
// communicate that directly to the component.
- mSource->configure(mNode, mDataSpace);
+ mSource->configure(
+ mOmxNode, static_cast<hardware::graphics::common::V1_0::Dataspace>(mDataSpace));
return OK;
}
@@ -220,21 +225,16 @@
source->onOmxIdle();
source->onOmxLoaded();
mNode.clear();
+ mOmxNode.clear();
}
- status_t GetStatus(const binder::Status &status) {
- status_t err = OK;
- if (!status.isOk()) {
- err = status.serviceSpecificErrorCode();
- if (err == OK) {
- err = status.transactionError();
- if (err == OK) {
- // binder status failed, but there is no servie or transaction error
- err = UNKNOWN_ERROR;
- }
- }
+ status_t GetStatus(hardware::Return<OmxStatus> &&status) {
+ if (status.isOk()) {
+ return static_cast<status_t>(status.withDefault(OmxStatus::UNKNOWN_ERROR));
+ } else if (status.isDeadObject()) {
+ return DEAD_OBJECT;
}
- return err;
+ return UNKNOWN_ERROR;
}
status_t start() override {
@@ -359,7 +359,15 @@
err = res;
} else {
status << " delayUs";
- res = GetStatus(mSource->getStopTimeOffsetUs(&config.mInputDelayUs));
+ hardware::Return<void> trans = mSource->getStopTimeOffsetUs(
+ [&res, &delayUs = config.mInputDelayUs](
+ auto status, auto stopTimeOffsetUs) {
+ res = static_cast<status_t>(status);
+ delayUs = stopTimeOffsetUs;
+ });
+ if (!trans.isOk()) {
+ res = trans.isDeadObject() ? DEAD_OBJECT : UNKNOWN_ERROR;
+ }
if (res != OK) {
status << " (=> " << asString(res) << ")";
} else {
@@ -388,8 +396,9 @@
}
private:
- sp<BGraphicBufferSource> mSource;
+ sp<HGraphicBufferSource> mSource;
sp<C2OMXNode> mNode;
+ sp<hardware::media::omx::V1_0::IOmxNode> mOmxNode;
uint32_t mWidth;
uint32_t mHeight;
Config mConfig;
@@ -1092,9 +1101,7 @@
gbs = source;
});
if (transStatus.isOk() && s == OmxStatus::OK) {
- return new PersistentSurface(
- new H2BGraphicBufferProducer(gbp),
- sp<::android::IGraphicBufferSource>(new LWGraphicBufferSource(gbs)));
+ return new PersistentSurface(new H2BGraphicBufferProducer(gbp), gbs);
}
return nullptr;
@@ -1125,28 +1132,28 @@
}
sp<PersistentSurface> persistentSurface = CreateCompatibleInputSurface();
+ sp<hidl::base::V1_0::IBase> hidlTarget = persistentSurface->getHidlTarget();
+ sp<IInputSurface> hidlInputSurface = IInputSurface::castFrom(hidlTarget);
+ sp<HGraphicBufferSource> gbs = HGraphicBufferSource::castFrom(hidlTarget);
- if (persistentSurface->getHidlTarget()) {
- sp<IInputSurface> hidlInputSurface = IInputSurface::castFrom(
- persistentSurface->getHidlTarget());
- if (!hidlInputSurface) {
- ALOGE("Corrupted input surface");
- mCallback->onInputSurfaceCreationFailed(UNKNOWN_ERROR);
- return;
- }
+ if (hidlInputSurface) {
std::shared_ptr<Codec2Client::InputSurface> inputSurface =
std::make_shared<Codec2Client::InputSurface>(hidlInputSurface);
err = setupInputSurface(std::make_shared<C2InputSurfaceWrapper>(
inputSurface));
bufferProducer = inputSurface->getGraphicBufferProducer();
- } else {
+ } else if (gbs) {
int32_t width = 0;
(void)outputFormat->findInt32("width", &width);
int32_t height = 0;
(void)outputFormat->findInt32("height", &height);
err = setupInputSurface(std::make_shared<GraphicBufferSourceWrapper>(
- persistentSurface->getBufferSource(), width, height, usage));
+ gbs, width, height, usage));
bufferProducer = persistentSurface->getBufferProducer();
+ } else {
+ ALOGE("Corrupted input surface");
+ mCallback->onInputSurfaceCreationFailed(UNKNOWN_ERROR);
+ return;
}
if (err != OK) {
@@ -1212,15 +1219,10 @@
outputFormat = config->mOutputFormat;
usage = config->mISConfig ? config->mISConfig->mUsage : 0;
}
- auto hidlTarget = surface->getHidlTarget();
- if (hidlTarget) {
- sp<IInputSurface> inputSurface =
- IInputSurface::castFrom(hidlTarget);
- if (!inputSurface) {
- ALOGE("Failed to set input surface: Corrupted surface.");
- mCallback->onInputSurfaceDeclined(UNKNOWN_ERROR);
- return;
- }
+ sp<hidl::base::V1_0::IBase> hidlTarget = surface->getHidlTarget();
+ sp<IInputSurface> inputSurface = IInputSurface::castFrom(hidlTarget);
+ sp<HGraphicBufferSource> gbs = HGraphicBufferSource::castFrom(hidlTarget);
+ if (inputSurface) {
status_t err = setupInputSurface(std::make_shared<C2InputSurfaceWrapper>(
std::make_shared<Codec2Client::InputSurface>(inputSurface)));
if (err != OK) {
@@ -1228,18 +1230,22 @@
mCallback->onInputSurfaceDeclined(err);
return;
}
- } else {
+ } else if (gbs) {
int32_t width = 0;
(void)outputFormat->findInt32("width", &width);
int32_t height = 0;
(void)outputFormat->findInt32("height", &height);
status_t err = setupInputSurface(std::make_shared<GraphicBufferSourceWrapper>(
- surface->getBufferSource(), width, height, usage));
+ gbs, width, height, usage));
if (err != OK) {
ALOGE("Failed to set up input surface: %d", err);
mCallback->onInputSurfaceDeclined(err);
return;
}
+ } else {
+ ALOGE("Failed to set input surface: Corrupted surface.");
+ mCallback->onInputSurfaceDeclined(UNKNOWN_ERROR);
+ return;
}
mCallback->onInputSurfaceAccepted(inputFormat, outputFormat);
}
@@ -1867,6 +1873,7 @@
// Create Codec 2.0 input surface
extern "C" android::PersistentSurface *CreateInputSurface() {
using namespace android;
+ using ::android::hardware::media::omx::V1_0::implementation::TWGraphicBufferSource;
// Attempt to create a Codec2's input surface.
std::shared_ptr<Codec2Client::InputSurface> inputSurface =
Codec2Client::CreateInputSurface();
@@ -1880,9 +1887,7 @@
return nullptr;
}
return new PersistentSurface(
- gbs->getIGraphicBufferProducer(),
- sp<IGraphicBufferSource>(
- new Omx2IGraphicBufferSource(gbs)));
+ gbs->getIGraphicBufferProducer(), new TWGraphicBufferSource(gbs));
} else {
return nullptr;
}
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.h b/media/codec2/sfplugin/CCodecBufferChannel.h
index ee3455d..c0fa138 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.h
+++ b/media/codec2/sfplugin/CCodecBufferChannel.h
@@ -29,7 +29,6 @@
#include <codec2/hidl/client.h>
#include <media/stagefright/foundation/Mutexed.h>
#include <media/stagefright/CodecBase.h>
-#include <media/ICrypto.h>
#include "CCodecBuffers.h"
#include "InputSurfaceWrapper.h"
diff --git a/media/codec2/sfplugin/CCodecBuffers.cpp b/media/codec2/sfplugin/CCodecBuffers.cpp
index 26c702d..ed8b832 100644
--- a/media/codec2/sfplugin/CCodecBuffers.cpp
+++ b/media/codec2/sfplugin/CCodecBuffers.cpp
@@ -878,9 +878,10 @@
switch (c2buffer->data().type()) {
case C2BufferData::LINEAR: {
uint32_t size = kLinearBufferSize;
- const C2ConstLinearBlock &block = c2buffer->data().linearBlocks().front();
- if (block.size() < kMaxLinearBufferSize / 2) {
- size = block.size() * 2;
+ const std::vector<C2ConstLinearBlock> &linear_blocks = c2buffer->data().linearBlocks();
+ const uint32_t block_size = linear_blocks.front().size();
+ if (block_size < kMaxLinearBufferSize / 2) {
+ size = block_size * 2;
} else {
size = kMaxLinearBufferSize;
}
diff --git a/media/codec2/sfplugin/CCodecConfig.cpp b/media/codec2/sfplugin/CCodecConfig.cpp
index 5adcd94..ee3cdf6 100644
--- a/media/codec2/sfplugin/CCodecConfig.cpp
+++ b/media/codec2/sfplugin/CCodecConfig.cpp
@@ -823,6 +823,14 @@
add(ConfigMapper(C2_PARAMKEY_INPUT_TIME_STRETCH, C2_PARAMKEY_INPUT_TIME_STRETCH, "value"));
+ add(ConfigMapper(KEY_LOW_LATENCY, C2_PARAMKEY_LOW_LATENCY_MODE, "value")
+ .limitTo(D::DECODER & (D::CONFIG | D::PARAM))
+ .withMapper([](C2Value v) -> C2Value {
+ int32_t value = 0;
+ (void)v.get(&value);
+ return value == 0 ? C2_FALSE : C2_TRUE;
+ }));
+
/* still to do
constexpr char KEY_PUSH_BLANK_BUFFERS_ON_STOP[] = "push-blank-buffers-on-shutdown";
diff --git a/media/codec2/sfplugin/Codec2Buffer.h b/media/codec2/sfplugin/Codec2Buffer.h
index 36dcab9..6f87101 100644
--- a/media/codec2/sfplugin/Codec2Buffer.h
+++ b/media/codec2/sfplugin/Codec2Buffer.h
@@ -25,7 +25,7 @@
#include <media/hardware/VideoAPI.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/MediaCodecBuffer.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
namespace android {
diff --git a/media/codec2/sfplugin/tests/Android.bp b/media/codec2/sfplugin/tests/Android.bp
index be7f55c..b6eb2b4 100644
--- a/media/codec2/sfplugin/tests/Android.bp
+++ b/media/codec2/sfplugin/tests/Android.bp
@@ -33,6 +33,10 @@
"frameworks/av/media/codec2/sfplugin",
],
+ header_libs: [
+ "libmediadrm_headers",
+ ],
+
shared_libs: [
"libbinder",
"libcodec2",
diff --git a/media/codec2/sfplugin/tests/MediaCodec_sanity_test.cpp b/media/codec2/sfplugin/tests/MediaCodec_sanity_test.cpp
index ba3687b..6deede0 100644
--- a/media/codec2/sfplugin/tests/MediaCodec_sanity_test.cpp
+++ b/media/codec2/sfplugin/tests/MediaCodec_sanity_test.cpp
@@ -21,7 +21,7 @@
#include <binder/ProcessState.h>
#include <gtest/gtest.h>
#include <gui/Surface.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/MediaCodecBuffer.h>
#include <media/hardware/VideoAPI.h>
#include <media/stagefright/MediaCodec.h>
diff --git a/media/codec2/sfplugin/utils/Codec2Mapper.cpp b/media/codec2/sfplugin/utils/Codec2Mapper.cpp
index ef6af48..2f3d688 100644
--- a/media/codec2/sfplugin/utils/Codec2Mapper.cpp
+++ b/media/codec2/sfplugin/utils/Codec2Mapper.cpp
@@ -190,6 +190,7 @@
{ C2Config::PROFILE_DV_HE_07, DolbyVisionProfileDvheDtb },
{ C2Config::PROFILE_DV_HE_08, DolbyVisionProfileDvheSt },
{ C2Config::PROFILE_DV_AV_09, DolbyVisionProfileDvavSe },
+ { C2Config::PROFILE_DV_AV1_10, DolbyVisionProfileDvav110 },
};
ALookup<C2Config::level_t, int32_t> sH263Levels = {
diff --git a/media/codec2/vndk/C2AllocatorIon.cpp b/media/codec2/vndk/C2AllocatorIon.cpp
index 752bc46..0470a31 100644
--- a/media/codec2/vndk/C2AllocatorIon.cpp
+++ b/media/codec2/vndk/C2AllocatorIon.cpp
@@ -600,7 +600,7 @@
}
std::shared_ptr<C2AllocationIon> alloc
- = std::make_shared<C2AllocationIon>(dup(mIonFd), capacity, align, heapMask, flags, mTraits->id);
+ = std::make_shared<C2AllocationIon>(dup(mIonFd), capacity, align, heapMask, flags, getId());
ret = alloc->status();
if (ret == C2_OK) {
*allocation = alloc;
@@ -622,7 +622,7 @@
// TODO: get capacity and validate it
const C2HandleIon *h = static_cast<const C2HandleIon*>(handle);
std::shared_ptr<C2AllocationIon> alloc
- = std::make_shared<C2AllocationIon>(dup(mIonFd), h->size(), h->bufferFd(), mTraits->id);
+ = std::make_shared<C2AllocationIon>(dup(mIonFd), h->size(), h->bufferFd(), getId());
c2_status_t ret = alloc->status();
if (ret == C2_OK) {
*allocation = alloc;
diff --git a/media/extractors/flac/FLACExtractor.h b/media/extractors/flac/FLACExtractor.h
index 5a73d20..223d359 100644
--- a/media/extractors/flac/FLACExtractor.h
+++ b/media/extractors/flac/FLACExtractor.h
@@ -17,7 +17,6 @@
#ifndef FLAC_EXTRACTOR_H_
#define FLAC_EXTRACTOR_H_
-#include <media/DataSourceBase.h>
#include <media/MediaExtractorPluginApi.h>
#include <media/MediaExtractorPluginHelper.h>
#include <media/NdkMediaFormat.h>
diff --git a/media/extractors/midi/Android.bp b/media/extractors/midi/Android.bp
index 7d42e70..d36cb49 100644
--- a/media/extractors/midi/Android.bp
+++ b/media/extractors/midi/Android.bp
@@ -6,6 +6,10 @@
"frameworks/av/media/libstagefright/include",
],
+ header_libs: [
+ "libmedia_headers",
+ ],
+
shared_libs: [
"liblog",
"libmediandk",
diff --git a/media/extractors/midi/MidiExtractor.h b/media/extractors/midi/MidiExtractor.h
index 2e78086..b486fc6 100644
--- a/media/extractors/midi/MidiExtractor.h
+++ b/media/extractors/midi/MidiExtractor.h
@@ -17,7 +17,6 @@
#ifndef MIDI_EXTRACTOR_H_
#define MIDI_EXTRACTOR_H_
-#include <media/DataSourceBase.h>
#include <media/MediaExtractorPluginApi.h>
#include <media/MediaExtractorPluginHelper.h>
#include <media/stagefright/MediaBufferBase.h>
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index b91d16f..81e1b8c 100755
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -133,6 +133,7 @@
bool mIsAVC;
bool mIsHEVC;
+ bool mIsDolbyVision;
bool mIsAC4;
bool mIsPcm;
size_t mNALLengthSize;
@@ -337,6 +338,14 @@
case FOURCC("hvc1"):
case FOURCC("hev1"):
return MEDIA_MIMETYPE_VIDEO_HEVC;
+
+ case FOURCC("dvav"):
+ case FOURCC("dva1"):
+ case FOURCC("dvhe"):
+ case FOURCC("dvh1"):
+ case FOURCC("dav1"):
+ return MEDIA_MIMETYPE_VIDEO_DOLBY_VISION;
+
case FOURCC("ac-4"):
return MEDIA_MIMETYPE_AUDIO_AC4;
case FOURCC("Opus"):
@@ -1062,6 +1071,62 @@
mLastTrack->mTx3gBuffer = NULL;
}
+ const char *mime;
+ AMediaFormat_getString(mLastTrack->meta, AMEDIAFORMAT_KEY_MIME, &mime);
+
+ if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION)) {
+ void *data;
+ size_t size;
+
+ if (AMediaFormat_getBuffer(mLastTrack->meta, AMEDIAFORMAT_KEY_CSD_2, &data, &size)) {
+ const uint8_t *ptr = (const uint8_t *)data;
+ const uint8_t profile = ptr[2] >> 1;
+ const uint8_t bl_compatibility_id = (ptr[4]) >> 4;
+
+ if (4 == profile || 7 == profile ||
+ (profile >= 8 && profile < 11 && bl_compatibility_id)) {
+ // we need a backward compatible track
+ ALOGV("Adding new backward compatible track");
+ Track *track_b = new Track;
+
+ track_b->timescale = mLastTrack->timescale;
+ track_b->sampleTable = mLastTrack->sampleTable;
+ track_b->includes_expensive_metadata = mLastTrack->includes_expensive_metadata;
+ track_b->skipTrack = mLastTrack->skipTrack;
+ track_b->has_elst = mLastTrack->has_elst;
+ track_b->elst_media_time = mLastTrack->elst_media_time;
+ track_b->elst_segment_duration = mLastTrack->elst_segment_duration;
+ track_b->elstShiftStartTicks = mLastTrack->elstShiftStartTicks;
+ track_b->subsample_encryption = mLastTrack->subsample_encryption;
+
+ track_b->mTx3gBuffer = mLastTrack->mTx3gBuffer;
+ track_b->mTx3gSize = mLastTrack->mTx3gSize;
+ track_b->mTx3gFilled = mLastTrack->mTx3gFilled;
+
+ track_b->meta = AMediaFormat_new();
+ AMediaFormat_copy(track_b->meta, mLastTrack->meta);
+
+ mLastTrack->next = track_b;
+ track_b->next = NULL;
+
+ auto id = track_b->meta->mFormat->findEntryByName(AMEDIAFORMAT_KEY_CSD_2);
+ track_b->meta->mFormat->removeEntryAt(id);
+
+ if (4 == profile || 7 == profile || 8 == profile ) {
+ AMediaFormat_setString(track_b->meta,
+ AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_HEVC);
+ } else if (9 == profile) {
+ AMediaFormat_setString(track_b->meta,
+ AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_AVC);
+ } else if (10 == profile) {
+ AMediaFormat_setString(track_b->meta,
+ AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_AV1);
+ } // Should never get to else part
+
+ mLastTrack = track_b;
+ }
+ }
+ }
} else if (chunk_type == FOURCC("moov")) {
mInitCheck = OK;
@@ -1830,6 +1895,11 @@
case FOURCC("avc1"):
case FOURCC("hvc1"):
case FOURCC("hev1"):
+ case FOURCC("dvav"):
+ case FOURCC("dva1"):
+ case FOURCC("dvhe"):
+ case FOURCC("dvh1"):
+ case FOURCC("dav1"):
case FOURCC("av01"):
{
uint8_t buffer[78];
@@ -1984,7 +2054,8 @@
// for audio, use 128KB
max_size = 1024 * 128;
} else if (!strcmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)
- || !strcmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)) {
+ || !strcmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)
+ || !strcmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION)) {
// AVC & HEVC requires compression ratio of at least 2, and uses
// macroblocks
max_size = ((width + 15) / 16) * ((height + 15) / 16) * 192;
@@ -2315,6 +2386,30 @@
*offset += chunk_size;
break;
}
+ case FOURCC("dvcC"):
+ case FOURCC("dvvC"): {
+ auto buffer = heapbuffer<uint8_t>(chunk_data_size);
+
+ if (buffer.get() == NULL) {
+ ALOGE("b/28471206");
+ return NO_MEMORY;
+ }
+
+ if (mDataSource->readAt(data_offset, buffer.get(), chunk_data_size) < chunk_data_size) {
+ return ERROR_IO;
+ }
+
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
+ AMediaFormat_setBuffer(mLastTrack->meta, AMEDIAFORMAT_KEY_CSD_2,
+ buffer.get(), chunk_data_size);
+ AMediaFormat_setString(mLastTrack->meta, AMEDIAFORMAT_KEY_MIME,
+ MEDIA_MIMETYPE_VIDEO_DOLBY_VISION);
+
+ *offset += chunk_size;
+ break;
+ }
case FOURCC("d263"):
{
*offset += chunk_size;
@@ -4127,7 +4222,20 @@
if (!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC)) {
itemTable = mItemTable;
}
- } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AV1)) {
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION)) {
+ void *data;
+ size_t size;
+ if (!AMediaFormat_getBuffer(track->meta, AMEDIAFORMAT_KEY_CSD_2, &data, &size)) {
+ return NULL;
+ }
+
+ const uint8_t *ptr = (const uint8_t *)data;
+
+ // dv_major.dv_minor Should be 1.0 or 2.1
+ if (size != 24 || ((ptr[0] != 1 || ptr[1] != 0) && (ptr[0] != 2 || ptr[1] != 1))) {
+ return NULL;
+ }
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AV1)) {
void *data;
size_t size;
if (!AMediaFormat_getBuffer(track->meta, AMEDIAFORMAT_KEY_CSD_0, &data, &size)) {
@@ -4172,6 +4280,10 @@
if (!AMediaFormat_getBuffer(track->meta, AMEDIAFORMAT_KEY_CSD_HEVC, &data, &size)) {
return ERROR_MALFORMED;
}
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION)) {
+ if (!AMediaFormat_getBuffer(track->meta, AMEDIAFORMAT_KEY_CSD_2, &data, &size)) {
+ return ERROR_MALFORMED;
+ }
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AV1)) {
if (!AMediaFormat_getBuffer(track->meta, AMEDIAFORMAT_KEY_CSD_0, &data, &size)) {
return ERROR_MALFORMED;
@@ -4659,6 +4771,7 @@
mCurrentSampleInfoOffsets(NULL),
mIsAVC(false),
mIsHEVC(false),
+ mIsDolbyVision(false),
mIsAC4(false),
mIsPcm(false),
mNALLengthSize(0),
@@ -4698,6 +4811,7 @@
mIsHEVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC) ||
!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC);
mIsAC4 = !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AC4);
+ mIsDolbyVision = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION);
if (mIsAVC) {
void *data;
@@ -4722,6 +4836,42 @@
CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1
mNALLengthSize = 1 + (ptr[14 + 7] & 3);
+ } else if (mIsDolbyVision) {
+ ALOGV("%s DolbyVision stream detected", __FUNCTION__);
+ void *data;
+ size_t size;
+ CHECK(AMediaFormat_getBuffer(format, AMEDIAFORMAT_KEY_CSD_2, &data, &size));
+
+ const uint8_t *ptr = (const uint8_t *)data;
+
+ CHECK(size == 24);
+
+ // dv_major.dv_minor Should be 1.0 or 2.1
+ CHECK(!((ptr[0] != 1 || ptr[1] != 0) && (ptr[0] != 2 || ptr[1] != 1)));
+
+ const uint8_t profile = ptr[2] >> 1;
+ // profile == (unknown,1,9) --> AVC; profile = (2,3,4,5,6,7,8) --> HEVC;
+ // profile == (10) --> AV1
+ if (profile > 1 && profile < 9) {
+ CHECK(AMediaFormat_getBuffer(format, AMEDIAFORMAT_KEY_CSD_HEVC, &data, &size));
+
+ const uint8_t *ptr = (const uint8_t *)data;
+
+ CHECK(size >= 22);
+ CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1
+
+ mNALLengthSize = 1 + (ptr[14 + 7] & 3);
+ } else if (10 == profile) {
+ /* AV1 profile nothing to do */
+ } else {
+ CHECK(AMediaFormat_getBuffer(format, AMEDIAFORMAT_KEY_CSD_AVC, &data, &size));
+ const uint8_t *ptr = (const uint8_t *)data;
+
+ CHECK(size >= 7);
+ CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1
+ // The number of bytes used to encode the length of a NAL unit.
+ mNALLengthSize = 1 + (ptr[4] & 3);
+ }
}
mIsPcm = !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW);
@@ -5789,7 +5939,7 @@
}
}
- if (!mIsAVC && !mIsHEVC && !mIsAC4) {
+ if (!mIsAVC && !mIsHEVC && !(mIsDolbyVision && mNALLengthSize) && !mIsAC4) {
if (newBuffer) {
if (mIsPcm) {
// The twos' PCM block reader assumes that all samples has the same size.
@@ -6179,7 +6329,7 @@
AMediaFormat_setBuffer(bufmeta, AMEDIAFORMAT_KEY_CRYPTO_IV, iv, ivlength);
}
- if (!mIsAVC && !mIsHEVC) {
+ if (!mIsAVC && !mIsHEVC && !(mIsDolbyVision && mNALLengthSize)) {
if (newBuffer) {
if (!isInRange((size_t)0u, mBuffer->size(), size)) {
mBuffer->release();
diff --git a/media/extractors/mp4/SampleIterator.cpp b/media/extractors/mp4/SampleIterator.cpp
index 2890b26..85fbf97 100644
--- a/media/extractors/mp4/SampleIterator.cpp
+++ b/media/extractors/mp4/SampleIterator.cpp
@@ -22,7 +22,6 @@
#include <arpa/inet.h>
-#include <media/DataSourceBase.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ByteUtils.h>
@@ -355,7 +354,7 @@
if (offset > 0) {
*time += offset;
} else {
- *time -= (offset == INT64_MIN ? INT64_MAX : (-offset));
+ *time -= (offset == INT32_MIN ? INT64_MAX : (-offset));
}
*duration = mTTSDuration;
diff --git a/media/extractors/mpeg2/Android.bp b/media/extractors/mpeg2/Android.bp
index 0f0c72c..1d9e1e6 100644
--- a/media/extractors/mpeg2/Android.bp
+++ b/media/extractors/mpeg2/Android.bp
@@ -16,6 +16,7 @@
"android.hardware.cas.native@1.0",
"android.hidl.token@1.0-utils",
"android.hidl.allocator@1.0",
+ "libcrypto",
"libhidlmemory",
"libhidlbase",
"liblog",
@@ -23,13 +24,13 @@
],
header_libs: [
+ "libaudioclient_headers",
"libbase_headers",
"libstagefright_headers",
"libmedia_headers",
],
static_libs: [
- "libcrypto",
"libstagefright_foundation_without_imemory",
"libstagefright_mpeg2support",
"libutils",
diff --git a/media/extractors/mpeg2/MPEG2PSExtractor.cpp b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
index 731584d..002a855 100644
--- a/media/extractors/mpeg2/MPEG2PSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
@@ -23,7 +23,6 @@
#include "mpeg2ts/AnotherPacketSource.h"
#include "mpeg2ts/ESQueue.h"
-#include <media/DataSourceBase.h>
#include <media/stagefright/foundation/ABitReader.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -111,8 +110,10 @@
AMediaFormat *meta = AMediaFormat_new();
for (size_t i = mTracks.size(); i > 0;) {
i--;
- if (mTracks.valueAt(i)->getFormat(meta) != AMEDIA_OK) {
+ Track *track = mTracks.valueAt(i);
+ if (track->getFormat(meta) != AMEDIA_OK) {
mTracks.removeItemsAt(i);
+ delete track;
}
}
AMediaFormat_delete(meta);
@@ -122,6 +123,10 @@
MPEG2PSExtractor::~MPEG2PSExtractor() {
delete mDataSource;
+ for (size_t i = mTracks.size(); i > 0;) {
+ i--;
+ delete mTracks.valueAt(i);
+ }
}
size_t MPEG2PSExtractor::countTracks() {
@@ -793,7 +798,9 @@
}
media_status_t MPEG2PSExtractor::WrappedTrack::start() {
+ delete mTrack->mBufferGroup;
mTrack->mBufferGroup = mBufferGroup;
+ mBufferGroup = nullptr;
return mTrack->start();
}
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index ee5d089..b707d78 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -700,7 +700,7 @@
* Added in API level 29.
*
* @param builder reference provided by AAudio_createStreamBuilder()
- * @param inputPreset the desired level of opt-out from being captured.
+ * @param capturePolicy the desired level of opt-out from being captured.
*/
AAUDIO_API void AAudioStreamBuilder_setAllowedCapturePolicy(AAudioStreamBuilder* builder,
aaudio_allowed_capture_policy_t capturePolicy) __INTRODUCED_IN(29);
diff --git a/media/libaaudio/src/Android.bp b/media/libaaudio/src/Android.bp
index 56c0170..850b1d0 100644
--- a/media/libaaudio/src/Android.bp
+++ b/media/libaaudio/src/Android.bp
@@ -10,7 +10,9 @@
"legacy",
"utility",
],
- header_libs: ["libaaudio_headers"],
+ header_libs: [
+ "libaaudio_headers",
+ ],
export_header_lib_headers: ["libaaudio_headers"],
version_script: "libaaudio.map.txt",
@@ -53,7 +55,10 @@
],
export_include_dirs: ["."],
- header_libs: ["libaaudio_headers"],
+ header_libs: [
+ "libaaudio_headers",
+ "libmedia_headers"
+ ],
export_header_lib_headers: ["libaaudio_headers"],
shared_libs: [
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 52eadd4..6614e5e 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -232,6 +232,24 @@
mCallbackBuffer = new uint8_t[callbackBufferSize];
}
+ // For debugging and analyzing the distribution of MMAP timestamps.
+ // For OUTPUT, use a NEGATIVE offset to move the CPU writes further BEFORE the HW reads.
+ // For INPUT, use a POSITIVE offset to move the CPU reads further AFTER the HW writes.
+ // You can use this offset to reduce glitching.
+ // You can also use this offset to force glitching. By iterating over multiple
+ // values you can reveal the distribution of the hardware timing jitter.
+ if (mAudioEndpoint.isFreeRunning()) { // MMAP?
+ int32_t offsetMicros = (getDirection() == AAUDIO_DIRECTION_OUTPUT)
+ ? AAudioProperty_getOutputMMapOffsetMicros()
+ : AAudioProperty_getInputMMapOffsetMicros();
+ // This log is used to debug some tricky glitch issues. Please leave.
+ ALOGD_IF(offsetMicros, "%s() - %s mmap offset = %d micros",
+ __func__,
+ (getDirection() == AAUDIO_DIRECTION_OUTPUT) ? "output" : "input",
+ offsetMicros);
+ mTimeOffsetNanos = offsetMicros * AAUDIO_NANOS_PER_MICROSECOND;
+ }
+
setState(AAUDIO_STREAM_STATE_OPEN);
return result;
@@ -478,7 +496,8 @@
#if LOG_TIMESTAMPS
logTimestamp(*message);
#endif
- processTimestamp(message->timestamp.position, message->timestamp.timestamp);
+ processTimestamp(message->timestamp.position,
+ message->timestamp.timestamp + mTimeOffsetNanos);
return AAUDIO_OK;
}
@@ -634,7 +653,7 @@
// Should we block?
if (timeoutNanoseconds == 0) {
break; // don't block
- } else if (framesLeft > 0) {
+ } else if (wakeTimeNanos != 0) {
if (!mAudioEndpoint.isFreeRunning()) {
// If there is software on the other end of the FIFO then it may get delayed.
// So wake up just a little after we expect it to be ready.
@@ -693,37 +712,38 @@
aaudio_result_t AudioStreamInternal::setBufferSize(int32_t requestedFrames) {
int32_t adjustedFrames = requestedFrames;
- int32_t actualFrames = 0;
- int32_t maximumSize = getBufferCapacity();
+ const int32_t maximumSize = getBufferCapacity() - mFramesPerBurst;
+ // The buffer size can be set to zero.
+ // This means that the callback may be called when the internal buffer becomes empty.
+ // This will be fine on some devices in ideal circumstances and will result in the
+ // lowest possible latency.
+ // If there are glitches then they should be detected as XRuns and the size can be increased.
+ static const int32_t minimumSize = 0;
// Clip to minimum size so that rounding up will work better.
- if (adjustedFrames < 1) {
- adjustedFrames = 1;
- }
+ adjustedFrames = std::max(minimumSize, adjustedFrames);
- if (adjustedFrames > maximumSize) {
- // Clip to maximum size.
+ // Prevent arithmetic overflow by clipping before we round.
+ if (adjustedFrames >= maximumSize) {
adjustedFrames = maximumSize;
} else {
// Round to the next highest burst size.
int32_t numBursts = (adjustedFrames + mFramesPerBurst - 1) / mFramesPerBurst;
adjustedFrames = numBursts * mFramesPerBurst;
- // Rounding may have gone above maximum.
- if (adjustedFrames > maximumSize) {
- adjustedFrames = maximumSize;
- }
}
- aaudio_result_t result = mAudioEndpoint.setBufferSizeInFrames(adjustedFrames, &actualFrames);
- if (result < 0) {
- return result;
- } else {
- return (aaudio_result_t) actualFrames;
- }
+ // Clip against the actual size from the endpoint.
+ int32_t actualFrames = 0;
+ mAudioEndpoint.setBufferSizeInFrames(maximumSize, &actualFrames);
+ // actualFrames should be <= maximumSize
+ adjustedFrames = std::min(actualFrames, adjustedFrames);
+
+ mBufferSizeInFrames = adjustedFrames;
+ return (aaudio_result_t) adjustedFrames;
}
int32_t AudioStreamInternal::getBufferSize() const {
- return mAudioEndpoint.getBufferSizeInFrames();
+ return mBufferSizeInFrames;
}
int32_t AudioStreamInternal::getBufferCapacity() const {
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index 86c4698..596d37f 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -194,6 +194,7 @@
// By delaying slightly we can avoid waking up before other side is ready.
const int32_t mWakeupDelayNanos; // delay past typical wakeup jitter
const int32_t mMinimumSleepNanos; // minimum sleep while polling
+ int32_t mTimeOffsetNanos = 0; // add to time part of an MMAP timestamp
AudioEndpointParcelable mEndPointParcelable; // description of the buffers filled by service
EndpointDescriptor mEndpointDescriptor; // buffer description with resolved addresses
@@ -203,6 +204,9 @@
// Sometimes the hardware is operating with a different channel count from the app.
// Then we require conversion in AAudio.
int32_t mDeviceChannelCount = 0;
+
+ int32_t mBufferSizeInFrames = 0; // local threshold to control latency
+
};
} /* namespace aaudio */
diff --git a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
index 366cc87..9684ee4 100644
--- a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
@@ -106,9 +106,10 @@
mNeedCatchUp.acknowledge();
}
- // If the write index passed the read index then consider it an overrun.
+ // If the capture buffer is full beyond capacity then consider it an overrun.
// For shared streams, the xRunCount is passed up from the service.
- if (mAudioEndpoint.isFreeRunning() && mAudioEndpoint.getEmptyFramesAvailable() < 0) {
+ if (mAudioEndpoint.isFreeRunning()
+ && mAudioEndpoint.getFullFramesAvailable() > mAudioEndpoint.getBufferCapacityInFrames()) {
mXRunCount++;
if (ATRACE_ENABLED()) {
ATRACE_INT("aaOverRuns", mXRunCount);
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index b8ef247..dc9f48c 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -167,8 +167,10 @@
ATRACE_INT("aaWrote", framesWritten);
}
+ // Sleep if there is too much data in the buffer.
// Calculate an ideal time to wake up.
- if (wakeTimePtr != nullptr && framesWritten >= 0) {
+ if (wakeTimePtr != nullptr
+ && (mAudioEndpoint.getFullFramesAvailable() >= getBufferSize())) {
// By default wake up a few milliseconds from now. // TODO review
int64_t wakeTime = currentNanoTime + (1 * AAUDIO_NANOS_PER_MILLISECOND);
aaudio_stream_state_t state = getState();
@@ -184,14 +186,10 @@
break;
case AAUDIO_STREAM_STATE_STARTED:
{
- // When do we expect the next read burst to occur?
-
- // Calculate frame position based off of the writeCounter because
- // the readCounter might have just advanced in the background,
- // causing us to sleep until a later burst.
- int64_t nextPosition = mAudioEndpoint.getDataWriteCounter() + mFramesPerBurst
- - mAudioEndpoint.getBufferSizeInFrames();
- wakeTime = mClockModel.convertPositionToTime(nextPosition);
+ // Sleep until the readCounter catches up and we only have
+ // the getBufferSize() frames of data sitting in the buffer.
+ int64_t nextReadPosition = mAudioEndpoint.getDataWriteCounter() - getBufferSize();
+ wakeTime = mClockModel.convertPositionToTime(nextReadPosition);
}
break;
default:
diff --git a/media/libaaudio/src/client/IsochronousClockModel.cpp b/media/libaaudio/src/client/IsochronousClockModel.cpp
index 9abdf53..bd46d05 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.cpp
+++ b/media/libaaudio/src/client/IsochronousClockModel.cpp
@@ -18,22 +18,43 @@
//#define LOG_NDEBUG 0
#include <log/log.h>
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
#include <stdint.h>
#include <algorithm>
#include "utility/AudioClock.h"
+#include "utility/AAudioUtilities.h"
#include "IsochronousClockModel.h"
using namespace aaudio;
+using namespace android::audio_utils;
+
+#ifndef ICM_LOG_DRIFT
+#define ICM_LOG_DRIFT 0
+#endif // ICM_LOG_DRIFT
+
+// To enable the timestamp histogram, enter this before opening the stream:
+// adb root
+// adb shell setprop aaudio.log_mask 1
+// A histogram of the lateness of the timestamps will be cleared when the stream is started.
+// It will be updated when the model is stable and receives a timestamp,
+// and dumped to the log when the stream is stopped.
+
IsochronousClockModel::IsochronousClockModel()
: mMarkerFramePosition(0)
, mMarkerNanoTime(0)
, mSampleRate(48000)
- , mFramesPerBurst(64)
+ , mFramesPerBurst(48)
, mMaxMeasuredLatenessNanos(0)
+ , mLatenessForDriftNanos(kInitialLatenessForDriftNanos)
, mState(STATE_STOPPED)
{
+ if ((AAudioProperty_getLogMask() & AAUDIO_LOG_CLOCK_MODEL_HISTOGRAM) != 0) {
+ mHistogramMicros = std::make_unique<Histogram>(kHistogramBinCount,
+ kHistogramBinWidthMicros);
+ }
}
IsochronousClockModel::~IsochronousClockModel() {
@@ -49,6 +70,9 @@
ALOGV("start(nanos = %lld)\n", (long long) nanoTime);
mMarkerNanoTime = nanoTime;
mState = STATE_STARTING;
+ if (mHistogramMicros) {
+ mHistogramMicros->clear();
+ }
}
void IsochronousClockModel::stop(int64_t nanoTime) {
@@ -58,6 +82,9 @@
setPositionAndTime(convertTimeToPosition(nanoTime), nanoTime);
// TODO should we set position?
mState = STATE_STOPPED;
+ if (mHistogramMicros) {
+ dumpHistogram();
+ }
}
bool IsochronousClockModel::isStarting() const {
@@ -90,6 +117,7 @@
// ALOGD("processTimestamp() - mSampleRate = %d", mSampleRate);
// ALOGD("processTimestamp() - mState = %d", mState);
+ int64_t latenessNanos = nanosDelta - expectedNanosDelta;
switch (mState) {
case STATE_STOPPED:
break;
@@ -99,7 +127,7 @@
break;
case STATE_SYNCING:
// This will handle a burst of rapid transfer at the beginning.
- if (nanosDelta < expectedNanosDelta) {
+ if (latenessNanos < 0) {
setPositionAndTime(framePosition, nanoTime);
} else {
// ALOGD("processTimestamp() - advance to STATE_RUNNING");
@@ -107,65 +135,67 @@
}
break;
case STATE_RUNNING:
- if (nanosDelta < expectedNanosDelta) {
+ if (mHistogramMicros) {
+ mHistogramMicros->add(latenessNanos / AAUDIO_NANOS_PER_MICROSECOND);
+ }
+ // Modify estimated position based on lateness.
+ // This affects the "early" side of the window, which controls output glitches.
+ if (latenessNanos < 0) {
// Earlier than expected timestamp.
// This data is probably more accurate, so use it.
// Or we may be drifting due to a fast HW clock.
- //int microsDelta = (int) (nanosDelta / 1000);
- //int expectedMicrosDelta = (int) (expectedNanosDelta / 1000);
- //ALOGD("%s() - STATE_RUNNING - #%d, %4d micros EARLY",
- //__func__, mTimestampCount, expectedMicrosDelta - microsDelta);
-
setPositionAndTime(framePosition, nanoTime);
- } else if (nanosDelta > (expectedNanosDelta + (2 * mBurstPeriodNanos))) {
- // In this case we do not update mMaxMeasuredLatenessNanos because it
- // would force it too high.
- // mMaxMeasuredLatenessNanos should range from 1 to 2 * mBurstPeriodNanos
- //int32_t measuredLatenessNanos = (int32_t)(nanosDelta - expectedNanosDelta);
- //ALOGD("%s() - STATE_RUNNING - #%d, lateness %d - max %d = %4d micros VERY LATE",
- //__func__,
- //mTimestampCount,
- //measuredLatenessNanos / 1000,
- //mMaxMeasuredLatenessNanos / 1000,
- //(measuredLatenessNanos - mMaxMeasuredLatenessNanos) / 1000
- //);
-
- // This typically happens when we are modelling a service instead of a DSP.
- setPositionAndTime(framePosition, nanoTime - (2 * mBurstPeriodNanos));
- } else if (nanosDelta > (expectedNanosDelta + mMaxMeasuredLatenessNanos)) {
- //int32_t previousLatenessNanos = mMaxMeasuredLatenessNanos;
- mMaxMeasuredLatenessNanos = (int32_t)(nanosDelta - expectedNanosDelta);
-
- //ALOGD("%s() - STATE_RUNNING - #%d, newmax %d - oldmax %d = %4d micros LATE",
- //__func__,
- //mTimestampCount,
- //mMaxMeasuredLatenessNanos / 1000,
- //previousLatenessNanos / 1000,
- //(mMaxMeasuredLatenessNanos - previousLatenessNanos) / 1000
- //);
-
- // When we are late, it may be because of preemption in the kernel,
+#if ICM_LOG_DRIFT
+ int earlyDeltaMicros = (int) ((expectedNanosDelta - nanosDelta)/ 1000);
+ ALOGD("%s() - STATE_RUNNING - #%d, %4d micros EARLY",
+ __func__, mTimestampCount, earlyDeltaMicros);
+#endif
+ } else if (latenessNanos > mLatenessForDriftNanos) {
+ // When we are on the late side, it may be because of preemption in the kernel,
// or timing jitter caused by resampling in the DSP,
// or we may be drifting due to a slow HW clock.
// We add slight drift value just in case there is actual long term drift
// forward caused by a slower clock.
// If the clock is faster than the model will get pushed earlier
- // by the code in the preceding branch.
+ // by the code in the earlier branch.
// The two opposing forces should allow the model to track the real clock
// over a long time.
int64_t driftingTime = mMarkerNanoTime + expectedNanosDelta + kDriftNanos;
setPositionAndTime(framePosition, driftingTime);
- //ALOGD("%s() - #%d, max lateness = %d micros",
- //__func__,
- //mTimestampCount,
- //(int) (mMaxMeasuredLatenessNanos / 1000));
+#if ICM_LOG_DRIFT
+ ALOGD("%s() - STATE_RUNNING - #%d, DRIFT, lateness = %d micros",
+ __func__,
+ mTimestampCount,
+ (int) (latenessNanos / 1000));
+#endif
+ }
+
+ // Modify mMaxMeasuredLatenessNanos.
+ // This affects the "late" side of the window, which controls input glitches.
+ if (latenessNanos > mMaxMeasuredLatenessNanos) { // increase
+#if ICM_LOG_DRIFT
+ ALOGD("%s() - STATE_RUNNING - #%d, newmax %d - oldmax %d = %4d micros LATE",
+ __func__,
+ mTimestampCount,
+ (int) (latenessNanos / 1000),
+ mMaxMeasuredLatenessNanos / 1000,
+ (int) ((latenessNanos - mMaxMeasuredLatenessNanos) / 1000)
+ );
+#endif
+ mMaxMeasuredLatenessNanos = (int32_t) latenessNanos;
+ // Calculate upper region that will trigger a drift forwards.
+ mLatenessForDriftNanos = mMaxMeasuredLatenessNanos - (mMaxMeasuredLatenessNanos >> 4);
+ } else { // decrease
+ // If these is an outlier in lateness then mMaxMeasuredLatenessNanos can go high
+ // and stay there. So we slowly reduce mMaxMeasuredLatenessNanos for better
+ // long term stability. The two opposing forces will keep mMaxMeasuredLatenessNanos
+ // within a reasonable range.
+ mMaxMeasuredLatenessNanos -= kDriftNanos;
}
break;
default:
break;
}
-
-// ALOGD("processTimestamp() - mState = %d", mState);
}
void IsochronousClockModel::setSampleRate(int32_t sampleRate) {
@@ -181,9 +211,6 @@
// Update expected lateness based on sampleRate and framesPerBurst
void IsochronousClockModel::update() {
mBurstPeriodNanos = convertDeltaPositionToTime(mFramesPerBurst); // uses mSampleRate
- // Timestamps may be late by up to a burst because we are randomly sampling the time period
- // after the DSP position is actually updated.
- mMaxMeasuredLatenessNanos = mBurstPeriodNanos;
}
int64_t IsochronousClockModel::convertDeltaPositionToTime(int64_t framesDelta) const {
@@ -227,9 +254,7 @@
}
int32_t IsochronousClockModel::getLateTimeOffsetNanos() const {
- // This will never be < 0 because mMaxLatenessNanos starts at
- // mBurstPeriodNanos and only gets bigger.
- return (mMaxMeasuredLatenessNanos - mBurstPeriodNanos) + kExtraLatenessNanos;
+ return mMaxMeasuredLatenessNanos + kExtraLatenessNanos;
}
int64_t IsochronousClockModel::convertPositionToLatestTime(int64_t framePosition) const {
@@ -241,10 +266,19 @@
}
void IsochronousClockModel::dump() const {
- ALOGD("mMarkerFramePosition = %lld", (long long) mMarkerFramePosition);
- ALOGD("mMarkerNanoTime = %lld", (long long) mMarkerNanoTime);
+ ALOGD("mMarkerFramePosition = %" PRIu64, mMarkerFramePosition);
+ ALOGD("mMarkerNanoTime = %" PRIu64, mMarkerNanoTime);
ALOGD("mSampleRate = %6d", mSampleRate);
ALOGD("mFramesPerBurst = %6d", mFramesPerBurst);
ALOGD("mMaxMeasuredLatenessNanos = %6d", mMaxMeasuredLatenessNanos);
ALOGD("mState = %6d", mState);
}
+
+void IsochronousClockModel::dumpHistogram() const {
+ if (!mHistogramMicros) return;
+ std::istringstream istr(mHistogramMicros->dump());
+ std::string line;
+ while (std::getline(istr, line)) {
+ ALOGD("lateness, %s", line.c_str());
+ }
+}
diff --git a/media/libaaudio/src/client/IsochronousClockModel.h b/media/libaaudio/src/client/IsochronousClockModel.h
index 582bf4e..40f066b 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.h
+++ b/media/libaaudio/src/client/IsochronousClockModel.h
@@ -18,6 +18,9 @@
#define ANDROID_AAUDIO_ISOCHRONOUS_CLOCK_MODEL_H
#include <stdint.h>
+
+#include <audio_utils/Histogram.h>
+
#include "utility/AudioClock.h"
namespace aaudio {
@@ -122,6 +125,8 @@
void dump() const;
+ void dumpHistogram() const;
+
private:
int32_t getLateTimeOffsetNanos() const;
@@ -134,21 +139,30 @@
};
// Amount of time to drift forward when we get a late timestamp.
- // This value was calculated to allow tracking of a clock with 50 ppm error.
- static constexpr int32_t kDriftNanos = 10 * 1000;
- // TODO review value of kExtraLatenessNanos
+ static constexpr int32_t kDriftNanos = 1 * 1000;
+ // Safety margin to add to the late edge of the timestamp window.
static constexpr int32_t kExtraLatenessNanos = 100 * 1000;
+ // Initial small threshold for causing a drift later in time.
+ static constexpr int32_t kInitialLatenessForDriftNanos = 10 * 1000;
- int64_t mMarkerFramePosition;
- int64_t mMarkerNanoTime;
+ static constexpr int32_t kHistogramBinWidthMicros = 50;
+ static constexpr int32_t kHistogramBinCount = 128;
+
+ int64_t mMarkerFramePosition; // Estimated HW position.
+ int64_t mMarkerNanoTime; // Estimated HW time.
int32_t mSampleRate;
- int32_t mFramesPerBurst;
- int32_t mBurstPeriodNanos;
+ int32_t mFramesPerBurst; // number of frames transferred at one time.
+ int32_t mBurstPeriodNanos; // Time between HW bursts.
// Includes mBurstPeriodNanos because we sample randomly over time.
int32_t mMaxMeasuredLatenessNanos;
- clock_model_state_t mState;
+ // Threshold for lateness that triggers a drift later in time.
+ int32_t mLatenessForDriftNanos;
+ clock_model_state_t mState; // State machine handles startup sequence.
- int32_t mTimestampCount = 0;
+ int32_t mTimestampCount = 0; // For logging.
+
+ // distribution of timestamps relative to earliest
+ std::unique_ptr<android::audio_utils::Histogram> mHistogramMicros;
void update();
};
diff --git a/media/libaaudio/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp
index cdd02c0..c2f7fd0 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.cpp
+++ b/media/libaaudio/src/utility/AAudioUtilities.cpp
@@ -335,6 +335,34 @@
return prop;
}
+static int32_t AAudioProperty_getMMapOffsetMicros(const char *functionName,
+ const char *propertyName) {
+ const int32_t minMicros = -20000; // arbitrary
+ const int32_t defaultMicros = 0; // arbitrary
+ const int32_t maxMicros = 20000; // arbitrary
+ int32_t prop = property_get_int32(propertyName, defaultMicros);
+ if (prop < minMicros) {
+ ALOGW("%s: clipped %d to %d", functionName, prop, minMicros);
+ prop = minMicros;
+ } else if (prop > maxMicros) {
+ ALOGW("%s: clipped %d to %d", functionName, prop, minMicros);
+ prop = maxMicros;
+ }
+ return prop;
+}
+
+int32_t AAudioProperty_getInputMMapOffsetMicros() {
+ return AAudioProperty_getMMapOffsetMicros(__func__, AAUDIO_PROP_INPUT_MMAP_OFFSET_USEC);
+}
+
+int32_t AAudioProperty_getOutputMMapOffsetMicros() {
+ return AAudioProperty_getMMapOffsetMicros(__func__, AAUDIO_PROP_OUTPUT_MMAP_OFFSET_USEC);
+}
+
+int32_t AAudioProperty_getLogMask() {
+ return property_get_int32(AAUDIO_PROP_LOG_MASK, 0);
+}
+
aaudio_result_t AAudio_isFlushAllowed(aaudio_stream_state_t state) {
aaudio_result_t result = AAUDIO_OK;
switch (state) {
diff --git a/media/libaaudio/src/utility/AAudioUtilities.h b/media/libaaudio/src/utility/AAudioUtilities.h
index 76d0457..5dcddf3 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.h
+++ b/media/libaaudio/src/utility/AAudioUtilities.h
@@ -94,31 +94,26 @@
// Note that this code may be replaced by Settings or by some other system configuration tool.
+/**
+ * Read system property.
+ * @return AAUDIO_UNSPECIFIED, AAUDIO_POLICY_NEVER or AAUDIO_POLICY_AUTO or AAUDIO_POLICY_ALWAYS
+ */
+int32_t AAudioProperty_getMMapPolicy();
#define AAUDIO_PROP_MMAP_POLICY "aaudio.mmap_policy"
/**
* Read system property.
* @return AAUDIO_UNSPECIFIED, AAUDIO_POLICY_NEVER or AAUDIO_POLICY_AUTO or AAUDIO_POLICY_ALWAYS
*/
-int32_t AAudioProperty_getMMapPolicy();
-
-#define AAUDIO_PROP_MMAP_EXCLUSIVE_POLICY "aaudio.mmap_exclusive_policy"
-
-/**
- * Read system property.
- * @return AAUDIO_UNSPECIFIED, AAUDIO_POLICY_NEVER or AAUDIO_POLICY_AUTO or AAUDIO_POLICY_ALWAYS
- */
int32_t AAudioProperty_getMMapExclusivePolicy();
-
-#define AAUDIO_PROP_MIXER_BURSTS "aaudio.mixer_bursts"
+#define AAUDIO_PROP_MMAP_EXCLUSIVE_POLICY "aaudio.mmap_exclusive_policy"
/**
* Read system property.
* @return number of bursts per AAudio service mixer cycle
*/
int32_t AAudioProperty_getMixerBursts();
-
-#define AAUDIO_PROP_HW_BURST_MIN_USEC "aaudio.hw_burst_min_usec"
+#define AAUDIO_PROP_MIXER_BURSTS "aaudio.mixer_bursts"
/**
* Read a system property that specifies the number of extra microseconds that a thread
@@ -130,7 +125,6 @@
* @return number of microseconds to delay the wakeup.
*/
int32_t AAudioProperty_getWakeupDelayMicros();
-
#define AAUDIO_PROP_WAKEUP_DELAY_USEC "aaudio.wakeup_delay_usec"
/**
@@ -139,7 +133,6 @@
* @return minimum number of microseconds to sleep.
*/
int32_t AAudioProperty_getMinimumSleepMicros();
-
#define AAUDIO_PROP_MINIMUM_SLEEP_USEC "aaudio.minimum_sleep_usec"
/**
@@ -153,7 +146,35 @@
* @return minimum number of microseconds for a MMAP HW burst
*/
int32_t AAudioProperty_getHardwareBurstMinMicros();
+#define AAUDIO_PROP_HW_BURST_MIN_USEC "aaudio.hw_burst_min_usec"
+/**
+ * Read a system property that specifies an offset that will be added to MMAP timestamps.
+ * This can be used to correct bias in the timestamp.
+ * It can also be used to analyze the time distribution of the timestamp
+ * by progressively modifying the offset and listening for glitches.
+ *
+ * @return number of microseconds to offset the time part of an MMAP timestamp
+ */
+int32_t AAudioProperty_getInputMMapOffsetMicros();
+#define AAUDIO_PROP_INPUT_MMAP_OFFSET_USEC "aaudio.in_mmap_offset_usec"
+
+int32_t AAudioProperty_getOutputMMapOffsetMicros();
+#define AAUDIO_PROP_OUTPUT_MMAP_OFFSET_USEC "aaudio.out_mmap_offset_usec"
+
+// These are powers of two that can be combined as a bit mask.
+// AAUDIO_LOG_CLOCK_MODEL_HISTOGRAM must be enabled before the stream is opened.
+#define AAUDIO_LOG_CLOCK_MODEL_HISTOGRAM 1
+#define AAUDIO_LOG_RESERVED_2 2
+#define AAUDIO_LOG_RESERVED_4 4
+#define AAUDIO_LOG_RESERVED_8 8
+
+/**
+ * Use a mask to enable various logs in AAudio.
+ * @return mask that enables various AAudio logs, such as AAUDIO_LOG_CLOCK_MODEL_HISTOGRAM
+ */
+int32_t AAudioProperty_getLogMask();
+#define AAUDIO_PROP_LOG_MASK "aaudio.log_mask"
/**
* Is flush allowed for the given state?
diff --git a/media/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp
index 19cd0a0..73fd896 100644
--- a/media/libaaudio/tests/Android.bp
+++ b/media/libaaudio/tests/Android.bp
@@ -215,3 +215,14 @@
srcs: ["test_full_queue.cpp"],
shared_libs: ["libaaudio"],
}
+
+cc_test {
+ name: "test_histogram",
+ defaults: ["libaaudio_tests_defaults"],
+ srcs: ["test_histogram.cpp"],
+ shared_libs: [
+ "libaudioutils",
+ "libcutils",
+ "libutils",
+ ],
+}
diff --git a/media/libaaudio/tests/test_histogram.cpp b/media/libaaudio/tests/test_histogram.cpp
new file mode 100644
index 0000000..431373d
--- /dev/null
+++ b/media/libaaudio/tests/test_histogram.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Test Histogram
+ */
+
+#include <iostream>
+
+#include <gtest/gtest.h>
+
+#include <audio_utils/Histogram.h>
+
+using namespace android::audio_utils;
+
+static constexpr int32_t kBinWidth = 10;
+static constexpr int32_t kNumBins = 20;
+
+TEST(test_histogram, module_sinki16) {
+ Histogram histogram(kNumBins, kBinWidth);
+ ASSERT_EQ(kNumBins, histogram.getNumBinsInRange());
+
+ // Is it clear initially?
+ for (int i = 0; i < kNumBins; i++) {
+ ASSERT_EQ(0, histogram.getCount(i));
+ }
+ ASSERT_EQ(0, histogram.getCountBelowRange());
+ ASSERT_EQ(0, histogram.getCountAboveRange());
+ ASSERT_EQ(0, histogram.getCount());
+
+ // Add some items.
+ histogram.add(27);
+ histogram.add(53);
+ histogram.add(171);
+ histogram.add(23);
+
+ // Did they count correctly.
+ ASSERT_EQ(2, histogram.getCount(2)); // For items 27 and 23
+ ASSERT_EQ(3, histogram.getLastItemNumber(2)); // Item 23 was the 0,1,2,3th item added.
+ ASSERT_EQ(1, histogram.getCount(5)); // For item 53
+ ASSERT_EQ(1, histogram.getLastItemNumber(5)); // item 53 was the second item added.
+ ASSERT_EQ(1, histogram.getCount(17)); // For item 171
+ ASSERT_EQ(4, histogram.getCount()); // A total of four items were added.
+
+ // Add values out of range.
+ histogram.add(-5);
+ ASSERT_EQ(1, histogram.getCountBelowRange()); // -5 is below zero.
+ ASSERT_EQ(0, histogram.getCountAboveRange());
+ ASSERT_EQ(5, histogram.getCount());
+
+ histogram.add(200);
+ ASSERT_EQ(1, histogram.getCountBelowRange());
+ ASSERT_EQ(1, histogram.getCountAboveRange()); // 200 is above top bin
+ ASSERT_EQ(6, histogram.getCount());
+
+ // Try to read values out of range. Should not crash.
+ // Legal index range is 0 to numBins-1
+ histogram.add(-1);
+ histogram.add(kNumBins);
+ ASSERT_EQ(0, histogram.getCount(-1)); // edge
+ ASSERT_EQ(0, histogram.getCount(kNumBins)); // edge
+ ASSERT_EQ(0, histogram.getCount(-1234)); // extreme
+ ASSERT_EQ(0, histogram.getCount(98765)); // extreme
+ ASSERT_EQ(0, histogram.getLastItemNumber(-1));
+ ASSERT_EQ(0, histogram.getLastItemNumber(kNumBins));
+
+ // Clear all the counts.
+ histogram.clear();
+ // Is it clear?
+ for (int i = 0; i < kNumBins; i++) {
+ ASSERT_EQ(0, histogram.getCount(i));
+ }
+ ASSERT_EQ(0, histogram.getCountBelowRange());
+ ASSERT_EQ(0, histogram.getCountAboveRange());
+ ASSERT_EQ(0, histogram.getCount());
+}
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index c516d20..32904bb 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -84,6 +84,7 @@
header_libs: [
"libaudioclient_headers",
"libbase_headers",
+ "libmedia_headers",
],
export_header_lib_headers: ["libaudioclient_headers"],
diff --git a/media/libaudioclient/AudioTrackShared.cpp b/media/libaudioclient/AudioTrackShared.cpp
index ee6c335..f1f8f9c 100644
--- a/media/libaudioclient/AudioTrackShared.cpp
+++ b/media/libaudioclient/AudioTrackShared.cpp
@@ -984,8 +984,9 @@
// ---------------------------------------------------------------------------
StaticAudioTrackServerProxy::StaticAudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers,
- size_t frameCount, size_t frameSize)
- : AudioTrackServerProxy(cblk, buffers, frameCount, frameSize),
+ size_t frameCount, size_t frameSize, uint32_t sampleRate)
+ : AudioTrackServerProxy(cblk, buffers, frameCount, frameSize, false /*clientInServer*/,
+ sampleRate),
mObserver(&cblk->u.mStatic.mSingleStateQueue),
mPosLoopMutator(&cblk->u.mStatic.mPosLoopQueue),
mFramesReadySafe(frameCount), mFramesReady(frameCount),
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 750fc21..46cfb68 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -24,8 +24,8 @@
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
-#include <media/TimeCheck.h>
#include <mediautils/ServiceUtilities.h>
+#include <mediautils/TimeCheck.h>
#include "IAudioFlinger.h"
namespace android {
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index 64f0aca..7cc95e5 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -26,8 +26,8 @@
#include <binder/Parcel.h>
#include <media/AudioEffect.h>
#include <media/IAudioPolicyService.h>
-#include <media/TimeCheck.h>
#include <mediautils/ServiceUtilities.h>
+#include <mediautils/TimeCheck.h>
#include <system/audio.h>
namespace android {
diff --git a/media/libaudioclient/tests/Android.bp b/media/libaudioclient/tests/Android.bp
index 52bb2fb..d509be6 100644
--- a/media/libaudioclient/tests/Android.bp
+++ b/media/libaudioclient/tests/Android.bp
@@ -11,6 +11,9 @@
defaults: ["libaudioclient_tests_defaults"],
srcs: ["test_create_audiotrack.cpp",
"test_create_utils.cpp"],
+ header_libs: [
+ "libmedia_headers",
+ ],
shared_libs: [
"libaudioclient",
"libbinder",
@@ -25,6 +28,9 @@
defaults: ["libaudioclient_tests_defaults"],
srcs: ["test_create_audiorecord.cpp",
"test_create_utils.cpp"],
+ header_libs: [
+ "libmedia_headers",
+ ],
shared_libs: [
"libaudioclient",
"libbinder",
diff --git a/media/libaudiofoundation/Android.bp b/media/libaudiofoundation/Android.bp
index 9b9f12f..1df0d16 100644
--- a/media/libaudiofoundation/Android.bp
+++ b/media/libaudiofoundation/Android.bp
@@ -2,13 +2,22 @@
name: "libaudiofoundation_headers",
vendor_available: true,
export_include_dirs: ["include"],
+ header_libs: [
+ "libaudio_system_headers",
+ "libmedia_helper_headers",
+ ],
+ export_header_lib_headers: [
+ "libaudio_system_headers",
+ "libmedia_helper_headers",
+ ],
}
-cc_library_shared {
+cc_library {
name: "libaudiofoundation",
vendor_available: true,
srcs: [
+ "AudioContainers.cpp",
"AudioGain.cpp",
"AudioPort.cpp",
"AudioProfile.cpp",
@@ -25,12 +34,12 @@
],
header_libs: [
- "libaudio_system_headers",
- "libaudioclient_headers",
"libaudiofoundation_headers",
],
- export_header_lib_headers: ["libaudiofoundation_headers"],
+ export_header_lib_headers: [
+ "libaudiofoundation_headers",
+ ],
cflags: [
"-Werror",
diff --git a/media/libaudiofoundation/AudioContainers.cpp b/media/libaudiofoundation/AudioContainers.cpp
new file mode 100644
index 0000000..adc5d40
--- /dev/null
+++ b/media/libaudiofoundation/AudioContainers.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sstream>
+#include <string>
+
+#include <media/AudioContainers.h>
+
+namespace android {
+
+const DeviceTypeSet& getAudioDeviceOutAllSet() {
+ static const DeviceTypeSet audioDeviceOutAllSet = DeviceTypeSet(
+ std::begin(AUDIO_DEVICE_OUT_ALL_ARRAY),
+ std::end(AUDIO_DEVICE_OUT_ALL_ARRAY));
+ return audioDeviceOutAllSet;
+}
+
+const DeviceTypeSet& getAudioDeviceOutAllA2dpSet() {
+ static const DeviceTypeSet audioDeviceOutAllA2dpSet = DeviceTypeSet(
+ std::begin(AUDIO_DEVICE_OUT_ALL_A2DP_ARRAY),
+ std::end(AUDIO_DEVICE_OUT_ALL_A2DP_ARRAY));
+ return audioDeviceOutAllA2dpSet;
+}
+
+const DeviceTypeSet& getAudioDeviceOutAllScoSet() {
+ static const DeviceTypeSet audioDeviceOutAllScoSet = DeviceTypeSet(
+ std::begin(AUDIO_DEVICE_OUT_ALL_SCO_ARRAY),
+ std::end(AUDIO_DEVICE_OUT_ALL_SCO_ARRAY));
+ return audioDeviceOutAllScoSet;
+}
+
+const DeviceTypeSet& getAudioDeviceInAllSet() {
+ static const DeviceTypeSet audioDeviceInAllSet = DeviceTypeSet(
+ std::begin(AUDIO_DEVICE_IN_ALL_ARRAY),
+ std::end(AUDIO_DEVICE_IN_ALL_ARRAY));
+ return audioDeviceInAllSet;
+}
+
+bool deviceTypesToString(const DeviceTypeSet &deviceTypes, std::string &str) {
+ bool ret = true;
+ for (auto it = deviceTypes.begin(); it != deviceTypes.end();) {
+ std::string deviceTypeStr;
+ ret = audio_is_output_device(*it) ?
+ OutputDeviceConverter::toString(*it, deviceTypeStr) :
+ InputDeviceConverter::toString(*it, deviceTypeStr);
+ if (!ret) {
+ break;
+ }
+ str.append(deviceTypeStr);
+ if (++it != deviceTypes.end()) {
+ str.append(" , ");
+ }
+ }
+ if (!ret) {
+ str = "Unknown values";
+ }
+ return ret;
+}
+
+std::string dumpDeviceTypes(const DeviceTypeSet &deviceTypes) {
+ std::string ret;
+ for (auto it = deviceTypes.begin(); it != deviceTypes.end();) {
+ std::stringstream ss;
+ ss << "0x" << std::hex << (*it);
+ ret.append(ss.str());
+ if (++it != deviceTypes.end()) {
+ ret.append(" , ");
+ }
+ }
+ return ret;
+}
+
+} // namespace android
diff --git a/media/libaudiofoundation/AudioGain.cpp b/media/libaudiofoundation/AudioGain.cpp
index 9d1d6db..0d28335 100644
--- a/media/libaudiofoundation/AudioGain.cpp
+++ b/media/libaudiofoundation/AudioGain.cpp
@@ -24,6 +24,8 @@
#define ALOGVV(a...) do { } while(0)
#endif
+#include <algorithm>
+
#include <android-base/stringprintf.h>
#include <media/AudioGain.h>
#include <utils/Log.h>
@@ -111,6 +113,22 @@
dst->append(base::StringPrintf("%*s- max_ramp_ms: %d ms\n", spaces, "", mGain.max_ramp_ms));
}
+bool AudioGain::equals(const sp<AudioGain>& other) const
+{
+ return other != nullptr &&
+ mUseInChannelMask == other->mUseInChannelMask &&
+ mUseForVolume == other->mUseForVolume &&
+ // Compare audio gain
+ mGain.mode == other->mGain.mode &&
+ mGain.channel_mask == other->mGain.channel_mask &&
+ mGain.min_value == other->mGain.min_value &&
+ mGain.max_value == other->mGain.max_value &&
+ mGain.default_value == other->mGain.default_value &&
+ mGain.step_value == other->mGain.step_value &&
+ mGain.min_ramp_ms == other->mGain.min_ramp_ms &&
+ mGain.max_ramp_ms == other->mGain.max_ramp_ms;
+}
+
status_t AudioGain::writeToParcel(android::Parcel *parcel) const
{
status_t status = NO_ERROR;
@@ -145,9 +163,17 @@
return status;
}
+bool AudioGains::equals(const AudioGains &other) const
+{
+ return std::equal(begin(), end(), other.begin(), other.end(),
+ [](const sp<AudioGain>& left, const sp<AudioGain>& right) {
+ return left->equals(right);
+ });
+}
+
status_t AudioGains::writeToParcel(android::Parcel *parcel) const {
status_t status = NO_ERROR;
- if ((status = parcel->writeUint64(this->size())) != NO_ERROR) return status;
+ if ((status = parcel->writeVectorSize(*this)) != NO_ERROR) return status;
for (const auto &audioGain : *this) {
if ((status = parcel->writeParcelable(*audioGain)) != NO_ERROR) {
break;
@@ -158,15 +184,14 @@
status_t AudioGains::readFromParcel(const android::Parcel *parcel) {
status_t status = NO_ERROR;
- uint64_t count;
- if ((status = parcel->readUint64(&count)) != NO_ERROR) return status;
- for (uint64_t i = 0; i < count; i++) {
- sp<AudioGain> audioGain = new AudioGain(0, false);
- if ((status = parcel->readParcelable(audioGain.get())) != NO_ERROR) {
+ this->clear();
+ if ((status = parcel->resizeOutVector(this)) != NO_ERROR) return status;
+ for (size_t i = 0; i < this->size(); i++) {
+ this->at(i) = new AudioGain(0, false);
+ if ((status = parcel->readParcelable(this->at(i).get())) != NO_ERROR) {
this->clear();
break;
}
- this->push_back(audioGain);
}
return status;
}
diff --git a/media/libaudiofoundation/AudioPort.cpp b/media/libaudiofoundation/AudioPort.cpp
index cde31e4..f988690 100644
--- a/media/libaudiofoundation/AudioPort.cpp
+++ b/media/libaudiofoundation/AudioPort.cpp
@@ -105,6 +105,46 @@
ALOGI("%s Port[nm:%s, type:%d, role:%d]", indent, mName.c_str(), mType, mRole);
}
+bool AudioPort::equals(const sp<AudioPort> &other) const
+{
+ return other != nullptr &&
+ mGains.equals(other->getGains()) &&
+ mName.compare(other->getName()) == 0 &&
+ mType == other->getType() &&
+ mRole == other->getRole() &&
+ mProfiles.equals(other->getAudioProfiles());
+}
+
+status_t AudioPort::writeToParcel(Parcel *parcel) const
+{
+ status_t status = NO_ERROR;
+ if ((status = parcel->writeUtf8AsUtf16(mName)) != NO_ERROR) return status;
+ if ((status = parcel->writeUint32(mType)) != NO_ERROR) return status;
+ if ((status = parcel->writeUint32(mRole)) != NO_ERROR) return status;
+ if ((status = parcel->writeParcelable(mProfiles)) != NO_ERROR) return status;
+ if ((status = parcel->writeParcelable(mGains)) != NO_ERROR) return status;
+ return status;
+}
+
+status_t AudioPort::readFromParcel(const Parcel *parcel)
+{
+ status_t status = NO_ERROR;
+ if ((status = parcel->readUtf8FromUtf16(&mName)) != NO_ERROR) return status;
+ static_assert(sizeof(mType) == sizeof(uint32_t));
+ if ((status = parcel->readUint32(reinterpret_cast<uint32_t*>(&mType))) != NO_ERROR) {
+ return status;
+ }
+ static_assert(sizeof(mRole) == sizeof(uint32_t));
+ if ((status = parcel->readUint32(reinterpret_cast<uint32_t*>(&mRole))) != NO_ERROR) {
+ return status;
+ }
+ mProfiles.clear();
+ if ((status = parcel->readParcelable(&mProfiles)) != NO_ERROR) return status;
+ mGains.clear();
+ if ((status = parcel->readParcelable(&mGains)) != NO_ERROR) return status;
+ return status;
+}
+
// --- AudioPortConfig class implementation
status_t AudioPortConfig::applyAudioPortConfig(
@@ -188,4 +228,60 @@
: audioport->getGains().size() > 0;
}
+bool AudioPortConfig::equals(const sp<AudioPortConfig> &other) const
+{
+ return other != nullptr &&
+ mSamplingRate == other->getSamplingRate() &&
+ mFormat == other->getFormat() &&
+ mChannelMask == other->getChannelMask() &&
+ // Compare audio gain config
+ mGain.index == other->mGain.index &&
+ mGain.mode == other->mGain.mode &&
+ mGain.channel_mask == other->mGain.channel_mask &&
+ std::equal(std::begin(mGain.values), std::end(mGain.values),
+ std::begin(other->mGain.values)) &&
+ mGain.ramp_duration_ms == other->mGain.ramp_duration_ms;
}
+
+status_t AudioPortConfig::writeToParcel(Parcel *parcel) const
+{
+ status_t status = NO_ERROR;
+ if ((status = parcel->writeUint32(mSamplingRate)) != NO_ERROR) return status;
+ if ((status = parcel->writeUint32(mFormat)) != NO_ERROR) return status;
+ if ((status = parcel->writeUint32(mChannelMask)) != NO_ERROR) return status;
+ if ((status = parcel->writeInt32(mId)) != NO_ERROR) return status;
+ // Write mGain to parcel.
+ if ((status = parcel->writeInt32(mGain.index)) != NO_ERROR) return status;
+ if ((status = parcel->writeUint32(mGain.mode)) != NO_ERROR) return status;
+ if ((status = parcel->writeUint32(mGain.channel_mask)) != NO_ERROR) return status;
+ if ((status = parcel->writeUint32(mGain.ramp_duration_ms)) != NO_ERROR) return status;
+ std::vector<int> values(std::begin(mGain.values), std::end(mGain.values));
+ if ((status = parcel->writeInt32Vector(values)) != NO_ERROR) return status;
+ return status;
+}
+
+status_t AudioPortConfig::readFromParcel(const Parcel *parcel)
+{
+ status_t status = NO_ERROR;
+ if ((status = parcel->readUint32(&mSamplingRate)) != NO_ERROR) return status;
+ static_assert(sizeof(mFormat) == sizeof(uint32_t));
+ if ((status = parcel->readUint32(reinterpret_cast<uint32_t*>(&mFormat))) != NO_ERROR) {
+ return status;
+ }
+ if ((status = parcel->readUint32(&mChannelMask)) != NO_ERROR) return status;
+ if ((status = parcel->readInt32(&mId)) != NO_ERROR) return status;
+ // Read mGain from parcel.
+ if ((status = parcel->readInt32(&mGain.index)) != NO_ERROR) return status;
+ if ((status = parcel->readUint32(&mGain.mode)) != NO_ERROR) return status;
+ if ((status = parcel->readUint32(&mGain.channel_mask)) != NO_ERROR) return status;
+ if ((status = parcel->readUint32(&mGain.ramp_duration_ms)) != NO_ERROR) return status;
+ std::vector<int> values;
+ if ((status = parcel->readInt32Vector(&values)) != NO_ERROR) return status;
+ if (values.size() != std::size(mGain.values)) {
+ return BAD_VALUE;
+ }
+ std::copy(values.begin(), values.end(), mGain.values);
+ return status;
+}
+
+} // namespace android
diff --git a/media/libaudiofoundation/AudioProfile.cpp b/media/libaudiofoundation/AudioProfile.cpp
index 1ae18c5..91be346 100644
--- a/media/libaudiofoundation/AudioProfile.cpp
+++ b/media/libaudiofoundation/AudioProfile.cpp
@@ -118,6 +118,56 @@
}
}
+bool AudioProfile::equals(const sp<AudioProfile>& other) const
+{
+ return other != nullptr &&
+ mName.compare(other->mName) == 0 &&
+ mFormat == other->getFormat() &&
+ mChannelMasks == other->getChannels() &&
+ mSamplingRates == other->getSampleRates() &&
+ mIsDynamicFormat == other->isDynamicFormat() &&
+ mIsDynamicChannels == other->isDynamicChannels() &&
+ mIsDynamicRate == other->isDynamicRate();
+}
+
+status_t AudioProfile::writeToParcel(Parcel *parcel) const
+{
+ status_t status = NO_ERROR;
+ if ((status = parcel->writeUtf8AsUtf16(mName)) != NO_ERROR) return status;
+ if ((status = parcel->writeUint32(mFormat)) != NO_ERROR) return status;
+ std::vector<int> values(mChannelMasks.begin(), mChannelMasks.end());
+ if ((status = parcel->writeInt32Vector(values)) != NO_ERROR) return status;
+ values.clear();
+ values.assign(mSamplingRates.begin(), mSamplingRates.end());
+ if ((status = parcel->writeInt32Vector(values)) != NO_ERROR) return status;
+ if ((status = parcel->writeBool(mIsDynamicFormat)) != NO_ERROR) return status;
+ if ((status = parcel->writeBool(mIsDynamicChannels)) != NO_ERROR) return status;
+ if ((status = parcel->writeBool(mIsDynamicRate)) != NO_ERROR) return status;
+ return status;
+}
+
+status_t AudioProfile::readFromParcel(const Parcel *parcel)
+{
+ status_t status = NO_ERROR;
+ if ((status = parcel->readUtf8FromUtf16(&mName)) != NO_ERROR) return status;
+ static_assert(sizeof(mFormat) == sizeof(uint32_t));
+ if ((status = parcel->readUint32(reinterpret_cast<uint32_t*>(&mFormat))) != NO_ERROR) {
+ return status;
+ }
+ std::vector<int> values;
+ if ((status = parcel->readInt32Vector(&values)) != NO_ERROR) return status;
+ mChannelMasks.clear();
+ mChannelMasks.insert(values.begin(), values.end());
+ values.clear();
+ if ((status = parcel->readInt32Vector(&values)) != NO_ERROR) return status;
+ mSamplingRates.clear();
+ mSamplingRates.insert(values.begin(), values.end());
+ if ((status = parcel->readBool(&mIsDynamicFormat)) != NO_ERROR) return status;
+ if ((status = parcel->readBool(&mIsDynamicChannels)) != NO_ERROR) return status;
+ if ((status = parcel->readBool(&mIsDynamicRate)) != NO_ERROR) return status;
+ return status;
+}
+
ssize_t AudioProfileVector::add(const sp<AudioProfile> &profile)
{
ssize_t index = size();
@@ -219,4 +269,39 @@
}
}
+status_t AudioProfileVector::writeToParcel(Parcel *parcel) const
+{
+ status_t status = NO_ERROR;
+ if ((status = parcel->writeVectorSize(*this)) != NO_ERROR) return status;
+ for (const auto &audioProfile : *this) {
+ if ((status = parcel->writeParcelable(*audioProfile)) != NO_ERROR) {
+ break;
+ }
+ }
+ return status;
+}
+
+status_t AudioProfileVector::readFromParcel(const Parcel *parcel)
+{
+ status_t status = NO_ERROR;
+ this->clear();
+ if ((status = parcel->resizeOutVector(this)) != NO_ERROR) return status;
+ for (size_t i = 0; i < this->size(); ++i) {
+ this->at(i) = new AudioProfile(AUDIO_FORMAT_DEFAULT, AUDIO_CHANNEL_NONE, 0 /*sampleRate*/);
+ if ((status = parcel->readParcelable(this->at(i).get())) != NO_ERROR) {
+ this->clear();
+ break;
+ }
+ }
+ return status;
+}
+
+bool AudioProfileVector::equals(const AudioProfileVector& other) const
+{
+ return std::equal(begin(), end(), other.begin(), other.end(),
+ [](const sp<AudioProfile>& left, const sp<AudioProfile>& right) {
+ return left->equals(right);
+ });
+}
+
} // namespace android
diff --git a/media/libaudiofoundation/DeviceDescriptorBase.cpp b/media/libaudiofoundation/DeviceDescriptorBase.cpp
index f92c05d..18fd184 100644
--- a/media/libaudiofoundation/DeviceDescriptorBase.cpp
+++ b/media/libaudiofoundation/DeviceDescriptorBase.cpp
@@ -110,4 +110,33 @@
AudioPort::log(" ");
}
+bool DeviceDescriptorBase::equals(const sp<DeviceDescriptorBase> &other) const
+{
+ return other != nullptr &&
+ static_cast<const AudioPort*>(this)->equals(other) &&
+ static_cast<const AudioPortConfig*>(this)->equals(other) &&
+ mAddress.compare(other->address()) == 0 &&
+ mDeviceType == other->type();
+}
+
+status_t DeviceDescriptorBase::writeToParcel(Parcel *parcel) const
+{
+ status_t status = NO_ERROR;
+ if ((status = AudioPort::writeToParcel(parcel)) != NO_ERROR) return status;
+ if ((status = AudioPortConfig::writeToParcel(parcel)) != NO_ERROR) return status;
+ if ((status = parcel->writeUtf8AsUtf16(mAddress)) != NO_ERROR) return status;
+ if ((status = parcel->writeUint32(mDeviceType)) != NO_ERROR) return status;
+ return status;
+}
+
+status_t DeviceDescriptorBase::readFromParcel(const Parcel *parcel)
+{
+ status_t status = NO_ERROR;
+ if ((status = AudioPort::readFromParcel(parcel)) != NO_ERROR) return status;
+ if ((status = AudioPortConfig::readFromParcel(parcel)) != NO_ERROR) return status;
+ if ((status = parcel->readUtf8FromUtf16(&mAddress)) != NO_ERROR) return status;
+ if ((status = parcel->readUint32(&mDeviceType)) != NO_ERROR) return status;
+ return status;
+}
+
} // namespace android
diff --git a/media/libaudiofoundation/TEST_MAPPING b/media/libaudiofoundation/TEST_MAPPING
new file mode 100644
index 0000000..f6d249a
--- /dev/null
+++ b/media/libaudiofoundation/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "audiofoundation_parcelable_test"
+ }
+ ]
+}
diff --git a/media/libaudiofoundation/include/media/AudioContainers.h b/media/libaudiofoundation/include/media/AudioContainers.h
index 3313224..8347c71 100644
--- a/media/libaudiofoundation/include/media/AudioContainers.h
+++ b/media/libaudiofoundation/include/media/AudioContainers.h
@@ -16,19 +16,37 @@
#pragma once
+#include <algorithm>
+#include <iterator>
#include <set>
#include <vector>
+#include <media/TypeConverter.h>
#include <system/audio.h>
namespace android {
using ChannelMaskSet = std::set<audio_channel_mask_t>;
+using DeviceTypeSet = std::set<audio_devices_t>;
using FormatSet = std::set<audio_format_t>;
using SampleRateSet = std::set<uint32_t>;
using FormatVector = std::vector<audio_format_t>;
+const DeviceTypeSet& getAudioDeviceOutAllSet();
+const DeviceTypeSet& getAudioDeviceOutAllA2dpSet();
+const DeviceTypeSet& getAudioDeviceOutAllScoSet();
+const DeviceTypeSet& getAudioDeviceInAllSet();
+
+template<typename T>
+static std::vector<T> Intersection(const std::set<T>& a, const std::set<T>& b) {
+ std::vector<T> intersection;
+ std::set_intersection(a.begin(), a.end(),
+ b.begin(), b.end(),
+ std::back_inserter(intersection));
+ return intersection;
+}
+
static inline ChannelMaskSet asInMask(const ChannelMaskSet& channelMasks) {
ChannelMaskSet inMaskSet;
for (const auto &channel : channelMasks) {
@@ -49,4 +67,55 @@
return outMaskSet;
}
+static inline bool isSingleDeviceType(const DeviceTypeSet& deviceTypes,
+ audio_devices_t deviceType) {
+ return deviceTypes.size() == 1 && *(deviceTypes.begin()) == deviceType;
+}
+
+typedef bool (*DeviceTypeUnaryPredicate)(audio_devices_t);
+static inline bool isSingleDeviceType(const DeviceTypeSet& deviceTypes,
+ DeviceTypeUnaryPredicate p) {
+ return deviceTypes.size() == 1 && p(*(deviceTypes.begin()));
+}
+
+static inline void resetDeviceTypes(DeviceTypeSet& deviceTypes, audio_devices_t typeToAdd) {
+ deviceTypes.clear();
+ deviceTypes.insert(typeToAdd);
+}
+
+// FIXME: This is temporary helper function. Remove this when getting rid of all
+// bit mask usages of audio device types.
+static inline audio_devices_t deviceTypesToBitMask(const DeviceTypeSet& deviceTypes) {
+ audio_devices_t types = AUDIO_DEVICE_NONE;
+ for (auto deviceType : deviceTypes) {
+ types |= deviceType;
+ }
+ return types;
+}
+
+// FIXME: This is temporary helper function. Remove this when getting rid of all
+// bit mask usages of audio device types.
+static inline DeviceTypeSet deviceTypesFromBitMask(audio_devices_t types) {
+ DeviceTypeSet deviceTypes;
+ if ((types & AUDIO_DEVICE_BIT_IN) == 0) {
+ for (auto deviceType : AUDIO_DEVICE_OUT_ALL_ARRAY) {
+ if ((types & deviceType) == deviceType) {
+ deviceTypes.insert(deviceType);
+ }
+ }
+ } else {
+ for (auto deviceType : AUDIO_DEVICE_IN_ALL_ARRAY) {
+ if ((types & deviceType) == deviceType) {
+ deviceTypes.insert(deviceType);
+ }
+ }
+ }
+ return deviceTypes;
+}
+
+bool deviceTypesToString(const DeviceTypeSet& deviceTypes, std::string &str);
+
+std::string dumpDeviceTypes(const DeviceTypeSet& deviceTypes);
+
+
} // namespace android
\ No newline at end of file
diff --git a/media/libaudiofoundation/include/media/AudioGain.h b/media/libaudiofoundation/include/media/AudioGain.h
index 6a7fb55..859f1e7 100644
--- a/media/libaudiofoundation/include/media/AudioGain.h
+++ b/media/libaudiofoundation/include/media/AudioGain.h
@@ -67,6 +67,8 @@
const struct audio_gain &getGain() const { return mGain; }
+ bool equals(const sp<AudioGain>& other) const;
+
status_t writeToParcel(Parcel* parcel) const override;
status_t readFromParcel(const Parcel* parcel) override;
@@ -96,6 +98,8 @@
return 0;
}
+ bool equals(const AudioGains& other) const;
+
status_t writeToParcel(Parcel* parcel) const override;
status_t readFromParcel(const Parcel* parcel) override;
};
diff --git a/media/libaudiofoundation/include/media/AudioPort.h b/media/libaudiofoundation/include/media/AudioPort.h
index b8d54de..3c013cb 100644
--- a/media/libaudiofoundation/include/media/AudioPort.h
+++ b/media/libaudiofoundation/include/media/AudioPort.h
@@ -18,6 +18,8 @@
#include <string>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
#include <media/AudioGain.h>
#include <media/AudioProfile.h>
#include <utils/Errors.h>
@@ -27,7 +29,7 @@
namespace android {
-class AudioPort : public virtual RefBase
+class AudioPort : public virtual RefBase, public virtual Parcelable
{
public:
AudioPort(const std::string& name, audio_port_type_t type, audio_port_role_t role) :
@@ -79,6 +81,11 @@
void log(const char* indent) const;
+ bool equals(const sp<AudioPort>& other) const;
+
+ status_t writeToParcel(Parcel* parcel) const override;
+ status_t readFromParcel(const Parcel* parcel) override;
+
AudioGains mGains; // gain controllers
protected:
std::string mName;
@@ -88,7 +95,7 @@
};
-class AudioPortConfig : public virtual RefBase
+class AudioPortConfig : public virtual RefBase, public virtual Parcelable
{
public:
virtual ~AudioPortConfig() = default;
@@ -108,6 +115,11 @@
bool hasGainController(bool canUseForVolume = false) const;
+ bool equals(const sp<AudioPortConfig>& other) const;
+
+ status_t writeToParcel(Parcel* parcel) const override;
+ status_t readFromParcel(const Parcel* parcel) override;
+
protected:
unsigned int mSamplingRate = 0u;
audio_format_t mFormat = AUDIO_FORMAT_INVALID;
diff --git a/media/libaudiofoundation/include/media/AudioProfile.h b/media/libaudiofoundation/include/media/AudioProfile.h
index f4c2e12..730138a 100644
--- a/media/libaudiofoundation/include/media/AudioProfile.h
+++ b/media/libaudiofoundation/include/media/AudioProfile.h
@@ -19,13 +19,15 @@
#include <string>
#include <vector>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
#include <media/AudioContainers.h>
#include <system/audio.h>
#include <utils/RefBase.h>
namespace android {
-class AudioProfile final : public RefBase
+class AudioProfile final : public RefBase, public Parcelable
{
public:
static sp<AudioProfile> createFullDynamic(audio_format_t dynamicFormat = AUDIO_FORMAT_DEFAULT);
@@ -66,6 +68,11 @@
void dump(std::string *dst, int spaces) const;
+ bool equals(const sp<AudioProfile>& other) const;
+
+ status_t writeToParcel(Parcel* parcel) const override;
+ status_t readFromParcel(const Parcel* parcel) override;
+
private:
std::string mName;
audio_format_t mFormat; // The format for an audio profile should only be set when initialized.
@@ -77,7 +84,7 @@
bool mIsDynamicRate = false;
};
-class AudioProfileVector : public std::vector<sp<AudioProfile>>
+class AudioProfileVector : public std::vector<sp<AudioProfile>>, public Parcelable
{
public:
virtual ~AudioProfileVector() = default;
@@ -99,6 +106,11 @@
bool hasDynamicRateFor(audio_format_t format) const;
virtual void dump(std::string *dst, int spaces) const;
+
+ bool equals(const AudioProfileVector& other) const;
+
+ status_t writeToParcel(Parcel* parcel) const override;
+ status_t readFromParcel(const Parcel* parcel) override;
};
bool operator == (const AudioProfile &left, const AudioProfile &right);
diff --git a/media/libaudiofoundation/include/media/DeviceDescriptorBase.h b/media/libaudiofoundation/include/media/DeviceDescriptorBase.h
index bbe0517..6a34b4d 100644
--- a/media/libaudiofoundation/include/media/DeviceDescriptorBase.h
+++ b/media/libaudiofoundation/include/media/DeviceDescriptorBase.h
@@ -16,6 +16,8 @@
#pragma once
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
#include <media/AudioPort.h>
#include <utils/Errors.h>
#include <cutils/config_utils.h>
@@ -51,6 +53,11 @@
void log() const;
std::string toString() const;
+ bool equals(const sp<DeviceDescriptorBase>& other) const;
+
+ status_t writeToParcel(Parcel* parcel) const override;
+ status_t readFromParcel(const Parcel* parcel) override;
+
protected:
std::string mAddress{""};
audio_devices_t mDeviceType;
diff --git a/media/libaudiofoundation/tests/Android.bp b/media/libaudiofoundation/tests/Android.bp
new file mode 100644
index 0000000..f258b14
--- /dev/null
+++ b/media/libaudiofoundation/tests/Android.bp
@@ -0,0 +1,25 @@
+cc_test {
+ name: "audiofoundation_parcelable_test",
+
+ shared_libs: [
+ "libaudiofoundation",
+ "libbinder",
+ "liblog",
+ "libutils",
+ ],
+
+ header_libs: [
+ "libaudio_system_headers",
+ ],
+
+ srcs: [
+ "audiofoundation_parcelable_test.cpp",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ test_suites: ["device-tests"],
+}
diff --git a/media/libaudiofoundation/tests/audiofoundation_parcelable_test.cpp b/media/libaudiofoundation/tests/audiofoundation_parcelable_test.cpp
new file mode 100644
index 0000000..5baa072
--- /dev/null
+++ b/media/libaudiofoundation/tests/audiofoundation_parcelable_test.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2019 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 "audiofoundation_parcelable_test"
+
+#include <gtest/gtest.h>
+
+#include <binder/IServiceManager.h>
+#include <binder/Parcelable.h>
+#include <binder/ProcessState.h>
+#include <media/AudioGain.h>
+#include <media/AudioPort.h>
+#include <media/AudioProfile.h>
+#include <media/DeviceDescriptorBase.h>
+#include <utils/Log.h>
+#include <utils/String16.h>
+
+namespace android {
+
+static const audio_port_config TEST_AUDIO_PORT_CONFIG = {
+ .id = 0,
+ .role = AUDIO_PORT_ROLE_SINK,
+ .type = AUDIO_PORT_TYPE_DEVICE,
+ .config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE | AUDIO_PORT_CONFIG_CHANNEL_MASK |
+ AUDIO_PORT_CONFIG_FORMAT | AUDIO_PORT_CONFIG_GAIN,
+ .sample_rate = 48000,
+ .channel_mask = AUDIO_CHANNEL_OUT_STEREO,
+ .format = AUDIO_FORMAT_PCM_16_BIT,
+ .gain = {
+ .index = 0,
+ .mode = AUDIO_GAIN_MODE_JOINT,
+ .channel_mask = AUDIO_CHANNEL_OUT_STEREO,
+ }
+};
+
+class AudioPortConfigTestStub : public AudioPortConfig {
+public:
+ sp<AudioPort> getAudioPort() const override { return nullptr; }
+};
+
+AudioGains getAudioGainsForTest() {
+ AudioGains audioGains;
+ sp<AudioGain> audioGain = new AudioGain(0 /*index*/, false /*useInChannelMask*/);
+ audioGain->setMode(AUDIO_GAIN_MODE_JOINT);
+ audioGain->setChannelMask(AUDIO_CHANNEL_OUT_STEREO);
+ audioGain->setMinValueInMb(-3200);
+ audioGain->setMaxValueInMb(600);
+ audioGain->setDefaultValueInMb(0);
+ audioGain->setStepValueInMb(100);
+ audioGain->setMinRampInMs(100);
+ audioGain->setMaxRampInMs(500);
+ audioGains.push_back(audioGain);
+ return audioGains;
+}
+
+AudioProfileVector getAudioProfileVectorForTest() {
+ AudioProfileVector audioProfiles;
+ sp<AudioProfile> audioProfile = AudioProfile::createFullDynamic();
+ audioProfile->setChannels({AUDIO_CHANNEL_OUT_MONO, AUDIO_CHANNEL_OUT_STEREO});
+ audioProfile->setSampleRates({48000});
+ audioProfiles.add(audioProfile);
+ return audioProfiles;
+}
+
+TEST(AudioFoundationParcelableTest, ParcelingAudioGain) {
+ Parcel data;
+ AudioGains audioGains = getAudioGainsForTest();
+
+ ASSERT_EQ(data.writeParcelable(audioGains), NO_ERROR);
+ data.setDataPosition(0);
+ AudioGains audioGainsFromParcel;
+ ASSERT_EQ(data.readParcelable(&audioGainsFromParcel), NO_ERROR);
+ ASSERT_TRUE(audioGainsFromParcel.equals(audioGains));
+}
+
+TEST(AudioFoundationParcelableTest, ParcelingAudioProfileVector) {
+ Parcel data;
+ AudioProfileVector audioProfiles = getAudioProfileVectorForTest();
+
+ ASSERT_EQ(data.writeParcelable(audioProfiles), NO_ERROR);
+ data.setDataPosition(0);
+ AudioProfileVector audioProfilesFromParcel;
+ ASSERT_EQ(data.readParcelable(&audioProfilesFromParcel), NO_ERROR);
+ ASSERT_TRUE(audioProfilesFromParcel.equals(audioProfiles));
+}
+
+TEST(AudioFoundationParcelableTest, ParcelingAudioPort) {
+ Parcel data;
+ sp<AudioPort> audioPort = new AudioPort(
+ "AudioPortName", AUDIO_PORT_TYPE_DEVICE, AUDIO_PORT_ROLE_SINK);
+ audioPort->setGains(getAudioGainsForTest());
+ audioPort->setAudioProfiles(getAudioProfileVectorForTest());
+
+ ASSERT_EQ(data.writeParcelable(*audioPort), NO_ERROR);
+ data.setDataPosition(0);
+ sp<AudioPort> audioPortFromParcel = new AudioPort(
+ "", AUDIO_PORT_TYPE_NONE, AUDIO_PORT_ROLE_NONE);
+ ASSERT_EQ(data.readParcelable(audioPortFromParcel.get()), NO_ERROR);
+ ASSERT_TRUE(audioPortFromParcel->equals(audioPort));
+}
+
+TEST(AudioFoundationParcelableTest, ParcelingAudioPortConfig) {
+ Parcel data;
+ sp<AudioPortConfig> audioPortConfig = new AudioPortConfigTestStub();
+ audioPortConfig->applyAudioPortConfig(&TEST_AUDIO_PORT_CONFIG);
+
+ ASSERT_EQ(data.writeParcelable(*audioPortConfig), NO_ERROR);
+ data.setDataPosition(0);
+ sp<AudioPortConfig> audioPortConfigFromParcel = new AudioPortConfigTestStub();
+ ASSERT_EQ(data.readParcelable(audioPortConfigFromParcel.get()), NO_ERROR);
+ ASSERT_TRUE(audioPortConfigFromParcel->equals(audioPortConfig));
+}
+
+TEST(AudioFoundationParcelableTest, ParcelingDeviceDescriptorBase) {
+ Parcel data;
+ sp<DeviceDescriptorBase> desc = new DeviceDescriptorBase(AUDIO_DEVICE_OUT_SPEAKER);
+ desc->setGains(getAudioGainsForTest());
+ desc->setAudioProfiles(getAudioProfileVectorForTest());
+ desc->applyAudioPortConfig(&TEST_AUDIO_PORT_CONFIG);
+ desc->setAddress("DeviceDescriptorBaseTestAddress");
+
+ ASSERT_EQ(data.writeParcelable(*desc), NO_ERROR);
+ data.setDataPosition(0);
+ sp<DeviceDescriptorBase> descFromParcel = new DeviceDescriptorBase(AUDIO_DEVICE_NONE);
+ ASSERT_EQ(data.readParcelable(descFromParcel.get()), NO_ERROR);
+ ASSERT_TRUE(descFromParcel->equals(desc));
+}
+
+} // namespace android
diff --git a/media/libaudiohal/Android.bp b/media/libaudiohal/Android.bp
index 5837fcf..74b48f3 100644
--- a/media/libaudiohal/Android.bp
+++ b/media/libaudiohal/Android.bp
@@ -16,6 +16,7 @@
"libaudiohal@2.0",
"libaudiohal@4.0",
"libaudiohal@5.0",
+ "libaudiohal@6.0",
"libutils",
],
diff --git a/media/libaudiohal/impl/Android.bp b/media/libaudiohal/impl/Android.bp
index d4a4f41..8669e2a 100644
--- a/media/libaudiohal/impl/Android.bp
+++ b/media/libaudiohal/impl/Android.bp
@@ -43,6 +43,7 @@
],
header_libs: [
"android.hardware.audio.common.util@all-versions",
+ "libaudioclient_headers",
"libaudiohal_headers"
],
@@ -98,3 +99,20 @@
"-include common/all-versions/VersionMacro.h",
]
}
+
+cc_library_shared {
+ name: "libaudiohal@6.0",
+ defaults: ["libaudiohal_default"],
+ shared_libs: [
+ "android.hardware.audio.common@6.0",
+ "android.hardware.audio.common@6.0-util",
+ "android.hardware.audio.effect@6.0",
+ "android.hardware.audio@6.0",
+ ],
+ cflags: [
+ "-DMAJOR_VERSION=6",
+ "-DMINOR_VERSION=0",
+ "-include common/all-versions/VersionMacro.h",
+ ]
+}
+
diff --git a/media/libaudiohal/impl/include/libaudiohal/FactoryHalHidl.h b/media/libaudiohal/impl/include/libaudiohal/FactoryHalHidl.h
index 829f99c..271bafc 100644
--- a/media/libaudiohal/impl/include/libaudiohal/FactoryHalHidl.h
+++ b/media/libaudiohal/impl/include/libaudiohal/FactoryHalHidl.h
@@ -34,6 +34,7 @@
* the preferred available impl.
*/
enum class AudioHALVersion {
+ V6_0,
V5_0,
V4_0,
V2_0,
diff --git a/media/libaudioprocessing/Android.bp b/media/libaudioprocessing/Android.bp
index e8aa700..9b5d58c 100644
--- a/media/libaudioprocessing/Android.bp
+++ b/media/libaudioprocessing/Android.bp
@@ -33,6 +33,7 @@
header_libs: [
"libbase_headers",
+ "libmedia_headers"
],
shared_libs: [
diff --git a/media/libmedia/include/media/RecordBufferConverter.h b/media/libaudioprocessing/include/media/RecordBufferConverter.h
similarity index 100%
rename from media/libmedia/include/media/RecordBufferConverter.h
rename to media/libaudioprocessing/include/media/RecordBufferConverter.h
diff --git a/media/libaudioprocessing/tests/Android.bp b/media/libaudioprocessing/tests/Android.bp
index d990111..20c2c2c 100644
--- a/media/libaudioprocessing/tests/Android.bp
+++ b/media/libaudioprocessing/tests/Android.bp
@@ -3,8 +3,13 @@
cc_defaults {
name: "libaudioprocessing_test_defaults",
- header_libs: ["libbase_headers"],
+ header_libs: [
+ "libbase_headers",
+ "libmedia_headers",
+ ],
+
shared_libs: [
+ "libaudioclient",
"libaudioprocessing",
"libaudioutils",
"libcutils",
diff --git a/media/libaudioprocessing/tests/fuzzer/Android.bp b/media/libaudioprocessing/tests/fuzzer/Android.bp
new file mode 100644
index 0000000..1df47b7
--- /dev/null
+++ b/media/libaudioprocessing/tests/fuzzer/Android.bp
@@ -0,0 +1,10 @@
+cc_fuzz {
+ name: "libaudioprocessing_resampler_fuzzer",
+ srcs: [
+ "libaudioprocessing_resampler_fuzzer.cpp",
+ ],
+ defaults: ["libaudioprocessing_test_defaults"],
+ static_libs: [
+ "libsndfile",
+ ],
+}
diff --git a/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_resampler_fuzzer.cpp b/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_resampler_fuzzer.cpp
new file mode 100644
index 0000000..938c610
--- /dev/null
+++ b/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_resampler_fuzzer.cpp
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/macros.h>
+#include <audio_utils/primitives.h>
+#include <audio_utils/sndfile.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <math.h>
+#include <media/AudioBufferProvider.h>
+#include <media/AudioResampler.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+#include <utils/Vector.h>
+
+#include <memory>
+
+using namespace android;
+
+const int MAX_FRAMES = 10;
+const int MIN_FREQ = 1e3;
+const int MAX_FREQ = 100e3;
+
+const AudioResampler::src_quality qualities[] = {
+ AudioResampler::DEFAULT_QUALITY,
+ AudioResampler::LOW_QUALITY,
+ AudioResampler::MED_QUALITY,
+ AudioResampler::HIGH_QUALITY,
+ AudioResampler::VERY_HIGH_QUALITY,
+ AudioResampler::DYN_LOW_QUALITY,
+ AudioResampler::DYN_MED_QUALITY,
+ AudioResampler::DYN_HIGH_QUALITY,
+};
+
+class Provider : public AudioBufferProvider {
+ const void* mAddr; // base address
+ const size_t mNumFrames; // total frames
+ const size_t mFrameSize; // size of each frame in bytes
+ size_t mNextFrame; // index of next frame to provide
+ size_t mUnrel; // number of frames not yet released
+ public:
+ Provider(const void* addr, size_t frames, size_t frameSize)
+ : mAddr(addr),
+ mNumFrames(frames),
+ mFrameSize(frameSize),
+ mNextFrame(0),
+ mUnrel(0) {}
+ status_t getNextBuffer(Buffer* buffer) override {
+ if (buffer->frameCount > mNumFrames - mNextFrame) {
+ buffer->frameCount = mNumFrames - mNextFrame;
+ }
+ mUnrel = buffer->frameCount;
+ if (buffer->frameCount > 0) {
+ buffer->raw = (char*)mAddr + mFrameSize * mNextFrame;
+ return NO_ERROR;
+ } else {
+ buffer->raw = nullptr;
+ return NOT_ENOUGH_DATA;
+ }
+ }
+ virtual void releaseBuffer(Buffer* buffer) {
+ if (buffer->frameCount > mUnrel) {
+ mNextFrame += mUnrel;
+ mUnrel = 0;
+ } else {
+ mNextFrame += buffer->frameCount;
+ mUnrel -= buffer->frameCount;
+ }
+ buffer->frameCount = 0;
+ buffer->raw = nullptr;
+ }
+ void reset() { mNextFrame = 0; }
+};
+
+audio_format_t chooseFormat(AudioResampler::src_quality quality,
+ uint8_t input_byte) {
+ switch (quality) {
+ case AudioResampler::DYN_LOW_QUALITY:
+ case AudioResampler::DYN_MED_QUALITY:
+ case AudioResampler::DYN_HIGH_QUALITY:
+ if (input_byte % 2) {
+ return AUDIO_FORMAT_PCM_FLOAT;
+ }
+ FALLTHROUGH_INTENDED;
+ default:
+ return AUDIO_FORMAT_PCM_16_BIT;
+ }
+}
+
+int parseValue(const uint8_t* src, int index, void* dst, size_t size) {
+ memcpy(dst, &src[index], size);
+ return size;
+}
+
+bool validFreq(int freq) { return freq > MIN_FREQ && freq < MAX_FREQ; }
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ int input_freq = 0;
+ int output_freq = 0;
+ int input_channels = 0;
+
+ float left_volume = 0;
+ float right_volume = 0;
+
+ size_t metadata_size = 2 + 3 * sizeof(int) + 2 * sizeof(float);
+ if (size < metadata_size) {
+ // not enough data to set options
+ return 0;
+ }
+
+ AudioResampler::src_quality quality = qualities[data[0] % 8];
+ audio_format_t format = chooseFormat(quality, data[1]);
+
+ int index = 2;
+
+ index += parseValue(data, index, &input_freq, sizeof(int));
+ index += parseValue(data, index, &output_freq, sizeof(int));
+ index += parseValue(data, index, &input_channels, sizeof(int));
+
+ index += parseValue(data, index, &left_volume, sizeof(float));
+ index += parseValue(data, index, &right_volume, sizeof(float));
+
+ if (!validFreq(input_freq) || !validFreq(output_freq)) {
+ // sampling frequencies must be reasonable
+ return 0;
+ }
+
+ if (input_channels < 1 ||
+ input_channels > (quality < AudioResampler::DYN_LOW_QUALITY ? 2 : 8)) {
+ // invalid number of input channels
+ return 0;
+ }
+
+ size_t single_channel_size =
+ format == AUDIO_FORMAT_PCM_FLOAT ? sizeof(float) : sizeof(int16_t);
+ size_t input_frame_size = single_channel_size * input_channels;
+ size_t input_size = size - metadata_size;
+ uint8_t input_data[input_size];
+ memcpy(input_data, &data[metadata_size], input_size);
+
+ size_t input_frames = input_size / input_frame_size;
+ if (input_frames > MAX_FRAMES) {
+ return 0;
+ }
+
+ Provider provider(input_data, input_frames, input_frame_size);
+
+ std::unique_ptr<AudioResampler> resampler(
+ AudioResampler::create(format, input_channels, output_freq, quality));
+
+ resampler->setSampleRate(input_freq);
+ resampler->setVolume(left_volume, right_volume);
+
+ // output is at least stereo samples
+ int output_channels = input_channels > 2 ? input_channels : 2;
+ size_t output_frame_size = output_channels * sizeof(int32_t);
+ size_t output_frames = (input_frames * output_freq) / input_freq;
+ size_t output_size = output_frames * output_frame_size;
+
+ uint8_t output_data[output_size];
+ for (size_t i = 0; i < output_frames; i++) {
+ memset(output_data, 0, output_size);
+ resampler->resample((int*)output_data, i, &provider);
+ }
+
+ return 0;
+}
diff --git a/media/libcpustats/Android.bp b/media/libcpustats/Android.bp
index 8fcd8a4..6e8ca1d 100644
--- a/media/libcpustats/Android.bp
+++ b/media/libcpustats/Android.bp
@@ -6,6 +6,14 @@
"ThreadCpuUsage.cpp",
],
+ local_include_dirs: [
+ "include",
+ ],
+
+ export_include_dirs: [
+ "include",
+ ],
+
cflags: [
"-Werror",
"-Wall",
diff --git a/media/libdatasource/Android.bp b/media/libdatasource/Android.bp
new file mode 100644
index 0000000..f191c21
--- /dev/null
+++ b/media/libdatasource/Android.bp
@@ -0,0 +1,63 @@
+cc_library {
+ name: "libdatasource",
+
+ srcs: [
+ "DataSourceFactory.cpp",
+ "DataURISource.cpp",
+ "FileSource.cpp",
+ "HTTPBase.cpp",
+ "MediaHTTP.cpp",
+ "NuCachedSource2.cpp",
+ ],
+
+ aidl: {
+ local_include_dirs: ["aidl"],
+ export_aidl_headers: true,
+ },
+
+ header_libs: [
+ "libstagefright_headers",
+ "media_ndk_headers",
+ "libmedia_headers",
+ ],
+
+ export_header_lib_headers: [
+ "libstagefright_headers",
+ "media_ndk_headers",
+ ],
+
+ shared_libs: [
+ "liblog",
+ "libcutils",
+ "libutils",
+ "libstagefright_foundation",
+ "libdl",
+ ],
+
+ static_libs: [
+ "libc_malloc_debug_backtrace", // for memory heap analysis
+ "libmedia_midiiowrapper",
+ ],
+
+ local_include_dirs: [
+ "include",
+ ],
+
+ export_include_dirs: [
+ "include",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wno-error=deprecated-declarations",
+ "-Wall",
+ ],
+
+ sanitize: {
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ cfi: true,
+ },
+}
diff --git a/media/libstagefright/DataSourceFactory.cpp b/media/libdatasource/DataSourceFactory.cpp
similarity index 72%
rename from media/libstagefright/DataSourceFactory.cpp
rename to media/libdatasource/DataSourceFactory.cpp
index 54bf0cc..bb6a08c 100644
--- a/media/libstagefright/DataSourceFactory.cpp
+++ b/media/libdatasource/DataSourceFactory.cpp
@@ -16,20 +16,33 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "DataSource"
-#include "include/HTTPBase.h"
-#include "include/NuCachedSource2.h"
+#include <datasource/DataSourceFactory.h>
+#include <datasource/DataURISource.h>
+#include <datasource/HTTPBase.h>
+#include <datasource/FileSource.h>
+#include <datasource/MediaHTTP.h>
+#include <datasource/NuCachedSource2.h>
#include <media/MediaHTTPConnection.h>
#include <media/MediaHTTPService.h>
-#include <media/stagefright/DataSourceFactory.h>
-#include <media/stagefright/DataURISource.h>
-#include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaHTTP.h>
#include <utils/String8.h>
namespace android {
// static
+sp<DataSourceFactory> DataSourceFactory::sInstance;
+// static
+Mutex DataSourceFactory::sInstanceLock;
+
+// static
+sp<DataSourceFactory> DataSourceFactory::getInstance() {
+ Mutex::Autolock l(sInstanceLock);
+ if (!sInstance) {
+ sInstance = new DataSourceFactory();
+ }
+ return sInstance;
+}
+
sp<DataSource> DataSourceFactory::CreateFromURI(
const sp<MediaHTTPService> &httpService,
const char *uri,
@@ -42,20 +55,16 @@
sp<DataSource> source;
if (!strncasecmp("file://", uri, 7)) {
- source = new FileSource(uri + 7);
+ source = CreateFileSource(uri + 7);
} else if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
if (httpService == NULL) {
ALOGE("Invalid http service!");
return NULL;
}
- if (httpSource == NULL) {
- sp<MediaHTTPConnection> conn = httpService->makeHTTPConnection();
- if (conn == NULL) {
- ALOGE("Failed to make http connection from http service!");
- return NULL;
- }
- httpSource = new MediaHTTP(conn);
+ sp<HTTPBase> mediaHTTP = httpSource;
+ if (mediaHTTP == NULL) {
+ mediaHTTP = static_cast<HTTPBase *>(CreateMediaHTTP(httpService).get());
}
String8 cacheConfig;
@@ -69,24 +78,24 @@
&disconnectAtHighwatermark);
}
- if (httpSource->connect(uri, &nonCacheSpecificHeaders) != OK) {
+ if (mediaHTTP->connect(uri, &nonCacheSpecificHeaders) != OK) {
ALOGE("Failed to connect http source!");
return NULL;
}
if (contentType != NULL) {
- *contentType = httpSource->getMIMEType();
+ *contentType = mediaHTTP->getMIMEType();
}
source = NuCachedSource2::Create(
- httpSource,
+ mediaHTTP,
cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
disconnectAtHighwatermark);
} else if (!strncasecmp("data:", uri, 5)) {
source = DataURISource::Create(uri);
} else {
// Assume it's a filename.
- source = new FileSource(uri);
+ source = CreateFileSource(uri);
}
if (source == NULL || source->initCheck() != OK) {
@@ -108,10 +117,15 @@
sp<MediaHTTPConnection> conn = httpService->makeHTTPConnection();
if (conn == NULL) {
+ ALOGE("Failed to make http connection from http service!");
return NULL;
} else {
return new MediaHTTP(conn);
}
}
+sp<DataSource> DataSourceFactory::CreateFileSource(const char *uri) {
+ return new FileSource(uri);
+}
+
} // namespace android
diff --git a/media/libstagefright/DataURISource.cpp b/media/libdatasource/DataURISource.cpp
similarity index 98%
rename from media/libstagefright/DataURISource.cpp
rename to media/libdatasource/DataURISource.cpp
index b975b38..216f3d0 100644
--- a/media/libstagefright/DataURISource.cpp
+++ b/media/libdatasource/DataURISource.cpp
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include <media/stagefright/DataURISource.h>
+#include <datasource/DataURISource.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/AString.h>
diff --git a/media/libstagefright/ClearFileSource.cpp b/media/libdatasource/FileSource.cpp
similarity index 85%
rename from media/libstagefright/ClearFileSource.cpp
rename to media/libdatasource/FileSource.cpp
index e3a2cb7..bbf7dda 100644
--- a/media/libstagefright/ClearFileSource.cpp
+++ b/media/libdatasource/FileSource.cpp
@@ -15,12 +15,12 @@
*/
//#define LOG_NDEBUG 0
-#define LOG_TAG "ClearFileSource"
+#define LOG_TAG "FileSource"
#include <utils/Log.h>
+#include <datasource/FileSource.h>
#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/ClearFileSource.h>
-#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
@@ -29,7 +29,7 @@
namespace android {
-ClearFileSource::ClearFileSource(const char *filename)
+FileSource::FileSource(const char *filename)
: mFd(-1),
mOffset(0),
mLength(-1),
@@ -48,7 +48,7 @@
}
}
-ClearFileSource::ClearFileSource(int fd, int64_t offset, int64_t length)
+FileSource::FileSource(int fd, int64_t offset, int64_t length)
: mFd(fd),
mOffset(offset),
mLength(length),
@@ -89,18 +89,18 @@
}
-ClearFileSource::~ClearFileSource() {
+FileSource::~FileSource() {
if (mFd >= 0) {
::close(mFd);
mFd = -1;
}
}
-status_t ClearFileSource::initCheck() const {
+status_t FileSource::initCheck() const {
return mFd >= 0 ? OK : NO_INIT;
}
-ssize_t ClearFileSource::readAt(off64_t offset, void *data, size_t size) {
+ssize_t FileSource::readAt(off64_t offset, void *data, size_t size) {
if (mFd < 0) {
return NO_INIT;
}
@@ -118,7 +118,7 @@
return readAt_l(offset, data, size);
}
-ssize_t ClearFileSource::readAt_l(off64_t offset, void *data, size_t size) {
+ssize_t FileSource::readAt_l(off64_t offset, void *data, size_t size) {
off64_t result = lseek64(mFd, offset + mOffset, SEEK_SET);
if (result == -1) {
ALOGE("seek to %lld failed", (long long)(offset + mOffset));
@@ -128,7 +128,7 @@
return ::read(mFd, data, size);
}
-status_t ClearFileSource::getSize(off64_t *size) {
+status_t FileSource::getSize(off64_t *size) {
Mutex::Autolock autoLock(mLock);
if (mFd < 0) {
diff --git a/media/libstagefright/HTTPBase.cpp b/media/libdatasource/HTTPBase.cpp
similarity index 98%
rename from media/libstagefright/HTTPBase.cpp
rename to media/libdatasource/HTTPBase.cpp
index d118e8c..ef29c48 100644
--- a/media/libstagefright/HTTPBase.cpp
+++ b/media/libdatasource/HTTPBase.cpp
@@ -18,7 +18,7 @@
#define LOG_TAG "HTTPBase"
#include <utils/Log.h>
-#include "include/HTTPBase.h"
+#include <datasource/HTTPBase.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
diff --git a/media/libstagefright/http/ClearMediaHTTP.cpp b/media/libdatasource/MediaHTTP.cpp
similarity index 82%
rename from media/libstagefright/http/ClearMediaHTTP.cpp
rename to media/libdatasource/MediaHTTP.cpp
index 9557c8a..58c1ce8 100644
--- a/media/libstagefright/http/ClearMediaHTTP.cpp
+++ b/media/libdatasource/MediaHTTP.cpp
@@ -15,30 +15,30 @@
*/
//#define LOG_NDEBUG 0
-#define LOG_TAG "ClearMediaHTTP"
+#define LOG_TAG "MediaHTTP"
#include <utils/Log.h>
-#include <media/stagefright/ClearMediaHTTP.h>
+#include <datasource/MediaHTTP.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#include <media/MediaHTTPConnection.h>
namespace android {
-ClearMediaHTTP::ClearMediaHTTP(const sp<MediaHTTPConnection> &conn)
+MediaHTTP::MediaHTTP(const sp<MediaHTTPConnection> &conn)
: mInitCheck((conn != NULL) ? OK : NO_INIT),
mHTTPConnection(conn),
mCachedSizeValid(false),
mCachedSize(0ll) {
}
-ClearMediaHTTP::~ClearMediaHTTP() {
+MediaHTTP::~MediaHTTP() {
}
-status_t ClearMediaHTTP::connect(
+status_t MediaHTTP::connect(
const char *uri,
const KeyedVector<String8, String8> *headers,
off64_t /* offset */) {
@@ -68,18 +68,18 @@
if (success) {
AString sanitized = uriDebugString(mLastURI);
- mName = String8::format("ClearMediaHTTP(%s)", sanitized.c_str());
+ mName = String8::format("MediaHTTP(%s)", sanitized.c_str());
}
return success ? OK : UNKNOWN_ERROR;
}
-void ClearMediaHTTP::close() {
+void MediaHTTP::close() {
disconnect();
}
-void ClearMediaHTTP::disconnect() {
- mName = String8("ClearMediaHTTP(<disconnected>)");
+void MediaHTTP::disconnect() {
+ mName = String8("MediaHTTP(<disconnected>)");
if (mInitCheck != OK) {
return;
}
@@ -87,11 +87,11 @@
mHTTPConnection->disconnect();
}
-status_t ClearMediaHTTP::initCheck() const {
+status_t MediaHTTP::initCheck() const {
return mInitCheck;
}
-ssize_t ClearMediaHTTP::readAt(off64_t offset, void *data, size_t size) {
+ssize_t MediaHTTP::readAt(off64_t offset, void *data, size_t size) {
if (mInitCheck != OK) {
return mInitCheck;
}
@@ -127,7 +127,7 @@
return numBytesRead;
}
-status_t ClearMediaHTTP::getSize(off64_t *size) {
+status_t MediaHTTP::getSize(off64_t *size) {
if (mInitCheck != OK) {
return mInitCheck;
}
@@ -145,16 +145,16 @@
return *size < 0 ? *size : static_cast<status_t>(OK);
}
-uint32_t ClearMediaHTTP::flags() {
+uint32_t MediaHTTP::flags() {
return kWantsPrefetching | kIsHTTPBasedSource;
}
-status_t ClearMediaHTTP::reconnectAtOffset(off64_t offset) {
+status_t MediaHTTP::reconnectAtOffset(off64_t offset) {
return connect(mLastURI.c_str(), &mLastHeaders, offset);
}
-String8 ClearMediaHTTP::getUri() {
+String8 MediaHTTP::getUri() {
if (mInitCheck != OK) {
return String8::empty();
}
@@ -166,7 +166,7 @@
return String8(mLastURI.c_str());
}
-String8 ClearMediaHTTP::getMIMEType() const {
+String8 MediaHTTP::getMIMEType() const {
if (mInitCheck != OK) {
return String8("application/octet-stream");
}
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libdatasource/NuCachedSource2.cpp
similarity index 99%
rename from media/libstagefright/NuCachedSource2.cpp
rename to media/libdatasource/NuCachedSource2.cpp
index 522c81d..7f5ae61 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libdatasource/NuCachedSource2.cpp
@@ -20,8 +20,8 @@
#define LOG_TAG "NuCachedSource2"
#include <utils/Log.h>
-#include "include/NuCachedSource2.h"
-#include "include/HTTPBase.h"
+#include <datasource/NuCachedSource2.h>
+#include <datasource/HTTPBase.h>
#include <cutils/properties.h>
#include <media/stagefright/foundation/ADebug.h>
diff --git a/media/libstagefright/include/media/stagefright/DataSourceFactory.h b/media/libdatasource/include/datasource/DataSourceFactory.h
similarity index 66%
rename from media/libstagefright/include/media/stagefright/DataSourceFactory.h
rename to media/libdatasource/include/datasource/DataSourceFactory.h
index 2a1d491..194abe2 100644
--- a/media/libstagefright/include/media/stagefright/DataSourceFactory.h
+++ b/media/libdatasource/include/datasource/DataSourceFactory.h
@@ -18,7 +18,9 @@
#define DATA_SOURCE_FACTORY_H_
+#include <media/DataSource.h>
#include <sys/types.h>
+#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
namespace android {
@@ -27,17 +29,27 @@
class String8;
struct HTTPBase;
-class DataSourceFactory {
+class DataSourceFactory : public RefBase {
public:
- static sp<DataSource> CreateFromURI(
+ static sp<DataSourceFactory> getInstance();
+ sp<DataSource> CreateFromURI(
const sp<MediaHTTPService> &httpService,
const char *uri,
const KeyedVector<String8, String8> *headers = NULL,
String8 *contentType = NULL,
HTTPBase *httpSource = NULL);
- static sp<DataSource> CreateMediaHTTP(const sp<MediaHTTPService> &httpService);
- static sp<DataSource> CreateFromFd(int fd, int64_t offset, int64_t length);
+ virtual sp<DataSource> CreateMediaHTTP(const sp<MediaHTTPService> &httpService);
+ sp<DataSource> CreateFromFd(int fd, int64_t offset, int64_t length);
+
+protected:
+ virtual sp<DataSource> CreateFileSource(const char *uri);
+ DataSourceFactory() {};
+ virtual ~DataSourceFactory() {};
+
+private:
+ static sp<DataSourceFactory> sInstance;
+ static Mutex sInstanceLock;
};
} // namespace android
diff --git a/media/libstagefright/include/media/stagefright/DataURISource.h b/media/libdatasource/include/datasource/DataURISource.h
similarity index 100%
rename from media/libstagefright/include/media/stagefright/DataURISource.h
rename to media/libdatasource/include/datasource/DataURISource.h
diff --git a/media/libstagefright/include/media/stagefright/ClearFileSource.h b/media/libdatasource/include/datasource/FileSource.h
similarity index 74%
rename from media/libstagefright/include/media/stagefright/ClearFileSource.h
rename to media/libdatasource/include/datasource/FileSource.h
index be83748..dee0c33 100644
--- a/media/libstagefright/include/media/stagefright/ClearFileSource.h
+++ b/media/libdatasource/include/datasource/FileSource.h
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-#ifndef CLEAR_FILE_SOURCE_H_
+#ifndef FILE_SOURCE_H_
-#define CLEAR_FILE_SOURCE_H_
+#define FILE_SOURCE_H_
#include <stdio.h>
@@ -26,11 +26,11 @@
namespace android {
-class ClearFileSource : public DataSource {
+class FileSource : public DataSource {
public:
- ClearFileSource(const char *filename);
- // ClearFileSource takes ownership and will close the fd
- ClearFileSource(int fd, int64_t offset, int64_t length);
+ FileSource(const char *filename);
+ // FileSource takes ownership and will close the fd
+ FileSource(int fd, int64_t offset, int64_t length);
virtual status_t initCheck() const;
@@ -47,7 +47,7 @@
}
protected:
- virtual ~ClearFileSource();
+ virtual ~FileSource();
virtual ssize_t readAt_l(off64_t offset, void *data, size_t size);
int mFd;
@@ -58,11 +58,11 @@
private:
String8 mName;
- ClearFileSource(const ClearFileSource &);
- ClearFileSource &operator=(const ClearFileSource &);
+ FileSource(const FileSource &);
+ FileSource &operator=(const FileSource &);
};
} // namespace android
-#endif // CLEAR_FILE_SOURCE_H_
+#endif // FILE_SOURCE_H_
diff --git a/media/libstagefright/include/HTTPBase.h b/media/libdatasource/include/datasource/HTTPBase.h
similarity index 100%
rename from media/libstagefright/include/HTTPBase.h
rename to media/libdatasource/include/datasource/HTTPBase.h
diff --git a/media/libstagefright/include/media/stagefright/ClearMediaHTTP.h b/media/libdatasource/include/datasource/MediaHTTP.h
similarity index 83%
rename from media/libstagefright/include/media/stagefright/ClearMediaHTTP.h
rename to media/libdatasource/include/datasource/MediaHTTP.h
index 72907a9..a8d203b 100644
--- a/media/libstagefright/include/media/stagefright/ClearMediaHTTP.h
+++ b/media/libdatasource/include/datasource/MediaHTTP.h
@@ -14,20 +14,20 @@
* limitations under the License.
*/
-#ifndef CLEAR_MEDIA_HTTP_H_
+#ifndef MEDIA_HTTP_H_
-#define CLEAR_MEDIA_HTTP_H_
+#define MEDIA_HTTP_H_
#include <media/stagefright/foundation/AString.h>
-#include "include/HTTPBase.h"
+#include "HTTPBase.h"
namespace android {
struct MediaHTTPConnection;
-struct ClearMediaHTTP : public HTTPBase {
- ClearMediaHTTP(const sp<MediaHTTPConnection> &conn);
+struct MediaHTTP : public HTTPBase {
+ MediaHTTP(const sp<MediaHTTPConnection> &conn);
virtual status_t connect(
const char *uri,
@@ -49,7 +49,7 @@
virtual status_t reconnectAtOffset(off64_t offset);
protected:
- virtual ~ClearMediaHTTP();
+ virtual ~MediaHTTP();
virtual String8 getUri();
virtual String8 getMIMEType() const;
@@ -65,9 +65,9 @@
bool mCachedSizeValid;
off64_t mCachedSize;
- DISALLOW_EVIL_CONSTRUCTORS(ClearMediaHTTP);
+ DISALLOW_EVIL_CONSTRUCTORS(MediaHTTP);
};
} // namespace android
-#endif // CLEAR_MEDIA_HTTP_H_
+#endif // MEDIA_HTTP_H_
diff --git a/media/libstagefright/include/NuCachedSource2.h b/media/libdatasource/include/datasource/NuCachedSource2.h
similarity index 100%
rename from media/libstagefright/include/NuCachedSource2.h
rename to media/libdatasource/include/datasource/NuCachedSource2.h
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 81291a1..8e96e8c 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -2,7 +2,7 @@
name: "libmedia_headers",
vendor_available: true,
export_include_dirs: ["include"],
- header_libs:[
+ header_libs: [
"libbase_headers",
"libgui_headers",
"libstagefright_headers",
@@ -15,40 +15,29 @@
],
}
-cc_library {
- name: "libmedia_helper",
- vendor_available: true,
- vndk: {
- enabled: true,
- },
- double_loadable: true,
- srcs: ["AudioParameter.cpp", "TypeConverter.cpp"],
- cflags: [
- "-Werror",
- "-Wno-error=deprecated-declarations",
- "-Wall",
- ],
- shared_libs: ["libutils", "liblog"],
- header_libs: [
- "libmedia_headers",
- "libaudioclient_headers",
- "libaudio_system_headers",
- ],
- export_header_lib_headers: [
- "libmedia_headers",
- ],
- clang: true,
-}
-
filegroup {
name: "libmedia_omx_aidl",
srcs: [
- "aidl/android/IGraphicBufferSource.aidl",
"aidl/android/IOMXBufferSource.aidl",
],
path: "aidl",
}
+aidl_interface {
+ name: "resourcemanager_aidl_interface",
+ local_include_dir: "aidl",
+ srcs: [
+ "aidl/android/media/IResourceManagerClient.aidl",
+ "aidl/android/media/IResourceManagerService.aidl",
+ "aidl/android/media/MediaResourceType.aidl",
+ "aidl/android/media/MediaResourceSubType.aidl",
+ "aidl/android/media/MediaResourceParcel.aidl",
+ "aidl/android/media/MediaResourcePolicyParcel.aidl",
+ ],
+ api_dir: "api/resourcemanager",
+ versions: ["1"],
+}
+
cc_library_shared {
name: "libmedia_omx",
vendor_available: true,
@@ -63,7 +52,6 @@
"IOMX.cpp",
"MediaCodecBuffer.cpp",
"OMXBuffer.cpp",
- "omx/1.0/WGraphicBufferSource.cpp",
"omx/1.0/WOmxBufferSource.cpp",
"omx/1.0/WOmxNode.cpp",
"omx/1.0/WOmxObserver.cpp",
@@ -73,7 +61,7 @@
local_include_dirs: ["aidl"],
export_aidl_headers: true,
},
-
+
local_include_dirs: [
"include",
],
@@ -127,7 +115,6 @@
},
}
-
cc_library_shared {
name: "libmedia_omx_client",
@@ -197,6 +184,7 @@
],
header_libs: [
+ "libmedia_headers",
"media_ndk_headers",
],
@@ -215,6 +203,49 @@
},
}
+cc_library_shared {
+ name: "libmedia_codeclist",
+
+ srcs: [
+ "IMediaCodecList.cpp",
+ "MediaCodecInfo.cpp",
+ ],
+
+ local_include_dirs: [
+ "include",
+ ],
+
+ shared_libs: [
+ "android.hardware.media.omx@1.0",
+ "libbinder",
+ "liblog",
+ "libstagefright_foundation",
+ "libutils",
+ ],
+
+ include_dirs: [
+ "system/libhidl/transport/token/1.0/utils/include",
+ ],
+
+ export_include_dirs: [
+ "include",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wno-error=deprecated-declarations",
+ "-Wall",
+ ],
+
+ sanitize: {
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ cfi: true,
+ },
+}
+
cc_library {
name: "libmedia",
@@ -222,7 +253,6 @@
"IDataSource.cpp",
"BufferingSettings.cpp",
"mediaplayer.cpp",
- "IMediaCodecList.cpp",
"IMediaHTTPConnection.cpp",
"IMediaHTTPService.cpp",
"IMediaExtractor.cpp",
@@ -235,17 +265,12 @@
"IMediaSource.cpp",
"IRemoteDisplay.cpp",
"IRemoteDisplayClient.cpp",
- "IResourceManagerClient.cpp",
- "IResourceManagerService.cpp",
"IStreamSource.cpp",
- "MediaCodecInfo.cpp",
"MediaUtils.cpp",
"Metadata.cpp",
"mediarecorder.cpp",
"IMediaMetadataRetriever.cpp",
"mediametadataretriever.cpp",
- "MidiDeviceInfo.cpp",
- "JetPlayer.cpp",
"MediaScanner.cpp",
"MediaScannerClient.cpp",
"CharacterEncodingDetector.cpp",
@@ -253,7 +278,6 @@
"MediaProfiles.cpp",
"MediaResource.cpp",
"MediaResourcePolicy.cpp",
- "Visualizer.cpp",
"StringArray.cpp",
"NdkMediaFormatPriv.cpp",
"NdkMediaErrorPriv.cpp",
@@ -289,8 +313,8 @@
"libstagefright_foundation",
"libgui",
"libdl",
- "libaudioutils",
"libaudioclient",
+ "libmedia_codeclist",
"libmedia_omx",
],
@@ -303,8 +327,12 @@
],
static_libs: [
- "libc_malloc_debug_backtrace", // for memory heap analysis
- "libmedia_midiiowrapper",
+ "libc_malloc_debug_backtrace", // for memory heap analysis
+ "resourcemanager_aidl_interface-cpp",
+ ],
+
+ export_static_lib_headers: [
+ "resourcemanager_aidl_interface-cpp",
],
export_include_dirs: [
@@ -327,64 +355,3 @@
cfi: true,
},
}
-
-cc_library_static {
- name: "libmedia_player2_util",
-
- srcs: [
- "AudioParameter.cpp",
- "BufferingSettings.cpp",
- "DataSourceDesc.cpp",
- "MediaCodecBuffer.cpp",
- "Metadata.cpp",
- "NdkWrapper.cpp",
- ],
-
- shared_libs: [
- "libbinder",
- "libcutils",
- "liblog",
- "libmediandk",
- "libnativewindow",
- "libmediandk_utils",
- "libstagefright_foundation",
- "libui",
- "libutils",
- ],
-
- export_shared_lib_headers: [
- "libbinder",
- "libmediandk",
- ],
-
- header_libs: [
- "media_plugin_headers",
- ],
-
- include_dirs: [
- "frameworks/av/media/ndk",
- ],
-
- static_libs: [
- "libstagefright_rtsp",
- "libstagefright_timedtext",
- ],
-
- export_include_dirs: [
- "include",
- ],
-
- cflags: [
- "-Werror",
- "-Wno-error=deprecated-declarations",
- "-Wall",
- ],
-
- sanitize: {
- misc_undefined: [
- "unsigned-integer-overflow",
- "signed-integer-overflow",
- ],
- cfi: true,
- },
-}
diff --git a/media/libmedia/DataSourceDesc.cpp b/media/libmedia/DataSourceDesc.cpp
deleted file mode 100644
index b7ccbce..0000000
--- a/media/libmedia/DataSourceDesc.cpp
+++ /dev/null
@@ -1,37 +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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "DataSourceDesc"
-
-#include <media/DataSource.h>
-#include <media/DataSourceDesc.h>
-#include <media/MediaHTTPService.h>
-
-namespace android {
-
-static const int64_t kLongMax = 0x7ffffffffffffffL;
-
-DataSourceDesc::DataSourceDesc()
- : mType(TYPE_NONE),
- mFDOffset(0),
- mFDLength(kLongMax),
- mId(0),
- mStartPositionMs(0),
- mEndPositionMs(0) {
-}
-
-} // namespace android
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index bc0c2cd..959a3d7 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -29,7 +29,6 @@
#include <utils/NativeHandle.h>
#include <media/omx/1.0/WOmxNode.h>
-#include <android/IGraphicBufferSource.h>
#include <android/IOMXBufferSource.h>
namespace android {
diff --git a/media/libmedia/IResourceManagerClient.cpp b/media/libmedia/IResourceManagerClient.cpp
deleted file mode 100644
index 1fea479..0000000
--- a/media/libmedia/IResourceManagerClient.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
-**
-** Copyright 2015, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include <utils/RefBase.h>
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
-
-#include <media/IResourceManagerClient.h>
-
-namespace android {
-
-enum {
- RECLAIM_RESOURCE = IBinder::FIRST_CALL_TRANSACTION,
- GET_NAME,
-};
-
-class BpResourceManagerClient: public BpInterface<IResourceManagerClient>
-{
-public:
- explicit BpResourceManagerClient(const sp<IBinder> &impl)
- : BpInterface<IResourceManagerClient>(impl)
- {
- }
-
- virtual bool reclaimResource() {
- Parcel data, reply;
- data.writeInterfaceToken(IResourceManagerClient::getInterfaceDescriptor());
-
- bool ret = false;
- status_t status = remote()->transact(RECLAIM_RESOURCE, data, &reply);
- if (status == NO_ERROR) {
- ret = (bool)reply.readInt32();
- }
- return ret;
- }
-
- virtual String8 getName() {
- Parcel data, reply;
- data.writeInterfaceToken(IResourceManagerClient::getInterfaceDescriptor());
-
- String8 ret;
- status_t status = remote()->transact(GET_NAME, data, &reply);
- if (status == NO_ERROR) {
- ret = reply.readString8();
- }
- return ret;
- }
-
-};
-
-IMPLEMENT_META_INTERFACE(ResourceManagerClient, "android.media.IResourceManagerClient");
-
-// ----------------------------------------------------------------------
-
-status_t BnResourceManagerClient::onTransact(
- uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags)
-{
- switch (code) {
- case RECLAIM_RESOURCE: {
- CHECK_INTERFACE(IResourceManagerClient, data, reply);
- bool ret = reclaimResource();
- reply->writeInt32(ret);
- return NO_ERROR;
- } break;
- case GET_NAME: {
- CHECK_INTERFACE(IResourceManagerClient, data, reply);
- String8 ret = getName();
- reply->writeString8(ret);
- return NO_ERROR;
- } break;
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-}; // namespace android
diff --git a/media/libmedia/IResourceManagerService.cpp b/media/libmedia/IResourceManagerService.cpp
deleted file mode 100644
index f8a0a14..0000000
--- a/media/libmedia/IResourceManagerService.cpp
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
-**
-** Copyright 2015, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "IResourceManagerService"
-#include <utils/Log.h>
-
-#include <media/IResourceManagerService.h>
-
-#include <binder/Parcel.h>
-
-#include <stdint.h>
-#include <sys/types.h>
-
-namespace android {
-
-enum {
- CONFIG = IBinder::FIRST_CALL_TRANSACTION,
- ADD_RESOURCE,
- REMOVE_RESOURCE,
- REMOVE_CLIENT,
- RECLAIM_RESOURCE,
-};
-
-template <typename T>
-static void writeToParcel(Parcel *data, const Vector<T> &items) {
- size_t size = items.size();
- // truncates size, but should be okay for this usecase
- data->writeUint32(static_cast<uint32_t>(size));
- for (size_t i = 0; i < size; i++) {
- items[i].writeToParcel(data);
- }
-}
-
-template <typename T>
-static void readFromParcel(const Parcel &data, Vector<T> *items) {
- size_t size = (size_t)data.readUint32();
- for (size_t i = 0; i < size && data.dataAvail() > 0; i++) {
- T item;
- item.readFromParcel(data);
- items->add(item);
- }
-}
-
-class BpResourceManagerService : public BpInterface<IResourceManagerService>
-{
-public:
- explicit BpResourceManagerService(const sp<IBinder> &impl)
- : BpInterface<IResourceManagerService>(impl)
- {
- }
-
- virtual void config(const Vector<MediaResourcePolicy> &policies) {
- Parcel data, reply;
- data.writeInterfaceToken(IResourceManagerService::getInterfaceDescriptor());
- writeToParcel(&data, policies);
- remote()->transact(CONFIG, data, &reply);
- }
-
- virtual void addResource(
- int pid,
- int uid,
- int64_t clientId,
- const sp<IResourceManagerClient> client,
- const Vector<MediaResource> &resources) {
- Parcel data, reply;
- data.writeInterfaceToken(IResourceManagerService::getInterfaceDescriptor());
- data.writeInt32(pid);
- data.writeInt32(uid);
- data.writeInt64(clientId);
- data.writeStrongBinder(IInterface::asBinder(client));
- writeToParcel(&data, resources);
-
- remote()->transact(ADD_RESOURCE, data, &reply);
- }
-
- virtual void removeResource(int pid, int64_t clientId, const Vector<MediaResource> &resources) {
- Parcel data, reply;
- data.writeInterfaceToken(IResourceManagerService::getInterfaceDescriptor());
- data.writeInt32(pid);
- data.writeInt64(clientId);
- writeToParcel(&data, resources);
-
- remote()->transact(REMOVE_RESOURCE, data, &reply);
- }
-
- virtual void removeClient(int pid, int64_t clientId) {
- Parcel data, reply;
- data.writeInterfaceToken(IResourceManagerService::getInterfaceDescriptor());
- data.writeInt32(pid);
- data.writeInt64(clientId);
-
- remote()->transact(REMOVE_CLIENT, data, &reply);
- }
-
- virtual bool reclaimResource(int callingPid, const Vector<MediaResource> &resources) {
- Parcel data, reply;
- data.writeInterfaceToken(IResourceManagerService::getInterfaceDescriptor());
- data.writeInt32(callingPid);
- writeToParcel(&data, resources);
-
- bool ret = false;
- status_t status = remote()->transact(RECLAIM_RESOURCE, data, &reply);
- if (status == NO_ERROR) {
- ret = (bool)reply.readInt32();
- }
- return ret;
- }
-};
-
-IMPLEMENT_META_INTERFACE(ResourceManagerService, "android.media.IResourceManagerService");
-
-// ----------------------------------------------------------------------
-
-
-status_t BnResourceManagerService::onTransact(
- uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags)
-{
- switch (code) {
- case CONFIG: {
- CHECK_INTERFACE(IResourceManagerService, data, reply);
- Vector<MediaResourcePolicy> policies;
- readFromParcel(data, &policies);
- config(policies);
- return NO_ERROR;
- } break;
-
- case ADD_RESOURCE: {
- CHECK_INTERFACE(IResourceManagerService, data, reply);
- int pid = data.readInt32();
- int uid = data.readInt32();
- int64_t clientId = data.readInt64();
- sp<IResourceManagerClient> client(
- interface_cast<IResourceManagerClient>(data.readStrongBinder()));
- if (client == NULL) {
- return NO_ERROR;
- }
- Vector<MediaResource> resources;
- readFromParcel(data, &resources);
- addResource(pid, uid, clientId, client, resources);
- return NO_ERROR;
- } break;
-
- case REMOVE_RESOURCE: {
- CHECK_INTERFACE(IResourceManagerService, data, reply);
- int pid = data.readInt32();
- int64_t clientId = data.readInt64();
- Vector<MediaResource> resources;
- readFromParcel(data, &resources);
- removeResource(pid, clientId, resources);
- return NO_ERROR;
- } break;
-
- case REMOVE_CLIENT: {
- CHECK_INTERFACE(IResourceManagerService, data, reply);
- int pid = data.readInt32();
- int64_t clientId = data.readInt64();
- removeClient(pid, clientId);
- return NO_ERROR;
- } break;
-
- case RECLAIM_RESOURCE: {
- CHECK_INTERFACE(IResourceManagerService, data, reply);
- int callingPid = data.readInt32();
- Vector<MediaResource> resources;
- readFromParcel(data, &resources);
- bool ret = reclaimResource(callingPid, resources);
- reply->writeInt32(ret);
- return NO_ERROR;
- } break;
-
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp
deleted file mode 100644
index 0d3c1ba..0000000
--- a/media/libmedia/JetPlayer.cpp
+++ /dev/null
@@ -1,471 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "JetPlayer-C"
-
-#include <utils/Log.h>
-#include <media/JetPlayer.h>
-
-
-namespace android
-{
-
-static const int MIX_NUM_BUFFERS = 4;
-static const S_EAS_LIB_CONFIG* pLibConfig = NULL;
-
-//-------------------------------------------------------------------------------------------------
-JetPlayer::JetPlayer(void *javaJetPlayer, int maxTracks, int trackBufferSize) :
- mEventCallback(NULL),
- mJavaJetPlayerRef(javaJetPlayer),
- mTid(-1),
- mRender(false),
- mPaused(false),
- mMaxTracks(maxTracks),
- mEasData(NULL),
- mIoWrapper(NULL),
- mTrackBufferSize(trackBufferSize)
-{
- ALOGV("JetPlayer constructor");
- mPreviousJetStatus.currentUserID = -1;
- mPreviousJetStatus.segmentRepeatCount = -1;
- mPreviousJetStatus.numQueuedSegments = -1;
- mPreviousJetStatus.paused = true;
-}
-
-//-------------------------------------------------------------------------------------------------
-JetPlayer::~JetPlayer()
-{
- ALOGV("~JetPlayer");
- release();
-}
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::init()
-{
- //Mutex::Autolock lock(&mMutex);
-
- EAS_RESULT result;
-
- // retrieve the EAS library settings
- if (pLibConfig == NULL)
- pLibConfig = EAS_Config();
- if (pLibConfig == NULL) {
- ALOGE("JetPlayer::init(): EAS library configuration could not be retrieved, aborting.");
- return EAS_FAILURE;
- }
-
- // init the EAS library
- result = EAS_Init(&mEasData);
- if (result != EAS_SUCCESS) {
- ALOGE("JetPlayer::init(): Error initializing Sonivox EAS library, aborting.");
- mState = EAS_STATE_ERROR;
- return result;
- }
- // init the JET library with the default app event controller range
- result = JET_Init(mEasData, NULL, sizeof(S_JET_CONFIG));
- if (result != EAS_SUCCESS) {
- ALOGE("JetPlayer::init(): Error initializing JET library, aborting.");
- mState = EAS_STATE_ERROR;
- return result;
- }
-
- // create the output AudioTrack
- mAudioTrack = new AudioTrack();
- status_t status = mAudioTrack->set(AUDIO_STREAM_MUSIC, //TODO parameterize this
- pLibConfig->sampleRate,
- AUDIO_FORMAT_PCM_16_BIT,
- audio_channel_out_mask_from_count(pLibConfig->numChannels),
- (size_t) mTrackBufferSize,
- AUDIO_OUTPUT_FLAG_NONE);
- if (status != OK) {
- ALOGE("JetPlayer::init(): Error initializing JET library; AudioTrack error %d", status);
- mAudioTrack.clear();
- mState = EAS_STATE_ERROR;
- return EAS_FAILURE;
- }
-
- // create render and playback thread
- {
- Mutex::Autolock l(mMutex);
- ALOGV("JetPlayer::init(): trying to start render thread");
- mThread = new JetPlayerThread(this);
- mThread->run("jetRenderThread", ANDROID_PRIORITY_AUDIO);
- mCondition.wait(mMutex);
- }
- if (mTid > 0) {
- // render thread started, we're ready
- ALOGV("JetPlayer::init(): render thread(%d) successfully started.", mTid);
- mState = EAS_STATE_READY;
- } else {
- ALOGE("JetPlayer::init(): failed to start render thread.");
- mState = EAS_STATE_ERROR;
- return EAS_FAILURE;
- }
-
- return EAS_SUCCESS;
-}
-
-void JetPlayer::setEventCallback(jetevent_callback eventCallback)
-{
- Mutex::Autolock l(mMutex);
- mEventCallback = eventCallback;
-}
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::release()
-{
- ALOGV("JetPlayer::release()");
- Mutex::Autolock lock(mMutex);
- mPaused = true;
- mRender = false;
- if (mEasData) {
- JET_Pause(mEasData);
- JET_CloseFile(mEasData);
- JET_Shutdown(mEasData);
- EAS_Shutdown(mEasData);
- }
- delete mIoWrapper;
- mIoWrapper = NULL;
- if (mAudioTrack != 0) {
- mAudioTrack->stop();
- mAudioTrack->flush();
- mAudioTrack.clear();
- }
- if (mAudioBuffer) {
- delete mAudioBuffer;
- mAudioBuffer = NULL;
- }
- mEasData = NULL;
-
- return EAS_SUCCESS;
-}
-
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::render() {
- EAS_RESULT result = EAS_FAILURE;
- EAS_I32 count;
- int temp;
- bool audioStarted = false;
-
- ALOGV("JetPlayer::render(): entering");
-
- // allocate render buffer
- mAudioBuffer =
- new EAS_PCM[pLibConfig->mixBufferSize * pLibConfig->numChannels * MIX_NUM_BUFFERS];
-
- // signal main thread that we started
- {
- Mutex::Autolock l(mMutex);
- mTid = gettid();
- ALOGV("JetPlayer::render(): render thread(%d) signal", mTid);
- mCondition.signal();
- }
-
- while (1) {
-
- mMutex.lock(); // [[[[[[[[ LOCK ---------------------------------------
-
- if (mEasData == NULL) {
- mMutex.unlock();
- ALOGV("JetPlayer::render(): NULL EAS data, exiting render.");
- goto threadExit;
- }
-
- // nothing to render, wait for client thread to wake us up
- while (!mRender)
- {
- ALOGV("JetPlayer::render(): signal wait");
- if (audioStarted) {
- mAudioTrack->pause();
- // we have to restart the playback once we start rendering again
- audioStarted = false;
- }
- mCondition.wait(mMutex);
- ALOGV("JetPlayer::render(): signal rx'd");
- }
-
- // render midi data into the input buffer
- int num_output = 0;
- EAS_PCM* p = mAudioBuffer;
- for (int i = 0; i < MIX_NUM_BUFFERS; i++) {
- result = EAS_Render(mEasData, p, pLibConfig->mixBufferSize, &count);
- if (result != EAS_SUCCESS) {
- ALOGE("JetPlayer::render(): EAS_Render returned error %ld", result);
- }
- p += count * pLibConfig->numChannels;
- num_output += count * pLibConfig->numChannels * sizeof(EAS_PCM);
-
- // send events that were generated (if any) to the event callback
- fireEventsFromJetQueue();
- }
-
- // update playback state
- //ALOGV("JetPlayer::render(): updating state");
- JET_Status(mEasData, &mJetStatus);
- fireUpdateOnStatusChange();
- mPaused = mJetStatus.paused;
-
- mMutex.unlock(); // UNLOCK ]]]]]]]] -----------------------------------
-
- // check audio output track
- if (mAudioTrack == NULL) {
- ALOGE("JetPlayer::render(): output AudioTrack was not created");
- goto threadExit;
- }
-
- // Write data to the audio hardware
- //ALOGV("JetPlayer::render(): writing to audio output");
- if ((temp = mAudioTrack->write(mAudioBuffer, num_output)) < 0) {
- ALOGE("JetPlayer::render(): Error in writing:%d",temp);
- return temp;
- }
-
- // start audio output if necessary
- if (!audioStarted) {
- ALOGV("JetPlayer::render(): starting audio playback");
- mAudioTrack->start();
- audioStarted = true;
- }
-
- }//while (1)
-
-threadExit:
- if (mAudioTrack != NULL) {
- mAudioTrack->stop();
- mAudioTrack->flush();
- }
- delete [] mAudioBuffer;
- mAudioBuffer = NULL;
- mMutex.lock();
- mTid = -1;
- mCondition.signal();
- mMutex.unlock();
- return result;
-}
-
-
-//-------------------------------------------------------------------------------------------------
-// fire up an update if any of the status fields has changed
-// precondition: mMutex locked
-void JetPlayer::fireUpdateOnStatusChange()
-{
- if ( (mJetStatus.currentUserID != mPreviousJetStatus.currentUserID)
- ||(mJetStatus.segmentRepeatCount != mPreviousJetStatus.segmentRepeatCount) ) {
- if (mEventCallback) {
- mEventCallback(
- JetPlayer::JET_USERID_UPDATE,
- mJetStatus.currentUserID,
- mJetStatus.segmentRepeatCount,
- mJavaJetPlayerRef);
- }
- mPreviousJetStatus.currentUserID = mJetStatus.currentUserID;
- mPreviousJetStatus.segmentRepeatCount = mJetStatus.segmentRepeatCount;
- }
-
- if (mJetStatus.numQueuedSegments != mPreviousJetStatus.numQueuedSegments) {
- if (mEventCallback) {
- mEventCallback(
- JetPlayer::JET_NUMQUEUEDSEGMENT_UPDATE,
- mJetStatus.numQueuedSegments,
- -1,
- mJavaJetPlayerRef);
- }
- mPreviousJetStatus.numQueuedSegments = mJetStatus.numQueuedSegments;
- }
-
- if (mJetStatus.paused != mPreviousJetStatus.paused) {
- if (mEventCallback) {
- mEventCallback(JetPlayer::JET_PAUSE_UPDATE,
- mJetStatus.paused,
- -1,
- mJavaJetPlayerRef);
- }
- mPreviousJetStatus.paused = mJetStatus.paused;
- }
-
-}
-
-
-//-------------------------------------------------------------------------------------------------
-// fire up all the JET events in the JET engine queue (until the queue is empty)
-// precondition: mMutex locked
-void JetPlayer::fireEventsFromJetQueue()
-{
- if (!mEventCallback) {
- // no callback, just empty the event queue
- while (JET_GetEvent(mEasData, NULL, NULL)) { }
- return;
- }
-
- EAS_U32 rawEvent;
- while (JET_GetEvent(mEasData, &rawEvent, NULL)) {
- mEventCallback(
- JetPlayer::JET_EVENT,
- rawEvent,
- -1,
- mJavaJetPlayerRef);
- }
-}
-
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::loadFromFile(const char* path)
-{
- ALOGV("JetPlayer::loadFromFile(): path=%s", path);
-
- Mutex::Autolock lock(mMutex);
-
- delete mIoWrapper;
- mIoWrapper = new MidiIoWrapper(path);
-
- EAS_RESULT result = JET_OpenFile(mEasData, mIoWrapper->getLocator());
- if (result != EAS_SUCCESS)
- mState = EAS_STATE_ERROR;
- else
- mState = EAS_STATE_OPEN;
- return( result );
-}
-
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::loadFromFD(const int fd, const long long offset, const long long length)
-{
- ALOGV("JetPlayer::loadFromFD(): fd=%d offset=%lld length=%lld", fd, offset, length);
-
- Mutex::Autolock lock(mMutex);
-
- delete mIoWrapper;
- mIoWrapper = new MidiIoWrapper(fd, offset, length);
-
- EAS_RESULT result = JET_OpenFile(mEasData, mIoWrapper->getLocator());
- if (result != EAS_SUCCESS)
- mState = EAS_STATE_ERROR;
- else
- mState = EAS_STATE_OPEN;
- return( result );
-}
-
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::closeFile()
-{
- Mutex::Autolock lock(mMutex);
- return JET_CloseFile(mEasData);
-}
-
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::play()
-{
- ALOGV("JetPlayer::play(): entering");
- Mutex::Autolock lock(mMutex);
-
- EAS_RESULT result = JET_Play(mEasData);
-
- mPaused = false;
- mRender = true;
-
- JET_Status(mEasData, &mJetStatus);
- this->dumpJetStatus(&mJetStatus);
-
- fireUpdateOnStatusChange();
-
- // wake up render thread
- ALOGV("JetPlayer::play(): wakeup render thread");
- mCondition.signal();
-
- return result;
-}
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::pause()
-{
- Mutex::Autolock lock(mMutex);
- mPaused = true;
- EAS_RESULT result = JET_Pause(mEasData);
-
- mRender = false;
-
- JET_Status(mEasData, &mJetStatus);
- this->dumpJetStatus(&mJetStatus);
- fireUpdateOnStatusChange();
-
-
- return result;
-}
-
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::queueSegment(int segmentNum, int libNum, int repeatCount, int transpose,
- EAS_U32 muteFlags, EAS_U8 userID)
-{
- ALOGV("JetPlayer::queueSegment segmentNum=%d, libNum=%d, repeatCount=%d, transpose=%d",
- segmentNum, libNum, repeatCount, transpose);
- Mutex::Autolock lock(mMutex);
- return JET_QueueSegment(mEasData, segmentNum, libNum, repeatCount, transpose, muteFlags,
- userID);
-}
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::setMuteFlags(EAS_U32 muteFlags, bool sync)
-{
- Mutex::Autolock lock(mMutex);
- return JET_SetMuteFlags(mEasData, muteFlags, sync);
-}
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::setMuteFlag(int trackNum, bool muteFlag, bool sync)
-{
- Mutex::Autolock lock(mMutex);
- return JET_SetMuteFlag(mEasData, trackNum, muteFlag, sync);
-}
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::triggerClip(int clipId)
-{
- ALOGV("JetPlayer::triggerClip clipId=%d", clipId);
- Mutex::Autolock lock(mMutex);
- return JET_TriggerClip(mEasData, clipId);
-}
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::clearQueue()
-{
- ALOGV("JetPlayer::clearQueue");
- Mutex::Autolock lock(mMutex);
- return JET_Clear_Queue(mEasData);
-}
-
-//-------------------------------------------------------------------------------------------------
-void JetPlayer::dump()
-{
-}
-
-void JetPlayer::dumpJetStatus(S_JET_STATUS* pJetStatus)
-{
- if (pJetStatus!=NULL)
- ALOGV(">> current JET player status: userID=%d segmentRepeatCount=%d numQueuedSegments=%d "
- "paused=%d",
- pJetStatus->currentUserID, pJetStatus->segmentRepeatCount,
- pJetStatus->numQueuedSegments, pJetStatus->paused);
- else
- ALOGE(">> JET player status is NULL");
-}
-
-
-} // end namespace android
diff --git a/media/libmedia/MediaResource.cpp b/media/libmedia/MediaResource.cpp
index e636a50..fe86d27 100644
--- a/media/libmedia/MediaResource.cpp
+++ b/media/libmedia/MediaResource.cpp
@@ -19,47 +19,73 @@
#include <utils/Log.h>
#include <media/MediaResource.h>
+#include <vector>
+
namespace android {
-MediaResource::MediaResource()
- : mType(kUnspecified),
- mSubType(kUnspecifiedSubType),
- mValue(0) {}
-
-MediaResource::MediaResource(Type type, uint64_t value)
- : mType(type),
- mSubType(kUnspecifiedSubType),
- mValue(value) {}
-
-MediaResource::MediaResource(Type type, SubType subType, uint64_t value)
- : mType(type),
- mSubType(subType),
- mValue(value) {}
-
-void MediaResource::readFromParcel(const Parcel &parcel) {
- mType = static_cast<Type>(parcel.readInt32());
- mSubType = static_cast<SubType>(parcel.readInt32());
- mValue = parcel.readUint64();
+MediaResource::MediaResource(Type type, int64_t value) {
+ this->type = type;
+ this->subType = SubType::kUnspecifiedSubType;
+ this->value = value;
}
-void MediaResource::writeToParcel(Parcel *parcel) const {
- parcel->writeInt32(static_cast<int32_t>(mType));
- parcel->writeInt32(static_cast<int32_t>(mSubType));
- parcel->writeUint64(mValue);
+MediaResource::MediaResource(Type type, SubType subType, int64_t value) {
+ this->type = type;
+ this->subType = subType;
+ this->value = value;
}
-String8 MediaResource::toString() const {
+MediaResource::MediaResource(Type type, const std::vector<uint8_t> &id, int64_t value) {
+ this->type = type;
+ this->subType = SubType::kUnspecifiedSubType;
+ this->id = id;
+ this->value = value;
+}
+
+//static
+MediaResource MediaResource::CodecResource(bool secure, bool video) {
+ return MediaResource(
+ secure ? Type::kSecureCodec : Type::kNonSecureCodec,
+ video ? SubType::kVideoCodec : SubType::kAudioCodec,
+ 1);
+}
+
+//static
+MediaResource MediaResource::GraphicMemoryResource(int64_t value) {
+ return MediaResource(Type::kGraphicMemory, value);
+}
+
+//static
+MediaResource MediaResource::CpuBoostResource() {
+ return MediaResource(Type::kCpuBoost, 1);
+}
+
+//static
+MediaResource MediaResource::VideoBatteryResource() {
+ return MediaResource(Type::kBattery, SubType::kVideoCodec, 1);
+}
+
+//static
+MediaResource MediaResource::DrmSessionResource(const std::vector<uint8_t> &id, int64_t value) {
+ return MediaResource(Type::kDrmSession, id, value);
+}
+
+static String8 bytesToHexString(const std::vector<uint8_t> &bytes) {
String8 str;
- str.appendFormat("%s/%s:%llu", asString(mType), asString(mSubType), (unsigned long long)mValue);
+ for (auto &b : bytes) {
+ str.appendFormat("%02x", b);
+ }
return str;
}
-bool MediaResource::operator==(const MediaResource &other) const {
- return (other.mType == mType) && (other.mSubType == mSubType) && (other.mValue == mValue);
-}
+String8 toString(const MediaResourceParcel& resource) {
+ String8 str;
-bool MediaResource::operator!=(const MediaResource &other) const {
- return !(*this == other);
+ str.appendFormat("%s/%s:[%s]:%lld",
+ asString(resource.type), asString(resource.subType),
+ bytesToHexString(resource.id).c_str(),
+ (long long)resource.value);
+ return str;
}
}; // namespace android
diff --git a/media/libmedia/MediaResourcePolicy.cpp b/media/libmedia/MediaResourcePolicy.cpp
index 5210825..c463179 100644
--- a/media/libmedia/MediaResourcePolicy.cpp
+++ b/media/libmedia/MediaResourcePolicy.cpp
@@ -18,31 +18,29 @@
#define LOG_TAG "MediaResourcePolicy"
#include <utils/Log.h>
#include <media/MediaResourcePolicy.h>
+#include <android/media/IResourceManagerService.h>
namespace android {
-const char kPolicySupportsMultipleSecureCodecs[] = "supports-multiple-secure-codecs";
-const char kPolicySupportsSecureWithNonSecureCodec[] = "supports-secure-with-non-secure-codec";
-
-MediaResourcePolicy::MediaResourcePolicy() {}
-
-MediaResourcePolicy::MediaResourcePolicy(String8 type, String8 value)
- : mType(type),
- mValue(value) {}
-
-void MediaResourcePolicy::readFromParcel(const Parcel &parcel) {
- mType = parcel.readString8();
- mValue = parcel.readString8();
+using android::media::IResourceManagerService;
+//static
+const ::std::string& MediaResourcePolicy::kPolicySupportsMultipleSecureCodecs() {
+ return IResourceManagerService::kPolicySupportsMultipleSecureCodecs();
+}
+//static
+const ::std::string& MediaResourcePolicy::kPolicySupportsSecureWithNonSecureCodec() {
+ return IResourceManagerService::kPolicySupportsSecureWithNonSecureCodec();
}
-void MediaResourcePolicy::writeToParcel(Parcel *parcel) const {
- parcel->writeString8(mType);
- parcel->writeString8(mValue);
+MediaResourcePolicy::MediaResourcePolicy(
+ const std::string& type, const std::string& value) {
+ this->type = type;
+ this->value = value;
}
-String8 MediaResourcePolicy::toString() const {
+String8 toString(const MediaResourcePolicyParcel &policy) {
String8 str;
- str.appendFormat("%s:%s", mType.string(), mValue.string());
+ str.appendFormat("%s:%s", policy.type.c_str(), policy.value.c_str());
return str;
}
diff --git a/media/libmedia/MidiDeviceInfo.cpp b/media/libmedia/MidiDeviceInfo.cpp
deleted file mode 100644
index 7588e00..0000000
--- a/media/libmedia/MidiDeviceInfo.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 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 "MidiDeviceInfo"
-
-#include <media/MidiDeviceInfo.h>
-
-#include <binder/Parcel.h>
-#include <log/log.h>
-#include <utils/Errors.h>
-#include <utils/String16.h>
-
-namespace android {
-namespace media {
-namespace midi {
-
-// The constant values need to be kept in sync with MidiDeviceInfo.java.
-// static
-const char* const MidiDeviceInfo::PROPERTY_NAME = "name";
-const char* const MidiDeviceInfo::PROPERTY_MANUFACTURER = "manufacturer";
-const char* const MidiDeviceInfo::PROPERTY_PRODUCT = "product";
-const char* const MidiDeviceInfo::PROPERTY_VERSION = "version";
-const char* const MidiDeviceInfo::PROPERTY_SERIAL_NUMBER = "serial_number";
-const char* const MidiDeviceInfo::PROPERTY_ALSA_CARD = "alsa_card";
-const char* const MidiDeviceInfo::PROPERTY_ALSA_DEVICE = "alsa_device";
-
-String16 MidiDeviceInfo::getProperty(const char* propertyName) {
- String16 value;
- if (mProperties.getString(String16(propertyName), &value)) {
- return value;
- } else {
- return String16();
- }
-}
-
-#define RETURN_IF_FAILED(calledOnce) \
- { \
- status_t returnStatus = calledOnce; \
- if (returnStatus) { \
- ALOGE("Failed at %s:%d (%s)", __FILE__, __LINE__, __func__); \
- return returnStatus; \
- } \
- }
-
-status_t MidiDeviceInfo::writeToParcel(Parcel* parcel) const {
- // Needs to be kept in sync with code in MidiDeviceInfo.java
- RETURN_IF_FAILED(parcel->writeInt32(mType));
- RETURN_IF_FAILED(parcel->writeInt32(mId));
- RETURN_IF_FAILED(parcel->writeInt32((int32_t)mInputPortNames.size()));
- RETURN_IF_FAILED(parcel->writeInt32((int32_t)mOutputPortNames.size()));
- RETURN_IF_FAILED(writeStringVector(parcel, mInputPortNames));
- RETURN_IF_FAILED(writeStringVector(parcel, mOutputPortNames));
- RETURN_IF_FAILED(parcel->writeInt32(mIsPrivate ? 1 : 0));
- RETURN_IF_FAILED(mProperties.writeToParcel(parcel));
- // This corresponds to "extra" properties written by Java code
- RETURN_IF_FAILED(mProperties.writeToParcel(parcel));
- return OK;
-}
-
-status_t MidiDeviceInfo::readFromParcel(const Parcel* parcel) {
- // Needs to be kept in sync with code in MidiDeviceInfo.java
- RETURN_IF_FAILED(parcel->readInt32(&mType));
- RETURN_IF_FAILED(parcel->readInt32(&mId));
- int32_t inputPortCount;
- RETURN_IF_FAILED(parcel->readInt32(&inputPortCount));
- int32_t outputPortCount;
- RETURN_IF_FAILED(parcel->readInt32(&outputPortCount));
- RETURN_IF_FAILED(readStringVector(parcel, &mInputPortNames, inputPortCount));
- RETURN_IF_FAILED(readStringVector(parcel, &mOutputPortNames, outputPortCount));
- int32_t isPrivate;
- RETURN_IF_FAILED(parcel->readInt32(&isPrivate));
- mIsPrivate = isPrivate == 1;
- RETURN_IF_FAILED(mProperties.readFromParcel(parcel));
- // Ignore "extra" properties as they may contain Java Parcelables
- return OK;
-}
-
-status_t MidiDeviceInfo::readStringVector(
- const Parcel* parcel, Vector<String16> *vectorPtr, size_t defaultLength) {
- std::unique_ptr<std::vector<std::unique_ptr<String16>>> v;
- status_t result = parcel->readString16Vector(&v);
- if (result != OK) return result;
- vectorPtr->clear();
- if (v.get() != nullptr) {
- for (const auto& iter : *v) {
- if (iter.get() != nullptr) {
- vectorPtr->push_back(*iter);
- } else {
- vectorPtr->push_back(String16());
- }
- }
- } else {
- vectorPtr->resize(defaultLength);
- }
- return OK;
-}
-
-status_t MidiDeviceInfo::writeStringVector(Parcel* parcel, const Vector<String16>& vector) const {
- std::vector<String16> v;
- for (size_t i = 0; i < vector.size(); ++i) {
- v.push_back(vector[i]);
- }
- return parcel->writeString16Vector(v);
-}
-
-// Vector does not define operator==
-static inline bool areVectorsEqual(const Vector<String16>& lhs, const Vector<String16>& rhs) {
- if (lhs.size() != rhs.size()) return false;
- for (size_t i = 0; i < lhs.size(); ++i) {
- if (lhs[i] != rhs[i]) return false;
- }
- return true;
-}
-
-bool operator==(const MidiDeviceInfo& lhs, const MidiDeviceInfo& rhs) {
- return (lhs.mType == rhs.mType && lhs.mId == rhs.mId &&
- areVectorsEqual(lhs.mInputPortNames, rhs.mInputPortNames) &&
- areVectorsEqual(lhs.mOutputPortNames, rhs.mOutputPortNames) &&
- lhs.mProperties == rhs.mProperties &&
- lhs.mIsPrivate == rhs.mIsPrivate);
-}
-
-} // namespace midi
-} // namespace media
-} // namespace android
diff --git a/media/libmedia/MidiIoWrapper.cpp b/media/libmedia/MidiIoWrapper.cpp
index d8ef9cf..6d46363 100644
--- a/media/libmedia/MidiIoWrapper.cpp
+++ b/media/libmedia/MidiIoWrapper.cpp
@@ -17,7 +17,6 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "MidiIoWrapper"
#include <utils/Log.h>
-#include <utils/RefBase.h>
#include <sys/stat.h>
#include <fcntl.h>
@@ -50,7 +49,7 @@
mDataSource = nullptr;
}
-class DataSourceUnwrapper : public DataSourceBase {
+class DataSourceUnwrapper {
public:
explicit DataSourceUnwrapper(CDataSource *csource) {
diff --git a/media/libmedia/NdkWrapper.cpp b/media/libmedia/NdkWrapper.cpp
deleted file mode 100644
index c150407..0000000
--- a/media/libmedia/NdkWrapper.cpp
+++ /dev/null
@@ -1,1290 +0,0 @@
-/*
- * Copyright 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NdkWrapper"
-
-#include <media/NdkWrapper.h>
-
-#include <android/native_window.h>
-#include <log/log.h>
-#include <media/NdkMediaCodec.h>
-#include <media/NdkMediaCrypto.h>
-#include <media/NdkMediaDrm.h>
-#include <media/NdkMediaFormat.h>
-#include <media/NdkMediaExtractor.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <utils/Errors.h>
-
-#include "NdkMediaDataSourceCallbacksPriv.h"
-
-namespace android {
-
-static const size_t kAESBlockSize = 16; // AES_BLOCK_SIZE
-
-static const char *AMediaFormatKeyGroupInt32[] = {
- AMEDIAFORMAT_KEY_AAC_DRC_ATTENUATION_FACTOR,
- AMEDIAFORMAT_KEY_AAC_DRC_BOOST_FACTOR,
- AMEDIAFORMAT_KEY_AAC_DRC_HEAVY_COMPRESSION,
- AMEDIAFORMAT_KEY_AAC_DRC_TARGET_REFERENCE_LEVEL,
- AMEDIAFORMAT_KEY_AAC_ENCODED_TARGET_LEVEL,
- AMEDIAFORMAT_KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT,
- AMEDIAFORMAT_KEY_AAC_PROFILE,
- AMEDIAFORMAT_KEY_AAC_SBR_MODE,
- AMEDIAFORMAT_KEY_AUDIO_SESSION_ID,
- AMEDIAFORMAT_KEY_BITRATE_MODE,
- AMEDIAFORMAT_KEY_BIT_RATE,
- AMEDIAFORMAT_KEY_CAPTURE_RATE,
- AMEDIAFORMAT_KEY_CHANNEL_COUNT,
- AMEDIAFORMAT_KEY_CHANNEL_MASK,
- AMEDIAFORMAT_KEY_COLOR_FORMAT,
- AMEDIAFORMAT_KEY_COLOR_RANGE,
- AMEDIAFORMAT_KEY_COLOR_STANDARD,
- AMEDIAFORMAT_KEY_COLOR_TRANSFER,
- AMEDIAFORMAT_KEY_COMPLEXITY,
- AMEDIAFORMAT_KEY_CREATE_INPUT_SURFACE_SUSPENDED,
- AMEDIAFORMAT_KEY_CRYPTO_DEFAULT_IV_SIZE,
- AMEDIAFORMAT_KEY_CRYPTO_ENCRYPTED_BYTE_BLOCK,
- AMEDIAFORMAT_KEY_CRYPTO_MODE,
- AMEDIAFORMAT_KEY_CRYPTO_SKIP_BYTE_BLOCK,
- AMEDIAFORMAT_KEY_FLAC_COMPRESSION_LEVEL,
- AMEDIAFORMAT_KEY_GRID_COLUMNS,
- AMEDIAFORMAT_KEY_GRID_ROWS,
- AMEDIAFORMAT_KEY_HAPTIC_CHANNEL_COUNT,
- AMEDIAFORMAT_KEY_HEIGHT,
- AMEDIAFORMAT_KEY_INTRA_REFRESH_PERIOD,
- AMEDIAFORMAT_KEY_IS_ADTS,
- AMEDIAFORMAT_KEY_IS_AUTOSELECT,
- AMEDIAFORMAT_KEY_IS_DEFAULT,
- AMEDIAFORMAT_KEY_IS_FORCED_SUBTITLE,
- AMEDIAFORMAT_KEY_LATENCY,
- AMEDIAFORMAT_KEY_LEVEL,
- AMEDIAFORMAT_KEY_MAX_HEIGHT,
- AMEDIAFORMAT_KEY_MAX_INPUT_SIZE,
- AMEDIAFORMAT_KEY_MAX_WIDTH,
- AMEDIAFORMAT_KEY_PCM_ENCODING,
- AMEDIAFORMAT_KEY_PRIORITY,
- AMEDIAFORMAT_KEY_PROFILE,
- AMEDIAFORMAT_KEY_PUSH_BLANK_BUFFERS_ON_STOP,
- AMEDIAFORMAT_KEY_ROTATION,
- AMEDIAFORMAT_KEY_SAMPLE_RATE,
- AMEDIAFORMAT_KEY_SLICE_HEIGHT,
- AMEDIAFORMAT_KEY_STRIDE,
- AMEDIAFORMAT_KEY_TRACK_ID,
- AMEDIAFORMAT_KEY_WIDTH,
- AMEDIAFORMAT_KEY_DISPLAY_HEIGHT,
- AMEDIAFORMAT_KEY_DISPLAY_WIDTH,
- AMEDIAFORMAT_KEY_TEMPORAL_LAYER_ID,
- AMEDIAFORMAT_KEY_TILE_HEIGHT,
- AMEDIAFORMAT_KEY_TILE_WIDTH,
- AMEDIAFORMAT_KEY_TRACK_INDEX,
-};
-
-static const char *AMediaFormatKeyGroupInt64[] = {
- AMEDIAFORMAT_KEY_DURATION,
- AMEDIAFORMAT_KEY_MAX_PTS_GAP_TO_ENCODER,
- AMEDIAFORMAT_KEY_REPEAT_PREVIOUS_FRAME_AFTER,
- AMEDIAFORMAT_KEY_TIME_US,
-};
-
-static const char *AMediaFormatKeyGroupString[] = {
- AMEDIAFORMAT_KEY_LANGUAGE,
- AMEDIAFORMAT_KEY_MIME,
- AMEDIAFORMAT_KEY_TEMPORAL_LAYERING,
-};
-
-static const char *AMediaFormatKeyGroupBuffer[] = {
- AMEDIAFORMAT_KEY_CRYPTO_IV,
- AMEDIAFORMAT_KEY_CRYPTO_KEY,
- AMEDIAFORMAT_KEY_HDR_STATIC_INFO,
- AMEDIAFORMAT_KEY_SEI,
- AMEDIAFORMAT_KEY_MPEG_USER_DATA,
-};
-
-static const char *AMediaFormatKeyGroupCsd[] = {
- AMEDIAFORMAT_KEY_CSD_0,
- AMEDIAFORMAT_KEY_CSD_1,
- AMEDIAFORMAT_KEY_CSD_2,
-};
-
-static const char *AMediaFormatKeyGroupRect[] = {
- AMEDIAFORMAT_KEY_DISPLAY_CROP,
-};
-
-static const char *AMediaFormatKeyGroupFloatInt32[] = {
- AMEDIAFORMAT_KEY_FRAME_RATE,
- AMEDIAFORMAT_KEY_I_FRAME_INTERVAL,
- AMEDIAFORMAT_KEY_MAX_FPS_TO_ENCODER,
- AMEDIAFORMAT_KEY_OPERATING_RATE,
-};
-
-static status_t translateErrorCode(media_status_t err) {
- if (err == AMEDIA_OK) {
- return OK;
- } else if (err == AMEDIA_ERROR_END_OF_STREAM) {
- return ERROR_END_OF_STREAM;
- } else if (err == AMEDIA_ERROR_IO) {
- return ERROR_IO;
- } else if (err == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
- return -EAGAIN;
- }
-
- ALOGE("ndk error code: %d", err);
- return UNKNOWN_ERROR;
-}
-
-static int32_t translateActionCode(int32_t actionCode) {
- if (AMediaCodecActionCode_isTransient(actionCode)) {
- return ACTION_CODE_TRANSIENT;
- } else if (AMediaCodecActionCode_isRecoverable(actionCode)) {
- return ACTION_CODE_RECOVERABLE;
- }
- return ACTION_CODE_FATAL;
-}
-
-static CryptoPlugin::Mode translateToCryptoPluginMode(cryptoinfo_mode_t mode) {
- CryptoPlugin::Mode ret = CryptoPlugin::kMode_Unencrypted;
- switch (mode) {
- case AMEDIACODECRYPTOINFO_MODE_AES_CTR: {
- ret = CryptoPlugin::kMode_AES_CTR;
- break;
- }
-
- case AMEDIACODECRYPTOINFO_MODE_AES_WV: {
- ret = CryptoPlugin::kMode_AES_WV;
- break;
- }
-
- case AMEDIACODECRYPTOINFO_MODE_AES_CBC: {
- ret = CryptoPlugin::kMode_AES_CBC;
- break;
- }
-
- default:
- break;
- }
-
- return ret;
-}
-
-static cryptoinfo_mode_t translateToCryptoInfoMode(CryptoPlugin::Mode mode) {
- cryptoinfo_mode_t ret = AMEDIACODECRYPTOINFO_MODE_CLEAR;
- switch (mode) {
- case CryptoPlugin::kMode_AES_CTR: {
- ret = AMEDIACODECRYPTOINFO_MODE_AES_CTR;
- break;
- }
-
- case CryptoPlugin::kMode_AES_WV: {
- ret = AMEDIACODECRYPTOINFO_MODE_AES_WV;
- break;
- }
-
- case CryptoPlugin::kMode_AES_CBC: {
- ret = AMEDIACODECRYPTOINFO_MODE_AES_CBC;
- break;
- }
-
- default:
- break;
- }
-
- return ret;
-}
-
-//////////// AMediaFormatWrapper
-// static
-sp<AMediaFormatWrapper> AMediaFormatWrapper::Create(const sp<AMessage> &message) {
- sp<AMediaFormatWrapper> aMediaFormat = new AMediaFormatWrapper();
-
- for (size_t i = 0; i < message->countEntries(); ++i) {
- AMessage::Type valueType;
- const char *key = message->getEntryNameAt(i, &valueType);
-
- switch (valueType) {
- case AMessage::kTypeInt32: {
- int32_t val;
- if (!message->findInt32(key, &val)) {
- ALOGE("AMediaFormatWrapper::Create: error at item %zu", i);
- continue;
- }
- aMediaFormat->setInt32(key, val);
- break;
- }
-
- case AMessage::kTypeInt64: {
- int64_t val;
- if (!message->findInt64(key, &val)) {
- ALOGE("AMediaFormatWrapper::Create: error at item %zu", i);
- continue;
- }
- aMediaFormat->setInt64(key, val);
- break;
- }
-
- case AMessage::kTypeFloat: {
- float val;
- if (!message->findFloat(key, &val)) {
- ALOGE("AMediaFormatWrapper::Create: error at item %zu", i);
- continue;
- }
- aMediaFormat->setFloat(key, val);
- break;
- }
-
- case AMessage::kTypeDouble: {
- double val;
- if (!message->findDouble(key, &val)) {
- ALOGE("AMediaFormatWrapper::Create: error at item %zu", i);
- continue;
- }
- aMediaFormat->setDouble(key, val);
- break;
- }
-
- case AMessage::kTypeSize: {
- size_t val;
- if (!message->findSize(key, &val)) {
- ALOGE("AMediaFormatWrapper::Create: error at item %zu", i);
- continue;
- }
- aMediaFormat->setSize(key, val);
- break;
- }
-
- case AMessage::kTypeRect: {
- int32_t left, top, right, bottom;
- if (!message->findRect(key, &left, &top, &right, &bottom)) {
- ALOGE("AMediaFormatWrapper::Create: error at item %zu", i);
- continue;
- }
- aMediaFormat->setRect(key, left, top, right, bottom);
- break;
- }
-
- case AMessage::kTypeString: {
- AString val;
- if (!message->findString(key, &val)) {
- ALOGE("AMediaFormatWrapper::Create: error at item %zu", i);
- continue;
- }
- aMediaFormat->setString(key, val);
- break;
- }
-
- case AMessage::kTypeBuffer: {
- sp<ABuffer> val;
- if (!message->findBuffer(key, &val)) {
- ALOGE("AMediaFormatWrapper::Create: error at item %zu", i);
- continue;
- }
- aMediaFormat->setBuffer(key, val->data(), val->size());
- break;
- }
-
- default: {
- break;
- }
- }
- }
-
- return aMediaFormat;
-}
-
-AMediaFormatWrapper::AMediaFormatWrapper() {
- mAMediaFormat = AMediaFormat_new();
-}
-
-AMediaFormatWrapper::AMediaFormatWrapper(AMediaFormat *aMediaFormat)
- : mAMediaFormat(aMediaFormat) {
-}
-
-AMediaFormatWrapper::~AMediaFormatWrapper() {
- release();
-}
-
-status_t AMediaFormatWrapper::release() {
- if (mAMediaFormat != NULL) {
- media_status_t err = AMediaFormat_delete(mAMediaFormat);
- mAMediaFormat = NULL;
- return translateErrorCode(err);
- }
- return OK;
-}
-
-AMediaFormat *AMediaFormatWrapper::getAMediaFormat() const {
- return mAMediaFormat;
-}
-
-sp<AMessage> AMediaFormatWrapper::toAMessage() const {
- sp<AMessage> msg;
- writeToAMessage(msg);
- return msg;
-}
-
-void AMediaFormatWrapper::writeToAMessage(sp<AMessage> &msg) const {
- if (mAMediaFormat == NULL) {
- msg = NULL;
- }
-
- if (msg == NULL) {
- msg = new AMessage;
- }
- for (auto& key : AMediaFormatKeyGroupInt32) {
- int32_t val;
- if (getInt32(key, &val)) {
- msg->setInt32(key, val);
- }
- }
- for (auto& key : AMediaFormatKeyGroupInt64) {
- int64_t val;
- if (getInt64(key, &val)) {
- msg->setInt64(key, val);
- }
- }
- for (auto& key : AMediaFormatKeyGroupString) {
- AString val;
- if (getString(key, &val)) {
- msg->setString(key, val);
- }
- }
- for (auto& key : AMediaFormatKeyGroupBuffer) {
- void *data;
- size_t size;
- if (getBuffer(key, &data, &size)) {
- sp<ABuffer> buffer = ABuffer::CreateAsCopy(data, size);
- msg->setBuffer(key, buffer);
- }
- }
- for (auto& key : AMediaFormatKeyGroupCsd) {
- void *data;
- size_t size;
- if (getBuffer(key, &data, &size)) {
- sp<ABuffer> buffer = ABuffer::CreateAsCopy(data, size);
- buffer->meta()->setInt32(AMEDIAFORMAT_KEY_CSD, 1);
- buffer->meta()->setInt64(AMEDIAFORMAT_KEY_TIME_US, 0);
- msg->setBuffer(key, buffer);
- }
- }
- for (auto& key : AMediaFormatKeyGroupRect) {
- int32_t left, top, right, bottom;
- if (getRect(key, &left, &top, &right, &bottom)) {
- msg->setRect(key, left, top, right, bottom);
- }
- }
- for (auto& key : AMediaFormatKeyGroupFloatInt32) {
- float valFloat;
- if (getFloat(key, &valFloat)) {
- msg->setFloat(key, valFloat);
- } else {
- int32_t valInt32;
- if (getInt32(key, &valInt32)) {
- msg->setFloat(key, (float)valInt32);
- }
- }
- }
-}
-
-const char* AMediaFormatWrapper::toString() const {
- if (mAMediaFormat == NULL) {
- return NULL;
- }
- return AMediaFormat_toString(mAMediaFormat);
-}
-
-bool AMediaFormatWrapper::getInt32(const char *name, int32_t *out) const {
- if (mAMediaFormat == NULL) {
- return false;
- }
- return AMediaFormat_getInt32(mAMediaFormat, name, out);
-}
-
-bool AMediaFormatWrapper::getInt64(const char *name, int64_t *out) const {
- if (mAMediaFormat == NULL) {
- return false;
- }
- return AMediaFormat_getInt64(mAMediaFormat, name, out);
-}
-
-bool AMediaFormatWrapper::getFloat(const char *name, float *out) const {
- if (mAMediaFormat == NULL) {
- return false;
- }
- return AMediaFormat_getFloat(mAMediaFormat, name, out);
-}
-
-bool AMediaFormatWrapper::getDouble(const char *name, double *out) const {
- if (mAMediaFormat == NULL) {
- return false;
- }
- return AMediaFormat_getDouble(mAMediaFormat, name, out);
-}
-
-bool AMediaFormatWrapper::getSize(const char *name, size_t *out) const {
- if (mAMediaFormat == NULL) {
- return false;
- }
- return AMediaFormat_getSize(mAMediaFormat, name, out);
-}
-
-bool AMediaFormatWrapper::getRect(
- const char *name, int32_t *left, int32_t *top, int32_t *right, int32_t *bottom) const {
- if (mAMediaFormat == NULL) {
- return false;
- }
- return AMediaFormat_getRect(mAMediaFormat, name, left, top, right, bottom);
-}
-
-bool AMediaFormatWrapper::getBuffer(const char *name, void** data, size_t *outSize) const {
- if (mAMediaFormat == NULL) {
- return false;
- }
- return AMediaFormat_getBuffer(mAMediaFormat, name, data, outSize);
-}
-
-bool AMediaFormatWrapper::getString(const char *name, AString *out) const {
- if (mAMediaFormat == NULL) {
- return false;
- }
- const char *outChar = NULL;
- bool ret = AMediaFormat_getString(mAMediaFormat, name, &outChar);
- if (ret) {
- *out = AString(outChar);
- }
- return ret;
-}
-
-void AMediaFormatWrapper::setInt32(const char* name, int32_t value) {
- if (mAMediaFormat != NULL) {
- AMediaFormat_setInt32(mAMediaFormat, name, value);
- }
-}
-
-void AMediaFormatWrapper::setInt64(const char* name, int64_t value) {
- if (mAMediaFormat != NULL) {
- AMediaFormat_setInt64(mAMediaFormat, name, value);
- }
-}
-
-void AMediaFormatWrapper::setFloat(const char* name, float value) {
- if (mAMediaFormat != NULL) {
- AMediaFormat_setFloat(mAMediaFormat, name, value);
- }
-}
-
-void AMediaFormatWrapper::setDouble(const char* name, double value) {
- if (mAMediaFormat != NULL) {
- AMediaFormat_setDouble(mAMediaFormat, name, value);
- }
-}
-
-void AMediaFormatWrapper::setSize(const char* name, size_t value) {
- if (mAMediaFormat != NULL) {
- AMediaFormat_setSize(mAMediaFormat, name, value);
- }
-}
-
-void AMediaFormatWrapper::setRect(
- const char* name, int32_t left, int32_t top, int32_t right, int32_t bottom) {
- if (mAMediaFormat != NULL) {
- AMediaFormat_setRect(mAMediaFormat, name, left, top, right, bottom);
- }
-}
-
-void AMediaFormatWrapper::setString(const char* name, const AString &value) {
- if (mAMediaFormat != NULL) {
- AMediaFormat_setString(mAMediaFormat, name, value.c_str());
- }
-}
-
-void AMediaFormatWrapper::setBuffer(const char* name, void* data, size_t size) {
- if (mAMediaFormat != NULL) {
- AMediaFormat_setBuffer(mAMediaFormat, name, data, size);
- }
-}
-
-
-//////////// ANativeWindowWrapper
-ANativeWindowWrapper::ANativeWindowWrapper(ANativeWindow *aNativeWindow)
- : mANativeWindow(aNativeWindow) {
- if (aNativeWindow != NULL) {
- ANativeWindow_acquire(aNativeWindow);
- }
-}
-
-ANativeWindowWrapper::~ANativeWindowWrapper() {
- release();
-}
-
-status_t ANativeWindowWrapper::release() {
- if (mANativeWindow != NULL) {
- ANativeWindow_release(mANativeWindow);
- mANativeWindow = NULL;
- }
- return OK;
-}
-
-ANativeWindow *ANativeWindowWrapper::getANativeWindow() const {
- return mANativeWindow;
-}
-
-
-//////////// AMediaDrmWrapper
-AMediaDrmWrapper::AMediaDrmWrapper(const uint8_t uuid[16]) {
- mAMediaDrm = AMediaDrm_createByUUID(uuid);
-}
-
-AMediaDrmWrapper::AMediaDrmWrapper(AMediaDrm *aMediaDrm)
- : mAMediaDrm(aMediaDrm) {
-}
-
-AMediaDrmWrapper::~AMediaDrmWrapper() {
- release();
-}
-
-status_t AMediaDrmWrapper::release() {
- if (mAMediaDrm != NULL) {
- AMediaDrm_release(mAMediaDrm);
- mAMediaDrm = NULL;
- }
- return OK;
-}
-
-AMediaDrm *AMediaDrmWrapper::getAMediaDrm() const {
- return mAMediaDrm;
-}
-
-// static
-bool AMediaDrmWrapper::isCryptoSchemeSupported(
- const uint8_t uuid[16],
- const char *mimeType) {
- return AMediaDrm_isCryptoSchemeSupported(uuid, mimeType);
-}
-
-
-//////////// AMediaCryptoWrapper
-AMediaCryptoWrapper::AMediaCryptoWrapper(
- const uint8_t uuid[16], const void *initData, size_t initDataSize) {
- mAMediaCrypto = AMediaCrypto_new(uuid, initData, initDataSize);
-}
-
-AMediaCryptoWrapper::AMediaCryptoWrapper(AMediaCrypto *aMediaCrypto)
- : mAMediaCrypto(aMediaCrypto) {
-}
-
-AMediaCryptoWrapper::~AMediaCryptoWrapper() {
- release();
-}
-
-status_t AMediaCryptoWrapper::release() {
- if (mAMediaCrypto != NULL) {
- AMediaCrypto_delete(mAMediaCrypto);
- mAMediaCrypto = NULL;
- }
- return OK;
-}
-
-AMediaCrypto *AMediaCryptoWrapper::getAMediaCrypto() const {
- return mAMediaCrypto;
-}
-
-bool AMediaCryptoWrapper::isCryptoSchemeSupported(const uint8_t uuid[16]) {
- if (mAMediaCrypto == NULL) {
- return false;
- }
- return AMediaCrypto_isCryptoSchemeSupported(uuid);
-}
-
-bool AMediaCryptoWrapper::requiresSecureDecoderComponent(const char *mime) {
- if (mAMediaCrypto == NULL) {
- return false;
- }
- return AMediaCrypto_requiresSecureDecoderComponent(mime);
-}
-
-
-//////////// AMediaCodecCryptoInfoWrapper
-// static
-sp<AMediaCodecCryptoInfoWrapper> AMediaCodecCryptoInfoWrapper::Create(MetaDataBase &meta) {
-
- uint32_t type;
- const void *crypteddata;
- size_t cryptedsize;
-
- if (!meta.findData(kKeyEncryptedSizes, &type, &crypteddata, &cryptedsize)) {
- return NULL;
- }
-
- int numSubSamples = cryptedsize / sizeof(size_t);
-
- if (numSubSamples <= 0) {
- ALOGE("Create: INVALID numSubSamples: %d", numSubSamples);
- return NULL;
- }
-
- const void *cleardata;
- size_t clearsize;
- if (meta.findData(kKeyPlainSizes, &type, &cleardata, &clearsize)) {
- if (clearsize != cryptedsize) {
- // The two must be of the same length.
- ALOGE("Create: mismatch cryptedsize: %zu != clearsize: %zu", cryptedsize, clearsize);
- return NULL;
- }
- }
-
- const void *key;
- size_t keysize;
- if (meta.findData(kKeyCryptoKey, &type, &key, &keysize)) {
- if (keysize != kAESBlockSize) {
- // Keys must be 16 bytes in length.
- ALOGE("Create: Keys must be %zu bytes in length: %zu", kAESBlockSize, keysize);
- return NULL;
- }
- }
-
- const void *iv;
- size_t ivsize;
- if (meta.findData(kKeyCryptoIV, &type, &iv, &ivsize)) {
- if (ivsize != kAESBlockSize) {
- // IVs must be 16 bytes in length.
- ALOGE("Create: IV must be %zu bytes in length: %zu", kAESBlockSize, ivsize);
- return NULL;
- }
- }
-
- int32_t mode;
- if (!meta.findInt32(kKeyCryptoMode, &mode)) {
- mode = CryptoPlugin::kMode_AES_CTR;
- }
-
- return new AMediaCodecCryptoInfoWrapper(
- numSubSamples,
- (uint8_t*) key,
- (uint8_t*) iv,
- (CryptoPlugin::Mode)mode,
- (size_t*) cleardata,
- (size_t*) crypteddata);
-}
-
-AMediaCodecCryptoInfoWrapper::AMediaCodecCryptoInfoWrapper(
- int numsubsamples,
- uint8_t key[16],
- uint8_t iv[16],
- CryptoPlugin::Mode mode,
- size_t *clearbytes,
- size_t *encryptedbytes) {
- mAMediaCodecCryptoInfo =
- AMediaCodecCryptoInfo_new(numsubsamples,
- key,
- iv,
- translateToCryptoInfoMode(mode),
- clearbytes,
- encryptedbytes);
-}
-
-AMediaCodecCryptoInfoWrapper::AMediaCodecCryptoInfoWrapper(
- AMediaCodecCryptoInfo *aMediaCodecCryptoInfo)
- : mAMediaCodecCryptoInfo(aMediaCodecCryptoInfo) {
-}
-
-AMediaCodecCryptoInfoWrapper::~AMediaCodecCryptoInfoWrapper() {
- release();
-}
-
-status_t AMediaCodecCryptoInfoWrapper::release() {
- if (mAMediaCodecCryptoInfo != NULL) {
- media_status_t err = AMediaCodecCryptoInfo_delete(mAMediaCodecCryptoInfo);
- mAMediaCodecCryptoInfo = NULL;
- return translateErrorCode(err);
- }
- return OK;
-}
-
-AMediaCodecCryptoInfo *AMediaCodecCryptoInfoWrapper::getAMediaCodecCryptoInfo() const {
- return mAMediaCodecCryptoInfo;
-}
-
-void AMediaCodecCryptoInfoWrapper::setPattern(CryptoPlugin::Pattern *pattern) {
- if (mAMediaCodecCryptoInfo == NULL || pattern == NULL) {
- return;
- }
- cryptoinfo_pattern_t ndkPattern = {(int32_t)pattern->mEncryptBlocks,
- (int32_t)pattern->mSkipBlocks };
- return AMediaCodecCryptoInfo_setPattern(mAMediaCodecCryptoInfo, &ndkPattern);
-}
-
-size_t AMediaCodecCryptoInfoWrapper::getNumSubSamples() {
- if (mAMediaCodecCryptoInfo == NULL) {
- return 0;
- }
- return AMediaCodecCryptoInfo_getNumSubSamples(mAMediaCodecCryptoInfo);
-}
-
-status_t AMediaCodecCryptoInfoWrapper::getKey(uint8_t *dst) {
- if (mAMediaCodecCryptoInfo == NULL) {
- return DEAD_OBJECT;
- }
- if (dst == NULL) {
- return BAD_VALUE;
- }
- return translateErrorCode(
- AMediaCodecCryptoInfo_getKey(mAMediaCodecCryptoInfo, dst));
-}
-
-status_t AMediaCodecCryptoInfoWrapper::getIV(uint8_t *dst) {
- if (mAMediaCodecCryptoInfo == NULL) {
- return DEAD_OBJECT;
- }
- if (dst == NULL) {
- return BAD_VALUE;
- }
- return translateErrorCode(
- AMediaCodecCryptoInfo_getIV(mAMediaCodecCryptoInfo, dst));
-}
-
-CryptoPlugin::Mode AMediaCodecCryptoInfoWrapper::getMode() {
- if (mAMediaCodecCryptoInfo == NULL) {
- return CryptoPlugin::kMode_Unencrypted;
- }
- return translateToCryptoPluginMode(
- AMediaCodecCryptoInfo_getMode(mAMediaCodecCryptoInfo));
-}
-
-status_t AMediaCodecCryptoInfoWrapper::getClearBytes(size_t *dst) {
- if (mAMediaCodecCryptoInfo == NULL) {
- return DEAD_OBJECT;
- }
- if (dst == NULL) {
- return BAD_VALUE;
- }
- return translateErrorCode(
- AMediaCodecCryptoInfo_getClearBytes(mAMediaCodecCryptoInfo, dst));
-}
-
-status_t AMediaCodecCryptoInfoWrapper::getEncryptedBytes(size_t *dst) {
- if (mAMediaCodecCryptoInfo == NULL) {
- return DEAD_OBJECT;
- }
- if (dst == NULL) {
- return BAD_VALUE;
- }
- return translateErrorCode(
- AMediaCodecCryptoInfo_getEncryptedBytes(mAMediaCodecCryptoInfo, dst));
-}
-
-
-//////////// AMediaCodecWrapper
-// static
-sp<AMediaCodecWrapper> AMediaCodecWrapper::CreateCodecByName(const AString &name) {
- AMediaCodec *aMediaCodec = AMediaCodec_createCodecByName(name.c_str());
- return new AMediaCodecWrapper(aMediaCodec);
-}
-
-// static
-sp<AMediaCodecWrapper> AMediaCodecWrapper::CreateDecoderByType(const AString &mimeType) {
- AMediaCodec *aMediaCodec = AMediaCodec_createDecoderByType(mimeType.c_str());
- return new AMediaCodecWrapper(aMediaCodec);
-}
-
-// static
-void AMediaCodecWrapper::OnInputAvailableCB(
- AMediaCodec * /* aMediaCodec */,
- void *userdata,
- int32_t index) {
- ALOGV("OnInputAvailableCB: index(%d)", index);
- sp<AMessage> msg = sp<AMessage>((AMessage *)userdata)->dup();
- msg->setInt32("callbackID", CB_INPUT_AVAILABLE);
- msg->setInt32("index", index);
- msg->post();
-}
-
-// static
-void AMediaCodecWrapper::OnOutputAvailableCB(
- AMediaCodec * /* aMediaCodec */,
- void *userdata,
- int32_t index,
- AMediaCodecBufferInfo *bufferInfo) {
- ALOGV("OnOutputAvailableCB: index(%d), (%d, %d, %lld, 0x%x)",
- index, bufferInfo->offset, bufferInfo->size,
- (long long)bufferInfo->presentationTimeUs, bufferInfo->flags);
- sp<AMessage> msg = sp<AMessage>((AMessage *)userdata)->dup();
- msg->setInt32("callbackID", CB_OUTPUT_AVAILABLE);
- msg->setInt32("index", index);
- msg->setSize("offset", (size_t)(bufferInfo->offset));
- msg->setSize("size", (size_t)(bufferInfo->size));
- msg->setInt64("timeUs", bufferInfo->presentationTimeUs);
- msg->setInt32("flags", (int32_t)(bufferInfo->flags));
- msg->post();
-}
-
-// static
-void AMediaCodecWrapper::OnFormatChangedCB(
- AMediaCodec * /* aMediaCodec */,
- void *userdata,
- AMediaFormat *format) {
- sp<AMediaFormatWrapper> formatWrapper = new AMediaFormatWrapper(format);
- sp<AMessage> outputFormat = formatWrapper->toAMessage();
- ALOGV("OnFormatChangedCB: format(%s)", outputFormat->debugString().c_str());
-
- sp<AMessage> msg = sp<AMessage>((AMessage *)userdata)->dup();
- msg->setInt32("callbackID", CB_OUTPUT_FORMAT_CHANGED);
- msg->setMessage("format", outputFormat);
- msg->post();
-}
-
-// static
-void AMediaCodecWrapper::OnErrorCB(
- AMediaCodec * /* aMediaCodec */,
- void *userdata,
- media_status_t err,
- int32_t actionCode,
- const char *detail) {
- ALOGV("OnErrorCB: err(%d), actionCode(%d), detail(%s)", err, actionCode, detail);
- sp<AMessage> msg = sp<AMessage>((AMessage *)userdata)->dup();
- msg->setInt32("callbackID", CB_ERROR);
- msg->setInt32("err", translateErrorCode(err));
- msg->setInt32("actionCode", translateActionCode(actionCode));
- msg->setString("detail", detail);
- msg->post();
-}
-
-AMediaCodecWrapper::AMediaCodecWrapper(AMediaCodec *aMediaCodec)
- : mAMediaCodec(aMediaCodec) {
-}
-
-AMediaCodecWrapper::~AMediaCodecWrapper() {
- release();
-}
-
-status_t AMediaCodecWrapper::release() {
- if (mAMediaCodec != NULL) {
- AMediaCodecOnAsyncNotifyCallback aCB = {};
- AMediaCodec_setAsyncNotifyCallback(mAMediaCodec, aCB, NULL);
- mCallback = NULL;
-
- media_status_t err = AMediaCodec_delete(mAMediaCodec);
- mAMediaCodec = NULL;
- return translateErrorCode(err);
- }
- return OK;
-}
-
-AMediaCodec *AMediaCodecWrapper::getAMediaCodec() const {
- return mAMediaCodec;
-}
-
-status_t AMediaCodecWrapper::getName(AString *outComponentName) const {
- if (mAMediaCodec == NULL) {
- return DEAD_OBJECT;
- }
- char *name = NULL;
- media_status_t err = AMediaCodec_getName(mAMediaCodec, &name);
- if (err != AMEDIA_OK) {
- return translateErrorCode(err);
- }
-
- *outComponentName = AString(name);
- AMediaCodec_releaseName(mAMediaCodec, name);
- return OK;
-}
-
-status_t AMediaCodecWrapper::configure(
- const sp<AMediaFormatWrapper> &format,
- const sp<ANativeWindowWrapper> &nww,
- const sp<AMediaCryptoWrapper> &crypto,
- uint32_t flags) {
- if (mAMediaCodec == NULL) {
- return DEAD_OBJECT;
- }
-
- media_status_t err = AMediaCodec_configure(
- mAMediaCodec,
- format->getAMediaFormat(),
- (nww == NULL ? NULL : nww->getANativeWindow()),
- crypto == NULL ? NULL : crypto->getAMediaCrypto(),
- flags);
-
- return translateErrorCode(err);
-}
-
-status_t AMediaCodecWrapper::setCallback(const sp<AMessage> &callback) {
- if (mAMediaCodec == NULL) {
- return DEAD_OBJECT;
- }
-
- mCallback = callback;
-
- AMediaCodecOnAsyncNotifyCallback aCB = {
- OnInputAvailableCB,
- OnOutputAvailableCB,
- OnFormatChangedCB,
- OnErrorCB
- };
-
- return translateErrorCode(
- AMediaCodec_setAsyncNotifyCallback(mAMediaCodec, aCB, callback.get()));
-}
-
-status_t AMediaCodecWrapper::releaseCrypto() {
- if (mAMediaCodec == NULL) {
- return DEAD_OBJECT;
- }
- return translateErrorCode(AMediaCodec_releaseCrypto(mAMediaCodec));
-}
-
-status_t AMediaCodecWrapper::start() {
- if (mAMediaCodec == NULL) {
- return DEAD_OBJECT;
- }
- return translateErrorCode(AMediaCodec_start(mAMediaCodec));
-}
-
-status_t AMediaCodecWrapper::stop() {
- if (mAMediaCodec == NULL) {
- return DEAD_OBJECT;
- }
- return translateErrorCode(AMediaCodec_stop(mAMediaCodec));
-}
-
-status_t AMediaCodecWrapper::flush() {
- if (mAMediaCodec == NULL) {
- return DEAD_OBJECT;
- }
- return translateErrorCode(AMediaCodec_flush(mAMediaCodec));
-}
-
-uint8_t* AMediaCodecWrapper::getInputBuffer(size_t idx, size_t *out_size) {
- if (mAMediaCodec == NULL) {
- return NULL;
- }
- return AMediaCodec_getInputBuffer(mAMediaCodec, idx, out_size);
-}
-
-uint8_t* AMediaCodecWrapper::getOutputBuffer(size_t idx, size_t *out_size) {
- if (mAMediaCodec == NULL) {
- return NULL;
- }
- return AMediaCodec_getOutputBuffer(mAMediaCodec, idx, out_size);
-}
-
-status_t AMediaCodecWrapper::queueInputBuffer(
- size_t idx,
- size_t offset,
- size_t size,
- uint64_t time,
- uint32_t flags) {
- if (mAMediaCodec == NULL) {
- return DEAD_OBJECT;
- }
- return translateErrorCode(
- AMediaCodec_queueInputBuffer(mAMediaCodec, idx, offset, size, time, flags));
-}
-
-status_t AMediaCodecWrapper::queueSecureInputBuffer(
- size_t idx,
- size_t offset,
- sp<AMediaCodecCryptoInfoWrapper> &codecCryptoInfo,
- uint64_t time,
- uint32_t flags) {
- if (mAMediaCodec == NULL) {
- return DEAD_OBJECT;
- }
- return translateErrorCode(
- AMediaCodec_queueSecureInputBuffer(
- mAMediaCodec,
- idx,
- offset,
- codecCryptoInfo->getAMediaCodecCryptoInfo(),
- time,
- flags));
-}
-
-sp<AMediaFormatWrapper> AMediaCodecWrapper::getOutputFormat() {
- if (mAMediaCodec == NULL) {
- return NULL;
- }
- return new AMediaFormatWrapper(AMediaCodec_getOutputFormat(mAMediaCodec));
-}
-
-sp<AMediaFormatWrapper> AMediaCodecWrapper::getInputFormat() {
- if (mAMediaCodec == NULL) {
- return NULL;
- }
- return new AMediaFormatWrapper(AMediaCodec_getInputFormat(mAMediaCodec));
-}
-
-status_t AMediaCodecWrapper::releaseOutputBuffer(size_t idx, bool render) {
- if (mAMediaCodec == NULL) {
- return DEAD_OBJECT;
- }
- return translateErrorCode(
- AMediaCodec_releaseOutputBuffer(mAMediaCodec, idx, render));
-}
-
-status_t AMediaCodecWrapper::setOutputSurface(const sp<ANativeWindowWrapper> &nww) {
- if (mAMediaCodec == NULL) {
- return DEAD_OBJECT;
- }
- return translateErrorCode(
- AMediaCodec_setOutputSurface(mAMediaCodec,
- (nww == NULL ? NULL : nww->getANativeWindow())));
-}
-
-status_t AMediaCodecWrapper::releaseOutputBufferAtTime(size_t idx, int64_t timestampNs) {
- if (mAMediaCodec == NULL) {
- return DEAD_OBJECT;
- }
- return translateErrorCode(
- AMediaCodec_releaseOutputBufferAtTime(mAMediaCodec, idx, timestampNs));
-}
-
-status_t AMediaCodecWrapper::setParameters(const sp<AMediaFormatWrapper> ¶ms) {
- if (mAMediaCodec == NULL) {
- return DEAD_OBJECT;
- }
- return translateErrorCode(
- AMediaCodec_setParameters(mAMediaCodec, params->getAMediaFormat()));
-}
-
-//////////// AMediaExtractorWrapper
-
-AMediaExtractorWrapper::AMediaExtractorWrapper(AMediaExtractor *aMediaExtractor)
- : mAMediaExtractor(aMediaExtractor) {
-}
-
-AMediaExtractorWrapper::~AMediaExtractorWrapper() {
- release();
-}
-
-status_t AMediaExtractorWrapper::release() {
- if (mAMediaExtractor != NULL) {
- media_status_t err = AMediaExtractor_delete(mAMediaExtractor);
- mAMediaExtractor = NULL;
- return translateErrorCode(err);
- }
- return OK;
-}
-
-AMediaExtractor *AMediaExtractorWrapper::getAMediaExtractor() const {
- return mAMediaExtractor;
-}
-
-status_t AMediaExtractorWrapper::setDataSource(int fd, off64_t offset, off64_t length) {
- if (mAMediaExtractor == NULL) {
- return DEAD_OBJECT;
- }
- return translateErrorCode(AMediaExtractor_setDataSourceFd(
- mAMediaExtractor, fd, offset, length));
-}
-
-status_t AMediaExtractorWrapper::setDataSource(const char *location) {
- if (mAMediaExtractor == NULL) {
- return DEAD_OBJECT;
- }
- return translateErrorCode(AMediaExtractor_setDataSource(mAMediaExtractor, location));
-}
-
-status_t AMediaExtractorWrapper::setDataSource(AMediaDataSource *source) {
- if (mAMediaExtractor == NULL) {
- return DEAD_OBJECT;
- }
- return translateErrorCode(AMediaExtractor_setDataSourceCustom(mAMediaExtractor, source));
-}
-
-size_t AMediaExtractorWrapper::getTrackCount() {
- if (mAMediaExtractor == NULL) {
- return 0;
- }
- return AMediaExtractor_getTrackCount(mAMediaExtractor);
-}
-
-sp<AMediaFormatWrapper> AMediaExtractorWrapper::getFormat() {
- if (mAMediaExtractor == NULL) {
- return NULL;
- }
- return new AMediaFormatWrapper(AMediaExtractor_getFileFormat(mAMediaExtractor));
-}
-
-sp<AMediaFormatWrapper> AMediaExtractorWrapper::getTrackFormat(size_t idx) {
- if (mAMediaExtractor == NULL) {
- return NULL;
- }
- return new AMediaFormatWrapper(AMediaExtractor_getTrackFormat(mAMediaExtractor, idx));
-}
-
-status_t AMediaExtractorWrapper::selectTrack(size_t idx) {
- if (mAMediaExtractor == NULL) {
- return DEAD_OBJECT;
- }
- return translateErrorCode(AMediaExtractor_selectTrack(mAMediaExtractor, idx));
-}
-
-status_t AMediaExtractorWrapper::unselectTrack(size_t idx) {
- if (mAMediaExtractor == NULL) {
- return DEAD_OBJECT;
- }
- return translateErrorCode(AMediaExtractor_unselectTrack(mAMediaExtractor, idx));
-}
-
-status_t AMediaExtractorWrapper::selectSingleTrack(size_t idx) {
- if (mAMediaExtractor == NULL) {
- return DEAD_OBJECT;
- }
- for (size_t i = 0; i < AMediaExtractor_getTrackCount(mAMediaExtractor); ++i) {
- if (i == idx) {
- media_status_t err = AMediaExtractor_selectTrack(mAMediaExtractor, i);
- if (err != AMEDIA_OK) {
- return translateErrorCode(err);
- }
- } else {
- media_status_t err = AMediaExtractor_unselectTrack(mAMediaExtractor, i);
- if (err != AMEDIA_OK) {
- return translateErrorCode(err);
- }
- }
- }
- return OK;
-}
-
-ssize_t AMediaExtractorWrapper::readSampleData(const sp<ABuffer> &buffer) {
- if (mAMediaExtractor == NULL) {
- return -1;
- }
- return AMediaExtractor_readSampleData(mAMediaExtractor, buffer->data(), buffer->capacity());
-}
-
-ssize_t AMediaExtractorWrapper::getSampleSize() {
- if (mAMediaExtractor == NULL) {
- return 0;
- }
- return AMediaExtractor_getSampleSize(mAMediaExtractor);
-}
-
-uint32_t AMediaExtractorWrapper::getSampleFlags() {
- if (mAMediaExtractor == NULL) {
- return 0;
- }
- return AMediaExtractor_getSampleFlags(mAMediaExtractor);
-}
-
-int AMediaExtractorWrapper::getSampleTrackIndex() {
- if (mAMediaExtractor == NULL) {
- return -1;
- }
- return AMediaExtractor_getSampleTrackIndex(mAMediaExtractor);
-}
-
-int64_t AMediaExtractorWrapper::getSampleTime() {
- if (mAMediaExtractor == NULL) {
- return -1;
- }
- return AMediaExtractor_getSampleTime(mAMediaExtractor);
-}
-
-status_t AMediaExtractorWrapper::getSampleFormat(sp<AMediaFormatWrapper> &formatWrapper) {
- if (mAMediaExtractor == NULL) {
- return DEAD_OBJECT;
- }
- AMediaFormat *format = AMediaFormat_new();
- formatWrapper = new AMediaFormatWrapper(format);
- return translateErrorCode(AMediaExtractor_getSampleFormat(mAMediaExtractor, format));
-}
-
-int64_t AMediaExtractorWrapper::getCachedDuration() {
- if (mAMediaExtractor == NULL) {
- return -1;
- }
- return AMediaExtractor_getCachedDuration(mAMediaExtractor);
-}
-
-bool AMediaExtractorWrapper::advance() {
- if (mAMediaExtractor == NULL) {
- return false;
- }
- return AMediaExtractor_advance(mAMediaExtractor);
-}
-
-status_t AMediaExtractorWrapper::seekTo(int64_t seekPosUs, MediaSource::ReadOptions::SeekMode mode) {
- if (mAMediaExtractor == NULL) {
- return DEAD_OBJECT;
- }
-
- SeekMode aMode;
- switch (mode) {
- case MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC: {
- aMode = AMEDIAEXTRACTOR_SEEK_PREVIOUS_SYNC;
- break;
- }
- case MediaSource::ReadOptions::SEEK_NEXT_SYNC: {
- aMode = AMEDIAEXTRACTOR_SEEK_NEXT_SYNC;
- break;
- }
- default: {
- aMode = AMEDIAEXTRACTOR_SEEK_CLOSEST_SYNC;
- break;
- }
- }
- return AMediaExtractor_seekTo(mAMediaExtractor, seekPosUs, aMode);
-}
-
-PsshInfo* AMediaExtractorWrapper::getPsshInfo() {
- if (mAMediaExtractor == NULL) {
- return NULL;
- }
- return AMediaExtractor_getPsshInfo(mAMediaExtractor);
-}
-
-sp<AMediaCodecCryptoInfoWrapper> AMediaExtractorWrapper::getSampleCryptoInfo() {
- if (mAMediaExtractor == NULL) {
- return NULL;
- }
- AMediaCodecCryptoInfo *cryptoInfo = AMediaExtractor_getSampleCryptoInfo(mAMediaExtractor);
- if (cryptoInfo == NULL) {
- return NULL;
- }
- return new AMediaCodecCryptoInfoWrapper(cryptoInfo);
-}
-
-AMediaDataSourceWrapper::AMediaDataSourceWrapper(const sp<DataSource> &dataSource)
- : mDataSource(dataSource),
- mAMediaDataSource(convertDataSourceToAMediaDataSource(dataSource)) {
-}
-
-AMediaDataSourceWrapper::AMediaDataSourceWrapper(AMediaDataSource *aDataSource)
- : mDataSource(NULL),
- mAMediaDataSource(aDataSource) {
-}
-
-AMediaDataSourceWrapper::~AMediaDataSourceWrapper() {
- if (mAMediaDataSource == NULL) {
- return;
- }
- AMediaDataSource_close(mAMediaDataSource);
- AMediaDataSource_delete(mAMediaDataSource);
- mAMediaDataSource = NULL;
-}
-
-AMediaDataSource* AMediaDataSourceWrapper::getAMediaDataSource() {
- return mAMediaDataSource;
-}
-
-void AMediaDataSourceWrapper::close() {
- AMediaDataSource_close(mAMediaDataSource);
-}
-
-} // namespace android
diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp
deleted file mode 100644
index 2bf0802..0000000
--- a/media/libmedia/Visualizer.cpp
+++ /dev/null
@@ -1,445 +0,0 @@
-/*
-**
-** Copyright 2010, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "Visualizer"
-#include <utils/Log.h>
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <limits.h>
-
-#include <media/Visualizer.h>
-#include <audio_utils/fixedfft.h>
-#include <utils/Thread.h>
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-Visualizer::Visualizer (const String16& opPackageName,
- int32_t priority,
- effect_callback_t cbf,
- void* user,
- audio_session_t sessionId)
- : AudioEffect(SL_IID_VISUALIZATION, opPackageName, NULL, priority, cbf, user, sessionId),
- mCaptureRate(CAPTURE_RATE_DEF),
- mCaptureSize(CAPTURE_SIZE_DEF),
- mSampleRate(44100000),
- mScalingMode(VISUALIZER_SCALING_MODE_NORMALIZED),
- mMeasurementMode(MEASUREMENT_MODE_NONE),
- mCaptureCallBack(NULL),
- mCaptureCbkUser(NULL)
-{
- initCaptureSize();
-}
-
-Visualizer::~Visualizer()
-{
- ALOGV("Visualizer::~Visualizer()");
- setEnabled(false);
- setCaptureCallBack(NULL, NULL, 0, 0);
-}
-
-void Visualizer::release()
-{
- ALOGV("Visualizer::release()");
- setEnabled(false);
- Mutex::Autolock _l(mCaptureLock);
-
- mCaptureThread.clear();
- mCaptureCallBack = NULL;
- mCaptureCbkUser = NULL;
- mCaptureFlags = 0;
- mCaptureRate = 0;
-}
-
-status_t Visualizer::setEnabled(bool enabled)
-{
- Mutex::Autolock _l(mCaptureLock);
-
- sp<CaptureThread> t = mCaptureThread;
- if (t != 0) {
- if (enabled) {
- if (t->exitPending()) {
- mCaptureLock.unlock();
- if (t->requestExitAndWait() == WOULD_BLOCK) {
- mCaptureLock.lock();
- ALOGE("Visualizer::enable() called from thread");
- return INVALID_OPERATION;
- }
- mCaptureLock.lock();
- }
- }
- t->mLock.lock();
- }
-
- status_t status = AudioEffect::setEnabled(enabled);
-
- if (t != 0) {
- if (enabled && status == NO_ERROR) {
- t->run("Visualizer");
- } else {
- t->requestExit();
- }
- }
-
- if (t != 0) {
- t->mLock.unlock();
- }
-
- return status;
-}
-
-status_t Visualizer::setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags,
- uint32_t rate)
-{
- if (rate > CAPTURE_RATE_MAX) {
- return BAD_VALUE;
- }
- Mutex::Autolock _l(mCaptureLock);
-
- if (mEnabled) {
- return INVALID_OPERATION;
- }
-
- if (mCaptureThread != 0) {
- mCaptureLock.unlock();
- mCaptureThread->requestExitAndWait();
- mCaptureLock.lock();
- }
-
- mCaptureThread.clear();
- mCaptureCallBack = cbk;
- mCaptureCbkUser = user;
- mCaptureFlags = flags;
- mCaptureRate = rate;
-
- if (cbk != NULL) {
- mCaptureThread = new CaptureThread(this, rate, ((flags & CAPTURE_CALL_JAVA) != 0));
- }
- ALOGV("setCaptureCallBack() rate: %d thread %p flags 0x%08x",
- rate, mCaptureThread.get(), mCaptureFlags);
- return NO_ERROR;
-}
-
-status_t Visualizer::setCaptureSize(uint32_t size)
-{
- if (size > VISUALIZER_CAPTURE_SIZE_MAX ||
- size < VISUALIZER_CAPTURE_SIZE_MIN ||
- popcount(size) != 1) {
- return BAD_VALUE;
- }
-
- Mutex::Autolock _l(mCaptureLock);
- if (mEnabled) {
- return INVALID_OPERATION;
- }
-
- uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
- effect_param_t *p = (effect_param_t *)buf32;
-
- p->psize = sizeof(uint32_t);
- p->vsize = sizeof(uint32_t);
- *(int32_t *)p->data = VISUALIZER_PARAM_CAPTURE_SIZE;
- *((int32_t *)p->data + 1)= size;
- status_t status = setParameter(p);
-
- ALOGV("setCaptureSize size %d status %d p->status %d", size, status, p->status);
-
- if (status == NO_ERROR) {
- status = p->status;
- if (status == NO_ERROR) {
- mCaptureSize = size;
- }
- }
-
- return status;
-}
-
-status_t Visualizer::setScalingMode(uint32_t mode) {
- if ((mode != VISUALIZER_SCALING_MODE_NORMALIZED)
- && (mode != VISUALIZER_SCALING_MODE_AS_PLAYED)) {
- return BAD_VALUE;
- }
-
- Mutex::Autolock _l(mCaptureLock);
-
- uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
- effect_param_t *p = (effect_param_t *)buf32;
-
- p->psize = sizeof(uint32_t);
- p->vsize = sizeof(uint32_t);
- *(int32_t *)p->data = VISUALIZER_PARAM_SCALING_MODE;
- *((int32_t *)p->data + 1)= mode;
- status_t status = setParameter(p);
-
- ALOGV("setScalingMode mode %d status %d p->status %d", mode, status, p->status);
-
- if (status == NO_ERROR) {
- status = p->status;
- if (status == NO_ERROR) {
- mScalingMode = mode;
- }
- }
-
- return status;
-}
-
-status_t Visualizer::setMeasurementMode(uint32_t mode) {
- if ((mode != MEASUREMENT_MODE_NONE)
- //Note: needs to be handled as a mask when more measurement modes are added
- && ((mode & MEASUREMENT_MODE_PEAK_RMS) != mode)) {
- return BAD_VALUE;
- }
-
- Mutex::Autolock _l(mCaptureLock);
-
- uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
- effect_param_t *p = (effect_param_t *)buf32;
-
- p->psize = sizeof(uint32_t);
- p->vsize = sizeof(uint32_t);
- *(int32_t *)p->data = VISUALIZER_PARAM_MEASUREMENT_MODE;
- *((int32_t *)p->data + 1)= mode;
- status_t status = setParameter(p);
-
- ALOGV("setMeasurementMode mode %d status %d p->status %d", mode, status, p->status);
-
- if (status == NO_ERROR) {
- status = p->status;
- if (status == NO_ERROR) {
- mMeasurementMode = mode;
- }
- }
- return status;
-}
-
-status_t Visualizer::getIntMeasurements(uint32_t type, uint32_t number, int32_t *measurements) {
- if (mMeasurementMode == MEASUREMENT_MODE_NONE) {
- ALOGE("Cannot retrieve int measurements, no measurement mode set");
- return INVALID_OPERATION;
- }
- if (!(mMeasurementMode & type)) {
- // measurement type has not been set on this Visualizer
- ALOGE("Cannot retrieve int measurements, requested measurement mode 0x%x not set(0x%x)",
- type, mMeasurementMode);
- return INVALID_OPERATION;
- }
- // only peak+RMS measurement supported
- if ((type != MEASUREMENT_MODE_PEAK_RMS)
- // for peak+RMS measurement, the results are 2 int32_t values
- || (number != 2)) {
- ALOGE("Cannot retrieve int measurements, MEASUREMENT_MODE_PEAK_RMS returns 2 ints, not %d",
- number);
- return BAD_VALUE;
- }
-
- status_t status = NO_ERROR;
- if (mEnabled) {
- uint32_t replySize = number * sizeof(int32_t);
- status = command(VISUALIZER_CMD_MEASURE,
- sizeof(uint32_t) /*cmdSize*/,
- &type /*cmdData*/,
- &replySize, measurements);
- ALOGV("getMeasurements() command returned %d", status);
- if ((status == NO_ERROR) && (replySize == 0)) {
- status = NOT_ENOUGH_DATA;
- }
- } else {
- ALOGV("getMeasurements() disabled");
- return INVALID_OPERATION;
- }
- return status;
-}
-
-status_t Visualizer::getWaveForm(uint8_t *waveform)
-{
- if (waveform == NULL) {
- return BAD_VALUE;
- }
- if (mCaptureSize == 0) {
- return NO_INIT;
- }
-
- status_t status = NO_ERROR;
- if (mEnabled) {
- uint32_t replySize = mCaptureSize;
- status = command(VISUALIZER_CMD_CAPTURE, 0, NULL, &replySize, waveform);
- ALOGV("getWaveForm() command returned %d", status);
- if ((status == NO_ERROR) && (replySize == 0)) {
- status = NOT_ENOUGH_DATA;
- }
- } else {
- ALOGV("getWaveForm() disabled");
- memset(waveform, 0x80, mCaptureSize);
- }
- return status;
-}
-
-status_t Visualizer::getFft(uint8_t *fft)
-{
- if (fft == NULL) {
- return BAD_VALUE;
- }
- if (mCaptureSize == 0) {
- return NO_INIT;
- }
-
- status_t status = NO_ERROR;
- if (mEnabled) {
- uint8_t buf[mCaptureSize];
- status = getWaveForm(buf);
- if (status == NO_ERROR) {
- status = doFft(fft, buf);
- }
- } else {
- memset(fft, 0, mCaptureSize);
- }
- return status;
-}
-
-status_t Visualizer::doFft(uint8_t *fft, uint8_t *waveform)
-{
- int32_t workspace[mCaptureSize >> 1];
- int32_t nonzero = 0;
-
- for (uint32_t i = 0; i < mCaptureSize; i += 2) {
- workspace[i >> 1] =
- ((waveform[i] ^ 0x80) << 24) | ((waveform[i + 1] ^ 0x80) << 8);
- nonzero |= workspace[i >> 1];
- }
-
- if (nonzero) {
- fixed_fft_real(mCaptureSize >> 1, workspace);
- }
-
- for (uint32_t i = 0; i < mCaptureSize; i += 2) {
- short tmp = workspace[i >> 1] >> 21;
- while (tmp > 127 || tmp < -128) tmp >>= 1;
- fft[i] = tmp;
- tmp = workspace[i >> 1];
- tmp >>= 5;
- while (tmp > 127 || tmp < -128) tmp >>= 1;
- fft[i + 1] = tmp;
- }
-
- return NO_ERROR;
-}
-
-void Visualizer::periodicCapture()
-{
- Mutex::Autolock _l(mCaptureLock);
- ALOGV("periodicCapture() %p mCaptureCallBack %p mCaptureFlags 0x%08x",
- this, mCaptureCallBack, mCaptureFlags);
- if (mCaptureCallBack != NULL &&
- (mCaptureFlags & (CAPTURE_WAVEFORM|CAPTURE_FFT)) &&
- mCaptureSize != 0) {
- uint8_t waveform[mCaptureSize];
- status_t status = getWaveForm(waveform);
- if (status != NO_ERROR) {
- return;
- }
- uint8_t fft[mCaptureSize];
- if (mCaptureFlags & CAPTURE_FFT) {
- status = doFft(fft, waveform);
- }
- if (status != NO_ERROR) {
- return;
- }
- uint8_t *wavePtr = NULL;
- uint8_t *fftPtr = NULL;
- uint32_t waveSize = 0;
- uint32_t fftSize = 0;
- if (mCaptureFlags & CAPTURE_WAVEFORM) {
- wavePtr = waveform;
- waveSize = mCaptureSize;
- }
- if (mCaptureFlags & CAPTURE_FFT) {
- fftPtr = fft;
- fftSize = mCaptureSize;
- }
- mCaptureCallBack(mCaptureCbkUser, waveSize, wavePtr, fftSize, fftPtr, mSampleRate);
- }
-}
-
-uint32_t Visualizer::initCaptureSize()
-{
- uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
- effect_param_t *p = (effect_param_t *)buf32;
-
- p->psize = sizeof(uint32_t);
- p->vsize = sizeof(uint32_t);
- *(int32_t *)p->data = VISUALIZER_PARAM_CAPTURE_SIZE;
- status_t status = getParameter(p);
-
- if (status == NO_ERROR) {
- status = p->status;
- }
-
- uint32_t size = 0;
- if (status == NO_ERROR) {
- size = *((int32_t *)p->data + 1);
- }
- mCaptureSize = size;
-
- ALOGV("initCaptureSize size %d status %d", mCaptureSize, status);
-
- return size;
-}
-
-void Visualizer::controlStatusChanged(bool controlGranted) {
- if (controlGranted) {
- // this Visualizer instance regained control of the effect, reset the scaling mode
- // and capture size as has been cached through it.
- ALOGV("controlStatusChanged(true) causes effect parameter reset:");
- ALOGV(" scaling mode reset to %d", mScalingMode);
- setScalingMode(mScalingMode);
- ALOGV(" capture size reset to %d", mCaptureSize);
- setCaptureSize(mCaptureSize);
- }
- AudioEffect::controlStatusChanged(controlGranted);
-}
-
-//-------------------------------------------------------------------------
-
-Visualizer::CaptureThread::CaptureThread(Visualizer* receiver, uint32_t captureRate,
- bool bCanCallJava)
- : Thread(bCanCallJava), mReceiver(receiver)
-{
- mSleepTimeUs = 1000000000 / captureRate;
- ALOGV("CaptureThread cstor %p captureRate %d mSleepTimeUs %d", this, captureRate, mSleepTimeUs);
-}
-
-bool Visualizer::CaptureThread::threadLoop()
-{
- ALOGV("CaptureThread %p enter", this);
- sp<Visualizer> receiver = mReceiver.promote();
- if (receiver == NULL) {
- return false;
- }
- while (!exitPending())
- {
- usleep(mSleepTimeUs);
- receiver->periodicCapture();
- }
- ALOGV("CaptureThread %p exiting", this);
- return false;
-}
-
-} // namespace android
diff --git a/media/libmedia/aidl/android/media/IResourceManagerClient.aidl b/media/libmedia/aidl/android/media/IResourceManagerClient.aidl
new file mode 100644
index 0000000..4c3ef47
--- /dev/null
+++ b/media/libmedia/aidl/android/media/IResourceManagerClient.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+/**
+ * IResourceManagerClient interface for the ResourceManagerService to
+ * call the client.
+ *
+ * {@hide}
+ */
+interface IResourceManagerClient {
+ /**
+ * Instruct the client to reclaim its resources.
+ *
+ * @return true if the reclaim was successful and false otherwise.
+ */
+ boolean reclaimResource();
+
+ /**
+ * Retrieve the name of the client.
+ *
+ * @return name of the client.
+ */
+ @utf8InCpp String getName();
+}
diff --git a/media/libmedia/aidl/android/media/IResourceManagerService.aidl b/media/libmedia/aidl/android/media/IResourceManagerService.aidl
new file mode 100644
index 0000000..3e6f8db
--- /dev/null
+++ b/media/libmedia/aidl/android/media/IResourceManagerService.aidl
@@ -0,0 +1,87 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.media.IResourceManagerClient;
+import android.media.MediaResourceParcel;
+import android.media.MediaResourcePolicyParcel;
+
+/**
+ * ResourceManagerService interface that keeps track of media resource
+ * owned by clients, and reclaims resources based on configured policies
+ * when necessary.
+ *
+ * {@hide}
+ */
+interface IResourceManagerService {
+ const @utf8InCpp String kPolicySupportsMultipleSecureCodecs
+ = "supports-multiple-secure-codecs";
+ const @utf8InCpp String kPolicySupportsSecureWithNonSecureCodec
+ = "supports-secure-with-non-secure-codec";
+
+ /**
+ * Configure the ResourceManagerService to adopted particular policies when
+ * managing the resources.
+ *
+ * @param policies an array of policies to be adopted.
+ */
+ void config(in MediaResourcePolicyParcel[] policies);
+
+ /**
+ * Add a client to a process with a list of resources.
+ *
+ * @param pid pid of the client.
+ * @param uid uid of the client.
+ * @param clientId an identifier that uniquely identifies the client within the pid.
+ * @param client interface for the ResourceManagerService to call the client.
+ * @param resources an array of resources to be added.
+ */
+ void addResource(
+ int pid,
+ int uid,
+ long clientId,
+ IResourceManagerClient client,
+ in MediaResourceParcel[] resources);
+
+ /**
+ * Remove the listed resources from a client.
+ *
+ * @param pid pid from which the list of resources will be removed.
+ * @param clientId clientId within the pid from which the list of resources will be removed.
+ * @param resources an array of resources to be removed from the client.
+ */
+ void removeResource(int pid, long clientId, in MediaResourceParcel[] resources);
+
+ /**
+ * Remove all resources from a client.
+ *
+ * @param pid pid from which the client's resources will be removed.
+ * @param clientId clientId within the pid that will be removed.
+ */
+ void removeClient(int pid, long clientId);
+
+ /**
+ * Tries to reclaim resource from processes with lower priority than the
+ * calling process according to the requested resources.
+ *
+ * @param callingPid pid of the calling process.
+ * @param resources an array of resources to be reclaimed.
+ *
+ * @return true if the reclaim was successful and false otherwise.
+ */
+ boolean reclaimResource(int callingPid, in MediaResourceParcel[] resources);
+}
diff --git a/media/libmedia/aidl/android/media/MediaResourceParcel.aidl b/media/libmedia/aidl/android/media/MediaResourceParcel.aidl
new file mode 100644
index 0000000..b0f2b71
--- /dev/null
+++ b/media/libmedia/aidl/android/media/MediaResourceParcel.aidl
@@ -0,0 +1,50 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.media.MediaResourceType;
+import android.media.MediaResourceSubType;
+
+/**
+ * Description of a media resource to be tracked by MediaResourceManager.
+ *
+ * {@hide}
+ */
+parcelable MediaResourceParcel {
+ // TODO: default enum value is not supported yet.
+ // Set default enum value when b/142739329 is fixed.
+
+ /**
+ * Type of the media resource.
+ */
+ MediaResourceType type;// = MediaResourceTypeEnum::kUnspecified;
+
+ /**
+ * Sub-type of the media resource.
+ */
+ MediaResourceSubType subType;// = MediaResourceSubTypeEnum::kUnspecifiedSubType;
+
+ /**
+ * Identifier of the media resource (eg. Drm session id).
+ */
+ byte[] id;
+
+ /**
+ * Number of units of the media resource (bytes of graphic memory, number of codecs, etc.).
+ */
+ long value = 0;
+}
diff --git a/media/libmedia/aidl/android/media/MediaResourcePolicyParcel.aidl b/media/libmedia/aidl/android/media/MediaResourcePolicyParcel.aidl
new file mode 100644
index 0000000..4ea859a
--- /dev/null
+++ b/media/libmedia/aidl/android/media/MediaResourcePolicyParcel.aidl
@@ -0,0 +1,33 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+/**
+ * Description of a policy to be adopted by ResourceManagerService.
+ * {@hide}
+ */
+parcelable MediaResourcePolicyParcel {
+ /**
+ * Name of the policy to be adopted.
+ */
+ @utf8InCpp String type;
+
+ /**
+ * Value of the policy to be adopted.
+ */
+ @utf8InCpp String value;
+}
diff --git a/media/libmedia/aidl/android/media/MediaResourceSubType.aidl b/media/libmedia/aidl/android/media/MediaResourceSubType.aidl
new file mode 100644
index 0000000..af2ba68
--- /dev/null
+++ b/media/libmedia/aidl/android/media/MediaResourceSubType.aidl
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+/**
+ * Sub-type enums of media resources.
+ *
+ * {@hide}
+ */
+@Backing(type="int")
+enum MediaResourceSubType {
+ kUnspecifiedSubType = 0,
+ kAudioCodec = 1,
+ kVideoCodec = 2,
+}
diff --git a/media/libmedia/aidl/android/media/MediaResourceType.aidl b/media/libmedia/aidl/android/media/MediaResourceType.aidl
new file mode 100644
index 0000000..b2bb71b
--- /dev/null
+++ b/media/libmedia/aidl/android/media/MediaResourceType.aidl
@@ -0,0 +1,33 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+/**
+ * Type enums of media resources.
+ *
+ * {@hide}
+ */
+@Backing(type="int")
+enum MediaResourceType {
+ kUnspecified = 0,
+ kSecureCodec = 1,
+ kNonSecureCodec = 2,
+ kGraphicMemory = 3,
+ kCpuBoost = 4,
+ kBattery = 5,
+ kDrmSession = 6,
+}
diff --git a/media/libmedia/api/resourcemanager/1/.hash b/media/libmedia/api/resourcemanager/1/.hash
new file mode 100644
index 0000000..e56d56b
--- /dev/null
+++ b/media/libmedia/api/resourcemanager/1/.hash
@@ -0,0 +1,18 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not
+// try to edit this file. It looks like you are doing that because you have
+// modified an AIDL interface in a backward-incompatible way, e.g., deleting a
+// function from an interface or a field from a parcelable and it broke the
+// build. That breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+58fe4b26909c9c4f17b1803baa4005c10ee40750 -
diff --git a/media/libmedia/api/resourcemanager/1/android/media/IResourceManagerClient.aidl b/media/libmedia/api/resourcemanager/1/android/media/IResourceManagerClient.aidl
new file mode 100644
index 0000000..20bfe72
--- /dev/null
+++ b/media/libmedia/api/resourcemanager/1/android/media/IResourceManagerClient.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not
+// try to edit this file. It looks like you are doing that because you have
+// modified an AIDL interface in a backward-incompatible way, e.g., deleting a
+// function from an interface or a field from a parcelable and it broke the
+// build. That breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media;
+interface IResourceManagerClient {
+ boolean reclaimResource();
+ @utf8InCpp String getName();
+}
diff --git a/media/libmedia/api/resourcemanager/1/android/media/IResourceManagerService.aidl b/media/libmedia/api/resourcemanager/1/android/media/IResourceManagerService.aidl
new file mode 100644
index 0000000..53cf036
--- /dev/null
+++ b/media/libmedia/api/resourcemanager/1/android/media/IResourceManagerService.aidl
@@ -0,0 +1,27 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not
+// try to edit this file. It looks like you are doing that because you have
+// modified an AIDL interface in a backward-incompatible way, e.g., deleting a
+// function from an interface or a field from a parcelable and it broke the
+// build. That breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media;
+interface IResourceManagerService {
+ void config(in android.media.MediaResourcePolicyParcel[] policies);
+ void addResource(int pid, int uid, long clientId, android.media.IResourceManagerClient client, in android.media.MediaResourceParcel[] resources);
+ void removeResource(int pid, long clientId, in android.media.MediaResourceParcel[] resources);
+ void removeClient(int pid, long clientId);
+ boolean reclaimResource(int pid, in android.media.MediaResourceParcel[] resources);
+ const String kPolicySupportsMultipleSecureCodecs = "supports-multiple-secure-codecs";
+ const String kPolicySupportsSecureWithNonSecureCodec = "supports-secure-with-non-secure-codec";
+}
diff --git a/media/libmedia/api/resourcemanager/1/android/media/MediaResourceParcel.aidl b/media/libmedia/api/resourcemanager/1/android/media/MediaResourceParcel.aidl
new file mode 100644
index 0000000..47ea9bc
--- /dev/null
+++ b/media/libmedia/api/resourcemanager/1/android/media/MediaResourceParcel.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not
+// try to edit this file. It looks like you are doing that because you have
+// modified an AIDL interface in a backward-incompatible way, e.g., deleting a
+// function from an interface or a field from a parcelable and it broke the
+// build. That breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media;
+parcelable MediaResourceParcel {
+ android.media.MediaResourceType type;
+ android.media.MediaResourceSubType subType;
+ byte[] id;
+ long value = 0;
+}
diff --git a/media/libmedia/api/resourcemanager/1/android/media/MediaResourcePolicyParcel.aidl b/media/libmedia/api/resourcemanager/1/android/media/MediaResourcePolicyParcel.aidl
new file mode 100644
index 0000000..85d2588
--- /dev/null
+++ b/media/libmedia/api/resourcemanager/1/android/media/MediaResourcePolicyParcel.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not
+// try to edit this file. It looks like you are doing that because you have
+// modified an AIDL interface in a backward-incompatible way, e.g., deleting a
+// function from an interface or a field from a parcelable and it broke the
+// build. That breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media;
+parcelable MediaResourcePolicyParcel {
+ @utf8InCpp String type;
+ @utf8InCpp String value;
+}
diff --git a/media/libmedia/api/resourcemanager/1/android/media/MediaResourceSubType.aidl b/media/libmedia/api/resourcemanager/1/android/media/MediaResourceSubType.aidl
new file mode 100644
index 0000000..19b68af
--- /dev/null
+++ b/media/libmedia/api/resourcemanager/1/android/media/MediaResourceSubType.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not
+// try to edit this file. It looks like you are doing that because you have
+// modified an AIDL interface in a backward-incompatible way, e.g., deleting a
+// function from an interface or a field from a parcelable and it broke the
+// build. That breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media;
+@Backing(type="int")
+enum MediaResourceSubType {
+ kUnspecifiedSubType = 0,
+ kAudioCodec = 1,
+ kVideoCodec = 2,
+}
diff --git a/media/libmedia/api/resourcemanager/1/android/media/MediaResourceType.aidl b/media/libmedia/api/resourcemanager/1/android/media/MediaResourceType.aidl
new file mode 100644
index 0000000..6a123fc
--- /dev/null
+++ b/media/libmedia/api/resourcemanager/1/android/media/MediaResourceType.aidl
@@ -0,0 +1,28 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not
+// try to edit this file. It looks like you are doing that because you have
+// modified an AIDL interface in a backward-incompatible way, e.g., deleting a
+// function from an interface or a field from a parcelable and it broke the
+// build. That breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media;
+@Backing(type="int")
+enum MediaResourceType {
+ kUnspecified = 0,
+ kSecureCodec = 1,
+ kNonSecureCodec = 2,
+ kGraphicMemory = 3,
+ kCpuBoost = 4,
+ kBattery = 5,
+ kDrmSession = 6,
+}
diff --git a/media/libmedia/include/media/DataSourceDesc.h b/media/libmedia/include/media/DataSourceDesc.h
deleted file mode 100644
index 4336767..0000000
--- a/media/libmedia/include/media/DataSourceDesc.h
+++ /dev/null
@@ -1,73 +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.
- */
-
-#ifndef ANDROID_DATASOURCEDESC_H
-#define ANDROID_DATASOURCEDESC_H
-
-#include <media/stagefright/foundation/ABase.h>
-#include <utils/RefBase.h>
-#include <utils/KeyedVector.h>
-#include <utils/String8.h>
-
-namespace android {
-
-class DataSource;
-struct MediaHTTPService;
-
-// A binder interface for implementing a stagefright DataSource remotely.
-struct DataSourceDesc : public RefBase {
-public:
- // intentionally less than INT64_MAX
- // keep consistent with JAVA code
- static const int64_t kMaxTimeMs = 0x7ffffffffffffffll / 1000;
- static const int64_t kMaxTimeUs = kMaxTimeMs * 1000;
-
- enum {
- /* No data source has been set yet */
- TYPE_NONE = 0,
- /* data source is type of MediaDataSource */
- TYPE_CALLBACK = 1,
- /* data source is type of FileDescriptor */
- TYPE_FD = 2,
- /* data source is type of Url */
- TYPE_URL = 3,
- };
-
- DataSourceDesc();
-
- int mType;
-
- sp<MediaHTTPService> mHttpService;
- String8 mUrl;
- KeyedVector<String8, String8> mHeaders;
-
- int mFD;
- int64_t mFDOffset;
- int64_t mFDLength;
-
- sp<DataSource> mCallbackSource;
-
- int64_t mId;
- int64_t mStartPositionMs;
- int64_t mEndPositionMs;
-
-private:
- DISALLOW_EVIL_CONSTRUCTORS(DataSourceDesc);
-};
-
-}; // namespace android
-
-#endif // ANDROID_DATASOURCEDESC_H
diff --git a/media/libmedia/include/media/IOMX.h b/media/libmedia/include/media/IOMX.h
index 7e7c2d2..70c8a74 100644
--- a/media/libmedia/include/media/IOMX.h
+++ b/media/libmedia/include/media/IOMX.h
@@ -34,9 +34,17 @@
#include <media/openmax/OMX_VideoExt.h>
namespace android {
+namespace hardware {
+namespace media {
+namespace omx {
+namespace V1_0 {
+struct IGraphicBufferSource;
+} // namespace V1_0
+} // namespace omx
+} // namespace media
+} // namespace hardware
class IGraphicBufferProducer;
-class IGraphicBufferSource;
class IMemory;
class IOMXBufferSource;
class IOMXNode;
@@ -82,7 +90,7 @@
virtual status_t createInputSurface(
sp<IGraphicBufferProducer> *bufferProducer,
- sp<IGraphicBufferSource> *bufferSource) = 0;
+ sp<hardware::media::omx::V1_0::IGraphicBufferSource> *bufferSource) = 0;
};
class IOMXNode : public IInterface {
diff --git a/media/libmedia/include/media/IResourceManagerClient.h b/media/libmedia/include/media/IResourceManagerClient.h
deleted file mode 100644
index aa0cd88..0000000
--- a/media/libmedia/include/media/IResourceManagerClient.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_IRESOURCEMANAGERCLIENT_H
-#define ANDROID_IRESOURCEMANAGERCLIENT_H
-
-#include <utils/RefBase.h>
-#include <utils/String8.h>
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
-
-namespace android {
-
-class IResourceManagerClient: public IInterface
-{
-public:
- DECLARE_META_INTERFACE(ResourceManagerClient);
-
- virtual bool reclaimResource() = 0;
- virtual String8 getName() = 0;
-};
-
-// ----------------------------------------------------------------------------
-
-class BnResourceManagerClient: public BnInterface<IResourceManagerClient>
-{
-public:
- virtual status_t onTransact(uint32_t code,
- const Parcel &data,
- Parcel *reply,
- uint32_t flags = 0);
-};
-
-}; // namespace android
-
-#endif // ANDROID_IRESOURCEMANAGERCLIENT_H
diff --git a/media/libmedia/include/media/IResourceManagerService.h b/media/libmedia/include/media/IResourceManagerService.h
deleted file mode 100644
index 8992f8b..0000000
--- a/media/libmedia/include/media/IResourceManagerService.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_IRESOURCEMANAGERSERVICE_H
-#define ANDROID_IRESOURCEMANAGERSERVICE_H
-
-#include <utils/Errors.h> // for status_t
-#include <utils/KeyedVector.h>
-#include <utils/RefBase.h>
-#include <utils/String8.h>
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
-
-#include <media/IResourceManagerClient.h>
-#include <media/MediaResource.h>
-#include <media/MediaResourcePolicy.h>
-
-namespace android {
-
-class IResourceManagerService: public IInterface
-{
-public:
- DECLARE_META_INTERFACE(ResourceManagerService);
-
- virtual void config(const Vector<MediaResourcePolicy> &policies) = 0;
-
- virtual void addResource(
- int pid,
- int uid,
- int64_t clientId,
- const sp<IResourceManagerClient> client,
- const Vector<MediaResource> &resources) = 0;
-
- virtual void removeResource(int pid, int64_t clientId,
- const Vector<MediaResource> &resources) = 0;
-
- virtual void removeClient(int pid, int64_t clientId) = 0;
-
- virtual bool reclaimResource(
- int callingPid,
- const Vector<MediaResource> &resources) = 0;
-};
-
-// ----------------------------------------------------------------------------
-
-class BnResourceManagerService: public BnInterface<IResourceManagerService>
-{
-public:
- virtual status_t onTransact(uint32_t code,
- const Parcel &data,
- Parcel *reply,
- uint32_t flags = 0);
-};
-
-}; // namespace android
-
-#endif // ANDROID_IRESOURCEMANAGERSERVICE_H
diff --git a/media/libmedia/include/media/JetPlayer.h b/media/libmedia/include/media/JetPlayer.h
deleted file mode 100644
index bb569bc..0000000
--- a/media/libmedia/include/media/JetPlayer.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2008 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 JETPLAYER_H_
-#define JETPLAYER_H_
-
-#include <utils/threads.h>
-
-#include <libsonivox/jet.h>
-#include <libsonivox/eas_types.h>
-#include <media/AudioTrack.h>
-#include <media/MidiIoWrapper.h>
-
-
-namespace android {
-
-typedef void (*jetevent_callback)(int eventType, int val1, int val2, void *cookie);
-
-class JetPlayer {
-
-public:
-
- // to keep in sync with the JetPlayer class constants
- // defined in frameworks/base/media/java/android/media/JetPlayer.java
- static const int JET_EVENT = 1;
- static const int JET_USERID_UPDATE = 2;
- static const int JET_NUMQUEUEDSEGMENT_UPDATE = 3;
- static const int JET_PAUSE_UPDATE = 4;
-
- JetPlayer(void *javaJetPlayer,
- int maxTracks = 32,
- int trackBufferSize = 1200);
- ~JetPlayer();
- int init();
- int release();
-
- int loadFromFile(const char* url);
- int loadFromFD(const int fd, const long long offset, const long long length);
- int closeFile();
- int play();
- int pause();
- int queueSegment(int segmentNum, int libNum, int repeatCount, int transpose,
- EAS_U32 muteFlags, EAS_U8 userID);
- int setMuteFlags(EAS_U32 muteFlags, bool sync);
- int setMuteFlag(int trackNum, bool muteFlag, bool sync);
- int triggerClip(int clipId);
- int clearQueue();
-
- void setEventCallback(jetevent_callback callback);
-
- int getMaxTracks() { return mMaxTracks; };
-
-
-private:
- int render();
- void fireUpdateOnStatusChange();
- void fireEventsFromJetQueue();
-
- JetPlayer() {} // no default constructor
- void dump();
- void dumpJetStatus(S_JET_STATUS* pJetStatus);
-
- jetevent_callback mEventCallback;
-
- void* mJavaJetPlayerRef;
- Mutex mMutex; // mutex to sync the render and playback thread with the JET calls
- pid_t mTid;
- Condition mCondition;
- volatile bool mRender;
- bool mPaused;
-
- EAS_STATE mState;
- int* mMemFailedVar;
-
- int mMaxTracks; // max number of MIDI tracks, usually 32
- EAS_DATA_HANDLE mEasData;
- MidiIoWrapper* mIoWrapper;
- EAS_PCM* mAudioBuffer;// EAS renders the MIDI data into this buffer,
- sp<AudioTrack> mAudioTrack; // and we play it in this audio track
- int mTrackBufferSize;
- S_JET_STATUS mJetStatus;
- S_JET_STATUS mPreviousJetStatus;
-
- class JetPlayerThread : public Thread {
- public:
- JetPlayerThread(JetPlayer *player) : mPlayer(player) {
- }
-
- protected:
- virtual ~JetPlayerThread() {}
-
- private:
- JetPlayer *mPlayer;
-
- bool threadLoop() {
- int result;
- result = mPlayer->render();
- return false;
- }
-
- JetPlayerThread(const JetPlayerThread &);
- JetPlayerThread &operator=(const JetPlayerThread &);
- };
-
- sp<JetPlayerThread> mThread;
-
-}; // end class JetPlayer
-
-} // end namespace android
-
-
-
-#endif /*JETPLAYER_H_*/
diff --git a/media/libmedia/include/media/LinearMap.h b/media/libmedia/include/media/LinearMap.h
deleted file mode 100644
index 2220a0c..0000000
--- a/media/libmedia/include/media/LinearMap.h
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * Copyright 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_LINEAR_MAP_H
-#define ANDROID_LINEAR_MAP_H
-
-#include <stdint.h>
-
-namespace android {
-
-/*
-A general purpose lookup utility that defines a mapping between X and Y as a
-continuous set of line segments with shared (x, y) end-points.
-The (x, y) points must be added in order, monotonically increasing in both x and y;
-a log warning is emitted if this does not happen (See general usage notes below).
-
-A limited history of (x, y) points is kept for space reasons (See general usage notes).
-
-In AudioFlinger, we use the LinearMap to associate track frames to
-sink frames. When we want to obtain a client track timestamp, we first
-get a timestamp from the sink. The sink timestamp's position (mPosition)
-corresponds to the sink frames written. We use LinearMap to figure out which track frame
-the sink frame corresponds to. This allows us to substitute a track frame for the
-the sink frame (keeping the mTime identical) and return that timestamp back to the client.
-
-The method findX() can be used to retrieve an x value from a given y value and is
-used for timestamps, similarly for findY() which is provided for completeness.
-
-We update the (track frame, sink frame) points in the LinearMap each time we write data
-to the sink by the AudioFlinger PlaybackThread (MixerThread).
-
-
-AudioFlinger Timestamp Notes:
-
-1) Example: Obtaining a track timestamp during playback. In this case, the LinearMap
-looks something like this:
-
-Track Frame Sink Frame
-(track start)
-0 50000 (track starts here, the sink may already be running)
-1000 51000
-2000 52000
-
-When we request a track timestamp, we call the sink getTimestamp() and get for example
-mPosition = 51020. Using the LinearMap, we find we have played to track frame 1020.
-We substitute the sink mPosition of 51020 with the track position 1020,
-and return that timestamp to the app.
-
-2) Example: Obtaining a track timestamp duing pause. In this case, the LinearMap
-looks something like this:
-
-Track Frame Sink Frame
-... (some time has gone by)
-15000 30000
-16000 31000
-17000 32000
-(pause here)
-(suppose we call sink getTimestamp() here and get sink mPosition = 31100; that means
- we have played to track frame 16100. The track timestamp mPosition will
- continue to advance until the sink timestamp returns a value of mPosition
- greater than 32000, corresponding to track frame 17000 when the pause was called).
-17000 33000
-17000 34000
-...
-
-3) If the track underruns, it appears as if a pause was called on that track.
-
-4) If there is an underrun in the HAL layer, then it may be possible that
-the sink getTimestamp() will return a value greater than the number of frames written
-(it should always be less). This should be rare, if not impossible by some
-HAL implementations of the sink getTimestamp. In that case, timing is lost
-and we will return the most recent track frame written.
-
-5) When called with no points in the map, findX() returns the start value (default 0).
-This is consistent with starting after a stop() or flush().
-
-6) Resuming after Track standby will be similar to coming out of pause, as the HAL ensures
-framesWritten() and getTimestamp() are contiguous for non-offloaded/direct tracks.
-
-7) LinearMap works for different speeds and sample rates as it uses
-linear interpolation. Since AudioFlinger only updates speed and sample rate
-exactly at the sample points pushed into the LinearMap, the returned values
-from findX() and findY() are accurate regardless of how many speed or sample
-rate changes are made, so long as the coordinate looked up is within the
-sample history.
-
-General usage notes:
-
-1) In order for the LinearMap to work reliably, you cannot look backwards more
-than the size of its circular buffer history, set upon creation (typically 16).
-If you look back further, the position is extrapolated either from a passed in
-extrapolation parameter or from the oldest line segment.
-
-2) Points must monotonically increase in x and y. The increment between adjacent
-points cannot be greater than signed 32 bits. Wrap in the x, y coordinates are supported,
-since we use differences in our computation.
-
-3) If the frame data is discontinuous (due to stop or flush) call reset() to clear
-the sample counter.
-
-4) If (x, y) are not strictly monotonic increasing, i.e. (x2 > x1) and (y2 > y1),
-then one or both of the inverses y = f(x) or x = g(y) may have multiple solutions.
-In that case, the most recent solution is returned by findX() or findY(). We
-do not warn if (x2 == x1) or (y2 == y1), but we do logcat warn if (x2 < x1) or
-(y2 < y1).
-
-5) Due to rounding it is possible x != findX(findY(x)) or y != findY(findX(y))
-even when the inverse exists. Nevertheless, the values should be close.
-
-*/
-
-template <typename T>
-class LinearMap {
-public:
- // This enumeration describes the reliability of the findX() or findY() estimation
- // in descending order.
- enum FindMethod {
- FIND_METHOD_INTERPOLATION, // High reliability (errors due to rounding)
- FIND_METHOD_FORWARD_EXTRAPOLATION, // Reliability based on no future speed changes
- FIND_METHOD_BACKWARD_EXTRAPOLATION, // Reliability based on prior estimated speed
- FIND_METHOD_START_VALUE, // No samples in history, using start value
- };
-
- explicit LinearMap(size_t size)
- : mSize(size),
- mPos(0), // a circular buffer, so could start anywhere. the first sample is at 1.
- mSamples(0),
- // mStepValid(false), // only valid if mSamples > 1
- // mExtrapolateTail(false), // only valid if mSamples > 0
- mX(new T[size]),
- mY(new T[size]) { }
-
- ~LinearMap() {
- delete[] mX;
- delete[] mY;
- }
-
- // Add a new sample point to the linear map.
- //
- // The difference between the new sample and the previous sample
- // in the x or y coordinate must be less than INT32_MAX for purposes
- // of the linear interpolation or extrapolation.
- //
- // The value should be monotonic increasing (e.g. diff >= 0);
- // logcat warnings are issued if they are not.
- __attribute__((no_sanitize("integer")))
- void push(T x, T y) {
- // Assumption: we assume x, y are monotonic increasing values,
- // which (can) wrap in precision no less than 32 bits and have
- // "step" or differences between adjacent points less than 32 bits.
-
- if (mSamples > 0) {
- const bool lastStepValid = mStepValid;
- int32_t xdiff;
- int32_t ydiff;
- // check difference assumption here
- mStepValid = checkedDiff(&xdiff, x, mX[mPos], "x")
- & /* bitwise AND to always warn for ydiff, though logical AND is also OK */
- checkedDiff(&ydiff, y, mY[mPos], "y");
-
- // Optimization: do not add a new sample if the line segment would
- // simply extend the previous line segment. This extends the useful
- // history by removing redundant points.
- if (mSamples > 1 && mStepValid && lastStepValid) {
- const size_t prev = previousPosition();
- const int32_t xdiff2 = x - mX[prev];
- const int32_t ydiff2 = y - mY[prev];
-
- // if both current step and previous step are valid (non-negative and
- // less than INT32_MAX for precision greater than 4 bytes)
- // then the sum of the two steps is valid when the
- // int32_t difference is non-negative.
- if (xdiff2 >= 0 && ydiff2 >= 0
- && (int64_t)xdiff2 * ydiff == (int64_t)ydiff2 * xdiff) {
- // ALOGD("reusing sample! (%u, %u) sample depth %zd", x, y, mSamples);
- mX[mPos] = x;
- mY[mPos] = y;
- return;
- }
- }
- }
- if (++mPos >= mSize) {
- mPos = 0;
- }
- if (mSamples < mSize) {
- mExtrapolateTail = false;
- ++mSamples;
- } else {
- // we enable extrapolation beyond the oldest sample
- // if the sample buffers are completely full and we
- // no longer know the full history.
- mExtrapolateTail = true;
- }
- mX[mPos] = x;
- mY[mPos] = y;
- }
-
- // clear all samples from the circular array
- void reset() {
- // no need to reset mPos, we use a circular buffer.
- // computed values such as mStepValid are set after a subsequent push().
- mSamples = 0;
- }
-
- // returns true if LinearMap contains at least one sample.
- bool hasData() const {
- return mSamples != 0;
- }
-
- // find the corresponding X point from a Y point.
- // See findU for details.
- __attribute__((no_sanitize("integer")))
- T findX(T y, FindMethod *method = NULL, double extrapolation = 0.0, T startValue = 0) const {
- return findU(y, mX, mY, method, extrapolation, startValue);
- }
-
- // find the corresponding Y point from a X point.
- // See findU for details.
- __attribute__((no_sanitize("integer")))
- T findY(T x, FindMethod *method = NULL, double extrapolation = 0.0, T startValue = 0) const {
- return findU(x, mY, mX, method, extrapolation, startValue);
- }
-
-protected:
-
- // returns false if the diff is out of int32_t bounds or negative.
- __attribute__((no_sanitize("integer")))
- static inline bool checkedDiff(int32_t *diff, T x2, T x1, const char *coord) {
- if (sizeof(T) >= 8) {
- const int64_t diff64 = x2 - x1;
- *diff = (int32_t)diff64; // intentionally lose precision
- if (diff64 > INT32_MAX) {
- ALOGW("LinearMap: %s overflow diff(%lld) from %llu - %llu exceeds INT32_MAX",
- coord, (long long)diff64,
- (unsigned long long)x2, (unsigned long long)x1);
- return false;
- } else if (diff64 < 0) {
- ALOGW("LinearMap: %s negative diff(%lld) from %llu - %llu",
- coord, (long long)diff64,
- (unsigned long long)x2, (unsigned long long)x1);
- return false;
- }
- return true;
- }
- // for 32 bit integers we cannot detect overflow (it
- // shows up as a negative difference).
- *diff = x2 - x1;
- if (*diff < 0) {
- ALOGW("LinearMap: %s negative diff(%d) from %u - %u",
- coord, *diff, (unsigned)x2, (unsigned)x1);
- return false;
- }
- return true;
- }
-
- // Returns the previous position in the mSamples array
- // going backwards back steps.
- //
- // Parameters:
- // back: number of backward steps, cannot be less than zero or greater than mSamples.
- //
- __attribute__((no_sanitize("integer")))
- size_t previousPosition(ssize_t back = 1) const {
- LOG_ALWAYS_FATAL_IF(back < 0 || (size_t)back > mSamples, "Invalid back(%zd)", back);
- ssize_t position = mPos - back;
- if (position < 0) position += mSize;
- return (size_t)position;
- }
-
- // A generic implementation of finding the "other coordinate" with coordinates
- // (u, v) = (x, y) or (u, v) = (y, x).
- //
- // Parameters:
- // uArray: the u axis samples.
- // vArray: the v axis samples.
- // method: [out] how the returned value was computed.
- // extrapolation: the slope used when extrapolating from the
- // first sample value or the last sample value in the history.
- // If mExtrapolateTail is set, the slope of the last line segment
- // is used if the extrapolation parameter is zero to continue the tail of history.
- // At this time, we do not use a different value for forward extrapolation from the
- // head of history from backward extrapolation from the tail of history.
- // TODO: back extrapolation value could be stored along with mX, mY in history.
- // startValue: used only when there are no samples in history. One can detect
- // whether there are samples in history by the method hasData().
- //
- __attribute__((no_sanitize("integer")))
- T findU(T v, T *uArray, T *vArray, FindMethod *method,
- double extrapolation, T startValue) const {
- if (mSamples == 0) {
- if (method != NULL) {
- *method = FIND_METHOD_START_VALUE;
- }
- return startValue; // nothing yet
- }
- ssize_t previous = 0;
- int32_t diff = 0;
- for (ssize_t i = 0; i < (ssize_t)mSamples; ++i) {
- size_t current = previousPosition(i);
-
- // Assumption: even though the type "T" may have precision greater
- // than 32 bits, the difference between adjacent points is limited to 32 bits.
- diff = v - vArray[current];
- if (diff >= 0 ||
- (i == (ssize_t)mSamples - 1 && mExtrapolateTail && extrapolation == 0.0)) {
- // ALOGD("depth = %zd out of %zd", i, limit);
- if (i == 0) {
- if (method != NULL) {
- *method = FIND_METHOD_FORWARD_EXTRAPOLATION;
- }
- return uArray[current] + diff * extrapolation;
- }
- // interpolate / extrapolate: For this computation, we
- // must use differentials here otherwise we have inconsistent
- // values on modulo wrap. previous is always valid here since
- // i > 0. we also perform rounding with the assumption
- // that uStep, vStep, and diff are non-negative.
- int32_t uStep = uArray[previous] - uArray[current]; // non-negative
- int32_t vStep = vArray[previous] - vArray[current]; // positive
- T u = uStep <= 0 || vStep <= 0 ? // we do not permit negative ustep or vstep
- uArray[current]
- : ((int64_t)diff * uStep + (vStep >> 1)) / vStep + uArray[current];
- // ALOGD("u:%u diff:%d uStep:%d vStep:%d u_current:%d",
- // u, diff, uStep, vStep, uArray[current]);
- if (method != NULL) {
- *method = (diff >= 0) ?
- FIND_METHOD_INTERPOLATION : FIND_METHOD_BACKWARD_EXTRAPOLATION;
- }
- return u;
- }
- previous = current;
- }
- // previous is always valid here.
- if (method != NULL) {
- *method = FIND_METHOD_BACKWARD_EXTRAPOLATION;
- }
- return uArray[previous] + diff * extrapolation;
- }
-
-private:
- const size_t mSize; // Size of mX and mY arrays (history).
- size_t mPos; // Index in mX and mY of last pushed data;
- // (incremented after push) [0, mSize - 1].
- size_t mSamples; // Number of valid samples in the array [0, mSize].
- bool mStepValid; // Last sample step was valid (non-negative)
- bool mExtrapolateTail; // extrapolate tail using oldest line segment
- T * const mX; // History of X values as a circular array.
- T * const mY; // History of Y values as a circular array.
-};
-
-} // namespace android
-
-#endif // ANDROID_LINEAR_MAP_H
diff --git a/media/libmedia/include/media/MediaResource.h b/media/libmedia/include/media/MediaResource.h
index 10a07bb..caf03b1 100644
--- a/media/libmedia/include/media/MediaResource.h
+++ b/media/libmedia/include/media/MediaResource.h
@@ -18,66 +18,55 @@
#ifndef ANDROID_MEDIA_RESOURCE_H
#define ANDROID_MEDIA_RESOURCE_H
-#include <binder/Parcel.h>
-#include <utils/String8.h>
+#include <android/media/MediaResourceParcel.h>
namespace android {
-class MediaResource {
+using android::media::MediaResourceParcel;
+using android::media::MediaResourceSubType;
+using android::media::MediaResourceType;
+
+class MediaResource : public MediaResourceParcel {
public:
- enum Type {
- kUnspecified = 0,
- kSecureCodec,
- kNonSecureCodec,
- kGraphicMemory,
- kCpuBoost,
- kBattery,
- };
+ using Type = MediaResourceType;
+ using SubType = MediaResourceSubType;
- enum SubType {
- kUnspecifiedSubType = 0,
- kAudioCodec,
- kVideoCodec,
- };
+ MediaResource() = delete;
+ MediaResource(Type type, int64_t value);
+ MediaResource(Type type, SubType subType, int64_t value);
+ MediaResource(Type type, const std::vector<uint8_t> &id, int64_t value);
- MediaResource();
- MediaResource(Type type, uint64_t value);
- MediaResource(Type type, SubType subType, uint64_t value);
-
- void readFromParcel(const Parcel &parcel);
- void writeToParcel(Parcel *parcel) const;
-
- String8 toString() const;
-
- bool operator==(const MediaResource &other) const;
- bool operator!=(const MediaResource &other) const;
-
- Type mType;
- SubType mSubType;
- uint64_t mValue;
+ static MediaResource CodecResource(bool secure, bool video);
+ static MediaResource GraphicMemoryResource(int64_t value);
+ static MediaResource CpuBoostResource();
+ static MediaResource VideoBatteryResource();
+ static MediaResource DrmSessionResource(const std::vector<uint8_t> &id, int64_t value);
};
inline static const char *asString(MediaResource::Type i, const char *def = "??") {
switch (i) {
- case MediaResource::kUnspecified: return "unspecified";
- case MediaResource::kSecureCodec: return "secure-codec";
- case MediaResource::kNonSecureCodec: return "non-secure-codec";
- case MediaResource::kGraphicMemory: return "graphic-memory";
- case MediaResource::kCpuBoost: return "cpu-boost";
- case MediaResource::kBattery: return "battery";
- default: return def;
+ case MediaResource::Type::kUnspecified: return "unspecified";
+ case MediaResource::Type::kSecureCodec: return "secure-codec";
+ case MediaResource::Type::kNonSecureCodec: return "non-secure-codec";
+ case MediaResource::Type::kGraphicMemory: return "graphic-memory";
+ case MediaResource::Type::kCpuBoost: return "cpu-boost";
+ case MediaResource::Type::kBattery: return "battery";
+ case MediaResource::Type::kDrmSession: return "drm-session";
+ default: return def;
}
}
inline static const char *asString(MediaResource::SubType i, const char *def = "??") {
switch (i) {
- case MediaResource::kUnspecifiedSubType: return "unspecified";
- case MediaResource::kAudioCodec: return "audio-codec";
- case MediaResource::kVideoCodec: return "video-codec";
+ case MediaResource::SubType::kUnspecifiedSubType: return "unspecified";
+ case MediaResource::SubType::kAudioCodec: return "audio-codec";
+ case MediaResource::SubType::kVideoCodec: return "video-codec";
default: return def;
}
}
+String8 toString(const MediaResourceParcel& resource);
+
}; // namespace android
#endif // ANDROID_MEDIA_RESOURCE_H
diff --git a/media/libmedia/include/media/MediaResourcePolicy.h b/media/libmedia/include/media/MediaResourcePolicy.h
index 9bc2eec..7ae1a73 100644
--- a/media/libmedia/include/media/MediaResourcePolicy.h
+++ b/media/libmedia/include/media/MediaResourcePolicy.h
@@ -18,28 +18,23 @@
#ifndef ANDROID_MEDIA_RESOURCE_POLICY_H
#define ANDROID_MEDIA_RESOURCE_POLICY_H
-#include <binder/Parcel.h>
-#include <utils/String8.h>
+#include <android/media/MediaResourcePolicyParcel.h>
namespace android {
-extern const char kPolicySupportsMultipleSecureCodecs[];
-extern const char kPolicySupportsSecureWithNonSecureCodec[];
+using media::MediaResourcePolicyParcel;
-class MediaResourcePolicy {
+class MediaResourcePolicy : public MediaResourcePolicyParcel {
public:
- MediaResourcePolicy();
- MediaResourcePolicy(String8 type, String8 value);
+ MediaResourcePolicy() = delete;
+ MediaResourcePolicy(const std::string& type, const std::string& value);
- void readFromParcel(const Parcel &parcel);
- void writeToParcel(Parcel *parcel) const;
-
- String8 toString() const;
-
- String8 mType;
- String8 mValue;
+ static const ::std::string& kPolicySupportsMultipleSecureCodecs();
+ static const ::std::string& kPolicySupportsSecureWithNonSecureCodec();
};
+String8 toString(const MediaResourcePolicyParcel &policy);
+
}; // namespace android
#endif // ANDROID_MEDIA_RESOURCE_POLICY_H
diff --git a/media/libmedia/include/media/MidiDeviceInfo.h b/media/libmedia/include/media/MidiDeviceInfo.h
deleted file mode 100644
index 5b4a241..0000000
--- a/media/libmedia/include/media/MidiDeviceInfo.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 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 ANDROID_MEDIA_MIDI_DEVICE_INFO_H
-#define ANDROID_MEDIA_MIDI_DEVICE_INFO_H
-
-#include <binder/Parcelable.h>
-#include <binder/PersistableBundle.h>
-#include <utils/String16.h>
-#include <utils/Vector.h>
-
-namespace android {
-namespace media {
-namespace midi {
-
-class MidiDeviceInfo : public Parcelable {
-public:
- MidiDeviceInfo() = default;
- virtual ~MidiDeviceInfo() = default;
- MidiDeviceInfo(const MidiDeviceInfo& midiDeviceInfo) = default;
-
- status_t writeToParcel(Parcel* parcel) const override;
- status_t readFromParcel(const Parcel* parcel) override;
-
- int getType() const { return mType; }
- int getUid() const { return mId; }
- bool isPrivate() const { return mIsPrivate; }
- const Vector<String16>& getInputPortNames() const { return mInputPortNames; }
- const Vector<String16>& getOutputPortNames() const { return mOutputPortNames; }
- String16 getProperty(const char* propertyName);
-
- // The constants need to be kept in sync with MidiDeviceInfo.java
- enum {
- TYPE_USB = 1,
- TYPE_VIRTUAL = 2,
- TYPE_BLUETOOTH = 3,
- };
- static const char* const PROPERTY_NAME;
- static const char* const PROPERTY_MANUFACTURER;
- static const char* const PROPERTY_PRODUCT;
- static const char* const PROPERTY_VERSION;
- static const char* const PROPERTY_SERIAL_NUMBER;
- static const char* const PROPERTY_ALSA_CARD;
- static const char* const PROPERTY_ALSA_DEVICE;
-
- friend bool operator==(const MidiDeviceInfo& lhs, const MidiDeviceInfo& rhs);
- friend bool operator!=(const MidiDeviceInfo& lhs, const MidiDeviceInfo& rhs) {
- return !(lhs == rhs);
- }
-
-private:
- status_t readStringVector(
- const Parcel* parcel, Vector<String16> *vectorPtr, size_t defaultLength);
- status_t writeStringVector(Parcel* parcel, const Vector<String16>& vector) const;
-
- int32_t mType;
- int32_t mId;
- Vector<String16> mInputPortNames;
- Vector<String16> mOutputPortNames;
- os::PersistableBundle mProperties;
- bool mIsPrivate;
-};
-
-} // namespace midi
-} // namespace media
-} // namespace android
-
-#endif // ANDROID_MEDIA_MIDI_DEVICE_INFO_H
diff --git a/media/libmedia/include/media/Visualizer.h b/media/libmedia/include/media/Visualizer.h
deleted file mode 100644
index 8078e36..0000000
--- a/media/libmedia/include/media/Visualizer.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_MEDIA_VISUALIZER_H
-#define ANDROID_MEDIA_VISUALIZER_H
-
-#include <media/AudioEffect.h>
-#include <system/audio_effects/effect_visualizer.h>
-#include <utils/Thread.h>
-
-/**
- * The Visualizer class enables application to retrieve part of the currently playing audio for
- * visualization purpose. It is not an audio recording interface and only returns partial and low
- * quality audio content. However, to protect privacy of certain audio data (e.g voice mail) the use
- * of the visualizer requires the permission android.permission.RECORD_AUDIO.
- * The audio session ID passed to the constructor indicates which audio content should be
- * visualized:
- * - If the session is 0, the audio output mix is visualized
- * - If the session is not 0, the audio from a particular MediaPlayer or AudioTrack
- * using this audio session is visualized
- * Two types of representation of audio content can be captured:
- * - Waveform data: consecutive 8-bit (unsigned) mono samples by using the getWaveForm() method
- * - Frequency data: 8-bit magnitude FFT by using the getFft() method
- *
- * The length of the capture can be retrieved or specified by calling respectively
- * getCaptureSize() and setCaptureSize() methods. Note that the size of the FFT
- * is half of the specified capture size but both sides of the spectrum are returned yielding in a
- * number of bytes equal to the capture size. The capture size must be a power of 2 in the range
- * returned by getMinCaptureSize() and getMaxCaptureSize().
- * In addition to the polling capture mode, a callback mode is also available by installing a
- * callback function by use of the setCaptureCallBack() method. The rate at which the callback
- * is called as well as the type of data returned is specified.
- * Before capturing data, the Visualizer must be enabled by calling the setEnabled() method.
- * When data capture is not needed any more, the Visualizer should be disabled.
- */
-
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-class Visualizer: public AudioEffect {
-public:
-
- enum callback_flags {
- CAPTURE_WAVEFORM = 0x00000001, // capture callback returns a PCM wave form
- CAPTURE_FFT = 0x00000002, // apture callback returns a frequency representation
- CAPTURE_CALL_JAVA = 0x00000004 // the callback thread can call java
- };
-
-
- /* Constructor.
- * See AudioEffect constructor for details on parameters.
- */
- Visualizer(const String16& opPackageName,
- int32_t priority = 0,
- effect_callback_t cbf = NULL,
- void* user = NULL,
- audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX);
-
- ~Visualizer();
-
- virtual status_t setEnabled(bool enabled);
-
- // maximum capture size in samples
- static uint32_t getMaxCaptureSize() { return VISUALIZER_CAPTURE_SIZE_MAX; }
- // minimum capture size in samples
- static uint32_t getMinCaptureSize() { return VISUALIZER_CAPTURE_SIZE_MIN; }
- // maximum capture rate in millihertz
- static uint32_t getMaxCaptureRate() { return CAPTURE_RATE_MAX; }
-
- // callback used to return periodic PCM or FFT captures to the application. Either one or both
- // types of data are returned (PCM and FFT) according to flags indicated when installing the
- // callback. When a type of data is not present, the corresponding size (waveformSize or
- // fftSize) is 0.
- typedef void (*capture_cbk_t)(void* user,
- uint32_t waveformSize,
- uint8_t *waveform,
- uint32_t fftSize,
- uint8_t *fft,
- uint32_t samplingrate);
-
- // install a callback to receive periodic captures. The capture rate is specified in milliHertz
- // and the capture format is according to flags (see callback_flags).
- status_t setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, uint32_t rate);
-
- // set the capture size capture size must be a power of two in the range
- // [VISUALIZER_CAPTURE_SIZE_MAX. VISUALIZER_CAPTURE_SIZE_MIN]
- // must be called when the visualizer is not enabled
- status_t setCaptureSize(uint32_t size);
- uint32_t getCaptureSize() { return mCaptureSize; }
-
- // returns the capture rate indicated when installing the callback
- uint32_t getCaptureRate() { return mCaptureRate; }
-
- // returns the sampling rate of the audio being captured
- uint32_t getSamplingRate() { return mSampleRate; }
-
- // set the way volume affects the captured data
- // mode must one of VISUALIZER_SCALING_MODE_NORMALIZED,
- // VISUALIZER_SCALING_MODE_AS_PLAYED
- status_t setScalingMode(uint32_t mode);
- uint32_t getScalingMode() { return mScalingMode; }
-
- // set which measurements are done on the audio buffers processed by the effect.
- // valid measurements (mask): MEASUREMENT_MODE_PEAK_RMS
- status_t setMeasurementMode(uint32_t mode);
- uint32_t getMeasurementMode() { return mMeasurementMode; }
-
- // return a set of int32_t measurements
- status_t getIntMeasurements(uint32_t type, uint32_t number, int32_t *measurements);
-
- // return a capture in PCM 8 bit unsigned format. The size of the capture is equal to
- // getCaptureSize()
- status_t getWaveForm(uint8_t *waveform);
-
- // return a capture in FFT 8 bit signed format. The size of the capture is equal to
- // getCaptureSize() but the length of the FFT is half of the size (both parts of the spectrum
- // are returned
- status_t getFft(uint8_t *fft);
- void release();
-
-protected:
- // from IEffectClient
- virtual void controlStatusChanged(bool controlGranted);
-
-private:
-
- static const uint32_t CAPTURE_RATE_MAX = 20000;
- static const uint32_t CAPTURE_RATE_DEF = 10000;
- static const uint32_t CAPTURE_SIZE_DEF = VISUALIZER_CAPTURE_SIZE_MAX;
-
- /* internal class to handle the callback */
- class CaptureThread : public Thread
- {
- public:
- CaptureThread(Visualizer* visualizer, uint32_t captureRate, bool bCanCallJava = false);
-
- private:
- friend class Visualizer;
- virtual bool threadLoop();
- wp<Visualizer> mReceiver;
- Mutex mLock;
- uint32_t mSleepTimeUs;
- };
-
- status_t doFft(uint8_t *fft, uint8_t *waveform);
- void periodicCapture();
- uint32_t initCaptureSize();
-
- Mutex mCaptureLock;
- uint32_t mCaptureRate;
- uint32_t mCaptureSize;
- uint32_t mSampleRate;
- uint32_t mScalingMode;
- uint32_t mMeasurementMode;
- capture_cbk_t mCaptureCallBack;
- void *mCaptureCbkUser;
- sp<CaptureThread> mCaptureThread;
- uint32_t mCaptureFlags;
-};
-
-
-}; // namespace android
-
-#endif // ANDROID_MEDIA_VISUALIZER_H
diff --git a/media/libmedia/include/media/omx/1.0/Conversion.h b/media/libmedia/include/media/omx/1.0/Conversion.h
index 6dc46b7..811936b 100644
--- a/media/libmedia/include/media/omx/1.0/Conversion.h
+++ b/media/libmedia/include/media/omx/1.0/Conversion.h
@@ -45,7 +45,6 @@
#include <android/hardware/media/omx/1.0/IOmxObserver.h>
#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
-#include <android/IGraphicBufferSource.h>
#include <android/IOMXBufferSource.h>
namespace android {
diff --git a/media/libmedia/include/media/omx/1.0/WOmx.h b/media/libmedia/include/media/omx/1.0/WOmx.h
index 0680eec..46ada9b 100644
--- a/media/libmedia/include/media/omx/1.0/WOmx.h
+++ b/media/libmedia/include/media/omx/1.0/WOmx.h
@@ -67,7 +67,7 @@
sp<IOMXNode>* omxNode) override;
status_t createInputSurface(
sp<::android::IGraphicBufferProducer>* bufferProducer,
- sp<::android::IGraphicBufferSource>* bufferSource) override;
+ sp<::android::hardware::media::omx::V1_0::IGraphicBufferSource>* bufferSource) override;
};
} // namespace utils
diff --git a/media/libmedia/omx/1.0/WOmx.cpp b/media/libmedia/omx/1.0/WOmx.cpp
index ce624fa..4bacdda 100644
--- a/media/libmedia/omx/1.0/WOmx.cpp
+++ b/media/libmedia/omx/1.0/WOmx.cpp
@@ -18,7 +18,6 @@
#include <media/omx/1.0/WOmx.h>
#include <media/omx/1.0/WOmxNode.h>
#include <media/omx/1.0/WOmxObserver.h>
-#include <media/omx/1.0/WGraphicBufferSource.h>
#include <media/omx/1.0/Conversion.h>
namespace android {
@@ -70,7 +69,7 @@
status_t LWOmx::createInputSurface(
sp<::android::IGraphicBufferProducer>* bufferProducer,
- sp<::android::IGraphicBufferSource>* bufferSource) {
+ sp<::android::hardware::media::omx::V1_0::IGraphicBufferSource>* bufferSource) {
status_t fnStatus;
status_t transStatus = toStatusT(mBase->createInputSurface(
[&fnStatus, bufferProducer, bufferSource] (
@@ -79,7 +78,7 @@
sp<IGraphicBufferSource> const& tSource) {
fnStatus = toStatusT(status);
*bufferProducer = new H2BGraphicBufferProducer(tProducer);
- *bufferSource = new LWGraphicBufferSource(tSource);
+ *bufferSource = tSource;
}));
return transStatus == NO_ERROR ? fnStatus : transStatus;
}
diff --git a/media/libmediahelper/Android.bp b/media/libmediahelper/Android.bp
new file mode 100644
index 0000000..72edeec
--- /dev/null
+++ b/media/libmediahelper/Android.bp
@@ -0,0 +1,29 @@
+cc_library_headers {
+ name: "libmedia_helper_headers",
+ vendor_available: true,
+ export_include_dirs: ["include"],
+}
+
+cc_library {
+ name: "libmedia_helper",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ double_loadable: true,
+ srcs: ["AudioParameter.cpp", "TypeConverter.cpp"],
+ cflags: [
+ "-Werror",
+ "-Wextra",
+ "-Wall",
+ ],
+ shared_libs: ["libutils", "liblog"],
+ header_libs: [
+ "libmedia_helper_headers",
+ "libaudio_system_headers",
+ ],
+ export_header_lib_headers: [
+ "libmedia_helper_headers",
+ ],
+ clang: true,
+}
diff --git a/media/libmedia/AudioParameter.cpp b/media/libmediahelper/AudioParameter.cpp
similarity index 100%
rename from media/libmedia/AudioParameter.cpp
rename to media/libmediahelper/AudioParameter.cpp
diff --git a/media/libmedia/TypeConverter.cpp b/media/libmediahelper/TypeConverter.cpp
similarity index 100%
rename from media/libmedia/TypeConverter.cpp
rename to media/libmediahelper/TypeConverter.cpp
diff --git a/media/libaudioclient/include/media/AudioParameter.h b/media/libmediahelper/include/media/AudioParameter.h
similarity index 100%
rename from media/libaudioclient/include/media/AudioParameter.h
rename to media/libmediahelper/include/media/AudioParameter.h
diff --git a/media/libmedia/include/media/TypeConverter.h b/media/libmediahelper/include/media/TypeConverter.h
similarity index 100%
rename from media/libmedia/include/media/TypeConverter.h
rename to media/libmediahelper/include/media/TypeConverter.h
diff --git a/media/libmedia/include/media/convert.h b/media/libmediahelper/include/media/convert.h
similarity index 100%
rename from media/libmedia/include/media/convert.h
rename to media/libmediahelper/include/media/convert.h
diff --git a/media/libmediametrics/Android.bp b/media/libmediametrics/Android.bp
index 9d348ec..f599190 100644
--- a/media/libmediametrics/Android.bp
+++ b/media/libmediametrics/Android.bp
@@ -44,6 +44,7 @@
},
visibility: [
+ "//cts/tests/tests/nativemedia/mediametrics",
"//frameworks/av:__subpackages__",
"//frameworks/base/core/jni",
"//frameworks/base/media/jni",
diff --git a/media/libmediametrics/IMediaAnalyticsService.cpp b/media/libmediametrics/IMediaAnalyticsService.cpp
index 9114927..1ab6653 100644
--- a/media/libmediametrics/IMediaAnalyticsService.cpp
+++ b/media/libmediametrics/IMediaAnalyticsService.cpp
@@ -32,15 +32,10 @@
#include <media/MediaAnalyticsItem.h>
#include <media/IMediaAnalyticsService.h>
-#define DEBUGGING 0
-#define DEBUGGING_FLOW 0
-#define DEBUGGING_RETURNS 0
-
namespace android {
enum {
- GENERATE_UNIQUE_SESSIONID = IBinder::FIRST_CALL_TRANSACTION,
- SUBMIT_ITEM,
+ SUBMIT_ITEM_ONEWAY = IBinder::FIRST_CALL_TRANSACTION,
};
class BpMediaAnalyticsService: public BpInterface<IMediaAnalyticsService>
@@ -51,61 +46,23 @@
{
}
- virtual MediaAnalyticsItem::SessionID_t generateUniqueSessionID() {
- Parcel data, reply;
- status_t err;
- MediaAnalyticsItem::SessionID_t sessionid =
- MediaAnalyticsItem::SessionIDInvalid;
-
- data.writeInterfaceToken(IMediaAnalyticsService::getInterfaceDescriptor());
- err = remote()->transact(GENERATE_UNIQUE_SESSIONID, data, &reply);
- if (err != NO_ERROR) {
- ALOGW("bad response from service for generateSessionId, err=%d", err);
- return MediaAnalyticsItem::SessionIDInvalid;
- }
- sessionid = reply.readInt64();
- if (DEBUGGING_RETURNS) {
- ALOGD("the caller gets a sessionid of %" PRId64 " back", sessionid);
- }
- return sessionid;
- }
-
- virtual MediaAnalyticsItem::SessionID_t submit(MediaAnalyticsItem *item, bool forcenew)
+ status_t submit(MediaAnalyticsItem *item) override
{
- // have this record submit itself
- // this will be a binder call with appropriate timing
- // return value is the uuid that the system generated for it.
- // the return value 0 and -1 are reserved.
- // -1 to indicate that there was a problem recording...
-
- Parcel data, reply;
- status_t err;
-
- if (item == NULL) {
- return MediaAnalyticsItem::SessionIDInvalid;
+ if (item == nullptr) {
+ return BAD_VALUE;
}
+ ALOGV("%s: (ONEWAY) item=%s", __func__, item->toString().c_str());
+ Parcel data;
data.writeInterfaceToken(IMediaAnalyticsService::getInterfaceDescriptor());
- if(DEBUGGING_FLOW) {
- ALOGD("client offers record: %s", item->toString().c_str());
- }
- data.writeBool(forcenew);
item->writeToParcel(&data);
- err = remote()->transact(SUBMIT_ITEM, data, &reply);
- if (err != NO_ERROR) {
- ALOGW("bad response from service for submit, err=%d", err);
- return MediaAnalyticsItem::SessionIDInvalid;
- }
-
- // get an answer out of 'reply'
- int64_t sessionid = reply.readInt64();
- if (DEBUGGING_RETURNS) {
- ALOGD("the caller gets sessionid=%" PRId64 "", sessionid);
- }
- return sessionid;
+ status_t err = remote()->transact(
+ SUBMIT_ITEM_ONEWAY, data, nullptr /* reply */, IBinder::FLAG_ONEWAY);
+ ALOGW_IF(err != NO_ERROR, "%s: bad response from service for submit, err=%d",
+ __func__, err);
+ return err;
}
-
};
IMPLEMENT_META_INTERFACE(MediaAnalyticsService, "android.media.IMediaAnalyticsService");
@@ -115,49 +72,23 @@
status_t BnMediaAnalyticsService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
-
-
- // get calling pid/tid
- IPCThreadState *ipc = IPCThreadState::self();
- int clientPid = ipc->getCallingPid();
- // permission checking
-
- if(DEBUGGING_FLOW) {
- ALOGD("running in service, code %d, pid %d; called from pid %d",
- code, getpid(), clientPid);
- }
+ const int clientPid = IPCThreadState::self()->getCallingPid();
switch (code) {
+ case SUBMIT_ITEM_ONEWAY: {
+ CHECK_INTERFACE(IMediaAnalyticsService, data, reply);
- case GENERATE_UNIQUE_SESSIONID: {
- CHECK_INTERFACE(IMediaAnalyticsService, data, reply);
+ MediaAnalyticsItem * const item = MediaAnalyticsItem::create();
+ if (item->readFromParcel(data) < 0) {
+ return BAD_VALUE;
+ }
+ item->setPid(clientPid);
+ const status_t status __unused = submitInternal(item, true /* release */);
+ return NO_ERROR;
+ } break;
- MediaAnalyticsItem::SessionID_t sessionid = generateUniqueSessionID();
- reply->writeInt64(sessionid);
-
- return NO_ERROR;
- } break;
-
- case SUBMIT_ITEM: {
- CHECK_INTERFACE(IMediaAnalyticsService, data, reply);
-
- bool forcenew;
- MediaAnalyticsItem *item = MediaAnalyticsItem::create();
-
- data.readBool(&forcenew);
- item->readFromParcel(data);
-
- item->setPid(clientPid);
-
- // submit() takes over ownership of 'item'
- MediaAnalyticsItem::SessionID_t sessionid = submit(item, forcenew);
- reply->writeInt64(sessionid);
-
- return NO_ERROR;
- } break;
-
- default:
- return BBinder::onTransact(code, data, reply, flags);
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
}
}
diff --git a/media/libmediametrics/MediaAnalyticsItem.cpp b/media/libmediametrics/MediaAnalyticsItem.cpp
index b7856a6..a4efa49 100644
--- a/media/libmediametrics/MediaAnalyticsItem.cpp
+++ b/media/libmediametrics/MediaAnalyticsItem.cpp
@@ -22,10 +22,11 @@
#include <string.h>
#include <sys/types.h>
+#include <mutex>
+
#include <binder/Parcel.h>
#include <utils/Errors.h>
#include <utils/Log.h>
-#include <utils/Mutex.h>
#include <utils/SortedVector.h>
#include <utils/threads.h>
@@ -44,14 +45,6 @@
// the service is off.
#define SVC_TRIES 2
-// the few universal keys we have
-const MediaAnalyticsItem::Key MediaAnalyticsItem::kKeyAny = "any";
-const MediaAnalyticsItem::Key MediaAnalyticsItem::kKeyNone = "none";
-
-const char * const MediaAnalyticsItem::EnabledProperty = "media.metrics.enabled";
-const char * const MediaAnalyticsItem::EnabledPropertyPersist = "persist.media.metrics.enabled";
-const int MediaAnalyticsItem::EnabledProperty_default = 1;
-
// So caller doesn't need to know size of allocated space
MediaAnalyticsItem *MediaAnalyticsItem::create()
{
@@ -74,34 +67,6 @@
return handle;
}
-// access functions for the class
-MediaAnalyticsItem::MediaAnalyticsItem()
- : mPid(-1),
- mUid(-1),
- mPkgVersionCode(0),
- mSessionID(MediaAnalyticsItem::SessionIDNone),
- mTimestamp(0),
- mFinalized(1),
- mPropCount(0), mPropSize(0), mProps(NULL)
-{
- mKey = MediaAnalyticsItem::kKeyNone;
-}
-
-MediaAnalyticsItem::MediaAnalyticsItem(MediaAnalyticsItem::Key key)
- : mPid(-1),
- mUid(-1),
- mPkgVersionCode(0),
- mSessionID(MediaAnalyticsItem::SessionIDNone),
- mTimestamp(0),
- mFinalized(1),
- mPropCount(0), mPropSize(0), mProps(NULL)
-{
- if (DEBUG_ALLOCATIONS) {
- ALOGD("Allocate MediaAnalyticsItem @ %p", this);
- }
- mKey = key;
-}
-
MediaAnalyticsItem::~MediaAnalyticsItem() {
if (DEBUG_ALLOCATIONS) {
ALOGD("Destroy MediaAnalyticsItem @ %p", this);
@@ -114,13 +79,10 @@
// clean allocated storage from key
mKey.clear();
- // clean various major parameters
- mSessionID = MediaAnalyticsItem::SessionIDNone;
-
// clean attributes
// contents of the attributes
for (size_t i = 0 ; i < mPropCount; i++ ) {
- clearProp(&mProps[i]);
+ mProps[i].clear();
}
// the attribute records themselves
if (mProps != NULL) {
@@ -143,14 +105,12 @@
dst->mUid = this->mUid;
dst->mPkgName = this->mPkgName;
dst->mPkgVersionCode = this->mPkgVersionCode;
- dst->mSessionID = this->mSessionID;
dst->mTimestamp = this->mTimestamp;
- dst->mFinalized = this->mFinalized;
// properties aka attributes
dst->growProps(this->mPropCount);
for(size_t i=0;i<mPropCount;i++) {
- copyProp(&dst->mProps[i], &this->mProps[i]);
+ dst->mProps[i] = this->mProps[i];
}
dst->mPropCount = this->mPropCount;
}
@@ -158,35 +118,6 @@
return dst;
}
-MediaAnalyticsItem &MediaAnalyticsItem::setSessionID(MediaAnalyticsItem::SessionID_t id) {
- mSessionID = id;
- return *this;
-}
-
-MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::getSessionID() const {
- return mSessionID;
-}
-
-MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::generateSessionID() {
-
- if (mSessionID == SessionIDNone) {
- // get one from the server
- MediaAnalyticsItem::SessionID_t newid = SessionIDNone;
- sp<IMediaAnalyticsService> svc = getInstance();
- if (svc != NULL) {
- newid = svc->generateUniqueSessionID();
- }
- mSessionID = newid;
- }
-
- return mSessionID;
-}
-
-MediaAnalyticsItem &MediaAnalyticsItem::clearSessionID() {
- mSessionID = MediaAnalyticsItem::SessionIDNone;
- return *this;
-}
-
MediaAnalyticsItem &MediaAnalyticsItem::setTimestamp(nsecs_t ts) {
mTimestamp = ts;
return *this;
@@ -234,32 +165,22 @@
return *this;
}
-MediaAnalyticsItem::Key MediaAnalyticsItem::getKey() {
- return mKey;
-}
-
// number of attributes we have in this record
int32_t MediaAnalyticsItem::count() const {
return mPropCount;
}
// find the proper entry in the list
-size_t MediaAnalyticsItem::findPropIndex(const char *name, size_t len)
+size_t MediaAnalyticsItem::findPropIndex(const char *name, size_t len) const
{
size_t i = 0;
for (; i < mPropCount; i++) {
- Prop *prop = &mProps[i];
- if (prop->mNameLen != len) {
- continue;
- }
- if (memcmp(name, prop->mName, len) == 0) {
- break;
- }
+ if (mProps[i].isNamed(name, len)) break;
}
return i;
}
-MediaAnalyticsItem::Prop *MediaAnalyticsItem::findProp(const char *name) {
+MediaAnalyticsItem::Prop *MediaAnalyticsItem::findProp(const char *name) const {
size_t len = strlen(name);
size_t i = findPropIndex(name, len);
if (i < mPropCount) {
@@ -268,16 +189,6 @@
return NULL;
}
-void MediaAnalyticsItem::Prop::setName(const char *name, size_t len) {
- free((void *)mName);
- mName = (const char *) malloc(len+1);
- LOG_ALWAYS_FATAL_IF(mName == NULL,
- "failed malloc() for property '%s' (len %zu)",
- name, len);
- memcpy ((void *)mName, name, len+1);
- mNameLen = len;
-}
-
// consider this "find-or-allocate".
// caller validates type and uses clearPropValue() accordingly
MediaAnalyticsItem::Prop *MediaAnalyticsItem::allocateProp(const char *name) {
@@ -307,12 +218,10 @@
size_t len = strlen(name);
size_t i = findPropIndex(name, len);
if (i < mPropCount) {
- Prop *prop = &mProps[i];
- clearProp(prop);
+ mProps[i].clear();
if (i != mPropCount-1) {
// in the middle, bring last one down to fill gap
- copyProp(prop, &mProps[mPropCount-1]);
- clearProp(&mProps[mPropCount-1]);
+ mProps[i].swap(mProps[mPropCount-1]);
}
mPropCount--;
return true;
@@ -320,206 +229,6 @@
return false;
}
-// set the values
-void MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr name, int32_t value) {
- Prop *prop = allocateProp(name);
- if (prop != NULL) {
- clearPropValue(prop);
- prop->mType = kTypeInt32;
- prop->u.int32Value = value;
- }
-}
-
-void MediaAnalyticsItem::setInt64(MediaAnalyticsItem::Attr name, int64_t value) {
- Prop *prop = allocateProp(name);
- if (prop != NULL) {
- clearPropValue(prop);
- prop->mType = kTypeInt64;
- prop->u.int64Value = value;
- }
-}
-
-void MediaAnalyticsItem::setDouble(MediaAnalyticsItem::Attr name, double value) {
- Prop *prop = allocateProp(name);
- if (prop != NULL) {
- clearPropValue(prop);
- prop->mType = kTypeDouble;
- prop->u.doubleValue = value;
- }
-}
-
-void MediaAnalyticsItem::setCString(MediaAnalyticsItem::Attr name, const char *value) {
-
- Prop *prop = allocateProp(name);
- // any old value will be gone
- if (prop != NULL) {
- clearPropValue(prop);
- prop->mType = kTypeCString;
- prop->u.CStringValue = strdup(value);
- }
-}
-
-void MediaAnalyticsItem::setRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
- Prop *prop = allocateProp(name);
- if (prop != NULL) {
- clearPropValue(prop);
- prop->mType = kTypeRate;
- prop->u.rate.count = count;
- prop->u.rate.duration = duration;
- }
-}
-
-
-// find/add/set fused into a single operation
-void MediaAnalyticsItem::addInt32(MediaAnalyticsItem::Attr name, int32_t value) {
- Prop *prop = allocateProp(name);
- if (prop == NULL) {
- return;
- }
- switch (prop->mType) {
- case kTypeInt32:
- prop->u.int32Value += value;
- break;
- default:
- clearPropValue(prop);
- prop->mType = kTypeInt32;
- prop->u.int32Value = value;
- break;
- }
-}
-
-void MediaAnalyticsItem::addInt64(MediaAnalyticsItem::Attr name, int64_t value) {
- Prop *prop = allocateProp(name);
- if (prop == NULL) {
- return;
- }
- switch (prop->mType) {
- case kTypeInt64:
- prop->u.int64Value += value;
- break;
- default:
- clearPropValue(prop);
- prop->mType = kTypeInt64;
- prop->u.int64Value = value;
- break;
- }
-}
-
-void MediaAnalyticsItem::addRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
- Prop *prop = allocateProp(name);
- if (prop == NULL) {
- return;
- }
- switch (prop->mType) {
- case kTypeRate:
- prop->u.rate.count += count;
- prop->u.rate.duration += duration;
- break;
- default:
- clearPropValue(prop);
- prop->mType = kTypeRate;
- prop->u.rate.count = count;
- prop->u.rate.duration = duration;
- break;
- }
-}
-
-void MediaAnalyticsItem::addDouble(MediaAnalyticsItem::Attr name, double value) {
- Prop *prop = allocateProp(name);
- if (prop == NULL) {
- return;
- }
- switch (prop->mType) {
- case kTypeDouble:
- prop->u.doubleValue += value;
- break;
- default:
- clearPropValue(prop);
- prop->mType = kTypeDouble;
- prop->u.doubleValue = value;
- break;
- }
-}
-
-// find & extract values
-bool MediaAnalyticsItem::getInt32(MediaAnalyticsItem::Attr name, int32_t *value) {
- Prop *prop = findProp(name);
- if (prop == NULL || prop->mType != kTypeInt32) {
- return false;
- }
- if (value != NULL) {
- *value = prop->u.int32Value;
- }
- return true;
-}
-
-bool MediaAnalyticsItem::getInt64(MediaAnalyticsItem::Attr name, int64_t *value) {
- Prop *prop = findProp(name);
- if (prop == NULL || prop->mType != kTypeInt64) {
- return false;
- }
- if (value != NULL) {
- *value = prop->u.int64Value;
- }
- return true;
-}
-
-bool MediaAnalyticsItem::getRate(MediaAnalyticsItem::Attr name, int64_t *count, int64_t *duration, double *rate) {
- Prop *prop = findProp(name);
- if (prop == NULL || prop->mType != kTypeRate) {
- return false;
- }
- if (count != NULL) {
- *count = prop->u.rate.count;
- }
- if (duration != NULL) {
- *duration = prop->u.rate.duration;
- }
- if (rate != NULL) {
- double r = 0.0;
- if (prop->u.rate.duration != 0) {
- r = prop->u.rate.count / (double) prop->u.rate.duration;
- }
- *rate = r;
- }
- return true;
-}
-
-bool MediaAnalyticsItem::getDouble(MediaAnalyticsItem::Attr name, double *value) {
- Prop *prop = findProp(name);
- if (prop == NULL || prop->mType != kTypeDouble) {
- return false;
- }
- if (value != NULL) {
- *value = prop->u.doubleValue;
- }
- return true;
-}
-
-// caller responsible for the returned string
-bool MediaAnalyticsItem::getCString(MediaAnalyticsItem::Attr name, char **value) {
- Prop *prop = findProp(name);
- if (prop == NULL || prop->mType != kTypeCString) {
- return false;
- }
- if (value != NULL) {
- *value = strdup(prop->u.CStringValue);
- }
- return true;
-}
-
-bool MediaAnalyticsItem::getString(MediaAnalyticsItem::Attr name, std::string *value) {
- Prop *prop = findProp(name);
- if (prop == NULL || prop->mType != kTypeCString) {
- return false;
- }
- if (value != NULL) {
- // std::string makes a copy for us
- *value = prop->u.CStringValue;
- }
- return true;
-}
-
// remove indicated keys and their values
// return value is # keys removed
int32_t MediaAnalyticsItem::filter(int n, MediaAnalyticsItem::Attr attrs[]) {
@@ -537,12 +246,12 @@
} else if (j+1 == mPropCount) {
// last one, shorten
zapped++;
- clearProp(&mProps[j]);
+ mProps[j].clear();
mPropCount--;
} else {
// in the middle, bring last one down and shorten
zapped++;
- clearProp(&mProps[j]);
+ mProps[j].clear();
mProps[j] = mProps[mPropCount-1];
mPropCount--;
}
@@ -560,13 +269,13 @@
for (ssize_t i = mPropCount-1 ; i >=0 ; i--) {
Prop *prop = &mProps[i];
for (ssize_t j = 0; j < n ; j++) {
- if (strcmp(prop->mName, attrs[j]) == 0) {
- clearProp(prop);
+ if (prop->isNamed(attrs[j])) {
+ prop->clear();
zapped++;
if (i != (ssize_t)(mPropCount-1)) {
*prop = mProps[mPropCount-1];
}
- initProp(&mProps[mPropCount-1]);
+ mProps[mPropCount-1].clear();
mPropCount--;
break;
}
@@ -581,63 +290,6 @@
return filter(1, &name);
}
-// handle individual items/properties stored within the class
-//
-
-void MediaAnalyticsItem::initProp(Prop *prop) {
- if (prop != NULL) {
- prop->mName = NULL;
- prop->mNameLen = 0;
-
- prop->mType = kTypeNone;
- }
-}
-
-void MediaAnalyticsItem::clearProp(Prop *prop)
-{
- if (prop != NULL) {
- if (prop->mName != NULL) {
- free((void *)prop->mName);
- prop->mName = NULL;
- prop->mNameLen = 0;
- }
-
- clearPropValue(prop);
- }
-}
-
-void MediaAnalyticsItem::clearPropValue(Prop *prop)
-{
- if (prop != NULL) {
- if (prop->mType == kTypeCString && prop->u.CStringValue != NULL) {
- free(prop->u.CStringValue);
- prop->u.CStringValue = NULL;
- }
- prop->mType = kTypeNone;
- }
-}
-
-void MediaAnalyticsItem::copyProp(Prop *dst, const Prop *src)
-{
- // get rid of any pointers in the dst
- clearProp(dst);
-
- *dst = *src;
-
- // fix any pointers that we blindly copied, so we have our own copies
- if (dst->mName) {
- void *p = malloc(dst->mNameLen + 1);
- LOG_ALWAYS_FATAL_IF(p == NULL,
- "failed malloc() duping property '%s' (len %zu)",
- dst->mName, dst->mNameLen);
- memcpy (p, src->mName, dst->mNameLen + 1);
- dst->mName = (const char *) p;
- }
- if (dst->mType == kTypeCString) {
- dst->u.CStringValue = strdup(src->u.CStringValue);
- }
-}
-
bool MediaAnalyticsItem::growProps(int increment)
{
if (increment <= 0) {
@@ -648,7 +300,7 @@
if (ni != NULL) {
for (int i = mPropSize; i < nsize; i++) {
- initProp(&ni[i]);
+ new (&ni[i]) Prop(); // placement new
}
mProps = ni;
mPropSize = nsize;
@@ -683,11 +335,8 @@
mUid = data.readInt32();
mPkgName = data.readCString();
mPkgVersionCode = data.readInt64();
- mSessionID = data.readInt64();
// We no longer pay attention to user setting of finalized, BUT it's
// still part of the wire packet -- so read & discard.
- mFinalized = data.readInt32();
- mFinalized = 1;
mTimestamp = data.readInt64();
int count = data.readInt32();
@@ -748,41 +397,14 @@
data->writeInt32(mUid);
data->writeCString(mPkgName.c_str());
data->writeInt64(mPkgVersionCode);
- data->writeInt64(mSessionID);
- data->writeInt32(mFinalized);
data->writeInt64(mTimestamp);
// set of items
- int count = mPropCount;
+ const size_t count = mPropCount;
data->writeInt32(count);
- for (int i = 0 ; i < count; i++ ) {
- Prop *prop = &mProps[i];
- data->writeCString(prop->mName);
- data->writeInt32(prop->mType);
- switch (prop->mType) {
- case MediaAnalyticsItem::kTypeInt32:
- data->writeInt32(prop->u.int32Value);
- break;
- case MediaAnalyticsItem::kTypeInt64:
- data->writeInt64(prop->u.int64Value);
- break;
- case MediaAnalyticsItem::kTypeDouble:
- data->writeDouble(prop->u.doubleValue);
- break;
- case MediaAnalyticsItem::kTypeRate:
- data->writeInt64(prop->u.rate.count);
- data->writeInt64(prop->u.rate.duration);
- break;
- case MediaAnalyticsItem::kTypeCString:
- data->writeCString(prop->u.CStringValue);
- break;
- default:
- ALOGE("found bad Prop type: %d, idx %d, name %s",
- prop->mType, i, prop->mName);
- break;
- }
+ for (size_t i = 0 ; i < count; i++ ) {
+ mProps[i].writeToParcel(data);
}
-
return 0;
}
@@ -795,11 +417,11 @@
return strdup(val.c_str());
}
-std::string MediaAnalyticsItem::toString() {
+std::string MediaAnalyticsItem::toString() const {
return toString(PROTO_LAST);
}
-std::string MediaAnalyticsItem::toString(int version) {
+std::string MediaAnalyticsItem::toString(int version) const {
// v0 : released with 'o'
// v1 : bug fix (missing pid/finalized separator),
@@ -825,9 +447,7 @@
// same order as we spill into the parcel, although not required
// key+session are our primary matching criteria
result.append(mKey.c_str());
- result.append(":");
- snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mSessionID);
- result.append(buffer);
+ result.append(":0:"); // sessionID
snprintf(buffer, sizeof(buffer), "%d:", mUid);
result.append(buffer);
@@ -846,7 +466,7 @@
}
result.append(buffer);
- snprintf(buffer, sizeof(buffer), "%d:", mFinalized);
+ snprintf(buffer, sizeof(buffer), "%d:", 0 /* finalized */); // TODO: remove this.
result.append(buffer);
snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mTimestamp);
result.append(buffer);
@@ -856,39 +476,8 @@
snprintf(buffer, sizeof(buffer), "%d:", count);
result.append(buffer);
for (int i = 0 ; i < count; i++ ) {
- Prop *prop = &mProps[i];
- switch (prop->mType) {
- case MediaAnalyticsItem::kTypeInt32:
- snprintf(buffer,sizeof(buffer),
- "%s=%d:", prop->mName, prop->u.int32Value);
- break;
- case MediaAnalyticsItem::kTypeInt64:
- snprintf(buffer,sizeof(buffer),
- "%s=%" PRId64 ":", prop->mName, prop->u.int64Value);
- break;
- case MediaAnalyticsItem::kTypeDouble:
- snprintf(buffer,sizeof(buffer),
- "%s=%e:", prop->mName, prop->u.doubleValue);
- break;
- case MediaAnalyticsItem::kTypeRate:
- snprintf(buffer,sizeof(buffer),
- "%s=%" PRId64 "/%" PRId64 ":", prop->mName,
- prop->u.rate.count, prop->u.rate.duration);
- break;
- case MediaAnalyticsItem::kTypeCString:
- snprintf(buffer,sizeof(buffer), "%s=", prop->mName);
- result.append(buffer);
- // XXX: sanitize string for ':' '='
- result.append(prop->u.CStringValue);
- buffer[0] = ':';
- buffer[1] = '\0';
- break;
- default:
- ALOGE("to_String bad item type: %d for %s",
- prop->mType, prop->mName);
- break;
- }
- result.append(buffer);
+ mProps[i].toString(buffer, sizeof(buffer));
+ result.append(buffer);
}
if (version == PROTO_V0) {
@@ -903,23 +492,12 @@
// for the lazy, we offer methods that finds the service and
// calls the appropriate daemon
bool MediaAnalyticsItem::selfrecord() {
- return selfrecord(false);
-}
-
-bool MediaAnalyticsItem::selfrecord(bool forcenew) {
-
- if (DEBUG_API) {
- std::string p = this->toString();
- ALOGD("selfrecord of: %s [forcenew=%d]", p.c_str(), forcenew);
- }
-
+ ALOGD_IF(DEBUG_API, "%s: delivering %s", __func__, this->toString().c_str());
sp<IMediaAnalyticsService> svc = getInstance();
-
if (svc != NULL) {
- MediaAnalyticsItem::SessionID_t newid = svc->submit(this, forcenew);
- if (newid == SessionIDInvalid) {
- std::string p = this->toString();
- ALOGW("Failed to record: %s [forcenew=%d]", p.c_str(), forcenew);
+ status_t status = svc->submit(this);
+ if (status != NO_ERROR) {
+ ALOGW("%s: failed to record: %s", __func__, this->toString().c_str());
return false;
}
return true;
@@ -928,29 +506,33 @@
}
}
-// get a connection we can reuse for most of our lifetime
-// static
-sp<IMediaAnalyticsService> MediaAnalyticsItem::sAnalyticsService;
-static Mutex sInitMutex;
-static int remainingBindAttempts = SVC_TRIES;
//static
bool MediaAnalyticsItem::isEnabled() {
- int enabled = property_get_int32(MediaAnalyticsItem::EnabledProperty, -1);
+ // completely skip logging from certain UIDs. We do this here
+ // to avoid the multi-second timeouts while we learn that
+ // sepolicy will not let us find the service.
+ // We do this only for a select set of UIDs
+ // The sepolicy protection is still in place, we just want a faster
+ // response from this specific, small set of uids.
+ // This is checked only once in the lifetime of the process.
+ const uid_t uid = getuid();
+ switch (uid) {
+ case AID_RADIO: // telephony subsystem, RIL
+ return false;
+ }
+
+ int enabled = property_get_int32(MediaAnalyticsItem::EnabledProperty, -1);
if (enabled == -1) {
enabled = property_get_int32(MediaAnalyticsItem::EnabledPropertyPersist, -1);
}
if (enabled == -1) {
enabled = MediaAnalyticsItem::EnabledProperty_default;
}
- if (enabled <= 0) {
- return false;
- }
- return true;
+ return enabled > 0;
}
-
// monitor health of our connection to the metrics service
class MediaMetricsDeathNotifier : public IBinder::DeathRecipient {
virtual void binderDied(const wp<IBinder> &) {
@@ -959,83 +541,56 @@
}
};
-static sp<MediaMetricsDeathNotifier> sNotifier = NULL;
+static sp<MediaMetricsDeathNotifier> sNotifier;
+// static
+sp<IMediaAnalyticsService> MediaAnalyticsItem::sAnalyticsService;
+static std::mutex sServiceMutex;
+static int sRemainingBindAttempts = SVC_TRIES;
// static
void MediaAnalyticsItem::dropInstance() {
- Mutex::Autolock _l(sInitMutex);
- remainingBindAttempts = SVC_TRIES;
- sAnalyticsService = NULL;
+ std::lock_guard _l(sServiceMutex);
+ sRemainingBindAttempts = SVC_TRIES;
+ sAnalyticsService = nullptr;
}
//static
sp<IMediaAnalyticsService> MediaAnalyticsItem::getInstance() {
-
static const char *servicename = "media.metrics";
- int enabled = isEnabled();
+ static const bool enabled = isEnabled(); // singleton initialized
if (enabled == false) {
- if (DEBUG_SERVICEACCESS) {
- ALOGD("disabled");
- }
- return NULL;
+ ALOGD_IF(DEBUG_SERVICEACCESS, "disabled");
+ return nullptr;
}
-
- // completely skip logging from certain UIDs. We do this here
- // to avoid the multi-second timeouts while we learn that
- // sepolicy will not let us find the service.
- // We do this only for a select set of UIDs
- // The sepolicy protection is still in place, we just want a faster
- // response from this specific, small set of uids.
- {
- uid_t uid = getuid();
- switch (uid) {
- case AID_RADIO: // telephony subsystem, RIL
- return NULL;
- break;
- default:
- // let sepolicy deny access if appropriate
- break;
- }
- }
-
- {
- Mutex::Autolock _l(sInitMutex);
+ std::lock_guard _l(sServiceMutex);
+ // think of remainingBindAttempts as telling us whether service == nullptr because
+ // (1) we haven't tried to initialize it yet
+ // (2) we've tried to initialize it, but failed.
+ if (sAnalyticsService == nullptr && sRemainingBindAttempts > 0) {
const char *badness = "";
-
- // think of remainingBindAttempts as telling us whether service==NULL because
- // (1) we haven't tried to initialize it yet
- // (2) we've tried to initialize it, but failed.
- if (sAnalyticsService == NULL && remainingBindAttempts > 0) {
- sp<IServiceManager> sm = defaultServiceManager();
- if (sm != NULL) {
- sp<IBinder> binder = sm->getService(String16(servicename));
- if (binder != NULL) {
- sAnalyticsService = interface_cast<IMediaAnalyticsService>(binder);
- if (sNotifier != NULL) {
- sNotifier = NULL;
- }
- sNotifier = new MediaMetricsDeathNotifier();
- binder->linkToDeath(sNotifier);
- } else {
- badness = "did not find service";
- }
+ sp<IServiceManager> sm = defaultServiceManager();
+ if (sm != nullptr) {
+ sp<IBinder> binder = sm->getService(String16(servicename));
+ if (binder != nullptr) {
+ sAnalyticsService = interface_cast<IMediaAnalyticsService>(binder);
+ sNotifier = new MediaMetricsDeathNotifier();
+ binder->linkToDeath(sNotifier);
} else {
- badness = "No Service Manager access";
+ badness = "did not find service";
}
-
- if (sAnalyticsService == NULL) {
- if (remainingBindAttempts > 0) {
- remainingBindAttempts--;
- }
- if (DEBUG_SERVICEACCESS) {
- ALOGD("Unable to bind to service %s: %s", servicename, badness);
- }
- }
+ } else {
+ badness = "No Service Manager access";
}
-
- return sAnalyticsService;
+ if (sAnalyticsService == nullptr) {
+ if (sRemainingBindAttempts > 0) {
+ sRemainingBindAttempts--;
+ }
+ ALOGD_IF(DEBUG_SERVICEACCESS, "%s: unable to bind to service %s: %s",
+ __func__, servicename, badness);
+ }
}
+ return sAnalyticsService;
}
// merge the info from 'incoming' into this record.
@@ -1046,8 +601,6 @@
// 'this' should never be missing both of them...
if (mKey.empty()) {
mKey = incoming->mKey;
- } else if (mSessionID == 0) {
- mSessionID = incoming->mSessionID;
}
// for each attribute from 'incoming', resolve appropriately
@@ -1068,12 +621,12 @@
// no oprop, so we insert the new one
oprop = allocateProp(p);
if (oprop != NULL) {
- copyProp(oprop, iprop);
+ *oprop = *iprop;
} else {
ALOGW("dropped property '%s'", iprop->mName);
}
} else {
- copyProp(oprop, iprop);
+ *oprop = *iprop;
}
}
@@ -1246,5 +799,58 @@
return false;
}
+void MediaAnalyticsItem::Prop::writeToParcel(Parcel *data) const
+{
+ data->writeCString(mName);
+ data->writeInt32(mType);
+ switch (mType) {
+ case kTypeInt32:
+ data->writeInt32(u.int32Value);
+ break;
+ case kTypeInt64:
+ data->writeInt64(u.int64Value);
+ break;
+ case kTypeDouble:
+ data->writeDouble(u.doubleValue);
+ break;
+ case kTypeRate:
+ data->writeInt64(u.rate.count);
+ data->writeInt64(u.rate.duration);
+ break;
+ case kTypeCString:
+ data->writeCString(u.CStringValue);
+ break;
+ default:
+ ALOGE("%s: found bad type: %d, name %s", __func__, mType, mName);
+ break;
+ }
+}
+
+void MediaAnalyticsItem::Prop::toString(char *buffer, size_t length) const {
+ switch (mType) {
+ case kTypeInt32:
+ snprintf(buffer, length, "%s=%d:", mName, u.int32Value);
+ break;
+ case MediaAnalyticsItem::kTypeInt64:
+ snprintf(buffer, length, "%s=%lld:", mName, (long long)u.int64Value);
+ break;
+ case MediaAnalyticsItem::kTypeDouble:
+ snprintf(buffer, length, "%s=%e:", mName, u.doubleValue);
+ break;
+ case MediaAnalyticsItem::kTypeRate:
+ snprintf(buffer, length, "%s=%lld/%lld:",
+ mName, (long long)u.rate.count, (long long)u.rate.duration);
+ break;
+ case MediaAnalyticsItem::kTypeCString:
+ // TODO sanitize string for ':' '='
+ snprintf(buffer, length, "%s=%s:", mName, u.CStringValue);
+ break;
+ default:
+ ALOGE("%s: bad item type: %d for %s", __func__, mType, mName);
+ if (length > 0) buffer[0] = 0;
+ break;
+ }
+}
+
} // namespace android
diff --git a/media/libmediametrics/include/IMediaAnalyticsService.h b/media/libmediametrics/include/IMediaAnalyticsService.h
index f635e94..1453b5f 100644
--- a/media/libmediametrics/include/IMediaAnalyticsService.h
+++ b/media/libmediametrics/include/IMediaAnalyticsService.h
@@ -39,19 +39,16 @@
public:
DECLARE_META_INTERFACE(MediaAnalyticsService);
- // generate a unique sessionID to use across multiple requests
- // 'unique' is within this device, since last reboot
- virtual MediaAnalyticsItem::SessionID_t generateUniqueSessionID() = 0;
-
- // submit the indicated record to the mediaanalytics service, where
- // it will be merged (if appropriate) with incomplete records that
- // share the same key and sessionid.
- // 'forcenew' marks any matching incomplete record as complete before
- // inserting this new record.
- // returns the sessionID associated with that item.
- // caller continues to own the passed item
- virtual MediaAnalyticsItem::SessionID_t submit(MediaAnalyticsItem *item, bool forcenew) = 0;
-
+ /**
+ * Submits the indicated record to the mediaanalytics service, where
+ * it will be merged (if appropriate) with incomplete records that
+ * share the same key and sessionID.
+ *
+ * \param item the item to submit.
+ * \return status which is negative if an error is detected (some errors
+ may be silent and return 0 - success).
+ */
+ virtual status_t submit(MediaAnalyticsItem *item) = 0;
};
// ----------------------------------------------------------------------------
@@ -59,10 +56,15 @@
class BnMediaAnalyticsService: public BnInterface<IMediaAnalyticsService>
{
public:
- virtual status_t onTransact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
+ status_t onTransact(uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0) override;
+
+protected:
+ // Internal call where release is true if the service is to delete the item.
+ virtual status_t submitInternal(
+ MediaAnalyticsItem *item, bool release) = 0;
};
}; // namespace android
diff --git a/media/libmediametrics/include/MediaAnalyticsItem.h b/media/libmediametrics/include/MediaAnalyticsItem.h
index 42a2f5b..f0deaaf 100644
--- a/media/libmediametrics/include/MediaAnalyticsItem.h
+++ b/media/libmediametrics/include/MediaAnalyticsItem.h
@@ -38,14 +38,10 @@
//
class MediaAnalyticsItem {
+ friend class MediaMetricsJNI; // TODO: remove this access
+ friend class MediaMetricsDeathNotifier; // for dropInstance
- friend class MediaAnalyticsService;
- friend class IMediaAnalyticsService;
- friend class MediaMetricsJNI;
- friend class MetricsSummarizer;
- friend class MediaMetricsDeathNotifier;
-
- public:
+public:
enum Type {
kTypeNone = 0,
@@ -56,20 +52,14 @@
kTypeRate = 5,
};
- // sessionid
- // unique within device, within boot,
- typedef int64_t SessionID_t;
- static constexpr SessionID_t SessionIDInvalid = -1;
- static constexpr SessionID_t SessionIDNone = 0;
-
- // Key: the record descriminator
- // values for the record discriminator
- // values can be "component/component"
- // basic values: "video", "audio", "drm"
- // XXX: need to better define the format
- typedef std::string Key;
- static const Key kKeyNone; // ""
- static const Key kKeyAny; // "*"
+ // Key: the record descriminator
+ // values for the record discriminator
+ // values can be "component/component"
+ // basic values: "video", "audio", "drm"
+ // XXX: need to better define the format
+ using Key = std::string;
+ static constexpr const char * const kKeyNone = "none";
+ static constexpr const char * const kKeyAny = "any";
// Attr: names for attributes within a record
// format "prop1" or "prop/subprop"
@@ -84,14 +74,12 @@
PROTO_LAST = PROTO_V1,
};
- private:
- // use the ::create() method instead
- MediaAnalyticsItem();
- MediaAnalyticsItem(Key);
- MediaAnalyticsItem(const MediaAnalyticsItem&);
- MediaAnalyticsItem &operator=(const MediaAnalyticsItem&);
-
- public:
+ // T must be convertible to mKey
+ template <typename T>
+ explicit MediaAnalyticsItem(T key)
+ : mKey(key) { }
+ MediaAnalyticsItem(const MediaAnalyticsItem&) = delete;
+ MediaAnalyticsItem &operator=(const MediaAnalyticsItem&) = delete;
static MediaAnalyticsItem* create(Key key);
static MediaAnalyticsItem* create();
@@ -102,16 +90,6 @@
// access functions for the class
~MediaAnalyticsItem();
- // SessionID ties multiple submissions for same key together
- // so that if video "height" and "width" are known at one point
- // and "framerate" is only known later, they can be be brought
- // together.
- MediaAnalyticsItem &setSessionID(SessionID_t);
- MediaAnalyticsItem &clearSessionID();
- SessionID_t getSessionID() const;
- // generates and stores a new ID iff mSessionID == SessionIDNone
- SessionID_t generateSessionID();
-
// reset all contents, discarding any extra data
void clear();
MediaAnalyticsItem *dup();
@@ -119,40 +97,96 @@
// set the key discriminator for the record.
// most often initialized as part of the constructor
MediaAnalyticsItem &setKey(MediaAnalyticsItem::Key);
- MediaAnalyticsItem::Key getKey();
+ const MediaAnalyticsItem::Key& getKey() const { return mKey; }
// # of attributes in the record
int32_t count() const;
- // set values appropriately
- void setInt32(Attr, int32_t value);
- void setInt64(Attr, int64_t value);
- void setDouble(Attr, double value);
- void setRate(Attr, int64_t count, int64_t duration);
- void setCString(Attr, const char *value);
+ template<typename S, typename T>
+ MediaAnalyticsItem &set(S key, T value) {
+ allocateProp(key)->set(value);
+ return *this;
+ }
- // fused get/add/set; if attr wasn't there, it's a simple set.
- // type-mismatch counts as "wasn't there".
- void addInt32(Attr, int32_t value);
- void addInt64(Attr, int64_t value);
- void addDouble(Attr, double value);
- void addRate(Attr, int64_t count, int64_t duration);
+ // set values appropriately
+ MediaAnalyticsItem &setInt32(Attr key, int32_t value) {
+ return set(key, value);
+ }
+ MediaAnalyticsItem &setInt64(Attr key, int64_t value) {
+ return set(key, value);
+ }
+ MediaAnalyticsItem &setDouble(Attr key, double value) {
+ return set(key, value);
+ }
+ MediaAnalyticsItem &setRate(Attr key, int64_t count, int64_t duration) {
+ return set(key, std::make_pair(count, duration));
+ }
+ MediaAnalyticsItem &setCString(Attr key, const char *value) {
+ return set(key, value);
+ }
- // find & extract values
- // return indicates whether attr exists (and thus value filled in)
- // NULL parameter value suppresses storage of value.
- bool getInt32(Attr, int32_t *value);
- bool getInt64(Attr, int64_t *value);
- bool getDouble(Attr, double *value);
- bool getRate(Attr, int64_t *count, int64_t *duration, double *rate);
- // Caller owns the returned string
- bool getCString(Attr, char **value);
- bool getString(Attr, std::string *value);
+ // fused get/add/set; if attr wasn't there, it's a simple set.
+ // type-mismatch counts as "wasn't there".
+ template<typename S, typename T>
+ MediaAnalyticsItem &add(S key, T value) {
+ allocateProp(key)->add(value);
+ return *this;
+ }
- // parameter indicates whether to close any existing open
- // record with same key before establishing a new record
- // caller retains ownership of 'this'.
- bool selfrecord(bool);
+ MediaAnalyticsItem &addInt32(Attr key, int32_t value) {
+ return add(key, value);
+ }
+ MediaAnalyticsItem &addInt64(Attr key, int64_t value) {
+ return add(key, value);
+ }
+ MediaAnalyticsItem &addDouble(Attr key, double value) {
+ return add(key, value);
+ }
+ MediaAnalyticsItem &addRate(Attr key, int64_t count, int64_t duration) {
+ return add(key, std::make_pair(count, duration));
+ }
+
+ // find & extract values
+ // return indicates whether attr exists (and thus value filled in)
+ // NULL parameter value suppresses storage of value.
+ template<typename S, typename T>
+ bool get(S key, T *value) const {
+ Prop *prop = findProp(key);
+ return prop != nullptr && prop->get(value);
+ }
+
+ bool getInt32(Attr key, int32_t *value) const {
+ return get(key, value);
+ }
+ bool getInt64(Attr key, int64_t *value) const {
+ return get(key, value);
+ }
+ bool getDouble(Attr key, double *value) const {
+ return get(key, value);
+ }
+ bool getRate(Attr key, int64_t *count, int64_t *duration, double *rate) const {
+ std::pair<int64_t, int64_t> value;
+ if (!get(key, &value)) return false;
+ if (count != nullptr) *count = value.first;
+ if (duration != nullptr) *duration = value.second;
+ if (rate != nullptr) {
+ if (value.second != 0) {
+ *rate = (double)value.first / value.second; // TODO: isn't INF OK?
+ } else {
+ *rate = 0.;
+ }
+ }
+ return true;
+ }
+ // Caller owns the returned string
+ bool getCString(Attr key, char **value) const {
+ return get(key, value);
+ }
+ bool getString(Attr key, std::string *value) const {
+ return get(key, value);
+ }
+
+ // Deliver the item to MediaMetrics
bool selfrecord();
// remove indicated attributes and their values
@@ -191,8 +225,8 @@
// supports the stable interface
bool dumpAttributes(char **pbuffer, size_t *plength);
- std::string toString();
- std::string toString(int version);
+ std::string toString() const;
+ std::string toString(int version) const;
const char *toCString();
const char *toCString(int version);
@@ -212,64 +246,261 @@
// caller continues to own 'incoming'
bool merge(MediaAnalyticsItem *incoming);
- // enabled 1, disabled 0
- static const char * const EnabledProperty;
- static const char * const EnabledPropertyPersist;
- static const int EnabledProperty_default;
+ // enabled 1, disabled 0
+ static constexpr const char * const EnabledProperty = "media.metrics.enabled";
+ static constexpr const char * const EnabledPropertyPersist = "persist.media.metrics.enabled";
+ static const int EnabledProperty_default = 1;
private:
- // to help validate that A doesn't mess with B's records
- pid_t mPid;
- uid_t mUid;
- std::string mPkgName;
- int64_t mPkgVersionCode;
+ // let's reuse a binder connection
+ static sp<IMediaAnalyticsService> sAnalyticsService;
+ static sp<IMediaAnalyticsService> getInstance();
+ static void dropInstance();
- // let's reuse a binder connection
- static sp<IMediaAnalyticsService> sAnalyticsService;
- static sp<IMediaAnalyticsService> getInstance();
- static void dropInstance();
+ class Prop {
+ friend class MediaMetricsJNI; // TODO: remove this access
+ public:
+ Prop() = default;
+ Prop(const Prop& other) {
+ *this = other;
+ }
+ Prop& operator=(const Prop& other) {
+ if (other.mName != nullptr) {
+ mName = strdup(other.mName);
+ } else {
+ mName = nullptr;
+ }
+ mNameLen = other.mNameLen;
+ mType = other.mType;
+ switch (mType) {
+ case kTypeInt32:
+ u.int32Value = other.u.int32Value;
+ break;
+ case kTypeInt64:
+ u.int64Value = other.u.int64Value;
+ break;
+ case kTypeDouble:
+ u.doubleValue = other.u.doubleValue;
+ break;
+ case kTypeCString:
+ u.CStringValue = strdup(other.u.CStringValue);
+ break;
+ case kTypeRate:
+ u.rate = {other.u.rate.count, other.u.rate.duration};
+ break;
+ case kTypeNone:
+ break;
+ default:
+ // abort?
+ break;
+ }
+ return *this;
+ }
- // tracking information
- SessionID_t mSessionID; // grouping similar records
- nsecs_t mTimestamp; // ns, system_time_monotonic
+ void clear() {
+ free(mName);
+ mName = nullptr;
+ mNameLen = 0;
+ clearValue();
+ }
+ void clearValue() {
+ if (mType == kTypeCString) {
+ free(u.CStringValue);
+ u.CStringValue = nullptr;
+ }
+ mType = kTypeNone;
+ }
- // will this record accept further updates
- bool mFinalized;
+ Type getType() const {
+ return mType;
+ }
- Key mKey;
+ const char *getName() const {
+ return mName;
+ }
- struct Prop {
+ void swap(Prop& other) {
+ std::swap(mName, other.mName);
+ std::swap(mNameLen, other.mNameLen);
+ std::swap(mType, other.mType);
+ std::swap(u, other.u);
+ }
- Type mType;
- const char *mName;
- size_t mNameLen; // the strlen(), doesn't include the null
- union {
- int32_t int32Value;
- int64_t int64Value;
- double doubleValue;
- char *CStringValue;
- struct { int64_t count, duration; } rate;
- } u;
- void setName(const char *name, size_t len);
- };
+ void setName(const char *name, size_t len) {
+ free(mName);
+ if (name != nullptr) {
+ mName = (char *)malloc(len + 1);
+ mNameLen = len;
+ strncpy(mName, name, len);
+ mName[len] = 0;
+ } else {
+ mName = nullptr;
+ mNameLen = 0;
+ }
+ }
- void initProp(Prop *item);
- void clearProp(Prop *item);
- void clearPropValue(Prop *item);
- void copyProp(Prop *dst, const Prop *src);
+ bool isNamed(const char *name, size_t len) const {
+ return len == mNameLen && memcmp(name, mName, len) == 0;
+ }
+
+ // TODO: remove duplicate but different definition
+ bool isNamed(const char *name) const {
+ return strcmp(name, mName) == 0;
+ }
+
+ template <typename T> bool get(T *value) const = delete;
+ template <>
+ bool get(int32_t *value) const {
+ if (mType != kTypeInt32) return false;
+ if (value != nullptr) *value = u.int32Value;
+ return true;
+ }
+ template <>
+ bool get(int64_t *value) const {
+ if (mType != kTypeInt64) return false;
+ if (value != nullptr) *value = u.int64Value;
+ return true;
+ }
+ template <>
+ bool get(double *value) const {
+ if (mType != kTypeDouble) return false;
+ if (value != nullptr) *value = u.doubleValue;
+ return true;
+ }
+ template <>
+ bool get(char** value) const {
+ if (mType != kTypeCString) return false;
+ if (value != nullptr) *value = strdup(u.CStringValue);
+ return true;
+ }
+ template <>
+ bool get(std::string* value) const {
+ if (mType != kTypeCString) return false;
+ if (value != nullptr) *value = u.CStringValue;
+ return true;
+ }
+ template <>
+ bool get(std::pair<int64_t, int64_t> *value) const {
+ if (mType != kTypeRate) return false;
+ if (value != nullptr) {
+ value->first = u.rate.count;
+ value->second = u.rate.duration;
+ }
+ return true;
+ }
+
+ template <typename T> void set(const T& value) = delete;
+ template <>
+ void set(const int32_t& value) {
+ mType = kTypeInt32;
+ u.int32Value = value;
+ }
+ template <>
+ void set(const int64_t& value) {
+ mType = kTypeInt64;
+ u.int64Value = value;
+ }
+ template <>
+ void set(const double& value) {
+ mType = kTypeDouble;
+ u.doubleValue = value;
+ }
+ template <>
+ void set(const char* const& value) {
+ if (mType == kTypeCString) {
+ free(u.CStringValue);
+ } else {
+ mType = kTypeCString;
+ }
+ if (value == nullptr) {
+ u.CStringValue = nullptr;
+ } else {
+ u.CStringValue = strdup(value);
+ }
+ }
+ template <>
+ void set(const std::pair<int64_t, int64_t> &value) {
+ mType = kTypeRate;
+ u.rate = {value.first, value.second};
+ }
+
+ template <typename T> void add(const T& value) = delete;
+ template <>
+ void add(const int32_t& value) {
+ if (mType == kTypeInt32) {
+ u.int32Value += value;
+ } else {
+ mType = kTypeInt32;
+ u.int32Value = value;
+ }
+ }
+ template <>
+ void add(const int64_t& value) {
+ if (mType == kTypeInt64) {
+ u.int64Value += value;
+ } else {
+ mType = kTypeInt64;
+ u.int64Value = value;
+ }
+ }
+ template <>
+ void add(const double& value) {
+ if (mType == kTypeDouble) {
+ u.doubleValue += value;
+ } else {
+ mType = kTypeDouble;
+ u.doubleValue = value;
+ }
+ }
+ template <>
+ void add(const std::pair<int64_t, int64_t>& value) {
+ if (mType == kTypeRate) {
+ u.rate.count += value.first;
+ u.rate.duration += value.second;
+ } else {
+ mType = kTypeRate;
+ u.rate = {value.first, value.second};
+ }
+ }
+
+ void writeToParcel(Parcel *data) const;
+ void toString(char *buffer, size_t length) const;
+
+ // TODO: make private
+ // private:
+ char *mName = nullptr;
+ size_t mNameLen = 0; // the strlen(), doesn't include the null
+ Type mType = kTypeNone;
+ union {
+ int32_t int32Value;
+ int64_t int64Value;
+ double doubleValue;
+ char *CStringValue;
+ struct { int64_t count, duration; } rate;
+ } u;
+ };
+
+ size_t findPropIndex(const char *name, size_t len) const;
+ Prop *findProp(const char *name) const;
+
enum {
kGrowProps = 10
};
bool growProps(int increment = kGrowProps);
- size_t findPropIndex(const char *name, size_t len);
- Prop *findProp(const char *name);
Prop *allocateProp(const char *name);
bool removeProp(const char *name);
- size_t mPropCount;
- size_t mPropSize;
- Prop *mProps;
+ size_t mPropCount = 0;
+ size_t mPropSize = 0;
+ Prop *mProps = nullptr;
+
+ pid_t mPid = -1;
+ uid_t mUid = -1;
+ std::string mPkgName;
+ int64_t mPkgVersionCode = 0;
+ Key mKey{kKeyNone};
+ nsecs_t mTimestamp = 0;
};
} // namespace android
diff --git a/media/libmediaplayer2/Android.bp b/media/libmediaplayer2/Android.bp
deleted file mode 100644
index dca6bb6..0000000
--- a/media/libmediaplayer2/Android.bp
+++ /dev/null
@@ -1,129 +0,0 @@
-cc_library_headers {
- name: "libmediaplayer2_headers",
- vendor_available: true,
- export_include_dirs: ["include"],
-}
-
-cc_library_static {
- name: "libmediaplayer2",
-
- srcs: [
- "MediaPlayer2AudioOutput.cpp",
- "mediaplayer2.cpp",
- ],
-
- shared_libs: [
- "libandroid_runtime",
- "libaudioclient",
- "libbinder",
- "libbinder_ndk",
- "libcutils",
- "libgui",
- "liblog",
- "libmedia_omx",
- "libui",
- "libutils",
-
- "libcrypto",
- "libmediametrics",
- "libmediandk",
- "libmediandk_utils",
- "libmediautils",
- "libmemunreachable",
- "libnativewindow",
- "libpowermanager",
- "libstagefright_httplive",
- ],
-
- export_shared_lib_headers: [
- "libaudioclient",
- "libbinder",
- "libgui",
- "libmedia_omx",
- ],
-
- header_libs: [
- "media_plugin_headers",
- ],
-
- include_dirs: [
- "frameworks/base/core/jni",
- ],
-
- static_libs: [
- "libmedia_helper",
- "libmediaplayer2-protos",
- "libmedia_player2_util",
- "libprotobuf-cpp-lite",
- "libstagefright_foundation_without_imemory",
- "libstagefright_nuplayer2",
- "libstagefright_player2",
- "libstagefright_rtsp",
- "libstagefright_timedtext2",
- "libmedia2_jni_core",
- ],
-
- export_include_dirs: [
- "include",
- ],
-
- cflags: [
- "-Werror",
- "-Wno-error=deprecated-declarations",
- "-Wall",
- ],
-
- sanitize: {
- misc_undefined: [
- "unsigned-integer-overflow",
- "signed-integer-overflow",
- ],
- cfi: true,
- },
-}
-
-cc_library {
- name: "libmedia2_jni_core",
-
- srcs: [
- "JavaVMHelper.cpp",
- "JAudioTrack.cpp",
- "JMedia2HTTPService.cpp",
- "JMedia2HTTPConnection.cpp",
- ],
-
- header_libs: [
- "libbinder_headers",
- "libnativehelper_header_only",
- ],
-
- shared_libs: [
- "liblog",
- "libutils",
- "libdl",
- ],
-
- include_dirs: [
- "frameworks/av/media/libmedia/include",
- "frameworks/base/core/jni",
- ],
-
- export_include_dirs: [
- "include",
- ],
-
- cflags: [
- "-Werror",
- "-Wno-error=deprecated-declarations",
- "-Wall",
- ],
-
- sanitize: {
- misc_undefined: [
- "unsigned-integer-overflow",
- "signed-integer-overflow",
- ],
- cfi: true,
- },
-
-}
diff --git a/media/libmediaplayer2/JAudioTrack.cpp b/media/libmediaplayer2/JAudioTrack.cpp
deleted file mode 100644
index fab6c64..0000000
--- a/media/libmediaplayer2/JAudioTrack.cpp
+++ /dev/null
@@ -1,768 +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.
- */
-
-#define LOG_TAG "JAudioTrack"
-
-#include "media/JAudioAttributes.h"
-#include "media/JAudioFormat.h"
-#include "mediaplayer2/JAudioTrack.h"
-
-#include <android_media_AudioErrors.h>
-#include <mediaplayer2/JavaVMHelper.h>
-
-namespace android {
-
-// TODO: Store Java class/methodID as a member variable in the class.
-// TODO: Add NULL && Exception checks after every JNI call.
-JAudioTrack::JAudioTrack( // < Usages of the arguments are below >
- uint32_t sampleRate, // AudioFormat && bufferSizeInBytes
- audio_format_t format, // AudioFormat && bufferSizeInBytes
- audio_channel_mask_t channelMask, // AudioFormat && bufferSizeInBytes
- callback_t cbf, // Offload
- void* user, // Offload
- size_t frameCount, // bufferSizeInBytes
- int32_t sessionId, // AudioTrack
- const jobject attributes, // AudioAttributes
- float maxRequiredSpeed) { // bufferSizeInBytes
-
- JNIEnv *env = JavaVMHelper::getJNIEnv();
-
- jclass jAudioTrackCls = env->FindClass("android/media/AudioTrack");
- mAudioTrackCls = reinterpret_cast<jclass>(env->NewGlobalRef(jAudioTrackCls));
- env->DeleteLocalRef(jAudioTrackCls);
-
- maxRequiredSpeed = std::min(std::max(maxRequiredSpeed, 1.0f), AUDIO_TIMESTRETCH_SPEED_MAX);
-
- int bufferSizeInBytes = 0;
- if (sampleRate == 0 || frameCount > 0) {
- // Manually calculate buffer size.
- bufferSizeInBytes = audio_channel_count_from_out_mask(channelMask)
- * audio_bytes_per_sample(format) * (frameCount > 0 ? frameCount : 1);
- } else if (sampleRate > 0) {
- // Call Java AudioTrack::getMinBufferSize().
- jmethodID jGetMinBufferSize =
- env->GetStaticMethodID(mAudioTrackCls, "getMinBufferSize", "(III)I");
- bufferSizeInBytes = env->CallStaticIntMethod(mAudioTrackCls, jGetMinBufferSize,
- sampleRate, outChannelMaskFromNative(channelMask), audioFormatFromNative(format));
- }
- bufferSizeInBytes = (int) (bufferSizeInBytes * maxRequiredSpeed);
-
- // Create a Java AudioTrack object through its Builder.
- jclass jBuilderCls = env->FindClass("android/media/AudioTrack$Builder");
- jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
- jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);
-
- {
- sp<JObjectHolder> audioAttributesObj;
- if (attributes != NULL) {
- audioAttributesObj = new JObjectHolder(attributes);
- } else {
- audioAttributesObj = new JObjectHolder(
- JAudioAttributes::createAudioAttributesObj(env, NULL));
- }
- jmethodID jSetAudioAttributes = env->GetMethodID(jBuilderCls, "setAudioAttributes",
- "(Landroid/media/AudioAttributes;)Landroid/media/AudioTrack$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderObj,
- jSetAudioAttributes, audioAttributesObj->getJObject());
- }
-
- jmethodID jSetAudioFormat = env->GetMethodID(jBuilderCls, "setAudioFormat",
- "(Landroid/media/AudioFormat;)Landroid/media/AudioTrack$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetAudioFormat,
- JAudioFormat::createAudioFormatObj(env, sampleRate, format, channelMask));
-
- jmethodID jSetBufferSizeInBytes = env->GetMethodID(jBuilderCls, "setBufferSizeInBytes",
- "(I)Landroid/media/AudioTrack$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetBufferSizeInBytes, bufferSizeInBytes);
-
- // We only use streaming mode of Java AudioTrack.
- jfieldID jModeStream = env->GetStaticFieldID(mAudioTrackCls, "MODE_STREAM", "I");
- jint transferMode = env->GetStaticIntField(mAudioTrackCls, jModeStream);
- jmethodID jSetTransferMode = env->GetMethodID(jBuilderCls, "setTransferMode",
- "(I)Landroid/media/AudioTrack$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetTransferMode,
- transferMode /* Java AudioTrack::MODE_STREAM */);
-
- if (sessionId != 0) {
- jmethodID jSetSessionId = env->GetMethodID(jBuilderCls, "setSessionId",
- "(I)Landroid/media/AudioTrack$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetSessionId, sessionId);
- }
-
- mFlags = AUDIO_OUTPUT_FLAG_NONE;
- if (cbf != NULL) {
- jmethodID jSetOffloadedPlayback = env->GetMethodID(jBuilderCls, "setOffloadedPlayback",
- "(Z)Landroid/media/AudioTrack$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetOffloadedPlayback, true);
- mFlags = AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
- }
-
- jmethodID jBuild = env->GetMethodID(jBuilderCls, "build", "()Landroid/media/AudioTrack;");
- jobject jAudioTrackObj = env->CallObjectMethod(jBuilderObj, jBuild);
- mAudioTrackObj = reinterpret_cast<jobject>(env->NewGlobalRef(jAudioTrackObj));
- env->DeleteLocalRef(jBuilderObj);
-
- if (cbf != NULL) {
- // Set offload mode callback
- jobject jStreamEventCallbackObj = createStreamEventCallback(cbf, user);
- jobject jExecutorObj = createCallbackExecutor();
- jmethodID jSetStreamEventCallback = env->GetMethodID(
- jAudioTrackCls,
- "setStreamEventCallback",
- "(Ljava/util/concurrent/Executor;Landroid/media/AudioTrack$StreamEventCallback;)V");
- env->CallVoidMethod(
- mAudioTrackObj, jSetStreamEventCallback, jExecutorObj, jStreamEventCallbackObj);
- }
-}
-
-JAudioTrack::~JAudioTrack() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- env->DeleteGlobalRef(mAudioTrackCls);
- env->DeleteGlobalRef(mAudioTrackObj);
-}
-
-size_t JAudioTrack::frameCount() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetBufferSizeInFrames = env->GetMethodID(
- mAudioTrackCls, "getBufferSizeInFrames", "()I");
- return env->CallIntMethod(mAudioTrackObj, jGetBufferSizeInFrames);
-}
-
-size_t JAudioTrack::channelCount() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetChannelCount = env->GetMethodID(mAudioTrackCls, "getChannelCount", "()I");
- return env->CallIntMethod(mAudioTrackObj, jGetChannelCount);
-}
-
-uint32_t JAudioTrack::latency() {
- // TODO: Currently hard-coded as returning zero.
- return 0;
-}
-
-status_t JAudioTrack::getPosition(uint32_t *position) {
- if (position == NULL) {
- return BAD_VALUE;
- }
-
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetPlaybackHeadPosition = env->GetMethodID(
- mAudioTrackCls, "getPlaybackHeadPosition", "()I");
- *position = env->CallIntMethod(mAudioTrackObj, jGetPlaybackHeadPosition);
-
- return NO_ERROR;
-}
-
-status_t JAudioTrack::getTimestamp(AudioTimestamp& timestamp) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
-
- jclass jAudioTimeStampCls = env->FindClass("android/media/AudioTimestamp");
- jobject jAudioTimeStampObj = env->AllocObject(jAudioTimeStampCls);
-
- jfieldID jFramePosition = env->GetFieldID(jAudioTimeStampCls, "framePosition", "J");
- jfieldID jNanoTime = env->GetFieldID(jAudioTimeStampCls, "nanoTime", "J");
-
- jmethodID jGetTimestamp = env->GetMethodID(mAudioTrackCls,
- "getTimestamp", "(Landroid/media/AudioTimestamp;)Z");
- bool success = env->CallBooleanMethod(mAudioTrackObj, jGetTimestamp, jAudioTimeStampObj);
-
- if (!success) {
- return NO_INIT;
- }
-
- long long framePosition = env->GetLongField(jAudioTimeStampObj, jFramePosition);
- long long nanoTime = env->GetLongField(jAudioTimeStampObj, jNanoTime);
-
- struct timespec ts;
- const long long secondToNano = 1000000000LL; // 1E9
- ts.tv_sec = nanoTime / secondToNano;
- ts.tv_nsec = nanoTime % secondToNano;
- timestamp.mTime = ts;
- timestamp.mPosition = (uint32_t) framePosition;
-
- return NO_ERROR;
-}
-
-status_t JAudioTrack::getTimestamp(ExtendedTimestamp *timestamp __unused) {
- // TODO: Implement this after appropriate Java AudioTrack method is available.
- return NO_ERROR;
-}
-
-status_t JAudioTrack::setPlaybackRate(const AudioPlaybackRate &playbackRate) {
- // TODO: existing native AudioTrack returns INVALID_OPERATION on offload/direct/fast tracks.
- // Should we do the same thing?
- JNIEnv *env = JavaVMHelper::getJNIEnv();
-
- jclass jPlaybackParamsCls = env->FindClass("android/media/PlaybackParams");
- jmethodID jPlaybackParamsCtor = env->GetMethodID(jPlaybackParamsCls, "<init>", "()V");
- jobject jPlaybackParamsObj = env->NewObject(jPlaybackParamsCls, jPlaybackParamsCtor);
-
- jmethodID jSetAudioFallbackMode = env->GetMethodID(
- jPlaybackParamsCls, "setAudioFallbackMode", "(I)Landroid/media/PlaybackParams;");
- jPlaybackParamsObj = env->CallObjectMethod(
- jPlaybackParamsObj, jSetAudioFallbackMode, playbackRate.mFallbackMode);
-
- jmethodID jSetAudioStretchMode = env->GetMethodID(
- jPlaybackParamsCls, "setAudioStretchMode", "(I)Landroid/media/PlaybackParams;");
- jPlaybackParamsObj = env->CallObjectMethod(
- jPlaybackParamsObj, jSetAudioStretchMode, playbackRate.mStretchMode);
-
- jmethodID jSetPitch = env->GetMethodID(
- jPlaybackParamsCls, "setPitch", "(F)Landroid/media/PlaybackParams;");
- jPlaybackParamsObj = env->CallObjectMethod(jPlaybackParamsObj, jSetPitch, playbackRate.mPitch);
-
- jmethodID jSetSpeed = env->GetMethodID(
- jPlaybackParamsCls, "setSpeed", "(F)Landroid/media/PlaybackParams;");
- jPlaybackParamsObj = env->CallObjectMethod(jPlaybackParamsObj, jSetSpeed, playbackRate.mSpeed);
-
-
- // Set this Java PlaybackParams object into Java AudioTrack.
- jmethodID jSetPlaybackParams = env->GetMethodID(
- mAudioTrackCls, "setPlaybackParams", "(Landroid/media/PlaybackParams;)V");
- env->CallVoidMethod(mAudioTrackObj, jSetPlaybackParams, jPlaybackParamsObj);
- // TODO: Should we catch the Java IllegalArgumentException?
-
- return NO_ERROR;
-}
-
-const AudioPlaybackRate JAudioTrack::getPlaybackRate() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
-
- jmethodID jGetPlaybackParams = env->GetMethodID(
- mAudioTrackCls, "getPlaybackParams", "()Landroid/media/PlaybackParams;");
- jobject jPlaybackParamsObj = env->CallObjectMethod(mAudioTrackObj, jGetPlaybackParams);
-
- AudioPlaybackRate playbackRate;
- jclass jPlaybackParamsCls = env->FindClass("android/media/PlaybackParams");
-
- jmethodID jGetAudioFallbackMode = env->GetMethodID(
- jPlaybackParamsCls, "getAudioFallbackMode", "()I");
- // TODO: Should we enable passing AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT?
- // The enum is internal only, so it is not defined in PlaybackParmas.java.
- // TODO: Is this right way to convert an int to an enum?
- playbackRate.mFallbackMode = static_cast<AudioTimestretchFallbackMode>(
- env->CallIntMethod(jPlaybackParamsObj, jGetAudioFallbackMode));
-
- jmethodID jGetAudioStretchMode = env->GetMethodID(
- jPlaybackParamsCls, "getAudioStretchMode", "()I");
- playbackRate.mStretchMode = static_cast<AudioTimestretchStretchMode>(
- env->CallIntMethod(jPlaybackParamsObj, jGetAudioStretchMode));
-
- jmethodID jGetPitch = env->GetMethodID(jPlaybackParamsCls, "getPitch", "()F");
- playbackRate.mPitch = env->CallFloatMethod(jPlaybackParamsObj, jGetPitch);
-
- jmethodID jGetSpeed = env->GetMethodID(jPlaybackParamsCls, "getSpeed", "()F");
- playbackRate.mSpeed = env->CallFloatMethod(jPlaybackParamsObj, jGetSpeed);
-
- return playbackRate;
-}
-
-media::VolumeShaper::Status JAudioTrack::applyVolumeShaper(
- const sp<media::VolumeShaper::Configuration>& configuration,
- const sp<media::VolumeShaper::Operation>& operation) {
-
- jobject jConfigurationObj = createVolumeShaperConfigurationObj(configuration);
- jobject jOperationObj = createVolumeShaperOperationObj(operation);
-
- if (jConfigurationObj == NULL || jOperationObj == NULL) {
- return media::VolumeShaper::Status(BAD_VALUE);
- }
-
- JNIEnv *env = JavaVMHelper::getJNIEnv();
-
- jmethodID jCreateVolumeShaper = env->GetMethodID(mAudioTrackCls, "createVolumeShaper",
- "(Landroid/media/VolumeShaper$Configuration;)Landroid/media/VolumeShaper;");
- jobject jVolumeShaperObj = env->CallObjectMethod(
- mAudioTrackObj, jCreateVolumeShaper, jConfigurationObj);
-
- jclass jVolumeShaperCls = env->FindClass("android/media/VolumeShaper");
- jmethodID jApply = env->GetMethodID(jVolumeShaperCls, "apply",
- "(Landroid/media/VolumeShaper$Operation;)V");
- env->CallVoidMethod(jVolumeShaperObj, jApply, jOperationObj);
-
- return media::VolumeShaper::Status(NO_ERROR);
-}
-
-status_t JAudioTrack::setAuxEffectSendLevel(float level) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jSetAuxEffectSendLevel = env->GetMethodID(
- mAudioTrackCls, "setAuxEffectSendLevel", "(F)I");
- int result = env->CallIntMethod(mAudioTrackObj, jSetAuxEffectSendLevel, level);
- return javaToNativeStatus(result);
-}
-
-status_t JAudioTrack::attachAuxEffect(int effectId) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jAttachAuxEffect = env->GetMethodID(mAudioTrackCls, "attachAuxEffect", "(I)I");
- int result = env->CallIntMethod(mAudioTrackObj, jAttachAuxEffect, effectId);
- return javaToNativeStatus(result);
-}
-
-status_t JAudioTrack::setVolume(float left, float right) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- // TODO: Java setStereoVolume is deprecated. Do we really need this method?
- jmethodID jSetStereoVolume = env->GetMethodID(mAudioTrackCls, "setStereoVolume", "(FF)I");
- int result = env->CallIntMethod(mAudioTrackObj, jSetStereoVolume, left, right);
- return javaToNativeStatus(result);
-}
-
-status_t JAudioTrack::setVolume(float volume) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jSetVolume = env->GetMethodID(mAudioTrackCls, "setVolume", "(F)I");
- int result = env->CallIntMethod(mAudioTrackObj, jSetVolume, volume);
- return javaToNativeStatus(result);
-}
-
-status_t JAudioTrack::start() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jPlay = env->GetMethodID(mAudioTrackCls, "play", "()V");
- // TODO: Should we catch the Java IllegalStateException from play()?
- env->CallVoidMethod(mAudioTrackObj, jPlay);
- return NO_ERROR;
-}
-
-ssize_t JAudioTrack::write(const void* buffer, size_t size, bool blocking) {
- if (buffer == NULL) {
- return BAD_VALUE;
- }
-
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jbyteArray jAudioData = env->NewByteArray(size);
- env->SetByteArrayRegion(jAudioData, 0, size, (jbyte *) buffer);
-
- jclass jByteBufferCls = env->FindClass("java/nio/ByteBuffer");
- jmethodID jWrap = env->GetStaticMethodID(jByteBufferCls, "wrap", "([B)Ljava/nio/ByteBuffer;");
- jobject jByteBufferObj = env->CallStaticObjectMethod(jByteBufferCls, jWrap, jAudioData);
-
- int writeMode = 0;
- if (blocking) {
- jfieldID jWriteBlocking = env->GetStaticFieldID(mAudioTrackCls, "WRITE_BLOCKING", "I");
- writeMode = env->GetStaticIntField(mAudioTrackCls, jWriteBlocking);
- } else {
- jfieldID jWriteNonBlocking = env->GetStaticFieldID(
- mAudioTrackCls, "WRITE_NON_BLOCKING", "I");
- writeMode = env->GetStaticIntField(mAudioTrackCls, jWriteNonBlocking);
- }
-
- jmethodID jWrite = env->GetMethodID(mAudioTrackCls, "write", "(Ljava/nio/ByteBuffer;II)I");
- int result = env->CallIntMethod(mAudioTrackObj, jWrite, jByteBufferObj, size, writeMode);
-
- if (result >= 0) {
- return result;
- } else {
- return javaToNativeStatus(result);
- }
-}
-
-void JAudioTrack::stop() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jStop = env->GetMethodID(mAudioTrackCls, "stop", "()V");
- env->CallVoidMethod(mAudioTrackObj, jStop);
- // TODO: Should we catch IllegalStateException?
-}
-
-// TODO: Is the right implementation?
-bool JAudioTrack::stopped() const {
- return !isPlaying();
-}
-
-void JAudioTrack::flush() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jFlush = env->GetMethodID(mAudioTrackCls, "flush", "()V");
- env->CallVoidMethod(mAudioTrackObj, jFlush);
-}
-
-void JAudioTrack::pause() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jPause = env->GetMethodID(mAudioTrackCls, "pause", "()V");
- env->CallVoidMethod(mAudioTrackObj, jPause);
- // TODO: Should we catch IllegalStateException?
-}
-
-bool JAudioTrack::isPlaying() const {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetPlayState = env->GetMethodID(mAudioTrackCls, "getPlayState", "()I");
- int currentPlayState = env->CallIntMethod(mAudioTrackObj, jGetPlayState);
-
- // TODO: In Java AudioTrack, there is no STOPPING state.
- // This means while stopping, isPlaying() will return different value in two class.
- // - in existing native AudioTrack: true
- // - in JAudioTrack: false
- // If not okay, also modify the implementation of stopped().
- jfieldID jPlayStatePlaying = env->GetStaticFieldID(mAudioTrackCls, "PLAYSTATE_PLAYING", "I");
- int statePlaying = env->GetStaticIntField(mAudioTrackCls, jPlayStatePlaying);
- return currentPlayState == statePlaying;
-}
-
-uint32_t JAudioTrack::getSampleRate() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetSampleRate = env->GetMethodID(mAudioTrackCls, "getSampleRate", "()I");
- return env->CallIntMethod(mAudioTrackObj, jGetSampleRate);
-}
-
-status_t JAudioTrack::getBufferDurationInUs(int64_t *duration) {
- if (duration == nullptr) {
- return BAD_VALUE;
- }
-
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetBufferSizeInFrames = env->GetMethodID(
- mAudioTrackCls, "getBufferSizeInFrames", "()I");
- int bufferSizeInFrames = env->CallIntMethod(mAudioTrackObj, jGetBufferSizeInFrames);
-
- const double secondToMicro = 1000000LL; // 1E6
- int sampleRate = JAudioTrack::getSampleRate();
- float speed = JAudioTrack::getPlaybackRate().mSpeed;
-
- *duration = (int64_t) (bufferSizeInFrames * secondToMicro / (sampleRate * speed));
- return NO_ERROR;
-}
-
-audio_format_t JAudioTrack::format() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetAudioFormat = env->GetMethodID(mAudioTrackCls, "getAudioFormat", "()I");
- int javaFormat = env->CallIntMethod(mAudioTrackObj, jGetAudioFormat);
- return audioFormatToNative(javaFormat);
-}
-
-size_t JAudioTrack::frameSize() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetFormat = env->GetMethodID(mAudioTrackCls,
- "getFormat", "()Landroid/media/AudioFormat;");
- jobject jAudioFormatObj = env->CallObjectMethod(mAudioTrackObj, jGetFormat);
-
- jclass jAudioFormatCls = env->FindClass("android/media/AudioFormat");
- jmethodID jGetFrameSizeInBytes = env->GetMethodID(
- jAudioFormatCls, "getFrameSizeInBytes", "()I");
- jint javaFrameSizeInBytes = env->CallIntMethod(jAudioFormatObj, jGetFrameSizeInBytes);
-
- return (size_t)javaFrameSizeInBytes;
-}
-
-status_t JAudioTrack::dump(int fd, const Vector<String16>& args __unused) const
-{
- String8 result;
-
- result.append(" JAudioTrack::dump\n");
-
- // TODO: Remove logs that includes unavailable information from below.
-// result.appendFormat(" status(%d), state(%d), session Id(%d), flags(%#x)\n",
-// mStatus, mState, mSessionId, mFlags);
-// result.appendFormat(" format(%#x), channel mask(%#x), channel count(%u)\n",
-// format(), mChannelMask, channelCount());
-// result.appendFormat(" sample rate(%u), original sample rate(%u), speed(%f)\n",
-// getSampleRate(), mOriginalSampleRate, mPlaybackRate.mSpeed);
-// result.appendFormat(" frame count(%zu), req. frame count(%zu)\n",
-// frameCount(), mReqFrameCount);
-// result.appendFormat(" notif. frame count(%u), req. notif. frame count(%u),"
-// " req. notif. per buff(%u)\n",
-// mNotificationFramesAct, mNotificationFramesReq, mNotificationsPerBufferReq);
-// result.appendFormat(" latency (%d), selected device Id(%d), routed device Id(%d)\n",
-// latency(), mSelectedDeviceId, getRoutedDeviceId());
-// result.appendFormat(" output(%d) AF latency (%u) AF frame count(%zu) AF SampleRate(%u)\n",
-// mOutput, mAfLatency, mAfFrameCount, mAfSampleRate);
- ::write(fd, result.string(), result.size());
- return NO_ERROR;
-}
-
-jobject JAudioTrack::getRoutedDevice() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetRoutedDevice = env->GetMethodID(mAudioTrackCls, "getRoutedDevice",
- "()Landroid/media/AudioDeviceInfo;");
- return env->CallObjectMethod(mAudioTrackObj, jGetRoutedDevice);
-}
-
-int32_t JAudioTrack::getAudioSessionId() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetAudioSessionId = env->GetMethodID(mAudioTrackCls, "getAudioSessionId", "()I");
- jint sessionId = env->CallIntMethod(mAudioTrackObj, jGetAudioSessionId);
- return sessionId;
-}
-
-status_t JAudioTrack::setPreferredDevice(jobject device) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jSetPreferredDeviceId = env->GetMethodID(mAudioTrackCls, "setPreferredDevice",
- "(Landroid/media/AudioDeviceInfo;)Z");
- jboolean result = env->CallBooleanMethod(mAudioTrackObj, jSetPreferredDeviceId, device);
- return result == true ? NO_ERROR : BAD_VALUE;
-}
-
-audio_stream_type_t JAudioTrack::getAudioStreamType() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jGetAudioAttributes = env->GetMethodID(mAudioTrackCls, "getAudioAttributes",
- "()Landroid/media/AudioAttributes;");
- jobject jAudioAttributes = env->CallObjectMethod(mAudioTrackObj, jGetAudioAttributes);
- jclass jAudioAttributesCls = env->FindClass("android/media/AudioAttributes");
- jmethodID jGetVolumeControlStream = env->GetMethodID(jAudioAttributesCls,
- "getVolumeControlStream", "()I");
- int javaAudioStreamType = env->CallIntMethod(jAudioAttributes, jGetVolumeControlStream);
- return (audio_stream_type_t)javaAudioStreamType;
-}
-
-status_t JAudioTrack::pendingDuration(int32_t *msec) {
- if (msec == nullptr) {
- return BAD_VALUE;
- }
-
- bool isPurePcmData = audio_is_linear_pcm(format()) && (getFlags() & AUDIO_FLAG_HW_AV_SYNC) == 0;
- if (!isPurePcmData) {
- return INVALID_OPERATION;
- }
-
- // TODO: Need to know the difference btw. client and server time.
- // If getTimestamp(ExtendedTimestamp) is ready, and un-comment below and modify appropriately.
- // (copied from AudioTrack.cpp)
-
-// ExtendedTimestamp ets;
-// ExtendedTimestamp::LOCATION location = ExtendedTimestamp::LOCATION_SERVER;
-// if (getTimestamp_l(&ets) == OK && ets.mTimeNs[location] > 0) {
-// int64_t diff = ets.mPosition[ExtendedTimestamp::LOCATION_CLIENT]
-// - ets.mPosition[location];
-// if (diff < 0) {
-// *msec = 0;
-// } else {
-// // ms is the playback time by frames
-// int64_t ms = (int64_t)((double)diff * 1000 /
-// ((double)mSampleRate * mPlaybackRate.mSpeed));
-// // clockdiff is the timestamp age (negative)
-// int64_t clockdiff = (mState != STATE_ACTIVE) ? 0 :
-// ets.mTimeNs[location]
-// + ets.mTimebaseOffset[ExtendedTimestamp::TIMEBASE_MONOTONIC]
-// - systemTime(SYSTEM_TIME_MONOTONIC);
-//
-// //ALOGV("ms: %lld clockdiff: %lld", (long long)ms, (long long)clockdiff);
-// static const int NANOS_PER_MILLIS = 1000000;
-// *msec = (int32_t)(ms + clockdiff / NANOS_PER_MILLIS);
-// }
-// return NO_ERROR;
-// }
-
- return NO_ERROR;
-}
-
-status_t JAudioTrack::addAudioDeviceCallback(jobject listener, jobject handler) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jAddOnRoutingChangedListener = env->GetMethodID(mAudioTrackCls,
- "addOnRoutingChangedListener",
- "(Landroid/media/AudioRouting$OnRoutingChangedListener;Landroid/os/Handler;)V");
- env->CallVoidMethod(mAudioTrackObj, jAddOnRoutingChangedListener, listener, handler);
- return NO_ERROR;
-}
-
-status_t JAudioTrack::removeAudioDeviceCallback(jobject listener) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jmethodID jRemoveOnRoutingChangedListener = env->GetMethodID(mAudioTrackCls,
- "removeOnRoutingChangedListener",
- "(Landroid/media/AudioRouting$OnRoutingChangedListener;)V");
- env->CallVoidMethod(mAudioTrackObj, jRemoveOnRoutingChangedListener, listener);
- return NO_ERROR;
-}
-
-void JAudioTrack::registerRoutingDelegates(
- Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>>& routingDelegates) {
- for (auto it = routingDelegates.begin(); it != routingDelegates.end(); it++) {
- addAudioDeviceCallback(it->second->getJObject(), getHandler(it->second->getJObject()));
- }
-}
-
-/////////////////////////////////////////////////////////////
-/// Static methods begin ///
-/////////////////////////////////////////////////////////////
-jobject JAudioTrack::getListener(const jobject routingDelegateObj) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jclass jRoutingDelegateCls = env->FindClass("android/media/RoutingDelegate");
- jmethodID jGetListener = env->GetMethodID(jRoutingDelegateCls,
- "getListener", "()Landroid/media/AudioRouting$OnRoutingChangedListener;");
- return env->CallObjectMethod(routingDelegateObj, jGetListener);
-}
-
-jobject JAudioTrack::getHandler(const jobject routingDelegateObj) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jclass jRoutingDelegateCls = env->FindClass("android/media/RoutingDelegate");
- jmethodID jGetHandler = env->GetMethodID(jRoutingDelegateCls,
- "getHandler", "()Landroid/os/Handler;");
- return env->CallObjectMethod(routingDelegateObj, jGetHandler);
-}
-
-jobject JAudioTrack::findByKey(
- Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>>& mp, const jobject key) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- for (auto it = mp.begin(); it != mp.end(); it++) {
- if (env->IsSameObject(it->first->getJObject(), key)) {
- return it->second->getJObject();
- }
- }
- return nullptr;
-}
-
-void JAudioTrack::eraseByKey(
- Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>>& mp, const jobject key) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- for (auto it = mp.begin(); it != mp.end(); it++) {
- if (env->IsSameObject(it->first->getJObject(), key)) {
- mp.erase(it);
- return;
- }
- }
-}
-
-/////////////////////////////////////////////////////////////
-/// Private method begins ///
-/////////////////////////////////////////////////////////////
-
-jobject JAudioTrack::createVolumeShaperConfigurationObj(
- const sp<media::VolumeShaper::Configuration>& config) {
-
- // TODO: Java VolumeShaper's setId() / setOptionFlags() are hidden.
- if (config == NULL || config->getType() == media::VolumeShaper::Configuration::TYPE_ID) {
- return NULL;
- }
-
- JNIEnv *env = JavaVMHelper::getJNIEnv();
-
- // Referenced "android_media_VolumeShaper.h".
- jfloatArray xarray = nullptr;
- jfloatArray yarray = nullptr;
- if (config->getType() == media::VolumeShaper::Configuration::TYPE_SCALE) {
- // convert curve arrays
- xarray = env->NewFloatArray(config->size());
- yarray = env->NewFloatArray(config->size());
- float * const x = env->GetFloatArrayElements(xarray, nullptr /* isCopy */);
- float * const y = env->GetFloatArrayElements(yarray, nullptr /* isCopy */);
- float *xptr = x, *yptr = y;
- for (const auto &pt : *config.get()) {
- *xptr++ = pt.first;
- *yptr++ = pt.second;
- }
- env->ReleaseFloatArrayElements(xarray, x, 0 /* mode */);
- env->ReleaseFloatArrayElements(yarray, y, 0 /* mode */);
- }
-
- jclass jBuilderCls = env->FindClass("android/media/VolumeShaper$Configuration$Builder");
- jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
- jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);
-
- jmethodID jSetDuration = env->GetMethodID(jBuilderCls, "setDuration",
- "(L)Landroid/media/VolumeShaper$Configuration$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetDuration, (jlong) config->getDurationMs());
-
- jmethodID jSetInterpolatorType = env->GetMethodID(jBuilderCls, "setInterpolatorType",
- "(I)Landroid/media/VolumeShaper$Configuration$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetInterpolatorType,
- config->getInterpolatorType());
-
- jmethodID jSetCurve = env->GetMethodID(jBuilderCls, "setCurve",
- "([F[F)Landroid/media/VolumeShaper$Configuration$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetCurve, xarray, yarray);
-
- jmethodID jBuild = env->GetMethodID(jBuilderCls, "build",
- "()Landroid/media/VolumeShaper$Configuration;");
- return env->CallObjectMethod(jBuilderObj, jBuild);
-}
-
-jobject JAudioTrack::createVolumeShaperOperationObj(
- const sp<media::VolumeShaper::Operation>& operation) {
-
- JNIEnv *env = JavaVMHelper::getJNIEnv();
-
- jclass jBuilderCls = env->FindClass("android/media/VolumeShaper$Operation$Builder");
- jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
- jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);
-
- // Set XOffset
- jmethodID jSetXOffset = env->GetMethodID(jBuilderCls, "setXOffset",
- "(F)Landroid/media/VolumeShaper$Operation$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetXOffset, operation->getXOffset());
-
- int32_t flags = operation->getFlags();
-
- if (operation->getReplaceId() >= 0) {
- jmethodID jReplace = env->GetMethodID(jBuilderCls, "replace",
- "(IB)Landroid/media/VolumeShaper$Operation$Builder;");
- bool join = (flags | media::VolumeShaper::Operation::FLAG_JOIN) != 0;
- jBuilderObj = env->CallObjectMethod(jBuilderCls, jReplace, operation->getReplaceId(), join);
- }
-
- if (flags | media::VolumeShaper::Operation::FLAG_REVERSE) {
- jmethodID jReverse = env->GetMethodID(jBuilderCls, "reverse",
- "()Landroid/media/VolumeShaper$Operation$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderCls, jReverse);
- }
-
- // TODO: VolumeShaper Javadoc says "Do not call terminate() directly". Can we call this?
- if (flags | media::VolumeShaper::Operation::FLAG_TERMINATE) {
- jmethodID jTerminate = env->GetMethodID(jBuilderCls, "terminate",
- "()Landroid/media/VolumeShaper$Operation$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderCls, jTerminate);
- }
-
- if (flags | media::VolumeShaper::Operation::FLAG_DELAY) {
- jmethodID jDefer = env->GetMethodID(jBuilderCls, "defer",
- "()Landroid/media/VolumeShaper$Operation$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderCls, jDefer);
- }
-
- if (flags | media::VolumeShaper::Operation::FLAG_CREATE_IF_NECESSARY) {
- jmethodID jCreateIfNeeded = env->GetMethodID(jBuilderCls, "createIfNeeded",
- "()Landroid/media/VolumeShaper$Operation$Builder;");
- jBuilderObj = env->CallObjectMethod(jBuilderCls, jCreateIfNeeded);
- }
-
- // TODO: Handle error case (can it be NULL?)
- jmethodID jBuild = env->GetMethodID(jBuilderCls, "build",
- "()Landroid/media/VolumeShaper$Operation;");
- return env->CallObjectMethod(jBuilderObj, jBuild);
-}
-
-jobject JAudioTrack::createStreamEventCallback(callback_t cbf, void* user) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jclass jCallbackCls = env->FindClass("android/media/MediaPlayer2$StreamEventCallback");
- jmethodID jCallbackCtor = env->GetMethodID(jCallbackCls, "<init>", "(JJJ)V");
- jobject jCallbackObj = env->NewObject(jCallbackCls, jCallbackCtor, this, cbf, user);
- return jCallbackObj;
-}
-
-jobject JAudioTrack::createCallbackExecutor() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jclass jExecutorsCls = env->FindClass("java/util/concurrent/Executors");
- jmethodID jNewSingleThreadExecutor = env->GetStaticMethodID(jExecutorsCls,
- "newSingleThreadExecutor", "()Ljava/util/concurrent/ExecutorService;");
- jobject jSingleThreadExecutorObj =
- env->CallStaticObjectMethod(jExecutorsCls, jNewSingleThreadExecutor);
- return jSingleThreadExecutorObj;
-}
-
-status_t JAudioTrack::javaToNativeStatus(int javaStatus) {
- switch (javaStatus) {
- case AUDIO_JAVA_SUCCESS:
- return NO_ERROR;
- case AUDIO_JAVA_BAD_VALUE:
- return BAD_VALUE;
- case AUDIO_JAVA_INVALID_OPERATION:
- return INVALID_OPERATION;
- case AUDIO_JAVA_PERMISSION_DENIED:
- return PERMISSION_DENIED;
- case AUDIO_JAVA_NO_INIT:
- return NO_INIT;
- case AUDIO_JAVA_WOULD_BLOCK:
- return WOULD_BLOCK;
- case AUDIO_JAVA_DEAD_OBJECT:
- return DEAD_OBJECT;
- default:
- return UNKNOWN_ERROR;
- }
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/JMedia2HTTPConnection.cpp b/media/libmediaplayer2/JMedia2HTTPConnection.cpp
deleted file mode 100644
index e1baa10..0000000
--- a/media/libmediaplayer2/JMedia2HTTPConnection.cpp
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "JMedia2HTTPConnection"
-#include <utils/Log.h>
-
-#include <mediaplayer2/JavaVMHelper.h>
-#include <mediaplayer2/JMedia2HTTPConnection.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <nativehelper/scoped_local_ref.h>
-
-#include "log/log.h"
-#include "jni.h"
-
-namespace android {
-
-static const size_t kBufferSize = 32768;
-
-JMedia2HTTPConnection::JMedia2HTTPConnection(JNIEnv *env, jobject thiz) {
- mMedia2HTTPConnectionObj = env->NewGlobalRef(thiz);
- CHECK(mMedia2HTTPConnectionObj != NULL);
-
- ScopedLocalRef<jclass> media2HTTPConnectionClass(
- env, env->GetObjectClass(mMedia2HTTPConnectionObj));
- CHECK(media2HTTPConnectionClass.get() != NULL);
-
- mConnectMethod = env->GetMethodID(
- media2HTTPConnectionClass.get(),
- "connect",
- "(Ljava/lang/String;Ljava/lang/String;)Z");
- CHECK(mConnectMethod != NULL);
-
- mDisconnectMethod = env->GetMethodID(
- media2HTTPConnectionClass.get(),
- "disconnect",
- "()V");
- CHECK(mDisconnectMethod != NULL);
-
- mReadAtMethod = env->GetMethodID(
- media2HTTPConnectionClass.get(),
- "readAt",
- "(J[BI)I");
- CHECK(mReadAtMethod != NULL);
-
- mGetSizeMethod = env->GetMethodID(
- media2HTTPConnectionClass.get(),
- "getSize",
- "()J");
- CHECK(mGetSizeMethod != NULL);
-
- mGetMIMETypeMethod = env->GetMethodID(
- media2HTTPConnectionClass.get(),
- "getMIMEType",
- "()Ljava/lang/String;");
- CHECK(mGetMIMETypeMethod != NULL);
-
- mGetUriMethod = env->GetMethodID(
- media2HTTPConnectionClass.get(),
- "getUri",
- "()Ljava/lang/String;");
- CHECK(mGetUriMethod != NULL);
-
- ScopedLocalRef<jbyteArray> tmp(
- env, env->NewByteArray(kBufferSize));
- mByteArrayObj = (jbyteArray)env->NewGlobalRef(tmp.get());
- CHECK(mByteArrayObj != NULL);
-}
-
-JMedia2HTTPConnection::~JMedia2HTTPConnection() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- env->DeleteGlobalRef(mMedia2HTTPConnectionObj);
- env->DeleteGlobalRef(mByteArrayObj);
-}
-
-bool JMedia2HTTPConnection::connect(
- const char *uri, const KeyedVector<String8, String8> *headers) {
- String8 tmp("");
- if (headers != NULL) {
- for (size_t i = 0; i < headers->size(); ++i) {
- tmp.append(headers->keyAt(i));
- tmp.append(String8(": "));
- tmp.append(headers->valueAt(i));
- tmp.append(String8("\r\n"));
- }
- }
-
- JNIEnv* env = JavaVMHelper::getJNIEnv();
- jstring juri = env->NewStringUTF(uri);
- jstring jheaders = env->NewStringUTF(tmp.string());
-
- jboolean ret =
- env->CallBooleanMethod(mMedia2HTTPConnectionObj, mConnectMethod, juri, jheaders);
-
- env->DeleteLocalRef(juri);
- env->DeleteLocalRef(jheaders);
-
- return (bool)ret;
-}
-
-void JMedia2HTTPConnection::disconnect() {
- JNIEnv* env = JavaVMHelper::getJNIEnv();
- env->CallVoidMethod(mMedia2HTTPConnectionObj, mDisconnectMethod);
-}
-
-ssize_t JMedia2HTTPConnection::readAt(off64_t offset, void *data, size_t size) {
- JNIEnv* env = JavaVMHelper::getJNIEnv();
-
- if (size > kBufferSize) {
- size = kBufferSize;
- }
-
- jint n = env->CallIntMethod(
- mMedia2HTTPConnectionObj, mReadAtMethod, (jlong)offset, mByteArrayObj, (jint)size);
-
- if (n > 0) {
- env->GetByteArrayRegion(
- mByteArrayObj,
- 0,
- n,
- (jbyte *)data);
- }
-
- return n;
-}
-
-off64_t JMedia2HTTPConnection::getSize() {
- JNIEnv* env = JavaVMHelper::getJNIEnv();
- return (off64_t)(env->CallLongMethod(mMedia2HTTPConnectionObj, mGetSizeMethod));
-}
-
-status_t JMedia2HTTPConnection::getMIMEType(String8 *mimeType) {
- JNIEnv* env = JavaVMHelper::getJNIEnv();
- jstring jmime = (jstring)env->CallObjectMethod(mMedia2HTTPConnectionObj, mGetMIMETypeMethod);
- jboolean flag = env->ExceptionCheck();
- if (flag) {
- env->ExceptionClear();
- return UNKNOWN_ERROR;
- }
-
- const char *str = env->GetStringUTFChars(jmime, 0);
- if (str != NULL) {
- *mimeType = String8(str);
- } else {
- *mimeType = "application/octet-stream";
- }
- env->ReleaseStringUTFChars(jmime, str);
- return OK;
-}
-
-status_t JMedia2HTTPConnection::getUri(String8 *uri) {
- JNIEnv* env = JavaVMHelper::getJNIEnv();
- jstring juri = (jstring)env->CallObjectMethod(mMedia2HTTPConnectionObj, mGetUriMethod);
- jboolean flag = env->ExceptionCheck();
- if (flag) {
- env->ExceptionClear();
- return UNKNOWN_ERROR;
- }
-
- const char *str = env->GetStringUTFChars(juri, 0);
- *uri = String8(str);
- env->ReleaseStringUTFChars(juri, str);
- return OK;
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/JMedia2HTTPService.cpp b/media/libmediaplayer2/JMedia2HTTPService.cpp
deleted file mode 100644
index 20e3573..0000000
--- a/media/libmediaplayer2/JMedia2HTTPService.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "JMedia2HTTPService"
-#include <utils/Log.h>
-
-#include <jni.h>
-
-#include <mediaplayer2/JavaVMHelper.h>
-#include <mediaplayer2/JMedia2HTTPService.h>
-#include <mediaplayer2/JMedia2HTTPConnection.h>
-#include <media/stagefright/foundation/ADebug.h>
-
-#include <nativehelper/scoped_local_ref.h>
-
-namespace android {
-
-JMedia2HTTPService::JMedia2HTTPService(JNIEnv *env, jobject thiz) {
- mMedia2HTTPServiceObj = env->NewGlobalRef(thiz);
- CHECK(mMedia2HTTPServiceObj != NULL);
-
- ScopedLocalRef<jclass> media2HTTPServiceClass(env, env->GetObjectClass(mMedia2HTTPServiceObj));
- CHECK(media2HTTPServiceClass.get() != NULL);
-
- mMakeHTTPConnectionMethod = env->GetMethodID(
- media2HTTPServiceClass.get(),
- "makeHTTPConnection",
- "()Landroid/media/Media2HTTPConnection;");
- CHECK(mMakeHTTPConnectionMethod != NULL);
-}
-
-JMedia2HTTPService::~JMedia2HTTPService() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- env->DeleteGlobalRef(mMedia2HTTPServiceObj);
-}
-
-sp<MediaHTTPConnection> JMedia2HTTPService::makeHTTPConnection() {
- JNIEnv* env = JavaVMHelper::getJNIEnv();
- jobject media2HTTPConnectionObj =
- env->CallObjectMethod(mMedia2HTTPServiceObj, mMakeHTTPConnectionMethod);
-
- return new JMedia2HTTPConnection(env, media2HTTPConnectionObj);
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/JavaVMHelper.cpp b/media/libmediaplayer2/JavaVMHelper.cpp
deleted file mode 100644
index 8d03ed0..0000000
--- a/media/libmediaplayer2/JavaVMHelper.cpp
+++ /dev/null
@@ -1,162 +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.
- */
-
-#define LOG_TAG "JavaVMHelper"
-
-#include "mediaplayer2/JavaVMHelper.h"
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <utils/threads.h>
-
-#include <stdlib.h>
-
-namespace android {
-
-// static
-std::atomic<JavaVM *> JavaVMHelper::sJavaVM(NULL);
-
-/*
- * Makes the current thread visible to the VM.
- *
- * The JNIEnv pointer returned is only valid for the current thread, and
- * thus must be tucked into thread-local storage.
- */
-static int javaAttachThread(const char* threadName, JNIEnv** pEnv) {
- JavaVMAttachArgs args;
- JavaVM* vm;
- jint result;
-
- vm = JavaVMHelper::getJavaVM();
- if (vm == NULL) {
- return JNI_ERR;
- }
-
- args.version = JNI_VERSION_1_4;
- args.name = (char*) threadName;
- args.group = NULL;
-
- result = vm->AttachCurrentThread(pEnv, (void*) &args);
- if (result != JNI_OK) {
- ALOGI("NOTE: attach of thread '%s' failed\n", threadName);
- }
-
- return result;
-}
-
-/*
- * Detach the current thread from the set visible to the VM.
- */
-static int javaDetachThread(void) {
- JavaVM* vm;
- jint result;
-
- vm = JavaVMHelper::getJavaVM();
- if (vm == NULL) {
- return JNI_ERR;
- }
-
- result = vm->DetachCurrentThread();
- if (result != JNI_OK) {
- ALOGE("ERROR: thread detach failed\n");
- }
- return result;
-}
-
-/*
- * When starting a native thread that will be visible from the VM, we
- * bounce through this to get the right attach/detach action.
- * Note that this function calls free(args)
- */
-static int javaThreadShell(void* args) {
- void* start = ((void**)args)[0];
- void* userData = ((void **)args)[1];
- char* name = (char*) ((void **)args)[2]; // we own this storage
- free(args);
- JNIEnv* env;
- int result;
-
- /* hook us into the VM */
- if (javaAttachThread(name, &env) != JNI_OK) {
- return -1;
- }
-
- /* start the thread running */
- result = (*(android_thread_func_t)start)(userData);
-
- /* unhook us */
- javaDetachThread();
- free(name);
-
- return result;
-}
-
-/*
- * This is invoked from androidCreateThreadEtc() via the callback
- * set with androidSetCreateThreadFunc().
- *
- * We need to create the new thread in such a way that it gets hooked
- * into the VM before it really starts executing.
- */
-static int javaCreateThreadEtc(
- android_thread_func_t entryFunction,
- void* userData,
- const char* threadName,
- int32_t threadPriority,
- size_t threadStackSize,
- android_thread_id_t* threadId) {
- void** args = (void**) malloc(3 * sizeof(void*)); // javaThreadShell must free
- int result;
-
- LOG_ALWAYS_FATAL_IF(threadName == nullptr, "threadName not provided to javaCreateThreadEtc");
-
- args[0] = (void*) entryFunction;
- args[1] = userData;
- args[2] = (void*) strdup(threadName); // javaThreadShell must free
-
- result = androidCreateRawThreadEtc(javaThreadShell, args,
- threadName, threadPriority, threadStackSize, threadId);
- return result;
-}
-
-// static
-JNIEnv *JavaVMHelper::getJNIEnv() {
- JNIEnv *env;
- JavaVM *vm = sJavaVM.load();
- CHECK(vm != NULL);
-
- if (vm->GetEnv((void **)&env, JNI_VERSION_1_4) != JNI_OK) {
- return NULL;
- }
-
- return env;
-}
-
-//static
-JavaVM *JavaVMHelper::getJavaVM() {
- return sJavaVM.load();
-}
-
-// static
-void JavaVMHelper::setJavaVM(JavaVM *vm) {
- sJavaVM.store(vm);
-
- // Ensure that Thread(/*canCallJava*/ true) in libutils is attached to the VM.
- // This is supposed to be done by runtime, but when libutils is used with linker
- // namespace, CreateThreadFunc should be initialized separately within the namespace.
- androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp b/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
deleted file mode 100644
index b4fa0c1..0000000
--- a/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
+++ /dev/null
@@ -1,656 +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.
-*/
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "MediaPlayer2AudioOutput"
-#include <mediaplayer2/MediaPlayer2AudioOutput.h>
-
-#include <cutils/properties.h> // for property_get
-#include <utils/Log.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-
-namespace {
-
-const float kMaxRequiredSpeed = 8.0f; // for PCM tracks allow up to 8x speedup.
-
-} // anonymous namespace
-
-namespace android {
-
-// TODO: Find real cause of Audio/Video delay in PV framework and remove this workaround
-/* static */ int MediaPlayer2AudioOutput::mMinBufferCount = 4;
-/* static */ bool MediaPlayer2AudioOutput::mIsOnEmulator = false;
-
-status_t MediaPlayer2AudioOutput::dump(int fd, const Vector<String16>& args) const {
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- result.append(" MediaPlayer2AudioOutput\n");
- snprintf(buffer, 255, " volume(%f)\n", mVolume);
- result.append(buffer);
- snprintf(buffer, 255, " msec per frame(%f), latency (%d)\n",
- mMsecsPerFrame, (mJAudioTrack != nullptr) ? mJAudioTrack->latency() : -1);
- result.append(buffer);
- snprintf(buffer, 255, " aux effect id(%d), send level (%f)\n",
- mAuxEffectId, mSendLevel);
- result.append(buffer);
-
- ::write(fd, result.string(), result.size());
- if (mJAudioTrack != nullptr) {
- mJAudioTrack->dump(fd, args);
- }
- return NO_ERROR;
-}
-
-MediaPlayer2AudioOutput::MediaPlayer2AudioOutput(int32_t sessionId, uid_t uid, int pid,
- const jobject attributes)
- : mCallback(nullptr),
- mCallbackCookie(nullptr),
- mCallbackData(nullptr),
- mVolume(1.0),
- mPlaybackRate(AUDIO_PLAYBACK_RATE_DEFAULT),
- mSampleRateHz(0),
- mMsecsPerFrame(0),
- mFrameSize(0),
- mSessionId(sessionId),
- mUid(uid),
- mPid(pid),
- mSendLevel(0.0),
- mAuxEffectId(0),
- mFlags(AUDIO_OUTPUT_FLAG_NONE) {
- ALOGV("MediaPlayer2AudioOutput(%d)", sessionId);
-
- if (attributes != nullptr) {
- mAttributes = new JObjectHolder(attributes);
- }
-
- setMinBufferCount();
- mRoutingDelegates.clear();
-}
-
-MediaPlayer2AudioOutput::~MediaPlayer2AudioOutput() {
- close();
- delete mCallbackData;
-}
-
-//static
-void MediaPlayer2AudioOutput::setMinBufferCount() {
- char value[PROPERTY_VALUE_MAX];
- if (property_get("ro.kernel.qemu", value, 0)) {
- mIsOnEmulator = true;
- mMinBufferCount = 12; // to prevent systematic buffer underrun for emulator
- }
-}
-
-// static
-bool MediaPlayer2AudioOutput::isOnEmulator() {
- setMinBufferCount(); // benign race wrt other threads
- return mIsOnEmulator;
-}
-
-// static
-int MediaPlayer2AudioOutput::getMinBufferCount() {
- setMinBufferCount(); // benign race wrt other threads
- return mMinBufferCount;
-}
-
-ssize_t MediaPlayer2AudioOutput::bufferSize() const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == nullptr) {
- return NO_INIT;
- }
- return mJAudioTrack->frameCount() * mFrameSize;
-}
-
-ssize_t MediaPlayer2AudioOutput::frameCount() const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == nullptr) {
- return NO_INIT;
- }
- return mJAudioTrack->frameCount();
-}
-
-ssize_t MediaPlayer2AudioOutput::channelCount() const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == nullptr) {
- return NO_INIT;
- }
- return mJAudioTrack->channelCount();
-}
-
-ssize_t MediaPlayer2AudioOutput::frameSize() const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == nullptr) {
- return NO_INIT;
- }
- return mFrameSize;
-}
-
-uint32_t MediaPlayer2AudioOutput::latency () const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == nullptr) {
- return 0;
- }
- return mJAudioTrack->latency();
-}
-
-float MediaPlayer2AudioOutput::msecsPerFrame() const {
- Mutex::Autolock lock(mLock);
- return mMsecsPerFrame;
-}
-
-status_t MediaPlayer2AudioOutput::getPosition(uint32_t *position) const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == nullptr) {
- return NO_INIT;
- }
- return mJAudioTrack->getPosition(position);
-}
-
-status_t MediaPlayer2AudioOutput::getTimestamp(AudioTimestamp &ts) const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == nullptr) {
- return NO_INIT;
- }
- return mJAudioTrack->getTimestamp(ts);
-}
-
-// TODO: Remove unnecessary calls to getPlayedOutDurationUs()
-// as it acquires locks and may query the audio driver.
-//
-// Some calls could conceivably retrieve extrapolated data instead of
-// accessing getTimestamp() or getPosition() every time a data buffer with
-// a media time is received.
-//
-// Calculate duration of played samples if played at normal rate (i.e., 1.0).
-int64_t MediaPlayer2AudioOutput::getPlayedOutDurationUs(int64_t nowUs) const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == nullptr || mSampleRateHz == 0) {
- return 0;
- }
-
- uint32_t numFramesPlayed;
- int64_t numFramesPlayedAtUs;
- AudioTimestamp ts;
-
- status_t res = mJAudioTrack->getTimestamp(ts);
-
- if (res == OK) { // case 1: mixing audio tracks and offloaded tracks.
- numFramesPlayed = ts.mPosition;
- numFramesPlayedAtUs = ts.mTime.tv_sec * 1000000LL + ts.mTime.tv_nsec / 1000;
- //ALOGD("getTimestamp: OK %d %lld", numFramesPlayed, (long long)numFramesPlayedAtUs);
- } else { // case 2: transitory state on start of a new track
- // case 3: transitory at new track or audio fast tracks.
- numFramesPlayed = 0;
- numFramesPlayedAtUs = nowUs;
- //ALOGD("getTimestamp: WOULD_BLOCK %d %lld",
- // numFramesPlayed, (long long)numFramesPlayedAtUs);
- }
-
- // CHECK_EQ(numFramesPlayed & (1 << 31), 0); // can't be negative until 12.4 hrs, test
- // TODO: remove the (int32_t) casting below as it may overflow at 12.4 hours.
- int64_t durationUs = (int64_t)((int32_t)numFramesPlayed * 1000000LL / mSampleRateHz)
- + nowUs - numFramesPlayedAtUs;
- if (durationUs < 0) {
- // Occurs when numFramesPlayed position is very small and the following:
- // (1) In case 1, the time nowUs is computed before getTimestamp() is called and
- // numFramesPlayedAtUs is greater than nowUs by time more than numFramesPlayed.
- // (2) In case 3, using getPosition and adding mAudioSink->latency() to
- // numFramesPlayedAtUs, by a time amount greater than numFramesPlayed.
- //
- // Both of these are transitory conditions.
- ALOGV("getPlayedOutDurationUs: negative duration %lld set to zero", (long long)durationUs);
- durationUs = 0;
- }
- ALOGV("getPlayedOutDurationUs(%lld) nowUs(%lld) frames(%u) framesAt(%lld)",
- (long long)durationUs, (long long)nowUs,
- numFramesPlayed, (long long)numFramesPlayedAtUs);
- return durationUs;
-}
-
-status_t MediaPlayer2AudioOutput::getFramesWritten(uint32_t *frameswritten) const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == nullptr) {
- return NO_INIT;
- }
- ExtendedTimestamp ets;
- status_t status = mJAudioTrack->getTimestamp(&ets);
- if (status == OK || status == WOULD_BLOCK) {
- *frameswritten = (uint32_t)ets.mPosition[ExtendedTimestamp::LOCATION_CLIENT];
- }
- return status;
-}
-
-void MediaPlayer2AudioOutput::setAudioAttributes(const jobject attributes) {
- Mutex::Autolock lock(mLock);
- mAttributes = (attributes == nullptr) ? nullptr : new JObjectHolder(attributes);
-}
-
-audio_stream_type_t MediaPlayer2AudioOutput::getAudioStreamType() const {
- ALOGV("getAudioStreamType");
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == nullptr) {
- return AUDIO_STREAM_DEFAULT;
- }
- return mJAudioTrack->getAudioStreamType();
-}
-
-void MediaPlayer2AudioOutput::close_l() {
- mJAudioTrack.clear();
-}
-
-status_t MediaPlayer2AudioOutput::open(
- uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
- audio_format_t format,
- AudioCallback cb, void *cookie,
- audio_output_flags_t flags,
- const audio_offload_info_t *offloadInfo,
- uint32_t suggestedFrameCount) {
- ALOGV("open(%u, %d, 0x%x, 0x%x, %d 0x%x)", sampleRate, channelCount, channelMask,
- format, mSessionId, flags);
-
- // offloading is only supported in callback mode for now.
- // offloadInfo must be present if offload flag is set
- if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) &&
- ((cb == nullptr) || (offloadInfo == nullptr))) {
- return BAD_VALUE;
- }
-
- // compute frame count for the AudioTrack internal buffer
- const size_t frameCount =
- ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) ? 0 : suggestedFrameCount;
-
- if (channelMask == CHANNEL_MASK_USE_CHANNEL_ORDER) {
- channelMask = audio_channel_out_mask_from_count(channelCount);
- if (0 == channelMask) {
- ALOGE("open() error, can\'t derive mask for %d audio channels", channelCount);
- return NO_INIT;
- }
- }
-
- Mutex::Autolock lock(mLock);
- mCallback = cb;
- mCallbackCookie = cookie;
-
- sp<JAudioTrack> jT;
- CallbackData *newcbd = nullptr;
-
- ALOGV("creating new JAudioTrack");
-
- if (mCallback != nullptr) {
- newcbd = new CallbackData(this);
- jT = new JAudioTrack(
- sampleRate,
- format,
- channelMask,
- CallbackWrapper,
- newcbd,
- frameCount,
- mSessionId,
- mAttributes != nullptr ? mAttributes->getJObject() : nullptr,
- 1.0f); // default value for maxRequiredSpeed
- } else {
- // TODO: Due to buffer memory concerns, we use a max target playback speed
- // based on mPlaybackRate at the time of open (instead of kMaxRequiredSpeed),
- // also clamping the target speed to 1.0 <= targetSpeed <= kMaxRequiredSpeed.
- const float targetSpeed =
- std::min(std::max(mPlaybackRate.mSpeed, 1.0f), kMaxRequiredSpeed);
- ALOGW_IF(targetSpeed != mPlaybackRate.mSpeed,
- "track target speed:%f clamped from playback speed:%f",
- targetSpeed, mPlaybackRate.mSpeed);
- jT = new JAudioTrack(
- sampleRate,
- format,
- channelMask,
- nullptr,
- nullptr,
- frameCount,
- mSessionId,
- mAttributes != nullptr ? mAttributes->getJObject() : nullptr,
- targetSpeed);
- }
-
- if (jT == 0) {
- ALOGE("Unable to create audio track");
- delete newcbd;
- // t goes out of scope, so reference count drops to zero
- return NO_INIT;
- }
-
- CHECK((jT != nullptr) && ((mCallback == nullptr) || (newcbd != nullptr)));
-
- mCallbackData = newcbd;
- ALOGV("setVolume");
- jT->setVolume(mVolume);
-
- mSampleRateHz = sampleRate;
- mFlags = flags;
- mMsecsPerFrame = 1E3f / (mPlaybackRate.mSpeed * sampleRate);
- mFrameSize = jT->frameSize();
- mJAudioTrack = jT;
-
- return updateTrack_l();
-}
-
-status_t MediaPlayer2AudioOutput::updateTrack_l() {
- if (mJAudioTrack == nullptr) {
- return NO_ERROR;
- }
-
- status_t res = NO_ERROR;
- // Note some output devices may give us a direct track even though we don't specify it.
- // Example: Line application b/17459982.
- if ((mJAudioTrack->getFlags()
- & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD | AUDIO_OUTPUT_FLAG_DIRECT)) == 0) {
- res = mJAudioTrack->setPlaybackRate(mPlaybackRate);
- if (res == NO_ERROR) {
- mJAudioTrack->setAuxEffectSendLevel(mSendLevel);
- res = mJAudioTrack->attachAuxEffect(mAuxEffectId);
- }
- }
- if (mPreferredDevice != nullptr) {
- mJAudioTrack->setPreferredDevice(mPreferredDevice->getJObject());
- }
-
- mJAudioTrack->registerRoutingDelegates(mRoutingDelegates);
-
- ALOGV("updateTrack_l() DONE status %d", res);
- return res;
-}
-
-status_t MediaPlayer2AudioOutput::start() {
- ALOGV("start");
- Mutex::Autolock lock(mLock);
- if (mCallbackData != nullptr) {
- mCallbackData->endTrackSwitch();
- }
- if (mJAudioTrack != nullptr) {
- mJAudioTrack->setVolume(mVolume);
- mJAudioTrack->setAuxEffectSendLevel(mSendLevel);
- status_t status = mJAudioTrack->start();
- return status;
- }
- return NO_INIT;
-}
-
-ssize_t MediaPlayer2AudioOutput::write(const void* buffer, size_t size, bool blocking) {
- Mutex::Autolock lock(mLock);
- LOG_ALWAYS_FATAL_IF(mCallback != nullptr, "Don't call write if supplying a callback.");
-
- //ALOGV("write(%p, %u)", buffer, size);
- if (mJAudioTrack != nullptr) {
- return mJAudioTrack->write(buffer, size, blocking);
- }
- return NO_INIT;
-}
-
-void MediaPlayer2AudioOutput::stop() {
- ALOGV("stop");
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack != nullptr) {
- mJAudioTrack->stop();
- }
-}
-
-void MediaPlayer2AudioOutput::flush() {
- ALOGV("flush");
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack != nullptr) {
- mJAudioTrack->flush();
- }
-}
-
-void MediaPlayer2AudioOutput::pause() {
- ALOGV("pause");
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack != nullptr) {
- mJAudioTrack->pause();
- }
-}
-
-void MediaPlayer2AudioOutput::close() {
- ALOGV("close");
- sp<JAudioTrack> track;
- {
- Mutex::Autolock lock(mLock);
- track = mJAudioTrack;
- close_l(); // clears mJAudioTrack
- }
- // destruction of the track occurs outside of mutex.
-}
-
-void MediaPlayer2AudioOutput::setVolume(float volume) {
- ALOGV("setVolume(%f)", volume);
- Mutex::Autolock lock(mLock);
- mVolume = volume;
- if (mJAudioTrack != nullptr) {
- mJAudioTrack->setVolume(volume);
- }
-}
-
-status_t MediaPlayer2AudioOutput::setPlaybackRate(const AudioPlaybackRate &rate) {
- ALOGV("setPlaybackRate(%f %f %d %d)",
- rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode);
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == 0) {
- // remember rate so that we can set it when the track is opened
- mPlaybackRate = rate;
- return OK;
- }
- status_t res = mJAudioTrack->setPlaybackRate(rate);
- if (res != NO_ERROR) {
- return res;
- }
- // rate.mSpeed is always greater than 0 if setPlaybackRate succeeded
- CHECK_GT(rate.mSpeed, 0.f);
- mPlaybackRate = rate;
- if (mSampleRateHz != 0) {
- mMsecsPerFrame = 1E3f / (rate.mSpeed * mSampleRateHz);
- }
- return res;
-}
-
-status_t MediaPlayer2AudioOutput::getPlaybackRate(AudioPlaybackRate *rate) {
- ALOGV("getPlaybackRate");
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == 0) {
- return NO_INIT;
- }
- *rate = mJAudioTrack->getPlaybackRate();
- return NO_ERROR;
-}
-
-status_t MediaPlayer2AudioOutput::setAuxEffectSendLevel(float level) {
- ALOGV("setAuxEffectSendLevel(%f)", level);
- Mutex::Autolock lock(mLock);
- mSendLevel = level;
- if (mJAudioTrack != nullptr) {
- return mJAudioTrack->setAuxEffectSendLevel(level);
- }
- return NO_ERROR;
-}
-
-status_t MediaPlayer2AudioOutput::attachAuxEffect(int effectId) {
- ALOGV("attachAuxEffect(%d)", effectId);
- Mutex::Autolock lock(mLock);
- mAuxEffectId = effectId;
- if (mJAudioTrack != nullptr) {
- return mJAudioTrack->attachAuxEffect(effectId);
- }
- return NO_ERROR;
-}
-
-status_t MediaPlayer2AudioOutput::setPreferredDevice(jobject device) {
- ALOGV("setPreferredDevice");
- Mutex::Autolock lock(mLock);
- status_t ret = NO_ERROR;
- if (mJAudioTrack != nullptr) {
- ret = mJAudioTrack->setPreferredDevice(device);
- }
- if (ret == NO_ERROR) {
- mPreferredDevice = new JObjectHolder(device);
- }
- return ret;
-}
-
-jobject MediaPlayer2AudioOutput::getRoutedDevice() {
- ALOGV("getRoutedDevice");
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack != nullptr) {
- return mJAudioTrack->getRoutedDevice();
- }
- return nullptr;
-}
-
-status_t MediaPlayer2AudioOutput::addAudioDeviceCallback(jobject jRoutingDelegate) {
- ALOGV("addAudioDeviceCallback");
- Mutex::Autolock lock(mLock);
- jobject listener = JAudioTrack::getListener(jRoutingDelegate);
- if (JAudioTrack::findByKey(mRoutingDelegates, listener) == nullptr) {
- sp<JObjectHolder> listenerHolder = new JObjectHolder(listener);
- jobject handler = JAudioTrack::getHandler(jRoutingDelegate);
- sp<JObjectHolder> routingDelegateHolder = new JObjectHolder(jRoutingDelegate);
-
- mRoutingDelegates.push_back(std::pair<sp<JObjectHolder>, sp<JObjectHolder>>(
- listenerHolder, routingDelegateHolder));
-
- if (mJAudioTrack != nullptr) {
- return mJAudioTrack->addAudioDeviceCallback(
- routingDelegateHolder->getJObject(), handler);
- }
- }
- return NO_ERROR;
-}
-
-status_t MediaPlayer2AudioOutput::removeAudioDeviceCallback(jobject listener) {
- ALOGV("removeAudioDeviceCallback");
- Mutex::Autolock lock(mLock);
- jobject routingDelegate = nullptr;
- if ((routingDelegate = JAudioTrack::findByKey(mRoutingDelegates, listener)) != nullptr) {
- if (mJAudioTrack != nullptr) {
- mJAudioTrack->removeAudioDeviceCallback(routingDelegate);
- }
- JAudioTrack::eraseByKey(mRoutingDelegates, listener);
- }
- return NO_ERROR;
-}
-
-// static
-void MediaPlayer2AudioOutput::CallbackWrapper(
- int event, void *cookie, void *info) {
- //ALOGV("callbackwrapper");
- CallbackData *data = (CallbackData*)cookie;
- // lock to ensure we aren't caught in the middle of a track switch.
- data->lock();
- MediaPlayer2AudioOutput *me = data->getOutput();
- JAudioTrack::Buffer *buffer = (JAudioTrack::Buffer *)info;
- if (me == nullptr) {
- // no output set, likely because the track was scheduled to be reused
- // by another player, but the format turned out to be incompatible.
- data->unlock();
- if (buffer != nullptr) {
- buffer->mSize = 0;
- }
- return;
- }
-
- switch(event) {
- case JAudioTrack::EVENT_MORE_DATA: {
- size_t actualSize = (*me->mCallback)(
- me, buffer->mData, buffer->mSize, me->mCallbackCookie,
- CB_EVENT_FILL_BUFFER);
-
- // Log when no data is returned from the callback.
- // (1) We may have no data (especially with network streaming sources).
- // (2) We may have reached the EOS and the audio track is not stopped yet.
- // Note that AwesomePlayer/AudioPlayer will only return zero size when it reaches the EOS.
- // NuPlayer2Renderer will return zero when it doesn't have data (it doesn't block to fill).
- //
- // This is a benign busy-wait, with the next data request generated 10 ms or more later;
- // nevertheless for power reasons, we don't want to see too many of these.
-
- ALOGV_IF(actualSize == 0 && buffer->mSize > 0, "callbackwrapper: empty buffer returned");
-
- buffer->mSize = actualSize;
- } break;
-
- case JAudioTrack::EVENT_STREAM_END:
- // currently only occurs for offloaded callbacks
- ALOGV("callbackwrapper: deliver EVENT_STREAM_END");
- (*me->mCallback)(me, nullptr /* buffer */, 0 /* size */,
- me->mCallbackCookie, CB_EVENT_STREAM_END);
- break;
-
- case JAudioTrack::EVENT_NEW_IAUDIOTRACK :
- ALOGV("callbackwrapper: deliver EVENT_TEAR_DOWN");
- (*me->mCallback)(me, nullptr /* buffer */, 0 /* size */,
- me->mCallbackCookie, CB_EVENT_TEAR_DOWN);
- break;
-
- case JAudioTrack::EVENT_UNDERRUN:
- // This occurs when there is no data available, typically
- // when there is a failure to supply data to the AudioTrack. It can also
- // occur in non-offloaded mode when the audio device comes out of standby.
- //
- // If an AudioTrack underruns it outputs silence. Since this happens suddenly
- // it may sound like an audible pop or glitch.
- //
- // The underrun event is sent once per track underrun; the condition is reset
- // when more data is sent to the AudioTrack.
- ALOGD("callbackwrapper: EVENT_UNDERRUN (discarded)");
- break;
-
- default:
- ALOGE("received unknown event type: %d inside CallbackWrapper !", event);
- }
-
- data->unlock();
-}
-
-int32_t MediaPlayer2AudioOutput::getSessionId() const {
- Mutex::Autolock lock(mLock);
- return mSessionId;
-}
-
-void MediaPlayer2AudioOutput::setSessionId(const int32_t sessionId) {
- Mutex::Autolock lock(mLock);
- mSessionId = sessionId;
-}
-
-uint32_t MediaPlayer2AudioOutput::getSampleRate() const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == 0) {
- return 0;
- }
- return mJAudioTrack->getSampleRate();
-}
-
-int64_t MediaPlayer2AudioOutput::getBufferDurationInUs() const {
- Mutex::Autolock lock(mLock);
- if (mJAudioTrack == 0) {
- return 0;
- }
- int64_t duration;
- if (mJAudioTrack->getBufferDurationInUs(&duration) != OK) {
- return 0;
- }
- return duration;
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h b/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h
deleted file mode 100644
index 2ed4632..0000000
--- a/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h
+++ /dev/null
@@ -1,461 +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.
- */
-
-#ifndef ANDROID_JAUDIOTRACK_H
-#define ANDROID_JAUDIOTRACK_H
-
-#include <utility>
-#include <jni.h>
-#include <media/AudioResamplerPublic.h>
-#include <media/AudioSystem.h>
-#include <media/VolumeShaper.h>
-#include <system/audio.h>
-#include <utils/Errors.h>
-#include <utils/Vector.h>
-#include <mediaplayer2/JObjectHolder.h>
-#include <media/AudioTimestamp.h> // It has dependency on audio.h/Errors.h, but doesn't
- // include them in it. Therefore it is included here at last.
-
-namespace android {
-
-class JAudioTrack : public RefBase {
-public:
-
- /* Events used by AudioTrack callback function (callback_t).
- * Keep in sync with frameworks/base/media/java/android/media/AudioTrack.java NATIVE_EVENT_*.
- */
- enum event_type {
- EVENT_MORE_DATA = 0, // Request to write more data to buffer.
- EVENT_UNDERRUN = 1, // Buffer underrun occurred. This will not occur for
- // static tracks.
- EVENT_NEW_IAUDIOTRACK = 6, // IAudioTrack was re-created, either due to re-routing and
- // voluntary invalidation by mediaserver, or mediaserver crash.
- EVENT_STREAM_END = 7, // Sent after all the buffers queued in AF and HW are played
- // back (after stop is called) for an offloaded track.
- };
-
- class Buffer
- {
- public:
- size_t mSize; // input/output in bytes.
- void* mData; // pointer to the audio data.
- };
-
- /* As a convenience, if a callback is supplied, a handler thread
- * is automatically created with the appropriate priority. This thread
- * invokes the callback when a new buffer becomes available or various conditions occur.
- *
- * Parameters:
- *
- * event: type of event notified (see enum AudioTrack::event_type).
- * user: Pointer to context for use by the callback receiver.
- * info: Pointer to optional parameter according to event type:
- * - EVENT_MORE_DATA: pointer to JAudioTrack::Buffer struct. The callback must not
- * write more bytes than indicated by 'size' field and update 'size' if fewer bytes
- * are written.
- * - EVENT_NEW_IAUDIOTRACK: unused.
- * - EVENT_STREAM_END: unused.
- */
-
- typedef void (*callback_t)(int event, void* user, void *info);
-
- /* Creates an JAudioTrack object for non-offload mode.
- * Once created, the track needs to be started before it can be used.
- * Unspecified values are set to appropriate default values.
- *
- * Parameters:
- *
- * streamType: Select the type of audio stream this track is attached to
- * (e.g. AUDIO_STREAM_MUSIC).
- * sampleRate: Data source sampling rate in Hz. Zero means to use the sink sample rate.
- * A non-zero value must be specified if AUDIO_OUTPUT_FLAG_DIRECT is set.
- * 0 will not work with current policy implementation for direct output
- * selection where an exact match is needed for sampling rate.
- * (TODO: Check direct output after flags can be used in Java AudioTrack.)
- * format: Audio format. For mixed tracks, any PCM format supported by server is OK.
- * For direct and offloaded tracks, the possible format(s) depends on the
- * output sink.
- * (TODO: How can we check whether a format is supported?)
- * channelMask: Channel mask, such that audio_is_output_channel(channelMask) is true.
- * cbf: Callback function. If not null, this function is called periodically
- * to provide new data and inform of marker, position updates, etc.
- * user: Context for use by the callback receiver.
- * frameCount: Minimum size of track PCM buffer in frames. This defines the
- * application's contribution to the latency of the track.
- * The actual size selected by the JAudioTrack could be larger if the
- * requested size is not compatible with current audio HAL configuration.
- * Zero means to use a default value.
- * sessionId: Specific session ID, or zero to use default.
- * pAttributes: If not NULL, supersedes streamType for use case selection.
- * maxRequiredSpeed: For PCM tracks, this creates an appropriate buffer size that will allow
- * maxRequiredSpeed playback. Values less than 1.0f and greater than
- * AUDIO_TIMESTRETCH_SPEED_MAX will be clamped. For non-PCM tracks
- * and direct or offloaded tracks, this parameter is ignored.
- * (TODO: Handle this after offload / direct track is supported.)
- *
- * TODO: Revive removed arguments after offload mode is supported.
- */
- JAudioTrack(uint32_t sampleRate,
- audio_format_t format,
- audio_channel_mask_t channelMask,
- callback_t cbf,
- void* user,
- size_t frameCount = 0,
- int32_t sessionId = AUDIO_SESSION_ALLOCATE,
- const jobject pAttributes = NULL,
- float maxRequiredSpeed = 1.0f);
-
- /*
- // Q. May be used in AudioTrack.setPreferredDevice(AudioDeviceInfo)?
- audio_port_handle_t selectedDeviceId,
-
- // TODO: No place to use these values.
- int32_t notificationFrames,
- const audio_offload_info_t *offloadInfo,
- */
-
- virtual ~JAudioTrack();
-
- size_t frameCount();
- size_t channelCount();
-
- /* Returns this track's estimated latency in milliseconds.
- * This includes the latency due to AudioTrack buffer size, AudioMixer (if any)
- * and audio hardware driver.
- */
- uint32_t latency();
-
- /* Return the total number of frames played since playback start.
- * The counter will wrap (overflow) periodically, e.g. every ~27 hours at 44.1 kHz.
- * It is reset to zero by flush(), reload(), and stop().
- *
- * Parameters:
- *
- * position: Address where to return play head position.
- *
- * Returned status (from utils/Errors.h) can be:
- * - NO_ERROR: successful operation
- * - BAD_VALUE: position is NULL
- */
- status_t getPosition(uint32_t *position);
-
- // TODO: Does this comment apply same to Java AudioTrack::getTimestamp?
- // Changed the return type from status_t to bool, since Java AudioTrack::getTimestamp returns
- // boolean. Will Java getTimestampWithStatus() be public?
- /* Poll for a timestamp on demand.
- * Use if EVENT_NEW_TIMESTAMP is not delivered often enough for your needs,
- * or if you need to get the most recent timestamp outside of the event callback handler.
- * Caution: calling this method too often may be inefficient;
- * if you need a high resolution mapping between frame position and presentation time,
- * consider implementing that at application level, based on the low resolution timestamps.
- * Returns NO_ERROR if timestamp is valid.
- * NO_INIT if finds error, and timestamp parameter will be undefined on return.
- */
- status_t getTimestamp(AudioTimestamp& timestamp);
-
- // TODO: This doc is just copied from AudioTrack.h. Revise it after implemenation.
- /* Return the extended timestamp, with additional timebase info and improved drain behavior.
- *
- * This is similar to the AudioTrack.java API:
- * getTimestamp(@NonNull AudioTimestamp timestamp, @AudioTimestamp.Timebase int timebase)
- *
- * Some differences between this method and the getTimestamp(AudioTimestamp& timestamp) method
- *
- * 1. stop() by itself does not reset the frame position.
- * A following start() resets the frame position to 0.
- * 2. flush() by itself does not reset the frame position.
- * The frame position advances by the number of frames flushed,
- * when the first frame after flush reaches the audio sink.
- * 3. BOOTTIME clock offsets are provided to help synchronize with
- * non-audio streams, e.g. sensor data.
- * 4. Position is returned with 64 bits of resolution.
- *
- * Parameters:
- * timestamp: A pointer to the caller allocated ExtendedTimestamp.
- *
- * Returns NO_ERROR on success; timestamp is filled with valid data.
- * BAD_VALUE if timestamp is NULL.
- * WOULD_BLOCK if called immediately after start() when the number
- * of frames consumed is less than the
- * overall hardware latency to physical output. In WOULD_BLOCK cases,
- * one might poll again, or use getPosition(), or use 0 position and
- * current time for the timestamp.
- * If WOULD_BLOCK is returned, the timestamp is still
- * modified with the LOCATION_CLIENT portion filled.
- * DEAD_OBJECT if AudioFlinger dies or the output device changes and
- * the track cannot be automatically restored.
- * The application needs to recreate the AudioTrack
- * because the audio device changed or AudioFlinger died.
- * This typically occurs for direct or offloaded tracks
- * or if mDoNotReconnect is true.
- * INVALID_OPERATION if called on a offloaded or direct track.
- * Use getTimestamp(AudioTimestamp& timestamp) instead.
- */
- status_t getTimestamp(ExtendedTimestamp *timestamp);
-
- /* Set source playback rate for timestretch
- * 1.0 is normal speed: < 1.0 is slower, > 1.0 is faster
- * 1.0 is normal pitch: < 1.0 is lower pitch, > 1.0 is higher pitch
- *
- * AUDIO_TIMESTRETCH_SPEED_MIN <= speed <= AUDIO_TIMESTRETCH_SPEED_MAX
- * AUDIO_TIMESTRETCH_PITCH_MIN <= pitch <= AUDIO_TIMESTRETCH_PITCH_MAX
- *
- * Speed increases the playback rate of media, but does not alter pitch.
- * Pitch increases the "tonal frequency" of media, but does not affect the playback rate.
- */
- status_t setPlaybackRate(const AudioPlaybackRate &playbackRate);
-
- /* Return current playback rate */
- const AudioPlaybackRate getPlaybackRate();
-
- /* Sets the volume shaper object */
- media::VolumeShaper::Status applyVolumeShaper(
- const sp<media::VolumeShaper::Configuration>& configuration,
- const sp<media::VolumeShaper::Operation>& operation);
-
- /* Set the send level for this track. An auxiliary effect should be attached
- * to the track with attachEffect(). Level must be >= 0.0 and <= 1.0.
- */
- status_t setAuxEffectSendLevel(float level);
-
- /* Attach track auxiliary output to specified effect. Use effectId = 0
- * to detach track from effect.
- *
- * Parameters:
- *
- * effectId: effectId obtained from AudioEffect::id().
- *
- * Returned status (from utils/Errors.h) can be:
- * - NO_ERROR: successful operation
- * - INVALID_OPERATION: The effect is not an auxiliary effect.
- * - BAD_VALUE: The specified effect ID is invalid.
- */
- status_t attachAuxEffect(int effectId);
-
- /* Set volume for this track, mostly used for games' sound effects
- * left and right volumes. Levels must be >= 0.0 and <= 1.0.
- * This is the older API. New applications should use setVolume(float) when possible.
- */
- status_t setVolume(float left, float right);
-
- /* Set volume for all channels. This is the preferred API for new applications,
- * especially for multi-channel content.
- */
- status_t setVolume(float volume);
-
- // TODO: Does this comment equally apply to the Java AudioTrack::play()?
- /* After it's created the track is not active. Call start() to
- * make it active. If set, the callback will start being called.
- * If the track was previously paused, volume is ramped up over the first mix buffer.
- */
- status_t start();
-
- // TODO: Does this comment still applies? It seems not. (obtainBuffer, AudioFlinger, ...)
- /* As a convenience we provide a write() interface to the audio buffer.
- * Input parameter 'size' is in byte units.
- * This is implemented on top of obtainBuffer/releaseBuffer. For best
- * performance use callbacks. Returns actual number of bytes written >= 0,
- * or one of the following negative status codes:
- * INVALID_OPERATION AudioTrack is configured for static buffer or streaming mode
- * BAD_VALUE size is invalid
- * WOULD_BLOCK when obtainBuffer() returns same, or
- * AudioTrack was stopped during the write
- * DEAD_OBJECT when AudioFlinger dies or the output device changes and
- * the track cannot be automatically restored.
- * The application needs to recreate the AudioTrack
- * because the audio device changed or AudioFlinger died.
- * This typically occurs for direct or offload tracks
- * or if mDoNotReconnect is true.
- * or any other error code returned by IAudioTrack::start() or restoreTrack_l().
- * Default behavior is to only return when all data has been transferred. Set 'blocking' to
- * false for the method to return immediately without waiting to try multiple times to write
- * the full content of the buffer.
- */
- ssize_t write(const void* buffer, size_t size, bool blocking = true);
-
- // TODO: Does this comment equally apply to the Java AudioTrack::stop()?
- /* Stop a track.
- * In static buffer mode, the track is stopped immediately.
- * In streaming mode, the callback will cease being called. Note that obtainBuffer() still
- * works and will fill up buffers until the pool is exhausted, and then will return WOULD_BLOCK.
- * In streaming mode the stop does not occur immediately: any data remaining in the buffer
- * is first drained, mixed, and output, and only then is the track marked as stopped.
- */
- void stop();
- bool stopped() const;
-
- // TODO: Does this comment equally apply to the Java AudioTrack::flush()?
- /* Flush a stopped or paused track. All previously buffered data is discarded immediately.
- * This has the effect of draining the buffers without mixing or output.
- * Flush is intended for streaming mode, for example before switching to non-contiguous content.
- * This function is a no-op if the track is not stopped or paused, or uses a static buffer.
- */
- void flush();
-
- // TODO: Does this comment equally apply to the Java AudioTrack::pause()?
- // At least we are not using obtainBuffer.
- /* Pause a track. After pause, the callback will cease being called and
- * obtainBuffer returns WOULD_BLOCK. Note that obtainBuffer() still works
- * and will fill up buffers until the pool is exhausted.
- * Volume is ramped down over the next mix buffer following the pause request,
- * and then the track is marked as paused. It can be resumed with ramp up by start().
- */
- void pause();
-
- bool isPlaying() const;
-
- /* Return current source sample rate in Hz.
- * If specified as zero in constructor, this will be the sink sample rate.
- */
- uint32_t getSampleRate();
-
- /* Returns the buffer duration in microseconds at current playback rate. */
- status_t getBufferDurationInUs(int64_t *duration);
-
- audio_format_t format();
-
- size_t frameSize();
-
- /*
- * Dumps the state of an audio track.
- * Not a general-purpose API; intended only for use by media player service to dump its tracks.
- */
- status_t dump(int fd, const Vector<String16>& args) const;
-
- /* Returns the AudioDeviceInfo used by the output to which this AudioTrack is
- * attached.
- */
- jobject getRoutedDevice();
-
- /* Returns the ID of the audio session this AudioTrack belongs to. */
- int32_t getAudioSessionId();
-
- /* Sets the preferred audio device to use for output of this AudioTrack.
- *
- * Parameters:
- * Device: an AudioDeviceInfo object.
- *
- * Returned value:
- * - NO_ERROR: successful operation
- * - BAD_VALUE: failed to set the device
- */
- status_t setPreferredDevice(jobject device);
-
- // TODO: Add AUDIO_OUTPUT_FLAG_DIRECT when it is possible to check.
- // TODO: Add AUDIO_FLAG_HW_AV_SYNC when it is possible to check.
- /* Returns the flags */
- audio_output_flags_t getFlags() const { return mFlags; }
-
- /* We don't keep stream type here,
- * instead, we keep attributes and call getVolumeControlStream() to get stream type
- */
- audio_stream_type_t getAudioStreamType();
-
- /* Obtain the pending duration in milliseconds for playback of pure PCM data remaining in
- * AudioTrack.
- *
- * Returns NO_ERROR if successful.
- * INVALID_OPERATION if the AudioTrack does not contain pure PCM data.
- * BAD_VALUE if msec is nullptr.
- */
- status_t pendingDuration(int32_t *msec);
-
- /* Adds an AudioDeviceCallback. The caller will be notified when the audio device to which this
- * AudioTrack is routed is updated.
- * Replaces any previously installed callback.
- *
- * Parameters:
- * Listener: the listener to receive notification of rerouting events.
- * Handler: the handler to handler the rerouting events.
- *
- * Returns NO_ERROR if successful.
- * (TODO) INVALID_OPERATION if the same callback is already installed.
- * (TODO) NO_INIT or PREMISSION_DENIED if AudioFlinger service is not reachable
- * (TODO) BAD_VALUE if the callback is NULL
- */
- status_t addAudioDeviceCallback(jobject listener, jobject rd);
-
- /* Removes an AudioDeviceCallback.
- *
- * Parameters:
- * Listener: the listener to receive notification of rerouting events.
- *
- * Returns NO_ERROR if successful.
- * (TODO) INVALID_OPERATION if the callback is not installed
- * (TODO) BAD_VALUE if the callback is NULL
- */
- status_t removeAudioDeviceCallback(jobject listener);
-
- /* Register all backed-up routing delegates.
- *
- * Parameters:
- * routingDelegates: backed-up routing delegates
- *
- */
- void registerRoutingDelegates(
- Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>>& routingDelegates);
-
- /* get listener from RoutingDelegate object
- */
- static jobject getListener(const jobject routingDelegateObj);
-
- /* get handler from RoutingDelegate object
- */
- static jobject getHandler(const jobject routingDelegateObj);
-
- /*
- * Parameters:
- * map and key
- *
- * Returns value if key is in the map
- * nullptr if key is not in the map
- */
- static jobject findByKey(
- Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>>& mp, const jobject key);
-
- /*
- * Parameters:
- * map and key
- */
- static void eraseByKey(
- Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>>& mp, const jobject key);
-
-private:
- audio_output_flags_t mFlags;
-
- jclass mAudioTrackCls;
- jobject mAudioTrackObj;
-
- /* Creates a Java VolumeShaper.Configuration object from VolumeShaper::Configuration */
- jobject createVolumeShaperConfigurationObj(
- const sp<media::VolumeShaper::Configuration>& config);
-
- /* Creates a Java VolumeShaper.Operation object from VolumeShaper::Operation */
- jobject createVolumeShaperOperationObj(
- const sp<media::VolumeShaper::Operation>& operation);
-
- /* Creates a Java StreamEventCallback object */
- jobject createStreamEventCallback(callback_t cbf, void* user);
-
- /* Creates a Java Executor object for running a callback */
- jobject createCallbackExecutor();
-
- status_t javaToNativeStatus(int javaStatus);
-};
-
-}; // namespace android
-
-#endif // ANDROID_JAUDIOTRACK_H
diff --git a/media/libmediaplayer2/include/mediaplayer2/JMedia2HTTPConnection.h b/media/libmediaplayer2/include/mediaplayer2/JMedia2HTTPConnection.h
deleted file mode 100644
index 15f7f83..0000000
--- a/media/libmediaplayer2/include/mediaplayer2/JMedia2HTTPConnection.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _J_MEDIA2_HTTP_CONNECTION_H_
-#define _J_MEDIA2_HTTP_CONNECTION_H_
-
-#include "jni.h"
-
-#include <media/MediaHTTPConnection.h>
-#include <media/stagefright/foundation/ABase.h>
-
-namespace android {
-
-struct JMedia2HTTPConnection : public MediaHTTPConnection {
- JMedia2HTTPConnection(JNIEnv *env, jobject thiz);
-
- virtual bool connect(
- const char *uri, const KeyedVector<String8, String8> *headers) override;
-
- virtual void disconnect() override;
- virtual ssize_t readAt(off64_t offset, void *data, size_t size) override;
- virtual off64_t getSize() override;
- virtual status_t getMIMEType(String8 *mimeType) override;
- virtual status_t getUri(String8 *uri) override;
-
-protected:
- virtual ~JMedia2HTTPConnection();
-
-private:
- jobject mMedia2HTTPConnectionObj;
- jmethodID mConnectMethod;
- jmethodID mDisconnectMethod;
- jmethodID mReadAtMethod;
- jmethodID mGetSizeMethod;
- jmethodID mGetMIMETypeMethod;
- jmethodID mGetUriMethod;
-
- jbyteArray mByteArrayObj;
-
- DISALLOW_EVIL_CONSTRUCTORS(JMedia2HTTPConnection);
-};
-
-} // namespace android
-
-#endif // _J_MEDIA2_HTTP_CONNECTION_H_
diff --git a/media/libmediaplayer2/include/mediaplayer2/JMedia2HTTPService.h b/media/libmediaplayer2/include/mediaplayer2/JMedia2HTTPService.h
deleted file mode 100644
index bf61a7f..0000000
--- a/media/libmediaplayer2/include/mediaplayer2/JMedia2HTTPService.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _J_MEDIA2_HTTP_SERVICE_H_
-#define _J_MEDIA2_HTTP_SERVICE_H_
-
-#include <jni.h>
-#include <utils/RefBase.h>
-
-#include <media/MediaHTTPService.h>
-#include <media/MediaHTTPConnection.h>
-#include <media/stagefright/foundation/ABase.h>
-
-namespace android {
-
-struct JMedia2HTTPService : public MediaHTTPService {
- JMedia2HTTPService(JNIEnv *env, jobject thiz);
-
- virtual sp<MediaHTTPConnection> makeHTTPConnection() override;
-
-protected:
- virtual ~JMedia2HTTPService();
-
-private:
- jobject mMedia2HTTPServiceObj;
-
- jmethodID mMakeHTTPConnectionMethod;
-
- DISALLOW_EVIL_CONSTRUCTORS(JMedia2HTTPService);
-};
-
-} // namespace android
-
-#endif // _J_MEDIA2_HTTP_SERVICE_H_
diff --git a/media/libmediaplayer2/include/mediaplayer2/JObjectHolder.h b/media/libmediaplayer2/include/mediaplayer2/JObjectHolder.h
deleted file mode 100644
index 93d8b40..0000000
--- a/media/libmediaplayer2/include/mediaplayer2/JObjectHolder.h
+++ /dev/null
@@ -1,47 +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.
- */
-
-#ifndef JOBJECT_HOLDER_H_
-
-#define JOBJECT_HOLDER_H_
-
-#include "jni.h"
-#include <mediaplayer2/JavaVMHelper.h>
-#include <utils/RefBase.h>
-
-namespace android {
-
-// Helper class for managing global reference of jobject.
-struct JObjectHolder : public RefBase {
- JObjectHolder(jobject obj) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- mJObject = reinterpret_cast<jobject>(env->NewGlobalRef(obj));
- }
-
- virtual ~JObjectHolder() {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- env->DeleteGlobalRef(mJObject);
- }
-
- jobject getJObject() { return mJObject; }
-
-private:
- jobject mJObject;
-};
-
-} //" android
-
-#endif // JOBJECT_HOLDER_H_
diff --git a/media/libmediaplayer2/include/mediaplayer2/JavaVMHelper.h b/media/libmediaplayer2/include/mediaplayer2/JavaVMHelper.h
deleted file mode 100644
index 4b56aca..0000000
--- a/media/libmediaplayer2/include/mediaplayer2/JavaVMHelper.h
+++ /dev/null
@@ -1,41 +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.
- */
-
-#ifndef JAVA_VM_HELPER_H_
-
-#define JAVA_VM_HELPER_H_
-
-#include "jni.h"
-
-#include <atomic>
-
-namespace android {
-
-struct JavaVMHelper {
- static JNIEnv *getJNIEnv();
- static JavaVM *getJavaVM();
- static void setJavaVM(JavaVM *vm);
-
-private:
- // Once a valid JavaVM has been set, it should never be reset or changed.
- // However, as it may be accessed from multiple threads, access needs to be
- // synchronized.
- static std::atomic<JavaVM *> sJavaVM;
-};
-
-} // namespace android
-
-#endif // JAVA_VM_HELPER_H_
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
deleted file mode 100644
index f38b7cc..0000000
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
+++ /dev/null
@@ -1,188 +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.
-*/
-
-#ifndef ANDROID_MEDIAPLAYER2AUDIOOUTPUT_H
-#define ANDROID_MEDIAPLAYER2AUDIOOUTPUT_H
-
-#include <mediaplayer2/MediaPlayer2Interface.h>
-#include <mediaplayer2/JAudioTrack.h>
-#include <mediaplayer2/JObjectHolder.h>
-
-#include <utility>
-#include <utils/String16.h>
-#include <utils/Vector.h>
-
-#include "jni.h"
-
-namespace android {
-
-class AudioTrack;
-
-class MediaPlayer2AudioOutput : public MediaPlayer2Interface::AudioSink
-{
- class CallbackData;
-
-public:
- MediaPlayer2AudioOutput(int32_t sessionId,
- uid_t uid,
- int pid,
- const jobject attributes);
- virtual ~MediaPlayer2AudioOutput();
-
- virtual bool ready() const {
- return mJAudioTrack != nullptr;
- }
- virtual ssize_t bufferSize() const;
- virtual ssize_t frameCount() const;
- virtual ssize_t channelCount() const;
- virtual ssize_t frameSize() const;
- virtual uint32_t latency() const;
- virtual float msecsPerFrame() const;
- virtual status_t getPosition(uint32_t *position) const;
- virtual status_t getTimestamp(AudioTimestamp &ts) const;
- virtual int64_t getPlayedOutDurationUs(int64_t nowUs) const;
- virtual status_t getFramesWritten(uint32_t *frameswritten) const;
- virtual int32_t getSessionId() const;
- virtual void setSessionId(const int32_t id);
- virtual uint32_t getSampleRate() const;
- virtual int64_t getBufferDurationInUs() const;
-
- virtual status_t open(
- uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
- audio_format_t format,
- AudioCallback cb, void *cookie,
- audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
- const audio_offload_info_t *offloadInfo = NULL,
- uint32_t suggestedFrameCount = 0);
-
- virtual status_t start();
- virtual ssize_t write(const void* buffer, size_t size, bool blocking = true);
- virtual void stop();
- virtual void flush();
- virtual void pause();
- virtual void close();
- void setAudioAttributes(const jobject attributes);
- virtual audio_stream_type_t getAudioStreamType() const;
-
- void setVolume(float volume);
- virtual status_t setPlaybackRate(const AudioPlaybackRate& rate);
- virtual status_t getPlaybackRate(AudioPlaybackRate* rate /* nonnull */);
-
- status_t setAuxEffectSendLevel(float level);
- status_t attachAuxEffect(int effectId);
- virtual status_t dump(int fd, const Vector<String16>& args) const;
-
- static bool isOnEmulator();
- static int getMinBufferCount();
- virtual bool needsTrailingPadding() {
- return true;
- // TODO: return correct value.
- //return mNextOutput == NULL;
- }
- // AudioRouting
- virtual status_t setPreferredDevice(jobject device);
- virtual jobject getRoutedDevice();
- virtual status_t addAudioDeviceCallback(jobject routingDelegate);
- virtual status_t removeAudioDeviceCallback(jobject listener);
-
-private:
- static void setMinBufferCount();
- static void CallbackWrapper(int event, void *me, void *info);
- void deleteRecycledTrack_l();
- void close_l();
- status_t updateTrack_l();
-
- sp<JAudioTrack> mJAudioTrack;
- AudioCallback mCallback;
- void * mCallbackCookie;
- CallbackData * mCallbackData;
- sp<JObjectHolder> mAttributes;
- float mVolume;
- AudioPlaybackRate mPlaybackRate;
- uint32_t mSampleRateHz; // sample rate of the content, as set in open()
- float mMsecsPerFrame;
- size_t mFrameSize;
- int32_t mSessionId;
- uid_t mUid;
- int mPid;
- float mSendLevel;
- int mAuxEffectId;
- audio_output_flags_t mFlags;
- sp<JObjectHolder> mPreferredDevice;
- mutable Mutex mLock;
-
- // <listener, routingDelegate>
- Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>> mRoutingDelegates;
-
- // static variables below not protected by mutex
- static bool mIsOnEmulator;
- static int mMinBufferCount; // 12 for emulator; otherwise 4
-
- // CallbackData is what is passed to the AudioTrack as the "user" data.
- // We need to be able to target this to a different Output on the fly,
- // so we can't use the Output itself for this.
- class CallbackData {
- friend MediaPlayer2AudioOutput;
- public:
- explicit CallbackData(MediaPlayer2AudioOutput *cookie) {
- mData = cookie;
- mSwitching = false;
- }
- MediaPlayer2AudioOutput *getOutput() const {
- return mData;
- }
- void setOutput(MediaPlayer2AudioOutput* newcookie) {
- mData = newcookie;
- }
- // lock/unlock are used by the callback before accessing the payload of this object
- void lock() const {
- mLock.lock();
- }
- void unlock() const {
- mLock.unlock();
- }
-
- // tryBeginTrackSwitch/endTrackSwitch are used when the CallbackData is handed over
- // to the next sink.
-
- // tryBeginTrackSwitch() returns true only if it obtains the lock.
- bool tryBeginTrackSwitch() {
- LOG_ALWAYS_FATAL_IF(mSwitching, "tryBeginTrackSwitch() already called");
- if (mLock.tryLock() != OK) {
- return false;
- }
- mSwitching = true;
- return true;
- }
- void endTrackSwitch() {
- if (mSwitching) {
- mLock.unlock();
- }
- mSwitching = false;
- }
-
- private:
- MediaPlayer2AudioOutput *mData;
- mutable Mutex mLock; // a recursive mutex might make this unnecessary.
- bool mSwitching;
- DISALLOW_EVIL_CONSTRUCTORS(CallbackData);
- };
-};
-
-}; // namespace android
-
-#endif // ANDROID_MEDIAPLAYER2AUDIOOUTPUT_H
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
deleted file mode 100644
index 7804a62..0000000
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_MEDIAPLAYER2INTERFACE_H
-#define ANDROID_MEDIAPLAYER2INTERFACE_H
-
-#ifdef __cplusplus
-
-#include <sys/types.h>
-#include <utils/Errors.h>
-#include <utils/String8.h>
-#include <utils/RefBase.h>
-#include <jni.h>
-
-#include <media/AVSyncSettings.h>
-#include <media/AudioResamplerPublic.h>
-#include <media/AudioSystem.h>
-#include <media/AudioTimestamp.h>
-#include <media/BufferingSettings.h>
-#include <media/stagefright/foundation/AHandler.h>
-#include <mediaplayer2/MediaPlayer2Types.h>
-
-#include "jni.h"
-#include "mediaplayer2.pb.h"
-
-using android::media::MediaPlayer2Proto::PlayerMessage;
-
-// Fwd decl to make sure everyone agrees that the scope of struct sockaddr_in is
-// global, and not in android::
-struct sockaddr_in;
-
-namespace android {
-
-struct DataSourceDesc;
-class Parcel;
-struct ANativeWindowWrapper;
-
-#define DEFAULT_AUDIOSINK_BUFFERSIZE 1200
-#define DEFAULT_AUDIOSINK_SAMPLERATE 44100
-
-// when the channel mask isn't known, use the channel count to derive a mask in AudioSink::open()
-#define CHANNEL_MASK_USE_CHANNEL_ORDER 0
-
-// duration below which we do not allow deep audio buffering
-#define AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US 5000000
-
-class MediaPlayer2InterfaceListener: public RefBase
-{
-public:
- virtual void notify(int64_t srcId, int msg, int ext1, int ext2,
- const PlayerMessage *obj) = 0;
-};
-
-class MediaPlayer2Interface : public AHandler {
-public:
- // AudioSink: abstraction layer for audio output
- class AudioSink : public RefBase {
- public:
- enum cb_event_t {
- CB_EVENT_FILL_BUFFER, // Request to write more data to buffer.
- CB_EVENT_STREAM_END, // Sent after all the buffers queued in AF and HW are played
- // back (after stop is called)
- CB_EVENT_TEAR_DOWN // The AudioTrack was invalidated due to use case change:
- // Need to re-evaluate offloading options
- };
-
- // Callback returns the number of bytes actually written to the buffer.
- typedef size_t (*AudioCallback)(
- AudioSink *audioSink, void *buffer, size_t size, void *cookie, cb_event_t event);
-
- virtual ~AudioSink() {}
- virtual bool ready() const = 0; // audio output is open and ready
- virtual ssize_t bufferSize() const = 0;
- virtual ssize_t frameCount() const = 0;
- virtual ssize_t channelCount() const = 0;
- virtual ssize_t frameSize() const = 0;
- virtual uint32_t latency() const = 0;
- virtual float msecsPerFrame() const = 0;
- virtual status_t getPosition(uint32_t *position) const = 0;
- virtual status_t getTimestamp(AudioTimestamp &ts) const = 0;
- virtual int64_t getPlayedOutDurationUs(int64_t nowUs) const = 0;
- virtual status_t getFramesWritten(uint32_t *frameswritten) const = 0;
- virtual int32_t getSessionId() const = 0;
- virtual audio_stream_type_t getAudioStreamType() const = 0;
- virtual uint32_t getSampleRate() const = 0;
- virtual int64_t getBufferDurationInUs() const = 0;
-
- // If no callback is specified, use the "write" API below to submit
- // audio data.
- virtual status_t open(
- uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
- audio_format_t format=AUDIO_FORMAT_PCM_16_BIT,
- AudioCallback cb = NULL,
- void *cookie = NULL,
- audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
- const audio_offload_info_t *offloadInfo = NULL,
- uint32_t suggestedFrameCount = 0) = 0;
-
- virtual status_t start() = 0;
-
- /* Input parameter |size| is in byte units stored in |buffer|.
- * Data is copied over and actual number of bytes written (>= 0)
- * is returned, or no data is copied and a negative status code
- * is returned (even when |blocking| is true).
- * When |blocking| is false, AudioSink will immediately return after
- * part of or full |buffer| is copied over.
- * When |blocking| is true, AudioSink will wait to copy the entire
- * buffer, unless an error occurs or the copy operation is
- * prematurely stopped.
- */
- virtual ssize_t write(const void* buffer, size_t size, bool blocking = true) = 0;
-
- virtual void stop() = 0;
- virtual void flush() = 0;
- virtual void pause() = 0;
- virtual void close() = 0;
-
- virtual status_t setPlaybackRate(const AudioPlaybackRate& rate) = 0;
- virtual status_t getPlaybackRate(AudioPlaybackRate* rate /* nonnull */) = 0;
- virtual bool needsTrailingPadding() {
- return true;
- }
-
- virtual status_t setParameters(const String8& /* keyValuePairs */) {
- return NO_ERROR;
- }
- virtual String8 getParameters(const String8& /* keys */) {
- return String8::empty();
- }
-
- // AudioRouting
- virtual status_t setPreferredDevice(jobject device);
- virtual jobject getRoutedDevice();
- virtual status_t addAudioDeviceCallback(jobject routingDelegate);
- virtual status_t removeAudioDeviceCallback(jobject listener);
- };
-
- MediaPlayer2Interface() : mListener(NULL) { }
- virtual ~MediaPlayer2Interface() { }
- virtual status_t initCheck() = 0;
-
- virtual void setAudioSink(const sp<AudioSink>& audioSink) {
- mAudioSink = audioSink;
- }
-
- virtual status_t setDataSource(const sp<DataSourceDesc> &dsd) = 0;
-
- virtual status_t prepareNextDataSource(const sp<DataSourceDesc> &dsd) = 0;
-
- virtual status_t playNextDataSource(int64_t srcId) = 0;
-
- // pass the buffered native window to the media player service
- virtual status_t setVideoSurfaceTexture(const sp<ANativeWindowWrapper>& nww) = 0;
-
- virtual status_t getBufferingSettings(BufferingSettings* buffering /* nonnull */) {
- *buffering = BufferingSettings();
- return OK;
- }
- virtual status_t setBufferingSettings(const BufferingSettings& /* buffering */) {
- return OK;
- }
-
- virtual status_t prepareAsync() = 0;
- virtual status_t start() = 0;
- virtual status_t pause() = 0;
- virtual bool isPlaying() = 0;
- virtual status_t setPlaybackSettings(const AudioPlaybackRate& rate) {
- // by default, players only support setting rate to the default
- if (!isAudioPlaybackRateEqual(rate, AUDIO_PLAYBACK_RATE_DEFAULT)) {
- return BAD_VALUE;
- }
- return OK;
- }
- virtual status_t getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */) {
- *rate = AUDIO_PLAYBACK_RATE_DEFAULT;
- return OK;
- }
- virtual status_t setSyncSettings(const AVSyncSettings& sync, float /* videoFps */) {
- // By default, players only support setting sync source to default; all other sync
- // settings are ignored. There is no requirement for getters to return set values.
- if (sync.mSource != AVSYNC_SOURCE_DEFAULT) {
- return BAD_VALUE;
- }
- return OK;
- }
- virtual status_t getSyncSettings(
- AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */) {
- *sync = AVSyncSettings();
- *videoFps = -1.f;
- return OK;
- }
- virtual status_t seekTo(
- int64_t msec, MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC) = 0;
- virtual status_t getCurrentPosition(int64_t *msec) = 0;
- virtual status_t getDuration(int64_t *msec) = 0;
- virtual status_t reset() = 0;
- virtual status_t notifyAt(int64_t /* mediaTimeUs */) {
- return INVALID_OPERATION;
- }
- virtual status_t setLooping(int loop) = 0;
- virtual status_t setParameter(int key, const Parcel &request) = 0;
- virtual status_t getParameter(int key, Parcel *reply) = 0;
-
- virtual status_t getMetrics(char **buffer, size_t *length) = 0;
-
- // Invoke a generic method on the player by using opaque parcels
- // for the request and reply.
- //
- // @param request Parcel that is positioned at the start of the
- // data sent by the java layer.
- // @param[out] reply Parcel to hold the reply data. Cannot be null.
- // @return OK if the call was successful.
- virtual status_t invoke(const PlayerMessage &request, PlayerMessage *reply) = 0;
-
- void setListener(const sp<MediaPlayer2InterfaceListener> &listener) {
- Mutex::Autolock autoLock(mListenerLock);
- mListener = listener;
- }
-
- void sendEvent(int64_t srcId, int msg, int ext1=0, int ext2=0, const PlayerMessage *obj=NULL) {
- sp<MediaPlayer2InterfaceListener> listener;
- {
- Mutex::Autolock autoLock(mListenerLock);
- listener = mListener;
- }
-
- if (listener) {
- listener->notify(srcId, msg, ext1, ext2, obj);
- }
- }
-
- virtual status_t dump(int /* fd */, const Vector<String16>& /* args */) const {
- return INVALID_OPERATION;
- }
-
- virtual void onMessageReceived(const sp<AMessage> & /* msg */) override { }
-
- // Modular DRM
- virtual status_t prepareDrm(int64_t /*srcId*/, const uint8_t /* uuid */[16],
- const Vector<uint8_t>& /* drmSessionId */) {
- return INVALID_OPERATION;
- }
- virtual status_t releaseDrm(int64_t /*srcId*/) {
- return INVALID_OPERATION;
- }
-
-protected:
- sp<AudioSink> mAudioSink;
-
-private:
- Mutex mListenerLock;
- sp<MediaPlayer2InterfaceListener> mListener;
-};
-
-}; // namespace android
-
-#endif // __cplusplus
-
-
-#endif // ANDROID_MEDIAPLAYER2INTERFACE_H
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
deleted file mode 100644
index 2430289..0000000
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
+++ /dev/null
@@ -1,204 +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.
- */
-
-#ifndef ANDROID_MEDIAPLAYER2_TYPES_H
-#define ANDROID_MEDIAPLAYER2_TYPES_H
-
-#include <media/mediaplayer_common.h>
-
-#include <media/MediaSource.h>
-
-namespace android {
-
-typedef MediaSource::ReadOptions::SeekMode MediaPlayer2SeekMode;
-
-enum media2_event_type {
- MEDIA2_NOP = 0, // interface test message
- MEDIA2_PREPARED = 1,
- MEDIA2_PLAYBACK_COMPLETE = 2,
- MEDIA2_BUFFERING_UPDATE = 3,
- MEDIA2_SEEK_COMPLETE = 4,
- MEDIA2_SET_VIDEO_SIZE = 5,
- MEDIA2_STARTED = 6,
- MEDIA2_PAUSED = 7,
- MEDIA2_SKIPPED = 8,
- MEDIA2_NOTIFY_TIME = 98,
- MEDIA2_TIMED_TEXT = 99,
- MEDIA2_ERROR = 100,
- MEDIA2_INFO = 200,
- MEDIA2_SUBTITLE_DATA = 201,
- MEDIA2_META_DATA = 202,
- MEDIA2_DRM_INFO = 210,
-};
-
-// Generic error codes for the media player framework. Errors are fatal, the
-// playback must abort.
-//
-// Errors are communicated back to the client using the
-// MediaPlayer2Listener::notify method defined below.
-// In this situation, 'notify' is invoked with the following:
-// 'msg' is set to MEDIA_ERROR.
-// 'ext1' should be a value from the enum media2_error_type.
-// 'ext2' contains an implementation dependant error code to provide
-// more details. Should default to 0 when not used.
-//
-// The codes are distributed as follow:
-// 0xx: Reserved
-// 1xx: Android Player errors. Something went wrong inside the MediaPlayer2.
-// 2xx: Media errors (e.g Codec not supported). There is a problem with the
-// media itself.
-// 3xx: Runtime errors. Some extraordinary condition arose making the playback
-// impossible.
-//
-enum media2_error_type {
- // 0xx
- MEDIA2_ERROR_UNKNOWN = 1,
- // 1xx
- // MEDIA2_ERROR_SERVER_DIED = 100,
- // 2xx
- MEDIA2_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200,
- // 3xx
- MEDIA2_ERROR_FAILED_TO_SET_DATA_SOURCE = 300,
-};
-
-
-// Info and warning codes for the media player framework. These are non fatal,
-// the playback is going on but there might be some user visible issues.
-//
-// Info and warning messages are communicated back to the client using the
-// MediaPlayer2Listener::notify method defined below. In this situation,
-// 'notify' is invoked with the following:
-// 'msg' is set to MEDIA_INFO.
-// 'ext1' should be a value from the enum media2_info_type.
-// 'ext2' contains an implementation dependant info code to provide
-// more details. Should default to 0 when not used.
-//
-// The codes are distributed as follow:
-// 0xx: Reserved
-// 7xx: Android Player info/warning (e.g player lagging behind.)
-// 8xx: Media info/warning (e.g media badly interleaved.)
-//
-enum media2_info_type {
- // 0xx
- MEDIA2_INFO_UNKNOWN = 1,
- // The player just started the playback of this data source.
- MEDIA2_INFO_DATA_SOURCE_START = 2,
- // The player just pushed the very first video frame for rendering
- MEDIA2_INFO_VIDEO_RENDERING_START = 3,
- // The player just pushed the very first audio frame for rendering
- MEDIA2_INFO_AUDIO_RENDERING_START = 4,
- // The player just completed the playback of this data source
- MEDIA2_INFO_DATA_SOURCE_END = 5,
- // The player just completed the playback of all data sources.
- // But this is not visible in native code. Just keep this entry for completeness.
- MEDIA2_INFO_DATA_SOURCE_LIST_END = 6,
- // The player just completed an iteration of playback loop. This event is sent only when
- // looping is enabled.
- MEDIA2_INFO_DATA_SOURCE_REPEAT = 7,
-
- //1xx
- // The player just prepared a data source.
- MEDIA2_INFO_PREPARED = 100,
- // The player just completed a call play().
- MEDIA2_INFO_COMPLETE_CALL_PLAY = 101,
- // The player just completed a call pause().
- MEDIA2_INFO_COMPLETE_CALL_PAUSE = 102,
- // The player just completed a call seekTo.
- MEDIA2_INFO_COMPLETE_CALL_SEEK = 103,
-
- // 7xx
- // The video is too complex for the decoder: it can't decode frames fast
- // enough. Possibly only the audio plays fine at this stage.
- MEDIA2_INFO_VIDEO_TRACK_LAGGING = 700,
- // MediaPlayer2 is temporarily pausing playback internally in order to
- // buffer more data.
- MEDIA2_INFO_BUFFERING_START = 701,
- // MediaPlayer2 is resuming playback after filling buffers.
- MEDIA2_INFO_BUFFERING_END = 702,
- // Bandwidth in recent past
- MEDIA2_INFO_NETWORK_BANDWIDTH = 703,
-
- // 8xx
- // Bad interleaving means that a media has been improperly interleaved or not
- // interleaved at all, e.g has all the video samples first then all the audio
- // ones. Video is playing but a lot of disk seek may be happening.
- MEDIA2_INFO_BAD_INTERLEAVING = 800,
- // The media is not seekable (e.g live stream).
- MEDIA2_INFO_NOT_SEEKABLE = 801,
- // New media metadata is available.
- MEDIA2_INFO_METADATA_UPDATE = 802,
- // Audio can not be played.
- MEDIA2_INFO_PLAY_AUDIO_ERROR = 804,
- // Video can not be played.
- MEDIA2_INFO_PLAY_VIDEO_ERROR = 805,
-
- //9xx
- MEDIA2_INFO_TIMED_TEXT_ERROR = 900,
-};
-
-// Do not change these values without updating their counterparts in MediaPlayer2.java
-enum mediaplayer2_states {
- MEDIAPLAYER2_STATE_IDLE = 1001,
- MEDIAPLAYER2_STATE_PREPARED = 1002,
- MEDIAPLAYER2_STATE_PAUSED = 1003,
- MEDIAPLAYER2_STATE_PLAYING = 1004,
- MEDIAPLAYER2_STATE_ERROR = 1005,
-};
-
-enum media_player2_internal_states {
- MEDIA_PLAYER2_STATE_ERROR = 0,
- MEDIA_PLAYER2_IDLE = 1 << 0,
- MEDIA_PLAYER2_INITIALIZED = 1 << 1,
- MEDIA_PLAYER2_PREPARING = 1 << 2,
- MEDIA_PLAYER2_PREPARED = 1 << 3,
- MEDIA_PLAYER2_STARTED = 1 << 4,
- MEDIA_PLAYER2_PAUSED = 1 << 5,
- MEDIA_PLAYER2_PLAYBACK_COMPLETE = 1 << 6
-};
-
-// Keep KEY_PARAMETER_* in sync with MediaPlayer2.java.
-// The same enum space is used for both set and get, in case there are future keys that
-// can be both set and get. But as of now, all parameters are either set only or get only.
-enum media2_parameter_keys {
- // Streaming/buffering parameters
- MEDIA2_KEY_PARAMETER_CACHE_STAT_COLLECT_FREQ_MS = 1100, // set only
-
- // Return a Parcel containing a single int, which is the channel count of the
- // audio track, or zero for error (e.g. no audio track) or unknown.
- MEDIA2_KEY_PARAMETER_AUDIO_CHANNEL_COUNT = 1200, // get only
-
- // Playback rate expressed in permille (1000 is normal speed), saved as int32_t, with negative
- // values used for rewinding or reverse playback.
- MEDIA2_KEY_PARAMETER_PLAYBACK_RATE_PERMILLE = 1300, // set only
-
- // Set a Parcel containing the value of a parcelled Java AudioAttribute instance
- MEDIA2_KEY_PARAMETER_AUDIO_ATTRIBUTES = 1400 // set only
-};
-
-// Keep INVOKE_ID_* in sync with MediaPlayer2.java.
-enum media_player2_invoke_ids {
- MEDIA_PLAYER2_INVOKE_ID_GET_TRACK_INFO = 1,
- MEDIA_PLAYER2_INVOKE_ID_ADD_EXTERNAL_SOURCE = 2,
- MEDIA_PLAYER2_INVOKE_ID_ADD_EXTERNAL_SOURCE_FD = 3,
- MEDIA_PLAYER2_INVOKE_ID_SELECT_TRACK = 4,
- MEDIA_PLAYER2_INVOKE_ID_UNSELECT_TRACK = 5,
- MEDIA_PLAYER2_INVOKE_ID_SET_VIDEO_SCALING_MODE = 6,
- MEDIA_PLAYER2_INVOKE_ID_GET_SELECTED_TRACK = 7
-};
-
-}; // namespace android
-
-#endif // ANDROID_MEDIAPLAYER2_TYPES_H
diff --git a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
deleted file mode 100644
index 1e8a1d5..0000000
--- a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_MEDIAPLAYER2_H
-#define ANDROID_MEDIAPLAYER2_H
-
-#include <media/AVSyncSettings.h>
-#include <media/AudioResamplerPublic.h>
-#include <media/BufferingSettings.h>
-#include <media/mediaplayer_common.h>
-#include <mediaplayer2/MediaPlayer2Interface.h>
-#include <mediaplayer2/MediaPlayer2Types.h>
-#include <mediaplayer2/JObjectHolder.h>
-
-#include <jni.h>
-#include <utils/Errors.h>
-#include <utils/Mutex.h>
-#include <utils/RefBase.h>
-#include <utils/String16.h>
-#include <utils/Vector.h>
-#include <system/audio-base.h>
-
-#include "jni.h"
-
-namespace android {
-
-struct ANativeWindowWrapper;
-struct DataSourceDesc;
-class MediaPlayer2AudioOutput;
-
-// ref-counted object for callbacks
-class MediaPlayer2Listener: virtual public RefBase
-{
-public:
- virtual void notify(int64_t srcId, int msg, int ext1, int ext2,
- const PlayerMessage *obj = NULL) = 0;
-};
-
-class MediaPlayer2 : public MediaPlayer2InterfaceListener
-{
-public:
- ~MediaPlayer2();
-
- static sp<MediaPlayer2> Create(int32_t sessionId, jobject context);
- static status_t DumpAll(int fd, const Vector<String16>& args);
-
- void disconnect();
-
- status_t getSrcId(int64_t *srcId);
- status_t setDataSource(const sp<DataSourceDesc> &dsd);
- status_t prepareNextDataSource(const sp<DataSourceDesc> &dsd);
- status_t playNextDataSource(int64_t srcId);
- status_t setVideoSurfaceTexture(const sp<ANativeWindowWrapper>& nww);
- status_t setListener(const sp<MediaPlayer2Listener>& listener);
- status_t getBufferingSettings(BufferingSettings* buffering /* nonnull */);
- status_t setBufferingSettings(const BufferingSettings& buffering);
- status_t prepareAsync();
- status_t start();
- status_t pause();
- bool isPlaying();
- mediaplayer2_states getState();
- status_t setPlaybackSettings(const AudioPlaybackRate& rate);
- status_t getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */);
- status_t setSyncSettings(const AVSyncSettings& sync, float videoFpsHint);
- status_t getSyncSettings(
- AVSyncSettings* sync /* nonnull */,
- float* videoFps /* nonnull */);
- status_t getVideoWidth(int *w);
- status_t getVideoHeight(int *h);
- status_t seekTo(
- int64_t msec,
- MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC);
- status_t notifyAt(int64_t mediaTimeUs);
- status_t getCurrentPosition(int64_t *msec);
- status_t getDuration(int64_t srcId, int64_t *msec);
- status_t reset();
- status_t setAudioStreamType(audio_stream_type_t type);
- status_t getAudioStreamType(audio_stream_type_t *type);
- status_t setLooping(int loop);
- bool isLooping();
- status_t setVolume(float volume);
- void notify(int64_t srcId, int msg, int ext1, int ext2,
- const PlayerMessage *obj = NULL);
- status_t invoke(const PlayerMessage &request, PlayerMessage *reply);
- status_t setAudioSessionId(int32_t sessionId);
- int32_t getAudioSessionId();
- status_t setAuxEffectSendLevel(float level);
- status_t attachAuxEffect(int effectId);
- status_t setAudioAttributes(const jobject attributes);
- jobject getAudioAttributes();
- status_t getParameter(int key, Parcel* reply);
- status_t getMetrics(char **buffer, size_t *length);
-
- // Modular DRM
- status_t prepareDrm(int64_t srcId,
- const uint8_t uuid[16],
- const Vector<uint8_t>& drmSessionId);
- status_t releaseDrm(int64_t srcId);
- // AudioRouting
- status_t setPreferredDevice(jobject device);
- jobject getRoutedDevice();
- status_t addAudioDeviceCallback(jobject routingDelegate);
- status_t removeAudioDeviceCallback(jobject listener);
-
- status_t dump(int fd, const Vector<String16>& args);
-
-private:
- MediaPlayer2(int32_t sessionId, jobject context);
- bool init();
-
- // Disconnect from the currently connected ANativeWindow.
- void disconnectNativeWindow_l();
-
- status_t setAudioAttributes_l(const jobject attributes);
-
- void clear_l();
- status_t seekTo_l(int64_t msec, MediaPlayer2SeekMode mode);
- status_t prepareAsync_l();
- status_t getDuration_l(int64_t *msec);
- status_t reset_l();
- status_t checkState_l();
-
- pid_t mPid;
- uid_t mUid;
- sp<MediaPlayer2Interface> mPlayer;
- sp<MediaPlayer2AudioOutput> mAudioOutput;
- int64_t mSrcId;
- thread_id_t mLockThreadId;
- mutable Mutex mLock;
- Mutex mNotifyLock;
- sp<MediaPlayer2Listener> mListener;
- media_player2_internal_states mCurrentState;
- bool mTransitionToNext;
- int64_t mCurrentPosition;
- MediaPlayer2SeekMode mCurrentSeekMode;
- int64_t mSeekPosition;
- MediaPlayer2SeekMode mSeekMode;
- audio_stream_type_t mStreamType;
- bool mLoop;
- float mVolume;
- int mVideoWidth;
- int mVideoHeight;
- int32_t mAudioSessionId;
- sp<JObjectHolder> mAudioAttributes;
- sp<JObjectHolder> mContext;
- float mSendLevel;
- sp<ANativeWindowWrapper> mConnectedWindow;
-};
-
-}; // namespace android
-
-#endif // ANDROID_MEDIAPLAYER2_H
diff --git a/media/libmediaplayer2/mediaplayer2.cpp b/media/libmediaplayer2/mediaplayer2.cpp
deleted file mode 100644
index de65f8d..0000000
--- a/media/libmediaplayer2/mediaplayer2.cpp
+++ /dev/null
@@ -1,1261 +0,0 @@
-/*
-**
-** Copyright 2017, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "MediaPlayer2Native"
-
-#include <android/binder_ibinder.h>
-#include <media/AudioSystem.h>
-#include <media/DataSourceDesc.h>
-#include <media/MemoryLeakTrackUtil.h>
-#include <media/NdkWrapper.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/ALooperRoster.h>
-#include <mediaplayer2/MediaPlayer2AudioOutput.h>
-#include <mediaplayer2/mediaplayer2.h>
-
-#include <utils/Log.h>
-#include <utils/SortedVector.h>
-#include <utils/String8.h>
-
-#include <system/audio.h>
-#include <system/window.h>
-
-#include <nuplayer2/NuPlayer2Driver.h>
-
-#include <dirent.h>
-#include <sys/stat.h>
-
-namespace android {
-
-extern ALooperRoster gLooperRoster;
-
-namespace {
-
-const int kDumpLockRetries = 50;
-const int kDumpLockSleepUs = 20000;
-
-class proxyListener : public MediaPlayer2InterfaceListener {
-public:
- proxyListener(const wp<MediaPlayer2> &player)
- : mPlayer(player) { }
-
- ~proxyListener() { };
-
- virtual void notify(int64_t srcId, int msg, int ext1, int ext2,
- const PlayerMessage *obj) override {
- sp<MediaPlayer2> player = mPlayer.promote();
- if (player != NULL) {
- player->notify(srcId, msg, ext1, ext2, obj);
- }
- }
-
-private:
- wp<MediaPlayer2> mPlayer;
-};
-
-Mutex sRecordLock;
-SortedVector<wp<MediaPlayer2> > *sPlayers;
-
-void ensureInit_l() {
- if (sPlayers == NULL) {
- sPlayers = new SortedVector<wp<MediaPlayer2> >();
- }
-}
-
-void addPlayer(const wp<MediaPlayer2>& player) {
- Mutex::Autolock lock(sRecordLock);
- ensureInit_l();
- sPlayers->add(player);
-}
-
-void removePlayer(const wp<MediaPlayer2>& player) {
- Mutex::Autolock lock(sRecordLock);
- ensureInit_l();
- sPlayers->remove(player);
-}
-
-/**
- * The only arguments this understands right now are -c, -von and -voff,
- * which are parsed by ALooperRoster::dump()
- */
-status_t dumpPlayers(int fd, const Vector<String16>& args) {
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
- SortedVector< sp<MediaPlayer2> > players; //to serialise the mutex unlock & client destruction.
-
- {
- Mutex::Autolock lock(sRecordLock);
- ensureInit_l();
- for (int i = 0, n = sPlayers->size(); i < n; ++i) {
- sp<MediaPlayer2> p = (*sPlayers)[i].promote();
- if (p != 0) {
- p->dump(fd, args);
- }
- players.add(p);
- }
- }
-
- result.append(" Files opened and/or mapped:\n");
- snprintf(buffer, SIZE, "/proc/%d/maps", getpid());
- FILE *f = fopen(buffer, "r");
- if (f) {
- while (!feof(f)) {
- fgets(buffer, SIZE, f);
- if (strstr(buffer, " /storage/") ||
- strstr(buffer, " /system/sounds/") ||
- strstr(buffer, " /data/") ||
- strstr(buffer, " /system/media/")) {
- result.append(" ");
- result.append(buffer);
- }
- }
- fclose(f);
- } else {
- result.append("couldn't open ");
- result.append(buffer);
- result.append("\n");
- }
-
- snprintf(buffer, SIZE, "/proc/%d/fd", getpid());
- DIR *d = opendir(buffer);
- if (d) {
- struct dirent *ent;
- while((ent = readdir(d)) != NULL) {
- if (strcmp(ent->d_name,".") && strcmp(ent->d_name,"..")) {
- snprintf(buffer, SIZE, "/proc/%d/fd/%s", getpid(), ent->d_name);
- struct stat s;
- if (lstat(buffer, &s) == 0) {
- if ((s.st_mode & S_IFMT) == S_IFLNK) {
- char linkto[256];
- int len = readlink(buffer, linkto, sizeof(linkto));
- if(len > 0) {
- if(len > 255) {
- linkto[252] = '.';
- linkto[253] = '.';
- linkto[254] = '.';
- linkto[255] = 0;
- } else {
- linkto[len] = 0;
- }
- if (strstr(linkto, "/storage/") == linkto ||
- strstr(linkto, "/system/sounds/") == linkto ||
- strstr(linkto, "/data/") == linkto ||
- strstr(linkto, "/system/media/") == linkto) {
- result.append(" ");
- result.append(buffer);
- result.append(" -> ");
- result.append(linkto);
- result.append("\n");
- }
- }
- } else {
- result.append(" unexpected type for ");
- result.append(buffer);
- result.append("\n");
- }
- }
- }
- }
- closedir(d);
- } else {
- result.append("couldn't open ");
- result.append(buffer);
- result.append("\n");
- }
-
- gLooperRoster.dump(fd, args);
-
- bool dumpMem = false;
- bool unreachableMemory = false;
- for (size_t i = 0; i < args.size(); i++) {
- if (args[i] == String16("-m")) {
- dumpMem = true;
- } else if (args[i] == String16("--unreachable")) {
- unreachableMemory = true;
- }
- }
- if (dumpMem) {
- result.append("\nDumping memory:\n");
- std::string s = dumpMemoryAddresses(100 /* limit */);
- result.append(s.c_str(), s.size());
- }
- if (unreachableMemory) {
- result.append("\nDumping unreachable memory:\n");
- // TODO - should limit be an argument parameter?
- // TODO: enable GetUnreachableMemoryString if it's part of stable API
- //std::string s = GetUnreachableMemoryString(true /* contents */, 10000 /* limit */);
- //result.append(s.c_str(), s.size());
- }
-
- write(fd, result.string(), result.size());
- return NO_ERROR;
-}
-
-} // anonymous namespace
-
-//static
-sp<MediaPlayer2> MediaPlayer2::Create(int32_t sessionId, jobject context) {
- sp<MediaPlayer2> player = new MediaPlayer2(sessionId, context);
-
- if (!player->init()) {
- return NULL;
- }
-
- ALOGV("Create new player(%p)", player.get());
-
- addPlayer(player);
- return player;
-}
-
-// static
-status_t MediaPlayer2::DumpAll(int fd, const Vector<String16>& args) {
- return dumpPlayers(fd, args);
-}
-
-MediaPlayer2::MediaPlayer2(int32_t sessionId, jobject context) {
- ALOGV("constructor");
- mSrcId = 0;
- mLockThreadId = 0;
- mListener = NULL;
- mStreamType = AUDIO_STREAM_MUSIC;
- mAudioAttributes = NULL;
- mContext = new JObjectHolder(context);
- mCurrentPosition = -1;
- mCurrentSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
- mSeekPosition = -1;
- mSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
- mCurrentState = MEDIA_PLAYER2_IDLE;
- mTransitionToNext = false;
- mLoop = false;
- mVolume = 1.0;
- mVideoWidth = mVideoHeight = 0;
- mSendLevel = 0;
-
- mPid = AIBinder_getCallingPid();
- mUid = AIBinder_getCallingUid();
-
- mAudioOutput = new MediaPlayer2AudioOutput(sessionId, mUid, mPid, NULL /*attributes*/);
-}
-
-MediaPlayer2::~MediaPlayer2() {
- ALOGV("destructor");
- disconnect();
- removePlayer(this);
-}
-
-bool MediaPlayer2::init() {
- // TODO: after merge with NuPlayer2Driver, MediaPlayer2 will have its own
- // looper for notification.
- return true;
-}
-
-void MediaPlayer2::disconnect() {
- ALOGV("disconnect");
- sp<MediaPlayer2Interface> p;
- {
- Mutex::Autolock _l(mLock);
- p = mPlayer;
- mPlayer.clear();
- }
-
- if (p != 0) {
- p->setListener(NULL);
- p->reset();
- }
-
- {
- Mutex::Autolock _l(mLock);
- disconnectNativeWindow_l();
- }
-}
-
-void MediaPlayer2::clear_l() {
- mCurrentPosition = -1;
- mCurrentSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
- mSeekPosition = -1;
- mSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
- mVideoWidth = mVideoHeight = 0;
-}
-
-status_t MediaPlayer2::setListener(const sp<MediaPlayer2Listener>& listener) {
- ALOGV("setListener");
- Mutex::Autolock _l(mLock);
- mListener = listener;
- return NO_ERROR;
-}
-
-status_t MediaPlayer2::getSrcId(int64_t *srcId) {
- if (srcId == NULL) {
- return BAD_VALUE;
- }
-
- Mutex::Autolock _l(mLock);
- *srcId = mSrcId;
- return OK;
-}
-
-status_t MediaPlayer2::setDataSource(const sp<DataSourceDesc> &dsd) {
- if (dsd == NULL) {
- return BAD_VALUE;
- }
- // Microsecond is used in NuPlayer2.
- if (dsd->mStartPositionMs > DataSourceDesc::kMaxTimeMs) {
- dsd->mStartPositionMs = DataSourceDesc::kMaxTimeMs;
- ALOGW("setDataSource, start poistion clamped to %lld ms", (long long)dsd->mStartPositionMs);
- }
- if (dsd->mEndPositionMs > DataSourceDesc::kMaxTimeMs) {
- dsd->mEndPositionMs = DataSourceDesc::kMaxTimeMs;
- ALOGW("setDataSource, end poistion clamped to %lld ms", (long long)dsd->mStartPositionMs);
- }
- ALOGV("setDataSource type(%d), srcId(%lld)", dsd->mType, (long long)dsd->mId);
-
- sp<MediaPlayer2Interface> oldPlayer;
-
- {
- Mutex::Autolock _l(mLock);
- if (!((mCurrentState & MEDIA_PLAYER2_IDLE)
- || mCurrentState == MEDIA_PLAYER2_STATE_ERROR)) {
- ALOGE("setDataSource called in wrong state %d", mCurrentState);
- return INVALID_OPERATION;
- }
-
- sp<MediaPlayer2Interface> player = new NuPlayer2Driver(mPid, mUid, mContext);
- status_t err = player->initCheck();
- if (err != NO_ERROR) {
- ALOGE("Failed to create player object, initCheck failed(%d)", err);
- return err;
- }
-
- clear_l();
-
- player->setListener(new proxyListener(this));
- player->setAudioSink(mAudioOutput);
-
- err = player->setDataSource(dsd);
- if (err != OK) {
- ALOGE("setDataSource error: %d", err);
- return err;
- }
-
- sp<MediaPlayer2Interface> oldPlayer = mPlayer;
- mPlayer = player;
- mSrcId = dsd->mId;
- mCurrentState = MEDIA_PLAYER2_INITIALIZED;
- }
-
- if (oldPlayer != NULL) {
- oldPlayer->setListener(NULL);
- oldPlayer->reset();
- }
-
- return OK;
-}
-
-status_t MediaPlayer2::prepareNextDataSource(const sp<DataSourceDesc> &dsd) {
- if (dsd == NULL) {
- return BAD_VALUE;
- }
- ALOGV("prepareNextDataSource type(%d), srcId(%lld)", dsd->mType, (long long)dsd->mId);
-
- Mutex::Autolock _l(mLock);
- if (mPlayer == NULL) {
- ALOGE("prepareNextDataSource failed: state %X, mPlayer(%p)", mCurrentState, mPlayer.get());
- return INVALID_OPERATION;
- }
- return mPlayer->prepareNextDataSource(dsd);
-}
-
-status_t MediaPlayer2::playNextDataSource(int64_t srcId) {
- ALOGV("playNextDataSource srcId(%lld)", (long long)srcId);
-
- Mutex::Autolock _l(mLock);
- if (mPlayer == NULL) {
- ALOGE("playNextDataSource failed: state %X, mPlayer(%p)", mCurrentState, mPlayer.get());
- return INVALID_OPERATION;
- }
- mSrcId = srcId;
- mTransitionToNext = true;
- return mPlayer->playNextDataSource(srcId);
-}
-
-status_t MediaPlayer2::invoke(const PlayerMessage &request, PlayerMessage *reply) {
- Mutex::Autolock _l(mLock);
- const bool hasBeenInitialized =
- (mCurrentState != MEDIA_PLAYER2_STATE_ERROR) &&
- ((mCurrentState & MEDIA_PLAYER2_IDLE) != MEDIA_PLAYER2_IDLE);
- if ((mPlayer == NULL) || !hasBeenInitialized) {
- ALOGE("invoke() failed: wrong state %X, mPlayer(%p)", mCurrentState, mPlayer.get());
- return INVALID_OPERATION;
- }
- return mPlayer->invoke(request, reply);
-}
-
-void MediaPlayer2::disconnectNativeWindow_l() {
- if (mConnectedWindow != NULL && mConnectedWindow->getANativeWindow() != NULL) {
- status_t err = native_window_api_disconnect(
- mConnectedWindow->getANativeWindow(), NATIVE_WINDOW_API_MEDIA);
-
- if (err != OK) {
- ALOGW("nativeWindowDisconnect returned an error: %s (%d)",
- strerror(-err), err);
- }
- }
- mConnectedWindow.clear();
-}
-
-status_t MediaPlayer2::setVideoSurfaceTexture(const sp<ANativeWindowWrapper>& nww) {
- ANativeWindow *anw = (nww == NULL ? NULL : nww->getANativeWindow());
- ALOGV("setVideoSurfaceTexture(%p)", anw);
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return NO_INIT;
- }
-
- if (anw != NULL) {
- if (mConnectedWindow != NULL
- && mConnectedWindow->getANativeWindow() == anw) {
- return OK;
- }
- status_t err = native_window_api_connect(anw, NATIVE_WINDOW_API_MEDIA);
-
- if (err != OK) {
- ALOGE("setVideoSurfaceTexture failed: %d", err);
- // Note that we must do the reset before disconnecting from the ANW.
- // Otherwise queue/dequeue calls could be made on the disconnected
- // ANW, which may result in errors.
- mPlayer->reset();
- disconnectNativeWindow_l();
- return err;
- }
- }
-
- // Note that we must set the player's new GraphicBufferProducer before
- // disconnecting the old one. Otherwise queue/dequeue calls could be made
- // on the disconnected ANW, which may result in errors.
- status_t err = mPlayer->setVideoSurfaceTexture(nww);
-
- disconnectNativeWindow_l();
-
- if (err == OK) {
- mConnectedWindow = nww;
- mLock.unlock();
- } else if (anw != NULL) {
- mLock.unlock();
- status_t err = native_window_api_disconnect(anw, NATIVE_WINDOW_API_MEDIA);
-
- if (err != OK) {
- ALOGW("nativeWindowDisconnect returned an error: %s (%d)",
- strerror(-err), err);
- }
- }
-
- return err;
-}
-
-status_t MediaPlayer2::getBufferingSettings(BufferingSettings* buffering /* nonnull */) {
- ALOGV("getBufferingSettings");
-
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return NO_INIT;
- }
-
- status_t ret = mPlayer->getBufferingSettings(buffering);
- if (ret == NO_ERROR) {
- ALOGV("getBufferingSettings{%s}", buffering->toString().string());
- } else {
- ALOGE("getBufferingSettings returned %d", ret);
- }
- return ret;
-}
-
-status_t MediaPlayer2::setBufferingSettings(const BufferingSettings& buffering) {
- ALOGV("setBufferingSettings{%s}", buffering.toString().string());
-
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return NO_INIT;
- }
- return mPlayer->setBufferingSettings(buffering);
-}
-
-status_t MediaPlayer2::setAudioAttributes_l(const jobject attributes) {
- if (mAudioOutput != NULL) {
- mAudioOutput->setAudioAttributes(attributes);
- }
- return NO_ERROR;
-}
-
-status_t MediaPlayer2::prepareAsync() {
- ALOGV("prepareAsync");
- Mutex::Autolock _l(mLock);
- if ((mPlayer != 0) && (mCurrentState & MEDIA_PLAYER2_INITIALIZED)) {
- if (mAudioAttributes != NULL) {
- status_t err = setAudioAttributes_l(mAudioAttributes->getJObject());
- if (err != OK) {
- return err;
- }
- }
- mCurrentState = MEDIA_PLAYER2_PREPARING;
- return mPlayer->prepareAsync();
- }
- ALOGE("prepareAsync called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());
- return INVALID_OPERATION;
-}
-
-status_t MediaPlayer2::start() {
- ALOGV("start");
-
- status_t ret = NO_ERROR;
- Mutex::Autolock _l(mLock);
-
- mLockThreadId = getThreadId();
-
- if (mCurrentState & MEDIA_PLAYER2_STARTED) {
- ret = NO_ERROR;
- } else if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER2_PREPARED |
- MEDIA_PLAYER2_PLAYBACK_COMPLETE | MEDIA_PLAYER2_PAUSED ) ) ) {
- mPlayer->setLooping(mLoop);
-
- if (mAudioOutput != 0) {
- mAudioOutput->setVolume(mVolume);
- }
-
- if (mAudioOutput != 0) {
- mAudioOutput->setAuxEffectSendLevel(mSendLevel);
- }
- mCurrentState = MEDIA_PLAYER2_STARTED;
- ret = mPlayer->start();
- if (ret != NO_ERROR) {
- mCurrentState = MEDIA_PLAYER2_STATE_ERROR;
- } else {
- if (mCurrentState == MEDIA_PLAYER2_PLAYBACK_COMPLETE) {
- ALOGV("playback completed immediately following start()");
- }
- }
- } else {
- ALOGE("start called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());
- ret = INVALID_OPERATION;
- }
-
- mLockThreadId = 0;
-
- return ret;
-}
-
-status_t MediaPlayer2::pause() {
- ALOGV("pause");
- Mutex::Autolock _l(mLock);
- if (mCurrentState & (MEDIA_PLAYER2_PAUSED|MEDIA_PLAYER2_PLAYBACK_COMPLETE))
- return NO_ERROR;
- if ((mPlayer != 0) && (mCurrentState & (MEDIA_PLAYER2_STARTED | MEDIA_PLAYER2_PREPARED))) {
- status_t ret = mPlayer->pause();
- if (ret != NO_ERROR) {
- mCurrentState = MEDIA_PLAYER2_STATE_ERROR;
- } else {
- mCurrentState = MEDIA_PLAYER2_PAUSED;
- mTransitionToNext = false;
- }
- return ret;
- }
- ALOGE("pause called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());
- return INVALID_OPERATION;
-}
-
-bool MediaPlayer2::isPlaying() {
- Mutex::Autolock _l(mLock);
- if (mPlayer != 0) {
- bool temp = mPlayer->isPlaying();
- ALOGV("isPlaying: %d", temp);
- if ((mCurrentState & MEDIA_PLAYER2_STARTED) && ! temp) {
- ALOGE("internal/external state mismatch corrected");
- mCurrentState = MEDIA_PLAYER2_PAUSED;
- } else if ((mCurrentState & MEDIA_PLAYER2_PAUSED) && temp) {
- ALOGE("internal/external state mismatch corrected");
- mCurrentState = MEDIA_PLAYER2_STARTED;
- }
- return temp;
- }
- ALOGV("isPlaying: no active player");
- return false;
-}
-
-mediaplayer2_states MediaPlayer2::getState() {
- Mutex::Autolock _l(mLock);
- if (mCurrentState & MEDIA_PLAYER2_STATE_ERROR) {
- return MEDIAPLAYER2_STATE_ERROR;
- }
- if (mPlayer == 0
- || (mCurrentState &
- (MEDIA_PLAYER2_IDLE | MEDIA_PLAYER2_INITIALIZED | MEDIA_PLAYER2_PREPARING))) {
- return MEDIAPLAYER2_STATE_IDLE;
- }
- if (mCurrentState & MEDIA_PLAYER2_STARTED) {
- return MEDIAPLAYER2_STATE_PLAYING;
- }
- if (mCurrentState & (MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_PLAYBACK_COMPLETE)) {
- return MEDIAPLAYER2_STATE_PAUSED;
- }
- // now only mCurrentState & MEDIA_PLAYER2_PREPARED is true
- return MEDIAPLAYER2_STATE_PREPARED;
-}
-
-status_t MediaPlayer2::setPlaybackSettings(const AudioPlaybackRate& rate) {
- ALOGV("setPlaybackSettings: %f %f %d %d",
- rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode);
- // Negative speed and pitch does not make sense. Further validation will
- // be done by the respective mediaplayers.
- if (rate.mSpeed <= 0.f || rate.mPitch < 0.f) {
- return BAD_VALUE;
- }
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return INVALID_OPERATION;
- }
-
- status_t err = mPlayer->setPlaybackSettings(rate);
- return err;
-}
-
-status_t MediaPlayer2::getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */) {
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return INVALID_OPERATION;
- }
- status_t ret = mPlayer->getPlaybackSettings(rate);
- if (ret == NO_ERROR) {
- ALOGV("getPlaybackSettings(%f, %f, %d, %d)",
- rate->mSpeed, rate->mPitch, rate->mFallbackMode, rate->mStretchMode);
- } else {
- ALOGV("getPlaybackSettings returned %d", ret);
- }
- return ret;
-}
-
-status_t MediaPlayer2::setSyncSettings(const AVSyncSettings& sync, float videoFpsHint) {
- ALOGV("setSyncSettings: %u %u %f %f",
- sync.mSource, sync.mAudioAdjustMode, sync.mTolerance, videoFpsHint);
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) return INVALID_OPERATION;
- return mPlayer->setSyncSettings(sync, videoFpsHint);
-}
-
-status_t MediaPlayer2::getSyncSettings(
- AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */) {
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return INVALID_OPERATION;
- }
- status_t ret = mPlayer->getSyncSettings(sync, videoFps);
- if (ret == NO_ERROR) {
- ALOGV("getSyncSettings(%u, %u, %f, %f)",
- sync->mSource, sync->mAudioAdjustMode, sync->mTolerance, *videoFps);
- } else {
- ALOGV("getSyncSettings returned %d", ret);
- }
- return ret;
-
-}
-
-status_t MediaPlayer2::getVideoWidth(int *w) {
- ALOGV("getVideoWidth");
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return INVALID_OPERATION;
- }
- *w = mVideoWidth;
- return NO_ERROR;
-}
-
-status_t MediaPlayer2::getVideoHeight(int *h) {
- ALOGV("getVideoHeight");
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return INVALID_OPERATION;
- }
- *h = mVideoHeight;
- return NO_ERROR;
-}
-
-status_t MediaPlayer2::getCurrentPosition(int64_t *msec) {
- ALOGV("getCurrentPosition");
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return INVALID_OPERATION;
- }
- if (mCurrentPosition >= 0) {
- ALOGV("Using cached seek position: %lld", (long long)mCurrentPosition);
- *msec = mCurrentPosition;
- return NO_ERROR;
- }
- status_t ret = mPlayer->getCurrentPosition(msec);
- if (ret == NO_ERROR) {
- ALOGV("getCurrentPosition = %lld", (long long)*msec);
- } else {
- ALOGE("getCurrentPosition returned %d", ret);
- }
- return ret;
-}
-
-status_t MediaPlayer2::getDuration(int64_t srcId, int64_t *msec) {
- Mutex::Autolock _l(mLock);
- // TODO: cache duration for currentSrcId and nextSrcId, and return correct
- // value for nextSrcId.
- if (srcId != mSrcId) {
- *msec = -1;
- return OK;
- }
-
- ALOGV("getDuration_l");
- bool isValidState = (mCurrentState & (MEDIA_PLAYER2_PREPARED | MEDIA_PLAYER2_STARTED |
- MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_PLAYBACK_COMPLETE));
- if (mPlayer == 0 || !isValidState) {
- ALOGE("Attempt to call getDuration in wrong state: mPlayer=%p, mCurrentState=%u",
- mPlayer.get(), mCurrentState);
- return INVALID_OPERATION;
- }
- int64_t durationMs;
- status_t ret = mPlayer->getDuration(&durationMs);
-
- if (ret == NO_ERROR) {
- ALOGV("getDuration = %lld", (long long)durationMs);
- } else {
- ALOGE("getDuration returned %d", ret);
- // Do not enter error state just because no duration was available.
- durationMs = -1;
- }
-
- if (msec) {
- *msec = durationMs;
- }
- return OK;
-}
-
-status_t MediaPlayer2::seekTo_l(int64_t msec, MediaPlayer2SeekMode mode) {
- ALOGV("seekTo (%lld, %d)", (long long)msec, mode);
- if ((mPlayer == 0) || !(mCurrentState & (MEDIA_PLAYER2_STARTED | MEDIA_PLAYER2_PREPARED |
- MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_PLAYBACK_COMPLETE))) {
- ALOGE("Attempt to perform seekTo in wrong state: mPlayer=%p, mCurrentState=%u",
- mPlayer.get(), mCurrentState);
- return INVALID_OPERATION;
- }
- if (msec < 0) {
- ALOGW("Attempt to seek to invalid position: %lld", (long long)msec);
- msec = 0;
- }
-
- int64_t durationMs;
- status_t err = mPlayer->getDuration(&durationMs);
-
- if (err != OK) {
- ALOGW("Stream has no duration and is therefore not seekable.");
- return err;
- }
-
- if (msec > durationMs) {
- ALOGW("Attempt to seek to past end of file: request = %lld, durationMs = %lld",
- (long long)msec, (long long)durationMs);
-
- msec = durationMs;
- }
-
- // cache duration
- mCurrentPosition = msec;
- mCurrentSeekMode = mode;
- if (mSeekPosition < 0) {
- mSeekPosition = msec;
- mSeekMode = mode;
- return mPlayer->seekTo(msec, mode);
- }
- ALOGV("Seek in progress - queue up seekTo[%lld, %d]", (long long)msec, mode);
- return NO_ERROR;
-}
-
-status_t MediaPlayer2::seekTo(int64_t msec, MediaPlayer2SeekMode mode) {
- mLockThreadId = getThreadId();
- Mutex::Autolock _l(mLock);
- status_t result = seekTo_l(msec, mode);
- mLockThreadId = 0;
-
- return result;
-}
-
-status_t MediaPlayer2::notifyAt(int64_t mediaTimeUs) {
- Mutex::Autolock _l(mLock);
- if (mPlayer != 0) {
- return INVALID_OPERATION;
- }
-
- return mPlayer->notifyAt(mediaTimeUs);
-}
-
-status_t MediaPlayer2::reset_l() {
- mLoop = false;
- if (mCurrentState == MEDIA_PLAYER2_IDLE) {
- return NO_ERROR;
- }
- if (mPlayer != 0) {
- status_t ret = mPlayer->reset();
- if (ret != NO_ERROR) {
- ALOGE("reset() failed with return code (%d)", ret);
- mCurrentState = MEDIA_PLAYER2_STATE_ERROR;
- } else {
- mPlayer->setListener(NULL);
- mCurrentState = MEDIA_PLAYER2_IDLE;
- mTransitionToNext = false;
- }
- // setDataSource has to be called again to create a
- // new mediaplayer.
- mPlayer = 0;
- return ret;
- }
- clear_l();
- return NO_ERROR;
-}
-
-status_t MediaPlayer2::reset() {
- ALOGV("reset");
- mLockThreadId = getThreadId();
- Mutex::Autolock _l(mLock);
- status_t result = reset_l();
- mLockThreadId = 0;
-
- return result;
-}
-
-status_t MediaPlayer2::setAudioStreamType(audio_stream_type_t type) {
- ALOGV("MediaPlayer2::setAudioStreamType");
- Mutex::Autolock _l(mLock);
- if (mStreamType == type) return NO_ERROR;
- if (mCurrentState & ( MEDIA_PLAYER2_PREPARED | MEDIA_PLAYER2_STARTED |
- MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_PLAYBACK_COMPLETE ) ) {
- // Can't change the stream type after prepare
- ALOGE("setAudioStream called in state %d", mCurrentState);
- return INVALID_OPERATION;
- }
- // cache
- mStreamType = type;
- return OK;
-}
-
-status_t MediaPlayer2::getAudioStreamType(audio_stream_type_t *type) {
- ALOGV("getAudioStreamType");
- Mutex::Autolock _l(mLock);
- *type = mStreamType;
- return OK;
-}
-
-status_t MediaPlayer2::setLooping(int loop) {
- ALOGV("MediaPlayer2::setLooping");
- Mutex::Autolock _l(mLock);
- mLoop = (loop != 0);
- if (mPlayer != 0) {
- return mPlayer->setLooping(loop);
- }
- return OK;
-}
-
-bool MediaPlayer2::isLooping() {
- ALOGV("isLooping");
- Mutex::Autolock _l(mLock);
- if (mPlayer != 0) {
- return mLoop;
- }
- ALOGV("isLooping: no active player");
- return false;
-}
-
-status_t MediaPlayer2::setVolume(float volume) {
- ALOGV("MediaPlayer2::setVolume(%f)", volume);
- Mutex::Autolock _l(mLock);
- mVolume = volume;
- if (mAudioOutput != 0) {
- mAudioOutput->setVolume(volume);
- }
- return OK;
-}
-
-status_t MediaPlayer2::setAudioSessionId(int32_t sessionId) {
- ALOGV("MediaPlayer2::setAudioSessionId(%d)", sessionId);
- Mutex::Autolock _l(mLock);
- if (!(mCurrentState & MEDIA_PLAYER2_IDLE)) {
- ALOGE("setAudioSessionId called in state %d", mCurrentState);
- return INVALID_OPERATION;
- }
- if (sessionId < 0) {
- return BAD_VALUE;
- }
- if (mAudioOutput != NULL && sessionId != mAudioOutput->getSessionId()) {
- mAudioOutput->setSessionId(sessionId);
- }
- return NO_ERROR;
-}
-
-int32_t MediaPlayer2::getAudioSessionId() {
- Mutex::Autolock _l(mLock);
- if (mAudioOutput != NULL) {
- return mAudioOutput->getSessionId();
- }
- return 0;
-}
-
-status_t MediaPlayer2::setAuxEffectSendLevel(float level) {
- ALOGV("MediaPlayer2::setAuxEffectSendLevel(%f)", level);
- Mutex::Autolock _l(mLock);
- mSendLevel = level;
- if (mAudioOutput != 0) {
- return mAudioOutput->setAuxEffectSendLevel(level);
- }
- return OK;
-}
-
-status_t MediaPlayer2::attachAuxEffect(int effectId) {
- ALOGV("MediaPlayer2::attachAuxEffect(%d)", effectId);
- Mutex::Autolock _l(mLock);
- if (mAudioOutput == 0 ||
- (mCurrentState & MEDIA_PLAYER2_IDLE) ||
- (mCurrentState == MEDIA_PLAYER2_STATE_ERROR )) {
- ALOGE("attachAuxEffect called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());
- return INVALID_OPERATION;
- }
-
- return mAudioOutput->attachAuxEffect(effectId);
-}
-
-// always call with lock held
-status_t MediaPlayer2::checkState_l() {
- if (mCurrentState & ( MEDIA_PLAYER2_PREPARED | MEDIA_PLAYER2_STARTED |
- MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_PLAYBACK_COMPLETE) ) {
- // Can't change the audio attributes after prepare
- ALOGE("trying to set audio attributes called in state %d", mCurrentState);
- return INVALID_OPERATION;
- }
- return OK;
-}
-
-status_t MediaPlayer2::setAudioAttributes(const jobject attributes) {
- ALOGV("MediaPlayer2::setAudioAttributes");
- status_t status = INVALID_OPERATION;
- Mutex::Autolock _l(mLock);
- if (checkState_l() != OK) {
- return status;
- }
- mAudioAttributes = new JObjectHolder(attributes);
- status = setAudioAttributes_l(attributes);
- return status;
-}
-
-jobject MediaPlayer2::getAudioAttributes() {
- ALOGV("MediaPlayer2::getAudioAttributes)");
- Mutex::Autolock _l(mLock);
- return mAudioAttributes != NULL ? mAudioAttributes->getJObject() : NULL;
-}
-
-status_t MediaPlayer2::getParameter(int key, Parcel *reply) {
- ALOGV("MediaPlayer2::getParameter(%d)", key);
- Mutex::Autolock _l(mLock);
- if (mPlayer == NULL) {
- ALOGV("getParameter: no active player");
- return INVALID_OPERATION;
- }
-
- status_t status = mPlayer->getParameter(key, reply);
- if (status != OK) {
- ALOGD("getParameter returns %d", status);
- }
- return status;
-}
-
-// for mediametrics
-status_t MediaPlayer2::getMetrics(char **buffer, size_t *length) {
- ALOGD("MediaPlayer2::getMetrics()");
- Mutex::Autolock _l(mLock);
- if (mPlayer == NULL) {
- ALOGV("getMetrics: no active player");
- return INVALID_OPERATION;
- }
-
- status_t status = mPlayer->getMetrics(buffer, length);
- if (status != OK) {
- ALOGD("getMetrics returns %d", status);
- }
- return status;
-}
-
-void MediaPlayer2::notify(int64_t srcId, int msg, int ext1, int ext2, const PlayerMessage *obj) {
- ALOGV("message received srcId=%lld, msg=%d, ext1=%d, ext2=%d",
- (long long)srcId, msg, ext1, ext2);
-
- bool send = true;
- bool locked = false;
-
- // TODO: In the future, we might be on the same thread if the app is
- // running in the same process as the media server. In that case,
- // this will deadlock.
- //
- // The threadId hack below works around this for the care of prepare,
- // seekTo, start, and reset within the same process.
- // FIXME: Remember, this is a hack, it's not even a hack that is applied
- // consistently for all use-cases, this needs to be revisited.
- if (mLockThreadId != getThreadId()) {
- mLock.lock();
- locked = true;
- }
-
- // Allows calls from JNI in idle state to notify errors
- if (!(msg == MEDIA2_ERROR && mCurrentState == MEDIA_PLAYER2_IDLE) && mPlayer == 0) {
- 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;
- }
-
- switch (msg) {
- case MEDIA2_NOP: // interface test message
- break;
- case MEDIA2_PREPARED:
- ALOGV("MediaPlayer2::notify() prepared, srcId=%lld", (long long)srcId);
- if (srcId == mSrcId) {
- mCurrentState = MEDIA_PLAYER2_PREPARED;
- }
- break;
- case MEDIA2_DRM_INFO:
- 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");
- if (mCurrentState == MEDIA_PLAYER2_IDLE) {
- ALOGE("playback complete in idle state");
- }
- if (!mLoop && srcId == mSrcId) {
- mCurrentState = MEDIA_PLAYER2_PLAYBACK_COMPLETE;
- }
- break;
- case MEDIA2_ERROR:
- // Always log errors.
- // ext1: Media framework error code.
- // ext2: Implementation dependant error code.
- ALOGE("error (%d, %d)", ext1, ext2);
- mCurrentState = MEDIA_PLAYER2_STATE_ERROR;
- break;
- case MEDIA2_INFO:
- // ext1: Media framework error code.
- // ext2: Implementation dependant error code.
- if (ext1 != MEDIA2_INFO_VIDEO_TRACK_LAGGING) {
- ALOGW("info/warning (%d, %d)", ext1, ext2);
-
- if (ext1 == MEDIA2_INFO_DATA_SOURCE_START && srcId == mSrcId && mTransitionToNext) {
- mCurrentState = MEDIA_PLAYER2_STARTED;
- mTransitionToNext = false;
- }
- }
- break;
- case MEDIA2_SEEK_COMPLETE:
- ALOGV("Received seek complete");
- if (mSeekPosition != mCurrentPosition || (mSeekMode != mCurrentSeekMode)) {
- ALOGV("Executing queued seekTo(%lld, %d)",
- (long long)mCurrentPosition, mCurrentSeekMode);
- mSeekPosition = -1;
- mSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
- seekTo_l(mCurrentPosition, mCurrentSeekMode);
- }
- else {
- ALOGV("All seeks complete - return to regularly scheduled program");
- mCurrentPosition = mSeekPosition = -1;
- mCurrentSeekMode = mSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
- }
- break;
- case MEDIA2_BUFFERING_UPDATE:
- ALOGV("buffering %d", ext1);
- break;
- case MEDIA2_SET_VIDEO_SIZE:
- ALOGV("New video size %d x %d", ext1, ext2);
- mVideoWidth = ext1;
- mVideoHeight = ext2;
- break;
- case MEDIA2_NOTIFY_TIME:
- ALOGV("Received notify time message");
- break;
- case MEDIA2_TIMED_TEXT:
- ALOGV("Received timed text message");
- break;
- case MEDIA2_SUBTITLE_DATA:
- ALOGV("Received subtitle data message");
- break;
- case MEDIA2_META_DATA:
- ALOGV("Received timed metadata message");
- break;
- default:
- ALOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
- break;
- }
-
- sp<MediaPlayer2Listener> listener = mListener;
- if (locked) mLock.unlock();
-
- // this prevents re-entrant calls into client code
- if ((listener != 0) && send) {
- Mutex::Autolock _l(mNotifyLock);
- ALOGV("callback application");
- listener->notify(srcId, msg, ext1, ext2, obj);
- ALOGV("back from callback");
- }
-}
-
-// Modular DRM
-status_t MediaPlayer2::prepareDrm(
- int64_t srcId, const uint8_t uuid[16], const Vector<uint8_t>& drmSessionId) {
- // TODO change to ALOGV
- ALOGD("prepareDrm: uuid: %p drmSessionId: %p(%zu)", uuid,
- drmSessionId.array(), drmSessionId.size());
- Mutex::Autolock _l(mLock);
- if (mPlayer == NULL) {
- return NO_INIT;
- }
-
- // Only allowed it in player's preparing/prepared state.
- // We get here only if MEDIA_DRM_INFO has already arrived (e.g., prepare is half-way through or
- // completed) so the state change to "prepared" might not have happened yet (e.g., buffering).
- // Still, we can allow prepareDrm for the use case of being called in OnDrmInfoListener.
- if (!(mCurrentState & (MEDIA_PLAYER2_PREPARING | MEDIA_PLAYER2_PREPARED))) {
- ALOGW("prepareDrm(%lld) called in non-prepare state(%d)", (long long)srcId, mCurrentState);
- if (srcId == mSrcId) {
- return INVALID_OPERATION;
- }
- }
-
- if (drmSessionId.isEmpty()) {
- ALOGE("prepareDrm: Unexpected. Can't proceed with crypto. Empty drmSessionId.");
- return INVALID_OPERATION;
- }
-
- // Passing down to mediaserver mainly for creating the crypto
- status_t status = mPlayer->prepareDrm(srcId, uuid, drmSessionId);
- ALOGE_IF(status != OK, "prepareDrm: Failed at mediaserver with ret: %d", status);
-
- // TODO change to ALOGV
- ALOGD("prepareDrm: mediaserver::prepareDrm ret=%d", status);
-
- return status;
-}
-
-status_t MediaPlayer2::releaseDrm(int64_t srcId) {
- Mutex::Autolock _l(mLock);
- if (mPlayer == NULL) {
- return NO_INIT;
- }
-
- // Not allowing releaseDrm in an active/resumable state
- if (mCurrentState & (MEDIA_PLAYER2_STARTED |
- MEDIA_PLAYER2_PAUSED |
- MEDIA_PLAYER2_PLAYBACK_COMPLETE |
- MEDIA_PLAYER2_STATE_ERROR)) {
- ALOGE("releaseDrm Unexpected state %d. Can only be called in stopped/idle.", mCurrentState);
- return INVALID_OPERATION;
- }
-
- status_t status = mPlayer->releaseDrm(srcId);
- // TODO change to ALOGV
- ALOGD("releaseDrm: mediaserver::releaseDrm ret: %d", status);
- if (status != OK) {
- ALOGE("releaseDrm: Failed at mediaserver with ret: %d", status);
- // Overriding to OK so the client proceed with its own cleanup
- // Client can't do more cleanup. mediaserver release its crypto at end of session anyway.
- status = OK;
- }
-
- return status;
-}
-
-status_t MediaPlayer2::setPreferredDevice(jobject device) {
- Mutex::Autolock _l(mLock);
- if (mAudioOutput == NULL) {
- ALOGV("setPreferredDevice: audio sink not init");
- return NO_INIT;
- }
- return mAudioOutput->setPreferredDevice(device);
-}
-
-jobject MediaPlayer2::getRoutedDevice() {
- Mutex::Autolock _l(mLock);
- if (mAudioOutput == NULL) {
- ALOGV("getRoutedDevice: audio sink not init");
- return nullptr;
- }
- return mAudioOutput->getRoutedDevice();
-}
-
-status_t MediaPlayer2::addAudioDeviceCallback(jobject routingDelegate) {
- Mutex::Autolock _l(mLock);
- if (mAudioOutput == NULL) {
- ALOGV("addAudioDeviceCallback: player not init");
- return NO_INIT;
- }
- return mAudioOutput->addAudioDeviceCallback(routingDelegate);
-}
-
-status_t MediaPlayer2::removeAudioDeviceCallback(jobject listener) {
- Mutex::Autolock _l(mLock);
- if (mAudioOutput == NULL) {
- ALOGV("addAudioDeviceCallback: player not init");
- return NO_INIT;
- }
- return mAudioOutput->removeAudioDeviceCallback(listener);
-}
-
-status_t MediaPlayer2::dump(int fd, const Vector<String16>& args) {
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
- result.append(" MediaPlayer2\n");
- snprintf(buffer, 255, " pid(%d), looping(%s)\n", mPid, mLoop?"true": "false");
- result.append(buffer);
-
- sp<MediaPlayer2Interface> player;
- sp<MediaPlayer2AudioOutput> audioOutput;
- bool locked = false;
- for (int i = 0; i < kDumpLockRetries; ++i) {
- if (mLock.tryLock() == NO_ERROR) {
- locked = true;
- break;
- }
- usleep(kDumpLockSleepUs);
- }
-
- if (locked) {
- player = mPlayer;
- audioOutput = mAudioOutput;
- mLock.unlock();
- } else {
- result.append(" lock is taken, no dump from player and audio output\n");
- }
- write(fd, result.string(), result.size());
-
- if (player != NULL) {
- player->dump(fd, args);
- }
- if (audioOutput != 0) {
- audioOutput->dump(fd, args);
- }
- write(fd, "\n", 1);
- return NO_ERROR;
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/Android.bp b/media/libmediaplayer2/nuplayer2/Android.bp
deleted file mode 100644
index 0f69b2e..0000000
--- a/media/libmediaplayer2/nuplayer2/Android.bp
+++ /dev/null
@@ -1,72 +0,0 @@
-cc_library_static {
-
- srcs: [
- "JMediaPlayer2Utils.cpp",
- "JWakeLock.cpp",
- "GenericSource2.cpp",
- "HTTPLiveSource2.cpp",
- "NuPlayer2.cpp",
- "NuPlayer2CCDecoder.cpp",
- "NuPlayer2Decoder.cpp",
- "NuPlayer2DecoderBase.cpp",
- "NuPlayer2DecoderPassThrough.cpp",
- "NuPlayer2Driver.cpp",
- "NuPlayer2Drm.cpp",
- "NuPlayer2Renderer.cpp",
- "RTSPSource2.cpp",
- ],
-
- header_libs: [
- "libbase_headers",
- "libmediaplayer2_headers",
- "media_plugin_headers",
- ],
-
- include_dirs: [
- "frameworks/av/media/libstagefright",
- "frameworks/av/media/libstagefright/httplive",
- "frameworks/av/media/libstagefright/include",
- "frameworks/av/media/libstagefright/mpeg2ts",
- "frameworks/av/media/libstagefright/rtsp",
- "frameworks/av/media/libstagefright/timedtext",
- "frameworks/av/media/ndk",
- "frameworks/base/core/jni",
- ],
-
- cflags: [
- "-Werror",
- "-Wall",
- ],
-
- product_variables: {
- debuggable: {
- cflags: [
- "-DENABLE_STAGEFRIGHT_EXPERIMENTS",
- ],
- }
- },
-
- shared_libs: [
- "libbinder",
- "libui",
- "libgui",
- "libmedia",
- "libmediametrics",
- "libmediandk",
- "libmediandk_utils",
- "libpowermanager",
- ],
-
- static_libs: [
- "libmedia_helper",
- "libmediaplayer2-protos",
- "libmedia2_jni_core",
- ],
-
- name: "libstagefright_nuplayer2",
-
- sanitize: {
- cfi: true,
- },
-
-}
diff --git a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
deleted file mode 100644
index 9552580..0000000
--- a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
+++ /dev/null
@@ -1,1547 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "GenericSource2"
-
-#include "GenericSource2.h"
-#include "NuPlayer2Drm.h"
-
-#include "AnotherPacketSource.h"
-#include <cutils/properties.h>
-#include <media/DataSource.h>
-#include <media/MediaBufferHolder.h>
-#include <media/NdkWrapper.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaClock.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/NdkUtils.h>
-#include <media/stagefright/Utils.h>
-
-namespace android {
-
-static const int kInitialMarkMs = 5000; // 5secs
-
-//static const int kPausePlaybackMarkMs = 2000; // 2secs
-static const int kResumePlaybackMarkMs = 15000; // 15secs
-
-NuPlayer2::GenericSource2::GenericSource2(
- const sp<AMessage> ¬ify,
- uid_t uid,
- const sp<MediaClock> &mediaClock)
- : Source(notify),
- mAudioTimeUs(0),
- mAudioLastDequeueTimeUs(0),
- mVideoTimeUs(0),
- mVideoLastDequeueTimeUs(0),
- mPrevBufferPercentage(-1),
- mPollBufferingGeneration(0),
- mSentPauseOnBuffering(false),
- mAudioDataGeneration(0),
- mVideoDataGeneration(0),
- mFetchSubtitleDataGeneration(0),
- mFetchTimedTextDataGeneration(0),
- mDurationUs(-1ll),
- mAudioIsVorbis(false),
- mIsSecure(false),
- mIsStreaming(false),
- mUID(uid),
- mMediaClock(mediaClock),
- mFd(-1),
- mBitrate(-1ll),
- mPendingReadBufferTypes(0) {
- ALOGV("GenericSource2");
- CHECK(mediaClock != NULL);
-
- mBufferingSettings.mInitialMarkMs = kInitialMarkMs;
- mBufferingSettings.mResumePlaybackMarkMs = kResumePlaybackMarkMs;
- resetDataSource();
-}
-
-void NuPlayer2::GenericSource2::resetDataSource() {
- ALOGV("resetDataSource");
-
- mDisconnected = false;
- mUri.clear();
- mUriHeaders.clear();
- if (mFd >= 0) {
- close(mFd);
- mFd = -1;
- }
- mOffset = 0;
- mLength = 0;
- mStarted = false;
- mPreparing = false;
-
- mIsDrmProtected = false;
- mIsDrmReleased = false;
- mIsSecure = false;
- mMimes.clear();
-}
-
-status_t NuPlayer2::GenericSource2::setDataSource(
- const char *url,
- const KeyedVector<String8, String8> *headers) {
- Mutex::Autolock _l(mLock);
- ALOGV("setDataSource url: %s", url);
-
- resetDataSource();
-
- mUri = url;
-
- if (headers) {
- mUriHeaders = *headers;
- }
-
- // delay data source creation to prepareAsync() to avoid blocking
- // the calling thread in setDataSource for any significant time.
- return OK;
-}
-
-status_t NuPlayer2::GenericSource2::setDataSource(
- int fd, int64_t offset, int64_t length) {
- Mutex::Autolock _l(mLock);
- ALOGV("setDataSource %d/%lld/%lld", fd, (long long)offset, (long long)length);
-
- resetDataSource();
-
- mFd = dup(fd);
- mOffset = offset;
- mLength = length;
-
- // delay data source creation to prepareAsync() to avoid blocking
- // the calling thread in setDataSource for any significant time.
- return OK;
-}
-
-status_t NuPlayer2::GenericSource2::setDataSource(const sp<DataSource>& source) {
- Mutex::Autolock _l(mLock);
- ALOGV("setDataSource (source: %p)", source.get());
-
- resetDataSource();
- mDataSourceWrapper = new AMediaDataSourceWrapper(source);
- return OK;
-}
-
-sp<MetaData> NuPlayer2::GenericSource2::getFileFormatMeta() const {
- Mutex::Autolock _l(mLock);
- return mFileMeta;
-}
-
-status_t NuPlayer2::GenericSource2::initFromDataSource() {
- mExtractor = new AMediaExtractorWrapper(AMediaExtractor_new());
- CHECK(mFd >=0 || mDataSourceWrapper != NULL);
- sp<AMediaDataSourceWrapper> aSourceWrapper = mDataSourceWrapper;
- const int fd = mFd;
-
- mLock.unlock();
- // This might take long time if data source is not reliable.
- status_t err;
- if (aSourceWrapper != NULL) {
- err = mExtractor->setDataSource(aSourceWrapper->getAMediaDataSource());
- } else {
- err = mExtractor->setDataSource(fd, mOffset, mLength);
- }
-
- if (err != OK) {
- ALOGE("initFromDataSource, failed to set extractor data source!");
- mLock.lock();
- return UNKNOWN_ERROR;
- }
-
- size_t numtracks = mExtractor->getTrackCount();
- if (numtracks == 0) {
- ALOGE("initFromDataSource, source has no track!");
- mLock.lock();
- return UNKNOWN_ERROR;
- }
-
- mFileMeta = convertMediaFormatWrapperToMetaData(mExtractor->getFormat());
- mLock.lock();
- if (mFileMeta != NULL) {
- int64_t duration;
- if (mFileMeta->findInt64(kKeyDuration, &duration)) {
- mDurationUs = duration;
- }
- }
-
- int32_t totalBitrate = 0;
-
- mMimes.clear();
-
- for (size_t i = 0; i < numtracks; ++i) {
-
- sp<AMediaFormatWrapper> trackFormat = mExtractor->getTrackFormat(i);
- if (trackFormat == NULL) {
- ALOGE("no metadata for track %zu", i);
- return UNKNOWN_ERROR;
- }
-
- sp<AMediaExtractorWrapper> trackExtractor = new AMediaExtractorWrapper(AMediaExtractor_new());
- if (aSourceWrapper != NULL) {
- trackExtractor->setDataSource(aSourceWrapper->getAMediaDataSource());
- } else {
- trackExtractor->setDataSource(fd, mOffset, mLength);
- }
-
- const char *mime;
- sp<MetaData> meta = convertMediaFormatWrapperToMetaData(trackFormat);
- CHECK(meta->findCString(kKeyMIMEType, &mime));
-
- ALOGV("initFromDataSource track[%zu]: %s", i, mime);
-
- // Do the string compare immediately with "mime",
- // we can't assume "mime" would stay valid after another
- // extractor operation, some extractors might modify meta
- // during getTrack() and make it invalid.
- if (!strncasecmp(mime, "audio/", 6)) {
- if (mAudioTrack.mExtractor == NULL) {
- mAudioTrack.mIndex = i;
- mAudioTrack.mExtractor = trackExtractor;
- mAudioTrack.mExtractor->selectTrack(i);
- mAudioTrack.mPackets = new AnotherPacketSource(meta);
-
- if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
- mAudioIsVorbis = true;
- } else {
- mAudioIsVorbis = false;
- }
-
- mMimes.add(String8(mime));
- }
- } else if (!strncasecmp(mime, "video/", 6)) {
- if (mVideoTrack.mExtractor == NULL) {
- mVideoTrack.mIndex = i;
- mVideoTrack.mExtractor = trackExtractor;
- mVideoTrack.mExtractor->selectTrack(i);
- mVideoTrack.mPackets = new AnotherPacketSource(meta);
-
- // video always at the beginning
- mMimes.insertAt(String8(mime), 0);
- }
- }
-
- mExtractors.push(trackExtractor);
- int64_t durationUs;
- if (meta->findInt64(kKeyDuration, &durationUs)) {
- if (durationUs > mDurationUs) {
- mDurationUs = durationUs;
- }
- }
-
- int32_t bitrate;
- if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) {
- totalBitrate += bitrate;
- } else {
- totalBitrate = -1;
- }
- }
-
- ALOGV("initFromDataSource mExtractors.size(): %zu mIsSecure: %d mime[0]: %s", mExtractors.size(),
- mIsSecure, (mMimes.isEmpty() ? "NONE" : mMimes[0].string()));
-
- if (mExtractors.size() == 0) {
- ALOGE("b/23705695");
- return UNKNOWN_ERROR;
- }
-
- // Modular DRM: The return value doesn't affect source initialization.
- (void)checkDrmInfo();
-
- mBitrate = totalBitrate;
-
- return OK;
-}
-
-status_t NuPlayer2::GenericSource2::getBufferingSettings(
- BufferingSettings* buffering /* nonnull */) {
- {
- Mutex::Autolock _l(mLock);
- *buffering = mBufferingSettings;
- }
-
- ALOGV("getBufferingSettings{%s}", buffering->toString().string());
- return OK;
-}
-
-status_t NuPlayer2::GenericSource2::setBufferingSettings(const BufferingSettings& buffering) {
- ALOGV("setBufferingSettings{%s}", buffering.toString().string());
-
- Mutex::Autolock _l(mLock);
- mBufferingSettings = buffering;
- return OK;
-}
-
-int64_t NuPlayer2::GenericSource2::getLastReadPosition() {
- if (mAudioTrack.mExtractor != NULL) {
- return mAudioTimeUs;
- } else if (mVideoTrack.mExtractor != NULL) {
- return mVideoTimeUs;
- } else {
- return 0;
- }
-}
-
-bool NuPlayer2::GenericSource2::isStreaming() const {
- Mutex::Autolock _l(mLock);
- return mIsStreaming;
-}
-
-NuPlayer2::GenericSource2::~GenericSource2() {
- ALOGV("~GenericSource2");
- if (mLooper != NULL) {
- mLooper->unregisterHandler(id());
- mLooper->stop();
- }
- if (mDataSourceWrapper != NULL) {
- mDataSourceWrapper->close();
- }
- resetDataSource();
-}
-
-void NuPlayer2::GenericSource2::prepareAsync(int64_t startTimeUs) {
- Mutex::Autolock _l(mLock);
- ALOGV("prepareAsync: (looper: %d)", (mLooper != NULL));
-
- if (mLooper == NULL) {
- mLooper = new ALooper;
- mLooper->setName("generic2");
- mLooper->start(false, /* runOnCallingThread */
- true, /* canCallJava */
- PRIORITY_DEFAULT);
-
- mLooper->registerHandler(this);
- }
-
- sp<AMessage> msg = new AMessage(kWhatPrepareAsync, this);
- msg->setInt64("startTimeUs", startTimeUs);
-
- msg->post();
-}
-
-void NuPlayer2::GenericSource2::onPrepareAsync(int64_t startTimeUs) {
- ALOGV("onPrepareAsync: mFd %d mUri %s mDataSourceWrapper: %p",
- mFd, mUri.c_str(), mDataSourceWrapper.get());
-
- if (!mUri.empty()) {
- const char* uri = mUri.c_str();
- size_t numheaders = mUriHeaders.size();
- const char **key_values = numheaders ? new const char *[numheaders * 2] : NULL;
- for (size_t i = 0; i < numheaders; ++i) {
- key_values[i * 2] = mUriHeaders.keyAt(i).c_str();
- key_values[i * 2 + 1] = mUriHeaders.valueAt(i).c_str();
- }
- mLock.unlock();
- AMediaDataSource *aSource = AMediaDataSource_newUri(uri, numheaders, key_values);
- mLock.lock();
- mDataSourceWrapper = aSource ? new AMediaDataSourceWrapper(aSource) : NULL;
- delete[] key_values;
- // For cached streaming cases, we need to wait for enough
- // buffering before reporting prepared.
- mIsStreaming = !strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8);
- }
-
- if (mDisconnected || (mFd < 0 && mDataSourceWrapper == NULL)) {
- ALOGE("mDisconnected(%d) or Failed to create data source!", mDisconnected);
- notifyPreparedAndCleanup(UNKNOWN_ERROR);
- return;
- }
-
- // init extractor from data source
- status_t err = initFromDataSource();
- if (mFd >= 0) {
- close(mFd);
- mFd = -1;
- }
-
- if (err != OK) {
- ALOGE("Failed to init from data source!");
- notifyPreparedAndCleanup(err);
- return;
- }
-
- if (mVideoTrack.mExtractor != NULL) {
- sp<MetaData> meta = getFormatMeta_l(false /* audio */);
- sp<AMessage> msg = new AMessage;
- err = convertMetaDataToMessage(meta, &msg);
- if(err != OK) {
- notifyPreparedAndCleanup(err);
- return;
- }
- notifyVideoSizeChanged(msg);
- }
-
- notifyFlagsChanged(
- // FLAG_SECURE will be known if/when prepareDrm is called by the app
- // FLAG_PROTECTED will be known if/when prepareDrm is called by the app
- FLAG_CAN_PAUSE |
- FLAG_CAN_SEEK_BACKWARD |
- FLAG_CAN_SEEK_FORWARD |
- FLAG_CAN_SEEK);
-
- doSeek(startTimeUs, MediaPlayer2SeekMode::SEEK_CLOSEST);
- finishPrepareAsync();
-
- ALOGV("onPrepareAsync: Done");
-}
-
-void NuPlayer2::GenericSource2::finishPrepareAsync() {
- ALOGV("finishPrepareAsync");
-
- if (mIsStreaming) {
- mPreparing = true;
- ++mPollBufferingGeneration;
- schedulePollBuffering();
- } else {
- notifyPrepared();
- }
-
- if (mAudioTrack.mExtractor != NULL) {
- postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
- }
-
- if (mVideoTrack.mExtractor != NULL) {
- postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
- }
-}
-
-void NuPlayer2::GenericSource2::notifyPreparedAndCleanup(status_t err) {
- if (err != OK) {
- mDataSourceWrapper.clear();
-
- mBitrate = -1;
- mPrevBufferPercentage = -1;
- ++mPollBufferingGeneration;
- }
- notifyPrepared(err);
-}
-
-void NuPlayer2::GenericSource2::start() {
- Mutex::Autolock _l(mLock);
- ALOGI("start");
-
- if (mAudioTrack.mExtractor != NULL) {
- postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
- }
-
- if (mVideoTrack.mExtractor != NULL) {
- postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
- }
-
- mStarted = true;
-}
-
-void NuPlayer2::GenericSource2::stop() {
- Mutex::Autolock _l(mLock);
- mStarted = false;
-}
-
-void NuPlayer2::GenericSource2::pause() {
- Mutex::Autolock _l(mLock);
- mStarted = false;
-}
-
-void NuPlayer2::GenericSource2::resume() {
- Mutex::Autolock _l(mLock);
- mStarted = true;
-}
-
-void NuPlayer2::GenericSource2::disconnect() {
- {
- Mutex::Autolock _l(mLock);
- mDisconnected = true;
- }
- if (mDataSourceWrapper != NULL) {
- mDataSourceWrapper->close();
- }
-}
-
-status_t NuPlayer2::GenericSource2::feedMoreTSData() {
- return OK;
-}
-
-void NuPlayer2::GenericSource2::onMessageReceived(const sp<AMessage> &msg) {
- Mutex::Autolock _l(mLock);
- switch (msg->what()) {
- case kWhatPrepareAsync:
- {
- int64_t startTimeUs;
- CHECK(msg->findInt64("startTimeUs", &startTimeUs));
- onPrepareAsync(startTimeUs);
- break;
- }
- case kWhatFetchSubtitleData:
- {
- fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
- mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
- break;
- }
-
- case kWhatFetchTimedTextData:
- {
- fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
- mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
- break;
- }
-
- case kWhatSendSubtitleData:
- {
- sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
- mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
- break;
- }
-
- case kWhatSendGlobalTimedTextData:
- {
- sendGlobalTextData(kWhatTimedTextData, mFetchTimedTextDataGeneration, msg);
- break;
- }
- case kWhatSendTimedTextData:
- {
- sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
- mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
- break;
- }
-
- case kWhatChangeAVSource:
- {
- int32_t trackIndex;
- CHECK(msg->findInt32("trackIndex", &trackIndex));
- const sp<AMediaExtractorWrapper> extractor = mExtractors.itemAt(trackIndex);
-
- Track* track;
- AString mime;
- media_track_type trackType, counterpartType;
- sp<AMediaFormatWrapper> format = extractor->getTrackFormat(trackIndex);
- format->getString(AMEDIAFORMAT_KEY_MIME, &mime);
- if (!strncasecmp(mime.c_str(), "audio/", 6)) {
- track = &mAudioTrack;
- trackType = MEDIA_TRACK_TYPE_AUDIO;
- counterpartType = MEDIA_TRACK_TYPE_VIDEO;;
- } else {
- CHECK(!strncasecmp(mime.c_str(), "video/", 6));
- track = &mVideoTrack;
- trackType = MEDIA_TRACK_TYPE_VIDEO;
- counterpartType = MEDIA_TRACK_TYPE_AUDIO;;
- }
-
-
- track->mExtractor = extractor;
- track->mExtractor->selectSingleTrack(trackIndex);
- track->mIndex = trackIndex;
- ++mAudioDataGeneration;
- ++mVideoDataGeneration;
-
- int64_t timeUs, actualTimeUs;
- const bool formatChange = true;
- if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
- timeUs = mAudioLastDequeueTimeUs;
- } else {
- timeUs = mVideoLastDequeueTimeUs;
- }
- readBuffer(trackType, timeUs, MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC /* mode */,
- &actualTimeUs, formatChange);
- readBuffer(counterpartType, -1, MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC /* mode */,
- NULL, !formatChange);
- ALOGV("timeUs %lld actualTimeUs %lld", (long long)timeUs, (long long)actualTimeUs);
-
- break;
- }
-
- case kWhatSeek:
- {
- onSeek(msg);
- break;
- }
-
- case kWhatReadBuffer:
- {
- onReadBuffer(msg);
- break;
- }
-
- case kWhatPollBuffering:
- {
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
- if (generation == mPollBufferingGeneration) {
- onPollBuffering();
- }
- break;
- }
-
- default:
- Source::onMessageReceived(msg);
- break;
- }
-}
-
-void NuPlayer2::GenericSource2::fetchTextData(
- uint32_t sendWhat,
- media_track_type type,
- int32_t curGen,
- const sp<AnotherPacketSource>& packets,
- const sp<AMessage>& msg) {
- int32_t msgGeneration;
- CHECK(msg->findInt32("generation", &msgGeneration));
- if (msgGeneration != curGen) {
- // stale
- return;
- }
-
- int32_t avail;
- if (packets->hasBufferAvailable(&avail)) {
- return;
- }
-
- int64_t timeUs;
- CHECK(msg->findInt64("timeUs", &timeUs));
-
- int64_t subTimeUs = 0;
- readBuffer(type, timeUs, MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC /* mode */, &subTimeUs);
-
- status_t eosResult;
- if (!packets->hasBufferAvailable(&eosResult)) {
- return;
- }
-
- if (msg->what() == kWhatFetchSubtitleData) {
- subTimeUs -= 1000000ll; // send subtile data one second earlier
- }
- sp<AMessage> msg2 = new AMessage(sendWhat, this);
- msg2->setInt32("generation", msgGeneration);
- mMediaClock->addTimer(msg2, subTimeUs);
-}
-
-void NuPlayer2::GenericSource2::sendTextData(
- uint32_t what,
- media_track_type type,
- int32_t curGen,
- const sp<AnotherPacketSource>& packets,
- const sp<AMessage>& msg) {
- int32_t msgGeneration;
- CHECK(msg->findInt32("generation", &msgGeneration));
- if (msgGeneration != curGen) {
- // stale
- return;
- }
-
- int64_t subTimeUs;
- if (packets->nextBufferTime(&subTimeUs) != OK) {
- return;
- }
-
- int64_t nextSubTimeUs;
- readBuffer(type, -1, MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC /* mode */, &nextSubTimeUs);
-
- sp<ABuffer> buffer;
- status_t dequeueStatus = packets->dequeueAccessUnit(&buffer);
- if (dequeueStatus == OK) {
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", what);
- notify->setBuffer("buffer", buffer);
- notify->post();
-
- if (msg->what() == kWhatSendSubtitleData) {
- nextSubTimeUs -= 1000000ll; // send subtile data one second earlier
- }
- mMediaClock->addTimer(msg, nextSubTimeUs);
- }
-}
-
-void NuPlayer2::GenericSource2::sendGlobalTextData(
- uint32_t what,
- int32_t curGen,
- sp<AMessage> msg) {
- int32_t msgGeneration;
- CHECK(msg->findInt32("generation", &msgGeneration));
- if (msgGeneration != curGen) {
- // stale
- return;
- }
-
- void *data = NULL;
- size_t size = 0;
- if (mTimedTextTrack.mExtractor->getTrackFormat(mTimedTextTrack.mIndex)->getBuffer(
- "text", &data, &size)) {
- mGlobalTimedText = new ABuffer(size);
- if (mGlobalTimedText->data()) {
- memcpy(mGlobalTimedText->data(), data, size);
- sp<AMessage> globalMeta = mGlobalTimedText->meta();
- globalMeta->setInt64("timeUs", 0);
- globalMeta->setString("mime", MEDIA_MIMETYPE_TEXT_3GPP);
- globalMeta->setInt32("global", 1);
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", what);
- notify->setBuffer("buffer", mGlobalTimedText);
- notify->post();
- }
- }
-}
-
-sp<AMessage> NuPlayer2::GenericSource2::getFormat(bool audio) {
- Mutex::Autolock _l(mLock);
- return getFormat_l(audio);
-}
-
-sp<MetaData> NuPlayer2::GenericSource2::getFormatMeta(bool audio) {
- Mutex::Autolock _l(mLock);
- return getFormatMeta_l(audio);
-}
-
-sp<AMessage> NuPlayer2::GenericSource2::getFormat_l(bool audio) {
- sp<AMediaExtractorWrapper> extractor = audio ? mAudioTrack.mExtractor : mVideoTrack.mExtractor;
- size_t trackIndex = audio ? mAudioTrack.mIndex : mVideoTrack.mIndex;
-
- if (extractor == NULL) {
- return NULL;
- }
-
- return extractor->getTrackFormat(trackIndex)->toAMessage();
-}
-
-sp<MetaData> NuPlayer2::GenericSource2::getFormatMeta_l(bool audio) {
- sp<AMediaExtractorWrapper> extractor = audio ? mAudioTrack.mExtractor : mVideoTrack.mExtractor;
- size_t trackIndex = audio ? mAudioTrack.mIndex : mVideoTrack.mIndex;
-
- if (extractor == NULL) {
- return NULL;
- }
-
- return convertMediaFormatWrapperToMetaData(extractor->getTrackFormat(trackIndex));
-}
-
-status_t NuPlayer2::GenericSource2::dequeueAccessUnit(
- bool audio, sp<ABuffer> *accessUnit) {
- Mutex::Autolock _l(mLock);
- // If has gone through stop/releaseDrm sequence, we no longer send down any buffer b/c
- // the codec's crypto object has gone away (b/37960096).
- // Note: This will be unnecessary when stop() changes behavior and releases codec (b/35248283).
- if (!mStarted && mIsDrmReleased) {
- return -EWOULDBLOCK;
- }
-
- Track *track = audio ? &mAudioTrack : &mVideoTrack;
-
- if (track->mExtractor == NULL) {
- return -EWOULDBLOCK;
- }
-
- status_t finalResult;
- if (!track->mPackets->hasBufferAvailable(&finalResult)) {
- if (finalResult == OK) {
- postReadBuffer(
- audio ? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
- return -EWOULDBLOCK;
- }
- return finalResult;
- }
-
- status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
-
- // start pulling in more buffers if cache is running low
- // so that decoder has less chance of being starved
- if (!mIsStreaming) {
- if (track->mPackets->getAvailableBufferCount(&finalResult) < 2) {
- postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
- }
- } else {
- int64_t durationUs = track->mPackets->getBufferedDurationUs(&finalResult);
- // TODO: maxRebufferingMarkMs could be larger than
- // mBufferingSettings.mResumePlaybackMarkMs
- int64_t restartBufferingMarkUs =
- mBufferingSettings.mResumePlaybackMarkMs * 1000ll / 2;
- if (finalResult == OK) {
- if (durationUs < restartBufferingMarkUs) {
- postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
- }
- if (track->mPackets->getAvailableBufferCount(&finalResult) < 2
- && !mSentPauseOnBuffering && !mPreparing) {
- mSentPauseOnBuffering = true;
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatPauseOnBufferingStart);
- notify->post();
- }
- }
- }
-
- if (result != OK) {
- if (mSubtitleTrack.mExtractor != NULL) {
- mSubtitleTrack.mPackets->clear();
- mFetchSubtitleDataGeneration++;
- }
- if (mTimedTextTrack.mExtractor != NULL) {
- mTimedTextTrack.mPackets->clear();
- mFetchTimedTextDataGeneration++;
- }
- return result;
- }
-
- int64_t timeUs;
- status_t eosResult; // ignored
- CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
- if (audio) {
- mAudioLastDequeueTimeUs = timeUs;
- } else {
- mVideoLastDequeueTimeUs = timeUs;
- }
-
- if (mSubtitleTrack.mExtractor != NULL
- && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
- sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, this);
- msg->setInt64("timeUs", timeUs);
- msg->setInt32("generation", mFetchSubtitleDataGeneration);
- msg->post();
- }
-
- if (mTimedTextTrack.mExtractor != NULL
- && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
- sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, this);
- msg->setInt64("timeUs", timeUs);
- msg->setInt32("generation", mFetchTimedTextDataGeneration);
- msg->post();
- }
-
- return result;
-}
-
-status_t NuPlayer2::GenericSource2::getDuration(int64_t *durationUs) {
- Mutex::Autolock _l(mLock);
- *durationUs = mDurationUs;
- return OK;
-}
-
-size_t NuPlayer2::GenericSource2::getTrackCount() const {
- Mutex::Autolock _l(mLock);
- return mExtractors.size();
-}
-
-sp<AMessage> NuPlayer2::GenericSource2::getTrackInfo(size_t trackIndex) const {
- Mutex::Autolock _l(mLock);
- size_t trackCount = mExtractors.size();
- if (trackIndex >= trackCount) {
- return NULL;
- }
-
- sp<AMessage> format = mExtractors.itemAt(trackIndex)->getTrackFormat(trackIndex)->toAMessage();
- if (format == NULL) {
- ALOGE("no metadata for track %zu", trackIndex);
- return NULL;
- }
-
- AString mime;
- CHECK(format->findString(AMEDIAFORMAT_KEY_MIME, &mime));
-
- int32_t trackType;
- if (!strncasecmp(mime.c_str(), "video/", 6)) {
- trackType = MEDIA_TRACK_TYPE_VIDEO;
- } else if (!strncasecmp(mime.c_str(), "audio/", 6)) {
- trackType = MEDIA_TRACK_TYPE_AUDIO;
- } else if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_TEXT_3GPP)) {
- trackType = MEDIA_TRACK_TYPE_TIMEDTEXT;
- } else {
- trackType = MEDIA_TRACK_TYPE_UNKNOWN;
- }
- format->setInt32("type", trackType);
-
- AString lang;
- if (!format->findString("language", &lang)) {
- format->setString("language", "und");
- }
-
- if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
- int32_t isAutoselect = 1, isDefault = 0, isForced = 0;
- format->findInt32(AMEDIAFORMAT_KEY_IS_AUTOSELECT, &isAutoselect);
- format->findInt32(AMEDIAFORMAT_KEY_IS_DEFAULT, &isDefault);
- format->findInt32(AMEDIAFORMAT_KEY_IS_FORCED_SUBTITLE, &isForced);
-
- format->setInt32("auto", !!isAutoselect);
- format->setInt32("default", !!isDefault);
- format->setInt32("forced", !!isForced);
- }
-
- return format;
-}
-
-ssize_t NuPlayer2::GenericSource2::getSelectedTrack(media_track_type type) const {
- Mutex::Autolock _l(mLock);
- const Track *track = NULL;
- switch (type) {
- case MEDIA_TRACK_TYPE_VIDEO:
- track = &mVideoTrack;
- break;
- case MEDIA_TRACK_TYPE_AUDIO:
- track = &mAudioTrack;
- break;
- case MEDIA_TRACK_TYPE_TIMEDTEXT:
- track = &mTimedTextTrack;
- break;
- case MEDIA_TRACK_TYPE_SUBTITLE:
- track = &mSubtitleTrack;
- break;
- default:
- break;
- }
-
- if (track != NULL && track->mExtractor != NULL) {
- return track->mIndex;
- }
-
- return -1;
-}
-
-status_t NuPlayer2::GenericSource2::selectTrack(size_t trackIndex, bool select, int64_t timeUs) {
- Mutex::Autolock _l(mLock);
- ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex);
-
- if (trackIndex >= mExtractors.size()) {
- return BAD_INDEX;
- }
-
- if (!select) {
- Track* track = NULL;
- if (mSubtitleTrack.mExtractor != NULL && trackIndex == mSubtitleTrack.mIndex) {
- track = &mSubtitleTrack;
- mFetchSubtitleDataGeneration++;
- } else if (mTimedTextTrack.mExtractor != NULL && trackIndex == mTimedTextTrack.mIndex) {
- track = &mTimedTextTrack;
- mFetchTimedTextDataGeneration++;
- }
- if (track == NULL) {
- return INVALID_OPERATION;
- }
- track->mExtractor = NULL;
- track->mPackets->clear();
- return OK;
- }
-
- const sp<AMediaExtractorWrapper> extractor = mExtractors.itemAt(trackIndex);
- sp<MetaData> meta = convertMediaFormatWrapperToMetaData(extractor->getTrackFormat(trackIndex));
- const char *mime;
- CHECK(meta->findCString(kKeyMIMEType, &mime));
- if (!strncasecmp(mime, "text/", 5)) {
- bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP);
- Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack;
- if (track->mExtractor != NULL && track->mIndex == trackIndex) {
- return OK;
- }
- track->mIndex = trackIndex;
- track->mExtractor = mExtractors.itemAt(trackIndex);
- track->mExtractor->selectSingleTrack(trackIndex);
- if (track->mPackets == NULL) {
- track->mPackets = new AnotherPacketSource(meta);
- } else {
- track->mPackets->clear();
- track->mPackets->setFormat(meta);
-
- }
-
- if (isSubtitle) {
- mFetchSubtitleDataGeneration++;
- } else {
- mFetchTimedTextDataGeneration++;
- }
-
- status_t eosResult; // ignored
- if (mSubtitleTrack.mExtractor != NULL
- && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
- sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, this);
- msg->setInt64("timeUs", timeUs);
- msg->setInt32("generation", mFetchSubtitleDataGeneration);
- msg->post();
- }
-
- sp<AMessage> msg2 = new AMessage(kWhatSendGlobalTimedTextData, this);
- msg2->setInt32("generation", mFetchTimedTextDataGeneration);
- msg2->post();
-
- if (mTimedTextTrack.mExtractor != NULL
- && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
- sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, this);
- msg->setInt64("timeUs", timeUs);
- msg->setInt32("generation", mFetchTimedTextDataGeneration);
- msg->post();
- }
-
- return OK;
- } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) {
- bool audio = !strncasecmp(mime, "audio/", 6);
- Track *track = audio ? &mAudioTrack : &mVideoTrack;
- if (track->mExtractor != NULL && track->mIndex == trackIndex) {
- return OK;
- }
-
- sp<AMessage> msg = new AMessage(kWhatChangeAVSource, this);
- msg->setInt32("trackIndex", trackIndex);
- msg->post();
- return OK;
- }
-
- return INVALID_OPERATION;
-}
-
-status_t NuPlayer2::GenericSource2::seekTo(int64_t seekTimeUs, MediaPlayer2SeekMode mode) {
- ALOGV("seekTo: %lld, %d", (long long)seekTimeUs, mode);
- sp<AMessage> msg = new AMessage(kWhatSeek, this);
- msg->setInt64("seekTimeUs", seekTimeUs);
- msg->setInt32("mode", mode);
-
- // Need to call readBuffer on |mLooper| to ensure the calls to
- // IMediaSource::read* are serialized. Note that IMediaSource::read*
- // is called without |mLock| acquired and MediaSource is not thread safe.
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- }
-
- return err;
-}
-
-void NuPlayer2::GenericSource2::onSeek(const sp<AMessage>& msg) {
- int64_t seekTimeUs;
- int32_t mode;
- CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
- CHECK(msg->findInt32("mode", &mode));
-
- sp<AMessage> response = new AMessage;
- status_t err = doSeek(seekTimeUs, (MediaPlayer2SeekMode)mode);
- response->setInt32("err", err);
-
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
-}
-
-status_t NuPlayer2::GenericSource2::doSeek(int64_t seekTimeUs, MediaPlayer2SeekMode mode) {
- if (mVideoTrack.mExtractor != NULL) {
- ++mVideoDataGeneration;
-
- int64_t actualTimeUs;
- readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, mode, &actualTimeUs);
-
- if (mode != MediaPlayer2SeekMode::SEEK_CLOSEST) {
- seekTimeUs = actualTimeUs;
- }
- mVideoLastDequeueTimeUs = actualTimeUs;
- }
-
- if (mAudioTrack.mExtractor != NULL) {
- ++mAudioDataGeneration;
- readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs, MediaPlayer2SeekMode::SEEK_CLOSEST);
- mAudioLastDequeueTimeUs = seekTimeUs;
- }
-
- if (mSubtitleTrack.mExtractor != NULL) {
- mSubtitleTrack.mPackets->clear();
- mFetchSubtitleDataGeneration++;
- }
-
- if (mTimedTextTrack.mExtractor != NULL) {
- mTimedTextTrack.mPackets->clear();
- mFetchTimedTextDataGeneration++;
- }
-
- ++mPollBufferingGeneration;
- schedulePollBuffering();
- return OK;
-}
-
-sp<ABuffer> NuPlayer2::GenericSource2::mediaBufferToABuffer(
- MediaBufferBase* mb,
- media_track_type trackType) {
- bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO;
- size_t outLength = mb->range_length();
-
- if (audio && mAudioIsVorbis) {
- outLength += sizeof(int32_t);
- }
-
- sp<ABuffer> ab;
-
- if (mIsDrmProtected) {
- // Modular DRM
- // Enabled for both video/audio so 1) media buffer is reused without extra copying
- // 2) meta data can be retrieved in onInputBufferFetched for calling queueSecureInputBuffer.
-
- // data is already provided in the buffer
- ab = new ABuffer(NULL, mb->range_length());
- ab->meta()->setObject("mediaBufferHolder", new MediaBufferHolder(mb));
-
- // Modular DRM: Required b/c of the above add_ref.
- // If ref>0, there must be an observer, or it'll crash at release().
- // TODO: MediaBuffer might need to be revised to ease such need.
- mb->setObserver(this);
- // setMediaBufferBase() interestingly doesn't increment the ref count on its own.
- // Extra increment (since we want to keep mb alive and attached to ab beyond this function
- // call. This is to counter the effect of mb->release() towards the end.
- mb->add_ref();
-
- } else {
- ab = new ABuffer(outLength);
- memcpy(ab->data(),
- (const uint8_t *)mb->data() + mb->range_offset(),
- mb->range_length());
- }
-
- if (audio && mAudioIsVorbis) {
- int32_t numPageSamples;
- if (!mb->meta_data().findInt32(kKeyValidSamples, &numPageSamples)) {
- numPageSamples = -1;
- }
-
- uint8_t* abEnd = ab->data() + mb->range_length();
- memcpy(abEnd, &numPageSamples, sizeof(numPageSamples));
- }
-
- sp<AMessage> meta = ab->meta();
-
- int64_t timeUs;
- CHECK(mb->meta_data().findInt64(kKeyTime, &timeUs));
- meta->setInt64("timeUs", timeUs);
-
- if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
- int32_t layerId;
- if (mb->meta_data().findInt32(kKeyTemporalLayerId, &layerId)) {
- meta->setInt32("temporal-layer-id", layerId);
- }
- }
-
- if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
- AString mime;
- sp<AMediaExtractorWrapper> extractor = mTimedTextTrack.mExtractor;
- size_t trackIndex = mTimedTextTrack.mIndex;
- CHECK(extractor != NULL
- && extractor->getTrackFormat(trackIndex)->getString(AMEDIAFORMAT_KEY_MIME, &mime));
- meta->setString("mime", mime.c_str());
- }
-
- int64_t durationUs;
- if (mb->meta_data().findInt64(kKeyDuration, &durationUs)) {
- meta->setInt64("durationUs", durationUs);
- }
-
- if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
- meta->setInt32(AMEDIAFORMAT_KEY_TRACK_INDEX, mSubtitleTrack.mIndex);
- }
-
- uint32_t dataType; // unused
- const void *seiData;
- size_t seiLength;
- if (mb->meta_data().findData(kKeySEI, &dataType, &seiData, &seiLength)) {
- sp<ABuffer> sei = ABuffer::CreateAsCopy(seiData, seiLength);;
- meta->setBuffer("sei", sei);
- }
-
- const void *mpegUserDataPointer;
- size_t mpegUserDataLength;
- if (mb->meta_data().findData(
- kKeyMpegUserData, &dataType, &mpegUserDataPointer, &mpegUserDataLength)) {
- sp<ABuffer> mpegUserData = ABuffer::CreateAsCopy(mpegUserDataPointer, mpegUserDataLength);
- meta->setBuffer(AMEDIAFORMAT_KEY_MPEG_USER_DATA, mpegUserData);
- }
-
- mb->release();
- mb = NULL;
-
- return ab;
-}
-
-int32_t NuPlayer2::GenericSource2::getDataGeneration(media_track_type type) const {
- int32_t generation = -1;
- switch (type) {
- case MEDIA_TRACK_TYPE_VIDEO:
- generation = mVideoDataGeneration;
- break;
- case MEDIA_TRACK_TYPE_AUDIO:
- generation = mAudioDataGeneration;
- break;
- case MEDIA_TRACK_TYPE_TIMEDTEXT:
- generation = mFetchTimedTextDataGeneration;
- break;
- case MEDIA_TRACK_TYPE_SUBTITLE:
- generation = mFetchSubtitleDataGeneration;
- break;
- default:
- break;
- }
-
- return generation;
-}
-
-void NuPlayer2::GenericSource2::postReadBuffer(media_track_type trackType) {
- if ((mPendingReadBufferTypes & (1 << trackType)) == 0) {
- mPendingReadBufferTypes |= (1 << trackType);
- sp<AMessage> msg = new AMessage(kWhatReadBuffer, this);
- msg->setInt32("trackType", trackType);
- msg->post();
- }
-}
-
-void NuPlayer2::GenericSource2::onReadBuffer(const sp<AMessage>& msg) {
- int32_t tmpType;
- CHECK(msg->findInt32("trackType", &tmpType));
- media_track_type trackType = (media_track_type)tmpType;
- mPendingReadBufferTypes &= ~(1 << trackType);
- readBuffer(trackType);
-}
-
-void NuPlayer2::GenericSource2::readBuffer(
- media_track_type trackType, int64_t seekTimeUs, MediaPlayer2SeekMode mode,
- int64_t *actualTimeUs, bool formatChange) {
- Track *track;
- size_t maxBuffers = 1;
- switch (trackType) {
- case MEDIA_TRACK_TYPE_VIDEO:
- track = &mVideoTrack;
- maxBuffers = 8; // too large of a number may influence seeks
- break;
- case MEDIA_TRACK_TYPE_AUDIO:
- track = &mAudioTrack;
- maxBuffers = 64;
- break;
- case MEDIA_TRACK_TYPE_SUBTITLE:
- track = &mSubtitleTrack;
- break;
- case MEDIA_TRACK_TYPE_TIMEDTEXT:
- track = &mTimedTextTrack;
- break;
- default:
- TRESPASS();
- }
-
- if (track->mExtractor == NULL) {
- return;
- }
-
- if (actualTimeUs) {
- *actualTimeUs = seekTimeUs;
- }
-
-
- bool seeking = false;
- sp<AMediaExtractorWrapper> extractor = track->mExtractor;
- if (seekTimeUs >= 0) {
- extractor->seekTo(seekTimeUs, mode);
- seeking = true;
- }
-
- int32_t generation = getDataGeneration(trackType);
- for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
- Vector<sp<ABuffer> > aBuffers;
-
- mLock.unlock();
-
- sp<AMediaFormatWrapper> format;
- ssize_t sampleSize = -1;
- status_t err = extractor->getSampleFormat(format);
- if (err == OK) {
- sampleSize = extractor->getSampleSize();
- }
-
- if (err != OK || sampleSize < 0) {
- mLock.lock();
- track->mPackets->signalEOS(err != OK ? err : ERROR_END_OF_STREAM);
- break;
- }
-
- sp<ABuffer> abuf = new ABuffer(sampleSize);
- sampleSize = extractor->readSampleData(abuf);
- mLock.lock();
-
- // in case track has been changed since we don't have lock for some time.
- if (generation != getDataGeneration(trackType)) {
- break;
- }
-
- int64_t timeUs = extractor->getSampleTime();
- if (timeUs < 0) {
- track->mPackets->signalEOS(ERROR_MALFORMED);
- break;
- }
-
- sp<AMessage> meta = abuf->meta();
- format->writeToAMessage(meta);
- meta->setInt64("timeUs", timeUs);
- if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
- mAudioTimeUs = timeUs;
- } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
- mVideoTimeUs = timeUs;
- }
-
- sp<AMediaCodecCryptoInfoWrapper> cryptInfo = extractor->getSampleCryptoInfo();
- if (cryptInfo != NULL) {
- meta->setObject("cryptInfo", cryptInfo);
- }
-
- queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track);
-
- if (numBuffers == 0 && actualTimeUs != nullptr) {
- *actualTimeUs = timeUs;
- }
- if (seeking) {
- if (meta != nullptr && mode == MediaPlayer2SeekMode::SEEK_CLOSEST
- && seekTimeUs > timeUs) {
- sp<AMessage> extra = new AMessage;
- extra->setInt64("resume-at-mediaTimeUs", seekTimeUs);
- meta->setMessage("extra", extra);
- }
- }
-
- track->mPackets->queueAccessUnit(abuf);
- formatChange = false;
- seeking = false;
- ++numBuffers;
- extractor->advance();
-
- }
-
- if (mIsStreaming
- && (trackType == MEDIA_TRACK_TYPE_VIDEO || trackType == MEDIA_TRACK_TYPE_AUDIO)) {
- status_t finalResult;
- int64_t durationUs = track->mPackets->getBufferedDurationUs(&finalResult);
-
- // TODO: maxRebufferingMarkMs could be larger than
- // mBufferingSettings.mResumePlaybackMarkMs
- int64_t markUs = (mPreparing ? mBufferingSettings.mInitialMarkMs
- : mBufferingSettings.mResumePlaybackMarkMs) * 1000ll;
- if (finalResult == ERROR_END_OF_STREAM || durationUs >= markUs) {
- if (mPreparing || mSentPauseOnBuffering) {
- Track *counterTrack =
- (trackType == MEDIA_TRACK_TYPE_VIDEO ? &mAudioTrack : &mVideoTrack);
- if (counterTrack->mExtractor != NULL) {
- durationUs = counterTrack->mPackets->getBufferedDurationUs(&finalResult);
- }
- if (finalResult == ERROR_END_OF_STREAM || durationUs >= markUs) {
- if (mPreparing) {
- notifyPrepared();
- mPreparing = false;
- } else {
- mSentPauseOnBuffering = false;
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatResumeOnBufferingEnd);
- notify->post();
- }
- }
- }
- return;
- }
-
- postReadBuffer(trackType);
- }
-}
-
-void NuPlayer2::GenericSource2::queueDiscontinuityIfNeeded(
- bool seeking, bool formatChange, media_track_type trackType, Track *track) {
- // formatChange && seeking: track whose source is changed during selection
- // formatChange && !seeking: track whose source is not changed during selection
- // !formatChange: normal seek
- if ((seeking || formatChange)
- && (trackType == MEDIA_TRACK_TYPE_AUDIO
- || trackType == MEDIA_TRACK_TYPE_VIDEO)) {
- ATSParser::DiscontinuityType type = (formatChange && seeking)
- ? ATSParser::DISCONTINUITY_FORMATCHANGE
- : ATSParser::DISCONTINUITY_NONE;
- track->mPackets->queueDiscontinuity(type, NULL /* extra */, true /* discard */);
- }
-}
-
-void NuPlayer2::GenericSource2::notifyBufferingUpdate(int32_t percentage) {
- // Buffering percent could go backward as it's estimated from remaining
- // data and last access time. This could cause the buffering position
- // drawn on media control to jitter slightly. Remember previously reported
- // percentage and don't allow it to go backward.
- if (percentage < mPrevBufferPercentage) {
- percentage = mPrevBufferPercentage;
- } else if (percentage > 100) {
- percentage = 100;
- }
-
- mPrevBufferPercentage = percentage;
-
- ALOGV("notifyBufferingUpdate: buffering %d%%", percentage);
-
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatBufferingUpdate);
- notify->setInt32("percentage", percentage);
- notify->post();
-}
-
-void NuPlayer2::GenericSource2::schedulePollBuffering() {
- if (mIsStreaming) {
- sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
- msg->setInt32("generation", mPollBufferingGeneration);
- // Enquires buffering status every second.
- msg->post(1000000ll);
- }
-}
-
-void NuPlayer2::GenericSource2::onPollBuffering() {
- int64_t cachedDurationUs = -1ll;
-
- sp<AMediaExtractorWrapper> extractor;
- if (mVideoTrack.mExtractor != NULL) {
- extractor = mVideoTrack.mExtractor;
- } else if (mAudioTrack.mExtractor != NULL) {
- extractor = mAudioTrack.mExtractor;
- }
-
- if (extractor != NULL) {
- cachedDurationUs = extractor->getCachedDuration();
- }
-
- if (cachedDurationUs >= 0ll) {
- ssize_t sampleSize = extractor->getSampleSize();
- if (sampleSize >= 0ll) {
- int64_t cachedPosUs = getLastReadPosition() + cachedDurationUs;
- int percentage = 100.0 * cachedPosUs / mDurationUs;
- if (percentage > 100) {
- percentage = 100;
- }
-
- notifyBufferingUpdate(percentage);
- ALOGV("onPollBuffering: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f);
- } else {
- notifyBufferingUpdate(100);
- ALOGV("onPollBuffering: EOS");
- }
- }
-
- schedulePollBuffering();
-}
-
-// Modular DRM
-status_t NuPlayer2::GenericSource2::prepareDrm(
- const uint8_t uuid[16],
- const Vector<uint8_t> &drmSessionId,
- sp<AMediaCryptoWrapper> *outCrypto) {
- Mutex::Autolock _l(mLock);
- ALOGV("prepareDrm");
-
- mIsDrmProtected = false;
- mIsDrmReleased = false;
- mIsSecure = false;
-
- status_t status = OK;
- sp<AMediaCryptoWrapper> crypto =
- new AMediaCryptoWrapper(uuid, drmSessionId.array(), drmSessionId.size());
- if (crypto == NULL) {
- ALOGE("prepareDrm: failed to create crypto.");
- return UNKNOWN_ERROR;
- }
- ALOGV("prepareDrm: crypto created for uuid: %s",
- DrmUUID::toHexString(uuid).string());
-
- *outCrypto = crypto;
- // as long a there is an active crypto
- mIsDrmProtected = true;
-
- if (mMimes.size() == 0) {
- status = UNKNOWN_ERROR;
- ALOGE("prepareDrm: Unexpected. Must have at least one track. status: %d", status);
- return status;
- }
-
- // first mime in this list is either the video track, or the first audio track
- const char *mime = mMimes[0].string();
- mIsSecure = crypto->requiresSecureDecoderComponent(mime);
- ALOGV("prepareDrm: requiresSecureDecoderComponent mime: %s isSecure: %d",
- mime, mIsSecure);
-
- // Checking the member flags while in the looper to send out the notification.
- // The legacy mDecryptHandle!=NULL check (for FLAG_PROTECTED) is equivalent to mIsDrmProtected.
- notifyFlagsChanged(
- (mIsSecure ? FLAG_SECURE : 0) |
- // Setting "protected screen" only for L1: b/38390836
- (mIsSecure ? FLAG_PROTECTED : 0) |
- FLAG_CAN_PAUSE |
- FLAG_CAN_SEEK_BACKWARD |
- FLAG_CAN_SEEK_FORWARD |
- FLAG_CAN_SEEK);
-
- if (status == OK) {
- ALOGV("prepareDrm: mCrypto: %p", outCrypto->get());
- ALOGD("prepareDrm ret: %d ", status);
- } else {
- ALOGE("prepareDrm err: %d", status);
- }
- return status;
-}
-
-status_t NuPlayer2::GenericSource2::releaseDrm() {
- Mutex::Autolock _l(mLock);
- ALOGV("releaseDrm");
-
- if (mIsDrmProtected) {
- mIsDrmProtected = false;
- // to prevent returning any more buffer after stop/releaseDrm (b/37960096)
- mIsDrmReleased = true;
- ALOGV("releaseDrm: mIsDrmProtected is reset.");
- } else {
- ALOGE("releaseDrm: mIsDrmProtected is already false.");
- }
-
- return OK;
-}
-
-status_t NuPlayer2::GenericSource2::checkDrmInfo()
-{
- // clearing the flag at prepare in case the player is reused after stop/releaseDrm with the
- // same source without being reset (called by prepareAsync/initFromDataSource)
- mIsDrmReleased = false;
-
- if (mExtractor == NULL) {
- ALOGV("checkDrmInfo: No extractor");
- return OK; // letting the caller responds accordingly
- }
-
- PsshInfo *psshInfo = mExtractor->getPsshInfo();
- if (psshInfo == NULL) {
- ALOGV("checkDrmInfo: No PSSH");
- return OK; // source without DRM info
- }
-
- PlayerMessage playerMsg;
- status_t ret = NuPlayer2Drm::retrieveDrmInfo(psshInfo, &playerMsg);
- ALOGV("checkDrmInfo: MEDIA_DRM_INFO PSSH drm info size: %d", (int)playerMsg.ByteSize());
-
- if (ret != OK) {
- ALOGE("checkDrmInfo: failed to retrive DrmInfo %d", ret);
- return UNKNOWN_ERROR;
- }
-
- int size = playerMsg.ByteSize();
- sp<ABuffer> drmInfoBuf = new ABuffer(size);
- playerMsg.SerializeToArray(drmInfoBuf->data(), size);
- drmInfoBuf->setRange(0, size);
- notifyDrmInfo(drmInfoBuf);
-
- return OK;
-}
-
-void NuPlayer2::GenericSource2::signalBufferReturned(MediaBufferBase *buffer)
-{
- //ALOGV("signalBufferReturned %p refCount: %d", buffer, buffer->localRefcount());
-
- buffer->setObserver(NULL);
- buffer->release(); // this leads to delete since that there is no observor
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/GenericSource2.h b/media/libmediaplayer2/nuplayer2/GenericSource2.h
deleted file mode 100644
index ade1aa3..0000000
--- a/media/libmediaplayer2/nuplayer2/GenericSource2.h
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef GENERIC_SOURCE2_H_
-
-#define GENERIC_SOURCE2_H_
-
-#include "NuPlayer2.h"
-#include "NuPlayer2Source.h"
-
-#include "ATSParser.h"
-
-#include <media/stagefright/MediaBuffer.h>
-#include <mediaplayer2/mediaplayer2.h>
-#include <media/NdkMediaDataSource.h>
-#include <media/NdkMediaExtractor.h>
-#include <media/NdkWrapper.h>
-
-namespace android {
-
-class DecryptHandle;
-struct AnotherPacketSource;
-struct ARTSPController;
-class DataSource;
-class IDataSource;
-class IMediaSource;
-struct MediaSource;
-class MediaBuffer;
-struct MediaClock;
-
-struct NuPlayer2::GenericSource2 : public NuPlayer2::Source,
- public MediaBufferObserver // Modular DRM
-{
- GenericSource2(const sp<AMessage> ¬ify, uid_t uid,
- const sp<MediaClock> &mediaClock);
-
- status_t setDataSource(
- const char *url,
- const KeyedVector<String8, String8> *headers);
-
- status_t setDataSource(int fd, int64_t offset, int64_t length);
-
- status_t setDataSource(const sp<DataSource>& dataSource);
-
- virtual status_t getBufferingSettings(
- BufferingSettings* buffering /* nonnull */) override;
- virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
-
- virtual void prepareAsync(int64_t startTimeUs);
-
- virtual void start();
- virtual void stop();
- virtual void pause();
- virtual void resume();
-
- virtual void disconnect();
-
- virtual status_t feedMoreTSData();
-
- virtual sp<MetaData> getFileFormatMeta() const;
-
- virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
-
- virtual status_t getDuration(int64_t *durationUs);
- virtual size_t getTrackCount() const;
- virtual sp<AMessage> getTrackInfo(size_t trackIndex) const;
- virtual ssize_t getSelectedTrack(media_track_type type) const;
- virtual status_t selectTrack(size_t trackIndex, bool select, int64_t timeUs);
- virtual status_t seekTo(
- int64_t seekTimeUs,
- MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC) override;
-
- virtual bool isStreaming() const;
-
- // Modular DRM
- virtual void signalBufferReturned(MediaBufferBase *buffer);
-
- virtual status_t prepareDrm(
- const uint8_t uuid[16],
- const Vector<uint8_t> &drmSessionId,
- sp<AMediaCryptoWrapper> *outCrypto);
-
- virtual status_t releaseDrm();
-
-
-protected:
- virtual ~GenericSource2();
-
- virtual void onMessageReceived(const sp<AMessage> &msg);
-
- virtual sp<AMessage> getFormat(bool audio);
- virtual sp<MetaData> getFormatMeta(bool audio);
-
-private:
- enum {
- kWhatPrepareAsync,
- kWhatFetchSubtitleData,
- kWhatFetchTimedTextData,
- kWhatSendSubtitleData,
- kWhatSendGlobalTimedTextData,
- kWhatSendTimedTextData,
- kWhatChangeAVSource,
- kWhatPollBuffering,
- kWhatSeek,
- kWhatReadBuffer,
- kWhatStart,
- kWhatResume,
- kWhatSecureDecodersInstantiated,
- };
-
- struct Track {
- size_t mIndex;
- sp<AMediaExtractorWrapper> mExtractor;
- sp<AnotherPacketSource> mPackets;
- };
-
- int64_t mAudioTimeUs;
- int64_t mAudioLastDequeueTimeUs;
- int64_t mVideoTimeUs;
- int64_t mVideoLastDequeueTimeUs;
-
- BufferingSettings mBufferingSettings;
- int32_t mPrevBufferPercentage;
- int32_t mPollBufferingGeneration;
- bool mSentPauseOnBuffering;
-
- int32_t mAudioDataGeneration;
- int32_t mVideoDataGeneration;
- int32_t mFetchSubtitleDataGeneration;
- int32_t mFetchTimedTextDataGeneration;
- int64_t mDurationUs;
- bool mAudioIsVorbis;
- // Secure codec is required.
- bool mIsSecure;
- bool mIsStreaming;
- uid_t mUID;
- const sp<MediaClock> mMediaClock;
- AString mUri;
- KeyedVector<String8, String8> mUriHeaders;
- int mFd;
- int64_t mOffset;
- int64_t mLength;
-
- bool mDisconnected;
- sp<MetaData> mFileMeta;
- sp<AMediaDataSourceWrapper> mDataSourceWrapper;
- sp<AMediaExtractorWrapper> mExtractor;
- Vector<sp<AMediaExtractorWrapper> > mExtractors;
- bool mStarted;
- bool mPreparing;
- int64_t mBitrate;
- uint32_t mPendingReadBufferTypes;
- sp<ABuffer> mGlobalTimedText;
-
- Track mVideoTrack;
- Track mAudioTrack;
- Track mSubtitleTrack;
- Track mTimedTextTrack;
-
- mutable Mutex mLock;
-
- sp<ALooper> mLooper;
-
- void resetDataSource();
-
- status_t initFromDataSource();
- int64_t getLastReadPosition();
-
- void notifyPreparedAndCleanup(status_t err);
- void onSecureDecodersInstantiated(status_t err);
- void finishPrepareAsync();
- status_t startSources();
-
- void onSeek(const sp<AMessage>& msg);
- status_t doSeek(int64_t seekTimeUs, MediaPlayer2SeekMode mode);
-
- void onPrepareAsync(int64_t startTimeUs);
-
- void fetchTextData(
- uint32_t what, media_track_type type,
- int32_t curGen, const sp<AnotherPacketSource>& packets, const sp<AMessage>& msg);
-
- void sendGlobalTextData(
- uint32_t what,
- int32_t curGen, sp<AMessage> msg);
-
- void sendTextData(
- uint32_t what, media_track_type type,
- int32_t curGen, const sp<AnotherPacketSource>& packets, const sp<AMessage>& msg);
-
- sp<ABuffer> mediaBufferToABuffer(
- MediaBufferBase *mbuf,
- media_track_type trackType);
-
- void postReadBuffer(media_track_type trackType);
- void onReadBuffer(const sp<AMessage>& msg);
- // When |mode| is MediaPlayer2SeekMode::SEEK_CLOSEST, the buffer read shall
- // include an item indicating skipping rendering all buffers with timestamp
- // earlier than |seekTimeUs|.
- // For other modes, the buffer read will not include the item as above in order
- // to facilitate fast seek operation.
- void readBuffer(
- media_track_type trackType,
- int64_t seekTimeUs = -1ll,
- MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC,
- int64_t *actualTimeUs = NULL, bool formatChange = false);
-
- void queueDiscontinuityIfNeeded(
- bool seeking, bool formatChange, media_track_type trackType, Track *track);
-
- void schedulePollBuffering();
- void onPollBuffering();
- void notifyBufferingUpdate(int32_t percentage);
-
- sp<AMessage> getFormat_l(bool audio);
- sp<MetaData> getFormatMeta_l(bool audio);
- int32_t getDataGeneration(media_track_type type) const;
-
- // Modular DRM
- // The source is DRM protected and is prepared for DRM.
- bool mIsDrmProtected;
- // releaseDrm has been processed.
- bool mIsDrmReleased;
- Vector<String8> mMimes;
-
- status_t checkDrmInfo();
-
- DISALLOW_EVIL_CONSTRUCTORS(GenericSource2);
-};
-
-} // namespace android
-
-#endif // GENERIC_SOURCE2_H_
diff --git a/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.cpp b/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.cpp
deleted file mode 100644
index e53900b..0000000
--- a/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.cpp
+++ /dev/null
@@ -1,450 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "HTTPLiveSource2"
-#include <utils/Log.h>
-
-#include "HTTPLiveSource2.h"
-
-#include "AnotherPacketSource.h"
-#include "LiveDataSource.h"
-
-#include <media/MediaHTTPService.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/Utils.h>
-
-// default buffer prepare/ready/underflow marks
-static const int kReadyMarkMs = 5000; // 5 seconds
-static const int kPrepareMarkMs = 1500; // 1.5 seconds
-
-namespace android {
-
-NuPlayer2::HTTPLiveSource2::HTTPLiveSource2(
- const sp<AMessage> ¬ify,
- const sp<MediaHTTPService> &httpService,
- const char *url,
- const KeyedVector<String8, String8> *headers)
- : Source(notify),
- mHTTPService(httpService),
- mURL(url),
- mFlags(0),
- mFinalResult(OK),
- mOffset(0),
- mFetchSubtitleDataGeneration(0),
- mFetchMetaDataGeneration(0),
- mHasMetadata(false),
- mMetadataSelected(false) {
- mBufferingSettings.mInitialMarkMs = kPrepareMarkMs;
- mBufferingSettings.mResumePlaybackMarkMs = kReadyMarkMs;
- if (headers) {
- mExtraHeaders = *headers;
-
- ssize_t index =
- mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log"));
-
- if (index >= 0) {
- mFlags |= kFlagIncognito;
-
- mExtraHeaders.removeItemsAt(index);
- }
- }
-}
-
-NuPlayer2::HTTPLiveSource2::~HTTPLiveSource2() {
- if (mLiveSession != NULL) {
- mLiveSession->disconnect();
-
- mLiveLooper->unregisterHandler(mLiveSession->id());
- mLiveLooper->unregisterHandler(id());
- mLiveLooper->stop();
-
- mLiveSession.clear();
- mLiveLooper.clear();
- }
-}
-
-status_t NuPlayer2::HTTPLiveSource2::getBufferingSettings(
- BufferingSettings* buffering /* nonnull */) {
- *buffering = mBufferingSettings;
-
- return OK;
-}
-
-status_t NuPlayer2::HTTPLiveSource2::setBufferingSettings(const BufferingSettings& buffering) {
- mBufferingSettings = buffering;
-
- if (mLiveSession != NULL) {
- mLiveSession->setBufferingSettings(mBufferingSettings);
- }
-
- return OK;
-}
-
-// TODO: fetch data starting from |startTimeUs|
-void NuPlayer2::HTTPLiveSource2::prepareAsync(int64_t /* startTimeUs */) {
- if (mLiveLooper == NULL) {
- mLiveLooper = new ALooper;
- mLiveLooper->setName("http live2");
- mLiveLooper->start(false, /* runOnCallingThread */
- true /* canCallJava */);
-
- mLiveLooper->registerHandler(this);
- }
-
- sp<AMessage> notify = new AMessage(kWhatSessionNotify, this);
-
- mLiveSession = new LiveSession(
- notify,
- (mFlags & kFlagIncognito) ? LiveSession::kFlagIncognito : 0,
- mHTTPService);
-
- mLiveLooper->registerHandler(mLiveSession);
-
- mLiveSession->setBufferingSettings(mBufferingSettings);
- mLiveSession->connectAsync(
- mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
-}
-
-void NuPlayer2::HTTPLiveSource2::start() {
-}
-
-sp<MetaData> NuPlayer2::HTTPLiveSource2::getFormatMeta(bool audio) {
- sp<MetaData> meta;
- if (mLiveSession != NULL) {
- mLiveSession->getStreamFormatMeta(
- audio ? LiveSession::STREAMTYPE_AUDIO
- : LiveSession::STREAMTYPE_VIDEO,
- &meta);
- }
-
- return meta;
-}
-
-sp<AMessage> NuPlayer2::HTTPLiveSource2::getFormat(bool audio) {
- sp<MetaData> meta;
- status_t err = -EWOULDBLOCK;
- if (mLiveSession != NULL) {
- err = mLiveSession->getStreamFormatMeta(
- audio ? LiveSession::STREAMTYPE_AUDIO
- : LiveSession::STREAMTYPE_VIDEO,
- &meta);
- }
-
- sp<AMessage> format;
- if (err == -EWOULDBLOCK) {
- format = new AMessage();
- format->setInt32("err", err);
- return format;
- }
-
- if (err != OK || convertMetaDataToMessage(meta, &format) != OK) {
- return NULL;
- }
- return format;
-}
-
-status_t NuPlayer2::HTTPLiveSource2::feedMoreTSData() {
- return OK;
-}
-
-status_t NuPlayer2::HTTPLiveSource2::dequeueAccessUnit(
- bool audio, sp<ABuffer> *accessUnit) {
- return mLiveSession->dequeueAccessUnit(
- audio ? LiveSession::STREAMTYPE_AUDIO
- : LiveSession::STREAMTYPE_VIDEO,
- accessUnit);
-}
-
-status_t NuPlayer2::HTTPLiveSource2::getDuration(int64_t *durationUs) {
- return mLiveSession->getDuration(durationUs);
-}
-
-size_t NuPlayer2::HTTPLiveSource2::getTrackCount() const {
- return mLiveSession->getTrackCount();
-}
-
-sp<AMessage> NuPlayer2::HTTPLiveSource2::getTrackInfo(size_t trackIndex) const {
- return mLiveSession->getTrackInfo(trackIndex);
-}
-
-ssize_t NuPlayer2::HTTPLiveSource2::getSelectedTrack(media_track_type type) const {
- if (mLiveSession == NULL) {
- return -1;
- } else if (type == MEDIA_TRACK_TYPE_METADATA) {
- // MEDIA_TRACK_TYPE_METADATA is always last track
- // mMetadataSelected can only be true when mHasMetadata is true
- return mMetadataSelected ? (mLiveSession->getTrackCount() - 1) : -1;
- } else {
- return mLiveSession->getSelectedTrack(type);
- }
-}
-
-status_t NuPlayer2::HTTPLiveSource2::selectTrack(size_t trackIndex, bool select, int64_t /*timeUs*/) {
- if (mLiveSession == NULL) {
- return INVALID_OPERATION;
- }
-
- status_t err = INVALID_OPERATION;
- bool postFetchMsg = false, isSub = false;
- if (!mHasMetadata || trackIndex != mLiveSession->getTrackCount() - 1) {
- err = mLiveSession->selectTrack(trackIndex, select);
- postFetchMsg = select;
- isSub = true;
- } else {
- // metadata track; i.e. (mHasMetadata && trackIndex == mLiveSession->getTrackCount() - 1)
- if (mMetadataSelected && !select) {
- err = OK;
- } else if (!mMetadataSelected && select) {
- postFetchMsg = true;
- err = OK;
- } else {
- err = BAD_VALUE; // behave as LiveSession::selectTrack
- }
-
- mMetadataSelected = select;
- }
-
- if (err == OK) {
- int32_t &generation = isSub ? mFetchSubtitleDataGeneration : mFetchMetaDataGeneration;
- generation++;
- if (postFetchMsg) {
- int32_t what = isSub ? kWhatFetchSubtitleData : kWhatFetchMetaData;
- sp<AMessage> msg = new AMessage(what, this);
- msg->setInt32("generation", generation);
- msg->post();
- }
- }
-
- // LiveSession::selectTrack returns BAD_VALUE when selecting the currently
- // selected track, or unselecting a non-selected track. In this case it's an
- // no-op so we return OK.
- return (err == OK || err == BAD_VALUE) ? (status_t)OK : err;
-}
-
-status_t NuPlayer2::HTTPLiveSource2::seekTo(int64_t seekTimeUs, MediaPlayer2SeekMode mode) {
- if (mLiveSession->isSeekable()) {
- return mLiveSession->seekTo(seekTimeUs, mode);
- } else {
- return INVALID_OPERATION;
- }
-}
-
-void NuPlayer2::HTTPLiveSource2::pollForRawData(
- const sp<AMessage> &msg, int32_t currentGeneration,
- LiveSession::StreamType fetchType, int32_t pushWhat) {
-
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
-
- if (generation != currentGeneration) {
- return;
- }
-
- sp<ABuffer> buffer;
- while (mLiveSession->dequeueAccessUnit(fetchType, &buffer) == OK) {
-
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", pushWhat);
- notify->setBuffer("buffer", buffer);
-
- int64_t timeUs, baseUs, delayUs;
- CHECK(buffer->meta()->findInt64("baseUs", &baseUs));
- CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
- delayUs = baseUs + timeUs - ALooper::GetNowUs();
-
- if (fetchType == LiveSession::STREAMTYPE_SUBTITLES) {
- notify->post();
- msg->post(delayUs > 0LL ? delayUs : 0LL);
- return;
- } else if (fetchType == LiveSession::STREAMTYPE_METADATA) {
- if (delayUs < -1000000LL) { // 1 second
- continue;
- }
- notify->post();
- // push all currently available metadata buffers in each invocation of pollForRawData
- // continue;
- } else {
- TRESPASS();
- }
- }
-
- // try again in 1 second
- msg->post(1000000LL);
-}
-
-void NuPlayer2::HTTPLiveSource2::onMessageReceived(const sp<AMessage> &msg) {
- switch (msg->what()) {
- case kWhatSessionNotify:
- {
- onSessionNotify(msg);
- break;
- }
-
- case kWhatFetchSubtitleData:
- {
- pollForRawData(
- msg, mFetchSubtitleDataGeneration,
- /* fetch */ LiveSession::STREAMTYPE_SUBTITLES,
- /* push */ kWhatSubtitleData);
-
- break;
- }
-
- case kWhatFetchMetaData:
- {
- if (!mMetadataSelected) {
- break;
- }
-
- pollForRawData(
- msg, mFetchMetaDataGeneration,
- /* fetch */ LiveSession::STREAMTYPE_METADATA,
- /* push */ kWhatTimedMetaData);
-
- break;
- }
-
- default:
- Source::onMessageReceived(msg);
- break;
- }
-}
-
-void NuPlayer2::HTTPLiveSource2::onSessionNotify(const sp<AMessage> &msg) {
- int32_t what;
- CHECK(msg->findInt32("what", &what));
-
- switch (what) {
- case LiveSession::kWhatPrepared:
- {
- // notify the current size here if we have it, otherwise report an initial size of (0,0)
- sp<AMessage> format = getFormat(false /* audio */);
- int32_t width;
- int32_t height;
- if (format != NULL &&
- format->findInt32("width", &width) && format->findInt32("height", &height)) {
- notifyVideoSizeChanged(format);
- } else {
- notifyVideoSizeChanged();
- }
-
- uint32_t flags = 0;
- if (mLiveSession->isSeekable()) {
- flags |= FLAG_CAN_PAUSE;
- flags |= FLAG_CAN_SEEK;
- flags |= FLAG_CAN_SEEK_BACKWARD;
- flags |= FLAG_CAN_SEEK_FORWARD;
- }
-
- if (mLiveSession->hasDynamicDuration()) {
- flags |= FLAG_DYNAMIC_DURATION;
- }
-
- notifyFlagsChanged(flags);
-
- notifyPrepared();
- break;
- }
-
- case LiveSession::kWhatPreparationFailed:
- {
- status_t err;
- CHECK(msg->findInt32("err", &err));
-
- notifyPrepared(err);
- break;
- }
-
- case LiveSession::kWhatStreamsChanged:
- {
- uint32_t changedMask;
- CHECK(msg->findInt32(
- "changedMask", (int32_t *)&changedMask));
-
- bool audio = changedMask & LiveSession::STREAMTYPE_AUDIO;
- bool video = changedMask & LiveSession::STREAMTYPE_VIDEO;
-
- sp<AMessage> reply;
- CHECK(msg->findMessage("reply", &reply));
-
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatQueueDecoderShutdown);
- notify->setInt32("audio", audio);
- notify->setInt32("video", video);
- notify->setMessage("reply", reply);
- notify->post();
- break;
- }
-
- case LiveSession::kWhatBufferingStart:
- {
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatPauseOnBufferingStart);
- notify->post();
- break;
- }
-
- case LiveSession::kWhatBufferingEnd:
- {
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatResumeOnBufferingEnd);
- notify->post();
- break;
- }
-
-
- case LiveSession::kWhatBufferingUpdate:
- {
- sp<AMessage> notify = dupNotify();
- int32_t percentage;
- CHECK(msg->findInt32("percentage", &percentage));
- notify->setInt32("what", kWhatBufferingUpdate);
- notify->setInt32("percentage", percentage);
- notify->post();
- break;
- }
-
- case LiveSession::kWhatMetadataDetected:
- {
- if (!mHasMetadata) {
- mHasMetadata = true;
-
- sp<AMessage> notify = dupNotify();
- // notification without buffer triggers MEDIA2_INFO_METADATA_UPDATE
- notify->setInt32("what", kWhatTimedMetaData);
- notify->post();
- }
- break;
- }
-
- case LiveSession::kWhatError:
- {
- break;
- }
-
- default:
- TRESPASS();
- }
-}
-
-} // namespace android
-
diff --git a/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.h b/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.h
deleted file mode 100644
index 8fc71e2..0000000
--- a/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef HTTP_LIVE_SOURCE2_H_
-
-#define HTTP_LIVE_SOURCE2_H_
-
-#include "NuPlayer2.h"
-#include "NuPlayer2Source.h"
-
-#include "LiveSession.h"
-
-namespace android {
-
-struct LiveSession;
-
-struct NuPlayer2::HTTPLiveSource2 : public NuPlayer2::Source {
- HTTPLiveSource2(
- const sp<AMessage> ¬ify,
- const sp<MediaHTTPService> &httpService,
- const char *url,
- const KeyedVector<String8, String8> *headers);
-
- virtual status_t getBufferingSettings(
- BufferingSettings* buffering /* nonnull */) override;
- virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
-
- virtual void prepareAsync(int64_t startTimeUs);
- virtual void start();
-
- virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
- virtual sp<MetaData> getFormatMeta(bool audio);
- virtual sp<AMessage> getFormat(bool audio);
-
- virtual status_t feedMoreTSData();
- virtual status_t getDuration(int64_t *durationUs);
- virtual size_t getTrackCount() const;
- virtual sp<AMessage> getTrackInfo(size_t trackIndex) const;
- virtual ssize_t getSelectedTrack(media_track_type /* type */) const;
- virtual status_t selectTrack(size_t trackIndex, bool select, int64_t timeUs);
- virtual status_t seekTo(
- int64_t seekTimeUs,
- MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC) override;
-
-protected:
- virtual ~HTTPLiveSource2();
-
- virtual void onMessageReceived(const sp<AMessage> &msg);
-
-private:
- enum Flags {
- // Don't log any URLs.
- kFlagIncognito = 1,
- };
-
- enum {
- kWhatSessionNotify,
- kWhatFetchSubtitleData,
- kWhatFetchMetaData,
- };
-
- sp<MediaHTTPService> mHTTPService;
- AString mURL;
- KeyedVector<String8, String8> mExtraHeaders;
- uint32_t mFlags;
- status_t mFinalResult;
- off64_t mOffset;
- sp<ALooper> mLiveLooper;
- sp<LiveSession> mLiveSession;
- int32_t mFetchSubtitleDataGeneration;
- int32_t mFetchMetaDataGeneration;
- bool mHasMetadata;
- bool mMetadataSelected;
- BufferingSettings mBufferingSettings;
-
- void onSessionNotify(const sp<AMessage> &msg);
- void pollForRawData(
- const sp<AMessage> &msg, int32_t currentGeneration,
- LiveSession::StreamType fetchType, int32_t pushWhat);
-
- DISALLOW_EVIL_CONSTRUCTORS(HTTPLiveSource2);
-};
-
-} // namespace android
-
-#endif // HTTP_LIVE_SOURCE2_H_
diff --git a/media/libmediaplayer2/nuplayer2/JMediaPlayer2Utils.cpp b/media/libmediaplayer2/nuplayer2/JMediaPlayer2Utils.cpp
deleted file mode 100644
index 89703de..0000000
--- a/media/libmediaplayer2/nuplayer2/JMediaPlayer2Utils.cpp
+++ /dev/null
@@ -1,65 +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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "JMediaPlayer2Utils"
-
-#include "JMediaPlayer2Utils.h"
-#include <mediaplayer2/JavaVMHelper.h>
-
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/Utils.h>
-#include <utils/Log.h>
-
-#include "log/log.h"
-
-namespace android {
-
-static const int64_t kOffloadMinDurationSec = 60;
-
-// static
-bool JMediaPlayer2Utils::isOffloadedAudioPlaybackSupported(
- const sp<MetaData>& meta, bool hasVideo, bool isStreaming, audio_stream_type_t streamType)
-{
- if (hasVideo || streamType != AUDIO_STREAM_MUSIC) {
- return false;
- }
-
- audio_offload_info_t info = AUDIO_INFO_INITIALIZER;
- if (OK != getAudioOffloadInfo(meta, hasVideo, isStreaming, streamType, &info)) {
- return false;
- }
-
- if (info.duration_us < kOffloadMinDurationSec * 1000000) {
- return false;
- }
-
- int32_t audioFormat = audioFormatFromNative(info.format);
- int32_t channelMask = outChannelMaskFromNative(info.channel_mask);
- if (audioFormat == ENCODING_INVALID || channelMask == CHANNEL_INVALID) {
- return false;
- }
-
- JNIEnv* env = JavaVMHelper::getJNIEnv();
- jclass jMP2UtilsCls = env->FindClass("android/media/MediaPlayer2Utils");
- jmethodID jSetAudioOutputDeviceById = env->GetStaticMethodID(
- jMP2UtilsCls, "isOffloadedAudioPlaybackSupported", "(III)Z");
- jboolean result = env->CallStaticBooleanMethod(
- jMP2UtilsCls, jSetAudioOutputDeviceById, audioFormat, info.sample_rate, channelMask);
- return result;
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/JMediaPlayer2Utils.h b/media/libmediaplayer2/nuplayer2/JMediaPlayer2Utils.h
deleted file mode 100644
index fcbd43c..0000000
--- a/media/libmediaplayer2/nuplayer2/JMediaPlayer2Utils.h
+++ /dev/null
@@ -1,35 +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.
- */
-
-#ifndef _J_MEDIAPLAYER2_UTILS2_H_
-#define _J_MEDIAPLAYER2_UTILS2_H_
-
-#include <media/stagefright/MetaData.h>
-
-#include "jni.h"
-#include "android_media_AudioFormat.h"
-
-namespace android {
-
-struct JMediaPlayer2Utils {
- static bool isOffloadedAudioPlaybackSupported(
- const sp<MetaData>& meta, bool hasVideo, bool isStreaming,
- audio_stream_type_t streamType);
-};
-
-} // namespace android
-
-#endif // _J_MEDIAPLAYER2_UTILS2_H_
diff --git a/media/libmediaplayer2/nuplayer2/JWakeLock.cpp b/media/libmediaplayer2/nuplayer2/JWakeLock.cpp
deleted file mode 100644
index 983d77e..0000000
--- a/media/libmediaplayer2/nuplayer2/JWakeLock.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "JWakeLock"
-#include <utils/Log.h>
-
-#include "JWakeLock.h"
-
-#include <media/stagefright/foundation/ADebug.h>
-
-namespace android {
-
-JWakeLock::JWakeLock(const sp<JObjectHolder> &context) :
- mWakeLockCount(0),
- mWakeLock(NULL),
- mContext(context) {}
-
-JWakeLock::~JWakeLock() {
- clearJavaWakeLock();
-}
-
-bool JWakeLock::acquire() {
- if (mWakeLockCount == 0) {
- if (mWakeLock == NULL) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jclass jContextCls = env->FindClass("android/content/Context");
- jclass jPowerManagerCls = env->FindClass("android/os/PowerManager");
-
- jmethodID jGetSystemService = env->GetMethodID(jContextCls,
- "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
- jobject javaPowerManagerObj = env->CallObjectMethod(mContext->getJObject(),
- jGetSystemService, env->NewStringUTF("power"));
-
- jfieldID jPARTIAL_WAKE_LOCK = env->GetStaticFieldID(jPowerManagerCls,
- "PARTIAL_WAKE_LOCK", "I");
- jint PARTIAL_WAKE_LOCK = env->GetStaticIntField(jPowerManagerCls, jPARTIAL_WAKE_LOCK);
-
- jmethodID jNewWakeLock = env->GetMethodID(jPowerManagerCls,
- "newWakeLock", "(ILjava/lang/String;)Landroid/os/PowerManager$WakeLock;");
- jobject javaWakeLock = env->CallObjectMethod(javaPowerManagerObj,
- jNewWakeLock, PARTIAL_WAKE_LOCK, env->NewStringUTF("JWakeLock"));
- mWakeLock = new JObjectHolder(javaWakeLock);
- env->DeleteLocalRef(javaPowerManagerObj);
- env->DeleteLocalRef(javaWakeLock);
- }
- if (mWakeLock != NULL) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jclass wakeLockCls = env->FindClass("android/os/PowerManager$WakeLock");
- jmethodID jAcquire = env->GetMethodID(wakeLockCls, "acquire", "()V");
- env->CallVoidMethod(mWakeLock->getJObject(), jAcquire);
- mWakeLockCount++;
- return true;
- }
- } else {
- mWakeLockCount++;
- return true;
- }
- return false;
-}
-
-void JWakeLock::release(bool force) {
- if (mWakeLockCount == 0) {
- return;
- }
- if (force) {
- // Force wakelock release below by setting reference count to 1.
- mWakeLockCount = 1;
- }
- if (--mWakeLockCount == 0) {
- if (mWakeLock != NULL) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jclass wakeLockCls = env->FindClass("android/os/PowerManager$WakeLock");
- jmethodID jRelease = env->GetMethodID(wakeLockCls, "release", "()V");
- env->CallVoidMethod(mWakeLock->getJObject(), jRelease);
- }
- }
-}
-
-void JWakeLock::clearJavaWakeLock() {
- release(true);
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/JWakeLock.h b/media/libmediaplayer2/nuplayer2/JWakeLock.h
deleted file mode 100644
index 36c542e..0000000
--- a/media/libmediaplayer2/nuplayer2/JWakeLock.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef J_WAKELOCK_H_
-#define J_WAKELOCK_H_
-
-#include <media/stagefright/foundation/ABase.h>
-#include <mediaplayer2/JObjectHolder.h>
-#include <utils/RefBase.h>
-
-namespace android {
-
-class JWakeLock : public RefBase {
-
-public:
- JWakeLock(const sp<JObjectHolder> &context);
-
- // NOTE: acquire and release are not thread safe
-
- // returns true if wakelock was acquired
- bool acquire();
- void release(bool force = false);
-
- virtual ~JWakeLock();
-
-private:
- uint32_t mWakeLockCount;
- sp<JObjectHolder> mWakeLock;
- const sp<JObjectHolder> mContext;
-
- void clearJavaWakeLock();
-
- DISALLOW_EVIL_CONSTRUCTORS(JWakeLock);
-};
-
-} // namespace android
-
-#endif // J_WAKELOCK_H_
diff --git a/media/libmediaplayer2/nuplayer2/MODULE_LICENSE_APACHE2 b/media/libmediaplayer2/nuplayer2/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/media/libmediaplayer2/nuplayer2/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/media/libmediaplayer2/nuplayer2/NOTICE b/media/libmediaplayer2/nuplayer2/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/media/libmediaplayer2/nuplayer2/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
- Copyright (c) 2005-2008, 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.
-
- 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.
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
deleted file mode 100644
index d608d4a..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
+++ /dev/null
@@ -1,3308 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NuPlayer2"
-
-#include <inttypes.h>
-
-#include <utils/Log.h>
-
-#include "NuPlayer2.h"
-
-#include "HTTPLiveSource2.h"
-#include "JMediaPlayer2Utils.h"
-#include "NuPlayer2CCDecoder.h"
-#include "NuPlayer2Decoder.h"
-#include "NuPlayer2DecoderBase.h"
-#include "NuPlayer2DecoderPassThrough.h"
-#include "NuPlayer2Driver.h"
-#include "NuPlayer2Renderer.h"
-#include "NuPlayer2Source.h"
-#include "RTSPSource2.h"
-#include "GenericSource2.h"
-#include "TextDescriptions2.h"
-
-#include "ATSParser.h"
-
-#include <cutils/properties.h>
-
-#include <media/AudioParameter.h>
-#include <media/AudioResamplerPublic.h>
-#include <media/AVSyncSettings.h>
-#include <media/DataSourceDesc.h>
-#include <media/MediaCodecBuffer.h>
-#include <media/NdkWrapper.h>
-
-#include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/foundation/avc_utils.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaClock.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MetaData.h>
-
-#include "ESDS.h"
-#include <media/stagefright/Utils.h>
-
-#include <system/window.h>
-
-namespace android {
-
-static status_t sendMetaDataToHal(sp<MediaPlayer2Interface::AudioSink>& sink,
- const sp<MetaData>& meta) {
- int32_t sampleRate = 0;
- int32_t bitRate = 0;
- int32_t channelMask = 0;
- int32_t delaySamples = 0;
- int32_t paddingSamples = 0;
-
- AudioParameter param = AudioParameter();
-
- if (meta->findInt32(kKeySampleRate, &sampleRate)) {
- param.addInt(String8(AUDIO_OFFLOAD_CODEC_SAMPLE_RATE), sampleRate);
- }
- if (meta->findInt32(kKeyChannelMask, &channelMask)) {
- param.addInt(String8(AUDIO_OFFLOAD_CODEC_NUM_CHANNEL), channelMask);
- }
- if (meta->findInt32(kKeyBitRate, &bitRate)) {
- param.addInt(String8(AUDIO_OFFLOAD_CODEC_AVG_BIT_RATE), bitRate);
- }
- if (meta->findInt32(kKeyEncoderDelay, &delaySamples)) {
- param.addInt(String8(AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES), delaySamples);
- }
- if (meta->findInt32(kKeyEncoderPadding, &paddingSamples)) {
- param.addInt(String8(AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES), paddingSamples);
- }
-
- ALOGV("sendMetaDataToHal: bitRate %d, sampleRate %d, chanMask %d,"
- "delaySample %d, paddingSample %d", bitRate, sampleRate,
- channelMask, delaySamples, paddingSamples);
-
- sink->setParameters(param.toString());
- return OK;
-}
-
-
-struct NuPlayer2::Action : public RefBase {
- Action() {}
-
- virtual void execute(NuPlayer2 *player) = 0;
-
-private:
- DISALLOW_EVIL_CONSTRUCTORS(Action);
-};
-
-struct NuPlayer2::SeekAction : public Action {
- explicit SeekAction(int64_t seekTimeUs, MediaPlayer2SeekMode mode)
- : mSeekTimeUs(seekTimeUs),
- mMode(mode) {
- }
-
- virtual void execute(NuPlayer2 *player) {
- player->performSeek(mSeekTimeUs, mMode);
- }
-
-private:
- int64_t mSeekTimeUs;
- MediaPlayer2SeekMode mMode;
-
- DISALLOW_EVIL_CONSTRUCTORS(SeekAction);
-};
-
-struct NuPlayer2::ResumeDecoderAction : public Action {
- explicit ResumeDecoderAction(bool needNotify)
- : mNeedNotify(needNotify) {
- }
-
- virtual void execute(NuPlayer2 *player) {
- player->performResumeDecoders(mNeedNotify);
- }
-
-private:
- bool mNeedNotify;
-
- DISALLOW_EVIL_CONSTRUCTORS(ResumeDecoderAction);
-};
-
-struct NuPlayer2::SetSurfaceAction : public Action {
- explicit SetSurfaceAction(const sp<ANativeWindowWrapper> &nww)
- : mNativeWindow(nww) {
- }
-
- virtual void execute(NuPlayer2 *player) {
- player->performSetSurface(mNativeWindow);
- }
-
-private:
- sp<ANativeWindowWrapper> mNativeWindow;
-
- DISALLOW_EVIL_CONSTRUCTORS(SetSurfaceAction);
-};
-
-struct NuPlayer2::FlushDecoderAction : public Action {
- FlushDecoderAction(FlushCommand audio, FlushCommand video)
- : mAudio(audio),
- mVideo(video) {
- }
-
- virtual void execute(NuPlayer2 *player) {
- player->performDecoderFlush(mAudio, mVideo);
- }
-
-private:
- FlushCommand mAudio;
- FlushCommand mVideo;
-
- DISALLOW_EVIL_CONSTRUCTORS(FlushDecoderAction);
-};
-
-struct NuPlayer2::PostMessageAction : public Action {
- explicit PostMessageAction(const sp<AMessage> &msg)
- : mMessage(msg) {
- }
-
- virtual void execute(NuPlayer2 *) {
- mMessage->post();
- }
-
-private:
- sp<AMessage> mMessage;
-
- DISALLOW_EVIL_CONSTRUCTORS(PostMessageAction);
-};
-
-// Use this if there's no state necessary to save in order to execute
-// the action.
-struct NuPlayer2::SimpleAction : public Action {
- typedef void (NuPlayer2::*ActionFunc)();
-
- explicit SimpleAction(ActionFunc func)
- : mFunc(func) {
- }
-
- virtual void execute(NuPlayer2 *player) {
- (player->*mFunc)();
- }
-
-private:
- ActionFunc mFunc;
-
- DISALLOW_EVIL_CONSTRUCTORS(SimpleAction);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
-NuPlayer2::NuPlayer2(
- pid_t pid, uid_t uid, const sp<MediaClock> &mediaClock, const sp<JObjectHolder> &context)
- : mPID(pid),
- mUID(uid),
- mMediaClock(mediaClock),
- mOffloadAudio(false),
- mAudioDecoderGeneration(0),
- mVideoDecoderGeneration(0),
- mRendererGeneration(0),
- mEOSMonitorGeneration(0),
- mLastStartedPlayingTimeNs(0),
- mPreviousSeekTimeUs(0),
- mAudioEOS(false),
- mVideoEOS(false),
- mScanSourcesPending(false),
- mScanSourcesGeneration(0),
- mPollDurationGeneration(0),
- mTimedTextGeneration(0),
- mFlushingAudio(NONE),
- mFlushingVideo(NONE),
- mResumePending(false),
- mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW),
- mPlaybackSettings(AUDIO_PLAYBACK_RATE_DEFAULT),
- mVideoFpsHint(-1.f),
- mStarted(false),
- mPrepared(false),
- mResetting(false),
- mSourceStarted(false),
- mAudioDecoderError(false),
- mVideoDecoderError(false),
- mPaused(false),
- mPausedByClient(true),
- mPausedForBuffering(false),
- mContext(context) {
- CHECK(mediaClock != NULL);
- clearFlushComplete();
-}
-
-NuPlayer2::~NuPlayer2() {
-}
-
-void NuPlayer2::setDriver(const wp<NuPlayer2Driver> &driver) {
- mDriver = driver;
-}
-
-static bool IsHTTPLiveURL(const char *url) {
- if (!strncasecmp("http://", url, 7)
- || !strncasecmp("https://", url, 8)
- || !strncasecmp("file://", url, 7)) {
- size_t len = strlen(url);
- if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {
- return true;
- }
-
- if (strstr(url,"m3u8")) {
- return true;
- }
- }
-
- return false;
-}
-
-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);
- notify->setInt64("srcId", dsd->mId);
-
- switch (dsd->mType) {
- case DataSourceDesc::TYPE_URL:
- {
- const char *url = dsd->mUrl.c_str();
- size_t len = strlen(url);
-
- const sp<MediaHTTPService> &httpService = dsd->mHttpService;
- KeyedVector<String8, String8> *headers = &(dsd->mHeaders);
-
- if (IsHTTPLiveURL(url)) {
- *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, 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, mUID, true);
- ALOGV("createNuPlayer2Source RTSPSource2 http/https/.sdp %s", url);
- *dataSourceType = DATA_SOURCE_TYPE_RTSP;
- } else {
- ALOGV("createNuPlayer2Source GenericSource2 %s", url);
-
- sp<GenericSource2> genericSource =
- new GenericSource2(notify, mUID, mMediaClock);
-
- err = genericSource->setDataSource(url, headers);
-
- if (err == OK) {
- *source = genericSource;
- } else {
- *source = NULL;
- ALOGE("Failed to create NuPlayer2Source!");
- }
-
- // regardless of success/failure
- *dataSourceType = DATA_SOURCE_TYPE_GENERIC_URL;
- }
- break;
- }
-
- case DataSourceDesc::TYPE_FD:
- {
- sp<GenericSource2> genericSource =
- new GenericSource2(notify, mUID, mMediaClock);
-
- ALOGV("createNuPlayer2Source fd %d/%lld/%lld source: %p",
- dsd->mFD, (long long)dsd->mFDOffset, (long long)dsd->mFDLength,
- genericSource.get());
-
- err = genericSource->setDataSource(dsd->mFD, dsd->mFDOffset, dsd->mFDLength);
-
- if (err != OK) {
- ALOGE("Failed to create NuPlayer2Source!");
- *source = NULL;
- } else {
- *source = genericSource;
- }
-
- *dataSourceType = DATA_SOURCE_TYPE_GENERIC_FD;
- break;
- }
-
- case DataSourceDesc::TYPE_CALLBACK:
- {
- sp<GenericSource2> genericSource =
- new GenericSource2(notify, mUID, mMediaClock);
- err = genericSource->setDataSource(dsd->mCallbackSource);
-
- if (err != OK) {
- ALOGE("Failed to create NuPlayer2Source!");
- *source = NULL;
- } else {
- *source = genericSource;
- }
-
- *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.
- */
-
- mCurrentSourceInfo.mDataSourceType = dataSourceType;
-
- sp<AMessage> msg = new AMessage(kWhatSetDataSource, this);
- msg->setObject("source", source);
- msg->setInt64("srcId", dsd->mId);
- msg->setInt64("startTimeUs", dsd->mStartPositionMs * 1000);
- msg->setInt64("endTimeUs", dsd->mEndPositionMs * 1000);
- 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.
- */
-
- mNextSourceInfo.mDataSourceType = dataSourceType;
-
- sp<AMessage> msg = new AMessage(kWhatPrepareNextDataSource, this);
- msg->setObject("source", source);
- msg->setInt64("srcId", dsd->mId);
- msg->setInt64("startTimeUs", dsd->mStartPositionMs * 1000);
- msg->setInt64("endTimeUs", dsd->mEndPositionMs * 1000);
- msg->post();
-}
-
-void NuPlayer2::playNextDataSource(int64_t srcId) {
- disconnectSource();
-
- sp<AMessage> msg = new AMessage(kWhatPlayNextDataSource, this);
- msg->setInt64("srcId", srcId);
- msg->post();
-}
-
-status_t NuPlayer2::getBufferingSettings(
- BufferingSettings *buffering /* nonnull */) {
- sp<AMessage> msg = new AMessage(kWhatGetBufferingSettings, this);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- if (err == OK) {
- readFromAMessage(response, buffering);
- }
- }
- return err;
-}
-
-status_t NuPlayer2::setBufferingSettings(const BufferingSettings& buffering) {
- sp<AMessage> msg = new AMessage(kWhatSetBufferingSettings, this);
- writeToAMessage(msg, buffering);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- }
- return err;
-}
-
-void NuPlayer2::prepareAsync() {
- ALOGV("prepareAsync");
-
- (new AMessage(kWhatPrepare, this))->post();
-}
-
-void NuPlayer2::setVideoSurfaceTextureAsync(const sp<ANativeWindowWrapper> &nww) {
- sp<AMessage> msg = new AMessage(kWhatSetVideoSurface, this);
-
- if (nww == NULL || nww->getANativeWindow() == NULL) {
- msg->setObject("surface", NULL);
- } else {
- msg->setObject("surface", nww);
- }
-
- msg->post();
-}
-
-void NuPlayer2::setAudioSink(const sp<MediaPlayer2Interface::AudioSink> &sink) {
- sp<AMessage> msg = new AMessage(kWhatSetAudioSink, this);
- msg->setObject("sink", sink);
- msg->post();
-}
-
-void NuPlayer2::start() {
- (new AMessage(kWhatStart, this))->post();
-}
-
-status_t NuPlayer2::setPlaybackSettings(const AudioPlaybackRate &rate) {
- // do some cursory validation of the settings here. audio modes are
- // only validated when set on the audiosink.
- if (rate.mSpeed < AUDIO_TIMESTRETCH_SPEED_MIN
- || rate.mSpeed > AUDIO_TIMESTRETCH_SPEED_MAX
- || rate.mPitch < AUDIO_TIMESTRETCH_SPEED_MIN
- || rate.mPitch > AUDIO_TIMESTRETCH_SPEED_MAX) {
- return BAD_VALUE;
- }
- sp<AMessage> msg = new AMessage(kWhatConfigPlayback, this);
- writeToAMessage(msg, rate);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- }
- return err;
-}
-
-status_t NuPlayer2::getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) {
- sp<AMessage> msg = new AMessage(kWhatGetPlaybackSettings, this);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- if (err == OK) {
- readFromAMessage(response, rate);
- }
- }
- return err;
-}
-
-status_t NuPlayer2::setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) {
- sp<AMessage> msg = new AMessage(kWhatConfigSync, this);
- writeToAMessage(msg, sync, videoFpsHint);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- }
- return err;
-}
-
-status_t NuPlayer2::getSyncSettings(
- AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */) {
- sp<AMessage> msg = new AMessage(kWhatGetSyncSettings, this);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- if (err == OK) {
- readFromAMessage(response, sync, videoFps);
- }
- }
- return err;
-}
-
-void NuPlayer2::pause() {
- (new AMessage(kWhatPause, this))->post();
-}
-
-void NuPlayer2::resetAsync() {
- disconnectSource();
- (new AMessage(kWhatReset, this))->post();
-}
-
-void NuPlayer2::disconnectSource() {
- sp<Source> source;
- {
- Mutex::Autolock autoLock(mSourceLock);
- source = mCurrentSourceInfo.mSource;
- }
-
- if (source != NULL) {
- // During a reset, the data source might be unresponsive already, we need to
- // disconnect explicitly so that reads exit promptly.
- // We can't queue the disconnect request to the looper, as it might be
- // queued behind a stuck read and never gets processed.
- // Doing a disconnect outside the looper to allows the pending reads to exit
- // (either successfully or with error).
- source->disconnect();
- }
-
-}
-
-status_t NuPlayer2::notifyAt(int64_t mediaTimeUs) {
- sp<AMessage> notify = new AMessage(kWhatNotifyTime, this);
- notify->setInt64("timerUs", mediaTimeUs);
- mMediaClock->addTimer(notify, mediaTimeUs);
- return OK;
-}
-
-void NuPlayer2::seekToAsync(int64_t seekTimeUs, MediaPlayer2SeekMode mode, bool needNotify) {
- sp<AMessage> msg = new AMessage(kWhatSeek, this);
- msg->setInt64("seekTimeUs", seekTimeUs);
- msg->setInt32("mode", mode);
- msg->setInt32("needNotify", needNotify);
- msg->post();
-}
-
-void NuPlayer2::rewind() {
- sp<AMessage> msg = new AMessage(kWhatRewind, this);
- msg->post();
-}
-
-void NuPlayer2::writeTrackInfo(
- PlayerMessage* reply, const sp<AMessage>& format) const {
- if (format == NULL) {
- ALOGE("NULL format");
- return;
- }
- int32_t trackType;
- if (!format->findInt32("type", &trackType)) {
- ALOGE("no track type");
- return;
- }
-
- AString mime;
- if (!format->findString("mime", &mime)) {
- // Java MediaPlayer only uses mimetype for subtitle and timedtext tracks.
- // If we can't find the mimetype here it means that we wouldn't be needing
- // the mimetype on the Java end. We still write a placeholder mime to keep the
- // (de)serialization logic simple.
- if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
- mime = "audio/";
- } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
- mime = "video/";
- } else {
- ALOGE("unknown track type: %d", trackType);
- return;
- }
- }
-
- AString lang;
- if (!format->findString("language", &lang)) {
- ALOGE("no language");
- return;
- }
-
- reply->add_values()->set_int32_value(trackType);
- reply->add_values()->set_string_value(mime.c_str());
- reply->add_values()->set_string_value(lang.c_str());
-
- if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
- int32_t isAuto, isDefault, isForced;
- CHECK(format->findInt32("auto", &isAuto));
- CHECK(format->findInt32("default", &isDefault));
- CHECK(format->findInt32("forced", &isForced));
-
- reply->add_values()->set_int32_value(isAuto);
- reply->add_values()->set_int32_value(isDefault);
- reply->add_values()->set_int32_value(isForced);
- }
-}
-
-void NuPlayer2::onMessageReceived(const sp<AMessage> &msg) {
-
- switch (msg->what()) {
- case kWhatSetDataSource:
- {
- ALOGV("kWhatSetDataSource");
-
- CHECK(mCurrentSourceInfo.mSource == NULL);
-
- status_t err = OK;
- sp<RefBase> obj;
- CHECK(msg->findObject("source", &obj));
- if (obj != NULL) {
- Mutex::Autolock autoLock(mSourceLock);
- CHECK(msg->findInt64("srcId", &mCurrentSourceInfo.mSrcId));
- CHECK(msg->findInt64("startTimeUs", &mCurrentSourceInfo.mStartTimeUs));
- CHECK(msg->findInt64("endTimeUs", &mCurrentSourceInfo.mEndTimeUs));
- mCurrentSourceInfo.mSource = static_cast<Source *>(obj.get());
- } else {
- err = UNKNOWN_ERROR;
- ALOGE("kWhatSetDataSource, source should not be NULL");
- }
-
- CHECK(mDriver != NULL);
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
- driver->notifySetDataSourceCompleted(mCurrentSourceInfo.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", &mNextSourceInfo.mSrcId));
- CHECK(msg->findInt64("startTimeUs", &mNextSourceInfo.mStartTimeUs));
- CHECK(msg->findInt64("endTimeUs", &mNextSourceInfo.mEndTimeUs));
- mNextSourceInfo.mSource = static_cast<Source *>(obj.get());
- mNextSourceInfo.mSource->prepareAsync(mNextSourceInfo.mStartTimeUs);
- } else {
- err = UNKNOWN_ERROR;
- }
-
- break;
- }
-
- case kWhatPlayNextDataSource:
- {
- ALOGV("kWhatPlayNextDataSource");
- int64_t srcId;
- CHECK(msg->findInt64("srcId", &srcId));
- if (srcId != mNextSourceInfo.mSrcId) {
- notifyListener(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, 0);
- return;
- }
-
- mResetting = true;
- stopPlaybackTimer("kWhatPlayNextDataSource");
- stopRebufferingTimer(true);
-
- mDeferredActions.push_back(
- new FlushDecoderAction(
- FLUSH_CMD_SHUTDOWN /* audio */,
- FLUSH_CMD_SHUTDOWN /* video */));
-
- mDeferredActions.push_back(
- new SimpleAction(&NuPlayer2::performPlayNextDataSource));
-
- processDeferredActions();
- break;
- }
-
- case kWhatEOSMonitor:
- {
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
- int32_t reason;
- CHECK(msg->findInt32("reason", &reason));
-
- if (generation != mEOSMonitorGeneration || reason != MediaClock::TIMER_REASON_REACHED) {
- break; // stale or reset
- }
-
- ALOGV("kWhatEOSMonitor");
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
- break;
- }
-
- case kWhatGetBufferingSettings:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
- ALOGV("kWhatGetBufferingSettings");
- BufferingSettings buffering;
- status_t err = OK;
- if (mCurrentSourceInfo.mSource != NULL) {
- err = mCurrentSourceInfo.mSource->getBufferingSettings(&buffering);
- } else {
- err = INVALID_OPERATION;
- }
- sp<AMessage> response = new AMessage;
- if (err == OK) {
- writeToAMessage(response, buffering);
- }
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatSetBufferingSettings:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
- ALOGV("kWhatSetBufferingSettings");
- BufferingSettings buffering;
- readFromAMessage(msg, &buffering);
- status_t err = OK;
- if (mCurrentSourceInfo.mSource != NULL) {
- err = mCurrentSourceInfo.mSource->setBufferingSettings(buffering);
- } else {
- err = INVALID_OPERATION;
- }
- sp<AMessage> response = new AMessage;
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatPrepare:
- {
- ALOGV("onMessageReceived kWhatPrepare");
-
- mCurrentSourceInfo.mSource->prepareAsync(mCurrentSourceInfo.mStartTimeUs);
- break;
- }
-
- case kWhatGetTrackInfo:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
- int64_t srcId;
- CHECK(msg->findInt64("srcId", (int64_t*)&srcId));
-
- PlayerMessage* reply;
- CHECK(msg->findPointer("reply", (void**)&reply));
-
- // TODO: use correct source info based on srcId.
- size_t inbandTracks = 0;
- if (mCurrentSourceInfo.mSource != NULL) {
- inbandTracks = mCurrentSourceInfo.mSource->getTrackCount();
- }
-
- size_t ccTracks = 0;
- if (mCCDecoder != NULL) {
- ccTracks = mCCDecoder->getTrackCount();
- }
-
- // total track count
- reply->add_values()->set_int32_value(inbandTracks + ccTracks);
-
- // write inband tracks
- for (size_t i = 0; i < inbandTracks; ++i) {
- writeTrackInfo(reply, mCurrentSourceInfo.mSource->getTrackInfo(i));
- }
-
- // write CC track
- for (size_t i = 0; i < ccTracks; ++i) {
- writeTrackInfo(reply, mCCDecoder->getTrackInfo(i));
- }
-
- sp<AMessage> response = new AMessage;
- response->postReply(replyID);
- break;
- }
-
- case kWhatGetSelectedTrack:
- {
- int64_t srcId;
- CHECK(msg->findInt64("srcId", (int64_t*)&srcId));
-
- int32_t type32;
- CHECK(msg->findInt32("type", (int32_t*)&type32));
- media_track_type type = (media_track_type)type32;
-
- // TODO: use correct source info based on srcId.
- size_t inbandTracks = 0;
- status_t err = INVALID_OPERATION;
- ssize_t selectedTrack = -1;
- if (mCurrentSourceInfo.mSource != NULL) {
- err = OK;
- inbandTracks = mCurrentSourceInfo.mSource->getTrackCount();
- selectedTrack = mCurrentSourceInfo.mSource->getSelectedTrack(type);
- }
-
- if (selectedTrack == -1 && mCCDecoder != NULL) {
- err = OK;
- selectedTrack = mCCDecoder->getSelectedTrack(type);
- if (selectedTrack != -1) {
- selectedTrack += inbandTracks;
- }
- }
-
- PlayerMessage* reply;
- CHECK(msg->findPointer("reply", (void**)&reply));
- reply->add_values()->set_int32_value(selectedTrack);
-
- sp<AMessage> response = new AMessage;
- response->setInt32("err", err);
-
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
- break;
- }
-
- case kWhatSelectTrack:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
- int64_t srcId;
- size_t trackIndex;
- int32_t select;
- int64_t timeUs;
- CHECK(msg->findInt64("srcId", (int64_t*)&srcId));
- CHECK(msg->findSize("trackIndex", &trackIndex));
- CHECK(msg->findInt32("select", &select));
- CHECK(msg->findInt64("timeUs", &timeUs));
-
- status_t err = INVALID_OPERATION;
-
- // TODO: use correct source info based on srcId.
- size_t inbandTracks = 0;
- if (mCurrentSourceInfo.mSource != NULL) {
- inbandTracks = mCurrentSourceInfo.mSource->getTrackCount();
- }
- size_t ccTracks = 0;
- if (mCCDecoder != NULL) {
- ccTracks = mCCDecoder->getTrackCount();
- }
-
- if (trackIndex < inbandTracks) {
- err = mCurrentSourceInfo.mSource->selectTrack(trackIndex, select, timeUs);
-
- if (!select && err == OK) {
- int32_t type;
- sp<AMessage> info = mCurrentSourceInfo.mSource->getTrackInfo(trackIndex);
- if (info != NULL
- && info->findInt32("type", &type)
- && type == MEDIA_TRACK_TYPE_TIMEDTEXT) {
- ++mTimedTextGeneration;
- }
- }
- } else {
- trackIndex -= inbandTracks;
-
- if (trackIndex < ccTracks) {
- err = mCCDecoder->selectTrack(trackIndex, select);
- }
- }
-
- sp<AMessage> response = new AMessage;
- response->setInt32("err", err);
-
- response->postReply(replyID);
- break;
- }
-
- case kWhatPollDuration:
- {
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
-
- if (generation != mPollDurationGeneration) {
- // stale
- break;
- }
-
- int64_t durationUs;
- if (mDriver != NULL && mCurrentSourceInfo.mSource->getDuration(&durationUs) == OK) {
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
- driver->notifyDuration(mCurrentSourceInfo.mSrcId, durationUs);
- }
- }
-
- msg->post(1000000LL); // poll again in a second.
- break;
- }
-
- case kWhatSetVideoSurface:
- {
-
- sp<RefBase> obj;
- CHECK(msg->findObject("surface", &obj));
- sp<ANativeWindowWrapper> nww = static_cast<ANativeWindowWrapper *>(obj.get());
-
- ALOGD("onSetVideoSurface(%p, %s video decoder)",
- (nww == NULL ? NULL : nww->getANativeWindow()),
- (mCurrentSourceInfo.mSource != NULL && mStarted
- && mCurrentSourceInfo.mSource->getFormat(false /* audio */) != NULL
- && mVideoDecoder != NULL) ? "have" : "no");
-
- // Need to check mStarted before calling mCurrentSourceInfo.mSource->getFormat
- // because NuPlayer2 might be in preparing state and it could take long time.
- // When mStarted is true, mCurrentSourceInfo.mSource must have been set.
- if (mCurrentSourceInfo.mSource == NULL || !mStarted
- || mCurrentSourceInfo.mSource->getFormat(false /* audio */) == NULL
- // NOTE: mVideoDecoder's mNativeWindow is always non-null
- || (mVideoDecoder != NULL && mVideoDecoder->setVideoSurface(nww) == OK)) {
- performSetSurface(nww);
- break;
- }
-
- mDeferredActions.push_back(
- new FlushDecoderAction(
- (obj != NULL ? FLUSH_CMD_FLUSH : FLUSH_CMD_NONE) /* audio */,
- FLUSH_CMD_SHUTDOWN /* video */));
-
- mDeferredActions.push_back(new SetSurfaceAction(nww));
-
- if (obj != NULL) {
- if (mStarted) {
- // Issue a seek to refresh the video screen only if started otherwise
- // the extractor may not yet be started and will assert.
- // If the video decoder is not set (perhaps audio only in this case)
- // do not perform a seek as it is not needed.
- int64_t currentPositionUs = 0;
- if (getCurrentPosition(¤tPositionUs) == OK) {
- mDeferredActions.push_back(
- new SeekAction(currentPositionUs,
- MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC /* mode */));
- }
- }
-
- // If there is a new surface texture, instantiate decoders
- // again if possible.
- mDeferredActions.push_back(
- new SimpleAction(&NuPlayer2::performScanSources));
-
- // After a flush without shutdown, decoder is paused.
- // Don't resume it until source seek is done, otherwise it could
- // start pulling stale data too soon.
- mDeferredActions.push_back(
- new ResumeDecoderAction(false /* needNotify */));
- }
-
- processDeferredActions();
- break;
- }
-
- case kWhatSetAudioSink:
- {
- ALOGV("kWhatSetAudioSink");
-
- sp<RefBase> obj;
- CHECK(msg->findObject("sink", &obj));
-
- mAudioSink = static_cast<MediaPlayer2Interface::AudioSink *>(obj.get());
- break;
- }
-
- case kWhatStart:
- {
- ALOGV("kWhatStart");
- if (mStarted) {
- // do not resume yet if the source is still buffering
- if (!mPausedForBuffering) {
- onResume();
- }
- } else {
- onStart(true /* play */);
- }
- mPausedByClient = false;
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_STARTED, 0, 0);
- break;
- }
-
- case kWhatConfigPlayback:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- AudioPlaybackRate rate /* sanitized */;
- readFromAMessage(msg, &rate);
- status_t err = OK;
- if (mRenderer != NULL) {
- // AudioSink allows only 1.f and 0.f for offload mode.
- // For other speed, switch to non-offload mode.
- if (mOffloadAudio && (rate.mSpeed != 1.f || rate.mPitch != 1.f)) {
- int64_t currentPositionUs;
- if (getCurrentPosition(¤tPositionUs) != OK) {
- currentPositionUs = mPreviousSeekTimeUs;
- }
-
- // Set mPlaybackSettings so that the new audio decoder can
- // be created correctly.
- mPlaybackSettings = rate;
- if (!mPaused) {
- mRenderer->pause();
- }
- restartAudio(
- currentPositionUs, true /* forceNonOffload */,
- true /* needsToCreateAudioDecoder */);
- if (!mPaused) {
- mRenderer->resume();
- }
- }
-
- err = mRenderer->setPlaybackSettings(rate);
- }
- if (err == OK) {
- mPlaybackSettings = rate;
-
- if (mVideoDecoder != NULL) {
- sp<AMessage> params = new AMessage();
- params->setFloat("playback-speed", mPlaybackSettings.mSpeed);
- mVideoDecoder->setParameters(params);
- }
- }
-
- sp<AMessage> response = new AMessage;
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatGetPlaybackSettings:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- AudioPlaybackRate rate = mPlaybackSettings;
- status_t err = OK;
- if (mRenderer != NULL) {
- err = mRenderer->getPlaybackSettings(&rate);
- }
- if (err == OK) {
- // get playback settings used by renderer, as it may be
- // slightly off due to audiosink not taking small changes.
- mPlaybackSettings = rate;
- }
- sp<AMessage> response = new AMessage;
- if (err == OK) {
- writeToAMessage(response, rate);
- }
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatConfigSync:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
- ALOGV("kWhatConfigSync");
- AVSyncSettings sync;
- float videoFpsHint;
- readFromAMessage(msg, &sync, &videoFpsHint);
- status_t err = OK;
- if (mRenderer != NULL) {
- err = mRenderer->setSyncSettings(sync, videoFpsHint);
- }
- if (err == OK) {
- mSyncSettings = sync;
- mVideoFpsHint = videoFpsHint;
- }
- sp<AMessage> response = new AMessage;
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatGetSyncSettings:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- AVSyncSettings sync = mSyncSettings;
- float videoFps = mVideoFpsHint;
- status_t err = OK;
- if (mRenderer != NULL) {
- err = mRenderer->getSyncSettings(&sync, &videoFps);
- if (err == OK) {
- mSyncSettings = sync;
- mVideoFpsHint = videoFps;
- }
- }
- sp<AMessage> response = new AMessage;
- if (err == OK) {
- writeToAMessage(response, sync, videoFps);
- }
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatScanSources:
- {
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
- if (generation != mScanSourcesGeneration) {
- // Drop obsolete msg.
- break;
- }
-
- mScanSourcesPending = false;
-
- ALOGV("scanning sources haveAudio=%d, haveVideo=%d",
- mAudioDecoder != NULL, mVideoDecoder != NULL);
-
- bool mHadAnySourcesBefore =
- (mAudioDecoder != NULL) || (mVideoDecoder != NULL);
- bool rescan = false;
-
- // initialize video before audio because successful initialization of
- // video may change deep buffer mode of audio.
- if (mNativeWindow != NULL && mNativeWindow->getANativeWindow() != NULL) {
- if (instantiateDecoder(false, &mVideoDecoder) == -EWOULDBLOCK) {
- rescan = true;
- }
- }
-
- // Don't try to re-open audio sink if there's an existing decoder.
- if (mAudioSink != NULL && mAudioDecoder == NULL) {
- if (instantiateDecoder(true, &mAudioDecoder) == -EWOULDBLOCK) {
- rescan = true;
- }
- }
-
- if (!mHadAnySourcesBefore
- && (mAudioDecoder != NULL || mVideoDecoder != NULL)) {
- // This is the first time we've found anything playable.
-
- if (mCurrentSourceInfo.mSourceFlags & Source::FLAG_DYNAMIC_DURATION) {
- schedulePollDuration();
- }
- }
-
- status_t err;
- if ((err = mCurrentSourceInfo.mSource->feedMoreTSData()) != OK) {
- if (mAudioDecoder == NULL && mVideoDecoder == NULL) {
- // We're not currently decoding anything (no audio or
- // video tracks found) and we just ran out of input data.
-
- if (err == ERROR_END_OF_STREAM) {
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
- } else {
- notifyListener(
- mCurrentSourceInfo.mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
- }
- }
- break;
- }
-
- if (rescan) {
- msg->post(100000LL);
- mScanSourcesPending = true;
- }
- break;
- }
-
- case kWhatVideoNotify:
- case kWhatAudioNotify:
- {
- bool audio = msg->what() == kWhatAudioNotify;
-
- int32_t currentDecoderGeneration =
- (audio? mAudioDecoderGeneration : mVideoDecoderGeneration);
- int32_t requesterGeneration = currentDecoderGeneration - 1;
- CHECK(msg->findInt32("generation", &requesterGeneration));
-
- if (requesterGeneration != currentDecoderGeneration) {
- ALOGV("got message from old %s decoder, generation(%d:%d)",
- audio ? "audio" : "video", requesterGeneration,
- currentDecoderGeneration);
- sp<AMessage> reply;
- if (!(msg->findMessage("reply", &reply))) {
- return;
- }
-
- reply->setInt32("err", INFO_DISCONTINUITY);
- reply->post();
- return;
- }
-
- int32_t what;
- CHECK(msg->findInt32("what", &what));
-
- if (what == DecoderBase::kWhatInputDiscontinuity) {
- int32_t formatChange;
- CHECK(msg->findInt32("formatChange", &formatChange));
-
- ALOGV("%s discontinuity: formatChange %d",
- audio ? "audio" : "video", formatChange);
-
- if (formatChange) {
- mDeferredActions.push_back(
- new FlushDecoderAction(
- audio ? FLUSH_CMD_SHUTDOWN : FLUSH_CMD_NONE,
- audio ? FLUSH_CMD_NONE : FLUSH_CMD_SHUTDOWN));
- }
-
- mDeferredActions.push_back(
- new SimpleAction(
- &NuPlayer2::performScanSources));
-
- processDeferredActions();
- } else if (what == DecoderBase::kWhatEOS) {
- int32_t err;
- CHECK(msg->findInt32("err", &err));
-
- if (err == ERROR_END_OF_STREAM) {
- ALOGV("got %s decoder EOS", audio ? "audio" : "video");
- } else {
- ALOGV("got %s decoder EOS w/ error %d",
- audio ? "audio" : "video",
- err);
- }
-
- mRenderer->queueEOS(audio, err);
- } else if (what == DecoderBase::kWhatFlushCompleted) {
- ALOGV("decoder %s flush completed", audio ? "audio" : "video");
-
- handleFlushComplete(audio, true /* isDecoder */);
- finishFlushIfPossible();
- } else if (what == DecoderBase::kWhatVideoSizeChanged) {
- sp<AMessage> format;
- CHECK(msg->findMessage("format", &format));
-
- sp<AMessage> inputFormat =
- mCurrentSourceInfo.mSource->getFormat(false /* audio */);
-
- setVideoScalingMode(mVideoScalingMode);
- updateVideoSize(mCurrentSourceInfo.mSrcId, inputFormat, format);
- } else if (what == DecoderBase::kWhatShutdownCompleted) {
- ALOGV("%s shutdown completed", audio ? "audio" : "video");
- if (audio) {
- Mutex::Autolock autoLock(mDecoderLock);
- mAudioDecoder.clear();
- mAudioDecoderError = false;
- ++mAudioDecoderGeneration;
-
- CHECK_EQ((int)mFlushingAudio, (int)SHUTTING_DOWN_DECODER);
- mFlushingAudio = SHUT_DOWN;
- } else {
- Mutex::Autolock autoLock(mDecoderLock);
- mVideoDecoder.clear();
- mVideoDecoderError = false;
- ++mVideoDecoderGeneration;
-
- CHECK_EQ((int)mFlushingVideo, (int)SHUTTING_DOWN_DECODER);
- mFlushingVideo = SHUT_DOWN;
- }
-
- finishFlushIfPossible();
- } else if (what == DecoderBase::kWhatResumeCompleted) {
- finishResume();
- } else if (what == DecoderBase::kWhatError) {
- status_t err;
- if (!msg->findInt32("err", &err) || err == OK) {
- err = UNKNOWN_ERROR;
- }
-
- // Decoder errors can be due to Source (e.g. from streaming),
- // or from decoding corrupted bitstreams, or from other decoder
- // MediaCodec operations (e.g. from an ongoing reset or seek).
- // They may also be due to openAudioSink failure at
- // decoder start or after a format change.
- //
- // We try to gracefully shut down the affected decoder if possible,
- // rather than trying to force the shutdown with something
- // similar to performReset(). This method can lead to a hang
- // if MediaCodec functions block after an error, but they should
- // typically return INVALID_OPERATION instead of blocking.
-
- FlushStatus *flushing = audio ? &mFlushingAudio : &mFlushingVideo;
- ALOGE("received error(%#x) from %s decoder, flushing(%d), now shutting down",
- err, audio ? "audio" : "video", *flushing);
-
- switch (*flushing) {
- case NONE:
- mDeferredActions.push_back(
- new FlushDecoderAction(
- audio ? FLUSH_CMD_SHUTDOWN : FLUSH_CMD_NONE,
- audio ? FLUSH_CMD_NONE : FLUSH_CMD_SHUTDOWN));
- processDeferredActions();
- break;
- case FLUSHING_DECODER:
- *flushing = FLUSHING_DECODER_SHUTDOWN; // initiate shutdown after flush.
- break; // Wait for flush to complete.
- case FLUSHING_DECODER_SHUTDOWN:
- break; // Wait for flush to complete.
- case SHUTTING_DOWN_DECODER:
- break; // Wait for shutdown to complete.
- case FLUSHED:
- getDecoder(audio)->initiateShutdown(); // In the middle of a seek.
- *flushing = SHUTTING_DOWN_DECODER; // Shut down.
- break;
- case SHUT_DOWN:
- finishFlushIfPossible(); // Should not occur.
- break; // Finish anyways.
- }
- if (mCurrentSourceInfo.mSource != nullptr) {
- if (audio) {
- if (mVideoDecoderError
- || mCurrentSourceInfo.mSource->getFormat(false /* audio */) == NULL
- || mNativeWindow == NULL
- || mNativeWindow->getANativeWindow() == NULL
- || mVideoDecoder == NULL) {
- // When both audio and video have error, or this stream has only audio
- // which has error, notify client of error.
- notifyListener(
- mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
- MEDIA2_ERROR_UNKNOWN, err);
- } else {
- // Only audio track has error. Video track could be still good to play.
- notifyListener(
- mCurrentSourceInfo.mSrcId, MEDIA2_INFO,
- MEDIA2_INFO_PLAY_AUDIO_ERROR, err);
- }
- mAudioDecoderError = true;
- } else {
- if (mAudioDecoderError
- || mCurrentSourceInfo.mSource->getFormat(true /* audio */) == NULL
- || 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(
- mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
- MEDIA2_ERROR_UNKNOWN, err);
- } else {
- // Only video track has error. Audio track could be still good to play.
- notifyListener(
- mCurrentSourceInfo.mSrcId, MEDIA2_INFO,
- MEDIA2_INFO_PLAY_VIDEO_ERROR, err);
- }
- mVideoDecoderError = true;
- }
- }
- } else {
- ALOGV("Unhandled decoder notification %d '%c%c%c%c'.",
- what,
- what >> 24,
- (what >> 16) & 0xff,
- (what >> 8) & 0xff,
- what & 0xff);
- }
-
- break;
- }
-
- case kWhatRendererNotify:
- {
- int32_t requesterGeneration = mRendererGeneration - 1;
- CHECK(msg->findInt32("generation", &requesterGeneration));
- if (requesterGeneration != mRendererGeneration) {
- ALOGV("got message from old renderer, generation(%d:%d)",
- requesterGeneration, mRendererGeneration);
- return;
- }
-
- int32_t what;
- CHECK(msg->findInt32("what", &what));
-
- if (what == Renderer::kWhatEOS) {
- int32_t audio;
- CHECK(msg->findInt32("audio", &audio));
-
- int32_t finalResult;
- CHECK(msg->findInt32("finalResult", &finalResult));
-
- if (audio) {
- mAudioEOS = true;
- } else {
- mVideoEOS = true;
- }
-
- if (finalResult == ERROR_END_OF_STREAM) {
- ALOGV("reached %s EOS", audio ? "audio" : "video");
- } else {
- ALOGE("%s track encountered an error (%d)",
- audio ? "audio" : "video", finalResult);
-
- notifyListener(
- mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
- MEDIA2_ERROR_UNKNOWN, finalResult);
- }
-
- if ((mAudioEOS || mAudioDecoder == NULL)
- && (mVideoEOS || mVideoDecoder == NULL)) {
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
- }
- } else if (what == Renderer::kWhatFlushComplete) {
- int32_t audio;
- CHECK(msg->findInt32("audio", &audio));
-
- if (audio) {
- mAudioEOS = false;
- } else {
- mVideoEOS = false;
- }
-
- ALOGV("renderer %s flush completed.", audio ? "audio" : "video");
- if (audio && (mFlushingAudio == NONE || mFlushingAudio == FLUSHED
- || mFlushingAudio == SHUT_DOWN)) {
- // Flush has been handled by tear down.
- break;
- }
- handleFlushComplete(audio, false /* isDecoder */);
- finishFlushIfPossible();
- } else if (what == Renderer::kWhatVideoRenderingStart) {
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_INFO,
- MEDIA2_INFO_VIDEO_RENDERING_START, 0);
- } else if (what == Renderer::kWhatMediaRenderingStart) {
- ALOGV("media rendering started");
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_STARTED, 0, 0);
- } else if (what == Renderer::kWhatAudioTearDown) {
- int32_t reason;
- CHECK(msg->findInt32("reason", &reason));
- ALOGV("Tear down audio with reason %d.", reason);
- if (reason == Renderer::kDueToTimeout && !(mPaused && mOffloadAudio)) {
- // TimeoutWhenPaused is only for offload mode.
- ALOGW("Receive a stale message for teardown.");
- break;
- }
- int64_t positionUs;
- if (!msg->findInt64("positionUs", &positionUs)) {
- positionUs = mPreviousSeekTimeUs;
- }
-
- restartAudio(
- positionUs, reason == Renderer::kForceNonOffload /* forceNonOffload */,
- reason != Renderer::kDueToTimeout /* needsToCreateAudioDecoder */);
- }
- break;
- }
-
- case kWhatMoreDataQueued:
- {
- break;
- }
-
- case kWhatReset:
- {
- ALOGV("kWhatReset");
-
- mResetting = true;
- stopPlaybackTimer("kWhatReset");
- stopRebufferingTimer(true);
-
- mDeferredActions.push_back(
- new FlushDecoderAction(
- FLUSH_CMD_SHUTDOWN /* audio */,
- FLUSH_CMD_SHUTDOWN /* video */));
-
- mDeferredActions.push_back(
- new SimpleAction(&NuPlayer2::performReset));
-
- processDeferredActions();
- break;
- }
-
- case kWhatNotifyTime:
- {
- ALOGV("kWhatNotifyTime");
- int64_t timerUs;
- CHECK(msg->findInt64("timerUs", &timerUs));
-
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_NOTIFY_TIME, timerUs, 0);
- break;
- }
-
- case kWhatSeek:
- {
- int64_t seekTimeUs;
- int32_t mode;
- int32_t needNotify;
- CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
- CHECK(msg->findInt32("mode", &mode));
- CHECK(msg->findInt32("needNotify", &needNotify));
-
- ALOGV("kWhatSeek seekTimeUs=%lld us, mode=%d, needNotify=%d",
- (long long)seekTimeUs, mode, needNotify);
-
- if (!mStarted) {
- if (!mSourceStarted) {
- mSourceStarted = true;
- mCurrentSourceInfo.mSource->start();
- }
- if (seekTimeUs > 0) {
- performSeek(seekTimeUs, (MediaPlayer2SeekMode)mode);
- }
-
- if (needNotify) {
- notifyDriverSeekComplete(mCurrentSourceInfo.mSrcId);
- }
- break;
- }
-
- // seeks can take a while, so we essentially paused
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PAUSED, 0, 0);
-
- mDeferredActions.push_back(
- new FlushDecoderAction(FLUSH_CMD_FLUSH /* audio */,
- FLUSH_CMD_FLUSH /* video */));
-
- mDeferredActions.push_back(
- new SeekAction(seekTimeUs, (MediaPlayer2SeekMode)mode));
-
- // After a flush without shutdown, decoder is paused.
- // Don't resume it until source seek is done, otherwise it could
- // start pulling stale data too soon.
- mDeferredActions.push_back(
- new ResumeDecoderAction(needNotify));
-
- processDeferredActions();
- break;
- }
-
- case kWhatRewind:
- {
- ALOGV("kWhatRewind");
-
- int64_t seekTimeUs = mCurrentSourceInfo.mStartTimeUs;
- int32_t mode = MediaPlayer2SeekMode::SEEK_CLOSEST;
-
- if (!mStarted) {
- if (!mSourceStarted) {
- mSourceStarted = true;
- mCurrentSourceInfo.mSource->start();
- }
- performSeek(seekTimeUs, (MediaPlayer2SeekMode)mode);
- break;
- }
-
- // seeks can take a while, so we essentially paused
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PAUSED, 0, 0);
-
- mDeferredActions.push_back(
- new FlushDecoderAction(FLUSH_CMD_FLUSH /* audio */,
- FLUSH_CMD_FLUSH /* video */));
-
- mDeferredActions.push_back(
- new SeekAction(seekTimeUs, (MediaPlayer2SeekMode)mode));
-
- // After a flush without shutdown, decoder is paused.
- // Don't resume it until source seek is done, otherwise it could
- // start pulling stale data too soon.
- mDeferredActions.push_back(
- new ResumeDecoderAction(false /* needNotify */));
-
- processDeferredActions();
- break;
- }
-
- case kWhatPause:
- {
- if (!mStarted) {
- onStart(false /* play */);
- }
- onPause();
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PAUSED, 0, 0);
- mPausedByClient = true;
- break;
- }
-
- case kWhatSourceNotify:
- {
- onSourceNotify(msg);
- break;
- }
-
- case kWhatClosedCaptionNotify:
- {
- onClosedCaptionNotify(msg);
- break;
- }
-
- case kWhatPrepareDrm:
- {
- status_t status = onPrepareDrm(msg);
-
- sp<AMessage> response = new AMessage;
- response->setInt32("status", status);
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
- break;
- }
-
- case kWhatReleaseDrm:
- {
- status_t status = onReleaseDrm(msg);
-
- sp<AMessage> response = new AMessage;
- response->setInt32("status", status);
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
- break;
- }
-
- default:
- TRESPASS();
- break;
- }
-}
-
-void NuPlayer2::onResume() {
- if (!mPaused || mResetting) {
- ALOGD_IF(mResetting, "resetting, onResume discarded");
- return;
- }
- mPaused = false;
- if (mCurrentSourceInfo.mSource != NULL) {
- mCurrentSourceInfo.mSource->resume();
- } else {
- ALOGW("resume called when source is gone or not set");
- }
- // |mAudioDecoder| may have been released due to the pause timeout, so re-create it if
- // needed.
- if (audioDecoderStillNeeded() && mAudioDecoder == NULL) {
- instantiateDecoder(true /* audio */, &mAudioDecoder);
- }
- if (mRenderer != NULL) {
- mRenderer->resume();
- } else {
- ALOGW("resume called when renderer is gone or not set");
- }
-
- startPlaybackTimer("onresume");
-}
-
-void NuPlayer2::onStart(bool play) {
- ALOGV("onStart: mCrypto: %p", mCurrentSourceInfo.mCrypto.get());
-
- if (!mSourceStarted) {
- mSourceStarted = true;
- mCurrentSourceInfo.mSource->start();
- }
-
- mOffloadAudio = false;
- mAudioEOS = false;
- mVideoEOS = false;
- mStarted = true;
- mPaused = false;
-
- uint32_t flags = 0;
-
- if (mCurrentSourceInfo.mSource->isRealTime()) {
- flags |= Renderer::FLAG_REAL_TIME;
- }
-
- bool hasAudio = (mCurrentSourceInfo.mSource->getFormat(true /* audio */) != NULL);
- bool hasVideo = (mCurrentSourceInfo.mSource->getFormat(false /* audio */) != NULL);
- if (!hasAudio && !hasVideo) {
- ALOGE("no metadata for either audio or video source");
- mCurrentSourceInfo.mSource->stop();
- mSourceStarted = false;
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
- MEDIA2_ERROR_UNKNOWN, ERROR_MALFORMED);
- return;
- }
- ALOGV_IF(!hasAudio, "no metadata for audio source"); // video only stream
-
- sp<MetaData> audioMeta = mCurrentSourceInfo.mSource->getFormatMeta(true /* audio */);
-
- audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
- if (mAudioSink != NULL) {
- streamType = mAudioSink->getAudioStreamType();
- }
-
- mOffloadAudio =
- JMediaPlayer2Utils::isOffloadedAudioPlaybackSupported(
- audioMeta, hasVideo, mCurrentSourceInfo.mSource->isStreaming(), streamType)
- && (mPlaybackSettings.mSpeed == 1.f && mPlaybackSettings.mPitch == 1.f);
-
- // Modular DRM: Disabling audio offload if the source is protected
- if (mOffloadAudio && mCurrentSourceInfo.mIsDrmProtected) {
- mOffloadAudio = false;
- ALOGV("onStart: Disabling mOffloadAudio now that the source is protected.");
- }
-
- if (mOffloadAudio) {
- flags |= Renderer::FLAG_OFFLOAD_AUDIO;
- }
-
- sp<AMessage> notify = new AMessage(kWhatRendererNotify, this);
- ++mRendererGeneration;
- notify->setInt32("generation", mRendererGeneration);
- mRenderer = new Renderer(mAudioSink, mMediaClock, notify, mContext, flags);
- mRendererLooper = new ALooper;
- mRendererLooper->setName("NuPlayer2Renderer");
- mRendererLooper->start(false, true, ANDROID_PRIORITY_AUDIO);
- mRendererLooper->registerHandler(mRenderer);
-
- status_t err = mRenderer->setPlaybackSettings(mPlaybackSettings);
- if (err != OK) {
- mCurrentSourceInfo.mSource->stop();
- mSourceStarted = false;
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
- return;
- }
-
- float rate = getFrameRate();
- if (rate > 0) {
- mRenderer->setVideoFrameRate(rate);
- }
-
- addEndTimeMonitor();
- // Renderer is created in paused state.
- if (play) {
- mRenderer->resume();
- }
-
- if (mVideoDecoder != NULL) {
- mVideoDecoder->setRenderer(mRenderer);
- }
- if (mAudioDecoder != NULL) {
- mAudioDecoder->setRenderer(mRenderer);
- }
-
- startPlaybackTimer("onstart");
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_START, 0);
-
- postScanSources();
-}
-
-void NuPlayer2::addEndTimeMonitor() {
- ++mEOSMonitorGeneration;
-
- if (mCurrentSourceInfo.mEndTimeUs == DataSourceDesc::kMaxTimeUs) {
- return;
- }
-
- sp<AMessage> msg = new AMessage(kWhatEOSMonitor, this);
- msg->setInt32("generation", mEOSMonitorGeneration);
- mMediaClock->addTimer(msg, mCurrentSourceInfo.mEndTimeUs);
-}
-
-void NuPlayer2::startPlaybackTimer(const char *where) {
- Mutex::Autolock autoLock(mPlayingTimeLock);
- if (mLastStartedPlayingTimeNs == 0) {
- mLastStartedPlayingTimeNs = systemTime();
- ALOGV("startPlaybackTimer() time %20" PRId64 " (%s)", mLastStartedPlayingTimeNs, where);
- }
-}
-
-void NuPlayer2::stopPlaybackTimer(const char *where) {
- Mutex::Autolock autoLock(mPlayingTimeLock);
-
- ALOGV("stopPlaybackTimer() time %20" PRId64 " (%s)", mLastStartedPlayingTimeNs, where);
-
- if (mLastStartedPlayingTimeNs != 0) {
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
- int64_t now = systemTime();
- int64_t played = now - mLastStartedPlayingTimeNs;
- ALOGV("stopPlaybackTimer() log %20" PRId64 "", played);
-
- if (played > 0) {
- driver->notifyMorePlayingTimeUs(mCurrentSourceInfo.mSrcId, (played+500)/1000);
- }
- }
- mLastStartedPlayingTimeNs = 0;
- }
-}
-
-void NuPlayer2::startRebufferingTimer() {
- Mutex::Autolock autoLock(mPlayingTimeLock);
- if (mLastStartedRebufferingTimeNs == 0) {
- mLastStartedRebufferingTimeNs = systemTime();
- ALOGV("startRebufferingTimer() time %20" PRId64 "", mLastStartedRebufferingTimeNs);
- }
-}
-
-void NuPlayer2::stopRebufferingTimer(bool exitingPlayback) {
- Mutex::Autolock autoLock(mPlayingTimeLock);
-
- ALOGV("stopRebufferTimer() time %20" PRId64 " (exiting %d)",
- mLastStartedRebufferingTimeNs, exitingPlayback);
-
- if (mLastStartedRebufferingTimeNs != 0) {
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
- int64_t now = systemTime();
- int64_t rebuffered = now - mLastStartedRebufferingTimeNs;
- ALOGV("stopRebufferingTimer() log %20" PRId64 "", rebuffered);
-
- if (rebuffered > 0) {
- driver->notifyMoreRebufferingTimeUs(
- mCurrentSourceInfo.mSrcId, (rebuffered+500)/1000);
- if (exitingPlayback) {
- driver->notifyRebufferingWhenExit(mCurrentSourceInfo.mSrcId, true);
- }
- }
- }
- mLastStartedRebufferingTimeNs = 0;
- }
-}
-
-void NuPlayer2::onPause() {
-
- stopPlaybackTimer("onPause");
-
- if (mPaused) {
- return;
- }
- mPaused = true;
- if (mCurrentSourceInfo.mSource != NULL) {
- mCurrentSourceInfo.mSource->pause();
- } else {
- ALOGW("pause called when source is gone or not set");
- }
- if (mRenderer != NULL) {
- mRenderer->pause();
- } else {
- ALOGW("pause called when renderer is gone or not set");
- }
-
-}
-
-bool NuPlayer2::audioDecoderStillNeeded() {
- // Audio decoder is no longer needed if it's in shut/shutting down status.
- return ((mFlushingAudio != SHUT_DOWN) && (mFlushingAudio != SHUTTING_DOWN_DECODER));
-}
-
-void NuPlayer2::handleFlushComplete(bool audio, bool isDecoder) {
- // We wait for both the decoder flush and the renderer flush to complete
- // before entering either the FLUSHED or the SHUTTING_DOWN_DECODER state.
-
- mFlushComplete[audio][isDecoder] = true;
- if (!mFlushComplete[audio][!isDecoder]) {
- return;
- }
-
- FlushStatus *state = audio ? &mFlushingAudio : &mFlushingVideo;
- switch (*state) {
- case FLUSHING_DECODER:
- {
- *state = FLUSHED;
- break;
- }
-
- case FLUSHING_DECODER_SHUTDOWN:
- {
- *state = SHUTTING_DOWN_DECODER;
-
- ALOGV("initiating %s decoder shutdown", audio ? "audio" : "video");
- getDecoder(audio)->initiateShutdown();
- break;
- }
-
- default:
- // decoder flush completes only occur in a flushing state.
- LOG_ALWAYS_FATAL_IF(isDecoder, "decoder flush in invalid state %d", *state);
- break;
- }
-}
-
-void NuPlayer2::finishFlushIfPossible() {
- if (mFlushingAudio != NONE && mFlushingAudio != FLUSHED
- && mFlushingAudio != SHUT_DOWN) {
- return;
- }
-
- if (mFlushingVideo != NONE && mFlushingVideo != FLUSHED
- && mFlushingVideo != SHUT_DOWN) {
- return;
- }
-
- ALOGV("both audio and video are flushed now.");
-
- mFlushingAudio = NONE;
- mFlushingVideo = NONE;
-
- clearFlushComplete();
-
- processDeferredActions();
-}
-
-void NuPlayer2::postScanSources() {
- if (mScanSourcesPending) {
- return;
- }
-
- sp<AMessage> msg = new AMessage(kWhatScanSources, this);
- msg->setInt32("generation", mScanSourcesGeneration);
- msg->post();
-
- mScanSourcesPending = true;
-}
-
-void NuPlayer2::tryOpenAudioSinkForOffload(
- const sp<AMessage> &format, const sp<MetaData> &audioMeta, bool hasVideo) {
- // Note: This is called early in NuPlayer2 to determine whether offloading
- // is possible; otherwise the decoders call the renderer openAudioSink directly.
-
- status_t err = mRenderer->openAudioSink(
- format, true /* offloadOnly */, hasVideo,
- AUDIO_OUTPUT_FLAG_NONE, &mOffloadAudio, mCurrentSourceInfo.mSource->isStreaming());
- if (err != OK) {
- // Any failure we turn off mOffloadAudio.
- mOffloadAudio = false;
- } else if (mOffloadAudio) {
- sendMetaDataToHal(mAudioSink, audioMeta);
- }
-}
-
-void NuPlayer2::closeAudioSink() {
- mRenderer->closeAudioSink();
-}
-
-void NuPlayer2::restartAudio(
- int64_t currentPositionUs, bool forceNonOffload, bool needsToCreateAudioDecoder) {
- if (mAudioDecoder != NULL) {
- mAudioDecoder->pause();
- Mutex::Autolock autoLock(mDecoderLock);
- mAudioDecoder.clear();
- mAudioDecoderError = false;
- ++mAudioDecoderGeneration;
- }
- if (mFlushingAudio == FLUSHING_DECODER) {
- mFlushComplete[1 /* audio */][1 /* isDecoder */] = true;
- mFlushingAudio = FLUSHED;
- finishFlushIfPossible();
- } else if (mFlushingAudio == FLUSHING_DECODER_SHUTDOWN
- || mFlushingAudio == SHUTTING_DOWN_DECODER) {
- mFlushComplete[1 /* audio */][1 /* isDecoder */] = true;
- mFlushingAudio = SHUT_DOWN;
- finishFlushIfPossible();
- needsToCreateAudioDecoder = false;
- }
- if (mRenderer == NULL) {
- return;
- }
- closeAudioSink();
- mRenderer->flush(true /* audio */, false /* notifyComplete */);
- if (mVideoDecoder != NULL) {
- mDeferredActions.push_back(
- new FlushDecoderAction(FLUSH_CMD_NONE /* audio */,
- FLUSH_CMD_FLUSH /* video */));
- mDeferredActions.push_back(
- new SeekAction(currentPositionUs,
- MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */));
- // After a flush without shutdown, decoder is paused.
- // Don't resume it until source seek is done, otherwise it could
- // start pulling stale data too soon.
- mDeferredActions.push_back(new ResumeDecoderAction(false));
- processDeferredActions();
- } else {
- performSeek(currentPositionUs, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */);
- }
-
- if (forceNonOffload) {
- mRenderer->signalDisableOffloadAudio();
- mOffloadAudio = false;
- }
- if (needsToCreateAudioDecoder) {
- instantiateDecoder(true /* audio */, &mAudioDecoder, !forceNonOffload);
- }
-}
-
-void NuPlayer2::determineAudioModeChange(const sp<AMessage> &audioFormat) {
- if (mCurrentSourceInfo.mSource == NULL || mAudioSink == NULL) {
- return;
- }
-
- if (mRenderer == NULL) {
- ALOGW("No renderer can be used to determine audio mode. Use non-offload for safety.");
- mOffloadAudio = false;
- return;
- }
-
- sp<MetaData> audioMeta = mCurrentSourceInfo.mSource->getFormatMeta(true /* audio */);
- sp<AMessage> videoFormat = mCurrentSourceInfo.mSource->getFormat(false /* audio */);
- audio_stream_type_t streamType = mAudioSink->getAudioStreamType();
- const bool hasVideo = (videoFormat != NULL);
- bool canOffload = JMediaPlayer2Utils::isOffloadedAudioPlaybackSupported(
- audioMeta, hasVideo, mCurrentSourceInfo.mSource->isStreaming(), streamType)
- && (mPlaybackSettings.mSpeed == 1.f && mPlaybackSettings.mPitch == 1.f);
-
- // Modular DRM: Disabling audio offload if the source is protected
- if (canOffload && mCurrentSourceInfo.mIsDrmProtected) {
- canOffload = false;
- ALOGV("determineAudioModeChange: Disabling mOffloadAudio b/c the source is protected.");
- }
-
- if (canOffload) {
- if (!mOffloadAudio) {
- mRenderer->signalEnableOffloadAudio();
- }
- // open audio sink early under offload mode.
- tryOpenAudioSinkForOffload(audioFormat, audioMeta, hasVideo);
- } else {
- if (mOffloadAudio) {
- mRenderer->signalDisableOffloadAudio();
- mOffloadAudio = false;
- }
- }
-}
-
-status_t NuPlayer2::instantiateDecoder(
- bool audio, sp<DecoderBase> *decoder, bool checkAudioModeChange) {
- // The audio decoder could be cleared by tear down. If still in shut down
- // process, no need to create a new audio decoder.
- if (*decoder != NULL || (audio && mFlushingAudio == SHUT_DOWN)) {
- return OK;
- }
-
- sp<AMessage> format = mCurrentSourceInfo.mSource->getFormat(audio);
-
- if (format == NULL) {
- return UNKNOWN_ERROR;
- } else {
- status_t err;
- if (format->findInt32("err", &err) && err) {
- return err;
- }
- }
-
- format->setInt32("priority", 0 /* realtime */);
-
- if (!audio) {
- AString mime;
- CHECK(format->findString("mime", &mime));
-
- sp<AMessage> ccNotify = new AMessage(kWhatClosedCaptionNotify, this);
- if (mCCDecoder == NULL) {
- mCCDecoder = new CCDecoder(ccNotify);
- }
-
- if (mCurrentSourceInfo.mSourceFlags & Source::FLAG_SECURE) {
- format->setInt32("secure", true);
- }
-
- if (mCurrentSourceInfo.mSourceFlags & Source::FLAG_PROTECTED) {
- format->setInt32("protected", true);
- }
-
- float rate = getFrameRate();
- if (rate > 0) {
- format->setFloat("operating-rate", rate * mPlaybackSettings.mSpeed);
- }
- }
-
- Mutex::Autolock autoLock(mDecoderLock);
-
- if (audio) {
- sp<AMessage> notify = new AMessage(kWhatAudioNotify, this);
- ++mAudioDecoderGeneration;
- notify->setInt32("generation", mAudioDecoderGeneration);
-
- if (checkAudioModeChange) {
- determineAudioModeChange(format);
- }
- if (mOffloadAudio) {
- mCurrentSourceInfo.mSource->setOffloadAudio(true /* offload */);
-
- const bool hasVideo = (mCurrentSourceInfo.mSource->getFormat(false /*audio */) != NULL);
- format->setInt32("has-video", hasVideo);
- *decoder = new DecoderPassThrough(notify, mCurrentSourceInfo.mSource, mRenderer);
- ALOGV("instantiateDecoder audio DecoderPassThrough hasVideo: %d", hasVideo);
- } else {
- mCurrentSourceInfo.mSource->setOffloadAudio(false /* offload */);
-
- *decoder = new Decoder(notify, mCurrentSourceInfo.mSource, mPID, mUID, mRenderer);
- ALOGV("instantiateDecoder audio Decoder");
- }
- mAudioDecoderError = false;
- } else {
- sp<AMessage> notify = new AMessage(kWhatVideoNotify, this);
- ++mVideoDecoderGeneration;
- notify->setInt32("generation", mVideoDecoderGeneration);
-
- *decoder = new Decoder(
- notify, mCurrentSourceInfo.mSource, mPID, mUID, mRenderer, mNativeWindow,
- mCCDecoder);
- mVideoDecoderError = false;
-
- // enable FRC if high-quality AV sync is requested, even if not
- // directly queuing to display, as this will even improve textureview
- // playback.
- {
- if (property_get_bool("persist.sys.media.avsync", false)) {
- format->setInt32("auto-frc", 1);
- }
- }
- }
- (*decoder)->init();
-
- // Modular DRM
- if (mCurrentSourceInfo.mIsDrmProtected) {
- format->setObject("crypto", mCurrentSourceInfo.mCrypto);
- ALOGV("instantiateDecoder: mCrypto: %p isSecure: %d",
- mCurrentSourceInfo.mCrypto.get(),
- (mCurrentSourceInfo.mSourceFlags & Source::FLAG_SECURE) != 0);
- }
-
- (*decoder)->configure(format);
-
- if (!audio) {
- sp<AMessage> params = new AMessage();
- float rate = getFrameRate();
- if (rate > 0) {
- params->setFloat("frame-rate-total", rate);
- }
-
- sp<MetaData> fileMeta = getFileMeta();
- if (fileMeta != NULL) {
- int32_t videoTemporalLayerCount;
- if (fileMeta->findInt32(kKeyTemporalLayerCount, &videoTemporalLayerCount)
- && videoTemporalLayerCount > 0) {
- params->setInt32("temporal-layer-count", videoTemporalLayerCount);
- }
- }
-
- if (params->countEntries() > 0) {
- (*decoder)->setParameters(params);
- }
- }
- return OK;
-}
-
-void NuPlayer2::updateVideoSize(
- int64_t srcId,
- const sp<AMessage> &inputFormat,
- const sp<AMessage> &outputFormat) {
- if (inputFormat == NULL) {
- ALOGW("Unknown video size, reporting 0x0!");
- notifyListener(srcId, MEDIA2_SET_VIDEO_SIZE, 0, 0);
- return;
- }
- int32_t err = OK;
- inputFormat->findInt32("err", &err);
- if (err == -EWOULDBLOCK) {
- ALOGW("Video meta is not available yet!");
- return;
- }
- if (err != OK) {
- ALOGW("Something is wrong with video meta!");
- return;
- }
-
- int32_t displayWidth, displayHeight;
- if (outputFormat != NULL) {
- int32_t width, height;
- CHECK(outputFormat->findInt32("width", &width));
- CHECK(outputFormat->findInt32("height", &height));
-
- int32_t cropLeft, cropTop, cropRight, cropBottom;
- CHECK(outputFormat->findRect(
- "crop",
- &cropLeft, &cropTop, &cropRight, &cropBottom));
-
- displayWidth = cropRight - cropLeft + 1;
- displayHeight = cropBottom - cropTop + 1;
-
- ALOGV("Video output format changed to %d x %d "
- "(crop: %d x %d @ (%d, %d))",
- width, height,
- displayWidth,
- displayHeight,
- cropLeft, cropTop);
- } else {
- CHECK(inputFormat->findInt32("width", &displayWidth));
- CHECK(inputFormat->findInt32("height", &displayHeight));
-
- ALOGV("Video input format %d x %d", displayWidth, displayHeight);
- }
-
- // Take into account sample aspect ratio if necessary:
- int32_t sarWidth, sarHeight;
- if (inputFormat->findInt32("sar-width", &sarWidth)
- && inputFormat->findInt32("sar-height", &sarHeight)
- && sarWidth > 0 && sarHeight > 0) {
- ALOGV("Sample aspect ratio %d : %d", sarWidth, sarHeight);
-
- displayWidth = (displayWidth * sarWidth) / sarHeight;
-
- ALOGV("display dimensions %d x %d", displayWidth, displayHeight);
- } else {
- int32_t width, height;
- if (inputFormat->findInt32("display-width", &width)
- && inputFormat->findInt32("display-height", &height)
- && width > 0 && height > 0
- && displayWidth > 0 && displayHeight > 0) {
- if (displayHeight * (int64_t)width / height > (int64_t)displayWidth) {
- displayHeight = (int32_t)(displayWidth * (int64_t)height / width);
- } else {
- displayWidth = (int32_t)(displayHeight * (int64_t)width / height);
- }
- ALOGV("Video display width and height are overridden to %d x %d",
- displayWidth, displayHeight);
- }
- }
-
- int32_t rotationDegrees;
- if (!inputFormat->findInt32("rotation-degrees", &rotationDegrees)) {
- rotationDegrees = 0;
- }
-
- if (rotationDegrees == 90 || rotationDegrees == 270) {
- int32_t tmp = displayWidth;
- displayWidth = displayHeight;
- displayHeight = tmp;
- }
-
- notifyListener(
- srcId,
- MEDIA2_SET_VIDEO_SIZE,
- displayWidth,
- displayHeight);
-}
-
-void NuPlayer2::notifyListener(
- int64_t srcId, int msg, int ext1, int ext2, const PlayerMessage *in) {
- if (mDriver == NULL) {
- return;
- }
-
- sp<NuPlayer2Driver> driver = mDriver.promote();
-
- if (driver == NULL) {
- return;
- }
-
- driver->notifyListener(srcId, msg, ext1, ext2, in);
-}
-
-void NuPlayer2::flushDecoder(bool audio, bool needShutdown) {
- ALOGV("[%s] flushDecoder needShutdown=%d",
- audio ? "audio" : "video", needShutdown);
-
- const sp<DecoderBase> &decoder = getDecoder(audio);
- if (decoder == NULL) {
- ALOGI("flushDecoder %s without decoder present",
- audio ? "audio" : "video");
- return;
- }
-
- // Make sure we don't continue to scan sources until we finish flushing.
- ++mScanSourcesGeneration;
- if (mScanSourcesPending) {
- if (!needShutdown) {
- mDeferredActions.push_back(
- new SimpleAction(&NuPlayer2::performScanSources));
- }
- mScanSourcesPending = false;
- }
-
- decoder->signalFlush();
-
- FlushStatus newStatus =
- needShutdown ? FLUSHING_DECODER_SHUTDOWN : FLUSHING_DECODER;
-
- mFlushComplete[audio][false /* isDecoder */] = (mRenderer == NULL);
- mFlushComplete[audio][true /* isDecoder */] = false;
- if (audio) {
- ALOGE_IF(mFlushingAudio != NONE,
- "audio flushDecoder() is called in state %d", mFlushingAudio);
- mFlushingAudio = newStatus;
- } else {
- ALOGE_IF(mFlushingVideo != NONE,
- "video flushDecoder() is called in state %d", mFlushingVideo);
- mFlushingVideo = newStatus;
- }
-}
-
-void NuPlayer2::queueDecoderShutdown(
- bool audio, bool video, const sp<AMessage> &reply) {
- ALOGI("queueDecoderShutdown audio=%d, video=%d", audio, video);
-
- mDeferredActions.push_back(
- new FlushDecoderAction(
- audio ? FLUSH_CMD_SHUTDOWN : FLUSH_CMD_NONE,
- video ? FLUSH_CMD_SHUTDOWN : FLUSH_CMD_NONE));
-
- mDeferredActions.push_back(
- new SimpleAction(&NuPlayer2::performScanSources));
-
- mDeferredActions.push_back(new PostMessageAction(reply));
-
- processDeferredActions();
-}
-
-status_t NuPlayer2::setVideoScalingMode(int32_t mode) {
- mVideoScalingMode = mode;
- if (mNativeWindow != NULL && mNativeWindow->getANativeWindow() != NULL) {
- status_t ret = native_window_set_scaling_mode(
- mNativeWindow->getANativeWindow(), mVideoScalingMode);
- if (ret != OK) {
- ALOGE("Failed to set scaling mode (%d): %s",
- -ret, strerror(-ret));
- return ret;
- }
- }
- return OK;
-}
-
-status_t NuPlayer2::getTrackInfo(int64_t srcId, PlayerMessage* reply) const {
- sp<AMessage> msg = new AMessage(kWhatGetTrackInfo, this);
- msg->setInt64("srcId", srcId);
- msg->setPointer("reply", reply);
-
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- return err;
-}
-
-status_t NuPlayer2::getSelectedTrack(int64_t srcId, int32_t type, PlayerMessage* reply) const {
- sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, this);
- msg->setPointer("reply", reply);
- msg->setInt64("srcId", srcId);
- msg->setInt32("type", type);
-
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- }
- return err;
-}
-
-status_t NuPlayer2::selectTrack(int64_t srcId, size_t trackIndex, bool select, int64_t timeUs) {
- sp<AMessage> msg = new AMessage(kWhatSelectTrack, this);
- msg->setInt64("srcId", srcId);
- msg->setSize("trackIndex", trackIndex);
- msg->setInt32("select", select);
- msg->setInt64("timeUs", timeUs);
-
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
-
- if (err != OK) {
- return err;
- }
-
- if (!response->findInt32("err", &err)) {
- err = OK;
- }
-
- return err;
-}
-
-status_t NuPlayer2::getCurrentPosition(int64_t *mediaUs) {
- sp<Renderer> renderer = mRenderer;
- if (renderer == NULL) {
- return NO_INIT;
- }
-
- return renderer->getCurrentPosition(mediaUs);
-}
-
-void NuPlayer2::getStats(Vector<sp<AMessage> > *mTrackStats) {
- CHECK(mTrackStats != NULL);
-
- mTrackStats->clear();
-
- Mutex::Autolock autoLock(mDecoderLock);
- if (mVideoDecoder != NULL) {
- mTrackStats->push_back(mVideoDecoder->getStats());
- }
- if (mAudioDecoder != NULL) {
- mTrackStats->push_back(mAudioDecoder->getStats());
- }
-}
-
-sp<MetaData> NuPlayer2::getFileMeta() {
- return mCurrentSourceInfo.mSource->getFileFormatMeta();
-}
-
-float NuPlayer2::getFrameRate() {
- sp<MetaData> meta = mCurrentSourceInfo.mSource->getFormatMeta(false /* audio */);
- if (meta == NULL) {
- return 0;
- }
- int32_t rate;
- if (!meta->findInt32(kKeyFrameRate, &rate)) {
- // fall back to try file meta
- sp<MetaData> fileMeta = getFileMeta();
- if (fileMeta == NULL) {
- ALOGW("source has video meta but not file meta");
- return -1;
- }
- int32_t fileMetaRate;
- if (!fileMeta->findInt32(kKeyFrameRate, &fileMetaRate)) {
- return -1;
- }
- return fileMetaRate;
- }
- return rate;
-}
-
-void NuPlayer2::schedulePollDuration() {
- sp<AMessage> msg = new AMessage(kWhatPollDuration, this);
- msg->setInt32("generation", mPollDurationGeneration);
- msg->post();
-}
-
-void NuPlayer2::cancelPollDuration() {
- ++mPollDurationGeneration;
-}
-
-void NuPlayer2::processDeferredActions() {
- while (!mDeferredActions.empty()) {
- // We won't execute any deferred actions until we're no longer in
- // an intermediate state, i.e. one more more decoders are currently
- // flushing or shutting down.
-
- if (mFlushingAudio != NONE || mFlushingVideo != NONE) {
- // We're currently flushing, postpone the reset until that's
- // completed.
-
- ALOGV("postponing action mFlushingAudio=%d, mFlushingVideo=%d",
- mFlushingAudio, mFlushingVideo);
-
- break;
- }
-
- sp<Action> action = *mDeferredActions.begin();
- mDeferredActions.erase(mDeferredActions.begin());
-
- action->execute(this);
- }
-}
-
-void NuPlayer2::performSeek(int64_t seekTimeUs, MediaPlayer2SeekMode mode) {
- ALOGV("performSeek seekTimeUs=%lld us (%.2f secs), mode=%d",
- (long long)seekTimeUs, seekTimeUs / 1E6, mode);
-
- if (mCurrentSourceInfo.mSource == NULL) {
- // This happens when reset occurs right before the loop mode
- // asynchronously seeks to the start of the stream.
- LOG_ALWAYS_FATAL_IF(mAudioDecoder != NULL || mVideoDecoder != NULL,
- "mCurrentSourceInfo.mSource is NULL and decoders not NULL audio(%p) video(%p)",
- mAudioDecoder.get(), mVideoDecoder.get());
- return;
- }
- mPreviousSeekTimeUs = seekTimeUs;
- mCurrentSourceInfo.mSource->seekTo(seekTimeUs, mode);
- ++mTimedTextGeneration;
-
- // everything's flushed, continue playback.
-}
-
-void NuPlayer2::performDecoderFlush(FlushCommand audio, FlushCommand video) {
- ALOGV("performDecoderFlush audio=%d, video=%d", audio, video);
-
- if ((audio == FLUSH_CMD_NONE || mAudioDecoder == NULL)
- && (video == FLUSH_CMD_NONE || mVideoDecoder == NULL)) {
- return;
- }
-
- if (audio != FLUSH_CMD_NONE && mAudioDecoder != NULL) {
- flushDecoder(true /* audio */, (audio == FLUSH_CMD_SHUTDOWN));
- }
-
- if (video != FLUSH_CMD_NONE && mVideoDecoder != NULL) {
- flushDecoder(false /* audio */, (video == FLUSH_CMD_SHUTDOWN));
- }
-}
-
-void NuPlayer2::performReset() {
- ALOGV("performReset");
-
- CHECK(mAudioDecoder == NULL);
- CHECK(mVideoDecoder == NULL);
-
- stopPlaybackTimer("performReset");
- stopRebufferingTimer(true);
-
- cancelPollDuration();
-
- ++mScanSourcesGeneration;
- mScanSourcesPending = false;
-
- if (mRendererLooper != NULL) {
- if (mRenderer != NULL) {
- mRendererLooper->unregisterHandler(mRenderer->id());
- }
- mRendererLooper->stop();
- mRendererLooper.clear();
- }
- mRenderer.clear();
- ++mRendererGeneration;
-
- resetSourceInfo(mCurrentSourceInfo);
- resetSourceInfo(mNextSourceInfo);
-
- if (mDriver != NULL) {
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
- driver->notifyResetComplete(mCurrentSourceInfo.mSrcId);
- }
- }
-
- mStarted = false;
- mPrepared = false;
- mResetting = false;
- mSourceStarted = false;
-
-}
-
-void NuPlayer2::performPlayNextDataSource() {
- ALOGV("performPlayNextDataSource");
-
- CHECK(mAudioDecoder == NULL);
- CHECK(mVideoDecoder == NULL);
-
- stopPlaybackTimer("performPlayNextDataSource");
- stopRebufferingTimer(true);
-
- cancelPollDuration();
-
- ++mScanSourcesGeneration;
- mScanSourcesPending = false;
-
- ++mRendererGeneration;
-
- if (mCurrentSourceInfo.mSource != NULL) {
- mCurrentSourceInfo.mSource->stop();
- }
-
- long previousSrcId;
- {
- Mutex::Autolock autoLock(mSourceLock);
- previousSrcId = mCurrentSourceInfo.mSrcId;
-
- mCurrentSourceInfo = mNextSourceInfo;
- mNextSourceInfo = SourceInfo();
- mNextSourceInfo.mSrcId = ~mCurrentSourceInfo.mSrcId; // to distinguish the two sources.
- }
-
- if (mDriver != NULL) {
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
- notifyListener(previousSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_END, 0);
-
- int64_t durationUs;
- if (mCurrentSourceInfo.mSource->getDuration(&durationUs) == OK) {
- driver->notifyDuration(mCurrentSourceInfo.mSrcId, durationUs);
- }
- notifyListener(
- mCurrentSourceInfo.mSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_START, 0);
- }
- }
-
- mStarted = false;
- mPrepared = true; // TODO: what if it's not prepared
- mResetting = false;
- mSourceStarted = false;
-
- addEndTimeMonitor();
-
- if (mRenderer != NULL) {
- mRenderer->resume();
- }
-
- onStart(true /* play */);
- mPausedByClient = false;
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_STARTED, 0, 0);
-}
-
-void NuPlayer2::performScanSources() {
- ALOGV("performScanSources");
-
- if (!mStarted) {
- return;
- }
-
- if (mAudioDecoder == NULL || mVideoDecoder == NULL) {
- postScanSources();
- }
-}
-
-void NuPlayer2::performSetSurface(const sp<ANativeWindowWrapper> &nww) {
- ALOGV("performSetSurface");
-
- mNativeWindow = nww;
-
- // XXX - ignore error from setVideoScalingMode for now
- setVideoScalingMode(mVideoScalingMode);
-
- if (mDriver != NULL) {
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
- driver->notifySetSurfaceComplete(mCurrentSourceInfo.mSrcId);
- }
- }
-}
-
-void NuPlayer2::performResumeDecoders(bool needNotify) {
- if (needNotify) {
- mResumePending = true;
- if (mVideoDecoder == NULL) {
- // if audio-only, we can notify seek complete now,
- // as the resume operation will be relatively fast.
- finishResume();
- }
- }
-
- if (mVideoDecoder != NULL) {
- // When there is continuous seek, MediaPlayer will cache the seek
- // position, and send down new seek request when previous seek is
- // complete. Let's wait for at least one video output frame before
- // notifying seek complete, so that the video thumbnail gets updated
- // when seekbar is dragged.
- mVideoDecoder->signalResume(needNotify);
- }
-
- if (mAudioDecoder != NULL) {
- mAudioDecoder->signalResume(false /* needNotify */);
- }
-}
-
-void NuPlayer2::finishResume() {
- if (mResumePending) {
- mResumePending = false;
- notifyDriverSeekComplete(mCurrentSourceInfo.mSrcId);
- }
-}
-
-void NuPlayer2::notifyDriverSeekComplete(int64_t srcId) {
- if (mDriver != NULL) {
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
- driver->notifySeekComplete(srcId);
- }
- }
-}
-
-void NuPlayer2::onSourceNotify(const sp<AMessage> &msg) {
- int32_t what;
- CHECK(msg->findInt32("what", &what));
-
- int64_t srcId;
- CHECK(msg->findInt64("srcId", &srcId));
- switch (what) {
- case Source::kWhatPrepared:
- {
- ALOGV("NuPlayer2::onSourceNotify Source::kWhatPrepared source:%p, Id(%lld)",
- mCurrentSourceInfo.mSource.get(), (long long)srcId);
- if (srcId == mCurrentSourceInfo.mSrcId) {
- if (mCurrentSourceInfo.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;
- }
-
- int32_t err;
- CHECK(msg->findInt32("err", &err));
-
- if (err != OK) {
- // shut down potential secure codecs in case client never calls reset
- mDeferredActions.push_back(
- new FlushDecoderAction(FLUSH_CMD_SHUTDOWN /* audio */,
- FLUSH_CMD_SHUTDOWN /* video */));
- processDeferredActions();
- } else {
- mPrepared = true;
- }
-
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
- // notify duration first, so that it's definitely set when
- // the app received the "prepare complete" callback.
- int64_t durationUs;
- if (mCurrentSourceInfo.mSource->getDuration(&durationUs) == OK) {
- driver->notifyDuration(srcId, durationUs);
- }
- driver->notifyPrepareCompleted(srcId, err);
- }
- } else if (srcId == mNextSourceInfo.mSrcId) {
- if (mNextSourceInfo.mSource == NULL) {
- break; // stale
- }
-
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
- int32_t err;
- CHECK(msg->findInt32("err", &err));
- driver->notifyPrepareCompleted(srcId, err);
- }
- }
-
- break;
- }
-
- // Modular DRM
- case Source::kWhatDrmInfo:
- {
- PlayerMessage playerMsg;
- sp<ABuffer> drmInfo;
- CHECK(msg->findBuffer("drmInfo", &drmInfo));
- playerMsg.ParseFromArray(drmInfo->data(), drmInfo->size());
-
- ALOGV("onSourceNotify() kWhatDrmInfo MEDIA2_DRM_INFO drmInfo: %p playerMsg size: %d",
- drmInfo.get(), playerMsg.ByteSize());
-
- notifyListener(srcId, MEDIA2_DRM_INFO, 0 /* ext1 */, 0 /* ext2 */, &playerMsg);
-
- break;
- }
-
- case Source::kWhatFlagsChanged:
- {
- uint32_t flags;
- CHECK(msg->findInt32("flags", (int32_t *)&flags));
-
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver != NULL) {
-
- ALOGV("onSourceNotify() kWhatFlagsChanged FLAG_CAN_PAUSE: %d "
- "FLAG_CAN_SEEK_BACKWARD: %d \n\t\t\t\t FLAG_CAN_SEEK_FORWARD: %d "
- "FLAG_CAN_SEEK: %d FLAG_DYNAMIC_DURATION: %d \n"
- "\t\t\t\t FLAG_SECURE: %d FLAG_PROTECTED: %d",
- (flags & Source::FLAG_CAN_PAUSE) != 0,
- (flags & Source::FLAG_CAN_SEEK_BACKWARD) != 0,
- (flags & Source::FLAG_CAN_SEEK_FORWARD) != 0,
- (flags & Source::FLAG_CAN_SEEK) != 0,
- (flags & Source::FLAG_DYNAMIC_DURATION) != 0,
- (flags & Source::FLAG_SECURE) != 0,
- (flags & Source::FLAG_PROTECTED) != 0);
-
- if ((flags & NuPlayer2::Source::FLAG_CAN_SEEK) == 0) {
- driver->notifyListener(
- srcId, MEDIA2_INFO, MEDIA2_INFO_NOT_SEEKABLE, 0);
- }
- if (srcId == mCurrentSourceInfo.mSrcId) {
- driver->notifyFlagsChanged(srcId, flags);
- }
- }
-
- if (srcId == mCurrentSourceInfo.mSrcId) {
- if ((mCurrentSourceInfo.mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
- && (!(flags & Source::FLAG_DYNAMIC_DURATION))) {
- cancelPollDuration();
- } else if (!(mCurrentSourceInfo.mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
- && (flags & Source::FLAG_DYNAMIC_DURATION)
- && (mAudioDecoder != NULL || mVideoDecoder != NULL)) {
- schedulePollDuration();
- }
-
- mCurrentSourceInfo.mSourceFlags = flags;
- } else if (srcId == mNextSourceInfo.mSrcId) {
- // TODO: handle duration polling for next source.
- mNextSourceInfo.mSourceFlags = flags;
- }
- break;
- }
-
- case Source::kWhatVideoSizeChanged:
- {
- sp<AMessage> format;
- CHECK(msg->findMessage("format", &format));
-
- updateVideoSize(srcId, format);
- break;
- }
-
- case Source::kWhatBufferingUpdate:
- {
- int32_t percentage;
- CHECK(msg->findInt32("percentage", &percentage));
-
- notifyListener(srcId, MEDIA2_BUFFERING_UPDATE, percentage, 0);
- break;
- }
-
- case Source::kWhatPauseOnBufferingStart:
- {
- // ignore if not playing
- if (mStarted) {
- ALOGI("buffer low, pausing...");
-
- startRebufferingTimer();
- mPausedForBuffering = true;
- onPause();
- }
- notifyListener(srcId, MEDIA2_INFO, MEDIA2_INFO_BUFFERING_START, 0);
- break;
- }
-
- case Source::kWhatResumeOnBufferingEnd:
- {
- // ignore if not playing
- if (mStarted) {
- ALOGI("buffer ready, resuming...");
-
- stopRebufferingTimer(false);
- mPausedForBuffering = false;
-
- // do not resume yet if client didn't unpause
- if (!mPausedByClient) {
- onResume();
- }
- }
- notifyListener(srcId, MEDIA2_INFO, MEDIA2_INFO_BUFFERING_END, 0);
- break;
- }
-
- case Source::kWhatCacheStats:
- {
- int32_t kbps;
- CHECK(msg->findInt32("bandwidth", &kbps));
-
- notifyListener(srcId, MEDIA2_INFO, MEDIA2_INFO_NETWORK_BANDWIDTH, kbps);
- break;
- }
-
- case Source::kWhatSubtitleData:
- {
- sp<ABuffer> buffer;
- CHECK(msg->findBuffer("buffer", &buffer));
-
- sendSubtitleData(buffer, 0 /* baseIndex */);
- break;
- }
-
- case Source::kWhatTimedMetaData:
- {
- sp<ABuffer> buffer;
- if (!msg->findBuffer("buffer", &buffer)) {
- notifyListener(srcId, MEDIA2_INFO, MEDIA2_INFO_METADATA_UPDATE, 0);
- } else {
- sendTimedMetaData(buffer);
- }
- break;
- }
-
- case Source::kWhatTimedTextData:
- {
- int32_t generation;
- if (msg->findInt32("generation", &generation)
- && generation != mTimedTextGeneration) {
- break;
- }
-
- sp<ABuffer> buffer;
- CHECK(msg->findBuffer("buffer", &buffer));
-
- sp<NuPlayer2Driver> driver = mDriver.promote();
- if (driver == NULL) {
- break;
- }
-
- int64_t posMs;
- int64_t timeUs, posUs;
- driver->getCurrentPosition(&posMs);
- posUs = posMs * 1000LL;
- CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
-
- if (posUs < timeUs) {
- if (!msg->findInt32("generation", &generation)) {
- msg->setInt32("generation", mTimedTextGeneration);
- }
- msg->post(timeUs - posUs);
- } else {
- sendTimedTextData(buffer);
- }
- break;
- }
-
- case Source::kWhatQueueDecoderShutdown:
- {
- int32_t audio, video;
- CHECK(msg->findInt32("audio", &audio));
- CHECK(msg->findInt32("video", &video));
-
- sp<AMessage> reply;
- CHECK(msg->findMessage("reply", &reply));
-
- queueDecoderShutdown(audio, video, reply);
- break;
- }
-
- case Source::kWhatDrmNoLicense:
- {
- notifyListener(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
- break;
- }
-
- default:
- TRESPASS();
- }
-}
-
-void NuPlayer2::onClosedCaptionNotify(const sp<AMessage> &msg) {
- int32_t what;
- CHECK(msg->findInt32("what", &what));
-
- switch (what) {
- case NuPlayer2::CCDecoder::kWhatClosedCaptionData:
- {
- sp<ABuffer> buffer;
- CHECK(msg->findBuffer("buffer", &buffer));
-
- size_t inbandTracks = 0;
- if (mCurrentSourceInfo.mSource != NULL) {
- inbandTracks = mCurrentSourceInfo.mSource->getTrackCount();
- }
-
- sendSubtitleData(buffer, inbandTracks);
- break;
- }
-
- case NuPlayer2::CCDecoder::kWhatTrackAdded:
- {
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_INFO, MEDIA2_INFO_METADATA_UPDATE, 0);
-
- break;
- }
-
- default:
- TRESPASS();
- }
-
-
-}
-
-void NuPlayer2::sendSubtitleData(const sp<ABuffer> &buffer, int32_t baseIndex) {
- int32_t trackIndex;
- int64_t timeUs, durationUs;
- CHECK(buffer->meta()->findInt32(AMEDIAFORMAT_KEY_TRACK_INDEX, &trackIndex));
- CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
- CHECK(buffer->meta()->findInt64("durationUs", &durationUs));
-
- PlayerMessage playerMsg;
- playerMsg.add_values()->set_int32_value(trackIndex + baseIndex);
- playerMsg.add_values()->set_int64_value(timeUs);
- playerMsg.add_values()->set_int64_value(durationUs);
- playerMsg.add_values()->set_bytes_value(buffer->data(), buffer->size());
-
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_SUBTITLE_DATA, 0, 0, &playerMsg);
-}
-
-void NuPlayer2::sendTimedMetaData(const sp<ABuffer> &buffer) {
- int64_t timeUs;
- CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
-
- PlayerMessage playerMsg;
- playerMsg.add_values()->set_int64_value(timeUs);
- playerMsg.add_values()->set_bytes_value(buffer->data(), buffer->size());
-
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_META_DATA, 0, 0, &playerMsg);
-}
-
-void NuPlayer2::sendTimedTextData(const sp<ABuffer> &buffer) {
- const void *data;
- size_t size = 0;
- int64_t timeUs;
- int32_t flag = TextDescriptions2::IN_BAND_TEXT_3GPP;
-
- AString mime;
- CHECK(buffer->meta()->findString("mime", &mime));
- CHECK(strcasecmp(mime.c_str(), MEDIA_MIMETYPE_TEXT_3GPP) == 0);
-
- data = buffer->data();
- size = buffer->size();
-
- PlayerMessage playerMsg;
- if (size > 0) {
- CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
- int32_t global = 0;
- if (buffer->meta()->findInt32("global", &global) && global) {
- flag |= TextDescriptions2::GLOBAL_DESCRIPTIONS;
- } else {
- flag |= TextDescriptions2::LOCAL_DESCRIPTIONS;
- }
- TextDescriptions2::getPlayerMessageOfDescriptions(
- (const uint8_t *)data, size, flag, timeUs / 1000, &playerMsg);
- }
-
- if (playerMsg.values_size() > 0) {
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_TIMED_TEXT, 0, 0, &playerMsg);
- } else { // send an empty timed text
- notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_TIMED_TEXT, 0, 0);
- }
-}
-
-const char *NuPlayer2::getDataSourceType() {
- switch (mCurrentSourceInfo.mDataSourceType) {
- case DATA_SOURCE_TYPE_HTTP_LIVE:
- return "HTTPLive";
-
- case DATA_SOURCE_TYPE_RTSP:
- return "RTSP";
-
- case DATA_SOURCE_TYPE_GENERIC_URL:
- return "GenURL";
-
- case DATA_SOURCE_TYPE_GENERIC_FD:
- return "GenFD";
-
- case DATA_SOURCE_TYPE_MEDIA:
- return "Media";
-
- case DATA_SOURCE_TYPE_NONE:
- default:
- return "None";
- }
- }
-
-NuPlayer2::SourceInfo* NuPlayer2::getSourceInfoByIdInMsg(const sp<AMessage> &msg) {
- int64_t srcId;
- CHECK(msg->findInt64("srcId", &srcId));
- if (mCurrentSourceInfo.mSrcId == srcId) {
- return &mCurrentSourceInfo;
- } else if (mNextSourceInfo.mSrcId == srcId) {
- return &mNextSourceInfo;
- } else {
- return NULL;
- }
-}
-
-void NuPlayer2::resetSourceInfo(NuPlayer2::SourceInfo &srcInfo) {
- if (srcInfo.mSource != NULL) {
- srcInfo.mSource->stop();
-
- Mutex::Autolock autoLock(mSourceLock);
- srcInfo.mSource.clear();
- }
- // Modular DRM
- ALOGD("performReset mCrypto: %p", srcInfo.mCrypto.get());
- srcInfo.mCrypto.clear();
- srcInfo.mIsDrmProtected = false;
-}
-
-// Modular DRM begin
-status_t NuPlayer2::prepareDrm(
- int64_t srcId, const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId)
-{
- ALOGV("prepareDrm ");
-
- // Passing to the looper anyway; called in a pre-config prepared state so no race on mCrypto
- sp<AMessage> msg = new AMessage(kWhatPrepareDrm, this);
- // synchronous call so just passing the address but with local copies of "const" args
- uint8_t UUID[16];
- memcpy(UUID, uuid, sizeof(UUID));
- Vector<uint8_t> sessionId = drmSessionId;
- msg->setInt64("srcId", srcId);
- msg->setPointer("uuid", (void*)UUID);
- msg->setPointer("drmSessionId", (void*)&sessionId);
-
- sp<AMessage> response;
- status_t status = msg->postAndAwaitResponse(&response);
-
- if (status == OK && response != NULL) {
- CHECK(response->findInt32("status", &status));
- ALOGV("prepareDrm ret: %d ", status);
- } else {
- ALOGE("prepareDrm err: %d", status);
- }
-
- return status;
-}
-
-status_t NuPlayer2::releaseDrm(int64_t srcId)
-{
- ALOGV("releaseDrm ");
-
- sp<AMessage> msg = new AMessage(kWhatReleaseDrm, this);
- msg->setInt64("srcId", srcId);
-
- sp<AMessage> response;
- status_t status = msg->postAndAwaitResponse(&response);
-
- if (status == OK && response != NULL) {
- CHECK(response->findInt32("status", &status));
- ALOGV("releaseDrm ret: %d ", status);
- } else {
- ALOGE("releaseDrm err: %d", status);
- }
-
- return status;
-}
-
-status_t NuPlayer2::onPrepareDrm(const sp<AMessage> &msg)
-{
- // TODO change to ALOGV
- ALOGD("onPrepareDrm ");
-
- status_t status = INVALID_OPERATION;
- SourceInfo *srcInfo = getSourceInfoByIdInMsg(msg);
- if (srcInfo == NULL) {
- return status;
- }
-
- int64_t srcId = srcInfo->mSrcId;
- if (srcInfo->mSource == NULL) {
- ALOGE("onPrepareDrm: srcInfo(%lld) No source. onPrepareDrm failed with %d.",
- (long long)srcId, status);
- return status;
- }
-
- uint8_t *uuid;
- Vector<uint8_t> *drmSessionId;
- CHECK(msg->findPointer("uuid", (void**)&uuid));
- CHECK(msg->findPointer("drmSessionId", (void**)&drmSessionId));
-
- status = OK;
- sp<AMediaCryptoWrapper> crypto = NULL;
-
- status = srcInfo->mSource->prepareDrm(uuid, *drmSessionId, &crypto);
- if (crypto == NULL) {
- ALOGE("onPrepareDrm: srcInfo(%lld).mSource->prepareDrm failed. status: %d",
- (long long)srcId, status);
- return status;
- }
- ALOGV("onPrepareDrm: srcInfo(%lld).mSource->prepareDrm succeeded", (long long)srcId);
-
- if (srcInfo->mCrypto != NULL) {
- ALOGE("onPrepareDrm: srcInfo(%lld) Unexpected. Already having mCrypto: %p",
- (long long)srcId, srcInfo->mCrypto.get());
- srcInfo->mCrypto.clear();
- }
-
- srcInfo->mCrypto = crypto;
- srcInfo->mIsDrmProtected = true;
- // TODO change to ALOGV
- ALOGD("onPrepareDrm: mCrypto: %p", srcInfo->mCrypto.get());
-
- return status;
-}
-
-status_t NuPlayer2::onReleaseDrm(const sp<AMessage> &msg)
-{
- // TODO change to ALOGV
- ALOGD("onReleaseDrm ");
- SourceInfo *srcInfo = getSourceInfoByIdInMsg(msg);;
- if (srcInfo == NULL) {
- return INVALID_OPERATION;
- }
-
- int64_t srcId = srcInfo->mSrcId;
- if (!srcInfo->mIsDrmProtected) {
- ALOGW("onReleaseDrm: srcInfo(%lld) Unexpected. mIsDrmProtected is already false.",
- (long long)srcId);
- }
-
- srcInfo->mIsDrmProtected = false;
-
- status_t status;
- if (srcInfo->mCrypto != NULL) {
- // notifying the source first before removing crypto from codec
- if (srcInfo->mSource != NULL) {
- srcInfo->mSource->releaseDrm();
- }
-
- status=OK;
- // first making sure the codecs have released their crypto reference
- const sp<DecoderBase> &videoDecoder = getDecoder(false/*audio*/);
- if (videoDecoder != NULL) {
- status = videoDecoder->releaseCrypto();
- ALOGV("onReleaseDrm: video decoder ret: %d", status);
- }
-
- const sp<DecoderBase> &audioDecoder = getDecoder(true/*audio*/);
- if (audioDecoder != NULL) {
- status_t status_audio = audioDecoder->releaseCrypto();
- if (status == OK) { // otherwise, returning the first error
- status = status_audio;
- }
- ALOGV("onReleaseDrm: audio decoder ret: %d", status_audio);
- }
-
- // TODO change to ALOGV
- ALOGD("onReleaseDrm: mCrypto: %p", srcInfo->mCrypto.get());
- srcInfo->mCrypto.clear();
- } else { // srcInfo->mCrypto == NULL
- ALOGE("onReleaseDrm: Unexpected. There is no crypto.");
- status = INVALID_OPERATION;
- }
-
- return status;
-}
-// Modular DRM end
-////////////////////////////////////////////////////////////////////////////////
-
-sp<AMessage> NuPlayer2::Source::getFormat(bool audio) {
- sp<MetaData> meta = getFormatMeta(audio);
-
- if (meta == NULL) {
- return NULL;
- }
-
- sp<AMessage> msg = new AMessage;
-
- if(convertMetaDataToMessage(meta, &msg) == OK) {
- return msg;
- }
- return NULL;
-}
-
-void NuPlayer2::Source::notifyFlagsChanged(uint32_t flags) {
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatFlagsChanged);
- notify->setInt32("flags", flags);
- notify->post();
-}
-
-void NuPlayer2::Source::notifyVideoSizeChanged(const sp<AMessage> &format) {
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatVideoSizeChanged);
- notify->setMessage("format", format);
- notify->post();
-}
-
-void NuPlayer2::Source::notifyPrepared(status_t err) {
- ALOGV("Source::notifyPrepared %d", err);
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatPrepared);
- notify->setInt32("err", err);
- notify->post();
-}
-
-void NuPlayer2::Source::notifyDrmInfo(const sp<ABuffer> &drmInfoBuffer)
-{
- ALOGV("Source::notifyDrmInfo");
-
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatDrmInfo);
- notify->setBuffer("drmInfo", drmInfoBuffer);
-
- notify->post();
-}
-
-void NuPlayer2::Source::onMessageReceived(const sp<AMessage> & /* msg */) {
- TRESPASS();
-}
-
-NuPlayer2::SourceInfo::SourceInfo()
- : mDataSourceType(DATA_SOURCE_TYPE_NONE),
- mSrcId(0),
- mSourceFlags(0),
- mStartTimeUs(0),
- mEndTimeUs(DataSourceDesc::kMaxTimeUs) {
-}
-
-NuPlayer2::SourceInfo & NuPlayer2::SourceInfo::operator=(const NuPlayer2::SourceInfo &other) {
- mSource = other.mSource;
- mCrypto = other.mCrypto;
- mDataSourceType = (DATA_SOURCE_TYPE)other.mDataSourceType;
- mSrcId = other.mSrcId;
- mSourceFlags = other.mSourceFlags;
- mStartTimeUs = other.mStartTimeUs;
- mEndTimeUs = other.mEndTimeUs;
- mIsDrmProtected = other.mIsDrmProtected;
- return *this;
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.h b/media/libmediaplayer2/nuplayer2/NuPlayer2.h
deleted file mode 100644
index b8fb988..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.h
+++ /dev/null
@@ -1,369 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NU_PLAYER2_H_
-
-#define NU_PLAYER2_H_
-
-#include <media/AudioResamplerPublic.h>
-#include <media/stagefright/foundation/AHandler.h>
-
-#include <mediaplayer2/MediaPlayer2Interface.h>
-#include <mediaplayer2/JObjectHolder.h>
-
-#include "mediaplayer2.pb.h"
-
-using android::media::MediaPlayer2Proto::PlayerMessage;
-
-namespace android {
-
-struct ABuffer;
-struct AMediaCryptoWrapper;
-struct AMessage;
-struct ANativeWindowWrapper;
-struct AudioPlaybackRate;
-struct AVSyncSettings;
-struct DataSourceDesc;
-struct MediaClock;
-struct MediaHTTPService;
-class MetaData;
-struct NuPlayer2Driver;
-
-struct NuPlayer2 : public AHandler {
- explicit NuPlayer2(pid_t pid, uid_t uid,
- const sp<MediaClock> &mediaClock, const sp<JObjectHolder> &context);
-
- void setDriver(const wp<NuPlayer2Driver> &driver);
-
- void setDataSourceAsync(const sp<DataSourceDesc> &dsd);
- void prepareNextDataSourceAsync(const sp<DataSourceDesc> &dsd);
- void playNextDataSource(int64_t srcId);
-
- status_t getBufferingSettings(BufferingSettings* buffering /* nonnull */);
- status_t setBufferingSettings(const BufferingSettings& buffering);
-
- void prepareAsync();
-
- void setVideoSurfaceTextureAsync(const sp<ANativeWindowWrapper> &nww);
-
- void setAudioSink(const sp<MediaPlayer2Interface::AudioSink> &sink);
- status_t setPlaybackSettings(const AudioPlaybackRate &rate);
- status_t getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */);
- status_t setSyncSettings(const AVSyncSettings &sync, float videoFpsHint);
- status_t getSyncSettings(AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */);
-
- void start();
-
- void pause();
-
- // Will notify the driver through "notifyResetComplete" once finished.
- void resetAsync();
-
- // Request a notification when specified media time is reached.
- status_t notifyAt(int64_t mediaTimeUs);
-
- // Will notify the driver through "notifySeekComplete" once finished
- // and needNotify is true.
- void seekToAsync(
- int64_t seekTimeUs,
- MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC,
- bool needNotify = false);
- void rewind();
-
- status_t setVideoScalingMode(int32_t mode);
- status_t getTrackInfo(int64_t srcId, PlayerMessage* reply) const;
- status_t getSelectedTrack(int64_t srcId, int32_t type, PlayerMessage* reply) const;
- status_t selectTrack(int64_t srcId, size_t trackIndex, bool select, int64_t timeUs);
- status_t getCurrentPosition(int64_t *mediaUs);
- void getStats(Vector<sp<AMessage> > *mTrackStats);
-
- sp<MetaData> getFileMeta();
- float getFrameRate();
-
- // Modular DRM
- status_t prepareDrm(int64_t srcId, const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId);
- status_t releaseDrm(int64_t srcId);
-
- const char *getDataSourceType();
-
-protected:
- virtual ~NuPlayer2();
-
- virtual void onMessageReceived(const sp<AMessage> &msg);
-
-public:
- struct StreamListener;
- struct Source;
-
-private:
- struct Decoder;
- struct DecoderBase;
- struct DecoderPassThrough;
- struct CCDecoder;
- struct GenericSource2;
- struct HTTPLiveSource2;
- struct Renderer;
- struct RTSPSource2;
- struct Action;
- struct SeekAction;
- struct SetSurfaceAction;
- struct ResumeDecoderAction;
- struct FlushDecoderAction;
- struct PostMessageAction;
- struct SimpleAction;
-
- enum {
- kWhatSetDataSource = '=DaS',
- kWhatPrepare = 'prep',
- kWhatPrepareNextDataSource = 'pNDS',
- kWhatPlayNextDataSource = 'plNS',
- kWhatSetVideoSurface = '=VSu',
- kWhatSetAudioSink = '=AuS',
- kWhatMoreDataQueued = 'more',
- kWhatConfigPlayback = 'cfPB',
- kWhatConfigSync = 'cfSy',
- kWhatGetPlaybackSettings = 'gPbS',
- kWhatGetSyncSettings = 'gSyS',
- kWhatStart = 'strt',
- kWhatScanSources = 'scan',
- kWhatVideoNotify = 'vidN',
- kWhatAudioNotify = 'audN',
- kWhatClosedCaptionNotify = 'capN',
- kWhatRendererNotify = 'renN',
- kWhatReset = 'rset',
- kWhatNotifyTime = 'nfyT',
- kWhatSeek = 'seek',
- kWhatPause = 'paus',
- kWhatResume = 'rsme',
- kWhatPollDuration = 'polD',
- kWhatSourceNotify = 'srcN',
- kWhatGetTrackInfo = 'gTrI',
- kWhatGetSelectedTrack = 'gSel',
- kWhatSelectTrack = 'selT',
- kWhatGetBufferingSettings = 'gBus',
- kWhatSetBufferingSettings = 'sBuS',
- kWhatPrepareDrm = 'pDrm',
- kWhatReleaseDrm = 'rDrm',
- kWhatRewind = 'reWd',
- kWhatEOSMonitor = 'eosM',
- };
-
- typedef enum {
- DATA_SOURCE_TYPE_NONE,
- DATA_SOURCE_TYPE_HTTP_LIVE,
- DATA_SOURCE_TYPE_RTSP,
- DATA_SOURCE_TYPE_GENERIC_URL,
- DATA_SOURCE_TYPE_GENERIC_FD,
- DATA_SOURCE_TYPE_MEDIA,
- } DATA_SOURCE_TYPE;
-
- struct SourceInfo {
- SourceInfo();
- SourceInfo &operator=(const SourceInfo &);
-
- sp<Source> mSource;
- std::atomic<DATA_SOURCE_TYPE> mDataSourceType;
- int64_t mSrcId;
- uint32_t mSourceFlags;
- int64_t mStartTimeUs;
- int64_t mEndTimeUs;
- // Modular DRM
- sp<AMediaCryptoWrapper> mCrypto;
- bool mIsDrmProtected = false;
- };
-
- wp<NuPlayer2Driver> mDriver;
- pid_t mPID;
- uid_t mUID;
- const sp<MediaClock> mMediaClock;
- Mutex mSourceLock; // guard |mSource|.
- SourceInfo mCurrentSourceInfo;
- SourceInfo mNextSourceInfo;
- sp<ANativeWindowWrapper> mNativeWindow;
- sp<MediaPlayer2Interface::AudioSink> mAudioSink;
- sp<DecoderBase> mVideoDecoder;
- bool mOffloadAudio;
- sp<DecoderBase> mAudioDecoder;
- Mutex mDecoderLock; // guard |mAudioDecoder| and |mVideoDecoder|.
- sp<CCDecoder> mCCDecoder;
- sp<Renderer> mRenderer;
- sp<ALooper> mRendererLooper;
- int32_t mAudioDecoderGeneration;
- int32_t mVideoDecoderGeneration;
- int32_t mRendererGeneration;
- int32_t mEOSMonitorGeneration;
-
- Mutex mPlayingTimeLock;
- int64_t mLastStartedPlayingTimeNs;
- void stopPlaybackTimer(const char *where);
- void startPlaybackTimer(const char *where);
-
- int64_t mLastStartedRebufferingTimeNs;
- void startRebufferingTimer();
- void stopRebufferingTimer(bool exitingPlayback);
-
- int64_t mPreviousSeekTimeUs;
-
- List<sp<Action> > mDeferredActions;
-
- bool mAudioEOS;
- bool mVideoEOS;
-
- bool mScanSourcesPending;
- int32_t mScanSourcesGeneration;
-
- int32_t mPollDurationGeneration;
- int32_t mTimedTextGeneration;
-
- enum FlushStatus {
- NONE,
- FLUSHING_DECODER,
- FLUSHING_DECODER_SHUTDOWN,
- SHUTTING_DOWN_DECODER,
- FLUSHED,
- SHUT_DOWN,
- };
-
- enum FlushCommand {
- FLUSH_CMD_NONE,
- FLUSH_CMD_FLUSH,
- FLUSH_CMD_SHUTDOWN,
- };
-
- // Status of flush responses from the decoder and renderer.
- bool mFlushComplete[2][2];
-
- FlushStatus mFlushingAudio;
- FlushStatus mFlushingVideo;
-
- // Status of flush responses from the decoder and renderer.
- bool mResumePending;
-
- int32_t mVideoScalingMode;
-
- AudioPlaybackRate mPlaybackSettings;
- AVSyncSettings mSyncSettings;
- float mVideoFpsHint;
- bool mStarted;
- bool mPrepared;
- bool mResetting;
- bool mSourceStarted;
- bool mAudioDecoderError;
- bool mVideoDecoderError;
-
- // Actual pause state, either as requested by client or due to buffering.
- bool mPaused;
-
- // Pause state as requested by client. Note that if mPausedByClient is
- // true, mPaused is always true; if mPausedByClient is false, mPaused could
- // still become true, when we pause internally due to buffering.
- bool mPausedByClient;
-
- // Pause state as requested by source (internally) due to buffering
- bool mPausedForBuffering;
-
- // Passed from JAVA
- const sp<JObjectHolder> mContext;
-
- inline const sp<DecoderBase> &getDecoder(bool audio) {
- return audio ? mAudioDecoder : mVideoDecoder;
- }
-
- inline void clearFlushComplete() {
- mFlushComplete[0][0] = false;
- mFlushComplete[0][1] = false;
- mFlushComplete[1][0] = false;
- mFlushComplete[1][1] = false;
- }
-
- void disconnectSource();
-
- 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();
- void restartAudio(
- int64_t currentPositionUs, bool forceNonOffload, bool needsToCreateAudioDecoder);
- void determineAudioModeChange(const sp<AMessage> &audioFormat);
-
- status_t instantiateDecoder(
- bool audio, sp<DecoderBase> *decoder, bool checkAudioModeChange = true);
-
- void updateVideoSize(
- int64_t srcId,
- const sp<AMessage> &inputFormat,
- const sp<AMessage> &outputFormat = NULL);
-
- void notifyListener(int64_t srcId, int msg, int ext1, int ext2, const PlayerMessage *in = NULL);
-
- void addEndTimeMonitor();
-
- void handleFlushComplete(bool audio, bool isDecoder);
- void finishFlushIfPossible();
-
- void onStart(bool play);
- void onResume();
- void onPause();
-
- bool audioDecoderStillNeeded();
-
- void flushDecoder(bool audio, bool needShutdown);
-
- void finishResume();
- void notifyDriverSeekComplete(int64_t srcId);
-
- void postScanSources();
-
- void schedulePollDuration();
- void cancelPollDuration();
-
- void processDeferredActions();
-
- void performSeek(int64_t seekTimeUs, MediaPlayer2SeekMode mode);
- void performDecoderFlush(FlushCommand audio, FlushCommand video);
- void performReset();
- void performPlayNextDataSource();
- void performScanSources();
- void performSetSurface(const sp<ANativeWindowWrapper> &nw);
- void performResumeDecoders(bool needNotify);
-
- void onSourceNotify(const sp<AMessage> &msg);
- void onClosedCaptionNotify(const sp<AMessage> &msg);
-
- void queueDecoderShutdown(
- bool audio, bool video, const sp<AMessage> &reply);
-
- void sendSubtitleData(const sp<ABuffer> &buffer, int32_t baseIndex);
- void sendTimedMetaData(const sp<ABuffer> &buffer);
- void sendTimedTextData(const sp<ABuffer> &buffer);
-
- void writeTrackInfo(PlayerMessage* reply, const sp<AMessage>& format) const;
-
- status_t onPrepareDrm(const sp<AMessage> &msg);
- status_t onReleaseDrm(const sp<AMessage> &msg);
-
- SourceInfo* getSourceInfoByIdInMsg(const sp<AMessage> &msg);
- void resetSourceInfo(SourceInfo &srcInfo);
-
- DISALLOW_EVIL_CONSTRUCTORS(NuPlayer2);
-};
-
-} // namespace android
-
-#endif // NU_PLAYER2_H_
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.cpp
deleted file mode 100644
index 98c3403..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.cpp
+++ /dev/null
@@ -1,606 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NuPlayer2CCDecoder"
-#include <utils/Log.h>
-#include <inttypes.h>
-
-#include "NuPlayer2CCDecoder.h"
-
-#include <media/NdkMediaFormat.h>
-#include <media/stagefright/foundation/ABitReader.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/foundation/avc_utils.h>
-#include <media/stagefright/MediaDefs.h>
-
-namespace android {
-
-// In CEA-708B, the maximum bandwidth of CC is set to 9600bps.
-static const size_t kMaxBandwithSizeBytes = 9600 / 8;
-
-struct CCData {
- CCData(uint8_t type, uint8_t data1, uint8_t data2)
- : mType(type), mData1(data1), mData2(data2) {
- }
- bool getChannel(size_t *channel) const {
- if (mData1 >= 0x10 && mData1 <= 0x1f) {
- *channel = (mData1 >= 0x18 ? 1 : 0) + (mType ? 2 : 0);
- return true;
- }
- return false;
- }
-
- uint8_t mType;
- uint8_t mData1;
- uint8_t mData2;
-};
-
-static bool isNullPad(CCData *cc) {
- return cc->mData1 < 0x10 && cc->mData2 < 0x10;
-}
-
-static void dumpBytePair(const sp<ABuffer> &ccBuf) __attribute__ ((unused));
-static void dumpBytePair(const sp<ABuffer> &ccBuf) {
- size_t offset = 0;
- AString out;
-
- while (offset < ccBuf->size()) {
- char tmp[128];
-
- CCData *cc = (CCData *) (ccBuf->data() + offset);
-
- if (isNullPad(cc)) {
- // 1 null pad or XDS metadata, ignore
- offset += sizeof(CCData);
- continue;
- }
-
- if (cc->mData1 >= 0x20 && cc->mData1 <= 0x7f) {
- // 2 basic chars
- snprintf(tmp, sizeof(tmp), "[%d]Basic: %c %c", cc->mType, cc->mData1, cc->mData2);
- } else if ((cc->mData1 == 0x11 || cc->mData1 == 0x19)
- && cc->mData2 >= 0x30 && cc->mData2 <= 0x3f) {
- // 1 special char
- snprintf(tmp, sizeof(tmp), "[%d]Special: %02x %02x", cc->mType, cc->mData1, cc->mData2);
- } else if ((cc->mData1 == 0x12 || cc->mData1 == 0x1A)
- && cc->mData2 >= 0x20 && cc->mData2 <= 0x3f){
- // 1 Spanish/French char
- snprintf(tmp, sizeof(tmp), "[%d]Spanish: %02x %02x", cc->mType, cc->mData1, cc->mData2);
- } else if ((cc->mData1 == 0x13 || cc->mData1 == 0x1B)
- && cc->mData2 >= 0x20 && cc->mData2 <= 0x3f){
- // 1 Portuguese/German/Danish char
- snprintf(tmp, sizeof(tmp), "[%d]German: %02x %02x", cc->mType, cc->mData1, cc->mData2);
- } else if ((cc->mData1 == 0x11 || cc->mData1 == 0x19)
- && cc->mData2 >= 0x20 && cc->mData2 <= 0x2f){
- // Mid-Row Codes (Table 69)
- snprintf(tmp, sizeof(tmp), "[%d]Mid-row: %02x %02x", cc->mType, cc->mData1, cc->mData2);
- } else if (((cc->mData1 == 0x14 || cc->mData1 == 0x1c)
- && cc->mData2 >= 0x20 && cc->mData2 <= 0x2f)
- ||
- ((cc->mData1 == 0x17 || cc->mData1 == 0x1f)
- && cc->mData2 >= 0x21 && cc->mData2 <= 0x23)){
- // Misc Control Codes (Table 70)
- snprintf(tmp, sizeof(tmp), "[%d]Ctrl: %02x %02x", cc->mType, cc->mData1, cc->mData2);
- } else if ((cc->mData1 & 0x70) == 0x10
- && (cc->mData2 & 0x40) == 0x40
- && ((cc->mData1 & 0x07) || !(cc->mData2 & 0x20)) ) {
- // Preamble Address Codes (Table 71)
- snprintf(tmp, sizeof(tmp), "[%d]PAC: %02x %02x", cc->mType, cc->mData1, cc->mData2);
- } else {
- snprintf(tmp, sizeof(tmp), "[%d]Invalid: %02x %02x", cc->mType, cc->mData1, cc->mData2);
- }
-
- if (out.size() > 0) {
- out.append(", ");
- }
-
- out.append(tmp);
-
- offset += sizeof(CCData);
- }
-
- ALOGI("%s", out.c_str());
-}
-
-NuPlayer2::CCDecoder::CCDecoder(const sp<AMessage> ¬ify)
- : mNotify(notify),
- mSelectedTrack(-1),
- mDTVCCPacket(new ABuffer(kMaxBandwithSizeBytes)) {
- mDTVCCPacket->setRange(0, 0);
-
- // In CEA-608, streams from packets which have the value 0 of cc_type contain CC1 and CC2, and
- // streams from packets which have the value 1 of cc_type contain CC3 and CC4.
- // The following array indicates the current transmitting channels for each value of cc_type.
- mLine21Channels[0] = 0; // CC1
- mLine21Channels[1] = 2; // CC3
-}
-
-size_t NuPlayer2::CCDecoder::getTrackCount() const {
- return mTracks.size();
-}
-
-sp<AMessage> NuPlayer2::CCDecoder::getTrackInfo(size_t index) const {
- if (!isTrackValid(index)) {
- return NULL;
- }
-
- sp<AMessage> format = new AMessage();
-
- CCTrack track = mTracks[index];
-
- format->setInt32("type", MEDIA_TRACK_TYPE_SUBTITLE);
- format->setString("language", "und");
-
- switch (track.mTrackType) {
- case kTrackTypeCEA608:
- format->setString("mime", MEDIA_MIMETYPE_TEXT_CEA_608);
- break;
- case kTrackTypeCEA708:
- format->setString("mime", MEDIA_MIMETYPE_TEXT_CEA_708);
- break;
- default:
- ALOGE("Unknown track type: %d", track.mTrackType);
- return NULL;
- }
-
- // For CEA-608 CC1, field 0 channel 0
- bool isDefaultAuto = track.mTrackType == kTrackTypeCEA608
- && track.mTrackChannel == 0;
- // For CEA-708, Primary Caption Service.
- bool isDefaultOnly = track.mTrackType == kTrackTypeCEA708
- && track.mTrackChannel == 1;
- format->setInt32("auto", isDefaultAuto);
- format->setInt32("default", isDefaultAuto || isDefaultOnly);
- format->setInt32("forced", 0);
-
- return format;
-}
-
-status_t NuPlayer2::CCDecoder::selectTrack(size_t index, bool select) {
- if (!isTrackValid(index)) {
- return BAD_VALUE;
- }
-
- if (select) {
- if (mSelectedTrack == (ssize_t)index) {
- ALOGE("track %zu already selected", index);
- return BAD_VALUE;
- }
- ALOGV("selected track %zu", index);
- mSelectedTrack = index;
- } else {
- if (mSelectedTrack != (ssize_t)index) {
- ALOGE("track %zu is not selected", index);
- return BAD_VALUE;
- }
- ALOGV("unselected track %zu", index);
- mSelectedTrack = -1;
- }
-
- // Clear the previous track payloads
- mCCMap.clear();
-
- return OK;
-}
-
-ssize_t NuPlayer2::CCDecoder::getSelectedTrack(media_track_type type) const {
- if (mSelectedTrack != -1) {
- CCTrack track = mTracks[mSelectedTrack];
- if (track.mTrackType == kTrackTypeCEA608 || track.mTrackType == kTrackTypeCEA708) {
- return (type == MEDIA_TRACK_TYPE_SUBTITLE ? mSelectedTrack : -1);
- }
- return (type == MEDIA_TRACK_TYPE_UNKNOWN ? mSelectedTrack : -1);
- }
-
- return -1;
-}
-
-bool NuPlayer2::CCDecoder::isSelected() const {
- return mSelectedTrack >= 0 && mSelectedTrack < (int32_t)getTrackCount();
-}
-
-bool NuPlayer2::CCDecoder::isTrackValid(size_t index) const {
- return index < getTrackCount();
-}
-
-// returns true if a new CC track is found
-bool NuPlayer2::CCDecoder::extractFromSEI(const sp<ABuffer> &accessUnit) {
- sp<ABuffer> sei;
- if (!accessUnit->meta()->findBuffer("sei", &sei) || sei == NULL) {
- return false;
- }
-
- int64_t timeUs;
- CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
-
- bool trackAdded = false;
-
- const NALPosition *nal = (NALPosition *)sei->data();
-
- for (size_t i = 0; i < sei->size() / sizeof(NALPosition); ++i, ++nal) {
- trackAdded |= parseSEINalUnit(
- timeUs, accessUnit->data() + nal->nalOffset, nal->nalSize);
- }
-
- return trackAdded;
-}
-
-// returns true if a new CC track is found
-bool NuPlayer2::CCDecoder::parseSEINalUnit(int64_t timeUs, const uint8_t *data, size_t size) {
- unsigned nalType = data[0] & 0x1f;
-
- // the buffer should only have SEI in it
- if (nalType != 6) {
- return false;
- }
-
- bool trackAdded = false;
- NALBitReader br(data + 1, size - 1);
-
- // sei_message()
- while (br.atLeastNumBitsLeft(16)) { // at least 16-bit for sei_message()
- uint32_t payload_type = 0;
- size_t payload_size = 0;
- uint8_t last_byte;
-
- do {
- last_byte = br.getBits(8);
- payload_type += last_byte;
- } while (last_byte == 0xFF);
-
- do {
- last_byte = br.getBits(8);
- payload_size += last_byte;
- } while (last_byte == 0xFF);
-
- if (payload_size > SIZE_MAX / 8
- || !br.atLeastNumBitsLeft(payload_size * 8)) {
- ALOGV("Malformed SEI payload");
- break;
- }
-
- // sei_payload()
- if (payload_type == 4) {
- bool isCC = false;
- if (payload_size > 1 + 2 + 4 + 1) {
- // user_data_registered_itu_t_t35()
-
- // ATSC A/72: 6.4.2
- uint8_t itu_t_t35_country_code = br.getBits(8);
- uint16_t itu_t_t35_provider_code = br.getBits(16);
- uint32_t user_identifier = br.getBits(32);
- uint8_t user_data_type_code = br.getBits(8);
-
- payload_size -= 1 + 2 + 4 + 1;
-
- isCC = itu_t_t35_country_code == 0xB5
- && itu_t_t35_provider_code == 0x0031
- && user_identifier == 'GA94'
- && user_data_type_code == 0x3;
- }
-
- if (isCC && payload_size > 2) {
- trackAdded |= parseMPEGCCData(timeUs, br.data(), br.numBitsLeft() / 8);
- } else {
- ALOGV("Malformed SEI payload type 4");
- }
- } else {
- ALOGV("Unsupported SEI payload type %d", payload_type);
- }
-
- // skipping remaining bits of this payload
- br.skipBits(payload_size * 8);
- }
-
- return trackAdded;
-}
-
-// returns true if a new CC track is found
-bool NuPlayer2::CCDecoder::extractFromMPEGUserData(const sp<ABuffer> &accessUnit) {
- sp<ABuffer> mpegUserData;
- if (!accessUnit->meta()->findBuffer(AMEDIAFORMAT_KEY_MPEG_USER_DATA, &mpegUserData)
- || mpegUserData == NULL) {
- return false;
- }
-
- int64_t timeUs;
- CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
-
- bool trackAdded = false;
-
- const size_t *userData = (size_t *)mpegUserData->data();
-
- for (size_t i = 0; i < mpegUserData->size() / sizeof(size_t); ++i) {
- trackAdded |= parseMPEGUserDataUnit(
- timeUs, accessUnit->data() + userData[i], accessUnit->size() - userData[i]);
- }
-
- return trackAdded;
-}
-
-// returns true if a new CC track is found
-bool NuPlayer2::CCDecoder::parseMPEGUserDataUnit(int64_t timeUs, const uint8_t *data, size_t size) {
- ABitReader br(data + 4, 5);
-
- uint32_t user_identifier = br.getBits(32);
- uint8_t user_data_type = br.getBits(8);
-
- if (user_identifier == 'GA94' && user_data_type == 0x3) {
- return parseMPEGCCData(timeUs, data + 9, size - 9);
- }
-
- return false;
-}
-
-// returns true if a new CC track is found
-bool NuPlayer2::CCDecoder::parseMPEGCCData(int64_t timeUs, const uint8_t *data, size_t size) {
- bool trackAdded = false;
-
- // MPEG_cc_data()
- // ATSC A/53 Part 4: 6.2.3.1
- ABitReader br(data, size);
-
- if (br.numBitsLeft() <= 16) {
- return false;
- }
-
- br.skipBits(1);
- bool process_cc_data_flag = br.getBits(1);
- br.skipBits(1);
- size_t cc_count = br.getBits(5);
- br.skipBits(8);
-
- if (!process_cc_data_flag || 3 * 8 * cc_count >= br.numBitsLeft()) {
- return false;
- }
-
- sp<ABuffer> line21CCBuf = NULL;
-
- for (size_t i = 0; i < cc_count; ++i) {
- br.skipBits(5);
- bool cc_valid = br.getBits(1);
- uint8_t cc_type = br.getBits(2);
-
- if (cc_valid) {
- if (cc_type == 3) {
- if (mDTVCCPacket->size() > 0) {
- trackAdded |= parseDTVCCPacket(
- timeUs, mDTVCCPacket->data(), mDTVCCPacket->size());
- mDTVCCPacket->setRange(0, 0);
- }
- if (mDTVCCPacket->size() + 2 > mDTVCCPacket->capacity()) {
- return false;
- }
- memcpy(mDTVCCPacket->data() + mDTVCCPacket->size(), br.data(), 2);
- mDTVCCPacket->setRange(0, mDTVCCPacket->size() + 2);
- br.skipBits(16);
- } else if (mDTVCCPacket->size() > 0 && cc_type == 2) {
- if (mDTVCCPacket->size() + 2 > mDTVCCPacket->capacity()) {
- return false;
- }
- memcpy(mDTVCCPacket->data() + mDTVCCPacket->size(), br.data(), 2);
- mDTVCCPacket->setRange(0, mDTVCCPacket->size() + 2);
- br.skipBits(16);
- } else if (cc_type == 0 || cc_type == 1) {
- uint8_t cc_data_1 = br.getBits(8) & 0x7f;
- uint8_t cc_data_2 = br.getBits(8) & 0x7f;
-
- CCData cc(cc_type, cc_data_1, cc_data_2);
-
- if (isNullPad(&cc)) {
- continue;
- }
-
- size_t channel;
- if (cc.getChannel(&channel)) {
- mLine21Channels[cc_type] = channel;
-
- // create a new track if it does not exist.
- getTrackIndex(kTrackTypeCEA608, channel, &trackAdded);
- }
-
- if (isSelected() && mTracks[mSelectedTrack].mTrackType == kTrackTypeCEA608
- && mTracks[mSelectedTrack].mTrackChannel == mLine21Channels[cc_type]) {
- if (line21CCBuf == NULL) {
- line21CCBuf = new ABuffer((cc_count - i) * sizeof(CCData));
- line21CCBuf->setRange(0, 0);
- }
- if (line21CCBuf->size() + sizeof(cc) > line21CCBuf->capacity()) {
- return false;
- }
- memcpy(line21CCBuf->data() + line21CCBuf->size(), &cc, sizeof(cc));
- line21CCBuf->setRange(0, line21CCBuf->size() + sizeof(CCData));
- }
- } else {
- br.skipBits(16);
- }
- } else {
- if ((cc_type == 3 || cc_type == 2) && mDTVCCPacket->size() > 0) {
- trackAdded |= parseDTVCCPacket(timeUs, mDTVCCPacket->data(), mDTVCCPacket->size());
- mDTVCCPacket->setRange(0, 0);
- }
- br.skipBits(16);
- }
- }
-
- if (isSelected() && mTracks[mSelectedTrack].mTrackType == kTrackTypeCEA608
- && line21CCBuf != NULL && line21CCBuf->size() > 0) {
- mCCMap.add(timeUs, line21CCBuf);
- }
-
- return trackAdded;
-}
-
-// returns true if a new CC track is found
-bool NuPlayer2::CCDecoder::parseDTVCCPacket(int64_t timeUs, const uint8_t *data, size_t size) {
- // CEA-708B 5 DTVCC Packet Layer.
- ABitReader br(data, size);
- br.skipBits(2);
-
- size_t packet_size = br.getBits(6);
- if (packet_size == 0) packet_size = 64;
- packet_size *= 2;
-
- if (size != packet_size) {
- return false;
- }
-
- bool trackAdded = false;
-
- while (br.numBitsLeft() >= 16) {
- // CEA-708B Figure 5 and 6.
- uint8_t service_number = br.getBits(3);
- size_t block_size = br.getBits(5);
-
- if (service_number == 64) {
- br.skipBits(2);
- service_number = br.getBits(6);
-
- if (service_number < 64) {
- return trackAdded;
- }
- }
-
- if (br.numBitsLeft() < block_size * 8) {
- return trackAdded;
- }
-
- if (block_size > 0) {
- size_t trackIndex = getTrackIndex(kTrackTypeCEA708, service_number, &trackAdded);
- if (mSelectedTrack == (ssize_t)trackIndex) {
- sp<ABuffer> ccPacket = new ABuffer(block_size);
- if (ccPacket->capacity() == 0) {
- return false;
- }
- memcpy(ccPacket->data(), br.data(), block_size);
- mCCMap.add(timeUs, ccPacket);
- }
- }
- br.skipBits(block_size * 8);
- }
-
- return trackAdded;
-}
-
-// return the track index for a given type and channel.
-// if the track does not exist, creates a new one.
-size_t NuPlayer2::CCDecoder::getTrackIndex(
- int32_t trackType, size_t channel, bool *trackAdded) {
- CCTrack track(trackType, channel);
- ssize_t index = mTrackIndices.indexOfKey(track);
-
- if (index < 0) {
- // A new track is added.
- index = mTracks.size();
- mTrackIndices.add(track, index);
- mTracks.add(track);
- *trackAdded = true;
- return index;
- }
-
- return mTrackIndices.valueAt(index);
-}
-
-void NuPlayer2::CCDecoder::decode(const sp<ABuffer> &accessUnit) {
- if (extractFromMPEGUserData(accessUnit) || extractFromSEI(accessUnit)) {
- sp<AMessage> msg = mNotify->dup();
- msg->setInt32("what", kWhatTrackAdded);
- msg->post();
- }
- // TODO: extract CC from other sources
-}
-
-void NuPlayer2::CCDecoder::display(int64_t timeUs) {
- if (!isSelected()) {
- return;
- }
-
- ssize_t index = mCCMap.indexOfKey(timeUs);
- if (index < 0) {
- ALOGV("cc for timestamp %" PRId64 " not found", timeUs);
- return;
- }
-
- sp<ABuffer> ccBuf;
-
- if (index == 0) {
- ccBuf = mCCMap.valueAt(index);
- } else {
- size_t size = 0;
-
- for (ssize_t i = 0; i <= index; ++i) {
- size += mCCMap.valueAt(i)->size();
- }
-
- ccBuf = new ABuffer(size);
- ccBuf->setRange(0, 0);
-
- if (ccBuf->capacity() > 0) {
- for (ssize_t i = 0; i <= index; ++i) {
- sp<ABuffer> buf = mCCMap.valueAt(i);
- memcpy(ccBuf->data() + ccBuf->size(), buf->data(), buf->size());
- ccBuf->setRange(0, ccBuf->size() + buf->size());
- }
- }
- }
-
- if (ccBuf->size() > 0) {
-#if 0
- dumpBytePair(ccBuf);
-#endif
-
- ccBuf->meta()->setInt32(AMEDIAFORMAT_KEY_TRACK_INDEX, mSelectedTrack);
- ccBuf->meta()->setInt64("timeUs", timeUs);
- ccBuf->meta()->setInt64("durationUs", 0LL);
-
- sp<AMessage> msg = mNotify->dup();
- msg->setInt32("what", kWhatClosedCaptionData);
- msg->setBuffer("buffer", ccBuf);
- msg->post();
- }
-
- // remove all entries before timeUs
- mCCMap.removeItemsAt(0, index + 1);
-}
-
-void NuPlayer2::CCDecoder::flush() {
- mCCMap.clear();
- mDTVCCPacket->setRange(0, 0);
-}
-
-int32_t NuPlayer2::CCDecoder::CCTrack::compare(const NuPlayer2::CCDecoder::CCTrack& rhs) const {
- int32_t cmp = mTrackType - rhs.mTrackType;
- if (cmp != 0) return cmp;
- return mTrackChannel - rhs.mTrackChannel;
-}
-
-bool NuPlayer2::CCDecoder::CCTrack::operator<(const NuPlayer2::CCDecoder::CCTrack& rhs) const {
- return compare(rhs) < 0;
-}
-
-bool NuPlayer2::CCDecoder::CCTrack::operator==(const NuPlayer2::CCDecoder::CCTrack& rhs) const {
- return compare(rhs) == 0;
-}
-
-bool NuPlayer2::CCDecoder::CCTrack::operator!=(const NuPlayer2::CCDecoder::CCTrack& rhs) const {
- return compare(rhs) != 0;
-}
-
-} // namespace android
-
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.h b/media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.h
deleted file mode 100644
index 97834d1..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NUPLAYER2_CCDECODER_H_
-
-#define NUPLAYER2_CCDECODER_H_
-
-#include "NuPlayer2.h"
-
-namespace android {
-
-struct NuPlayer2::CCDecoder : public RefBase {
- enum {
- kWhatClosedCaptionData,
- kWhatTrackAdded,
- };
-
- enum {
- kTrackTypeCEA608,
- kTrackTypeCEA708,
- };
-
- explicit CCDecoder(const sp<AMessage> ¬ify);
-
- size_t getTrackCount() const;
- sp<AMessage> getTrackInfo(size_t index) const;
- status_t selectTrack(size_t index, bool select);
- ssize_t getSelectedTrack(media_track_type type) const;
- bool isSelected() const;
- void decode(const sp<ABuffer> &accessUnit);
- void display(int64_t timeUs);
- void flush();
-
-private:
- // CC track identifier.
- struct CCTrack {
- CCTrack() : mTrackType(0), mTrackChannel(0) { }
-
- CCTrack(const int32_t trackType, const size_t trackChannel)
- : mTrackType(trackType), mTrackChannel(trackChannel) { }
-
- int32_t mTrackType;
- size_t mTrackChannel;
-
- // The ordering of CCTracks is to build a map of track to index.
- // It is necessary to find the index of the matched CCTrack when CC data comes.
- int compare(const NuPlayer2::CCDecoder::CCTrack& rhs) const;
- inline bool operator<(const NuPlayer2::CCDecoder::CCTrack& rhs) const;
- inline bool operator==(const NuPlayer2::CCDecoder::CCTrack& rhs) const;
- inline bool operator!=(const NuPlayer2::CCDecoder::CCTrack& rhs) const;
- };
-
- sp<AMessage> mNotify;
- KeyedVector<int64_t, sp<ABuffer> > mCCMap;
- ssize_t mSelectedTrack;
- KeyedVector<CCTrack, size_t> mTrackIndices;
- Vector<CCTrack> mTracks;
-
- // CEA-608 closed caption
- size_t mLine21Channels[2]; // The current channels of NTSC_CC_FIELD_{1, 2}
-
- // CEA-708 closed caption
- sp<ABuffer> mDTVCCPacket;
-
- bool isTrackValid(size_t index) const;
- size_t getTrackIndex(int32_t trackType, size_t channel, bool *trackAdded);
-
- // Extract from H.264 SEIs
- bool extractFromSEI(const sp<ABuffer> &accessUnit);
- bool parseSEINalUnit(int64_t timeUs, const uint8_t *data, size_t size);
-
- // Extract from MPEG user data
- bool extractFromMPEGUserData(const sp<ABuffer> &accessUnit);
- bool parseMPEGUserDataUnit(int64_t timeUs, const uint8_t *data, size_t size);
-
- // Extract CC tracks from MPEG_cc_data
- bool parseMPEGCCData(int64_t timeUs, const uint8_t *data, size_t size);
- bool parseDTVCCPacket(int64_t timeUs, const uint8_t *data, size_t size);
-
- DISALLOW_EVIL_CONSTRUCTORS(CCDecoder);
-};
-
-} // namespace android
-
-#endif // NUPLAYER2_CCDECODER_H_
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp
deleted file mode 100644
index 66bfae5..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp
+++ /dev/null
@@ -1,1315 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NuPlayer2Decoder"
-#include <utils/Log.h>
-#include <inttypes.h>
-
-#include <algorithm>
-
-#include "NuPlayer2CCDecoder.h"
-#include "NuPlayer2Decoder.h"
-#include "NuPlayer2Drm.h"
-#include "NuPlayer2Renderer.h"
-#include "NuPlayer2Source.h"
-
-#include <cutils/properties.h>
-#include <media/MediaBufferHolder.h>
-#include <media/MediaCodecBuffer.h>
-#include <media/NdkMediaCodec.h>
-#include <media/NdkWrapper.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/foundation/avc_utils.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/SurfaceUtils.h>
-
-#include <system/window.h>
-#include "ATSParser.h"
-
-namespace android {
-
-static float kDisplayRefreshingRate = 60.f; // TODO: get this from the display
-
-// The default total video frame rate of a stream when that info is not available from
-// the source.
-static float kDefaultVideoFrameRateTotal = 30.f;
-
-static inline bool getAudioDeepBufferSetting() {
- return property_get_bool("media.stagefright.audio.deep", false /* default_value */);
-}
-
-NuPlayer2::Decoder::Decoder(
- const sp<AMessage> ¬ify,
- const sp<Source> &source,
- pid_t pid,
- uid_t uid,
- const sp<Renderer> &renderer,
- const sp<ANativeWindowWrapper> &nww,
- const sp<CCDecoder> &ccDecoder)
- : DecoderBase(notify),
- mNativeWindow(nww),
- mSource(source),
- mRenderer(renderer),
- mCCDecoder(ccDecoder),
- mPid(pid),
- mUid(uid),
- mSkipRenderingUntilMediaTimeUs(-1LL),
- mNumFramesTotal(0LL),
- mNumInputFramesDropped(0LL),
- mNumOutputFramesDropped(0LL),
- mVideoWidth(0),
- mVideoHeight(0),
- mIsAudio(true),
- mIsVideoAVC(false),
- mIsSecure(false),
- mIsEncrypted(false),
- mIsEncryptedObservedEarlier(false),
- mFormatChangePending(false),
- mTimeChangePending(false),
- mFrameRateTotal(kDefaultVideoFrameRateTotal),
- mPlaybackSpeed(1.0f),
- mNumVideoTemporalLayerTotal(1), // decode all layers
- mNumVideoTemporalLayerAllowed(1),
- mCurrentMaxVideoTemporalLayerId(0),
- mResumePending(false),
- mComponentName("decoder") {
- mVideoTemporalLayerAggregateFps[0] = mFrameRateTotal;
-}
-
-NuPlayer2::Decoder::~Decoder() {
- // Need to stop looper first since mCodec could be accessed on the mDecoderLooper.
- stopLooper();
- if (mCodec != NULL) {
- mCodec->release();
- }
- releaseAndResetMediaBuffers();
-}
-
-sp<AMessage> NuPlayer2::Decoder::getStats() const {
- mStats->setInt64("frames-total", mNumFramesTotal);
- mStats->setInt64("frames-dropped-input", mNumInputFramesDropped);
- mStats->setInt64("frames-dropped-output", mNumOutputFramesDropped);
- mStats->setFloat("frame-rate-total", mFrameRateTotal);
-
- // i'm mutexed right now.
- // make our own copy, so we aren't victim to any later changes.
- sp<AMessage> copiedStats = mStats->dup();
- return copiedStats;
-}
-
-status_t NuPlayer2::Decoder::setVideoSurface(const sp<ANativeWindowWrapper> &nww) {
- if (nww == NULL || nww->getANativeWindow() == NULL
- || ADebug::isExperimentEnabled("legacy-setsurface")) {
- return BAD_VALUE;
- }
-
- sp<AMessage> msg = new AMessage(kWhatSetVideoSurface, this);
-
- msg->setObject("surface", nww);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- }
- return err;
-}
-
-void NuPlayer2::Decoder::onMessageReceived(const sp<AMessage> &msg) {
- ALOGV("[%s] onMessage: %s", mComponentName.c_str(), msg->debugString().c_str());
-
- switch (msg->what()) {
- case kWhatCodecNotify:
- {
- int32_t cbID;
- CHECK(msg->findInt32("callbackID", &cbID));
-
- ALOGV("[%s] kWhatCodecNotify: cbID = %d, paused = %d",
- mIsAudio ? "audio" : "video", cbID, mPaused);
-
- if (mPaused) {
- break;
- }
-
- switch (cbID) {
- case AMediaCodecWrapper::CB_INPUT_AVAILABLE:
- {
- int32_t index;
- CHECK(msg->findInt32("index", &index));
-
- handleAnInputBuffer(index);
- break;
- }
-
- case AMediaCodecWrapper::CB_OUTPUT_AVAILABLE:
- {
- int32_t index;
- size_t offset;
- size_t size;
- int64_t timeUs;
- int32_t flags;
-
- CHECK(msg->findInt32("index", &index));
- CHECK(msg->findSize("offset", &offset));
- CHECK(msg->findSize("size", &size));
- CHECK(msg->findInt64("timeUs", &timeUs));
- CHECK(msg->findInt32("flags", &flags));
-
- handleAnOutputBuffer(index, offset, size, timeUs, flags);
- break;
- }
-
- case AMediaCodecWrapper::CB_OUTPUT_FORMAT_CHANGED:
- {
- sp<AMessage> format;
- CHECK(msg->findMessage("format", &format));
-
- handleOutputFormatChange(format);
- break;
- }
-
- case AMediaCodecWrapper::CB_ERROR:
- {
- status_t err;
- CHECK(msg->findInt32("err", &err));
- ALOGE("Decoder (%s) reported error : 0x%x",
- mIsAudio ? "audio" : "video", err);
-
- handleError(err);
- break;
- }
-
- default:
- {
- TRESPASS();
- break;
- }
- }
-
- break;
- }
-
- case kWhatRenderBuffer:
- {
- if (!isStaleReply(msg)) {
- onRenderBuffer(msg);
- }
- break;
- }
-
- case kWhatAudioOutputFormatChanged:
- {
- if (!isStaleReply(msg)) {
- status_t err;
- if (msg->findInt32("err", &err) && err != OK) {
- ALOGE("Renderer reported 0x%x when changing audio output format", err);
- handleError(err);
- }
- }
- break;
- }
-
- case kWhatSetVideoSurface:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
- sp<RefBase> obj;
- CHECK(msg->findObject("surface", &obj));
- sp<ANativeWindowWrapper> nww =
- static_cast<ANativeWindowWrapper *>(obj.get()); // non-null
- if (nww == NULL || nww->getANativeWindow() == NULL) {
- break;
- }
- int32_t err = INVALID_OPERATION;
- // NOTE: in practice mNativeWindow is always non-null,
- // but checking here for completeness
- if (mCodec != NULL
- && mNativeWindow != NULL && mNativeWindow->getANativeWindow() != NULL) {
- // TODO: once AwesomePlayer is removed, remove this automatic connecting
- // to the surface by MediaPlayerService.
- //
- // at this point MediaPlayer2Manager::client has already connected to the
- // surface, which MediaCodec does not expect
- err = native_window_api_disconnect(nww->getANativeWindow(),
- NATIVE_WINDOW_API_MEDIA);
- if (err == OK) {
- err = mCodec->setOutputSurface(nww);
- ALOGI_IF(err, "codec setOutputSurface returned: %d", err);
- if (err == OK) {
- // reconnect to the old surface as MPS::Client will expect to
- // be able to disconnect from it.
- (void)native_window_api_connect(mNativeWindow->getANativeWindow(),
- NATIVE_WINDOW_API_MEDIA);
-
- mNativeWindow = nww;
- }
- }
- if (err != OK) {
- // reconnect to the new surface on error as MPS::Client will expect to
- // be able to disconnect from it.
- (void)native_window_api_connect(nww->getANativeWindow(),
- NATIVE_WINDOW_API_MEDIA);
- }
- }
-
- sp<AMessage> response = new AMessage;
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatDrmReleaseCrypto:
- {
- ALOGV("kWhatDrmReleaseCrypto");
- onReleaseCrypto(msg);
- break;
- }
-
- default:
- DecoderBase::onMessageReceived(msg);
- break;
- }
-}
-
-void NuPlayer2::Decoder::onConfigure(const sp<AMessage> &format) {
- ALOGV("[%s] onConfigure (format=%s)", mComponentName.c_str(), format->debugString().c_str());
- CHECK(mCodec == NULL);
-
- mFormatChangePending = false;
- mTimeChangePending = false;
-
- ++mBufferGeneration;
-
- AString mime;
- CHECK(format->findString("mime", &mime));
-
- mIsAudio = !strncasecmp("audio/", mime.c_str(), 6);
- mIsVideoAVC = !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime.c_str());
-
- mComponentName = mime;
- mComponentName.append(" decoder");
- ALOGV("[%s] onConfigure (nww=%p)", mComponentName.c_str(),
- (mNativeWindow == NULL ? NULL : mNativeWindow->getANativeWindow()));
-
- mCodec = AMediaCodecWrapper::CreateDecoderByType(mime);
- int32_t secure = 0;
- if (format->findInt32("secure", &secure) && secure != 0) {
- if (mCodec != NULL) {
- if (mCodec->getName(&mComponentName) == OK) {
- mComponentName.append(".secure");
- mCodec->release();
- ALOGI("[%s] creating", mComponentName.c_str());
- mCodec = AMediaCodecWrapper::CreateCodecByName(mComponentName);
- } else {
- mCodec = NULL;
- }
- }
- }
- if (mCodec == NULL) {
- ALOGE("Failed to create %s%s decoder",
- (secure ? "secure " : ""), mime.c_str());
- handleError(NO_INIT);
- return;
- }
- mIsSecure = secure;
-
- mCodec->getName(&mComponentName);
-
- status_t err;
- if (mNativeWindow != NULL && mNativeWindow->getANativeWindow() != NULL) {
- // disconnect from surface as MediaCodec will reconnect
- err = native_window_api_disconnect(mNativeWindow->getANativeWindow(),
- NATIVE_WINDOW_API_MEDIA);
- // We treat this as a warning, as this is a preparatory step.
- // Codec will try to connect to the surface, which is where
- // any error signaling will occur.
- ALOGW_IF(err != OK, "failed to disconnect from surface: %d", err);
- }
-
- // Modular DRM
- sp<RefBase> objCrypto;
- format->findObject("crypto", &objCrypto);
- sp<AMediaCryptoWrapper> crypto = static_cast<AMediaCryptoWrapper *>(objCrypto.get());
- // non-encrypted source won't have a crypto
- mIsEncrypted = (crypto != NULL);
- // configure is called once; still using OR in case the behavior changes.
- mIsEncryptedObservedEarlier = mIsEncryptedObservedEarlier || mIsEncrypted;
- ALOGV("onConfigure mCrypto: %p, mIsSecure: %d", crypto.get(), mIsSecure);
-
- err = mCodec->configure(
- AMediaFormatWrapper::Create(format),
- mNativeWindow,
- crypto,
- 0 /* flags */);
-
- if (err != OK) {
- ALOGE("Failed to configure [%s] decoder (err=%d)", mComponentName.c_str(), err);
- mCodec->release();
- mCodec.clear();
- handleError(err);
- return;
- }
- rememberCodecSpecificData(format);
-
- // the following should work in configured state
- sp<AMediaFormatWrapper> outputFormat = mCodec->getOutputFormat();
- if (outputFormat == NULL) {
- handleError(INVALID_OPERATION);
- return;
- }
- mInputFormat = mCodec->getInputFormat();
- if (mInputFormat == NULL) {
- handleError(INVALID_OPERATION);
- return;
- }
-
- mStats->setString("mime", mime.c_str());
- mStats->setString("component-name", mComponentName.c_str());
-
- if (!mIsAudio) {
- int32_t width, height;
- if (outputFormat->getInt32("width", &width)
- && outputFormat->getInt32("height", &height)) {
- mStats->setInt32("width", width);
- mStats->setInt32("height", height);
- }
- }
-
- sp<AMessage> reply = new AMessage(kWhatCodecNotify, this);
- mCodec->setCallback(reply);
-
- err = mCodec->start();
- if (err != OK) {
- ALOGE("Failed to start [%s] decoder (err=%d)", mComponentName.c_str(), err);
- mCodec->release();
- mCodec.clear();
- handleError(err);
- return;
- }
-
- releaseAndResetMediaBuffers();
-
- mPaused = false;
- mResumePending = false;
-}
-
-void NuPlayer2::Decoder::onSetParameters(const sp<AMessage> ¶ms) {
- bool needAdjustLayers = false;
- float frameRateTotal;
- if (params->findFloat("frame-rate-total", &frameRateTotal)
- && mFrameRateTotal != frameRateTotal) {
- needAdjustLayers = true;
- mFrameRateTotal = frameRateTotal;
- }
-
- int32_t numVideoTemporalLayerTotal;
- if (params->findInt32("temporal-layer-count", &numVideoTemporalLayerTotal)
- && numVideoTemporalLayerTotal >= 0
- && numVideoTemporalLayerTotal <= kMaxNumVideoTemporalLayers
- && mNumVideoTemporalLayerTotal != numVideoTemporalLayerTotal) {
- needAdjustLayers = true;
- mNumVideoTemporalLayerTotal = std::max(numVideoTemporalLayerTotal, 1);
- }
-
- if (needAdjustLayers && mNumVideoTemporalLayerTotal > 1) {
- // TODO: For now, layer fps is calculated for some specific architectures.
- // But it really should be extracted from the stream.
- mVideoTemporalLayerAggregateFps[0] =
- mFrameRateTotal / (float)(1LL << (mNumVideoTemporalLayerTotal - 1));
- for (int32_t i = 1; i < mNumVideoTemporalLayerTotal; ++i) {
- mVideoTemporalLayerAggregateFps[i] =
- mFrameRateTotal / (float)(1LL << (mNumVideoTemporalLayerTotal - i))
- + mVideoTemporalLayerAggregateFps[i - 1];
- }
- }
-
- float playbackSpeed;
- if (params->findFloat("playback-speed", &playbackSpeed)
- && mPlaybackSpeed != playbackSpeed) {
- needAdjustLayers = true;
- mPlaybackSpeed = playbackSpeed;
- }
-
- if (needAdjustLayers) {
- float decodeFrameRate = mFrameRateTotal;
- // enable temporal layering optimization only if we know the layering depth
- if (mNumVideoTemporalLayerTotal > 1) {
- int32_t layerId;
- for (layerId = 0; layerId < mNumVideoTemporalLayerTotal - 1; ++layerId) {
- if (mVideoTemporalLayerAggregateFps[layerId] * mPlaybackSpeed
- >= kDisplayRefreshingRate * 0.9) {
- break;
- }
- }
- mNumVideoTemporalLayerAllowed = layerId + 1;
- decodeFrameRate = mVideoTemporalLayerAggregateFps[layerId];
- }
- ALOGV("onSetParameters: allowed layers=%d, decodeFps=%g",
- mNumVideoTemporalLayerAllowed, decodeFrameRate);
-
- if (mCodec == NULL) {
- ALOGW("onSetParameters called before codec is created.");
- return;
- }
-
- sp<AMediaFormatWrapper> codecParams = new AMediaFormatWrapper();
- codecParams->setFloat("operating-rate", decodeFrameRate * mPlaybackSpeed);
- mCodec->setParameters(codecParams);
- }
-}
-
-void NuPlayer2::Decoder::onSetRenderer(const sp<Renderer> &renderer) {
- mRenderer = renderer;
-}
-
-void NuPlayer2::Decoder::onResume(bool notifyComplete) {
- mPaused = false;
-
- if (notifyComplete) {
- mResumePending = true;
- }
-
- if (mCodec == NULL) {
- ALOGE("[%s] onResume without a valid codec", mComponentName.c_str());
- handleError(NO_INIT);
- return;
- }
- mCodec->start();
-}
-
-void NuPlayer2::Decoder::doFlush(bool notifyComplete) {
- if (mCCDecoder != NULL) {
- mCCDecoder->flush();
- }
-
- if (mRenderer != NULL) {
- mRenderer->flush(mIsAudio, notifyComplete);
- mRenderer->signalTimeDiscontinuity();
- }
-
- status_t err = OK;
- if (mCodec != NULL) {
- err = mCodec->flush();
- mCSDsToSubmit = mCSDsForCurrentFormat; // copy operator
- ++mBufferGeneration;
- }
-
- if (err != OK) {
- ALOGE("failed to flush [%s] (err=%d)", mComponentName.c_str(), err);
- handleError(err);
- // finish with posting kWhatFlushCompleted.
- // we attempt to release the buffers even if flush fails.
- }
- releaseAndResetMediaBuffers();
- mPaused = true;
-}
-
-
-void NuPlayer2::Decoder::onFlush() {
- doFlush(true);
-
- if (isDiscontinuityPending()) {
- // This could happen if the client starts seeking/shutdown
- // after we queued an EOS for discontinuities.
- // We can consider discontinuity handled.
- finishHandleDiscontinuity(false /* flushOnTimeChange */);
- }
-
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatFlushCompleted);
- notify->post();
-}
-
-void NuPlayer2::Decoder::onShutdown(bool notifyComplete) {
- status_t err = OK;
-
- // if there is a pending resume request, notify complete now
- notifyResumeCompleteIfNecessary();
-
- if (mCodec != NULL) {
- err = mCodec->release();
- mCodec = NULL;
- ++mBufferGeneration;
-
- if (mNativeWindow != NULL && mNativeWindow->getANativeWindow() != NULL) {
- // reconnect to surface as MediaCodec disconnected from it
- status_t error = native_window_api_connect(mNativeWindow->getANativeWindow(),
- NATIVE_WINDOW_API_MEDIA);
- ALOGW_IF(error != NO_ERROR,
- "[%s] failed to connect to native window, error=%d",
- mComponentName.c_str(), error);
- }
- mComponentName = "decoder";
- }
-
- releaseAndResetMediaBuffers();
-
- if (err != OK) {
- ALOGE("failed to release [%s] (err=%d)", mComponentName.c_str(), err);
- handleError(err);
- // finish with posting kWhatShutdownCompleted.
- }
-
- if (notifyComplete) {
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatShutdownCompleted);
- notify->post();
- mPaused = true;
- }
-}
-
-/*
- * returns true if we should request more data
- */
-bool NuPlayer2::Decoder::doRequestBuffers() {
- if (isDiscontinuityPending()) {
- return false;
- }
- status_t err = OK;
- while (err == OK && !mDequeuedInputBuffers.empty()) {
- size_t bufferIx = *mDequeuedInputBuffers.begin();
- sp<AMessage> msg = new AMessage();
- msg->setSize("buffer-ix", bufferIx);
- err = fetchInputData(msg);
- if (err != OK && err != ERROR_END_OF_STREAM) {
- // if EOS, need to queue EOS buffer
- break;
- }
- mDequeuedInputBuffers.erase(mDequeuedInputBuffers.begin());
-
- if (!mPendingInputMessages.empty()
- || !onInputBufferFetched(msg)) {
- mPendingInputMessages.push_back(msg);
- }
- }
-
- return err == -EWOULDBLOCK
- && mSource->feedMoreTSData() == OK;
-}
-
-void NuPlayer2::Decoder::handleError(int32_t err)
-{
- // We cannot immediately release the codec due to buffers still outstanding
- // in the renderer. We signal to the player the error so it can shutdown/release the
- // decoder after flushing and increment the generation to discard unnecessary messages.
-
- ++mBufferGeneration;
-
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatError);
- notify->setInt32("err", err);
- notify->post();
-}
-
-status_t NuPlayer2::Decoder::releaseCrypto()
-{
- ALOGV("releaseCrypto");
-
- sp<AMessage> msg = new AMessage(kWhatDrmReleaseCrypto, this);
-
- sp<AMessage> response;
- status_t status = msg->postAndAwaitResponse(&response);
- if (status == OK && response != NULL) {
- CHECK(response->findInt32("status", &status));
- ALOGV("releaseCrypto ret: %d ", status);
- } else {
- ALOGE("releaseCrypto err: %d", status);
- }
-
- return status;
-}
-
-void NuPlayer2::Decoder::onReleaseCrypto(const sp<AMessage>& msg)
-{
- status_t status = INVALID_OPERATION;
- if (mCodec != NULL) {
- status = mCodec->releaseCrypto();
- } else {
- // returning OK if the codec has been already released
- status = OK;
- ALOGE("onReleaseCrypto No mCodec. err: %d", status);
- }
-
- sp<AMessage> response = new AMessage;
- response->setInt32("status", status);
- // Clearing the state as it's tied to crypto. mIsEncryptedObservedEarlier is sticky though
- // and lasts for the lifetime of this codec. See its use in fetchInputData.
- mIsEncrypted = false;
-
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
-}
-
-bool NuPlayer2::Decoder::handleAnInputBuffer(size_t index) {
- if (isDiscontinuityPending()) {
- return false;
- }
-
- if (mCodec == NULL) {
- ALOGE("[%s] handleAnInputBuffer without a valid codec", mComponentName.c_str());
- handleError(NO_INIT);
- return false;
- }
-
- size_t bufferSize = 0;
- uint8_t *bufferBase = mCodec->getInputBuffer(index, &bufferSize);
-
- if (bufferBase == NULL) {
- ALOGE("[%s] handleAnInputBuffer, failed to get input buffer", mComponentName.c_str());
- handleError(UNKNOWN_ERROR);
- return false;
- }
-
- sp<MediaCodecBuffer> buffer =
- new MediaCodecBuffer(NULL /* format */, new ABuffer(bufferBase, bufferSize));
-
- if (index >= mInputBuffers.size()) {
- for (size_t i = mInputBuffers.size(); i <= index; ++i) {
- mInputBuffers.add();
- mMediaBuffers.add();
- mInputBufferIsDequeued.add();
- mMediaBuffers.editItemAt(i) = NULL;
- mInputBufferIsDequeued.editItemAt(i) = false;
- }
- }
- mInputBuffers.editItemAt(index) = buffer;
-
- //CHECK_LT(bufferIx, mInputBuffers.size());
-
- if (mMediaBuffers[index] != NULL) {
- mMediaBuffers[index]->release();
- mMediaBuffers.editItemAt(index) = NULL;
- }
- mInputBufferIsDequeued.editItemAt(index) = true;
-
- if (!mCSDsToSubmit.isEmpty()) {
- sp<AMessage> msg = new AMessage();
- msg->setSize("buffer-ix", index);
-
- sp<ABuffer> buffer = mCSDsToSubmit.itemAt(0);
- ALOGI("[%s] resubmitting CSD", mComponentName.c_str());
- msg->setBuffer("buffer", buffer);
- mCSDsToSubmit.removeAt(0);
- if (!onInputBufferFetched(msg)) {
- handleError(UNKNOWN_ERROR);
- return false;
- }
- return true;
- }
-
- while (!mPendingInputMessages.empty()) {
- sp<AMessage> msg = *mPendingInputMessages.begin();
- if (!onInputBufferFetched(msg)) {
- break;
- }
- mPendingInputMessages.erase(mPendingInputMessages.begin());
- }
-
- if (!mInputBufferIsDequeued.editItemAt(index)) {
- return true;
- }
-
- mDequeuedInputBuffers.push_back(index);
-
- onRequestInputBuffers();
- return true;
-}
-
-bool NuPlayer2::Decoder::handleAnOutputBuffer(
- size_t index,
- size_t offset,
- size_t size,
- int64_t timeUs,
- int32_t flags) {
- if (mCodec == NULL) {
- ALOGE("[%s] handleAnOutputBuffer without a valid codec", mComponentName.c_str());
- handleError(NO_INIT);
- return false;
- }
-
-// CHECK_LT(bufferIx, mOutputBuffers.size());
-
- size_t bufferSize = 0;
- uint8_t *bufferBase = mCodec->getOutputBuffer(index, &bufferSize);
-
- if (bufferBase == NULL) {
- ALOGE("[%s] handleAnOutputBuffer, failed to get output buffer", mComponentName.c_str());
- handleError(UNKNOWN_ERROR);
- return false;
- }
-
- sp<MediaCodecBuffer> buffer =
- new MediaCodecBuffer(NULL /* format */, new ABuffer(bufferBase, bufferSize));
-
- if (index >= mOutputBuffers.size()) {
- for (size_t i = mOutputBuffers.size(); i <= index; ++i) {
- mOutputBuffers.add();
- }
- }
-
- mOutputBuffers.editItemAt(index) = buffer;
-
- buffer->setRange(offset, size);
- buffer->meta()->clear();
- buffer->meta()->setInt64("timeUs", timeUs);
-
- bool eos = flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM;
- // we do not expect CODECCONFIG or SYNCFRAME for decoder
-
- sp<AMessage> reply = new AMessage(kWhatRenderBuffer, this);
- reply->setSize("buffer-ix", index);
- reply->setInt32("generation", mBufferGeneration);
-
- if (eos) {
- ALOGI("[%s] saw output EOS", mIsAudio ? "audio" : "video");
-
- buffer->meta()->setInt32("eos", true);
- reply->setInt32("eos", true);
- }
-
- mNumFramesTotal += !mIsAudio;
-
- if (mSkipRenderingUntilMediaTimeUs >= 0) {
- if (timeUs < mSkipRenderingUntilMediaTimeUs) {
- ALOGV("[%s] dropping buffer at time %lld as requested.",
- mComponentName.c_str(), (long long)timeUs);
-
- reply->post();
- if (eos) {
- notifyResumeCompleteIfNecessary();
- if (mRenderer != NULL && !isDiscontinuityPending()) {
- mRenderer->queueEOS(mIsAudio, ERROR_END_OF_STREAM);
- }
- }
- return true;
- }
-
- mSkipRenderingUntilMediaTimeUs = -1;
- }
-
- // wait until 1st frame comes out to signal resume complete
- notifyResumeCompleteIfNecessary();
-
- if (mRenderer != NULL) {
- // send the buffer to renderer.
- mRenderer->queueBuffer(mIsAudio, buffer, reply);
- if (eos && !isDiscontinuityPending()) {
- mRenderer->queueEOS(mIsAudio, ERROR_END_OF_STREAM);
- }
- }
-
- return true;
-}
-
-void NuPlayer2::Decoder::handleOutputFormatChange(const sp<AMessage> &format) {
- if (!mIsAudio) {
- int32_t width, height;
- if (format->findInt32("width", &width)
- && format->findInt32("height", &height)) {
- mStats->setInt32("width", width);
- mStats->setInt32("height", height);
- }
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatVideoSizeChanged);
- notify->setMessage("format", format);
- notify->post();
- } else if (mRenderer != NULL) {
- uint32_t flags;
- int64_t durationUs;
- bool hasVideo = (mSource->getFormat(false /* audio */) != NULL);
- if (getAudioDeepBufferSetting() // override regardless of source duration
- || (mSource->getDuration(&durationUs) == OK
- && durationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US)) {
- flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
- } else {
- flags = AUDIO_OUTPUT_FLAG_NONE;
- }
-
- sp<AMessage> reply = new AMessage(kWhatAudioOutputFormatChanged, this);
- reply->setInt32("generation", mBufferGeneration);
- mRenderer->changeAudioFormat(
- format, false /* offloadOnly */, hasVideo,
- flags, mSource->isStreaming(), reply);
- }
-}
-
-void NuPlayer2::Decoder::releaseAndResetMediaBuffers() {
- for (size_t i = 0; i < mMediaBuffers.size(); i++) {
- if (mMediaBuffers[i] != NULL) {
- mMediaBuffers[i]->release();
- mMediaBuffers.editItemAt(i) = NULL;
- }
- }
- mMediaBuffers.resize(mInputBuffers.size());
- for (size_t i = 0; i < mMediaBuffers.size(); i++) {
- mMediaBuffers.editItemAt(i) = NULL;
- }
- mInputBufferIsDequeued.clear();
- mInputBufferIsDequeued.resize(mInputBuffers.size());
- for (size_t i = 0; i < mInputBufferIsDequeued.size(); i++) {
- mInputBufferIsDequeued.editItemAt(i) = false;
- }
-
- mPendingInputMessages.clear();
- mDequeuedInputBuffers.clear();
- mSkipRenderingUntilMediaTimeUs = -1;
-}
-
-bool NuPlayer2::Decoder::isStaleReply(const sp<AMessage> &msg) {
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
- return generation != mBufferGeneration;
-}
-
-status_t NuPlayer2::Decoder::fetchInputData(sp<AMessage> &reply) {
- sp<ABuffer> accessUnit;
- bool dropAccessUnit = true;
- do {
- status_t err = mSource->dequeueAccessUnit(mIsAudio, &accessUnit);
-
- if (err == -EWOULDBLOCK) {
- return err;
- } else if (err != OK) {
- if (err == INFO_DISCONTINUITY) {
- int32_t type;
- CHECK(accessUnit->meta()->findInt32("discontinuity", &type));
-
- bool formatChange =
- (mIsAudio &&
- (type & ATSParser::DISCONTINUITY_AUDIO_FORMAT))
- || (!mIsAudio &&
- (type & ATSParser::DISCONTINUITY_VIDEO_FORMAT));
-
- bool timeChange = (type & ATSParser::DISCONTINUITY_TIME) != 0;
-
- ALOGI("%s discontinuity (format=%d, time=%d)",
- mIsAudio ? "audio" : "video", formatChange, timeChange);
-
- bool seamlessFormatChange = false;
- sp<AMessage> newFormat = mSource->getFormat(mIsAudio);
- if (formatChange) {
- seamlessFormatChange =
- supportsSeamlessFormatChange(newFormat);
- // treat seamless format change separately
- formatChange = !seamlessFormatChange;
- }
-
- // For format or time change, return EOS to queue EOS input,
- // then wait for EOS on output.
- if (formatChange /* not seamless */) {
- mFormatChangePending = true;
- err = ERROR_END_OF_STREAM;
- } else if (timeChange) {
- rememberCodecSpecificData(newFormat);
- mTimeChangePending = true;
- err = ERROR_END_OF_STREAM;
- } else if (seamlessFormatChange) {
- // reuse existing decoder and don't flush
- rememberCodecSpecificData(newFormat);
- continue;
- } else {
- // This stream is unaffected by the discontinuity
- return -EWOULDBLOCK;
- }
- }
-
- // reply should only be returned without a buffer set
- // when there is an error (including EOS)
- CHECK(err != OK);
-
- reply->setInt32("err", err);
- return ERROR_END_OF_STREAM;
- }
-
- dropAccessUnit = false;
- if (!mIsAudio && !mIsEncrypted) {
- // Extra safeguard if higher-level behavior changes. Otherwise, not required now.
- // Preventing the buffer from being processed (and sent to codec) if this is a later
- // round of playback but this time without prepareDrm. Or if there is a race between
- // stop (which is not blocking) and releaseDrm allowing buffers being processed after
- // Crypto has been released (GenericSource currently prevents this race though).
- // Particularly doing this check before IsAVCReferenceFrame call to prevent parsing
- // of encrypted data.
- if (mIsEncryptedObservedEarlier) {
- ALOGE("fetchInputData: mismatched mIsEncrypted/mIsEncryptedObservedEarlier (0/1)");
-
- return INVALID_OPERATION;
- }
-
- int32_t layerId = 0;
- bool haveLayerId = accessUnit->meta()->findInt32("temporal-layer-id", &layerId);
- if (mRenderer->getVideoLateByUs() > 100000LL
- && mIsVideoAVC
- && !IsAVCReferenceFrame(accessUnit)) {
- dropAccessUnit = true;
- } else if (haveLayerId && mNumVideoTemporalLayerTotal > 1) {
- // Add only one layer each time.
- if (layerId > mCurrentMaxVideoTemporalLayerId + 1
- || layerId >= mNumVideoTemporalLayerAllowed) {
- dropAccessUnit = true;
- ALOGV("dropping layer(%d), speed=%g, allowed layer count=%d, max layerId=%d",
- layerId, mPlaybackSpeed, mNumVideoTemporalLayerAllowed,
- mCurrentMaxVideoTemporalLayerId);
- } else if (layerId > mCurrentMaxVideoTemporalLayerId) {
- mCurrentMaxVideoTemporalLayerId = layerId;
- } else if (layerId == 0 && mNumVideoTemporalLayerTotal > 1
- && IsIDR(accessUnit->data(), accessUnit->size())) {
- mCurrentMaxVideoTemporalLayerId = mNumVideoTemporalLayerTotal - 1;
- }
- }
- if (dropAccessUnit) {
- if (layerId <= mCurrentMaxVideoTemporalLayerId && layerId > 0) {
- mCurrentMaxVideoTemporalLayerId = layerId - 1;
- }
- ++mNumInputFramesDropped;
- }
- }
- } while (dropAccessUnit);
-
- // ALOGV("returned a valid buffer of %s data", mIsAudio ? "mIsAudio" : "video");
-#if 0
- int64_t mediaTimeUs;
- CHECK(accessUnit->meta()->findInt64("timeUs", &mediaTimeUs));
- ALOGV("[%s] feeding input buffer at media time %.3f",
- mIsAudio ? "audio" : "video",
- mediaTimeUs / 1E6);
-#endif
-
- if (mCCDecoder != NULL) {
- mCCDecoder->decode(accessUnit);
- }
-
- reply->setBuffer("buffer", accessUnit);
-
- return OK;
-}
-
-bool NuPlayer2::Decoder::onInputBufferFetched(const sp<AMessage> &msg) {
- if (mCodec == NULL) {
- ALOGE("[%s] onInputBufferFetched without a valid codec", mComponentName.c_str());
- handleError(NO_INIT);
- return false;
- }
-
- size_t bufferIx;
- CHECK(msg->findSize("buffer-ix", &bufferIx));
- CHECK_LT(bufferIx, mInputBuffers.size());
- sp<MediaCodecBuffer> codecBuffer = mInputBuffers[bufferIx];
-
- sp<ABuffer> buffer;
- bool hasBuffer = msg->findBuffer("buffer", &buffer);
- bool needsCopy = true;
-
- if (buffer == NULL /* includes !hasBuffer */) {
- int32_t streamErr = ERROR_END_OF_STREAM;
- CHECK(msg->findInt32("err", &streamErr) || !hasBuffer);
-
- CHECK(streamErr != OK);
-
- // attempt to queue EOS
- status_t err = mCodec->queueInputBuffer(
- bufferIx,
- 0,
- 0,
- 0,
- AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM);
- if (err == OK) {
- mInputBufferIsDequeued.editItemAt(bufferIx) = false;
- } else if (streamErr == ERROR_END_OF_STREAM) {
- streamErr = err;
- // err will not be ERROR_END_OF_STREAM
- }
-
- if (streamErr != ERROR_END_OF_STREAM) {
- ALOGE("Stream error for [%s] (err=%d), EOS %s queued",
- mComponentName.c_str(),
- streamErr,
- err == OK ? "successfully" : "unsuccessfully");
- handleError(streamErr);
- }
- } else {
- sp<AMessage> extra;
- if (buffer->meta()->findMessage("extra", &extra) && extra != NULL) {
- int64_t resumeAtMediaTimeUs;
- if (extra->findInt64(
- "resume-at-mediaTimeUs", &resumeAtMediaTimeUs)) {
- ALOGI("[%s] suppressing rendering until %lld us",
- mComponentName.c_str(), (long long)resumeAtMediaTimeUs);
- mSkipRenderingUntilMediaTimeUs = resumeAtMediaTimeUs;
- }
- }
-
- int64_t timeUs = 0;
- uint32_t flags = 0;
- CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
-
- int32_t eos, csd;
- // we do not expect SYNCFRAME for decoder
- if (buffer->meta()->findInt32("eos", &eos) && eos) {
- flags |= AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM;
- } else if (buffer->meta()->findInt32("csd", &csd) && csd) {
- flags |= AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG;
- }
-
- // Modular DRM
- MediaBufferBase *mediaBuf = NULL;
- sp<AMediaCodecCryptoInfoWrapper> cryptInfo;
-
- // copy into codec buffer
- if (needsCopy) {
- if (buffer->size() > codecBuffer->capacity()) {
- handleError(ERROR_BUFFER_TOO_SMALL);
- mDequeuedInputBuffers.push_back(bufferIx);
- return false;
- }
-
- if (buffer->data() != NULL) {
- codecBuffer->setRange(0, buffer->size());
- memcpy(codecBuffer->data(), buffer->data(), buffer->size());
- } else { // No buffer->data()
- //Modular DRM
- sp<RefBase> holder;
- if (buffer->meta()->findObject("mediaBufferHolder", &holder)) {
- mediaBuf = (holder != nullptr) ?
- static_cast<MediaBufferHolder*>(holder.get())->mediaBuffer() : nullptr;
- }
- if (mediaBuf != NULL) {
- if (mediaBuf->size() > codecBuffer->capacity()) {
- handleError(ERROR_BUFFER_TOO_SMALL);
- mDequeuedInputBuffers.push_back(bufferIx);
- return false;
- }
-
- codecBuffer->setRange(0, mediaBuf->size());
- memcpy(codecBuffer->data(), mediaBuf->data(), mediaBuf->size());
-
- MetaDataBase &meta_data = mediaBuf->meta_data();
- cryptInfo = AMediaCodecCryptoInfoWrapper::Create(meta_data);
- } else { // No mediaBuf
- ALOGE("onInputBufferFetched: buffer->data()/mediaBuf are NULL for %p",
- buffer.get());
- handleError(UNKNOWN_ERROR);
- return false;
- }
- } // buffer->data()
- } // needsCopy
-
- sp<RefBase> cryptInfoObj;
- if (buffer->meta()->findObject("cryptInfo", &cryptInfoObj)) {
- cryptInfo = static_cast<AMediaCodecCryptoInfoWrapper *>(cryptInfoObj.get());
- }
-
- status_t err;
- if (cryptInfo != NULL) {
- err = mCodec->queueSecureInputBuffer(
- bufferIx,
- codecBuffer->offset(),
- cryptInfo,
- timeUs,
- flags);
- // synchronous call so done with cryptInfo here
- } else {
- err = mCodec->queueInputBuffer(
- bufferIx,
- codecBuffer->offset(),
- codecBuffer->size(),
- timeUs,
- flags);
- } // no cryptInfo
-
- if (err != OK) {
- ALOGE("onInputBufferFetched: queue%sInputBuffer failed for [%s] (err=%d)",
- (cryptInfo != NULL ? "Secure" : ""),
- mComponentName.c_str(), err);
- handleError(err);
- } else {
- mInputBufferIsDequeued.editItemAt(bufferIx) = false;
- }
-
- } // buffer != NULL
- return true;
-}
-
-void NuPlayer2::Decoder::onRenderBuffer(const sp<AMessage> &msg) {
- status_t err;
- int32_t render;
- size_t bufferIx;
- int32_t eos;
- CHECK(msg->findSize("buffer-ix", &bufferIx));
-
- if (!mIsAudio) {
- int64_t timeUs;
- sp<MediaCodecBuffer> buffer = mOutputBuffers[bufferIx];
- buffer->meta()->findInt64("timeUs", &timeUs);
-
- if (mCCDecoder != NULL && mCCDecoder->isSelected()) {
- mCCDecoder->display(timeUs);
- }
- }
-
- if (mCodec == NULL) {
- err = NO_INIT;
- } else if (msg->findInt32("render", &render) && render) {
- int64_t timestampNs;
- CHECK(msg->findInt64("timestampNs", ×tampNs));
- err = mCodec->releaseOutputBufferAtTime(bufferIx, timestampNs);
- } else {
- mNumOutputFramesDropped += !mIsAudio;
- err = mCodec->releaseOutputBuffer(bufferIx, false /* render */);
- }
- if (err != OK) {
- ALOGE("failed to release output buffer for [%s] (err=%d)",
- mComponentName.c_str(), err);
- handleError(err);
- }
- if (msg->findInt32("eos", &eos) && eos
- && isDiscontinuityPending()) {
- finishHandleDiscontinuity(true /* flushOnTimeChange */);
- }
-}
-
-bool NuPlayer2::Decoder::isDiscontinuityPending() const {
- return mFormatChangePending || mTimeChangePending;
-}
-
-void NuPlayer2::Decoder::finishHandleDiscontinuity(bool flushOnTimeChange) {
- ALOGV("finishHandleDiscontinuity: format %d, time %d, flush %d",
- mFormatChangePending, mTimeChangePending, flushOnTimeChange);
-
- // If we have format change, pause and wait to be killed;
- // If we have time change only, flush and restart fetching.
-
- if (mFormatChangePending) {
- mPaused = true;
- } else if (mTimeChangePending) {
- if (flushOnTimeChange) {
- doFlush(false /* notifyComplete */);
- signalResume(false /* notifyComplete */);
- }
- }
-
- // Notify NuPlayer2 to either shutdown decoder, or rescan sources
- sp<AMessage> msg = mNotify->dup();
- msg->setInt32("what", kWhatInputDiscontinuity);
- msg->setInt32("formatChange", mFormatChangePending);
- msg->post();
-
- mFormatChangePending = false;
- mTimeChangePending = false;
-}
-
-bool NuPlayer2::Decoder::supportsSeamlessAudioFormatChange(
- const sp<AMessage> &targetFormat) const {
- if (targetFormat == NULL) {
- return true;
- }
-
- AString mime;
- if (!targetFormat->findString("mime", &mime)) {
- return false;
- }
-
- if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_AUDIO_AAC)) {
- // field-by-field comparison
- const char * keys[] = { "channel-count", "sample-rate", "is-adts" };
- for (unsigned int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) {
- int32_t oldVal, newVal;
- if (!mInputFormat->getInt32(keys[i], &oldVal) ||
- !targetFormat->findInt32(keys[i], &newVal) ||
- oldVal != newVal) {
- return false;
- }
- }
-
- sp<ABuffer> newBuf;
- uint8_t *oldBufData = NULL;
- size_t oldBufSize = 0;
- if (mInputFormat->getBuffer("csd-0", (void**)&oldBufData, &oldBufSize) &&
- targetFormat->findBuffer("csd-0", &newBuf)) {
- if (oldBufSize != newBuf->size()) {
- return false;
- }
- return !memcmp(oldBufData, newBuf->data(), oldBufSize);
- }
- }
- return false;
-}
-
-bool NuPlayer2::Decoder::supportsSeamlessFormatChange(const sp<AMessage> &targetFormat) const {
- if (mInputFormat == NULL) {
- return false;
- }
-
- if (targetFormat == NULL) {
- return true;
- }
-
- AString oldMime, newMime;
- if (!mInputFormat->getString("mime", &oldMime)
- || !targetFormat->findString("mime", &newMime)
- || !(oldMime == newMime)) {
- return false;
- }
-
- bool audio = !strncasecmp(oldMime.c_str(), "audio/", strlen("audio/"));
- bool seamless;
- if (audio) {
- seamless = supportsSeamlessAudioFormatChange(targetFormat);
- } else {
- int32_t isAdaptive;
- seamless = (mCodec != NULL &&
- mInputFormat->getInt32("adaptive-playback", &isAdaptive) &&
- isAdaptive);
- }
-
- ALOGV("%s seamless support for %s", seamless ? "yes" : "no", oldMime.c_str());
- return seamless;
-}
-
-void NuPlayer2::Decoder::rememberCodecSpecificData(const sp<AMessage> &format) {
- if (format == NULL) {
- return;
- }
- mCSDsForCurrentFormat.clear();
- for (int32_t i = 0; ; ++i) {
- AString tag = "csd-";
- tag.append(i);
- sp<ABuffer> buffer;
- if (!format->findBuffer(tag.c_str(), &buffer)) {
- break;
- }
- mCSDsForCurrentFormat.push(buffer);
- }
-}
-
-void NuPlayer2::Decoder::notifyResumeCompleteIfNecessary() {
- if (mResumePending) {
- mResumePending = false;
-
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatResumeCompleted);
- notify->post();
- }
-}
-
-} // namespace android
-
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.h
deleted file mode 100644
index fdfb10e..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NUPLAYER2_DECODER_H_
-#define NUPLAYER2_DECODER_H_
-
-#include "NuPlayer2.h"
-
-#include "NuPlayer2DecoderBase.h"
-
-namespace android {
-
-class MediaCodecBuffer;
-
-struct AMediaCodecWrapper;
-struct AMediaFormatWrapper;
-
-struct NuPlayer2::Decoder : public DecoderBase {
- Decoder(const sp<AMessage> ¬ify,
- const sp<Source> &source,
- pid_t pid,
- uid_t uid,
- const sp<Renderer> &renderer = NULL,
- const sp<ANativeWindowWrapper> &nww = NULL,
- const sp<CCDecoder> &ccDecoder = NULL);
-
- virtual sp<AMessage> getStats() const;
-
- // sets the output surface of video decoders.
- virtual status_t setVideoSurface(const sp<ANativeWindowWrapper> &nww);
-
- virtual status_t releaseCrypto();
-
-protected:
- virtual ~Decoder();
-
- virtual void onMessageReceived(const sp<AMessage> &msg);
-
- virtual void onConfigure(const sp<AMessage> &format);
- virtual void onSetParameters(const sp<AMessage> ¶ms);
- virtual void onSetRenderer(const sp<Renderer> &renderer);
- virtual void onResume(bool notifyComplete);
- virtual void onFlush();
- virtual void onShutdown(bool notifyComplete);
- virtual bool doRequestBuffers();
-
-private:
- enum {
- kWhatCodecNotify = 'cdcN',
- kWhatRenderBuffer = 'rndr',
- kWhatSetVideoSurface = 'sSur',
- kWhatAudioOutputFormatChanged = 'aofc',
- kWhatDrmReleaseCrypto = 'rDrm',
- };
-
- enum {
- kMaxNumVideoTemporalLayers = 32,
- };
-
- sp<ANativeWindowWrapper> mNativeWindow;
-
- sp<Source> mSource;
- sp<Renderer> mRenderer;
- sp<CCDecoder> mCCDecoder;
-
- sp<AMediaFormatWrapper> mInputFormat;
- sp<AMediaCodecWrapper> mCodec;
-
- List<sp<AMessage> > mPendingInputMessages;
-
- Vector<sp<MediaCodecBuffer> > mInputBuffers;
- Vector<sp<MediaCodecBuffer> > mOutputBuffers;
- Vector<sp<ABuffer> > mCSDsForCurrentFormat;
- Vector<sp<ABuffer> > mCSDsToSubmit;
- Vector<bool> mInputBufferIsDequeued;
- Vector<MediaBuffer *> mMediaBuffers;
- Vector<size_t> mDequeuedInputBuffers;
-
- const pid_t mPid;
- const uid_t mUid;
- int64_t mSkipRenderingUntilMediaTimeUs;
- int64_t mNumFramesTotal;
- int64_t mNumInputFramesDropped;
- int64_t mNumOutputFramesDropped;
- int32_t mVideoWidth;
- int32_t mVideoHeight;
- bool mIsAudio;
- bool mIsVideoAVC;
- bool mIsSecure;
- bool mIsEncrypted;
- bool mIsEncryptedObservedEarlier;
- bool mFormatChangePending;
- bool mTimeChangePending;
- float mFrameRateTotal;
- float mPlaybackSpeed;
- int32_t mNumVideoTemporalLayerTotal;
- int32_t mNumVideoTemporalLayerAllowed;
- int32_t mCurrentMaxVideoTemporalLayerId;
- float mVideoTemporalLayerAggregateFps[kMaxNumVideoTemporalLayers];
-
- bool mResumePending;
- AString mComponentName;
-
- void handleError(int32_t err);
- bool handleAnInputBuffer(size_t index);
- bool handleAnOutputBuffer(
- size_t index,
- size_t offset,
- size_t size,
- int64_t timeUs,
- int32_t flags);
- void handleOutputFormatChange(const sp<AMessage> &format);
-
- void releaseAndResetMediaBuffers();
- bool isStaleReply(const sp<AMessage> &msg);
-
- void doFlush(bool notifyComplete);
- status_t fetchInputData(sp<AMessage> &reply);
- bool onInputBufferFetched(const sp<AMessage> &msg);
- void onRenderBuffer(const sp<AMessage> &msg);
-
- bool supportsSeamlessFormatChange(const sp<AMessage> &to) const;
- bool supportsSeamlessAudioFormatChange(const sp<AMessage> &targetFormat) const;
- void rememberCodecSpecificData(const sp<AMessage> &format);
- bool isDiscontinuityPending() const;
- void finishHandleDiscontinuity(bool flushOnTimeChange);
-
- void notifyResumeCompleteIfNecessary();
-
- void onReleaseCrypto(const sp<AMessage>& msg);
-
- DISALLOW_EVIL_CONSTRUCTORS(Decoder);
-};
-
-} // namespace android
-
-#endif // NUPLAYER2_DECODER_H_
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderBase.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderBase.cpp
deleted file mode 100644
index 914f29f..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderBase.cpp
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NuPlayer2DecoderBase"
-#include <utils/Log.h>
-#include <inttypes.h>
-
-#include "NuPlayer2DecoderBase.h"
-
-#include "NuPlayer2Renderer.h"
-
-#include <media/MediaCodecBuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-
-namespace android {
-
-NuPlayer2::DecoderBase::DecoderBase(const sp<AMessage> ¬ify)
- : mNotify(notify),
- mBufferGeneration(0),
- mPaused(false),
- mStats(new AMessage),
- mRequestInputBuffersPending(false) {
- // Every decoder has its own looper because MediaCodec operations
- // are blocking, but NuPlayer2 needs asynchronous operations.
- mDecoderLooper = new ALooper;
- mDecoderLooper->setName("NP2Decoder");
- mDecoderLooper->start(false, /* runOnCallingThread */
- true, /* canCallJava */
- ANDROID_PRIORITY_AUDIO);
-}
-
-NuPlayer2::DecoderBase::~DecoderBase() {
- stopLooper();
-}
-
-static
-status_t PostAndAwaitResponse(
- const sp<AMessage> &msg, sp<AMessage> *response) {
- status_t err = msg->postAndAwaitResponse(response);
-
- if (err != OK) {
- return err;
- }
-
- if (!(*response)->findInt32("err", &err)) {
- err = OK;
- }
-
- return err;
-}
-
-void NuPlayer2::DecoderBase::configure(const sp<AMessage> &format) {
- sp<AMessage> msg = new AMessage(kWhatConfigure, this);
- msg->setMessage("format", format);
- msg->post();
-}
-
-void NuPlayer2::DecoderBase::init() {
- mDecoderLooper->registerHandler(this);
-}
-
-void NuPlayer2::DecoderBase::stopLooper() {
- mDecoderLooper->unregisterHandler(id());
- mDecoderLooper->stop();
-}
-
-void NuPlayer2::DecoderBase::setParameters(const sp<AMessage> ¶ms) {
- sp<AMessage> msg = new AMessage(kWhatSetParameters, this);
- msg->setMessage("params", params);
- msg->post();
-}
-
-void NuPlayer2::DecoderBase::setRenderer(const sp<Renderer> &renderer) {
- sp<AMessage> msg = new AMessage(kWhatSetRenderer, this);
- msg->setObject("renderer", renderer);
- msg->post();
-}
-
-void NuPlayer2::DecoderBase::pause() {
- sp<AMessage> msg = new AMessage(kWhatPause, this);
-
- sp<AMessage> response;
- PostAndAwaitResponse(msg, &response);
-}
-
-void NuPlayer2::DecoderBase::signalFlush() {
- (new AMessage(kWhatFlush, this))->post();
-}
-
-void NuPlayer2::DecoderBase::signalResume(bool notifyComplete) {
- sp<AMessage> msg = new AMessage(kWhatResume, this);
- msg->setInt32("notifyComplete", notifyComplete);
- msg->post();
-}
-
-void NuPlayer2::DecoderBase::initiateShutdown() {
- (new AMessage(kWhatShutdown, this))->post();
-}
-
-void NuPlayer2::DecoderBase::onRequestInputBuffers() {
- if (mRequestInputBuffersPending) {
- return;
- }
-
- // doRequestBuffers() return true if we should request more data
- if (doRequestBuffers()) {
- mRequestInputBuffersPending = true;
-
- sp<AMessage> msg = new AMessage(kWhatRequestInputBuffers, this);
- msg->post(10 * 1000LL);
- }
-}
-
-void NuPlayer2::DecoderBase::onMessageReceived(const sp<AMessage> &msg) {
-
- switch (msg->what()) {
- case kWhatConfigure:
- {
- sp<AMessage> format;
- CHECK(msg->findMessage("format", &format));
- onConfigure(format);
- break;
- }
-
- case kWhatSetParameters:
- {
- sp<AMessage> params;
- CHECK(msg->findMessage("params", ¶ms));
- onSetParameters(params);
- break;
- }
-
- case kWhatSetRenderer:
- {
- sp<RefBase> obj;
- CHECK(msg->findObject("renderer", &obj));
- onSetRenderer(static_cast<Renderer *>(obj.get()));
- break;
- }
-
- case kWhatPause:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
- mPaused = true;
-
- (new AMessage)->postReply(replyID);
- break;
- }
-
- case kWhatRequestInputBuffers:
- {
- mRequestInputBuffersPending = false;
- onRequestInputBuffers();
- break;
- }
-
- case kWhatFlush:
- {
- onFlush();
- break;
- }
-
- case kWhatResume:
- {
- int32_t notifyComplete;
- CHECK(msg->findInt32("notifyComplete", ¬ifyComplete));
-
- onResume(notifyComplete);
- break;
- }
-
- case kWhatShutdown:
- {
- onShutdown(true);
- break;
- }
-
- default:
- TRESPASS();
- break;
- }
-}
-
-void NuPlayer2::DecoderBase::handleError(int32_t err)
-{
- // We cannot immediately release the codec due to buffers still outstanding
- // in the renderer. We signal to the player the error so it can shutdown/release the
- // decoder after flushing and increment the generation to discard unnecessary messages.
-
- ++mBufferGeneration;
-
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatError);
- notify->setInt32("err", err);
- notify->post();
-}
-
-} // namespace android
-
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderBase.h b/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderBase.h
deleted file mode 100644
index 1e57f0d..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderBase.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NUPLAYER2_DECODER_BASE_H_
-
-#define NUPLAYER2_DECODER_BASE_H_
-
-#include "NuPlayer2.h"
-
-#include <media/stagefright/foundation/AHandler.h>
-
-namespace android {
-
-struct ABuffer;
-struct ANativeWindowWrapper;
-struct MediaCodec;
-class MediaBuffer;
-class MediaCodecBuffer;
-
-struct NuPlayer2::DecoderBase : public AHandler {
- explicit DecoderBase(const sp<AMessage> ¬ify);
-
- void configure(const sp<AMessage> &format);
- void init();
- void setParameters(const sp<AMessage> ¶ms);
-
- // Synchronous call to ensure decoder will not request or send out data.
- void pause();
-
- void setRenderer(const sp<Renderer> &renderer);
- virtual status_t setVideoSurface(const sp<ANativeWindowWrapper> &) { return INVALID_OPERATION; }
-
- void signalFlush();
- void signalResume(bool notifyComplete);
- void initiateShutdown();
-
- virtual sp<AMessage> getStats() const {
- return mStats;
- }
-
- virtual status_t releaseCrypto() {
- return INVALID_OPERATION;
- }
-
- enum {
- kWhatInputDiscontinuity = 'inDi',
- kWhatVideoSizeChanged = 'viSC',
- kWhatFlushCompleted = 'flsC',
- kWhatShutdownCompleted = 'shDC',
- kWhatResumeCompleted = 'resC',
- kWhatEOS = 'eos ',
- kWhatError = 'err ',
- };
-
-protected:
-
- virtual ~DecoderBase();
-
- void stopLooper();
-
- virtual void onMessageReceived(const sp<AMessage> &msg);
-
- virtual void onConfigure(const sp<AMessage> &format) = 0;
- virtual void onSetParameters(const sp<AMessage> ¶ms) = 0;
- virtual void onSetRenderer(const sp<Renderer> &renderer) = 0;
- virtual void onResume(bool notifyComplete) = 0;
- virtual void onFlush() = 0;
- virtual void onShutdown(bool notifyComplete) = 0;
-
- void onRequestInputBuffers();
- virtual bool doRequestBuffers() = 0;
- virtual void handleError(int32_t err);
-
- sp<AMessage> mNotify;
- int32_t mBufferGeneration;
- bool mPaused;
- sp<AMessage> mStats;
-
-private:
- enum {
- kWhatConfigure = 'conf',
- kWhatSetParameters = 'setP',
- kWhatSetRenderer = 'setR',
- kWhatPause = 'paus',
- kWhatRequestInputBuffers = 'reqB',
- kWhatFlush = 'flus',
- kWhatShutdown = 'shuD',
- };
-
- sp<ALooper> mDecoderLooper;
- bool mRequestInputBuffersPending;
-
- DISALLOW_EVIL_CONSTRUCTORS(DecoderBase);
-};
-
-} // namespace android
-
-#endif // NUPLAYER2_DECODER_BASE_H_
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderPassThrough.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderPassThrough.cpp
deleted file mode 100644
index 0514e88..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderPassThrough.cpp
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NuPlayer2DecoderPassThrough"
-#include <utils/Log.h>
-#include <inttypes.h>
-
-#include "NuPlayer2DecoderPassThrough.h"
-
-#include "NuPlayer2Renderer.h"
-#include "NuPlayer2Source.h"
-
-#include <media/MediaCodecBuffer.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MediaErrors.h>
-
-#include "ATSParser.h"
-
-namespace android {
-
-// TODO optimize buffer size for power consumption
-// The offload read buffer size is 32 KB but 24 KB uses less power.
-static const size_t kAggregateBufferSizeBytes = 24 * 1024;
-static const size_t kMaxCachedBytes = 200000;
-
-NuPlayer2::DecoderPassThrough::DecoderPassThrough(
- const sp<AMessage> ¬ify,
- const sp<Source> &source,
- const sp<Renderer> &renderer)
- : DecoderBase(notify),
- mSource(source),
- mRenderer(renderer),
- mSkipRenderingUntilMediaTimeUs(-1LL),
- mReachedEOS(true),
- mPendingAudioErr(OK),
- mPendingBuffersToDrain(0),
- mCachedBytes(0),
- mComponentName("pass through decoder") {
- ALOGW_IF(renderer == NULL, "expect a non-NULL renderer");
-}
-
-NuPlayer2::DecoderPassThrough::~DecoderPassThrough() {
-}
-
-void NuPlayer2::DecoderPassThrough::onConfigure(const sp<AMessage> &format) {
- ALOGV("[%s] onConfigure", mComponentName.c_str());
- mCachedBytes = 0;
- mPendingBuffersToDrain = 0;
- mReachedEOS = false;
- ++mBufferGeneration;
-
- onRequestInputBuffers();
-
- int32_t hasVideo = 0;
- format->findInt32("has-video", &hasVideo);
-
- // The audio sink is already opened before the PassThrough decoder is created.
- // Opening again might be relevant if decoder is instantiated after shutdown and
- // format is different.
- status_t err = mRenderer->openAudioSink(
- format, true /* offloadOnly */, hasVideo,
- AUDIO_OUTPUT_FLAG_NONE /* flags */, NULL /* isOffloaded */, mSource->isStreaming());
- if (err != OK) {
- handleError(err);
- }
-}
-
-void NuPlayer2::DecoderPassThrough::onSetParameters(const sp<AMessage> &/*params*/) {
- ALOGW("onSetParameters() called unexpectedly");
-}
-
-void NuPlayer2::DecoderPassThrough::onSetRenderer(
- const sp<Renderer> &renderer) {
- // renderer can't be changed during offloading
- ALOGW_IF(renderer != mRenderer,
- "ignoring request to change renderer");
-}
-
-bool NuPlayer2::DecoderPassThrough::isStaleReply(const sp<AMessage> &msg) {
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
- return generation != mBufferGeneration;
-}
-
-bool NuPlayer2::DecoderPassThrough::isDoneFetching() const {
- ALOGV("[%s] mCachedBytes = %zu, mReachedEOS = %d mPaused = %d",
- mComponentName.c_str(), mCachedBytes, mReachedEOS, mPaused);
-
- return mCachedBytes >= kMaxCachedBytes || mReachedEOS || mPaused;
-}
-
-/*
- * returns true if we should request more data
- */
-bool NuPlayer2::DecoderPassThrough::doRequestBuffers() {
- status_t err = OK;
- while (!isDoneFetching()) {
- sp<AMessage> msg = new AMessage();
-
- err = fetchInputData(msg);
- if (err != OK) {
- break;
- }
-
- onInputBufferFetched(msg);
- }
-
- return err == -EWOULDBLOCK
- && mSource->feedMoreTSData() == OK;
-}
-
-status_t NuPlayer2::DecoderPassThrough::dequeueAccessUnit(sp<ABuffer> *accessUnit) {
- status_t err;
-
- // Did we save an accessUnit earlier because of a discontinuity?
- if (mPendingAudioAccessUnit != NULL) {
- *accessUnit = mPendingAudioAccessUnit;
- mPendingAudioAccessUnit.clear();
- err = mPendingAudioErr;
- ALOGV("feedDecoderInputData() use mPendingAudioAccessUnit");
- } else {
- err = mSource->dequeueAccessUnit(true /* audio */, accessUnit);
- }
-
- if (err == INFO_DISCONTINUITY || err == ERROR_END_OF_STREAM) {
- if (mAggregateBuffer != NULL) {
- // We already have some data so save this for later.
- mPendingAudioErr = err;
- mPendingAudioAccessUnit = *accessUnit;
- (*accessUnit).clear();
- ALOGD("return aggregated buffer and save err(=%d) for later", err);
- err = OK;
- }
- }
-
- return err;
-}
-
-sp<ABuffer> NuPlayer2::DecoderPassThrough::aggregateBuffer(
- const sp<ABuffer> &accessUnit) {
- sp<ABuffer> aggregate;
-
- if (accessUnit == NULL) {
- // accessUnit is saved to mPendingAudioAccessUnit
- // return current mAggregateBuffer
- aggregate = mAggregateBuffer;
- mAggregateBuffer.clear();
- return aggregate;
- }
-
- size_t smallSize = accessUnit->size();
- if ((mAggregateBuffer == NULL)
- // Don't bother if only room for a few small buffers.
- && (smallSize < (kAggregateBufferSizeBytes / 3))) {
- // Create a larger buffer for combining smaller buffers from the extractor.
- mAggregateBuffer = new ABuffer(kAggregateBufferSizeBytes);
- mAggregateBuffer->setRange(0, 0); // start empty
- }
-
- if (mAggregateBuffer != NULL) {
- int64_t timeUs;
- int64_t dummy;
- bool smallTimestampValid = accessUnit->meta()->findInt64("timeUs", &timeUs);
- bool bigTimestampValid = mAggregateBuffer->meta()->findInt64("timeUs", &dummy);
- // Will the smaller buffer fit?
- size_t bigSize = mAggregateBuffer->size();
- size_t roomLeft = mAggregateBuffer->capacity() - bigSize;
- // Should we save this small buffer for the next big buffer?
- // If the first small buffer did not have a timestamp then save
- // any buffer that does have a timestamp until the next big buffer.
- if ((smallSize > roomLeft)
- || (!bigTimestampValid && (bigSize > 0) && smallTimestampValid)) {
- mPendingAudioErr = OK;
- mPendingAudioAccessUnit = accessUnit;
- aggregate = mAggregateBuffer;
- mAggregateBuffer.clear();
- } else {
- // Grab time from first small buffer if available.
- if ((bigSize == 0) && smallTimestampValid) {
- mAggregateBuffer->meta()->setInt64("timeUs", timeUs);
- }
- // Append small buffer to the bigger buffer.
- memcpy(mAggregateBuffer->base() + bigSize, accessUnit->data(), smallSize);
- bigSize += smallSize;
- mAggregateBuffer->setRange(0, bigSize);
-
- ALOGV("feedDecoderInputData() smallSize = %zu, bigSize = %zu, capacity = %zu",
- smallSize, bigSize, mAggregateBuffer->capacity());
- }
- } else {
- // decided not to aggregate
- aggregate = accessUnit;
- }
-
- return aggregate;
-}
-
-status_t NuPlayer2::DecoderPassThrough::fetchInputData(sp<AMessage> &reply) {
- sp<ABuffer> accessUnit;
-
- do {
- status_t err = dequeueAccessUnit(&accessUnit);
-
- if (err == -EWOULDBLOCK) {
- // Flush out the aggregate buffer to try to avoid underrun.
- accessUnit = aggregateBuffer(NULL /* accessUnit */);
- if (accessUnit != NULL) {
- break;
- }
- return err;
- } else if (err != OK) {
- if (err == INFO_DISCONTINUITY) {
- int32_t type;
- CHECK(accessUnit->meta()->findInt32("discontinuity", &type));
-
- bool formatChange =
- (type & ATSParser::DISCONTINUITY_AUDIO_FORMAT) != 0;
-
- bool timeChange =
- (type & ATSParser::DISCONTINUITY_TIME) != 0;
-
- ALOGI("audio discontinuity (formatChange=%d, time=%d)",
- formatChange, timeChange);
-
- if (formatChange || timeChange) {
- sp<AMessage> msg = mNotify->dup();
- msg->setInt32("what", kWhatInputDiscontinuity);
- // will perform seamless format change,
- // only notify NuPlayer2 to scan sources
- msg->setInt32("formatChange", false);
- msg->post();
- }
-
- if (timeChange) {
- doFlush(false /* notifyComplete */);
- err = OK;
- } else if (formatChange) {
- // do seamless format change
- err = OK;
- } else {
- // This stream is unaffected by the discontinuity
- return -EWOULDBLOCK;
- }
- }
-
- reply->setInt32("err", err);
- return OK;
- }
-
- accessUnit = aggregateBuffer(accessUnit);
- } while (accessUnit == NULL);
-
-#if 0
- int64_t mediaTimeUs;
- CHECK(accessUnit->meta()->findInt64("timeUs", &mediaTimeUs));
- ALOGV("feeding audio input buffer at media time %.2f secs",
- mediaTimeUs / 1E6);
-#endif
-
- reply->setBuffer("buffer", accessUnit);
-
- return OK;
-}
-
-void NuPlayer2::DecoderPassThrough::onInputBufferFetched(
- const sp<AMessage> &msg) {
- if (mReachedEOS) {
- return;
- }
-
- sp<ABuffer> buffer;
- bool hasBuffer = msg->findBuffer("buffer", &buffer);
- if (buffer == NULL) {
- int32_t streamErr = ERROR_END_OF_STREAM;
- CHECK(msg->findInt32("err", &streamErr) || !hasBuffer);
- if (streamErr == OK) {
- return;
- }
-
- if (streamErr != ERROR_END_OF_STREAM) {
- handleError(streamErr);
- }
- mReachedEOS = true;
- if (mRenderer != NULL) {
- mRenderer->queueEOS(true /* audio */, ERROR_END_OF_STREAM);
- }
- return;
- }
-
- sp<AMessage> extra;
- if (buffer->meta()->findMessage("extra", &extra) && extra != NULL) {
- int64_t resumeAtMediaTimeUs;
- if (extra->findInt64(
- "resume-at-mediatimeUs", &resumeAtMediaTimeUs)) {
- ALOGI("[%s] suppressing rendering until %lld us",
- mComponentName.c_str(), (long long)resumeAtMediaTimeUs);
- mSkipRenderingUntilMediaTimeUs = resumeAtMediaTimeUs;
- }
- }
-
- int32_t bufferSize = buffer->size();
- mCachedBytes += bufferSize;
-
- int64_t timeUs = 0;
- CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
- if (mSkipRenderingUntilMediaTimeUs >= 0) {
- if (timeUs < mSkipRenderingUntilMediaTimeUs) {
- ALOGV("[%s] dropping buffer at time %lld as requested.",
- mComponentName.c_str(), (long long)timeUs);
-
- onBufferConsumed(bufferSize);
- return;
- }
-
- mSkipRenderingUntilMediaTimeUs = -1;
- }
-
- if (mRenderer == NULL) {
- onBufferConsumed(bufferSize);
- return;
- }
-
- sp<AMessage> reply = new AMessage(kWhatBufferConsumed, this);
- reply->setInt32("generation", mBufferGeneration);
- reply->setInt32("size", bufferSize);
-
- sp<MediaCodecBuffer> mcBuffer = new MediaCodecBuffer(nullptr, buffer);
- mcBuffer->meta()->setInt64("timeUs", timeUs);
-
- mRenderer->queueBuffer(true /* audio */, mcBuffer, reply);
-
- ++mPendingBuffersToDrain;
- ALOGV("onInputBufferFilled: #ToDrain = %zu, cachedBytes = %zu",
- mPendingBuffersToDrain, mCachedBytes);
-}
-
-void NuPlayer2::DecoderPassThrough::onBufferConsumed(int32_t size) {
- --mPendingBuffersToDrain;
- mCachedBytes -= size;
- ALOGV("onBufferConsumed: #ToDrain = %zu, cachedBytes = %zu",
- mPendingBuffersToDrain, mCachedBytes);
- onRequestInputBuffers();
-}
-
-void NuPlayer2::DecoderPassThrough::onResume(bool notifyComplete) {
- mPaused = false;
-
- onRequestInputBuffers();
-
- if (notifyComplete) {
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatResumeCompleted);
- notify->post();
- }
-}
-
-void NuPlayer2::DecoderPassThrough::doFlush(bool notifyComplete) {
- ++mBufferGeneration;
- mSkipRenderingUntilMediaTimeUs = -1;
- mPendingAudioAccessUnit.clear();
- mPendingAudioErr = OK;
- mAggregateBuffer.clear();
-
- if (mRenderer != NULL) {
- mRenderer->flush(true /* audio */, notifyComplete);
- mRenderer->signalTimeDiscontinuity();
- }
-
- mPendingBuffersToDrain = 0;
- mCachedBytes = 0;
- mReachedEOS = false;
-}
-
-void NuPlayer2::DecoderPassThrough::onFlush() {
- doFlush(true /* notifyComplete */);
-
- mPaused = true;
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatFlushCompleted);
- notify->post();
-
-}
-
-void NuPlayer2::DecoderPassThrough::onShutdown(bool notifyComplete) {
- ++mBufferGeneration;
- mSkipRenderingUntilMediaTimeUs = -1;
-
- if (notifyComplete) {
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatShutdownCompleted);
- notify->post();
- }
-
- mReachedEOS = true;
-}
-
-void NuPlayer2::DecoderPassThrough::onMessageReceived(const sp<AMessage> &msg) {
- ALOGV("[%s] onMessage: %s", mComponentName.c_str(),
- msg->debugString().c_str());
-
- switch (msg->what()) {
- case kWhatBufferConsumed:
- {
- if (!isStaleReply(msg)) {
- int32_t size;
- CHECK(msg->findInt32("size", &size));
- onBufferConsumed(size);
- }
- break;
- }
-
- default:
- DecoderBase::onMessageReceived(msg);
- break;
- }
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderPassThrough.h b/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderPassThrough.h
deleted file mode 100644
index 838c60a..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2DecoderPassThrough.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NUPLAYER2_DECODER_PASS_THROUGH_H_
-
-#define NUPLAYER2_DECODER_PASS_THROUGH_H_
-
-#include "NuPlayer2.h"
-
-#include "NuPlayer2DecoderBase.h"
-
-namespace android {
-
-struct NuPlayer2::DecoderPassThrough : public DecoderBase {
- DecoderPassThrough(const sp<AMessage> ¬ify,
- const sp<Source> &source,
- const sp<Renderer> &renderer);
-
-protected:
-
- virtual ~DecoderPassThrough();
-
- virtual void onMessageReceived(const sp<AMessage> &msg);
-
- virtual void onConfigure(const sp<AMessage> &format);
- virtual void onSetParameters(const sp<AMessage> ¶ms);
- virtual void onSetRenderer(const sp<Renderer> &renderer);
- virtual void onResume(bool notifyComplete);
- virtual void onFlush();
- virtual void onShutdown(bool notifyComplete);
- virtual bool doRequestBuffers();
-
-private:
- enum {
- kWhatBufferConsumed = 'bufC',
- };
-
- sp<Source> mSource;
- sp<Renderer> mRenderer;
- int64_t mSkipRenderingUntilMediaTimeUs;
-
- bool mReachedEOS;
-
- // Used by feedDecoderInputData to aggregate small buffers into
- // one large buffer.
- sp<ABuffer> mPendingAudioAccessUnit;
- status_t mPendingAudioErr;
- sp<ABuffer> mAggregateBuffer;
-
- // mPendingBuffersToDrain are only for debugging. It can be removed
- // when the power investigation is done.
- size_t mPendingBuffersToDrain;
- size_t mCachedBytes;
- AString mComponentName;
-
- bool isStaleReply(const sp<AMessage> &msg);
- bool isDoneFetching() const;
-
- status_t dequeueAccessUnit(sp<ABuffer> *accessUnit);
- sp<ABuffer> aggregateBuffer(const sp<ABuffer> &accessUnit);
- status_t fetchInputData(sp<AMessage> &reply);
- void doFlush(bool notifyComplete);
-
- void onInputBufferFetched(const sp<AMessage> &msg);
- void onBufferConsumed(int32_t size);
-
- DISALLOW_EVIL_CONSTRUCTORS(DecoderPassThrough);
-};
-
-} // namespace android
-
-#endif // NUPLAYER2_DECODER_PASS_THROUGH_H_
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
deleted file mode 100644
index 1876496..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
+++ /dev/null
@@ -1,1010 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NuPlayer2Driver"
-#include <inttypes.h>
-#include <android-base/macros.h>
-#include <utils/Log.h>
-#include <cutils/properties.h>
-
-#include "NuPlayer2Driver.h"
-
-#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>
-#include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/MediaClock.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
-
-#include <media/IMediaAnalyticsService.h>
-
-using google::protobuf::RepeatedPtrField;
-using android::media::MediaPlayer2Proto::Value;
-
-static const int kDumpLockRetries = 50;
-static const int kDumpLockSleepUs = 20000;
-
-namespace android {
-
-struct PlayerMessageWrapper : public RefBase {
- static sp<PlayerMessageWrapper> Create(const PlayerMessage *p) {
- if (p != NULL) {
- sp<PlayerMessageWrapper> pw = new PlayerMessageWrapper();
- pw->copyFrom(p);
- return pw;
- }
- return NULL;
- }
-
- const PlayerMessage *getPlayerMessage() {
- return mPlayerMessage;
- }
-
-protected:
- virtual ~PlayerMessageWrapper() {
- if (mPlayerMessage != NULL) {
- delete mPlayerMessage;
- }
- }
-
-private:
- PlayerMessageWrapper()
- : mPlayerMessage(NULL) { }
-
- void copyFrom(const PlayerMessage *p) {
- if (mPlayerMessage == NULL) {
- mPlayerMessage = new PlayerMessage;
- }
- mPlayerMessage->CopyFrom(*p);
- }
-
- PlayerMessage *mPlayerMessage;
-};
-
-// key for media statistics
-static const char *kKeyPlayer = "nuplayer2";
-// 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";
-static const char *kPlayerHeight = "android.media.mediaplayer.height";
-static const char *kPlayerFrames = "android.media.mediaplayer.frames";
-static const char *kPlayerFramesDropped = "android.media.mediaplayer.dropped";
-static const char *kPlayerFrameRate = "android.media.mediaplayer.fps";
-static const char *kPlayerAMime = "android.media.mediaplayer.audio.mime";
-static const char *kPlayerACodec = "android.media.mediaplayer.audio.codec";
-static const char *kPlayerDuration = "android.media.mediaplayer.durationMs";
-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";
-//
-static const char *kPlayerRebuffering = "android.media.mediaplayer.rebufferingMs";
-static const char *kPlayerRebufferingCount = "android.media.mediaplayer.rebuffers";
-static const char *kPlayerRebufferingAtExit = "android.media.mediaplayer.rebufferExit";
-
-static const char *kPlayerVersion = "android.media.mediaplayer.version";
-
-
-NuPlayer2Driver::NuPlayer2Driver(pid_t pid, uid_t uid, const sp<JObjectHolder> &context)
- : mState(STATE_IDLE),
- mAsyncResult(UNKNOWN_ERROR),
- mSrcId(0),
- mSetSurfaceInProgress(false),
- mDurationUs(-1),
- mPositionUs(-1),
- mSeekInProgress(false),
- mPlayingTimeUs(0),
- mRebufferingTimeUs(0),
- mRebufferingEvents(0),
- mRebufferingAtExit(false),
- mLooper(new ALooper),
- mNuPlayer2Looper(new ALooper),
- mMediaClock(new MediaClock),
- mPlayer(new NuPlayer2(pid, uid, mMediaClock, context)),
- mPlayerFlags(0),
- mMetricsHandle(0),
- mPlayerVersion(0),
- mClientUid(uid),
- mAtEOS(false),
- mLooping(false),
- mAutoLoop(false) {
- ALOGD("NuPlayer2Driver(%p) created, clientPid(%d)", this, pid);
- mLooper->setName("NuPlayer2Driver Looper");
- mNuPlayer2Looper->setName("NuPlayer2 Looper");
-
- mMediaClock->init();
-
- // XXX: what version are we?
- // Ideally, this ticks with the apk version info for the APEX packaging
-
- // set up media metrics record
- mMetricsHandle = mediametrics_create(kKeyPlayer);
- mediametrics_setUid(mMetricsHandle, mClientUid);
- mediametrics_setInt64(mMetricsHandle, kPlayerVersion, mPlayerVersion);
-
- mNuPlayer2Looper->start(
- false, /* runOnCallingThread */
- true, /* canCallJava */
- PRIORITY_AUDIO);
-
- mNuPlayer2Looper->registerHandler(mPlayer);
-
- mPlayer->setDriver(this);
-}
-
-NuPlayer2Driver::~NuPlayer2Driver() {
- ALOGV("~NuPlayer2Driver(%p)", this);
- mNuPlayer2Looper->stop();
- mLooper->stop();
-
- // finalize any pending metrics, usually a no-op.
- updateMetrics("destructor");
- logMetrics("destructor");
-
- mediametrics_delete(mMetricsHandle);
-}
-
-status_t NuPlayer2Driver::initCheck() {
- mLooper->start(
- false, /* runOnCallingThread */
- true, /* canCallJava */
- PRIORITY_AUDIO);
-
- mLooper->registerHandler(this);
- return OK;
-}
-
-status_t NuPlayer2Driver::setDataSource(const sp<DataSourceDesc> &dsd) {
- ALOGV("setDataSource(%p)", this);
- Mutex::Autolock autoLock(mLock);
-
- if (mState != STATE_IDLE) {
- return INVALID_OPERATION;
- }
-
- mSrcId = dsd->mId;
- mState = STATE_SET_DATASOURCE_PENDING;
-
- mPlayer->setDataSourceAsync(dsd);
-
- while (mState == STATE_SET_DATASOURCE_PENDING) {
- mCondition.wait(mLock);
- }
-
- return mAsyncResult;
-}
-
-status_t NuPlayer2Driver::prepareNextDataSource(const sp<DataSourceDesc> &dsd) {
- ALOGV("prepareNextDataSource(%p)", this);
- Mutex::Autolock autoLock(mLock);
-
- mPlayer->prepareNextDataSourceAsync(dsd);
-
- return OK;
-}
-
-status_t NuPlayer2Driver::playNextDataSource(int64_t srcId) {
- ALOGV("playNextDataSource(%p)", this);
- Mutex::Autolock autoLock(mLock);
-
- mSrcId = srcId;
- mPlayer->playNextDataSource(srcId);
-
- return OK;
-}
-
-status_t NuPlayer2Driver::setVideoSurfaceTexture(const sp<ANativeWindowWrapper> &nww) {
- ALOGV("setVideoSurfaceTexture(%p)", this);
- Mutex::Autolock autoLock(mLock);
-
- if (mSetSurfaceInProgress) {
- return INVALID_OPERATION;
- }
-
- switch (mState) {
- case STATE_SET_DATASOURCE_PENDING:
- case STATE_RESET_IN_PROGRESS:
- return INVALID_OPERATION;
-
- default:
- break;
- }
-
- mSetSurfaceInProgress = true;
-
- mPlayer->setVideoSurfaceTextureAsync(nww);
-
- while (mSetSurfaceInProgress) {
- mCondition.wait(mLock);
- }
-
- return OK;
-}
-
-status_t NuPlayer2Driver::getBufferingSettings(BufferingSettings* buffering) {
- ALOGV("getBufferingSettings(%p)", this);
- {
- Mutex::Autolock autoLock(mLock);
- if (mState == STATE_IDLE) {
- return INVALID_OPERATION;
- }
- }
-
- return mPlayer->getBufferingSettings(buffering);
-}
-
-status_t NuPlayer2Driver::setBufferingSettings(const BufferingSettings& buffering) {
- ALOGV("setBufferingSettings(%p)", this);
- {
- Mutex::Autolock autoLock(mLock);
- if (mState == STATE_IDLE) {
- return INVALID_OPERATION;
- }
- }
-
- return mPlayer->setBufferingSettings(buffering);
-}
-
-status_t NuPlayer2Driver::prepareAsync() {
- ALOGV("prepareAsync(%p)", this);
- Mutex::Autolock autoLock(mLock);
-
- switch (mState) {
- case STATE_UNPREPARED:
- mState = STATE_PREPARING;
- mPlayer->prepareAsync();
- return OK;
- default:
- return INVALID_OPERATION;
- };
-}
-
-status_t NuPlayer2Driver::start() {
- ALOGD("start(%p), state is %d, eos is %d", this, mState, mAtEOS);
- Mutex::Autolock autoLock(mLock);
- return start_l();
-}
-
-status_t NuPlayer2Driver::start_l() {
- switch (mState) {
- case STATE_PAUSED:
- case STATE_PREPARED:
- {
- mPlayer->start();
- FALLTHROUGH_INTENDED;
- }
-
- case STATE_RUNNING:
- {
- if (mAtEOS) {
- mPlayer->rewind();
- mAtEOS = false;
- mPositionUs = -1;
- }
- break;
- }
-
- default:
- return INVALID_OPERATION;
- }
-
- mState = STATE_RUNNING;
-
- return OK;
-}
-
-status_t NuPlayer2Driver::pause() {
- ALOGD("pause(%p)", this);
- // The NuPlayerRenderer may get flushed if pause for long enough, e.g. the pause timeout tear
- // down for audio offload mode. If that happens, the NuPlayerRenderer will no longer know the
- // current position. So similar to seekTo, update |mPositionUs| to the pause position by calling
- // getCurrentPosition here.
- int64_t unused;
- getCurrentPosition(&unused);
-
- Mutex::Autolock autoLock(mLock);
-
- switch (mState) {
- case STATE_PAUSED:
- return OK;
-
- case STATE_PREPARED:
- case STATE_RUNNING:
- mState = STATE_PAUSED;
- mPlayer->pause();
- break;
-
- default:
- return INVALID_OPERATION;
- }
-
- return OK;
-}
-
-bool NuPlayer2Driver::isPlaying() {
- return mState == STATE_RUNNING && !mAtEOS;
-}
-
-status_t NuPlayer2Driver::setPlaybackSettings(const AudioPlaybackRate &rate) {
- status_t err = mPlayer->setPlaybackSettings(rate);
- if (err == OK) {
- // try to update position
- int64_t unused;
- getCurrentPosition(&unused);
- }
- return err;
-}
-
-status_t NuPlayer2Driver::getPlaybackSettings(AudioPlaybackRate *rate) {
- return mPlayer->getPlaybackSettings(rate);
-}
-
-status_t NuPlayer2Driver::setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) {
- return mPlayer->setSyncSettings(sync, videoFpsHint);
-}
-
-status_t NuPlayer2Driver::getSyncSettings(AVSyncSettings *sync, float *videoFps) {
- return mPlayer->getSyncSettings(sync, videoFps);
-}
-
-status_t NuPlayer2Driver::seekTo(int64_t msec, MediaPlayer2SeekMode mode) {
- ALOGD("seekTo(%p) (%lld ms, %d) at state %d", this, (long long)msec, mode, mState);
- Mutex::Autolock autoLock(mLock);
-
- int64_t seekTimeUs = msec * 1000LL;
-
- switch (mState) {
- case STATE_PREPARED:
- case STATE_PAUSED:
- case STATE_RUNNING:
- {
- mAtEOS = false;
- mSeekInProgress = true;
- mPlayer->seekToAsync(seekTimeUs, mode, true /* needNotify */);
- break;
- }
-
- default:
- return INVALID_OPERATION;
- }
-
- mPositionUs = seekTimeUs;
- return OK;
-}
-
-status_t NuPlayer2Driver::getCurrentPosition(int64_t *msec) {
- int64_t tempUs = 0;
- {
- Mutex::Autolock autoLock(mLock);
- if (mSeekInProgress || (mState == STATE_PAUSED && !mAtEOS)) {
- tempUs = (mPositionUs <= 0) ? 0 : mPositionUs;
- *msec = divRound(tempUs, (int64_t)(1000));
- return OK;
- }
- }
-
- status_t ret = mPlayer->getCurrentPosition(&tempUs);
-
- Mutex::Autolock autoLock(mLock);
- // We need to check mSeekInProgress here because mPlayer->seekToAsync is an async call, which
- // means getCurrentPosition can be called before seek is completed. Iow, renderer may return a
- // position value that's different the seek to position.
- if (ret != OK) {
- tempUs = (mPositionUs <= 0) ? 0 : mPositionUs;
- } else {
- mPositionUs = tempUs;
- }
- *msec = divRound(tempUs, (int64_t)(1000));
- return OK;
-}
-
-status_t NuPlayer2Driver::getDuration(int64_t *msec) {
- Mutex::Autolock autoLock(mLock);
-
- if (mDurationUs < 0) {
- return UNKNOWN_ERROR;
- }
-
- *msec = (mDurationUs + 500LL) / 1000;
-
- return OK;
-}
-
-void NuPlayer2Driver::updateMetrics(const char *where) {
- if (where == NULL) {
- where = "unknown";
- }
- ALOGV("updateMetrics(%p) from %s at state %d", this, where, mState);
-
- // gather the final stats for this record
- Vector<sp<AMessage>> trackStats;
- mPlayer->getStats(&trackStats);
-
- if (trackStats.size() > 0) {
- for (size_t i = 0; i < trackStats.size(); ++i) {
- const sp<AMessage> &stats = trackStats.itemAt(i);
-
- AString mime;
- stats->findString("mime", &mime);
-
- AString name;
- stats->findString("component-name", &name);
-
- if (mime.startsWith("video/")) {
- int32_t width, height;
- mediametrics_setCString(mMetricsHandle, kPlayerVMime, mime.c_str());
- if (!name.empty()) {
- mediametrics_setCString(mMetricsHandle, kPlayerVCodec, name.c_str());
- }
-
- if (stats->findInt32("width", &width)
- && stats->findInt32("height", &height)) {
- mediametrics_setInt32(mMetricsHandle, kPlayerWidth, width);
- mediametrics_setInt32(mMetricsHandle, kPlayerHeight, height);
- }
-
- int64_t numFramesTotal = 0;
- int64_t numFramesDropped = 0;
- stats->findInt64("frames-total", &numFramesTotal);
- stats->findInt64("frames-dropped-output", &numFramesDropped);
-
- mediametrics_setInt64(mMetricsHandle, kPlayerFrames, numFramesTotal);
- mediametrics_setInt64(mMetricsHandle, kPlayerFramesDropped, numFramesDropped);
-
- float frameRate = 0;
- if (stats->findFloat("frame-rate-output", &frameRate)) {
- mediametrics_setInt64(mMetricsHandle, kPlayerFrameRate, frameRate);
- }
-
- } else if (mime.startsWith("audio/")) {
- mediametrics_setCString(mMetricsHandle, kPlayerAMime, mime.c_str());
- if (!name.empty()) {
- mediametrics_setCString(mMetricsHandle, kPlayerACodec, name.c_str());
- }
- }
- }
- }
-
- // always provide duration and playing time, even if they have 0/unknown values.
-
- // getDuration() uses mLock for mutex -- careful where we use it.
- int64_t duration_ms = -1;
- getDuration(&duration_ms);
- mediametrics_setInt64(mMetricsHandle, kPlayerDuration, duration_ms);
-
- mediametrics_setInt64(mMetricsHandle, kPlayerPlaying, (mPlayingTimeUs+500)/1000 );
-
- if (mRebufferingEvents != 0) {
- mediametrics_setInt64(mMetricsHandle, kPlayerRebuffering, (mRebufferingTimeUs+500)/1000 );
- mediametrics_setInt32(mMetricsHandle, kPlayerRebufferingCount, mRebufferingEvents);
- mediametrics_setInt32(mMetricsHandle, kPlayerRebufferingAtExit, mRebufferingAtExit);
- }
-
- mediametrics_setCString(mMetricsHandle, kPlayerDataSourceType, mPlayer->getDataSourceType());
-}
-
-
-void NuPlayer2Driver::logMetrics(const char *where) {
- if (where == NULL) {
- where = "unknown";
- }
- ALOGV("logMetrics(%p) from %s at state %d", this, where, mState);
-
- if (mMetricsHandle == 0 || mediametrics_isEnabled() == false) {
- return;
- }
-
- // log only non-empty records
- // we always updateMetrics() before we get here
- // and that always injects 3 fields (duration, playing time, and
- // datasource) into the record.
- // So the canonical "empty" record has 3 elements in it.
- if (mediametrics_count(mMetricsHandle) > 3) {
- mediametrics_selfRecord(mMetricsHandle);
- // re-init in case we prepare() and start() again.
- mediametrics_delete(mMetricsHandle);
- mMetricsHandle = mediametrics_create(kKeyPlayer);
- mediametrics_setUid(mMetricsHandle, mClientUid);
- mediametrics_setInt64(mMetricsHandle, kPlayerVersion, mPlayerVersion);
- } else {
- ALOGV("did not have anything to record");
- }
-}
-
-status_t NuPlayer2Driver::reset() {
- ALOGD("reset(%p) at state %d", this, mState);
-
- updateMetrics("reset");
- logMetrics("reset");
-
- Mutex::Autolock autoLock(mLock);
-
- switch (mState) {
- case STATE_IDLE:
- return OK;
-
- case STATE_SET_DATASOURCE_PENDING:
- case STATE_RESET_IN_PROGRESS:
- return INVALID_OPERATION;
-
- case STATE_PREPARING:
- {
- notifyListener_l(mSrcId, MEDIA2_PREPARED);
- break;
- }
-
- default:
- break;
- }
-
- mState = STATE_RESET_IN_PROGRESS;
- mPlayer->resetAsync();
-
- while (mState == STATE_RESET_IN_PROGRESS) {
- mCondition.wait(mLock);
- }
-
- mDurationUs = -1;
- mPositionUs = -1;
- mLooping = false;
- mPlayingTimeUs = 0;
- mRebufferingTimeUs = 0;
- mRebufferingEvents = 0;
- mRebufferingAtExit = false;
-
- return OK;
-}
-
-status_t NuPlayer2Driver::notifyAt(int64_t mediaTimeUs) {
- ALOGV("notifyAt(%p), time:%lld", this, (long long)mediaTimeUs);
- return mPlayer->notifyAt(mediaTimeUs);
-}
-
-status_t NuPlayer2Driver::setLooping(int loop) {
- mLooping = loop != 0;
- return OK;
-}
-
-status_t NuPlayer2Driver::invoke(const PlayerMessage &request, PlayerMessage *response) {
- if (response == NULL) {
- ALOGE("reply is a NULL pointer");
- return BAD_VALUE;
- }
-
- RepeatedPtrField<const Value>::const_iterator it = request.values().cbegin();
- int32_t methodId = (it++)->int32_value();
-
- switch (methodId) {
- case MEDIA_PLAYER2_INVOKE_ID_SET_VIDEO_SCALING_MODE:
- {
- int mode = (it++)->int32_value();
- return mPlayer->setVideoScalingMode(mode);
- }
-
- case MEDIA_PLAYER2_INVOKE_ID_GET_TRACK_INFO:
- {
- int64_t srcId = (it++)->int64_value();
- return mPlayer->getTrackInfo(srcId, response);
- }
-
- case MEDIA_PLAYER2_INVOKE_ID_SELECT_TRACK:
- {
- int64_t srcId = (it++)->int64_value();
- int trackIndex = (it++)->int32_value();
- int64_t msec = 0;
- // getCurrentPosition should always return OK
- getCurrentPosition(&msec);
- return mPlayer->selectTrack(srcId, trackIndex, true /* select */, msec * 1000LL);
- }
-
- case MEDIA_PLAYER2_INVOKE_ID_UNSELECT_TRACK:
- {
- int64_t srcId = (it++)->int64_value();
- int trackIndex = (it++)->int32_value();
- return mPlayer->selectTrack(
- srcId, trackIndex, false /* select */, 0xdeadbeef /* not used */);
- }
-
- case MEDIA_PLAYER2_INVOKE_ID_GET_SELECTED_TRACK:
- {
- int64_t srcId = (it++)->int64_value();
- int32_t type = (it++)->int32_value();
- return mPlayer->getSelectedTrack(srcId, type, response);
- }
-
- default:
- {
- return INVALID_OPERATION;
- }
- }
-}
-
-void NuPlayer2Driver::setAudioSink(const sp<AudioSink> &audioSink) {
- mPlayer->setAudioSink(audioSink);
- mAudioSink = audioSink;
-}
-
-status_t NuPlayer2Driver::setParameter(
- int /* key */, const Parcel & /* request */) {
- return INVALID_OPERATION;
-}
-
-status_t NuPlayer2Driver::getParameter(int key __unused, Parcel *reply __unused) {
- return INVALID_OPERATION;
-}
-
-status_t NuPlayer2Driver::getMetrics(char **buffer, size_t *length) {
- updateMetrics("api");
- if (mediametrics_getAttributes(mMetricsHandle, buffer, length))
- return OK;
- else
- return FAILED_TRANSACTION;
-}
-
-void NuPlayer2Driver::notifyResetComplete(int64_t /* srcId */) {
- ALOGD("notifyResetComplete(%p)", this);
- Mutex::Autolock autoLock(mLock);
-
- CHECK_EQ(mState, STATE_RESET_IN_PROGRESS);
- mState = STATE_IDLE;
- mCondition.broadcast();
-}
-
-void NuPlayer2Driver::notifySetSurfaceComplete(int64_t /* srcId */) {
- ALOGV("notifySetSurfaceComplete(%p)", this);
- Mutex::Autolock autoLock(mLock);
-
- CHECK(mSetSurfaceInProgress);
- mSetSurfaceInProgress = false;
-
- mCondition.broadcast();
-}
-
-void NuPlayer2Driver::notifyDuration(int64_t /* srcId */, int64_t durationUs) {
- Mutex::Autolock autoLock(mLock);
- mDurationUs = durationUs;
-}
-
-void NuPlayer2Driver::notifyMorePlayingTimeUs(int64_t /* srcId */, int64_t playingUs) {
- Mutex::Autolock autoLock(mLock);
- mPlayingTimeUs += playingUs;
-}
-
-void NuPlayer2Driver::notifyMoreRebufferingTimeUs(int64_t /* srcId */, int64_t rebufferingUs) {
- Mutex::Autolock autoLock(mLock);
- mRebufferingTimeUs += rebufferingUs;
- mRebufferingEvents++;
-}
-
-void NuPlayer2Driver::notifyRebufferingWhenExit(int64_t /* srcId */, bool status) {
- Mutex::Autolock autoLock(mLock);
- mRebufferingAtExit = status;
-}
-
-void NuPlayer2Driver::notifySeekComplete(int64_t srcId) {
- ALOGV("notifySeekComplete(%p)", this);
- Mutex::Autolock autoLock(mLock);
- mSeekInProgress = false;
- notifyListener_l(srcId, MEDIA2_SEEK_COMPLETE);
-}
-
-status_t NuPlayer2Driver::dump(
- int fd, const Vector<String16> & /* args */) const {
-
- Vector<sp<AMessage> > trackStats;
- mPlayer->getStats(&trackStats);
-
- AString logString(" NuPlayer2\n");
- char buf[256] = {0};
-
- bool locked = false;
- for (int i = 0; i < kDumpLockRetries; ++i) {
- if (mLock.tryLock() == NO_ERROR) {
- locked = true;
- break;
- }
- usleep(kDumpLockSleepUs);
- }
-
- if (locked) {
- snprintf(buf, sizeof(buf), " state(%d), atEOS(%d), looping(%d), autoLoop(%d)\n",
- mState, mAtEOS, mLooping, mAutoLoop);
- mLock.unlock();
- } else {
- snprintf(buf, sizeof(buf), " NPD(%p) lock is taken\n", this);
- }
- logString.append(buf);
-
- for (size_t i = 0; i < trackStats.size(); ++i) {
- const sp<AMessage> &stats = trackStats.itemAt(i);
-
- AString mime;
- if (stats->findString("mime", &mime)) {
- snprintf(buf, sizeof(buf), " mime(%s)\n", mime.c_str());
- logString.append(buf);
- }
-
- AString name;
- if (stats->findString("component-name", &name)) {
- snprintf(buf, sizeof(buf), " decoder(%s)\n", name.c_str());
- logString.append(buf);
- }
-
- if (mime.startsWith("video/")) {
- int32_t width, height;
- if (stats->findInt32("width", &width)
- && stats->findInt32("height", &height)) {
- snprintf(buf, sizeof(buf), " resolution(%d x %d)\n", width, height);
- logString.append(buf);
- }
-
- int64_t numFramesTotal = 0;
- int64_t numFramesDropped = 0;
-
- stats->findInt64("frames-total", &numFramesTotal);
- stats->findInt64("frames-dropped-output", &numFramesDropped);
- snprintf(buf, sizeof(buf), " numFramesTotal(%lld), numFramesDropped(%lld), "
- "percentageDropped(%.2f%%)\n",
- (long long)numFramesTotal,
- (long long)numFramesDropped,
- numFramesTotal == 0
- ? 0.0 : (double)(numFramesDropped * 100) / numFramesTotal);
- logString.append(buf);
- }
- }
-
- ALOGI("%s", logString.c_str());
-
- if (fd >= 0) {
- FILE *out = fdopen(dup(fd), "w");
- fprintf(out, "%s", logString.c_str());
- fclose(out);
- out = NULL;
- }
-
- return OK;
-}
-
-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);
- sp<PlayerMessageWrapper> in;
- sp<RefBase> obj;
- if (msg->findObject("obj", &obj) && obj != NULL) {
- in = static_cast<PlayerMessageWrapper *>(obj.get());
- }
- sendEvent(srcId, msgId, ext1, ext2, (in == NULL ? NULL : in->getPlayerMessage()));
- break;
- }
- default:
- break;
- }
-}
-
-void NuPlayer2Driver::notifyListener(
- int64_t srcId, int msg, int ext1, int ext2, const PlayerMessage *in) {
- Mutex::Autolock autoLock(mLock);
- notifyListener_l(srcId, msg, ext1, ext2, in);
-}
-
-void NuPlayer2Driver::notifyListener_l(
- int64_t srcId, int msg, int ext1, int ext2, const PlayerMessage *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->ByteSize()), mAutoLoop, mLooping);
- if (srcId == mSrcId) {
- switch (msg) {
- case MEDIA2_PLAYBACK_COMPLETE:
- {
- if (mState != STATE_RESET_IN_PROGRESS) {
- if (mAutoLoop) {
- audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
- if (mAudioSink != NULL) {
- streamType = mAudioSink->getAudioStreamType();
- }
- if (streamType == AUDIO_STREAM_NOTIFICATION) {
- ALOGW("disabling auto-loop for notification");
- mAutoLoop = false;
- }
- }
- if (mLooping || mAutoLoop) {
- mPlayer->rewind();
- if (mAudioSink != NULL) {
- // The renderer has stopped the sink at the end in order to play out
- // the last little bit of audio. In looping mode, we need to restart it.
- mAudioSink->start();
- }
-
- sp<AMessage> notify = new AMessage(kWhatNotifyListener, this);
- notify->setInt64("srcId", srcId);
- notify->setInt32("messageId", MEDIA2_INFO);
- notify->setInt32("ext1", MEDIA2_INFO_DATA_SOURCE_REPEAT);
- notify->post();
- return;
- }
- if (property_get_bool("persist.debug.sf.stats", false)) {
- Vector<String16> args;
- dump(-1, args);
- }
- mPlayer->pause();
- mState = STATE_PAUSED;
- }
- FALLTHROUGH_INTENDED;
- }
-
- case MEDIA2_ERROR:
- {
- // when we have an error, add it to the analytics for this playback.
- // ext1 is our primary 'error type' value. Only add ext2 when non-zero.
- // [test against msg is due to fall through from previous switch value]
- if (msg == MEDIA2_ERROR) {
- mediametrics_setInt32(mMetricsHandle, kPlayerError, ext1);
- if (ext2 != 0) {
- mediametrics_setInt32(mMetricsHandle, kPlayerErrorCode, ext2);
- }
- mediametrics_setCString(mMetricsHandle, kPlayerErrorState, stateString(mState).c_str());
- }
- mAtEOS = true;
- break;
- }
-
- default:
- break;
- }
- }
-
- sp<AMessage> notify = new AMessage(kWhatNotifyListener, this);
- notify->setInt64("srcId", srcId);
- notify->setInt32("messageId", msg);
- notify->setInt32("ext1", ext1);
- notify->setInt32("ext2", ext2);
- notify->setObject("obj", PlayerMessageWrapper::Create((PlayerMessage*)in));
- notify->post();
-}
-
-void NuPlayer2Driver::notifySetDataSourceCompleted(int64_t /* srcId */, status_t err) {
- Mutex::Autolock autoLock(mLock);
-
- CHECK_EQ(mState, STATE_SET_DATASOURCE_PENDING);
-
- mAsyncResult = err;
- mState = (err == OK) ? STATE_UNPREPARED : STATE_IDLE;
- mCondition.broadcast();
-}
-
-void NuPlayer2Driver::notifyPrepareCompleted(int64_t srcId, status_t err) {
- ALOGV("notifyPrepareCompleted %d", err);
-
- Mutex::Autolock autoLock(mLock);
-
- if (srcId != mSrcId) {
- if (err == OK) {
- notifyListener_l(srcId, MEDIA2_PREPARED);
- } else {
- notifyListener_l(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
- }
- return;
- }
-
- if (mState != STATE_PREPARING) {
- // We were preparing asynchronously when the client called
- // reset(), we sent a premature "prepared" notification and
- // then initiated the reset. This notification is stale.
- CHECK(mState == STATE_RESET_IN_PROGRESS || mState == STATE_IDLE);
- return;
- }
-
- CHECK_EQ(mState, STATE_PREPARING);
-
- mAsyncResult = err;
-
- if (err == OK) {
- // update state before notifying client, so that if client calls back into NuPlayer2Driver
- // in response, NuPlayer2Driver has the right state
- mState = STATE_PREPARED;
- notifyListener_l(srcId, MEDIA2_PREPARED);
- } else {
- mState = STATE_UNPREPARED;
- notifyListener_l(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
- }
-
- sp<MetaData> meta = mPlayer->getFileMeta();
- int32_t loop;
- if (meta != NULL
- && meta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
- mAutoLoop = true;
- }
-
- mCondition.broadcast();
-}
-
-void NuPlayer2Driver::notifyFlagsChanged(int64_t /* srcId */, uint32_t flags) {
- Mutex::Autolock autoLock(mLock);
-
- mPlayerFlags = flags;
-}
-
-// Modular DRM
-status_t NuPlayer2Driver::prepareDrm(
- int64_t srcId, const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId)
-{
- ALOGV("prepareDrm(%p) state: %d", this, mState);
-
- // leaving the state verification for mediaplayer.cpp
- status_t ret = mPlayer->prepareDrm(srcId, uuid, drmSessionId);
-
- ALOGV("prepareDrm ret: %d", ret);
-
- return ret;
-}
-
-status_t NuPlayer2Driver::releaseDrm(int64_t srcId)
-{
- ALOGV("releaseDrm(%p) state: %d", this, mState);
-
- // leaving the state verification for mediaplayer.cpp
- status_t ret = mPlayer->releaseDrm(srcId);
-
- ALOGV("releaseDrm ret: %d", ret);
-
- return ret;
-}
-
-std::string NuPlayer2Driver::stateString(State state) {
- const char *rval = NULL;
- char rawbuffer[16]; // allows "%d"
-
- switch (state) {
- case STATE_IDLE: rval = "IDLE"; break;
- case STATE_SET_DATASOURCE_PENDING: rval = "SET_DATASOURCE_PENDING"; break;
- case STATE_UNPREPARED: rval = "UNPREPARED"; break;
- case STATE_PREPARING: rval = "PREPARING"; break;
- case STATE_PREPARED: rval = "PREPARED"; break;
- case STATE_RUNNING: rval = "RUNNING"; break;
- case STATE_PAUSED: rval = "PAUSED"; break;
- case STATE_RESET_IN_PROGRESS: rval = "RESET_IN_PROGRESS"; break;
- default:
- // yes, this buffer is shared and vulnerable to races
- snprintf(rawbuffer, sizeof(rawbuffer), "%d", state);
- rval = rawbuffer;
- break;
- }
-
- return rval;
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h
deleted file mode 100644
index c97e247..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <mediaplayer2/MediaPlayer2Interface.h>
-
-#include <media/MediaMetrics.h>
-#include <media/stagefright/foundation/ABase.h>
-#include <mediaplayer2/JObjectHolder.h>
-
-namespace android {
-
-struct ALooper;
-struct MediaClock;
-struct NuPlayer2;
-
-struct NuPlayer2Driver : public MediaPlayer2Interface {
- explicit NuPlayer2Driver(pid_t pid, uid_t uid, const sp<JObjectHolder> &context);
-
- virtual status_t initCheck() override;
-
- virtual status_t setDataSource(const sp<DataSourceDesc> &dsd) override;
- virtual status_t prepareNextDataSource(const sp<DataSourceDesc> &dsd) override;
- virtual status_t playNextDataSource(int64_t srcId) override;
-
- virtual status_t setVideoSurfaceTexture(const sp<ANativeWindowWrapper> &nww) override;
-
- virtual status_t getBufferingSettings(
- BufferingSettings* buffering /* nonnull */) override;
- virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
-
- virtual status_t prepareAsync() override;
- virtual status_t start() override;
- virtual status_t pause() override;
- virtual bool isPlaying() override;
- virtual status_t setPlaybackSettings(const AudioPlaybackRate &rate) override;
- virtual status_t getPlaybackSettings(AudioPlaybackRate *rate) override;
- virtual status_t setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) override;
- virtual status_t getSyncSettings(AVSyncSettings *sync, float *videoFps) override;
- virtual status_t seekTo(
- int64_t msec,
- MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC) override;
- virtual status_t getCurrentPosition(int64_t *msec) override;
- virtual status_t getDuration(int64_t *msec) override;
- virtual status_t reset() override;
- virtual status_t notifyAt(int64_t mediaTimeUs) override;
- virtual status_t setLooping(int loop) override;
- virtual status_t invoke(const PlayerMessage &request, PlayerMessage *response) override;
- virtual void setAudioSink(const sp<AudioSink> &audioSink) override;
- virtual status_t setParameter(int key, const Parcel &request) override;
- virtual status_t getParameter(int key, Parcel *reply) override;
- virtual status_t getMetrics(char **buf, size_t *length) override;
-
- virtual status_t dump(int fd, const Vector<String16> &args) const override;
-
- virtual void onMessageReceived(const sp<AMessage> &msg) override;
-
- 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 notifyListener(int64_t srcId, int msg, int ext1 = 0, int ext2 = 0,
- const PlayerMessage *in = NULL);
- void notifyFlagsChanged(int64_t srcId, uint32_t flags);
-
- // Modular DRM
- virtual status_t prepareDrm(
- int64_t srcId, const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId);
- virtual status_t releaseDrm(int64_t srcId);
-
-protected:
- virtual ~NuPlayer2Driver();
-
-private:
- enum State {
- STATE_IDLE,
- STATE_SET_DATASOURCE_PENDING,
- STATE_UNPREPARED,
- STATE_PREPARING,
- STATE_PREPARED,
- STATE_RUNNING,
- STATE_PAUSED,
- STATE_RESET_IN_PROGRESS,
- };
-
- std::string stateString(State state);
-
- enum {
- kWhatNotifyListener,
- };
-
- mutable Mutex mLock;
- Condition mCondition;
-
- State mState;
-
- status_t mAsyncResult;
-
- // The following are protected through "mLock"
- // >>>
- int64_t mSrcId;
- bool mSetSurfaceInProgress;
- int64_t mDurationUs;
- int64_t mPositionUs;
- bool mSeekInProgress;
- int64_t mPlayingTimeUs;
- int64_t mRebufferingTimeUs;
- int32_t mRebufferingEvents;
- bool mRebufferingAtExit;
- // <<<
-
- sp<ALooper> mLooper;
- sp<ALooper> mNuPlayer2Looper;
- const sp<MediaClock> mMediaClock;
- const sp<NuPlayer2> mPlayer;
- sp<AudioSink> mAudioSink;
- uint32_t mPlayerFlags;
-
- mediametrics_handle_t mMetricsHandle;
- int64_t mPlayerVersion;
- uid_t mClientUid;
-
- bool mAtEOS;
- bool mLooping;
- bool mAutoLoop;
-
- void updateMetrics(const char *where);
- void logMetrics(const char *where);
-
- status_t start_l();
- void notifyListener_l(int64_t srcId, int msg, int ext1 = 0, int ext2 = 0,
- const PlayerMessage *in = NULL);
-
- DISALLOW_EVIL_CONSTRUCTORS(NuPlayer2Driver);
-};
-
-} // namespace android
-
-
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.cpp
deleted file mode 100644
index f41a431..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.cpp
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NuPlayer2Drm"
-
-#include "NuPlayer2Drm.h"
-
-#include <media/NdkWrapper.h>
-#include <utils/Log.h>
-#include <sstream>
-
-namespace android {
-
-Vector<DrmUUID> NuPlayer2Drm::parsePSSH(const void *pssh, size_t psshsize)
-{
- Vector<DrmUUID> drmSchemes, empty;
- const int DATALEN_SIZE = 4;
-
- // the format of the buffer is 1 or more of:
- // {
- // 16 byte uuid
- // 4 byte data length N
- // N bytes of data
- // }
- // Determine the number of entries in the source data.
- // Since we got the data from stagefright, we trust it is valid and properly formatted.
-
- const uint8_t *data = (const uint8_t*)pssh;
- size_t len = psshsize;
- size_t numentries = 0;
- while (len > 0) {
- if (len < DrmUUID::UUID_SIZE) {
- ALOGE("ParsePSSH: invalid PSSH data");
- return empty;
- }
-
- const uint8_t *uuidPtr = data;
-
- // skip uuid
- data += DrmUUID::UUID_SIZE;
- len -= DrmUUID::UUID_SIZE;
-
- // get data length
- if (len < DATALEN_SIZE) {
- ALOGE("ParsePSSH: invalid PSSH data");
- return empty;
- }
-
- uint32_t datalen = *((uint32_t*)data);
- data += DATALEN_SIZE;
- len -= DATALEN_SIZE;
-
- if (len < datalen) {
- ALOGE("ParsePSSH: invalid PSSH data");
- return empty;
- }
-
- // skip the data
- data += datalen;
- len -= datalen;
-
- DrmUUID _uuid(uuidPtr);
- drmSchemes.add(_uuid);
-
- ALOGV("ParsePSSH[%zu]: %s: %s", numentries,
- _uuid.toHexString().string(),
- DrmUUID::arrayToHex(data, datalen).string()
- );
-
- numentries++;
- }
-
- return drmSchemes;
-}
-
-Vector<DrmUUID> NuPlayer2Drm::getSupportedDrmSchemes(const void *pssh, size_t psshsize)
-{
- Vector<DrmUUID> psshDRMs = parsePSSH(pssh, psshsize);
-
- Vector<DrmUUID> supportedDRMs;
- for (size_t i = 0; i < psshDRMs.size(); i++) {
- DrmUUID uuid = psshDRMs[i];
- if (AMediaDrmWrapper::isCryptoSchemeSupported(uuid.ptr(), NULL)) {
- supportedDRMs.add(uuid);
- }
- }
-
- ALOGV("getSupportedDrmSchemes: psshDRMs: %zu supportedDRMs: %zu",
- psshDRMs.size(), supportedDRMs.size());
-
- return supportedDRMs;
-}
-
-sp<ABuffer> NuPlayer2Drm::retrieveDrmInfo(const void *pssh, uint32_t psshsize)
-{
- std::ostringstream buf;
-
- // 1) PSSH bytes
- buf.write(reinterpret_cast<const char *>(&psshsize), sizeof(psshsize));
- buf.write(reinterpret_cast<const char *>(pssh), psshsize);
-
- ALOGV("retrieveDrmInfo: MEDIA2_DRM_INFO PSSH: size: %u %s", psshsize,
- DrmUUID::arrayToHex((uint8_t*)pssh, psshsize).string());
-
- // 2) supportedDRMs
- Vector<DrmUUID> supportedDRMs = getSupportedDrmSchemes(pssh, psshsize);
- uint32_t n = supportedDRMs.size();
- buf.write(reinterpret_cast<char *>(&n), sizeof(n));
- for (size_t i = 0; i < n; i++) {
- DrmUUID uuid = supportedDRMs[i];
- buf.write(reinterpret_cast<const char *>(&n), sizeof(n));
- buf.write(reinterpret_cast<const char *>(uuid.ptr()), DrmUUID::UUID_SIZE);
-
- ALOGV("retrieveDrmInfo: MEDIA2_DRM_INFO supportedScheme[%zu] %s", i,
- uuid.toHexString().string());
- }
-
- sp<ABuffer> drmInfoBuffer = ABuffer::CreateAsCopy(buf.str().c_str(), buf.tellp());
- return drmInfoBuffer;
-}
-
-status_t NuPlayer2Drm::retrieveDrmInfo(PsshInfo *psshInfo, PlayerMessage *playerMsg)
-{
- std::ostringstream pssh, drmInfo;
-
- // 0) Generate PSSH bytes
- for (size_t i = 0; i < psshInfo->numentries; i++) {
- PsshEntry *entry = &psshInfo->entries[i];
- uint32_t datalen = entry->datalen;
- pssh.write(reinterpret_cast<const char *>(&entry->uuid), sizeof(entry->uuid));
- pssh.write(reinterpret_cast<const char *>(&datalen), sizeof(datalen));
- pssh.write(reinterpret_cast<const char *>(entry->data), datalen);
- }
-
- uint32_t psshSize = pssh.tellp();
- std::string psshBase = pssh.str();
- const auto* psshPtr = reinterpret_cast<const uint8_t*>(psshBase.c_str());
- ALOGV("retrieveDrmInfo: MEDIA_DRM_INFO PSSH: size: %u %s", psshSize,
- DrmUUID::arrayToHex(psshPtr, psshSize).string());
-
- // 1) Write PSSH bytes
- playerMsg->add_values()->set_bytes_value(
- reinterpret_cast<const char *>(pssh.str().c_str()), psshSize);
-
- // 2) Write supportedDRMs
- uint32_t numentries = psshInfo->numentries;
- playerMsg->add_values()->set_int32_value(numentries);
- for (size_t i = 0; i < numentries; i++) {
- PsshEntry *entry = &psshInfo->entries[i];
- playerMsg->add_values()->set_bytes_value(
- reinterpret_cast<const char *>(&entry->uuid), sizeof(entry->uuid));
- ALOGV("retrieveDrmInfo: MEDIA_DRM_INFO supportedScheme[%zu] %s", i,
- DrmUUID::arrayToHex((const uint8_t*)&entry->uuid, sizeof(AMediaUUID)).string());
- }
- return OK;
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.h
deleted file mode 100644
index 968d1be..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NUPLAYER2_DRM_H_
-#define NUPLAYER2_DRM_H_
-
-#include <media/NdkMediaExtractor.h>
-#include <media/stagefright/foundation/ABuffer.h>
-
-#include <utils/String8.h>
-#include <utils/Vector.h>
-
-#include "mediaplayer2.pb.h"
-
-using android::media::MediaPlayer2Proto::PlayerMessage;
-
-namespace android {
-
- struct DrmUUID {
- static const int UUID_SIZE = 16;
-
- DrmUUID() {
- memset(this->uuid, 0, sizeof(uuid));
- }
-
- // to allow defining Vector/KeyedVector of UUID type
- DrmUUID(const DrmUUID &a) {
- memcpy(this->uuid, a.uuid, sizeof(uuid));
- }
-
- // to allow defining Vector/KeyedVector of UUID type
- DrmUUID(const uint8_t uuid_in[UUID_SIZE]) {
- memcpy(this->uuid, uuid_in, sizeof(uuid));
- }
-
- const uint8_t *ptr() const {
- return uuid;
- }
-
- String8 toHexString() const {
- return arrayToHex(uuid, UUID_SIZE);
- }
-
- static String8 toHexString(const uint8_t uuid_in[UUID_SIZE]) {
- return arrayToHex(uuid_in, UUID_SIZE);
- }
-
- static String8 arrayToHex(const uint8_t *array, int bytes) {
- String8 result;
- for (int i = 0; i < bytes; i++) {
- result.appendFormat("%02x", array[i]);
- }
-
- return result;
- }
-
- protected:
- uint8_t uuid[UUID_SIZE];
- };
-
-
- struct NuPlayer2Drm {
-
- // static helpers - internal
-
- protected:
- static Vector<DrmUUID> parsePSSH(const void *pssh, size_t psshsize);
- static Vector<DrmUUID> getSupportedDrmSchemes(const void *pssh, size_t psshsize);
-
- // static helpers - public
-
- public:
- static sp<ABuffer> retrieveDrmInfo(const void *pssh, uint32_t psshsize);
- static status_t retrieveDrmInfo(PsshInfo *, PlayerMessage *);
-
- }; // NuPlayer2Drm
-
-} // android
-
-#endif //NUPLAYER2_DRM_H_
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
deleted file mode 100644
index fd459df..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
+++ /dev/null
@@ -1,2096 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NuPlayer2Renderer"
-#include <utils/Log.h>
-
-#include "JWakeLock.h"
-#include "NuPlayer2Renderer.h"
-#include <algorithm>
-#include <cutils/properties.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/foundation/AUtils.h>
-#include <media/stagefright/MediaClock.h>
-#include <media/stagefright/MediaCodecConstants.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/Utils.h>
-#include <media/stagefright/VideoFrameScheduler2.h>
-#include <media/MediaCodecBuffer.h>
-
-#include <inttypes.h>
-
-namespace android {
-
-/*
- * Example of common configuration settings in shell script form
-
- #Turn offload audio off (use PCM for Play Music) -- AudioPolicyManager
- adb shell setprop audio.offload.disable 1
-
- #Allow offload audio with video (requires offloading to be enabled) -- AudioPolicyManager
- adb shell setprop audio.offload.video 1
-
- #Use audio callbacks for PCM data
- adb shell setprop media.stagefright.audio.cbk 1
-
- #Use deep buffer for PCM data with video (it is generally enabled for audio-only)
- adb shell setprop media.stagefright.audio.deep 1
-
- #Set size of buffers for pcm audio sink in msec (example: 1000 msec)
- adb shell setprop media.stagefright.audio.sink 1000
-
- * These configurations take effect for the next track played (not the current track).
- */
-
-static inline bool getUseAudioCallbackSetting() {
- return property_get_bool("media.stagefright.audio.cbk", false /* default_value */);
-}
-
-static inline int32_t getAudioSinkPcmMsSetting() {
- return property_get_int32(
- "media.stagefright.audio.sink", 500 /* default_value */);
-}
-
-// Maximum time in paused state when offloading audio decompression. When elapsed, the AudioSink
-// is closed to allow the audio DSP to power down.
-static const int64_t kOffloadPauseMaxUs = 10000000LL;
-
-// Maximum allowed delay from AudioSink, 1.5 seconds.
-static const int64_t kMaxAllowedAudioSinkDelayUs = 1500000LL;
-
-static const int64_t kMinimumAudioClockUpdatePeriodUs = 20 /* msec */ * 1000;
-
-// Default video frame display duration when only video exists.
-// Used to set max media time in MediaClock.
-static const int64_t kDefaultVideoFrameIntervalUs = 100000LL;
-
-// static
-const NuPlayer2::Renderer::PcmInfo NuPlayer2::Renderer::AUDIO_PCMINFO_INITIALIZER = {
- AUDIO_CHANNEL_NONE,
- AUDIO_OUTPUT_FLAG_NONE,
- AUDIO_FORMAT_INVALID,
- 0, // mNumChannels
- 0 // mSampleRate
-};
-
-// static
-const int64_t NuPlayer2::Renderer::kMinPositionUpdateDelayUs = 100000LL;
-
-static audio_format_t constexpr audioFormatFromEncoding(int32_t pcmEncoding) {
- switch (pcmEncoding) {
- case kAudioEncodingPcmFloat:
- return AUDIO_FORMAT_PCM_FLOAT;
- case kAudioEncodingPcm16bit:
- return AUDIO_FORMAT_PCM_16_BIT;
- case kAudioEncodingPcm8bit:
- return AUDIO_FORMAT_PCM_8_BIT; // TODO: do we want to support this?
- default:
- ALOGE("%s: Invalid encoding: %d", __func__, pcmEncoding);
- return AUDIO_FORMAT_INVALID;
- }
-}
-
-NuPlayer2::Renderer::Renderer(
- const sp<MediaPlayer2Interface::AudioSink> &sink,
- const sp<MediaClock> &mediaClock,
- const sp<AMessage> ¬ify,
- const sp<JObjectHolder> &context,
- uint32_t flags)
- : mAudioSink(sink),
- mUseVirtualAudioSink(false),
- mNotify(notify),
- mFlags(flags),
- mNumFramesWritten(0),
- mDrainAudioQueuePending(false),
- mDrainVideoQueuePending(false),
- mAudioQueueGeneration(0),
- mVideoQueueGeneration(0),
- mAudioDrainGeneration(0),
- mVideoDrainGeneration(0),
- mAudioEOSGeneration(0),
- mMediaClock(mediaClock),
- mPlaybackSettings(AUDIO_PLAYBACK_RATE_DEFAULT),
- mAudioFirstAnchorTimeMediaUs(-1),
- mAnchorTimeMediaUs(-1),
- mAnchorNumFramesWritten(-1),
- mVideoLateByUs(0LL),
- mNextVideoTimeMediaUs(-1),
- mHasAudio(false),
- mHasVideo(false),
- mNotifyCompleteAudio(false),
- mNotifyCompleteVideo(false),
- mSyncQueues(false),
- mPaused(true),
- mPauseDrainAudioAllowedUs(0),
- mVideoSampleReceived(false),
- mVideoRenderingStarted(false),
- mVideoRenderingStartGeneration(0),
- mAudioRenderingStartGeneration(0),
- mRenderingDataDelivered(false),
- mNextAudioClockUpdateTimeUs(-1),
- mLastAudioMediaTimeUs(-1),
- mAudioOffloadPauseTimeoutGeneration(0),
- mAudioTornDown(false),
- mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER),
- mCurrentPcmInfo(AUDIO_PCMINFO_INITIALIZER),
- mTotalBuffersQueued(0),
- mLastAudioBufferDrained(0),
- mUseAudioCallback(false),
- mWakeLock(new JWakeLock(context)) {
- CHECK(mediaClock != NULL);
- mMediaClock->setPlaybackRate(mPlaybackSettings.mSpeed);
-}
-
-NuPlayer2::Renderer::~Renderer() {
- if (offloadingAudio()) {
- mAudioSink->stop();
- mAudioSink->flush();
- mAudioSink->close();
- }
-
- // Try to avoid racing condition in case callback is still on.
- Mutex::Autolock autoLock(mLock);
- if (mUseAudioCallback) {
- flushQueue(&mAudioQueue);
- flushQueue(&mVideoQueue);
- }
- mWakeLock.clear();
- mVideoScheduler.clear();
- mNotify.clear();
- mAudioSink.clear();
-}
-
-void NuPlayer2::Renderer::queueBuffer(
- bool audio,
- const sp<MediaCodecBuffer> &buffer,
- const sp<AMessage> ¬ifyConsumed) {
- sp<AMessage> msg = new AMessage(kWhatQueueBuffer, this);
- msg->setInt32("queueGeneration", getQueueGeneration(audio));
- msg->setInt32("audio", static_cast<int32_t>(audio));
- msg->setObject("buffer", buffer);
- msg->setMessage("notifyConsumed", notifyConsumed);
- msg->post();
-}
-
-void NuPlayer2::Renderer::queueEOS(bool audio, status_t finalResult) {
- CHECK_NE(finalResult, (status_t)OK);
-
- sp<AMessage> msg = new AMessage(kWhatQueueEOS, this);
- msg->setInt32("queueGeneration", getQueueGeneration(audio));
- msg->setInt32("audio", static_cast<int32_t>(audio));
- msg->setInt32("finalResult", finalResult);
- msg->post();
-}
-
-status_t NuPlayer2::Renderer::setPlaybackSettings(const AudioPlaybackRate &rate) {
- sp<AMessage> msg = new AMessage(kWhatConfigPlayback, this);
- writeToAMessage(msg, rate);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- }
- return err;
-}
-
-status_t NuPlayer2::Renderer::onConfigPlayback(const AudioPlaybackRate &rate /* sanitized */) {
- if (rate.mSpeed <= 0.f) {
- ALOGW("playback rate cannot be %f", rate.mSpeed);
- return BAD_VALUE;
- }
-
- if (mAudioSink != NULL && mAudioSink->ready()) {
- status_t err = mAudioSink->setPlaybackRate(rate);
- if (err != OK) {
- ALOGW("failed to get playback rate from audio sink, err(%d)", err);
- return err;
- }
- }
- mPlaybackSettings = rate;
- mMediaClock->setPlaybackRate(mPlaybackSettings.mSpeed);
- return OK;
-}
-
-status_t NuPlayer2::Renderer::getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) {
- sp<AMessage> msg = new AMessage(kWhatGetPlaybackSettings, this);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- if (err == OK) {
- readFromAMessage(response, rate);
- }
- }
- return err;
-}
-
-status_t NuPlayer2::Renderer::onGetPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) {
- if (mAudioSink != NULL && mAudioSink->ready()) {
- status_t err = mAudioSink->getPlaybackRate(rate);
- if (err == OK) {
- if (!isAudioPlaybackRateEqual(*rate, mPlaybackSettings)) {
- ALOGW("correcting mismatch in internal/external playback rate, %f vs %f",
- rate->mSpeed, mPlaybackSettings.mSpeed);
- }
- // get playback settings used by audiosink, as it may be
- // slightly off due to audiosink not taking small changes.
- mPlaybackSettings = *rate;
- }
- return err;
- }
- *rate = mPlaybackSettings;
- return OK;
-}
-
-status_t NuPlayer2::Renderer::setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) {
- sp<AMessage> msg = new AMessage(kWhatConfigSync, this);
- writeToAMessage(msg, sync, videoFpsHint);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- }
- return err;
-}
-
-status_t NuPlayer2::Renderer::onConfigSync(const AVSyncSettings &sync, float videoFpsHint __unused) {
- if (sync.mSource != AVSYNC_SOURCE_DEFAULT) {
- return BAD_VALUE;
- }
- // TODO: support sync sources
- return INVALID_OPERATION;
-}
-
-status_t NuPlayer2::Renderer::getSyncSettings(AVSyncSettings *sync, float *videoFps) {
- sp<AMessage> msg = new AMessage(kWhatGetSyncSettings, this);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- if (err == OK) {
- readFromAMessage(response, sync, videoFps);
- }
- }
- return err;
-}
-
-status_t NuPlayer2::Renderer::onGetSyncSettings(
- AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */) {
- *sync = mSyncSettings;
- *videoFps = -1.f;
- return OK;
-}
-
-void NuPlayer2::Renderer::flush(bool audio, bool notifyComplete) {
- {
- Mutex::Autolock autoLock(mLock);
- if (audio) {
- mNotifyCompleteAudio |= notifyComplete;
- clearAudioFirstAnchorTime_l();
- ++mAudioQueueGeneration;
- ++mAudioDrainGeneration;
- } else {
- mNotifyCompleteVideo |= notifyComplete;
- ++mVideoQueueGeneration;
- ++mVideoDrainGeneration;
- mNextVideoTimeMediaUs = -1;
- }
-
- mMediaClock->clearAnchor();
- mVideoLateByUs = 0;
- mSyncQueues = false;
- }
-
- sp<AMessage> msg = new AMessage(kWhatFlush, this);
- msg->setInt32("audio", static_cast<int32_t>(audio));
- msg->post();
-}
-
-void NuPlayer2::Renderer::signalTimeDiscontinuity() {
-}
-
-void NuPlayer2::Renderer::signalDisableOffloadAudio() {
- (new AMessage(kWhatDisableOffloadAudio, this))->post();
-}
-
-void NuPlayer2::Renderer::signalEnableOffloadAudio() {
- (new AMessage(kWhatEnableOffloadAudio, this))->post();
-}
-
-void NuPlayer2::Renderer::pause() {
- (new AMessage(kWhatPause, this))->post();
-}
-
-void NuPlayer2::Renderer::resume() {
- (new AMessage(kWhatResume, this))->post();
-}
-
-void NuPlayer2::Renderer::setVideoFrameRate(float fps) {
- sp<AMessage> msg = new AMessage(kWhatSetVideoFrameRate, this);
- msg->setFloat("frame-rate", fps);
- msg->post();
-}
-
-// Called on any threads without mLock acquired.
-status_t NuPlayer2::Renderer::getCurrentPosition(int64_t *mediaUs) {
- status_t result = mMediaClock->getMediaTime(ALooper::GetNowUs(), mediaUs);
- if (result == OK) {
- return result;
- }
-
- // MediaClock has not started yet. Try to start it if possible.
- {
- Mutex::Autolock autoLock(mLock);
- if (mAudioFirstAnchorTimeMediaUs == -1) {
- return result;
- }
-
- AudioTimestamp ts;
- status_t res = mAudioSink->getTimestamp(ts);
- if (res != OK) {
- return result;
- }
-
- // AudioSink has rendered some frames.
- int64_t nowUs = ALooper::GetNowUs();
- int64_t nowMediaUs = mAudioSink->getPlayedOutDurationUs(nowUs)
- + mAudioFirstAnchorTimeMediaUs;
- mMediaClock->updateAnchor(nowMediaUs, nowUs, -1);
- }
-
- return mMediaClock->getMediaTime(ALooper::GetNowUs(), mediaUs);
-}
-
-void NuPlayer2::Renderer::clearAudioFirstAnchorTime_l() {
- mAudioFirstAnchorTimeMediaUs = -1;
- mMediaClock->setStartingTimeMedia(-1);
-}
-
-void NuPlayer2::Renderer::setAudioFirstAnchorTimeIfNeeded_l(int64_t mediaUs) {
- if (mAudioFirstAnchorTimeMediaUs == -1) {
- mAudioFirstAnchorTimeMediaUs = mediaUs;
- mMediaClock->setStartingTimeMedia(mediaUs);
- }
-}
-
-// Called on renderer looper.
-void NuPlayer2::Renderer::clearAnchorTime() {
- mMediaClock->clearAnchor();
- mAnchorTimeMediaUs = -1;
- mAnchorNumFramesWritten = -1;
-}
-
-void NuPlayer2::Renderer::setVideoLateByUs(int64_t lateUs) {
- Mutex::Autolock autoLock(mLock);
- mVideoLateByUs = lateUs;
-}
-
-int64_t NuPlayer2::Renderer::getVideoLateByUs() {
- Mutex::Autolock autoLock(mLock);
- return mVideoLateByUs;
-}
-
-status_t NuPlayer2::Renderer::openAudioSink(
- const sp<AMessage> &format,
- bool offloadOnly,
- bool hasVideo,
- uint32_t flags,
- bool *isOffloaded,
- bool isStreaming) {
- sp<AMessage> msg = new AMessage(kWhatOpenAudioSink, this);
- msg->setMessage("format", format);
- msg->setInt32("offload-only", offloadOnly);
- msg->setInt32("has-video", hasVideo);
- msg->setInt32("flags", flags);
- msg->setInt32("isStreaming", isStreaming);
-
- sp<AMessage> response;
- status_t postStatus = msg->postAndAwaitResponse(&response);
-
- int32_t err;
- if (postStatus != OK || response.get() == nullptr || !response->findInt32("err", &err)) {
- err = INVALID_OPERATION;
- } else if (err == OK && isOffloaded != NULL) {
- int32_t offload;
- CHECK(response->findInt32("offload", &offload));
- *isOffloaded = (offload != 0);
- }
- return err;
-}
-
-void NuPlayer2::Renderer::closeAudioSink() {
- sp<AMessage> msg = new AMessage(kWhatCloseAudioSink, this);
-
- sp<AMessage> response;
- msg->postAndAwaitResponse(&response);
-}
-
-void NuPlayer2::Renderer::changeAudioFormat(
- const sp<AMessage> &format,
- bool offloadOnly,
- bool hasVideo,
- uint32_t flags,
- bool isStreaming,
- const sp<AMessage> ¬ify) {
- sp<AMessage> meta = new AMessage;
- meta->setMessage("format", format);
- meta->setInt32("offload-only", offloadOnly);
- meta->setInt32("has-video", hasVideo);
- meta->setInt32("flags", flags);
- meta->setInt32("isStreaming", isStreaming);
-
- sp<AMessage> msg = new AMessage(kWhatChangeAudioFormat, this);
- msg->setInt32("queueGeneration", getQueueGeneration(true /* audio */));
- msg->setMessage("notify", notify);
- msg->setMessage("meta", meta);
- msg->post();
-}
-
-void NuPlayer2::Renderer::onMessageReceived(const sp<AMessage> &msg) {
- switch (msg->what()) {
- case kWhatOpenAudioSink:
- {
- sp<AMessage> format;
- CHECK(msg->findMessage("format", &format));
-
- int32_t offloadOnly;
- CHECK(msg->findInt32("offload-only", &offloadOnly));
-
- int32_t hasVideo;
- CHECK(msg->findInt32("has-video", &hasVideo));
-
- uint32_t flags;
- CHECK(msg->findInt32("flags", (int32_t *)&flags));
-
- uint32_t isStreaming;
- CHECK(msg->findInt32("isStreaming", (int32_t *)&isStreaming));
-
- status_t err = onOpenAudioSink(format, offloadOnly, hasVideo, flags, isStreaming);
-
- sp<AMessage> response = new AMessage;
- response->setInt32("err", err);
- response->setInt32("offload", offloadingAudio());
-
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
-
- break;
- }
-
- case kWhatCloseAudioSink:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
- onCloseAudioSink();
-
- sp<AMessage> response = new AMessage;
- response->postReply(replyID);
- break;
- }
-
- case kWhatStopAudioSink:
- {
- mAudioSink->stop();
- break;
- }
-
- case kWhatChangeAudioFormat:
- {
- int32_t queueGeneration;
- CHECK(msg->findInt32("queueGeneration", &queueGeneration));
-
- sp<AMessage> notify;
- CHECK(msg->findMessage("notify", ¬ify));
-
- if (offloadingAudio()) {
- ALOGW("changeAudioFormat should NOT be called in offload mode");
- notify->setInt32("err", INVALID_OPERATION);
- notify->post();
- break;
- }
-
- sp<AMessage> meta;
- CHECK(msg->findMessage("meta", &meta));
-
- if (queueGeneration != getQueueGeneration(true /* audio */)
- || mAudioQueue.empty()) {
- onChangeAudioFormat(meta, notify);
- break;
- }
-
- QueueEntry entry;
- entry.mNotifyConsumed = notify;
- entry.mMeta = meta;
-
- Mutex::Autolock autoLock(mLock);
- mAudioQueue.push_back(entry);
- postDrainAudioQueue_l();
-
- break;
- }
-
- case kWhatDrainAudioQueue:
- {
- mDrainAudioQueuePending = false;
-
- int32_t generation;
- CHECK(msg->findInt32("drainGeneration", &generation));
- if (generation != getDrainGeneration(true /* audio */)) {
- break;
- }
-
- if (onDrainAudioQueue()) {
- uint32_t numFramesPlayed;
- CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed),
- (status_t)OK);
-
- // Handle AudioTrack race when start is immediately called after flush.
- uint32_t numFramesPendingPlayout =
- (mNumFramesWritten > numFramesPlayed ?
- mNumFramesWritten - numFramesPlayed : 0);
-
- // This is how long the audio sink will have data to
- // play back.
- int64_t delayUs =
- mAudioSink->msecsPerFrame()
- * numFramesPendingPlayout * 1000ll;
- if (mPlaybackSettings.mSpeed > 1.0f) {
- delayUs /= mPlaybackSettings.mSpeed;
- }
-
- // Let's give it more data after about half that time
- // has elapsed.
- delayUs /= 2;
- // check the buffer size to estimate maximum delay permitted.
- const int64_t maxDrainDelayUs = std::max(
- mAudioSink->getBufferDurationInUs(), (int64_t)500000 /* half second */);
- ALOGD_IF(delayUs > maxDrainDelayUs, "postDrainAudioQueue long delay: %lld > %lld",
- (long long)delayUs, (long long)maxDrainDelayUs);
- Mutex::Autolock autoLock(mLock);
- postDrainAudioQueue_l(delayUs);
- }
- break;
- }
-
- case kWhatDrainVideoQueue:
- {
- int32_t generation;
- CHECK(msg->findInt32("drainGeneration", &generation));
- if (generation != getDrainGeneration(false /* audio */)) {
- break;
- }
-
- mDrainVideoQueuePending = false;
-
- onDrainVideoQueue();
-
- postDrainVideoQueue();
- break;
- }
-
- case kWhatPostDrainVideoQueue:
- {
- int32_t generation;
- CHECK(msg->findInt32("drainGeneration", &generation));
- if (generation != getDrainGeneration(false /* audio */)) {
- break;
- }
-
- mDrainVideoQueuePending = false;
- postDrainVideoQueue();
- break;
- }
-
- case kWhatQueueBuffer:
- {
- onQueueBuffer(msg);
- break;
- }
-
- case kWhatQueueEOS:
- {
- onQueueEOS(msg);
- break;
- }
-
- case kWhatEOS:
- {
- int32_t generation;
- CHECK(msg->findInt32("audioEOSGeneration", &generation));
- if (generation != mAudioEOSGeneration) {
- break;
- }
- status_t finalResult;
- CHECK(msg->findInt32("finalResult", &finalResult));
- notifyEOS(true /* audio */, finalResult);
- break;
- }
-
- case kWhatConfigPlayback:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- AudioPlaybackRate rate;
- readFromAMessage(msg, &rate);
- status_t err = onConfigPlayback(rate);
- sp<AMessage> response = new AMessage;
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatGetPlaybackSettings:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- AudioPlaybackRate rate = AUDIO_PLAYBACK_RATE_DEFAULT;
- status_t err = onGetPlaybackSettings(&rate);
- sp<AMessage> response = new AMessage;
- if (err == OK) {
- writeToAMessage(response, rate);
- }
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatConfigSync:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- AVSyncSettings sync;
- float videoFpsHint;
- readFromAMessage(msg, &sync, &videoFpsHint);
- status_t err = onConfigSync(sync, videoFpsHint);
- sp<AMessage> response = new AMessage;
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatGetSyncSettings:
- {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
- ALOGV("kWhatGetSyncSettings");
- AVSyncSettings sync;
- float videoFps = -1.f;
- status_t err = onGetSyncSettings(&sync, &videoFps);
- sp<AMessage> response = new AMessage;
- if (err == OK) {
- writeToAMessage(response, sync, videoFps);
- }
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
-
- case kWhatFlush:
- {
- onFlush(msg);
- break;
- }
-
- case kWhatDisableOffloadAudio:
- {
- onDisableOffloadAudio();
- break;
- }
-
- case kWhatEnableOffloadAudio:
- {
- onEnableOffloadAudio();
- break;
- }
-
- case kWhatPause:
- {
- onPause();
- break;
- }
-
- case kWhatResume:
- {
- onResume();
- break;
- }
-
- case kWhatSetVideoFrameRate:
- {
- float fps;
- CHECK(msg->findFloat("frame-rate", &fps));
- onSetVideoFrameRate(fps);
- break;
- }
-
- case kWhatAudioTearDown:
- {
- int32_t reason;
- CHECK(msg->findInt32("reason", &reason));
-
- onAudioTearDown((AudioTearDownReason)reason);
- break;
- }
-
- case kWhatAudioOffloadPauseTimeout:
- {
- int32_t generation;
- CHECK(msg->findInt32("drainGeneration", &generation));
- if (generation != mAudioOffloadPauseTimeoutGeneration) {
- break;
- }
- ALOGV("Audio Offload tear down due to pause timeout.");
- onAudioTearDown(kDueToTimeout);
- mWakeLock->release();
- break;
- }
-
- default:
- TRESPASS();
- break;
- }
-}
-
-void NuPlayer2::Renderer::postDrainAudioQueue_l(int64_t delayUs) {
- if (mDrainAudioQueuePending || mSyncQueues || mUseAudioCallback) {
- return;
- }
-
- if (mAudioQueue.empty()) {
- return;
- }
-
- // FIXME: if paused, wait until AudioTrack stop() is complete before delivering data.
- if (mPaused) {
- const int64_t diffUs = mPauseDrainAudioAllowedUs - ALooper::GetNowUs();
- if (diffUs > delayUs) {
- delayUs = diffUs;
- }
- }
-
- mDrainAudioQueuePending = true;
- sp<AMessage> msg = new AMessage(kWhatDrainAudioQueue, this);
- msg->setInt32("drainGeneration", mAudioDrainGeneration);
- msg->post(delayUs);
-}
-
-void NuPlayer2::Renderer::prepareForMediaRenderingStart_l() {
- mAudioRenderingStartGeneration = mAudioDrainGeneration;
- mVideoRenderingStartGeneration = mVideoDrainGeneration;
- mRenderingDataDelivered = false;
-}
-
-void NuPlayer2::Renderer::notifyIfMediaRenderingStarted_l() {
- if (mVideoRenderingStartGeneration == mVideoDrainGeneration &&
- mAudioRenderingStartGeneration == mAudioDrainGeneration) {
- mRenderingDataDelivered = true;
- if (mPaused) {
- return;
- }
- mVideoRenderingStartGeneration = -1;
- mAudioRenderingStartGeneration = -1;
-
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatMediaRenderingStart);
- notify->post();
- }
-}
-
-// static
-size_t NuPlayer2::Renderer::AudioSinkCallback(
- MediaPlayer2Interface::AudioSink * /* audioSink */,
- void *buffer,
- size_t size,
- void *cookie,
- MediaPlayer2Interface::AudioSink::cb_event_t event) {
- NuPlayer2::Renderer *me = (NuPlayer2::Renderer *)cookie;
-
- switch (event) {
- case MediaPlayer2Interface::AudioSink::CB_EVENT_FILL_BUFFER:
- {
- return me->fillAudioBuffer(buffer, size);
- break;
- }
-
- case MediaPlayer2Interface::AudioSink::CB_EVENT_STREAM_END:
- {
- ALOGV("AudioSink::CB_EVENT_STREAM_END");
- me->notifyEOSCallback();
- break;
- }
-
- case MediaPlayer2Interface::AudioSink::CB_EVENT_TEAR_DOWN:
- {
- ALOGV("AudioSink::CB_EVENT_TEAR_DOWN");
- me->notifyAudioTearDown(kDueToError);
- break;
- }
- }
-
- return 0;
-}
-
-void NuPlayer2::Renderer::notifyEOSCallback() {
- Mutex::Autolock autoLock(mLock);
-
- if (!mUseAudioCallback) {
- return;
- }
-
- notifyEOS_l(true /* audio */, ERROR_END_OF_STREAM);
-}
-
-size_t NuPlayer2::Renderer::fillAudioBuffer(void *buffer, size_t size) {
- Mutex::Autolock autoLock(mLock);
-
- if (!mUseAudioCallback) {
- return 0;
- }
-
- bool hasEOS = false;
-
- size_t sizeCopied = 0;
- bool firstEntry = true;
- QueueEntry *entry; // will be valid after while loop if hasEOS is set.
- while (sizeCopied < size && !mAudioQueue.empty()) {
- entry = &*mAudioQueue.begin();
-
- if (entry->mBuffer == NULL) { // EOS
- hasEOS = true;
- mAudioQueue.erase(mAudioQueue.begin());
- break;
- }
-
- if (firstEntry && entry->mOffset == 0) {
- firstEntry = false;
- int64_t mediaTimeUs;
- CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
- ALOGV("fillAudioBuffer: rendering audio at media time %.2f secs", mediaTimeUs / 1E6);
- setAudioFirstAnchorTimeIfNeeded_l(mediaTimeUs);
- }
-
- size_t copy = entry->mBuffer->size() - entry->mOffset;
- size_t sizeRemaining = size - sizeCopied;
- if (copy > sizeRemaining) {
- copy = sizeRemaining;
- }
-
- memcpy((char *)buffer + sizeCopied,
- entry->mBuffer->data() + entry->mOffset,
- copy);
-
- entry->mOffset += copy;
- if (entry->mOffset == entry->mBuffer->size()) {
- entry->mNotifyConsumed->post();
- mAudioQueue.erase(mAudioQueue.begin());
- entry = NULL;
- }
- sizeCopied += copy;
-
- notifyIfMediaRenderingStarted_l();
- }
-
- if (mAudioFirstAnchorTimeMediaUs >= 0) {
- int64_t nowUs = ALooper::GetNowUs();
- int64_t nowMediaUs =
- mAudioFirstAnchorTimeMediaUs + mAudioSink->getPlayedOutDurationUs(nowUs);
- // we don't know how much data we are queueing for offloaded tracks.
- mMediaClock->updateAnchor(nowMediaUs, nowUs, INT64_MAX);
- }
-
- // for non-offloaded audio, we need to compute the frames written because
- // there is no EVENT_STREAM_END notification. The frames written gives
- // an estimate on the pending played out duration.
- if (!offloadingAudio()) {
- mNumFramesWritten += sizeCopied / mAudioSink->frameSize();
- }
-
- if (hasEOS) {
- (new AMessage(kWhatStopAudioSink, this))->post();
- // As there is currently no EVENT_STREAM_END callback notification for
- // non-offloaded audio tracks, we need to post the EOS ourselves.
- if (!offloadingAudio()) {
- int64_t postEOSDelayUs = 0;
- if (mAudioSink->needsTrailingPadding()) {
- postEOSDelayUs = getPendingAudioPlayoutDurationUs(ALooper::GetNowUs());
- }
- ALOGV("fillAudioBuffer: notifyEOS_l "
- "mNumFramesWritten:%u finalResult:%d postEOSDelay:%lld",
- mNumFramesWritten, entry->mFinalResult, (long long)postEOSDelayUs);
- notifyEOS_l(true /* audio */, entry->mFinalResult, postEOSDelayUs);
- }
- }
- return sizeCopied;
-}
-
-void NuPlayer2::Renderer::drainAudioQueueUntilLastEOS() {
- List<QueueEntry>::iterator it = mAudioQueue.begin(), itEOS = it;
- bool foundEOS = false;
- while (it != mAudioQueue.end()) {
- int32_t eos;
- QueueEntry *entry = &*it++;
- if ((entry->mBuffer == nullptr && entry->mNotifyConsumed == nullptr)
- || (entry->mNotifyConsumed->findInt32("eos", &eos) && eos != 0)) {
- itEOS = it;
- foundEOS = true;
- }
- }
-
- if (foundEOS) {
- // post all replies before EOS and drop the samples
- for (it = mAudioQueue.begin(); it != itEOS; it++) {
- if (it->mBuffer == nullptr) {
- if (it->mNotifyConsumed == nullptr) {
- // delay doesn't matter as we don't even have an AudioTrack
- notifyEOS(true /* audio */, it->mFinalResult);
- } else {
- // TAG for re-opening audio sink.
- onChangeAudioFormat(it->mMeta, it->mNotifyConsumed);
- }
- } else {
- it->mNotifyConsumed->post();
- }
- }
- mAudioQueue.erase(mAudioQueue.begin(), itEOS);
- }
-}
-
-bool NuPlayer2::Renderer::onDrainAudioQueue() {
- // do not drain audio during teardown as queued buffers may be invalid.
- if (mAudioTornDown) {
- return false;
- }
- // TODO: This call to getPosition checks if AudioTrack has been created
- // in AudioSink before draining audio. If AudioTrack doesn't exist, then
- // CHECKs on getPosition will fail.
- // We still need to figure out why AudioTrack is not created when
- // this function is called. One possible reason could be leftover
- // audio. Another possible place is to check whether decoder
- // has received INFO_FORMAT_CHANGED as the first buffer since
- // AudioSink is opened there, and possible interactions with flush
- // immediately after start. Investigate error message
- // "vorbis_dsp_synthesis returned -135", along with RTSP.
- uint32_t numFramesPlayed;
- if (mAudioSink->getPosition(&numFramesPlayed) != OK) {
- // When getPosition fails, renderer will not reschedule the draining
- // unless new samples are queued.
- // If we have pending EOS (or "eos" marker for discontinuities), we need
- // to post these now as NuPlayer2Decoder might be waiting for it.
- drainAudioQueueUntilLastEOS();
-
- ALOGW("onDrainAudioQueue(): audio sink is not ready");
- return false;
- }
-
-#if 0
- ssize_t numFramesAvailableToWrite =
- mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed);
-
- if (numFramesAvailableToWrite == mAudioSink->frameCount()) {
- ALOGI("audio sink underrun");
- } else {
- ALOGV("audio queue has %d frames left to play",
- mAudioSink->frameCount() - numFramesAvailableToWrite);
- }
-#endif
-
- uint32_t prevFramesWritten = mNumFramesWritten;
- while (!mAudioQueue.empty()) {
- QueueEntry *entry = &*mAudioQueue.begin();
-
- if (entry->mBuffer == NULL) {
- if (entry->mNotifyConsumed != nullptr) {
- // TAG for re-open audio sink.
- onChangeAudioFormat(entry->mMeta, entry->mNotifyConsumed);
- mAudioQueue.erase(mAudioQueue.begin());
- continue;
- }
-
- // EOS
- if (mPaused) {
- // Do not notify EOS when paused.
- // This is needed to avoid switch to next clip while in pause.
- ALOGV("onDrainAudioQueue(): Do not notify EOS when paused");
- return false;
- }
-
- int64_t postEOSDelayUs = 0;
- if (mAudioSink->needsTrailingPadding()) {
- postEOSDelayUs = getPendingAudioPlayoutDurationUs(ALooper::GetNowUs());
- }
- notifyEOS(true /* audio */, entry->mFinalResult, postEOSDelayUs);
- mLastAudioMediaTimeUs = getDurationUsIfPlayedAtSampleRate(mNumFramesWritten);
-
- mAudioQueue.erase(mAudioQueue.begin());
- entry = NULL;
- if (mAudioSink->needsTrailingPadding()) {
- // If we're not in gapless playback (i.e. through setNextPlayer), we
- // need to stop the track here, because that will play out the last
- // little bit at the end of the file. Otherwise short files won't play.
- mAudioSink->stop();
- mNumFramesWritten = 0;
- }
- return false;
- }
-
- mLastAudioBufferDrained = entry->mBufferOrdinal;
-
- // ignore 0-sized buffer which could be EOS marker with no data
- if (entry->mOffset == 0 && entry->mBuffer->size() > 0) {
- int64_t mediaTimeUs;
- CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
- ALOGV("onDrainAudioQueue: rendering audio at media time %.2f secs",
- mediaTimeUs / 1E6);
- onNewAudioMediaTime(mediaTimeUs);
- }
-
- size_t copy = entry->mBuffer->size() - entry->mOffset;
-
- ssize_t written = mAudioSink->write(entry->mBuffer->data() + entry->mOffset,
- copy, false /* blocking */);
- if (written < 0) {
- // An error in AudioSink write. Perhaps the AudioSink was not properly opened.
- if (written == WOULD_BLOCK) {
- ALOGV("AudioSink write would block when writing %zu bytes", copy);
- } else {
- ALOGE("AudioSink write error(%zd) when writing %zu bytes", written, copy);
- // This can only happen when AudioSink was opened with doNotReconnect flag set to
- // true, in which case the NuPlayer2 will handle the reconnect.
- notifyAudioTearDown(kDueToError);
- }
- break;
- }
-
- entry->mOffset += written;
- size_t remainder = entry->mBuffer->size() - entry->mOffset;
- if ((ssize_t)remainder < mAudioSink->frameSize()) {
- if (remainder > 0) {
- ALOGW("Corrupted audio buffer has fractional frames, discarding %zu bytes.",
- remainder);
- entry->mOffset += remainder;
- copy -= remainder;
- }
-
- entry->mNotifyConsumed->post();
- mAudioQueue.erase(mAudioQueue.begin());
-
- entry = NULL;
- }
-
- size_t copiedFrames = written / mAudioSink->frameSize();
- mNumFramesWritten += copiedFrames;
-
- {
- Mutex::Autolock autoLock(mLock);
- int64_t maxTimeMedia;
- maxTimeMedia =
- mAnchorTimeMediaUs +
- (int64_t)(max((long long)mNumFramesWritten - mAnchorNumFramesWritten, 0LL)
- * 1000LL * mAudioSink->msecsPerFrame());
- mMediaClock->updateMaxTimeMedia(maxTimeMedia);
-
- notifyIfMediaRenderingStarted_l();
- }
-
- if (written != (ssize_t)copy) {
- // A short count was received from AudioSink::write()
- //
- // AudioSink write is called in non-blocking mode.
- // It may return with a short count when:
- //
- // 1) Size to be copied is not a multiple of the frame size. Fractional frames are
- // discarded.
- // 2) The data to be copied exceeds the available buffer in AudioSink.
- // 3) An error occurs and data has been partially copied to the buffer in AudioSink.
- // 4) AudioSink is an AudioCache for data retrieval, and the AudioCache is exceeded.
-
- // (Case 1)
- // Must be a multiple of the frame size. If it is not a multiple of a frame size, it
- // needs to fail, as we should not carry over fractional frames between calls.
- CHECK_EQ(copy % mAudioSink->frameSize(), 0u);
-
- // (Case 2, 3, 4)
- // Return early to the caller.
- // Beware of calling immediately again as this may busy-loop if you are not careful.
- ALOGV("AudioSink write short frame count %zd < %zu", written, copy);
- break;
- }
- }
-
- // calculate whether we need to reschedule another write.
- bool reschedule = !mAudioQueue.empty()
- && (!mPaused
- || prevFramesWritten != mNumFramesWritten); // permit pause to fill buffers
- //ALOGD("reschedule:%d empty:%d mPaused:%d prevFramesWritten:%u mNumFramesWritten:%u",
- // reschedule, mAudioQueue.empty(), mPaused, prevFramesWritten, mNumFramesWritten);
- return reschedule;
-}
-
-int64_t NuPlayer2::Renderer::getDurationUsIfPlayedAtSampleRate(uint32_t numFrames) {
- int32_t sampleRate = offloadingAudio() ?
- mCurrentOffloadInfo.sample_rate : mCurrentPcmInfo.mSampleRate;
- if (sampleRate == 0) {
- ALOGE("sampleRate is 0 in %s mode", offloadingAudio() ? "offload" : "non-offload");
- return 0;
- }
- return (int64_t)(numFrames * 1000000LL / sampleRate);
-}
-
-// Calculate duration of pending samples if played at normal rate (i.e., 1.0).
-int64_t NuPlayer2::Renderer::getPendingAudioPlayoutDurationUs(int64_t nowUs) {
- int64_t writtenAudioDurationUs = getDurationUsIfPlayedAtSampleRate(mNumFramesWritten);
- if (mUseVirtualAudioSink) {
- int64_t nowUs = ALooper::GetNowUs();
- int64_t mediaUs;
- if (mMediaClock->getMediaTime(nowUs, &mediaUs) != OK) {
- return 0LL;
- } else {
- return writtenAudioDurationUs - (mediaUs - mAudioFirstAnchorTimeMediaUs);
- }
- }
-
- const int64_t audioSinkPlayedUs = mAudioSink->getPlayedOutDurationUs(nowUs);
- int64_t pendingUs = writtenAudioDurationUs - audioSinkPlayedUs;
- if (pendingUs < 0) {
- // This shouldn't happen unless the timestamp is stale.
- ALOGW("%s: pendingUs %lld < 0, clamping to zero, potential resume after pause "
- "writtenAudioDurationUs: %lld, audioSinkPlayedUs: %lld",
- __func__, (long long)pendingUs,
- (long long)writtenAudioDurationUs, (long long)audioSinkPlayedUs);
- pendingUs = 0;
- }
- return pendingUs;
-}
-
-int64_t NuPlayer2::Renderer::getRealTimeUs(int64_t mediaTimeUs, int64_t nowUs) {
- int64_t realUs;
- if (mMediaClock->getRealTimeFor(mediaTimeUs, &realUs) != OK) {
- // If failed to get current position, e.g. due to audio clock is
- // not ready, then just play out video immediately without delay.
- return nowUs;
- }
- return realUs;
-}
-
-void NuPlayer2::Renderer::onNewAudioMediaTime(int64_t mediaTimeUs) {
- Mutex::Autolock autoLock(mLock);
- // TRICKY: vorbis decoder generates multiple frames with the same
- // timestamp, so only update on the first frame with a given timestamp
- if (mediaTimeUs == mAnchorTimeMediaUs) {
- return;
- }
- setAudioFirstAnchorTimeIfNeeded_l(mediaTimeUs);
-
- // mNextAudioClockUpdateTimeUs is -1 if we're waiting for audio sink to start
- if (mNextAudioClockUpdateTimeUs == -1) {
- AudioTimestamp ts;
- if (mAudioSink->getTimestamp(ts) == OK && ts.mPosition > 0) {
- mNextAudioClockUpdateTimeUs = 0; // start our clock updates
- }
- }
- int64_t nowUs = ALooper::GetNowUs();
- if (mNextAudioClockUpdateTimeUs >= 0) {
- if (nowUs >= mNextAudioClockUpdateTimeUs) {
- int64_t nowMediaUs = mediaTimeUs - getPendingAudioPlayoutDurationUs(nowUs);
- mMediaClock->updateAnchor(nowMediaUs, nowUs, mediaTimeUs);
- mUseVirtualAudioSink = false;
- mNextAudioClockUpdateTimeUs = nowUs + kMinimumAudioClockUpdatePeriodUs;
- }
- } else {
- int64_t unused;
- if ((mMediaClock->getMediaTime(nowUs, &unused) != OK)
- && (getDurationUsIfPlayedAtSampleRate(mNumFramesWritten)
- > kMaxAllowedAudioSinkDelayUs)) {
- // Enough data has been sent to AudioSink, but AudioSink has not rendered
- // any data yet. Something is wrong with AudioSink, e.g., the device is not
- // connected to audio out.
- // Switch to system clock. This essentially creates a virtual AudioSink with
- // initial latenty of getDurationUsIfPlayedAtSampleRate(mNumFramesWritten).
- // This virtual AudioSink renders audio data starting from the very first sample
- // and it's paced by system clock.
- ALOGW("AudioSink stuck. ARE YOU CONNECTED TO AUDIO OUT? Switching to system clock.");
- mMediaClock->updateAnchor(mAudioFirstAnchorTimeMediaUs, nowUs, mediaTimeUs);
- mUseVirtualAudioSink = true;
- }
- }
- mAnchorNumFramesWritten = mNumFramesWritten;
- mAnchorTimeMediaUs = mediaTimeUs;
-}
-
-// Called without mLock acquired.
-void NuPlayer2::Renderer::postDrainVideoQueue() {
- if (mDrainVideoQueuePending
- || getSyncQueues()
- || (mPaused && mVideoSampleReceived)) {
- return;
- }
-
- if (mVideoQueue.empty()) {
- return;
- }
-
- QueueEntry &entry = *mVideoQueue.begin();
-
- sp<AMessage> msg = new AMessage(kWhatDrainVideoQueue, this);
- msg->setInt32("drainGeneration", getDrainGeneration(false /* audio */));
-
- if (entry.mBuffer == NULL) {
- // EOS doesn't carry a timestamp.
- msg->post();
- mDrainVideoQueuePending = true;
- return;
- }
-
- int64_t nowUs = ALooper::GetNowUs();
- if (mFlags & FLAG_REAL_TIME) {
- int64_t realTimeUs;
- CHECK(entry.mBuffer->meta()->findInt64("timeUs", &realTimeUs));
-
- realTimeUs = mVideoScheduler->schedule(realTimeUs * 1000) / 1000;
-
- int64_t twoVsyncsUs = 2 * (mVideoScheduler->getVsyncPeriod() / 1000);
-
- int64_t delayUs = realTimeUs - nowUs;
-
- ALOGW_IF(delayUs > 500000, "unusually high delayUs: %lld", (long long)delayUs);
- // post 2 display refreshes before rendering is due
- msg->post(delayUs > twoVsyncsUs ? delayUs - twoVsyncsUs : 0);
-
- mDrainVideoQueuePending = true;
- return;
- }
-
- int64_t mediaTimeUs;
- CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
-
- {
- Mutex::Autolock autoLock(mLock);
- if (mAnchorTimeMediaUs < 0) {
- mMediaClock->updateAnchor(mediaTimeUs, nowUs, mediaTimeUs);
- mAnchorTimeMediaUs = mediaTimeUs;
- }
- }
- mNextVideoTimeMediaUs = mediaTimeUs;
- if (!mHasAudio) {
- // smooth out videos >= 10fps
- mMediaClock->updateMaxTimeMedia(mediaTimeUs + kDefaultVideoFrameIntervalUs);
- }
-
- if (!mVideoSampleReceived || mediaTimeUs < mAudioFirstAnchorTimeMediaUs) {
- msg->post();
- } else {
- int64_t twoVsyncsUs = 2 * (mVideoScheduler->getVsyncPeriod() / 1000);
-
- // post 2 display refreshes before rendering is due
- mMediaClock->addTimer(msg, mediaTimeUs, -twoVsyncsUs);
- }
-
- mDrainVideoQueuePending = true;
-}
-
-void NuPlayer2::Renderer::onDrainVideoQueue() {
- if (mVideoQueue.empty()) {
- return;
- }
-
- QueueEntry *entry = &*mVideoQueue.begin();
-
- if (entry->mBuffer == NULL) {
- // EOS
-
- notifyEOS(false /* audio */, entry->mFinalResult);
-
- mVideoQueue.erase(mVideoQueue.begin());
- entry = NULL;
-
- setVideoLateByUs(0);
- return;
- }
-
- int64_t nowUs = ALooper::GetNowUs();
- int64_t realTimeUs;
- int64_t mediaTimeUs = -1;
- if (mFlags & FLAG_REAL_TIME) {
- CHECK(entry->mBuffer->meta()->findInt64("timeUs", &realTimeUs));
- } else {
- CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
-
- realTimeUs = getRealTimeUs(mediaTimeUs, nowUs);
- }
- realTimeUs = mVideoScheduler->schedule(realTimeUs * 1000) / 1000;
-
- bool tooLate = false;
-
- if (!mPaused) {
- setVideoLateByUs(nowUs - realTimeUs);
- tooLate = (mVideoLateByUs > 40000);
-
- if (tooLate) {
- ALOGV("video late by %lld us (%.2f secs)",
- (long long)mVideoLateByUs, mVideoLateByUs / 1E6);
- } else {
- int64_t mediaUs = 0;
- mMediaClock->getMediaTime(realTimeUs, &mediaUs);
- ALOGV("rendering video at media time %.2f secs",
- (mFlags & FLAG_REAL_TIME ? realTimeUs :
- mediaUs) / 1E6);
-
- if (!(mFlags & FLAG_REAL_TIME)
- && mLastAudioMediaTimeUs != -1
- && mediaTimeUs > mLastAudioMediaTimeUs) {
- // If audio ends before video, video continues to drive media clock.
- // Also smooth out videos >= 10fps.
- mMediaClock->updateMaxTimeMedia(mediaTimeUs + kDefaultVideoFrameIntervalUs);
- }
- }
- } else {
- setVideoLateByUs(0);
- if (!mVideoSampleReceived && !mHasAudio) {
- // This will ensure that the first frame after a flush won't be used as anchor
- // when renderer is in paused state, because resume can happen any time after seek.
- clearAnchorTime();
- }
- }
-
- // Always render the first video frame while keeping stats on A/V sync.
- if (!mVideoSampleReceived) {
- realTimeUs = nowUs;
- tooLate = false;
- }
-
- entry->mNotifyConsumed->setInt64("timestampNs", realTimeUs * 1000LL);
- entry->mNotifyConsumed->setInt32("render", !tooLate);
- entry->mNotifyConsumed->post();
- mVideoQueue.erase(mVideoQueue.begin());
- entry = NULL;
-
- mVideoSampleReceived = true;
-
- if (!mPaused) {
- if (!mVideoRenderingStarted) {
- mVideoRenderingStarted = true;
- notifyVideoRenderingStart();
- }
- Mutex::Autolock autoLock(mLock);
- notifyIfMediaRenderingStarted_l();
- }
-}
-
-void NuPlayer2::Renderer::notifyVideoRenderingStart() {
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatVideoRenderingStart);
- notify->post();
-}
-
-void NuPlayer2::Renderer::notifyEOS(bool audio, status_t finalResult, int64_t delayUs) {
- Mutex::Autolock autoLock(mLock);
- notifyEOS_l(audio, finalResult, delayUs);
-}
-
-void NuPlayer2::Renderer::notifyEOS_l(bool audio, status_t finalResult, int64_t delayUs) {
- if (audio && delayUs > 0) {
- sp<AMessage> msg = new AMessage(kWhatEOS, this);
- msg->setInt32("audioEOSGeneration", mAudioEOSGeneration);
- msg->setInt32("finalResult", finalResult);
- msg->post(delayUs);
- return;
- }
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatEOS);
- notify->setInt32("audio", static_cast<int32_t>(audio));
- notify->setInt32("finalResult", finalResult);
- notify->post(delayUs);
-
- if (audio) {
- // Video might outlive audio. Clear anchor to enable video only case.
- mAnchorTimeMediaUs = -1;
- mHasAudio = false;
- if (mNextVideoTimeMediaUs >= 0) {
- int64_t mediaUs = 0;
- int64_t nowUs = ALooper::GetNowUs();
- status_t result = mMediaClock->getMediaTime(nowUs, &mediaUs);
- if (result == OK) {
- if (mNextVideoTimeMediaUs > mediaUs) {
- mMediaClock->updateMaxTimeMedia(mNextVideoTimeMediaUs);
- }
- } else {
- mMediaClock->updateAnchor(
- mNextVideoTimeMediaUs, nowUs,
- mNextVideoTimeMediaUs + kDefaultVideoFrameIntervalUs);
- }
- }
- }
-}
-
-void NuPlayer2::Renderer::notifyAudioTearDown(AudioTearDownReason reason) {
- sp<AMessage> msg = new AMessage(kWhatAudioTearDown, this);
- msg->setInt32("reason", reason);
- msg->post();
-}
-
-void NuPlayer2::Renderer::onQueueBuffer(const sp<AMessage> &msg) {
- int32_t audio;
- CHECK(msg->findInt32("audio", &audio));
-
- if (dropBufferIfStale(audio, msg)) {
- return;
- }
-
- if (audio) {
- mHasAudio = true;
- } else {
- mHasVideo = true;
- }
-
- if (mHasVideo) {
- if (mVideoScheduler == NULL) {
- mVideoScheduler = new VideoFrameScheduler2();
- mVideoScheduler->init();
- }
- }
-
- sp<RefBase> obj;
- CHECK(msg->findObject("buffer", &obj));
- sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
-
- sp<AMessage> notifyConsumed;
- CHECK(msg->findMessage("notifyConsumed", ¬ifyConsumed));
-
- QueueEntry entry;
- entry.mBuffer = buffer;
- entry.mNotifyConsumed = notifyConsumed;
- entry.mOffset = 0;
- entry.mFinalResult = OK;
- entry.mBufferOrdinal = ++mTotalBuffersQueued;
-
- if (audio) {
- Mutex::Autolock autoLock(mLock);
- mAudioQueue.push_back(entry);
- postDrainAudioQueue_l();
- } else {
- mVideoQueue.push_back(entry);
- postDrainVideoQueue();
- }
-
- Mutex::Autolock autoLock(mLock);
- if (!mSyncQueues || mAudioQueue.empty() || mVideoQueue.empty()) {
- return;
- }
-
- sp<MediaCodecBuffer> firstAudioBuffer = (*mAudioQueue.begin()).mBuffer;
- sp<MediaCodecBuffer> firstVideoBuffer = (*mVideoQueue.begin()).mBuffer;
-
- if (firstAudioBuffer == NULL || firstVideoBuffer == NULL) {
- // EOS signalled on either queue.
- syncQueuesDone_l();
- return;
- }
-
- int64_t firstAudioTimeUs;
- int64_t firstVideoTimeUs;
- CHECK(firstAudioBuffer->meta()
- ->findInt64("timeUs", &firstAudioTimeUs));
- CHECK(firstVideoBuffer->meta()
- ->findInt64("timeUs", &firstVideoTimeUs));
-
- int64_t diff = firstVideoTimeUs - firstAudioTimeUs;
-
- ALOGV("queueDiff = %.2f secs", diff / 1E6);
-
- if (diff > 100000LL) {
- // Audio data starts More than 0.1 secs before video.
- // Drop some audio.
-
- (*mAudioQueue.begin()).mNotifyConsumed->post();
- mAudioQueue.erase(mAudioQueue.begin());
- return;
- }
-
- syncQueuesDone_l();
-}
-
-void NuPlayer2::Renderer::syncQueuesDone_l() {
- if (!mSyncQueues) {
- return;
- }
-
- mSyncQueues = false;
-
- if (!mAudioQueue.empty()) {
- postDrainAudioQueue_l();
- }
-
- if (!mVideoQueue.empty()) {
- mLock.unlock();
- postDrainVideoQueue();
- mLock.lock();
- }
-}
-
-void NuPlayer2::Renderer::onQueueEOS(const sp<AMessage> &msg) {
- int32_t audio;
- CHECK(msg->findInt32("audio", &audio));
-
- if (dropBufferIfStale(audio, msg)) {
- return;
- }
-
- int32_t finalResult;
- CHECK(msg->findInt32("finalResult", &finalResult));
-
- QueueEntry entry;
- entry.mOffset = 0;
- entry.mFinalResult = finalResult;
-
- if (audio) {
- Mutex::Autolock autoLock(mLock);
- if (mAudioQueue.empty() && mSyncQueues) {
- syncQueuesDone_l();
- }
- mAudioQueue.push_back(entry);
- postDrainAudioQueue_l();
- } else {
- if (mVideoQueue.empty() && getSyncQueues()) {
- Mutex::Autolock autoLock(mLock);
- syncQueuesDone_l();
- }
- mVideoQueue.push_back(entry);
- postDrainVideoQueue();
- }
-}
-
-void NuPlayer2::Renderer::onFlush(const sp<AMessage> &msg) {
- int32_t audio, notifyComplete;
- CHECK(msg->findInt32("audio", &audio));
-
- {
- Mutex::Autolock autoLock(mLock);
- if (audio) {
- notifyComplete = mNotifyCompleteAudio;
- mNotifyCompleteAudio = false;
- mLastAudioMediaTimeUs = -1;
-
- mHasAudio = false;
- if (mNextVideoTimeMediaUs >= 0) {
- int64_t nowUs = ALooper::GetNowUs();
- mMediaClock->updateAnchor(
- mNextVideoTimeMediaUs, nowUs,
- mNextVideoTimeMediaUs + kDefaultVideoFrameIntervalUs);
- }
- } else {
- notifyComplete = mNotifyCompleteVideo;
- mNotifyCompleteVideo = false;
- mVideoRenderingStarted = false;
- }
-
- // If we're currently syncing the queues, i.e. dropping audio while
- // aligning the first audio/video buffer times and only one of the
- // two queues has data, we may starve that queue by not requesting
- // more buffers from the decoder. If the other source then encounters
- // a discontinuity that leads to flushing, we'll never find the
- // corresponding discontinuity on the other queue.
- // Therefore we'll stop syncing the queues if at least one of them
- // is flushed.
- syncQueuesDone_l();
- }
- clearAnchorTime();
-
- ALOGV("flushing %s", audio ? "audio" : "video");
- if (audio) {
- {
- Mutex::Autolock autoLock(mLock);
- flushQueue(&mAudioQueue);
-
- ++mAudioDrainGeneration;
- ++mAudioEOSGeneration;
- prepareForMediaRenderingStart_l();
-
- // the frame count will be reset after flush.
- clearAudioFirstAnchorTime_l();
- }
-
- mDrainAudioQueuePending = false;
-
- if (offloadingAudio()) {
- mAudioSink->pause();
- mAudioSink->flush();
- if (!mPaused) {
- mAudioSink->start();
- }
- } else {
- mAudioSink->pause();
- mAudioSink->flush();
- // Call stop() to signal to the AudioSink to completely fill the
- // internal buffer before resuming playback.
- // FIXME: this is ignored after flush().
- mAudioSink->stop();
- if (mPaused) {
- // Race condition: if renderer is paused and audio sink is stopped,
- // we need to make sure that the audio track buffer fully drains
- // before delivering data.
- // FIXME: remove this if we can detect if stop() is complete.
- const int delayUs = 2 * 50 * 1000; // (2 full mixer thread cycles at 50ms)
- mPauseDrainAudioAllowedUs = ALooper::GetNowUs() + delayUs;
- } else {
- mAudioSink->start();
- }
- mNumFramesWritten = 0;
- }
- mNextAudioClockUpdateTimeUs = -1;
- } else {
- flushQueue(&mVideoQueue);
-
- mDrainVideoQueuePending = false;
-
- if (mVideoScheduler != NULL) {
- mVideoScheduler->restart();
- }
-
- Mutex::Autolock autoLock(mLock);
- ++mVideoDrainGeneration;
- prepareForMediaRenderingStart_l();
- }
-
- mVideoSampleReceived = false;
-
- if (notifyComplete) {
- notifyFlushComplete(audio);
- }
-}
-
-void NuPlayer2::Renderer::flushQueue(List<QueueEntry> *queue) {
- while (!queue->empty()) {
- QueueEntry *entry = &*queue->begin();
-
- if (entry->mBuffer != NULL) {
- entry->mNotifyConsumed->post();
- } else if (entry->mNotifyConsumed != nullptr) {
- // Is it needed to open audio sink now?
- onChangeAudioFormat(entry->mMeta, entry->mNotifyConsumed);
- }
-
- queue->erase(queue->begin());
- entry = NULL;
- }
-}
-
-void NuPlayer2::Renderer::notifyFlushComplete(bool audio) {
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatFlushComplete);
- notify->setInt32("audio", static_cast<int32_t>(audio));
- notify->post();
-}
-
-bool NuPlayer2::Renderer::dropBufferIfStale(
- bool audio, const sp<AMessage> &msg) {
- int32_t queueGeneration;
- CHECK(msg->findInt32("queueGeneration", &queueGeneration));
-
- if (queueGeneration == getQueueGeneration(audio)) {
- return false;
- }
-
- sp<AMessage> notifyConsumed;
- if (msg->findMessage("notifyConsumed", ¬ifyConsumed)) {
- notifyConsumed->post();
- }
-
- return true;
-}
-
-void NuPlayer2::Renderer::onAudioSinkChanged() {
- if (offloadingAudio()) {
- return;
- }
- CHECK(!mDrainAudioQueuePending);
- mNumFramesWritten = 0;
- mAnchorNumFramesWritten = -1;
- uint32_t written;
- if (mAudioSink->getFramesWritten(&written) == OK) {
- mNumFramesWritten = written;
- }
-}
-
-void NuPlayer2::Renderer::onDisableOffloadAudio() {
- Mutex::Autolock autoLock(mLock);
- mFlags &= ~FLAG_OFFLOAD_AUDIO;
- ++mAudioDrainGeneration;
- if (mAudioRenderingStartGeneration != -1) {
- prepareForMediaRenderingStart_l();
- }
-}
-
-void NuPlayer2::Renderer::onEnableOffloadAudio() {
- Mutex::Autolock autoLock(mLock);
- mFlags |= FLAG_OFFLOAD_AUDIO;
- ++mAudioDrainGeneration;
- if (mAudioRenderingStartGeneration != -1) {
- prepareForMediaRenderingStart_l();
- }
-}
-
-void NuPlayer2::Renderer::onPause() {
- if (mPaused) {
- return;
- }
-
- {
- Mutex::Autolock autoLock(mLock);
- // we do not increment audio drain generation so that we fill audio buffer during pause.
- ++mVideoDrainGeneration;
- prepareForMediaRenderingStart_l();
- mPaused = true;
- mMediaClock->setPlaybackRate(0.0);
- }
-
- mDrainAudioQueuePending = false;
- mDrainVideoQueuePending = false;
-
- // Note: audio data may not have been decoded, and the AudioSink may not be opened.
- mAudioSink->pause();
- startAudioOffloadPauseTimeout();
-
- ALOGV("now paused audio queue has %zu entries, video has %zu entries",
- mAudioQueue.size(), mVideoQueue.size());
-}
-
-void NuPlayer2::Renderer::onResume() {
- if (!mPaused) {
- return;
- }
-
- // Note: audio data may not have been decoded, and the AudioSink may not be opened.
- cancelAudioOffloadPauseTimeout();
- if (mAudioSink->ready()) {
- status_t err = mAudioSink->start();
- if (err != OK) {
- ALOGE("cannot start AudioSink err %d", err);
- notifyAudioTearDown(kDueToError);
- }
- }
-
- {
- Mutex::Autolock autoLock(mLock);
- mPaused = false;
- // rendering started message may have been delayed if we were paused.
- if (mRenderingDataDelivered) {
- notifyIfMediaRenderingStarted_l();
- }
- // configure audiosink as we did not do it when pausing
- if (mAudioSink != NULL && mAudioSink->ready()) {
- mAudioSink->setPlaybackRate(mPlaybackSettings);
- }
-
- mMediaClock->setPlaybackRate(mPlaybackSettings.mSpeed);
-
- if (!mAudioQueue.empty()) {
- postDrainAudioQueue_l();
- }
- }
-
- if (!mVideoQueue.empty()) {
- postDrainVideoQueue();
- }
-}
-
-void NuPlayer2::Renderer::onSetVideoFrameRate(float fps) {
- if (mVideoScheduler == NULL) {
- mVideoScheduler = new VideoFrameScheduler2();
- }
- mVideoScheduler->init(fps);
-}
-
-int32_t NuPlayer2::Renderer::getQueueGeneration(bool audio) {
- Mutex::Autolock autoLock(mLock);
- return (audio ? mAudioQueueGeneration : mVideoQueueGeneration);
-}
-
-int32_t NuPlayer2::Renderer::getDrainGeneration(bool audio) {
- Mutex::Autolock autoLock(mLock);
- return (audio ? mAudioDrainGeneration : mVideoDrainGeneration);
-}
-
-bool NuPlayer2::Renderer::getSyncQueues() {
- Mutex::Autolock autoLock(mLock);
- return mSyncQueues;
-}
-
-void NuPlayer2::Renderer::onAudioTearDown(AudioTearDownReason reason) {
- if (mAudioTornDown) {
- return;
- }
- mAudioTornDown = true;
-
- int64_t currentPositionUs;
- sp<AMessage> notify = mNotify->dup();
- if (getCurrentPosition(¤tPositionUs) == OK) {
- notify->setInt64("positionUs", currentPositionUs);
- }
-
- mAudioSink->stop();
- mAudioSink->flush();
-
- notify->setInt32("what", kWhatAudioTearDown);
- notify->setInt32("reason", reason);
- notify->post();
-}
-
-void NuPlayer2::Renderer::startAudioOffloadPauseTimeout() {
- if (offloadingAudio()) {
- mWakeLock->acquire();
- sp<AMessage> msg = new AMessage(kWhatAudioOffloadPauseTimeout, this);
- msg->setInt32("drainGeneration", mAudioOffloadPauseTimeoutGeneration);
- msg->post(kOffloadPauseMaxUs);
- }
-}
-
-void NuPlayer2::Renderer::cancelAudioOffloadPauseTimeout() {
- // We may have called startAudioOffloadPauseTimeout() without
- // the AudioSink open and with offloadingAudio enabled.
- //
- // When we cancel, it may be that offloadingAudio is subsequently disabled, so regardless
- // we always release the wakelock and increment the pause timeout generation.
- //
- // Note: The acquired wakelock prevents the device from suspending
- // immediately after offload pause (in case a resume happens shortly thereafter).
- mWakeLock->release(true);
- ++mAudioOffloadPauseTimeoutGeneration;
-}
-
-status_t NuPlayer2::Renderer::onOpenAudioSink(
- const sp<AMessage> &format,
- bool offloadOnly,
- bool hasVideo,
- uint32_t flags,
- bool isStreaming) {
- ALOGV("openAudioSink: offloadOnly(%d) offloadingAudio(%d)",
- offloadOnly, offloadingAudio());
-
- bool audioSinkChanged = false;
-
- int32_t numChannels;
- CHECK(format->findInt32("channel-count", &numChannels));
-
- int32_t channelMask;
- if (!format->findInt32("channel-mask", &channelMask)) {
- // signal to the AudioSink to derive the mask from count.
- channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER;
- }
-
- int32_t sampleRate;
- CHECK(format->findInt32("sample-rate", &sampleRate));
-
- // read pcm encoding from MediaCodec output format, if available
- int32_t pcmEncoding;
- audio_format_t audioFormat =
- format->findInt32(KEY_PCM_ENCODING, &pcmEncoding) ?
- audioFormatFromEncoding(pcmEncoding) : AUDIO_FORMAT_PCM_16_BIT;
-
- if (offloadingAudio()) {
- AString mime;
- CHECK(format->findString("mime", &mime));
- status_t err = mapMimeToAudioFormat(audioFormat, mime.c_str());
-
- if (err != OK) {
- ALOGE("Couldn't map mime \"%s\" to a valid "
- "audio_format", mime.c_str());
- onDisableOffloadAudio();
- } else {
- ALOGV("Mime \"%s\" mapped to audio_format 0x%x",
- mime.c_str(), audioFormat);
-
- int avgBitRate = -1;
- format->findInt32("bitrate", &avgBitRate);
-
- int32_t aacProfile = -1;
- if (audioFormat == AUDIO_FORMAT_AAC
- && format->findInt32("aac-profile", &aacProfile)) {
- // Redefine AAC format as per aac profile
- mapAACProfileToAudioFormat(
- audioFormat,
- aacProfile);
- }
-
- audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER;
- offloadInfo.duration_us = -1;
- format->findInt64(
- "durationUs", &offloadInfo.duration_us);
- offloadInfo.sample_rate = sampleRate;
- offloadInfo.channel_mask = channelMask;
- offloadInfo.format = audioFormat;
- offloadInfo.stream_type = AUDIO_STREAM_MUSIC;
- offloadInfo.bit_rate = avgBitRate;
- offloadInfo.has_video = hasVideo;
- offloadInfo.is_streaming = isStreaming;
-
- if (memcmp(&mCurrentOffloadInfo, &offloadInfo, sizeof(offloadInfo)) == 0) {
- ALOGV("openAudioSink: no change in offload mode");
- // no change from previous configuration, everything ok.
- return OK;
- }
- mCurrentPcmInfo = AUDIO_PCMINFO_INITIALIZER;
-
- ALOGV("openAudioSink: try to open AudioSink in offload mode");
- uint32_t offloadFlags = flags;
- offloadFlags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
- offloadFlags &= ~AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
- audioSinkChanged = true;
- mAudioSink->close();
-
- err = mAudioSink->open(
- sampleRate,
- numChannels,
- (audio_channel_mask_t)channelMask,
- audioFormat,
- &NuPlayer2::Renderer::AudioSinkCallback,
- this,
- (audio_output_flags_t)offloadFlags,
- &offloadInfo);
-
- if (err == OK) {
- err = mAudioSink->setPlaybackRate(mPlaybackSettings);
- }
-
- if (err == OK) {
- // If the playback is offloaded to h/w, we pass
- // the HAL some metadata information.
- // We don't want to do this for PCM because it
- // will be going through the AudioFlinger mixer
- // before reaching the hardware.
- // TODO
- mCurrentOffloadInfo = offloadInfo;
- if (!mPaused) { // for preview mode, don't start if paused
- err = mAudioSink->start();
- }
- ALOGV_IF(err == OK, "openAudioSink: offload succeeded");
- }
- if (err != OK) {
- // Clean up, fall back to non offload mode.
- mAudioSink->close();
- onDisableOffloadAudio();
- mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER;
- ALOGV("openAudioSink: offload failed");
- if (offloadOnly) {
- notifyAudioTearDown(kForceNonOffload);
- }
- } else {
- mUseAudioCallback = true; // offload mode transfers data through callback
- ++mAudioDrainGeneration; // discard pending kWhatDrainAudioQueue message.
- }
- }
- }
- if (!offloadOnly && !offloadingAudio()) {
- ALOGV("openAudioSink: open AudioSink in NON-offload mode");
- uint32_t pcmFlags = flags;
- pcmFlags &= ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
-
- const PcmInfo info = {
- (audio_channel_mask_t)channelMask,
- (audio_output_flags_t)pcmFlags,
- audioFormat,
- numChannels,
- sampleRate
- };
- if (memcmp(&mCurrentPcmInfo, &info, sizeof(info)) == 0) {
- ALOGV("openAudioSink: no change in pcm mode");
- // no change from previous configuration, everything ok.
- return OK;
- }
-
- audioSinkChanged = true;
- mAudioSink->close();
- mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER;
- // Note: It is possible to set up the callback, but not use it to send audio data.
- // This requires a fix in AudioSink to explicitly specify the transfer mode.
- mUseAudioCallback = getUseAudioCallbackSetting();
- if (mUseAudioCallback) {
- ++mAudioDrainGeneration; // discard pending kWhatDrainAudioQueue message.
- }
-
- // Compute the desired buffer size.
- // For callback mode, the amount of time before wakeup is about half the buffer size.
- const uint32_t frameCount =
- (unsigned long long)sampleRate * getAudioSinkPcmMsSetting() / 1000;
-
- // We should always be able to set our playback settings if the sink is closed.
- LOG_ALWAYS_FATAL_IF(mAudioSink->setPlaybackRate(mPlaybackSettings) != OK,
- "onOpenAudioSink: can't set playback rate on closed sink");
- status_t err = mAudioSink->open(
- sampleRate,
- numChannels,
- (audio_channel_mask_t)channelMask,
- audioFormat,
- mUseAudioCallback ? &NuPlayer2::Renderer::AudioSinkCallback : NULL,
- mUseAudioCallback ? this : NULL,
- (audio_output_flags_t)pcmFlags,
- NULL,
- frameCount);
- if (err != OK) {
- ALOGW("openAudioSink: non offloaded open failed status: %d", err);
- mAudioSink->close();
- mCurrentPcmInfo = AUDIO_PCMINFO_INITIALIZER;
- return err;
- }
- mCurrentPcmInfo = info;
- if (!mPaused) { // for preview mode, don't start if paused
- mAudioSink->start();
- }
- }
- if (audioSinkChanged) {
- onAudioSinkChanged();
- }
- mAudioTornDown = false;
- return OK;
-}
-
-void NuPlayer2::Renderer::onCloseAudioSink() {
- mAudioSink->close();
- mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER;
- mCurrentPcmInfo = AUDIO_PCMINFO_INITIALIZER;
-}
-
-void NuPlayer2::Renderer::onChangeAudioFormat(
- const sp<AMessage> &meta, const sp<AMessage> ¬ify) {
- sp<AMessage> format;
- CHECK(meta->findMessage("format", &format));
-
- int32_t offloadOnly;
- CHECK(meta->findInt32("offload-only", &offloadOnly));
-
- int32_t hasVideo;
- CHECK(meta->findInt32("has-video", &hasVideo));
-
- uint32_t flags;
- CHECK(meta->findInt32("flags", (int32_t *)&flags));
-
- uint32_t isStreaming;
- CHECK(meta->findInt32("isStreaming", (int32_t *)&isStreaming));
-
- status_t err = onOpenAudioSink(format, offloadOnly, hasVideo, flags, isStreaming);
-
- if (err != OK) {
- notify->setInt32("err", err);
- }
- notify->post();
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.h
deleted file mode 100644
index d065dee..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.h
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NUPLAYER2_RENDERER_H_
-
-#define NUPLAYER2_RENDERER_H_
-
-#include <media/AudioResamplerPublic.h>
-#include <media/AVSyncSettings.h>
-#include <mediaplayer2/JObjectHolder.h>
-
-#include "NuPlayer2.h"
-
-namespace android {
-
-class JWakeLock;
-struct MediaClock;
-class MediaCodecBuffer;
-struct VideoFrameSchedulerBase;
-
-struct NuPlayer2::Renderer : public AHandler {
- enum Flags {
- FLAG_REAL_TIME = 1,
- FLAG_OFFLOAD_AUDIO = 2,
- };
- Renderer(const sp<MediaPlayer2Interface::AudioSink> &sink,
- const sp<MediaClock> &mediaClock,
- const sp<AMessage> ¬ify,
- const sp<JObjectHolder> &context,
- uint32_t flags = 0);
-
- static size_t AudioSinkCallback(
- MediaPlayer2Interface::AudioSink *audioSink,
- void *data, size_t size, void *me,
- MediaPlayer2Interface::AudioSink::cb_event_t event);
-
- void queueBuffer(
- bool audio,
- const sp<MediaCodecBuffer> &buffer,
- const sp<AMessage> ¬ifyConsumed);
-
- void queueEOS(bool audio, status_t finalResult);
-
- status_t setPlaybackSettings(const AudioPlaybackRate &rate /* sanitized */);
- status_t getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */);
- status_t setSyncSettings(const AVSyncSettings &sync, float videoFpsHint);
- status_t getSyncSettings(AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */);
-
- void flush(bool audio, bool notifyComplete);
-
- void signalTimeDiscontinuity();
-
- void signalDisableOffloadAudio();
- void signalEnableOffloadAudio();
-
- void pause();
- void resume();
-
- void setVideoFrameRate(float fps);
-
- status_t getCurrentPosition(int64_t *mediaUs);
- int64_t getVideoLateByUs();
-
- status_t openAudioSink(
- const sp<AMessage> &format,
- bool offloadOnly,
- bool hasVideo,
- uint32_t flags,
- bool *isOffloaded,
- bool isStreaming);
- void closeAudioSink();
-
- // re-open audio sink after all pending audio buffers played.
- void changeAudioFormat(
- const sp<AMessage> &format,
- bool offloadOnly,
- bool hasVideo,
- uint32_t flags,
- bool isStreaming,
- const sp<AMessage> ¬ify);
-
- enum {
- kWhatEOS = 'eos ',
- kWhatFlushComplete = 'fluC',
- kWhatPosition = 'posi',
- kWhatVideoRenderingStart = 'vdrd',
- kWhatMediaRenderingStart = 'mdrd',
- kWhatAudioTearDown = 'adTD',
- kWhatAudioOffloadPauseTimeout = 'aOPT',
- };
-
- enum AudioTearDownReason {
- kDueToError = 0, // Could restart with either offload or non-offload.
- kDueToTimeout,
- kForceNonOffload, // Restart only with non-offload.
- };
-
-protected:
- virtual ~Renderer();
-
- virtual void onMessageReceived(const sp<AMessage> &msg);
-
-private:
- enum {
- kWhatDrainAudioQueue = 'draA',
- kWhatDrainVideoQueue = 'draV',
- kWhatPostDrainVideoQueue = 'pDVQ',
- kWhatQueueBuffer = 'queB',
- kWhatQueueEOS = 'qEOS',
- kWhatConfigPlayback = 'cfPB',
- kWhatConfigSync = 'cfSy',
- kWhatGetPlaybackSettings = 'gPbS',
- kWhatGetSyncSettings = 'gSyS',
- kWhatFlush = 'flus',
- kWhatPause = 'paus',
- kWhatResume = 'resm',
- kWhatOpenAudioSink = 'opnA',
- kWhatCloseAudioSink = 'clsA',
- kWhatChangeAudioFormat = 'chgA',
- kWhatStopAudioSink = 'stpA',
- kWhatDisableOffloadAudio = 'noOA',
- kWhatEnableOffloadAudio = 'enOA',
- kWhatSetVideoFrameRate = 'sVFR',
- };
-
- // if mBuffer != nullptr, it's a buffer containing real data.
- // else if mNotifyConsumed == nullptr, it's EOS.
- // else it's a tag for re-opening audio sink in different format.
- struct QueueEntry {
- sp<MediaCodecBuffer> mBuffer;
- sp<AMessage> mMeta;
- sp<AMessage> mNotifyConsumed;
- size_t mOffset;
- status_t mFinalResult;
- int32_t mBufferOrdinal;
- };
-
- static const int64_t kMinPositionUpdateDelayUs;
-
- sp<MediaPlayer2Interface::AudioSink> mAudioSink;
- bool mUseVirtualAudioSink;
- sp<AMessage> mNotify;
- Mutex mLock;
- uint32_t mFlags;
- List<QueueEntry> mAudioQueue;
- List<QueueEntry> mVideoQueue;
- uint32_t mNumFramesWritten;
- sp<VideoFrameSchedulerBase> mVideoScheduler;
-
- bool mDrainAudioQueuePending;
- bool mDrainVideoQueuePending;
- int32_t mAudioQueueGeneration;
- int32_t mVideoQueueGeneration;
- int32_t mAudioDrainGeneration;
- int32_t mVideoDrainGeneration;
- int32_t mAudioEOSGeneration;
-
- const sp<MediaClock> mMediaClock;
-
- AudioPlaybackRate mPlaybackSettings;
- AVSyncSettings mSyncSettings;
- float mVideoFpsHint;
-
- int64_t mAudioFirstAnchorTimeMediaUs;
- int64_t mAnchorTimeMediaUs;
- int64_t mAnchorNumFramesWritten;
- int64_t mVideoLateByUs;
- int64_t mNextVideoTimeMediaUs;
- bool mHasAudio;
- bool mHasVideo;
-
- bool mNotifyCompleteAudio;
- bool mNotifyCompleteVideo;
-
- bool mSyncQueues;
-
- // modified on only renderer's thread.
- bool mPaused;
- int64_t mPauseDrainAudioAllowedUs; // time when we can drain/deliver audio in pause mode.
-
- bool mVideoSampleReceived;
- bool mVideoRenderingStarted;
- int32_t mVideoRenderingStartGeneration;
- int32_t mAudioRenderingStartGeneration;
- bool mRenderingDataDelivered;
-
- int64_t mNextAudioClockUpdateTimeUs;
- // the media timestamp of last audio sample right before EOS.
- int64_t mLastAudioMediaTimeUs;
-
- int32_t mAudioOffloadPauseTimeoutGeneration;
- bool mAudioTornDown;
- audio_offload_info_t mCurrentOffloadInfo;
-
- struct PcmInfo {
- audio_channel_mask_t mChannelMask;
- audio_output_flags_t mFlags;
- audio_format_t mFormat;
- int32_t mNumChannels;
- int32_t mSampleRate;
- };
- PcmInfo mCurrentPcmInfo;
- static const PcmInfo AUDIO_PCMINFO_INITIALIZER;
-
- int32_t mTotalBuffersQueued;
- int32_t mLastAudioBufferDrained;
- bool mUseAudioCallback;
-
- sp<JWakeLock> mWakeLock;
-
- status_t getCurrentPositionOnLooper(int64_t *mediaUs);
- status_t getCurrentPositionOnLooper(
- int64_t *mediaUs, int64_t nowUs, bool allowPastQueuedVideo = false);
- bool getCurrentPositionIfPaused_l(int64_t *mediaUs);
- status_t getCurrentPositionFromAnchor(
- int64_t *mediaUs, int64_t nowUs, bool allowPastQueuedVideo = false);
-
- void notifyEOSCallback();
- size_t fillAudioBuffer(void *buffer, size_t size);
-
- bool onDrainAudioQueue();
- void drainAudioQueueUntilLastEOS();
- int64_t getPendingAudioPlayoutDurationUs(int64_t nowUs);
- void postDrainAudioQueue_l(int64_t delayUs = 0);
-
- void clearAnchorTime();
- void clearAudioFirstAnchorTime_l();
- void setAudioFirstAnchorTimeIfNeeded_l(int64_t mediaUs);
- void setVideoLateByUs(int64_t lateUs);
-
- void onNewAudioMediaTime(int64_t mediaTimeUs);
- int64_t getRealTimeUs(int64_t mediaTimeUs, int64_t nowUs);
-
- void onDrainVideoQueue();
- void postDrainVideoQueue();
-
- void prepareForMediaRenderingStart_l();
- void notifyIfMediaRenderingStarted_l();
-
- void onQueueBuffer(const sp<AMessage> &msg);
- void onQueueEOS(const sp<AMessage> &msg);
- void onFlush(const sp<AMessage> &msg);
- void onAudioSinkChanged();
- void onDisableOffloadAudio();
- void onEnableOffloadAudio();
- status_t onConfigPlayback(const AudioPlaybackRate &rate /* sanitized */);
- status_t onGetPlaybackSettings(AudioPlaybackRate *rate /* nonnull */);
- status_t onConfigSync(const AVSyncSettings &sync, float videoFpsHint);
- status_t onGetSyncSettings(AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */);
-
- void onPause();
- void onResume();
- void onSetVideoFrameRate(float fps);
- int32_t getQueueGeneration(bool audio);
- int32_t getDrainGeneration(bool audio);
- bool getSyncQueues();
- void onAudioTearDown(AudioTearDownReason reason);
- status_t onOpenAudioSink(
- const sp<AMessage> &format,
- bool offloadOnly,
- bool hasVideo,
- uint32_t flags,
- bool isStreaming);
- void onCloseAudioSink();
- void onChangeAudioFormat(const sp<AMessage> &meta, const sp<AMessage> ¬ify);
-
- void notifyEOS(bool audio, status_t finalResult, int64_t delayUs = 0);
- void notifyEOS_l(bool audio, status_t finalResult, int64_t delayUs = 0);
- void notifyFlushComplete(bool audio);
- void notifyPosition();
- void notifyVideoLateBy(int64_t lateByUs);
- void notifyVideoRenderingStart();
- void notifyAudioTearDown(AudioTearDownReason reason);
-
- void flushQueue(List<QueueEntry> *queue);
- bool dropBufferIfStale(bool audio, const sp<AMessage> &msg);
- void syncQueuesDone_l();
-
- bool offloadingAudio() const { return (mFlags & FLAG_OFFLOAD_AUDIO) != 0; }
-
- void startAudioOffloadPauseTimeout();
- void cancelAudioOffloadPauseTimeout();
-
- int64_t getDurationUsIfPlayedAtSampleRate(uint32_t numFrames);
-
- DISALLOW_EVIL_CONSTRUCTORS(Renderer);
-};
-
-} // namespace android
-
-#endif // NUPLAYER2_RENDERER_H_
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h
deleted file mode 100644
index 9298a99..0000000
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NUPLAYER2_SOURCE_H_
-
-#define NUPLAYER2_SOURCE_H_
-
-#include "NuPlayer2.h"
-
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MetaData.h>
-#include <mediaplayer2/mediaplayer2.h>
-#include <utils/Vector.h>
-
-namespace android {
-
-struct ABuffer;
-struct AMediaCryptoWrapper;
-class MediaBuffer;
-
-struct NuPlayer2::Source : public AHandler {
- enum Flags {
- FLAG_CAN_PAUSE = 1,
- FLAG_CAN_SEEK_BACKWARD = 2, // the "10 sec back button"
- FLAG_CAN_SEEK_FORWARD = 4, // the "10 sec forward button"
- FLAG_CAN_SEEK = 8, // the "seek bar"
- FLAG_DYNAMIC_DURATION = 16,
- FLAG_SECURE = 32, // Secure codec is required.
- FLAG_PROTECTED = 64, // The screen needs to be protected (screenshot is disabled).
- };
-
- enum {
- kWhatPrepared,
- kWhatFlagsChanged,
- kWhatVideoSizeChanged,
- kWhatBufferingUpdate,
- kWhatPauseOnBufferingStart,
- kWhatResumeOnBufferingEnd,
- kWhatCacheStats,
- kWhatSubtitleData,
- kWhatTimedTextData,
- kWhatTimedMetaData,
- kWhatQueueDecoderShutdown,
- kWhatDrmNoLicense,
- // Modular DRM
- kWhatDrmInfo,
- };
-
- // The provides message is used to notify the player about various
- // events.
- explicit Source(const sp<AMessage> ¬ify)
- : mNotify(notify) {
- }
-
- virtual status_t getBufferingSettings(
- BufferingSettings* buffering /* nonnull */) = 0;
- virtual status_t setBufferingSettings(const BufferingSettings& buffering) = 0;
-
- virtual void prepareAsync(int64_t startTimeUs) = 0;
-
- virtual void start() = 0;
- virtual void stop() {}
- virtual void pause() {}
- virtual void resume() {}
-
- // Explicitly disconnect the underling data source
- virtual void disconnect() {}
-
- // Returns OK iff more data was available,
- // an error or ERROR_END_OF_STREAM if not.
- virtual status_t feedMoreTSData() = 0;
-
- // Returns non-NULL format when the specified track exists.
- // When the format has "err" set to -EWOULDBLOCK, source needs more time to get valid meta data.
- // Returns NULL if the specified track doesn't exist or is invalid;
- virtual sp<AMessage> getFormat(bool audio);
-
- virtual sp<MetaData> getFormatMeta(bool /* audio */) { return NULL; }
- virtual sp<MetaData> getFileFormatMeta() const { return NULL; }
-
- virtual status_t dequeueAccessUnit(
- bool audio, sp<ABuffer> *accessUnit) = 0;
-
- virtual status_t getDuration(int64_t * /* durationUs */) {
- return INVALID_OPERATION;
- }
-
- virtual size_t getTrackCount() const {
- return 0;
- }
-
- virtual sp<AMessage> getTrackInfo(size_t /* trackIndex */) const {
- return NULL;
- }
-
- virtual ssize_t getSelectedTrack(media_track_type /* type */) const {
- return INVALID_OPERATION;
- }
-
- virtual status_t selectTrack(size_t /* trackIndex */, bool /* select */, int64_t /* timeUs*/) {
- return INVALID_OPERATION;
- }
-
- virtual status_t seekTo(
- int64_t /* seekTimeUs */,
- MediaPlayer2SeekMode /* mode */ = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC) {
- return INVALID_OPERATION;
- }
-
- virtual bool isRealTime() const {
- return false;
- }
-
- virtual bool isStreaming() const {
- return true;
- }
-
- virtual void setOffloadAudio(bool /* offload */) {}
-
- // Modular DRM
- virtual status_t prepareDrm(
- const uint8_t /* uuid */[16], const Vector<uint8_t> & /* drmSessionId */,
- sp<AMediaCryptoWrapper> * /* crypto */) {
- return INVALID_OPERATION;
- }
-
- virtual status_t releaseDrm() {
- return INVALID_OPERATION;
- }
-
-protected:
- virtual ~Source() {}
-
- virtual void onMessageReceived(const sp<AMessage> &msg);
-
- sp<AMessage> dupNotify() const { return mNotify->dup(); }
-
- void notifyFlagsChanged(uint32_t flags);
- void notifyVideoSizeChanged(const sp<AMessage> &format = NULL);
- void notifyPrepared(status_t err = OK);
- // Modular DRM
- void notifyDrmInfo(const sp<ABuffer> &buffer);
-
-private:
- sp<AMessage> mNotify;
-
- DISALLOW_EVIL_CONSTRUCTORS(Source);
-};
-
-} // namespace android
-
-#endif // NUPLAYER2_SOURCE_H_
-
diff --git a/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp b/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp
deleted file mode 100644
index a70269e..0000000
--- a/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp
+++ /dev/null
@@ -1,903 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "RTSPSource2"
-#include <utils/Log.h>
-
-#include "RTSPSource2.h"
-
-#include "AnotherPacketSource.h"
-#include "MyHandler.h"
-#include "SDPLoader.h"
-
-#include <media/MediaHTTPService.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MetaData.h>
-
-namespace android {
-
-const int64_t kNearEOSTimeoutUs = 2000000LL; // 2 secs
-
-// Default Buffer Underflow/Prepare/StartServer/Overflow Marks
-static const int kUnderflowMarkMs = 1000; // 1 second
-static const int kPrepareMarkMs = 3000; // 3 seconds
-//static const int kStartServerMarkMs = 5000;
-static const int kOverflowMarkMs = 10000; // 10 seconds
-
-NuPlayer2::RTSPSource2::RTSPSource2(
- const sp<AMessage> ¬ify,
- const sp<MediaHTTPService> &httpService,
- const char *url,
- const KeyedVector<String8, String8> *headers,
- uid_t uid,
- bool isSDP)
- : Source(notify),
- mHTTPService(httpService),
- mURL(url),
- mUID(uid),
- mFlags(0),
- mIsSDP(isSDP),
- mState(DISCONNECTED),
- mFinalResult(OK),
- mDisconnectReplyID(0),
- mBuffering(false),
- mInPreparationPhase(true),
- mEOSPending(false),
- mSeekGeneration(0),
- mEOSTimeoutAudio(0),
- mEOSTimeoutVideo(0) {
- mBufferingSettings.mInitialMarkMs = kPrepareMarkMs;
- mBufferingSettings.mResumePlaybackMarkMs = kOverflowMarkMs;
- if (headers) {
- mExtraHeaders = *headers;
-
- ssize_t index =
- mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log"));
-
- if (index >= 0) {
- mFlags |= kFlagIncognito;
-
- mExtraHeaders.removeItemsAt(index);
- }
- }
-}
-
-NuPlayer2::RTSPSource2::~RTSPSource2() {
- if (mLooper != NULL) {
- mLooper->unregisterHandler(id());
- mLooper->stop();
- }
-}
-
-status_t NuPlayer2::RTSPSource2::getBufferingSettings(
- BufferingSettings* buffering /* nonnull */) {
- Mutex::Autolock _l(mBufferingSettingsLock);
- *buffering = mBufferingSettings;
- return OK;
-}
-
-status_t NuPlayer2::RTSPSource2::setBufferingSettings(const BufferingSettings& buffering) {
- Mutex::Autolock _l(mBufferingSettingsLock);
- mBufferingSettings = buffering;
- return OK;
-}
-
-// TODO: fetch data starting from |startTimeUs|
-void NuPlayer2::RTSPSource2::prepareAsync(int64_t /* startTimeUs */) {
- if (mIsSDP && mHTTPService == NULL) {
- notifyPrepared(BAD_VALUE);
- return;
- }
-
- if (mLooper == NULL) {
- mLooper = new ALooper;
- mLooper->setName("rtsp2");
- mLooper->start();
-
- mLooper->registerHandler(this);
- }
-
- CHECK(mHandler == NULL);
- CHECK(mSDPLoader == NULL);
-
- sp<AMessage> notify = new AMessage(kWhatNotify, this);
-
- CHECK_EQ(mState, (int)DISCONNECTED);
- mState = CONNECTING;
-
- if (mIsSDP) {
- mSDPLoader = new SDPLoader(notify,
- (mFlags & kFlagIncognito) ? SDPLoader::kFlagIncognito : 0,
- mHTTPService);
-
- mSDPLoader->load(
- mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
- } else {
- mHandler = new MyHandler(mURL.c_str(), notify, true /* uidValid */, mUID);
- mLooper->registerHandler(mHandler);
-
- mHandler->connect();
- }
-
- startBufferingIfNecessary();
-}
-
-void NuPlayer2::RTSPSource2::start() {
-}
-
-void NuPlayer2::RTSPSource2::stop() {
- if (mLooper == NULL) {
- return;
- }
- sp<AMessage> msg = new AMessage(kWhatDisconnect, this);
-
- sp<AMessage> dummy;
- msg->postAndAwaitResponse(&dummy);
-}
-
-status_t NuPlayer2::RTSPSource2::feedMoreTSData() {
- Mutex::Autolock _l(mBufferingLock);
- return mFinalResult;
-}
-
-sp<MetaData> NuPlayer2::RTSPSource2::getFormatMeta(bool audio) {
- sp<AnotherPacketSource> source = getSource(audio);
-
- if (source == NULL) {
- return NULL;
- }
-
- return source->getFormat();
-}
-
-bool NuPlayer2::RTSPSource2::haveSufficientDataOnAllTracks() {
- // We're going to buffer at least 2 secs worth data on all tracks before
- // starting playback (both at startup and after a seek).
-
- static const int64_t kMinDurationUs = 2000000LL;
-
- int64_t mediaDurationUs = 0;
- getDuration(&mediaDurationUs);
- if ((mAudioTrack != NULL && mAudioTrack->isFinished(mediaDurationUs))
- || (mVideoTrack != NULL && mVideoTrack->isFinished(mediaDurationUs))) {
- return true;
- }
-
- status_t err;
- int64_t durationUs;
- if (mAudioTrack != NULL
- && (durationUs = mAudioTrack->getBufferedDurationUs(&err))
- < kMinDurationUs
- && err == OK) {
- ALOGV("audio track doesn't have enough data yet. (%.2f secs buffered)",
- durationUs / 1E6);
- return false;
- }
-
- if (mVideoTrack != NULL
- && (durationUs = mVideoTrack->getBufferedDurationUs(&err))
- < kMinDurationUs
- && err == OK) {
- ALOGV("video track doesn't have enough data yet. (%.2f secs buffered)",
- durationUs / 1E6);
- return false;
- }
-
- return true;
-}
-
-status_t NuPlayer2::RTSPSource2::dequeueAccessUnit(
- bool audio, sp<ABuffer> *accessUnit) {
- if (!stopBufferingIfNecessary()) {
- return -EWOULDBLOCK;
- }
-
- sp<AnotherPacketSource> source = getSource(audio);
-
- if (source == NULL) {
- return -EWOULDBLOCK;
- }
-
- status_t finalResult;
- if (!source->hasBufferAvailable(&finalResult)) {
- if (finalResult == OK) {
-
- // If other source already signaled EOS, this source should also return EOS
- if (sourceReachedEOS(!audio)) {
- return ERROR_END_OF_STREAM;
- }
-
- // If this source has detected near end, give it some time to retrieve more
- // data before returning EOS
- int64_t mediaDurationUs = 0;
- getDuration(&mediaDurationUs);
- if (source->isFinished(mediaDurationUs)) {
- int64_t eosTimeout = audio ? mEOSTimeoutAudio : mEOSTimeoutVideo;
- if (eosTimeout == 0) {
- setEOSTimeout(audio, ALooper::GetNowUs());
- } else if ((ALooper::GetNowUs() - eosTimeout) > kNearEOSTimeoutUs) {
- setEOSTimeout(audio, 0);
- return ERROR_END_OF_STREAM;
- }
- return -EWOULDBLOCK;
- }
-
- if (!sourceNearEOS(!audio)) {
- // We should not enter buffering mode
- // if any of the sources already have detected EOS.
- startBufferingIfNecessary();
- }
-
- return -EWOULDBLOCK;
- }
- return finalResult;
- }
-
- setEOSTimeout(audio, 0);
-
- return source->dequeueAccessUnit(accessUnit);
-}
-
-sp<AnotherPacketSource> NuPlayer2::RTSPSource2::getSource(bool audio) {
- if (mTSParser != NULL) {
- sp<MediaSource> source = mTSParser->getSource(
- audio ? ATSParser::AUDIO : ATSParser::VIDEO);
-
- return static_cast<AnotherPacketSource *>(source.get());
- }
-
- return audio ? mAudioTrack : mVideoTrack;
-}
-
-void NuPlayer2::RTSPSource2::setEOSTimeout(bool audio, int64_t timeout) {
- if (audio) {
- mEOSTimeoutAudio = timeout;
- } else {
- mEOSTimeoutVideo = timeout;
- }
-}
-
-status_t NuPlayer2::RTSPSource2::getDuration(int64_t *durationUs) {
- *durationUs = -1LL;
-
- int64_t audioDurationUs;
- if (mAudioTrack != NULL
- && mAudioTrack->getFormat()->findInt64(
- kKeyDuration, &audioDurationUs)
- && audioDurationUs > *durationUs) {
- *durationUs = audioDurationUs;
- }
-
- int64_t videoDurationUs;
- if (mVideoTrack != NULL
- && mVideoTrack->getFormat()->findInt64(
- kKeyDuration, &videoDurationUs)
- && videoDurationUs > *durationUs) {
- *durationUs = videoDurationUs;
- }
-
- return OK;
-}
-
-status_t NuPlayer2::RTSPSource2::seekTo(int64_t seekTimeUs, MediaPlayer2SeekMode mode) {
- sp<AMessage> msg = new AMessage(kWhatPerformSeek, this);
- msg->setInt32("generation", ++mSeekGeneration);
- msg->setInt64("timeUs", seekTimeUs);
- msg->setInt32("mode", mode);
-
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- }
-
- return err;
-}
-
-void NuPlayer2::RTSPSource2::performSeek(int64_t seekTimeUs) {
- if (mState != CONNECTED) {
- finishSeek(INVALID_OPERATION);
- return;
- }
-
- mState = SEEKING;
- mHandler->seek(seekTimeUs);
- mEOSPending = false;
-}
-
-void NuPlayer2::RTSPSource2::schedulePollBuffering() {
- sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
- msg->post(1000000LL); // 1 second intervals
-}
-
-void NuPlayer2::RTSPSource2::checkBuffering(
- bool *prepared, bool *underflow, bool *overflow, bool *startServer, bool *finished) {
- size_t numTracks = mTracks.size();
- size_t preparedCount, underflowCount, overflowCount, startCount, finishedCount;
- preparedCount = underflowCount = overflowCount = startCount = finishedCount = 0;
-
- size_t count = numTracks;
- for (size_t i = 0; i < count; ++i) {
- status_t finalResult;
- TrackInfo *info = &mTracks.editItemAt(i);
- sp<AnotherPacketSource> src = info->mSource;
- if (src == NULL) {
- --numTracks;
- continue;
- }
- int64_t bufferedDurationUs = src->getBufferedDurationUs(&finalResult);
-
- int64_t initialMarkUs;
- int64_t maxRebufferingMarkUs;
- {
- Mutex::Autolock _l(mBufferingSettingsLock);
- initialMarkUs = mBufferingSettings.mInitialMarkMs * 1000LL;
- // TODO: maxRebufferingMarkUs could be larger than
- // mBufferingSettings.mResumePlaybackMarkMs * 1000ll.
- maxRebufferingMarkUs = mBufferingSettings.mResumePlaybackMarkMs * 1000LL;
- }
- // isFinished when duration is 0 checks for EOS result only
- if (bufferedDurationUs > initialMarkUs
- || src->isFinished(/* duration */ 0)) {
- ++preparedCount;
- }
-
- if (src->isFinished(/* duration */ 0)) {
- ++overflowCount;
- ++finishedCount;
- } else {
- // TODO: redefine kUnderflowMarkMs to a fair value,
- if (bufferedDurationUs < kUnderflowMarkMs * 1000) {
- ++underflowCount;
- }
- if (bufferedDurationUs > maxRebufferingMarkUs) {
- ++overflowCount;
- }
- int64_t startServerMarkUs =
- (kUnderflowMarkMs * 1000LL + maxRebufferingMarkUs) / 2;
- if (bufferedDurationUs < startServerMarkUs) {
- ++startCount;
- }
- }
- }
-
- *prepared = (preparedCount == numTracks);
- *underflow = (underflowCount > 0);
- *overflow = (overflowCount == numTracks);
- *startServer = (startCount > 0);
- *finished = (finishedCount > 0);
-}
-
-void NuPlayer2::RTSPSource2::onPollBuffering() {
- bool prepared, underflow, overflow, startServer, finished;
- checkBuffering(&prepared, &underflow, &overflow, &startServer, &finished);
-
- if (prepared && mInPreparationPhase) {
- mInPreparationPhase = false;
- notifyPrepared();
- }
-
- if (!mInPreparationPhase && underflow) {
- startBufferingIfNecessary();
- }
-
- if (haveSufficientDataOnAllTracks()) {
- stopBufferingIfNecessary();
- }
-
- if (overflow && mHandler != NULL) {
- mHandler->pause();
- }
-
- if (startServer && mHandler != NULL) {
- mHandler->resume();
- }
-
- if (finished && mHandler != NULL) {
- mHandler->cancelAccessUnitTimeoutCheck();
- }
-
- schedulePollBuffering();
-}
-
-void NuPlayer2::RTSPSource2::signalSourceEOS(status_t result) {
- const bool audio = true;
- const bool video = false;
-
- sp<AnotherPacketSource> source = getSource(audio);
- if (source != NULL) {
- source->signalEOS(result);
- }
-
- source = getSource(video);
- if (source != NULL) {
- source->signalEOS(result);
- }
-}
-
-bool NuPlayer2::RTSPSource2::sourceReachedEOS(bool audio) {
- sp<AnotherPacketSource> source = getSource(audio);
- status_t finalResult;
- return (source != NULL &&
- !source->hasBufferAvailable(&finalResult) &&
- finalResult == ERROR_END_OF_STREAM);
-}
-
-bool NuPlayer2::RTSPSource2::sourceNearEOS(bool audio) {
- sp<AnotherPacketSource> source = getSource(audio);
- int64_t mediaDurationUs = 0;
- getDuration(&mediaDurationUs);
- return (source != NULL && source->isFinished(mediaDurationUs));
-}
-
-void NuPlayer2::RTSPSource2::onSignalEOS(const sp<AMessage> &msg) {
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
-
- if (generation != mSeekGeneration) {
- return;
- }
-
- if (mEOSPending) {
- signalSourceEOS(ERROR_END_OF_STREAM);
- mEOSPending = false;
- }
-}
-
-void NuPlayer2::RTSPSource2::postSourceEOSIfNecessary() {
- const bool audio = true;
- const bool video = false;
- // If a source has detected near end, give it some time to retrieve more
- // data before signaling EOS
- if (sourceNearEOS(audio) || sourceNearEOS(video)) {
- if (!mEOSPending) {
- sp<AMessage> msg = new AMessage(kWhatSignalEOS, this);
- msg->setInt32("generation", mSeekGeneration);
- msg->post(kNearEOSTimeoutUs);
- mEOSPending = true;
- }
- }
-}
-
-void NuPlayer2::RTSPSource2::onMessageReceived(const sp<AMessage> &msg) {
- if (msg->what() == kWhatDisconnect) {
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
- mDisconnectReplyID = replyID;
- finishDisconnectIfPossible();
- return;
- } else if (msg->what() == kWhatPerformSeek) {
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
- CHECK(msg->senderAwaitsResponse(&mSeekReplyID));
-
- if (generation != mSeekGeneration) {
- // obsolete.
- finishSeek(OK);
- return;
- }
-
- int64_t seekTimeUs;
- int32_t mode;
- CHECK(msg->findInt64("timeUs", &seekTimeUs));
- CHECK(msg->findInt32("mode", &mode));
-
- // TODO: add "mode" to performSeek.
- performSeek(seekTimeUs/*, (MediaPlayer2SeekMode)mode */);
- return;
- } else if (msg->what() == kWhatPollBuffering) {
- onPollBuffering();
- return;
- } else if (msg->what() == kWhatSignalEOS) {
- onSignalEOS(msg);
- return;
- }
-
- CHECK_EQ(msg->what(), kWhatNotify);
-
- int32_t what;
- CHECK(msg->findInt32("what", &what));
-
- switch (what) {
- case MyHandler::kWhatConnected:
- {
- onConnected();
-
- notifyVideoSizeChanged();
-
- uint32_t flags = 0;
-
- if (mHandler->isSeekable()) {
- flags = FLAG_CAN_PAUSE
- | FLAG_CAN_SEEK
- | FLAG_CAN_SEEK_BACKWARD
- | FLAG_CAN_SEEK_FORWARD;
- }
-
- notifyFlagsChanged(flags);
- schedulePollBuffering();
- break;
- }
-
- case MyHandler::kWhatDisconnected:
- {
- onDisconnected(msg);
- break;
- }
-
- case MyHandler::kWhatSeekDone:
- {
- mState = CONNECTED;
- // Unblock seekTo here in case we attempted to seek in a live stream
- finishSeek(OK);
- break;
- }
-
- case MyHandler::kWhatSeekPaused:
- {
- sp<AnotherPacketSource> source = getSource(true /* audio */);
- if (source != NULL) {
- source->queueDiscontinuity(ATSParser::DISCONTINUITY_NONE,
- /* extra */ NULL,
- /* discard */ true);
- }
- source = getSource(false /* video */);
- if (source != NULL) {
- source->queueDiscontinuity(ATSParser::DISCONTINUITY_NONE,
- /* extra */ NULL,
- /* discard */ true);
- };
-
- status_t err = OK;
- msg->findInt32("err", &err);
-
- if (err == OK) {
- int64_t timeUs;
- CHECK(msg->findInt64("time", &timeUs));
- mHandler->continueSeekAfterPause(timeUs);
- } else {
- finishSeek(err);
- }
- break;
- }
-
- case MyHandler::kWhatAccessUnit:
- {
- size_t trackIndex;
- CHECK(msg->findSize("trackIndex", &trackIndex));
-
- if (mTSParser == NULL) {
- CHECK_LT(trackIndex, mTracks.size());
- } else {
- CHECK_EQ(trackIndex, 0u);
- }
-
- sp<ABuffer> accessUnit;
- CHECK(msg->findBuffer("accessUnit", &accessUnit));
-
- int32_t damaged;
- if (accessUnit->meta()->findInt32("damaged", &damaged)
- && damaged) {
- ALOGI("dropping damaged access unit.");
- break;
- }
-
- if (mTSParser != NULL) {
- size_t offset = 0;
- status_t err = OK;
- while (offset + 188 <= accessUnit->size()) {
- err = mTSParser->feedTSPacket(
- accessUnit->data() + offset, 188);
- if (err != OK) {
- break;
- }
-
- offset += 188;
- }
-
- if (offset < accessUnit->size()) {
- err = ERROR_MALFORMED;
- }
-
- if (err != OK) {
- signalSourceEOS(err);
- }
-
- postSourceEOSIfNecessary();
- break;
- }
-
- TrackInfo *info = &mTracks.editItemAt(trackIndex);
-
- sp<AnotherPacketSource> source = info->mSource;
- if (source != NULL) {
- uint32_t rtpTime;
- CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
-
- if (!info->mNPTMappingValid) {
- // This is a live stream, we didn't receive any normal
- // playtime mapping. We won't map to npt time.
- source->queueAccessUnit(accessUnit);
- break;
- }
-
- int64_t nptUs =
- ((double)rtpTime - (double)info->mRTPTime)
- / info->mTimeScale
- * 1000000LL
- + info->mNormalPlaytimeUs;
-
- accessUnit->meta()->setInt64("timeUs", nptUs);
-
- source->queueAccessUnit(accessUnit);
- }
- postSourceEOSIfNecessary();
- break;
- }
-
- case MyHandler::kWhatEOS:
- {
- int32_t finalResult;
- CHECK(msg->findInt32("finalResult", &finalResult));
- CHECK_NE(finalResult, (status_t)OK);
-
- if (mTSParser != NULL) {
- signalSourceEOS(finalResult);
- }
-
- size_t trackIndex;
- CHECK(msg->findSize("trackIndex", &trackIndex));
- CHECK_LT(trackIndex, mTracks.size());
-
- TrackInfo *info = &mTracks.editItemAt(trackIndex);
- sp<AnotherPacketSource> source = info->mSource;
- if (source != NULL) {
- source->signalEOS(finalResult);
- }
-
- break;
- }
-
- case MyHandler::kWhatSeekDiscontinuity:
- {
- size_t trackIndex;
- CHECK(msg->findSize("trackIndex", &trackIndex));
- CHECK_LT(trackIndex, mTracks.size());
-
- TrackInfo *info = &mTracks.editItemAt(trackIndex);
- sp<AnotherPacketSource> source = info->mSource;
- if (source != NULL) {
- source->queueDiscontinuity(
- ATSParser::DISCONTINUITY_TIME,
- NULL,
- true /* discard */);
- }
-
- break;
- }
-
- case MyHandler::kWhatNormalPlayTimeMapping:
- {
- size_t trackIndex;
- CHECK(msg->findSize("trackIndex", &trackIndex));
- CHECK_LT(trackIndex, mTracks.size());
-
- uint32_t rtpTime;
- CHECK(msg->findInt32("rtpTime", (int32_t *)&rtpTime));
-
- int64_t nptUs;
- CHECK(msg->findInt64("nptUs", &nptUs));
-
- TrackInfo *info = &mTracks.editItemAt(trackIndex);
- info->mRTPTime = rtpTime;
- info->mNormalPlaytimeUs = nptUs;
- info->mNPTMappingValid = true;
- break;
- }
-
- case SDPLoader::kWhatSDPLoaded:
- {
- onSDPLoaded(msg);
- break;
- }
-
- default:
- TRESPASS();
- }
-}
-
-void NuPlayer2::RTSPSource2::onConnected() {
- CHECK(mAudioTrack == NULL);
- CHECK(mVideoTrack == NULL);
-
- size_t numTracks = mHandler->countTracks();
- for (size_t i = 0; i < numTracks; ++i) {
- int32_t timeScale;
- sp<MetaData> format = mHandler->getTrackFormat(i, &timeScale);
-
- const char *mime;
- CHECK(format->findCString(kKeyMIMEType, &mime));
-
- if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
- // Very special case for MPEG2 Transport Streams.
- CHECK_EQ(numTracks, 1u);
-
- mTSParser = new ATSParser;
- return;
- }
-
- bool isAudio = !strncasecmp(mime, "audio/", 6);
- bool isVideo = !strncasecmp(mime, "video/", 6);
-
- TrackInfo info;
- info.mTimeScale = timeScale;
- info.mRTPTime = 0;
- info.mNormalPlaytimeUs = 0LL;
- info.mNPTMappingValid = false;
-
- if ((isAudio && mAudioTrack == NULL)
- || (isVideo && mVideoTrack == NULL)) {
- sp<AnotherPacketSource> source = new AnotherPacketSource(format);
-
- if (isAudio) {
- mAudioTrack = source;
- } else {
- mVideoTrack = source;
- }
-
- info.mSource = source;
- }
-
- mTracks.push(info);
- }
-
- mState = CONNECTED;
-}
-
-void NuPlayer2::RTSPSource2::onSDPLoaded(const sp<AMessage> &msg) {
- status_t err;
- CHECK(msg->findInt32("result", &err));
-
- mSDPLoader.clear();
-
- if (mDisconnectReplyID != 0) {
- err = UNKNOWN_ERROR;
- }
-
- if (err == OK) {
- sp<ASessionDescription> desc;
- sp<RefBase> obj;
- CHECK(msg->findObject("description", &obj));
- desc = static_cast<ASessionDescription *>(obj.get());
-
- AString rtspUri;
- if (!desc->findAttribute(0, "a=control", &rtspUri)) {
- ALOGE("Unable to find url in SDP");
- err = UNKNOWN_ERROR;
- } else {
- sp<AMessage> notify = new AMessage(kWhatNotify, this);
-
- mHandler = new MyHandler(rtspUri.c_str(), notify, true /* uidValid */, mUID);
- mLooper->registerHandler(mHandler);
-
- mHandler->loadSDP(desc);
- }
- }
-
- if (err != OK) {
- if (mState == CONNECTING) {
- // We're still in the preparation phase, signal that it
- // failed.
- notifyPrepared(err);
- }
-
- mState = DISCONNECTED;
- setError(err);
-
- if (mDisconnectReplyID != 0) {
- finishDisconnectIfPossible();
- }
- }
-}
-
-void NuPlayer2::RTSPSource2::onDisconnected(const sp<AMessage> &msg) {
- if (mState == DISCONNECTED) {
- return;
- }
-
- status_t err;
- CHECK(msg->findInt32("result", &err));
- CHECK_NE(err, (status_t)OK);
-
- mLooper->unregisterHandler(mHandler->id());
- mHandler.clear();
-
- if (mState == CONNECTING) {
- // We're still in the preparation phase, signal that it
- // failed.
- notifyPrepared(err);
- }
-
- mState = DISCONNECTED;
- setError(err);
-
- if (mDisconnectReplyID != 0) {
- finishDisconnectIfPossible();
- }
-}
-
-void NuPlayer2::RTSPSource2::finishDisconnectIfPossible() {
- if (mState != DISCONNECTED) {
- if (mHandler != NULL) {
- mHandler->disconnect();
- } else if (mSDPLoader != NULL) {
- mSDPLoader->cancel();
- }
- return;
- }
-
- (new AMessage)->postReply(mDisconnectReplyID);
- mDisconnectReplyID = 0;
-}
-
-void NuPlayer2::RTSPSource2::setError(status_t err) {
- Mutex::Autolock _l(mBufferingLock);
- mFinalResult = err;
-}
-
-void NuPlayer2::RTSPSource2::startBufferingIfNecessary() {
- Mutex::Autolock _l(mBufferingLock);
-
- if (!mBuffering) {
- mBuffering = true;
-
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatPauseOnBufferingStart);
- notify->post();
- }
-}
-
-bool NuPlayer2::RTSPSource2::stopBufferingIfNecessary() {
- Mutex::Autolock _l(mBufferingLock);
-
- if (mBuffering) {
- if (!haveSufficientDataOnAllTracks()) {
- return false;
- }
-
- mBuffering = false;
-
- sp<AMessage> notify = dupNotify();
- notify->setInt32("what", kWhatResumeOnBufferingEnd);
- notify->post();
- }
-
- return true;
-}
-
-void NuPlayer2::RTSPSource2::finishSeek(status_t err) {
- if (mSeekReplyID == NULL) {
- return;
- }
- sp<AMessage> seekReply = new AMessage;
- seekReply->setInt32("err", err);
- seekReply->postReply(mSeekReplyID);
- mSeekReplyID = NULL;
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/RTSPSource2.h b/media/libmediaplayer2/nuplayer2/RTSPSource2.h
deleted file mode 100644
index e5f1716..0000000
--- a/media/libmediaplayer2/nuplayer2/RTSPSource2.h
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef RTSP_SOURCE2_H_
-
-#define RTSP_SOURCE2_H_
-
-#include "NuPlayer2Source.h"
-
-#include "ATSParser.h"
-
-namespace android {
-
-struct ALooper;
-struct AReplyToken;
-struct AnotherPacketSource;
-struct MyHandler;
-struct SDPLoader;
-
-struct NuPlayer2::RTSPSource2 : public NuPlayer2::Source {
- RTSPSource2(
- const sp<AMessage> ¬ify,
- const sp<MediaHTTPService> &httpService,
- const char *url,
- const KeyedVector<String8, String8> *headers,
- uid_t uid = 0,
- bool isSDP = false);
-
- virtual status_t getBufferingSettings(
- BufferingSettings* buffering /* nonnull */) override;
- virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
-
- virtual void prepareAsync(int64_t startTimeUs);
- virtual void start();
- virtual void stop();
-
- virtual status_t feedMoreTSData();
-
- virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
-
- virtual status_t getDuration(int64_t *durationUs);
- virtual status_t seekTo(
- int64_t seekTimeUs,
- MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC) override;
-
- void onMessageReceived(const sp<AMessage> &msg);
-
-protected:
- virtual ~RTSPSource2();
-
- virtual sp<MetaData> getFormatMeta(bool audio);
-
-private:
- enum {
- kWhatNotify = 'noti',
- kWhatDisconnect = 'disc',
- kWhatPerformSeek = 'seek',
- kWhatPollBuffering = 'poll',
- kWhatSignalEOS = 'eos ',
- };
-
- enum State {
- DISCONNECTED,
- CONNECTING,
- CONNECTED,
- SEEKING,
- };
-
- enum Flags {
- // Don't log any URLs.
- kFlagIncognito = 1,
- };
-
- struct TrackInfo {
- sp<AnotherPacketSource> mSource;
-
- int32_t mTimeScale;
- uint32_t mRTPTime;
- int64_t mNormalPlaytimeUs;
- bool mNPTMappingValid;
- };
-
- sp<MediaHTTPService> mHTTPService;
- AString mURL;
- KeyedVector<String8, String8> mExtraHeaders;
- uid_t mUID;
- uint32_t mFlags;
- bool mIsSDP;
- State mState;
- status_t mFinalResult;
- sp<AReplyToken> mDisconnectReplyID;
- Mutex mBufferingLock;
- bool mBuffering;
- bool mInPreparationPhase;
- bool mEOSPending;
-
- Mutex mBufferingSettingsLock;
- BufferingSettings mBufferingSettings;
-
- sp<ALooper> mLooper;
- sp<MyHandler> mHandler;
- sp<SDPLoader> mSDPLoader;
-
- Vector<TrackInfo> mTracks;
- sp<AnotherPacketSource> mAudioTrack;
- sp<AnotherPacketSource> mVideoTrack;
-
- sp<ATSParser> mTSParser;
-
- int32_t mSeekGeneration;
-
- int64_t mEOSTimeoutAudio;
- int64_t mEOSTimeoutVideo;
-
- sp<AReplyToken> mSeekReplyID;
-
- sp<AnotherPacketSource> getSource(bool audio);
-
- void onConnected();
- void onSDPLoaded(const sp<AMessage> &msg);
- void onDisconnected(const sp<AMessage> &msg);
- void finishDisconnectIfPossible();
-
- void performSeek(int64_t seekTimeUs);
- void schedulePollBuffering();
- void checkBuffering(
- bool *prepared,
- bool *underflow,
- bool *overflow,
- bool *startServer,
- bool *finished);
- void onPollBuffering();
-
- bool haveSufficientDataOnAllTracks();
-
- void setEOSTimeout(bool audio, int64_t timeout);
- void setError(status_t err);
- void startBufferingIfNecessary();
- bool stopBufferingIfNecessary();
- void finishSeek(status_t err);
-
- void postSourceEOSIfNecessary();
- void signalSourceEOS(status_t result);
- void onSignalEOS(const sp<AMessage> &msg);
-
- bool sourceNearEOS(bool audio);
- bool sourceReachedEOS(bool audio);
-
- DISALLOW_EVIL_CONSTRUCTORS(RTSPSource2);
-};
-
-} // namespace android
-
-#endif // RTSP_SOURCE2_H_
diff --git a/media/libmediaplayerservice/Android.bp b/media/libmediaplayerservice/Android.bp
index 6709585..5301f5c 100644
--- a/media/libmediaplayerservice/Android.bp
+++ b/media/libmediaplayerservice/Android.bp
@@ -7,6 +7,7 @@
"MediaPlayerService.cpp",
"MediaRecorderClient.cpp",
"MetadataRetrieverClient.cpp",
+ "StagefrightMetadataRetriever.cpp",
"StagefrightRecorder.cpp",
"TestPlayerStub.cpp",
],
@@ -21,11 +22,14 @@
"libcodec2_client",
"libcrypto",
"libcutils",
+ "libdatasource",
"libdl",
+ "libdrmframework",
"libgui",
"libhidlbase",
"liblog",
"libmedia",
+ "libmedia_codeclist",
"libmedia_omx",
"libmediadrm",
"libmediametrics",
@@ -44,6 +48,7 @@
],
static_libs: [
+ "libplayerservice_datasource",
"libstagefright_nuplayer",
"libstagefright_rtsp",
"libstagefright_timedtext",
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
index 1376ccc..05f7365 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -20,9 +20,9 @@
#include <utils/Log.h>
#include <cutils/properties.h>
+#include <datasource/FileSource.h>
#include <media/DataSource.h>
#include <media/IMediaPlayer.h>
-#include <media/stagefright/FileSource.h>
#include <media/stagefright/foundation/ADebug.h>
#include <utils/Errors.h>
#include <utils/misc.h>
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 8ac169f..81ffcbc 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -48,6 +48,7 @@
#include <utils/Vector.h>
#include <codec2/hidl/client.h>
+#include <datasource/HTTPBase.h>
#include <media/IMediaHTTPService.h>
#include <media/IRemoteDisplay.h>
#include <media/IRemoteDisplayClient.h>
@@ -62,6 +63,7 @@
#include <media/stagefright/MediaCodecList.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooperRoster.h>
#include <media/stagefright/SurfaceUtils.h>
@@ -81,7 +83,6 @@
#include "TestPlayerStub.h"
#include "nuplayer/NuPlayerDriver.h"
-#include "HTTPBase.h"
static const int kDumpLockRetries = 50;
static const int kDumpLockSleepUs = 20000;
@@ -421,9 +422,9 @@
printList("colors", list);
}
- snprintf(buffer, SIZE - 1, " details: %s\n",
- caps->getDetails()->debugString(6).c_str());
- result.append(buffer);
+ result.append(" details: ");
+ result.append(caps->getDetails()->debugString(6).c_str());
+ result.append("\n");
}
}
result.append("\n");
@@ -688,6 +689,10 @@
gLooperRoster.dump(fd, args);
+ sp<IMediaCodecList> codecList = getCodecList();
+ dumpCodecDetails(fd, codecList, true /* decoders */);
+ dumpCodecDetails(fd, codecList, false /* !decoders */);
+
bool dumpMem = false;
bool unreachableMemory = false;
for (size_t i = 0; i < args.size(); i++) {
@@ -711,10 +716,6 @@
}
write(fd, result.string(), result.size());
- sp<IMediaCodecList> codecList = getCodecList();
- dumpCodecDetails(fd, codecList, true /* decoders */);
- dumpCodecDetails(fd, codecList, false /* !decoders */);
-
return NO_ERROR;
}
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 49688ce..2562b8f 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -26,10 +26,12 @@
#include <utils/String8.h>
#include <utils/Vector.h>
+#include <media/AudioSystem.h>
#include <media/MediaPlayerInterface.h>
#include <media/Metadata.h>
#include <media/stagefright/foundation/ABase.h>
+
#include <system/audio.h>
namespace android {
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index b44eb43..fb228ca 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -37,6 +37,7 @@
#include <media/MediaPlayerInterface.h>
#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#include <private/media/VideoFrame.h>
#include "MetadataRetrieverClient.h"
#include "StagefrightMetadataRetriever.h"
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
similarity index 98%
rename from media/libstagefright/StagefrightMetadataRetriever.cpp
rename to media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
index 6f536a9..41b6f72 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
@@ -22,14 +22,14 @@
#include <utils/Log.h>
#include <cutils/properties.h>
-#include "include/FrameDecoder.h"
-#include "include/StagefrightMetadataRetriever.h"
+#include "StagefrightMetadataRetriever.h"
+#include "FrameDecoder.h"
+#include <datasource/PlayerServiceDataSourceFactory.h>
+#include <datasource/PlayerServiceFileSource.h>
#include <media/IMediaHTTPService.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSourceFactory.h>
-#include <media/stagefright/FileSource.h>
#include <media/stagefright/MediaCodecList.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
@@ -63,7 +63,8 @@
ALOGV("setDataSource(%s)", uri);
clearMetadata();
- mSource = DataSourceFactory::CreateFromURI(httpService, uri, headers);
+ mSource = PlayerServiceDataSourceFactory::getInstance()->CreateFromURI(
+ httpService, uri, headers);
if (mSource == NULL) {
ALOGE("Unable to create data source for '%s'.", uri);
@@ -91,7 +92,7 @@
ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
clearMetadata();
- mSource = new FileSource(fd, offset, length);
+ mSource = new PlayerServiceFileSource(fd, offset, length);
status_t err;
if ((err = mSource->initCheck()) != OK) {
diff --git a/media/libstagefright/include/StagefrightMetadataRetriever.h b/media/libmediaplayerservice/StagefrightMetadataRetriever.h
similarity index 100%
rename from media/libstagefright/include/StagefrightMetadataRetriever.h
rename to media/libmediaplayerservice/StagefrightMetadataRetriever.h
diff --git a/media/libmediaplayerservice/datasource/Android.bp b/media/libmediaplayerservice/datasource/Android.bp
new file mode 100644
index 0000000..71fa50b
--- /dev/null
+++ b/media/libmediaplayerservice/datasource/Android.bp
@@ -0,0 +1,43 @@
+cc_library_static {
+ name: "libplayerservice_datasource",
+
+ srcs: [
+ "PlayerServiceDataSourceFactory.cpp",
+ "PlayerServiceFileSource.cpp",
+ "PlayerServiceMediaHTTP.cpp",
+ ],
+
+ header_libs: [
+ "media_ndk_headers",
+ "libmedia_headers",
+ ],
+
+ shared_libs: [
+ "libdatasource",
+ "libdrmframework",
+ "liblog",
+ "libutils",
+ ],
+
+ local_include_dirs: [
+ "include",
+ ],
+
+ export_include_dirs: [
+ "include",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wno-error=deprecated-declarations",
+ "-Wall",
+ ],
+
+ sanitize: {
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ cfi: true,
+ },
+}
diff --git a/media/libmediaplayerservice/datasource/PlayerServiceDataSourceFactory.cpp b/media/libmediaplayerservice/datasource/PlayerServiceDataSourceFactory.cpp
new file mode 100644
index 0000000..ef946e9
--- /dev/null
+++ b/media/libmediaplayerservice/datasource/PlayerServiceDataSourceFactory.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+//#define LOG_NDEBUG 0
+#define LOG_TAG "PlayerServuceDataSourceFactory"
+
+
+#include <datasource/PlayerServiceDataSourceFactory.h>
+#include <datasource/PlayerServiceFileSource.h>
+#include <datasource/PlayerServiceMediaHTTP.h>
+#include <media/MediaHTTPConnection.h>
+#include <media/MediaHTTPService.h>
+
+namespace android {
+
+// static
+sp<PlayerServiceDataSourceFactory> PlayerServiceDataSourceFactory::sInstance;
+// static
+Mutex PlayerServiceDataSourceFactory::sInstanceLock;
+
+// static
+sp<PlayerServiceDataSourceFactory> PlayerServiceDataSourceFactory::getInstance() {
+ Mutex::Autolock l(sInstanceLock);
+ if (!sInstance) {
+ sInstance = new PlayerServiceDataSourceFactory();
+ }
+ return sInstance;
+}
+
+sp<DataSource> PlayerServiceDataSourceFactory::CreateMediaHTTP(
+ const sp<MediaHTTPService> &httpService) {
+ if (httpService == NULL) {
+ return NULL;
+ }
+
+ sp<MediaHTTPConnection> conn = httpService->makeHTTPConnection();
+ if (conn == NULL) {
+ ALOGE("Failed to make http connection from http service!");
+ return NULL;
+ } else {
+ return new PlayerServiceMediaHTTP(conn);
+ }
+}
+
+sp<DataSource> PlayerServiceDataSourceFactory::CreateFileSource(const char *uri) {
+ return new PlayerServiceFileSource(uri);
+}
+
+} // namespace android
diff --git a/media/libstagefright/FileSource.cpp b/media/libmediaplayerservice/datasource/PlayerServiceFileSource.cpp
similarity index 84%
rename from media/libstagefright/FileSource.cpp
rename to media/libmediaplayerservice/datasource/PlayerServiceFileSource.cpp
index aee7fd8..1580891 100644
--- a/media/libstagefright/FileSource.cpp
+++ b/media/libmediaplayerservice/datasource/PlayerServiceFileSource.cpp
@@ -15,18 +15,17 @@
*/
//#define LOG_NDEBUG 0
-#define LOG_TAG "FileSource"
+#define LOG_TAG "PlayerServiceFileSource"
#include <utils/Log.h>
+#include <datasource/PlayerServiceFileSource.h>
#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/FileSource.h>
-#include <media/stagefright/Utils.h>
#include <private/android_filesystem_config.h>
namespace android {
-FileSource::FileSource(const char *filename)
- : ClearFileSource(filename),
+PlayerServiceFileSource::PlayerServiceFileSource(const char *filename)
+ : FileSource(filename),
mDecryptHandle(NULL),
mDrmManagerClient(NULL),
mDrmBufOffset(0),
@@ -34,8 +33,8 @@
mDrmBuf(NULL){
}
-FileSource::FileSource(int fd, int64_t offset, int64_t length)
- : ClearFileSource(fd, offset, length),
+PlayerServiceFileSource::PlayerServiceFileSource(int fd, int64_t offset, int64_t length)
+ : FileSource(fd, offset, length),
mDecryptHandle(NULL),
mDrmManagerClient(NULL),
mDrmBufOffset(0),
@@ -43,7 +42,7 @@
mDrmBuf(NULL) {
}
-FileSource::~FileSource() {
+PlayerServiceFileSource::~PlayerServiceFileSource() {
if (mDrmBuf != NULL) {
delete[] mDrmBuf;
mDrmBuf = NULL;
@@ -62,7 +61,7 @@
}
}
-ssize_t FileSource::readAt(off64_t offset, void *data, size_t size) {
+ssize_t PlayerServiceFileSource::readAt(off64_t offset, void *data, size_t size) {
if (mFd < 0) {
return NO_INIT;
}
@@ -87,7 +86,7 @@
}
}
-sp<DecryptHandle> FileSource::DrmInitialization(const char *mime) {
+sp<DecryptHandle> PlayerServiceFileSource::DrmInitialization(const char *mime) {
if (getuid() == AID_MEDIA_EX) return nullptr; // no DRM in media extractor
if (mDrmManagerClient == NULL) {
mDrmManagerClient = new DrmManagerClient();
@@ -110,7 +109,7 @@
return mDecryptHandle;
}
-ssize_t FileSource::readAtDRM_l(off64_t offset, void *data, size_t size) {
+ssize_t PlayerServiceFileSource::readAtDRM_l(off64_t offset, void *data, size_t size) {
size_t DRM_CACHE_SIZE = 1024;
if (mDrmBuf == NULL) {
mDrmBuf = new unsigned char[DRM_CACHE_SIZE];
@@ -141,7 +140,7 @@
}
/* static */
-bool FileSource::requiresDrm(int fd, int64_t offset, int64_t length, const char *mime) {
+bool PlayerServiceFileSource::requiresDrm(int fd, int64_t offset, int64_t length, const char *mime) {
std::unique_ptr<DrmManagerClient> drmClient(new DrmManagerClient());
sp<DecryptHandle> decryptHandle =
drmClient->openDecryptSession(fd, offset, length, mime);
diff --git a/media/libstagefright/http/MediaHTTP.cpp b/media/libmediaplayerservice/datasource/PlayerServiceMediaHTTP.cpp
similarity index 78%
rename from media/libstagefright/http/MediaHTTP.cpp
rename to media/libmediaplayerservice/datasource/PlayerServiceMediaHTTP.cpp
index 0fba3dc..0124720 100644
--- a/media/libstagefright/http/MediaHTTP.cpp
+++ b/media/libmediaplayerservice/datasource/PlayerServiceMediaHTTP.cpp
@@ -15,32 +15,32 @@
*/
//#define LOG_NDEBUG 0
-#define LOG_TAG "MediaHTTP"
+#define LOG_TAG "PlayerServiceMediaHTTP"
#include <utils/Log.h>
-#include <media/stagefright/MediaHTTP.h>
+#include <datasource/PlayerServiceMediaHTTP.h>
#include <binder/IServiceManager.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#include <media/MediaHTTPConnection.h>
namespace android {
-MediaHTTP::MediaHTTP(const sp<MediaHTTPConnection> &conn)
- : ClearMediaHTTP(conn),
+PlayerServiceMediaHTTP::PlayerServiceMediaHTTP(const sp<MediaHTTPConnection> &conn)
+ : MediaHTTP(conn),
mDrmManagerClient(NULL) {
}
-MediaHTTP::~MediaHTTP() {
+PlayerServiceMediaHTTP::~PlayerServiceMediaHTTP() {
clearDRMState_l();
}
// DRM...
-sp<DecryptHandle> MediaHTTP::DrmInitialization(const char* mime) {
+sp<DecryptHandle> PlayerServiceMediaHTTP::DrmInitialization(const char* mime) {
if (mDrmManagerClient == NULL) {
mDrmManagerClient = new DrmManagerClient();
}
@@ -62,7 +62,7 @@
return mDecryptHandle;
}
-void MediaHTTP::clearDRMState_l() {
+void PlayerServiceMediaHTTP::clearDRMState_l() {
if (mDecryptHandle != NULL) {
// To release mDecryptHandle
CHECK(mDrmManagerClient);
diff --git a/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceDataSourceFactory.h b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceDataSourceFactory.h
new file mode 100644
index 0000000..7d58c5c
--- /dev/null
+++ b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceDataSourceFactory.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef PLAYER_SERVICE_DATA_SOURCE_FACTORY_H_
+
+#define PLAYER_SERVICE_DATA_SOURCE_FACTORY_H_
+
+#include <datasource/DataSourceFactory.h>
+#include <media/DataSource.h>
+#include <sys/types.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+struct MediaHTTPService;
+class String8;
+struct HTTPBase;
+
+class PlayerServiceDataSourceFactory : public DataSourceFactory {
+public:
+ static sp<PlayerServiceDataSourceFactory> getInstance();
+ virtual sp<DataSource> CreateMediaHTTP(const sp<MediaHTTPService> &httpService);
+
+protected:
+ virtual sp<DataSource> CreateFileSource(const char *uri);
+
+private:
+ static sp<PlayerServiceDataSourceFactory> sInstance;
+ static Mutex sInstanceLock;
+ PlayerServiceDataSourceFactory() {};
+};
+
+} // namespace android
+
+#endif // PLAYER_SERVICE_DATA_SOURCE_FACTORY_H_
diff --git a/media/libstagefright/include/media/stagefright/FileSource.h b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceFileSource.h
similarity index 65%
rename from media/libstagefright/include/media/stagefright/FileSource.h
rename to media/libmediaplayerservice/datasource/include/datasource/PlayerServiceFileSource.h
index b610eef..08a013e 100644
--- a/media/libstagefright/include/media/stagefright/FileSource.h
+++ b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceFileSource.h
@@ -14,24 +14,26 @@
* limitations under the License.
*/
-#ifndef FILE_SOURCE_H_
+#ifndef PLAYER_SERVICE_FILE_SOURCE_H_
-#define FILE_SOURCE_H_
+#define PLAYER_SERVICE_FILE_SOURCE_H_
#include <stdio.h>
-#include <media/stagefright/ClearFileSource.h>
+#include <datasource/FileSource.h>
#include <media/stagefright/MediaErrors.h>
#include <utils/threads.h>
#include <drm/DrmManagerClient.h>
namespace android {
-class FileSource : public ClearFileSource {
+// FileSource implementation which works on MediaPlayerService.
+// Supports OMA(forword-lock) files.
+class PlayerServiceFileSource : public FileSource {
public:
- FileSource(const char *filename);
- // FileSource takes ownership and will close the fd
- FileSource(int fd, int64_t offset, int64_t length);
+ PlayerServiceFileSource(const char *filename);
+ // PlayerServiceFileSource takes ownership and will close the fd
+ PlayerServiceFileSource(int fd, int64_t offset, int64_t length);
virtual ssize_t readAt(off64_t offset, void *data, size_t size);
@@ -40,7 +42,7 @@
static bool requiresDrm(int fd, int64_t offset, int64_t length, const char *mime);
protected:
- virtual ~FileSource();
+ virtual ~PlayerServiceFileSource();
private:
/*for DRM*/
@@ -52,11 +54,11 @@
ssize_t readAtDRM_l(off64_t offset, void *data, size_t size);
- FileSource(const FileSource &);
- FileSource &operator=(const FileSource &);
+ PlayerServiceFileSource(const PlayerServiceFileSource &);
+ PlayerServiceFileSource &operator=(const PlayerServiceFileSource &);
};
} // namespace android
-#endif // FILE_SOURCE_H_
+#endif // PLAYER_SERVICE_FILE_SOURCE_H_
diff --git a/media/libstagefright/include/media/stagefright/MediaHTTP.h b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceMediaHTTP.h
similarity index 67%
rename from media/libstagefright/include/media/stagefright/MediaHTTP.h
rename to media/libmediaplayerservice/datasource/include/datasource/PlayerServiceMediaHTTP.h
index acaa6c4..0032cd7 100644
--- a/media/libstagefright/include/media/stagefright/MediaHTTP.h
+++ b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceMediaHTTP.h
@@ -14,22 +14,24 @@
* limitations under the License.
*/
-#ifndef MEDIA_HTTP_H_
+#ifndef PLAYER_SERVICE_MEDIA_HTTP_H_
-#define MEDIA_HTTP_H_
+#define PLAYER_SERVICE_MEDIA_HTTP_H_
+#include <datasource/MediaHTTP.h>
#include <media/stagefright/foundation/AString.h>
-#include <media/stagefright/ClearMediaHTTP.h>
namespace android {
struct MediaHTTPConnection;
-struct MediaHTTP : public ClearMediaHTTP {
- MediaHTTP(const sp<MediaHTTPConnection> &conn);
+// MediaHTTP implementation which works on MediaPlayerService.
+// Supports OMA(forword-lock) stream.
+struct PlayerServiceMediaHTTP : public MediaHTTP {
+ PlayerServiceMediaHTTP(const sp<MediaHTTPConnection> &conn);
protected:
- virtual ~MediaHTTP();
+ virtual ~PlayerServiceMediaHTTP();
virtual sp<DecryptHandle> DrmInitialization(const char* mime);
@@ -39,9 +41,9 @@
void clearDRMState_l();
- DISALLOW_EVIL_CONSTRUCTORS(MediaHTTP);
+ DISALLOW_EVIL_CONSTRUCTORS(PlayerServiceMediaHTTP);
};
} // namespace android
-#endif // MEDIA_HTTP_H_
+#endif // PLAYER_SERVICE_MEDIA_HTTP_H_
diff --git a/media/libmediaplayerservice/include/MediaPlayerInterface.h b/media/libmediaplayerservice/include/MediaPlayerInterface.h
index 0ad4d04..436cb31 100644
--- a/media/libmediaplayerservice/include/MediaPlayerInterface.h
+++ b/media/libmediaplayerservice/include/MediaPlayerInterface.h
@@ -27,7 +27,6 @@
#include <media/mediaplayer.h>
#include <media/AudioResamplerPublic.h>
-#include <media/AudioSystem.h>
#include <media/AudioTimestamp.h>
#include <media/AVSyncSettings.h>
#include <media/BufferingSettings.h>
diff --git a/media/libmediaplayerservice/nuplayer/Android.bp b/media/libmediaplayerservice/nuplayer/Android.bp
index 23a19e7..c8f48a2 100644
--- a/media/libmediaplayerservice/nuplayer/Android.bp
+++ b/media/libmediaplayerservice/nuplayer/Android.bp
@@ -18,6 +18,7 @@
],
header_libs: [
+ "libmediadrm_headers",
"media_plugin_headers",
],
@@ -45,6 +46,7 @@
shared_libs: [
"libbinder",
+ "libdatasource",
"libui",
"libgui",
"libmedia",
@@ -52,6 +54,10 @@
"libpowermanager",
],
+ static_libs: [
+ "libplayerservice_datasource",
+ ],
+
name: "libstagefright_nuplayer",
sanitize: {
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 4653711..00e3443 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -23,6 +23,10 @@
#include "AnotherPacketSource.h"
#include <binder/IServiceManager.h>
#include <cutils/properties.h>
+#include <datasource/PlayerServiceDataSourceFactory.h>
+#include <datasource/PlayerServiceFileSource.h>
+#include <datasource/HTTPBase.h>
+#include <datasource/NuCachedSource2.h>
#include <media/DataSource.h>
#include <media/MediaBufferHolder.h>
#include <media/MediaSource.h>
@@ -31,8 +35,6 @@
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSourceFactory.h>
-#include <media/stagefright/FileSource.h>
#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaClock.h>
@@ -41,8 +43,6 @@
#include <media/stagefright/MediaExtractorFactory.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
-#include "../../libstagefright/include/NuCachedSource2.h"
-#include "../../libstagefright/include/HTTPBase.h"
namespace android {
@@ -385,7 +385,8 @@
if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
sp<DataSource> httpSource;
mDisconnectLock.unlock();
- httpSource = DataSourceFactory::CreateMediaHTTP(mHTTPService);
+ httpSource = PlayerServiceDataSourceFactory::getInstance()
+ ->CreateMediaHTTP(mHTTPService);
if (httpSource == NULL) {
ALOGE("Failed to create http source!");
notifyPreparedAndCleanup(UNKNOWN_ERROR);
@@ -401,9 +402,9 @@
mLock.unlock();
mDisconnectLock.unlock();
// This might take long time if connection has some issue.
- sp<DataSource> dataSource = DataSourceFactory::CreateFromURI(
- mHTTPService, uri, &mUriHeaders, &contentType,
- static_cast<HTTPBase *>(mHttpSource.get()));
+ sp<DataSource> dataSource = PlayerServiceDataSourceFactory::getInstance()
+ ->CreateFromURI(mHTTPService, uri, &mUriHeaders, &contentType,
+ static_cast<HTTPBase *>(mHttpSource.get()));
mDisconnectLock.lock();
mLock.lock();
if (!mDisconnected) {
@@ -411,7 +412,8 @@
}
} else {
if (property_get_bool("media.stagefright.extractremote", true) &&
- !FileSource::requiresDrm(mFd, mOffset, mLength, nullptr /* mime */)) {
+ !PlayerServiceFileSource::requiresDrm(
+ mFd, mOffset, mLength, nullptr /* mime */)) {
sp<IBinder> binder =
defaultServiceManager()->getService(String16("media.extractor"));
if (binder != nullptr) {
@@ -438,7 +440,7 @@
}
if (mDataSource == nullptr) {
ALOGD("FileSource local");
- mDataSource = new FileSource(mFd, mOffset, mLength);
+ mDataSource = new PlayerServiceFileSource(mFd, mOffset, mLength);
}
// TODO: close should always be done on mFd, see the lines following
// CreateDataSourceFromIDataSource above,
@@ -782,7 +784,7 @@
return;
}
- int64_t nextSubTimeUs;
+ int64_t nextSubTimeUs = 0;
readBuffer(type, -1, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */, &nextSubTimeUs);
sp<ABuffer> buffer;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 9f5be06..0e58ec2 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -19,7 +19,7 @@
#define NU_PLAYER_H_
#include <media/AudioResamplerPublic.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/MediaPlayerInterface.h>
#include <media/stagefright/foundation/AHandler.h>
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index ee463ce..f734439 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -28,7 +28,7 @@
#include "NuPlayerSource.h"
#include <cutils/properties.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/MediaBufferHolder.h>
#include <media/MediaCodecBuffer.h>
#include <media/stagefright/foundation/ABuffer.h>
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
index 0997e7d..793014e 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
@@ -24,7 +24,7 @@
#include "NuPlayerRenderer.h"
#include "NuPlayerSource.h"
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/MediaCodecBuffer.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 865cb2a..95c973a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -33,6 +33,7 @@
#include <media/stagefright/MediaClock.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#include <media/IMediaAnalyticsService.h>
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.h b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.h
index 50f69ff..4360656 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.h
@@ -18,8 +18,8 @@
#define NUPLAYER_DRM_H_
#include <binder/Parcel.h>
-#include <media/ICrypto.h>
-#include <media/IDrm.h>
+#include <mediadrm/ICrypto.h>
+#include <mediadrm/IDrm.h>
#include <media/stagefright/MetaData.h> // for CryptInfo
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index 9f5ef78..f137c52 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -20,7 +20,7 @@
#include "NuPlayer.h"
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/mediaplayer.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MetaData.h>
diff --git a/media/libmediaplayerservice/tests/Android.bp b/media/libmediaplayerservice/tests/Android.bp
index f8c89e5..8357925 100644
--- a/media/libmediaplayerservice/tests/Android.bp
+++ b/media/libmediaplayerservice/tests/Android.bp
@@ -6,14 +6,22 @@
shared_libs: [
"liblog",
+ "libbinder",
+ "libmedia",
"libmediaplayerservice",
"libmediadrm",
+ "libresourcemanagerservice",
"libutils",
"android.hardware.drm@1.0",
"android.hardware.drm@1.1",
"android.hardware.drm@1.2",
],
+ include_dirs: [
+ "frameworks/av/include",
+ "frameworks/av/services/mediaresourcemanager",
+ ],
+
cflags: [
"-Werror",
"-Wall",
diff --git a/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp b/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
index d81ee05..262fe32 100644
--- a/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
+++ b/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
@@ -20,14 +20,33 @@
#include <gtest/gtest.h>
+#include <android/media/BnResourceManagerClient.h>
+#include <android/media/IResourceManagerService.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/ProcessInfoInterface.h>
#include <mediadrm/DrmHal.h>
#include <mediadrm/DrmSessionClientInterface.h>
#include <mediadrm/DrmSessionManager.h>
+#include <algorithm>
+#include <vector>
+
+#include "ResourceManagerService.h"
+
namespace android {
+using ::android::binder::Status;
+using ::android::media::BnResourceManagerClient;
+using ::android::media::ResourceManagerService;
+
+static Vector<uint8_t> toAndroidVector(const std::vector<uint8_t> &vec) {
+ Vector<uint8_t> aVec;
+ for (auto b : vec) {
+ aVec.push_back(b);
+ }
+ return aVec;
+}
+
struct FakeProcessInfo : public ProcessInfoInterface {
FakeProcessInfo() {}
virtual ~FakeProcessInfo() {}
@@ -47,173 +66,130 @@
DISALLOW_EVIL_CONSTRUCTORS(FakeProcessInfo);
};
-struct FakeDrm : public DrmSessionClientInterface {
- FakeDrm() {}
+struct FakeDrm : public BnResourceManagerClient {
+ FakeDrm(const std::vector<uint8_t>& sessionId, const sp<DrmSessionManager>& manager)
+ : mSessionId(toAndroidVector(sessionId)),
+ mReclaimed(false),
+ mDrmSessionManager(manager) {}
+
virtual ~FakeDrm() {}
- virtual bool reclaimSession(const Vector<uint8_t>& sessionId) {
- mReclaimedSessions.push_back(sessionId);
- return true;
+ Status reclaimResource(bool* _aidl_return) {
+ mReclaimed = true;
+ mDrmSessionManager->removeSession(mSessionId);
+ *_aidl_return = true;
+ return Status::ok();
}
- const Vector<Vector<uint8_t> >& reclaimedSessions() const {
- return mReclaimedSessions;
+ Status getName(::std::string* _aidl_return) {
+ String8 name("FakeDrm[");
+ for (size_t i = 0; i < mSessionId.size(); ++i) {
+ name.appendFormat("%02x", mSessionId[i]);
+ }
+ name.append("]");
+ *_aidl_return = name;
+ return Status::ok();
}
+ bool isReclaimed() const {
+ return mReclaimed;
+ }
+
+ const Vector<uint8_t> mSessionId;
+
private:
- Vector<Vector<uint8_t> > mReclaimedSessions;
+ bool mReclaimed;
+ const sp<DrmSessionManager> mDrmSessionManager;
DISALLOW_EVIL_CONSTRUCTORS(FakeDrm);
};
+struct FakeSystemCallback :
+ public ResourceManagerService::SystemCallbackInterface {
+ FakeSystemCallback() {}
+
+ virtual void noteStartVideo(int /*uid*/) override {}
+
+ virtual void noteStopVideo(int /*uid*/) override {}
+
+ virtual void noteResetVideo() override {}
+
+ virtual bool requestCpusetBoost(
+ bool /*enable*/, const sp<IInterface> &/*client*/) override {
+ return true;
+ }
+
+protected:
+ virtual ~FakeSystemCallback() {}
+
+private:
+
+ DISALLOW_EVIL_CONSTRUCTORS(FakeSystemCallback);
+};
+
static const int kTestPid1 = 30;
static const int kTestPid2 = 20;
-static const uint8_t kTestSessionId1[] = {1, 2, 3};
-static const uint8_t kTestSessionId2[] = {4, 5, 6, 7, 8};
-static const uint8_t kTestSessionId3[] = {9, 0};
+static const std::vector<uint8_t> kTestSessionId1{1, 2, 3};
+static const std::vector<uint8_t> kTestSessionId2{4, 5, 6, 7, 8};
+static const std::vector<uint8_t> kTestSessionId3{9, 0};
class DrmSessionManagerTest : public ::testing::Test {
public:
DrmSessionManagerTest()
- : mDrmSessionManager(new DrmSessionManager(new FakeProcessInfo())),
- mTestDrm1(new FakeDrm()),
- mTestDrm2(new FakeDrm()) {
- GetSessionId(kTestSessionId1, ARRAY_SIZE(kTestSessionId1), &mSessionId1);
- GetSessionId(kTestSessionId2, ARRAY_SIZE(kTestSessionId2), &mSessionId2);
- GetSessionId(kTestSessionId3, ARRAY_SIZE(kTestSessionId3), &mSessionId3);
+ : mService(new ResourceManagerService(new FakeProcessInfo(), new FakeSystemCallback())),
+ mDrmSessionManager(new DrmSessionManager(mService)),
+ mTestDrm1(new FakeDrm(kTestSessionId1, mDrmSessionManager)),
+ mTestDrm2(new FakeDrm(kTestSessionId2, mDrmSessionManager)),
+ mTestDrm3(new FakeDrm(kTestSessionId3, mDrmSessionManager)) {
+ DrmSessionManager *ptr = new DrmSessionManager(mService);
+ EXPECT_NE(ptr, nullptr);
+ /* mDrmSessionManager = ptr; */
}
protected:
- static void GetSessionId(const uint8_t* ids, size_t num, Vector<uint8_t>* sessionId) {
- for (size_t i = 0; i < num; ++i) {
- sessionId->push_back(ids[i]);
- }
- }
-
- static void ExpectEqSessionInfo(const SessionInfo& info, sp<DrmSessionClientInterface> drm,
- const Vector<uint8_t>& sessionId, int64_t timeStamp) {
- EXPECT_EQ(drm, info.drm);
- EXPECT_TRUE(isEqualSessionId(sessionId, info.sessionId));
- EXPECT_EQ(timeStamp, info.timeStamp);
- }
-
void addSession() {
- mDrmSessionManager->addSession(kTestPid1, mTestDrm1, mSessionId1);
- mDrmSessionManager->addSession(kTestPid2, mTestDrm2, mSessionId2);
- mDrmSessionManager->addSession(kTestPid2, mTestDrm2, mSessionId3);
- const PidSessionInfosMap& map = sessionMap();
- EXPECT_EQ(2u, map.size());
- ssize_t index1 = map.indexOfKey(kTestPid1);
- ASSERT_GE(index1, 0);
- const SessionInfos& infos1 = map[index1];
- EXPECT_EQ(1u, infos1.size());
- ExpectEqSessionInfo(infos1[0], mTestDrm1, mSessionId1, 0);
-
- ssize_t index2 = map.indexOfKey(kTestPid2);
- ASSERT_GE(index2, 0);
- const SessionInfos& infos2 = map[index2];
- EXPECT_EQ(2u, infos2.size());
- ExpectEqSessionInfo(infos2[0], mTestDrm2, mSessionId2, 1);
- ExpectEqSessionInfo(infos2[1], mTestDrm2, mSessionId3, 2);
+ mDrmSessionManager->addSession(kTestPid1, mTestDrm1, mTestDrm1->mSessionId);
+ mDrmSessionManager->addSession(kTestPid2, mTestDrm2, mTestDrm2->mSessionId);
+ mDrmSessionManager->addSession(kTestPid2, mTestDrm3, mTestDrm3->mSessionId);
}
- const PidSessionInfosMap& sessionMap() {
- return mDrmSessionManager->mSessionMap;
- }
-
- void testGetLowestPriority() {
- int pid;
- int priority;
- EXPECT_FALSE(mDrmSessionManager->getLowestPriority_l(&pid, &priority));
-
- addSession();
- EXPECT_TRUE(mDrmSessionManager->getLowestPriority_l(&pid, &priority));
-
- EXPECT_EQ(kTestPid1, pid);
- FakeProcessInfo processInfo;
- int priority1;
- processInfo.getPriority(kTestPid1, &priority1);
- EXPECT_EQ(priority1, priority);
- }
-
- void testGetLeastUsedSession() {
- sp<DrmSessionClientInterface> drm;
- Vector<uint8_t> sessionId;
- EXPECT_FALSE(mDrmSessionManager->getLeastUsedSession_l(kTestPid1, &drm, &sessionId));
-
- addSession();
-
- EXPECT_TRUE(mDrmSessionManager->getLeastUsedSession_l(kTestPid1, &drm, &sessionId));
- EXPECT_EQ(mTestDrm1, drm);
- EXPECT_TRUE(isEqualSessionId(mSessionId1, sessionId));
-
- EXPECT_TRUE(mDrmSessionManager->getLeastUsedSession_l(kTestPid2, &drm, &sessionId));
- EXPECT_EQ(mTestDrm2, drm);
- EXPECT_TRUE(isEqualSessionId(mSessionId2, sessionId));
-
- // mSessionId2 is no longer the least used session.
- mDrmSessionManager->useSession(mSessionId2);
- EXPECT_TRUE(mDrmSessionManager->getLeastUsedSession_l(kTestPid2, &drm, &sessionId));
- EXPECT_EQ(mTestDrm2, drm);
- EXPECT_TRUE(isEqualSessionId(mSessionId3, sessionId));
- }
-
+ sp<IResourceManagerService> mService;
sp<DrmSessionManager> mDrmSessionManager;
sp<FakeDrm> mTestDrm1;
sp<FakeDrm> mTestDrm2;
- Vector<uint8_t> mSessionId1;
- Vector<uint8_t> mSessionId2;
- Vector<uint8_t> mSessionId3;
+ sp<FakeDrm> mTestDrm3;
};
TEST_F(DrmSessionManagerTest, addSession) {
addSession();
+
+ EXPECT_EQ(3u, mDrmSessionManager->getSessionCount());
+ EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm1->mSessionId));
+ EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm2->mSessionId));
+ EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm3->mSessionId));
}
TEST_F(DrmSessionManagerTest, useSession) {
addSession();
- mDrmSessionManager->useSession(mSessionId1);
- mDrmSessionManager->useSession(mSessionId3);
+ mDrmSessionManager->useSession(mTestDrm1->mSessionId);
+ mDrmSessionManager->useSession(mTestDrm3->mSessionId);
- const PidSessionInfosMap& map = sessionMap();
- const SessionInfos& infos1 = map.valueFor(kTestPid1);
- const SessionInfos& infos2 = map.valueFor(kTestPid2);
- ExpectEqSessionInfo(infos1[0], mTestDrm1, mSessionId1, 3);
- ExpectEqSessionInfo(infos2[1], mTestDrm2, mSessionId3, 4);
+ EXPECT_EQ(3u, mDrmSessionManager->getSessionCount());
+ EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm1->mSessionId));
+ EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm2->mSessionId));
+ EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm3->mSessionId));
}
TEST_F(DrmSessionManagerTest, removeSession) {
addSession();
- mDrmSessionManager->removeSession(mSessionId2);
+ mDrmSessionManager->removeSession(mTestDrm2->mSessionId);
- const PidSessionInfosMap& map = sessionMap();
- EXPECT_EQ(2u, map.size());
- const SessionInfos& infos1 = map.valueFor(kTestPid1);
- const SessionInfos& infos2 = map.valueFor(kTestPid2);
- EXPECT_EQ(1u, infos1.size());
- EXPECT_EQ(1u, infos2.size());
- // mSessionId2 has been removed.
- ExpectEqSessionInfo(infos2[0], mTestDrm2, mSessionId3, 2);
-}
-
-TEST_F(DrmSessionManagerTest, removeDrm) {
- addSession();
-
- sp<FakeDrm> drm = new FakeDrm;
- const uint8_t ids[] = {123};
- Vector<uint8_t> sessionId;
- GetSessionId(ids, ARRAY_SIZE(ids), &sessionId);
- mDrmSessionManager->addSession(kTestPid2, drm, sessionId);
-
- mDrmSessionManager->removeDrm(mTestDrm2);
-
- const PidSessionInfosMap& map = sessionMap();
- const SessionInfos& infos2 = map.valueFor(kTestPid2);
- EXPECT_EQ(1u, infos2.size());
- // mTestDrm2 has been removed.
- ExpectEqSessionInfo(infos2[0], drm, sessionId, 3);
+ EXPECT_EQ(2u, mDrmSessionManager->getSessionCount());
+ EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm1->mSessionId));
+ EXPECT_FALSE(mDrmSessionManager->containsSession(mTestDrm2->mSessionId));
+ EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm3->mSessionId));
}
TEST_F(DrmSessionManagerTest, reclaimSession) {
@@ -224,30 +200,63 @@
EXPECT_FALSE(mDrmSessionManager->reclaimSession(50));
EXPECT_TRUE(mDrmSessionManager->reclaimSession(10));
- EXPECT_EQ(1u, mTestDrm1->reclaimedSessions().size());
- EXPECT_TRUE(isEqualSessionId(mSessionId1, mTestDrm1->reclaimedSessions()[0]));
-
- mDrmSessionManager->removeSession(mSessionId1);
+ EXPECT_TRUE(mTestDrm1->isReclaimed());
// add a session from a higher priority process.
- sp<FakeDrm> drm = new FakeDrm;
- const uint8_t ids[] = {1, 3, 5};
- Vector<uint8_t> sessionId;
- GetSessionId(ids, ARRAY_SIZE(ids), &sessionId);
- mDrmSessionManager->addSession(15, drm, sessionId);
+ const std::vector<uint8_t> sid{1, 3, 5};
+ sp<FakeDrm> drm = new FakeDrm(sid, mDrmSessionManager);
+ mDrmSessionManager->addSession(15, drm, drm->mSessionId);
+ // make sure mTestDrm2 is reclaimed next instead of mTestDrm3
+ mDrmSessionManager->useSession(mTestDrm3->mSessionId);
EXPECT_TRUE(mDrmSessionManager->reclaimSession(18));
- EXPECT_EQ(1u, mTestDrm2->reclaimedSessions().size());
- // mSessionId2 is reclaimed.
- EXPECT_TRUE(isEqualSessionId(mSessionId2, mTestDrm2->reclaimedSessions()[0]));
+ EXPECT_TRUE(mTestDrm2->isReclaimed());
+
+ EXPECT_EQ(2u, mDrmSessionManager->getSessionCount());
+ EXPECT_FALSE(mDrmSessionManager->containsSession(mTestDrm1->mSessionId));
+ EXPECT_FALSE(mDrmSessionManager->containsSession(mTestDrm2->mSessionId));
+ EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm3->mSessionId));
+ EXPECT_TRUE(mDrmSessionManager->containsSession(drm->mSessionId));
}
-TEST_F(DrmSessionManagerTest, getLowestPriority) {
- testGetLowestPriority();
-}
+TEST_F(DrmSessionManagerTest, reclaimAfterUse) {
+ // nothing to reclaim yet
+ EXPECT_FALSE(mDrmSessionManager->reclaimSession(kTestPid1));
+ EXPECT_FALSE(mDrmSessionManager->reclaimSession(kTestPid2));
-TEST_F(DrmSessionManagerTest, getLeastUsedSession_l) {
- testGetLeastUsedSession();
+ // add sessions from same pid
+ mDrmSessionManager->addSession(kTestPid2, mTestDrm1, mTestDrm1->mSessionId);
+ mDrmSessionManager->addSession(kTestPid2, mTestDrm2, mTestDrm2->mSessionId);
+ mDrmSessionManager->addSession(kTestPid2, mTestDrm3, mTestDrm3->mSessionId);
+
+ // use some but not all sessions
+ mDrmSessionManager->useSession(mTestDrm1->mSessionId);
+ mDrmSessionManager->useSession(mTestDrm1->mSessionId);
+ mDrmSessionManager->useSession(mTestDrm2->mSessionId);
+
+ // calling pid priority is too low
+ int lowPriorityPid = kTestPid2 + 1;
+ EXPECT_FALSE(mDrmSessionManager->reclaimSession(lowPriorityPid));
+
+ // unused session is reclaimed first
+ int highPriorityPid = kTestPid2 - 1;
+ EXPECT_TRUE(mDrmSessionManager->reclaimSession(highPriorityPid));
+ EXPECT_FALSE(mTestDrm1->isReclaimed());
+ EXPECT_FALSE(mTestDrm2->isReclaimed());
+ EXPECT_TRUE(mTestDrm3->isReclaimed());
+ mDrmSessionManager->removeSession(mTestDrm3->mSessionId);
+
+ // less-used session is reclaimed next
+ EXPECT_TRUE(mDrmSessionManager->reclaimSession(highPriorityPid));
+ EXPECT_FALSE(mTestDrm1->isReclaimed());
+ EXPECT_TRUE(mTestDrm2->isReclaimed());
+ EXPECT_TRUE(mTestDrm3->isReclaimed());
+
+ // most-used session still open
+ EXPECT_EQ(1u, mDrmSessionManager->getSessionCount());
+ EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm1->mSessionId));
+ EXPECT_FALSE(mDrmSessionManager->containsSession(mTestDrm2->mSessionId));
+ EXPECT_FALSE(mDrmSessionManager->containsSession(mTestDrm3->mSessionId));
}
} // namespace android
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 369e13f..965e5a6 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -24,6 +24,8 @@
#include <inttypes.h>
#include <utils/Trace.h>
+#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
+
#include <gui/Surface.h>
#include <media/stagefright/ACodec.h>
@@ -45,6 +47,7 @@
#include <media/hardware/HardwareAPI.h>
#include <media/MediaBufferHolder.h>
#include <media/OMXBuffer.h>
+#include <media/omx/1.0/Conversion.h>
#include <media/omx/1.0/WOmxNode.h>
#include <hidlmemory/mapping.h>
@@ -63,7 +66,9 @@
namespace android {
-using binder::Status;
+typedef hardware::media::omx::V1_0::IGraphicBufferSource HGraphicBufferSource;
+
+using hardware::media::omx::V1_0::Status;
enum {
kMaxIndicesToCheck = 32, // used when enumerating supported formats and profiles
@@ -98,16 +103,11 @@
}
}
-static inline status_t statusFromBinderStatus(const Status &status) {
+static inline status_t statusFromBinderStatus(hardware::Return<Status> &&status) {
if (status.isOk()) {
- return OK;
- }
- status_t err;
- if ((err = status.serviceSpecificErrorCode()) != OK) {
- return err;
- }
- if ((err = status.transactionError()) != OK) {
- return err;
+ return static_cast<status_t>(status.withDefault(Status::UNKNOWN_ERROR));
+ } else if (status.isDeadObject()) {
+ return DEAD_OBJECT;
}
// Other exception
return UNKNOWN_ERROR;
@@ -1780,6 +1780,14 @@
}
}
+ int32_t lowLatency = 0;
+ if (msg->findInt32("low-latency", &lowLatency)) {
+ err = setLowLatency(lowLatency);
+ if (err != OK) {
+ return err;
+ }
+ }
+
int32_t prependSPSPPS = 0;
if (encoder && mIsVideo
&& msg->findInt32("prepend-sps-pps-to-idr-frames", &prependSPSPPS)
@@ -2348,6 +2356,24 @@
return err;
}
+status_t ACodec::setLowLatency(int32_t lowLatency) {
+ if (mIsEncoder) {
+ ALOGE("encoder does not support low-latency");
+ return BAD_VALUE;
+ }
+
+ OMX_CONFIG_BOOLEANTYPE config;
+ InitOMXParams(&config);
+ config.bEnabled = (OMX_BOOL)(lowLatency != 0);
+ status_t err = mOMXNode->setConfig(
+ (OMX_INDEXTYPE)OMX_IndexConfigLowLatency,
+ &config, sizeof(config));
+ if (err != OK) {
+ ALOGE("decoder can not set low-latency to %d (err %d)", lowLatency, err);
+ }
+ return err;
+}
+
status_t ACodec::setLatency(uint32_t latency) {
OMX_PARAM_U32TYPE config;
InitOMXParams(&config);
@@ -6880,8 +6906,11 @@
return err;
}
+ using hardware::media::omx::V1_0::utils::TWOmxNode;
err = statusFromBinderStatus(
- mCodec->mGraphicBufferSource->configure(mCodec->mOMXNode, dataSpace));
+ mCodec->mGraphicBufferSource->configure(
+ new TWOmxNode(mCodec->mOMXNode),
+ static_cast<hardware::graphics::common::V1_0::Dataspace>(dataSpace)));
if (err != OK) {
ALOGE("[%s] Unable to configure for node (err %d)",
mCodec->mComponentName.c_str(), err);
@@ -6901,7 +6930,7 @@
}
}
- if (mCodec->mMaxPtsGapUs != 0LL) {
+ if (mCodec->mIsVideo && mCodec->mMaxPtsGapUs != 0LL) {
OMX_PARAM_U32TYPE maxPtsGapParams;
InitOMXParams(&maxPtsGapParams);
maxPtsGapParams.nPortIndex = kPortIndexInput;
@@ -6967,8 +6996,9 @@
}
err = statusFromBinderStatus(
- mCodec->mGraphicBufferSource->setColorAspects(ColorUtils::packToU32(
- *(ColorAspects *)colorAspectsBuffer->base())));
+ mCodec->mGraphicBufferSource->setColorAspects(
+ hardware::media::omx::V1_0::utils::toHardwareColorAspects(
+ *(ColorAspects *)colorAspectsBuffer->base())));
if (err != OK) {
ALOGE("[%s] Unable to configure color aspects (err %d)",
@@ -6984,8 +7014,10 @@
ALOGV("onCreateInputSurface");
sp<IGraphicBufferProducer> bufferProducer;
+ sp<HGraphicBufferSource> bufferSource;
status_t err = mCodec->mOMX->createInputSurface(
- &bufferProducer, &mCodec->mGraphicBufferSource);
+ &bufferProducer, &bufferSource);
+ mCodec->mGraphicBufferSource = bufferSource;
if (err == OK) {
err = setupInputSurface();
@@ -7018,8 +7050,12 @@
}
sp<PersistentSurface> surface = static_cast<PersistentSurface *>(obj.get());
- mCodec->mGraphicBufferSource = surface->getBufferSource();
- status_t err = setupInputSurface();
+ sp<HGraphicBufferSource> hgbs = HGraphicBufferSource::castFrom(surface->getHidlTarget());
+ status_t err = BAD_VALUE;
+ if (hgbs) {
+ mCodec->mGraphicBufferSource = hgbs;
+ err = setupInputSurface();
+ }
if (err == OK) {
mCodec->mCallback->onInputSurfaceAccepted(
@@ -7538,8 +7574,14 @@
}
int64_t stopTimeOffsetUs;
- err = statusFromBinderStatus(
- mGraphicBufferSource->getStopTimeOffsetUs(&stopTimeOffsetUs));
+ hardware::Return<void> trans = mGraphicBufferSource->getStopTimeOffsetUs(
+ [&err, &stopTimeOffsetUs](auto status, auto result) {
+ err = static_cast<status_t>(status);
+ stopTimeOffsetUs = result;
+ });
+ if (!trans.isOk()) {
+ err = trans.isDeadObject() ? DEAD_OBJECT : UNKNOWN_ERROR;
+ }
if (err != OK) {
ALOGE("Failed to get stop time offset (err %d)", err);
@@ -7582,6 +7624,14 @@
}
}
+ int32_t lowLatency = 0;
+ if (params->findInt32("low-latency", &lowLatency)) {
+ status_t err = setLowLatency(lowLatency);
+ if (err != OK) {
+ return err;
+ }
+ }
+
int32_t latency = 0;
if (params->findInt32("latency", &latency) && latency > 0) {
status_t err = setLatency(latency);
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 832f9aa..e504327 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -19,8 +19,10 @@
],
cfi: true,
},
-
- shared_libs: ["libmedia"],
+ shared_libs: [
+ "libstagefright_foundation",
+ "libutils"
+ ],
}
cc_library_static {
@@ -58,10 +60,14 @@
"-Wall",
],
+ header_libs: [
+ "libmediadrm_headers",
+ ],
+
shared_libs: [
"libgui",
"liblog",
- "libmedia",
+ "libmedia_codeclist",
"libstagefright_foundation",
"libui",
"libutils",
@@ -96,6 +102,10 @@
"include",
],
+ header_libs: [
+ "libmedia_helper_headers",
+ ],
+
cflags: [
"-Wno-multichar",
"-Werror",
@@ -121,7 +131,6 @@
"ACodecBufferChannel.cpp",
"AHierarchicalStateMachine.cpp",
"AMRWriter.cpp",
- "AudioPlayer.cpp",
"AudioSource.cpp",
"BufferImpl.cpp",
"CallbackDataSource.cpp",
@@ -129,12 +138,7 @@
"CameraSource.cpp",
"CameraSourceTimeLapse.cpp",
"DataConverter.cpp",
- "DataSourceFactory.cpp",
- "DataURISource.cpp",
- "ClearFileSource.cpp",
- "FileSource.cpp",
"FrameDecoder.cpp",
- "HTTPBase.cpp",
"HevcUtils.cpp",
"InterfaceUtils.cpp",
"JPEGSource.cpp",
@@ -151,10 +155,7 @@
"MediaSource.cpp",
"MediaSync.cpp",
"MediaTrack.cpp",
- "http/ClearMediaHTTP.cpp",
- "http/MediaHTTP.cpp",
"MediaMuxer.cpp",
- "NuCachedSource2.cpp",
"NuMediaExtractor.cpp",
"OggWriter.cpp",
"OMXClient.cpp",
@@ -164,11 +165,10 @@
"SimpleDecodingSource.cpp",
"SkipCutBuffer.cpp",
"StagefrightMediaScanner.cpp",
- "StagefrightMetadataRetriever.cpp",
"StagefrightPluginLoader.cpp",
"SurfaceUtils.cpp",
- "Utils.cpp",
"ThrottledSource.cpp",
+ "Utils.cpp",
"VideoFrameSchedulerBase.cpp",
"VideoFrameScheduler.cpp",
],
@@ -179,12 +179,13 @@
"libbinder",
"libcamera_client",
"libcutils",
+ "libdatasource",
"libdl",
"libdl_android",
- "libdrmframework",
"libgui",
"liblog",
"libmedia",
+ "libmedia_codeclist",
"libmedia_omx",
"libmedia_omx_client",
"libaudioclient",
@@ -205,6 +206,7 @@
],
static_libs: [
+ "libstagefright_esds",
"libstagefright_color_conversion",
"libyuv_static",
"libstagefright_mediafilter",
@@ -212,12 +214,11 @@
"libstagefright_timedtext",
"libogg",
"libwebm",
- "libstagefright_esds",
"libstagefright_id3",
- "libFLAC",
],
header_libs:[
+ "libmediadrm_headers",
"libnativeloader-headers",
"libstagefright_xmlparser_headers",
"media_ndk_headers",
@@ -258,62 +259,3 @@
],
},
}
-
-cc_library_static {
- name: "libstagefright_player2",
-
- srcs: [
- "ClearFileSource.cpp",
- "DataURISource.cpp",
- "HTTPBase.cpp",
- "HevcUtils.cpp",
- "MediaClock.cpp",
- "MediaSource.cpp",
- "NdkUtils.cpp",
- "Utils.cpp",
- "VideoFrameSchedulerBase.cpp",
- "VideoFrameScheduler2.cpp",
- "http/ClearMediaHTTP.cpp",
- ],
-
- shared_libs: [
- "libgui",
- "liblog",
- "libnetd_client",
- "libutils",
- "libstagefright_foundation",
- "libandroid",
- ],
-
- static_libs: [
- "libmedia_player2_util",
- "libmedia2_jni_core",
- ],
-
- export_include_dirs: [
- "include",
- ],
-
- cflags: [
- "-Wno-multichar",
- "-Werror",
- "-Wno-error=deprecated-declarations",
- "-Wall",
- ],
-
- product_variables: {
- debuggable: {
- // enable experiments only in userdebug and eng builds
- cflags: ["-DENABLE_STAGEFRIGHT_EXPERIMENTS"],
- },
- },
-
- sanitize: {
- cfi: true,
- misc_undefined: [
- "unsigned-integer-overflow",
- "signed-integer-overflow",
- ],
- },
-}
-
diff --git a/media/libstagefright/BufferImpl.cpp b/media/libstagefright/BufferImpl.cpp
index 68440e6..b097324 100644
--- a/media/libstagefright/BufferImpl.cpp
+++ b/media/libstagefright/BufferImpl.cpp
@@ -21,7 +21,7 @@
#include <binder/IMemory.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <utils/NativeHandle.h>
#include "include/SecureBuffer.h"
diff --git a/media/libstagefright/CodecBase.cpp b/media/libstagefright/CodecBase.cpp
index d0610b2..97f38f8 100644
--- a/media/libstagefright/CodecBase.cpp
+++ b/media/libstagefright/CodecBase.cpp
@@ -18,7 +18,7 @@
#define LOG_TAG "CodecBase"
#include <android/hardware/cas/native/1.0/IDescrambler.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/stagefright/CodecBase.h>
#include <utils/Log.h>
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index a5a07d6..03415d5 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -23,7 +23,7 @@
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <inttypes.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/IMediaSource.h>
#include <media/MediaCodecBuffer.h>
#include <media/stagefright/foundation/avc_utils.h>
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index f130c9b..bf4e7de 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -2213,8 +2213,10 @@
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC) ||
!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC)) {
mMeta->findData(kKeyHVCC, &type, &data, &size);
- } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)
- || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION)) {
+ mMeta->findData(kKeyDVCC, &type, &data, &size);
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
+ !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
if (mMeta->findData(kKeyESDS, &type, &data, &size)) {
ESDS esds(data, size);
if (esds.getCodecSpecificInfo(&data, &size) == OK &&
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index b1404de..14564c9 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -21,13 +21,14 @@
#include <inttypes.h>
#include <stdlib.h>
-#include "include/SecureBuffer.h"
-#include "include/SharedMemoryBuffer.h"
#include "include/SoftwareRenderer.h"
#include "StagefrightPluginLoader.h"
#include <android/hardware/cas/native/1.0/IDescrambler.h>
+#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
+#include <android/media/BnResourceManagerClient.h>
+#include <android/media/IResourceManagerService.h>
#include <binder/IMemory.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
@@ -35,11 +36,11 @@
#include <cutils/properties.h>
#include <gui/BufferQueue.h>
#include <gui/Surface.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/IOMX.h>
-#include <media/IResourceManagerService.h>
#include <media/MediaCodecBuffer.h>
#include <media/MediaAnalyticsItem.h>
+#include <media/MediaResource.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
@@ -63,6 +64,10 @@
namespace android {
+using ::android::binder::Status;
+using ::android::media::BnResourceManagerClient;
+using ::android::media::IResourceManagerService;
+
// key for media statistics
static const char *kCodecKeyName = "codec";
// attrs for media statistics
@@ -123,11 +128,12 @@
struct ResourceManagerClient : public BnResourceManagerClient {
explicit ResourceManagerClient(MediaCodec* codec) : mMediaCodec(codec) {}
- virtual bool reclaimResource() {
+ Status reclaimResource(bool* _aidl_return) override {
sp<MediaCodec> codec = mMediaCodec.promote();
if (codec == NULL) {
// codec is already gone.
- return true;
+ *_aidl_return = true;
+ return Status::ok();
}
status_t err = codec->reclaim();
if (err == WOULD_BLOCK) {
@@ -139,22 +145,23 @@
if (err != OK) {
ALOGW("ResourceManagerClient failed to release codec with err %d", err);
}
- return (err == OK);
+ *_aidl_return = (err == OK);
+ return Status::ok();
}
- virtual String8 getName() {
- String8 ret;
+ Status getName(::std::string* _aidl_return) override {
+ _aidl_return->clear();
sp<MediaCodec> codec = mMediaCodec.promote();
if (codec == NULL) {
// codec is already gone.
- return ret;
+ return Status::ok();
}
AString name;
if (codec->getName(&name) == OK) {
- ret.setTo(name.c_str());
+ *_aidl_return = name.c_str();
}
- return ret;
+ return Status::ok();
}
protected:
@@ -166,6 +173,35 @@
DISALLOW_EVIL_CONSTRUCTORS(ResourceManagerClient);
};
+struct MediaCodec::ResourceManagerServiceProxy : public IBinder::DeathRecipient {
+ ResourceManagerServiceProxy(pid_t pid, uid_t uid);
+ ~ResourceManagerServiceProxy();
+
+ void init();
+
+ // implements DeathRecipient
+ virtual void binderDied(const wp<IBinder>& /*who*/);
+
+ void addResource(
+ int64_t clientId,
+ const sp<IResourceManagerClient> &client,
+ const std::vector<MediaResourceParcel> &resources);
+
+ void removeResource(
+ int64_t clientId,
+ const std::vector<MediaResourceParcel> &resources);
+
+ void removeClient(int64_t clientId);
+
+ bool reclaimResource(const std::vector<MediaResourceParcel> &resources);
+
+private:
+ Mutex mLock;
+ sp<android::media::IResourceManagerService> mService;
+ pid_t mPid;
+ uid_t mUid;
+};
+
MediaCodec::ResourceManagerServiceProxy::ResourceManagerServiceProxy(
pid_t pid, uid_t uid)
: mPid(pid), mUid(uid) {
@@ -200,7 +236,7 @@
void MediaCodec::ResourceManagerServiceProxy::addResource(
int64_t clientId,
const sp<IResourceManagerClient> &client,
- const Vector<MediaResource> &resources) {
+ const std::vector<MediaResourceParcel> &resources) {
Mutex::Autolock _l(mLock);
if (mService == NULL) {
return;
@@ -210,7 +246,7 @@
void MediaCodec::ResourceManagerServiceProxy::removeResource(
int64_t clientId,
- const Vector<MediaResource> &resources) {
+ const std::vector<MediaResourceParcel> &resources) {
Mutex::Autolock _l(mLock);
if (mService == NULL) {
return;
@@ -227,12 +263,14 @@
}
bool MediaCodec::ResourceManagerServiceProxy::reclaimResource(
- const Vector<MediaResource> &resources) {
+ const std::vector<MediaResourceParcel> &resources) {
Mutex::Autolock _l(mLock);
if (mService == NULL) {
return false;
}
- return mService->reclaimResource(mPid, resources);
+ bool success;
+ Status status = mService->reclaimResource(mPid, resources, &success);
+ return status.isOk() && success;
}
////////////////////////////////////////////////////////////////////////////////
@@ -506,7 +544,7 @@
sp<IOMX> omx = client.interface();
sp<IGraphicBufferProducer> bufferProducer;
- sp<IGraphicBufferSource> bufferSource;
+ sp<hardware::media::omx::V1_0::IGraphicBufferSource> bufferSource;
status_t err = omx->createInputSurface(&bufferProducer, &bufferSource);
@@ -754,7 +792,7 @@
if (mBatteryChecker != nullptr) {
mBatteryChecker->onCodecActivity([this] () {
- addResource(MediaResource::kBattery, MediaResource::kVideoCodec, 1);
+ addResource(MediaResource::VideoBatteryResource());
});
}
@@ -794,7 +832,7 @@
if (mBatteryChecker != nullptr) {
mBatteryChecker->onCodecActivity([this] () {
- addResource(MediaResource::kBattery, MediaResource::kVideoCodec, 1);
+ addResource(MediaResource::VideoBatteryResource());
});
}
@@ -992,12 +1030,8 @@
}
status_t err;
- Vector<MediaResource> resources;
- MediaResource::Type type =
- secureCodec ? MediaResource::kSecureCodec : MediaResource::kNonSecureCodec;
- MediaResource::SubType subtype =
- mIsVideo ? MediaResource::kVideoCodec : MediaResource::kAudioCodec;
- resources.push_back(MediaResource(type, subtype, 1));
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(MediaResource::CodecResource(secureCodec, mIsVideo));
for (int i = 0; i <= kMaxRetry; ++i) {
if (i > 0) {
// Don't try to reclaim resource for the first time.
@@ -1108,15 +1142,11 @@
mConfigureMsg = msg;
status_t err;
- Vector<MediaResource> resources;
- MediaResource::Type type = (mFlags & kFlagIsSecure) ?
- MediaResource::kSecureCodec : MediaResource::kNonSecureCodec;
- MediaResource::SubType subtype =
- mIsVideo ? MediaResource::kVideoCodec : MediaResource::kAudioCodec;
- resources.push_back(MediaResource(type, subtype, 1));
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(MediaResource::CodecResource(mFlags & kFlagIsSecure, mIsVideo));
// Don't know the buffer size at this point, but it's fine to use 1 because
// the reclaimResource call doesn't consider the requester's buffer size for now.
- resources.push_back(MediaResource(MediaResource::kGraphicMemory, 1));
+ resources.push_back(MediaResource::GraphicMemoryResource(1));
for (int i = 0; i <= kMaxRetry; ++i) {
if (i > 0) {
// Don't try to reclaim resource for the first time.
@@ -1241,18 +1271,16 @@
return size;
}
-void MediaCodec::addResource(
- MediaResource::Type type, MediaResource::SubType subtype, uint64_t value) {
- Vector<MediaResource> resources;
- resources.push_back(MediaResource(type, subtype, value));
+void MediaCodec::addResource(const MediaResourceParcel &resource) {
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(resource);
mResourceManagerService->addResource(
getId(mResourceManagerClient), mResourceManagerClient, resources);
}
-void MediaCodec::removeResource(
- MediaResource::Type type, MediaResource::SubType subtype, uint64_t value) {
- Vector<MediaResource> resources;
- resources.push_back(MediaResource(type, subtype, value));
+void MediaCodec::removeResource(const MediaResourceParcel &resource) {
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(resource);
mResourceManagerService->removeResource(getId(mResourceManagerClient), resources);
}
@@ -1260,15 +1288,11 @@
sp<AMessage> msg = new AMessage(kWhatStart, this);
status_t err;
- Vector<MediaResource> resources;
- MediaResource::Type type = (mFlags & kFlagIsSecure) ?
- MediaResource::kSecureCodec : MediaResource::kNonSecureCodec;
- MediaResource::SubType subtype =
- mIsVideo ? MediaResource::kVideoCodec : MediaResource::kAudioCodec;
- resources.push_back(MediaResource(type, subtype, 1));
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(MediaResource::CodecResource(mFlags & kFlagIsSecure, mIsVideo));
// Don't know the buffer size at this point, but it's fine to use 1 because
// the reclaimResource call doesn't consider the requester's buffer size for now.
- resources.push_back(MediaResource(MediaResource::kGraphicMemory, 1));
+ resources.push_back(MediaResource::GraphicMemoryResource(1));
for (int i = 0; i <= kMaxRetry; ++i) {
if (i > 0) {
// Don't try to reclaim resource for the first time.
@@ -1710,8 +1734,7 @@
totalPixel = width * height;
}
if (totalPixel >= 1920 * 1080) {
- addResource(MediaResource::kCpuBoost,
- MediaResource::kUnspecifiedSubType, 1);
+ addResource(MediaResource::CpuBoostResource());
mCpuBoostRequested = true;
}
}
@@ -2056,20 +2079,17 @@
}
mOwnerName = owner;
- MediaResource::Type resourceType;
if (mComponentName.endsWith(".secure")) {
mFlags |= kFlagIsSecure;
- resourceType = MediaResource::kSecureCodec;
mediametrics_setInt32(mMetricsHandle, kCodecSecure, 1);
} else {
mFlags &= ~kFlagIsSecure;
- resourceType = MediaResource::kNonSecureCodec;
mediametrics_setInt32(mMetricsHandle, kCodecSecure, 0);
}
if (mIsVideo) {
// audio codec is currently ignored.
- addResource(resourceType, MediaResource::kVideoCodec, 1);
+ addResource(MediaResource::CodecResource(mFlags & kFlagIsSecure, mIsVideo));
}
(new AMessage)->postReply(mReplyID);
@@ -2190,10 +2210,8 @@
CHECK_EQ(mState, STARTING);
if (mIsVideo) {
- addResource(
- MediaResource::kGraphicMemory,
- MediaResource::kUnspecifiedSubType,
- getGraphicBufferSize());
+ addResource(MediaResource::GraphicMemoryResource(
+ getGraphicBufferSize()));
}
setState(STARTED);
(new AMessage)->postReply(mReplyID);
@@ -3132,7 +3150,7 @@
{
if (mBatteryChecker != nullptr) {
mBatteryChecker->onCheckBatteryTimer(msg, [this] () {
- removeResource(MediaResource::kBattery, MediaResource::kVideoCodec, 1);
+ removeResource(MediaResource::VideoBatteryResource());
});
}
break;
diff --git a/media/libstagefright/MediaCodecListOverrides.cpp b/media/libstagefright/MediaCodecListOverrides.cpp
index dd7c3e6..6b5b50e 100644
--- a/media/libstagefright/MediaCodecListOverrides.cpp
+++ b/media/libstagefright/MediaCodecListOverrides.cpp
@@ -22,7 +22,7 @@
#include <cutils/properties.h>
#include <gui/Surface.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/IMediaCodecList.h>
#include <media/MediaCodecInfo.h>
#include <media/MediaResourcePolicy.h>
@@ -264,7 +264,9 @@
}
}
}
- global_results->add(kPolicySupportsMultipleSecureCodecs, supportMultipleSecureCodecs);
+ global_results->add(
+ MediaResourcePolicy::kPolicySupportsMultipleSecureCodecs().c_str(),
+ supportMultipleSecureCodecs);
}
static AString globalResultsToXml(const CodecSettings &results) {
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index 50e454c..7243b82 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -22,7 +22,7 @@
#include <gui/IGraphicBufferProducer.h>
#include <gui/Surface.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/MediaBufferHolder.h>
#include <media/MediaCodecBuffer.h>
#include <media/MediaSource.h>
diff --git a/media/libstagefright/NdkUtils.cpp b/media/libstagefright/NdkUtils.cpp
deleted file mode 100644
index 904fe72..0000000
--- a/media/libstagefright/NdkUtils.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-
-#include <media/stagefright/NdkUtils.h>
-#include <media/stagefright/Utils.h>
-#include <media/stagefright/foundation/AMessage.h>
-
-namespace android {
-
-sp<MetaData> convertMediaFormatWrapperToMetaData(const sp<AMediaFormatWrapper> &fmt) {
- sp<AMessage> msg = fmt->toAMessage();
- sp<MetaData> meta = new MetaData;
- convertMessageToMetaData(msg, meta);
- return meta;
-}
-
-} // namespace android
-
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 680d426..66fb4b0 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -22,13 +22,13 @@
#include "include/ESDS.h"
+#include <datasource/DataSourceFactory.h>
+#include <datasource/FileSource.h>
#include <media/DataSource.h>
#include <media/MediaSource.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSourceFactory.h>
-#include <media/stagefright/FileSource.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
@@ -36,6 +36,7 @@
#include <media/stagefright/MediaExtractorFactory.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
namespace android {
@@ -81,7 +82,7 @@
}
sp<DataSource> dataSource =
- DataSourceFactory::CreateFromURI(httpService, path, headers);
+ DataSourceFactory::getInstance()->CreateFromURI(httpService, path, headers);
if (dataSource == NULL) {
return -ENOENT;
diff --git a/media/libstagefright/SimpleDecodingSource.cpp b/media/libstagefright/SimpleDecodingSource.cpp
index 8b6262f..771dfea 100644
--- a/media/libstagefright/SimpleDecodingSource.cpp
+++ b/media/libstagefright/SimpleDecodingSource.cpp
@@ -20,7 +20,7 @@
#include <gui/Surface.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/MediaCodecBuffer.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/foundation/ALooper.h>
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 135151f..ac4d087 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -227,6 +227,68 @@
}
}
+static void parseDolbyVisionProfileLevelFromDvcc(const uint8_t *ptr, size_t size, sp<AMessage> &format) {
+ // dv_major.dv_minor Should be 1.0 or 2.1
+ if (size != 24 || ((ptr[0] != 1 || ptr[1] != 0) && (ptr[0] != 2 || ptr[1] != 1))) {
+ ALOGV("Size %zu, dv_major %d, dv_minor %d", size, ptr[0], ptr[1]);
+ return;
+ }
+
+ const uint8_t profile = ptr[2] >> 1;
+ const uint8_t level = ((ptr[2] & 0x1) << 5) | ((ptr[3] >> 3) & 0x1f);
+ const uint8_t rpu_present_flag = (ptr[3] >> 2) & 0x01;
+ const uint8_t el_present_flag = (ptr[3] >> 1) & 0x01;
+ const uint8_t bl_present_flag = (ptr[3] & 0x01);
+ const int32_t bl_compatibility_id = (int32_t)(ptr[4] >> 4);
+
+ ALOGV("profile-level-compatibility value in dv(c|v)c box %d-%d-%d",
+ profile, level, bl_compatibility_id);
+
+ // All Dolby Profiles will have profile and level info in MediaFormat
+ // Profile 8 and 9 will have bl_compatibility_id too.
+ const static ALookup<uint8_t, OMX_VIDEO_DOLBYVISIONPROFILETYPE> profiles{
+ {1, OMX_VIDEO_DolbyVisionProfileDvavPen},
+ {3, OMX_VIDEO_DolbyVisionProfileDvheDen},
+ {4, OMX_VIDEO_DolbyVisionProfileDvheDtr},
+ {5, OMX_VIDEO_DolbyVisionProfileDvheStn},
+ {6, OMX_VIDEO_DolbyVisionProfileDvheDth},
+ {7, OMX_VIDEO_DolbyVisionProfileDvheDtb},
+ {8, OMX_VIDEO_DolbyVisionProfileDvheSt},
+ {9, OMX_VIDEO_DolbyVisionProfileDvavSe},
+ {10, OMX_VIDEO_DolbyVisionProfileDvav110},
+ };
+
+ const static ALookup<uint8_t, OMX_VIDEO_DOLBYVISIONLEVELTYPE> levels{
+ {0, OMX_VIDEO_DolbyVisionLevelUnknown},
+ {1, OMX_VIDEO_DolbyVisionLevelHd24},
+ {2, OMX_VIDEO_DolbyVisionLevelHd30},
+ {3, OMX_VIDEO_DolbyVisionLevelFhd24},
+ {4, OMX_VIDEO_DolbyVisionLevelFhd30},
+ {5, OMX_VIDEO_DolbyVisionLevelFhd60},
+ {6, OMX_VIDEO_DolbyVisionLevelUhd24},
+ {7, OMX_VIDEO_DolbyVisionLevelUhd30},
+ {8, OMX_VIDEO_DolbyVisionLevelUhd48},
+ {9, OMX_VIDEO_DolbyVisionLevelUhd60},
+ };
+ // set rpuAssoc
+ if (rpu_present_flag && el_present_flag && !bl_present_flag) {
+ format->setInt32("rpuAssoc", 1);
+ }
+ // set profile & level if they are recognized
+ OMX_VIDEO_DOLBYVISIONPROFILETYPE codecProfile;
+ OMX_VIDEO_DOLBYVISIONLEVELTYPE codecLevel;
+ if (profiles.map(profile, &codecProfile)) {
+ format->setInt32("profile", codecProfile);
+ if (codecProfile == OMX_VIDEO_DolbyVisionProfileDvheSt ||
+ codecProfile == OMX_VIDEO_DolbyVisionProfileDvavSe) {
+ format->setInt32("bl_compatibility_id", bl_compatibility_id);
+ }
+ if (levels.map(level, &codecLevel)) {
+ format->setInt32("level", codecLevel);
+ }
+ }
+}
+
static void parseH263ProfileLevelFromD263(const uint8_t *ptr, size_t size, sp<AMessage> &format) {
if (size < 7) {
return;
@@ -1411,6 +1473,12 @@
msg->setBuffer("csd-0", buffer);
}
+ if (meta->findData(kKeyDVCC, &type, &data, &size)) {
+ const uint8_t *ptr = (const uint8_t *)data;
+ ALOGV("DV: calling parseDolbyVisionProfileLevelFromDvcc with data size %zu", size);
+ parseDolbyVisionProfileLevelFromDvcc(ptr, size, msg);
+ }
+
*format = msg;
return OK;
@@ -1839,6 +1907,32 @@
meta->setData(kKeyHVCC, kTypeHVCC, hvcc.data(), outsize);
} else if (mime == MEDIA_MIMETYPE_VIDEO_AV1) {
meta->setData(kKeyAV1C, 0, csd0->data(), csd0->size());
+ } else if (mime == MEDIA_MIMETYPE_VIDEO_DOLBY_VISION) {
+ if (msg->findBuffer("csd-2", &csd2)) {
+ meta->setData(kKeyDVCC, kTypeDVCC, csd2->data(), csd2->size());
+
+ size_t dvcc_size = 1024;
+ uint8_t dvcc[dvcc_size];
+ memcpy(dvcc, csd2->data(), dvcc_size);
+ const uint8_t profile = dvcc[2] >> 1;
+
+ if (profile > 1 && profile < 9) {
+ std::vector<uint8_t> hvcc(csd0size + 1024);
+ size_t outsize = reassembleHVCC(csd0, hvcc.data(), hvcc.size(), 4);
+ meta->setData(kKeyHVCC, kTypeHVCC, hvcc.data(), outsize);
+ } else if (DolbyVisionProfileDvav110 == profile) {
+ meta->setData(kKeyAV1C, 0, csd0->data(), csd0->size());
+ } else {
+ sp<ABuffer> csd1;
+ if (msg->findBuffer("csd-1", &csd1)) {
+ std::vector<char> avcc(csd0size + csd1->size() + 1024);
+ size_t outsize = reassembleAVCC(csd0, csd1, avcc.data());
+ meta->setData(kKeyAVCC, kTypeAVCC, avcc.data(), outsize);
+ }
+ }
+ } else {
+ ALOGW("We need csd-2!!. %s", msg->debugString().c_str());
+ }
} else if (mime == MEDIA_MIMETYPE_VIDEO_VP9) {
meta->setData(kKeyVp9CodecPrivate, 0, csd0->data(), csd0->size());
} else if (mime == MEDIA_MIMETYPE_AUDIO_OPUS) {
@@ -1885,8 +1979,18 @@
meta->setData(kKeyStreamHeader, 'mdat', csd0->data(), csd0->size());
} else if (msg->findBuffer("d263", &csd0)) {
meta->setData(kKeyD263, kTypeD263, csd0->data(), csd0->size());
- }
+ } else if (mime == MEDIA_MIMETYPE_VIDEO_DOLBY_VISION && msg->findBuffer("csd-2", &csd2)) {
+ meta->setData(kKeyDVCC, kTypeDVCC, csd2->data(), csd2->size());
+ // Remove CSD-2 from the data here to avoid duplicate data in meta
+ meta->remove(kKeyOpaqueCSD2);
+
+ if (msg->findBuffer("csd-avc", &csd0)) {
+ meta->setData(kKeyAVCC, kTypeAVCC, csd0->data(), csd0->size());
+ } else if (msg->findBuffer("csd-hevc", &csd0)) {
+ meta->setData(kKeyHVCC, kTypeHVCC, csd0->data(), csd0->size());
+ }
+ }
// XXX TODO add whatever other keys there are
#if 0
@@ -1895,22 +1999,6 @@
#endif
}
-AString MakeUserAgent() {
- AString ua;
- ua.append("stagefright/1.2 (Linux;Android ");
-
-#if (PROPERTY_VALUE_MAX < 8)
-#error "PROPERTY_VALUE_MAX must be at least 8"
-#endif
-
- char value[PROPERTY_VALUE_MAX];
- property_get("ro.build.version.release", value, "Unknown");
- ua.append(value);
- ua.append(")");
-
- return ua;
-}
-
status_t sendMetaDataToHal(sp<MediaPlayerBase::AudioSink>& sink,
const sp<MetaData>& meta)
{
@@ -2099,39 +2187,6 @@
return AudioSystem::isOffloadSupported(info);
}
-AString uriDebugString(const AString &uri, bool incognito) {
- if (incognito) {
- return AString("<URI suppressed>");
- }
-
- if (property_get_bool("media.stagefright.log-uri", false)) {
- return uri;
- }
-
- // find scheme
- AString scheme;
- const char *chars = uri.c_str();
- for (size_t i = 0; i < uri.size(); i++) {
- const char c = chars[i];
- if (!isascii(c)) {
- break;
- } else if (isalpha(c)) {
- continue;
- } else if (i == 0) {
- // first character must be a letter
- break;
- } else if (isdigit(c) || c == '+' || c == '.' || c =='-') {
- continue;
- } else if (c != ':') {
- break;
- }
- scheme = AString(uri, 0, i);
- scheme.append("://<suppressed>");
- return scheme;
- }
- return AString("<no-scheme URI suppressed>");
-}
-
HLSTime::HLSTime(const sp<AMessage>& meta) :
mSeq(-1),
mTimeUs(-1LL),
@@ -2230,36 +2285,4 @@
}
}
-AString nameForFd(int fd) {
- const size_t SIZE = 256;
- char buffer[SIZE];
- AString result;
- snprintf(buffer, SIZE, "/proc/%d/fd/%d", getpid(), fd);
- struct stat s;
- if (lstat(buffer, &s) == 0) {
- if ((s.st_mode & S_IFMT) == S_IFLNK) {
- char linkto[256];
- int len = readlink(buffer, linkto, sizeof(linkto));
- if(len > 0) {
- if(len > 255) {
- linkto[252] = '.';
- linkto[253] = '.';
- linkto[254] = '.';
- linkto[255] = 0;
- } else {
- linkto[len] = 0;
- }
- result.append(linkto);
- }
- } else {
- result.append("unexpected type for ");
- result.append(buffer);
- }
- } else {
- result.append("couldn't open ");
- result.append(buffer);
- }
- return result;
-}
-
} // namespace android
diff --git a/media/libstagefright/VideoFrameScheduler2.cpp b/media/libstagefright/VideoFrameScheduler2.cpp
deleted file mode 100644
index 23671f2..0000000
--- a/media/libstagefright/VideoFrameScheduler2.cpp
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "VideoFrameScheduler2"
-#include <utils/Log.h>
-#define ATRACE_TAG ATRACE_TAG_VIDEO
-#include <utils/Mutex.h>
-#include <utils/Thread.h>
-#include <utils/Trace.h>
-
-#include <algorithm>
-#include <jni.h>
-#include <math.h>
-
-#include <android/choreographer.h>
-#include <android/looper.h>
-#include <media/stagefright/VideoFrameScheduler2.h>
-#include <mediaplayer2/JavaVMHelper.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AUtils.h>
-
-namespace android {
-
-static void getVsyncOffset(nsecs_t* appVsyncOffsetPtr, nsecs_t* sfVsyncOffsetPtr);
-
-/* ======================================================================= */
-/* VsyncTracker */
-/* ======================================================================= */
-
-class VsyncTracker : public RefBase{
-public:
- VsyncTracker();
- ~VsyncTracker() {}
- nsecs_t getVsyncPeriod();
- nsecs_t getVsyncTime(nsecs_t periodOffset);
- void addSample(nsecs_t timestamp);
-
-private:
- static const int kMaxSamples = 32;
- static const int kMinSamplesForUpdate = 6;
- int mNumSamples;
- int mFirstSample;
- nsecs_t mReferenceTime;
- nsecs_t mPhase;
- nsecs_t mPeriod;
- nsecs_t mTimestampSamples[kMaxSamples];
- Mutex mLock;
-
- void updateModelLocked();
-};
-
-VsyncTracker::VsyncTracker()
- : mNumSamples(0),
- mFirstSample(0),
- mReferenceTime(0),
- mPhase(0),
- mPeriod(0) {
- for (int i = 0; i < kMaxSamples; i++) {
- mTimestampSamples[i] = 0;
- }
-}
-
-nsecs_t VsyncTracker::getVsyncPeriod() {
- Mutex::Autolock dataLock(mLock);
- return mPeriod;
-}
-
-nsecs_t VsyncTracker::getVsyncTime(nsecs_t periodOffset) {
- Mutex::Autolock dataLock(mLock);
- const nsecs_t now = systemTime();
- nsecs_t phase = mReferenceTime + mPhase;
-
- // result = (((now - phase) / mPeriod) + periodOffset + 1) * mPeriod + phase
- // prevent overflow
- nsecs_t result = (now - phase) / mPeriod;
- if (result > LONG_LONG_MAX - periodOffset - 1) {
- return LONG_LONG_MAX;
- } else {
- result += periodOffset + 1;
- }
- if (result > LONG_LONG_MAX / mPeriod) {
- return LONG_LONG_MAX;
- } else {
- result *= mPeriod;
- }
- if (result > LONG_LONG_MAX - phase) {
- return LONG_LONG_MAX;
- } else {
- result += phase;
- }
-
- return result;
-}
-
-void VsyncTracker::addSample(nsecs_t timestamp) {
- Mutex::Autolock dataLock(mLock);
- if (mNumSamples == 0) {
- mPhase = 0;
- mReferenceTime = timestamp;
- }
- int idx = (mFirstSample + mNumSamples) % kMaxSamples;
- mTimestampSamples[idx] = timestamp;
- if (mNumSamples < kMaxSamples) {
- mNumSamples++;
- } else {
- mFirstSample = (mFirstSample + 1) % kMaxSamples;
- }
- updateModelLocked();
-}
-
-void VsyncTracker::updateModelLocked() {
- if (mNumSamples < kMinSamplesForUpdate) {
- return;
- }
- nsecs_t durationSum = 0;
- nsecs_t minDuration = LONG_MAX;
- nsecs_t maxDuration = 0;
-
- for (int i = 1; i < mNumSamples; i++) {
- int idx = (mFirstSample + i) % kMaxSamples;
- int prev = (idx + kMaxSamples - 1) % kMaxSamples;
- long duration = mTimestampSamples[idx] - mTimestampSamples[prev];
- durationSum += duration;
- if (minDuration > duration) { minDuration = duration; }
- if (maxDuration < duration) { maxDuration = duration; }
- }
-
- durationSum -= (minDuration + maxDuration);
- mPeriod = durationSum / (mNumSamples - 3);
-
- double sampleAvgX = 0.0;
- double sampleAvgY = 0.0;
- double scale = 2.0 * M_PI / (double) mPeriod;
-
- for (int i = 1; i < mNumSamples; i++) {
- int idx = (mFirstSample + i) % kMaxSamples;
- long sample = mTimestampSamples[idx] - mReferenceTime;
- double samplePhase = (double) (sample % mPeriod) * scale;
- sampleAvgX += cos(samplePhase);
- sampleAvgY += sin(samplePhase);
- }
-
- sampleAvgX /= (double) mNumSamples - 1.0;
- sampleAvgY /= (double) mNumSamples - 1.0;
- mPhase = (long) (atan2(sampleAvgY, sampleAvgX) / scale);
-}
-
-static void frameCallback(int64_t frameTimeNanos, void* data) {
- if (data == NULL) {
- return;
- }
- sp<VsyncTracker> vsyncTracker(static_cast<VsyncTracker*>(data));
- vsyncTracker->addSample(frameTimeNanos);
- AChoreographer_postFrameCallback64(AChoreographer_getInstance(),
- frameCallback, static_cast<void*>(vsyncTracker.get()));
-}
-
-/* ======================================================================= */
-/* JNI */
-/* ======================================================================= */
-
-static void getVsyncOffset(nsecs_t* appVsyncOffsetPtr, nsecs_t* sfVsyncOffsetPtr) {
- static const nsecs_t kOneMillisecInNanosec = 1000000;
- static const nsecs_t kOneSecInNanosec = kOneMillisecInNanosec * 1000;
-
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- jclass jDisplayManagerGlobalCls = env->FindClass(
- "android/hardware/display/DisplayManagerGlobal");
- jclass jDisplayCls = env->FindClass("android/view/Display");
-
- jmethodID jGetInstance = env->GetStaticMethodID(jDisplayManagerGlobalCls,
- "getInstance", "()Landroid/hardware/display/DisplayManagerGlobal;");
- jobject javaDisplayManagerGlobalObj = env->CallStaticObjectMethod(
- jDisplayManagerGlobalCls, jGetInstance);
-
- jfieldID jDEFAULT_DISPLAY = env->GetStaticFieldID(jDisplayCls, "DEFAULT_DISPLAY", "I");
- jint DEFAULT_DISPLAY = env->GetStaticIntField(jDisplayCls, jDEFAULT_DISPLAY);
-
- jmethodID jgetRealDisplay = env->GetMethodID(jDisplayManagerGlobalCls,
- "getRealDisplay", "(I)Landroid/view/Display;");
- jobject javaDisplayObj = env->CallObjectMethod(
- javaDisplayManagerGlobalObj, jgetRealDisplay, DEFAULT_DISPLAY);
-
- jmethodID jGetRefreshRate = env->GetMethodID(jDisplayCls, "getRefreshRate", "()F");
- jfloat javaRefreshRate = env->CallFloatMethod(javaDisplayObj, jGetRefreshRate);
- nsecs_t vsyncPeriod = (nsecs_t) (kOneSecInNanosec / (float) javaRefreshRate);
-
- jmethodID jGetAppVsyncOffsetNanos = env->GetMethodID(
- jDisplayCls, "getAppVsyncOffsetNanos", "()J");
- jlong javaAppVsyncOffset = env->CallLongMethod(javaDisplayObj, jGetAppVsyncOffsetNanos);
- *appVsyncOffsetPtr = (nsecs_t) javaAppVsyncOffset;
-
- jmethodID jGetPresentationDeadlineNanos = env->GetMethodID(
- jDisplayCls, "getPresentationDeadlineNanos", "()J");
- jlong javaPresentationDeadline = env->CallLongMethod(
- javaDisplayObj, jGetPresentationDeadlineNanos);
-
- *sfVsyncOffsetPtr = vsyncPeriod - ((nsecs_t) javaPresentationDeadline - kOneMillisecInNanosec);
-}
-
-/* ======================================================================= */
-/* Choreographer Thread */
-/* ======================================================================= */
-
-struct ChoreographerThread : public Thread {
- ChoreographerThread(bool canCallJava);
- status_t init(void* data);
- virtual status_t readyToRun() override;
- virtual bool threadLoop() override;
-
-protected:
- virtual ~ChoreographerThread() {}
-
-private:
- DISALLOW_EVIL_CONSTRUCTORS(ChoreographerThread);
- void* mData;
-};
-
-ChoreographerThread::ChoreographerThread(bool canCallJava) : Thread(canCallJava) {
-}
-
-status_t ChoreographerThread::init(void* data) {
- if (data == NULL) {
- return NO_INIT;
- }
- mData = data;
- return OK;
-}
-
-status_t ChoreographerThread::readyToRun() {
- ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
- if (AChoreographer_getInstance() == NULL) {
- return NO_INIT;
- }
- AChoreographer_postFrameCallback64(AChoreographer_getInstance(), frameCallback, mData);
- return OK;
-}
-
-bool ChoreographerThread::threadLoop() {
- ALooper_pollOnce(-1, nullptr, nullptr, nullptr);
- return true;
-}
-
-/* ======================================================================= */
-/* Frame Scheduler */
-/* ======================================================================= */
-
-VideoFrameScheduler2::VideoFrameScheduler2() : VideoFrameSchedulerBase() {
-
- getVsyncOffset(&mAppVsyncOffset, &mSfVsyncOffset);
-
- Mutex::Autolock threadLock(mLock);
- mChoreographerThread = new ChoreographerThread(true);
-
- mVsyncTracker = new VsyncTracker();
- if (mChoreographerThread->init(static_cast<void*>(mVsyncTracker.get())) != OK) {
- mChoreographerThread.clear();
- }
- if (mChoreographerThread != NULL && mChoreographerThread->run("Choreographer") != OK) {
- mChoreographerThread.clear();
- }
-}
-
-void VideoFrameScheduler2::updateVsync() {
- mVsyncTime = 0;
- mVsyncPeriod = 0;
-
- if (mVsyncTracker != NULL) {
- mVsyncPeriod = mVsyncTracker->getVsyncPeriod();
- mVsyncTime = mVsyncTracker->getVsyncTime(mSfVsyncOffset - mAppVsyncOffset);
- }
- mVsyncRefreshAt = systemTime(SYSTEM_TIME_MONOTONIC) + kVsyncRefreshPeriod;
-}
-
-void VideoFrameScheduler2::release() {
- // Do not change order
- {
- Mutex::Autolock threadLock(mLock);
- mChoreographerThread->requestExitAndWait();
- mChoreographerThread.clear();
- }
-
- mVsyncTracker.clear();
-}
-
-VideoFrameScheduler2::~VideoFrameScheduler2() {
- release();
-}
-
-} // namespace android
diff --git a/media/libstagefright/filters/Android.bp b/media/libstagefright/filters/Android.bp
index b1f62c7..88f30c4 100644
--- a/media/libstagefright/filters/Android.bp
+++ b/media/libstagefright/filters/Android.bp
@@ -23,6 +23,10 @@
"-Wall",
],
+ header_libs: [
+ "libmediadrm_headers",
+ ],
+
shared_libs: [
"libgui",
"libmedia",
diff --git a/media/libstagefright/foundation/Android.bp b/media/libstagefright/foundation/Android.bp
index 4b88ae4..5485f6d 100644
--- a/media/libstagefright/foundation/Android.bp
+++ b/media/libstagefright/foundation/Android.bp
@@ -65,6 +65,7 @@
"AudioPresentationInfo.cpp",
"ByteUtils.cpp",
"ColorUtils.cpp",
+ "FoundationUtils.cpp",
"MediaBuffer.cpp",
"MediaBufferBase.cpp",
"MediaBufferGroup.cpp",
diff --git a/media/libstagefright/foundation/FoundationUtils.cpp b/media/libstagefright/foundation/FoundationUtils.cpp
new file mode 100644
index 0000000..8285e4c
--- /dev/null
+++ b/media/libstagefright/foundation/FoundationUtils.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "FoundationUtils"
+#include <utils/Log.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <cutils/properties.h>
+#include <media/stagefright/foundation/AString.h>
+
+namespace android {
+
+AString uriDebugString(const AString &uri, bool incognito) {
+ if (incognito) {
+ return AString("<URI suppressed>");
+ }
+
+ if (property_get_bool("media.stagefright.log-uri", false)) {
+ return uri;
+ }
+
+ // find scheme
+ AString scheme;
+ const char *chars = uri.c_str();
+ for (size_t i = 0; i < uri.size(); i++) {
+ const char c = chars[i];
+ if (!isascii(c)) {
+ break;
+ } else if (isalpha(c)) {
+ continue;
+ } else if (i == 0) {
+ // first character must be a letter
+ break;
+ } else if (isdigit(c) || c == '+' || c == '.' || c =='-') {
+ continue;
+ } else if (c != ':') {
+ break;
+ }
+ scheme = AString(uri, 0, i);
+ scheme.append("://<suppressed>");
+ return scheme;
+ }
+ return AString("<no-scheme URI suppressed>");
+}
+
+AString MakeUserAgent() {
+ AString ua;
+ ua.append("stagefright/1.2 (Linux;Android ");
+
+#if (PROPERTY_VALUE_MAX < 8)
+#error "PROPERTY_VALUE_MAX must be at least 8"
+#endif
+
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.build.version.release", value, "Unknown");
+ ua.append(value);
+ ua.append(")");
+
+ return ua;
+}
+
+AString nameForFd(int fd) {
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ AString result;
+ snprintf(buffer, SIZE, "/proc/%d/fd/%d", getpid(), fd);
+ struct stat s;
+ if (lstat(buffer, &s) == 0) {
+ if ((s.st_mode & S_IFMT) == S_IFLNK) {
+ char linkto[256];
+ int len = readlink(buffer, linkto, sizeof(linkto));
+ if(len > 0) {
+ if(len > 255) {
+ linkto[252] = '.';
+ linkto[253] = '.';
+ linkto[254] = '.';
+ linkto[255] = 0;
+ } else {
+ linkto[len] = 0;
+ }
+ result.append(linkto);
+ }
+ } else {
+ result.append("unexpected type for ");
+ result.append(buffer);
+ }
+ } else {
+ result.append("couldn't open ");
+ result.append(buffer);
+ }
+ return result;
+}
+
+} // namespace android
diff --git a/media/libstagefright/httplive/Android.bp b/media/libstagefright/httplive/Android.bp
index c0ee14e..12e7ca6 100644
--- a/media/libstagefright/httplive/Android.bp
+++ b/media/libstagefright/httplive/Android.bp
@@ -31,6 +31,7 @@
"liblog",
"libcrypto",
"libcutils",
+ "libdatasource",
"libmedia",
"libmediandk",
"libstagefright",
diff --git a/media/libstagefright/httplive/HTTPDownloader.cpp b/media/libstagefright/httplive/HTTPDownloader.cpp
index c7e92cd..68f1de9 100644
--- a/media/libstagefright/httplive/HTTPDownloader.cpp
+++ b/media/libstagefright/httplive/HTTPDownloader.cpp
@@ -21,13 +21,13 @@
#include "HTTPDownloader.h"
#include "M3UParser.h"
+#include <datasource/MediaHTTP.h>
+#include <datasource/FileSource.h>
#include <media/DataSource.h>
#include <media/MediaHTTPConnection.h>
#include <media/MediaHTTPService.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/ClearMediaHTTP.h>
-#include <media/stagefright/ClearFileSource.h>
#include <openssl/aes.h>
#include <openssl/md5.h>
#include <utils/Mutex.h>
@@ -38,7 +38,7 @@
HTTPDownloader::HTTPDownloader(
const sp<MediaHTTPService> &httpService,
const KeyedVector<String8, String8> &headers) :
- mHTTPDataSource(new ClearMediaHTTP(httpService->makeHTTPConnection())),
+ mHTTPDataSource(new MediaHTTP(httpService->makeHTTPConnection())),
mExtraHeaders(headers),
mDisconnecting(false) {
}
@@ -91,7 +91,7 @@
if (reconnect) {
if (!strncasecmp(url, "file://", 7)) {
- mDataSource = new ClearFileSource(url + 7);
+ mDataSource = new FileSource(url + 7);
} else if (strncasecmp(url, "http://", 7)
&& strncasecmp(url, "https://", 8)) {
return ERROR_UNSUPPORTED;
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 9cf97c7..3bad015 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -34,6 +34,7 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#include <utils/Mutex.h>
diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
index cb97a3c..e0324e3 100644
--- a/media/libstagefright/httplive/M3UParser.cpp
+++ b/media/libstagefright/httplive/M3UParser.cpp
@@ -27,6 +27,7 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#include <media/mediaplayer.h>
namespace android {
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index 0950db0..fdcde29 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -28,17 +28,18 @@
#include "mpeg2ts/AnotherPacketSource.h"
#include "mpeg2ts/HlsSampleDecryptor.h"
+#include <datasource/DataURISource.h>
#include <media/stagefright/foundation/ABitReader.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ByteUtils.h>
#include <media/stagefright/foundation/MediaKeys.h>
#include <media/stagefright/foundation/avc_utils.h>
-#include <media/stagefright/DataURISource.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MetaDataUtils.h>
#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#include <ctype.h>
#include <inttypes.h>
diff --git a/media/libstagefright/id3/Android.bp b/media/libstagefright/id3/Android.bp
index 7151d07..c8173cf 100644
--- a/media/libstagefright/id3/Android.bp
+++ b/media/libstagefright/id3/Android.bp
@@ -4,6 +4,7 @@
srcs: ["ID3.cpp"],
header_libs: [
+ "libmedia_headers",
"media_ndk_headers",
],
@@ -33,6 +34,7 @@
],
shared_libs: [
+ "libdatasource",
"libstagefright",
"libutils",
"liblog",
diff --git a/media/libstagefright/id3/testid3.cpp b/media/libstagefright/id3/testid3.cpp
index 86e6adf..9984d85 100644
--- a/media/libstagefright/id3/testid3.cpp
+++ b/media/libstagefright/id3/testid3.cpp
@@ -22,7 +22,7 @@
#include <dirent.h>
#include <binder/ProcessState.h>
-#include <media/stagefright/FileSource.h>
+#include <datasource/FileSource.h>
#include <media/stagefright/foundation/ADebug.h>
#define MAXPATHLEN 256
diff --git a/media/libstagefright/include/ACodecBufferChannel.h b/media/libstagefright/include/ACodecBufferChannel.h
index 7c01e45..3a087d1 100644
--- a/media/libstagefright/include/ACodecBufferChannel.h
+++ b/media/libstagefright/include/ACodecBufferChannel.h
@@ -25,7 +25,7 @@
#include <media/openmax/OMX_Types.h>
#include <media/stagefright/CodecBase.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/IOMX.h>
namespace android {
diff --git a/media/libstagefright/include/SecureBuffer.h b/media/libstagefright/include/SecureBuffer.h
index cf7933a..c45e0e5 100644
--- a/media/libstagefright/include/SecureBuffer.h
+++ b/media/libstagefright/include/SecureBuffer.h
@@ -18,7 +18,7 @@
#define SECURE_BUFFER_H_
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/MediaCodecBuffer.h>
namespace android {
diff --git a/media/libstagefright/include/media/stagefright/ACodec.h b/media/libstagefright/include/media/stagefright/ACodec.h
index 784fd36..7754de4 100644
--- a/media/libstagefright/include/media/stagefright/ACodec.h
+++ b/media/libstagefright/include/media/stagefright/ACodec.h
@@ -37,6 +37,15 @@
#define TRACK_BUFFER_TIMING 0
namespace android {
+namespace hardware {
+namespace media {
+namespace omx {
+namespace V1_0 {
+struct IGraphicBufferSource;
+} // namespace V1_0
+} // namespace omx
+} // namespace media
+} // namespace hardware
struct ABuffer;
class ACodecBufferChannel;
@@ -279,7 +288,7 @@
size_t mNumUndequeuedBuffers;
sp<DataConverter> mConverter[2];
- sp<IGraphicBufferSource> mGraphicBufferSource;
+ sp<hardware::media::omx::V1_0::IGraphicBufferSource> mGraphicBufferSource;
int64_t mRepeatFrameDelayUs;
int64_t mMaxPtsGapUs;
float mMaxFps;
@@ -496,6 +505,7 @@
AudioEncoding encoding = kAudioEncodingPcm16bit);
status_t setPriority(int32_t priority);
+ status_t setLowLatency(int32_t lowLatency);
status_t setLatency(uint32_t latency);
status_t getLatency(uint32_t *latency);
status_t setAudioPresentation(int32_t presentationId, int32_t programId);
diff --git a/media/libstagefright/include/media/stagefright/NdkUtils.h b/media/libstagefright/include/media/stagefright/FoundationUtils.h
similarity index 66%
rename from media/libstagefright/include/media/stagefright/NdkUtils.h
rename to media/libstagefright/include/media/stagefright/FoundationUtils.h
index a68884a..1548981 100644
--- a/media/libstagefright/include/media/stagefright/NdkUtils.h
+++ b/media/libstagefright/include/media/stagefright/FoundationUtils.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 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.
@@ -14,18 +14,19 @@
* limitations under the License.
*/
-#ifndef NDK_UTILS_H_
+#ifndef FOUNDATION_UTILS_H_
-#define NDK_UTILS_H_
+#define FOUNDATION_UTILS_H_
-#include <media/stagefright/MetaData.h>
-#include <media/NdkWrapper.h>
+#include <media/stagefright/foundation/AString.h>
namespace android {
-sp<MetaData> convertMediaFormatWrapperToMetaData(
- const sp<AMediaFormatWrapper> &fmt);
+AString MakeUserAgent();
+AString uriDebugString(const AString &uri, bool incognito = false);
+
+AString nameForFd(int fd);
} // namespace android
-#endif // NDK_UTILS_H_
+#endif // FOUNDATION_UTILS_H_
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index 01d0325..78d00b1 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -24,7 +24,6 @@
#include <gui/IGraphicBufferProducer.h>
#include <media/hardware/CryptoAPI.h>
#include <media/MediaCodecInfo.h>
-#include <media/MediaResource.h>
#include <media/MediaMetrics.h>
#include <media/stagefright/foundation/AHandler.h>
#include <media/stagefright/FrameRenderTracker.h>
@@ -43,8 +42,6 @@
struct ICrypto;
class MediaCodecBuffer;
class IMemory;
-class IResourceManagerClient;
-class IResourceManagerService;
struct PersistentSurface;
class SoftwareRenderer;
class Surface;
@@ -54,7 +51,13 @@
namespace V1_0 {
struct IDescrambler;
}}}}
+namespace media {
+class IResourceManagerClient;
+class MediaResourceParcel;
+}
using hardware::cas::native::V1_0::IDescrambler;
+using media::IResourceManagerClient;
+using media::MediaResourceParcel;
struct MediaCodec : public AHandler {
enum ConfigureFlags {
@@ -284,34 +287,7 @@
bool mOwnedByClient;
};
- struct ResourceManagerServiceProxy : public IBinder::DeathRecipient {
- ResourceManagerServiceProxy(pid_t pid, uid_t uid);
- ~ResourceManagerServiceProxy();
-
- void init();
-
- // implements DeathRecipient
- virtual void binderDied(const wp<IBinder>& /*who*/);
-
- void addResource(
- int64_t clientId,
- const sp<IResourceManagerClient> &client,
- const Vector<MediaResource> &resources);
-
- void removeResource(
- int64_t clientId,
- const Vector<MediaResource> &resources);
-
- void removeClient(int64_t clientId);
-
- bool reclaimResource(const Vector<MediaResource> &resources);
-
- private:
- Mutex mLock;
- sp<IResourceManagerService> mService;
- pid_t mPid;
- uid_t mUid;
- };
+ struct ResourceManagerServiceProxy;
State mState;
uid_t mUid;
@@ -434,8 +410,8 @@
bool isExecuting() const;
uint64_t getGraphicBufferSize();
- void addResource(MediaResource::Type type, MediaResource::SubType subtype, uint64_t value);
- void removeResource(MediaResource::Type type, MediaResource::SubType subtype, uint64_t value);
+ void addResource(const MediaResourceParcel &resource);
+ void removeResource(const MediaResourceParcel &resource);
void requestCpuBoostIfNeeded();
bool hasPendingBuffer(int portIndex);
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
index 50d7724..16e207d 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
@@ -510,22 +510,24 @@
constexpr int32_t DolbyVisionProfileDvheStn = 0x20;
constexpr int32_t DolbyVisionProfileDvheDth = 0x40;
constexpr int32_t DolbyVisionProfileDvheDtb = 0x80;
-constexpr int32_t DolbyVisionProfileDvheSt = 0x100;
-constexpr int32_t DolbyVisionProfileDvavSe = 0x200;
+constexpr int32_t DolbyVisionProfileDvheSt = 0x100;
+constexpr int32_t DolbyVisionProfileDvavSe = 0x200;
+constexpr int32_t DolbyVisionProfileDvav110 = 0x400;
inline static const char *asString_DolbyVisionProfile(int32_t i, const char *def = "??") {
switch (i) {
- case DolbyVisionProfileDvavPer: return "DvavPer";
- case DolbyVisionProfileDvavPen: return "DvavPen";
- case DolbyVisionProfileDvheDer: return "DvheDer";
- case DolbyVisionProfileDvheDen: return "DvheDen";
- case DolbyVisionProfileDvheDtr: return "DvheDtr";
- case DolbyVisionProfileDvheStn: return "DvheStn";
- case DolbyVisionProfileDvheDth: return "DvheDth";
- case DolbyVisionProfileDvheDtb: return "DvheDtb";
- case DolbyVisionProfileDvheSt: return "DvheSt";
- case DolbyVisionProfileDvavSe: return "DvavSe";
- default: return def;
+ case DolbyVisionProfileDvavPer: return "DvavPer";
+ case DolbyVisionProfileDvavPen: return "DvavPen";
+ case DolbyVisionProfileDvheDer: return "DvheDer";
+ case DolbyVisionProfileDvheDen: return "DvheDen";
+ case DolbyVisionProfileDvheDtr: return "DvheDtr";
+ case DolbyVisionProfileDvheStn: return "DvheStn";
+ case DolbyVisionProfileDvheDth: return "DvheDth";
+ case DolbyVisionProfileDvheDtb: return "DvheDtb";
+ case DolbyVisionProfileDvheSt: return "DvheSt";
+ case DolbyVisionProfileDvavSe: return "DvavSe";
+ case DolbyVisionProfileDvav110: return "Dav110";
+ default: return def;
}
}
@@ -774,6 +776,7 @@
constexpr char KEY_LANGUAGE[] = "language";
constexpr char KEY_LATENCY[] = "latency";
constexpr char KEY_LEVEL[] = "level";
+constexpr char KEY_LOW_LATENCY[] = "low-latency";
constexpr char KEY_MAX_B_FRAMES[] = "max-bframes";
constexpr char KEY_MAX_BIT_RATE[] = "max-bitrate";
constexpr char KEY_MAX_FPS_TO_ENCODER[] = "max-fps-to-encoder";
diff --git a/media/libstagefright/include/media/stagefright/MediaErrors.h b/media/libstagefright/include/media/stagefright/MediaErrors.h
index 09639e2..6f48c5d 100644
--- a/media/libstagefright/include/media/stagefright/MediaErrors.h
+++ b/media/libstagefright/include/media/stagefright/MediaErrors.h
@@ -99,7 +99,13 @@
ERROR_CAS_DEVICE_REVOKED = CAS_ERROR_BASE - 9,
ERROR_CAS_RESOURCE_BUSY = CAS_ERROR_BASE - 10,
ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION = CAS_ERROR_BASE - 11,
- ERROR_CAS_LAST_USED_ERRORCODE = CAS_ERROR_BASE - 11,
+ ERROR_CAS_NEED_ACTIVATION = CAS_ERROR_BASE - 12,
+ ERROR_CAS_NEED_PAIRING = CAS_ERROR_BASE - 13,
+ ERROR_CAS_NO_CARD = CAS_ERROR_BASE - 14,
+ ERROR_CAS_CARD_MUTE = CAS_ERROR_BASE - 15,
+ ERROR_CAS_CARD_INVALID = CAS_ERROR_BASE - 16,
+ ERROR_CAS_BLACKOUT = CAS_ERROR_BASE - 17,
+ ERROR_CAS_LAST_USED_ERRORCODE = CAS_ERROR_BASE - 17,
ERROR_CAS_VENDOR_MAX = CAS_ERROR_BASE - 500,
ERROR_CAS_VENDOR_MIN = CAS_ERROR_BASE - 999,
diff --git a/media/libstagefright/include/media/stagefright/MetaDataBase.h b/media/libstagefright/include/media/stagefright/MetaDataBase.h
index 659bd5b..e17093a 100644
--- a/media/libstagefright/include/media/stagefright/MetaDataBase.h
+++ b/media/libstagefright/include/media/stagefright/MetaDataBase.h
@@ -59,6 +59,7 @@
kKeyAACProfile = 'aacp', // int32_t
kKeyAVCC = 'avcc', // raw data
kKeyHVCC = 'hvcc', // raw data
+ kKeyDVCC = 'dvcc', // raw data
kKeyAV1C = 'av1c', // raw data
kKeyThumbnailHVCC = 'thvc', // raw data
kKeyD263 = 'd263', // raw data
@@ -245,6 +246,7 @@
kTypeAVCC = 'avcc',
kTypeHVCC = 'hvcc',
kTypeAV1C = 'av1c',
+ kTypeDVCC = 'dvcc',
kTypeD263 = 'd263',
};
diff --git a/media/libstagefright/include/media/stagefright/PersistentSurface.h b/media/libstagefright/include/media/stagefright/PersistentSurface.h
index 49b36c9..f4943c3 100644
--- a/media/libstagefright/include/media/stagefright/PersistentSurface.h
+++ b/media/libstagefright/include/media/stagefright/PersistentSurface.h
@@ -18,31 +18,21 @@
#define PERSISTENT_SURFACE_H_
-#include <android/IGraphicBufferSource.h>
#include <binder/Parcel.h>
#include <hidl/HidlSupport.h>
#include <hidl/HybridInterface.h>
#include <gui/IGraphicBufferProducer.h>
#include <media/stagefright/foundation/ABase.h>
-using android::hidl::base::V1_0::IBase;
-
namespace android {
struct PersistentSurface : public RefBase {
PersistentSurface() {}
- // create an OMX persistent surface
+ // create a persistent surface
PersistentSurface(
const sp<IGraphicBufferProducer>& bufferProducer,
- const sp<IGraphicBufferSource>& bufferSource) :
- mBufferProducer(bufferProducer),
- mBufferSource(bufferSource) { }
-
- // create a HIDL persistent surface
- PersistentSurface(
- const sp<IGraphicBufferProducer>& bufferProducer,
- const sp<IBase>& hidlTarget) :
+ const sp<hidl::base::V1_0::IBase>& hidlTarget) :
mBufferProducer(bufferProducer),
mHidlTarget(hidlTarget) { }
@@ -50,18 +40,12 @@
return mBufferProducer;
}
- sp<IGraphicBufferSource> getBufferSource() const {
- return mBufferSource;
- }
-
- sp<IBase> getHidlTarget() const {
+ sp<hidl::base::V1_0::IBase> getHidlTarget() const {
return mHidlTarget;
}
status_t writeToParcel(Parcel *parcel) const {
parcel->writeStrongBinder(IInterface::asBinder(mBufferProducer));
- // this can handle null
- parcel->writeStrongBinder(IInterface::asBinder(mBufferSource));
// write hidl target
if (mHidlTarget != nullptr) {
HalToken token;
@@ -79,8 +63,6 @@
status_t readFromParcel(const Parcel *parcel) {
mBufferProducer = interface_cast<IGraphicBufferProducer>(
parcel->readStrongBinder());
- mBufferSource = interface_cast<IGraphicBufferSource>(
- parcel->readStrongBinder());
// read hidl target
bool haveHidlTarget = parcel->readBool();
if (haveHidlTarget) {
@@ -97,8 +79,7 @@
private:
sp<IGraphicBufferProducer> mBufferProducer;
- sp<IGraphicBufferSource> mBufferSource;
- sp<IBase> mHidlTarget;
+ sp<hidl::base::V1_0::IBase> mHidlTarget;
DISALLOW_EVIL_CONSTRUCTORS(PersistentSurface);
};
diff --git a/media/libstagefright/include/media/stagefright/Utils.h b/media/libstagefright/include/media/stagefright/Utils.h
index e8e0a11..2b9b759 100644
--- a/media/libstagefright/include/media/stagefright/Utils.h
+++ b/media/libstagefright/include/media/stagefright/Utils.h
@@ -41,8 +41,6 @@
// TODO: combine this with avc_utils::getNextNALUnit
const uint8_t *findNextNalStartCode(const uint8_t *data, size_t length);
-AString MakeUserAgent();
-
// Convert a MIME type to a AudioSystem::audio_format
status_t mapMimeToAudioFormat(audio_format_t& format, const char* mime);
@@ -60,8 +58,6 @@
bool canOffloadStream(const sp<MetaData>& meta, bool hasVideo,
bool isStreaming, audio_stream_type_t streamType);
-AString uriDebugString(const AString &uri, bool incognito = false);
-
struct HLSTime {
int32_t mSeq;
int64_t mTimeUs;
@@ -85,7 +81,6 @@
void writeToAMessage(const sp<AMessage> &msg, const BufferingSettings &buffering);
void readFromAMessage(const sp<AMessage> &msg, BufferingSettings *buffering /* nonnull */);
-AString nameForFd(int fd);
} // namespace android
#endif // UTILS_H_
diff --git a/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp b/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp
index ed272bb..7d217eb 100644
--- a/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp
+++ b/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+#ifdef __LP64__
+#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
+#endif
+
//#define LOG_NDEBUG 0
#define LOG_TAG "TWGraphicBufferSource"
@@ -21,6 +25,7 @@
#include <media/stagefright/omx/1.0/WOmxNode.h>
#include <media/stagefright/omx/1.0/Conversion.h>
#include <media/stagefright/omx/OMXUtils.h>
+#include <media/stagefright/omx/OmxGraphicBufferSource.h>
#include <android/hardware/media/omx/1.0/IOmxBufferSource.h>
#include <android/hardware/media/omx/1.0/IOmxNode.h>
#include <media/openmax/OMX_Component.h>
diff --git a/media/libstagefright/omx/OmxGraphicBufferSource.cpp b/media/libstagefright/omx/OmxGraphicBufferSource.cpp
index 8de1f4f..7b187f9 100644
--- a/media/libstagefright/omx/OmxGraphicBufferSource.cpp
+++ b/media/libstagefright/omx/OmxGraphicBufferSource.cpp
@@ -14,12 +14,18 @@
* limitations under the License.
*/
+#ifdef __LP64__
+#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
+#endif
+
#include <inttypes.h>
#define LOG_TAG "OmxGraphicBufferSource"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
+#include <media/openmax/OMX_Core.h>
+
#include <media/stagefright/bqhelper/ComponentWrapper.h>
#include <media/stagefright/bqhelper/GraphicBufferSource.h>
#include <media/stagefright/omx/OmxGraphicBufferSource.h>
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 9669677..264c01d 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
@@ -48,7 +48,6 @@
#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
#include <android/hardware/media/omx/1.0/IOmxObserver.h>
-#include <android/IGraphicBufferSource.h>
#include <android/IOMXBufferSource.h>
namespace android {
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/1.0/WGraphicBufferSource.h b/media/libstagefright/omx/include/media/stagefright/omx/1.0/WGraphicBufferSource.h
index 4e56c98..02d4b7b 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/1.0/WGraphicBufferSource.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/1.0/WGraphicBufferSource.h
@@ -26,18 +26,16 @@
#include <android/hardware/media/omx/1.0/IOmxNode.h>
#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
-#include <android/BnGraphicBufferSource.h>
-
-#include <media/stagefright/omx/OmxGraphicBufferSource.h>
-
namespace android {
+
+class OmxGraphicBufferSource;
+
namespace hardware {
namespace media {
namespace omx {
namespace V1_0 {
namespace implementation {
-using ::android::OmxGraphicBufferSource;
using ::android::hardware::graphics::common::V1_0::Dataspace;
using ::android::hardware::media::omx::V1_0::ColorAspects;
using ::android::hardware::media::omx::V1_0::IGraphicBufferSource;
@@ -52,8 +50,6 @@
using ::android::hardware::Void;
using ::android::sp;
-using ::android::IOMXNode;
-
/**
* Wrapper classes for conversion
* ==============================
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/OmxGraphicBufferSource.h b/media/libstagefright/omx/include/media/stagefright/omx/OmxGraphicBufferSource.h
index 518e0cb..e576d75 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/OmxGraphicBufferSource.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/OmxGraphicBufferSource.h
@@ -21,7 +21,6 @@
#include <media/stagefright/bqhelper/GraphicBufferSource.h>
#include <media/stagefright/foundation/ABase.h>
-#include <android/BnGraphicBufferSource.h>
#include <android/BnOMXBufferSource.h>
#include "IOmxNodeWrapper.h"
diff --git a/media/libstagefright/omx/tests/Android.bp b/media/libstagefright/omx/tests/Android.bp
index 569fa88..eb01543 100644
--- a/media/libstagefright/omx/tests/Android.bp
+++ b/media/libstagefright/omx/tests/Android.bp
@@ -7,6 +7,7 @@
shared_libs: [
"libstagefright",
"libbinder",
+ "libdatasource",
"libmedia",
"libmedia_omx",
"libutils",
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index cc8c234..6848a83 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -27,13 +27,13 @@
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <cutils/properties.h>
+#include <datasource/DataSourceFactory.h>
#include <media/DataSource.h>
#include <media/IMediaHTTPService.h>
#include <media/MediaSource.h>
#include <media/OMXBuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/DataSourceFactory.h>
#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaDefs.h>
@@ -278,7 +278,7 @@
static sp<IMediaExtractor> CreateExtractorFromURI(const char *uri) {
sp<DataSource> source =
- DataSourceFactory::CreateFromURI(NULL /* httpService */, uri);
+ DataSourceFactory::getInstance()->CreateFromURI(NULL /* httpService */, uri);
if (source == NULL) {
return NULL;
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index 789e62a..cac1af9 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -21,12 +21,14 @@
#include "ARTSPConnection.h"
#include "NetworkUtils.h"
+#include <datasource/HTTPBase.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/base64.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#include <arpa/inet.h>
#include <fcntl.h>
@@ -34,7 +36,6 @@
#include <openssl/md5.h>
#include <sys/socket.h>
-#include "include/HTTPBase.h"
namespace android {
diff --git a/media/libstagefright/rtsp/Android.bp b/media/libstagefright/rtsp/Android.bp
index 9bc9c89..a5a895e 100644
--- a/media/libstagefright/rtsp/Android.bp
+++ b/media/libstagefright/rtsp/Android.bp
@@ -21,6 +21,7 @@
shared_libs: [
"libcrypto",
+ "libdatasource",
"libmedia",
],
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 85ffba2..7f025a5 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -36,18 +36,19 @@
#include <ctype.h>
#include <cutils/properties.h>
+#include <datasource/HTTPBase.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
-#include "HTTPBase.h"
#if LOG_NDEBUG
#define UNUSED_UNLESS_VERBOSE(x) (void)(x)
diff --git a/media/libstagefright/rtsp/SDPLoader.cpp b/media/libstagefright/rtsp/SDPLoader.cpp
index 665d51a..e236267 100644
--- a/media/libstagefright/rtsp/SDPLoader.cpp
+++ b/media/libstagefright/rtsp/SDPLoader.cpp
@@ -22,12 +22,13 @@
#include "ASessionDescription.h"
+#include <datasource/MediaHTTP.h>
#include <media/MediaHTTPConnection.h>
#include <media/MediaHTTPService.h>
-#include <media/stagefright/ClearMediaHTTP.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#define DEFAULT_SDP_SIZE 100000
@@ -41,7 +42,7 @@
mFlags(flags),
mNetLooper(new ALooper),
mCancelled(false),
- mHTTPDataSource(new ClearMediaHTTP(httpService->makeHTTPConnection())) {
+ mHTTPDataSource(new MediaHTTP(httpService->makeHTTPConnection())) {
mNetLooper->setName("sdp net");
mNetLooper->start(false /* runOnCallingThread */,
false /* canCallJava */,
diff --git a/media/libstagefright/timedtext/Android.bp b/media/libstagefright/timedtext/Android.bp
index 6935655..4f4ceb1 100644
--- a/media/libstagefright/timedtext/Android.bp
+++ b/media/libstagefright/timedtext/Android.bp
@@ -23,32 +23,4 @@
shared_libs: ["libmedia"],
}
-cc_library_static {
- name: "libstagefright_timedtext2",
- srcs: ["TextDescriptions2.cpp"],
-
- static_libs: [
- "libmediaplayer2-protos",
- "libprotobuf-cpp-lite",
- ],
-
- cflags: [
- "-Wno-multichar",
- "-Werror",
- "-Wall",
- ],
-
- sanitize: {
- misc_undefined: [
- "signed-integer-overflow",
- ],
- cfi: true,
- },
-
- include_dirs: [
- "frameworks/av/media/libstagefright",
- ],
-
- shared_libs: ["libmedia"],
-}
diff --git a/media/libstagefright/timedtext/TextDescriptions2.cpp b/media/libstagefright/timedtext/TextDescriptions2.cpp
deleted file mode 100644
index fd42d3a..0000000
--- a/media/libstagefright/timedtext/TextDescriptions2.cpp
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "TextDescriptions2.h"
-#include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/MediaErrors.h>
-
-namespace android {
-
-TextDescriptions2::TextDescriptions2() {
-}
-
-status_t TextDescriptions2::getPlayerMessageOfDescriptions(
- const uint8_t *data, ssize_t size,
- uint32_t flags, int timeMs, PlayerMessage *playerMsg) {
- if (flags & IN_BAND_TEXT_3GPP) {
- if (flags & GLOBAL_DESCRIPTIONS) {
- return extract3GPPGlobalDescriptions(data, size, playerMsg);
- } else if (flags & LOCAL_DESCRIPTIONS) {
- return extract3GPPLocalDescriptions(data, size, timeMs, playerMsg);
- }
- } else if (flags & OUT_OF_BAND_TEXT_SRT) {
- if (flags & LOCAL_DESCRIPTIONS) {
- return extractSRTLocalDescriptions(data, size, timeMs, playerMsg);
- }
- }
-
- return ERROR_UNSUPPORTED;
-}
-
-// Parse the SRT text sample, and store the timing and text sample in a PlayerMessage.
-// The PlayerMessage will be sent to MediaPlayer2.java through event, and will be
-// parsed in TimedText.java.
-status_t TextDescriptions2::extractSRTLocalDescriptions(
- const uint8_t *data, ssize_t size, int timeMs, PlayerMessage *playerMsg) {
- playerMsg->add_values()->set_int32_value(KEY_LOCAL_SETTING);
- playerMsg->add_values()->set_int32_value(KEY_START_TIME);
- playerMsg->add_values()->set_int32_value(timeMs);
-
- playerMsg->add_values()->set_int32_value(KEY_STRUCT_TEXT);
- playerMsg->add_values()->set_bytes_value(data, size);
-
- return OK;
-}
-
-// Extract the local 3GPP display descriptions. 3GPP local descriptions
-// are appended to the text sample if any.
-status_t TextDescriptions2::extract3GPPLocalDescriptions(
- const uint8_t *data, ssize_t size,
- int timeMs, PlayerMessage *playerMsg) {
-
- playerMsg->add_values()->set_int32_value(KEY_LOCAL_SETTING);
-
- // write start time to display this text sample
- playerMsg->add_values()->set_int32_value(KEY_START_TIME);
- playerMsg->add_values()->set_int32_value(timeMs);
-
- if (size < 2) {
- return OK;
- }
- ssize_t textLen = (*data) << 8 | (*(data + 1));
-
- if (size < textLen + 2) {
- return OK;
- }
-
- // write text sample length and text sample itself
- playerMsg->add_values()->set_int32_value(KEY_STRUCT_TEXT);
- playerMsg->add_values()->set_bytes_value(data + 2, textLen);
-
- if (size > textLen + 2) {
- data += (textLen + 2);
- size -= (textLen + 2);
- } else {
- return OK;
- }
-
- while (size >= 8) {
- const uint8_t *tmpData = data;
- ssize_t chunkSize = U32_AT(tmpData); // size includes size and type
- uint32_t chunkType = U32_AT(tmpData + 4);
-
- if (chunkSize <= 8 || chunkSize > size) {
- return OK;
- }
-
- size_t remaining = chunkSize - 8;
-
- tmpData += 8;
-
- switch(chunkType) {
- // 'tbox' box to indicate the position of the text with values
- // of top, left, bottom and right
- case FOURCC('t', 'b', 'o', 'x'):
- {
- if (remaining < 8) {
- return OK;
- }
- playerMsg->add_values()->set_int32_value(KEY_STRUCT_TEXT_POS);
- playerMsg->add_values()->set_int32_value(U16_AT(tmpData));
- playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 2));
- playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 4));
- playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 6));
-
- tmpData += 8;
- remaining -= 8;
- break;
- }
- default:
- {
- break;
- }
- }
-
- data += chunkSize;
- size -= chunkSize;
- }
-
- return OK;
-}
-
-// To extract box 'tx3g' defined in 3GPP TS 26.245, and store it in a PlayerMessage
-status_t TextDescriptions2::extract3GPPGlobalDescriptions(
- const uint8_t *data, ssize_t size, PlayerMessage *playerMsg) {
-
- playerMsg->add_values()->set_int32_value(KEY_GLOBAL_SETTING);
-
- while (size >= 8) {
- ssize_t chunkSize = U32_AT(data);
- uint32_t chunkType = U32_AT(data + 4);
- const uint8_t *tmpData = data;
- tmpData += 8;
- size_t remaining = size - 8;
-
- if (chunkSize <= 8 || size < chunkSize) {
- return OK;
- }
- switch(chunkType) {
- case FOURCC('t', 'x', '3', 'g'):
- {
- if (remaining < 18) {
- return OK;
- }
- // Skip DISPLAY_FLAGS, STRUCT_JUSTIFICATION, and BACKGROUND_COLOR_RGBA
- tmpData += 18;
- remaining -= 18;
-
- if (remaining < 8) {
- return OK;
- }
- playerMsg->add_values()->set_int32_value(KEY_STRUCT_TEXT_POS);
- playerMsg->add_values()->set_int32_value(U16_AT(tmpData));
- playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 2));
- playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 4));
- playerMsg->add_values()->set_int32_value(U16_AT(tmpData + 6));
-
- tmpData += 8;
- remaining -= 18;
- // Ignore remaining data.
- break;
- }
- default:
- {
- break;
- }
- }
-
- data += chunkSize;
- size -= chunkSize;
- }
-
- return OK;
-}
-
-} // namespace android
diff --git a/media/libstagefright/timedtext/TextDescriptions2.h b/media/libstagefright/timedtext/TextDescriptions2.h
deleted file mode 100644
index 7c7d2d0..0000000
--- a/media/libstagefright/timedtext/TextDescriptions2.h
+++ /dev/null
@@ -1,88 +0,0 @@
- /*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef TEXT_DESCRIPTIONS2_H_
-
-#define TEXT_DESCRIPTIONS2_H_
-
-#include <binder/Parcel.h>
-#include <media/stagefright/foundation/ABase.h>
-
-#include "mediaplayer2.pb.h"
-
-using android::media::MediaPlayer2Proto::PlayerMessage;
-
-namespace android {
-
-class TextDescriptions2 {
-public:
- enum {
- IN_BAND_TEXT_3GPP = 0x01,
- OUT_OF_BAND_TEXT_SRT = 0x02,
-
- GLOBAL_DESCRIPTIONS = 0x100,
- LOCAL_DESCRIPTIONS = 0x200,
- };
-
- static status_t getPlayerMessageOfDescriptions(
- const uint8_t *data, ssize_t size,
- uint32_t flags, int timeMs, PlayerMessage *playerMsg);
-private:
- TextDescriptions2();
-
- enum {
- // These keys must be in sync with the keys in TimedText.java
- KEY_DISPLAY_FLAGS = 1, // int
- KEY_STYLE_FLAGS = 2, // int
- KEY_BACKGROUND_COLOR_RGBA = 3, // int
- KEY_HIGHLIGHT_COLOR_RGBA = 4, // int
- KEY_SCROLL_DELAY = 5, // int
- KEY_WRAP_TEXT = 6, // int
- KEY_START_TIME = 7, // int
- KEY_STRUCT_BLINKING_TEXT_LIST = 8, // List<CharPos>
- KEY_STRUCT_FONT_LIST = 9, // List<Font>
- KEY_STRUCT_HIGHLIGHT_LIST = 10, // List<CharPos>
- KEY_STRUCT_HYPER_TEXT_LIST = 11, // List<HyperText>
- KEY_STRUCT_KARAOKE_LIST = 12, // List<Karaoke>
- KEY_STRUCT_STYLE_LIST = 13, // List<Style>
- KEY_STRUCT_TEXT_POS = 14, // TextPos
- KEY_STRUCT_JUSTIFICATION = 15, // Justification
- KEY_STRUCT_TEXT = 16, // Text
-
- KEY_GLOBAL_SETTING = 101,
- KEY_LOCAL_SETTING = 102,
- KEY_START_CHAR = 103,
- KEY_END_CHAR = 104,
- KEY_FONT_ID = 105,
- KEY_FONT_SIZE = 106,
- KEY_TEXT_COLOR_RGBA = 107,
- };
-
- static status_t extractSRTLocalDescriptions(
- const uint8_t *data, ssize_t size,
- int timeMs, PlayerMessage *playerMsg);
- static status_t extract3GPPGlobalDescriptions(
- const uint8_t *data, ssize_t size,
- PlayerMessage *playerMsg);
- static status_t extract3GPPLocalDescriptions(
- const uint8_t *data, ssize_t size,
- int timeMs, PlayerMessage *playerMsg);
-
- DISALLOW_EVIL_CONSTRUCTORS(TextDescriptions2);
-};
-
-} // namespace android
-#endif // TEXT_DESCRIPTIONS2_H_
diff --git a/media/libstagefright/webm/Android.bp b/media/libstagefright/webm/Android.bp
index 64ecc2d..2cebe8f 100644
--- a/media/libstagefright/webm/Android.bp
+++ b/media/libstagefright/webm/Android.bp
@@ -27,12 +27,14 @@
include_dirs: ["frameworks/av/include"],
shared_libs: [
+ "libdatasource",
"libstagefright_foundation",
"libutils",
"liblog",
],
header_libs: [
+ "libmedia_headers",
"media_ndk_headers",
],
}
diff --git a/media/libstagefright/webm/WebmFrameThread.h b/media/libstagefright/webm/WebmFrameThread.h
index 1ddaf9a..2dde20a 100644
--- a/media/libstagefright/webm/WebmFrameThread.h
+++ b/media/libstagefright/webm/WebmFrameThread.h
@@ -20,8 +20,8 @@
#include "WebmFrame.h"
#include "LinkedBlockingQueue.h"
+#include <datasource/FileSource.h>
#include <media/MediaSource.h>
-#include <media/stagefright/FileSource.h>
#include <utils/List.h>
#include <utils/Errors.h>
diff --git a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
index 9783e9b..d905b8d 100644
--- a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
+++ b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
@@ -1269,7 +1269,7 @@
void MediaCodecsXmlParser::Impl::State::addDetail(
const std::string &key, const std::string &value) {
CHECK(inType());
- ALOGI("limit: %s = %s", key.c_str(), value.c_str());
+ ALOGV("limit: %s = %s", key.c_str(), value.c_str());
const StringSet &variants = mVariantsStack.back();
if (variants.empty()) {
type()[key] = value;
diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp
index 7b22b05..1f65372 100644
--- a/media/mediaserver/main_mediaserver.cpp
+++ b/media/mediaserver/main_mediaserver.cpp
@@ -40,7 +40,7 @@
ALOGI("ServiceManager: %p", sm.get());
AIcu_initializeIcuOrDie();
MediaPlayerService::instantiate();
- ResourceManagerService::instantiate();
+ media::ResourceManagerService::instantiate();
registerExtensions();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 6adf563..af69a10 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -42,6 +42,7 @@
#include "MtpServer.h"
#include "MtpStorage.h"
#include "MtpStringBuffer.h"
+#include "android-base/strings.h"
namespace android {
static const int SN_EVENT_LOG_ID = 0x534e4554;
@@ -956,6 +957,11 @@
if (!mData.getString(modified)) return MTP_RESPONSE_INVALID_PARAMETER; // date modified
// keywords follow
+ int type = storage->getType();
+ if (type == MTP_STORAGE_REMOVABLE_RAM) {
+ std::string str = android::base::Trim((const char*)name);
+ name.set(str.c_str());
+ }
ALOGV("name: %s format: 0x%04X (%s)\n", (const char*)name, format,
MtpDebug::getFormatCodeName(format));
time_t modifiedTime;
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index a3cabd8..aac6d71 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -54,7 +54,6 @@
],
include_dirs: [
- "bionic/libc/private",
"frameworks/base/core/jni",
"frameworks/native/include/media/openmax",
"system/media/camera/include",
@@ -70,16 +69,21 @@
"libgrallocusage",
],
+ header_libs: [
+ "libmediadrm_headers",
+ ],
+
shared_libs: [
"android.hardware.graphics.bufferqueue@1.0",
"android.hidl.token@1.0-utils",
"libandroid_runtime_lazy",
"libbase",
"libbinder",
+ "libdatasource",
"libmedia",
+ "libmediadrm",
"libmedia_omx",
"libmedia_jni_utils",
- "libmediadrm",
"libstagefright",
"libstagefright_foundation",
"liblog",
@@ -90,7 +94,6 @@
"libhidlbase",
"libgui",
"libui",
- "libmedia2_jni_core",
"libmediandk_utils",
],
@@ -146,6 +149,10 @@
"-Wall",
],
+ header_libs: [
+ "libmedia_headers",
+ ],
+
shared_libs: [
],
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index e041533..af21a99 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -250,8 +250,8 @@
ALOGE("CB_ERROR: err is expected.");
break;
}
- if (!msg->findInt32("action", &actionCode)) {
- ALOGE("CB_ERROR: action is expected.");
+ if (!msg->findInt32("actionCode", &actionCode)) {
+ ALOGE("CB_ERROR: actionCode is expected.");
break;
}
msg->findString("detail", &detail);
diff --git a/media/ndk/NdkMediaCrypto.cpp b/media/ndk/NdkMediaCrypto.cpp
index ce2c660..792fc00 100644
--- a/media/ndk/NdkMediaCrypto.cpp
+++ b/media/ndk/NdkMediaCrypto.cpp
@@ -27,8 +27,8 @@
#include <utils/Log.h>
#include <utils/StrongPointer.h>
#include <binder/IServiceManager.h>
-#include <media/ICrypto.h>
-#include <media/IMediaDrmService.h>
+#include <mediadrm/ICrypto.h>
+#include <mediadrm/IMediaDrmService.h>
#include <android_util_Binder.h>
#include <jni.h>
diff --git a/media/ndk/NdkMediaCryptoPriv.h b/media/ndk/NdkMediaCryptoPriv.h
index 14ea928..8664d95 100644
--- a/media/ndk/NdkMediaCryptoPriv.h
+++ b/media/ndk/NdkMediaCryptoPriv.h
@@ -30,7 +30,7 @@
#include <sys/types.h>
#include <utils/StrongPointer.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
using namespace android;
diff --git a/media/ndk/NdkMediaDataSource.cpp b/media/ndk/NdkMediaDataSource.cpp
index 7979c2f..c1d4686 100644
--- a/media/ndk/NdkMediaDataSource.cpp
+++ b/media/ndk/NdkMediaDataSource.cpp
@@ -26,18 +26,16 @@
#include <android_runtime/AndroidRuntime.h>
#include <android_util_Binder.h>
#include <cutils/properties.h>
-#include <utils/Log.h>
-#include <utils/StrongPointer.h>
+#include <datasource/DataSourceFactory.h>
+#include <datasource/HTTPBase.h>
+#include <datasource/NuCachedSource2.h>
#include <media/IMediaHTTPService.h>
#include <media/NdkMediaError.h>
#include <media/NdkMediaDataSource.h>
-#include <media/stagefright/DataSourceFactory.h>
#include <media/stagefright/InterfaceUtils.h>
-#include <mediaplayer2/JavaVMHelper.h>
-#include <mediaplayer2/JMedia2HTTPService.h>
+#include <utils/Log.h>
+#include <utils/StrongPointer.h>
-#include "../../libstagefright/include/HTTPBase.h"
-#include "../../libstagefright/include/NuCachedSource2.h"
#include "NdkMediaDataSourceCallbacksPriv.h"
@@ -120,18 +118,11 @@
return size >= 0 ? OK : UNKNOWN_ERROR;
}
-static sp<MediaHTTPService> createMediaHttpServiceFromJavaObj(JNIEnv *env, jobject obj, int version) {
+static sp<MediaHTTPService> createMediaHttpServiceFromJavaObj(JNIEnv *env, jobject obj) {
if (obj == NULL) {
return NULL;
}
- switch (version) {
- case 1:
- return interface_cast<IMediaHTTPService>(ibinderForJavaObject(env, obj));
- case 2:
- return new JMedia2HTTPService(env, obj);
- default:
- return NULL;
- }
+ return interface_cast<IMediaHTTPService>(ibinderForJavaObject(env, obj));
}
static sp<MediaHTTPService> createMediaHttpServiceTemplate(
@@ -139,8 +130,7 @@
const char *uri,
const char *clazz,
const char *method,
- const char *signature,
- int version) {
+ const char *signature) {
jobject service = NULL;
if (env == NULL) {
ALOGE("http service must be created from Java thread");
@@ -167,34 +157,22 @@
env->DeleteLocalRef(juri);
env->ExceptionClear();
- sp<MediaHTTPService> httpService = createMediaHttpServiceFromJavaObj(env, service, version);
+ sp<MediaHTTPService> httpService = createMediaHttpServiceFromJavaObj(env, service);
return httpService;
}
-sp<MediaHTTPService> createMediaHttpService(const char *uri, int version) {
+sp<MediaHTTPService> createMediaHttpService(const char *uri) {
JNIEnv *env;
const char *clazz, *method, *signature;
- switch (version) {
- case 1:
- env = AndroidRuntime::getJNIEnv();
- clazz = "android/media/MediaHTTPService";
- method = "createHttpServiceBinderIfNecessary";
- signature = "(Ljava/lang/String;)Landroid/os/IBinder;";
- break;
- case 2:
- env = JavaVMHelper::getJNIEnv();
- clazz = "android/media/Media2HTTPService";
- method = "createHTTPService";
- signature = "(Ljava/lang/String;)Landroid/media/Media2HTTPService;";
- break;
- default:
- return NULL;
- }
+ env = AndroidRuntime::getJNIEnv();
+ clazz = "android/media/MediaHTTPService";
+ method = "createHttpServiceBinderIfNecessary";
+ signature = "(Ljava/lang/String;)Landroid/os/IBinder;";
- return createMediaHttpServiceTemplate(env, uri, clazz, method, signature, version);
+ return createMediaHttpServiceTemplate(env, uri, clazz, method, signature);
}
@@ -216,7 +194,7 @@
int numheaders,
const char * const *key_values) {
- sp<MediaHTTPService> service = createMediaHttpService(uri, /* version = */ 1);
+ sp<MediaHTTPService> service = createMediaHttpService(uri);
KeyedVector<String8, String8> headers;
for (int i = 0; i < numheaders; ++i) {
String8 key8(key_values[i * 2]);
@@ -224,7 +202,7 @@
headers.add(key8, value8);
}
- sp<DataSource> source = DataSourceFactory::CreateFromURI(service, uri, &headers);
+ sp<DataSource> source = DataSourceFactory::getInstance()->CreateFromURI(service, uri, &headers);
if (source == NULL) {
ALOGE("AMediaDataSource_newUri source is null");
return NULL;
diff --git a/media/ndk/NdkMediaDataSourcePriv.h b/media/ndk/NdkMediaDataSourcePriv.h
index 16ff974..ddcd7da 100644
--- a/media/ndk/NdkMediaDataSourcePriv.h
+++ b/media/ndk/NdkMediaDataSourcePriv.h
@@ -62,7 +62,7 @@
};
-sp<MediaHTTPService> createMediaHttpService(const char *uri, int version);
+sp<MediaHTTPService> createMediaHttpService(const char *uri);
#endif // _NDK_MEDIA_DATASOURCE_PRIV_H
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index cd5a23a..842216c 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -29,12 +29,12 @@
#include <android-base/properties.h>
#include <binder/PermissionController.h>
-#include <media/IDrm.h>
-#include <media/IDrmClient.h>
+#include <mediadrm/IDrm.h>
+#include <mediadrm/IDrmClient.h>
#include <media/stagefright/MediaErrors.h>
#include <binder/IServiceManager.h>
-#include <media/IMediaDrmService.h>
#include <media/NdkMediaCrypto.h>
+#include <mediadrm/IMediaDrmService.h>
using namespace android;
diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
index c83b255..0da0740 100644
--- a/media/ndk/NdkMediaExtractor.cpp
+++ b/media/ndk/NdkMediaExtractor.cpp
@@ -89,7 +89,7 @@
ALOGV("setDataSource(%s)", uri);
- sp<MediaHTTPService> httpService = createMediaHttpService(uri, /* version = */ 1);
+ sp<MediaHTTPService> httpService = createMediaHttpService(uri);
if (httpService == NULL) {
ALOGE("can't create http service");
return AMEDIA_ERROR_UNSUPPORTED;
diff --git a/media/tests/benchmark/Android.bp b/media/tests/benchmark/Android.bp
index 8a7a59f..de408dd 100644
--- a/media/tests/benchmark/Android.bp
+++ b/media/tests/benchmark/Android.bp
@@ -17,4 +17,5 @@
subdirs = [
"src",
"tests",
-]
\ No newline at end of file
+ "MediaBenchmarkTest",
+]
diff --git a/media/tests/benchmark/MediaBenchmarkTest/Android.bp b/media/tests/benchmark/MediaBenchmarkTest/Android.bp
new file mode 100644
index 0000000..91b03f1
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/Android.bp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+android_test {
+ name: "MediaBenchmarkTest",
+
+ // Include all the test code
+ srcs: ["src/androidTest/**/*.java"],
+
+ sdk_version: "system_current",
+
+ resource_dirs: ["res"],
+
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+
+ static_libs: [
+ "libMediaBenchmark",
+ "junit",
+ "androidx.test.runner",
+ ],
+}
+
+android_library {
+ name: "libMediaBenchmark",
+
+ // Include all the libraries
+ srcs: ["src/main/**/*.java"],
+
+ sdk_version: "system_current",
+
+ static_libs: [
+ "androidx.test.core",
+ ],
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/AndroidManifest.xml b/media/tests/benchmark/MediaBenchmarkTest/AndroidManifest.xml
new file mode 100644
index 0000000..eea9914
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2019 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.android.media.benchmark">
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
+
+ <application
+ tools:ignore="AllowBackup,GoogleAppIndexingWarning,MissingApplicationIcon"
+ tools:remove="android:appComponentFactory">
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.media.benchmark"
+ android:label="Benchmark Media Test"/>
+</manifest>
\ No newline at end of file
diff --git a/media/tests/benchmark/MediaBenchmarkTest/AndroidTest.xml b/media/tests/benchmark/MediaBenchmarkTest/AndroidTest.xml
new file mode 100644
index 0000000..89d6ce2
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs Media Benchmark Tests">
+ <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="test-file-name" value="MediaBenchmarkTest.apk" />
+ </target_preparer>
+
+ <option name="test-tag" value="MediaBenchmarkTest" />
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.media.benchmark" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+</configuration>
diff --git a/media/tests/benchmark/MediaBenchmarkTest/build.gradle b/media/tests/benchmark/MediaBenchmarkTest/build.gradle
new file mode 100644
index 0000000..b0ee692
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/build.gradle
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+buildscript {
+ repositories {
+ google()
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.5.0'
+ }
+}
+
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 29
+ defaultConfig {
+ applicationId "com.android.media.benchmark"
+ minSdkVersion 21
+ targetSdkVersion 29
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+ sourceSets {
+ main {
+ java.srcDirs 'src/main/java'
+ res.srcDirs 'res'
+ manifest.srcFile 'AndroidManifest.xml'
+ }
+ androidTest {
+ java.srcDirs 'src/androidTest/java'
+ res.srcDirs 'res'
+ manifest.srcFile 'AndroidManifest.xml'
+ }
+ }
+}
+
+repositories {
+ google()
+ jcenter()
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ implementation 'androidx.appcompat:appcompat:1.1.0'
+ testImplementation 'junit:junit:4.12'
+ androidTestImplementation 'androidx.test:runner:1.2.0'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.1'
+}
\ No newline at end of file
diff --git a/media/tests/benchmark/MediaBenchmarkTest/res/values/strings.xml b/media/tests/benchmark/MediaBenchmarkTest/res/values/strings.xml
new file mode 100644
index 0000000..24dbccc
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/res/values/strings.xml
@@ -0,0 +1,4 @@
+<resources>
+ <string name="input_file_path">/data/local/tmp/MediaBenchmark/res/</string>
+ <string name="output_file_path">/data/local/tmp/MediaBenchmark/output/</string>
+</resources>
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/DecoderTest.java b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/DecoderTest.java
new file mode 100644
index 0000000..be2633d
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/DecoderTest.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2019 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.benchmark.tests;
+
+import android.content.Context;
+import android.media.MediaCodec;
+import android.media.MediaFormat;
+import android.util.Log;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.media.benchmark.R;
+import com.android.media.benchmark.library.CodecUtils;
+import com.android.media.benchmark.library.Decoder;
+import com.android.media.benchmark.library.Extractor;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+public class DecoderTest {
+ private static final Context mContext =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
+ private static final String mInputFilePath = mContext.getString(R.string.input_file_path);
+ private static final String mOutputFilePath = mContext.getString(R.string.output_file_path);
+ private static final String TAG = "DecoderTest";
+ private static final long PER_TEST_TIMEOUT_MS = 60000;
+ private static final boolean DEBUG = false;
+ private static final boolean WRITE_OUTPUT = false;
+ private String mInputFile;
+ private boolean mAsyncMode;
+
+ public DecoderTest(String inputFile, boolean asyncMode) {
+ this.mInputFile = inputFile;
+ this.mAsyncMode = asyncMode;
+ }
+
+ @Parameterized.Parameters
+ public static Collection<Object[]> input() {
+ return Arrays.asList(new Object[][]{
+ //Audio Sync Test
+ {"bbb_44100hz_2ch_128kbps_aac_30sec.mp4", false},
+ {"bbb_44100hz_2ch_128kbps_mp3_30sec.mp3", false},
+ {"bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", false},
+ {"bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", false},
+ {"bbb_44100hz_2ch_80kbps_vorbis_30sec.mp4", false},
+ {"bbb_44100hz_2ch_600kbps_flac_30sec.mp4", false},
+ {"bbb_48000hz_2ch_100kbps_opus_30sec.webm", false},
+ // Audio Async Test
+ {"bbb_44100hz_2ch_128kbps_aac_30sec.mp4", true},
+ {"bbb_44100hz_2ch_128kbps_mp3_30sec.mp3", true},
+ {"bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", true},
+ {"bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", true},
+ {"bbb_44100hz_2ch_80kbps_vorbis_30sec.mp4", true},
+ {"bbb_44100hz_2ch_600kbps_flac_30sec.mp4", true},
+ {"bbb_48000hz_2ch_100kbps_opus_30sec.webm", true},
+ // Video Sync Test
+ {"crowd_1920x1080_25fps_4000kbps_vp9.webm", false},
+ {"crowd_1920x1080_25fps_4000kbps_vp8.webm", false},
+ {"crowd_1920x1080_25fps_4000kbps_av1.webm", false},
+ {"crowd_1920x1080_25fps_7300kbps_mpeg2.mp4", false},
+ {"crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", false},
+ {"crowd_352x288_25fps_6000kbps_h263.3gp", false},
+ {"crowd_1920x1080_25fps_6700kbps_h264.ts", false},
+ {"crowd_1920x1080_25fps_4000kbps_h265.mkv", false},
+ // Video Async Test
+ {"crowd_1920x1080_25fps_4000kbps_vp9.webm", true},
+ {"crowd_1920x1080_25fps_4000kbps_vp8.webm", true},
+ {"crowd_1920x1080_25fps_4000kbps_av1.webm", true},
+ {"crowd_1920x1080_25fps_7300kbps_mpeg2.mp4", true},
+ {"crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", true},
+ {"crowd_352x288_25fps_6000kbps_h263.3gp", true},
+ {"crowd_1920x1080_25fps_6700kbps_h264.ts", true},
+ {"crowd_1920x1080_25fps_4000kbps_h265.mkv", true}});
+ }
+
+ @Test(timeout = PER_TEST_TIMEOUT_MS)
+ public void testDecoder() throws IOException {
+ File inputFile = new File(mInputFilePath + mInputFile);
+ if (inputFile.exists()) {
+ FileInputStream fileInput = new FileInputStream(inputFile);
+ FileDescriptor fileDescriptor = fileInput.getFD();
+ Extractor extractor = new Extractor();
+ int trackCount = extractor.setUpExtractor(fileDescriptor);
+ ArrayList<ByteBuffer> inputBuffer = new ArrayList<>();
+ ArrayList<MediaCodec.BufferInfo> frameInfo = new ArrayList<>();
+ if (trackCount <= 0) {
+ Log.e(TAG, "Extraction failed. No tracks for file: " + mInputFile);
+ return;
+ }
+ for (int currentTrack = 0; currentTrack < trackCount; currentTrack++) {
+ extractor.selectExtractorTrack(currentTrack);
+ MediaFormat format = extractor.getFormat(currentTrack);
+ String mime = format.getString(MediaFormat.KEY_MIME);
+ ArrayList<String> mediaCodecs = CodecUtils.selectCodecs(mime, false);
+ if (mediaCodecs.size() <= 0) {
+ Log.e(TAG,
+ "No suitable codecs found for file: " + mInputFile
+ + " track : " + currentTrack + " mime: " + mime);
+ continue;
+ }
+ // Get samples from extractor
+ int sampleSize;
+ do {
+ sampleSize = extractor.getFrameSample();
+ MediaCodec.BufferInfo bufInfo = new MediaCodec.BufferInfo();
+ MediaCodec.BufferInfo info = extractor.getBufferInfo();
+ ByteBuffer dataBuffer = ByteBuffer.allocate(info.size);
+ dataBuffer.put(extractor.getFrameBuffer().array(), 0, info.size);
+ bufInfo.set(info.offset, info.size, info.presentationTimeUs, info.flags);
+ inputBuffer.add(dataBuffer);
+ frameInfo.add(bufInfo);
+ if (DEBUG) {
+ Log.d(TAG,
+ "Extracted bufInfo: flag = " + bufInfo.flags + " timestamp = "
+ + bufInfo.presentationTimeUs + " size = " + bufInfo.size);
+ }
+ } while (sampleSize > 0);
+ for (String codecName : mediaCodecs) {
+ FileOutputStream decodeOutputStream = null;
+ if (WRITE_OUTPUT) {
+ if (!Paths.get(mOutputFilePath).toFile().exists()) {
+ Files.createDirectories(Paths.get(mOutputFilePath));
+ }
+ File outFile = new File(mOutputFilePath + "decoder.out");
+ if (outFile.exists()) {
+ if (!outFile.delete()) {
+ Log.e(TAG, " Unable to delete existing file" + outFile.toString());
+ }
+ }
+ if (outFile.createNewFile()) {
+ decodeOutputStream = new FileOutputStream(outFile);
+ } else {
+ Log.e(TAG, "Unable to create file: " + outFile.toString());
+ }
+ }
+ Decoder decoder = new Decoder();
+ decoder.setupDecoder(decodeOutputStream);
+ int status =
+ decoder.decode(inputBuffer, frameInfo, mAsyncMode, format, codecName);
+ decoder.deInitCodec();
+ if (status == 0) {
+ decoder.dumpStatistics(
+ mInputFile + " " + codecName, extractor.getClipDuration());
+ Log.i(TAG,
+ "Decoding Successful for file: " + mInputFile
+ + " with codec: " + codecName);
+ } else {
+ Log.e(TAG,
+ "Decoder returned error " + status + " for file: " + mInputFile
+ + " with codec: " + codecName);
+ }
+ decoder.resetDecoder();
+ if (decodeOutputStream != null) {
+ decodeOutputStream.close();
+ }
+ }
+ extractor.unselectExtractorTrack(currentTrack);
+ inputBuffer.clear();
+ frameInfo.clear();
+ }
+ extractor.deinitExtractor();
+ fileInput.close();
+ } else {
+ Log.w(TAG,
+ "Warning: Test Skipped. Cannot find " + mInputFile + " in directory "
+ + mInputFilePath);
+ }
+ }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/EncoderTest.java b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/EncoderTest.java
new file mode 100644
index 0000000..9db9c84
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/EncoderTest.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2019 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.benchmark.tests;
+
+import android.content.Context;
+import android.media.MediaCodec;
+import android.media.MediaFormat;
+import android.util.Log;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.media.benchmark.R;
+import com.android.media.benchmark.library.CodecUtils;
+import com.android.media.benchmark.library.Decoder;
+import com.android.media.benchmark.library.Encoder;
+import com.android.media.benchmark.library.Extractor;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.nio.ByteBuffer;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+public class EncoderTest {
+ private static final Context mContext =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
+ private static final String mInputFilePath = mContext.getString(R.string.input_file_path);
+ private static final String mOutputFilePath = mContext.getString(R.string.output_file_path);
+ private static final String TAG = "EncoderTest";
+ private static final long PER_TEST_TIMEOUT_MS = 120000;
+ private static final boolean DEBUG = false;
+ private static final boolean WRITE_OUTPUT = false;
+ private static final int ENCODE_DEFAULT_FRAME_RATE = 25;
+ private static final int ENCODE_DEFAULT_BIT_RATE = 8000000 /* 8 Mbps */;
+ private static final int ENCODE_MIN_BIT_RATE = 600000 /* 600 Kbps */;
+
+ private String mInputFile;
+
+ @Parameterized.Parameters
+ public static Collection<Object[]> inputFiles() {
+ return Arrays.asList(new Object[][]{
+ // Audio Test
+ {"bbb_44100hz_2ch_128kbps_aac_30sec.mp4"},
+ {"bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp"},
+ {"bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp"},
+ {"bbb_44100hz_2ch_600kbps_flac_30sec.mp4"},
+ {"bbb_48000hz_2ch_100kbps_opus_30sec.webm"},
+ // Video Test
+ {"crowd_1920x1080_25fps_4000kbps_vp8.webm"},
+ {"crowd_1920x1080_25fps_6700kbps_h264.ts"},
+ {"crowd_1920x1080_25fps_4000kbps_h265.mkv"},
+ {"crowd_1920x1080_25fps_4000kbps_vp9.webm"},
+ {"crowd_176x144_25fps_6000kbps_mpeg4.mp4"},
+ {"crowd_176x144_25fps_6000kbps_h263.3gp"}});
+ }
+
+ public EncoderTest(String inputFileName) {
+ this.mInputFile = inputFileName;
+ }
+
+ @Test(timeout = PER_TEST_TIMEOUT_MS)
+ public void sampleEncoderTest() throws Exception {
+ int status;
+ int frameSize;
+
+ //Parameters for video
+ int width = 0;
+ int height = 0;
+ int profile = 0;
+ int level = 0;
+ int frameRate = 0;
+
+ //Parameters for audio
+ int bitRate = 0;
+ int sampleRate = 0;
+ int numChannels = 0;
+
+ File inputFile = new File(mInputFilePath + mInputFile);
+ if (inputFile.exists()) {
+ FileInputStream fileInput = new FileInputStream(inputFile);
+ FileDescriptor fileDescriptor = fileInput.getFD();
+ Extractor extractor = new Extractor();
+ int trackCount = extractor.setUpExtractor(fileDescriptor);
+ if (trackCount <= 0) {
+ Log.e(TAG, "Extraction failed. No tracks for file: " + mInputFile);
+ return;
+ }
+ ArrayList<ByteBuffer> inputBuffer = new ArrayList<>();
+ ArrayList<MediaCodec.BufferInfo> frameInfo = new ArrayList<>();
+ for (int currentTrack = 0; currentTrack < trackCount; currentTrack++) {
+ extractor.selectExtractorTrack(currentTrack);
+ MediaFormat format = extractor.getFormat(currentTrack);
+ // Get samples from extractor
+ int sampleSize;
+ do {
+ sampleSize = extractor.getFrameSample();
+ MediaCodec.BufferInfo bufInfo = new MediaCodec.BufferInfo();
+ MediaCodec.BufferInfo info = extractor.getBufferInfo();
+ ByteBuffer dataBuffer = ByteBuffer.allocate(info.size);
+ dataBuffer.put(extractor.getFrameBuffer().array(), 0, info.size);
+ bufInfo.set(info.offset, info.size, info.presentationTimeUs, info.flags);
+ inputBuffer.add(dataBuffer);
+ frameInfo.add(bufInfo);
+ if (DEBUG) {
+ Log.d(TAG, "Extracted bufInfo: flag = " + bufInfo.flags + " timestamp = " +
+ bufInfo.presentationTimeUs + " size = " + bufInfo.size);
+ }
+ } while (sampleSize > 0);
+
+ int tid = android.os.Process.myTid();
+ File decodedFile = new File(mContext.getFilesDir() + "/decoder_" + tid + ".out");
+ FileOutputStream decodeOutputStream = new FileOutputStream(decodedFile);
+ Decoder decoder = new Decoder();
+ decoder.setupDecoder(decodeOutputStream);
+ status = decoder.decode(inputBuffer, frameInfo, false, format, "");
+ if (status == 0) {
+ Log.i(TAG, "Decoding complete.");
+ } else {
+ Log.e(TAG, "Decode returned error. Encoding did not take place." + status);
+ return;
+ }
+ decoder.deInitCodec();
+ extractor.unselectExtractorTrack(currentTrack);
+ inputBuffer.clear();
+ frameInfo.clear();
+ if (decodeOutputStream != null) {
+ decodeOutputStream.close();
+ }
+ String mime = format.getString(MediaFormat.KEY_MIME);
+ ArrayList<String> mediaCodecs = CodecUtils.selectCodecs(mime, true);
+ if (mediaCodecs.size() <= 0) {
+ Log.e(TAG, "No suitable codecs found for file: " + mInputFile + " track : " +
+ currentTrack + " mime: " + mime);
+ return;
+ }
+ Boolean[] encodeMode = {true, false};
+ /* Encoding the decoder's output */
+ for (Boolean asyncMode : encodeMode) {
+ for (String codecName : mediaCodecs) {
+ FileOutputStream encodeOutputStream = null;
+ if (WRITE_OUTPUT) {
+ File outEncodeFile = new File(mOutputFilePath + "encoder.out");
+ if (outEncodeFile.exists()) {
+ if (!outEncodeFile.delete()) {
+ Log.e(TAG, "Unable to delete existing file" +
+ decodedFile.toString());
+ }
+ }
+ if (outEncodeFile.createNewFile()) {
+ encodeOutputStream = new FileOutputStream(outEncodeFile);
+ } else {
+ Log.e(TAG, "Unable to create file to write encoder output: " +
+ outEncodeFile.toString());
+ }
+ }
+ File rawFile =
+ new File(mContext.getFilesDir() + "/decoder_" + tid + ".out");
+ if (rawFile.exists()) {
+ if (DEBUG) {
+ Log.i(TAG, "Path of decoded input file: " + rawFile.toString());
+ }
+ FileInputStream eleStream = new FileInputStream(rawFile);
+ if (mime.startsWith("video/")) {
+ width = format.getInteger(MediaFormat.KEY_WIDTH);
+ height = format.getInteger(MediaFormat.KEY_HEIGHT);
+ if (format.containsKey(MediaFormat.KEY_FRAME_RATE)) {
+ frameRate = format.getInteger(MediaFormat.KEY_FRAME_RATE);
+ } else if (frameRate <= 0) {
+ frameRate = ENCODE_DEFAULT_FRAME_RATE;
+ }
+ if (format.containsKey(MediaFormat.KEY_BIT_RATE)) {
+ bitRate = format.getInteger(MediaFormat.KEY_BIT_RATE);
+ } else if (bitRate <= 0) {
+ if (mime.contains("video/3gpp") ||
+ mime.contains("video/mp4v-es")) {
+ bitRate = ENCODE_MIN_BIT_RATE;
+ } else {
+ bitRate = ENCODE_DEFAULT_BIT_RATE;
+ }
+ }
+ if (format.containsKey(MediaFormat.KEY_PROFILE)) {
+ profile = format.getInteger(MediaFormat.KEY_PROFILE);
+ }
+ if (format.containsKey(MediaFormat.KEY_PROFILE)) {
+ level = format.getInteger(MediaFormat.KEY_LEVEL);
+ }
+ } else {
+ sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
+ numChannels = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
+ bitRate = sampleRate * numChannels * 16;
+ }
+ /*Setup Encode Format*/
+ MediaFormat encodeFormat;
+ if (mime.startsWith("video/")) {
+ frameSize = width * height * 3 / 2;
+ encodeFormat = MediaFormat.createVideoFormat(mime, width, height);
+ encodeFormat.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);
+ encodeFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
+ encodeFormat.setInteger(MediaFormat.KEY_PROFILE, profile);
+ encodeFormat.setInteger(MediaFormat.KEY_LEVEL, level);
+ encodeFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);
+ encodeFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, frameSize);
+ } else {
+ encodeFormat = MediaFormat
+ .createAudioFormat(mime, sampleRate, numChannels);
+ encodeFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
+ frameSize = 4096;
+ }
+ Encoder encoder = new Encoder();
+ encoder.setupEncoder(encodeOutputStream, eleStream);
+ status = encoder.encode(codecName, encodeFormat, mime, frameRate,
+ sampleRate, frameSize, asyncMode);
+ encoder.deInitEncoder();
+ if (status == 0) {
+ encoder.dumpStatistics(mInputFile + "with " + codecName + " for " +
+ "aSyncMode = " + asyncMode, extractor.getClipDuration());
+ Log.i(TAG, "Encoding complete for file: " + mInputFile +
+ " with codec: " + codecName + " for aSyncMode = " +
+ asyncMode);
+ } else {
+ Log.e(TAG,
+ codecName + " encoder returned error " + status + " for " +
+ "file:" + " " + mInputFile);
+ }
+ encoder.resetEncoder();
+ eleStream.close();
+ if (encodeOutputStream != null) {
+ encodeOutputStream.close();
+ }
+ }
+ }
+ }
+ //Cleanup temporary input file
+ if (decodedFile.exists()) {
+ if (decodedFile.delete()) {
+ Log.i(TAG, "Successfully deleted decoded file");
+ } else {
+ Log.e(TAG, "Unable to delete decoded file");
+ }
+ }
+ }
+ extractor.deinitExtractor();
+ fileInput.close();
+ } else {
+ Log.w(TAG, "Warning: Test Skipped. Cannot find " + mInputFile + " in directory " +
+ mInputFilePath);
+ }
+ }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/ExtractorTest.java b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/ExtractorTest.java
new file mode 100644
index 0000000..a02011c
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/ExtractorTest.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2019 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.benchmark.tests;
+
+import com.android.media.benchmark.R;
+import com.android.media.benchmark.library.Extractor;
+
+import android.content.Context;
+import android.util.Log;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+@RunWith(Parameterized.class)
+public class ExtractorTest {
+ private static Context mContext =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
+ private static final String mInputFilePath = mContext.getString(R.string.input_file_path);
+ private static final String TAG = "ExtractorTest";
+ private String mInputFileName;
+ private int mTrackId;
+
+ @Parameterized.Parameters
+ public static Collection<Object[]> inputFiles() {
+ return Arrays.asList(new Object[][]{/* Parameters: filename, trackId*/
+ {"crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", 0},
+ {"crowd_1920x1080_25fps_6700kbps_h264.ts", 0},
+ {"crowd_1920x1080_25fps_7300kbps_mpeg2.mp4", 0},
+ {"crowd_1920x1080_25fps_4000kbps_av1.webm", 0},
+ {"crowd_1920x1080_25fps_4000kbps_h265.mkv", 0},
+ {"crowd_1920x1080_25fps_4000kbps_vp8.webm", 0},
+ {"bbb_44100hz_2ch_128kbps_aac_5mins.mp4", 0},
+ {"bbb_44100hz_2ch_128kbps_mp3_5mins.mp3", 0},
+ {"bbb_44100hz_2ch_600kbps_flac_5mins.flac", 0},
+ {"bbb_8000hz_1ch_8kbps_amrnb_5mins.3gp", 0},
+ {"bbb_16000hz_1ch_9kbps_amrwb_5mins.3gp", 0},
+ {"bbb_44100hz_2ch_80kbps_vorbis_5mins.mp4", 0},
+ {"bbb_48000hz_2ch_100kbps_opus_5mins.webm", 0}});
+ }
+
+ public ExtractorTest(String filename, int track) {
+ this.mInputFileName = filename;
+ this.mTrackId = track;
+ }
+
+ @Test
+ public void sampleExtractTest() throws IOException {
+ int status = -1;
+ File inputFile = new File(mInputFilePath + mInputFileName);
+ if (inputFile.exists()) {
+ FileInputStream fileInput = new FileInputStream(inputFile);
+ FileDescriptor fileDescriptor = fileInput.getFD();
+ Extractor extractor = new Extractor();
+ extractor.setUpExtractor(fileDescriptor);
+ status = extractor.extractSample(mTrackId);
+ extractor.deinitExtractor();
+ extractor.dumpStatistics(mInputFileName);
+ fileInput.close();
+ } else {
+ Log.e(TAG, "Cannot find " + mInputFileName + " in directory " + mInputFilePath);
+ }
+ assertThat(status, is(equalTo(0)));
+ }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/MuxerTest.java b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/MuxerTest.java
new file mode 100644
index 0000000..8c3080c
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/MuxerTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2019 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.benchmark.tests;
+
+import com.android.media.benchmark.R;
+import com.android.media.benchmark.library.Extractor;
+import com.android.media.benchmark.library.Muxer;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import android.content.Context;
+import android.media.MediaCodec;
+import android.media.MediaFormat;
+import android.media.MediaMuxer;
+import android.util.Log;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Hashtable;
+import java.util.Map;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+@RunWith(Parameterized.class)
+public class MuxerTest {
+ private static Context mContext =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
+ private static final String mInputFilePath = mContext.getString(R.string.input_file_path);
+ private static final String TAG = "MuxerTest";
+ private static final Map<String, Integer> mMapFormat = new Hashtable<String, Integer>() {
+ {
+ put("mp4", MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
+ put("webm", MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM);
+ put("3gpp", MediaMuxer.OutputFormat.MUXER_OUTPUT_3GPP);
+ put("ogg", MediaMuxer.OutputFormat.MUXER_OUTPUT_OGG);
+ }
+ };
+ private String mInputFileName;
+ private String mFormat;
+
+ @Parameterized.Parameters
+ public static Collection<Object[]> inputFiles() {
+ return Arrays.asList(new Object[][]{
+ /* Parameters: filename, format */
+ {"crowd_1920x1080_25fps_4000kbps_vp8.webm", "webm"},
+ {"crowd_1920x1080_25fps_4000kbps_vp9.webm", "webm"},
+ {"crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", "mp4"},
+ {"crowd_352x288_25fps_6000kbps_h263.3gp", "mp4"},
+ {"crowd_1920x1080_25fps_6700kbps_h264.ts", "mp4"},
+ {"crowd_1920x1080_25fps_4000kbps_h265.mkv", "mp4"},
+ {"crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", "3gpp"},
+ {"crowd_352x288_25fps_6000kbps_h263.3gp", "3gpp"},
+ {"crowd_1920x1080_25fps_6700kbps_h264.ts", "3gpp"},
+ {"crowd_1920x1080_25fps_4000kbps_h265.mkv", "3gpp"},
+ {"bbb_48000hz_2ch_100kbps_opus_5mins.webm", "ogg"},
+ {"bbb_44100hz_2ch_80kbps_vorbis_5mins.mp4", "webm"},
+ {"bbb_48000hz_2ch_100kbps_opus_5mins.webm", "webm"},
+ {"bbb_44100hz_2ch_128kbps_aac_5mins.mp4", "mp4"},
+ {"bbb_8000hz_1ch_8kbps_amrnb_5mins.3gp", "mp4"},
+ {"bbb_16000hz_1ch_9kbps_amrwb_5mins.3gp", "mp4"},
+ {"bbb_44100hz_2ch_128kbps_aac_5mins.mp4", "3gpp"},
+ {"bbb_8000hz_1ch_8kbps_amrnb_5mins.3gp", "3gpp"},
+ {"bbb_16000hz_1ch_9kbps_amrwb_5mins.3gp", "3gpp"}});
+ }
+
+ public MuxerTest(String filename, String outputFormat) {
+ this.mInputFileName = filename;
+ this.mFormat = outputFormat;
+ }
+
+ @Test
+ public void sampleMuxerTest() throws IOException {
+ int status = -1;
+ File inputFile = new File(mInputFilePath + mInputFileName);
+ if (inputFile.exists()) {
+ FileInputStream fileInput = new FileInputStream(inputFile);
+ FileDescriptor fileDescriptor = fileInput.getFD();
+ ArrayList<ByteBuffer> inputBuffer = new ArrayList<>();
+ ArrayList<MediaCodec.BufferInfo> inputBufferInfo = new ArrayList<>();
+ Extractor extractor = new Extractor();
+ int trackCount = extractor.setUpExtractor(fileDescriptor);
+ for (int currentTrack = 0; currentTrack < trackCount; currentTrack++) {
+ extractor.selectExtractorTrack(currentTrack);
+ while (true) {
+ int sampleSize = extractor.getFrameSample();
+ MediaCodec.BufferInfo bufferInfo = extractor.getBufferInfo();
+ MediaCodec.BufferInfo tempBufferInfo = new MediaCodec.BufferInfo();
+ tempBufferInfo
+ .set(bufferInfo.offset, bufferInfo.size, bufferInfo.presentationTimeUs,
+ bufferInfo.flags);
+ inputBufferInfo.add(tempBufferInfo);
+ ByteBuffer tempSampleBuffer = ByteBuffer.allocate(tempBufferInfo.size);
+ tempSampleBuffer.put(extractor.getFrameBuffer().array(), 0, bufferInfo.size);
+ inputBuffer.add(tempSampleBuffer);
+ if (sampleSize < 0) {
+ break;
+ }
+ }
+ MediaFormat format = extractor.getFormat(currentTrack);
+ int outputFormat = mMapFormat.getOrDefault(mFormat, -1);
+ if (outputFormat != -1) {
+ Muxer muxer = new Muxer();
+ int trackIndex = muxer.setUpMuxer(mContext, outputFormat, format);
+ status = muxer.mux(trackIndex, inputBuffer, inputBufferInfo);
+ if (status != 0) {
+ Log.e(TAG, "Cannot perform write operation for " + mInputFileName);
+ }
+ muxer.deInitMuxer();
+ muxer.dumpStatistics(mInputFileName, extractor.getClipDuration());
+ muxer.resetMuxer();
+ extractor.unselectExtractorTrack(currentTrack);
+ inputBufferInfo.clear();
+ inputBuffer.clear();
+ } else {
+ Log.e(TAG, "Test failed for " + mInputFileName + ". Returned invalid " +
+ "output format for given " + mFormat + " format.");
+ }
+ }
+ extractor.deinitExtractor();
+ fileInput.close();
+ } else {
+ Log.w(TAG, "Warning: Test Skipped. Cannot find " + mInputFileName + " in directory " +
+ mInputFilePath);
+ }
+ assertThat(status, is(equalTo(0)));
+ }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/CodecUtils.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/CodecUtils.java
new file mode 100644
index 0000000..08035c9
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/CodecUtils.java
@@ -0,0 +1,39 @@
+package com.android.media.benchmark.library;
+
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecList;
+import android.os.Build;
+
+import java.util.ArrayList;
+
+public class CodecUtils {
+ private CodecUtils() {}
+
+ /**
+ * Queries the MediaCodecList and returns codec names of supported codecs.
+ *
+ * @param mimeType Mime type of input
+ * @param isEncoder Specifies encoder or decoder
+ * @return ArrayList of codec names
+ */
+ public static ArrayList<String> selectCodecs(String mimeType, boolean isEncoder) {
+ MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+ MediaCodecInfo[] codecInfos = codecList.getCodecInfos();
+ ArrayList<String> supportedCodecs = new ArrayList<>();
+ for (MediaCodecInfo codecInfo : codecInfos) {
+ if (isEncoder != codecInfo.isEncoder()) {
+ continue;
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && codecInfo.isAlias()) {
+ continue;
+ }
+ String[] types = codecInfo.getSupportedTypes();
+ for (String type : types) {
+ if (type.equalsIgnoreCase(mimeType)) {
+ supportedCodecs.add(codecInfo.getName());
+ }
+ }
+ }
+ return supportedCodecs;
+ }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java
new file mode 100644
index 0000000..2cd27c2
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2019 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.benchmark.library;
+
+import android.media.MediaCodec;
+import android.media.MediaCodec.BufferInfo;
+import android.media.MediaFormat;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+public class Decoder {
+ private static final String TAG = "Decoder";
+ private static final boolean DEBUG = false;
+ private static final int kQueueDequeueTimeoutUs = 1000;
+
+ private final Object mLock = new Object();
+ private MediaCodec mCodec;
+ private ArrayList<BufferInfo> mInputBufferInfo;
+ private Stats mStats;
+
+ private boolean mSawInputEOS;
+ private boolean mSawOutputEOS;
+ private boolean mSignalledError;
+
+ private int mNumOutputFrame;
+ private int mIndex;
+
+ private ArrayList<ByteBuffer> mInputBuffer;
+ private FileOutputStream mOutputStream;
+
+ public Decoder() { mStats = new Stats(); }
+
+ /**
+ * Setup of decoder
+ *
+ * @param outputStream Will dump the output in this stream if not null.
+ */
+ public void setupDecoder(FileOutputStream outputStream) {
+ mSignalledError = false;
+ mOutputStream = outputStream;
+ }
+
+ private MediaCodec createCodec(String codecName, MediaFormat format) throws IOException {
+ String mime = format.getString(MediaFormat.KEY_MIME);
+ try {
+ MediaCodec codec;
+ if (codecName.isEmpty()) {
+ Log.i(TAG, "File mime type: " + mime);
+ if (mime != null) {
+ codec = MediaCodec.createDecoderByType(mime);
+ Log.i(TAG, "Decoder created for mime type " + mime);
+ return codec;
+ } else {
+ Log.e(TAG, "Mime type is null, please specify a mime type to create decoder");
+ return null;
+ }
+ } else {
+ codec = MediaCodec.createByCodecName(codecName);
+ Log.i(TAG, "Decoder created with codec name: " + codecName + " mime: " + mime);
+ return codec;
+ }
+ } catch (IllegalArgumentException ex) {
+ ex.printStackTrace();
+ Log.e(TAG, "Failed to create decoder for " + codecName + " mime:" + mime);
+ return null;
+ }
+ }
+
+ /**
+ * Decodes the given input buffer,
+ * provided valid list of buffer info and format are passed as inputs.
+ *
+ * @param inputBuffer Decode the provided list of ByteBuffers
+ * @param inputBufferInfo List of buffer info corresponding to provided input buffers
+ * @param asyncMode Will run on async implementation if true
+ * @param format For creating the decoder if codec name is empty and configuring it
+ * @param codecName Will create the decoder with codecName
+ * @return 0 if decode was successful , -1 for fail, -2 for decoder not created
+ * @throws IOException if the codec cannot be created.
+ */
+ public int decode(@NonNull ArrayList<ByteBuffer> inputBuffer,
+ @NonNull ArrayList<BufferInfo> inputBufferInfo, final boolean asyncMode,
+ @NonNull MediaFormat format, String codecName) throws IOException {
+ mInputBuffer = new ArrayList<>(inputBuffer.size());
+ mInputBuffer.addAll(inputBuffer);
+ mInputBufferInfo = new ArrayList<>(inputBufferInfo.size());
+ mInputBufferInfo.addAll(inputBufferInfo);
+ mSawInputEOS = false;
+ mSawOutputEOS = false;
+ mNumOutputFrame = 0;
+ mIndex = 0;
+ long sTime = mStats.getCurTime();
+ mCodec = createCodec(codecName, format);
+ if (mCodec == null) {
+ return -2;
+ }
+ if (asyncMode) {
+ mCodec.setCallback(new MediaCodec.Callback() {
+ @Override
+ public void onInputBufferAvailable(
+ @NonNull MediaCodec mediaCodec, int inputBufferId) {
+ try {
+ mStats.addInputTime();
+ onInputAvailable(inputBufferId, mediaCodec);
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.e(TAG, e.toString());
+ }
+ }
+
+ @Override
+ public void onOutputBufferAvailable(@NonNull MediaCodec mediaCodec,
+ int outputBufferId, @NonNull MediaCodec.BufferInfo bufferInfo) {
+ mStats.addOutputTime();
+ onOutputAvailable(mediaCodec, outputBufferId, bufferInfo);
+ if (mSawOutputEOS) {
+ Log.i(TAG, "Saw output EOS");
+ synchronized (mLock) { mLock.notify(); }
+ }
+ }
+
+ @Override
+ public void onOutputFormatChanged(
+ @NonNull MediaCodec mediaCodec, @NonNull MediaFormat format) {
+ Log.i(TAG, "Output format changed. Format: " + format.toString());
+ }
+
+ @Override
+ public void onError(
+ @NonNull MediaCodec mediaCodec, @NonNull MediaCodec.CodecException e) {
+ mSignalledError = true;
+ Log.e(TAG, "Codec Error: " + e.toString());
+ e.printStackTrace();
+ synchronized (mLock) { mLock.notify(); }
+ }
+ });
+ }
+ int isEncoder = 0;
+ if (DEBUG) {
+ Log.d(TAG, "Media Format : " + format.toString());
+ }
+ mCodec.configure(format, null, null, isEncoder);
+ mCodec.start();
+ Log.i(TAG, "Codec started ");
+ long eTime = mStats.getCurTime();
+ mStats.setInitTime(mStats.getTimeDiff(sTime, eTime));
+ mStats.setStartTime();
+ if (asyncMode) {
+ try {
+ synchronized (mLock) { mLock.wait(); }
+ if (mSignalledError) {
+ return -1;
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ } else {
+ while (!mSawOutputEOS && !mSignalledError) {
+ /* Queue input data */
+ if (!mSawInputEOS) {
+ int inputBufferId = mCodec.dequeueInputBuffer(kQueueDequeueTimeoutUs);
+ if (inputBufferId < 0 && inputBufferId != MediaCodec.INFO_TRY_AGAIN_LATER) {
+ Log.e(TAG,
+ "MediaCodec.dequeueInputBuffer "
+ + " returned invalid index : " + inputBufferId);
+ return -1;
+ }
+ mStats.addInputTime();
+ onInputAvailable(inputBufferId, mCodec);
+ }
+ /* Dequeue output data */
+ BufferInfo outputBufferInfo = new BufferInfo();
+ int outputBufferId =
+ mCodec.dequeueOutputBuffer(outputBufferInfo, kQueueDequeueTimeoutUs);
+ if (outputBufferId < 0) {
+ if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+ MediaFormat outFormat = mCodec.getOutputFormat();
+ Log.i(TAG, "Output format changed. Format: " + outFormat.toString());
+ } else if (outputBufferId == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
+ Log.i(TAG, "Ignoring deprecated flag: INFO_OUTPUT_BUFFERS_CHANGED");
+ } else if (outputBufferId != MediaCodec.INFO_TRY_AGAIN_LATER) {
+ Log.e(TAG,
+ "MediaCodec.dequeueOutputBuffer"
+ + " returned invalid index " + outputBufferId);
+ return -1;
+ }
+ } else {
+ mStats.addOutputTime();
+ if (DEBUG) {
+ Log.d(TAG, "Dequeue O/P buffer with BufferID " + outputBufferId);
+ }
+ onOutputAvailable(mCodec, outputBufferId, outputBufferInfo);
+ }
+ if (outputBufferInfo.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM) {
+ Log.i(TAG, "Saw output EOS");
+ }
+ }
+ }
+ mInputBuffer.clear();
+ mInputBufferInfo.clear();
+ return 0;
+ }
+
+ /**
+ * Stops the codec and releases codec resources.
+ */
+ public void deInitCodec() {
+ long sTime = mStats.getCurTime();
+ if (mCodec != null) {
+ mCodec.stop();
+ mCodec.release();
+ mCodec = null;
+ }
+ long eTime = mStats.getCurTime();
+ mStats.setDeInitTime(mStats.getTimeDiff(sTime, eTime));
+ }
+
+ /**
+ * Prints out the statistics in the information log
+ *
+ * @param inputReference The operation being performed, in this case decode
+ * @param durationUs Duration of the clip in microseconds
+ */
+ public void dumpStatistics(String inputReference, long durationUs) {
+ String operation = "decode";
+ mStats.dumpStatistics(operation, inputReference, durationUs);
+ }
+
+ /**
+ * Resets the stats
+ */
+ public void resetDecoder() { mStats.reset(); }
+
+ private void onInputAvailable(int inputBufferId, MediaCodec mediaCodec) {
+ if ((inputBufferId >= 0) && !mSawInputEOS) {
+ ByteBuffer inputCodecBuffer = mediaCodec.getInputBuffer(inputBufferId);
+ BufferInfo bufInfo = mInputBufferInfo.get(mIndex);
+ inputCodecBuffer.put(mInputBuffer.get(mIndex).array());
+ mIndex++;
+ if (bufInfo.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM) {
+ mSawInputEOS = true;
+ Log.i(TAG, "Saw input EOS");
+ }
+ mStats.addFrameSize(bufInfo.size);
+ mediaCodec.queueInputBuffer(inputBufferId, bufInfo.offset, bufInfo.size,
+ bufInfo.presentationTimeUs, bufInfo.flags);
+ if (DEBUG) {
+ Log.d(TAG,
+ "Codec Input: "
+ + "flag = " + bufInfo.flags + " timestamp = "
+ + bufInfo.presentationTimeUs + " size = " + bufInfo.size);
+ }
+ }
+ }
+
+ private void onOutputAvailable(
+ MediaCodec mediaCodec, int outputBufferId, BufferInfo outputBufferInfo) {
+ if (mSawOutputEOS || outputBufferId < 0) {
+ return;
+ }
+ mNumOutputFrame++;
+ if (DEBUG) {
+ Log.d(TAG,
+ "In OutputBufferAvailable ,"
+ + " output frame number = " + mNumOutputFrame);
+ }
+ if (mOutputStream != null) {
+ try {
+ ByteBuffer outputBuffer = mediaCodec.getOutputBuffer(outputBufferId);
+ byte[] bytesOutput = new byte[outputBuffer.remaining()];
+ outputBuffer.get(bytesOutput);
+ mOutputStream.write(bytesOutput);
+ } catch (IOException e) {
+ e.printStackTrace();
+ Log.d(TAG, "Error Dumping File: Exception " + e.toString());
+ }
+ }
+ mediaCodec.releaseOutputBuffer(outputBufferId, false);
+ mSawOutputEOS = (outputBufferInfo.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM);
+ }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Encoder.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Encoder.java
new file mode 100644
index 0000000..03db294
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Encoder.java
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2019 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.benchmark.library;
+
+import android.media.MediaCodec;
+import android.media.MediaCodec.CodecException;
+import android.media.MediaFormat;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public class Encoder {
+ private static final int ENCODE_DEFAULT_MAX_INPUT_SIZE = 3840;
+ private static final String TAG = "Encoder";
+ private static final boolean DEBUG = false;
+ private static final int kQueueDequeueTimeoutUs = 1000;
+
+ private final Object mLock = new Object();
+ private MediaCodec mCodec;
+ private String mMime;
+ private Stats mStats;
+
+ private int mOffset;
+ private int mFrameSize;
+ private int mNumInputFrame;
+ private int mNumFrames;
+ private int mFrameRate;
+ private int mSampleRate;
+ private long mInputBufferSize;
+
+ private boolean mSawInputEOS;
+ private boolean mSawOutputEOS;
+ private boolean mSignalledError;
+
+ private FileInputStream mInputStream;
+ private FileOutputStream mOutputStream;
+
+ public Encoder() {
+ mStats = new Stats();
+ mNumInputFrame = 0;
+ mSawInputEOS = false;
+ mSawOutputEOS = false;
+ mSignalledError = false;
+ }
+
+ /**
+ * Setup of encoder
+ *
+ * @param encoderOutputStream Will dump the encoder output in this stream if not null.
+ * @param fileInputStream Will read the decoded output from this stream
+ */
+ public void setupEncoder(FileOutputStream encoderOutputStream,
+ FileInputStream fileInputStream) {
+ this.mInputStream = fileInputStream;
+ this.mOutputStream = encoderOutputStream;
+ }
+
+ private MediaCodec createCodec(String codecName, String mime) throws IOException {
+ try {
+ MediaCodec codec;
+ if (codecName.isEmpty()) {
+ Log.i(TAG, "Mime type: " + mime);
+ if (mime != null) {
+ codec = MediaCodec.createEncoderByType(mime);
+ Log.i(TAG, "Encoder created for mime type " + mime);
+ return codec;
+ } else {
+ Log.e(TAG, "Mime type is null, please specify a mime type to create encoder");
+ return null;
+ }
+ } else {
+ codec = MediaCodec.createByCodecName(codecName);
+ Log.i(TAG, "Encoder created with codec name: " + codecName + " and mime: " + mime);
+ return codec;
+ }
+ } catch (IllegalArgumentException ex) {
+ ex.printStackTrace();
+ Log.e(TAG, "Failed to create encoder for " + codecName + " mime: " + mime);
+ return null;
+ }
+ }
+
+ /**
+ * Encodes the given raw input file and measures the performance of encode operation,
+ * provided a valid list of parameters are passed as inputs.
+ *
+ * @param codecName Will create the encoder with codecName
+ * @param mime For creating encode format
+ * @param encodeFormat Format of the output data
+ * @param frameSize Size of the frame
+ * @param asyncMode Will run on async implementation if true
+ * @return 0 if encode was successful , -1 for fail, -2 for encoder not created
+ * @throws IOException If the codec cannot be created.
+ */
+ public int encode(String codecName, MediaFormat encodeFormat, String mime, int frameRate,
+ int sampleRate, int frameSize, boolean asyncMode) throws IOException {
+ mInputBufferSize = mInputStream.getChannel().size();
+ mMime = mime;
+ mOffset = 0;
+ mFrameRate = frameRate;
+ mSampleRate = sampleRate;
+ long sTime = mStats.getCurTime();
+ mCodec = createCodec(codecName, mime);
+ if (mCodec == null) {
+ return -2;
+ }
+ /*Configure Codec*/
+ try {
+ mCodec.configure(encodeFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
+ } catch (IllegalArgumentException | IllegalStateException | MediaCodec.CryptoException e) {
+ Log.e(TAG, "Failed to configure " + mCodec.getName() + " encoder.");
+ e.printStackTrace();
+ return -2;
+ }
+ if (mMime.startsWith("video/")) {
+ mFrameSize = frameSize;
+ } else {
+ int maxInputSize = ENCODE_DEFAULT_MAX_INPUT_SIZE;
+ MediaFormat format = mCodec.getInputFormat();
+ if (format.containsKey(MediaFormat.KEY_MAX_INPUT_SIZE)) {
+ maxInputSize = format.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE);
+ }
+ mFrameSize = frameSize;
+ if (mFrameSize > maxInputSize && maxInputSize > 0) {
+ mFrameSize = maxInputSize;
+ }
+ }
+ mNumFrames = (int) ((mInputBufferSize + mFrameSize - 1) / mFrameSize);
+ if (asyncMode) {
+ mCodec.setCallback(new MediaCodec.Callback() {
+ @Override
+ public void onInputBufferAvailable(@NonNull MediaCodec mediaCodec,
+ int inputBufferId) {
+ try {
+ mStats.addInputTime();
+ onInputAvailable(mediaCodec, inputBufferId);
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.e(TAG, e.toString());
+ }
+ }
+
+ @Override
+ public void onOutputBufferAvailable(@NonNull MediaCodec mediaCodec,
+ int outputBufferId,
+ @NonNull MediaCodec.BufferInfo bufferInfo) {
+ mStats.addOutputTime();
+ onOutputAvailable(mediaCodec, outputBufferId, bufferInfo);
+ if (mSawOutputEOS) {
+ Log.i(TAG, "Saw output EOS");
+ synchronized (mLock) { mLock.notify(); }
+ }
+ }
+
+ @Override
+ public void onError(@NonNull MediaCodec mediaCodec, @NonNull CodecException e) {
+ mediaCodec.stop();
+ mediaCodec.release();
+ Log.e(TAG, "CodecError: " + e.toString());
+ e.printStackTrace();
+ }
+
+ @Override
+ public void onOutputFormatChanged(@NonNull MediaCodec mediaCodec,
+ @NonNull MediaFormat format) {
+ Log.i(TAG, "Output format changed. Format: " + format.toString());
+ }
+ });
+ }
+ mCodec.start();
+ long eTime = mStats.getCurTime();
+ mStats.setInitTime(mStats.getTimeDiff(sTime, eTime));
+ mStats.setStartTime();
+ if (asyncMode) {
+ try {
+ synchronized (mLock) { mLock.wait(); }
+ if (mSignalledError) {
+ return -1;
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ } else {
+ while (!mSawOutputEOS && !mSignalledError) {
+ /* Queue input data */
+ if (!mSawInputEOS) {
+ int inputBufferId = mCodec.dequeueInputBuffer(kQueueDequeueTimeoutUs);
+ if (inputBufferId < 0 && inputBufferId != MediaCodec.INFO_TRY_AGAIN_LATER) {
+ Log.e(TAG, "MediaCodec.dequeueInputBuffer " + "returned invalid index : " +
+ inputBufferId);
+ return -1;
+ }
+ mStats.addInputTime();
+ onInputAvailable(mCodec, inputBufferId);
+ }
+ /* Dequeue output data */
+ MediaCodec.BufferInfo outputBufferInfo = new MediaCodec.BufferInfo();
+ int outputBufferId =
+ mCodec.dequeueOutputBuffer(outputBufferInfo, kQueueDequeueTimeoutUs);
+ if (outputBufferId < 0) {
+ if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+ MediaFormat outFormat = mCodec.getOutputFormat();
+ Log.i(TAG, "Output format changed. Format: " + outFormat.toString());
+ } else if (outputBufferId != MediaCodec.INFO_TRY_AGAIN_LATER) {
+ Log.e(TAG, "MediaCodec.dequeueOutputBuffer" + " returned invalid index " +
+ outputBufferId);
+ return -1;
+ }
+ } else {
+ mStats.addOutputTime();
+ if (DEBUG) {
+ Log.d(TAG, "Dequeue O/P buffer with BufferID " + outputBufferId);
+ }
+ onOutputAvailable(mCodec, outputBufferId, outputBufferInfo);
+ }
+ }
+ }
+ return 0;
+ }
+
+ private void onOutputAvailable(MediaCodec mediaCodec, int outputBufferId,
+ MediaCodec.BufferInfo outputBufferInfo) {
+ if (mSawOutputEOS || outputBufferId < 0) {
+ if (mSawOutputEOS) {
+ Log.i(TAG, "Saw output EOS");
+ }
+ return;
+ }
+ ByteBuffer outputBuffer = mediaCodec.getOutputBuffer(outputBufferId);
+ if (mOutputStream != null) {
+ try {
+
+ byte[] bytesOutput = new byte[outputBuffer.remaining()];
+ outputBuffer.get(bytesOutput);
+ mOutputStream.write(bytesOutput);
+ } catch (IOException e) {
+ e.printStackTrace();
+ Log.d(TAG, "Error Dumping File: Exception " + e.toString());
+ return;
+ }
+ }
+ mStats.addFrameSize(outputBuffer.remaining());
+ mediaCodec.releaseOutputBuffer(outputBufferId, false);
+ mSawOutputEOS = (outputBufferInfo.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM);
+ }
+
+ private void onInputAvailable(MediaCodec mediaCodec, int inputBufferId) throws IOException {
+ if (mSawOutputEOS || inputBufferId < 0) {
+ if (mSawOutputEOS) {
+ Log.i(TAG, "Saw input EOS");
+ }
+ return;
+ }
+ if (mInputBufferSize < mOffset) {
+ Log.e(TAG, "Out of bound access of input buffer");
+ mSignalledError = true;
+ return;
+ }
+ ByteBuffer inputBuffer = mCodec.getInputBuffer(inputBufferId);
+ if (inputBuffer == null) {
+ mSignalledError = true;
+ return;
+ }
+ int bufSize = inputBuffer.capacity();
+ int bytesRead = mFrameSize;
+ if (mInputBufferSize - mOffset < mFrameSize) {
+ bytesRead = (int) (mInputBufferSize - mOffset);
+ }
+ if (bufSize < bytesRead) {
+ mSignalledError = true;
+ return;
+ }
+ byte[] inputArray = new byte[bytesRead];
+ mInputStream.read(inputArray, 0, bytesRead);
+ inputBuffer.put(inputArray);
+ int flag = 0;
+ if (mNumInputFrame >= mNumFrames - 1 || bytesRead == 0) {
+ Log.i(TAG, "Sending EOS on input last frame");
+ mSawInputEOS = true;
+ flag = MediaCodec.BUFFER_FLAG_END_OF_STREAM;
+ }
+ int presentationTimeUs;
+ if (mMime.startsWith("video/")) {
+ presentationTimeUs = mNumInputFrame * (1000000 / mFrameRate);
+ } else {
+ presentationTimeUs = mNumInputFrame * mFrameSize * 1000000 / mSampleRate;
+ }
+ mediaCodec.queueInputBuffer(inputBufferId, 0, bytesRead, presentationTimeUs, flag);
+ mNumInputFrame++;
+ mOffset += bytesRead;
+ }
+
+ /**
+ * Stops the codec and releases codec resources.
+ */
+ public void deInitEncoder() {
+ long sTime = mStats.getCurTime();
+ if (mCodec != null) {
+ mCodec.stop();
+ mCodec.release();
+ mCodec = null;
+ }
+ long eTime = mStats.getCurTime();
+ mStats.setDeInitTime(mStats.getTimeDiff(sTime, eTime));
+ }
+
+ /**
+ * Prints out the statistics in the information log
+ *
+ * @param inputReference The operation being performed, in this case encode
+ * @param durationUs Duration of the clip in microseconds
+ */
+ public void dumpStatistics(String inputReference, long durationUs) {
+ String operation = "encode";
+ mStats.dumpStatistics(operation, inputReference, durationUs);
+ }
+
+ /**
+ * Resets the stats
+ */
+ public void resetEncoder() {
+ mOffset = 0;
+ mInputBufferSize = 0;
+ mNumInputFrame = 0;
+ mSawInputEOS = false;
+ mSawOutputEOS = false;
+ mSignalledError = false;
+ mStats.reset();
+ }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Extractor.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Extractor.java
new file mode 100644
index 0000000..459e2a9
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Extractor.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2019 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.benchmark.library;
+
+import android.media.MediaCodec;
+import android.media.MediaExtractor;
+import android.media.MediaFormat;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public class Extractor {
+ private static final String TAG = "Extractor";
+ private static final int kMaxBufSize = 1024 * 1024 * 16;
+ private MediaExtractor mExtractor;
+ private ByteBuffer mFrameBuffer;
+ private MediaCodec.BufferInfo mBufferInfo;
+ private Stats mStats;
+ private long mDurationUs;
+
+ public Extractor() {
+ mFrameBuffer = ByteBuffer.allocate(kMaxBufSize);
+ mBufferInfo = new MediaCodec.BufferInfo();
+ mStats = new Stats();
+ }
+
+ /**
+ * Creates a Media Extractor and sets data source(FileDescriptor)to use
+ *
+ * @param fileDescriptor FileDescriptor for the file which is to be extracted
+ * @return TrackCount of the sample
+ * @throws IOException If FileDescriptor is null
+ */
+ public int setUpExtractor(FileDescriptor fileDescriptor) throws IOException {
+ long sTime = mStats.getCurTime();
+ mExtractor = new MediaExtractor();
+ mExtractor.setDataSource(fileDescriptor);
+ long eTime = mStats.getCurTime();
+ long timeTaken = mStats.getTimeDiff(sTime, eTime);
+ mStats.setInitTime(timeTaken);
+ return mExtractor.getTrackCount();
+ }
+
+ /**
+ * Returns the track format of the specified index
+ *
+ * @param trackID Index of the track
+ * @return Format of the track
+ */
+ public MediaFormat getFormat(int trackID) { return mExtractor.getTrackFormat(trackID); }
+
+ /**
+ * Returns the extracted buffer for the input clip
+ */
+ public ByteBuffer getFrameBuffer() { return this.mFrameBuffer; }
+
+ /**
+ * Returns the information of buffer related to sample
+ */
+ public MediaCodec.BufferInfo getBufferInfo() { return this.mBufferInfo; }
+
+ /**
+ * Returns the duration of the sample
+ */
+ public long getClipDuration() { return this.mDurationUs; }
+
+ /**
+ * Retrieve the current sample and store it in the byte buffer
+ * Also, sets the information related to extracted sample and store it in buffer info
+ *
+ * @return Sample size of the extracted sample
+ */
+ public int getFrameSample() {
+ int sampleSize = mExtractor.readSampleData(mFrameBuffer, 0);
+ if (sampleSize < 0) {
+ mBufferInfo.flags = MediaCodec.BUFFER_FLAG_END_OF_STREAM;
+ mBufferInfo.size = 0;
+ } else {
+ mBufferInfo.size = sampleSize;
+ mBufferInfo.offset = 0;
+ mBufferInfo.flags = mExtractor.getSampleFlags();
+ mBufferInfo.presentationTimeUs = mExtractor.getSampleTime();
+ mExtractor.advance();
+ }
+ return sampleSize;
+ }
+
+ /**
+ * Setup the track format and get the duration of the sample
+ * Track is selected here for extraction
+ *
+ * @param trackId Track index to be selected
+ * @return 0 for valid track, otherwise -1
+ */
+ public int selectExtractorTrack(int trackId) {
+ MediaFormat trackFormat = mExtractor.getTrackFormat(trackId);
+ mDurationUs = trackFormat.getLong(MediaFormat.KEY_DURATION);
+ if (mDurationUs < 0) {
+ Log.e(TAG, "Invalid Clip");
+ return -1;
+ }
+ mExtractor.selectTrack(trackId);
+ return 0;
+ }
+
+ /**
+ * Unselect the track
+ *
+ * @param trackId Track Index to be unselected
+ */
+ public void unselectExtractorTrack(int trackId) { mExtractor.unselectTrack(trackId); }
+
+ /**
+ * Free up the resources
+ */
+ public void deinitExtractor() {
+ long sTime = mStats.getCurTime();
+ mExtractor.release();
+ long eTime = mStats.getCurTime();
+ long timeTaken = mStats.getTimeDiff(sTime, eTime);
+ mStats.setDeInitTime(timeTaken);
+ }
+
+ /**
+ * Performs extract operation
+ *
+ * @param currentTrack Track index to be extracted
+ * @return Status as 0 if extraction is successful, -1 otherwise
+ */
+ public int extractSample(int currentTrack) {
+ int status;
+ status = selectExtractorTrack(currentTrack);
+ if (status == -1) {
+ Log.e(TAG, "Failed to select track");
+ return -1;
+ }
+ mStats.setStartTime();
+ while (true) {
+ int readSampleSize = getFrameSample();
+ if (readSampleSize <= 0) {
+ break;
+ }
+ mStats.addOutputTime();
+ mStats.addFrameSize(readSampleSize);
+ }
+ unselectExtractorTrack(currentTrack);
+ return 0;
+ }
+
+ /**
+ * Write the benchmark logs for the given input file
+ *
+ * @param inputReference Name of the input file
+ */
+ public void dumpStatistics(String inputReference) {
+ String operation = "extract";
+ mStats.dumpStatistics(operation, inputReference, mDurationUs);
+ }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Muxer.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Muxer.java
new file mode 100644
index 0000000..49eaa1c
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Muxer.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2019 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.benchmark.library;
+
+import android.content.Context;
+import android.media.MediaCodec;
+import android.media.MediaFormat;
+import android.media.MediaMuxer;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+public class Muxer {
+ private Stats mStats;
+ private MediaMuxer mMuxer;
+
+ /**
+ * Creates a Media Muxer for the specified path
+ *
+ * @param context App context to specify the output file path
+ * @param outputFormat Format of the output media file
+ * @param trackFormat Format of the current track
+ * @return Returns the track index of the newly added track, -1 otherwise
+ */
+ public int setUpMuxer(Context context, int outputFormat, MediaFormat trackFormat) {
+ try {
+ mStats = new Stats();
+ long sTime = mStats.getCurTime();
+ mMuxer = new MediaMuxer(context.getFilesDir().getPath() + "/mux.out.", outputFormat);
+ int trackIndex = mMuxer.addTrack(trackFormat);
+ mMuxer.start();
+ long eTime = mStats.getCurTime();
+ long timeTaken = mStats.getTimeDiff(sTime, eTime);
+ mStats.setInitTime(timeTaken);
+ return trackIndex;
+ } catch (IllegalArgumentException | IOException e) {
+ e.printStackTrace();
+ return -1;
+ }
+ }
+
+ /**
+ * Performs the Mux operation
+ *
+ * @param trackIndex Track index of the sample
+ * @param inputExtractedBuffer Buffer containing encoded samples
+ * @param inputBufferInfo Buffer information related to these samples
+ * @return Returns Status as 0 if write operation is successful, -1 otherwise
+ */
+ public int mux(int trackIndex, ArrayList<ByteBuffer> inputExtractedBuffer,
+ ArrayList<MediaCodec.BufferInfo> inputBufferInfo) {
+ mStats.setStartTime();
+ for (int sampleCount = 0; sampleCount < inputExtractedBuffer.size(); sampleCount++) {
+ try {
+ mMuxer.writeSampleData(trackIndex, inputExtractedBuffer.get(sampleCount),
+ inputBufferInfo.get(sampleCount));
+ mStats.addOutputTime();
+ mStats.addFrameSize(inputBufferInfo.get(sampleCount).size);
+ } catch (IllegalArgumentException | IllegalStateException e) {
+ e.printStackTrace();
+ return -1;
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Stops the muxer and free up the resources
+ */
+ public void deInitMuxer() {
+ long sTime = mStats.getCurTime();
+ mMuxer.stop();
+ mMuxer.release();
+ long eTime = mStats.getCurTime();
+ long timeTaken = mStats.getTimeDiff(sTime, eTime);
+ mStats.setDeInitTime(timeTaken);
+ }
+
+ /**
+ * Resets the stats
+ */
+ public void resetMuxer() {
+ mStats.reset();
+ }
+
+ /**
+ * Write the benchmark logs for the given input file
+ *
+ * @param inputReference Name of the input file
+ * @param clipDuration Duration of the given inputReference file
+ */
+ public void dumpStatistics(String inputReference, long clipDuration) {
+ String operation = "mux";
+ mStats.dumpStatistics(operation, inputReference, clipDuration);
+ }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Stats.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Stats.java
new file mode 100644
index 0000000..18ab5be
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Stats.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2019 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.benchmark.library;
+
+import android.util.Log;
+
+import java.util.ArrayList;
+
+/**
+ * Measures Performance.
+ */
+public class Stats {
+ private static final String TAG = "Stats";
+ private long mInitTimeNs;
+ private long mDeInitTimeNs;
+ private long mStartTimeNs;
+ private ArrayList<Integer> mFrameSizes;
+ private ArrayList<Long> mInputTimer;
+ private ArrayList<Long> mOutputTimer;
+
+ public Stats() {
+ mFrameSizes = new ArrayList<>();
+ mInputTimer = new ArrayList<>();
+ mOutputTimer = new ArrayList<>();
+ mInitTimeNs = 0;
+ mDeInitTimeNs = 0;
+ }
+
+ public long getCurTime() { return System.nanoTime(); }
+
+ public void setInitTime(long initTime) { mInitTimeNs = initTime; }
+
+ public void setDeInitTime(long deInitTime) { mDeInitTimeNs = deInitTime; }
+
+ public void setStartTime() { mStartTimeNs = System.nanoTime(); }
+
+ public void addFrameSize(int size) { mFrameSizes.add(size); }
+
+ public void addInputTime() { mInputTimer.add(System.nanoTime()); }
+
+ public void addOutputTime() { mOutputTimer.add(System.nanoTime()); }
+
+ public void reset() {
+ if (mFrameSizes.size() != 0) {
+ mFrameSizes.clear();
+ }
+
+ if (mInputTimer.size() != 0) {
+ mInputTimer.clear();
+ }
+
+ if (mOutputTimer.size() != 0) {
+ mOutputTimer.clear();
+ }
+ }
+
+ public long getInitTime() { return mInitTimeNs; }
+
+ public long getDeInitTime() { return mDeInitTimeNs; }
+
+ public long getTimeDiff(long sTime, long eTime) { return (eTime - sTime); }
+
+ private long getTotalTime() {
+ if (mOutputTimer.size() == 0) {
+ return -1;
+ }
+ long lastTime = mOutputTimer.get(mOutputTimer.size() - 1);
+ return lastTime - mStartTimeNs;
+ }
+
+ private long getTotalSize() {
+ long totalSize = 0;
+ for (long size : mFrameSizes) {
+ totalSize += size;
+ }
+ return totalSize;
+ }
+
+ /**
+ * Dumps the stats of the operation for a given input media.
+ * <p>
+ * \param operation describes the operation performed on the input media
+ * (i.e. extract/mux/decode/encode)
+ * \param inputReference input media
+ * \param durationUs is a duration of the input media in microseconds.
+ */
+ public void dumpStatistics(String operation, String inputReference, long durationUs) {
+ if (mOutputTimer.size() == 0) {
+ Log.e(TAG, "No output produced");
+ return;
+ }
+ long totalTimeTakenNs = getTotalTime();
+ long timeTakenPerSec = (totalTimeTakenNs * 1000000) / durationUs;
+ long timeToFirstFrameNs = mOutputTimer.get(0) - mStartTimeNs;
+ long size = getTotalSize();
+ // get min and max output intervals.
+ long intervalNs;
+ long minTimeTakenNs = Long.MAX_VALUE;
+ long maxTimeTakenNs = 0;
+ long prevIntervalNs = mStartTimeNs;
+ for (int idx = 0; idx < mOutputTimer.size() - 1; idx++) {
+ intervalNs = mOutputTimer.get(idx) - prevIntervalNs;
+ prevIntervalNs = mOutputTimer.get(idx);
+ if (minTimeTakenNs > intervalNs) {
+ minTimeTakenNs = intervalNs;
+ } else if (maxTimeTakenNs < intervalNs) {
+ maxTimeTakenNs = intervalNs;
+ }
+ }
+ // Print the Stats
+ Log.i(TAG, "Input Reference : " + inputReference);
+ Log.i(TAG, "Setup Time in nano sec : " + mInitTimeNs);
+ Log.i(TAG, "Average Time in nano sec : " + totalTimeTakenNs / mOutputTimer.size());
+ Log.i(TAG, "Time to first frame in nano sec : " + timeToFirstFrameNs);
+ Log.i(TAG, "Time taken (in nano sec) to " + operation + " 1 sec of content : " +
+ timeTakenPerSec);
+ Log.i(TAG, "Total bytes " + operation + "ed : " + size);
+ Log.i(TAG, "Number of bytes " + operation + "ed per second : " +
+ (size * 1000000000) / totalTimeTakenNs);
+ Log.i(TAG, "Minimum Time in nano sec : " + minTimeTakenNs);
+ Log.i(TAG, "Maximum Time in nano sec : " + maxTimeTakenNs);
+ Log.i(TAG, "Destroy Time in nano sec : " + mDeInitTimeNs);
+ }
+}
\ No newline at end of file
diff --git a/media/tests/benchmark/README.md b/media/tests/benchmark/README.md
index 8db3fd3..487ddb8 100644
--- a/media/tests/benchmark/README.md
+++ b/media/tests/benchmark/README.md
@@ -1,10 +1,19 @@
# Benchmark tests
+Benchmark app analyses the time taken by MediaCodec, MediaExtractor and MediaMuxer for given set of inputs. It is used to benchmark these modules on android devices.
+Benchmark results are emitted to logcat.
+
+This page describes steps to run the NDK and SDK layer test.
+
Run the following steps to build the test suite:
```
mmm frameworks/av/media/tests/benchmark/
```
+# NDK
+
+To run the test suite for measuring performance of the native layer, follow the following steps:
+
The binaries will be created in the following path : ${OUT}/data/nativetest64/
adb push $(OUT)/data/nativetest64/* /data/local/tmp/
@@ -13,20 +22,25 @@
To run the binary, follow the commands mentioned below under each module.
-The resource files for the tests are taken from [here](https://drive.google.com/open?id=1ghMr17BBJ7n0pqbm7oREiTN_MNemJUqy)
+The resource file for the tests is taken from [here](https://drive.google.com/open?id=1ghMr17BBJ7n0pqbm7oREiTN_MNemJUqy)
+
+Download the MediaBenchmark.zip file, unzip and push it to /data/local/tmp/ on the device.
+
+```
+unzip MediaBenchmark.zip
+adb push MediaBenchmark /data/local/tmp
+```
## Extractor
The test extracts elementary stream and benchmarks the extractors available in NDK.
-Push the resource files to /sdcard/res on the device.
-
-You can use a different location, but you have to modify the rest of the instructions to replace /sdcard/res with wherever you chose to put the files.
+The resource files are assumed to be at /data/local/tmp/MediaBenchmark/res/. You can use a different location, but you have to modify the rest of the instructions to replace /data/local/tmp/MediaBenchmark/res/ with wherever you chose to put the files.
The path to these files on the device is required to be given for the test.
```
-adb shell /data/local/tmp/extractorTest -P /sdcard/res/
+adb shell /data/local/tmp/extractorTest -P /data/local/tmp/MediaBenchmark/res/
```
## Decoder
@@ -36,7 +50,7 @@
Setup steps are same as extractor.
```
-adb shell /data/local/tmp/decoderTest -P /sdcard/res/
+adb shell /data/local/tmp/decoderTest -P /data/local/tmp/MediaBenchmark/res/
```
## Muxer
@@ -46,7 +60,7 @@
Setup steps are same as extractor.
```
-adb shell /data/local/tmp/muxerTest -P /sdcard/res/
+adb shell /data/local/tmp/muxerTest -P /data/local/tmp/MediaBenchmark/res/
```
## Encoder
@@ -56,5 +70,53 @@
Setup steps are same as extractor.
```
-adb shell /data/local/tmp/encoderTest -P /sdcard/res/
+adb shell /data/local/tmp/encoderTest -P /data/local/tmp/MediaBenchmark/res/
+```
+
+# SDK
+
+To run the test suite for measuring performance of the SDK APIs, follow the following steps:
+
+The apk will be created at the following path:
+${OUT}/testcases/MediaBenchmarkApp/arm64/
+
+To get the resorce files for the test follow instructions given in [NDK](#NDK)
+
+For installing the apk, run the command:
+```
+adb install -f -r ${OUT}/testcases/MediaBenchmarkApp/arm64/MediaBenchmarkApp.apk
+```
+
+For running all the tests, run the command:
+```
+adb shell am instrument -w -r -e package com.android.media.benchmark.tests com.android.media.benchmark/androidx.test.runner.AndroidJUnitRunner
+```
+
+## Extractor
+
+The test extracts elementary stream and benchmarks the extractors available in SDK.
+```
+adb shell am instrument -w -r -e class 'com.android.media.benchmark.tests.ExtractorTest' com.android.media.benchmark/androidx.test.runner.AndroidJUnitRunner
+```
+
+## Decoder
+
+The test decodes input stream and benchmarks the decoders available in SDK.
+```
+adb shell am instrument -w -r -e class 'com.android.media.benchmark.tests.DecoderTest' com.android.media.benchmark/androidx.test.runner.AndroidJUnitRunner
+```
+
+## Muxer
+
+The test muxes elementary stream and benchmarks different writers available in SDK.
+```
+adb shell am instrument -w -r -e class 'com.android.media.benchmark.tests.MuxerTest' com.android.media.benchmark/androidx.test.runner.AndroidJUnitRunner
+```
+
+## Encoder
+
+The test encodes input stream and benchmarks the encoders available in SDK.
+```
+adb shell am instrument -w -r -e class 'com.android.media.benchmark.tests.EncoderTest' com.android.media.benchmark/androidx.test.runner.AndroidJUnitRunner
+
```
diff --git a/media/tests/benchmark/src/native/common/Android.bp b/media/tests/benchmark/src/native/common/Android.bp
index 527f588..1da0102 100644
--- a/media/tests/benchmark/src/native/common/Android.bp
+++ b/media/tests/benchmark/src/native/common/Android.bp
@@ -15,10 +15,10 @@
*/
cc_library_static {
- name: "libbenchmark_common",
+ name: "libmediabenchmark_common",
defaults: [
- "libbenchmark-defaults",
- "libbenchmark_soft_sanitize_all-defaults",
+ "libmediabenchmark-defaults",
+ "libmediabenchmark_soft_sanitize_all-defaults",
],
srcs: [
@@ -32,23 +32,19 @@
}
cc_defaults {
- name: "libbenchmark_common-defaults",
+ name: "libmediabenchmark_common-defaults",
defaults: [
- "libbenchmark-defaults",
+ "libmediabenchmark-defaults",
],
static_libs: [
- "libbenchmark_common",
+ "libmediabenchmark_common",
],
}
cc_defaults {
- name: "libbenchmark-defaults",
-
- header_libs: [
- "media_ndk_headers",
- ],
+ name: "libmediabenchmark-defaults",
shared_libs: [
"libmediandk",
@@ -65,7 +61,7 @@
// public dependency for native implementation
// to be used by code under media/benchmark/* only
cc_defaults {
- name: "libbenchmark_soft_sanitize_all-defaults",
+ name: "libmediabenchmark_soft_sanitize_all-defaults",
sanitize: {
misc_undefined: [
@@ -73,6 +69,5 @@
"signed-integer-overflow",
],
cfi: true,
- address: true,
}
}
diff --git a/media/tests/benchmark/src/native/decoder/Android.bp b/media/tests/benchmark/src/native/decoder/Android.bp
index f2d3db5..b6286d4 100644
--- a/media/tests/benchmark/src/native/decoder/Android.bp
+++ b/media/tests/benchmark/src/native/decoder/Android.bp
@@ -15,15 +15,15 @@
*/
cc_library_static {
- name: "libbenchmark_decoder",
+ name: "libmediabenchmark_decoder",
defaults: [
- "libbenchmark_common-defaults",
- "libbenchmark_soft_sanitize_all-defaults",
+ "libmediabenchmark_common-defaults",
+ "libmediabenchmark_soft_sanitize_all-defaults",
],
srcs: ["Decoder.cpp"],
- static_libs: ["libbenchmark_extractor"],
+ static_libs: ["libmediabenchmark_extractor"],
export_include_dirs: ["."],
diff --git a/media/tests/benchmark/src/native/encoder/Android.bp b/media/tests/benchmark/src/native/encoder/Android.bp
index c14c319..239f378 100644
--- a/media/tests/benchmark/src/native/encoder/Android.bp
+++ b/media/tests/benchmark/src/native/encoder/Android.bp
@@ -15,16 +15,16 @@
*/
cc_library_static {
- name: "libbenchmark_encoder",
+ name: "libmediabenchmark_encoder",
defaults: [
- "libbenchmark_common-defaults",
- "libbenchmark_soft_sanitize_all-defaults",
+ "libmediabenchmark_common-defaults",
+ "libmediabenchmark_soft_sanitize_all-defaults",
],
srcs: ["Encoder.cpp"],
- static_libs: ["libbenchmark_extractor",
- "libbenchmark_decoder",
+ static_libs: ["libmediabenchmark_extractor",
+ "libmediabenchmark_decoder",
],
export_include_dirs: ["."],
diff --git a/media/tests/benchmark/src/native/extractor/Android.bp b/media/tests/benchmark/src/native/extractor/Android.bp
index 2fbe4e8..dfd0d49 100644
--- a/media/tests/benchmark/src/native/extractor/Android.bp
+++ b/media/tests/benchmark/src/native/extractor/Android.bp
@@ -15,10 +15,10 @@
*/
cc_library_static {
- name: "libbenchmark_extractor",
+ name: "libmediabenchmark_extractor",
defaults: [
- "libbenchmark_common-defaults",
- "libbenchmark_soft_sanitize_all-defaults",
+ "libmediabenchmark_common-defaults",
+ "libmediabenchmark_soft_sanitize_all-defaults",
],
srcs: ["Extractor.cpp"],
diff --git a/media/tests/benchmark/src/native/muxer/Android.bp b/media/tests/benchmark/src/native/muxer/Android.bp
index 6ef2a2e..f669d4a 100644
--- a/media/tests/benchmark/src/native/muxer/Android.bp
+++ b/media/tests/benchmark/src/native/muxer/Android.bp
@@ -15,15 +15,15 @@
*/
cc_library_static {
- name: "libbenchmark_muxer",
+ name: "libmediabenchmark_muxer",
defaults: [
- "libbenchmark_common-defaults",
- "libbenchmark_soft_sanitize_all-defaults",
+ "libmediabenchmark_common-defaults",
+ "libmediabenchmark_soft_sanitize_all-defaults",
],
srcs: ["Muxer.cpp"],
- static_libs: ["libbenchmark_extractor"],
+ static_libs: ["libmediabenchmark_extractor"],
export_include_dirs: ["."],
diff --git a/media/tests/benchmark/tests/Android.bp b/media/tests/benchmark/tests/Android.bp
index fc21ef7..24fd68c 100644
--- a/media/tests/benchmark/tests/Android.bp
+++ b/media/tests/benchmark/tests/Android.bp
@@ -18,28 +18,28 @@
name: "extractorTest",
gtest: true,
defaults: [
- "libbenchmark_common-defaults",
- "libbenchmark_soft_sanitize_all-defaults",
+ "libmediabenchmark_common-defaults",
+ "libmediabenchmark_soft_sanitize_all-defaults",
],
srcs: ["ExtractorTest.cpp"],
- static_libs: ["libbenchmark_extractor"]
+ static_libs: ["libmediabenchmark_extractor"]
}
cc_test {
name: "decoderTest",
gtest: true,
defaults: [
- "libbenchmark_common-defaults",
- "libbenchmark_soft_sanitize_all-defaults",
+ "libmediabenchmark_common-defaults",
+ "libmediabenchmark_soft_sanitize_all-defaults",
],
srcs: ["DecoderTest.cpp"],
static_libs: [
- "libbenchmark_extractor",
- "libbenchmark_decoder",
+ "libmediabenchmark_extractor",
+ "libmediabenchmark_decoder",
],
}
@@ -47,15 +47,15 @@
name: "muxerTest",
gtest: true,
defaults: [
- "libbenchmark_common-defaults",
- "libbenchmark_soft_sanitize_all-defaults",
+ "libmediabenchmark_common-defaults",
+ "libmediabenchmark_soft_sanitize_all-defaults",
],
srcs: ["MuxerTest.cpp"],
static_libs: [
- "libbenchmark_extractor",
- "libbenchmark_muxer",
+ "libmediabenchmark_extractor",
+ "libmediabenchmark_muxer",
],
}
@@ -63,15 +63,15 @@
name: "encoderTest",
gtest: true,
defaults: [
- "libbenchmark_common-defaults",
- "libbenchmark_soft_sanitize_all-defaults",
+ "libmediabenchmark_common-defaults",
+ "libmediabenchmark_soft_sanitize_all-defaults",
],
srcs: ["EncoderTest.cpp"],
static_libs: [
- "libbenchmark_extractor",
- "libbenchmark_decoder",
- "libbenchmark_encoder",
+ "libmediabenchmark_extractor",
+ "libmediabenchmark_decoder",
+ "libmediabenchmark_encoder",
],
}
diff --git a/media/tests/benchmark/tests/DecoderTest.cpp b/media/tests/benchmark/tests/DecoderTest.cpp
index 6cb42d6..242178f 100644
--- a/media/tests/benchmark/tests/DecoderTest.cpp
+++ b/media/tests/benchmark/tests/DecoderTest.cpp
@@ -72,24 +72,7 @@
vector<AMediaCodecBufferInfo> frameInfo;
AMediaCodecBufferInfo info;
uint32_t inputBufferOffset = 0;
- int32_t idx = 0;
- // Get CSD data
- while (1) {
- void *csdBuffer = extractor->getCSDSample(info, idx);
- if (!csdBuffer || !info.size) break;
-
- // copy the meta data and buffer to be passed to decoder
- if (inputBufferOffset + info.size > kMaxBufferSize) {
- cout << "[ WARN ] Test Skipped. Memory allocated not sufficient\n";
- free(inputBuffer);
- return;
- }
- memcpy(inputBuffer + inputBufferOffset, csdBuffer, info.size);
- frameInfo.push_back(info);
- inputBufferOffset += info.size;
- idx++;
- }
// Get frame data
while (1) {
status = extractor->getFrameSample(info);
@@ -135,6 +118,7 @@
make_tuple("bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", "", false),
make_tuple("bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", "", false),
make_tuple("bbb_44100hz_2ch_80kbps_vorbis_30sec.mp4", "", false),
+ make_tuple("bbb_44100hz_2ch_600kbps_flac_30sec.mp4", "", false),
make_tuple("bbb_48000hz_2ch_100kbps_opus_30sec.webm", "", false)));
INSTANTIATE_TEST_SUITE_P(
@@ -144,6 +128,7 @@
make_tuple("bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", "", true),
make_tuple("bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", "", true),
make_tuple("bbb_44100hz_2ch_80kbps_vorbis_30sec.mp4", "", true),
+ make_tuple("bbb_44100hz_2ch_600kbps_flac_30sec.mp4", "", true),
make_tuple("bbb_48000hz_2ch_100kbps_opus_30sec.webm", "", true)));
INSTANTIATE_TEST_SUITE_P(VideDecoderSyncTest, DecoderTest,
diff --git a/media/tests/benchmark/tests/EncoderTest.cpp b/media/tests/benchmark/tests/EncoderTest.cpp
index 574083d..9f42c64 100644
--- a/media/tests/benchmark/tests/EncoderTest.cpp
+++ b/media/tests/benchmark/tests/EncoderTest.cpp
@@ -72,24 +72,6 @@
vector<AMediaCodecBufferInfo> frameInfo;
AMediaCodecBufferInfo info;
uint32_t inputBufferOffset = 0;
- int32_t idx = 0;
-
- // Get CSD data
- while (1) {
- void *csdBuffer = extractor->getCSDSample(info, idx);
- if (!csdBuffer || !info.size) break;
-
- // copy the meta data and buffer to be passed to decoder
- if (inputBufferOffset + info.size > kMaxBufferSize) {
- cout << "[ WARN ] Test Skipped. Memory allocated not sufficient\n";
- free(inputBuffer);
- return;
- }
- memcpy(inputBuffer + inputBufferOffset, csdBuffer, info.size);
- frameInfo.push_back(info);
- inputBufferOffset += info.size;
- idx++;
- }
// Get frame data
while (1) {
@@ -189,6 +171,7 @@
::testing::Values(make_tuple("bbb_44100hz_2ch_128kbps_aac_30sec.mp4", "", false),
make_tuple("bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", "", false),
make_tuple("bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", "", false),
+ make_tuple("bbb_44100hz_2ch_600kbps_flac_30sec.mp4", "", false),
make_tuple("bbb_48000hz_2ch_100kbps_opus_30sec.webm", "", false)));
INSTANTIATE_TEST_SUITE_P(
@@ -196,6 +179,7 @@
::testing::Values(make_tuple("bbb_44100hz_2ch_128kbps_aac_30sec.mp4", "", true),
make_tuple("bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", "", true),
make_tuple("bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", "", true),
+ make_tuple("bbb_44100hz_2ch_600kbps_flac_30sec.mp4", "", true),
make_tuple("bbb_48000hz_2ch_100kbps_opus_30sec.webm", "", true)));
INSTANTIATE_TEST_SUITE_P(VideEncoderSyncTest, EncoderTest,
diff --git a/media/utils/Android.bp b/media/utils/Android.bp
index c0967d9..8a9039c 100644
--- a/media/utils/Android.bp
+++ b/media/utils/Android.bp
@@ -48,6 +48,7 @@
header_libs: [
"bionic_libc_platform_headers",
+ "libmedia_headers",
],
local_include_dirs: ["include"],
diff --git a/media/utils/ProcessInfo.cpp b/media/utils/ProcessInfo.cpp
index 27f1a79..113e4a7 100644
--- a/media/utils/ProcessInfo.cpp
+++ b/media/utils/ProcessInfo.cpp
@@ -23,6 +23,7 @@
#include <binder/IPCThreadState.h>
#include <binder/IProcessInfoService.h>
#include <binder/IServiceManager.h>
+#include <private/android_filesystem_config.h>
namespace android {
@@ -55,8 +56,9 @@
bool ProcessInfo::isValidPid(int pid) {
int callingPid = IPCThreadState::self()->getCallingPid();
+ int callingUid = IPCThreadState::self()->getCallingUid();
// Trust it if this is called from the same process otherwise pid has to match the calling pid.
- return (callingPid == getpid()) || (callingPid == pid);
+ return (callingPid == getpid()) || (callingPid == pid) || (callingUid == AID_MEDIA);
}
ProcessInfo::~ProcessInfo() {}
diff --git a/media/utils/TimeCheck.cpp b/media/utils/TimeCheck.cpp
index 59cf4ef..96f7802 100644
--- a/media/utils/TimeCheck.cpp
+++ b/media/utils/TimeCheck.cpp
@@ -16,8 +16,8 @@
#include <utils/Log.h>
-#include <media/TimeCheck.h>
-#include <media/EventLog.h>
+#include <mediautils/TimeCheck.h>
+#include <mediautils/EventLog.h>
namespace android {
@@ -82,10 +82,10 @@
if (waitTimeNs > 0) {
status = mCond.waitRelative(mMutex, waitTimeNs);
}
- }
- if (status != NO_ERROR) {
- LOG_EVENT_STRING(LOGTAG_AUDIO_BINDER_TIMEOUT, tag);
- LOG_ALWAYS_FATAL("TimeCheck timeout for %s", tag);
+ if (status != NO_ERROR) {
+ LOG_EVENT_STRING(LOGTAG_AUDIO_BINDER_TIMEOUT, tag);
+ LOG_ALWAYS_FATAL("TimeCheck timeout for %s", tag);
+ }
}
return true;
}
diff --git a/services/audioflinger/Android.bp b/services/audioflinger/Android.bp
index 96ad54b..d50a556 100644
--- a/services/audioflinger/Android.bp
+++ b/services/audioflinger/Android.bp
@@ -60,6 +60,10 @@
"libsndfile",
],
+ header_libs: [
+ "libmedia_headers",
+ ],
+
cflags: [
"-DSTATE_QUEUE_INSTANTIATIONS=\"StateQueueInstantiations.cpp\"",
"-fvisibility=hidden",
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 27d7856..65261da 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -19,6 +19,9 @@
#define LOG_TAG "AudioFlinger"
//#define LOG_NDEBUG 0
+// Define AUDIO_ARRAYS_STATIC_CHECK to check all audio arrays are correct
+#define AUDIO_ARRAYS_STATIC_CHECK 1
+
#include "Configuration.h"
#include <dirent.h>
#include <math.h>
@@ -810,7 +813,33 @@
continue;
}
- size_t frameCount = std::lcm(thread->frameCount(), secondaryThread->frameCount());
+ size_t sourceFrameCount = thread->frameCount() * output.sampleRate
+ / thread->sampleRate();
+ size_t sinkFrameCount = secondaryThread->frameCount() * output.sampleRate
+ / secondaryThread->sampleRate();
+ // If the secondary output has just been opened, the first secondaryThread write
+ // will not block as it will fill the empty startup buffer of the HAL,
+ // so a second sink buffer needs to be ready for the immediate next blocking write.
+ // Additionally, have a margin of one main thread buffer as the scheduling jitter
+ // can reorder the writes (eg if thread A&B have the same write intervale,
+ // the scheduler could schedule AB...BA)
+ size_t frameCountToBeReady = 2 * sinkFrameCount + sourceFrameCount;
+ // Total secondary output buffer must be at least as the read frames plus
+ // the margin of a few buffers on both sides in case the
+ // threads scheduling has some jitter.
+ // That value should not impact latency as the secondary track is started before
+ // its buffer is full, see frameCountToBeReady.
+ size_t frameCount = frameCountToBeReady + 2 * (sourceFrameCount + sinkFrameCount);
+ // The frameCount should also not be smaller than the secondary thread min frame
+ // count
+ size_t minFrameCount = AudioSystem::calculateMinFrameCount(
+ [&] { Mutex::Autolock _l(secondaryThread->mLock);
+ return secondaryThread->latency_l(); }(),
+ secondaryThread->mNormalFrameCount,
+ secondaryThread->mSampleRate,
+ output.sampleRate,
+ input.speed);
+ frameCount = std::max(frameCount, minFrameCount);
using namespace std::chrono_literals;
auto inChannelMask = audio_channel_mask_out_to_in(input.config.channel_mask);
@@ -843,7 +872,8 @@
patchRecord->buffer(),
patchRecord->bufferSize(),
outputFlags,
- 0ns /* timeout */);
+ 0ns /* timeout */,
+ frameCountToBeReady);
status = patchTrack->initCheck();
if (status != NO_ERROR) {
ALOGE("Secondary output patchTrack init failed: %d", status);
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 5e4509f..d2de5fe 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -67,11 +67,11 @@
#include <media/AudioBufferProvider.h>
#include <media/AudioMixer.h>
#include <media/ExtendedAudioBufferProvider.h>
-#include <media/LinearMap.h>
#include <media/VolumeShaper.h>
#include <audio_utils/clock.h>
#include <audio_utils/FdToString.h>
+#include <audio_utils/LinearMap.h>
#include <audio_utils/SimpleLog.h>
#include <audio_utils/TimestampVerifier.h>
@@ -547,6 +547,16 @@
bool mute;
};
+ // Abstraction for the Audio Source for the RecordThread (HAL or PassthruPatchRecord).
+ struct Source
+ {
+ virtual ~Source() = default;
+ // The following methods have the same signatures as in StreamHalInterface.
+ virtual status_t read(void *buffer, size_t bytes, size_t *read) = 0;
+ virtual status_t getCapturePosition(int64_t *frames, int64_t *time) = 0;
+ virtual status_t standby() = 0;
+ };
+
// --- PlaybackThread ---
#ifdef FLOAT_EFFECT_CHAIN
#define EFFECT_BUFFER_FORMAT AUDIO_FORMAT_PCM_FLOAT
@@ -749,7 +759,7 @@
// For emphasis, we could also make all pointers to them be "const *",
// but that would clutter the code unnecessarily.
- struct AudioStreamIn {
+ struct AudioStreamIn : public Source {
AudioHwDevice* const audioHwDev;
sp<StreamInHalInterface> stream;
audio_input_flags_t flags;
@@ -758,6 +768,13 @@
AudioStreamIn(AudioHwDevice *dev, sp<StreamInHalInterface> in, audio_input_flags_t flags) :
audioHwDev(dev), stream(in), flags(flags) {}
+ status_t read(void *buffer, size_t bytes, size_t *read) override {
+ return stream->read(buffer, bytes, read);
+ }
+ status_t getCapturePosition(int64_t *frames, int64_t *time) override {
+ return stream->getCapturePosition(frames, time);
+ }
+ status_t standby() override { return stream->standby(); }
};
struct TeePatch {
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index edb331d..18cb53b 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -483,19 +483,6 @@
// Fast mode is not available in this case.
inputFlags = (audio_input_flags_t) (inputFlags & ~AUDIO_INPUT_FLAG_FAST);
}
- sp<RecordThread::PatchRecord> tempRecordTrack = new (std::nothrow) RecordThread::PatchRecord(
- mRecord.thread().get(),
- sampleRate,
- inChannelMask,
- format,
- frameCount,
- NULL,
- (size_t)0 /* bufferSize */,
- inputFlags);
- status = mRecord.checkTrack(tempRecordTrack.get());
- if (status != NO_ERROR) {
- return status;
- }
audio_output_flags_t outputFlags = mAudioPatch.sinks[0].config_mask & AUDIO_PORT_CONFIG_FLAGS ?
mAudioPatch.sinks[0].flags.output : AUDIO_OUTPUT_FLAG_NONE;
@@ -512,9 +499,34 @@
outputFlags = (audio_output_flags_t) (outputFlags & ~AUDIO_OUTPUT_FLAG_FAST);
}
+ sp<RecordThread::PatchRecord> tempRecordTrack;
+ if ((inputFlags & AUDIO_INPUT_FLAG_DIRECT) && (outputFlags & AUDIO_OUTPUT_FLAG_DIRECT)) {
+ tempRecordTrack = new RecordThread::PassthruPatchRecord(
+ mRecord.thread().get(),
+ sampleRate,
+ inChannelMask,
+ format,
+ frameCount,
+ inputFlags);
+ } else {
+ tempRecordTrack = new RecordThread::PatchRecord(
+ mRecord.thread().get(),
+ sampleRate,
+ inChannelMask,
+ format,
+ frameCount,
+ nullptr,
+ (size_t)0 /* bufferSize */,
+ inputFlags);
+ }
+ status = mRecord.checkTrack(tempRecordTrack.get());
+ if (status != NO_ERROR) {
+ return status;
+ }
+
// create a special playback track to render to playback thread.
// this track is given the same buffer as the PatchRecord buffer
- sp<PlaybackThread::PatchTrack> tempPatchTrack = new (std::nothrow) PlaybackThread::PatchTrack(
+ sp<PlaybackThread::PatchTrack> tempPatchTrack = new PlaybackThread::PatchTrack(
mPlayback.thread().get(),
streamType,
sampleRate,
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index a093893..1ff03c4 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -74,7 +74,10 @@
uid_t uid,
audio_output_flags_t flags,
track_type type,
- audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE);
+ audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE,
+ /** default behaviour is to start when there are as many frames
+ * ready as possible (aka. Buffer is full). */
+ size_t frameCountToBeReady = SIZE_MAX);
virtual ~Track();
virtual status_t initCheck() const;
@@ -263,11 +266,11 @@
};
sp<AudioVibrationController> mAudioVibrationController;
sp<os::ExternalVibration> mExternalVibration;
+ /** How many frames should be in the buffer before the track is considered ready */
+ const size_t mFrameCountToBeReady;
private:
void interceptBuffer(const AudioBufferProvider::Buffer& buffer);
- /** Write the source data in the buffer provider. @return written frame count. */
- size_t writeFrames(AudioBufferProvider* dest, const void* src, size_t frameCount);
template <class F>
void forEachTeePatchTrack(F f) {
for (auto& tp : mTeePatches) { f(tp.patchTrack); }
@@ -384,9 +387,15 @@
void *buffer,
size_t bufferSize,
audio_output_flags_t flags,
- const Timeout& timeout = {});
+ const Timeout& timeout = {},
+ size_t frameCountToBeReady = 1 /** Default behaviour is to start
+ * as soon as possible to have
+ * the lowest possible latency
+ * even if it might glitch. */);
virtual ~PatchTrack();
+ size_t framesReady() const override;
+
virtual status_t start(AudioSystem::sync_event_t event =
AudioSystem::SYNC_EVENT_NONE,
audio_session_t triggerSession = AUDIO_SESSION_NONE);
@@ -402,5 +411,4 @@
private:
void restartIfDisabled();
-
}; // end of PatchTrack
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index c8397cd..d5257bd 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -167,6 +167,8 @@
const Timeout& timeout = {});
virtual ~PatchRecord();
+ virtual Source* getSource() { return nullptr; }
+
// AudioBufferProvider interface
virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
@@ -175,4 +177,71 @@
virtual status_t obtainBuffer(Proxy::Buffer *buffer,
const struct timespec *timeOut = NULL);
virtual void releaseBuffer(Proxy::Buffer *buffer);
+
+ size_t writeFrames(const void* src, size_t frameCount, size_t frameSize) {
+ return writeFrames(this, src, frameCount, frameSize);
+ }
+
+protected:
+ /** Write the source data into the buffer provider. @return written frame count. */
+ static size_t writeFrames(AudioBufferProvider* dest, const void* src,
+ size_t frameCount, size_t frameSize);
+
}; // end of PatchRecord
+
+class PassthruPatchRecord : public PatchRecord, public Source {
+public:
+ PassthruPatchRecord(RecordThread *recordThread,
+ uint32_t sampleRate,
+ audio_channel_mask_t channelMask,
+ audio_format_t format,
+ size_t frameCount,
+ audio_input_flags_t flags);
+
+ Source* getSource() override { return static_cast<Source*>(this); }
+
+ // Source interface
+ status_t read(void *buffer, size_t bytes, size_t *read) override;
+ status_t getCapturePosition(int64_t *frames, int64_t *time) override;
+ status_t standby() override;
+
+ // AudioBufferProvider interface
+ // This interface is used by RecordThread to pass the data obtained
+ // from HAL or other source to the client. PassthruPatchRecord receives
+ // the data in 'obtainBuffer' so these calls are stubbed out.
+ status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) override;
+ void releaseBuffer(AudioBufferProvider::Buffer* buffer) override;
+
+ // PatchProxyBufferProvider interface
+ // This interface is used from DirectOutputThread to acquire data from HAL.
+ bool producesBufferOnDemand() const override { return true; }
+ status_t obtainBuffer(Proxy::Buffer *buffer, const struct timespec *timeOut = nullptr) override;
+ void releaseBuffer(Proxy::Buffer *buffer) override;
+
+private:
+ // This is to use with PatchRecord::writeFrames
+ struct PatchRecordAudioBufferProvider : public AudioBufferProvider {
+ explicit PatchRecordAudioBufferProvider(PassthruPatchRecord& passthru) :
+ mPassthru(passthru) {}
+ status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) override {
+ return mPassthru.PatchRecord::getNextBuffer(buffer);
+ }
+ void releaseBuffer(AudioBufferProvider::Buffer* buffer) override {
+ return mPassthru.PatchRecord::releaseBuffer(buffer);
+ }
+ private:
+ PassthruPatchRecord& mPassthru;
+ };
+
+ sp<StreamInHalInterface> obtainStream(sp<ThreadBase>* thread);
+
+ PatchRecordAudioBufferProvider mPatchRecordAudioBufferProvider;
+ std::unique_ptr<void, decltype(free)*> mSinkBuffer; // frame size aligned continuous buffer
+ std::unique_ptr<void, decltype(free)*> mStubBuffer; // buffer used for AudioBufferProvider
+ size_t mUnconsumedFrames = 0;
+ std::mutex mReadLock;
+ std::condition_variable mReadCV;
+ size_t mReadBytes = 0; // GUARDED_BY(mReadLock)
+ status_t mReadError = NO_ERROR; // GUARDED_BY(mReadLock)
+ int64_t mLastReadFrames = 0; // accessed on RecordThread only
+};
diff --git a/services/audioflinger/SpdifStreamOut.cpp b/services/audioflinger/SpdifStreamOut.cpp
index a44ab2a..c7aba79 100644
--- a/services/audioflinger/SpdifStreamOut.cpp
+++ b/services/audioflinger/SpdifStreamOut.cpp
@@ -59,6 +59,7 @@
// TODO Move this into the audio_utils as a static method.
switch(config->format) {
case AUDIO_FORMAT_E_AC3:
+ case AUDIO_FORMAT_E_AC3_JOC:
mRateMultiplier = 4;
break;
case AUDIO_FORMAT_AC3:
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 8fddc13..8704d16 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -6679,6 +6679,7 @@
) :
ThreadBase(audioFlinger, id, outDevice, inDevice, RECORD, systemReady),
mInput(input),
+ mSource(mInput),
mActiveTracks(&this->mLocalLog),
mRsmpInBuffer(NULL),
// mRsmpInFrames, mRsmpInFramesP2, and mRsmpInFramesOA are set by readInputParameters_l()
@@ -7131,7 +7132,7 @@
} else {
ATRACE_BEGIN("read");
size_t bytesRead;
- status_t result = mInput->stream->read(
+ status_t result = mSource->read(
(uint8_t*)mRsmpInBuffer + rear * mFrameSize, mBufferSize, &bytesRead);
ATRACE_END();
if (result < 0) {
@@ -7153,7 +7154,7 @@
int64_t position, time;
if (mStandby) {
mTimestampVerifier.discontinuity();
- } else if (mInput->stream->getCapturePosition(&position, &time) == NO_ERROR
+ } else if (mSource->getCapturePosition(&position, &time) == NO_ERROR
&& time > mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL]) {
mTimestampVerifier.add(position, time, mSampleRate);
@@ -7434,7 +7435,7 @@
sq->end(false /*didModify*/);
}
}
- status_t result = mInput->stream->standby();
+ status_t result = mSource->standby();
ALOGE_IF(result != OK, "Error when putting input stream into standby: %d", result);
// If going into standby, flush the pipe source.
@@ -8420,11 +8421,17 @@
{
Mutex::Autolock _l(mLock);
mTracks.add(record);
+ if (record->getSource()) {
+ mSource = record->getSource();
+ }
}
void AudioFlinger::RecordThread::deletePatchTrack(const sp<PatchRecord>& record)
{
Mutex::Autolock _l(mLock);
+ if (mSource == record->getSource()) {
+ mSource = mInput;
+ }
destroyTrack_l(record);
}
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 6a9c0e7..34a3f34 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1647,6 +1647,7 @@
void checkBtNrec_l();
AudioStreamIn *mInput;
+ Source *mSource;
SortedVector < sp<RecordTrack> > mTracks;
// mActiveTracks has dual roles: it indicates the current active track(s), and
// is used together with mStartStopCond to indicate start()/stop() progress
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 7cf34c1..051f1e3 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -337,6 +337,7 @@
virtual ~PatchProxyBufferProvider() {}
+ virtual bool producesBufferOnDemand() const = 0;
virtual status_t obtainBuffer(Proxy::Buffer* buffer,
const struct timespec *requested = NULL) = 0;
virtual void releaseBuffer(Proxy::Buffer* buffer) = 0;
@@ -359,6 +360,8 @@
mPeerProxy = nullptr;
}
+ bool producesBufferOnDemand() const override { return false; }
+
protected:
const sp<ClientProxy> mProxy;
sp<RefBase> mPeerReferenceHold; // keeps mPeerProxy alive during access.
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 6a999fc..41a71d5 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -508,7 +508,8 @@
uid_t uid,
audio_output_flags_t flags,
track_type type,
- audio_port_handle_t portId)
+ audio_port_handle_t portId,
+ size_t frameCountToBeReady)
: TrackBase(thread, client, attr, sampleRate, format, channelMask, frameCount,
// TODO: Using unsecurePointer() has some associated security pitfalls
// (see declaration for details).
@@ -531,6 +532,7 @@
mVolumeHandler(new media::VolumeHandler(sampleRate)),
mOpPlayAudioMonitor(OpPlayAudioMonitor::createIfNeeded(uid, attr, id(), streamType)),
// mSinkTimestamp
+ mFrameCountToBeReady(frameCountToBeReady),
mFastIndex(-1),
mCachedVolume(1.0),
/* The track might not play immediately after being active, similarly as if its volume was 0.
@@ -561,7 +563,7 @@
mFrameSize, !isExternalTrack(), sampleRate);
} else {
mAudioTrackServerProxy = new StaticAudioTrackServerProxy(mCblk, mBuffer, frameCount,
- mFrameSize);
+ mFrameSize, sampleRate);
}
mServerProxy = mAudioTrackServerProxy;
@@ -823,16 +825,9 @@
}
for (auto& teePatch : mTeePatches) {
RecordThread::PatchRecord* patchRecord = teePatch.patchRecord.get();
-
- size_t framesWritten = writeFrames(patchRecord, sourceBuffer.i8, frameCount);
- // On buffer wrap, the buffer frame count will be less than requested,
- // when this happens a second buffer needs to be used to write the leftover audio
- size_t framesLeft = frameCount - framesWritten;
- if (framesWritten != 0 && framesLeft != 0) {
- framesWritten +=
- writeFrames(patchRecord, sourceBuffer.i8 + framesWritten * mFrameSize, framesLeft);
- framesLeft = frameCount - framesWritten;
- }
+ const size_t framesWritten = patchRecord->writeFrames(
+ sourceBuffer.i8, frameCount, mFrameSize);
+ const size_t framesLeft = frameCount - framesWritten;
ALOGW_IF(framesLeft != 0, "%s(%d) PatchRecord %d can not provide big enough "
"buffer %zu/%zu, dropping %zu frames", __func__, mId, patchRecord->mId,
framesWritten, frameCount, framesLeft);
@@ -840,30 +835,10 @@
auto spent = ceil<std::chrono::microseconds>(std::chrono::steady_clock::now() - start);
using namespace std::chrono_literals;
// Average is ~20us per track, this should virtually never be logged (Logging takes >200us)
- ALOGD_IF(spent > 200us, "%s: took %lldus to intercept %zu tracks", __func__,
+ ALOGD_IF(spent > 500us, "%s: took %lldus to intercept %zu tracks", __func__,
spent.count(), mTeePatches.size());
}
-size_t AudioFlinger::PlaybackThread::Track::writeFrames(AudioBufferProvider* dest,
- const void* src,
- size_t frameCount) {
- AudioBufferProvider::Buffer patchBuffer;
- patchBuffer.frameCount = frameCount;
- auto status = dest->getNextBuffer(&patchBuffer);
- if (status != NO_ERROR) {
- ALOGW("%s PathRecord getNextBuffer failed with error %d: %s",
- __func__, status, strerror(-status));
- return 0;
- }
- ALOG_ASSERT(patchBuffer.frameCount <= frameCount);
- memcpy(patchBuffer.raw, src, patchBuffer.frameCount * mFrameSize);
- auto framesWritten = patchBuffer.frameCount;
- dest->releaseBuffer(&patchBuffer);
- return framesWritten;
-}
-
-// releaseBuffer() is not overridden
-
// ExtendedAudioBufferProvider interface
// framesReady() may return an approximation of the number of frames if called
@@ -913,8 +888,12 @@
return true;
}
- if (framesReady() >= mServerProxy->getBufferSizeInFrames() ||
- (mCblk->mFlags & CBLK_FORCEREADY)) {
+ size_t bufferSizeInFrames = mServerProxy->getBufferSizeInFrames();
+ size_t framesToBeReady = std::min(mFrameCountToBeReady, bufferSizeInFrames);
+
+ if (framesReady() >= framesToBeReady || (mCblk->mFlags & CBLK_FORCEREADY)) {
+ ALOGV("%s(%d): consider track ready with %zu/%zu, target was %zu)",
+ __func__, mId, framesReady(), bufferSizeInFrames, framesToBeReady);
mFillingUpStatus = FS_FILLED;
android_atomic_and(~CBLK_FORCEREADY, &mCblk->mFlags);
return true;
@@ -1416,6 +1395,7 @@
void AudioFlinger::PlaybackThread::Track::disable()
{
+ // TODO(b/142394888): the filling status should also be reset to filling
signalClientFlag(CBLK_DISABLED);
}
@@ -1793,12 +1773,14 @@
void *buffer,
size_t bufferSize,
audio_output_flags_t flags,
- const Timeout& timeout)
+ const Timeout& timeout,
+ size_t frameCountToBeReady)
: Track(playbackThread, NULL, streamType,
audio_attributes_t{} /* currently unused for patch track */,
sampleRate, format, channelMask, frameCount,
buffer, bufferSize, nullptr /* sharedBuffer */,
- AUDIO_SESSION_NONE, getpid(), AID_AUDIOSERVER, flags, TYPE_PATCH),
+ AUDIO_SESSION_NONE, getpid(), AID_AUDIOSERVER, flags, TYPE_PATCH,
+ AUDIO_PORT_HANDLE_NONE, frameCountToBeReady),
PatchTrackBase(new ClientProxy(mCblk, mBuffer, frameCount, mFrameSize, true, true),
*playbackThread, timeout)
{
@@ -1813,6 +1795,15 @@
ALOGV("%s(%d)", __func__, mId);
}
+size_t AudioFlinger::PlaybackThread::PatchTrack::framesReady() const
+{
+ if (mPeerProxy && mPeerProxy->producesBufferOnDemand()) {
+ return std::numeric_limits<size_t>::max();
+ } else {
+ return Track::framesReady();
+ }
+}
+
status_t AudioFlinger::PlaybackThread::PatchTrack::start(AudioSystem::sync_event_t event,
audio_session_t triggerSession)
{
@@ -1882,7 +1873,6 @@
{
mProxy->releaseBuffer(buffer);
restartIfDisabled();
- android_atomic_or(CBLK_FORCEREADY, &mCblk->mFlags);
}
void AudioFlinger::PlaybackThread::PatchTrack::restartIfDisabled()
@@ -2405,6 +2395,39 @@
ALOGV("%s(%d)", __func__, mId);
}
+static size_t writeFramesHelper(
+ AudioBufferProvider* dest, const void* src, size_t frameCount, size_t frameSize)
+{
+ AudioBufferProvider::Buffer patchBuffer;
+ patchBuffer.frameCount = frameCount;
+ auto status = dest->getNextBuffer(&patchBuffer);
+ if (status != NO_ERROR) {
+ ALOGW("%s PathRecord getNextBuffer failed with error %d: %s",
+ __func__, status, strerror(-status));
+ return 0;
+ }
+ ALOG_ASSERT(patchBuffer.frameCount <= frameCount);
+ memcpy(patchBuffer.raw, src, patchBuffer.frameCount * frameSize);
+ size_t framesWritten = patchBuffer.frameCount;
+ dest->releaseBuffer(&patchBuffer);
+ return framesWritten;
+}
+
+// static
+size_t AudioFlinger::RecordThread::PatchRecord::writeFrames(
+ AudioBufferProvider* dest, const void* src, size_t frameCount, size_t frameSize)
+{
+ size_t framesWritten = writeFramesHelper(dest, src, frameCount, frameSize);
+ // On buffer wrap, the buffer frame count will be less than requested,
+ // when this happens a second buffer needs to be used to write the leftover audio
+ const size_t framesLeft = frameCount - framesWritten;
+ if (framesWritten != 0 && framesLeft != 0) {
+ framesWritten += writeFramesHelper(dest, (const char*)src + framesWritten * frameSize,
+ framesLeft, frameSize);
+ }
+ return framesWritten;
+}
+
// AudioBufferProvider interface
status_t AudioFlinger::RecordThread::PatchRecord::getNextBuffer(
AudioBufferProvider::Buffer* buffer)
@@ -2449,6 +2472,180 @@
mProxy->releaseBuffer(buffer);
}
+#undef LOG_TAG
+#define LOG_TAG "AF::PthrPatchRecord"
+
+static std::unique_ptr<void, decltype(free)*> allocAligned(size_t alignment, size_t size)
+{
+ void *ptr = nullptr;
+ (void)posix_memalign(&ptr, alignment, size);
+ return std::unique_ptr<void, decltype(free)*>(ptr, free);
+}
+
+AudioFlinger::RecordThread::PassthruPatchRecord::PassthruPatchRecord(
+ RecordThread *recordThread,
+ uint32_t sampleRate,
+ audio_channel_mask_t channelMask,
+ audio_format_t format,
+ size_t frameCount,
+ audio_input_flags_t flags)
+ : PatchRecord(recordThread, sampleRate, channelMask, format, frameCount,
+ nullptr /*buffer*/, 0 /*bufferSize*/, flags),
+ mPatchRecordAudioBufferProvider(*this),
+ mSinkBuffer(allocAligned(32, mFrameCount * mFrameSize)),
+ mStubBuffer(allocAligned(32, mFrameCount * mFrameSize))
+{
+ memset(mStubBuffer.get(), 0, mFrameCount * mFrameSize);
+}
+
+sp<StreamInHalInterface> AudioFlinger::RecordThread::PassthruPatchRecord::obtainStream(
+ sp<ThreadBase>* thread)
+{
+ *thread = mThread.promote();
+ if (!*thread) return nullptr;
+ RecordThread *recordThread = static_cast<RecordThread*>((*thread).get());
+ Mutex::Autolock _l(recordThread->mLock);
+ return recordThread->mInput ? recordThread->mInput->stream : nullptr;
+}
+
+// PatchProxyBufferProvider methods are called on DirectOutputThread
+status_t AudioFlinger::RecordThread::PassthruPatchRecord::obtainBuffer(
+ Proxy::Buffer* buffer, const struct timespec* timeOut)
+{
+ if (mUnconsumedFrames) {
+ buffer->mFrameCount = std::min(buffer->mFrameCount, mUnconsumedFrames);
+ // mUnconsumedFrames is decreased in releaseBuffer to use actual frame consumption figure.
+ return PatchRecord::obtainBuffer(buffer, timeOut);
+ }
+
+ // Otherwise, execute a read from HAL and write into the buffer.
+ nsecs_t startTimeNs = 0;
+ if (timeOut && (timeOut->tv_sec != 0 || timeOut->tv_nsec != 0) && timeOut->tv_sec != INT_MAX) {
+ // Will need to correct timeOut by elapsed time.
+ startTimeNs = systemTime();
+ }
+ const size_t framesToRead = std::min(buffer->mFrameCount, mFrameCount);
+ buffer->mFrameCount = 0;
+ buffer->mRaw = nullptr;
+ sp<ThreadBase> thread;
+ sp<StreamInHalInterface> stream = obtainStream(&thread);
+ if (!stream) return NO_INIT; // If there is no stream, RecordThread is not reading.
+
+ status_t result = NO_ERROR;
+ size_t bytesRead = 0;
+ {
+ ATRACE_NAME("read");
+ result = stream->read(mSinkBuffer.get(), framesToRead * mFrameSize, &bytesRead);
+ if (result != NO_ERROR) goto stream_error;
+ if (bytesRead == 0) return NO_ERROR;
+ }
+
+ {
+ std::lock_guard<std::mutex> lock(mReadLock);
+ mReadBytes += bytesRead;
+ mReadError = NO_ERROR;
+ }
+ mReadCV.notify_one();
+ // writeFrames handles wraparound and should write all the provided frames.
+ // If it couldn't, there is something wrong with the client/server buffer of the software patch.
+ buffer->mFrameCount = writeFrames(
+ &mPatchRecordAudioBufferProvider,
+ mSinkBuffer.get(), bytesRead / mFrameSize, mFrameSize);
+ ALOGW_IF(buffer->mFrameCount < bytesRead / mFrameSize,
+ "Lost %zu frames obtained from HAL", bytesRead / mFrameSize - buffer->mFrameCount);
+ mUnconsumedFrames = buffer->mFrameCount;
+ struct timespec newTimeOut;
+ if (startTimeNs) {
+ // Correct the timeout by elapsed time.
+ nsecs_t newTimeOutNs = audio_utils_ns_from_timespec(timeOut) - (systemTime() - startTimeNs);
+ if (newTimeOutNs < 0) newTimeOutNs = 0;
+ newTimeOut.tv_sec = newTimeOutNs / NANOS_PER_SECOND;
+ newTimeOut.tv_nsec = newTimeOutNs - newTimeOut.tv_sec * NANOS_PER_SECOND;
+ timeOut = &newTimeOut;
+ }
+ return PatchRecord::obtainBuffer(buffer, timeOut);
+
+stream_error:
+ stream->standby();
+ {
+ std::lock_guard<std::mutex> lock(mReadLock);
+ mReadError = result;
+ }
+ mReadCV.notify_one();
+ return result;
+}
+
+void AudioFlinger::RecordThread::PassthruPatchRecord::releaseBuffer(Proxy::Buffer* buffer)
+{
+ if (buffer->mFrameCount <= mUnconsumedFrames) {
+ mUnconsumedFrames -= buffer->mFrameCount;
+ } else {
+ ALOGW("Write side has consumed more frames than we had: %zu > %zu",
+ buffer->mFrameCount, mUnconsumedFrames);
+ mUnconsumedFrames = 0;
+ }
+ PatchRecord::releaseBuffer(buffer);
+}
+
+// AudioBufferProvider and Source methods are called on RecordThread
+// 'read' emulates actual audio data with 0's. This is OK as 'getNextBuffer'
+// and 'releaseBuffer' are stubbed out and ignore their input.
+// It's not possible to retrieve actual data here w/o blocking 'obtainBuffer'
+// until we copy it.
+status_t AudioFlinger::RecordThread::PassthruPatchRecord::read(
+ void* buffer, size_t bytes, size_t* read)
+{
+ bytes = std::min(bytes, mFrameCount * mFrameSize);
+ {
+ std::unique_lock<std::mutex> lock(mReadLock);
+ mReadCV.wait(lock, [&]{ return mReadError != NO_ERROR || mReadBytes != 0; });
+ if (mReadError != NO_ERROR) {
+ mLastReadFrames = 0;
+ return mReadError;
+ }
+ *read = std::min(bytes, mReadBytes);
+ mReadBytes -= *read;
+ }
+ mLastReadFrames = *read / mFrameSize;
+ memset(buffer, 0, *read);
+ return 0;
+}
+
+status_t AudioFlinger::RecordThread::PassthruPatchRecord::getCapturePosition(
+ int64_t* frames, int64_t* time)
+{
+ sp<ThreadBase> thread;
+ sp<StreamInHalInterface> stream = obtainStream(&thread);
+ return stream ? stream->getCapturePosition(frames, time) : NO_INIT;
+}
+
+status_t AudioFlinger::RecordThread::PassthruPatchRecord::standby()
+{
+ // RecordThread issues 'standby' command in two major cases:
+ // 1. Error on read--this case is handled in 'obtainBuffer'.
+ // 2. Track is stopping--as PassthruPatchRecord assumes continuous
+ // output, this can only happen when the software patch
+ // is being torn down. In this case, the RecordThread
+ // will terminate and close the HAL stream.
+ return 0;
+}
+
+// As the buffer gets filled in obtainBuffer, here we only simulate data consumption.
+status_t AudioFlinger::RecordThread::PassthruPatchRecord::getNextBuffer(
+ AudioBufferProvider::Buffer* buffer)
+{
+ buffer->frameCount = mLastReadFrames;
+ buffer->raw = buffer->frameCount != 0 ? mStubBuffer.get() : nullptr;
+ return NO_ERROR;
+}
+
+void AudioFlinger::RecordThread::PassthruPatchRecord::releaseBuffer(
+ AudioBufferProvider::Buffer* buffer)
+{
+ buffer->frameCount = 0;
+ buffer->raw = nullptr;
+}
+
// ----------------------------------------------------------------------------
#undef LOG_TAG
#define LOG_TAG "AF::MmapTrack"
diff --git a/services/audiopolicy/TEST_MAPPING b/services/audiopolicy/TEST_MAPPING
index a94fd87..eb6c19e 100644
--- a/services/audiopolicy/TEST_MAPPING
+++ b/services/audiopolicy/TEST_MAPPING
@@ -2,9 +2,6 @@
"presubmit": [
{
"name": "audiopolicy_tests"
- },
- {
- "name": "systemaudio_tests"
}
]
}
diff --git a/services/audiopolicy/common/Android.bp b/services/audiopolicy/common/Android.bp
index a925b9a..6e0d2f6 100644
--- a/services/audiopolicy/common/Android.bp
+++ b/services/audiopolicy/common/Android.bp
@@ -1,4 +1,7 @@
cc_library_headers {
name: "libaudiopolicycommon",
+ header_libs: [
+ "libaudiofoundation_headers",
+ ],
export_include_dirs: ["include"],
}
diff --git a/services/audiopolicy/common/include/Volume.h b/services/audiopolicy/common/include/Volume.h
index 1dbd1eb..c3a02f9 100644
--- a/services/audiopolicy/common/include/Volume.h
+++ b/services/audiopolicy/common/include/Volume.h
@@ -17,6 +17,7 @@
#pragma once
#include <media/AudioCommonTypes.h>
+#include <media/AudioContainers.h>
#include <system/audio.h>
#include <utils/Log.h>
#include <math.h>
@@ -82,43 +83,55 @@
*
* @return subset of device required to limit the number of volume category per device
*/
- static audio_devices_t getDeviceForVolume(audio_devices_t device)
+ static audio_devices_t getDeviceForVolume(const android::DeviceTypeSet& deviceTypes)
{
- if (device == AUDIO_DEVICE_NONE) {
+ audio_devices_t deviceType = AUDIO_DEVICE_NONE;
+ if (deviceTypes.empty()) {
// this happens when forcing a route update and no track is active on an output.
// In this case the returned category is not important.
- device = AUDIO_DEVICE_OUT_SPEAKER;
- } else if (popcount(device) > 1) {
+ deviceType = AUDIO_DEVICE_OUT_SPEAKER;
+ } else if (deviceTypes.size() > 1) {
// Multiple device selection is either:
// - speaker + one other device: give priority to speaker in this case.
// - one A2DP device + another device: happens with duplicated output. In this case
// retain the device on the A2DP output as the other must not correspond to an active
// selection if not the speaker.
// - HDMI-CEC system audio mode only output: give priority to available item in order.
- if (device & AUDIO_DEVICE_OUT_SPEAKER) {
- device = AUDIO_DEVICE_OUT_SPEAKER;
- } else if (device & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
- device = AUDIO_DEVICE_OUT_SPEAKER_SAFE;
- } else if (device & AUDIO_DEVICE_OUT_HDMI_ARC) {
- device = AUDIO_DEVICE_OUT_HDMI_ARC;
- } else if (device & AUDIO_DEVICE_OUT_AUX_LINE) {
- device = AUDIO_DEVICE_OUT_AUX_LINE;
- } else if (device & AUDIO_DEVICE_OUT_SPDIF) {
- device = AUDIO_DEVICE_OUT_SPDIF;
+ if (deviceTypes.count(AUDIO_DEVICE_OUT_SPEAKER) != 0) {
+ deviceType = AUDIO_DEVICE_OUT_SPEAKER;
+ } else if (deviceTypes.count(AUDIO_DEVICE_OUT_SPEAKER_SAFE) != 0) {
+ deviceType = AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+ } else if (deviceTypes.count(AUDIO_DEVICE_OUT_HDMI_ARC) != 0) {
+ deviceType = AUDIO_DEVICE_OUT_HDMI_ARC;
+ } else if (deviceTypes.count(AUDIO_DEVICE_OUT_AUX_LINE) != 0) {
+ deviceType = AUDIO_DEVICE_OUT_AUX_LINE;
+ } else if (deviceTypes.count(AUDIO_DEVICE_OUT_SPDIF) != 0) {
+ deviceType = AUDIO_DEVICE_OUT_SPDIF;
} else {
- device = (audio_devices_t)(device & AUDIO_DEVICE_OUT_ALL_A2DP);
+ std::vector<audio_devices_t> a2dpDevices = android::Intersection(
+ deviceTypes, android::getAudioDeviceOutAllA2dpSet());
+ if (a2dpDevices.size() > 1) {
+ ALOGW("getDeviceForVolume() invalid device combination: %s",
+ android::dumpDeviceTypes(deviceTypes).c_str());
+ }
+ if (!a2dpDevices.empty()) {
+ deviceType = a2dpDevices[0];
+ }
}
+ } else {
+ deviceType = *(deviceTypes.begin());
}
/*SPEAKER_SAFE is an alias of SPEAKER for purposes of volume control*/
- if (device == AUDIO_DEVICE_OUT_SPEAKER_SAFE)
- device = AUDIO_DEVICE_OUT_SPEAKER;
+ if (deviceType == AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
+ deviceType = AUDIO_DEVICE_OUT_SPEAKER;
+ }
- ALOGW_IF(popcount(device) != 1,
- "getDeviceForVolume() invalid device combination: %08x",
- device);
+ ALOGW_IF(deviceType == AUDIO_DEVICE_NONE,
+ "getDeviceForVolume() invalid device combination: %s, returning AUDIO_DEVICE_NONE",
+ android::dumpDeviceTypes(deviceTypes).c_str());
- return device;
+ return deviceType;
}
/**
@@ -128,9 +141,9 @@
*
* @return device category.
*/
- static device_category getDeviceCategory(audio_devices_t device)
+ static device_category getDeviceCategory(const android::DeviceTypeSet& deviceTypes)
{
- switch(getDeviceForVolume(device)) {
+ switch(getDeviceForVolume(deviceTypes)) {
case AUDIO_DEVICE_OUT_EARPIECE:
return DEVICE_CATEGORY_EARPIECE;
case AUDIO_DEVICE_OUT_WIRED_HEADSET:
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 96fec4a..41f7dfc 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -21,6 +21,7 @@
#include <sys/types.h>
+#include <media/AudioContainers.h>
#include <utils/Errors.h>
#include <utils/Timers.h>
#include <utils/KeyedVector.h>
@@ -156,10 +157,10 @@
virtual DeviceVector supportedDevices() const { return mDevices; }
virtual bool isDuplicated() const { return false; }
virtual uint32_t latency() { return 0; }
- virtual bool isFixedVolume(audio_devices_t device);
+ virtual bool isFixedVolume(const DeviceTypeSet& deviceTypes);
virtual bool setVolume(float volumeDb,
VolumeSource volumeSource, const StreamTypeVector &streams,
- audio_devices_t device,
+ const DeviceTypeSet& deviceTypes,
uint32_t delayMs,
bool force);
@@ -329,10 +330,10 @@
void setDevices(const DeviceVector &devices) { mDevices = devices; }
bool sharesHwModuleWith(const sp<SwAudioOutputDescriptor>& outputDesc);
virtual DeviceVector supportedDevices() const;
- virtual bool deviceSupportsEncodedFormats(audio_devices_t device);
+ virtual bool devicesSupportEncodedFormats(const DeviceTypeSet& deviceTypes);
virtual uint32_t latency();
virtual bool isDuplicated() const { return (mOutput1 != NULL && mOutput2 != NULL); }
- virtual bool isFixedVolume(audio_devices_t device);
+ virtual bool isFixedVolume(const DeviceTypeSet& deviceTypes);
sp<SwAudioOutputDescriptor> subOutput1() { return mOutput1; }
sp<SwAudioOutputDescriptor> subOutput2() { return mOutput2; }
void setClientActive(const sp<TrackClientDescriptor>& client, bool active) override;
@@ -344,7 +345,7 @@
}
virtual bool setVolume(float volumeDb,
VolumeSource volumeSource, const StreamTypeVector &streams,
- audio_devices_t device,
+ const DeviceTypeSet& device,
uint32_t delayMs,
bool force);
@@ -418,7 +419,7 @@
virtual bool setVolume(float volumeDb,
VolumeSource volumeSource, const StreamTypeVector &streams,
- audio_devices_t device,
+ const DeviceTypeSet& deviceTypes,
uint32_t delayMs,
bool force);
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index eb1bfa7..158215d 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -17,6 +17,7 @@
#pragma once
#include "PolicyAudioPort.h"
+#include <media/AudioContainers.h>
#include <media/DeviceDescriptorBase.h>
#include <utils/Errors.h>
#include <utils/String8.h>
@@ -93,7 +94,7 @@
class DeviceVector : public SortedVector<sp<DeviceDescriptor> >
{
public:
- DeviceVector() : SortedVector(), mDeviceTypes(AUDIO_DEVICE_NONE) {}
+ DeviceVector() : SortedVector() {}
explicit DeviceVector(const sp<DeviceDescriptor>& item) : DeviceVector()
{
add(item);
@@ -105,13 +106,16 @@
void remove(const DeviceVector &devices);
ssize_t indexOf(const sp<DeviceDescriptor>& item) const;
- audio_devices_t types() const { return mDeviceTypes; }
+ DeviceTypeSet types() const { return mDeviceTypes; }
// If 'address' is empty and 'codec' is AUDIO_FORMAT_DEFAULT, a device with a non-empty
// address may be returned if there is no device with the specified 'type' and empty address.
sp<DeviceDescriptor> getDevice(audio_devices_t type, const String8 &address,
audio_format_t codec) const;
- DeviceVector getDevicesFromTypeMask(audio_devices_t types) const;
+ DeviceVector getDevicesFromTypes(const DeviceTypeSet& types) const;
+ DeviceVector getDevicesFromType(audio_devices_t type) const {
+ return getDevicesFromTypes({type});
+ }
/**
* @brief getDeviceFromId
@@ -122,7 +126,6 @@
sp<DeviceDescriptor> getDeviceFromId(audio_port_handle_t id) const;
sp<DeviceDescriptor> getDeviceFromTagName(const std::string &tagName) const;
DeviceVector getDevicesFromHwModule(audio_module_handle_t moduleHandle) const;
- audio_devices_t getDeviceTypesFromHwModule(audio_module_handle_t moduleHandle) const;
DeviceVector getFirstDevicesFromTypes(std::vector<audio_devices_t> orderedTypes) const;
sp<DeviceDescriptor> getFirstExistingDevice(std::vector<audio_devices_t> orderedTypes) const;
@@ -131,6 +134,18 @@
// remove all the devices with the given type and add all the devices to add.
void replaceDevicesByType(audio_devices_t typeToRemove, const DeviceVector &devicesToAdd);
+ bool containsDeviceAmongTypes(const DeviceTypeSet& deviceTypes) const {
+ return !Intersection(mDeviceTypes, deviceTypes).empty();
+ }
+
+ bool containsDeviceWithType(audio_devices_t deviceType) const {
+ return containsDeviceAmongTypes({deviceType});
+ }
+
+ bool onlyContainsDevicesWithType(audio_devices_t deviceType) const {
+ return isSingleDeviceType(mDeviceTypes, deviceType);
+ }
+
bool contains(const sp<DeviceDescriptor>& item) const { return indexOf(item) >= 0; }
/**
@@ -223,7 +238,7 @@
private:
void refreshTypes();
- audio_devices_t mDeviceTypes;
+ DeviceTypeSet mDeviceTypes;
};
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/HwModule.h b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
index 028cb63..23f0c9a 100644
--- a/services/audiopolicy/common/managerdefinitions/include/HwModule.h
+++ b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
@@ -131,8 +131,8 @@
public:
sp<HwModule> getModuleFromName(const char *name) const;
- sp<HwModule> getModuleForDeviceTypes(audio_devices_t device,
- audio_format_t encodedFormat) const;
+ sp<HwModule> getModuleForDeviceType(audio_devices_t device,
+ audio_format_t encodedFormat) const;
sp<HwModule> getModuleForDevice(const sp<DeviceDescriptor> &device,
audio_format_t encodedFormat) const;
diff --git a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
index dcb4730..2044863 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
@@ -19,6 +19,7 @@
#include "DeviceDescriptor.h"
#include "PolicyAudioPort.h"
#include "policy.h"
+#include <media/AudioContainers.h>
#include <utils/String8.h>
#include <system/audio.h>
@@ -102,15 +103,12 @@
bool hasSupportedDevices() const { return !mSupportedDevices.isEmpty(); }
- bool supportsDeviceTypes(audio_devices_t device) const
+ bool supportsDeviceTypes(const DeviceTypeSet& deviceTypes) const
{
- if (audio_is_output_devices(device)) {
- if (deviceSupportsEncodedFormats(device)) {
- return mSupportedDevices.types() & device;
- }
- return false;
- }
- return mSupportedDevices.types() & (device & ~AUDIO_DEVICE_BIT_IN);
+ const bool areOutputDevices = Intersection(deviceTypes, getAudioDeviceInAllSet()).empty();
+ const bool devicesSupported = !mSupportedDevices.getDevicesFromTypes(deviceTypes).empty();
+ return devicesSupported &&
+ (!areOutputDevices || devicesSupportEncodedFormats(deviceTypes));
}
/**
@@ -125,18 +123,18 @@
bool supportsDevice(const sp<DeviceDescriptor> &device, bool forceCheckOnAddress = false) const
{
if (!device_distinguishes_on_address(device->type()) && !forceCheckOnAddress) {
- return supportsDeviceTypes(device->type());
+ return supportsDeviceTypes(DeviceTypeSet({device->type()}));
}
return mSupportedDevices.contains(device);
}
- bool deviceSupportsEncodedFormats(audio_devices_t device) const
+ bool devicesSupportEncodedFormats(DeviceTypeSet deviceTypes) const
{
- if (device == AUDIO_DEVICE_NONE) {
+ if (deviceTypes.empty()) {
return true; // required for isOffloadSupported() check
}
DeviceVector deviceList =
- mSupportedDevices.getDevicesFromTypeMask(device);
+ mSupportedDevices.getDevicesFromTypes(deviceTypes);
if (!deviceList.empty()) {
return deviceList.itemAt(0)->hasCurrentEncodedFormat();
}
diff --git a/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h b/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h
index d408446..fd8b81a 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h
@@ -16,8 +16,9 @@
#pragma once
-#include <system/audio.h>
#include <Volume.h>
+#include <media/AudioContainers.h>
+#include <system/audio.h>
#include <utils/Errors.h>
#include <utils/String8.h>
#include <vector>
@@ -33,7 +34,7 @@
virtual void addCurrentVolumeIndex(audio_devices_t device, int index) = 0;
virtual bool canBeMuted() const = 0;
virtual int getVolumeIndexMin() const = 0;
- virtual int getVolumeIndex(audio_devices_t device) const = 0;
+ virtual int getVolumeIndex(const DeviceTypeSet& device) const = 0;
virtual int getVolumeIndexMax() const = 0;
virtual float volIndexToDb(device_category device, int indexInUi) const = 0;
virtual bool hasVolumeIndexForDevice(audio_devices_t device) const = 0;
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 00000fe..4ff69ee 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -30,10 +30,11 @@
// A device mask for all audio output devices that are considered "remote" when evaluating
// active output devices in isStreamActiveRemotely()
-#define APM_AUDIO_OUT_DEVICE_REMOTE_ALL AUDIO_DEVICE_OUT_REMOTE_SUBMIX
namespace android {
+DeviceTypeSet APM_AUDIO_OUT_DEVICE_REMOTE_ALL = {AUDIO_DEVICE_OUT_REMOTE_SUBMIX};
+
AudioOutputDescriptor::AudioOutputDescriptor(const sp<PolicyAudioPort>& policyAudioPort,
AudioPolicyClientInterface *clientInterface)
: mPolicyAudioPort(policyAudioPort), mClientInterface(clientInterface)
@@ -140,7 +141,7 @@
return false;
}
-bool AudioOutputDescriptor::isFixedVolume(audio_devices_t device __unused)
+bool AudioOutputDescriptor::isFixedVolume(const DeviceTypeSet& deviceTypes __unused)
{
return false;
}
@@ -148,7 +149,7 @@
bool AudioOutputDescriptor::setVolume(float volumeDb,
VolumeSource volumeSource,
const StreamTypeVector &/*streams*/,
- audio_devices_t /*device*/,
+ const DeviceTypeSet& /*deviceTypes*/,
uint32_t delayMs,
bool force)
{
@@ -334,13 +335,13 @@
return filteredDevices.filter(devices);
}
-bool SwAudioOutputDescriptor::deviceSupportsEncodedFormats(audio_devices_t device)
+bool SwAudioOutputDescriptor::devicesSupportEncodedFormats(const DeviceTypeSet& deviceTypes)
{
if (isDuplicated()) {
- return (mOutput1->deviceSupportsEncodedFormats(device)
- || mOutput2->deviceSupportsEncodedFormats(device));
+ return (mOutput1->devicesSupportEncodedFormats(deviceTypes)
+ || mOutput2->devicesSupportEncodedFormats(deviceTypes));
} else {
- return mProfile->deviceSupportsEncodedFormats(device);
+ return mProfile->devicesSupportEncodedFormats(deviceTypes);
}
}
@@ -363,16 +364,16 @@
AudioOutputDescriptor::setClientActive(client, active);
}
-bool SwAudioOutputDescriptor::isFixedVolume(audio_devices_t device)
+bool SwAudioOutputDescriptor::isFixedVolume(const DeviceTypeSet& deviceTypes)
{
// unit gain if rerouting to external policy
- if (device == AUDIO_DEVICE_OUT_REMOTE_SUBMIX) {
+ if (isSingleDeviceType(deviceTypes, AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) {
if (mPolicyMix != NULL) {
ALOGV("max gain when rerouting for output=%d", mIoHandle);
return true;
}
}
- if (device == AUDIO_DEVICE_OUT_TELEPHONY_TX) {
+ if (isSingleDeviceType(deviceTypes, AUDIO_DEVICE_OUT_TELEPHONY_TX)) {
ALOGV("max gain when output device is telephony tx");
return true;
}
@@ -405,12 +406,12 @@
bool SwAudioOutputDescriptor::setVolume(float volumeDb,
VolumeSource vs, const StreamTypeVector &streamTypes,
- audio_devices_t device,
+ const DeviceTypeSet& deviceTypes,
uint32_t delayMs,
bool force)
{
StreamTypeVector streams = streamTypes;
- if (!AudioOutputDescriptor::setVolume(volumeDb, vs, streamTypes, device, delayMs, force)) {
+ if (!AudioOutputDescriptor::setVolume(volumeDb, vs, streamTypes, deviceTypes, delayMs, force)) {
return false;
}
if (streams.empty()) {
@@ -420,7 +421,7 @@
// APM loops on all group, so filter on active group to set the port gain,
// let the other groups set the stream volume as per legacy
// TODO: Pass in the device address and check against it.
- if (device == devicePort->type() &&
+ if (isSingleDeviceType(deviceTypes, devicePort->type()) &&
devicePort->hasGainController(true) && isActive(vs)) {
ALOGV("%s: device %s has gain controller", __func__, devicePort->toString().c_str());
// @todo: here we might be in trouble if the SwOutput has several active clients with
@@ -467,7 +468,7 @@
{
mDevices = devices;
const String8& address = devices.getFirstValidAddress();
- audio_devices_t device = devices.types();
+ DeviceTypeSet deviceTypes = devices.types();
audio_config_t lConfig;
if (config == nullptr) {
@@ -499,21 +500,25 @@
ALOGV("opening output for device %s profile %p name %s",
mDevices.toString().c_str(), mProfile.get(), mProfile->getName().c_str());
+ // FIXME: Stop using device types as bit mask when the interface updated.
+ audio_devices_t deviceType = deviceTypesToBitMask(deviceTypes);
status_t status = mClientInterface->openOutput(mProfile->getModuleHandle(),
output,
&lConfig,
- &device,
+ &deviceType,
address,
&mLatency,
mFlags);
- LOG_ALWAYS_FATAL_IF(mDevices.types() != device,
- "%s openOutput returned device %08x when given device %08x",
- __FUNCTION__, mDevices.types(), device);
+ deviceTypes = deviceTypesFromBitMask(deviceType);
+ LOG_ALWAYS_FATAL_IF(mDevices.types() != deviceTypes,
+ "%s openOutput returned device %s when given device %s",
+ __FUNCTION__, dumpDeviceTypes(mDevices.types()).c_str(),
+ dumpDeviceTypes(deviceTypes).c_str());
if (status == NO_ERROR) {
LOG_ALWAYS_FATAL_IF(*output == AUDIO_IO_HANDLE_NONE,
- "%s openOutput returned output handle %d for device %08x",
- __FUNCTION__, *output, device);
+ "%s openOutput returned output handle %d for device %s",
+ __FUNCTION__, *output, dumpDeviceTypes(deviceTypes).c_str());
mSamplingRate = lConfig.sample_rate;
mChannelMask = lConfig.channel_mask;
mFormat = lConfig.format;
@@ -646,12 +651,12 @@
bool HwAudioOutputDescriptor::setVolume(float volumeDb,
VolumeSource volumeSource, const StreamTypeVector &streams,
- audio_devices_t device,
+ const DeviceTypeSet& deviceTypes,
uint32_t delayMs,
bool force)
{
- bool changed =
- AudioOutputDescriptor::setVolume(volumeDb, volumeSource, streams, device, delayMs, force);
+ bool changed = AudioOutputDescriptor::setVolume(
+ volumeDb, volumeSource, streams, deviceTypes, delayMs, force);
if (changed) {
// TODO: use gain controller on source device if any to adjust volume
@@ -678,7 +683,8 @@
for (size_t i = 0; i < this->size(); i++) {
const sp<SwAudioOutputDescriptor> outputDesc = this->valueAt(i);
if (outputDesc->isActive(volumeSource, inPastMs, sysTime)
- && ((outputDesc->devices().types() & APM_AUDIO_OUT_DEVICE_REMOTE_ALL) == 0)) {
+ && (!(outputDesc->devices()
+ .containsDeviceAmongTypes(APM_AUDIO_OUT_DEVICE_REMOTE_ALL)))) {
return true;
}
}
@@ -690,7 +696,7 @@
nsecs_t sysTime = systemTime();
for (size_t i = 0; i < size(); i++) {
const sp<SwAudioOutputDescriptor> outputDesc = valueAt(i);
- if (((outputDesc->devices().types() & APM_AUDIO_OUT_DEVICE_REMOTE_ALL) != 0) &&
+ if (outputDesc->devices().containsDeviceAmongTypes(APM_AUDIO_OUT_DEVICE_REMOTE_ALL) &&
outputDesc->isActive(volumeSource, inPastMs, sysTime)) {
// do not consider re routing (when the output is going to a dynamic policy)
// as "remote playback"
@@ -721,9 +727,8 @@
for (size_t i = 0; i < size(); i++) {
sp<SwAudioOutputDescriptor> outputDesc = valueAt(i);
if (!outputDesc->isDuplicated() &&
- outputDesc->devices().types() & AUDIO_DEVICE_OUT_ALL_A2DP &&
- outputDesc->deviceSupportsEncodedFormats(
- AUDIO_DEVICE_OUT_BLUETOOTH_A2DP)) {
+ outputDesc->devices().containsDeviceAmongTypes(getAudioDeviceOutAllA2dpSet()) &&
+ outputDesc->devicesSupportEncodedFormats(getAudioDeviceOutAllA2dpSet())) {
return this->keyAt(i);
}
}
@@ -739,7 +744,7 @@
sp<HwModule> primaryHwModule = primaryOutput->mProfile->getModule();
for (const auto &outputProfile : primaryHwModule->getOutputProfiles()) {
- if (outputProfile->supportsDeviceTypes(AUDIO_DEVICE_OUT_ALL_A2DP)) {
+ if (outputProfile->supportsDeviceTypes(getAudioDeviceOutAllA2dpSet())) {
return true;
}
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index 3d3eb9c..4e8c01c 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -164,11 +164,11 @@
void DeviceVector::refreshTypes()
{
- mDeviceTypes = AUDIO_DEVICE_NONE;
+ mDeviceTypes.clear();
for (size_t i = 0; i < size(); i++) {
- mDeviceTypes |= itemAt(i)->type();
+ mDeviceTypes.insert(itemAt(i)->type());
}
- ALOGV("DeviceVector::refreshTypes() mDeviceTypes %08x", mDeviceTypes);
+ ALOGV("DeviceVector::refreshTypes() mDeviceTypes %s", dumpDeviceTypes(mDeviceTypes).c_str());
}
ssize_t DeviceVector::indexOf(const sp<DeviceDescriptor>& item) const
@@ -243,17 +243,6 @@
return devices;
}
-audio_devices_t DeviceVector::getDeviceTypesFromHwModule(audio_module_handle_t moduleHandle) const
-{
- audio_devices_t deviceTypes = AUDIO_DEVICE_NONE;
- for (const auto& device : *this) {
- if (device->getModuleHandle() == moduleHandle) {
- deviceTypes |= device->type();
- }
- }
- return deviceTypes;
-}
-
sp<DeviceDescriptor> DeviceVector::getDevice(audio_devices_t type, const String8& address,
audio_format_t format) const
{
@@ -290,15 +279,14 @@
return nullptr;
}
-DeviceVector DeviceVector::getDevicesFromTypeMask(audio_devices_t type) const
+DeviceVector DeviceVector::getDevicesFromTypes(const DeviceTypeSet& types) const
{
DeviceVector devices;
- bool isOutput = audio_is_output_devices(type);
- type &= ~AUDIO_DEVICE_BIT_IN;
- for (size_t i = 0; (i < size()) && (type != AUDIO_DEVICE_NONE); i++) {
- bool curIsOutput = audio_is_output_devices(itemAt(i)->type());
- audio_devices_t curType = itemAt(i)->type() & ~AUDIO_DEVICE_BIT_IN;
- if ((isOutput == curIsOutput) && ((type & curType) != 0)) {
+ if (types.empty()) {
+ return devices;
+ }
+ for (size_t i = 0; i < size(); i++) {
+ if (types.count(itemAt(i)->type()) != 0) {
devices.add(itemAt(i));
ALOGV("DeviceVector::%s() for type %08x found %p",
__func__, itemAt(i)->type(), itemAt(i).get());
@@ -322,7 +310,7 @@
{
DeviceVector devices;
for (auto deviceType : orderedTypes) {
- if (!(devices = getDevicesFromTypeMask(deviceType)).isEmpty()) {
+ if (!(devices = getDevicesFromType(deviceType)).isEmpty()) {
break;
}
}
@@ -342,7 +330,7 @@
void DeviceVector::replaceDevicesByType(
audio_devices_t typeToRemove, const DeviceVector &devicesToAdd) {
- DeviceVector devicesToRemove = getDevicesFromTypeMask(typeToRemove);
+ DeviceVector devicesToRemove = getDevicesFromType(typeToRemove);
if (!devicesToRemove.isEmpty() && !devicesToAdd.isEmpty()) {
remove(devicesToRemove);
add(devicesToAdd);
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index 453006a..0b4d3d4 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -273,14 +273,14 @@
return nullptr;
}
-sp <HwModule> HwModuleCollection::getModuleForDeviceTypes(audio_devices_t type,
- audio_format_t encodedFormat) const
+sp <HwModule> HwModuleCollection::getModuleForDeviceType(audio_devices_t type,
+ audio_format_t encodedFormat) const
{
for (const auto& module : *this) {
const auto& profiles = audio_is_output_device(type) ?
module->getOutputProfiles() : module->getInputProfiles();
for (const auto& profile : profiles) {
- if (profile->supportsDeviceTypes(type)) {
+ if (profile->supportsDeviceTypes({type})) {
if (encodedFormat != AUDIO_FORMAT_DEFAULT) {
DeviceVector declaredDevices = module->getDeclaredDevices();
sp <DeviceDescriptor> deviceDesc =
@@ -300,7 +300,7 @@
sp<HwModule> HwModuleCollection::getModuleForDevice(const sp<DeviceDescriptor> &device,
audio_format_t encodedFormat) const
{
- return getModuleForDeviceTypes(device->type(), encodedFormat);
+ return getModuleForDeviceType(device->type(), encodedFormat);
}
DeviceVector HwModuleCollection::getAvailableDevicesFromModuleName(
@@ -354,7 +354,7 @@
const char *name,
const audio_format_t encodedFormat) const
{
- sp<HwModule> hwModule = getModuleForDeviceTypes(type, encodedFormat);
+ sp<HwModule> hwModule = getModuleForDeviceType(type, encodedFormat);
if (hwModule == 0) {
ALOGE("%s: could not find HW module for device %04x address %s", __FUNCTION__, type,
address);
diff --git a/services/audiopolicy/config/Android.bp b/services/audiopolicy/config/Android.bp
new file mode 100644
index 0000000..4b5e788
--- /dev/null
+++ b/services/audiopolicy/config/Android.bp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+soong_namespace {
+}
+
+prebuilt_etc {
+ name: "a2dp_in_audio_policy_configuration.xml",
+ vendor: true,
+ src: ":a2dp_in_audio_policy_configuration",
+}
+prebuilt_etc {
+ name: "a2dp_audio_policy_configuration.xml",
+ vendor: true,
+ src: ":a2dp_audio_policy_configuration",
+}
+prebuilt_etc {
+ name: "audio_policy_configuration.xml",
+ vendor: true,
+ src: ":audio_policy_configuration_generic",
+}
+prebuilt_etc {
+ name: "r_submix_audio_policy_configuration.xml",
+ vendor: true,
+ src: ":r_submix_audio_policy_configuration",
+}
+prebuilt_etc {
+ name: "audio_policy_volumes.xml",
+ vendor: true,
+ src: ":audio_policy_volumes",
+}
+prebuilt_etc {
+ name: "default_volume_tables.xml",
+ vendor: true,
+ src: ":default_volume_tables",
+}
+prebuilt_etc {
+ name: "surround_sound_configuration_5_0.xml",
+ vendor: true,
+ src: ":surround_sound_configuration_5_0",
+}
+prebuilt_etc {
+ name: "usb_audio_policy_configuration.xml",
+ vendor: true,
+ src: ":usb_audio_policy_configuration",
+}
+prebuilt_etc {
+ name: "primary_audio_policy_configuration.xml",
+ src: ":primary_audio_policy_configuration",
+ vendor: true,
+}
+
+filegroup {
+ name: "a2dp_in_audio_policy_configuration",
+ srcs: ["a2dp_in_audio_policy_configuration.xml"],
+}
+filegroup {
+ name: "a2dp_audio_policy_configuration",
+ srcs: ["a2dp_audio_policy_configuration.xml"],
+}
+filegroup {
+ name: "primary_audio_policy_configuration",
+ srcs: ["primary_audio_policy_configuration.xml"],
+}
+filegroup {
+ name: "surround_sound_configuration_5_0",
+ srcs: ["surround_sound_configuration_5_0.xml"],
+}
+filegroup {
+ name: "default_volume_tables",
+ srcs: ["default_volume_tables.xml"],
+}
+filegroup {
+ name: "audio_policy_volumes",
+ srcs: ["audio_policy_volumes.xml"],
+}
+filegroup {
+ name: "audio_policy_configuration_generic",
+ srcs: ["audio_policy_configuration_generic.xml"],
+}
+filegroup {
+ name: "usb_audio_policy_configuration",
+ srcs: ["usb_audio_policy_configuration.xml"],
+}
+filegroup {
+ name: "r_submix_audio_policy_configuration",
+ srcs: ["r_submix_audio_policy_configuration.xml"],
+}
diff --git a/services/audiopolicy/engine/common/Android.bp b/services/audiopolicy/engine/common/Android.bp
index d0775ad..b87c71d 100644
--- a/services/audiopolicy/engine/common/Android.bp
+++ b/services/audiopolicy/engine/common/Android.bp
@@ -44,4 +44,7 @@
"libaudiopolicycomponents",
"libaudiopolicyengine_config",
],
+ shared_libs: [
+ "libaudiofoundation",
+ ],
}
diff --git a/services/audiopolicy/engine/common/include/ProductStrategy.h b/services/audiopolicy/engine/common/include/ProductStrategy.h
index c538f52..ab8eff3 100644
--- a/services/audiopolicy/engine/common/include/ProductStrategy.h
+++ b/services/audiopolicy/engine/common/include/ProductStrategy.h
@@ -27,6 +27,7 @@
#include <utils/Errors.h>
#include <utils/String8.h>
#include <media/AudioAttributes.h>
+#include <media/AudioContainers.h>
namespace android {
@@ -77,12 +78,12 @@
std::string getDeviceAddress() const { return mDeviceAddress; }
- void setDeviceTypes(audio_devices_t devices)
+ void setDeviceTypes(const DeviceTypeSet& devices)
{
mApplicableDevices = devices;
}
- audio_devices_t getDeviceTypes() const { return mApplicableDevices; }
+ DeviceTypeSet getDeviceTypes() const { return mApplicableDevices; }
audio_attributes_t getAttributesForStreamType(audio_stream_type_t stream) const;
audio_stream_type_t getStreamTypeForAttributes(const audio_attributes_t &attr) const;
@@ -109,7 +110,7 @@
/**
* Applicable device(s) type mask for this strategy.
*/
- audio_devices_t mApplicableDevices = AUDIO_DEVICE_NONE;
+ DeviceTypeSet mApplicableDevices;
};
class ProductStrategyMap : public std::map<product_strategy_t, sp<ProductStrategy> >
@@ -144,7 +145,7 @@
*/
audio_attributes_t getAttributesForProductStrategy(product_strategy_t strategy) const;
- audio_devices_t getDeviceTypesForProductStrategy(product_strategy_t strategy) const;
+ DeviceTypeSet getDeviceTypesForProductStrategy(product_strategy_t strategy) const;
std::string getDeviceAddressForProductStrategy(product_strategy_t strategy) const;
diff --git a/services/audiopolicy/engine/common/include/VolumeCurve.h b/services/audiopolicy/engine/common/include/VolumeCurve.h
index d3d0904..2e75ff1 100644
--- a/services/audiopolicy/engine/common/include/VolumeCurve.h
+++ b/services/audiopolicy/engine/common/include/VolumeCurve.h
@@ -91,9 +91,9 @@
return valueFor(device);
}
- virtual int getVolumeIndex(audio_devices_t device) const
+ virtual int getVolumeIndex(const DeviceTypeSet& deviceTypes) const
{
- device = Volume::getDeviceForVolume(device);
+ audio_devices_t device = Volume::getDeviceForVolume(deviceTypes);
// there is always a valid entry for AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME
if (mIndexCur.find(device) == end(mIndexCur)) {
device = AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME;
@@ -114,7 +114,7 @@
bool hasVolumeIndexForDevice(audio_devices_t device) const
{
- device = Volume::getDeviceForVolume(device);
+ device = Volume::getDeviceForVolume({device});
return mIndexCur.find(device) != end(mIndexCur);
}
diff --git a/services/audiopolicy/engine/common/src/EngineBase.cpp b/services/audiopolicy/engine/common/src/EngineBase.cpp
index 07a7e65..840eb34 100644
--- a/services/audiopolicy/engine/common/src/EngineBase.cpp
+++ b/services/audiopolicy/engine/common/src/EngineBase.cpp
@@ -39,7 +39,7 @@
{
ALOGV("setPhoneState() state %d", state);
- if (state < 0 || state >= AUDIO_MODE_CNT) {
+ if (state < 0 || uint32_t(state) >= AUDIO_MODE_CNT) {
ALOGW("setPhoneState() invalid state %d", state);
return BAD_VALUE;
}
diff --git a/services/audiopolicy/engine/common/src/ProductStrategy.cpp b/services/audiopolicy/engine/common/src/ProductStrategy.cpp
index ac3e462..14c9dd1 100644
--- a/services/audiopolicy/engine/common/src/ProductStrategy.cpp
+++ b/services/audiopolicy/engine/common/src/ProductStrategy.cpp
@@ -143,8 +143,9 @@
{
dst->appendFormat("\n%*s-%s (id: %d)\n", spaces, "", mName.c_str(), mId);
std::string deviceLiteral;
- if (!OutputDeviceConverter::toString(mApplicableDevices, deviceLiteral)) {
- ALOGE("%s: failed to convert device %d", __FUNCTION__, mApplicableDevices);
+ if (!deviceTypesToString(mApplicableDevices, deviceLiteral)) {
+ ALOGE("%s: failed to convert device %s",
+ __FUNCTION__, dumpDeviceTypes(mApplicableDevices).c_str());
}
dst->appendFormat("%*sSelected Device: {type:%s, @:%s}\n", spaces + 2, "",
deviceLiteral.c_str(), mDeviceAddress.c_str());
@@ -236,14 +237,14 @@
}
-audio_devices_t ProductStrategyMap::getDeviceTypesForProductStrategy(
+DeviceTypeSet ProductStrategyMap::getDeviceTypesForProductStrategy(
product_strategy_t strategy) const
{
if (find(strategy) == end()) {
ALOGE("Invalid %d strategy requested, returning device for default strategy", strategy);
product_strategy_t defaultStrategy = getDefault();
if (defaultStrategy == PRODUCT_STRATEGY_NONE) {
- return AUDIO_DEVICE_NONE;
+ return {AUDIO_DEVICE_NONE};
}
return at(getDefault())->getDeviceTypes();
}
diff --git a/services/audiopolicy/engineconfigurable/config/Android.bp b/services/audiopolicy/engineconfigurable/config/Android.bp
new file mode 100644
index 0000000..fe3eae0
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/config/Android.bp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// Root soong_namespace for common components
+
+prebuilt_etc {
+ name: "audio_policy_engine_criteria.xml",
+ vendor: true,
+ src: ":audio_policy_engine_criteria",
+}
+filegroup {
+ name: "audio_policy_engine_criterion_types_template",
+ srcs: ["example/common/audio_policy_engine_criterion_types.xml.in"],
+}
+filegroup {
+ name: "audio_policy_engine_criteria",
+ srcs: ["example/common/audio_policy_engine_criteria.xml"],
+}
diff --git a/services/audiopolicy/engineconfigurable/config/example/Android.mk b/services/audiopolicy/engineconfigurable/config/example/Android.mk
deleted file mode 100644
index a0f1a90..0000000
--- a/services/audiopolicy/engineconfigurable/config/example/Android.mk
+++ /dev/null
@@ -1,151 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-ifdef BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION
-
-TOOLS := frameworks/av/services/audiopolicy/engineconfigurable/tools
-PROVISION_CRITERION_TYPES := $(TOOLS)/provision_criterion_types_from_android_headers.mk
-
-##################################################################
-# CONFIGURATION TOP FILE
-##################################################################
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), phone_configurable)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_configuration.xml
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
-
-LOCAL_REQUIRED_MODULES := \
- audio_policy_engine_product_strategies.xml \
- audio_policy_engine_stream_volumes.xml \
- audio_policy_engine_default_stream_volumes.xml \
- audio_policy_engine_criteria.xml \
- audio_policy_engine_criterion_types.xml
-
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_product_strategies.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_stream_volumes.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_default_stream_volumes.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-endif # ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), phone_configurable)
-
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),automotive_configurable caremu_configurable))
-
-##################################################################
-# AUTOMOTIVE CONFIGURATION TOP FILE
-##################################################################
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_configuration.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := automotive/$(LOCAL_MODULE)
-
-LOCAL_REQUIRED_MODULES := \
- audio_policy_engine_product_strategies.xml \
- audio_policy_engine_criteria.xml \
- audio_policy_engine_criterion_types.xml \
- audio_policy_engine_volumes.xml
-
-include $(BUILD_PREBUILT)
-
-endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),automotive_configurable caremu_configurable))
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), automotive_configurable)
-
-##################################################################
-# CONFIGURATION FILES
-##################################################################
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_product_strategies.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := automotive/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_volumes.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := automotive/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), automotive_configurable)
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), caremu_configurable)
-
-##################################################################
-# CONFIGURATION FILES
-##################################################################
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_product_strategies.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := caremu/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_volumes.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := caremu/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), caremu_configurable)
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable caremu_configurable))
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_criteria.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := common/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_criterion_types.xml
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_VENDOR_ETC)/primary_audio_policy_configuration.xml
-ANDROID_AUDIO_BASE_HEADER_FILE := system/media/audio/include/system/audio-base.h
-AUDIO_POLICY_CONFIGURATION_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_configuration.xml
-CRITERION_TYPES_FILE := $(LOCAL_PATH)/common/$(LOCAL_MODULE).in
-
-include $(PROVISION_CRITERION_TYPES)
-
-endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable caremu_configurable))
-
-endif #ifdef BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION
diff --git a/services/audiopolicy/engineconfigurable/config/example/automotive/Android.bp b/services/audiopolicy/engineconfigurable/config/example/automotive/Android.bp
new file mode 100644
index 0000000..f913a14
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/config/example/automotive/Android.bp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// Import this namespace in order to use AOSP Automotive configuration example
+
+soong_namespace {
+ imports: [
+ "frameworks/av/services/audiopolicy/config",
+ ],
+}
+
+prebuilt_etc {
+ name: "audio_policy_engine_configuration.xml",
+ vendor: true,
+ src: ":audio_policy_engine_configuration",
+ required: [
+ ":audio_policy_engine_criterion_types.xml",
+ ":audio_policy_engine_criteria.xml",
+ ":audio_policy_engine_product_strategies.xml",
+ ":audio_policy_engine_volumes.xml",
+ ],
+}
+prebuilt_etc {
+ name: "audio_policy_engine_product_strategies.xml",
+ vendor: true,
+ src: "audio_policy_engine_product_strategies.xml",
+}
+prebuilt_etc {
+ name: "audio_policy_engine_volumes.xml",
+ vendor: true,
+ src: ":audio_policy_engine_volumes",
+}
+prebuilt_etc {
+ name: "audio_policy_engine_criterion_types.xml",
+ vendor: true,
+ src: ":audio_policy_engine_criterion_types",
+}
+
+//
+// Generate audio_policy_engine criterion type file => provides device addresses criterion type
+//
+genrule {
+ name: "audio_policy_engine_criterion_types",
+ defaults: ["buildpolicycriteriontypesrule"],
+ srcs: [
+ ":audio_policy_configuration_top_file",
+ ":audio_policy_configuration_files",
+ ],
+}
+filegroup {
+ name: "audio_policy_configuration_files",
+ srcs: [
+ ":r_submix_audio_policy_configuration",
+ ":default_volume_tables",
+ ":audio_policy_volumes",
+ ":surround_sound_configuration_5_0",
+ ":primary_audio_policy_configuration",
+ ],
+}
+filegroup {
+ name : "audio_policy_configuration_top_file",
+ srcs: [":audio_policy_configuration_generic"],
+}
+filegroup {
+ name: "audio_policy_engine_configuration",
+ srcs: ["audio_policy_engine_configuration.xml"],
+}
+filegroup {
+ name: "audio_policy_engine_volumes",
+ srcs: ["audio_policy_engine_volumes.xml"],
+}
+filegroup {
+ name: "audio_policy_engine_configuration_files",
+ srcs: [
+ ":audio_policy_engine_configuration",
+ "audio_policy_engine_product_strategies.xml",
+ ":audio_policy_engine_volumes",
+ ":audio_policy_engine_criterion_types",
+ ":audio_policy_engine_criteria",
+ ],
+}
diff --git a/services/audiopolicy/engineconfigurable/config/example/caremu/Android.bp b/services/audiopolicy/engineconfigurable/config/example/caremu/Android.bp
new file mode 100644
index 0000000..fae6b7b
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/config/example/caremu/Android.bp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// Import this namespace in order to use AOSP Car Emulator configuration example
+
+soong_namespace {
+ imports: [
+ "frameworks/av/services/audiopolicy/engineconfigurable/config/example/automotive",
+ "frameworks/av/services/audiopolicy/config",
+ ],
+}
+
+prebuilt_etc {
+ name: "audio_policy_engine_configuration.xml",
+ vendor: true,
+ src: ":audio_policy_engine_configuration",
+ required: [
+ "audio_policy_engine_criterion_types.xml",
+ "audio_policy_engine_criteria.xml",
+ "audio_policy_engine_product_strategies.xml",
+ ":audio_policy_engine_volumes.xml",
+ ],
+}
+prebuilt_etc {
+ name: "audio_policy_engine_product_strategies.xml",
+ vendor: true,
+ src: "audio_policy_engine_product_strategies.xml",
+}
+prebuilt_etc {
+ name: "audio_policy_engine_criterion_types.xml",
+ vendor: true,
+ src: ":audio_policy_engine_criterion_types",
+}
+
+//
+// Generate audio_policy_engine criterion type file => provides device addresses criterion type
+//
+genrule {
+ name: "audio_policy_engine_criterion_types",
+ defaults: ["buildpolicycriteriontypesrule"],
+ srcs: [
+ ":audio_policy_configuration_top_file",
+ ":audio_policy_configuration_files",
+ ],
+}
+filegroup {
+ name: "audio_policy_configuration_files",
+ srcs: [
+ ":r_submix_audio_policy_configuration",
+ ":default_volume_tables",
+ ":audio_policy_volumes",
+ ":surround_sound_configuration_5_0",
+ ":primary_audio_policy_configuration",
+ ],
+}
+filegroup {
+ name : "audio_policy_configuration_top_file",
+ srcs: [":audio_policy_configuration_generic"],
+}
+filegroup {
+ name: "audio_policy_engine_configuration_files",
+ srcs: [
+ ":audio_policy_engine_configuration",
+ "audio_policy_engine_product_strategies.xml",
+ ":audio_policy_engine_volumes",
+ ":audio_policy_engine_criterion_types",
+ ":audio_policy_engine_criteria",
+ ],
+}
diff --git a/services/audiopolicy/engineconfigurable/config/example/phone/Android.bp b/services/audiopolicy/engineconfigurable/config/example/phone/Android.bp
new file mode 100644
index 0000000..94d33bd
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/config/example/phone/Android.bp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// Import this namespace in order to use AOSP Phone configuration example
+
+soong_namespace {
+ imports: [
+ "frameworks/av/services/audiopolicy/config",
+ ],
+}
+
+prebuilt_etc {
+ name: "audio_policy_engine_configuration.xml",
+ vendor: true,
+ src: ":audio_policy_engine_configuration",
+ required: [
+ ":audio_policy_engine_criterion_types.xml",
+ ":audio_policy_engine_criteria.xml",
+ ":audio_policy_engine_product_strategies.xml",
+ ":audio_policy_engine_volumes.xml",
+ ],
+}
+prebuilt_etc {
+ name: "audio_policy_engine_product_strategies.xml",
+ vendor: true,
+ src: "audio_policy_engine_product_strategies.xml",
+}
+prebuilt_etc {
+ name: "audio_policy_engine_stream_volumes.xml",
+ vendor: true,
+ src: ":audio_policy_engine_stream_volumes",
+}
+prebuilt_etc {
+ name: "audio_policy_engine_default_stream_volumes.xml",
+ vendor: true,
+ src: ":audio_policy_engine_default_stream_volumes",
+}
+prebuilt_etc {
+ name: "audio_policy_engine_criterion_types.xml",
+ vendor: true,
+ src: ":audio_policy_engine_criterion_types",
+}
+
+//
+// Generate audio_policy_engine criterion type file => provides device addresses criterion type
+//
+genrule {
+ name: "audio_policy_engine_criterion_types",
+ defaults: ["buildpolicycriteriontypesrule"],
+ srcs: [
+ ":audio_policy_configuration_top_file",
+ ":audio_policy_configuration_files",
+ ],
+}
+filegroup {
+ name: "audio_policy_configuration_files",
+ srcs: [
+ ":r_submix_audio_policy_configuration",
+ ":default_volume_tables",
+ ":audio_policy_volumes",
+ ":surround_sound_configuration_5_0",
+ ":primary_audio_policy_configuration",
+ ],
+}
+filegroup {
+ name : "audio_policy_configuration_top_file",
+ srcs: [":audio_policy_configuration_generic"],
+}
+filegroup {
+ name: "audio_policy_engine_configuration",
+ srcs: ["audio_policy_engine_configuration.xml"],
+}
+filegroup {
+ name: "audio_policy_engine_stream_volumes",
+ srcs: ["audio_policy_engine_stream_volumes.xml"],
+}
+filegroup {
+ name: "audio_policy_engine_default_stream_volumes",
+ srcs: ["audio_policy_engine_default_stream_volumes.xml"],
+}
+filegroup {
+ name: "audio_policy_engine_configuration_files",
+ srcs: [
+ ":audio_policy_engine_configuration",
+ "audio_policy_engine_product_strategies.xml",
+ ":audio_policy_engine_stream_volumes",
+ ":audio_policy_engine_default_stream_volumes",
+ ":audio_policy_engine_criterion_types",
+ ":audio_policy_engine_criteria",
+ ],
+}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/Android.bp
new file mode 100644
index 0000000..a0b874a
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/Android.bp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// Root soong_namespace for common components
+
+prebuilt_etc {
+ name: "PolicyClass.xml",
+ vendor: true,
+ src: ":PolicyClass",
+ sub_dir: "parameter-framework/Structure/Policy",
+}
+prebuilt_etc {
+ name: "PolicySubsystem.xml",
+ vendor: true,
+ src: ":PolicySubsystem",
+ sub_dir: "parameter-framework/Structure/Policy",
+}
+prebuilt_etc {
+ name: "PolicySubsystem-CommonTypes.xml",
+ vendor: true,
+ src: ":PolicySubsystem-CommonTypes",
+ sub_dir: "parameter-framework/Structure/Policy",
+}
+
+filegroup {
+ name: "product_strategies_structure_template",
+ srcs: ["examples/common/Structure/ProductStrategies.xml.in"],
+}
+filegroup {
+ name: "PolicySubsystem",
+ srcs: ["examples/common/Structure/PolicySubsystem.xml"],
+}
+filegroup {
+ name: "PolicySubsystem-no-strategy",
+ srcs: ["examples/common/Structure/PolicySubsystem-no-strategy.xml"],
+}
+filegroup {
+ name: "PolicySubsystem-CommonTypes",
+ srcs: ["examples/common/Structure/PolicySubsystem-CommonTypes.xml"],
+}
+filegroup {
+ name: "PolicyClass",
+ srcs: ["examples/common/Structure/PolicyClass.xml"],
+}
+filegroup {
+ name: "volumes.pfw",
+ srcs: ["examples/Settings/volumes.pfw"],
+}
+filegroup {
+ name: "device_for_input_source.pfw",
+ srcs: ["examples/Settings/device_for_input_source.pfw"],
+}
+filegroup {
+ name: "ParameterFrameworkConfigurationPolicy.userdebug.xml",
+ srcs: ["examples/ParameterFrameworkConfigurationPolicy.userdebug.xml"],
+}
+filegroup {
+ name: "ParameterFrameworkConfigurationPolicy.user.xml",
+ srcs: ["examples/ParameterFrameworkConfigurationPolicy.user.xml"],
+}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Android.mk
deleted file mode 100644
index 19f93b3..0000000
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Android.mk
+++ /dev/null
@@ -1,187 +0,0 @@
-################################################################################################
-#
-# @NOTE:
-# Audio Policy Engine configurable example for generic device build
-#
-# Any vendor shall have its own configuration within the corresponding device folder
-#
-################################################################################################
-
-LOCAL_PATH := $(call my-dir)
-
-ifdef BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable caremu_configurable no-output_configurable no-input_configurable))
-
-PFW_CORE := external/parameter-framework
-#@TODO: upstream new domain generator
-#BUILD_PFW_SETTINGS := $(PFW_CORE)/support/android/build_pfw_settings.mk
-PFW_DEFAULT_SCHEMAS_DIR := $(PFW_CORE)/upstream/schemas
-PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
-
-TOOLS := frameworks/av/services/audiopolicy/engineconfigurable/tools
-BUILD_PFW_SETTINGS := $(TOOLS)/build_audio_pfw_settings.mk
-
-PROVISION_STRATEGIES_STRUCTURE := $(TOOLS)/provision_strategies_structure.mk
-
-endif
-
-##################################################################
-# CONFIGURATION FILES
-##################################################################
-######### Policy PFW top level file #########
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable caremu_configurable))
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := ParameterFrameworkConfigurationPolicy.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework
-LOCAL_SRC_FILES := $(LOCAL_MODULE).in
-LOCAL_REQUIRED_MODULES := \
- PolicySubsystem.xml \
- PolicyClass.xml
-
-# external/parameter-framework prevents from using debug interface
-AUDIO_PATTERN = @TUNING_ALLOWED@
-ifeq ($(TARGET_BUILD_VARIANT),user)
-AUDIO_VALUE = false
-else
-AUDIO_VALUE = true
-endif
-
-LOCAL_POST_INSTALL_CMD := $(hide) sed -i -e 's|$(AUDIO_PATTERN)|$(AUDIO_VALUE)|g' $(TARGET_OUT_VENDOR_ETC)/$(LOCAL_MODULE_RELATIVE_PATH)/$(LOCAL_MODULE)
-
-include $(BUILD_PREBUILT)
-
-########## Policy PFW Common Structures #########
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := PolicySubsystem.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_REQUIRED_MODULES := \
- PolicySubsystem-CommonTypes.xml \
- ProductStrategies.xml
-
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
-LOCAL_SRC_FILES := common/Structure/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := PolicySubsystem-CommonTypes.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
-LOCAL_SRC_FILES := common/Structure/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := PolicyClass.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
-LOCAL_SRC_FILES := common/Structure/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := ProductStrategies.xml
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
-
-AUDIO_POLICY_ENGINE_CONFIGURATION_FILE := \
- $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_configuration.xml
-STRATEGIES_STRUCTURE_FILE := $(LOCAL_PATH)/common/Structure/$(LOCAL_MODULE).in
-
-include $(PROVISION_STRATEGIES_STRUCTURE)
-
-endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable caremu_configurable))
-
-########## Policy PFW Example Structures #########
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),no-output_configurable no-input_configurable))
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := PolicySubsystem.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_REQUIRED_MODULES := PolicySubsystem-CommonTypes.xml
-
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
-LOCAL_SRC_FILES := common/Structure/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := ParameterFrameworkConfigurationPolicy-no-strategy.xml
-LOCAL_MODULE_STEM := ParameterFrameworkConfigurationPolicy.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework
-LOCAL_SRC_FILES := $(LOCAL_MODULE).in
-LOCAL_REQUIRED_MODULES := \
- PolicySubsystem.xml \
- PolicyClass.xml
-AUDIO_VALUE = false
-LOCAL_POST_INSTALL_CMD := $(hide) sed -i -e 's|$(AUDIO_PATTERN)|$(AUDIO_VALUE)|g' $(TARGET_OUT_VENDOR_ETC)/$(LOCAL_MODULE_RELATIVE_PATH)/$(LOCAL_MODULE)
-
-include $(BUILD_PREBUILT)
-
-endif # ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),no-output_configurable no-input_configurable))
-
-######### Policy PFW Settings - No Output #########
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),no-output_configurable)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := parameter-framework.policy
-LOCAL_MODULE_STEM := PolicyConfigurableDomains-NoOutputDevice.xml
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Settings/Policy
-
-PFW_TOPLEVEL_FILE := $(TARGET_OUT_VENDOR_ETC)/parameter-framework/ParameterFrameworkConfigurationPolicy.xml
-PFW_CRITERION_TYPES_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criterion_types.xml
-PFW_CRITERIA_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criteria.xml
-PFW_EDD_FILES := \
- $(LOCAL_PATH)/SettingsNoOutput/device_for_strategies.pfw \
- $(LOCAL_PATH)/Settings/device_for_input_source.pfw \
- $(LOCAL_PATH)/Settings/volumes.pfw
-LOCAL_REQUIRED_MODULES := libpolicy-subsystem
-include $(BUILD_PFW_SETTINGS)
-
-endif # ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),no-output_configurable)
-######### Policy PFW Settings - No Input #########
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),no-input_configurable)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := parameter-framework.policy
-LOCAL_MODULE_STEM := PolicyConfigurableDomains-NoInputDevice.xml
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Settings/Policy
-
-PFW_TOPLEVEL_FILE := $(TARGET_OUT_VENDOR_ETC)/parameter-framework/ParameterFrameworkConfigurationPolicy.xml
-PFW_CRITERION_TYPES_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criterion_types.xml
-PFW_CRITERIA_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criteria.xml
-PFW_EDD_FILES := \
- $(LOCAL_PATH)/SettingsNoInput/device_for_input_source.pfw \
- $(LOCAL_PATH)/Settings/volumes.pfw
-LOCAL_REQUIRED_MODULES := libpolicy-subsystem
-include $(BUILD_PFW_SETTINGS)
-
-endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),no-input_configurable)
-#######################################################################
-# Recursive call sub-folder Android.mk
-#######################################################################
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
-
-endif #ifdef BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION
-
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.bp
new file mode 100644
index 0000000..5078268
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.bp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// Import this namespace in order to use AOSP Automotive configuration example
+
+soong_namespace {
+ imports: [
+ "frameworks/av/services/audiopolicy/engineconfigurable/config/example/automotive",
+ "frameworks/av/services/audiopolicy/config",
+ ],
+}
+
+//
+// Generate Audio Policy Parameter Framework Product Strategies Structure file from template
+//
+prebuilt_etc {
+ name: "ProductStrategies.xml",
+ vendor: true,
+ src: ":buildstrategiesstructure_gen",
+ sub_dir: "parameter-framework/Structure/Policy",
+ required: ["libpolicy-subsystem"],
+}
+genrule {
+ name: "buildstrategiesstructure_gen",
+ defaults: ["buildstrategiesstructurerule"],
+ srcs: [
+ ":audio_policy_engine_configuration_files",
+ ],
+}
+
+//
+// Generate Audio Policy Parameter Framework Configurable Domains
+//
+prebuilt_etc {
+ name: "parameter-framework.policy",
+ filename_from_src: true,
+ vendor: true,
+ src: ":domaingeneratorpolicyrule_gen",
+ sub_dir: "parameter-framework/Settings/Policy",
+ required: [
+ "ProductStrategies.xml",
+ "PolicyClass.xml",
+ "PolicySubsystem.xml",
+ "PolicySubsystem-CommonTypes.xml",
+ ],
+}
+genrule {
+ name: "domaingeneratorpolicyrule_gen",
+ defaults: ["domaingeneratorpolicyrule"],
+ srcs: [
+ ":audio_policy_pfw_toplevel",
+ ":audio_policy_pfw_structure_files",
+ ":audio_policy_engine_criterion_types",
+ ":edd_files",
+ ],
+}
+filegroup {
+ name: "edd_files",
+ srcs: [
+ ":device_for_input_source.pfw",
+ ":volumes.pfw",
+ "Settings/device_for_product_strategies.pfw",
+ ],
+}
+// This is for Settings generation, must use socket port, so userdebug version is required
+filegroup {
+ name: "audio_policy_pfw_toplevel",
+ srcs: [":ParameterFrameworkConfigurationPolicy.userdebug.xml"],
+}
+filegroup {
+ name: "audio_policy_pfw_structure_files",
+ srcs: [
+ ":PolicyClass",
+ ":PolicySubsystem",
+ ":PolicySubsystem-CommonTypes",
+ ":buildstrategiesstructure_gen",
+ ],
+}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.mk
deleted file mode 100644
index 7304ec2..0000000
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.mk
+++ /dev/null
@@ -1,47 +0,0 @@
-################################################################################################
-#
-# @NOTE:
-# Audio Policy Engine configurable example for generic device build
-#
-# Any vendor shall have its own configuration within the corresponding device folder
-#
-################################################################################################
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), automotive_configurable)
-LOCAL_PATH := $(call my-dir)
-
-PFW_CORE := external/parameter-framework
-PFW_DEFAULT_SCHEMAS_DIR := $(PFW_CORE)/upstream/schemas
-PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
-
-TOOLS := frameworks/av/services/audiopolicy/engineconfigurable/tools
-BUILD_PFW_SETTINGS := $(TOOLS)/build_audio_pfw_settings.mk
-
-
-##################################################################
-# CONFIGURATION FILES
-##################################################################
-
-########## Policy PFW Structures #########
-######### Policy PFW Settings #########
-include $(CLEAR_VARS)
-LOCAL_MODULE := parameter-framework.policy
-LOCAL_MODULE_STEM := PolicyConfigurableDomains.xml
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Settings/Policy
-LOCAL_REQUIRED_MODULES := libpolicy-subsystem
-
-PFW_EDD_FILES := \
- $(LOCAL_PATH)/Settings/device_for_product_strategies.pfw \
- $(LOCAL_PATH)/../Settings/device_for_input_source.pfw \
- $(LOCAL_PATH)/../Settings/volumes.pfw
-
-PFW_CRITERION_TYPES_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criterion_types.xml
-PFW_CRITERIA_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criteria.xml
-PFW_TOPLEVEL_FILE := $(TARGET_OUT_VENDOR_ETC)/parameter-framework/ParameterFrameworkConfigurationPolicy.xml
-PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
-
-include $(BUILD_PFW_SETTINGS)
-
-endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), automotive_configurable)
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.bp
new file mode 100644
index 0000000..0917440
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.bp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// Import this namespace in order to use AOSP Car Emulator configuration example
+
+soong_namespace {
+ imports: [
+ "frameworks/av/services/audiopolicy/engineconfigurable/config/example/caremu",
+ "frameworks/av/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car",
+ "frameworks/av/services/audiopolicy/config",
+ ],
+}
+
+//
+// Generate Audio Policy Parameter Framework Product Strategies Structure file from template
+//
+prebuilt_etc {
+ name: "ProductStrategies.xml",
+ vendor: true,
+ src: ":buildstrategiesstructure_gen",
+ sub_dir: "parameter-framework/Structure/Policy",
+ required: ["libpolicy-subsystem"],
+}
+genrule {
+ name: "buildstrategiesstructure_gen",
+ defaults: ["buildstrategiesstructurerule"],
+ srcs: [
+ ":audio_policy_engine_configuration_files",
+ ],
+}
+
+//
+// Generate Audio Policy Parameter Framework Configurable Domains
+//
+prebuilt_etc {
+ name: "parameter-framework.policy",
+ filename_from_src: true,
+ vendor: true,
+ src: ":domaingeneratorpolicyrule_gen",
+ sub_dir: "parameter-framework/Settings/Policy",
+ required: [
+ "ProductStrategies.xml",
+ "PolicyClass.xml",
+ "PolicySubsystem.xml",
+ "PolicySubsystem-CommonTypes.xml",
+ ],
+}
+genrule {
+ name: "domaingeneratorpolicyrule_gen",
+ defaults: ["domaingeneratorpolicyrule"],
+ srcs: [
+ ":audio_policy_pfw_toplevel",
+ ":audio_policy_pfw_structure_files",
+ ":audio_policy_engine_criterion_types",
+ ":edd_files",
+ ],
+}
+filegroup {
+ name: "edd_files",
+ srcs: [
+ ":device_for_input_source.pfw",
+ ":volumes.pfw",
+ "Settings/device_for_product_strategies.pfw",
+ ],
+}
+// This is for Settings generation, must use socket port, so userdebug version is required
+filegroup {
+ name: "audio_policy_pfw_toplevel",
+ srcs: [":ParameterFrameworkConfigurationPolicy.userdebug.xml"],
+}
+filegroup {
+ name: "audio_policy_pfw_structure_files",
+ srcs: [
+ ":PolicyClass",
+ ":PolicySubsystem",
+ ":PolicySubsystem-CommonTypes",
+ ":buildstrategiesstructure_gen",
+ ],
+}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.mk
deleted file mode 100644
index f5eb7d1..0000000
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.mk
+++ /dev/null
@@ -1,46 +0,0 @@
-################################################################################################
-#
-# @NOTE:
-# Audio Policy Engine configurable example for generic device build
-#
-# Any vendor shall have its own configuration within the corresponding device folder
-#
-################################################################################################
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), caremu_configurable)
-LOCAL_PATH := $(call my-dir)
-
-PFW_CORE := external/parameter-framework
-PFW_DEFAULT_SCHEMAS_DIR := $(PFW_CORE)/upstream/schemas
-PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
-
-TOOLS := frameworks/av/services/audiopolicy/engineconfigurable/tools
-BUILD_PFW_SETTINGS := $(TOOLS)/build_audio_pfw_settings.mk
-
-
-##################################################################
-# CONFIGURATION FILES
-##################################################################
-
-########## Policy PFW Structures #########
-######### Policy PFW Settings #########
-include $(CLEAR_VARS)
-LOCAL_MODULE := parameter-framework.policy
-LOCAL_MODULE_STEM := PolicyConfigurableDomains.xml
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Settings/Policy
-LOCAL_REQUIRED_MODULES := libpolicy-subsystem
-
-PFW_EDD_FILES := \
- $(LOCAL_PATH)/Settings/device_for_product_strategies.pfw \
- $(LOCAL_PATH)/../Settings/device_for_input_source.pfw \
- $(LOCAL_PATH)/../Settings/volumes.pfw
-PFW_CRITERION_TYPES_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criterion_types.xml
-PFW_CRITERIA_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criteria.xml
-PFW_TOPLEVEL_FILE := $(TARGET_OUT_VENDOR_ETC)/parameter-framework/ParameterFrameworkConfigurationPolicy.xml
-PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
-
-include $(BUILD_PFW_SETTINGS)
-
-endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), caremu_configurable)
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.xml.in b/services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.user.xml
similarity index 81%
copy from services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.xml.in
copy to services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.user.xml
index 1be67dd..c5960cb 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.xml.in
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.user.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<ParameterFrameworkConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- SystemClassName="Policy" ServerPort="unix:///dev/socket/audioserver/policy_debug"
- TuningAllowed="@TUNING_ALLOWED@">
+ SystemClassName="Policy" TuningAllowed="false">
<SubsystemPlugins>
<Location Folder="">
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.xml.in b/services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.userdebug.xml
similarity index 93%
rename from services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.xml.in
rename to services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.userdebug.xml
index 1be67dd..1b7d7d8 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.xml.in
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.userdebug.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ParameterFrameworkConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
SystemClassName="Policy" ServerPort="unix:///dev/socket/audioserver/policy_debug"
- TuningAllowed="@TUNING_ALLOWED@">
+ TuningAllowed="true">
<SubsystemPlugins>
<Location Folder="">
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.bp
new file mode 100644
index 0000000..11e220b
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.bp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// Import this namespace in order to use AOSP Phone configuration example
+
+soong_namespace {
+ imports: [
+ "frameworks/av/services/audiopolicy/engineconfigurable/config/example/phone",
+ "frameworks/av/services/audiopolicy/config",
+ ],
+}
+
+//
+// Generate Audio Policy Parameter Framework Product Strategies Structure file from template
+//
+prebuilt_etc {
+ name: "ProductStrategies.xml",
+ vendor: true,
+ src: ":buildstrategiesstructure_gen",
+ sub_dir: "parameter-framework/Structure/Policy",
+ required: ["libpolicy-subsystem"],
+}
+genrule {
+ name: "buildstrategiesstructure_gen",
+ defaults: ["buildstrategiesstructurerule"],
+ srcs: [
+ ":audio_policy_engine_configuration_files",
+ ],
+}
+
+//
+// Generate Audio Policy Parameter Framework Configurable Domains
+//
+prebuilt_etc {
+ name: "parameter-framework.policy",
+ filename_from_src: true,
+ vendor: true,
+ src: ":domaingeneratorpolicyrule_gen",
+ sub_dir: "parameter-framework/Settings/Policy",
+ required: [
+ "ProductStrategies.xml",
+ "PolicyClass.xml",
+ "PolicySubsystem.xml",
+ "PolicySubsystem-CommonTypes.xml",
+ ],
+}
+genrule {
+ name: "domaingeneratorpolicyrule_gen",
+ defaults: ["domaingeneratorpolicyrule"],
+ srcs: [
+ ":audio_policy_pfw_toplevel",
+ ":audio_policy_pfw_structure_files",
+ ":audio_policy_engine_criterion_types",
+ ":edd_files",
+ ],
+}
+filegroup {
+ name: "edd_files",
+ srcs: [
+ ":device_for_input_source.pfw",
+ ":volumes.pfw",
+ "Settings/device_for_product_strategy_media.pfw",
+ "Settings/device_for_product_strategy_accessibility.pfw",
+ "Settings/device_for_product_strategy_dtmf.pfw",
+ "Settings/device_for_product_strategy_enforced_audible.pfw",
+ "Settings/device_for_product_strategy_phone.pfw",
+ "Settings/device_for_product_strategy_sonification.pfw",
+ "Settings/device_for_product_strategy_sonification_respectful.pfw",
+ "Settings/device_for_product_strategy_transmitted_through_speaker.pfw",
+ "Settings/device_for_product_strategy_rerouting.pfw",
+ "Settings/device_for_product_strategy_patch.pfw",
+ ],
+}
+// This is for Settings generation, must use socket port, so userdebug version is required
+filegroup {
+ name: "audio_policy_pfw_toplevel",
+ srcs: [":ParameterFrameworkConfigurationPolicy.userdebug.xml"],
+}
+filegroup {
+ name: "audio_policy_pfw_structure_files",
+ srcs: [
+ ":PolicyClass",
+ ":PolicySubsystem",
+ ":PolicySubsystem-CommonTypes",
+ ":buildstrategiesstructure_gen",
+ ],
+}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.mk
deleted file mode 100644
index 0b20781..0000000
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.mk
+++ /dev/null
@@ -1,54 +0,0 @@
-################################################################################################
-#
-# @NOTE:
-# Audio Policy Engine configurable example for generic device build
-#
-# Any vendor shall have its own configuration within the corresponding device folder
-#
-################################################################################################
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), phone_configurable)
-
-LOCAL_PATH := $(call my-dir)
-
-PFW_CORE := external/parameter-framework
-PFW_DEFAULT_SCHEMAS_DIR := $(PFW_CORE)/upstream/schemas
-PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
-
-TOOLS := frameworks/av/services/audiopolicy/engineconfigurable/tools
-BUILD_PFW_SETTINGS := $(TOOLS)/build_audio_pfw_settings.mk
-
-##################################################################
-# CONFIGURATION FILES
-##################################################################
-########## Policy PFW Structures #########
-######### Policy PFW Settings #########
-include $(CLEAR_VARS)
-LOCAL_MODULE := parameter-framework.policy
-LOCAL_MODULE_STEM := PolicyConfigurableDomains.xml
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Settings/Policy
-LOCAL_REQUIRED_MODULES := libpolicy-subsystem
-
-PFW_EDD_FILES := \
- $(LOCAL_PATH)/../Settings/device_for_input_source.pfw \
- $(LOCAL_PATH)/../Settings/volumes.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_media.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_accessibility.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_dtmf.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_enforced_audible.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_phone.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_sonification.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_sonification_respectful.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_transmitted_through_speaker.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_rerouting.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_patch.pfw
-PFW_CRITERION_TYPES_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criterion_types.xml
-PFW_CRITERIA_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criteria.xml
-PFW_TOPLEVEL_FILE := $(TARGET_OUT_VENDOR_ETC)/parameter-framework/ParameterFrameworkConfigurationPolicy.xml
-PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
-
-include $(BUILD_PFW_SETTINGS)
-
-endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), phone_configurable)
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/device_for_input_source.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/device_for_input_source.pfw
index a990879..9e0957c 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/device_for_input_source.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/device_for_input_source.pfw
@@ -18,7 +18,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/mic/applicable_input_device/mask
communication = 0
ambient = 0
@@ -36,7 +35,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/voice_downlink/applicable_input_device/mask
communication = 0
ambient = 0
@@ -58,7 +56,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/voice_call/applicable_input_device/mask
communication = 0
ambient = 0
@@ -80,7 +77,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/voice_uplink/applicable_input_device/mask
communication = 0
ambient = 0
@@ -102,7 +98,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/camcorder/applicable_input_device/mask
communication = 0
ambient = 0
@@ -123,7 +118,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/voice_recognition/applicable_input_device/mask
communication = 0
ambient = 0
@@ -142,7 +136,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/voice_communication/applicable_input_device/mask
communication = 0
ambient = 0
@@ -160,7 +153,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/remote_submix/applicable_input_device/mask
communication = 0
ambient = 0
@@ -182,7 +174,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/hotword/applicable_input_device/mask
communication = 0
ambient = 0
@@ -201,7 +192,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/unprocessed/applicable_input_device/mask
communication = 0
ambient = 0
@@ -220,7 +210,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/fm_tuner/applicable_input_device/mask
communication = 0
ambient = 0
@@ -242,7 +231,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
domain: DefaultAndMic
conf: A2dp
@@ -255,12 +243,14 @@
usb_device = 0
builtin_mic = 0
bluetooth_sco_headset = 0
+ stub = 0
component: mic/applicable_input_device/mask/
bluetooth_a2dp = 1
wired_headset = 0
usb_device = 0
builtin_mic = 0
bluetooth_sco_headset = 0
+ stub = 0
conf: Sco
AvailableInputDevices Includes BluetoothScoHeadset
@@ -273,12 +263,14 @@
usb_device = 0
builtin_mic = 0
bluetooth_sco_headset = 1
+ stub = 0
component: mic/applicable_input_device/mask/
bluetooth_a2dp = 0
wired_headset = 0
usb_device = 0
builtin_mic = 0
bluetooth_sco_headset = 1
+ stub = 0
conf: WiredHeadset
AvailableInputDevices Includes WiredHeadset
@@ -290,12 +282,14 @@
usb_device = 0
builtin_mic = 0
bluetooth_sco_headset = 0
+ stub = 0
component: mic/applicable_input_device/mask/
bluetooth_a2dp = 0
wired_headset = 1
usb_device = 0
builtin_mic = 0
bluetooth_sco_headset = 0
+ stub = 0
conf: UsbDevice
AvailableInputDevices Includes UsbDevice
@@ -307,12 +301,14 @@
usb_device = 1
builtin_mic = 0
bluetooth_sco_headset = 0
+ stub = 0
component: mic/applicable_input_device/mask/
bluetooth_a2dp = 0
wired_headset = 0
usb_device = 1
builtin_mic = 0
bluetooth_sco_headset = 0
+ stub = 0
conf: BuiltinMic
AvailableInputDevices Includes BuiltinMic
@@ -324,12 +320,33 @@
usb_device = 0
builtin_mic = 1
bluetooth_sco_headset = 0
+ stub = 0
component: mic/applicable_input_device/mask/
bluetooth_a2dp = 0
wired_headset = 0
usb_device = 0
builtin_mic = 1
bluetooth_sco_headset = 0
+ stub = 0
+
+ conf: Stub
+ AvailableInputDevices Includes Default
+
+ component: /Policy/policy/input_sources
+ component: default/applicable_input_device/mask/
+ bluetooth_a2dp = 0
+ wired_headset = 0
+ usb_device = 0
+ builtin_mic = 0
+ bluetooth_sco_headset = 0
+ stub = 1
+ component: mic/applicable_input_device/mask/
+ bluetooth_a2dp = 0
+ wired_headset = 0
+ usb_device = 0
+ builtin_mic = 0
+ bluetooth_sco_headset = 0
+ stub = 1
conf: Default
component: /Policy/policy/input_sources
@@ -339,12 +356,14 @@
usb_device = 0
builtin_mic = 0
bluetooth_sco_headset = 0
+ stub = 0
component: mic/applicable_input_device/mask/
bluetooth_a2dp = 0
wired_headset = 0
usb_device = 0
builtin_mic = 0
bluetooth_sco_headset = 0
+ stub = 0
domain: VoiceUplinkAndVoiceDownlinkAndVoiceCall
conf: VoiceCall
@@ -354,12 +373,29 @@
voice_downlink/applicable_input_device/mask/telephony_rx = 1
voice_call/applicable_input_device/mask/telephony_rx = 1
voice_uplink/applicable_input_device/mask/telephony_rx = 1
+ voice_downlink/applicable_input_device/mask/stub = 0
+ voice_call/applicable_input_device/mask/stub = 0
+ voice_uplink/applicable_input_device/mask/stub = 0
+
+ conf: Stub
+ AvailableInputDevices Includes Default
+
+ component: /Policy/policy/input_sources
+ voice_downlink/applicable_input_device/mask/telephony_rx = 0
+ voice_call/applicable_input_device/mask/telephony_rx = 0
+ voice_uplink/applicable_input_device/mask/telephony_rx = 0
+ voice_downlink/applicable_input_device/mask/stub = 1
+ voice_call/applicable_input_device/mask/stub = 1
+ voice_uplink/applicable_input_device/mask/stub = 1
conf: Default
component: /Policy/policy/input_sources
voice_downlink/applicable_input_device/mask/telephony_rx = 0
voice_call/applicable_input_device/mask/telephony_rx = 0
voice_uplink/applicable_input_device/mask/telephony_rx = 0
+ voice_downlink/applicable_input_device/mask/stub = 0
+ voice_call/applicable_input_device/mask/stub = 0
+ voice_uplink/applicable_input_device/mask/stub = 0
domain: Camcorder
conf: BackMic
@@ -368,6 +404,7 @@
component: /Policy/policy/input_sources/camcorder/applicable_input_device/mask
back_mic = 1
builtin_mic = 0
+ stub = 0
conf: BuiltinMic
AvailableInputDevices Includes BuiltinMic
@@ -375,11 +412,21 @@
component: /Policy/policy/input_sources/camcorder/applicable_input_device/mask
back_mic = 0
builtin_mic = 1
+ stub = 0
+
+ conf: Stub
+ AvailableInputDevices Includes Default
+
+ component: /Policy/policy/input_sources/camcorder/applicable_input_device/mask
+ back_mic = 0
+ builtin_mic = 0
+ stub = 1
conf: Default
component: /Policy/policy/input_sources/camcorder/applicable_input_device/mask
back_mic = 0
builtin_mic = 0
+ stub = 0
domain: VoiceRecognitionAndUnprocessedAndHotword
conf: ScoHeadset
@@ -392,16 +439,19 @@
wired_headset = 0
usb_device = 0
builtin_mic = 0
+ stub = 0
component: unprocessed/applicable_input_device/mask
bluetooth_sco_headset = 1
wired_headset = 0
usb_device = 0
builtin_mic = 0
+ stub = 0
component: hotword/applicable_input_device/mask
bluetooth_sco_headset = 1
wired_headset = 0
usb_device = 0
builtin_mic = 0
+ stub = 0
conf: WiredHeadset
AvailableInputDevices Includes WiredHeadset
@@ -411,17 +461,20 @@
bluetooth_sco_headset = 0
wired_headset = 1
usb_device = 0
+ stub = 0
builtin_mic = 0
component: unprocessed/applicable_input_device/mask
bluetooth_sco_headset = 0
wired_headset = 1
usb_device = 0
builtin_mic = 0
+ stub = 0
component: hotword/applicable_input_device/mask
bluetooth_sco_headset = 0
wired_headset = 1
usb_device = 0
builtin_mic = 0
+ stub = 0
conf: UsbDevice
AvailableInputDevices Includes UsbDevice
@@ -432,16 +485,19 @@
wired_headset = 0
usb_device = 1
builtin_mic = 0
+ stub = 0
component: unprocessed/applicable_input_device/mask
bluetooth_sco_headset = 0
wired_headset = 0
usb_device = 1
builtin_mic = 0
+ stub = 0
component: hotword/applicable_input_device/mask
bluetooth_sco_headset = 0
wired_headset = 0
usb_device = 1
builtin_mic = 0
+ stub = 0
conf: BuiltinMic
AvailableInputDevices Includes BuiltinMic
@@ -452,17 +508,42 @@
wired_headset = 0
usb_device = 0
builtin_mic = 1
+ stub = 0
component: unprocessed/applicable_input_device/mask
bluetooth_sco_headset = 0
wired_headset = 0
usb_device = 0
builtin_mic = 1
+ stub = 0
component: hotword/applicable_input_device/mask
bluetooth_sco_headset = 0
wired_headset = 0
usb_device = 0
builtin_mic = 1
+ stub = 0
+ conf: Stub
+ AvailableInputDevices Includes Default
+
+ component: /Policy/policy/input_sources
+ component: voice_recognition/applicable_input_device/mask
+ bluetooth_sco_headset = 0
+ wired_headset = 0
+ usb_device = 0
+ builtin_mic = 0
+ stub = 1
+ component: unprocessed/applicable_input_device/mask
+ bluetooth_sco_headset = 0
+ wired_headset = 0
+ usb_device = 0
+ builtin_mic = 0
+ stub = 1
+ component: hotword/applicable_input_device/mask
+ bluetooth_sco_headset = 0
+ wired_headset = 0
+ usb_device = 0
+ builtin_mic = 0
+ stub = 1
conf: Default
component: /Policy/policy/input_sources
component: voice_recognition/applicable_input_device/mask
@@ -470,16 +551,19 @@
wired_headset = 0
usb_device = 0
builtin_mic = 0
+ stub = 0
component: unprocessed/applicable_input_device/mask
bluetooth_sco_headset = 0
wired_headset = 0
usb_device = 0
builtin_mic = 0
+ stub = 0
component: hotword/applicable_input_device/mask
bluetooth_sco_headset = 0
wired_headset = 0
usb_device = 0
builtin_mic = 0
+ stub = 0
domain: VoiceCommunication
conf: ScoHeadset
@@ -495,6 +579,7 @@
usb_device = 0
builtin_mic = 0
back_mic = 0
+ stub = 0
conf: WiredHeadset
ForceUseForCommunication Is ForceNone
@@ -506,6 +591,7 @@
usb_device = 0
builtin_mic = 0
back_mic = 0
+ stub = 0
conf: UsbDevice
ForceUseForCommunication Is ForceNone
@@ -517,6 +603,7 @@
usb_device = 1
builtin_mic = 0
back_mic = 0
+ stub = 0
conf: BuiltinMic
AvailableInputDevices Includes BuiltinMic
@@ -532,6 +619,7 @@
usb_device = 0
builtin_mic = 1
back_mic = 0
+ stub = 0
conf: BackMic
ForceUseForCommunication Is ForceSpeaker
@@ -543,6 +631,7 @@
usb_device = 0
builtin_mic = 0
back_mic = 1
+ stub = 0
conf: Default
#
@@ -554,6 +643,7 @@
usb_device = 0
builtin_mic = 1
back_mic = 0
+ stub = 0
domain: RemoteSubmix
conf: RemoteSubmix
@@ -561,10 +651,19 @@
component: /Policy/policy/input_sources/remote_submix/applicable_input_device/mask
remote_submix = 1
+ stub = 0
+
+ conf: Stub
+ AvailableInputDevices Includes Default
+
+ component: /Policy/policy/input_sources/remote_submix/applicable_input_device/mask
+ remote_submix = 0
+ stub = 1
conf: Default
component: /Policy/policy/input_sources/remote_submix/applicable_input_device/mask
remote_submix = 0
+ stub = 0
domain: FmTuner
conf: FmTuner
@@ -572,8 +671,29 @@
component: /Policy/policy/input_sources/fm_tuner/applicable_input_device/mask
fm_tuner = 1
+ stub = 0
+
+ conf: Stub
+ AvailableInputDevices Includes Default
+
+ component: /Policy/policy/input_sources/fm_tuner/applicable_input_device/mask
+ fm_tuner = 0
+ stub = 1
conf: Default
component: /Policy/policy/input_sources/fm_tuner/applicable_input_device/mask
fm_tuner = 0
+ stub = 0
+
+ domain: Voice
+ conf: Stub
+ AvailableInputDevices Includes Default
+
+ /Policy/policy/input_sources/echo_reference/applicable_input_device/mask/stub = 1
+ /Policy/policy/input_sources/voice_performance/applicable_input_device/mask/stub = 1
+
+ conf: Default
+ /Policy/policy/input_sources/echo_reference/applicable_input_device/mask/stub = 0
+ /Policy/policy/input_sources/voice_performance/applicable_input_device/mask/stub = 0
+
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoInput/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoInput/Android.bp
new file mode 100644
index 0000000..ffd494e
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoInput/Android.bp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// Import this namespace in order to use AOSP No Input configuration example
+
+soong_namespace {
+ imports: [
+ "frameworks/av/services/audiopolicy/engineconfigurable/config/example/phone",
+ "frameworks/av/services/audiopolicy/config",
+ ],
+}
+
+prebuilt_etc {
+ name: "parameter-framework.policy",
+ filename_from_src: true,
+ vendor: true,
+ src: ":domaingeneratorpolicyrule_gen",
+ sub_dir: "parameter-framework/Settings/Policy",
+ required: [
+ "PolicyClass.xml",
+ "PolicySubsystem.xml",
+ "PolicySubsystem-CommonTypes.xml",
+ ],
+}
+
+genrule {
+ name: "domaingeneratorpolicyrule_gen",
+ defaults: ["domaingeneratorpolicyrule"],
+ srcs: [
+ ":audio_policy_pfw_toplevel",
+ ":audio_policy_pfw_structure_files",
+ ":audio_policy_engine_criterion_types",
+ ":edd_files",
+ ],
+}
+filegroup {
+ name: "audio_policy_pfw_toplevel",
+ srcs: [":ParameterFrameworkConfigurationPolicy.userdebug.xml"],
+}
+filegroup {
+ name: "audio_policy_pfw_structure_files",
+ srcs: [
+ ":PolicyClass",
+ ":PolicySubsystem",
+ ":PolicySubsystem-CommonTypes",
+ ],
+}
+filegroup {
+ name: "edd_files",
+ srcs: [
+ "device_for_input_source.pfw",
+ ":volumes.pfw",
+ ],
+}
+prebuilt_etc {
+ name: "PolicySubsystem.xml",
+ vendor: true,
+ src: ":PolicySubsystem-no-strategy",
+ sub_dir: "parameter-framework/Structure/Policy",
+}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoOutput/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoOutput/Android.bp
new file mode 100644
index 0000000..6fca048
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoOutput/Android.bp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// Import this namespace in order to use AOSP No output configuration example
+
+soong_namespace {
+ imports: [
+ "frameworks/av/services/audiopolicy/engineconfigurable/config/example/phone",
+ "frameworks/av/services/audiopolicy/config",
+ ],
+}
+
+prebuilt_etc {
+ name: "parameter-framework.policy",
+ filename_from_src: true,
+ vendor: true,
+ src: ":domaingeneratorpolicyrule_gen",
+ sub_dir: "parameter-framework/Settings/Policy",
+ required: [
+ "PolicyClass.xml",
+ "PolicySubsystem.xml",
+ "PolicySubsystem-CommonTypes.xml",
+ ],
+}
+genrule {
+ name: "domaingeneratorpolicyrule_gen",
+ defaults: ["domaingeneratorpolicyrule"],
+ srcs: [
+ ":audio_policy_pfw_toplevel",
+ ":audio_policy_pfw_structure_files",
+ ":audio_policy_engine_criterion_types",
+ ":edd_files",
+ ],
+}
+filegroup {
+ name: "audio_policy_pfw_toplevel",
+ srcs: [":ParameterFrameworkConfigurationPolicy.userdebug.xml"],
+}
+filegroup {
+ name: "audio_policy_pfw_structure_files",
+ srcs: [
+ ":PolicyClass",
+ ":PolicySubsystem",
+ ":PolicySubsystem-CommonTypes",
+ ],
+}
+filegroup {
+ name: "edd_files",
+ srcs: [
+ "device_for_strategies.pfw",
+ ":volumes.pfw",
+ ":device_for_input_source.pfw",
+ ],
+}
+prebuilt_etc {
+ name: "PolicySubsystem.xml",
+ vendor: true,
+ src: ":PolicySubsystem-no-strategy",
+ sub_dir: "parameter-framework/Structure/Policy",
+}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem.xml b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem.xml
index b55ce2c..585ce87 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem.xml
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem.xml
@@ -73,10 +73,13 @@
Mapping="Name:AUDIO_SOURCE_REMOTE_SUBMIX"/>
<Component Name="unprocessed" Type="InputSource"
Mapping="Name:AUDIO_SOURCE_UNPROCESSED"/>
+ <Component Name="voice_performance" Type="InputSource"
+ Mapping="Name:AUDIO_SOURCE_VOICE_PERFORMANCE"/>
+ <Component Name="echo_reference" Type="InputSource"
+ Mapping="Name:AUDIO_SOURCE_ECHO_REFERENCE"/>
<Component Name="fm_tuner" Type="InputSource" Mapping="Name:AUDIO_SOURCE_FM_TUNER"/>
<Component Name="hotword" Type="InputSource" Mapping="Name:AUDIO_SOURCE_HOTWORD"/>
</ComponentType>
-
<!--#################### INPUT SOURCE END ####################-->
</ComponentLibrary>
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.cpp b/services/audiopolicy/engineconfigurable/src/Engine.cpp
index c37efca..0a88685 100644
--- a/services/audiopolicy/engineconfigurable/src/Engine.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Engine.cpp
@@ -32,6 +32,9 @@
#include <policy.h>
#include <AudioIODescriptorInterface.h>
#include <ParameterManagerWrapper.h>
+#include <media/AudioContainers.h>
+
+#include <media/TypeConverter.h>
using std::string;
using std::map;
@@ -165,11 +168,13 @@
mPolicyParameterMgr->setDeviceConnectionState(devDesc, state);
if (audio_is_output_device(devDesc->type())) {
+ // FIXME: Use DeviceTypeSet when the interface is ready
return mPolicyParameterMgr->setAvailableOutputDevices(
- getApmObserver()->getAvailableOutputDevices().types());
+ deviceTypesToBitMask(getApmObserver()->getAvailableOutputDevices().types()));
} else if (audio_is_input_device(devDesc->type())) {
+ // FIXME: Use DeviceTypeSet when the interface is ready
return mPolicyParameterMgr->setAvailableInputDevices(
- getApmObserver()->getAvailableInputDevices().types());
+ deviceTypesToBitMask(getApmObserver()->getAvailableInputDevices().types()));
}
return BAD_TYPE;
}
@@ -209,7 +214,7 @@
}
const DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
- uint32_t availableOutputDevicesType = availableOutputDevices.types();
+ DeviceTypeSet availableOutputDevicesTypes = availableOutputDevices.types();
/** This is the only case handled programmatically because the PFW is unable to know the
* activity of streams.
@@ -221,7 +226,7 @@
*
* -When media is not playing anymore, fall back on the sonification behavior
*/
- audio_devices_t devices = AUDIO_DEVICE_NONE;
+ DeviceTypeSet deviceTypes;
if (ps == getProductStrategyForStream(AUDIO_STREAM_NOTIFICATION) &&
!is_state_in_call(getPhoneState()) &&
!outputs.isActiveRemotely(toVolumeSource(AUDIO_STREAM_MUSIC),
@@ -230,7 +235,7 @@
SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
product_strategy_t strategyForMedia =
getProductStrategyForStream(AUDIO_STREAM_MUSIC);
- devices = productStrategies.getDeviceTypesForProductStrategy(strategyForMedia);
+ deviceTypes = productStrategies.getDeviceTypesForProductStrategy(strategyForMedia);
} else if (ps == getProductStrategyForStream(AUDIO_STREAM_ACCESSIBILITY) &&
(outputs.isActive(toVolumeSource(AUDIO_STREAM_RING)) ||
outputs.isActive(toVolumeSource(AUDIO_STREAM_ALARM)))) {
@@ -238,28 +243,37 @@
// compressed format as they would likely not be mixed and dropped.
// Device For Sonification conf file has HDMI, SPDIF and HDMI ARC unreacheable.
product_strategy_t strategyNotification = getProductStrategyForStream(AUDIO_STREAM_RING);
- devices = productStrategies.getDeviceTypesForProductStrategy(strategyNotification);
+ deviceTypes = productStrategies.getDeviceTypesForProductStrategy(strategyNotification);
} else {
- devices = productStrategies.getDeviceTypesForProductStrategy(ps);
+ deviceTypes = productStrategies.getDeviceTypesForProductStrategy(ps);
}
- if (devices == AUDIO_DEVICE_NONE ||
- (devices & availableOutputDevicesType) == AUDIO_DEVICE_NONE) {
- devices = getApmObserver()->getDefaultOutputDevice()->type();
- ALOGE_IF(devices == AUDIO_DEVICE_NONE, "%s: no valid default device defined", __FUNCTION__);
- return DeviceVector(getApmObserver()->getDefaultOutputDevice());
+ if (deviceTypes.empty() ||
+ Intersection(deviceTypes, availableOutputDevicesTypes).empty()) {
+ auto defaultDevice = getApmObserver()->getDefaultOutputDevice();
+ ALOG_ASSERT(defaultDevice != nullptr, "no valid default device defined");
+ return DeviceVector(defaultDevice);
}
- if (/*device_distinguishes_on_address(devices)*/ devices == AUDIO_DEVICE_OUT_BUS) {
+ if (/*device_distinguishes_on_address(*deviceTypes.begin())*/ isSingleDeviceType(
+ deviceTypes, AUDIO_DEVICE_OUT_BUS)) {
// We do expect only one device for these types of devices
// Criterion device address garantee this one is available
// If this criterion is not wished, need to ensure this device is available
const String8 address(productStrategies.getDeviceAddressForProductStrategy(ps).c_str());
- ALOGV("%s:device 0x%x %s %d", __FUNCTION__, devices, address.c_str(), ps);
- return DeviceVector(availableOutputDevices.getDevice(devices,
- address,
- AUDIO_FORMAT_DEFAULT));
+ ALOGV("%s:device %s %s %d",
+ __FUNCTION__, dumpDeviceTypes(deviceTypes).c_str(), address.c_str(), ps);
+ auto busDevice = availableOutputDevices.getDevice(
+ *deviceTypes.begin(), address, AUDIO_FORMAT_DEFAULT);
+ if (busDevice == nullptr) {
+ ALOGE("%s:unavailable device %s %s, fallback on default", __func__,
+ dumpDeviceTypes(deviceTypes).c_str(), address.c_str());
+ auto defaultDevice = getApmObserver()->getDefaultOutputDevice();
+ ALOG_ASSERT(defaultDevice != nullptr, "Default Output Device NOT available");
+ return DeviceVector(defaultDevice);
+ }
+ return DeviceVector(busDevice);
}
- ALOGV("%s:device 0x%x %d", __FUNCTION__, devices, ps);
- return availableOutputDevices.getDevicesFromTypeMask(devices);
+ ALOGV("%s:device %s %d", __FUNCTION__, dumpDeviceTypes(deviceTypes).c_str(), ps);
+ return availableOutputDevices.getDevicesFromTypes(deviceTypes);
}
DeviceVector Engine::getOutputDevicesForAttributes(const audio_attributes_t &attributes,
@@ -356,7 +370,8 @@
ALOGE("%s: set device %d on invalid strategy %d", __FUNCTION__, devices, strategy);
return false;
}
- getProductStrategies().at(strategy)->setDeviceTypes(devices);
+ // FIXME: stop using deviceTypesFromBitMask when the interface is ready
+ getProductStrategies().at(strategy)->setDeviceTypes(deviceTypesFromBitMask(devices));
return true;
}
diff --git a/services/audiopolicy/engineconfigurable/tools/Android.bp b/services/audiopolicy/engineconfigurable/tools/Android.bp
index 8c16972..d9e97af 100644
--- a/services/audiopolicy/engineconfigurable/tools/Android.bp
+++ b/services/audiopolicy/engineconfigurable/tools/Android.bp
@@ -16,14 +16,17 @@
name: "tools_default",
version: {
py2: {
- enabled: true,
+ enabled: false,
},
py3: {
- enabled: false,
+ enabled: true,
},
},
}
+//##################################################################################################
+// Tools for audio policy engine criterion type configuration file
+//
python_binary_host {
name: "buildPolicyCriterionTypes.py",
main: "buildPolicyCriterionTypes.py",
@@ -33,6 +36,30 @@
defaults: ["tools_default"],
}
+genrule_defaults {
+ name: "buildpolicycriteriontypesrule",
+ tools: ["buildPolicyCriterionTypes.py"],
+ cmd: "cp $(locations :audio_policy_configuration_files) $(genDir)/. && " +
+ "cp $(location :audio_policy_configuration_top_file) $(genDir)/audio_policy_configuration.xml && " +
+ "$(location buildPolicyCriterionTypes.py) " +
+ // @todo update if 1428659 is merged "--androidaudiobaseheader $(location :android_audio_base_header_file) " +
+ " --androidaudiobaseheader system/media/audio/include/system/audio-base.h " +
+ "--audiopolicyconfigurationfile $(genDir)/audio_policy_configuration.xml " +
+ "--criteriontypes $(location :audio_policy_engine_criterion_types_template) " +
+ "--outputfile $(out)",
+ srcs: [
+ // The commented inputs must be provided to use this genrule_defaults
+ // @todo uncomment if 1428659 is merged":android_audio_base_header_file",
+ ":audio_policy_engine_criterion_types_template",
+ // ":audio_policy_configuration_top_file",
+ // ":audio_policy_configuration_files",
+ ],
+ out: ["audio_policy_engine_criterion_types.xml"],
+}
+
+//##################################################################################################
+// Tools for audio policy engine parameter framework configurable domains
+//
python_binary_host {
name: "domainGeneratorPolicy.py",
main: "domainGeneratorPolicy.py",
@@ -50,6 +77,38 @@
],
}
+genrule_defaults {
+ name: "domaingeneratorpolicyrule",
+ tools: [
+ "domainGeneratorPolicy.py",
+ "domainGeneratorConnector",
+ ],
+ cmd: "mkdir -p $(genDir)/Structure/Policy && " +
+ "cp $(locations :audio_policy_pfw_structure_files) $(genDir)/Structure/Policy && " +
+ "cp $(location :audio_policy_pfw_toplevel) $(genDir)/top_level && " +
+ "$(location domainGeneratorPolicy.py) " +
+ "--validate " +
+ "--domain-generator-tool $(location domainGeneratorConnector) " +
+ "--toplevel-config $(genDir)/top_level " +
+ "--criteria $(location :audio_policy_engine_criteria) " +
+ "--criteriontypes $(location :audio_policy_engine_criterion_types) " +
+ "--add-edds $(locations :edd_files) " +
+ "--schemas-dir external/parameter-framework/upstream/schemas " +
+ " > $(out)",
+ srcs: [
+ // The commented inputs must be provided to use this genrule_defaults
+ // ":audio_policy_pfw_toplevel",
+ // ":audio_policy_pfw_structure_files",
+ ":audio_policy_engine_criteria",
+ // ":audio_policy_engine_criterion_types",
+ // ":edd_files",
+ ],
+ out: ["PolicyConfigurableDomains.xml"],
+}
+
+//##################################################################################################
+// Tools for policy parameter-framework product strategies structure file generation
+//
python_binary_host {
name: "buildStrategiesStructureFile.py",
main: "buildStrategiesStructureFile.py",
@@ -58,3 +117,19 @@
],
defaults: ["tools_default"],
}
+
+genrule_defaults {
+ name: "buildstrategiesstructurerule",
+ tools: ["buildStrategiesStructureFile.py"],
+ cmd: "cp $(locations :audio_policy_engine_configuration_files) $(genDir) && ls -l $(genDir) &&"+
+ "$(location buildStrategiesStructureFile.py) " +
+ "--audiopolicyengineconfigurationfile $(genDir)/audio_policy_engine_configuration.xml "+
+ "--productstrategiesstructurefile $(location :product_strategies_structure_template) " +
+ "--outputfile $(out)",
+ srcs: [
+ // The commented inputs must be provided to use this genrule_defaults
+ // ":audio_policy_engine_configuration_files",
+ ":product_strategies_structure_template",
+ ],
+ out: ["ProductStrategies.xml"],
+}
diff --git a/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py b/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py
index a63c858..b8b60c1 100755
--- a/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py
+++ b/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
#
# Copyright 2018, The Android Open Source Project
@@ -19,10 +19,8 @@
import argparse
import re
import sys
-import tempfile
import os
import logging
-import subprocess
import xml.etree.ElementTree as ET
import xml.etree.ElementInclude as EI
import xml.dom.minidom as MINIDOM
@@ -49,33 +47,35 @@
def parseArgs():
argparser = argparse.ArgumentParser(description="Parameter-Framework XML \
- audio criterion type file generator.\n\
- Exit with the number of (recoverable or not) error that occured.")
+ audio criterion type file generator.\n\
+ Exit with the number of (recoverable or not) \
+ error that occured.")
argparser.add_argument('--androidaudiobaseheader',
- help="Android Audio Base C header file, Mandatory.",
- metavar="ANDROID_AUDIO_BASE_HEADER",
- type=argparse.FileType('r'),
- required=True)
+ help="Android Audio Base C header file, Mandatory.",
+ metavar="ANDROID_AUDIO_BASE_HEADER",
+ type=argparse.FileType('r'),
+ required=True)
argparser.add_argument('--audiopolicyconfigurationfile',
- help="Android Audio Policy Configuration file, Mandatory.",
- metavar="(AUDIO_POLICY_CONFIGURATION_FILE)",
- type=argparse.FileType('r'),
- required=True)
+ help="Android Audio Policy Configuration file, Mandatory.",
+ metavar="(AUDIO_POLICY_CONFIGURATION_FILE)",
+ type=argparse.FileType('r'),
+ required=True)
argparser.add_argument('--criteriontypes',
- help="Criterion types XML base file, in \
- '<criterion_types> \
- <criterion_type name="" type=<inclusive|exclusive> values=<value1,value2,...>/>' \
- format. Mandatory.",
- metavar="CRITERION_TYPE_FILE",
- type=argparse.FileType('r'),
- required=True)
+ help="Criterion types XML base file, in \
+ '<criterion_types> \
+ <criterion_type name="" type=<inclusive|exclusive> \
+ values=<value1,value2,...>/>' \
+ format. Mandatory.",
+ metavar="CRITERION_TYPE_FILE",
+ type=argparse.FileType('r'),
+ required=True)
argparser.add_argument('--outputfile',
- help="Criterion types outputfile file. Mandatory.",
- metavar="CRITERION_TYPE_OUTPUT_FILE",
- type=argparse.FileType('w'),
- required=True)
+ help="Criterion types outputfile file. Mandatory.",
+ metavar="CRITERION_TYPE_OUTPUT_FILE",
+ type=argparse.FileType('w'),
+ required=True)
argparser.add_argument('--verbose',
- action='store_true')
+ action='store_true')
return argparser.parse_args()
@@ -120,7 +120,7 @@
reparsed = MINIDOM.parseString(xmlstr)
prettyXmlStr = reparsed.toprettyxml(newl='\r\n')
prettyXmlStr = os.linesep.join([s for s in prettyXmlStr.splitlines() if s.strip()])
- outputFile.write(prettyXmlStr.encode('utf-8'))
+ outputFile.write(prettyXmlStr)
def capitalizeLine(line):
return ' '.join((w.capitalize() for w in line.split(' ')))
@@ -137,30 +137,30 @@
#
address_criteria_mapping_table = {
'sink' : "OutputDevicesAddressesType",
- 'source' : "InputDevicesAddressesType" }
+ 'source' : "InputDevicesAddressesType"}
address_criteria = {
'OutputDevicesAddressesType' : [],
- 'InputDevicesAddressesType' : [] }
+ 'InputDevicesAddressesType' : []}
- oldWorkingDir = os.getcwd()
- print "Current working directory %s" % oldWorkingDir
+ old_working_dir = os.getcwd()
+ print("Current working directory %s" % old_working_dir)
- newDir = os.path.join(oldWorkingDir , audiopolicyconfigurationfile.name)
+ new_dir = os.path.join(old_working_dir, audiopolicyconfigurationfile.name)
policy_in_tree = ET.parse(audiopolicyconfigurationfile)
- os.chdir(os.path.dirname(os.path.normpath(newDir)))
+ os.chdir(os.path.dirname(os.path.normpath(new_dir)))
- print "new working directory %s" % os.getcwd()
+ print("new working directory %s" % os.getcwd())
policy_root = policy_in_tree.getroot()
EI.include(policy_root)
- os.chdir(oldWorkingDir)
+ os.chdir(old_working_dir)
for device in policy_root.iter('devicePort'):
for key in address_criteria_mapping_table.keys():
- if device.get('role') == key and device.get('address') :
+ if device.get('role') == key and device.get('address'):
logging.info("{}: <{}>".format(key, device.get('address')))
address_criteria[address_criteria_mapping_table[key]].append(device.get('address'))
@@ -188,15 +188,15 @@
all_criteria = {
'AndroidModeType' : {},
'OutputDevicesMaskType' : {},
- 'InputDevicesMaskType' : {} }
+ 'InputDevicesMaskType' : {}}
#
# _CNT, _MAX, _ALL and _NONE are prohibited values as ther are just helpers for enum users.
#
- ignored_values = [ 'CNT', 'MAX', 'ALL', 'NONE' ]
+ ignored_values = ['CNT', 'MAX', 'ALL', 'NONE']
criteria_pattern = re.compile(
- r"\s*(?P<type>(?:"+'|'.join(criterion_mapping_table.keys()) + "))\_" \
+ r"\s*(?P<type>(?:"+'|'.join(criterion_mapping_table.keys()) + "))_" \
r"(?P<literal>(?!" + '|'.join(ignored_values) + ")\w*)\s*=\s*" \
r"(?P<values>(?:0[xX])?[0-9a-fA-F]+)")
@@ -221,7 +221,7 @@
logging.info("criterion {} duplicated values:".format(criterion_name))
logging.info("{}:{}".format(numerical_value, literal))
logging.info("KEEPING LATEST")
- for key in all_criteria[criterion_name].keys():
+ for key in list(all_criteria[criterion_name]):
if all_criteria[criterion_name][key] == int(numerical_value, 0):
del all_criteria[criterion_name][key]
diff --git a/services/audiopolicy/engineconfigurable/tools/buildStrategiesStructureFile.py b/services/audiopolicy/engineconfigurable/tools/buildStrategiesStructureFile.py
index af40602..f69d346 100755
--- a/services/audiopolicy/engineconfigurable/tools/buildStrategiesStructureFile.py
+++ b/services/audiopolicy/engineconfigurable/tools/buildStrategiesStructureFile.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
#
# Copyright 2019, The Android Open Source Project
@@ -17,16 +17,12 @@
#
import argparse
-import re
import sys
-import tempfile
import os
import logging
-import subprocess
import xml.etree.ElementTree as ET
import xml.etree.ElementInclude as EI
import xml.dom.minidom as MINIDOM
-from collections import OrderedDict
#
# Helper script that helps to feed at build time the XML Product Strategies Structure file file used
@@ -46,33 +42,34 @@
def parseArgs():
argparser = argparse.ArgumentParser(description="Parameter-Framework XML \
- product strategies structure file generator.\n\
- Exit with the number of (recoverable or not) error that occured.")
+ product strategies structure file generator.\n\
+ Exit with the number of (recoverable or not) \
+ error that occured.")
argparser.add_argument('--audiopolicyengineconfigurationfile',
- help="Android Audio Policy Engine Configuration file, Mandatory.",
- metavar="(AUDIO_POLICY_ENGINE_CONFIGURATION_FILE)",
- type=argparse.FileType('r'),
- required=True)
+ help="Android Audio Policy Engine Configuration file, Mandatory.",
+ metavar="(AUDIO_POLICY_ENGINE_CONFIGURATION_FILE)",
+ type=argparse.FileType('r'),
+ required=True)
argparser.add_argument('--productstrategiesstructurefile',
- help="Product Strategies Structure XML base file, Mandatory.",
- metavar="STRATEGIES_STRUCTURE_FILE",
- type=argparse.FileType('r'),
- required=True)
+ help="Product Strategies Structure XML base file, Mandatory.",
+ metavar="STRATEGIES_STRUCTURE_FILE",
+ type=argparse.FileType('r'),
+ required=True)
argparser.add_argument('--outputfile',
- help="Product Strategies Structure output file, Mandatory.",
- metavar="STRATEGIES_STRUCTURE_OUTPUT_FILE",
- type=argparse.FileType('w'),
- required=True)
+ help="Product Strategies Structure output file, Mandatory.",
+ metavar="STRATEGIES_STRUCTURE_OUTPUT_FILE",
+ type=argparse.FileType('w'),
+ required=True)
argparser.add_argument('--verbose',
- action='store_true')
+ action='store_true')
return argparser.parse_args()
-def generateXmlStructureFile(strategies, strategyStructureInFile, outputFile):
+def generateXmlStructureFile(strategies, strategy_structure_in_file, output_file):
- logging.info("Importing strategyStructureInFile {}".format(strategyStructureInFile))
- strategies_in_tree = ET.parse(strategyStructureInFile)
+ logging.info("Importing strategy_structure_in_file {}".format(strategy_structure_in_file))
+ strategies_in_tree = ET.parse(strategy_structure_in_file)
strategies_root = strategies_in_tree.getroot()
strategy_components = strategies_root.find('ComponentType')
@@ -80,13 +77,15 @@
for strategy_name in strategies:
context_mapping = "".join(map(str, ["Name:", strategy_name]))
strategy_pfw_name = strategy_name.replace('STRATEGY_', '').lower()
- strategy_component_node = ET.SubElement(strategy_components, "Component", Name=strategy_pfw_name, Type="ProductStrategy", Mapping=context_mapping)
+ ET.SubElement(strategy_components, "Component",
+ Name=strategy_pfw_name, Type="ProductStrategy",
+ Mapping=context_mapping)
xmlstr = ET.tostring(strategies_root, encoding='utf8', method='xml')
reparsed = MINIDOM.parseString(xmlstr)
prettyXmlStr = reparsed.toprettyxml(newl='\r\n')
prettyXmlStr = os.linesep.join([s for s in prettyXmlStr.splitlines() if s.strip()])
- outputFile.write(prettyXmlStr.encode('utf-8'))
+ output_file.write(prettyXmlStr)
def capitalizeLine(line):
return ' '.join((w.capitalize() for w in line.split(' ')))
@@ -97,26 +96,27 @@
#
def parseAndroidAudioPolicyEngineConfigurationFile(audiopolicyengineconfigurationfile):
- logging.info("Checking Audio Policy Engine Configuration file {}".format(audiopolicyengineconfigurationfile))
+ logging.info("Checking Audio Policy Engine Configuration file {}".format(
+ audiopolicyengineconfigurationfile))
#
# extract all product strategies name from audio policy engine configuration file
#
strategy_names = []
- oldWorkingDir = os.getcwd()
- print "Current working directory %s" % oldWorkingDir
+ old_working_dir = os.getcwd()
+ print("Current working directory %s" % old_working_dir)
- newDir = os.path.join(oldWorkingDir , audiopolicyengineconfigurationfile.name)
+ new_dir = os.path.join(old_working_dir, audiopolicyengineconfigurationfile.name)
policy_engine_in_tree = ET.parse(audiopolicyengineconfigurationfile)
- os.chdir(os.path.dirname(os.path.normpath(newDir)))
+ os.chdir(os.path.dirname(os.path.normpath(new_dir)))
- print "new working directory %s" % os.getcwd()
+ print("new working directory %s" % os.getcwd())
policy_engine_root = policy_engine_in_tree.getroot()
EI.include(policy_engine_root)
- os.chdir(oldWorkingDir)
+ os.chdir(old_working_dir)
for strategy in policy_engine_root.iter('ProductStrategy'):
strategy_names.append(strategy.get('name'))
@@ -128,7 +128,8 @@
logging.root.setLevel(logging.INFO)
args = parseArgs()
- strategies = parseAndroidAudioPolicyEngineConfigurationFile(args.audiopolicyengineconfigurationfile)
+ strategies = parseAndroidAudioPolicyEngineConfigurationFile(
+ args.audiopolicyengineconfigurationfile)
product_strategies_structure = args.productstrategiesstructurefile
diff --git a/services/audiopolicy/engineconfigurable/tools/build_audio_pfw_settings.mk b/services/audiopolicy/engineconfigurable/tools/build_audio_pfw_settings.mk
deleted file mode 100644
index ac60ef7..0000000
--- a/services/audiopolicy/engineconfigurable/tools/build_audio_pfw_settings.mk
+++ /dev/null
@@ -1,38 +0,0 @@
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_TAGS := optional
-LOCAL_ADDITIONAL_DEPENDENCIES += \
- $(HOST_OUT_EXECUTABLES)/domainGeneratorPolicy.py \
- $(PFW_TOPLEVEL_FILE) $(PFW_CRITERIA_FILE) $(PFW_CRITERION_TYPES_FILE)
-
-include $(BUILD_SYSTEM)/base_rules.mk
-
-$(LOCAL_BUILT_MODULE): MY_CRITERION_TYPES_FILE := $(PFW_CRITERION_TYPES_FILE)
-$(LOCAL_BUILT_MODULE): MY_TOOL := $(HOST_OUT_EXECUTABLES)/domainGeneratorPolicy.py
-$(LOCAL_BUILT_MODULE): MY_TOPLEVEL_FILE := $(PFW_TOPLEVEL_FILE)
-$(LOCAL_BUILT_MODULE): MY_CRITERIA_FILE := $(PFW_CRITERIA_FILE)
-$(LOCAL_BUILT_MODULE): MY_TUNING_FILE := $(PFW_TUNING_FILE)
-$(LOCAL_BUILT_MODULE): MY_EDD_FILES := $(PFW_EDD_FILES)
-$(LOCAL_BUILT_MODULE): MY_DOMAIN_FILES := $(PFW_DOMAIN_FILES)
-$(LOCAL_BUILT_MODULE): MY_SCHEMAS_DIR := $(PFW_SCHEMAS_DIR)
-$(LOCAL_BUILT_MODULE): MY_CRITERION_TYPES_FILE := $(PFW_CRITERION_TYPES_FILE)
-$(LOCAL_BUILT_MODULE): $(LOCAL_ADDITIONAL_DEPENDENCIES)
-
- "$(MY_TOOL)" --validate \
- --toplevel-config "$(MY_TOPLEVEL_FILE)" \
- --criteria "$(MY_CRITERIA_FILE)" \
- --criteriontypes "$(MY_CRITERION_TYPES_FILE)" \
- --initial-settings $(MY_TUNING_FILE) \
- --add-edds $(MY_EDD_FILES) \
- --add-domains $(MY_DOMAIN_FILES) \
- --schemas-dir $(MY_SCHEMAS_DIR) > "$@"
-
-
-# Clear variables for further use
-PFW_TOPLEVEL_FILE :=
-PFW_STRUCTURE_FILES :=
-PFW_CRITERIA_FILE :=
-PFW_CRITERION_TYPES_FILE :=
-PFW_TUNING_FILE :=
-PFW_EDD_FILES :=
-PFW_DOMAIN_FILES :=
-PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
diff --git a/services/audiopolicy/engineconfigurable/tools/domainGeneratorPolicy.py b/services/audiopolicy/engineconfigurable/tools/domainGeneratorPolicy.py
index 4dec9a2..b0c4b66 100755
--- a/services/audiopolicy/engineconfigurable/tools/domainGeneratorPolicy.py
+++ b/services/audiopolicy/engineconfigurable/tools/domainGeneratorPolicy.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
#
# Copyright 2018, The Android Open Source Project
@@ -16,12 +16,7 @@
# limitations under the License.
#
-import EddParser
-from PFWScriptGenerator import PfwScriptTranslator
-import hostConfig
-
import argparse
-import re
import sys
import tempfile
import os
@@ -29,6 +24,10 @@
import subprocess
import xml.etree.ElementTree as ET
+import EddParser
+from PFWScriptGenerator import PfwScriptTranslator
+import hostConfig
+
#
# In order to build the XML Settings file at build time, an instance of the parameter-framework
# shall be started and fed with all the criterion types/criteria that will be used by
@@ -39,61 +38,67 @@
def parseArgs():
argparser = argparse.ArgumentParser(description="Parameter-Framework XML \
- Settings file generator.\n\
- Exit with the number of (recoverable or not) error that occured.")
+ Settings file generator.\n\
+ Exit with the number of (recoverable or not) \
+ error that occured.")
+ argparser.add_argument('--domain-generator-tool',
+ help="ParameterFramework domain generator tool. Mandatory.",
+ metavar="PFW_DOMAIN_GENERATOR_TOOL",
+ required=True)
argparser.add_argument('--toplevel-config',
- help="Top-level parameter-framework configuration file. Mandatory.",
- metavar="TOPLEVEL_CONFIG_FILE",
- required=True)
+ help="Top-level parameter-framework configuration file. Mandatory.",
+ metavar="TOPLEVEL_CONFIG_FILE",
+ required=True)
argparser.add_argument('--criteria',
- help="Criteria file, in XML format: \
- in '<criteria> \
- <criterion name="" type=""/> \
- </criteria>' \
- format. Mandatory.",
- metavar="CRITERIA_FILE",
- type=argparse.FileType('r'),
- required=True)
+ help="Criteria file, in XML format: \
+ in '<criteria> \
+ <criterion name="" type=""/> \
+ </criteria>' \
+ format. Mandatory.",
+ metavar="CRITERIA_FILE",
+ type=argparse.FileType('r'),
+ required=True)
argparser.add_argument('--criteriontypes',
- help="Criterion types XML file, in \
- '<criterion_types> \
- <criterion_type name="" type=<inclusive|exclusive> values=<value1,value2,...>/> \
- </criterion_types>' \
- format. Mandatory.",
- metavar="CRITERION_TYPE_FILE",
- type=argparse.FileType('r'),
- required=False)
+ help="Criterion types XML file, in \
+ '<criterion_types> \
+ <criterion_type name="" type=<inclusive|exclusive> \
+ values=<value1,value2,...>/> \
+ </criterion_types>' \
+ format. Mandatory.",
+ metavar="CRITERION_TYPE_FILE",
+ type=argparse.FileType('r'),
+ required=False)
argparser.add_argument('--initial-settings',
- help="Initial XML settings file (containing a \
- <ConfigurableDomains> tag",
- nargs='?',
- default=None,
- metavar="XML_SETTINGS_FILE")
+ help="Initial XML settings file (containing a \
+ <ConfigurableDomains> tag",
+ nargs='?',
+ default=None,
+ metavar="XML_SETTINGS_FILE")
argparser.add_argument('--add-domains',
- help="List of single domain files (each containing a single \
- <ConfigurableDomain> tag",
- metavar="XML_DOMAIN_FILE",
- nargs='*',
- dest='xml_domain_files',
- default=[])
+ help="List of single domain files (each containing a single \
+ <ConfigurableDomain> tag",
+ metavar="XML_DOMAIN_FILE",
+ nargs='*',
+ dest='xml_domain_files',
+ default=[])
argparser.add_argument('--add-edds',
- help="List of files in EDD syntax (aka \".pfw\" files)",
- metavar="EDD_FILE",
- type=argparse.FileType('r'),
- nargs='*',
- default=[],
- dest='edd_files')
+ help="List of files in EDD syntax (aka \".pfw\" files)",
+ metavar="EDD_FILE",
+ type=argparse.FileType('r'),
+ nargs='*',
+ default=[],
+ dest='edd_files')
argparser.add_argument('--schemas-dir',
- help="Directory of parameter-framework XML Schemas for generation \
- validation",
- default=None)
+ help="Directory of parameter-framework XML Schemas for generation \
+ validation",
+ default=None)
argparser.add_argument('--target-schemas-dir',
- help="Ignored. Kept for retro-compatibility")
+ help="Ignored. Kept for retro-compatibility")
argparser.add_argument('--validate',
- help="Validate the settings against XML schemas",
- action='store_true')
+ help="Validate the settings against XML schemas",
+ action='store_true')
argparser.add_argument('--verbose',
- action='store_true')
+ action='store_true')
return argparser.parse_args()
@@ -112,7 +117,6 @@
logging.info("Importing criterionTypesFile {}".format(criterionTypesFile))
criteria_root = criteria_tree.getroot()
- criterion_types_root = criterion_types_tree.getroot()
all_criteria = []
for criterion in criteria_root.findall('criterion'):
@@ -165,7 +169,7 @@
try:
root.propagate()
- except EddParser.MyPropagationError, ex :
+ except EddParser.MyPropagationError as ex:
logging.critical(str(ex))
logging.info("EXIT ON FAILURE")
exit(1)
@@ -179,32 +183,32 @@
# It takes as input the collection of criteria, the domains and the simplified settings read from
# pfw.
#
-def generateDomainCommands(logging, all_criteria, initial_settings, xml_domain_files, parsed_edds):
- # create and inject all the criteria
- logging.info("Creating all criteria")
- for criterion in all_criteria:
- yield ["createSelectionCriterion", criterion['inclusive'],
- criterion['name']] + criterion['values']
+def generateDomainCommands(logger, all_criteria, initial_settings, xml_domain_files, parsed_edds):
+ # create and inject all the criteria
+ logger.info("Creating all criteria")
+ for criterion in all_criteria:
+ yield ["createSelectionCriterion", criterion['inclusive'],
+ criterion['name']] + criterion['values']
- yield ["start"]
+ yield ["start"]
- # Import initial settings file
- if initial_settings:
- logging.info("Importing initial settings file {}".format(initial_settings))
- yield ["importDomainsWithSettingsXML", initial_settings]
+ # Import initial settings file
+ if initial_settings:
+ logger.info("Importing initial settings file {}".format(initial_settings))
+ yield ["importDomainsWithSettingsXML", initial_settings]
- # Import each standalone domain files
- for domain_file in xml_domain_files:
- logging.info("Importing single domain file {}".format(domain_file))
- yield ["importDomainWithSettingsXML", domain_file]
+ # Import each standalone domain files
+ for domain_file in xml_domain_files:
+ logger.info("Importing single domain file {}".format(domain_file))
+ yield ["importDomainWithSettingsXML", domain_file]
- # Generate the script for each EDD file
- for filename, parsed_edd in parsed_edds:
- logging.info("Translating and injecting EDD file {}".format(filename))
- translator = PfwScriptTranslator()
- parsed_edd.translate(translator)
- for command in translator.getScript():
- yield command
+ # Generate the script for each EDD file
+ for filename, parsed_edd in parsed_edds:
+ logger.info("Translating and injecting EDD file {}".format(filename))
+ translator = PfwScriptTranslator()
+ parsed_edd.translate(translator)
+ for command in translator.getScript():
+ yield command
#
# Entry point of the domain generator.
@@ -232,30 +236,29 @@
prefix="TMPdomainGeneratorPFConfig_")
install_path = os.path.dirname(os.path.realpath(args.toplevel_config))
- hostConfig.configure(
- infile=args.toplevel_config,
- outfile=fake_toplevel_config,
- structPath=install_path)
+ hostConfig.configure(infile=args.toplevel_config,
+ outfile=fake_toplevel_config,
+ structPath=install_path)
fake_toplevel_config.close()
# Create the connector. Pipe its input to us in order to write commands;
# connect its output to stdout in order to have it dump the domains
# there; connect its error output to stderr.
- connector = subprocess.Popen(["domainGeneratorConnector",
- fake_toplevel_config.name,
- 'verbose' if args.verbose else 'no-verbose',
- 'validate' if args.validate else 'no-validate',
- args.schemas_dir],
- stdout=sys.stdout, stdin=subprocess.PIPE, stderr=sys.stderr)
+ connector = subprocess.Popen([args.domain_generator_tool,
+ fake_toplevel_config.name,
+ 'verbose' if args.verbose else 'no-verbose',
+ 'validate' if args.validate else 'no-validate',
+ args.schemas_dir],
+ stdout=sys.stdout, stdin=subprocess.PIPE, stderr=sys.stderr)
initial_settings = None
if args.initial_settings:
initial_settings = os.path.realpath(args.initial_settings)
for command in generateDomainCommands(logging, all_criteria, initial_settings,
- args.xml_domain_files, parsed_edds):
- connector.stdin.write('\0'.join(command))
- connector.stdin.write("\n")
+ args.xml_domain_files, parsed_edds):
+ connector.stdin.write('\0'.join(command).encode('utf-8'))
+ connector.stdin.write("\n".encode('utf-8'))
# Closing the connector's input triggers the domain generation
connector.stdin.close()
diff --git a/services/audiopolicy/engineconfigurable/tools/provision_criterion_types_from_android_headers.mk b/services/audiopolicy/engineconfigurable/tools/provision_criterion_types_from_android_headers.mk
deleted file mode 100644
index dab5a0f..0000000
--- a/services/audiopolicy/engineconfigurable/tools/provision_criterion_types_from_android_headers.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_TAGS := optional
-LOCAL_ADDITIONAL_DEPENDENCIES += \
- $(HOST_OUT_EXECUTABLES)/buildPolicyCriterionTypes.py \
- $(CRITERION_TYPES_FILE) $(AUDIO_POLICY_CONFIGURATION_FILE) \
- $(ANDROID_AUDIO_BASE_HEADER_FILE)
-
-include $(BUILD_SYSTEM)/base_rules.mk
-
-$(LOCAL_BUILT_MODULE): MY_CRITERION_TYPES_FILE := $(CRITERION_TYPES_FILE)
-$(LOCAL_BUILT_MODULE): MY_ANDROID_AUDIO_BASE_HEADER_FILE := $(ANDROID_AUDIO_BASE_HEADER_FILE)
-$(LOCAL_BUILT_MODULE): MY_AUDIO_POLICY_CONFIGURATION_FILE := $(AUDIO_POLICY_CONFIGURATION_FILE)
-$(LOCAL_BUILT_MODULE): MY_CRITERION_TOOL := $(HOST_OUT_EXECUTABLES)/buildPolicyCriterionTypes.py
-$(LOCAL_BUILT_MODULE): $(LOCAL_ADDITIONAL_DEPENDENCIES)
-
- "$(MY_CRITERION_TOOL)" \
- --androidaudiobaseheader "$(MY_ANDROID_AUDIO_BASE_HEADER_FILE)" \
- --audiopolicyconfigurationfile "$(MY_AUDIO_POLICY_CONFIGURATION_FILE)" \
- --criteriontypes "$(MY_CRITERION_TYPES_FILE)" \
- --outputfile "$(@)"
-
-# Clear variables for further use
-CRITERION_TYPES_FILE :=
-ANDROID_AUDIO_BASE_HEADER_FILE :=
-AUDIO_POLICY_CONFIGURATION_FILE :=
diff --git a/services/audiopolicy/engineconfigurable/tools/provision_strategies_structure.mk b/services/audiopolicy/engineconfigurable/tools/provision_strategies_structure.mk
deleted file mode 100644
index f2b1a19..0000000
--- a/services/audiopolicy/engineconfigurable/tools/provision_strategies_structure.mk
+++ /dev/null
@@ -1,21 +0,0 @@
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_TAGS := optional
-LOCAL_ADDITIONAL_DEPENDENCIES += \
- $(HOST_OUT_EXECUTABLES)/buildStrategiesStructureFile.py \
- $(STRATEGIES_STRUCTURE_FILE) $(AUDIO_POLICY_ENGINE_CONFIGURATION_FILE)
-
-include $(BUILD_SYSTEM)/base_rules.mk
-
-$(LOCAL_BUILT_MODULE): MY_STRATEGIES_STRUCTURE_FILE := $(STRATEGIES_STRUCTURE_FILE)
-$(LOCAL_BUILT_MODULE): MY_AUDIO_POLICY_ENGINE_CONFIGURATION_FILE := $(AUDIO_POLICY_ENGINE_CONFIGURATION_FILE)
-$(LOCAL_BUILT_MODULE): MY_PROVISION_TOOL := $(HOST_OUT_EXECUTABLES)/buildStrategiesStructureFile.py
-$(LOCAL_BUILT_MODULE): $(LOCAL_ADDITIONAL_DEPENDENCIES)
-
- "$(MY_PROVISION_TOOL)" \
- --audiopolicyengineconfigurationfile "$(MY_AUDIO_POLICY_ENGINE_CONFIGURATION_FILE)" \
- --productstrategiesstructurefile "$(MY_STRATEGIES_STRUCTURE_FILE)" \
- --outputfile "$(@)"
-
-# Clear variables for further use
-STRATEGIES_STRUCTURE_FILE :=
-AUDIO_POLICY_ENGINE_CONFIGURATION_FILE :=
diff --git a/services/audiopolicy/enginedefault/config/example/Android.bp b/services/audiopolicy/enginedefault/config/example/Android.bp
new file mode 100644
index 0000000..0bfcaa1
--- /dev/null
+++ b/services/audiopolicy/enginedefault/config/example/Android.bp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// Import this namespace in order to use AOSP Phone with Default Engine configuration example
+
+soong_namespace {
+}
+
+prebuilt_etc {
+ name: "audio_policy_engine_configuration.xml",
+ vendor: true,
+ src: "phone/audio_policy_engine_configuration.xml",
+ required: [
+ ":audio_policy_engine_stream_volumes.xml",
+ ":audio_policy_engine_default_stream_volumes.xml",
+ ":audio_policy_engine_product_strategies.xml",
+ ],
+}
+prebuilt_etc {
+ name: "audio_policy_engine_product_strategies.xml",
+ vendor: true,
+ src: "phone/audio_policy_engine_product_strategies.xml",
+}
+prebuilt_etc {
+ name: "audio_policy_engine_stream_volumes.xml",
+ vendor: true,
+ src: "phone/audio_policy_engine_stream_volumes.xml",
+}
+prebuilt_etc {
+ name: "audio_policy_engine_default_stream_volumes.xml",
+ vendor: true,
+ src: "phone/audio_policy_engine_default_stream_volumes.xml",
+}
diff --git a/services/audiopolicy/enginedefault/config/example/Android.mk b/services/audiopolicy/enginedefault/config/example/Android.mk
deleted file mode 100644
index 0badac8..0000000
--- a/services/audiopolicy/enginedefault/config/example/Android.mk
+++ /dev/null
@@ -1,48 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-##################################################################
-# CONFIGURATION TOP FILE
-##################################################################
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), phone_default)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_configuration.xml
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
-
-LOCAL_REQUIRED_MODULES := \
- audio_policy_engine_product_strategies.xml \
- audio_policy_engine_stream_volumes.xml \
- audio_policy_engine_default_stream_volumes.xml
-
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_product_strategies.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_stream_volumes.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_default_stream_volumes.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-endif # ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), phone_default)
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index a2b39dd..2a5cd49 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -31,6 +31,7 @@
#include <IOProfile.h>
#include <AudioIODescriptorInterface.h>
#include <policy.h>
+#include <media/AudioContainers.h>
#include <utils/String8.h>
#include <utils/Log.h>
@@ -146,7 +147,7 @@
switch (strategy) {
case STRATEGY_TRANSMITTED_THROUGH_SPEAKER:
- devices = availableOutputDevices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_SPEAKER);
+ devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
break;
case STRATEGY_SONIFICATION_RESPECTFUL:
@@ -161,7 +162,7 @@
toVolumeSource(AUDIO_STREAM_ACCESSIBILITY),
SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY);
// routing is same as media without the "remote" device
- availableOutputDevices.remove(availableOutputDevices.getDevicesFromTypeMask(
+ availableOutputDevices.remove(availableOutputDevices.getDevicesFromType(
AUDIO_DEVICE_OUT_REMOTE_SUBMIX));
devices = getDevicesForStrategyInt(STRATEGY_MEDIA,
availableOutputDevices,
@@ -171,7 +172,7 @@
if (!media_active_locally) {
devices.replaceDevicesByType(
AUDIO_DEVICE_OUT_SPEAKER,
- availableOutputDevices.getDevicesFromTypeMask(
+ availableOutputDevices.getDevicesFromType(
AUDIO_DEVICE_OUT_SPEAKER_SAFE));
}
}
@@ -196,6 +197,7 @@
audio_devices_t txDevice = getDeviceForInputSource(
AUDIO_SOURCE_VOICE_COMMUNICATION)->type();
sp<AudioOutputDescriptor> primaryOutput = outputs.getPrimaryOutput();
+ LOG_ALWAYS_FATAL_IF(primaryOutput == nullptr, "Primary output not found");
DeviceVector availPrimaryInputDevices =
availableInputDevices.getDevicesFromHwModule(primaryOutput->getModuleHandle());
@@ -203,10 +205,10 @@
// audio_policy_configuration.xml, hearing aid is not there, but it's
// a primary device
// FIXME: this is not the right way of solving this problem
- DeviceVector availPrimaryOutputDevices = availableOutputDevices.getDevicesFromTypeMask(
+ DeviceVector availPrimaryOutputDevices = availableOutputDevices.getDevicesFromTypes(
primaryOutput->supportedDevices().types());
availPrimaryOutputDevices.add(
- availableOutputDevices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_HEARING_AID));
+ availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_HEARING_AID));
if ((availableInputDevices.getDevice(AUDIO_DEVICE_IN_TELEPHONY_RX,
String8(""), AUDIO_FORMAT_DEFAULT) == nullptr) ||
@@ -221,7 +223,7 @@
switch (getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION)) {
case AUDIO_POLICY_FORCE_BT_SCO:
if (!isInCall() || strategy != STRATEGY_DTMF) {
- devices = availableOutputDevices.getDevicesFromTypeMask(
+ devices = availableOutputDevices.getDevicesFromType(
AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT);
if (!devices.isEmpty()) break;
}
@@ -232,7 +234,7 @@
FALLTHROUGH_INTENDED;
default: // FORCE_NONE
- devices = availableOutputDevices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_HEARING_AID);
+ devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_HEARING_AID);
if (!devices.isEmpty()) break;
// when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP
if (!isInCall() &&
@@ -254,7 +256,7 @@
AUDIO_DEVICE_OUT_AUX_DIGITAL, AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET});
if (!devices.isEmpty()) break;
}
- devices = availableOutputDevices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_EARPIECE);
+ devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_EARPIECE);
break;
case AUDIO_POLICY_FORCE_SPEAKER:
@@ -263,7 +265,7 @@
if (!isInCall() &&
(getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
outputs.isA2dpSupported()) {
- devices = availableOutputDevices.getDevicesFromTypeMask(
+ devices = availableOutputDevices.getDevicesFromType(
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER);
if (!devices.isEmpty()) break;
}
@@ -274,7 +276,7 @@
AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET});
if (!devices.isEmpty()) break;
}
- devices = availableOutputDevices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_SPEAKER);
+ devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
break;
}
break;
@@ -298,12 +300,12 @@
if ((strategy == STRATEGY_SONIFICATION) ||
(getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)) {
- devices = availableOutputDevices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_SPEAKER);
+ devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
}
// if SCO headset is connected and we are told to use it, play ringtone over
// speaker and BT SCO
- if (!availableOutputDevices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_ALL_SCO).isEmpty()) {
+ if (!availableOutputDevices.getDevicesFromTypes(getAudioDeviceOutAllScoSet()).isEmpty()) {
DeviceVector devices2;
devices2 = availableOutputDevices.getFirstDevicesFromTypes({
AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT, AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET,
@@ -324,7 +326,7 @@
if (strategy == STRATEGY_SONIFICATION) {
devices.replaceDevicesByType(
AUDIO_DEVICE_OUT_SPEAKER,
- availableOutputDevices.getDevicesFromTypeMask(
+ availableOutputDevices.getDevicesFromType(
AUDIO_DEVICE_OUT_SPEAKER_SAFE));
}
if (!devices2.isEmpty()) {
@@ -343,9 +345,9 @@
for (size_t i = 0; i < outputs.size(); i++) {
sp<AudioOutputDescriptor> desc = outputs.valueAt(i);
if (desc->isActive() && !audio_is_linear_pcm(desc->getFormat())) {
- availableOutputDevices.remove(desc->devices().getDevicesFromTypeMask(
- AUDIO_DEVICE_OUT_HDMI | AUDIO_DEVICE_OUT_SPDIF
- | AUDIO_DEVICE_OUT_HDMI_ARC));
+ availableOutputDevices.remove(desc->devices().getDevicesFromTypes({
+ AUDIO_DEVICE_OUT_HDMI, AUDIO_DEVICE_OUT_SPDIF,
+ AUDIO_DEVICE_OUT_HDMI_ARC}));
}
}
if (outputs.isActive(toVolumeSource(AUDIO_STREAM_RING)) ||
@@ -382,7 +384,7 @@
// FIXME: Find a better solution to prevent routing to BT hearing aid(b/122931261).
if ((devices2.isEmpty()) &&
(getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP)) {
- devices2 = availableOutputDevices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_HEARING_AID);
+ devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_HEARING_AID);
}
if ((devices2.isEmpty()) &&
(getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
@@ -393,7 +395,7 @@
}
if ((devices2.isEmpty()) &&
(getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) == AUDIO_POLICY_FORCE_SPEAKER)) {
- devices2 = availableOutputDevices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_SPEAKER);
+ devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
}
if (devices2.isEmpty()) {
devices2 = availableOutputDevices.getFirstDevicesFromTypes({
@@ -404,21 +406,21 @@
}
if ((devices2.isEmpty()) && (strategy != STRATEGY_SONIFICATION)) {
// no sonification on aux digital (e.g. HDMI)
- devices2 = availableOutputDevices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_AUX_DIGITAL);
+ devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_AUX_DIGITAL);
}
if ((devices2.isEmpty()) &&
(getForceUse(AUDIO_POLICY_FORCE_FOR_DOCK) == AUDIO_POLICY_FORCE_ANALOG_DOCK)) {
- devices2 = availableOutputDevices.getDevicesFromTypeMask(
+ devices2 = availableOutputDevices.getDevicesFromType(
AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET);
}
if (devices2.isEmpty()) {
- devices2 = availableOutputDevices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_SPEAKER);
+ devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
}
DeviceVector devices3;
if (strategy == STRATEGY_MEDIA) {
// ARC, SPDIF and AUX_LINE can co-exist with others.
- devices3 = availableOutputDevices.getDevicesFromTypeMask(
- AUDIO_DEVICE_OUT_HDMI_ARC | AUDIO_DEVICE_OUT_SPDIF | AUDIO_DEVICE_OUT_AUX_LINE);
+ devices3 = availableOutputDevices.getDevicesFromTypes({
+ AUDIO_DEVICE_OUT_HDMI_ARC, AUDIO_DEVICE_OUT_SPDIF, AUDIO_DEVICE_OUT_AUX_LINE});
}
devices2.add(devices3);
@@ -430,7 +432,7 @@
if ((strategy == STRATEGY_MEDIA) &&
(getForceUse(AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO) ==
AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED)) {
- devices.remove(devices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_SPEAKER));
+ devices.remove(devices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER));
}
// for STRATEGY_SONIFICATION:
@@ -438,7 +440,7 @@
if (strategy == STRATEGY_SONIFICATION) {
devices.replaceDevicesByType(
AUDIO_DEVICE_OUT_SPEAKER,
- availableOutputDevices.getDevicesFromTypeMask(
+ availableOutputDevices.getDevicesFromType(
AUDIO_DEVICE_OUT_SPEAKER_SAFE));
}
} break;
@@ -471,8 +473,8 @@
const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
DeviceVector availableDevices = availableInputDevices;
sp<AudioOutputDescriptor> primaryOutput = outputs.getPrimaryOutput();
- DeviceVector availablePrimaryDevices = availableInputDevices.getDevicesFromHwModule(
- primaryOutput->getModuleHandle());
+ DeviceVector availablePrimaryDevices = primaryOutput == nullptr ? DeviceVector()
+ : availableInputDevices.getDevicesFromHwModule(primaryOutput->getModuleHandle());
sp<DeviceDescriptor> device;
// when a call is active, force device selection to match source VOICE_COMMUNICATION
@@ -515,6 +517,7 @@
if ((getPhoneState() == AUDIO_MODE_IN_CALL) &&
(availableOutputDevices.getDevice(AUDIO_DEVICE_OUT_TELEPHONY_TX,
String8(""), AUDIO_FORMAT_DEFAULT)) == nullptr) {
+ LOG_ALWAYS_FATAL_IF(availablePrimaryDevices.isEmpty(), "Primary devices not found");
availableDevices = availablePrimaryDevices;
}
@@ -545,6 +548,9 @@
case AUDIO_SOURCE_UNPROCESSED:
case AUDIO_SOURCE_HOTWORD:
if (inputSource == AUDIO_SOURCE_HOTWORD) {
+ // We should not use primary output criteria for Hotword but rather limit
+ // to devices attached to the same HW module as the build in mic
+ LOG_ALWAYS_FATAL_IF(availablePrimaryDevices.isEmpty(), "Primary devices not found");
availableDevices = availablePrimaryDevices;
}
if (getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) == AUDIO_POLICY_FORCE_BT_SCO) {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index aec9cee..3223530 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -425,7 +425,7 @@
if (!audio_is_output_device(device) && !audio_is_input_device(device)) return BAD_VALUE;
// Check if the device is currently connected
- DeviceVector deviceList = mAvailableOutputDevices.getDevicesFromTypeMask(device);
+ DeviceVector deviceList = mAvailableOutputDevices.getDevicesFromType(device);
if (deviceList.empty()) {
// Nothing to do: device is not connected
return NO_ERROR;
@@ -439,8 +439,8 @@
// Case 1: A2DP active device switches from primary to primary
// module
// Case 2: A2DP device config changes on primary module.
- if (device & AUDIO_DEVICE_OUT_ALL_A2DP) {
- sp<HwModule> module = mHwModules.getModuleForDeviceTypes(device, encodedFormat);
+ if (audio_is_a2dp_out_device(device)) {
+ sp<HwModule> module = mHwModules.getModuleForDeviceType(device, encodedFormat);
audio_module_handle_t primaryHandle = mPrimaryOutput->getModuleHandle();
if (availablePrimaryOutputDevices().contains(devDesc) &&
(module != 0 && module->getHandle() == primaryHandle)) {
@@ -496,8 +496,8 @@
ALOGE("%s() unable to get primary module", __func__);
return NO_INIT;
}
- DeviceVector declaredDevices = primaryModule->getDeclaredDevices().getDevicesFromTypeMask(
- AUDIO_DEVICE_OUT_ALL_A2DP);
+ DeviceVector declaredDevices = primaryModule->getDeclaredDevices().getDevicesFromTypes(
+ getAudioDeviceOutAllA2dpSet());
for (const auto& device : declaredDevices) {
formatSet.insert(device->encodedFormats().begin(), device->encodedFormats().end());
}
@@ -511,7 +511,8 @@
bool createRxPatch = false;
uint32_t muteWaitMs = 0;
- if(!hasPrimaryOutput() || mPrimaryOutput->devices().types() == AUDIO_DEVICE_OUT_STUB) {
+ if(!hasPrimaryOutput() ||
+ mPrimaryOutput->devices().onlyContainsDevicesWithType(AUDIO_DEVICE_OUT_STUB)) {
return muteWaitMs;
}
ALOG_ASSERT(!rxDevices.isEmpty(), "updateCallRouting() no selected output device");
@@ -535,9 +536,9 @@
}
auto telephonyRxModule =
- mHwModules.getModuleForDeviceTypes(AUDIO_DEVICE_IN_TELEPHONY_RX, AUDIO_FORMAT_DEFAULT);
+ mHwModules.getModuleForDeviceType(AUDIO_DEVICE_IN_TELEPHONY_RX, AUDIO_FORMAT_DEFAULT);
auto telephonyTxModule =
- mHwModules.getModuleForDeviceTypes(AUDIO_DEVICE_OUT_TELEPHONY_TX, AUDIO_FORMAT_DEFAULT);
+ mHwModules.getModuleForDeviceType(AUDIO_DEVICE_OUT_TELEPHONY_TX, AUDIO_FORMAT_DEFAULT);
// retrieve Rx Source and Tx Sink device descriptors
sp<DeviceDescriptor> rxSourceDevice =
mAvailableInputDevices.getDevice(AUDIO_DEVICE_IN_TELEPHONY_RX,
@@ -648,20 +649,6 @@
return audioPatch;
}
-sp<DeviceDescriptor> AudioPolicyManager::findDevice(
- const DeviceVector& devices, audio_devices_t device) const {
- DeviceVector deviceList = devices.getDevicesFromTypeMask(device);
- ALOG_ASSERT(!deviceList.isEmpty(),
- "%s() selected device type %#x is not in devices list", __func__, device);
- return deviceList.itemAt(0);
-}
-
-audio_devices_t AudioPolicyManager::getModuleDeviceTypes(
- const DeviceVector& devices, const char *moduleId) const {
- sp<HwModule> mod = mHwModules.getModuleFromName(moduleId);
- return mod != 0 ? devices.getDeviceTypesFromHwModule(mod->getHandle()) : AUDIO_DEVICE_NONE;
-}
-
bool AudioPolicyManager::isDeviceOfModule(
const sp<DeviceDescriptor>& devDesc, const char *moduleId) const {
sp<HwModule> module = mHwModules.getModuleFromName(moduleId);
@@ -881,7 +868,7 @@
continue;
}
// reject profiles if connected device does not support codec
- if (!curProfile->deviceSupportsEncodedFormats(devices.types())) {
+ if (!curProfile->devicesSupportEncodedFormats(devices.types())) {
continue;
}
if (!directOnly) return curProfile;
@@ -1025,7 +1012,7 @@
// FIXME: provide a more generic approach which is not device specific and move this back
// to getOutputForDevice.
// TODO: Remove check of AUDIO_STREAM_MUSIC once migration is completed on the app side.
- if (outputDevices.types() == AUDIO_DEVICE_OUT_TELEPHONY_TX &&
+ if (outputDevices.onlyContainsDevicesWithType(AUDIO_DEVICE_OUT_TELEPHONY_TX) &&
(*stream == AUDIO_STREAM_MUSIC || resultAttr->usage == AUDIO_USAGE_VOICE_COMMUNICATION) &&
audio_is_linear_pcm(config->format) &&
isInCall()) {
@@ -1106,8 +1093,9 @@
}
audio_config_base_t clientConfig = {.sample_rate = config->sample_rate,
+ .channel_mask = config->channel_mask,
.format = config->format,
- .channel_mask = config->channel_mask };
+ };
*portId = PolicyAudioPort::getNextUniqueId();
sp<TrackClientDescriptor> clientDesc =
@@ -1234,7 +1222,7 @@
for (size_t j = 0; j < patch->mPatch.num_sinks; ++j) {
const struct audio_port_config *sink = &patch->mPatch.sinks[j];
if (sink->type == AUDIO_PORT_TYPE_DEVICE &&
- (sink->ext.device.type & devices.types()) != AUDIO_DEVICE_NONE &&
+ devices.containsDeviceWithType(sink->ext.device.type) &&
(address.isEmpty() || strncmp(sink->ext.device.address, address.string(),
AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0)) {
releaseAudioPatch(patch->mHandle, mUidCached);
@@ -1777,14 +1765,15 @@
}
if (stream == AUDIO_STREAM_ENFORCED_AUDIBLE &&
- mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) {
+ mEngine->getForceUse(
+ AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) {
setStrategyMute(streamToStrategy(AUDIO_STREAM_ALARM), true, outputDesc);
}
// Automatically enable the remote submix input when output is started on a re routing mix
// of type MIX_TYPE_RECORDERS
- if (audio_is_remote_submix_device(devices.types()) && policyMix != NULL &&
- policyMix->mMixType == MIX_TYPE_RECORDERS) {
+ if (isSingleDeviceType(devices.types(), &audio_is_remote_submix_device) &&
+ policyMix != NULL && policyMix->mMixType == MIX_TYPE_RECORDERS) {
setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
address,
@@ -1831,7 +1820,8 @@
// Automatically disable the remote submix input when output is stopped on a
// re routing mix of type MIX_TYPE_RECORDERS
sp<AudioPolicyMix> policyMix = outputDesc->mPolicyMix.promote();
- if (audio_is_remote_submix_device(outputDesc->devices().types()) &&
+ if (isSingleDeviceType(
+ outputDesc->devices().types(), &audio_is_remote_submix_device) &&
policyMix != NULL &&
policyMix->mMixType == MIX_TYPE_RECORDERS) {
setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
@@ -2491,10 +2481,12 @@
{
// if device is AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME, return volume for device selected for this
// stream by the engine.
+ DeviceTypeSet deviceTypes = {device};
if (device == AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
- device = mEngine->getOutputDevicesForStream(stream, true /*fromCache*/).types();
+ deviceTypes = mEngine->getOutputDevicesForStream(
+ stream, true /*fromCache*/).types();
}
- return getVolumeIndex(getVolumeCurves(stream), *index, device);
+ return getVolumeIndex(getVolumeCurves(stream), *index, deviceTypes);
}
status_t AudioPolicyManager::setVolumeIndexForAttributes(const audio_attributes_t &attributes,
@@ -2519,19 +2511,20 @@
return status;
}
- audio_devices_t curSrcDevice;
+ DeviceTypeSet curSrcDevices;
auto curCurvAttrs = curves.getAttributes();
if (!curCurvAttrs.empty() && curCurvAttrs.front() != defaultAttr) {
auto attr = curCurvAttrs.front();
- curSrcDevice = mEngine->getOutputDevicesForAttributes(attr, nullptr, false).types();
+ curSrcDevices = mEngine->getOutputDevicesForAttributes(attr, nullptr, false).types();
} else if (!curves.getStreamTypes().empty()) {
auto stream = curves.getStreamTypes().front();
- curSrcDevice = mEngine->getOutputDevicesForStream(stream, false).types();
+ curSrcDevices = mEngine->getOutputDevicesForStream(stream, false).types();
} else {
ALOGE("%s: Invalid src %d: no valid attributes nor stream",__func__, vs);
return BAD_VALUE;
}
- curSrcDevice = Volume::getDeviceForVolume(curSrcDevice);
+ audio_devices_t curSrcDevice = Volume::getDeviceForVolume(curSrcDevices);
+ resetDeviceTypes(curSrcDevices, curSrcDevice);
// update volume on all outputs and streams matching the following:
// - The requested stream (or a stream matching for volume control) is active on the output
@@ -2543,11 +2536,10 @@
// no specific device volume value exists for currently selected device.
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
- audio_devices_t curDevice = desc->devices().types();
+ DeviceTypeSet curDevices = desc->devices().types();
- if (curDevice & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
- curDevice |= AUDIO_DEVICE_OUT_SPEAKER;
- curDevice &= ~AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+ if (curDevices.erase(AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
+ curDevices.insert(AUDIO_DEVICE_OUT_SPEAKER);
}
// Inter / intra volume group priority management: Loop on strategies arranged by priority
@@ -2591,7 +2583,7 @@
if (!applyVolume) {
continue; // next output
}
- status_t volStatus = checkAndSetVolume(curves, vs, index, desc, curDevice,
+ status_t volStatus = checkAndSetVolume(curves, vs, index, desc, curDevices,
(vs == toVolumeSource(AUDIO_STREAM_SYSTEM)?
TOUCH_SOUND_FIXED_DELAY_MS : 0));
if (volStatus != NO_ERROR) {
@@ -2602,12 +2594,14 @@
if (!(desc->isActive(vs) || isInCall())) {
continue;
}
- if ((device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) && ((curDevice & device) == 0)) {
+ if (device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME &&
+ curDevices.find(device) == curDevices.end()) {
continue;
}
if (device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
- curSrcDevice |= device;
- applyVolume = (Volume::getDeviceForVolume(curDevice) & curSrcDevice) != 0;
+ curSrcDevices.insert(device);
+ applyVolume = (curSrcDevices.find(
+ Volume::getDeviceForVolume(curDevices)) != curSrcDevices.end());
} else {
applyVolume = !curves.hasVolumeIndexForDevice(curSrcDevice);
}
@@ -2616,7 +2610,7 @@
// delayed volume change for system stream to be removed when the problem is
// handled by system UI
status_t volStatus = checkAndSetVolume(
- curves, vs, index, desc, curDevice,
+ curves, vs, index, desc, curDevices,
((vs == toVolumeSource(AUDIO_STREAM_SYSTEM))?
TOUCH_SOUND_FIXED_DELAY_MS : 0));
if (volStatus != NO_ERROR) {
@@ -2659,22 +2653,23 @@
{
// if device is AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME, return volume for device selected for this
// stream by the engine.
+ DeviceTypeSet deviceTypes = {device};
if (device == AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
- device = mEngine->getOutputDevicesForAttributes(attr, nullptr, true /*fromCache*/).types();
+ DeviceTypeSet deviceTypes = mEngine->getOutputDevicesForAttributes(
+ attr, nullptr, true /*fromCache*/).types();
}
- return getVolumeIndex(getVolumeCurves(attr), index, device);
+ return getVolumeIndex(getVolumeCurves(attr), index, deviceTypes);
}
status_t AudioPolicyManager::getVolumeIndex(const IVolumeCurves &curves,
int &index,
- audio_devices_t device) const
+ const DeviceTypeSet& deviceTypes) const
{
- if (!audio_is_output_device(device)) {
+ if (isSingleDeviceType(deviceTypes, audio_is_output_device)) {
return BAD_VALUE;
}
- device = Volume::getDeviceForVolume(device);
- index = curves.getVolumeIndex(device);
- ALOGV("%s: device %08x index %d", __FUNCTION__, device, index);
+ index = curves.getVolumeIndex(deviceTypes);
+ ALOGV("%s: device %s index %d", __FUNCTION__, dumpDeviceTypes(deviceTypes).c_str(), index);
return NO_ERROR;
}
@@ -3438,8 +3433,8 @@
}
// TODO: reconfigure output format and channels here
- ALOGV("createAudioPatch() setting device %08x on output %d",
- devices.types(), outputDesc->mIoHandle);
+ ALOGV("createAudioPatch() setting device %s on output %d",
+ dumpDeviceTypes(devices.types()).c_str(), outputDesc->mIoHandle);
setOutputDevices(outputDesc, devices, true, 0, handle);
index = mAudioPatches.indexOfKey(*handle);
if (index >= 0) {
@@ -3919,12 +3914,14 @@
&selectedDeviceId, &isRequestedDeviceForExclusiveUse,
&secondaryOutputs);
if (output == AUDIO_IO_HANDLE_NONE) {
- ALOGV("%s no output for device %08x", __FUNCTION__, sinkDevices.types());
+ ALOGV("%s no output for device %s",
+ __FUNCTION__, dumpDeviceTypes(sinkDevices.types()).c_str());
return INVALID_OPERATION;
}
sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
if (outputDesc->isDuplicated()) {
- ALOGV("%s output for device %08x is duplicated", __FUNCTION__, sinkDevices.types());
+ ALOGV("%s output for device %s is duplicated",
+ __FUNCTION__, dumpDeviceTypes(sinkDevices.types()).c_str());
return INVALID_OPERATION;
}
status_t status = outputDesc->start();
@@ -4033,7 +4030,7 @@
float AudioPolicyManager::getStreamVolumeDB(
audio_stream_type_t stream, int index, audio_devices_t device)
{
- return computeVolume(getVolumeCurves(stream), toVolumeSource(stream), index, device);
+ return computeVolume(getVolumeCurves(stream), toVolumeSource(stream), index, {device});
}
status_t AudioPolicyManager::getSurroundFormats(unsigned int *numSurroundFormats,
@@ -4133,8 +4130,8 @@
sp<SwAudioOutputDescriptor> outputDesc;
bool profileUpdated = false;
- DeviceVector hdmiOutputDevices = mAvailableOutputDevices.getDevicesFromTypeMask(
- AUDIO_DEVICE_OUT_HDMI);
+ DeviceVector hdmiOutputDevices = mAvailableOutputDevices.getDevicesFromType(
+ AUDIO_DEVICE_OUT_HDMI);
for (size_t i = 0; i < hdmiOutputDevices.size(); i++) {
// Simulate reconnection to update enabled surround sound formats.
String8 address = String8(hdmiOutputDevices[i]->address().c_str());
@@ -4155,7 +4152,7 @@
profileUpdated |= (status == NO_ERROR);
}
// FIXME: Why doing this for input HDMI devices if we don't augment their reported formats?
- DeviceVector hdmiInputDevices = mAvailableInputDevices.getDevicesFromTypeMask(
+ DeviceVector hdmiInputDevices = mAvailableInputDevices.getDevicesFromType(
AUDIO_DEVICE_IN_HDMI);
for (size_t i = 0; i < hdmiInputDevices.size(); i++) {
// Simulate reconnection to update enabled surround sound formats.
@@ -4551,7 +4548,7 @@
const sp<SwAudioOutputDescriptor>& outputDesc)
{
mOutputs.add(output, outputDesc);
- applyStreamVolumes(outputDesc, AUDIO_DEVICE_NONE, 0 /* delayMs */, true /* force */);
+ applyStreamVolumes(outputDesc, DeviceTypeSet(), 0 /* delayMs */, true /* force */);
updateMono(output); // update mono status when adding to output list
selectOutputForMusicEffects();
nextAudioPortGeneration();
@@ -4588,7 +4585,7 @@
for (size_t i = 0; i < mOutputs.size(); i++) {
desc = mOutputs.valueAt(i);
if (!desc->isDuplicated() && desc->supportsDevice(device)
- && desc->deviceSupportsEncodedFormats(deviceType)) {
+ && desc->devicesSupportEncodedFormats({deviceType})) {
ALOGV("checkOutputsForDevice(): adding opened output %d on device %s",
mOutputs.keyAt(i), device->toString().c_str());
outputs.add(mOutputs.keyAt(i));
@@ -4753,7 +4750,7 @@
if (!desc->isDuplicated()) {
// exact match on device
if (device_distinguishes_on_address(deviceType) && desc->supportsDevice(device)
- && desc->deviceSupportsEncodedFormats(deviceType)) {
+ && desc->devicesSupportEncodedFormats({deviceType})) {
outputs.add(mOutputs.keyAt(i));
} else if (!mAvailableOutputDevices.containsAtLeastOne(desc->supportedDevices())) {
ALOGV("checkOutputsForDevice(): disconnecting adding output %d",
@@ -5024,7 +5021,7 @@
i, openOutputs.valueAt(i)->isDuplicated(),
openOutputs.valueAt(i)->supportedDevices().toString().c_str());
if (openOutputs.valueAt(i)->supportsAllDevices(devices)
- && openOutputs.valueAt(i)->deviceSupportsEncodedFormats(devices.types())) {
+ && openOutputs.valueAt(i)->devicesSupportEncodedFormats(devices.types())) {
ALOGVV("%s() found output %d", __func__, openOutputs.keyAt(i));
outputs.add(openOutputs.keyAt(i));
}
@@ -5199,9 +5196,8 @@
}
bool isScoConnected =
- ((mAvailableInputDevices.types() & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET &
- ~AUDIO_DEVICE_BIT_IN) != 0) ||
- ((mAvailableOutputDevices.types() & AUDIO_DEVICE_OUT_ALL_SCO) != 0);
+ (mAvailableInputDevices.types().count(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) != 0 ||
+ !Intersection(mAvailableOutputDevices.types(), getAudioDeviceOutAllScoSet()).empty());
// if suspended, restore A2DP output if:
// ((SCO device is NOT connected) ||
@@ -5363,12 +5359,13 @@
}
/*Filter SPEAKER_SAFE out of results, as AudioService doesn't know about it
and doesn't really need to.*/
- DeviceVector speakerSafeDevices = devices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_SPEAKER_SAFE);
+ DeviceVector speakerSafeDevices = devices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER_SAFE);
if (!speakerSafeDevices.isEmpty()) {
- devices.merge(mAvailableOutputDevices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_SPEAKER));
+ devices.merge(mAvailableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER));
devices.remove(speakerSafeDevices);
}
- return devices.types();
+ // FIXME: use DeviceTypeSet when Java layer is ready for it.
+ return deviceTypesToBitMask(devices.types());
}
void AudioPolicyManager::handleNotificationRoutingForStream(audio_stream_type_t stream) {
@@ -5428,7 +5425,7 @@
auto ttsVolumeSource = toVolumeSource(AUDIO_STREAM_TTS);
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
- setVolumeSourceMute(ttsVolumeSource, mute/*on*/, desc, 0 /*delay*/, AUDIO_DEVICE_NONE);
+ setVolumeSourceMute(ttsVolumeSource, mute/*on*/, desc, 0 /*delay*/, DeviceTypeSet());
const uint32_t latency = desc->latency() * 2;
if (latency > maxLatency) {
maxLatency = latency;
@@ -5744,9 +5741,9 @@
float AudioPolicyManager::computeVolume(IVolumeCurves &curves,
VolumeSource volumeSource,
int index,
- audio_devices_t device)
+ const DeviceTypeSet& deviceTypes)
{
- float volumeDb = curves.volIndexToDb(Volume::getDeviceCategory(device), index);
+ float volumeDb = curves.volIndexToDb(Volume::getDeviceCategory(deviceTypes), index);
// handle the case of accessibility active while a ringtone is playing: if the ringtone is much
// louder than the accessibility prompt, the prompt cannot be heard, thus masking the touch
@@ -5762,7 +5759,7 @@
&& (AUDIO_MODE_RINGTONE == mEngine->getPhoneState()) &&
mOutputs.isActive(ringVolumeSrc, 0)) {
auto &ringCurves = getVolumeCurves(AUDIO_STREAM_RING);
- const float ringVolumeDb = computeVolume(ringCurves, ringVolumeSrc, index, device);
+ const float ringVolumeDb = computeVolume(ringCurves, ringVolumeSrc, index, deviceTypes);
return ringVolumeDb - 4 > volumeDb ? ringVolumeDb - 4 : volumeDb;
}
@@ -5777,9 +5774,9 @@
volumeSource == toVolumeSource(AUDIO_STREAM_DTMF) ||
volumeSource == a11yVolumeSrc)) {
auto &voiceCurves = getVolumeCurves(callVolumeSrc);
- int voiceVolumeIndex = voiceCurves.getVolumeIndex(device);
+ int voiceVolumeIndex = voiceCurves.getVolumeIndex(deviceTypes);
const float maxVoiceVolDb =
- computeVolume(voiceCurves, callVolumeSrc, voiceVolumeIndex, device)
+ computeVolume(voiceCurves, callVolumeSrc, voiceVolumeIndex, deviceTypes)
+ IN_CALL_EARPIECE_HEADROOM_DB;
// FIXME: Workaround for call screening applications until a proper audio mode is defined
// to support this scenario : Exempt the RING stream from the audio cap if the audio was
@@ -5805,9 +5802,10 @@
// speaker is part of the select devices
// - if music is playing, always limit the volume to current music volume,
// with a minimum threshold at -36dB so that notification is always perceived.
- if ((device & (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP | AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
- AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
- AUDIO_DEVICE_OUT_USB_HEADSET | AUDIO_DEVICE_OUT_HEARING_AID)) &&
+ if (!Intersection(deviceTypes,
+ {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,
+ AUDIO_DEVICE_OUT_WIRED_HEADSET, AUDIO_DEVICE_OUT_WIRED_HEADPHONE,
+ AUDIO_DEVICE_OUT_USB_HEADSET, AUDIO_DEVICE_OUT_HEARING_AID}).empty() &&
((volumeSource == alarmVolumeSrc ||
volumeSource == ringVolumeSrc) ||
(volumeSource == toVolumeSource(AUDIO_STREAM_NOTIFICATION)) ||
@@ -5822,31 +5820,33 @@
if (isStreamActive(AUDIO_STREAM_MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY) ||
mLimitRingtoneVolume) {
volumeDb += SONIFICATION_HEADSET_VOLUME_FACTOR_DB;
- audio_devices_t musicDevice =
+ DeviceTypeSet musicDevice =
mEngine->getOutputDevicesForAttributes(attributes_initializer(AUDIO_USAGE_MEDIA),
nullptr, true /*fromCache*/).types();
auto &musicCurves = getVolumeCurves(AUDIO_STREAM_MUSIC);
- float musicVolDb = computeVolume(musicCurves, musicVolumeSrc,
- musicCurves.getVolumeIndex(musicDevice), musicDevice);
+ float musicVolDb = computeVolume(musicCurves,
+ musicVolumeSrc,
+ musicCurves.getVolumeIndex(musicDevice),
+ musicDevice);
float minVolDb = (musicVolDb > SONIFICATION_HEADSET_VOLUME_MIN_DB) ?
musicVolDb : SONIFICATION_HEADSET_VOLUME_MIN_DB;
if (volumeDb > minVolDb) {
volumeDb = minVolDb;
ALOGV("computeVolume limiting volume to %f musicVol %f", minVolDb, musicVolDb);
}
- if (device & (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
- AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES)) {
+ if (!Intersection(deviceTypes, {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES}).empty()) {
// on A2DP, also ensure notification volume is not too low compared to media when
// intended to be played
if ((volumeDb > -96.0f) &&
(musicVolDb - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB > volumeDb)) {
- ALOGV("%s increasing volume for volume source=%d device=0x%X from %f to %f",
- __func__, volumeSource, device, volumeDb,
+ ALOGV("%s increasing volume for volume source=%d device=%s from %f to %f",
+ __func__, volumeSource, dumpDeviceTypes(deviceTypes).c_str(), volumeDb,
musicVolDb - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB);
volumeDb = musicVolDb - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB;
}
}
- } else if ((Volume::getDeviceForVolume(device) != AUDIO_DEVICE_OUT_SPEAKER) ||
+ } else if ((Volume::getDeviceForVolume(deviceTypes) != AUDIO_DEVICE_OUT_SPEAKER) ||
(!(volumeSource == alarmVolumeSrc || volumeSource == ringVolumeSrc))) {
volumeDb += SONIFICATION_HEADSET_VOLUME_FACTOR_DB;
}
@@ -5885,7 +5885,7 @@
VolumeSource volumeSource,
int index,
const sp<AudioOutputDescriptor>& outputDesc,
- audio_devices_t device,
+ DeviceTypeSet deviceTypes,
int delayMs,
bool force)
{
@@ -5911,17 +5911,20 @@
volumeSource, forceUseForComm);
return INVALID_OPERATION;
}
- if (device == AUDIO_DEVICE_NONE) {
- device = outputDesc->devices().types();
+ if (deviceTypes.empty()) {
+ deviceTypes = outputDesc->devices().types();
}
- float volumeDb = computeVolume(curves, volumeSource, index, device);
- if (outputDesc->isFixedVolume(device) ||
+ float volumeDb = computeVolume(curves, volumeSource, index, deviceTypes);
+ if (outputDesc->isFixedVolume(deviceTypes) ||
// Force VoIP volume to max for bluetooth SCO
- ((isVoiceVolSrc || isBtScoVolSrc) && (device & AUDIO_DEVICE_OUT_ALL_SCO) != 0)) {
+
+ ((isVoiceVolSrc || isBtScoVolSrc) &&
+ isSingleDeviceType(deviceTypes, audio_is_bluetooth_out_sco_device))) {
volumeDb = 0.0f;
}
- outputDesc->setVolume(volumeDb, volumeSource, curves.getStreamTypes(), device, delayMs, force);
+ outputDesc->setVolume(
+ volumeDb, volumeSource, curves.getStreamTypes(), deviceTypes, delayMs, force);
if (isVoiceVolSrc || isBtScoVolSrc) {
float voiceVolume;
@@ -5940,15 +5943,16 @@
}
void AudioPolicyManager::applyStreamVolumes(const sp<AudioOutputDescriptor>& outputDesc,
- audio_devices_t device,
- int delayMs,
- bool force)
+ const DeviceTypeSet& deviceTypes,
+ int delayMs,
+ bool force)
{
ALOGVV("applyStreamVolumes() for device %08x", device);
for (const auto &volumeGroup : mEngine->getVolumeGroups()) {
auto &curves = getVolumeCurves(toVolumeSource(volumeGroup));
checkAndSetVolume(curves, toVolumeSource(volumeGroup),
- curves.getVolumeIndex(device), outputDesc, device, delayMs, force);
+ curves.getVolumeIndex(deviceTypes),
+ outputDesc, deviceTypes, delayMs, force);
}
}
@@ -5956,7 +5960,7 @@
bool on,
const sp<AudioOutputDescriptor>& outputDesc,
int delayMs,
- audio_devices_t device)
+ DeviceTypeSet deviceTypes)
{
std::vector<VolumeSource> sourcesToMute;
for (auto attributes: mEngine->getAllAttributesForProductStrategy(strategy)) {
@@ -5968,7 +5972,7 @@
}
}
for (auto source : sourcesToMute) {
- setVolumeSourceMute(source, on, outputDesc, delayMs, device);
+ setVolumeSourceMute(source, on, outputDesc, delayMs, deviceTypes);
}
}
@@ -5977,10 +5981,10 @@
bool on,
const sp<AudioOutputDescriptor>& outputDesc,
int delayMs,
- audio_devices_t device)
+ DeviceTypeSet deviceTypes)
{
- if (device == AUDIO_DEVICE_NONE) {
- device = outputDesc->devices().types();
+ if (deviceTypes.empty()) {
+ deviceTypes = outputDesc->devices().types();
}
auto &curves = getVolumeCurves(volumeSource);
if (on) {
@@ -5989,7 +5993,7 @@
(volumeSource != toVolumeSource(AUDIO_STREAM_ENFORCED_AUDIBLE) ||
(mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) ==
AUDIO_POLICY_FORCE_NONE))) {
- checkAndSetVolume(curves, volumeSource, 0, outputDesc, device, delayMs);
+ checkAndSetVolume(curves, volumeSource, 0, outputDesc, deviceTypes, delayMs);
}
}
// increment mMuteCount after calling checkAndSetVolume() so that volume change is not
@@ -6002,9 +6006,9 @@
}
if (outputDesc->decMuteCount(volumeSource) == 0) {
checkAndSetVolume(curves, volumeSource,
- curves.getVolumeIndex(device),
+ curves.getVolumeIndex(deviceTypes),
outputDesc,
- device,
+ deviceTypes,
delayMs);
}
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 93d67ea..707e4b0 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -176,7 +176,7 @@
IVolumeCurves &volumeCurves);
status_t getVolumeIndex(const IVolumeCurves &curves, int &index,
- audio_devices_t device) const;
+ const DeviceTypeSet& deviceTypes) const;
// return the strategy corresponding to a given stream type
virtual uint32_t getStrategyForStream(audio_stream_type_t stream)
@@ -346,7 +346,7 @@
}
virtual const DeviceVector getAvailableOutputDevices() const
{
- return mAvailableOutputDevices;
+ return mAvailableOutputDevices.filterForEngine();
}
virtual const DeviceVector getAvailableInputDevices() const
{
@@ -422,7 +422,7 @@
virtual float computeVolume(IVolumeCurves &curves,
VolumeSource volumeSource,
int index,
- audio_devices_t device);
+ const DeviceTypeSet& deviceTypes);
// rescale volume index from srcStream within range of dstStream
int rescaleVolumeIndex(int srcIndex,
@@ -432,12 +432,13 @@
virtual status_t checkAndSetVolume(IVolumeCurves &curves,
VolumeSource volumeSource, int index,
const sp<AudioOutputDescriptor>& outputDesc,
- audio_devices_t device,
+ DeviceTypeSet deviceTypes,
int delayMs = 0, bool force = false);
// apply all stream volumes to the specified output and device
void applyStreamVolumes(const sp<AudioOutputDescriptor>& outputDesc,
- audio_devices_t device, int delayMs = 0, bool force = false);
+ const DeviceTypeSet& deviceTypes,
+ int delayMs = 0, bool force = false);
/**
* @brief setStrategyMute Mute or unmute all active clients on the considered output
@@ -452,7 +453,7 @@
bool on,
const sp<AudioOutputDescriptor>& outputDesc,
int delayMs = 0,
- audio_devices_t device = AUDIO_DEVICE_NONE);
+ DeviceTypeSet deviceTypes = DeviceTypeSet());
/**
* @brief setVolumeSourceMute Mute or unmute the volume source on the specified output
@@ -467,7 +468,7 @@
bool on,
const sp<AudioOutputDescriptor>& outputDesc,
int delayMs = 0,
- audio_devices_t device = AUDIO_DEVICE_NONE);
+ DeviceTypeSet deviceTypes = DeviceTypeSet());
audio_mode_t getPhoneState();
@@ -653,10 +654,6 @@
uint32_t updateCallRouting(const DeviceVector &rxDevices, uint32_t delayMs = 0);
sp<AudioPatch> createTelephonyPatch(bool isRx, const sp<DeviceDescriptor> &device,
uint32_t delayMs);
- sp<DeviceDescriptor> findDevice(
- const DeviceVector& devices, audio_devices_t device) const;
- audio_devices_t getModuleDeviceTypes(
- const DeviceVector& devices, const char *moduleId) const;
bool isDeviceOfModule(const sp<DeviceDescriptor>& devDesc, const char *moduleId) const;
status_t startSource(const sp<SwAudioOutputDescriptor>& outputDesc,
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 7dfc205..2319838 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -422,12 +422,18 @@
// AND is on TOP
// AND the source is VOICE_RECOGNITION or HOTWORD
// OR the client source is virtual (remote submix, call audio TX or RX...)
+// OR the client source is HOTWORD
+// AND is on TOP
+// OR all active clients are using HOTWORD source
+// AND no call is active
+// OR client has CAPTURE_AUDIO_OUTPUT privileged permission
// OR Any client
// AND The assistant is not on TOP
// AND is on TOP or latest started
// AND there is no active privacy sensitive capture or call
// OR client has CAPTURE_AUDIO_OUTPUT privileged permission
+
sp<AudioRecordClient> topActive;
sp<AudioRecordClient> latestActive;
sp<AudioRecordClient> latestSensitiveActive;
@@ -442,6 +448,7 @@
bool rttCallActive =
(mPhoneState == AUDIO_MODE_IN_CALL || mPhoneState == AUDIO_MODE_IN_COMMUNICATION)
&& mUidPolicy->isRttEnabled();
+ bool onlyHotwordActive = true;
// if Sensor Privacy is enabled then all recordings should be silenced.
if (mSensorPrivacyPolicy->isSensorPrivacyEnabled()) {
@@ -473,12 +480,11 @@
isAssistantOnTop = true;
}
}
- // Assistant capturing for HOTWORD or Accessibility services not considered
+ // Client capturing for HOTWORD or Accessibility services not considered
// for latest active to avoid masking regular clients started before
if (current->startTimeNs > latestStartNs
- && !((current->attributes.source == AUDIO_SOURCE_HOTWORD
- || isA11yOnTop || rttCallActive)
- && isAssistant)
+ && !(current->attributes.source == AUDIO_SOURCE_HOTWORD
+ || ((isA11yOnTop || rttCallActive) && isAssistant))
&& !isAccessibility) {
latestActive = current;
latestStartNs = current->startTimeNs;
@@ -490,6 +496,9 @@
}
isSensitiveActive = true;
}
+ if (current->attributes.source != AUDIO_SOURCE_HOTWORD) {
+ onlyHotwordActive = false;
+ }
}
// if no active client with UI on Top, consider latest active as top
@@ -556,6 +565,14 @@
allowCapture = true;
}
}
+ } else if (source == AUDIO_SOURCE_HOTWORD) {
+ // For HOTWORD source allow capture when not on TOP if:
+ // All active clients are using HOTWORD source
+ // AND no call is active
+ // OR client has CAPTURE_AUDIO_OUTPUT privileged permission
+ if (onlyHotwordActive && !(isInCall && !current->canCaptureOutput)) {
+ allowCapture = true;
+ }
}
setAppState_l(current->portId,
allowCapture ? apmStatFromAmState(mUidPolicy->getUidState(current->uid)) :
diff --git a/services/audiopolicy/tests/Android.bp b/services/audiopolicy/tests/Android.bp
index df23410..efdb241 100644
--- a/services/audiopolicy/tests/Android.bp
+++ b/services/audiopolicy/tests/Android.bp
@@ -39,22 +39,27 @@
}
-// system/audio.h utilities test
cc_test {
- name: "systemaudio_tests",
+ name: "audio_health_tests",
shared_libs: [
"libaudiofoundation",
- "libbase",
+ "libaudioclient",
+ "libaudiopolicymanagerdefault",
"liblog",
"libmedia_helper",
"libutils",
],
- header_libs: ["libmedia_headers"],
+ static_libs: ["libaudiopolicycomponents"],
- srcs: ["systemaudio_tests.cpp"],
+ header_libs: [
+ "libaudiopolicyengine_interface_headers",
+ "libaudiopolicymanager_interface_headers",
+ ],
+
+ srcs: ["audio_health_tests.cpp"],
cflags: [
"-Werror",
diff --git a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
new file mode 100644
index 0000000..afe6f20
--- /dev/null
+++ b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <map>
+
+#include <system/audio.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include "AudioPolicyTestClient.h"
+
+namespace android {
+
+class AudioPolicyManagerTestClient : public AudioPolicyTestClient {
+public:
+ // AudioPolicyClientInterface implementation
+ audio_module_handle_t loadHwModule(const char * /*name*/) override {
+ return mNextModuleHandle++;
+ }
+
+ status_t openOutput(audio_module_handle_t module,
+ audio_io_handle_t *output,
+ audio_config_t * /*config*/,
+ audio_devices_t * /*devices*/,
+ const String8 & /*address*/,
+ uint32_t * /*latencyMs*/,
+ audio_output_flags_t /*flags*/) override {
+ if (module >= mNextModuleHandle) {
+ ALOGE("%s: Module handle %d has not been allocated yet (next is %d)",
+ __func__, module, mNextModuleHandle);
+ return BAD_VALUE;
+ }
+ *output = mNextIoHandle++;
+ return NO_ERROR;
+ }
+
+ audio_io_handle_t openDuplicateOutput(audio_io_handle_t /*output1*/,
+ audio_io_handle_t /*output2*/) override {
+ audio_io_handle_t id = mNextIoHandle++;
+ return id;
+ }
+
+ status_t openInput(audio_module_handle_t module,
+ audio_io_handle_t *input,
+ audio_config_t * /*config*/,
+ audio_devices_t * /*device*/,
+ const String8 & /*address*/,
+ audio_source_t /*source*/,
+ audio_input_flags_t /*flags*/) override {
+ if (module >= mNextModuleHandle) {
+ ALOGE("%s: Module handle %d has not been allocated yet (next is %d)",
+ __func__, module, mNextModuleHandle);
+ return BAD_VALUE;
+ }
+ *input = mNextIoHandle++;
+ return NO_ERROR;
+ }
+
+ status_t createAudioPatch(const struct audio_patch *patch,
+ audio_patch_handle_t *handle,
+ int /*delayMs*/) override {
+ *handle = mNextPatchHandle++;
+ mActivePatches.insert(std::make_pair(*handle, *patch));
+ return NO_ERROR;
+ }
+
+ status_t releaseAudioPatch(audio_patch_handle_t handle,
+ int /*delayMs*/) override {
+ if (mActivePatches.erase(handle) != 1) {
+ if (handle >= mNextPatchHandle) {
+ ALOGE("%s: Patch handle %d has not been allocated yet (next is %d)",
+ __func__, handle, mNextPatchHandle);
+ } else {
+ ALOGE("%s: Attempt to release patch %d twice", __func__, handle);
+ }
+ return BAD_VALUE;
+ }
+ return NO_ERROR;
+ }
+
+ // Helper methods for tests
+ size_t getActivePatchesCount() const { return mActivePatches.size(); }
+
+ const struct audio_patch *getLastAddedPatch() const {
+ if (mActivePatches.empty()) {
+ return nullptr;
+ }
+ auto it = --mActivePatches.end();
+ return &it->second;
+ };
+
+private:
+ audio_module_handle_t mNextModuleHandle = AUDIO_MODULE_HANDLE_NONE + 1;
+ audio_io_handle_t mNextIoHandle = AUDIO_IO_HANDLE_NONE + 1;
+ audio_patch_handle_t mNextPatchHandle = AUDIO_PATCH_HANDLE_NONE + 1;
+ std::map<audio_patch_handle_t, struct audio_patch> mActivePatches;
+};
+
+} // namespace android
diff --git a/services/audiopolicy/tests/AudioPolicyTestManager.h b/services/audiopolicy/tests/AudioPolicyTestManager.h
index ba1412b..bafcc63 100644
--- a/services/audiopolicy/tests/AudioPolicyTestManager.h
+++ b/services/audiopolicy/tests/AudioPolicyTestManager.h
@@ -24,6 +24,7 @@
explicit AudioPolicyTestManager(AudioPolicyClientInterface *clientInterface)
: AudioPolicyManager(clientInterface, true /*forTesting*/) { }
using AudioPolicyManager::getConfig;
+ using AudioPolicyManager::loadConfig;
using AudioPolicyManager::initialize;
using AudioPolicyManager::getOutputs;
};
diff --git a/services/audiopolicy/tests/audio_health_tests.cpp b/services/audiopolicy/tests/audio_health_tests.cpp
new file mode 100644
index 0000000..8736cf1
--- /dev/null
+++ b/services/audiopolicy/tests/audio_health_tests.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2019 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 "AudioPolicy_Boot_Test"
+
+#include <unordered_set>
+
+#include <gtest/gtest.h>
+
+#include <media/AudioSystem.h>
+#include <system/audio.h>
+#include <utils/Log.h>
+
+#include "AudioPolicyManagerTestClient.h"
+#include "AudioPolicyTestManager.h"
+
+using namespace android;
+
+TEST(AudioHealthTest, AttachedDeviceFound) {
+ unsigned int numPorts;
+ unsigned int generation1;
+ unsigned int generation;
+ struct audio_port *audioPorts = NULL;
+ int attempts = 10;
+ do {
+ if (attempts-- < 0) {
+ free(audioPorts);
+ GTEST_FAIL() << "Query audio ports time out";
+ }
+ numPorts = 0;
+ ASSERT_EQ(NO_ERROR, AudioSystem::listAudioPorts(
+ AUDIO_PORT_ROLE_NONE, AUDIO_PORT_TYPE_DEVICE, &numPorts, NULL, &generation1));
+ if (numPorts == 0) {
+ free(audioPorts);
+ GTEST_FAIL() << "Number of audio ports should not be zero";
+ }
+
+ audioPorts = (struct audio_port *)realloc(audioPorts, numPorts * sizeof(struct audio_port));
+ status_t status = AudioSystem::listAudioPorts(
+ AUDIO_PORT_ROLE_NONE, AUDIO_PORT_TYPE_DEVICE, &numPorts, audioPorts, &generation);
+ if (status != NO_ERROR) {
+ free(audioPorts);
+ GTEST_FAIL() << "Query audio ports failed";
+ }
+ } while (generation1 != generation);
+ std::unordered_set<audio_devices_t> attachedDevices;
+ for (int i = 0 ; i < numPorts; i++) {
+ attachedDevices.insert(audioPorts[i].ext.device.type);
+ }
+ free(audioPorts);
+
+ AudioPolicyManagerTestClient client;
+ AudioPolicyTestManager manager(&client);
+ manager.loadConfig();
+ ASSERT_NE("AudioPolicyConfig::setDefault", manager.getConfig().getSource());
+
+ for (auto desc : manager.getConfig().getAvailableInputDevices()) {
+ ASSERT_NE(attachedDevices.end(), attachedDevices.find(desc->type()));
+ }
+ for (auto desc : manager.getConfig().getAvailableOutputDevices()) {
+ ASSERT_NE(attachedDevices.end(), attachedDevices.find(desc->type()));
+ }
+}
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index d3d839e..1ee1eea 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#include <map>
#include <memory>
#include <string>
#include <sys/wait.h>
@@ -32,6 +31,7 @@
#include <utils/Vector.h>
#include "AudioPolicyInterface.h"
+#include "AudioPolicyManagerTestClient.h"
#include "AudioPolicyTestClient.h"
#include "AudioPolicyTestManager.h"
@@ -57,91 +57,6 @@
}
-class AudioPolicyManagerTestClient : public AudioPolicyTestClient {
- public:
- // AudioPolicyClientInterface implementation
- audio_module_handle_t loadHwModule(const char* /*name*/) override {
- return mNextModuleHandle++;
- }
-
- status_t openOutput(audio_module_handle_t module,
- audio_io_handle_t* output,
- audio_config_t* /*config*/,
- audio_devices_t* /*devices*/,
- const String8& /*address*/,
- uint32_t* /*latencyMs*/,
- audio_output_flags_t /*flags*/) override {
- if (module >= mNextModuleHandle) {
- ALOGE("%s: Module handle %d has not been allocated yet (next is %d)",
- __func__, module, mNextModuleHandle);
- return BAD_VALUE;
- }
- *output = mNextIoHandle++;
- return NO_ERROR;
- }
-
- audio_io_handle_t openDuplicateOutput(audio_io_handle_t /*output1*/,
- audio_io_handle_t /*output2*/) override {
- audio_io_handle_t id = mNextIoHandle++;
- return id;
- }
-
- status_t openInput(audio_module_handle_t module,
- audio_io_handle_t* input,
- audio_config_t* /*config*/,
- audio_devices_t* /*device*/,
- const String8& /*address*/,
- audio_source_t /*source*/,
- audio_input_flags_t /*flags*/) override {
- if (module >= mNextModuleHandle) {
- ALOGE("%s: Module handle %d has not been allocated yet (next is %d)",
- __func__, module, mNextModuleHandle);
- return BAD_VALUE;
- }
- *input = mNextIoHandle++;
- return NO_ERROR;
- }
-
- status_t createAudioPatch(const struct audio_patch* patch,
- audio_patch_handle_t* handle,
- int /*delayMs*/) override {
- *handle = mNextPatchHandle++;
- mActivePatches.insert(std::make_pair(*handle, *patch));
- return NO_ERROR;
- }
-
- status_t releaseAudioPatch(audio_patch_handle_t handle,
- int /*delayMs*/) override {
- if (mActivePatches.erase(handle) != 1) {
- if (handle >= mNextPatchHandle) {
- ALOGE("%s: Patch handle %d has not been allocated yet (next is %d)",
- __func__, handle, mNextPatchHandle);
- } else {
- ALOGE("%s: Attempt to release patch %d twice", __func__, handle);
- }
- return BAD_VALUE;
- }
- return NO_ERROR;
- }
-
- // Helper methods for tests
- size_t getActivePatchesCount() const { return mActivePatches.size(); }
-
- const struct audio_patch* getLastAddedPatch() const {
- if (mActivePatches.empty()) {
- return nullptr;
- }
- auto it = --mActivePatches.end();
- return &it->second;
- };
-
- private:
- audio_module_handle_t mNextModuleHandle = AUDIO_MODULE_HANDLE_NONE + 1;
- audio_io_handle_t mNextIoHandle = AUDIO_IO_HANDLE_NONE + 1;
- audio_patch_handle_t mNextPatchHandle = AUDIO_PATCH_HANDLE_NONE + 1;
- std::map<audio_patch_handle_t, struct audio_patch> mActivePatches;
-};
-
class PatchCountCheck {
public:
explicit PatchCountCheck(AudioPolicyManagerTestClient *client)
diff --git a/services/audiopolicy/tests/systemaudio_tests.cpp b/services/audiopolicy/tests/systemaudio_tests.cpp
deleted file mode 100644
index 1e4d07f..0000000
--- a/services/audiopolicy/tests/systemaudio_tests.cpp
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <unordered_set>
-
-#include <gtest/gtest.h>
-
-#define LOG_TAG "SysAudio_Test"
-#include <log/log.h>
-#include <media/PatchBuilder.h>
-#include <system/audio.h>
-
-using namespace android;
-
-TEST(SystemAudioTest, PatchInvalid) {
- audio_patch patch{};
- ASSERT_FALSE(audio_patch_is_valid(&patch));
- patch.num_sources = AUDIO_PATCH_PORTS_MAX + 1;
- patch.num_sinks = 1;
- ASSERT_FALSE(audio_patch_is_valid(&patch));
- patch.num_sources = 1;
- patch.num_sinks = AUDIO_PATCH_PORTS_MAX + 1;
- ASSERT_FALSE(audio_patch_is_valid(&patch));
- patch.num_sources = 0;
- patch.num_sinks = 1;
- ASSERT_FALSE(audio_patch_is_valid(&patch));
-}
-
-TEST(SystemAudioTest, PatchValid) {
- const audio_port_config src = {
- .id = 1, .role = AUDIO_PORT_ROLE_SOURCE, .type = AUDIO_PORT_TYPE_DEVICE };
- // It's OK not to have sinks.
- ASSERT_TRUE(audio_patch_is_valid((PatchBuilder{}).addSource(src).patch()));
- const audio_port_config sink = {
- .id = 2, .role = AUDIO_PORT_ROLE_SINK, .type = AUDIO_PORT_TYPE_DEVICE };
- ASSERT_TRUE(audio_patch_is_valid((PatchBuilder{}).addSource(src).addSink(sink).patch()));
- ASSERT_TRUE(audio_patch_is_valid(
- (PatchBuilder{}).addSource(src).addSource(src).addSink(sink).patch()));
- ASSERT_TRUE(audio_patch_is_valid(
- (PatchBuilder{}).addSource(src).addSink(sink).addSink(sink).patch()));
- ASSERT_TRUE(audio_patch_is_valid(
- (PatchBuilder{}).addSource(src).addSource(src).
- addSink(sink).addSink(sink).patch()));
-}
-
-TEST(SystemAudioTest, PatchHwAvSync) {
- audio_port_config device_src_cfg = {
- .id = 1, .role = AUDIO_PORT_ROLE_SOURCE, .type = AUDIO_PORT_TYPE_DEVICE };
- ASSERT_FALSE(audio_port_config_has_hw_av_sync(&device_src_cfg));
- device_src_cfg.config_mask |= AUDIO_PORT_CONFIG_FLAGS;
- ASSERT_FALSE(audio_port_config_has_hw_av_sync(&device_src_cfg));
- device_src_cfg.flags.input = AUDIO_INPUT_FLAG_HW_AV_SYNC;
- ASSERT_TRUE(audio_port_config_has_hw_av_sync(&device_src_cfg));
-
- audio_port_config device_sink_cfg = {
- .id = 1, .role = AUDIO_PORT_ROLE_SINK, .type = AUDIO_PORT_TYPE_DEVICE };
- ASSERT_FALSE(audio_port_config_has_hw_av_sync(&device_sink_cfg));
- device_sink_cfg.config_mask |= AUDIO_PORT_CONFIG_FLAGS;
- ASSERT_FALSE(audio_port_config_has_hw_av_sync(&device_sink_cfg));
- device_sink_cfg.flags.output = AUDIO_OUTPUT_FLAG_HW_AV_SYNC;
- ASSERT_TRUE(audio_port_config_has_hw_av_sync(&device_sink_cfg));
-
- audio_port_config mix_sink_cfg = {
- .id = 1, .role = AUDIO_PORT_ROLE_SINK, .type = AUDIO_PORT_TYPE_MIX };
- ASSERT_FALSE(audio_port_config_has_hw_av_sync(&mix_sink_cfg));
- mix_sink_cfg.config_mask |= AUDIO_PORT_CONFIG_FLAGS;
- ASSERT_FALSE(audio_port_config_has_hw_av_sync(&mix_sink_cfg));
- mix_sink_cfg.flags.input = AUDIO_INPUT_FLAG_HW_AV_SYNC;
- ASSERT_TRUE(audio_port_config_has_hw_av_sync(&mix_sink_cfg));
-
- audio_port_config mix_src_cfg = {
- .id = 1, .role = AUDIO_PORT_ROLE_SOURCE, .type = AUDIO_PORT_TYPE_MIX };
- ASSERT_FALSE(audio_port_config_has_hw_av_sync(&mix_src_cfg));
- mix_src_cfg.config_mask |= AUDIO_PORT_CONFIG_FLAGS;
- ASSERT_FALSE(audio_port_config_has_hw_av_sync(&mix_src_cfg));
- mix_src_cfg.flags.output = AUDIO_OUTPUT_FLAG_HW_AV_SYNC;
- ASSERT_TRUE(audio_port_config_has_hw_av_sync(&mix_src_cfg));
-}
-
-TEST(SystemAudioTest, PatchEqual) {
- const audio_patch patch1{}, patch2{};
- // Invalid patches are not equal.
- ASSERT_FALSE(audio_patches_are_equal(&patch1, &patch2));
- const audio_port_config src = {
- .id = 1, .role = AUDIO_PORT_ROLE_SOURCE, .type = AUDIO_PORT_TYPE_DEVICE };
- const audio_port_config sink = {
- .id = 2, .role = AUDIO_PORT_ROLE_SINK, .type = AUDIO_PORT_TYPE_DEVICE };
- ASSERT_FALSE(audio_patches_are_equal(
- (PatchBuilder{}).addSource(src).patch(),
- (PatchBuilder{}).addSource(src).addSink(sink).patch()));
- ASSERT_TRUE(audio_patches_are_equal(
- (PatchBuilder{}).addSource(src).addSink(sink).patch(),
- (PatchBuilder{}).addSource(src).addSink(sink).patch()));
- ASSERT_FALSE(audio_patches_are_equal(
- (PatchBuilder{}).addSource(src).addSink(sink).patch(),
- (PatchBuilder{}).addSource(src).addSource(src).addSink(sink).patch()));
- audio_port_config sink_hw_av_sync = sink;
- sink_hw_av_sync.config_mask |= AUDIO_PORT_CONFIG_FLAGS;
- sink_hw_av_sync.flags.output = AUDIO_OUTPUT_FLAG_HW_AV_SYNC;
- ASSERT_FALSE(audio_patches_are_equal(
- (PatchBuilder{}).addSource(src).addSink(sink).patch(),
- (PatchBuilder{}).addSource(src).addSink(sink_hw_av_sync).patch()));
- ASSERT_TRUE(audio_patches_are_equal(
- (PatchBuilder{}).addSource(src).addSink(sink_hw_av_sync).patch(),
- (PatchBuilder{}).addSource(src).addSink(sink_hw_av_sync).patch()));
-}
-
-void runAudioDeviceTypeHelperFunction(const std::unordered_set<audio_devices_t>& allDevices,
- const audio_devices_t targetDevices[],
- unsigned int targetDeviceCount,
- const std::string& deviceTag,
- bool (*device_type_helper_function)(audio_devices_t))
-{
- std::unordered_set<audio_devices_t> devices(targetDevices, targetDevices + targetDeviceCount);
- for (auto device : allDevices) {
- if (devices.find(device) == devices.end()) {
- ASSERT_FALSE(device_type_helper_function(device))
- << std::hex << device << " should not be " << deviceTag << " device";
- } else {
- ASSERT_TRUE(device_type_helper_function(device))
- << std::hex << device << " should be " << deviceTag << " device";
- }
- }
-}
-
-TEST(SystemAudioTest, AudioDeviceTypeHelperFunction) {
- std::unordered_set<audio_devices_t> allDeviceTypes;
- allDeviceTypes.insert(std::begin(AUDIO_DEVICE_OUT_ALL_ARRAY),
- std::end(AUDIO_DEVICE_OUT_ALL_ARRAY));
- allDeviceTypes.insert(std::begin(AUDIO_DEVICE_IN_ALL_ARRAY),
- std::end(AUDIO_DEVICE_IN_ALL_ARRAY));
-
- runAudioDeviceTypeHelperFunction(allDeviceTypes, AUDIO_DEVICE_OUT_ALL_ARRAY,
- std::size(AUDIO_DEVICE_OUT_ALL_ARRAY), "output", audio_is_output_device);
- runAudioDeviceTypeHelperFunction(allDeviceTypes, AUDIO_DEVICE_IN_ALL_ARRAY,
- std::size(AUDIO_DEVICE_IN_ALL_ARRAY), "input", audio_is_input_device);
- runAudioDeviceTypeHelperFunction(allDeviceTypes, AUDIO_DEVICE_OUT_ALL_A2DP_ARRAY,
- std::size(AUDIO_DEVICE_OUT_ALL_A2DP_ARRAY), "a2dp out", audio_is_a2dp_out_device);
- const audio_devices_t bluetoothInA2dpDevices[] = { AUDIO_DEVICE_IN_BLUETOOTH_A2DP };
- runAudioDeviceTypeHelperFunction(allDeviceTypes, bluetoothInA2dpDevices,
- std::size(bluetoothInA2dpDevices), "a2dp in", audio_is_a2dp_in_device);
- runAudioDeviceTypeHelperFunction(allDeviceTypes, AUDIO_DEVICE_OUT_ALL_SCO_ARRAY,
- std::size(AUDIO_DEVICE_OUT_ALL_SCO_ARRAY), "bluetooth out sco",
- audio_is_bluetooth_out_sco_device);
- runAudioDeviceTypeHelperFunction(allDeviceTypes, AUDIO_DEVICE_IN_ALL_SCO_ARRAY,
- std::size(AUDIO_DEVICE_IN_ALL_SCO_ARRAY), "bluetooth in sco",
- audio_is_bluetooth_in_sco_device);
- const unsigned int scoDeviceCount = AUDIO_DEVICE_OUT_SCO_CNT + AUDIO_DEVICE_IN_SCO_CNT;
- audio_devices_t scoDevices[scoDeviceCount];
- std::copy(std::begin(AUDIO_DEVICE_OUT_ALL_SCO_ARRAY), std::end(AUDIO_DEVICE_OUT_ALL_SCO_ARRAY),
- std::begin(scoDevices));
- std::copy(std::begin(AUDIO_DEVICE_IN_ALL_SCO_ARRAY), std::end(AUDIO_DEVICE_IN_ALL_SCO_ARRAY),
- std::begin(scoDevices) + AUDIO_DEVICE_OUT_SCO_CNT);
- runAudioDeviceTypeHelperFunction(allDeviceTypes, scoDevices,
- std::size(scoDevices), "bluetooth sco", audio_is_bluetooth_sco_device);
- const audio_devices_t hearingAidOutDevices[] = { AUDIO_DEVICE_OUT_HEARING_AID };
- runAudioDeviceTypeHelperFunction(allDeviceTypes, hearingAidOutDevices,
- std::size(hearingAidOutDevices), "hearing aid out", audio_is_hearing_aid_out_device);
- runAudioDeviceTypeHelperFunction(allDeviceTypes, AUDIO_DEVICE_OUT_ALL_USB_ARRAY,
- std::size(AUDIO_DEVICE_OUT_ALL_USB_ARRAY), "usb out", audio_is_usb_out_device);
- runAudioDeviceTypeHelperFunction(allDeviceTypes, AUDIO_DEVICE_IN_ALL_USB_ARRAY,
- std::size(AUDIO_DEVICE_IN_ALL_USB_ARRAY), "usb in", audio_is_usb_in_device);
- const audio_devices_t remoteSubmixDevices[] = {
- AUDIO_DEVICE_IN_REMOTE_SUBMIX, AUDIO_DEVICE_OUT_REMOTE_SUBMIX };
- runAudioDeviceTypeHelperFunction(allDeviceTypes, remoteSubmixDevices,
- std::size(remoteSubmixDevices), "remote submix", audio_is_remote_submix_device);
- runAudioDeviceTypeHelperFunction(allDeviceTypes, AUDIO_DEVICE_OUT_ALL_DIGITAL_ARRAY,
- std::size(AUDIO_DEVICE_OUT_ALL_DIGITAL_ARRAY), "digital out",
- audio_is_digital_out_device);
- runAudioDeviceTypeHelperFunction(allDeviceTypes, AUDIO_DEVICE_IN_ALL_DIGITAL_ARRAY,
- std::size(AUDIO_DEVICE_IN_ALL_DIGITAL_ARRAY), "digital in",
- audio_is_digital_in_device);
- const unsigned int digitalDeviceCount
- = AUDIO_DEVICE_OUT_DIGITAL_CNT + AUDIO_DEVICE_IN_DIGITAL_CNT;
- audio_devices_t digitalDevices[digitalDeviceCount];
- std::copy(std::begin(AUDIO_DEVICE_OUT_ALL_DIGITAL_ARRAY),
- std::end(AUDIO_DEVICE_OUT_ALL_DIGITAL_ARRAY),
- std::begin(digitalDevices));
- std::copy(std::begin(AUDIO_DEVICE_IN_ALL_DIGITAL_ARRAY),
- std::end(AUDIO_DEVICE_IN_ALL_DIGITAL_ARRAY),
- std::begin(digitalDevices) + AUDIO_DEVICE_OUT_DIGITAL_CNT);
- runAudioDeviceTypeHelperFunction(allDeviceTypes, digitalDevices,
- std::size(digitalDevices), "digital", audio_device_is_digital);
-}
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index b26398e..c50a3c6 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -69,6 +69,10 @@
"utils/LatencyHistogram.cpp",
],
+ header_libs: [
+ "libmediadrm_headers"
+ ],
+
shared_libs: [
"libbase",
"libdl",
@@ -88,6 +92,7 @@
"libhardware",
"libhidlbase",
"libjpeg",
+ "libmedia_codeclist",
"libmedia_omx",
"libmemunreachable",
"libsensorprivacy",
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 94642f2..a02178e 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -268,8 +268,12 @@
const std::vector<std::string> &normalDeviceIds) {
mNormalDeviceIdsWithoutSystemCamera.clear();
for (auto &deviceId : normalDeviceIds) {
- if (getSystemCameraKind(String8(deviceId.c_str())) ==
- SystemCameraKind::SYSTEM_ONLY_CAMERA) {
+ SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
+ if (getSystemCameraKind(String8(deviceId.c_str()), &deviceKind) != OK) {
+ ALOGE("%s: Invalid camera id %s, skipping", __FUNCTION__, deviceId.c_str());
+ continue;
+ }
+ if (deviceKind == SystemCameraKind::SYSTEM_ONLY_CAMERA) {
// All system camera ids will necessarily come after public camera
// device ids as per the HAL interface contract.
break;
@@ -280,6 +284,16 @@
mNormalDeviceIdsWithoutSystemCamera.size());
}
+status_t CameraService::getSystemCameraKind(const String8& cameraId, SystemCameraKind *kind) const {
+ auto state = getCameraState(cameraId);
+ if (state != nullptr) {
+ *kind = state->getSystemCameraKind();
+ return OK;
+ }
+ // Hidden physical camera ids won't have CameraState
+ return mCameraProviderManager->getSystemCameraKind(cameraId.c_str(), kind);
+}
+
void CameraService::updateCameraNumAndIds() {
Mutex::Autolock l(mServiceLock);
std::pair<int, int> systemAndNonSystemCameras = mCameraProviderManager->getCameraCount();
@@ -296,10 +310,16 @@
std::string cameraId(id.c_str());
hardware::camera::common::V1_0::CameraResourceCost cost;
status_t res = mCameraProviderManager->getResourceCost(cameraId, &cost);
+ SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
if (res != OK) {
ALOGE("Failed to query device resource cost: %s (%d)", strerror(-res), res);
return;
}
+ res = mCameraProviderManager->getSystemCameraKind(cameraId, &deviceKind);
+ if (res != OK) {
+ ALOGE("Failed to query device kind: %s (%d)", strerror(-res), res);
+ return;
+ }
std::set<String8> conflicting;
for (size_t i = 0; i < cost.conflictingDevices.size(); i++) {
conflicting.emplace(String8(cost.conflictingDevices[i].c_str()));
@@ -308,7 +328,7 @@
{
Mutex::Autolock lock(mCameraStatesLock);
mCameraStates.emplace(id, std::make_shared<CameraState>(id, cost.resourceCost,
- conflicting));
+ conflicting, deviceKind));
}
if (mFlashlight->hasFlashUnit(id)) {
@@ -594,7 +614,12 @@
"characteristics for device %s: %s (%d)", String8(cameraId).string(),
strerror(-res), res);
}
-
+ SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
+ if (getSystemCameraKind(String8(cameraId), &deviceKind) != OK) {
+ ALOGE("%s: Invalid camera id %s, skipping", __FUNCTION__, String8(cameraId).string());
+ return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Unable to retrieve camera kind "
+ "for device %s", String8(cameraId).string());
+ }
int callingPid = CameraThreadState::getCallingPid();
int callingUid = CameraThreadState::getCallingUid();
std::vector<int32_t> tagsRemoved;
@@ -602,7 +627,7 @@
// android.permission.CAMERA is required. If android.permission.SYSTEM_CAMERA was needed,
// it would've already been checked in shouldRejectSystemCameraConnection.
if ((callingPid != getpid()) &&
- (getSystemCameraKind(String8(cameraId)) != SystemCameraKind::SYSTEM_ONLY_CAMERA) &&
+ (deviceKind != SystemCameraKind::SYSTEM_ONLY_CAMERA) &&
!checkPermission(sCameraPermission, callingPid, callingUid)) {
res = cameraInfo->removePermissionEntries(
mCameraProviderManager->getProviderTagIdLocked(String8(cameraId).string()),
@@ -1049,11 +1074,19 @@
return STATUS_ERROR_FMT(ERROR_DISCONNECTED, "No camera device with ID \"%s\" is"
"available", cameraId.string());
}
+ SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
+ if (getSystemCameraKind(cameraId, &deviceKind) != OK) {
+ ALOGE("%s: Invalid camera id %s, skipping", __FUNCTION__, cameraId.string());
+ return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT, "No camera device with ID \"%s\""
+ "found while trying to query device kind", cameraId.string());
+
+ }
+
// If it's not calling from cameraserver, check the permission if the
// device isn't a system only camera (shouldRejectSystemCameraConnection already checks for
// android.permission.SYSTEM_CAMERA for system only camera devices).
if (callingPid != getpid() &&
- (getSystemCameraKind(cameraId) != SystemCameraKind::SYSTEM_ONLY_CAMERA) &&
+ (deviceKind != SystemCameraKind::SYSTEM_ONLY_CAMERA) &&
!checkPermission(sCameraPermission, clientPid, clientUid)) {
ALOGE("Permission Denial: can't use the camera pid=%d, uid=%d", clientPid, clientUid);
return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
@@ -1407,9 +1440,8 @@
return ret;
}
-bool CameraService::shouldSkipStatusUpdates(const String8& cameraId, bool isVendorListener,
- int clientPid, int clientUid) const {
- SystemCameraKind systemCameraKind = getSystemCameraKind(cameraId);
+bool CameraService::shouldSkipStatusUpdates(SystemCameraKind systemCameraKind,
+ bool isVendorListener, int clientPid, int clientUid) {
// If the client is not a vendor client, don't add listener if
// a) the camera is a publicly hidden secure camera OR
// b) the camera is a system only camera and the client doesn't
@@ -1435,7 +1467,11 @@
int cPid = CameraThreadState::getCallingPid();
int cUid = CameraThreadState::getCallingUid();
- SystemCameraKind systemCameraKind = getSystemCameraKind(cameraId);
+ SystemCameraKind systemCameraKind = SystemCameraKind::PUBLIC;
+ if (getSystemCameraKind(cameraId, &systemCameraKind) != OK) {
+ ALOGE("%s: Invalid camera id %s, ", __FUNCTION__, cameraId.c_str());
+ return true;
+ }
// (1) Cameraserver trying to connect, accept.
if (CameraThreadState::getCallingPid() == getpid()) {
@@ -1926,14 +1962,24 @@
{
Mutex::Autolock lock(mCameraStatesLock);
for (auto& i : mCameraStates) {
- if (shouldSkipStatusUpdates(i.first, isVendorListener, clientPid, clientUid)) {
- ALOGV("Cannot add public listener for hidden system-only %s for pid %d",
- i.first.c_str(), CameraThreadState::getCallingPid());
- continue;
- }
cameraStatuses->emplace_back(i.first, mapToInterface(i.second->getStatus()));
}
}
+ // Remove the camera statuses that should be hidden from the client, we do
+ // this after collecting the states in order to avoid holding
+ // mCameraStatesLock and mInterfaceLock (held in getSystemCameraKind()) at
+ // the same time.
+ cameraStatuses->erase(std::remove_if(cameraStatuses->begin(), cameraStatuses->end(),
+ [this, &isVendorListener, &clientPid, &clientUid](const hardware::CameraStatus& s) {
+ SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
+ if (getSystemCameraKind(s.cameraId, &deviceKind) != OK) {
+ ALOGE("%s: Invalid camera id %s, skipping status update",
+ __FUNCTION__, s.cameraId.c_str());
+ return true;
+ }
+ return shouldSkipStatusUpdates(deviceKind, isVendorListener, clientPid,
+ clientUid);}), cameraStatuses->end());
+
/*
* Immediately signal current torch status to this listener only
@@ -3023,8 +3069,9 @@
// ----------------------------------------------------------------------------
CameraService::CameraState::CameraState(const String8& id, int cost,
- const std::set<String8>& conflicting) : mId(id),
- mStatus(StatusInternal::NOT_PRESENT), mCost(cost), mConflicting(conflicting) {}
+ const std::set<String8>& conflicting, SystemCameraKind systemCameraKind) : mId(id),
+ mStatus(StatusInternal::NOT_PRESENT), mCost(cost), mConflicting(conflicting),
+ mSystemCameraKind(systemCameraKind) {}
CameraService::CameraState::~CameraState() {}
@@ -3053,6 +3100,10 @@
return mId;
}
+SystemCameraKind CameraService::CameraState::getSystemCameraKind() const {
+ return mSystemCameraKind;
+}
+
// ----------------------------------------------------------------------------
// ClientEventListener
// ----------------------------------------------------------------------------
@@ -3391,9 +3442,16 @@
return;
}
+ // Avoid calling getSystemCameraKind() with mStatusListenerLock held (b/141756275)
+ SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
+ if (getSystemCameraKind(cameraId, &deviceKind) != OK) {
+ ALOGE("%s: Invalid camera id %s, skipping", __FUNCTION__, cameraId.string());
+ return;
+ }
+
// Update the status for this camera state, then send the onStatusChangedCallbacks to each
// of the listeners with both the mStatusStatus and mStatusListenerLock held
- state->updateStatus(status, cameraId, rejectSourceStates, [this]
+ state->updateStatus(status, cameraId, rejectSourceStates, [this, &deviceKind]
(const String8& cameraId, StatusInternal status) {
if (status != StatusInternal::ENUMERATING) {
@@ -3415,7 +3473,7 @@
Mutex::Autolock lock(mStatusListenerLock);
for (auto& listener : mListenerList) {
- if (shouldSkipStatusUpdates(cameraId, listener->isVendorListener(),
+ if (shouldSkipStatusUpdates(deviceKind, listener->isVendorListener(),
listener->getListenerPid(), listener->getListenerUid())) {
ALOGV("Skipping camera discovery callback for system-only camera %s",
cameraId.c_str());
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 058d57e..8765fbf 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -490,7 +490,8 @@
* Make a new CameraState and set the ID, cost, and conflicting devices using the values
* returned in the HAL's camera_info struct for each device.
*/
- CameraState(const String8& id, int cost, const std::set<String8>& conflicting);
+ CameraState(const String8& id, int cost, const std::set<String8>& conflicting,
+ SystemCameraKind deviceKind);
virtual ~CameraState();
/**
@@ -542,6 +543,11 @@
*/
String8 getId() const;
+ /**
+ * Return the kind (SystemCameraKind) of this camera device.
+ */
+ SystemCameraKind getSystemCameraKind() const;
+
private:
const String8 mId;
StatusInternal mStatus; // protected by mStatusLock
@@ -549,6 +555,7 @@
std::set<String8> mConflicting;
mutable Mutex mStatusLock;
CameraParameters mShimParams;
+ const SystemCameraKind mSystemCameraKind;
}; // class CameraState
// Observer for UID lifecycle enforcing that UIDs in idle
@@ -660,12 +667,14 @@
// Should a device status update be skipped for a particular camera device ? (this can happen
// under various conditions. For example if a camera device is advertised as
// system only or hidden secure camera, amongst possible others.
- bool shouldSkipStatusUpdates(const String8& cameraId, bool isVendorListener, int clientPid,
- int clientUid) const;
+ static bool shouldSkipStatusUpdates(SystemCameraKind systemCameraKind, bool isVendorListener,
+ int clientPid, int clientUid);
- inline SystemCameraKind getSystemCameraKind(const String8& cameraId) const {
- return mCameraProviderManager->getSystemCameraKind(cameraId.c_str());
- }
+ // Gets the kind of camera device (i.e public, hidden secure or system only)
+ // getSystemCameraKind() needs mInterfaceMutex which might lead to deadlocks
+ // if held along with mStatusListenerLock (depending on lock ordering, b/141756275), it is
+ // recommended that we don't call this function with mStatusListenerLock held.
+ status_t getSystemCameraKind(const String8& cameraId, SystemCameraKind *kind) const;
// Update the set of API1Compatible camera devices without including system
// cameras and secure cameras. This is used for hiding system only cameras
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index d93d26f..08fb153 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -2032,6 +2032,15 @@
}
}
+ for (size_t i = 0; i < mCompositeStreamMap.size(); i++) {
+ auto ret = mCompositeStreamMap.valueAt(i)->deleteInternalStreams();
+ if (ret != OK) {
+ ALOGE("%s: Failed removing composite stream %s (%d)", __FUNCTION__,
+ strerror(-ret), ret);
+ }
+ }
+ mCompositeStreamMap.clear();
+
Camera2ClientBase::detachDevice();
}
diff --git a/services/camera/libcameraservice/api2/DepthCompositeStream.cpp b/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
index 8ebaa2b..0b91016 100644
--- a/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
@@ -247,7 +247,7 @@
return ret;
}
-status_t DepthCompositeStream::processInputFrame(const InputFrame &inputFrame) {
+status_t DepthCompositeStream::processInputFrame(nsecs_t ts, const InputFrame &inputFrame) {
status_t res;
sp<ANativeWindow> outputANW = mOutputSurface;
ANativeWindowBuffer *anb;
@@ -370,6 +370,13 @@
return NO_MEMORY;
}
+ res = native_window_set_buffers_timestamp(mOutputSurface.get(), ts);
+ if (res != OK) {
+ ALOGE("%s: Stream %d: Error setting timestamp: %s (%d)", __FUNCTION__,
+ getStreamId(), strerror(-res), res);
+ return res;
+ }
+
ALOGV("%s: Final jpeg size: %zu", __func__, finalJpegSize);
uint8_t* header = static_cast<uint8_t *> (dstBuffer) +
(gb->getWidth() - sizeof(struct camera3_jpeg_blob));
@@ -459,7 +466,7 @@
}
}
- auto res = processInputFrame(mPendingInputFrames[currentTs]);
+ auto res = processInputFrame(currentTs, mPendingInputFrames[currentTs]);
Mutex::Autolock l(mMutex);
if (res != OK) {
ALOGE("%s: Failed processing frame with timestamp: %" PRIu64 ": %s (%d)", __FUNCTION__,
diff --git a/services/camera/libcameraservice/api2/DepthCompositeStream.h b/services/camera/libcameraservice/api2/DepthCompositeStream.h
index 975c59b..28a7826 100644
--- a/services/camera/libcameraservice/api2/DepthCompositeStream.h
+++ b/services/camera/libcameraservice/api2/DepthCompositeStream.h
@@ -97,7 +97,7 @@
size_t maxJpegSize, uint8_t jpegQuality,
std::vector<std::unique_ptr<Item>>* items /*out*/);
std::unique_ptr<ImagingModel> getImagingModel();
- status_t processInputFrame(const InputFrame &inputFrame);
+ status_t processInputFrame(nsecs_t ts, const InputFrame &inputFrame);
// Buffer/Results handling
void compilePendingInputLocked();
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
index 678d1a2..4088e92 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
@@ -28,7 +28,7 @@
#include <utils/Log.h>
#include <utils/Trace.h>
-#include <media/ICrypto.h>
+#include <mediadrm/ICrypto.h>
#include <media/MediaCodecBuffer.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/MediaDefs.h>
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 974026c..7ed4c3d 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -110,7 +110,12 @@
int publicCameraCount = 0;
for (auto& provider : mProviders) {
for (auto &id : provider->mUniqueCameraIds) {
- switch(getSystemCameraKindLocked(id)) {
+ SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
+ if (getSystemCameraKindLocked(id, &deviceKind) != OK) {
+ ALOGE("%s: Invalid camera id %s, skipping", __FUNCTION__, id.c_str());
+ continue;
+ }
+ switch(deviceKind) {
case SystemCameraKind::PUBLIC:
publicCameraCount++;
break;
@@ -140,7 +145,12 @@
std::vector<std::string>& publicDeviceIds,
std::vector<std::string>& systemDeviceIds) const {
for (auto &deviceId : deviceIds) {
- if (getSystemCameraKindLocked(deviceId) == SystemCameraKind::SYSTEM_ONLY_CAMERA) {
+ SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
+ if (getSystemCameraKindLocked(deviceId, &deviceKind) != OK) {
+ ALOGE("%s: Invalid camera id %s, skipping", __FUNCTION__, deviceId.c_str());
+ continue;
+ }
+ if (deviceKind == SystemCameraKind::SYSTEM_ONLY_CAMERA) {
systemDeviceIds.push_back(deviceId);
} else {
publicDeviceIds.push_back(deviceId);
@@ -158,9 +168,13 @@
// Secure cameras should not be exposed through camera 1 api
providerDeviceIds.erase(std::remove_if(providerDeviceIds.begin(), providerDeviceIds.end(),
[this](const std::string& s) {
- bool rem = this->getSystemCameraKindLocked(s) ==
- SystemCameraKind::HIDDEN_SECURE_CAMERA;
- return rem;}), providerDeviceIds.end());
+ SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
+ if (getSystemCameraKindLocked(s, &deviceKind) != OK) {
+ ALOGE("%s: Invalid camera id %s, skipping", __FUNCTION__, s.c_str());
+ return true;
+ }
+ return deviceKind == SystemCameraKind::HIDDEN_SECURE_CAMERA;}),
+ providerDeviceIds.end());
// API1 app doesn't handle logical and physical camera devices well. So
// for each camera facing, only take the first id advertised by HAL in
// all [logical, physical1, physical2, ...] id combos, and filter out the rest.
@@ -1089,26 +1103,45 @@
return deviceInfo->mIsLogicalCamera;
}
-SystemCameraKind CameraProviderManager::getSystemCameraKind(const std::string& id) const {
+status_t CameraProviderManager::getSystemCameraKind(const std::string& id,
+ SystemCameraKind *kind) const {
std::lock_guard<std::mutex> lock(mInterfaceMutex);
- return getSystemCameraKindLocked(id);
+ return getSystemCameraKindLocked(id, kind);
}
-SystemCameraKind CameraProviderManager::getSystemCameraKindLocked(const std::string& id) const {
+status_t CameraProviderManager::getSystemCameraKindLocked(const std::string& id,
+ SystemCameraKind *kind) const {
auto deviceInfo = findDeviceInfoLocked(id);
- if (deviceInfo == nullptr) {
- return SystemCameraKind::PUBLIC;
+ if (deviceInfo != nullptr) {
+ *kind = deviceInfo->mSystemCameraKind;
+ return OK;
}
- return deviceInfo->mSystemCameraKind;
+ // If this is a hidden physical camera, we should return what kind of
+ // camera the enclosing logical camera is.
+ auto isHiddenAndParent = isHiddenPhysicalCameraInternal(id);
+ if (isHiddenAndParent.first) {
+ LOG_ALWAYS_FATAL_IF(id == isHiddenAndParent.second->mId,
+ "%s: hidden physical camera id %s and enclosing logical camera id %s are the same",
+ __FUNCTION__, id.c_str(), isHiddenAndParent.second->mId.c_str());
+ return getSystemCameraKindLocked(isHiddenAndParent.second->mId, kind);
+ }
+ // Neither a hidden physical camera nor a logical camera
+ return NAME_NOT_FOUND;
}
-bool CameraProviderManager::isHiddenPhysicalCamera(const std::string& cameraId) {
+bool CameraProviderManager::isHiddenPhysicalCamera(const std::string& cameraId) const {
+ return isHiddenPhysicalCameraInternal(cameraId).first;
+}
+
+std::pair<bool, CameraProviderManager::ProviderInfo::DeviceInfo *>
+CameraProviderManager::isHiddenPhysicalCameraInternal(const std::string& cameraId) const {
+ auto falseRet = std::make_pair(false, nullptr);
for (auto& provider : mProviders) {
for (auto& deviceInfo : provider->mDevices) {
if (deviceInfo->mId == cameraId) {
// cameraId is found in public camera IDs advertised by the
// provider.
- return false;
+ return falseRet;
}
}
}
@@ -1120,7 +1153,7 @@
if (res != OK) {
ALOGE("%s: Failed to getCameraCharacteristics for id %s", __FUNCTION__,
deviceInfo->mId.c_str());
- return false;
+ return falseRet;
}
std::vector<std::string> physicalIds;
@@ -1132,16 +1165,16 @@
if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_5) {
ALOGE("%s: Wrong deviceVersion %x for hiddenPhysicalCameraId %s",
__FUNCTION__, deviceVersion, cameraId.c_str());
- return false;
+ return falseRet;
} else {
- return true;
+ return std::make_pair(true, deviceInfo.get());
}
}
}
}
}
- return false;
+ return falseRet;
}
status_t CameraProviderManager::addProviderLocked(const std::string& newProvider) {
@@ -1154,7 +1187,7 @@
}
sp<provider::V2_4::ICameraProvider> interface;
- interface = mServiceProxy->getService(newProvider);
+ interface = mServiceProxy->tryGetService(newProvider);
if (interface == nullptr) {
ALOGE("%s: Camera provider HAL '%s' is not actually available", __FUNCTION__,
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index f4cf667..2ef1f6f 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -96,6 +96,10 @@
const std::string &serviceName,
const sp<hidl::manager::V1_0::IServiceNotification>
¬ification) = 0;
+ // Will not wait for service to start if it's not already running
+ virtual sp<hardware::camera::provider::V2_4::ICameraProvider> tryGetService(
+ const std::string &serviceName) = 0;
+ // Will block for service if it exists but isn't running
virtual sp<hardware::camera::provider::V2_4::ICameraProvider> getService(
const std::string &serviceName) = 0;
virtual hardware::hidl_vec<hardware::hidl_string> listServices() = 0;
@@ -112,6 +116,10 @@
return hardware::camera::provider::V2_4::ICameraProvider::registerForNotifications(
serviceName, notification);
}
+ virtual sp<hardware::camera::provider::V2_4::ICameraProvider> tryGetService(
+ const std::string &serviceName) override {
+ return hardware::camera::provider::V2_4::ICameraProvider::tryGetService(serviceName);
+ }
virtual sp<hardware::camera::provider::V2_4::ICameraProvider> getService(
const std::string &serviceName) override {
return hardware::camera::provider::V2_4::ICameraProvider::getService(serviceName);
@@ -292,8 +300,8 @@
*/
bool isLogicalCamera(const std::string& id, std::vector<std::string>* physicalCameraIds);
- SystemCameraKind getSystemCameraKind(const std::string& id) const;
- bool isHiddenPhysicalCamera(const std::string& cameraId);
+ status_t getSystemCameraKind(const std::string& id, SystemCameraKind *kind) const;
+ bool isHiddenPhysicalCamera(const std::string& cameraId) const;
static const float kDepthARTolerance;
private:
@@ -616,7 +624,8 @@
CameraMetadata* characteristics) const;
void filterLogicalCameraIdsLocked(std::vector<std::string>& deviceIds) const;
- SystemCameraKind getSystemCameraKindLocked(const std::string& id) const;
+ status_t getSystemCameraKindLocked(const std::string& id, SystemCameraKind *kind) const;
+ std::pair<bool, ProviderInfo::DeviceInfo *> isHiddenPhysicalCameraInternal(const std::string& cameraId) const;
void collectDeviceIdsLocked(const std::vector<std::string> deviceIds,
std::vector<std::string>& normalDeviceIds,
diff --git a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
index 78d737d..084dc62 100644
--- a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
+++ b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
@@ -183,6 +183,7 @@
sp<TestICameraProvider> mTestCameraProvider;
TestInteractionProxy() {}
+
void setProvider(sp<TestICameraProvider> provider) {
mTestCameraProvider = provider;
}
@@ -199,13 +200,31 @@
return true;
}
+ virtual sp<hardware::camera::provider::V2_4::ICameraProvider> tryGetService(
+ const std::string &serviceName) override {
+ // If no provider has been given, act like the HAL isn't available and return null.
+ if (mTestCameraProvider == nullptr) return nullptr;
+ return getService(serviceName);
+ }
+
virtual sp<hardware::camera::provider::V2_4::ICameraProvider> getService(
const std::string &serviceName) override {
+ // If no provider has been given, fail; in reality, getService would
+ // block for HALs that don't start correctly, so we should never use
+ // getService when we don't have a valid HAL running
+ if (mTestCameraProvider == nullptr) {
+ ADD_FAILURE() << "getService called with no valid provider; would block indefinitely";
+ // Real getService would block, but that's bad in unit tests. So
+ // just record an error and return nullptr
+ return nullptr;
+ }
mLastRequestedServiceNames.push_back(serviceName);
return mTestCameraProvider;
}
virtual hardware::hidl_vec<hardware::hidl_string> listServices() override {
+ // Always provide a list even if there's no actual provider yet, to
+ // simulate stuck HAL situations as well
hardware::hidl_vec<hardware::hidl_string> ret = {"test/0"};
return ret;
}
@@ -438,3 +457,52 @@
<< "Unable to change device state";
}
+
+// Test that CameraProviderManager doesn't get stuck when the camera HAL isn't really working
+TEST(CameraProviderManagerTest, BadHalStartupTest) {
+
+ std::vector<hardware::hidl_string> deviceNames;
+ deviceNames.push_back("device@3.2/test/0");
+ deviceNames.push_back("device@1.0/test/0");
+ deviceNames.push_back("device@3.2/test/1");
+ hardware::hidl_vec<common::V1_0::VendorTagSection> vendorSection;
+ status_t res;
+
+ sp<CameraProviderManager> providerManager = new CameraProviderManager();
+ sp<TestStatusListener> statusListener = new TestStatusListener();
+ TestInteractionProxy serviceProxy;
+ sp<TestICameraProvider> provider = new TestICameraProvider(deviceNames,
+ vendorSection);
+
+ // Not setting up provider in the service proxy yet, to test cases where a
+ // HAL isn't starting right
+ res = providerManager->initialize(statusListener, &serviceProxy);
+ ASSERT_EQ(res, OK) << "Unable to initialize provider manager";
+
+ // Now set up provider and trigger a registration
+ serviceProxy.setProvider(provider);
+ int numProviders = static_cast<int>(serviceProxy.listServices().size());
+
+ hardware::hidl_string testProviderFqInterfaceName =
+ "android.hardware.camera.provider@2.4::ICameraProvider";
+ hardware::hidl_string testProviderInstanceName = "test/0";
+ serviceProxy.mManagerNotificationInterface->onRegistration(
+ testProviderFqInterfaceName,
+ testProviderInstanceName, false);
+
+ // Check that new provider is called once for all the init methods
+ EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::SET_CALLBACK], numProviders) <<
+ "Only one call to setCallback per provider expected during register";
+ EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::GET_VENDOR_TAGS], numProviders) <<
+ "Only one call to getVendorTags per provider expected during register";
+ EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::IS_SET_TORCH_MODE_SUPPORTED],
+ numProviders) <<
+ "Only one call to isSetTorchModeSupported per provider expected during init";
+ EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::GET_CAMERA_ID_LIST], numProviders) <<
+ "Only one call to getCameraIdList per provider expected during init";
+ EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::NOTIFY_DEVICE_STATE], numProviders) <<
+ "Only one call to notifyDeviceState per provider expected during init";
+
+ ASSERT_EQ(serviceProxy.mLastRequestedServiceNames.back(), testProviderInstanceName) <<
+ "Incorrect instance requested from service manager";
+}
diff --git a/services/mediaanalytics/Android.bp b/services/mediaanalytics/Android.bp
index 72f4b52..dc72064 100644
--- a/services/mediaanalytics/Android.bp
+++ b/services/mediaanalytics/Android.bp
@@ -6,8 +6,32 @@
srcs: [
"main_mediametrics.cpp",
- "MediaAnalyticsService.cpp",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "liblog",
+ "libmediaanalyticsservice",
+ "libutils",
+ ],
+
+ init_rc: [
+ "mediametrics.rc",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+}
+
+cc_library_shared {
+ name: "libmediaanalyticsservice",
+
+ srcs: [
"iface_statsd.cpp",
+ "MediaAnalyticsService.cpp",
"statsd_audiopolicy.cpp",
"statsd_audiorecord.cpp",
"statsd_audiothread.cpp",
@@ -24,45 +48,25 @@
},
shared_libs: [
- "libcutils",
- "liblog",
- "libmedia",
- "libutils",
"libbinder",
- "libdl",
- "libgui",
- "libmedia",
- "libmediautils",
+ "liblog",
"libmediametrics",
- "libstagefright_foundation",
+ "libprotobuf-cpp-lite",
"libstatslog",
"libutils",
- "libprotobuf-cpp-lite",
],
static_libs: [
"libplatformprotos",
- "libregistermsext",
],
include_dirs: [
- "frameworks/av/media/libstagefright/include",
- "frameworks/av/media/libstagefright/rtsp",
- "frameworks/av/media/libstagefright/webm",
- "frameworks/av/include/media",
- "frameworks/av/include/camera",
- "frameworks/native/include/media/openmax",
- "frameworks/native/include/media/hardware",
- "external/tremolo/Tremolo",
+ "system/media/audio_utils/include",
],
- init_rc: ["mediametrics.rc"],
-
cflags: [
- "-Werror",
"-Wall",
- "-Wno-error=deprecated-declarations",
+ "-Werror",
+ "-Wextra",
],
- clang: true,
-
}
diff --git a/services/mediaanalytics/MediaAnalyticsService.cpp b/services/mediaanalytics/MediaAnalyticsService.cpp
index 988c06b..1ed8b74 100644
--- a/services/mediaanalytics/MediaAnalyticsService.cpp
+++ b/services/mediaanalytics/MediaAnalyticsService.cpp
@@ -14,66 +14,20 @@
* limitations under the License.
*/
-// Proxy for media player implementations
-
//#define LOG_NDEBUG 0
#define LOG_TAG "MediaAnalyticsService"
#include <utils/Log.h>
-#include <stdint.h>
-#include <inttypes.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <dirent.h>
-#include <pthread.h>
-#include <unistd.h>
-
-#include <string.h>
-#include <pwd.h>
-
-#include <cutils/atomic.h>
-#include <cutils/properties.h> // for property_get
-
-#include <utils/misc.h>
-
-#include <android/content/pm/IPackageManagerNative.h>
-
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <binder/MemoryHeapBase.h>
-#include <binder/MemoryBase.h>
-#include <gui/Surface.h>
-#include <utils/Errors.h> // for status_t
-#include <utils/List.h>
-#include <utils/String8.h>
-#include <utils/SystemClock.h>
-#include <utils/Timers.h>
-#include <utils/Vector.h>
-
-#include <media/IMediaHTTPService.h>
-#include <media/IRemoteDisplay.h>
-#include <media/IRemoteDisplayClient.h>
-#include <media/MediaPlayerInterface.h>
-#include <media/mediarecorder.h>
-#include <media/MediaMetadataRetrieverInterface.h>
-#include <media/Metadata.h>
-#include <media/AudioTrack.h>
-#include <media/MemoryLeakTrackUtil.h>
-#include <media/stagefright/MediaCodecList.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/Utils.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/ALooperRoster.h>
-#include <mediautils/BatteryNotifier.h>
-
-//#include <memunreachable/memunreachable.h>
-#include <system/audio.h>
-
-#include <private/android_filesystem_config.h>
-
#include "MediaAnalyticsService.h"
+#include <pwd.h> //getpwuid
+
+#include <audio_utils/clock.h> // clock conversions
+#include <android/content/pm/IPackageManagerNative.h> // package info
+#include <binder/IPCThreadState.h> // get calling uid
+#include <cutils/properties.h> // for property_get
+#include <private/android_filesystem_config.h> // UID
+
namespace android {
// individual records kept in memory: age or count
@@ -81,193 +35,143 @@
// count: hard limit of # records
// (0 for either of these disables that threshold)
//
-static constexpr nsecs_t kMaxRecordAgeNs = 28 * 3600 * (1000*1000*1000ll);
+static constexpr nsecs_t kMaxRecordAgeNs = 28 * 3600 * NANOS_PER_SECOND;
// 2019/6: average daily per device is currently 375-ish;
// setting this to 2000 is large enough to catch most devices
// we'll lose some data on very very media-active devices, but only for
// the gms collection; statsd will have already covered those for us.
// This also retains enough information to help with bugreports
-static constexpr int kMaxRecords = 2000;
+static constexpr size_t kMaxRecords = 2000;
// max we expire in a single call, to constrain how long we hold the
// mutex, which also constrains how long a client might wait.
-static constexpr int kMaxExpiredAtOnce = 50;
+static constexpr size_t kMaxExpiredAtOnce = 50;
// TODO: need to look at tuning kMaxRecords and friends for low-memory devices
-static const char *kServiceName = "media.metrics";
-
-void MediaAnalyticsService::instantiate() {
- defaultServiceManager()->addService(
- String16(kServiceName), new MediaAnalyticsService());
-}
-
MediaAnalyticsService::MediaAnalyticsService()
: mMaxRecords(kMaxRecords),
mMaxRecordAgeNs(kMaxRecordAgeNs),
mMaxRecordsExpiredAtOnce(kMaxExpiredAtOnce),
- mDumpProto(MediaAnalyticsItem::PROTO_V1),
- mDumpProtoDefault(MediaAnalyticsItem::PROTO_V1) {
-
- ALOGD("MediaAnalyticsService created");
-
- mItemsSubmitted = 0;
- mItemsFinalized = 0;
- mItemsDiscarded = 0;
- mItemsDiscardedExpire = 0;
- mItemsDiscardedCount = 0;
-
- mLastSessionID = 0;
- // recover any persistency we set up
- // etc
-}
-
-MediaAnalyticsService::~MediaAnalyticsService() {
- ALOGD("MediaAnalyticsService destroyed");
-
- while (mItems.size() > 0) {
- MediaAnalyticsItem * oitem = *(mItems.begin());
- mItems.erase(mItems.begin());
- delete oitem;
- mItemsDiscarded++;
- mItemsDiscardedCount++;
- }
-}
-
-
-MediaAnalyticsItem::SessionID_t MediaAnalyticsService::generateUniqueSessionID() {
- // generate a new sessionid
-
- Mutex::Autolock _l(mLock_ids);
- return (++mLastSessionID);
-}
-
-// caller surrenders ownership of 'item'
-MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(MediaAnalyticsItem *item, bool forcenew)
+ mDumpProtoDefault(MediaAnalyticsItem::PROTO_V1)
{
- UNUSED(forcenew);
+ ALOGD("%s", __func__);
+}
- // fill in a sessionID if we do not yet have one
- if (item->getSessionID() <= MediaAnalyticsItem::SessionIDNone) {
- item->setSessionID(generateUniqueSessionID());
- }
+MediaAnalyticsService::~MediaAnalyticsService()
+{
+ ALOGD("%s", __func__);
+ // the class destructor clears anyhow, but we enforce clearing items first.
+ mItemsDiscarded += mItems.size();
+ mItems.clear();
+}
+status_t MediaAnalyticsService::submitInternal(MediaAnalyticsItem *item, bool release)
+{
// we control these, generally not trusting user input
nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
// round nsecs to seconds
- now = ((now + 500000000) / 1000000000) * 1000000000;
+ now = (now + NANOS_PER_SECOND / 2) / NANOS_PER_SECOND * NANOS_PER_SECOND;
+ // TODO: if we convert to boot time, do we need to round timestamp?
item->setTimestamp(now);
- int pid = IPCThreadState::self()->getCallingPid();
- int uid = IPCThreadState::self()->getCallingUid();
- int uid_given = item->getUid();
- int pid_given = item->getPid();
+ const int pid = IPCThreadState::self()->getCallingPid();
+ const int uid = IPCThreadState::self()->getCallingUid();
+ const int uid_given = item->getUid();
+ const int pid_given = item->getPid();
- // although we do make exceptions for some trusted client uids
- bool isTrusted = false;
-
- ALOGV("caller has uid=%d, embedded uid=%d", uid, uid_given);
-
- switch (uid) {
- case AID_DRM:
- case AID_MEDIA:
- case AID_MEDIA_CODEC:
- case AID_MEDIA_EX:
- case AID_MEDIA_DRM:
- // trusted source, only override default values
- isTrusted = true;
- if (uid_given == (-1)) {
- item->setUid(uid);
- }
- if (pid_given == (-1)) {
- item->setPid(pid);
- }
- break;
- default:
- isTrusted = false;
- item->setPid(pid);
+ ALOGV("%s: caller has uid=%d, embedded uid=%d", __func__, uid, uid_given);
+ bool isTrusted;
+ switch (uid) {
+ case AID_DRM:
+ case AID_MEDIA:
+ case AID_MEDIA_CODEC:
+ case AID_MEDIA_EX:
+ case AID_MEDIA_DRM:
+ // trusted source, only override default values
+ isTrusted = true;
+ if (uid_given == -1) {
item->setUid(uid);
- break;
+ }
+ if (pid_given == -1) {
+ item->setPid(pid);
+ }
+ break;
+ default:
+ isTrusted = false;
+ item->setPid(pid);
+ item->setUid(uid);
+ break;
}
// Overwrite package name and version if the caller was untrusted.
if (!isTrusted) {
- setPkgInfo(item, item->getUid(), true, true);
+ mUidInfo.setPkgInfo(item, item->getUid(), true, true);
} else if (item->getPkgName().empty()) {
- // empty, so fill out both parts
- setPkgInfo(item, item->getUid(), true, true);
+ // empty, so fill out both parts
+ mUidInfo.setPkgInfo(item, item->getUid(), true, true);
} else {
- // trusted, provided a package, do nothing
+ // trusted, provided a package, do nothing
}
- ALOGV("given uid %d; sanitized uid: %d sanitized pkg: %s "
- "sanitized pkg version: %" PRId64,
+ ALOGV("%s: given uid %d; sanitized uid: %d sanitized pkg: %s "
+ "sanitized pkg version: %lld",
+ __func__,
uid_given, item->getUid(),
item->getPkgName().c_str(),
- item->getPkgVersionCode());
+ (long long)item->getPkgVersionCode());
mItemsSubmitted++;
// validate the record; we discard if we don't like it
- if (contentValid(item, isTrusted) == false) {
- delete item;
- return MediaAnalyticsItem::SessionIDInvalid;
+ if (isContentValid(item, isTrusted) == false) {
+ if (release) delete item;
+ return PERMISSION_DENIED;
}
// XXX: if we have a sessionid in the new record, look to make
// sure it doesn't appear in the finalized list.
if (item->count() == 0) {
- ALOGV("dropping empty record...");
- delete item;
- item = NULL;
- return MediaAnalyticsItem::SessionIDInvalid;
+ ALOGV("%s: dropping empty record...", __func__);
+ if (release) delete item;
+ return BAD_VALUE;
}
- // save the new record
- //
- // send a copy to statsd
- dump2Statsd(item);
+ // send to statsd
+ extern bool dump2Statsd(MediaAnalyticsItem *item); // extern hook
+ (void)dump2Statsd(item); // failure should be logged in function.
- // and keep our copy for dumpsys
- MediaAnalyticsItem::SessionID_t id = item->getSessionID();
+ if (!release) item = item->dup();
saveItem(item);
- mItemsFinalized++;
-
- return id;
+ return NO_ERROR;
}
-
status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)
{
- const size_t SIZE = 512;
- char buffer[SIZE];
String8 result;
if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
- snprintf(buffer, SIZE, "Permission Denial: "
+ result.appendFormat("Permission Denial: "
"can't dump MediaAnalyticsService from pid=%d, uid=%d\n",
IPCThreadState::self()->getCallingPid(),
IPCThreadState::self()->getCallingUid());
- result.append(buffer);
write(fd, result.string(), result.size());
return NO_ERROR;
}
// crack any parameters
- String16 protoOption("-proto");
+ const String16 protoOption("-proto");
int chosenProto = mDumpProtoDefault;
- String16 clearOption("-clear");
+ const String16 clearOption("-clear");
bool clear = false;
- String16 sinceOption("-since");
+ const String16 sinceOption("-since");
nsecs_t ts_since = 0;
- String16 helpOption("-help");
- String16 onlyOption("-only");
+ const String16 helpOption("-help");
+ const String16 onlyOption("-only");
std::string only;
- int n = args.size();
-
+ const int n = args.size();
for (int i = 0; i < n; i++) {
- String8 myarg(args[i]);
if (args[i] == clearOption) {
clear = true;
} else if (args[i] == protoOption) {
@@ -305,7 +209,7 @@
ts_since = 0;
}
// command line is milliseconds; internal units are nano-seconds
- ts_since *= 1000*1000;
+ ts_since *= NANOS_PER_MILLISECOND;
} else if (args[i] == onlyOption) {
i++;
if (i < n) {
@@ -313,6 +217,10 @@
only = value.string();
}
} else if (args[i] == helpOption) {
+ // TODO: consider function area dumping.
+ // dumpsys media.metrics audiotrack,codec
+ // or dumpsys media.metrics audiotrack codec
+
result.append("Recognized parameters:\n");
result.append("-help this help message\n");
result.append("-proto # dump using protocol #");
@@ -325,31 +233,18 @@
}
}
- Mutex::Autolock _l(mLock);
- // mutex between insertion and dumping the contents
+ {
+ std::lock_guard _l(mLock);
- mDumpProto = chosenProto;
+ result.appendFormat("Dump of the %s process:\n", kServiceName);
+ dumpHeaders_l(result, chosenProto, ts_since);
+ dumpRecent_l(result, chosenProto, ts_since, only.c_str());
- // we ALWAYS dump this piece
- snprintf(buffer, SIZE, "Dump of the %s process:\n", kServiceName);
- result.append(buffer);
-
- dumpHeaders(result, ts_since);
-
- dumpRecent(result, ts_since, only.c_str());
-
-
- if (clear) {
- // remove everything from the finalized queue
- while (mItems.size() > 0) {
- MediaAnalyticsItem * oitem = *(mItems.begin());
- mItems.erase(mItems.begin());
- delete oitem;
- mItemsDiscarded++;
+ if (clear) {
+ mItemsDiscarded += mItems.size();
+ mItems.clear();
+ // shall we clear the summary data too?
}
-
- // shall we clear the summary data too?
-
}
write(fd, result.string(), result.size());
@@ -357,275 +252,207 @@
}
// dump headers
-void MediaAnalyticsService::dumpHeaders(String8 &result, nsecs_t ts_since)
+void MediaAnalyticsService::dumpHeaders_l(String8 &result, int dumpProto, nsecs_t ts_since)
{
- const size_t SIZE = 512;
- char buffer[SIZE];
-
- snprintf(buffer, SIZE, "Protocol Version: %d\n", mDumpProto);
- result.append(buffer);
-
- int enabled = MediaAnalyticsItem::isEnabled();
- if (enabled) {
- snprintf(buffer, SIZE, "Metrics gathering: enabled\n");
+ result.appendFormat("Protocol Version: %d\n", dumpProto);
+ if (MediaAnalyticsItem::isEnabled()) {
+ result.append("Metrics gathering: enabled\n");
} else {
- snprintf(buffer, SIZE, "Metrics gathering: DISABLED via property\n");
+ result.append("Metrics gathering: DISABLED via property\n");
}
- result.append(buffer);
-
- snprintf(buffer, SIZE,
- "Since Boot: Submissions: %8" PRId64
- " Accepted: %8" PRId64 "\n",
- mItemsSubmitted, mItemsFinalized);
- result.append(buffer);
- snprintf(buffer, SIZE,
- "Records Discarded: %8" PRId64
- " (by Count: %" PRId64 " by Expiration: %" PRId64 ")\n",
- mItemsDiscarded, mItemsDiscardedCount, mItemsDiscardedExpire);
- result.append(buffer);
+ result.appendFormat(
+ "Since Boot: Submissions: %lld Accepted: %lld\n",
+ (long long)mItemsSubmitted.load(), (long long)mItemsFinalized);
+ result.appendFormat(
+ "Records Discarded: %lld (by Count: %lld by Expiration: %lld)\n",
+ (long long)mItemsDiscarded, (long long)mItemsDiscardedCount,
+ (long long)mItemsDiscardedExpire);
if (ts_since != 0) {
- snprintf(buffer, SIZE,
- "Emitting Queue entries more recent than: %" PRId64 "\n",
- (int64_t) ts_since);
- result.append(buffer);
+ result.appendFormat(
+ "Emitting Queue entries more recent than: %lld\n",
+ (long long)ts_since);
}
}
-// the recent, detailed queues
-void MediaAnalyticsService::dumpRecent(String8 &result, nsecs_t ts_since, const char * only)
+void MediaAnalyticsService::dumpRecent_l(
+ String8 &result, int dumpProto, nsecs_t ts_since, const char * only)
{
- const size_t SIZE = 512;
- char buffer[SIZE];
-
- if (only != NULL && *only == '\0') {
- only = NULL;
+ if (only != nullptr && *only == '\0') {
+ only = nullptr;
}
-
- // show the recently recorded records
- snprintf(buffer, sizeof(buffer), "\nFinalized Metrics (oldest first):\n");
- result.append(buffer);
- result.append(this->dumpQueue(ts_since, only));
+ result.append("\nFinalized Metrics (oldest first):\n");
+ dumpQueue_l(result, dumpProto, ts_since, only);
// show who is connected and injecting records?
// talk about # records fed to the 'readers'
// talk about # records we discarded, perhaps "discarded w/o reading" too
}
-// caller has locked mLock...
-String8 MediaAnalyticsService::dumpQueue() {
- return dumpQueue((nsecs_t) 0, NULL);
+void MediaAnalyticsService::dumpQueue_l(String8 &result, int dumpProto) {
+ dumpQueue_l(result, dumpProto, (nsecs_t) 0, nullptr /* only */);
}
-String8 MediaAnalyticsService::dumpQueue(nsecs_t ts_since, const char * only) {
- String8 result;
+void MediaAnalyticsService::dumpQueue_l(
+ String8 &result, int dumpProto, nsecs_t ts_since, const char * only) {
int slot = 0;
if (mItems.empty()) {
- result.append("empty\n");
+ result.append("empty\n");
} else {
- List<MediaAnalyticsItem *>::iterator it = mItems.begin();
- for (; it != mItems.end(); it++) {
- nsecs_t when = (*it)->getTimestamp();
+ for (const auto &item : mItems) {
+ nsecs_t when = item->getTimestamp();
if (when < ts_since) {
continue;
}
- if (only != NULL &&
- strcmp(only, (*it)->getKey().c_str()) != 0) {
- ALOGV("Omit '%s', it's not '%s'", (*it)->getKey().c_str(), only);
+ // TODO: Only should be a set<string>
+ if (only != nullptr &&
+ item->getKey() /* std::string */ != only) {
+ ALOGV("%s: omit '%s', it's not '%s'",
+ __func__, item->getKey().c_str(), only);
continue;
}
- std::string entry = (*it)->toString(mDumpProto);
- result.appendFormat("%5d: %s\n", slot, entry.c_str());
+ result.appendFormat("%5d: %s\n",
+ slot, item->toString(dumpProto).c_str());
slot++;
}
}
-
- return result;
}
//
// Our Cheap in-core, non-persistent records management.
-
-// we hold mLock when we get here
// if item != NULL, it's the item we just inserted
// true == more items eligible to be recovered
bool MediaAnalyticsService::expirations_l(MediaAnalyticsItem *item)
{
bool more = false;
- int handled = 0;
- // keep removing old records the front until we're in-bounds (count)
- // since we invoke this with each insertion, it should be 0/1 iterations.
- if (mMaxRecords > 0) {
- while (mItems.size() > (size_t) mMaxRecords) {
- MediaAnalyticsItem * oitem = *(mItems.begin());
- if (oitem == item) {
- break;
- }
- if (handled >= mMaxRecordsExpiredAtOnce) {
- // unlikely in this loop
- more = true;
- break;
- }
- handled++;
- mItems.erase(mItems.begin());
- delete oitem;
- mItemsDiscarded++;
- mItemsDiscardedCount++;
+ // check queue size
+ size_t overlimit = 0;
+ if (mMaxRecords > 0 && mItems.size() > mMaxRecords) {
+ overlimit = mItems.size() - mMaxRecords;
+ if (overlimit > mMaxRecordsExpiredAtOnce) {
+ more = true;
+ overlimit = mMaxRecordsExpiredAtOnce;
}
}
- // keep removing old records the front until we're in-bounds (age)
- // limited to mMaxRecordsExpiredAtOnce items per invocation.
- if (mMaxRecordAgeNs > 0) {
- nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
- while (mItems.size() > 0) {
- MediaAnalyticsItem * oitem = *(mItems.begin());
+ // check queue times
+ size_t expired = 0;
+ if (!more && mMaxRecordAgeNs > 0) {
+ const nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
+ // we check one at a time, skip search would be more efficient.
+ size_t i = overlimit;
+ for (; i < mItems.size(); ++i) {
+ auto &oitem = mItems[i];
nsecs_t when = oitem->getTimestamp();
- if (oitem == item) {
+ if (oitem.get() == item) {
break;
}
- // careful about timejumps too
- if ((now > when) && (now-when) <= mMaxRecordAgeNs) {
- // this (and the rest) are recent enough to keep
- break;
+ if (now > when && (now - when) <= mMaxRecordAgeNs) {
+ break; // TODO: if we use BOOTTIME, should be monotonic.
}
- if (handled >= mMaxRecordsExpiredAtOnce) {
+ if (i >= mMaxRecordsExpiredAtOnce) {
// this represents "one too many"; tell caller there are
// more to be reclaimed.
more = true;
break;
}
- handled++;
- mItems.erase(mItems.begin());
- delete oitem;
- mItemsDiscarded++;
- mItemsDiscardedExpire++;
}
+ expired = i - overlimit;
}
- // we only indicate whether there's more to clean;
- // caller chooses whether to schedule further cleanup.
+ if (const size_t toErase = overlimit + expired;
+ toErase > 0) {
+ mItemsDiscardedCount += overlimit;
+ mItemsDiscardedExpire += expired;
+ mItemsDiscarded += toErase;
+ mItems.erase(mItems.begin(), mItems.begin() + toErase); // erase from front
+ }
return more;
}
-// process expirations in bite sized chunks, allowing new insertions through
-// runs in a pthread specifically started for this (which then exits)
-bool MediaAnalyticsService::processExpirations()
+void MediaAnalyticsService::processExpirations()
{
bool more;
do {
sleep(1);
- {
- Mutex::Autolock _l(mLock);
- more = expirations_l(NULL);
- if (!more) {
- break;
- }
- }
+ std::lock_guard _l(mLock);
+ more = expirations_l(nullptr);
} while (more);
- return true; // value is for std::future thread synchronization
}
-// insert appropriately into queue
-void MediaAnalyticsService::saveItem(MediaAnalyticsItem * item)
+void MediaAnalyticsService::saveItem(MediaAnalyticsItem *item)
{
-
- Mutex::Autolock _l(mLock);
- // mutex between insertion and dumping the contents
-
- // we want to dump 'in FIFO order', so insert at the end
- mItems.push_back(item);
-
- // clean old stuff from the queue
- bool more = expirations_l(item);
-
- // consider scheduling some asynchronous cleaning, if not running
- if (more) {
- if (!mExpireFuture.valid()
- || mExpireFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
-
- mExpireFuture = std::async(std::launch::async, [this]()
- {return this->processExpirations();});
- }
+ std::lock_guard _l(mLock);
+ // we assume the items are roughly in time order.
+ mItems.emplace_back(item);
+ ++mItemsFinalized;
+ if (expirations_l(item)
+ && (!mExpireFuture.valid()
+ || mExpireFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready)) {
+ mExpireFuture = std::async(std::launch::async, [this] { processExpirations(); });
}
}
-static std::string allowedKeys[] =
+/* static */
+bool MediaAnalyticsService::isContentValid(const MediaAnalyticsItem *item, bool isTrusted)
{
- "audiopolicy",
- "audiorecord",
- "audiothread",
- "audiotrack",
- "codec",
- "extractor",
- "nuplayer",
-};
-
-static const int nAllowedKeys = sizeof(allowedKeys) / sizeof(allowedKeys[0]);
-
-// are the contents good
-bool MediaAnalyticsService::contentValid(MediaAnalyticsItem *item, bool isTrusted) {
-
+ if (isTrusted) return true;
// untrusted uids can only send us a limited set of keys
- if (isTrusted == false) {
- // restrict to a specific set of keys
- std::string key = item->getKey();
-
- size_t i;
- for(i = 0; i < nAllowedKeys; i++) {
- if (key == allowedKeys[i]) {
- break;
- }
- }
- if (i == nAllowedKeys) {
- ALOGD("Ignoring (key): %s", item->toString().c_str());
- return false;
+ const std::string &key = item->getKey();
+ for (const char *allowedKey : {
+ "audiopolicy",
+ "audiorecord",
+ "audiothread",
+ "audiotrack",
+ "codec",
+ "extractor",
+ "nuplayer",
+ }) {
+ if (key == allowedKey) {
+ return true;
}
}
-
- // internal consistency
-
- return true;
-}
-
-// are we rate limited, normally false
-bool MediaAnalyticsService::rateLimited(MediaAnalyticsItem *) {
-
+ ALOGD("%s: invalid key: %s", __func__, item->toString().c_str());
return false;
}
-// how long we hold package info before we re-fetch it
-#define PKG_EXPIRATION_NS (30*60*1000000000ll) // 30 minutes, in nsecs
+// are we rate limited, normally false
+bool MediaAnalyticsService::isRateLimited(MediaAnalyticsItem *) const
+{
+ return false;
+}
+
+// How long we hold package info before we re-fetch it
+constexpr nsecs_t PKG_EXPIRATION_NS = 30 * 60 * NANOS_PER_SECOND; // 30 minutes
// give me the package name, perhaps going to find it
// manages its own mutex operations internally
-void MediaAnalyticsService::setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion)
+void MediaAnalyticsService::UidInfo::setPkgInfo(
+ MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion)
{
- ALOGV("asking for packagename to go with uid=%d", uid);
+ ALOGV("%s: uid=%d", __func__, uid);
if (!setName && !setVersion) {
- // setting nothing? strange
- return;
+ return; // setting nothing? strange
}
- nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
- struct UidToPkgMap mapping;
- mapping.uid = (uid_t)(-1);
-
+ const nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
+ struct UidToPkgInfo mapping;
{
- Mutex::Autolock _l(mLock_mappings);
- int i = mPkgMappings.indexOfKey(uid);
- if (i >= 0) {
- mapping = mPkgMappings.valueAt(i);
- ALOGV("Expiration? uid %d expiration %" PRId64 " now %" PRId64,
- uid, mapping.expiration, now);
+ std::lock_guard _l(mUidInfoLock);
+ auto it = mPkgMappings.find(uid);
+ if (it != mPkgMappings.end()) {
+ mapping = it->second;
+ ALOGV("%s: uid %d expiration %lld now %lld",
+ __func__, uid, (long long)mapping.expiration, (long long)now);
if (mapping.expiration <= now) {
// purge the stale entry and fall into re-fetching
- ALOGV("entry for uid %d expired, now= %" PRId64 "", uid, now);
- mPkgMappings.removeItemsAt(i);
- mapping.uid = (uid_t)(-1);
+ ALOGV("%s: entry for uid %d expired, now %lld",
+ __func__, uid, (long long)now);
+ mPkgMappings.erase(it);
+ mapping.uid = (uid_t)-1; // this is always fully overwritten
}
}
}
@@ -633,115 +460,103 @@
// if we did not find it
if (mapping.uid == (uid_t)(-1)) {
std::string pkg;
- std::string installer = "";
+ std::string installer;
int64_t versionCode = 0;
- struct passwd *pw = getpwuid(uid);
+ const struct passwd *pw = getpwuid(uid);
if (pw) {
pkg = pw->pw_name;
}
- // find the proper value
-
- sp<IBinder> binder = NULL;
sp<IServiceManager> sm = defaultServiceManager();
- if (sm == NULL) {
- ALOGE("defaultServiceManager failed");
+ sp<content::pm::IPackageManagerNative> package_mgr;
+ if (sm.get() == nullptr) {
+ ALOGE("%s: Cannot find service manager", __func__);
} else {
- binder = sm->getService(String16("package_native"));
- if (binder == NULL) {
- ALOGE("getService package_native failed");
+ sp<IBinder> binder = sm->getService(String16("package_native"));
+ if (binder.get() == nullptr) {
+ ALOGE("%s: Cannot find package_native", __func__);
+ } else {
+ package_mgr = interface_cast<content::pm::IPackageManagerNative>(binder);
}
}
- if (binder != NULL) {
- sp<content::pm::IPackageManagerNative> package_mgr =
- interface_cast<content::pm::IPackageManagerNative>(binder);
- binder::Status status;
-
+ if (package_mgr != nullptr) {
std::vector<int> uids;
std::vector<std::string> names;
-
uids.push_back(uid);
-
- status = package_mgr->getNamesForUids(uids, &names);
+ binder::Status status = package_mgr->getNamesForUids(uids, &names);
if (!status.isOk()) {
- ALOGE("package_native::getNamesForUids failed: %s",
- status.exceptionMessage().c_str());
- } else {
- if (!names[0].empty()) {
- pkg = names[0].c_str();
- }
+ ALOGE("%s: getNamesForUids failed: %s",
+ __func__, status.exceptionMessage().c_str());
+ }
+ if (!names[0].empty()) {
+ pkg = names[0].c_str();
+ }
+ }
+
+ // strip any leading "shared:" strings that came back
+ if (pkg.compare(0, 7, "shared:") == 0) {
+ pkg.erase(0, 7);
+ }
+ // determine how pkg was installed and the versionCode
+ if (pkg.empty()) {
+ pkg = std::to_string(uid); // no name for us to manage
+ } else if (strchr(pkg.c_str(), '.') == NULL) {
+ // not of form 'com.whatever...'; assume internal and ok
+ } else if (strncmp(pkg.c_str(), "android.", 8) == 0) {
+ // android.* packages are assumed fine
+ } else if (package_mgr.get() != nullptr) {
+ String16 pkgName16(pkg.c_str());
+ binder::Status status = package_mgr->getInstallerForPackage(pkgName16, &installer);
+ if (!status.isOk()) {
+ ALOGE("%s: getInstallerForPackage failed: %s",
+ __func__, status.exceptionMessage().c_str());
}
- // strip any leading "shared:" strings that came back
- if (pkg.compare(0, 7, "shared:") == 0) {
- pkg.erase(0, 7);
- }
-
- // determine how pkg was installed and the versionCode
- //
- if (pkg.empty()) {
- // no name for us to manage
- } else if (strchr(pkg.c_str(), '.') == NULL) {
- // not of form 'com.whatever...'; assume internal and ok
- } else if (strncmp(pkg.c_str(), "android.", 8) == 0) {
- // android.* packages are assumed fine
- } else {
- String16 pkgName16(pkg.c_str());
- status = package_mgr->getInstallerForPackage(pkgName16, &installer);
+ // skip if we didn't get an installer
+ if (status.isOk()) {
+ status = package_mgr->getVersionCodeForPackage(pkgName16, &versionCode);
if (!status.isOk()) {
- ALOGE("package_native::getInstallerForPackage failed: %s",
- status.exceptionMessage().c_str());
- }
-
- // skip if we didn't get an installer
- if (status.isOk()) {
- status = package_mgr->getVersionCodeForPackage(pkgName16, &versionCode);
- if (!status.isOk()) {
- ALOGE("package_native::getVersionCodeForPackage failed: %s",
- status.exceptionMessage().c_str());
- }
- }
-
-
- ALOGV("package '%s' installed by '%s' versioncode %" PRId64 " / %" PRIx64,
- pkg.c_str(), installer.c_str(), versionCode, versionCode);
-
- if (strncmp(installer.c_str(), "com.android.", 12) == 0) {
- // from play store, we keep info
- } else if (strncmp(installer.c_str(), "com.google.", 11) == 0) {
- // some google source, we keep info
- } else if (strcmp(installer.c_str(), "preload") == 0) {
- // preloads, we keep the info
- } else if (installer.c_str()[0] == '\0') {
- // sideload (no installer); do not report
- pkg = "";
- versionCode = 0;
- } else {
- // unknown installer; do not report
- pkg = "";
- versionCode = 0;
+ ALOGE("%s: getVersionCodeForPackage failed: %s",
+ __func__, status.exceptionMessage().c_str());
}
}
+
+ ALOGV("%s: package '%s' installed by '%s' versioncode %lld",
+ __func__, pkg.c_str(), installer.c_str(), (long long)versionCode);
+
+ if (strncmp(installer.c_str(), "com.android.", 12) == 0) {
+ // from play store, we keep info
+ } else if (strncmp(installer.c_str(), "com.google.", 11) == 0) {
+ // some google source, we keep info
+ } else if (strcmp(installer.c_str(), "preload") == 0) {
+ // preloads, we keep the info
+ } else if (installer.c_str()[0] == '\0') {
+ // sideload (no installer); report UID only
+ pkg = std::to_string(uid);
+ versionCode = 0;
+ } else {
+ // unknown installer; report UID only
+ pkg = std::to_string(uid);
+ versionCode = 0;
+ }
+ } else {
+ // unvalidated by package_mgr just send uid.
+ pkg = std::to_string(uid);
}
// add it to the map, to save a subsequent lookup
- if (!pkg.empty()) {
- Mutex::Autolock _l(mLock_mappings);
- ALOGV("Adding uid %d pkg '%s'", uid, pkg.c_str());
- ssize_t i = mPkgMappings.indexOfKey(uid);
- if (i < 0) {
- mapping.uid = uid;
- mapping.pkg = pkg;
- mapping.installer = installer.c_str();
- mapping.versionCode = versionCode;
- mapping.expiration = now + PKG_EXPIRATION_NS;
- ALOGV("expiration for uid %d set to %" PRId64 "", uid, mapping.expiration);
-
- mPkgMappings.add(uid, mapping);
- }
- }
+ std::lock_guard _l(mUidInfoLock);
+ // always overwrite
+ mapping.uid = uid;
+ mapping.pkg = std::move(pkg);
+ mapping.installer = std::move(installer);
+ mapping.versionCode = versionCode;
+ mapping.expiration = now + PKG_EXPIRATION_NS;
+ ALOGV("%s: adding uid %d pkg '%s' expiration: %lld",
+ __func__, uid, mapping.pkg.c_str(), (long long)mapping.expiration);
+ mPkgMappings[uid] = mapping;
}
if (mapping.uid != (uid_t)(-1)) {
diff --git a/services/mediaanalytics/MediaAnalyticsService.h b/services/mediaanalytics/MediaAnalyticsService.h
index 6c9cbaa..eb7d725 100644
--- a/services/mediaanalytics/MediaAnalyticsService.h
+++ b/services/mediaanalytics/MediaAnalyticsService.h
@@ -14,109 +14,110 @@
* limitations under the License.
*/
+#pragma once
-#ifndef ANDROID_MEDIAANALYTICSSERVICE_H
-#define ANDROID_MEDIAANALYTICSSERVICE_H
-
-#include <arpa/inet.h>
-
-#include <utils/threads.h>
-#include <utils/Errors.h>
-#include <utils/KeyedVector.h>
-#include <utils/String8.h>
-#include <utils/List.h>
-
+#include <atomic>
+#include <deque>
#include <future>
+#include <mutex>
+#include <unordered_map>
+// IMediaAnalyticsService must include Vector, String16, Errors
#include <media/IMediaAnalyticsService.h>
+#include <utils/String8.h>
namespace android {
class MediaAnalyticsService : public BnMediaAnalyticsService
{
+public:
+ MediaAnalyticsService();
+ ~MediaAnalyticsService() override;
- public:
+ /**
+ * Submits the indicated record to the mediaanalytics service.
+ *
+ * \param item the item to submit.
+ * \return status failure, which is negative on binder transaction failure.
+ * As the transaction is one-way, remote failures will not be reported.
+ */
+ status_t submit(MediaAnalyticsItem *item) override {
+ return submitInternal(item, false /* release */);
+ }
- // on this side, caller surrenders ownership
- virtual int64_t submit(MediaAnalyticsItem *item, bool forcenew);
+ status_t dump(int fd, const Vector<String16>& args) override;
- static void instantiate();
- virtual status_t dump(int fd, const Vector<String16>& args);
+ static constexpr const char * const kServiceName = "media.metrics";
- MediaAnalyticsService();
- virtual ~MediaAnalyticsService();
+protected:
- bool processExpirations();
+ // Internal call where release is true if ownership of item is transferred
+ // to the service (that is, the service will eventually delete the item).
+ status_t submitInternal(MediaAnalyticsItem *item, bool release) override;
- private:
- MediaAnalyticsItem::SessionID_t generateUniqueSessionID();
+private:
+ void processExpirations();
+ // input validation after arrival from client
+ static bool isContentValid(const MediaAnalyticsItem *item, bool isTrusted);
+ bool isRateLimited(MediaAnalyticsItem *) const;
+ void saveItem(MediaAnalyticsItem *);
- // statistics about our analytics
- int64_t mItemsSubmitted;
- int64_t mItemsFinalized;
- int64_t mItemsDiscarded;
- int64_t mItemsDiscardedExpire;
- int64_t mItemsDiscardedCount;
- MediaAnalyticsItem::SessionID_t mLastSessionID;
+ // The following methods are GUARDED_BY(mLock)
+ bool expirations_l(MediaAnalyticsItem *);
- // partitioned a bit so we don't over serialize
- mutable Mutex mLock;
- mutable Mutex mLock_ids;
- mutable Mutex mLock_mappings;
+ // support for generating output
+ void dumpQueue_l(String8 &result, int dumpProto);
+ void dumpQueue_l(String8 &result, int dumpProto, nsecs_t, const char *only);
+ void dumpHeaders_l(String8 &result, int dumpProto, nsecs_t ts_since);
+ void dumpSummaries_l(String8 &result, int dumpProto, nsecs_t ts_since, const char * only);
+ void dumpRecent_l(String8 &result, int dumpProto, nsecs_t ts_since, const char * only);
+
+ // The following variables accessed without mLock
// limit how many records we'll retain
// by count (in each queue (open, finalized))
- int32_t mMaxRecords;
- // by time (none older than this long agan
- nsecs_t mMaxRecordAgeNs;
+ const size_t mMaxRecords;
+ // by time (none older than this)
+ const nsecs_t mMaxRecordAgeNs;
// max to expire per expirations_l() invocation
- int32_t mMaxRecordsExpiredAtOnce;
- //
- // # of sets of summaries
- int32_t mMaxRecordSets;
- // nsecs until we start a new record set
- nsecs_t mNewSetInterval;
+ const size_t mMaxRecordsExpiredAtOnce;
+ const int mDumpProtoDefault;
- // input validation after arrival from client
- bool contentValid(MediaAnalyticsItem *item, bool isTrusted);
- bool rateLimited(MediaAnalyticsItem *);
+ class UidInfo {
+ public:
+ void setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion);
- // (oldest at front) so it prints nicely for dumpsys
- List<MediaAnalyticsItem *> mItems;
- void saveItem(MediaAnalyticsItem *);
+ private:
+ std::mutex mUidInfoLock;
- bool expirations_l(MediaAnalyticsItem *);
- std::future<bool> mExpireFuture;
+ struct UidToPkgInfo {
+ uid_t uid = -1;
+ std::string pkg;
+ std::string installer;
+ int64_t versionCode = 0;
+ nsecs_t expiration = 0; // TODO: remove expiration.
+ };
- // support for generating output
- int mDumpProto;
- int mDumpProtoDefault;
- String8 dumpQueue();
- String8 dumpQueue(nsecs_t, const char *only);
+ // TODO: use concurrent hashmap with striped lock.
+ std::unordered_map<uid_t, struct UidToPkgInfo> mPkgMappings; // GUARDED_BY(mUidInfoLock)
+ } mUidInfo; // mUidInfo can be accessed without lock (locked internally)
- void dumpHeaders(String8 &result, nsecs_t ts_since);
- void dumpSummaries(String8 &result, nsecs_t ts_since, const char * only);
- void dumpRecent(String8 &result, nsecs_t ts_since, const char * only);
+ std::atomic<int64_t> mItemsSubmitted{}; // accessed outside of lock.
- // mapping uids to package names
- struct UidToPkgMap {
- uid_t uid;
- std::string pkg;
- std::string installer;
- int64_t versionCode;
- nsecs_t expiration;
- };
+ std::mutex mLock;
+ // statistics about our analytics
+ int64_t mItemsFinalized = 0; // GUARDED_BY(mLock)
+ int64_t mItemsDiscarded = 0; // GUARDED_BY(mLock)
+ int64_t mItemsDiscardedExpire = 0; // GUARDED_BY(mLock)
+ int64_t mItemsDiscardedCount = 0; // GUARDED_BY(mLock)
- KeyedVector<uid_t,struct UidToPkgMap> mPkgMappings;
- void setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion);
+ // If we have a worker thread to garbage collect
+ std::future<void> mExpireFuture; // GUARDED_BY(mLock)
+ // Our item queue, generally (oldest at front)
+ // TODO: Make separate class, use segmented queue, write lock only end.
+ // Note: Another analytics module might have ownership of an item longer than the log.
+ std::deque<std::shared_ptr<const MediaAnalyticsItem>> mItems; // GUARDED_BY(mLock)
};
-// hook to send things off to the statsd subsystem
-extern bool dump2Statsd(MediaAnalyticsItem *item);
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_MEDIAANALYTICSSERVICE_H
+} // namespace android
diff --git a/services/mediaanalytics/OWNERS b/services/mediaanalytics/OWNERS
index 9af258b..e37a1f8 100644
--- a/services/mediaanalytics/OWNERS
+++ b/services/mediaanalytics/OWNERS
@@ -1 +1,2 @@
essick@google.com
+hunga@google.com
diff --git a/services/mediaanalytics/iface_statsd.cpp b/services/mediaanalytics/iface_statsd.cpp
index 6fd4415..e02c9cf 100644
--- a/services/mediaanalytics/iface_statsd.cpp
+++ b/services/mediaanalytics/iface_statsd.cpp
@@ -52,7 +52,7 @@
};
// keep this sorted, so we can do binary searches
-struct statsd_hooks statsd_handlers[] =
+static constexpr struct statsd_hooks statsd_handlers[] =
{
{ "audiopolicy", statsd_audiopolicy },
{ "audiorecord", statsd_audiorecord },
@@ -68,7 +68,6 @@
{ "recorder", statsd_recorder },
};
-
// give me a record, i'll look at the type and upload appropriately
bool dump2Statsd(MediaAnalyticsItem *item) {
if (item == NULL) return false;
@@ -81,10 +80,9 @@
return false;
}
- int i;
- for(i = 0;i < sizeof(statsd_handlers) / sizeof(statsd_handlers[0]) ; i++) {
- if (key == statsd_handlers[i].key) {
- return (*statsd_handlers[i].handler)(item);
+ for (const auto &statsd_handler : statsd_handlers) {
+ if (key == statsd_handler.key) {
+ return statsd_handler.handler(item);
}
}
return false;
diff --git a/services/mediaanalytics/main_mediametrics.cpp b/services/mediaanalytics/main_mediametrics.cpp
index 8020a03..6833fe2 100644
--- a/services/mediaanalytics/main_mediametrics.cpp
+++ b/services/mediaanalytics/main_mediametrics.cpp
@@ -16,33 +16,33 @@
#define LOG_TAG "mediametrics"
//#define LOG_NDEBUG 0
-
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
-#include <binder/IServiceManager.h>
#include <utils/Log.h>
-//#include "RegisterExtensions.h"
-// from LOCAL_C_INCLUDES
#include "MediaAnalyticsService.h"
-using namespace android;
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
int main(int argc __unused, char **argv __unused)
{
+ using namespace android;
+
signal(SIGPIPE, SIG_IGN);
// to match the service name
// we're replacing "/system/bin/mediametrics" with "media.metrics"
// we add a ".", but discard the path components: we finish with a shorter string
- strcpy(argv[0], "media.metrics");
+ strcpy(argv[0], MediaAnalyticsService::kServiceName);
- sp<ProcessState> proc(ProcessState::self());
- sp<IServiceManager> sm(defaultServiceManager());
- ALOGI("ServiceManager: %p", sm.get());
+ defaultServiceManager()->addService(
+ String16(MediaAnalyticsService::kServiceName), new MediaAnalyticsService());
- MediaAnalyticsService::instantiate();
-
- ProcessState::self()->startThreadPool();
+ sp<ProcessState> processState(ProcessState::self());
+ // processState->setThreadPoolMaxThreadCount(8);
+ processState->startThreadPool();
IPCThreadState::self()->joinThreadPool();
+
+ return EXIT_SUCCESS;
}
diff --git a/services/mediaanalytics/statsd_audiopolicy.cpp b/services/mediaanalytics/statsd_audiopolicy.cpp
index 06c4dde..95cb274 100644
--- a/services/mediaanalytics/statsd_audiopolicy.cpp
+++ b/services/mediaanalytics/statsd_audiopolicy.cpp
@@ -60,14 +60,14 @@
metrics_proto.set_status(status);
}
//string char kAudioPolicyRqstSrc[] = "android.media.audiopolicy.rqst.src";
- char *rqst_src = NULL;
- if (item->getCString("android.media.audiopolicy.rqst.src", &rqst_src)) {
- metrics_proto.set_request_source(rqst_src);
+ std::string rqst_src;
+ if (item->getString("android.media.audiopolicy.rqst.src", &rqst_src)) {
+ metrics_proto.set_request_source(std::move(rqst_src));
}
//string char kAudioPolicyRqstPkg[] = "android.media.audiopolicy.rqst.pkg";
- char *rqst_pkg = NULL;
- if (item->getCString("android.media.audiopolicy.rqst.pkg", &rqst_pkg)) {
- metrics_proto.set_request_package(rqst_pkg);
+ std::string rqst_pkg;
+ if (item->getString("android.media.audiopolicy.rqst.pkg", &rqst_pkg)) {
+ metrics_proto.set_request_package(std::move(rqst_pkg));
}
//int32 char kAudioPolicyRqstSession[] = "android.media.audiopolicy.rqst.session";
int32_t rqst_session = -1;
@@ -75,20 +75,20 @@
metrics_proto.set_request_session(rqst_session);
}
//string char kAudioPolicyRqstDevice[] = "android.media.audiopolicy.rqst.device";
- char *rqst_device = NULL;
- if (item->getCString("android.media.audiopolicy.rqst.device", &rqst_device)) {
- metrics_proto.set_request_device(rqst_device);
+ std::string rqst_device;
+ if (item->getString("android.media.audiopolicy.rqst.device", &rqst_device)) {
+ metrics_proto.set_request_device(std::move(rqst_device));
}
//string char kAudioPolicyActiveSrc[] = "android.media.audiopolicy.active.src";
- char *active_src = NULL;
- if (item->getCString("android.media.audiopolicy.active.src", &active_src)) {
- metrics_proto.set_active_source(active_src);
+ std::string active_src;
+ if (item->getString("android.media.audiopolicy.active.src", &active_src)) {
+ metrics_proto.set_active_source(std::move(active_src));
}
//string char kAudioPolicyActivePkg[] = "android.media.audiopolicy.active.pkg";
- char *active_pkg = NULL;
- if (item->getCString("android.media.audiopolicy.active.pkg", &active_pkg)) {
- metrics_proto.set_active_package(active_pkg);
+ std::string active_pkg;
+ if (item->getString("android.media.audiopolicy.active.pkg", &active_pkg)) {
+ metrics_proto.set_active_package(std::move(active_pkg));
}
//int32 char kAudioPolicyActiveSession[] = "android.media.audiopolicy.active.session";
int32_t active_session = -1;
@@ -96,9 +96,9 @@
metrics_proto.set_active_session(active_session);
}
//string char kAudioPolicyActiveDevice[] = "android.media.audiopolicy.active.device";
- char *active_device = NULL;
- if (item->getCString("android.media.audiopolicy.active.device", &active_device)) {
- metrics_proto.set_active_device(active_device);
+ std::string active_device;
+ if (item->getString("android.media.audiopolicy.active.device", &active_device)) {
+ metrics_proto.set_active_device(std::move(active_device));
}
@@ -119,14 +119,6 @@
ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
}
- // must free the strings that we were given
- free(rqst_src);
- free(rqst_pkg);
- free(rqst_device);
- free(active_src);
- free(active_pkg);
- free(active_device);
-
return true;
}
diff --git a/services/mediaanalytics/statsd_audiorecord.cpp b/services/mediaanalytics/statsd_audiorecord.cpp
index c9edb27..7c7a62c 100644
--- a/services/mediaanalytics/statsd_audiorecord.cpp
+++ b/services/mediaanalytics/statsd_audiorecord.cpp
@@ -54,14 +54,14 @@
// flesh out the protobuf we'll hand off with our data
//
- char *encoding = NULL;
- if (item->getCString("android.media.audiorecord.encoding", &encoding)) {
- metrics_proto.set_encoding(encoding);
+ std::string encoding;
+ if (item->getString("android.media.audiorecord.encoding", &encoding)) {
+ metrics_proto.set_encoding(std::move(encoding));
}
- char *source = NULL;
- if (item->getCString("android.media.audiorecord.source", &source)) {
- metrics_proto.set_source(source);
+ std::string source;
+ if (item->getString("android.media.audiorecord.source", &source)) {
+ metrics_proto.set_source(std::move(source));
}
int32_t latency = -1;
@@ -101,11 +101,11 @@
metrics_proto.set_error_code(errcode);
}
- char *errfunc = NULL;
- if (item->getCString("android.media.audiorecord.errfunc", &errfunc)) {
- metrics_proto.set_error_function(errfunc);
- } else if (item->getCString("android.media.audiorecord.lastError.at", &errfunc)) {
- metrics_proto.set_error_function(errfunc);
+ std::string errfunc;
+ if (item->getString("android.media.audiorecord.errfunc", &errfunc)) {
+ metrics_proto.set_error_function(std::move(errfunc));
+ } else if (item->getString("android.media.audiorecord.lastError.at", &errfunc)) {
+ metrics_proto.set_error_function(std::move(errfunc));
}
// portId (int32)
@@ -119,9 +119,9 @@
metrics_proto.set_frame_count(frameCount);
}
// attributes (string)
- char *attributes = NULL;
- if (item->getCString("android.media.audiorecord.attributes", &attributes)) {
- metrics_proto.set_attributes(attributes);
+ std::string attributes;
+ if (item->getString("android.media.audiorecord.attributes", &attributes)) {
+ metrics_proto.set_attributes(std::move(attributes));
}
// channelMask (int64)
int64_t channelMask = -1;
@@ -152,12 +152,6 @@
ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
}
- // must free the strings that we were given
- free(encoding);
- free(source);
- free(errfunc);
- free(attributes);
-
return true;
}
diff --git a/services/mediaanalytics/statsd_audiothread.cpp b/services/mediaanalytics/statsd_audiothread.cpp
index 8232424..e9d6b17 100644
--- a/services/mediaanalytics/statsd_audiothread.cpp
+++ b/services/mediaanalytics/statsd_audiothread.cpp
@@ -56,9 +56,9 @@
// flesh out the protobuf we'll hand off with our data
//
- char *mytype = NULL;
- if (item->getCString(MM_PREFIX "type", &mytype)) {
- metrics_proto.set_type(mytype);
+ std::string mytype;
+ if (item->getString(MM_PREFIX "type", &mytype)) {
+ metrics_proto.set_type(std::move(mytype));
}
int32_t framecount = -1;
if (item->getInt32(MM_PREFIX "framecount", &framecount)) {
@@ -68,17 +68,17 @@
if (item->getInt32(MM_PREFIX "samplerate", &samplerate)) {
metrics_proto.set_samplerate(samplerate);
}
- char *workhist = NULL;
- if (item->getCString(MM_PREFIX "workMs.hist", &workhist)) {
- metrics_proto.set_work_millis_hist(workhist);
+ std::string workhist;
+ if (item->getString(MM_PREFIX "workMs.hist", &workhist)) {
+ metrics_proto.set_work_millis_hist(std::move(workhist));
}
- char *latencyhist = NULL;
- if (item->getCString(MM_PREFIX "latencyMs.hist", &latencyhist)) {
- metrics_proto.set_latency_millis_hist(latencyhist);
+ std::string latencyhist;
+ if (item->getString(MM_PREFIX "latencyMs.hist", &latencyhist)) {
+ metrics_proto.set_latency_millis_hist(std::move(latencyhist));
}
- char *warmuphist = NULL;
- if (item->getCString(MM_PREFIX "warmupMs.hist", &warmuphist)) {
- metrics_proto.set_warmup_millis_hist(warmuphist);
+ std::string warmuphist;
+ if (item->getString(MM_PREFIX "warmupMs.hist", &warmuphist)) {
+ metrics_proto.set_warmup_millis_hist(std::move(warmuphist));
}
int64_t underruns = -1;
if (item->getInt64(MM_PREFIX "underruns", &underruns)) {
@@ -108,9 +108,9 @@
metrics_proto.set_port_id(port_id);
}
// item->setCString(MM_PREFIX "type", threadTypeToString(mType));
- char *type = NULL;
- if (item->getCString(MM_PREFIX "type", &type)) {
- metrics_proto.set_type(type);
+ std::string type;
+ if (item->getString(MM_PREFIX "type", &type)) {
+ metrics_proto.set_type(std::move(type));
}
// item->setInt32(MM_PREFIX "sampleRate", (int32_t)mSampleRate);
int32_t sample_rate = -1;
@@ -123,9 +123,9 @@
metrics_proto.set_channel_mask(channel_mask);
}
// item->setCString(MM_PREFIX "encoding", toString(mFormat).c_str());
- char *encoding = NULL;
- if (item->getCString(MM_PREFIX "encoding", &encoding)) {
- metrics_proto.set_encoding(encoding);
+ std::string encoding;
+ if (item->getString(MM_PREFIX "encoding", &encoding)) {
+ metrics_proto.set_encoding(std::move(encoding));
}
// item->setInt32(MM_PREFIX "frameCount", (int32_t)mFrameCount);
int32_t frame_count = -1;
@@ -133,14 +133,14 @@
metrics_proto.set_frame_count(frame_count);
}
// item->setCString(MM_PREFIX "outDevice", toString(mOutDevice).c_str());
- char *outDevice = NULL;
- if (item->getCString(MM_PREFIX "outDevice", &outDevice)) {
- metrics_proto.set_output_device(outDevice);
+ std::string outDevice;
+ if (item->getString(MM_PREFIX "outDevice", &outDevice)) {
+ metrics_proto.set_output_device(std::move(outDevice));
}
// item->setCString(MM_PREFIX "inDevice", toString(mInDevice).c_str());
- char *inDevice = NULL;
- if (item->getCString(MM_PREFIX "inDevice", &inDevice)) {
- metrics_proto.set_input_device(inDevice);
+ std::string inDevice;
+ if (item->getString(MM_PREFIX "inDevice", &inDevice)) {
+ metrics_proto.set_input_device(std::move(inDevice));
}
// item->setDouble(MM_PREFIX "ioJitterMs.mean", mIoJitterMs.getMean());
double iojitters_ms_mean = -1;
@@ -201,16 +201,6 @@
ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
}
- // must free the strings that we were given
- free(mytype);
- free(workhist);
- free(latencyhist);
- free(warmuphist);
- free(type);
- free(encoding);
- free(inDevice);
- free(outDevice);
-
return true;
}
diff --git a/services/mediaanalytics/statsd_audiotrack.cpp b/services/mediaanalytics/statsd_audiotrack.cpp
index f250ced..57cda99 100644
--- a/services/mediaanalytics/statsd_audiotrack.cpp
+++ b/services/mediaanalytics/statsd_audiotrack.cpp
@@ -57,23 +57,23 @@
// static constexpr char kAudioTrackStreamType[] = "android.media.audiotrack.streamtype";
// optional string streamType;
- char *streamtype = NULL;
- if (item->getCString("android.media.audiotrack.streamtype", &streamtype)) {
- metrics_proto.set_stream_type(streamtype);
+ std::string streamtype;
+ if (item->getString("android.media.audiotrack.streamtype", &streamtype)) {
+ metrics_proto.set_stream_type(std::move(streamtype));
}
// static constexpr char kAudioTrackContentType[] = "android.media.audiotrack.type";
// optional string contentType;
- char *contenttype = NULL;
- if (item->getCString("android.media.audiotrack.type", &contenttype)) {
- metrics_proto.set_content_type(contenttype);
+ std::string contenttype;
+ if (item->getString("android.media.audiotrack.type", &contenttype)) {
+ metrics_proto.set_content_type(std::move(contenttype));
}
// static constexpr char kAudioTrackUsage[] = "android.media.audiotrack.usage";
// optional string trackUsage;
- char *trackusage = NULL;
- if (item->getCString("android.media.audiotrack.usage", &trackusage)) {
- metrics_proto.set_track_usage(trackusage);
+ std::string trackusage;
+ if (item->getString("android.media.audiotrack.usage", &trackusage)) {
+ metrics_proto.set_track_usage(std::move(trackusage));
}
// static constexpr char kAudioTrackSampleRate[] = "android.media.audiotrack.samplerate";
@@ -111,9 +111,9 @@
metrics_proto.set_port_id(port_id);
}
// encoding (string)
- char *encoding = NULL;
- if (item->getCString("android.media.audiotrack.encoding", &encoding)) {
- metrics_proto.set_encoding(encoding);
+ std::string encoding;
+ if (item->getString("android.media.audiotrack.encoding", &encoding)) {
+ metrics_proto.set_encoding(std::move(encoding));
}
// frameCount (int32)
int32_t frame_count = -1;
@@ -121,9 +121,9 @@
metrics_proto.set_frame_count(frame_count);
}
// attributes (string)
- char *attributes = NULL;
- if (item->getCString("android.media.audiotrack.attributes", &attributes)) {
- metrics_proto.set_attributes(attributes);
+ std::string attributes;
+ if (item->getString("android.media.audiotrack.attributes", &attributes)) {
+ metrics_proto.set_attributes(std::move(attributes));
}
std::string serialized;
@@ -143,13 +143,6 @@
ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
}
- // must free the strings that we were given
- free(streamtype);
- free(contenttype);
- free(trackusage);
- free(encoding);
- free(attributes);
-
return true;
}
diff --git a/services/mediaanalytics/statsd_codec.cpp b/services/mediaanalytics/statsd_codec.cpp
index dc8e4ef..bf82e50 100644
--- a/services/mediaanalytics/statsd_codec.cpp
+++ b/services/mediaanalytics/statsd_codec.cpp
@@ -55,19 +55,19 @@
// flesh out the protobuf we'll hand off with our data
//
// android.media.mediacodec.codec string
- char *codec = NULL;
- if (item->getCString("android.media.mediacodec.codec", &codec)) {
- metrics_proto.set_codec(codec);
+ std::string codec;
+ if (item->getString("android.media.mediacodec.codec", &codec)) {
+ metrics_proto.set_codec(std::move(codec));
}
// android.media.mediacodec.mime string
- char *mime = NULL;
- if (item->getCString("android.media.mediacodec.mime", &mime)) {
- metrics_proto.set_mime(mime);
+ std::string mime;
+ if (item->getString("android.media.mediacodec.mime", &mime)) {
+ metrics_proto.set_mime(std::move(mime));
}
// android.media.mediacodec.mode string
- char *mode = NULL;
- if ( item->getCString("android.media.mediacodec.mode", &mode)) {
- metrics_proto.set_mode(mode);
+ std::string mode;
+ if ( item->getString("android.media.mediacodec.mode", &mode)) {
+ metrics_proto.set_mode(std::move(mode));
}
// android.media.mediacodec.encoder int32
int32_t encoder = -1;
@@ -125,9 +125,9 @@
metrics_proto.set_error_code(errcode);
}
// android.media.mediacodec.errstate string
- char *errstate = NULL;
- if ( item->getCString("android.media.mediacodec.errstate", &errstate)) {
- metrics_proto.set_error_state(errstate);
+ std::string errstate;
+ if ( item->getString("android.media.mediacodec.errstate", &errstate)) {
+ metrics_proto.set_error_state(std::move(errstate));
}
// android.media.mediacodec.latency.max int64
int64_t latency_max = -1;
@@ -173,12 +173,6 @@
ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
}
- // must free the strings that we were given
- free(codec);
- free(mime);
- free(mode);
- free(errstate);
-
return true;
}
diff --git a/services/mediaanalytics/statsd_extractor.cpp b/services/mediaanalytics/statsd_extractor.cpp
index 395c912..d84930c 100644
--- a/services/mediaanalytics/statsd_extractor.cpp
+++ b/services/mediaanalytics/statsd_extractor.cpp
@@ -56,14 +56,14 @@
//
// android.media.mediaextractor.fmt string
- char *fmt = NULL;
- if (item->getCString("android.media.mediaextractor.fmt", &fmt)) {
- metrics_proto.set_format(fmt);
+ std::string fmt;
+ if (item->getString("android.media.mediaextractor.fmt", &fmt)) {
+ metrics_proto.set_format(std::move(fmt));
}
// android.media.mediaextractor.mime string
- char *mime = NULL;
- if (item->getCString("android.media.mediaextractor.mime", &mime)) {
- metrics_proto.set_mime(mime);
+ std::string mime;
+ if (item->getString("android.media.mediaextractor.mime", &mime)) {
+ metrics_proto.set_mime(std::move(mime));
}
// android.media.mediaextractor.ntrk int32
int32_t ntrk = -1;
@@ -88,10 +88,6 @@
ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
}
- // must free the strings that we were given
- free(fmt);
- free(mime);
-
return true;
}
diff --git a/services/mediaanalytics/statsd_nuplayer.cpp b/services/mediaanalytics/statsd_nuplayer.cpp
index 5ec118a..e6e0f2c 100644
--- a/services/mediaanalytics/statsd_nuplayer.cpp
+++ b/services/mediaanalytics/statsd_nuplayer.cpp
@@ -62,13 +62,13 @@
// differentiate between nuplayer and nuplayer2
metrics_proto.set_whichplayer(item->getKey().c_str());
- char *video_mime = NULL;
- if (item->getCString("android.media.mediaplayer.video.mime", &video_mime)) {
- metrics_proto.set_video_mime(video_mime);
+ std::string video_mime;
+ if (item->getString("android.media.mediaplayer.video.mime", &video_mime)) {
+ metrics_proto.set_video_mime(std::move(video_mime));
}
- char *video_codec = NULL;
- if (item->getCString("android.media.mediaplayer.video.codec", &video_codec)) {
- metrics_proto.set_video_codec(video_codec);
+ std::string video_codec;
+ if (item->getString("android.media.mediaplayer.video.codec", &video_codec)) {
+ metrics_proto.set_video_codec(std::move(video_codec));
}
int32_t width = -1;
@@ -97,13 +97,13 @@
metrics_proto.set_framerate(fps);
}
- char *audio_mime = NULL;
- if (item->getCString("android.media.mediaplayer.audio.mime", &audio_mime)) {
- metrics_proto.set_audio_mime(audio_mime);
+ std::string audio_mime;
+ if (item->getString("android.media.mediaplayer.audio.mime", &audio_mime)) {
+ metrics_proto.set_audio_mime(std::move(audio_mime));
}
- char *audio_codec = NULL;
- if (item->getCString("android.media.mediaplayer.audio.codec", &audio_codec)) {
- metrics_proto.set_audio_codec(audio_codec);
+ std::string audio_codec;
+ if (item->getString("android.media.mediaplayer.audio.codec", &audio_codec)) {
+ metrics_proto.set_audio_codec(std::move(audio_codec));
}
int64_t duration_ms = -1;
@@ -123,14 +123,14 @@
if (item->getInt32("android.media.mediaplayer.errcode", &error_code)) {
metrics_proto.set_error_code(error_code);
}
- char *error_state = NULL;
- if (item->getCString("android.media.mediaplayer.errstate", &error_state)) {
- metrics_proto.set_error_state(error_state);
+ std::string error_state;
+ if (item->getString("android.media.mediaplayer.errstate", &error_state)) {
+ metrics_proto.set_error_state(std::move(error_state));
}
- char *data_source_type = NULL;
- if (item->getCString("android.media.mediaplayer.dataSource", &data_source_type)) {
- metrics_proto.set_data_source_type(data_source_type);
+ std::string data_source_type;
+ if (item->getString("android.media.mediaplayer.dataSource", &data_source_type)) {
+ metrics_proto.set_data_source_type(std::move(data_source_type));
}
int64_t rebufferingMs = -1;
@@ -164,14 +164,6 @@
ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
}
- // must free the strings that we were given
- free(video_mime);
- free(video_codec);
- free(audio_mime);
- free(audio_codec);
- free(error_state);
- free(data_source_type);
-
return true;
}
diff --git a/services/mediaanalytics/statsd_recorder.cpp b/services/mediaanalytics/statsd_recorder.cpp
index 4d981b4..d286f00 100644
--- a/services/mediaanalytics/statsd_recorder.cpp
+++ b/services/mediaanalytics/statsd_recorder.cpp
@@ -56,14 +56,14 @@
//
// string kRecorderAudioMime = "android.media.mediarecorder.audio.mime";
- char *audio_mime = NULL;
- if (item->getCString("android.media.mediarecorder.audio.mime", &audio_mime)) {
- metrics_proto.set_audio_mime(audio_mime);
+ std::string audio_mime;
+ if (item->getString("android.media.mediarecorder.audio.mime", &audio_mime)) {
+ metrics_proto.set_audio_mime(std::move(audio_mime));
}
// string kRecorderVideoMime = "android.media.mediarecorder.video.mime";
- char *video_mime = NULL;
- if (item->getCString("android.media.mediarecorder.video.mime", &video_mime)) {
- metrics_proto.set_video_mime(video_mime);
+ std::string video_mime;
+ if (item->getString("android.media.mediarecorder.video.mime", &video_mime)) {
+ metrics_proto.set_video_mime(std::move(video_mime));
}
// int32 kRecorderVideoProfile = "android.media.mediarecorder.video-encoder-profile";
int32_t videoProfile = -1;
@@ -183,10 +183,6 @@
ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
}
- // must free the strings that we were given
- free(audio_mime);
- free(video_mime);
-
return true;
}
diff --git a/services/mediaanalytics/tests/Android.bp b/services/mediaanalytics/tests/Android.bp
new file mode 100644
index 0000000..7bca1c4
--- /dev/null
+++ b/services/mediaanalytics/tests/Android.bp
@@ -0,0 +1,25 @@
+cc_test {
+ name: "mediametrics_tests",
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+
+ include_dirs: [
+ "frameworks/av/services/mediaanalytics",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "liblog",
+ "libmediaanalyticsservice",
+ "libmediametrics",
+ "libutils",
+ ],
+
+ srcs: [
+ "mediametrics_tests.cpp",
+ ],
+}
diff --git a/services/mediaanalytics/tests/build_and_run_all_unit_tests.sh b/services/mediaanalytics/tests/build_and_run_all_unit_tests.sh
new file mode 100755
index 0000000..2511c30
--- /dev/null
+++ b/services/mediaanalytics/tests/build_and_run_all_unit_tests.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+#
+# Run tests in this directory.
+#
+
+if [ -z "$ANDROID_BUILD_TOP" ]; then
+ echo "Android build environment not set"
+ exit -1
+fi
+
+# ensure we have mm
+. $ANDROID_BUILD_TOP/build/envsetup.sh
+
+mm
+
+echo "waiting for device"
+
+adb root && adb wait-for-device remount
+
+echo "========================================"
+
+echo "testing mediametrics"
+adb push $OUT/data/nativetest/mediametrics_tests/mediametrics_tests /system/bin
+adb shell /system/bin/mediametrics_tests
diff --git a/services/mediaanalytics/tests/mediametrics_tests.cpp b/services/mediaanalytics/tests/mediametrics_tests.cpp
new file mode 100644
index 0000000..7a6f5a4
--- /dev/null
+++ b/services/mediaanalytics/tests/mediametrics_tests.cpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2019 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 "mediametrics_tests"
+#include <utils/Log.h>
+
+#include "MediaAnalyticsService.h"
+
+#include <stdio.h>
+
+#include <gtest/gtest.h>
+#include <media/MediaAnalyticsItem.h>
+
+using namespace android;
+
+TEST(mediametrics_tests, instantiate) {
+ sp mediaMetrics = new MediaAnalyticsService();
+ status_t status;
+
+ // random keys ignored when empty
+ std::unique_ptr<MediaAnalyticsItem> random_key(MediaAnalyticsItem::create("random_key"));
+ status = mediaMetrics->submit(random_key.get());
+ ASSERT_EQ(PERMISSION_DENIED, status);
+
+ // random keys ignored with data
+ random_key->setInt32("foo", 10);
+ status = mediaMetrics->submit(random_key.get());
+ ASSERT_EQ(PERMISSION_DENIED, status);
+
+ // known keys ignored if empty
+ std::unique_ptr<MediaAnalyticsItem> audiotrack_key(MediaAnalyticsItem::create("audiotrack"));
+ status = mediaMetrics->submit(audiotrack_key.get());
+ ASSERT_EQ(BAD_VALUE, status);
+
+ // known keys not ignored if not empty
+ audiotrack_key->addInt32("foo", 10);
+ status = mediaMetrics->submit(audiotrack_key.get());
+ ASSERT_EQ(NO_ERROR, status);
+
+
+ /*
+ // fluent style that goes directly to mediametrics
+ ASSERT_EQ(true, MediaAnalyticsItem("audiorecord")
+ .setInt32("value", 2)
+ .addInt32("bar", 1)
+ .addInt32("value", 3)
+ .selfrecord());
+ */
+
+ mediaMetrics->dump(fileno(stdout), {} /* args */);
+}
+
+TEST(mediametrics_tests, item_manipulation) {
+ MediaAnalyticsItem item("audiorecord");
+
+ item.setInt32("value", 2).addInt32("bar", 3).addInt32("value", 4);
+
+ int32_t i32;
+ ASSERT_TRUE(item.getInt32("value", &i32));
+ ASSERT_EQ(6, i32);
+
+ ASSERT_TRUE(item.getInt32("bar", &i32));
+ ASSERT_EQ(3, i32);
+
+ item.setInt64("big", INT64_MAX).setInt64("smaller", INT64_MAX - 1).addInt64("smaller", -2);
+
+ int64_t i64;
+ ASSERT_TRUE(item.getInt64("big", &i64));
+ ASSERT_EQ(INT64_MAX, i64);
+
+ ASSERT_TRUE(item.getInt64("smaller", &i64));
+ ASSERT_EQ(INT64_MAX - 3, i64);
+
+ item.setDouble("precise", 10.5).setDouble("small", 0.125).addDouble("precise", 0.25);
+
+ double d;
+ ASSERT_TRUE(item.getDouble("precise", &d));
+ ASSERT_EQ(10.75, d);
+
+ ASSERT_TRUE(item.getDouble("small", &d));
+ ASSERT_EQ(0.125, d);
+
+ char *s;
+ item.setCString("name", "Frank").setCString("mother", "June").setCString("mother", "July");
+ ASSERT_TRUE(item.getCString("name", &s));
+ ASSERT_EQ(0, strcmp(s, "Frank"));
+ free(s);
+
+ ASSERT_TRUE(item.getCString("mother", &s));
+ ASSERT_EQ(0, strcmp(s, "July")); // "July" overwrites "June"
+ free(s);
+
+ item.setRate("burgersPerHour", 5, 2);
+ int64_t b, h;
+ ASSERT_TRUE(item.getRate("burgersPerHour", &b, &h, &d));
+ ASSERT_EQ(5, b);
+ ASSERT_EQ(2, h);
+ ASSERT_EQ(2.5, d);
+
+ item.addRate("burgersPerHour", 4, 2);
+ ASSERT_TRUE(item.getRate("burgersPerHour", &b, &h, &d));
+ ASSERT_EQ(9, b);
+ ASSERT_EQ(4, h);
+ ASSERT_EQ(2.25, d);
+
+ printf("item: %s\n", item.toString().c_str());
+ fflush(stdout);
+
+ sp mediaMetrics = new MediaAnalyticsService();
+ status_t status = mediaMetrics->submit(&item);
+ ASSERT_EQ(NO_ERROR, status);
+ mediaMetrics->dump(fileno(stdout), {} /* args */);
+}
+
+TEST(mediametrics_tests, superbig_item) {
+ MediaAnalyticsItem item("TheBigOne");
+ constexpr size_t count = 10000;
+
+ for (size_t i = 0; i < count; ++i) {
+ item.setInt32(std::to_string(i).c_str(), i);
+ }
+ for (size_t i = 0; i < count; ++i) {
+ int32_t i32;
+ ASSERT_TRUE(item.getInt32(std::to_string(i).c_str(), &i32));
+ ASSERT_EQ((int32_t)i, i32);
+ }
+}
+
+TEST(mediametrics_tests, superbig_item_removal) {
+ MediaAnalyticsItem item("TheOddBigOne");
+ constexpr size_t count = 10000;
+
+ for (size_t i = 0; i < count; ++i) {
+ item.setInt32(std::to_string(i).c_str(), i);
+ }
+ for (size_t i = 0; i < count; i += 2) {
+ item.filter(std::to_string(i).c_str()); // filter out all the evens.
+ }
+ for (size_t i = 0; i < count; ++i) {
+ int32_t i32;
+ if (i & 1) { // check to see that only the odds are left.
+ ASSERT_TRUE(item.getInt32(std::to_string(i).c_str(), &i32));
+ ASSERT_EQ((int32_t)i, i32);
+ } else {
+ ASSERT_FALSE(item.getInt32(std::to_string(i).c_str(), &i32));
+ }
+ }
+}
+
+TEST(mediametrics_tests, item_transmutation) {
+ MediaAnalyticsItem item("Alchemist's Stone");
+
+ item.setInt64("convert", 123);
+ int64_t i64;
+ ASSERT_TRUE(item.getInt64("convert", &i64));
+ ASSERT_EQ(123, i64);
+
+ item.addInt32("convert", 2); // changes type of 'convert' from i64 to i32 (and re-init).
+ ASSERT_FALSE(item.getInt64("convert", &i64)); // should be false, no value in i64.
+
+ int32_t i32;
+ ASSERT_TRUE(item.getInt32("convert", &i32)); // check it is i32 and 2 (123 is discarded).
+ ASSERT_EQ(2, i32);
+}
diff --git a/services/mediadrm/Android.mk b/services/mediadrm/Android.mk
index 3e94596..72d42ae 100644
--- a/services/mediadrm/Android.mk
+++ b/services/mediadrm/Android.mk
@@ -20,9 +20,14 @@
MediaDrmService.cpp \
main_mediadrmserver.cpp
+LOCAL_HEADER_LIBRARIES:= \
+ libmedia_headers \
+ libmediadrm_headers
+
LOCAL_SHARED_LIBRARIES:= \
libbinder \
liblog \
+ libmedia \
libmediadrm \
libutils \
libhidlbase \
diff --git a/services/mediaextractor/Android.bp b/services/mediaextractor/Android.bp
index 98cc69f..828e89a 100644
--- a/services/mediaextractor/Android.bp
+++ b/services/mediaextractor/Android.bp
@@ -8,6 +8,7 @@
srcs: ["MediaExtractorService.cpp"],
shared_libs: [
+ "libdatasource",
"libmedia",
"libstagefright",
"libbinder",
diff --git a/services/mediaextractor/MediaExtractorService.cpp b/services/mediaextractor/MediaExtractorService.cpp
index 36e084b..6239fb2 100644
--- a/services/mediaextractor/MediaExtractorService.cpp
+++ b/services/mediaextractor/MediaExtractorService.cpp
@@ -20,8 +20,8 @@
#include <utils/Vector.h>
+#include <datasource/DataSourceFactory.h>
#include <media/DataSource.h>
-#include <media/stagefright/DataSourceFactory.h>
#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/MediaExtractorFactory.h>
#include <media/stagefright/RemoteDataSource.h>
@@ -55,7 +55,7 @@
sp<IDataSource> MediaExtractorService::makeIDataSource(int fd, int64_t offset, int64_t length)
{
- sp<DataSource> source = DataSourceFactory::CreateFromFd(fd, offset, length);
+ sp<DataSource> source = DataSourceFactory::getInstance()->CreateFromFd(fd, offset, length);
return CreateIDataSourceFromDataSource(source);
}
diff --git a/services/medialog/Android.bp b/services/medialog/Android.bp
index bee5d25..74b63d5 100644
--- a/services/medialog/Android.bp
+++ b/services/medialog/Android.bp
@@ -6,6 +6,10 @@
"MediaLogService.cpp",
],
+ header_libs: [
+ "libmedia_headers",
+ ],
+
shared_libs: [
"libaudioutils",
"libbinder",
diff --git a/services/mediaresourcemanager/Android.bp b/services/mediaresourcemanager/Android.bp
index f3339a0..d468406 100644
--- a/services/mediaresourcemanager/Android.bp
+++ b/services/mediaresourcemanager/Android.bp
@@ -23,4 +23,6 @@
"-Wall",
],
+ export_include_dirs: ["."],
+
}
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index bdcd5e4..ae832c7 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -23,6 +23,7 @@
#include <binder/IServiceManager.h>
#include <cutils/sched_policy.h>
#include <dirent.h>
+#include <media/MediaResourcePolicy.h>
#include <media/stagefright/ProcessInfo.h>
#include <mediautils/BatteryNotifier.h>
#include <mediautils/SchedulingPolicyService.h>
@@ -37,7 +38,7 @@
namespace android {
-namespace {
+namespace media {
class DeathNotifier : public IBinder::DeathRecipient {
public:
@@ -60,20 +61,18 @@
int64_t mClientId;
};
-} // namespace
-
template <typename T>
-static String8 getString(const Vector<T> &items) {
+static String8 getString(const std::vector<T> &items) {
String8 itemsStr;
for (size_t i = 0; i < items.size(); ++i) {
- itemsStr.appendFormat("%s ", items[i].toString().string());
+ itemsStr.appendFormat("%s ", toString(items[i]).string());
}
return itemsStr;
}
static bool hasResourceType(MediaResource::Type type, const ResourceList& resources) {
for (auto it = resources.begin(); it != resources.end(); it++) {
- if (it->second.mType == type) {
+ if (it->second.type == type) {
return true;
}
}
@@ -121,15 +120,15 @@
return infos.editValueAt(index);
}
-static void notifyResourceGranted(int pid, const Vector<MediaResource> &resources) {
+static void notifyResourceGranted(int pid, const std::vector<MediaResourceParcel> &resources) {
static const char* const kServiceName = "media_resource_monitor";
sp<IBinder> binder = defaultServiceManager()->checkService(String16(kServiceName));
if (binder != NULL) {
sp<IMediaResourceMonitor> service = interface_cast<IMediaResourceMonitor>(binder);
for (size_t i = 0; i < resources.size(); ++i) {
- if (resources[i].mSubType == MediaResource::kAudioCodec) {
+ if (resources[i].subType == MediaResource::SubType::kAudioCodec) {
service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_AUDIO_CODEC);
- } else if (resources[i].mSubType == MediaResource::kVideoCodec) {
+ } else if (resources[i].subType == MediaResource::SubType::kVideoCodec) {
service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_VIDEO_CODEC);
}
}
@@ -182,13 +181,18 @@
snprintf(buffer, SIZE, " Id: %lld\n", (long long)infos[j].clientId);
result.append(buffer);
- snprintf(buffer, SIZE, " Name: %s\n", infos[j].client->getName().string());
+ std::string clientName;
+ Status status = infos[j].client->getName(&clientName);
+ if (!status.isOk()) {
+ clientName = "<unknown client>";
+ }
+ snprintf(buffer, SIZE, " Name: %s\n", clientName.c_str());
result.append(buffer);
const ResourceList &resources = infos[j].resources;
result.append(" Resources:\n");
for (auto it = resources.begin(); it != resources.end(); it++) {
- snprintf(buffer, SIZE, " %s\n", it->second.toString().string());
+ snprintf(buffer, SIZE, " %s\n", toString(it->second).string());
result.append(buffer);
}
}
@@ -242,27 +246,28 @@
ResourceManagerService::~ResourceManagerService() {}
-void ResourceManagerService::config(const Vector<MediaResourcePolicy> &policies) {
+Status ResourceManagerService::config(const std::vector<MediaResourcePolicyParcel>& policies) {
String8 log = String8::format("config(%s)", getString(policies).string());
mServiceLog->add(log);
Mutex::Autolock lock(mLock);
for (size_t i = 0; i < policies.size(); ++i) {
- String8 type = policies[i].mType;
- String8 value = policies[i].mValue;
- if (type == kPolicySupportsMultipleSecureCodecs) {
+ const std::string &type = policies[i].type;
+ const std::string &value = policies[i].value;
+ if (type == MediaResourcePolicy::kPolicySupportsMultipleSecureCodecs()) {
mSupportsMultipleSecureCodecs = (value == "true");
- } else if (type == kPolicySupportsSecureWithNonSecureCodec) {
+ } else if (type == MediaResourcePolicy::kPolicySupportsSecureWithNonSecureCodec()) {
mSupportsSecureWithNonSecureCodec = (value == "true");
}
}
+ return Status::ok();
}
void ResourceManagerService::onFirstAdded(
- const MediaResource& resource, const ResourceInfo& clientInfo) {
+ const MediaResourceParcel& resource, const ResourceInfo& clientInfo) {
// first time added
- if (resource.mType == MediaResource::kCpuBoost
- && resource.mSubType == MediaResource::kUnspecifiedSubType) {
+ if (resource.type == MediaResource::Type::kCpuBoost
+ && resource.subType == MediaResource::SubType::kUnspecifiedSubType) {
// Request it on every new instance of kCpuBoost, as the media.codec
// could have died, if we only do it the first time subsequent instances
// never gets the boost.
@@ -270,32 +275,49 @@
ALOGW("couldn't request cpuset boost");
}
mCpuBoostCount++;
- } else if (resource.mType == MediaResource::kBattery
- && resource.mSubType == MediaResource::kVideoCodec) {
+ } else if (resource.type == MediaResource::Type::kBattery
+ && resource.subType == MediaResource::SubType::kVideoCodec) {
mSystemCB->noteStartVideo(clientInfo.uid);
}
}
void ResourceManagerService::onLastRemoved(
- const MediaResource& resource, const ResourceInfo& clientInfo) {
- if (resource.mType == MediaResource::kCpuBoost
- && resource.mSubType == MediaResource::kUnspecifiedSubType
+ const MediaResourceParcel& resource, const ResourceInfo& clientInfo) {
+ if (resource.type == MediaResource::Type::kCpuBoost
+ && resource.subType == MediaResource::SubType::kUnspecifiedSubType
&& mCpuBoostCount > 0) {
if (--mCpuBoostCount == 0) {
mSystemCB->requestCpusetBoost(false, this);
}
- } else if (resource.mType == MediaResource::kBattery
- && resource.mSubType == MediaResource::kVideoCodec) {
+ } else if (resource.type == MediaResource::Type::kBattery
+ && resource.subType == MediaResource::SubType::kVideoCodec) {
mSystemCB->noteStopVideo(clientInfo.uid);
}
}
-void ResourceManagerService::addResource(
- int pid,
- int uid,
+void ResourceManagerService::mergeResources(
+ MediaResourceParcel& r1, const MediaResourceParcel& r2) {
+ // The resource entry on record is maintained to be in [0,INT64_MAX].
+ // Clamp if merging in the new resource value causes it to go out of bound.
+ // Note that the new resource value could be negative, eg.DrmSession, the
+ // value goes lower when the session is used more often. During reclaim
+ // the session with the highest value (lowest usage) would be closed.
+ if (r2.value < INT64_MAX - r1.value) {
+ r1.value += r2.value;
+ if (r1.value < 0) {
+ r1.value = 0;
+ }
+ } else {
+ r1.value = INT64_MAX;
+ }
+}
+
+Status ResourceManagerService::addResource(
+ int32_t pid,
+ int32_t uid,
int64_t clientId,
- const sp<IResourceManagerClient> client,
- const Vector<MediaResource> &resources) {
+ const sp<IResourceManagerClient>& client,
+ const std::vector<MediaResourceParcel>& resources) {
String8 log = String8::format("addResource(pid %d, clientId %lld, resources %s)",
pid, (long long) clientId, getString(resources).string());
mServiceLog->add(log);
@@ -303,29 +325,43 @@
Mutex::Autolock lock(mLock);
if (!mProcessInfo->isValidPid(pid)) {
ALOGE("Rejected addResource call with invalid pid.");
- return;
+ return Status::fromServiceSpecificError(BAD_VALUE);
}
ResourceInfos& infos = getResourceInfosForEdit(pid, mMap);
ResourceInfo& info = getResourceInfoForEdit(uid, clientId, client, infos);
for (size_t i = 0; i < resources.size(); ++i) {
- const auto resType = std::make_pair(resources[i].mType, resources[i].mSubType);
+ const auto &res = resources[i];
+ const auto resType = std::tuple(res.type, res.subType, res.id);
+
+ if (res.value < 0 && res.type != MediaResource::Type::kDrmSession) {
+ ALOGW("Ignoring request to remove negative value of non-drm resource");
+ continue;
+ }
if (info.resources.find(resType) == info.resources.end()) {
- onFirstAdded(resources[i], info);
- info.resources[resType] = resources[i];
+ if (res.value <= 0) {
+ // We can't init a new entry with negative value, although it's allowed
+ // to merge in negative values after the initial add.
+ ALOGW("Ignoring request to add new resource entry with value <= 0");
+ continue;
+ }
+ onFirstAdded(res, info);
+ info.resources[resType] = res;
} else {
- info.resources[resType].mValue += resources[i].mValue;
+ mergeResources(info.resources[resType], res);
}
}
- if (info.deathNotifier == nullptr) {
+ if (info.deathNotifier == nullptr && client != nullptr) {
info.deathNotifier = new DeathNotifier(this, pid, clientId);
IInterface::asBinder(client)->linkToDeath(info.deathNotifier);
}
notifyResourceGranted(pid, resources);
+ return Status::ok();
}
-void ResourceManagerService::removeResource(int pid, int64_t clientId,
- const Vector<MediaResource> &resources) {
+Status ResourceManagerService::removeResource(
+ int32_t pid, int64_t clientId,
+ const std::vector<MediaResourceParcel>& resources) {
String8 log = String8::format("removeResource(pid %d, clientId %lld, resources %s)",
pid, (long long) clientId, getString(resources).string());
mServiceLog->add(log);
@@ -333,43 +369,51 @@
Mutex::Autolock lock(mLock);
if (!mProcessInfo->isValidPid(pid)) {
ALOGE("Rejected removeResource call with invalid pid.");
- return;
+ return Status::fromServiceSpecificError(BAD_VALUE);
}
ssize_t index = mMap.indexOfKey(pid);
if (index < 0) {
ALOGV("removeResource: didn't find pid %d for clientId %lld", pid, (long long) clientId);
- return;
+ return Status::ok();
}
ResourceInfos &infos = mMap.editValueAt(index);
index = infos.indexOfKey(clientId);
if (index < 0) {
ALOGV("removeResource: didn't find clientId %lld", (long long) clientId);
- return;
+ return Status::ok();
}
ResourceInfo &info = infos.editValueAt(index);
for (size_t i = 0; i < resources.size(); ++i) {
- const auto resType = std::make_pair(resources[i].mType, resources[i].mSubType);
+ const auto &res = resources[i];
+ const auto resType = std::tuple(res.type, res.subType, res.id);
+
+ if (res.value < 0) {
+ ALOGW("Ignoring request to remove negative value of resource");
+ continue;
+ }
// ignore if we don't have it
if (info.resources.find(resType) != info.resources.end()) {
- MediaResource &resource = info.resources[resType];
- if (resource.mValue > resources[i].mValue) {
- resource.mValue -= resources[i].mValue;
+ MediaResourceParcel &resource = info.resources[resType];
+ if (resource.value > res.value) {
+ resource.value -= res.value;
} else {
- onLastRemoved(resources[i], info);
+ onLastRemoved(res, info);
info.resources.erase(resType);
}
}
}
+ return Status::ok();
}
-void ResourceManagerService::removeClient(int pid, int64_t clientId) {
+Status ResourceManagerService::removeClient(int32_t pid, int64_t clientId) {
removeResource(pid, clientId, true);
+ return Status::ok();
}
-void ResourceManagerService::removeResource(int pid, int64_t clientId, bool checkValid) {
+Status ResourceManagerService::removeResource(int pid, int64_t clientId, bool checkValid) {
String8 log = String8::format(
"removeResource(pid %d, clientId %lld)",
pid, (long long) clientId);
@@ -378,19 +422,19 @@
Mutex::Autolock lock(mLock);
if (checkValid && !mProcessInfo->isValidPid(pid)) {
ALOGE("Rejected removeResource call with invalid pid.");
- return;
+ return Status::fromServiceSpecificError(BAD_VALUE);
}
ssize_t index = mMap.indexOfKey(pid);
if (index < 0) {
ALOGV("removeResource: didn't find pid %d for clientId %lld", pid, (long long) clientId);
- return;
+ return Status::ok();
}
ResourceInfos &infos = mMap.editValueAt(index);
index = infos.indexOfKey(clientId);
if (index < 0) {
ALOGV("removeResource: didn't find clientId %lld", (long long) clientId);
- return;
+ return Status::ok();
}
const ResourceInfo &info = infos[index];
@@ -401,66 +445,79 @@
IInterface::asBinder(info.client)->unlinkToDeath(info.deathNotifier);
infos.removeItemsAt(index);
+ return Status::ok();
}
void ResourceManagerService::getClientForResource_l(
- int callingPid, const MediaResource *res, Vector<sp<IResourceManagerClient>> *clients) {
+ int callingPid, const MediaResourceParcel *res, Vector<sp<IResourceManagerClient>> *clients) {
if (res == NULL) {
return;
}
sp<IResourceManagerClient> client;
- if (getLowestPriorityBiggestClient_l(callingPid, res->mType, &client)) {
+ if (getLowestPriorityBiggestClient_l(callingPid, res->type, &client)) {
clients->push_back(client);
}
}
-bool ResourceManagerService::reclaimResource(
- int callingPid, const Vector<MediaResource> &resources) {
+Status ResourceManagerService::reclaimResource(
+ int32_t callingPid,
+ const std::vector<MediaResourceParcel>& resources,
+ bool* _aidl_return) {
String8 log = String8::format("reclaimResource(callingPid %d, resources %s)",
callingPid, getString(resources).string());
mServiceLog->add(log);
+ *_aidl_return = false;
Vector<sp<IResourceManagerClient>> clients;
{
Mutex::Autolock lock(mLock);
if (!mProcessInfo->isValidPid(callingPid)) {
ALOGE("Rejected reclaimResource call with invalid callingPid.");
- return false;
+ return Status::fromServiceSpecificError(BAD_VALUE);
}
- const MediaResource *secureCodec = NULL;
- const MediaResource *nonSecureCodec = NULL;
- const MediaResource *graphicMemory = NULL;
+ const MediaResourceParcel *secureCodec = NULL;
+ const MediaResourceParcel *nonSecureCodec = NULL;
+ const MediaResourceParcel *graphicMemory = NULL;
+ const MediaResourceParcel *drmSession = NULL;
for (size_t i = 0; i < resources.size(); ++i) {
- MediaResource::Type type = resources[i].mType;
- if (resources[i].mType == MediaResource::kSecureCodec) {
+ MediaResource::Type type = resources[i].type;
+ if (resources[i].type == MediaResource::Type::kSecureCodec) {
secureCodec = &resources[i];
- } else if (type == MediaResource::kNonSecureCodec) {
+ } else if (type == MediaResource::Type::kNonSecureCodec) {
nonSecureCodec = &resources[i];
- } else if (type == MediaResource::kGraphicMemory) {
+ } else if (type == MediaResource::Type::kGraphicMemory) {
graphicMemory = &resources[i];
+ } else if (type == MediaResource::Type::kDrmSession) {
+ drmSession = &resources[i];
}
}
// first pass to handle secure/non-secure codec conflict
if (secureCodec != NULL) {
if (!mSupportsMultipleSecureCodecs) {
- if (!getAllClients_l(callingPid, MediaResource::kSecureCodec, &clients)) {
- return false;
+ if (!getAllClients_l(callingPid, MediaResource::Type::kSecureCodec, &clients)) {
+ return Status::ok();
}
}
if (!mSupportsSecureWithNonSecureCodec) {
- if (!getAllClients_l(callingPid, MediaResource::kNonSecureCodec, &clients)) {
- return false;
+ if (!getAllClients_l(callingPid, MediaResource::Type::kNonSecureCodec, &clients)) {
+ return Status::ok();
}
}
}
if (nonSecureCodec != NULL) {
if (!mSupportsSecureWithNonSecureCodec) {
- if (!getAllClients_l(callingPid, MediaResource::kSecureCodec, &clients)) {
- return false;
+ if (!getAllClients_l(callingPid, MediaResource::Type::kSecureCodec, &clients)) {
+ return Status::ok();
}
}
}
+ if (drmSession != NULL) {
+ getClientForResource_l(callingPid, drmSession, &clients);
+ if (clients.size() == 0) {
+ return Status::ok();
+ }
+ }
if (clients.size() == 0) {
// if no secure/non-secure codec conflict, run second pass to handle other resources.
@@ -476,32 +533,35 @@
if (clients.size() == 0) {
// if we are here, run the fourth pass to free one codec with the different type.
if (secureCodec != NULL) {
- MediaResource temp(MediaResource::kNonSecureCodec, 1);
+ MediaResource temp(MediaResource::Type::kNonSecureCodec, 1);
getClientForResource_l(callingPid, &temp, &clients);
}
if (nonSecureCodec != NULL) {
- MediaResource temp(MediaResource::kSecureCodec, 1);
+ MediaResource temp(MediaResource::Type::kSecureCodec, 1);
getClientForResource_l(callingPid, &temp, &clients);
}
}
}
if (clients.size() == 0) {
- return false;
+ return Status::ok();
}
sp<IResourceManagerClient> failedClient;
for (size_t i = 0; i < clients.size(); ++i) {
log = String8::format("reclaimResource from client %p", clients[i].get());
mServiceLog->add(log);
- if (!clients[i]->reclaimResource()) {
+ bool success;
+ Status status = clients[i]->reclaimResource(&success);
+ if (!status.isOk() || !success) {
failedClient = clients[i];
break;
}
}
if (failedClient == NULL) {
- return true;
+ *_aidl_return = true;
+ return Status::ok();
}
{
@@ -526,7 +586,7 @@
}
}
- return false;
+ return Status::ok();
}
bool ResourceManagerService::getAllClients_l(
@@ -641,10 +701,10 @@
for (size_t i = 0; i < infos.size(); ++i) {
const ResourceList &resources = infos[i].resources;
for (auto it = resources.begin(); it != resources.end(); it++) {
- const MediaResource &resource = it->second;
- if (resource.mType == type) {
- if (resource.mValue > largestValue) {
- largestValue = resource.mValue;
+ const MediaResourceParcel &resource = it->second;
+ if (resource.type == type) {
+ if (resource.value > largestValue) {
+ largestValue = resource.value;
clientTemp = infos[i].client;
}
}
@@ -660,4 +720,5 @@
return true;
}
+} // namespace media
} // namespace android
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index f086dc3..b5b9f86 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -15,25 +15,32 @@
** limitations under the License.
*/
-#ifndef ANDROID_RESOURCEMANAGERSERVICE_H
-#define ANDROID_RESOURCEMANAGERSERVICE_H
+#ifndef ANDROID_MEDIA_RESOURCEMANAGERSERVICE_H
+#define ANDROID_MEDIA_RESOURCEMANAGERSERVICE_H
+#include <android/media/BnResourceManagerService.h>
#include <arpa/inet.h>
#include <binder/BinderService.h>
+#include <media/MediaResource.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/String8.h>
#include <utils/threads.h>
#include <utils/Vector.h>
-#include <media/IResourceManagerService.h>
-
namespace android {
class ServiceLog;
struct ProcessInfoInterface;
-typedef std::map<std::pair<MediaResource::Type, MediaResource::SubType>, MediaResource> ResourceList;
+namespace media {
+
+using android::binder::Status;
+
+typedef std::map<std::tuple<
+ MediaResource::Type, MediaResource::SubType, std::vector<uint8_t>>,
+ MediaResourceParcel> ResourceList;
+
struct ResourceInfo {
int64_t clientId;
uid_t uid;
@@ -69,26 +76,31 @@
const sp<SystemCallbackInterface> &systemResource);
// IResourceManagerService interface
- virtual void config(const Vector<MediaResourcePolicy> &policies);
+ Status config(const std::vector<MediaResourcePolicyParcel>& policies) override;
- virtual void addResource(
- int pid,
- int uid,
+ Status addResource(
+ int32_t pid,
+ int32_t uid,
int64_t clientId,
- const sp<IResourceManagerClient> client,
- const Vector<MediaResource> &resources);
+ const sp<IResourceManagerClient>& client,
+ const std::vector<MediaResourceParcel>& resources) override;
- virtual void removeResource(int pid, int64_t clientId,
- const Vector<MediaResource> &resources);
+ Status removeResource(
+ int32_t pid,
+ int64_t clientId,
+ const std::vector<MediaResourceParcel>& resources) override;
- virtual void removeClient(int pid, int64_t clientId);
+ Status removeClient(int32_t pid, int64_t clientId) override;
// Tries to reclaim resource from processes with lower priority than the calling process
// according to the requested resources.
// Returns true if any resource has been reclaimed, otherwise returns false.
- virtual bool reclaimResource(int callingPid, const Vector<MediaResource> &resources);
+ Status reclaimResource(
+ int32_t callingPid,
+ const std::vector<MediaResourceParcel>& resources,
+ bool* _aidl_return) override;
- void removeResource(int pid, int64_t clientId, bool checkValid);
+ Status removeResource(int pid, int64_t clientId, bool checkValid);
protected:
virtual ~ResourceManagerService();
@@ -120,11 +132,14 @@
// A helper function basically calls getLowestPriorityBiggestClient_l and add the result client
// to the given Vector.
- void getClientForResource_l(
- int callingPid, const MediaResource *res, Vector<sp<IResourceManagerClient>> *clients);
+ void getClientForResource_l(int callingPid,
+ const MediaResourceParcel *res, Vector<sp<IResourceManagerClient>> *clients);
- void onFirstAdded(const MediaResource& res, const ResourceInfo& clientInfo);
- void onLastRemoved(const MediaResource& res, const ResourceInfo& clientInfo);
+ void onFirstAdded(const MediaResourceParcel& res, const ResourceInfo& clientInfo);
+ void onLastRemoved(const MediaResourceParcel& res, const ResourceInfo& clientInfo);
+
+ // Merge r2 into r1
+ void mergeResources(MediaResourceParcel& r1, const MediaResourceParcel& r2);
mutable Mutex mLock;
sp<ProcessInfoInterface> mProcessInfo;
@@ -137,7 +152,7 @@
};
// ----------------------------------------------------------------------------
+} // namespace media
+} // namespace android
-}; // namespace android
-
-#endif // ANDROID_RESOURCEMANAGERSERVICE_H
+#endif // ANDROID_MEDIA_RESOURCEMANAGERSERVICE_H
diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
index ae97ec8..203baf5 100644
--- a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
@@ -21,13 +21,16 @@
#include <gtest/gtest.h>
#include "ResourceManagerService.h"
-#include <media/IResourceManagerService.h>
+#include <android/media/BnResourceManagerClient.h>
#include <media/MediaResource.h>
#include <media/MediaResourcePolicy.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/ProcessInfoInterface.h>
namespace android {
+namespace media {
+
+using ::android::binder::Status;
static int64_t getId(const sp<IResourceManagerClient>& client) {
return (int64_t) client.get();
@@ -112,15 +115,17 @@
TestClient(int pid, sp<ResourceManagerService> service)
: mReclaimed(false), mPid(pid), mService(service) {}
- virtual bool reclaimResource() {
+ Status reclaimResource(bool* _aidl_return) override {
sp<IResourceManagerClient> client(this);
mService->removeClient(mPid, (int64_t) client.get());
mReclaimed = true;
- return true;
+ *_aidl_return = true;
+ return Status::ok();
}
- virtual String8 getName() {
- return String8("test_client");
+ Status getName(::std::string* _aidl_return) override {
+ *_aidl_return = "test_client";
+ return Status::ok();
}
bool reclaimed() const {
@@ -157,6 +162,12 @@
return lhs.type == rhs.type && lhs.arg == rhs.arg;
}
+#define CHECK_STATUS_TRUE(condition) \
+ EXPECT_TRUE((condition).isOk() && (result))
+
+#define CHECK_STATUS_FALSE(condition) \
+ EXPECT_TRUE((condition).isOk() && !(result))
+
class ResourceManagerServiceTest : public ::testing::Test {
public:
ResourceManagerServiceTest()
@@ -168,13 +179,14 @@
}
protected:
- static bool isEqualResources(const Vector<MediaResource> &resources1,
+ static bool isEqualResources(const std::vector<MediaResourceParcel> &resources1,
const ResourceList &resources2) {
// convert resource1 to ResourceList
ResourceList r1;
for (size_t i = 0; i < resources1.size(); ++i) {
- const auto resType = std::make_pair(resources1[i].mType, resources1[i].mSubType);
- r1[resType] = resources1[i];
+ const auto &res = resources1[i];
+ const auto resType = std::tuple(res.type, res.subType, res.id);
+ r1[resType] = res;
}
return r1 == resources2;
}
@@ -182,7 +194,7 @@
static void expectEqResourceInfo(const ResourceInfo &info,
int uid,
sp<IResourceManagerClient> client,
- const Vector<MediaResource> &resources) {
+ const std::vector<MediaResourceParcel> &resources) {
EXPECT_EQ(uid, info.uid);
EXPECT_EQ(client, info.client);
EXPECT_TRUE(isEqualResources(resources, info.resources));
@@ -218,25 +230,25 @@
// ---------------------------------------------------------------------------------
void addResource() {
// kTestPid1 mTestClient1
- Vector<MediaResource> resources1;
- resources1.push_back(MediaResource(MediaResource::kSecureCodec, 1));
+ std::vector<MediaResourceParcel> resources1;
+ resources1.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
- resources1.push_back(MediaResource(MediaResource::kGraphicMemory, 200));
- Vector<MediaResource> resources11;
- resources11.push_back(MediaResource(MediaResource::kGraphicMemory, 200));
+ resources1.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 200));
+ std::vector<MediaResourceParcel> resources11;
+ resources11.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 200));
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources11);
// kTestPid2 mTestClient2
- Vector<MediaResource> resources2;
- resources2.push_back(MediaResource(MediaResource::kNonSecureCodec, 1));
- resources2.push_back(MediaResource(MediaResource::kGraphicMemory, 300));
+ std::vector<MediaResourceParcel> resources2;
+ resources2.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
+ resources2.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 300));
mService->addResource(kTestPid2, kTestUid2, getId(mTestClient2), mTestClient2, resources2);
// kTestPid2 mTestClient3
- Vector<MediaResource> resources3;
+ std::vector<MediaResourceParcel> resources3;
mService->addResource(kTestPid2, kTestUid2, getId(mTestClient3), mTestClient3, resources3);
- resources3.push_back(MediaResource(MediaResource::kSecureCodec, 1));
- resources3.push_back(MediaResource(MediaResource::kGraphicMemory, 100));
+ resources3.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
+ resources3.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 100));
mService->addResource(kTestPid2, kTestUid2, getId(mTestClient3), mTestClient3, resources3);
const PidResourceInfosMap &map = mService->mMap;
@@ -255,32 +267,92 @@
expectEqResourceInfo(infos2.valueFor(getId(mTestClient3)), kTestUid2, mTestClient3, resources3);
}
+ void testCombineResourceWithNegativeValues() {
+ // kTestPid1 mTestClient1
+ std::vector<MediaResourceParcel> resources1;
+ resources1.push_back(MediaResource(MediaResource::Type::kDrmSession, -100));
+ resources1.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, -100));
+ mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
+
+ // Expected result:
+ // 1) the client should have been added;
+ // 2) both resource entries should have been rejected, resource list should be empty.
+ const PidResourceInfosMap &map = mService->mMap;
+ EXPECT_EQ(1u, map.size());
+ ssize_t index1 = map.indexOfKey(kTestPid1);
+ ASSERT_GE(index1, 0);
+ const ResourceInfos &infos1 = map[index1];
+ EXPECT_EQ(1u, infos1.size());
+ std::vector<MediaResourceParcel> expected;
+ expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+
+ resources1.clear();
+ resources1.push_back(MediaResource(MediaResource::Type::kDrmSession, INT64_MAX));
+ resources1.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, INT64_MAX));
+ mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
+ resources1.clear();
+ resources1.push_back(MediaResource(MediaResource::Type::kDrmSession, 10));
+ resources1.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 10));
+ mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
+
+ // Expected result:
+ // Both values should saturate to INT64_MAX
+ expected.push_back(MediaResource(MediaResource::Type::kDrmSession, INT64_MAX));
+ expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, INT64_MAX));
+ expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+
+ resources1.clear();
+ resources1.push_back(MediaResource(MediaResource::Type::kDrmSession, -10));
+ resources1.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, -10));
+ mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
+
+ // Expected result:
+ // 1) DrmSession resource should allow negative value addition, and value should drop accordingly
+ // 2) Non-drm session resource should ignore negative value addition.
+ expected.push_back(MediaResource(MediaResource::Type::kDrmSession, INT64_MAX - 10));
+ expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, INT64_MAX));
+ expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+
+ resources1.clear();
+ resources1.push_back(MediaResource(MediaResource::Type::kDrmSession, INT64_MIN));
+ expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, INT64_MIN));
+ mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
+
+ // Expected result:
+ // 1) DrmSession resource value should drop to 0, but the entry shouldn't be removed.
+ // 2) Non-drm session resource should ignore negative value addition.
+ expected.clear();
+ expected.push_back(MediaResource(MediaResource::Type::kDrmSession, 0));
+ expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, INT64_MAX));
+ expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+ }
+
void testConfig() {
EXPECT_TRUE(mService->mSupportsMultipleSecureCodecs);
EXPECT_TRUE(mService->mSupportsSecureWithNonSecureCodec);
- Vector<MediaResourcePolicy> policies1;
+ std::vector<MediaResourcePolicyParcel> policies1;
policies1.push_back(
MediaResourcePolicy(
- String8(kPolicySupportsMultipleSecureCodecs),
- String8("true")));
+ IResourceManagerService::kPolicySupportsMultipleSecureCodecs(),
+ "true"));
policies1.push_back(
MediaResourcePolicy(
- String8(kPolicySupportsSecureWithNonSecureCodec),
- String8("false")));
+ IResourceManagerService::kPolicySupportsSecureWithNonSecureCodec(),
+ "false"));
mService->config(policies1);
EXPECT_TRUE(mService->mSupportsMultipleSecureCodecs);
EXPECT_FALSE(mService->mSupportsSecureWithNonSecureCodec);
- Vector<MediaResourcePolicy> policies2;
+ std::vector<MediaResourcePolicyParcel> policies2;
policies2.push_back(
MediaResourcePolicy(
- String8(kPolicySupportsMultipleSecureCodecs),
- String8("false")));
+ IResourceManagerService::kPolicySupportsMultipleSecureCodecs(),
+ "false"));
policies2.push_back(
MediaResourcePolicy(
- String8(kPolicySupportsSecureWithNonSecureCodec),
- String8("true")));
+ IResourceManagerService::kPolicySupportsSecureWithNonSecureCodec(),
+ "true"));
mService->config(policies2);
EXPECT_FALSE(mService->mSupportsMultipleSecureCodecs);
EXPECT_TRUE(mService->mSupportsSecureWithNonSecureCodec);
@@ -288,12 +360,12 @@
void testCombineResource() {
// kTestPid1 mTestClient1
- Vector<MediaResource> resources1;
- resources1.push_back(MediaResource(MediaResource::kSecureCodec, 1));
+ std::vector<MediaResourceParcel> resources1;
+ resources1.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
- Vector<MediaResource> resources11;
- resources11.push_back(MediaResource(MediaResource::kGraphicMemory, 200));
+ std::vector<MediaResourceParcel> resources11;
+ resources11.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 200));
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources11);
const PidResourceInfosMap &map = mService->mMap;
@@ -304,35 +376,35 @@
EXPECT_EQ(1u, infos1.size());
// test adding existing types to combine values
- resources1.push_back(MediaResource(MediaResource::kGraphicMemory, 100));
+ resources1.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 100));
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
- Vector<MediaResource> expected;
- expected.push_back(MediaResource(MediaResource::kSecureCodec, 2));
- expected.push_back(MediaResource(MediaResource::kGraphicMemory, 300));
+ std::vector<MediaResourceParcel> expected;
+ expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, 2));
+ expected.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 300));
expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
// test adding new types (including types that differs only in subType)
- resources11.push_back(MediaResource(MediaResource::kNonSecureCodec, 1));
- resources11.push_back(MediaResource(MediaResource::kSecureCodec, MediaResource::kVideoCodec, 1));
+ resources11.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
+ resources11.push_back(MediaResource(MediaResource::Type::kSecureCodec, MediaResource::SubType::kVideoCodec, 1));
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources11);
expected.clear();
- expected.push_back(MediaResource(MediaResource::kSecureCodec, 2));
- expected.push_back(MediaResource(MediaResource::kNonSecureCodec, 1));
- expected.push_back(MediaResource(MediaResource::kSecureCodec, MediaResource::kVideoCodec, 1));
- expected.push_back(MediaResource(MediaResource::kGraphicMemory, 500));
+ expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, 2));
+ expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
+ expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, MediaResource::SubType::kVideoCodec, 1));
+ expected.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 500));
expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
}
void testRemoveResource() {
// kTestPid1 mTestClient1
- Vector<MediaResource> resources1;
- resources1.push_back(MediaResource(MediaResource::kSecureCodec, 1));
+ std::vector<MediaResourceParcel> resources1;
+ resources1.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
- Vector<MediaResource> resources11;
- resources11.push_back(MediaResource(MediaResource::kGraphicMemory, 200));
+ std::vector<MediaResourceParcel> resources11;
+ resources11.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 200));
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources11);
const PidResourceInfosMap &map = mService->mMap;
@@ -343,20 +415,26 @@
EXPECT_EQ(1u, infos1.size());
// test partial removal
- resources11.editItemAt(0).mValue = 100;
+ resources11[0].value = 100;
mService->removeResource(kTestPid1, getId(mTestClient1), resources11);
- Vector<MediaResource> expected;
- expected.push_back(MediaResource(MediaResource::kSecureCodec, 1));
- expected.push_back(MediaResource(MediaResource::kGraphicMemory, 100));
+ std::vector<MediaResourceParcel> expected;
+ expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
+ expected.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 100));
+ expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+
+ // test removal request with negative value, should be ignored
+ resources11[0].value = -10000;
+ mService->removeResource(kTestPid1, getId(mTestClient1), resources11);
+
expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
// test complete removal with overshoot value
- resources11.editItemAt(0).mValue = 1000;
+ resources11[0].value = 1000;
mService->removeResource(kTestPid1, getId(mTestClient1), resources11);
expected.clear();
- expected.push_back(MediaResource(MediaResource::kSecureCodec, 1));
+ expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
}
@@ -379,7 +457,7 @@
void testGetAllClients() {
addResource();
- MediaResource::Type type = MediaResource::kSecureCodec;
+ MediaResource::Type type = MediaResource::Type::kSecureCodec;
Vector<sp<IResourceManagerClient> > clients;
EXPECT_FALSE(mService->getAllClients_l(kLowPriorityPid, type, &clients));
// some higher priority process (e.g. kTestPid2) owns the resource, so getAllClients_l
@@ -394,9 +472,10 @@
}
void testReclaimResourceSecure() {
- Vector<MediaResource> resources;
- resources.push_back(MediaResource(MediaResource::kSecureCodec, 1));
- resources.push_back(MediaResource(MediaResource::kGraphicMemory, 150));
+ bool result;
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
+ resources.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 150));
// ### secure codec can't coexist and secure codec can coexist with non-secure codec ###
{
@@ -405,19 +484,19 @@
mService->mSupportsSecureWithNonSecureCodec = true;
// priority too low
- EXPECT_FALSE(mService->reclaimResource(kLowPriorityPid, resources));
- EXPECT_FALSE(mService->reclaimResource(kMidPriorityPid, resources));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kLowPriorityPid, resources, &result));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kMidPriorityPid, resources, &result));
// reclaim all secure codecs
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
verifyClients(true /* c1 */, false /* c2 */, true /* c3 */);
// call again should reclaim one largest graphic memory from lowest process
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
// nothing left
- EXPECT_FALSE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
}
// ### secure codecs can't coexist and secure codec can't coexist with non-secure codec ###
@@ -427,15 +506,15 @@
mService->mSupportsSecureWithNonSecureCodec = false;
// priority too low
- EXPECT_FALSE(mService->reclaimResource(kLowPriorityPid, resources));
- EXPECT_FALSE(mService->reclaimResource(kMidPriorityPid, resources));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kLowPriorityPid, resources, &result));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kMidPriorityPid, resources, &result));
// reclaim all secure and non-secure codecs
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
verifyClients(true /* c1 */, true /* c2 */, true /* c3 */);
// nothing left
- EXPECT_FALSE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
}
@@ -446,23 +525,23 @@
mService->mSupportsSecureWithNonSecureCodec = false;
// priority too low
- EXPECT_FALSE(mService->reclaimResource(kLowPriorityPid, resources));
- EXPECT_FALSE(mService->reclaimResource(kMidPriorityPid, resources));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kLowPriorityPid, resources, &result));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kMidPriorityPid, resources, &result));
// reclaim all non-secure codecs
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
// call again should reclaim one largest graphic memory from lowest process
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
// call again should reclaim another largest graphic memory from lowest process
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
verifyClients(false /* c1 */, false /* c2 */, true /* c3 */);
// nothing left
- EXPECT_FALSE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
}
// ### secure codecs can coexist and secure codec can coexist with non-secure codec ###
@@ -472,22 +551,22 @@
mService->mSupportsSecureWithNonSecureCodec = true;
// priority too low
- EXPECT_FALSE(mService->reclaimResource(kLowPriorityPid, resources));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kLowPriorityPid, resources, &result));
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
// one largest graphic memory from lowest process got reclaimed
verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
// call again should reclaim another graphic memory from lowest process
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
// call again should reclaim another graphic memory from lowest process
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
verifyClients(false /* c1 */, false /* c2 */, true /* c3 */);
// nothing left
- EXPECT_FALSE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
}
// ### secure codecs can coexist and secure codec can coexist with non-secure codec ###
@@ -496,27 +575,28 @@
mService->mSupportsMultipleSecureCodecs = true;
mService->mSupportsSecureWithNonSecureCodec = true;
- Vector<MediaResource> resources;
- resources.push_back(MediaResource(MediaResource::kSecureCodec, 1));
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
// secure codec from lowest process got reclaimed
verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
// call again should reclaim another secure codec from lowest process
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
verifyClients(false /* c1 */, false /* c2 */, true /* c3 */);
// no more secure codec, non-secure codec will be reclaimed.
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
}
}
void testReclaimResourceNonSecure() {
- Vector<MediaResource> resources;
- resources.push_back(MediaResource(MediaResource::kNonSecureCodec, 1));
- resources.push_back(MediaResource(MediaResource::kGraphicMemory, 150));
+ bool result;
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
+ resources.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 150));
// ### secure codec can't coexist with non-secure codec ###
{
@@ -524,19 +604,19 @@
mService->mSupportsSecureWithNonSecureCodec = false;
// priority too low
- EXPECT_FALSE(mService->reclaimResource(kLowPriorityPid, resources));
- EXPECT_FALSE(mService->reclaimResource(kMidPriorityPid, resources));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kLowPriorityPid, resources, &result));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kMidPriorityPid, resources, &result));
// reclaim all secure codecs
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
verifyClients(true /* c1 */, false /* c2 */, true /* c3 */);
// call again should reclaim one graphic memory from lowest process
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
// nothing left
- EXPECT_FALSE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
}
@@ -546,22 +626,22 @@
mService->mSupportsSecureWithNonSecureCodec = true;
// priority too low
- EXPECT_FALSE(mService->reclaimResource(kLowPriorityPid, resources));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kLowPriorityPid, resources, &result));
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
// one largest graphic memory from lowest process got reclaimed
verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
// call again should reclaim another graphic memory from lowest process
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
// call again should reclaim another graphic memory from lowest process
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
verifyClients(false /* c1 */, false /* c2 */, true /* c3 */);
// nothing left
- EXPECT_FALSE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
}
// ### secure codec can coexist with non-secure codec ###
@@ -569,15 +649,15 @@
addResource();
mService->mSupportsSecureWithNonSecureCodec = true;
- Vector<MediaResource> resources;
- resources.push_back(MediaResource(MediaResource::kNonSecureCodec, 1));
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
// one non secure codec from lowest process got reclaimed
verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
// no more non-secure codec, secure codec from lowest priority process will be reclaimed
- EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+ CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
// clean up client 3 which still left
@@ -586,7 +666,7 @@
}
void testGetLowestPriorityBiggestClient() {
- MediaResource::Type type = MediaResource::kGraphicMemory;
+ MediaResource::Type type = MediaResource::Type::kGraphicMemory;
sp<IResourceManagerClient> client;
EXPECT_FALSE(mService->getLowestPriorityBiggestClient_l(kHighPriorityPid, type, &client));
@@ -595,8 +675,8 @@
EXPECT_FALSE(mService->getLowestPriorityBiggestClient_l(kLowPriorityPid, type, &client));
EXPECT_TRUE(mService->getLowestPriorityBiggestClient_l(kHighPriorityPid, type, &client));
- // kTestPid1 is the lowest priority process with MediaResource::kGraphicMemory.
- // mTestClient1 has the largest MediaResource::kGraphicMemory within kTestPid1.
+ // kTestPid1 is the lowest priority process with MediaResource::Type::kGraphicMemory.
+ // mTestClient1 has the largest MediaResource::Type::kGraphicMemory within kTestPid1.
EXPECT_EQ(mTestClient1, client);
}
@@ -605,7 +685,7 @@
int priority;
TestProcessInfo processInfo;
- MediaResource::Type type = MediaResource::kGraphicMemory;
+ MediaResource::Type type = MediaResource::Type::kGraphicMemory;
EXPECT_FALSE(mService->getLowestPriorityPid_l(type, &pid, &priority));
addResource();
@@ -616,7 +696,7 @@
processInfo.getPriority(kTestPid1, &priority1);
EXPECT_EQ(priority1, priority);
- type = MediaResource::kNonSecureCodec;
+ type = MediaResource::Type::kNonSecureCodec;
EXPECT_TRUE(mService->getLowestPriorityPid_l(type, &pid, &priority));
EXPECT_EQ(kTestPid2, pid);
int priority2;
@@ -625,7 +705,7 @@
}
void testGetBiggestClient() {
- MediaResource::Type type = MediaResource::kGraphicMemory;
+ MediaResource::Type type = MediaResource::Type::kGraphicMemory;
sp<IResourceManagerClient> client;
EXPECT_FALSE(mService->getBiggestClient_l(kTestPid2, type, &client));
@@ -647,8 +727,8 @@
EXPECT_EQ(EventType::VIDEO_RESET, mSystemCB->lastEventType());
// new client request should cause VIDEO_ON
- Vector<MediaResource> resources1;
- resources1.push_back(MediaResource(MediaResource::kBattery, MediaResource::kVideoCodec, 1));
+ std::vector<MediaResourceParcel> resources1;
+ resources1.push_back(MediaResource(MediaResource::Type::kBattery, MediaResource::SubType::kVideoCodec, 1));
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
EXPECT_EQ(2u, mSystemCB->eventCount());
EXPECT_EQ(EventEntry({EventType::VIDEO_ON, kTestUid1}), mSystemCB->lastEvent());
@@ -658,8 +738,8 @@
EXPECT_EQ(2u, mSystemCB->eventCount());
// new client request should cause VIDEO_ON
- Vector<MediaResource> resources2;
- resources2.push_back(MediaResource(MediaResource::kBattery, MediaResource::kVideoCodec, 2));
+ std::vector<MediaResourceParcel> resources2;
+ resources2.push_back(MediaResource(MediaResource::Type::kBattery, MediaResource::SubType::kVideoCodec, 2));
mService->addResource(kTestPid2, kTestUid2, getId(mTestClient2), mTestClient2, resources2);
EXPECT_EQ(3u, mSystemCB->eventCount());
EXPECT_EQ(EventEntry({EventType::VIDEO_ON, kTestUid2}), mSystemCB->lastEvent());
@@ -686,8 +766,8 @@
EXPECT_EQ(EventType::VIDEO_RESET, mSystemCB->lastEventType());
// new client request should cause CPUSET_ENABLE
- Vector<MediaResource> resources1;
- resources1.push_back(MediaResource(MediaResource::kCpuBoost, 1));
+ std::vector<MediaResourceParcel> resources1;
+ resources1.push_back(MediaResource(MediaResource::Type::kCpuBoost, 1));
mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
EXPECT_EQ(2u, mSystemCB->eventCount());
EXPECT_EQ(EventType::CPUSET_ENABLE, mSystemCB->lastEventType());
@@ -697,8 +777,8 @@
EXPECT_EQ(2u, mSystemCB->eventCount());
// new client request should cause CPUSET_ENABLE
- Vector<MediaResource> resources2;
- resources2.push_back(MediaResource(MediaResource::kCpuBoost, 2));
+ std::vector<MediaResourceParcel> resources2;
+ resources2.push_back(MediaResource(MediaResource::Type::kCpuBoost, 2));
mService->addResource(kTestPid2, kTestUid2, getId(mTestClient2), mTestClient2, resources2);
EXPECT_EQ(3u, mSystemCB->eventCount());
EXPECT_EQ(EventType::CPUSET_ENABLE, mSystemCB->lastEventType());
@@ -737,6 +817,10 @@
testCombineResource();
}
+TEST_F(ResourceManagerServiceTest, combineResourceNegative) {
+ testCombineResourceWithNegativeValues();
+}
+
TEST_F(ResourceManagerServiceTest, removeResource) {
testRemoveResource();
}
@@ -778,4 +862,5 @@
testCpusetBoost();
}
+} // namespace media
} // namespace android
diff --git a/services/oboeservice/Android.bp b/services/oboeservice/Android.bp
index 1b7a20c..ca1354d 100644
--- a/services/oboeservice/Android.bp
+++ b/services/oboeservice/Android.bp
@@ -46,6 +46,7 @@
"libaaudio_internal",
"libaudioclient",
"libaudioflinger",
+ "libaudioutils",
"libbase",
"libbinder",
"libcutils",