Merge "aaudio: fix small underflow when a stream is stopped"
diff --git a/Android.bp b/Android.bp
index a3679b1..e4f12c8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -2,5 +2,6 @@
"camera",
"drm/*",
"media/*",
+ "services/*",
"soundtrigger",
]
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index a0aef0d..6d0a2e0 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -7,16 +7,16 @@
jpeg.cpp \
SineSource.cpp
+LOCAL_HEADER_LIBRARIES := \
+ media_plugin_headers \
+
LOCAL_SHARED_LIBRARIES := \
libstagefright libmedia libmediaextractor libutils libbinder \
libstagefright_foundation libjpeg libui libgui libcutils liblog \
- libhidlmemory \
+ libhidlbase \
android.hardware.media.omx@1.0 \
LOCAL_C_INCLUDES:= \
- frameworks/av/media/libstagefright \
- frameworks/av/media/libstagefright/include \
- frameworks/native/include/media/openmax \
external/jpeg \
LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
@@ -35,15 +35,13 @@
SineSource.cpp \
record.cpp
+LOCAL_HEADER_LIBRARIES := \
+ media_plugin_headers \
+
LOCAL_SHARED_LIBRARIES := \
libstagefright libmedia libmediaextractor liblog libutils libbinder \
libstagefright_foundation
-LOCAL_C_INCLUDES:= \
- frameworks/av/media/libstagefright \
- frameworks/native/include/media/openmax \
- frameworks/native/include/media/hardware
-
LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
LOCAL_MODULE_TAGS := optional
@@ -60,15 +58,13 @@
SineSource.cpp \
recordvideo.cpp
+LOCAL_HEADER_LIBRARIES := \
+ media_plugin_headers \
+
LOCAL_SHARED_LIBRARIES := \
libstagefright libmedia libmediaextractor liblog libutils libbinder \
libstagefright_foundation
-LOCAL_C_INCLUDES:= \
- frameworks/av/media/libstagefright \
- frameworks/native/include/media/openmax \
- frameworks/native/include/media/hardware
-
LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
LOCAL_MODULE_TAGS := optional
@@ -86,14 +82,13 @@
SineSource.cpp \
audioloop.cpp
+LOCAL_HEADER_LIBRARIES := \
+ media_plugin_headers \
+
LOCAL_SHARED_LIBRARIES := \
libstagefright libmedia libmediaextractor liblog libutils libbinder \
libstagefright_foundation
-LOCAL_C_INCLUDES:= \
- frameworks/av/media/libstagefright \
- frameworks/native/include/media/openmax
-
LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
LOCAL_MODULE_TAGS := optional
@@ -109,14 +104,13 @@
LOCAL_SRC_FILES:= \
stream.cpp \
+LOCAL_HEADER_LIBRARIES := \
+ media_plugin_headers \
+
LOCAL_SHARED_LIBRARIES := \
libstagefright liblog libutils libbinder libui libgui \
libstagefright_foundation libmedia libcutils
-LOCAL_C_INCLUDES:= \
- frameworks/av/media/libstagefright \
- frameworks/native/include/media/openmax
-
LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
LOCAL_MODULE_TAGS := optional
@@ -133,14 +127,13 @@
codec.cpp \
SimplePlayer.cpp \
+LOCAL_HEADER_LIBRARIES := \
+ media_plugin_headers \
+
LOCAL_SHARED_LIBRARIES := \
libstagefright liblog libutils libbinder libstagefright_foundation \
libmedia libaudioclient libui libgui libcutils
-LOCAL_C_INCLUDES:= \
- frameworks/av/media/libstagefright \
- frameworks/native/include/media/openmax
-
LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
LOCAL_MODULE_TAGS := optional
@@ -159,6 +152,9 @@
filters/saturation.rs \
mediafilter.cpp \
+LOCAL_HEADER_LIBRARIES := \
+ media_plugin_headers \
+
LOCAL_SHARED_LIBRARIES := \
libstagefright \
liblog \
@@ -171,12 +167,6 @@
libcutils \
libRScpp \
-LOCAL_C_INCLUDES:= \
- frameworks/av/media/libstagefright \
- frameworks/native/include/media/openmax \
- frameworks/rs/cpp \
- frameworks/rs \
-
intermediates := $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,TARGET,)
LOCAL_C_INCLUDES += $(intermediates)
@@ -201,14 +191,13 @@
LOCAL_SRC_FILES:= \
muxer.cpp \
+LOCAL_HEADER_LIBRARIES := \
+ media_plugin_headers \
+
LOCAL_SHARED_LIBRARIES := \
libstagefright liblog libutils libbinder libstagefright_foundation \
libcutils libc
-LOCAL_C_INCLUDES:= \
- frameworks/av/media/libstagefright \
- frameworks/native/include/media/openmax
-
LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
LOCAL_MODULE_TAGS := optional
diff --git a/cmds/stagefright/mediafilter.cpp b/cmds/stagefright/mediafilter.cpp
index f24d2dd..c90a2e4 100644
--- a/cmds/stagefright/mediafilter.cpp
+++ b/cmds/stagefright/mediafilter.cpp
@@ -20,7 +20,7 @@
#include <inttypes.h>
#include <binder/ProcessState.h>
-#include <filters/ColorConvert.h>
+#include <ColorConvert.h>
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/Surface.h>
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 50b034a..f873ba5 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -36,13 +36,12 @@
#include <media/MediaSource.h>
#include <media/ICrypto.h>
#include <media/IMediaHTTPService.h>
-#include <media/IMediaCodecService.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 <NuCachedSource2.h>
#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/DataSourceFactory.h>
#include <media/stagefright/JPEGSource.h>
@@ -68,7 +67,6 @@
#include <gui/SurfaceComposerClient.h>
#include <android/hardware/media/omx/1.0/IOmx.h>
-#include <media/omx/1.0/WOmx.h>
using namespace android;
@@ -912,37 +910,24 @@
}
if (listComponents) {
- sp<IOMX> omx;
- if (property_get_bool("persist.media.treble_omx", true)) {
- using namespace ::android::hardware::media::omx::V1_0;
- sp<IOmx> tOmx = IOmx::getService();
+ using ::android::hardware::hidl_vec;
+ using ::android::hardware::hidl_string;
+ using namespace ::android::hardware::media::omx::V1_0;
+ sp<IOmx> omx = IOmx::getService();
+ CHECK(omx.get() != nullptr);
- CHECK(tOmx.get() != NULL);
-
- omx = new utils::LWOmx(tOmx);
- } else {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder = sm->getService(String16("media.codec"));
- sp<IMediaCodecService> service = interface_cast<IMediaCodecService>(binder);
-
- CHECK(service.get() != NULL);
-
- omx = service->getOMX();
- }
- CHECK(omx.get() != NULL);
-
- List<IOMX::ComponentInfo> list;
- omx->listNodes(&list);
-
- for (List<IOMX::ComponentInfo>::iterator it = list.begin();
- it != list.end(); ++it) {
- printf("%s\t Roles: ", (*it).mName.string());
- for (List<String8>::iterator itRoles = (*it).mRoles.begin() ;
- itRoles != (*it).mRoles.end() ; ++itRoles) {
- printf("%s\t", (*itRoles).string());
- }
- printf("\n");
- }
+ hidl_vec<IOmx::ComponentInfo> nodeList;
+ auto transStatus = omx->listNodes([](
+ const auto& status, const auto& nodeList) {
+ CHECK(status == Status::OK);
+ for (const auto& info : nodeList) {
+ printf("%s\t Roles: ", info.mName.c_str());
+ for (const auto& role : info.mRoles) {
+ printf("%s\t", role.c_str());
+ }
+ }
+ });
+ CHECK(transStatus.isOk());
}
sp<SurfaceComposerClient> composerClient;
diff --git a/drm/common/Android.bp b/drm/common/Android.bp
index 0098c89..1552c3f 100644
--- a/drm/common/Android.bp
+++ b/drm/common/Android.bp
@@ -33,6 +33,8 @@
"ReadWriteUtils.cpp",
],
+ cflags: ["-Wall", "-Werror"],
+
static_libs: ["libbinder"],
export_include_dirs: ["include"],
diff --git a/drm/libdrmframework/plugins/common/util/Android.bp b/drm/libdrmframework/plugins/common/util/Android.bp
index 0c0b6f2..7372eb7 100644
--- a/drm/libdrmframework/plugins/common/util/Android.bp
+++ b/drm/libdrmframework/plugins/common/util/Android.bp
@@ -19,5 +19,7 @@
srcs: ["src/MimeTypeUtil.cpp"],
+ cflags: ["-Wall", "-Werror"],
+
export_include_dirs: ["include"],
}
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp
index 3f0f5f7..28a78aa 100644
--- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp
@@ -21,6 +21,9 @@
"-DUSE_64BIT_DRM_API",
// The flag below turns on local debug printouts
//"-DDRM_OMA_FL_ENGINE_DEBUG",
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-variable",
],
srcs: ["src/FwdLockEngine.cpp"],
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.bp b/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.bp
index 698f278..3be327a 100644
--- a/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.bp
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.bp
@@ -19,6 +19,8 @@
srcs: ["FwdLockGlue.c"],
+ cflags: ["-Wall", "-Werror"],
+
shared_libs: ["libcrypto"],
export_include_dirs: ["."],
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.bp b/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.bp
index 33f2fe0..d4e04b8 100644
--- a/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.bp
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.bp
@@ -19,6 +19,8 @@
srcs: ["FwdLockConv.c"],
+ cflags: ["-Wall", "-Werror"],
+
shared_libs: ["libcrypto"],
static_libs: ["libfwdlock-common"],
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.bp b/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.bp
index b6d7a06..0bf2737 100644
--- a/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.bp
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.bp
@@ -19,6 +19,8 @@
srcs: ["FwdLockFile.c"],
+ cflags: ["-Wall", "-Werror"],
+
shared_libs: ["libcrypto"],
static_libs: ["libfwdlock-common"],
diff --git a/drm/libdrmframework/plugins/passthru/Android.bp b/drm/libdrmframework/plugins/passthru/Android.bp
index 1dcf89c..05b6440 100644
--- a/drm/libdrmframework/plugins/passthru/Android.bp
+++ b/drm/libdrmframework/plugins/passthru/Android.bp
@@ -32,5 +32,7 @@
cflags: [
// Set the following flag to enable the decryption passthru flow
//"-DENABLE_PASSTHRU_DECRYPTION",
+ "-Wall",
+ "-Werror",
],
}
diff --git a/drm/libmediadrm/Android.bp b/drm/libmediadrm/Android.bp
index f906564..0c14201 100644
--- a/drm/libmediadrm/Android.bp
+++ b/drm/libmediadrm/Android.bp
@@ -34,8 +34,8 @@
"libstagefright_foundation",
"libutils",
"android.hardware.drm@1.0",
+ "libhidlallocatorutils",
"libhidlbase",
- "libhidlmemory",
"libhidltransport",
],
diff --git a/drm/libmediadrm/CryptoHal.cpp b/drm/libmediadrm/CryptoHal.cpp
index d613a5b..b9b3685 100644
--- a/drm/libmediadrm/CryptoHal.cpp
+++ b/drm/libmediadrm/CryptoHal.cpp
@@ -29,6 +29,7 @@
#include <media/stagefright/foundation/AString.h>
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MediaErrors.h>
+#include <hidlmemory/FrameworkUtils.h>
using ::android::hardware::drm::V1_0::BufferType;
using ::android::hardware::drm::V1_0::DestinationBuffer;
@@ -227,6 +228,9 @@
* are sent by providing an offset into the heap and a buffer size.
*/
int32_t CryptoHal::setHeapBase(const sp<IMemoryHeap>& heap) {
+ using ::android::hardware::fromHeap;
+ using ::android::hardware::HidlMemory;
+
if (heap == NULL) {
ALOGE("setHeapBase(): heap is NULL");
return -1;
@@ -240,12 +244,9 @@
Mutex::Autolock autoLock(mLock);
int32_t seqNum = mHeapSeqNum++;
- int fd = heap->getHeapID();
- nativeHandle->data[0] = fd;
- auto hidlHandle = hidl_handle(nativeHandle);
- auto hidlMemory = hidl_memory("ashmem", hidlHandle, heap->getSize());
+ sp<HidlMemory> hidlMemory = fromHeap(heap);
mHeapBases.add(seqNum, mNextBufferId);
- Return<void> hResult = mPlugin->setSharedBufferBase(hidlMemory, mNextBufferId++);
+ Return<void> hResult = mPlugin->setSharedBufferBase(*hidlMemory, mNextBufferId++);
ALOGE_IF(!hResult.isOk(), "setSharedBufferBase(): remote call failed");
return seqNum;
}
diff --git a/drm/mediadrm/plugins/clearkey/Android.bp b/drm/mediadrm/plugins/clearkey/Android.bp
index 2973fcf..385815c 100644
--- a/drm/mediadrm/plugins/clearkey/Android.bp
+++ b/drm/mediadrm/plugins/clearkey/Android.bp
@@ -35,6 +35,8 @@
vendor: true,
relative_install_path: "mediadrm",
+ cflags: ["-Wall", "-Werror"],
+
shared_libs: [
"libcrypto",
"liblog",
diff --git a/drm/mediadrm/plugins/clearkey/tests/Android.bp b/drm/mediadrm/plugins/clearkey/tests/Android.bp
index 0fcfc64..ea17bbb 100644
--- a/drm/mediadrm/plugins/clearkey/tests/Android.bp
+++ b/drm/mediadrm/plugins/clearkey/tests/Android.bp
@@ -21,6 +21,8 @@
name: "ClearKeyDrmUnitTest",
vendor: true,
+ cflags: ["-Wall", "-Werror"],
+
srcs: [
"AesCtrDecryptorUnittest.cpp",
"InitDataParserUnittest.cpp",
diff --git a/drm/mediadrm/plugins/mock/Android.bp b/drm/mediadrm/plugins/mock/Android.bp
index abd1884..dd2ad7b 100644
--- a/drm/mediadrm/plugins/mock/Android.bp
+++ b/drm/mediadrm/plugins/mock/Android.bp
@@ -32,5 +32,7 @@
cflags: [
// Set the following flag to enable the decryption passthru flow
//"-DENABLE_PASSTHRU_DECRYPTION",
+ "-Wall",
+ "-Werror",
],
}
diff --git a/media/extractors/midi/Android.bp b/media/extractors/midi/Android.bp
index 79c43b4..68f8766 100644
--- a/media/extractors/midi/Android.bp
+++ b/media/extractors/midi/Android.bp
@@ -8,13 +8,15 @@
shared_libs: [
"liblog",
- "libmedia", // Needed for MidiIoWrapper
"libmediaextractor",
- "libsonivox",
"libstagefright_foundation",
"libutils",
],
+ static_libs: [
+ "libmedia_midiiowrapper",
+ "libsonivox",
+ ],
name: "libmidiextractor",
relative_install_path: "extractors",
diff --git a/media/extractors/mkv/Android.bp b/media/extractors/mkv/Android.bp
index 476109a..350c6fe 100644
--- a/media/extractors/mkv/Android.bp
+++ b/media/extractors/mkv/Android.bp
@@ -12,12 +12,12 @@
shared_libs: [
"liblog",
"libmediaextractor",
- "libstagefright_flacdec",
"libstagefright_foundation",
"libutils",
],
static_libs: [
+ "libstagefright_flacdec",
"libwebm",
],
diff --git a/media/extractors/mkv/MatroskaExtractor.cpp b/media/extractors/mkv/MatroskaExtractor.cpp
index d57305c..5a8e79d 100644
--- a/media/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/extractors/mkv/MatroskaExtractor.cpp
@@ -1459,6 +1459,14 @@
continue;
}
+ const char *language = track->GetLanguage();
+ if (language != NULL) {
+ char lang[4];
+ strncpy(lang, language, 3);
+ lang[3] = '\0';
+ meta->setCString(kKeyMediaLanguage, lang);
+ }
+
if (err != OK) {
ALOGE("skipping track, codec specific data was malformed.");
continue;
diff --git a/media/extractors/ogg/Android.bp b/media/extractors/ogg/Android.bp
index 03c4c24..6bd8025 100644
--- a/media/extractors/ogg/Android.bp
+++ b/media/extractors/ogg/Android.bp
@@ -12,6 +12,9 @@
"libmediaextractor",
"libstagefright_foundation",
"libutils",
+ ],
+
+ static_libs: [
"libvorbisidec",
],
diff --git a/media/libaaudio/Android.bp b/media/libaaudio/Android.bp
index 6e60f24..f00f7a8 100644
--- a/media/libaaudio/Android.bp
+++ b/media/libaaudio/Android.bp
@@ -28,3 +28,10 @@
first_version: "26",
unversioned_until: "current",
}
+
+cc_library_headers {
+ name: "libaaudio_headers",
+ export_include_dirs: ["include"],
+}
+
+subdirs = ["*"]
diff --git a/media/libaaudio/Android.mk b/media/libaaudio/Android.mk
deleted file mode 100644
index 5053e7d..0000000
--- a/media/libaaudio/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)
diff --git a/media/libaaudio/examples/Android.bp b/media/libaaudio/examples/Android.bp
new file mode 100644
index 0000000..f2e00a7
--- /dev/null
+++ b/media/libaaudio/examples/Android.bp
@@ -0,0 +1,4 @@
+cc_library_headers {
+ name: "libaaudio_example_utils",
+ export_include_dirs: ["."],
+}
diff --git a/media/libaaudio/examples/Android.mk b/media/libaaudio/examples/Android.mk
deleted file mode 100644
index 5053e7d..0000000
--- a/media/libaaudio/examples/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)
diff --git a/media/libaaudio/examples/input_monitor/Android.mk b/media/libaaudio/examples/input_monitor/Android.mk
deleted file mode 100644
index 5053e7d..0000000
--- a/media/libaaudio/examples/input_monitor/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)
diff --git a/media/libaaudio/examples/loopback/Android.mk b/media/libaaudio/examples/loopback/Android.mk
deleted file mode 100644
index 5053e7d..0000000
--- a/media/libaaudio/examples/loopback/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)
diff --git a/media/libaaudio/examples/utils/AAudioArgsParser.h b/media/libaaudio/examples/utils/AAudioArgsParser.h
index ada37e2..142b295 100644
--- a/media/libaaudio/examples/utils/AAudioArgsParser.h
+++ b/media/libaaudio/examples/utils/AAudioArgsParser.h
@@ -17,6 +17,8 @@
#ifndef AAUDIO_EXAMPLE_ARGS_PARSER_H
#define AAUDIO_EXAMPLE_ARGS_PARSER_H
+#define MAX_CHANNELS 8
+
#include <cctype>
#include <unistd.h>
#include <stdio.h>
@@ -39,6 +41,10 @@
}
void setChannelCount(int32_t channelCount) {
+ if (channelCount > MAX_CHANNELS) {
+ printf("Sorry, MAX of %d channels!\n", MAX_CHANNELS);
+ channelCount = MAX_CHANNELS;
+ }
mChannelCount = channelCount;
}
diff --git a/media/libaaudio/examples/utils/AAudioSimplePlayer.h b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
index 606c4ba..1061e42 100644
--- a/media/libaaudio/examples/utils/AAudioSimplePlayer.h
+++ b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
@@ -19,11 +19,10 @@
#ifndef AAUDIO_SIMPLE_PLAYER_H
#define AAUDIO_SIMPLE_PLAYER_H
-#include <unistd.h>
#include <sched.h>
+#include <unistd.h>
#include <aaudio/AAudio.h>
-#include <atomic>
#include "AAudioArgsParser.h"
#include "SineGenerator.h"
@@ -36,7 +35,7 @@
// How long to sleep in a callback to cause an intentional glitch. For testing.
#define FORCED_UNDERRUN_SLEEP_MICROS (10 * 1000)
-#define MAX_TIMESTAMPS 16
+#define MAX_TIMESTAMPS 16
typedef struct Timestamp {
int64_t position;
@@ -70,13 +69,6 @@
}
// TODO Extract a common base class for record and playback.
- /**
- * Also known as "sample rate"
- * Only call this after open() has been called.
- */
- int32_t getFramesPerSecond() const {
- return getSampleRate(); // alias
- }
/**
* Only call this after open() has been called.
@@ -172,6 +164,7 @@
result = AAudioStreamBuilder_openStream(builder, &mStream);
AAudioStreamBuilder_delete(builder);
+
return result;
}
@@ -212,13 +205,35 @@
aaudio_result_t result = AAudioStream_requestStop(mStream);
if (result != AAUDIO_OK) {
printf("ERROR - AAudioStream_requestStop() returned %d %s\n",
- result, AAudio_convertResultToText(result));
+ result, AAudio_convertResultToText(result));
}
int32_t xRunCount = AAudioStream_getXRunCount(mStream);
printf("AAudioStream_getXRunCount %d\n", xRunCount);
return result;
}
+ // Pause the stream. AAudio will stop calling your callback function.
+ aaudio_result_t pause() {
+ aaudio_result_t result = AAudioStream_requestPause(mStream);
+ if (result != AAUDIO_OK) {
+ printf("ERROR - AAudioStream_requestPause() returned %d %s\n",
+ result, AAudio_convertResultToText(result));
+ }
+ int32_t xRunCount = AAudioStream_getXRunCount(mStream);
+ printf("AAudioStream_getXRunCount %d\n", xRunCount);
+ return result;
+ }
+
+ // Flush the stream. AAudio will stop calling your callback function.
+ aaudio_result_t flush() {
+ aaudio_result_t result = AAudioStream_requestFlush(mStream);
+ if (result != AAUDIO_OK) {
+ printf("ERROR - AAudioStream_requestFlush() returned %d %s\n",
+ result, AAudio_convertResultToText(result));
+ }
+ return result;
+ }
+
AAudioStream *getStream() const {
return mStream;
}
@@ -232,23 +247,49 @@
typedef struct SineThreadedData_s {
- SineGenerator sineOsc1;
- SineGenerator sineOsc2;
- Timestamp timestamps[MAX_TIMESTAMPS];
- int64_t framesTotal = 0;
- int64_t nextFrameToGlitch = FORCED_UNDERRUN_PERIOD_FRAMES;
- int32_t minNumFrames = INT32_MAX;
- int32_t maxNumFrames = 0;
- int32_t timestampCount = 0; // in timestamps
+ SineGenerator sineOscillators[MAX_CHANNELS];
+ Timestamp timestamps[MAX_TIMESTAMPS];
+ int64_t framesTotal = 0;
+ int64_t nextFrameToGlitch = FORCED_UNDERRUN_PERIOD_FRAMES;
+ int32_t minNumFrames = INT32_MAX;
+ int32_t maxNumFrames = 0;
+ int32_t timestampCount = 0; // in timestamps
+ int32_t sampleRate = 48000;
+ int32_t prefixToneFrames = 0;
+ bool sweepSetup = false;
- int scheduler = 0;
- bool schedulerChecked = false;
- bool forceUnderruns = false;
+ int scheduler = 0;
+ bool schedulerChecked = false;
+ bool forceUnderruns = false;
AAudioSimplePlayer simplePlayer;
int32_t callbackCount = 0;
WakeUp waker{AAUDIO_OK};
+ /**
+ * Set sampleRate first.
+ */
+ void setupSineBlip() {
+ for (int i = 0; i < MAX_CHANNELS; ++i) {
+ double centerFrequency = 880.0 * (i + 2);
+ sineOscillators[i].setup(centerFrequency, sampleRate);
+ sineOscillators[i].setSweep(centerFrequency, centerFrequency, 0.0);
+ }
+ }
+
+ void setupSineSweeps() {
+ for (int i = 0; i < MAX_CHANNELS; ++i) {
+ double centerFrequency = 220.0 * (i + 2);
+ sineOscillators[i].setup(centerFrequency, sampleRate);
+ double minFrequency = centerFrequency * 2.0 / 3.0;
+ // Change range slightly so they will go out of phase.
+ double maxFrequency = centerFrequency * 3.0 / 2.0;
+ double sweepSeconds = 5.0 + i;
+ sineOscillators[i].setSweep(minFrequency, maxFrequency, sweepSeconds);
+ }
+ sweepSetup = true;
+ }
+
} SineThreadedData_t;
// Callback function that fills the audio output buffer.
@@ -265,9 +306,11 @@
return AAUDIO_CALLBACK_RESULT_STOP;
}
SineThreadedData_t *sineData = (SineThreadedData_t *) userData;
- sineData->callbackCount++;
- sineData->framesTotal += numFrames;
+ // Play an initial high tone so we can tell whether the beginning was truncated.
+ if (!sineData->sweepSetup && sineData->framesTotal >= sineData->prefixToneFrames) {
+ sineData->setupSineSweeps();
+ }
if (sineData->forceUnderruns) {
if (sineData->framesTotal > sineData->nextFrameToGlitch) {
@@ -301,33 +344,32 @@
}
int32_t samplesPerFrame = AAudioStream_getChannelCount(stream);
- // This code only plays on the first one or two channels.
- // TODO Support arbitrary number of channels.
+
+
+ int numActiveOscilators = (samplesPerFrame > MAX_CHANNELS) ? MAX_CHANNELS : samplesPerFrame;
switch (AAudioStream_getFormat(stream)) {
case AAUDIO_FORMAT_PCM_I16: {
int16_t *audioBuffer = (int16_t *) audioData;
- // Render sine waves as shorts to first channel.
- sineData->sineOsc1.render(&audioBuffer[0], samplesPerFrame, numFrames);
- // Render sine waves to second channel if there is one.
- if (samplesPerFrame > 1) {
- sineData->sineOsc2.render(&audioBuffer[1], samplesPerFrame, numFrames);
+ for (int i = 0; i < numActiveOscilators; ++i) {
+ sineData->sineOscillators[i].render(&audioBuffer[i], samplesPerFrame,
+ numFrames);
}
}
- break;
+ break;
case AAUDIO_FORMAT_PCM_FLOAT: {
float *audioBuffer = (float *) audioData;
- // Render sine waves as floats to first channel.
- sineData->sineOsc1.render(&audioBuffer[0], samplesPerFrame, numFrames);
- // Render sine waves to second channel if there is one.
- if (samplesPerFrame > 1) {
- sineData->sineOsc2.render(&audioBuffer[1], samplesPerFrame, numFrames);
+ for (int i = 0; i < numActiveOscilators; ++i) {
+ sineData->sineOscillators[i].render(&audioBuffer[i], samplesPerFrame,
+ numFrames);
}
}
- break;
+ break;
default:
return AAUDIO_CALLBACK_RESULT_STOP;
}
+ sineData->callbackCount++;
+ sineData->framesTotal += numFrames;
return AAUDIO_CALLBACK_RESULT_CONTINUE;
}
diff --git a/media/libaaudio/examples/utils/SineGenerator.h b/media/libaaudio/examples/utils/SineGenerator.h
index a755582..9e6d46d 100644
--- a/media/libaaudio/examples/utils/SineGenerator.h
+++ b/media/libaaudio/examples/utils/SineGenerator.h
@@ -31,20 +31,20 @@
}
void setSweep(double frequencyLow, double frequencyHigh, double seconds) {
- mPhaseIncrementLow = frequencyLow * M_PI * 2 / mFrameRate;
- mPhaseIncrementHigh = frequencyHigh * M_PI * 2 / mFrameRate;
-
- double numFrames = seconds * mFrameRate;
- mUpScaler = pow((frequencyHigh / frequencyLow), (1.0 / numFrames));
- mDownScaler = 1.0 / mUpScaler;
- mGoingUp = true;
- mSweeping = true;
+ mSweeping = seconds > 0.0;
+ if (mSweeping) {
+ mPhaseIncrementLow = frequencyLow * M_PI * 2 / mFrameRate;
+ mPhaseIncrementHigh = frequencyHigh * M_PI * 2 / mFrameRate;
+ double numFrames = seconds * mFrameRate;
+ mUpScaler = pow((frequencyHigh / frequencyLow), (1.0 / numFrames));
+ mDownScaler = 1.0 / mUpScaler;
+ }
}
void render(int16_t *buffer, int32_t channelStride, int32_t numFrames) {
int sampleIndex = 0;
for (int i = 0; i < numFrames; i++) {
- buffer[sampleIndex] = (int16_t) (32767 * sin(mPhase) * mAmplitude);
+ buffer[sampleIndex] = (int16_t) (INT16_MAX * sin(mPhase) * mAmplitude);
sampleIndex += channelStride;
advancePhase();
}
@@ -61,6 +61,7 @@
void setAmplitude(double amplitude) {
mAmplitude = amplitude;
}
+
double getAmplitude() const {
return mAmplitude;
}
diff --git a/media/libaaudio/examples/write_sine/Android.mk b/media/libaaudio/examples/write_sine/Android.mk
deleted file mode 100644
index 5053e7d..0000000
--- a/media/libaaudio/examples/write_sine/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)
diff --git a/media/libaaudio/examples/write_sine/src/write_sine.cpp b/media/libaaudio/examples/write_sine/src/write_sine.cpp
index 677fb6c..65d98d1 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine.cpp
@@ -48,6 +48,7 @@
int32_t framesToPlay = 0;
int32_t framesLeft = 0;
int32_t xRunCount = 0;
+ int numActiveOscilators = 0;
float *floatData = nullptr;
int16_t *shortData = nullptr;
@@ -77,8 +78,8 @@
actualSampleRate = AAudioStream_getSampleRate(aaudioStream);
actualDataFormat = AAudioStream_getFormat(aaudioStream);
- myData.sineOsc1.setup(440.0, actualSampleRate);
- myData.sineOsc2.setup(660.0, actualSampleRate);
+ myData.sampleRate = actualSampleRate;
+ myData.setupSineSweeps();
// Some DMA might use very short bursts of 16 frames. We don't need to write such small
// buffers. But it helps to use a multiple of the burst size for predictable scheduling.
@@ -117,19 +118,18 @@
// Play for a while.
framesToPlay = actualSampleRate * argParser.getDurationSeconds();
framesLeft = framesToPlay;
+ numActiveOscilators = (actualChannelCount > MAX_CHANNELS) ? MAX_CHANNELS : actualChannelCount;
while (framesLeft > 0) {
-
+ // Render as FLOAT or PCM
if (actualDataFormat == AAUDIO_FORMAT_PCM_FLOAT) {
- // Render sine waves to left and right channels.
- myData.sineOsc1.render(&floatData[0], actualChannelCount, framesPerWrite);
- if (actualChannelCount > 1) {
- myData.sineOsc2.render(&floatData[1], actualChannelCount, framesPerWrite);
+ for (int i = 0; i < numActiveOscilators; ++i) {
+ myData.sineOscillators[i].render(&floatData[i], actualChannelCount,
+ framesPerWrite);
}
} else if (actualDataFormat == AAUDIO_FORMAT_PCM_I16) {
- // Render sine waves to left and right channels.
- myData.sineOsc1.render(&shortData[0], actualChannelCount, framesPerWrite);
- if (actualChannelCount > 1) {
- myData.sineOsc2.render(&shortData[1], actualChannelCount, framesPerWrite);
+ for (int i = 0; i < numActiveOscilators; ++i) {
+ myData.sineOscillators[i].render(&shortData[i], actualChannelCount,
+ framesPerWrite);
}
}
diff --git a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
index 4f9cde6..c2dd7af 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
@@ -28,7 +28,6 @@
#include <aaudio/AAudio.h>
#include "AAudioExampleUtils.h"
#include "AAudioSimplePlayer.h"
-#include "../../utils/AAudioSimplePlayer.h"
/**
* Open stream, play some sine waves, then close the stream.
@@ -36,37 +35,39 @@
* @param argParser
* @return AAUDIO_OK or negative error code
*/
-static aaudio_result_t testOpenPlayClose(AAudioArgsParser &argParser)
+static aaudio_result_t testOpenPlayClose(AAudioArgsParser &argParser,
+ int32_t loopCount,
+ int32_t prefixToneMsec)
{
SineThreadedData_t myData;
AAudioSimplePlayer &player = myData.simplePlayer;
aaudio_result_t result = AAUDIO_OK;
bool disconnected = false;
+ bool bailOut = false;
int64_t startedAtNanos;
printf("----------------------- run complete test --------------------------\n");
myData.schedulerChecked = false;
myData.callbackCount = 0;
+ // TODO add a command line option for the forceUnderruns
myData.forceUnderruns = false; // set true to test AAudioStream_getXRunCount()
result = player.open(argParser,
SimplePlayerDataCallbackProc, SimplePlayerErrorCallbackProc, &myData);
if (result != AAUDIO_OK) {
- fprintf(stderr, "ERROR - player.open() returned %d\n", result);
+ fprintf(stderr, "ERROR - player.open() returned %s\n",
+ AAudio_convertResultToText(result));
goto error;
}
argParser.compareWithStream(player.getStream());
- // Setup sine wave generators.
- {
- int32_t actualSampleRate = player.getSampleRate();
- myData.sineOsc1.setup(440.0, actualSampleRate);
- myData.sineOsc1.setSweep(300.0, 600.0, 5.0);
- myData.sineOsc1.setAmplitude(0.2);
- myData.sineOsc2.setup(660.0, actualSampleRate);
- myData.sineOsc2.setSweep(350.0, 900.0, 7.0);
- myData.sineOsc2.setAmplitude(0.2);
+ myData.sampleRate = player.getSampleRate();
+ myData.prefixToneFrames = prefixToneMsec * myData.sampleRate / 1000;
+ if (myData.prefixToneFrames > 0) {
+ myData.setupSineBlip();
+ } else {
+ myData.setupSineSweeps();
}
#if 0
@@ -78,42 +79,93 @@
}
#endif
- result = player.start();
- if (result != AAUDIO_OK) {
- fprintf(stderr, "ERROR - player.start() returned %d\n", result);
- goto error;
- }
+ for (int loopIndex = 0; loopIndex < loopCount; loopIndex++) {
+ // Only play data on every other loop so we can hear if there is stale data.
+ double amplitude;
+ int32_t durationSeconds;
+ if ((loopIndex & 1) == 0) {
+ printf("--------------- SINE ------\n");
+ amplitude = 0.2;
+ durationSeconds = argParser.getDurationSeconds();
+ } else {
+ printf("--------------- QUIET -----\n");
+ amplitude = 0.0;
+ durationSeconds = 2; // just wait briefly when quiet
+ }
+ for (int i = 0; i < MAX_CHANNELS; ++i) {
+ myData.sineOscillators[i].setAmplitude(amplitude);
+ }
- // Play a sine wave in the background.
- printf("Sleep for %d seconds while audio plays in a callback thread.\n",
- argParser.getDurationSeconds());
- startedAtNanos = getNanoseconds(CLOCK_MONOTONIC);
- for (int second = 0; second < argParser.getDurationSeconds(); second++)
- {
- // Sleep a while. Wake up early if there is an error, for example a DISCONNECT.
- long ret = myData.waker.wait(AAUDIO_OK, NANOS_PER_SECOND);
- int64_t millis = (getNanoseconds(CLOCK_MONOTONIC) - startedAtNanos) / NANOS_PER_MILLISECOND;
- result = myData.waker.get();
- printf("wait() returns %ld, aaudio_result = %d, at %6d millis"
- ", second = %d, framesWritten = %8d, underruns = %d\n",
- ret, result, (int) millis,
- second,
- (int) AAudioStream_getFramesWritten(player.getStream()),
- (int) AAudioStream_getXRunCount(player.getStream()));
+ result = player.start();
if (result != AAUDIO_OK) {
- if (result == AAUDIO_ERROR_DISCONNECTED) {
- disconnected = true;
+ fprintf(stderr, "ERROR - player.start() returned %d\n", result);
+ goto error;
+ }
+
+ // Play a sine wave in the background.
+ printf("Sleep for %d seconds while audio plays in a callback thread. %d of %d\n",
+ argParser.getDurationSeconds(), (loopIndex + 1), loopCount);
+ startedAtNanos = getNanoseconds(CLOCK_MONOTONIC);
+ for (int second = 0; second < durationSeconds; second++) {
+ // Sleep a while. Wake up early if there is an error, for example a DISCONNECT.
+ long ret = myData.waker.wait(AAUDIO_OK, NANOS_PER_SECOND);
+ int64_t millis =
+ (getNanoseconds(CLOCK_MONOTONIC) - startedAtNanos) / NANOS_PER_MILLISECOND;
+ result = myData.waker.get();
+ printf("wait() returns %ld, aaudio_result = %d, at %6d millis"
+ ", second = %3d, framesWritten = %8d, underruns = %d\n",
+ ret, result, (int) millis,
+ second,
+ (int) AAudioStream_getFramesWritten(player.getStream()),
+ (int) AAudioStream_getXRunCount(player.getStream()));
+ if (result != AAUDIO_OK) {
+ disconnected = (result == AAUDIO_ERROR_DISCONNECTED);
+ bailOut = true;
+ break;
}
+ }
+ printf("AAudio result = %d = %s\n", result, AAudio_convertResultToText(result));
+
+ // Alternate between using stop or pause for each sine/quiet pair.
+ // Repeat this pattern: {sine-stop-quiet-stop-sine-pause-quiet-pause}
+ if ((loopIndex & 2) == 0) {
+ printf("STOP, callback # = %d\n", myData.callbackCount);
+ result = player.stop();
+ } else {
+ printf("PAUSE/FLUSH, callback # = %d\n", myData.callbackCount);
+ result = player.pause();
+ if (result != AAUDIO_OK) {
+ goto error;
+ }
+ result = player.flush();
+ }
+ if (result != AAUDIO_OK) {
+ goto error;
+ }
+
+ if (bailOut) {
break;
}
- }
- printf("AAudio result = %d = %s\n", result, AAudio_convertResultToText(result));
- printf("call stop() callback # = %d\n", myData.callbackCount);
- result = player.stop();
- if (result != AAUDIO_OK) {
- goto error;
+ {
+ aaudio_stream_state_t state = AAudioStream_getState(player.getStream());
+ aaudio_stream_state_t finalState = AAUDIO_STREAM_STATE_UNINITIALIZED;
+ int64_t timeoutNanos = 2000 * NANOS_PER_MILLISECOND;
+ result = AAudioStream_waitForStateChange(player.getStream(), state,
+ &finalState, timeoutNanos);
+ printf("waitForStateChange returns %s, state = %s\n",
+ AAudio_convertResultToText(result),
+ AAudio_convertStreamStateToText(finalState));
+ int64_t written = AAudioStream_getFramesWritten(player.getStream());
+ int64_t read = AAudioStream_getFramesRead(player.getStream());
+ printf(" framesWritten = %lld, framesRead = %lld, diff = %d\n",
+ (long long) written,
+ (long long) read,
+ (int) (written - read));
+ }
+
}
+
printf("call close()\n");
result = player.close();
if (result != AAUDIO_OK) {
@@ -147,23 +199,54 @@
return disconnected ? AAUDIO_ERROR_DISCONNECTED : result;
}
+static void usage() {
+ AAudioArgsParser::usage();
+ printf(" -l{count} loopCount start/stop, every other one is silent\n");
+ printf(" -t{msec} play a high pitched tone at the beginning\n");
+}
+
int main(int argc, const char **argv)
{
AAudioArgsParser argParser;
aaudio_result_t result;
+ int32_t loopCount = 1;
+ int32_t prefixToneMsec = 0;
// Make printf print immediately so that debug info is not stuck
// in a buffer if we hang or crash.
setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
- printf("%s - Play a sine sweep using an AAudio callback V0.1.2\n", argv[0]);
+ printf("%s - Play a sine sweep using an AAudio callback V0.1.3\n", argv[0]);
- if (argParser.parseArgs(argc, argv)) {
- return EXIT_FAILURE;
+ for (int i = 1; i < argc; i++) {
+ const char *arg = argv[i];
+ if (argParser.parseArg(arg)) {
+ // Handle options that are not handled by the ArgParser
+ if (arg[0] == '-') {
+ char option = arg[1];
+ switch (option) {
+ case 'l':
+ loopCount = atoi(&arg[2]);
+ break;
+ case 't':
+ prefixToneMsec = atoi(&arg[2]);
+ break;
+ default:
+ usage();
+ exit(EXIT_FAILURE);
+ break;
+ }
+ } else {
+ usage();
+ exit(EXIT_FAILURE);
+ break;
+ }
+ }
}
// Keep looping until we can complete the test without disconnecting.
- while((result = testOpenPlayClose(argParser)) == AAUDIO_ERROR_DISCONNECTED);
+ while((result = testOpenPlayClose(argParser, loopCount, prefixToneMsec))
+ == AAUDIO_ERROR_DISCONNECTED);
return (result) ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/media/libaaudio/src/Android.bp b/media/libaaudio/src/Android.bp
new file mode 100644
index 0000000..788833b
--- /dev/null
+++ b/media/libaaudio/src/Android.bp
@@ -0,0 +1,66 @@
+cc_library {
+ name: "libaaudio",
+
+ local_include_dirs: [
+ "binding",
+ "client",
+ "core",
+ "fifo",
+ "legacy",
+ "utility",
+ ],
+ export_include_dirs: ["."],
+ header_libs: ["libaaudio_headers"],
+ export_header_lib_headers: ["libaaudio_headers"],
+
+ srcs: [
+ "core/AudioStream.cpp",
+ "core/AudioStreamBuilder.cpp",
+ "core/AAudioAudio.cpp",
+ "core/AAudioStreamParameters.cpp",
+ "legacy/AudioStreamLegacy.cpp",
+ "legacy/AudioStreamRecord.cpp",
+ "legacy/AudioStreamTrack.cpp",
+ "utility/AAudioUtilities.cpp",
+ "utility/FixedBlockAdapter.cpp",
+ "utility/FixedBlockReader.cpp",
+ "utility/FixedBlockWriter.cpp",
+ "utility/LinearRamp.cpp",
+ "fifo/FifoBuffer.cpp",
+ "fifo/FifoControllerBase.cpp",
+ "client/AudioEndpoint.cpp",
+ "client/AudioStreamInternal.cpp",
+ "client/AudioStreamInternalCapture.cpp",
+ "client/AudioStreamInternalPlay.cpp",
+ "client/IsochronousClockModel.cpp",
+ "binding/AudioEndpointParcelable.cpp",
+ "binding/AAudioBinderClient.cpp",
+ "binding/AAudioStreamRequest.cpp",
+ "binding/AAudioStreamConfiguration.cpp",
+ "binding/IAAudioClient.cpp",
+ "binding/IAAudioService.cpp",
+ "binding/RingBufferParcelable.cpp",
+ "binding/SharedMemoryParcelable.cpp",
+ "binding/SharedRegionParcelable.cpp",
+ ],
+
+ cflags: [
+ "-Wno-unused-parameter",
+ "-Wall",
+ "-Werror",
+
+ // By default, all symbols are hidden.
+ // "-fvisibility=hidden",
+ // AAUDIO_API is used to explicitly export a function or a variable as a visible symbol.
+ "-DAAUDIO_API=__attribute__((visibility(\"default\")))",
+ ],
+
+ shared_libs: [
+ "libaudioclient",
+ "liblog",
+ "libcutils",
+ "libutils",
+ "libbinder",
+ "libaudiomanager",
+ ],
+}
diff --git a/media/libaaudio/src/Android.mk b/media/libaaudio/src/Android.mk
deleted file mode 100644
index f7a5f9b..0000000
--- a/media/libaaudio/src/Android.mk
+++ /dev/null
@@ -1,132 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# ======================= STATIC LIBRARY ==========================
-# This is being built because it make AAudio testing very easy with a complete executable.
-# TODO Remove this target later, when not needed.
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libaaudio
-LOCAL_MODULE_TAGS := optional
-
-LIBAAUDIO_DIR := $(TOP)/frameworks/av/media/libaaudio
-LIBAAUDIO_SRC_DIR := $(LIBAAUDIO_DIR)/src
-
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/native/include \
- system/core/base/include \
- frameworks/native/media/libaaudio/include/include \
- frameworks/av/media/libaaudio/include \
- frameworks/native/include \
- frameworks/av/media/libaudioclient/include \
- $(LOCAL_PATH) \
- $(LOCAL_PATH)/binding \
- $(LOCAL_PATH)/client \
- $(LOCAL_PATH)/core \
- $(LOCAL_PATH)/fifo \
- $(LOCAL_PATH)/legacy \
- $(LOCAL_PATH)/utility
-
-LOCAL_AIDL_INCLUDES := frameworks/av/media/libaudioclient/aidl
-
-# If you add a file here then also add it below in the SHARED target
-LOCAL_SRC_FILES = \
- core/AudioStream.cpp \
- core/AudioStreamBuilder.cpp \
- core/AAudioAudio.cpp \
- core/AAudioStreamParameters.cpp \
- legacy/AudioStreamLegacy.cpp \
- legacy/AudioStreamRecord.cpp \
- legacy/AudioStreamTrack.cpp \
- utility/AAudioUtilities.cpp \
- utility/FixedBlockAdapter.cpp \
- utility/FixedBlockReader.cpp \
- utility/FixedBlockWriter.cpp \
- utility/LinearRamp.cpp \
- fifo/FifoBuffer.cpp \
- fifo/FifoControllerBase.cpp \
- client/AudioEndpoint.cpp \
- client/AudioStreamInternal.cpp \
- client/AudioStreamInternalCapture.cpp \
- client/AudioStreamInternalPlay.cpp \
- client/IsochronousClockModel.cpp \
- binding/AudioEndpointParcelable.cpp \
- binding/AAudioBinderClient.cpp \
- binding/AAudioStreamRequest.cpp \
- binding/AAudioStreamConfiguration.cpp \
- binding/IAAudioClient.cpp \
- binding/IAAudioService.cpp \
- binding/RingBufferParcelable.cpp \
- binding/SharedMemoryParcelable.cpp \
- binding/SharedRegionParcelable.cpp \
- ../../libaudioclient/aidl/android/media/IAudioRecord.aidl \
- ../../libaudioclient/aidl/android/media/IPlayer.aidl
-
-LOCAL_CFLAGS += -Wno-unused-parameter -Wall -Werror
-
-# By default, all symbols are hidden.
-# LOCAL_CFLAGS += -fvisibility=hidden
-# AAUDIO_API is used to explicitly export a function or a variable as a visible symbol.
-LOCAL_CFLAGS += -DAAUDIO_API='__attribute__((visibility("default")))'
-
-include $(BUILD_STATIC_LIBRARY)
-
-# ======================= SHARED LIBRARY ==========================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libaaudio
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/native/include \
- system/core/base/include \
- frameworks/native/media/libaaudio/include/include \
- frameworks/av/media/libaaudio/include \
- $(LOCAL_PATH) \
- $(LOCAL_PATH)/binding \
- $(LOCAL_PATH)/client \
- $(LOCAL_PATH)/core \
- $(LOCAL_PATH)/fifo \
- $(LOCAL_PATH)/legacy \
- $(LOCAL_PATH)/utility
-
-LOCAL_SRC_FILES = core/AudioStream.cpp \
- core/AudioStreamBuilder.cpp \
- core/AAudioAudio.cpp \
- core/AAudioStreamParameters.cpp \
- legacy/AudioStreamLegacy.cpp \
- legacy/AudioStreamRecord.cpp \
- legacy/AudioStreamTrack.cpp \
- utility/AAudioUtilities.cpp \
- utility/FixedBlockAdapter.cpp \
- utility/FixedBlockReader.cpp \
- utility/FixedBlockWriter.cpp \
- utility/LinearRamp.cpp \
- fifo/FifoBuffer.cpp \
- fifo/FifoControllerBase.cpp \
- client/AudioEndpoint.cpp \
- client/AudioStreamInternal.cpp \
- client/AudioStreamInternalCapture.cpp \
- client/AudioStreamInternalPlay.cpp \
- client/IsochronousClockModel.cpp \
- binding/AudioEndpointParcelable.cpp \
- binding/AAudioBinderClient.cpp \
- binding/AAudioStreamRequest.cpp \
- binding/AAudioStreamConfiguration.cpp \
- binding/IAAudioClient.cpp \
- binding/IAAudioService.cpp \
- binding/RingBufferParcelable.cpp \
- binding/SharedMemoryParcelable.cpp \
- binding/SharedRegionParcelable.cpp
-
-LOCAL_CFLAGS += -Wno-unused-parameter -Wall -Werror
-
-# By default, all symbols are hidden.
-# LOCAL_CFLAGS += -fvisibility=hidden
-# AAUDIO_API is used to explicitly export a function or a variable as a visible symbol.
-LOCAL_CFLAGS += -DAAUDIO_API='__attribute__((visibility("default")))'
-
-LOCAL_SHARED_LIBRARIES := libaudioclient liblog libcutils libutils libbinder libaudiomanager
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp
new file mode 100644
index 0000000..099f416
--- /dev/null
+++ b/media/libaaudio/tests/Android.bp
@@ -0,0 +1,84 @@
+cc_test {
+ name: "test_aaudio_marshalling",
+ srcs: ["test_marshalling.cpp"],
+ shared_libs: [
+ "libaaudio",
+ "libbinder",
+ "libcutils",
+ "libutils",
+ ],
+}
+
+cc_test {
+ name: "test_block_adapter",
+ srcs: ["test_block_adapter.cpp"],
+ shared_libs: ["libaaudio"],
+}
+
+cc_test {
+ name: "test_timestamps",
+ srcs: ["test_timestamps.cpp"],
+ header_libs: ["libaaudio_example_utils"],
+ shared_libs: ["libaaudio"],
+}
+
+cc_test {
+ name: "test_linear_ramp",
+ srcs: ["test_linear_ramp.cpp"],
+ shared_libs: ["libaaudio"],
+}
+
+cc_test {
+ name: "test_open_params",
+ srcs: ["test_open_params.cpp"],
+ shared_libs: [
+ "libaaudio",
+ "libbinder",
+ "libcutils",
+ "libutils",
+ ],
+}
+
+cc_test {
+ name: "test_no_close",
+ srcs: ["test_no_close.cpp"],
+ shared_libs: [
+ "libaaudio",
+ "libbinder",
+ "libcutils",
+ "libutils",
+ ],
+}
+
+cc_test {
+ name: "test_aaudio_recovery",
+ srcs: ["test_recovery.cpp"],
+ shared_libs: [
+ "libaaudio",
+ "libbinder",
+ "libcutils",
+ "libutils",
+ ],
+}
+
+cc_test {
+ name: "test_n_streams",
+ srcs: ["test_n_streams.cpp"],
+ shared_libs: [
+ "libaaudio",
+ "libbinder",
+ "libcutils",
+ "libutils",
+ ],
+}
+
+cc_test {
+ name: "test_bad_disconnect",
+ srcs: ["test_bad_disconnect.cpp"],
+ shared_libs: [
+ "libaaudio",
+ "libbinder",
+ "libcutils",
+ "libutils",
+ ],
+}
diff --git a/media/libaaudio/tests/Android.mk b/media/libaaudio/tests/Android.mk
deleted file mode 100644
index 4120f7f..0000000
--- a/media/libaaudio/tests/Android.mk
+++ /dev/null
@@ -1,92 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/av/media/libaaudio/include \
- frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_marshalling.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
-LOCAL_MODULE := test_aaudio_marshalling
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/av/media/libaaudio/include \
- frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_block_adapter.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio
-LOCAL_MODULE := test_block_adapter
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/av/media/libaaudio/include \
- frameworks/av/media/libaaudio/src \
- frameworks/av/media/libaaudio/examples
-LOCAL_SRC_FILES:= test_timestamps.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio
-LOCAL_MODULE := test_timestamps
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/av/media/libaaudio/include \
- frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_linear_ramp.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio
-LOCAL_MODULE := test_linear_ramp
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/av/media/libaaudio/include \
- frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_open_params.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
-LOCAL_MODULE := test_open_params
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/av/media/libaaudio/include \
- frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_no_close.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
-LOCAL_MODULE := test_no_close
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/av/media/libaaudio/include \
- frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_recovery.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
-LOCAL_MODULE := test_aaudio_recovery
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/av/media/libaaudio/include \
- frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_n_streams.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
-LOCAL_MODULE := test_n_streams
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/av/media/libaaudio/include \
- frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_bad_disconnect.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
-LOCAL_MODULE := test_bad_disconnect
-include $(BUILD_NATIVE_TEST)
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 4479b4b..71c1ffb 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -43,9 +43,7 @@
"aidl/android/IOMXBufferSource.aidl",
"IMediaCodecList.cpp",
- "IMediaCodecService.cpp",
"IOMX.cpp",
- "IOMXStore.cpp",
"MediaCodecBuffer.cpp",
"MediaCodecInfo.cpp",
"OMXBuffer.cpp",
@@ -122,6 +120,33 @@
defaults: ["libmedia_omx_defaults"],
}
+cc_library_static {
+ name: "libmedia_midiiowrapper",
+
+ srcs: ["MidiIoWrapper.cpp"],
+
+ static_libs: [
+ "libsonivox",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wno-error=deprecated-declarations",
+ "-Wall",
+ ],
+
+ sanitize: {
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ cfi: true,
+ diag: {
+ cfi: true,
+ },
+ },
+}
+
cc_library_shared {
name: "libmedia",
defaults: ["libmedia_omx_defaults"],
@@ -151,7 +176,6 @@
"IMediaMetadataRetriever.cpp",
"mediametadataretriever.cpp",
"MidiDeviceInfo.cpp",
- "MidiIoWrapper.cpp",
"JetPlayer.cpp",
"MediaScanner.cpp",
"MediaScannerClient.cpp",
@@ -193,9 +217,9 @@
"libsonivox",
],
- // for memory heap analysis
static_libs: [
- "libc_malloc_debug_backtrace",
+ "libc_malloc_debug_backtrace", // for memory heap analysis
+ "libmedia_midiiowrapper",
],
export_include_dirs: [
diff --git a/media/libmedia/IMediaCodecService.cpp b/media/libmedia/IMediaCodecService.cpp
deleted file mode 100644
index adfa93d..0000000
--- a/media/libmedia/IMediaCodecService.cpp
+++ /dev/null
@@ -1,86 +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_TAG "IMediaCodecService"
-//#define LOG_NDEBUG 0
-
-#include <utils/Log.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <binder/Parcel.h>
-#include <media/IMediaCodecService.h>
-
-namespace android {
-
-enum {
- GET_OMX = IBinder::FIRST_CALL_TRANSACTION,
- GET_OMX_STORE
-};
-
-class BpMediaCodecService : public BpInterface<IMediaCodecService>
-{
-public:
- explicit BpMediaCodecService(const sp<IBinder>& impl)
- : BpInterface<IMediaCodecService>(impl)
- {
- }
-
- virtual sp<IOMX> getOMX() {
- Parcel data, reply;
- data.writeInterfaceToken(IMediaCodecService::getInterfaceDescriptor());
- remote()->transact(GET_OMX, data, &reply);
- return interface_cast<IOMX>(reply.readStrongBinder());
- }
-
- virtual sp<IOMXStore> getOMXStore() {
- Parcel data, reply;
- data.writeInterfaceToken(IMediaCodecService::getInterfaceDescriptor());
- remote()->transact(GET_OMX_STORE, data, &reply);
- return interface_cast<IOMXStore>(reply.readStrongBinder());
- }
-
-};
-
-IMPLEMENT_META_INTERFACE(MediaCodecService, "android.media.IMediaCodecService");
-
-// ----------------------------------------------------------------------
-
-status_t BnMediaCodecService::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch (code) {
-
- case GET_OMX: {
- CHECK_INTERFACE(IMediaCodecService, data, reply);
- sp<IOMX> omx = getOMX();
- reply->writeStrongBinder(IInterface::asBinder(omx));
- return NO_ERROR;
- }
- case GET_OMX_STORE: {
- CHECK_INTERFACE(IMediaCodecService, data, reply);
- sp<IOMXStore> omxStore = getOMXStore();
- reply->writeStrongBinder(IInterface::asBinder(omxStore));
- return NO_ERROR;
- }
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-// ----------------------------------------------------------------------------
-
-} // namespace android
diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
index 3c43a72..a8a7b82 100644
--- a/media/libmedia/IMediaExtractor.cpp
+++ b/media/libmedia/IMediaExtractor.cpp
@@ -23,6 +23,7 @@
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
+#include <binder/PermissionCache.h>
#include <media/IMediaExtractor.h>
#include <media/stagefright/MetaData.h>
@@ -323,13 +324,21 @@
status_t dumpExtractors(int fd, const Vector<String16>&) {
String8 out;
- out.append("Recent extractors, most recent first:\n");
- {
- Mutex::Autolock lock(sExtractorsLock);
- for (size_t i = 0; i < sExtractors.size(); i++) {
- const ExtractorInstance &instance = sExtractors.itemAt(i);
- out.append(" ");
- out.append(instance.toString());
+ const IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ if (!PermissionCache::checkPermission(String16("android.permission.DUMP"), pid, uid)) {
+ out.appendFormat("Permission Denial: "
+ "can't dump MediaExtractor from pid=%d, uid=%d\n", pid, uid);
+ } else {
+ out.append("Recent extractors, most recent first:\n");
+ {
+ Mutex::Autolock lock(sExtractorsLock);
+ for (size_t i = 0; i < sExtractors.size(); i++) {
+ const ExtractorInstance &instance = sExtractors.itemAt(i);
+ out.append(" ");
+ out.append(instance.toString());
+ }
}
}
write(fd, out.string(), out.size());
diff --git a/media/libmedia/IOMXStore.cpp b/media/libmedia/IOMXStore.cpp
deleted file mode 100644
index 4948f1a..0000000
--- a/media/libmedia/IOMXStore.cpp
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * Copyright (c) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "IOMXStore"
-
-#include <utils/Log.h>
-
-#include <media/IOMX.h>
-#include <media/IOMXStore.h>
-#include <android/hardware/media/omx/1.0/IOmxStore.h>
-
-#include <binder/IInterface.h>
-#include <binder/IBinder.h>
-#include <binder/Parcel.h>
-
-#include <vector>
-#include <string>
-
-namespace android {
-
-namespace {
-
-enum {
- CONNECT = IBinder::FIRST_CALL_TRANSACTION,
- LIST_SERVICE_ATTRIBUTES,
- GET_NODE_PREFIX,
- LIST_ROLES,
- GET_OMX,
-};
-
-// Forward declarations of std::vector<T> <-> Parcel conversion funcitons that
-// depend on writeToParcel() and readToParcel() for T <-> Parcel.
-
-template <typename T>
-status_t writeToParcel(const std::vector<T>& v, Parcel* p);
-
-template <typename T>
-status_t readFromParcel(std::vector<T>* v, const Parcel& p);
-
-// std::string <-> Parcel
-
-status_t writeToParcel(const std::string& s, Parcel* p) {
- if (s.size() > INT32_MAX) {
- return BAD_VALUE;
- }
- return p->writeByteArray(
- s.size(), reinterpret_cast<const uint8_t*>(s.c_str()));
-}
-
-status_t readFromParcel(std::string* s, const Parcel& p) {
- int32_t len;
- status_t status = p.readInt32(&len);
- if (status != NO_ERROR) {
- return status;
- } else if ((len < 0) || (static_cast<uint64_t>(len) > SIZE_MAX)) {
- return BAD_VALUE;
- }
- s->resize(len);
- if (len == 0) {
- return NO_ERROR;
- }
- return p.read(static_cast<void*>(&s->front()), static_cast<size_t>(len));
-}
-
-// IOMXStore::Attribute <-> Parcel
-
-status_t writeToParcel(const IOMXStore::Attribute& a, Parcel* p) {
- status_t status = writeToParcel(a.key, p);
- if (status != NO_ERROR) {
- return status;
- }
- return writeToParcel(a.value, p);
-}
-
-status_t readFromParcel(IOMXStore::Attribute* a, const Parcel& p) {
- status_t status = readFromParcel(&(a->key), p);
- if (status != NO_ERROR) {
- return status;
- }
- return readFromParcel(&(a->value), p);
-}
-
-// IOMXStore::NodeInfo <-> Parcel
-
-status_t writeToParcel(const IOMXStore::NodeInfo& n, Parcel* p) {
- status_t status = writeToParcel(n.name, p);
- if (status != NO_ERROR) {
- return status;
- }
- status = writeToParcel(n.owner, p);
- if (status != NO_ERROR) {
- return status;
- }
- return writeToParcel(n.attributes, p);
-}
-
-status_t readFromParcel(IOMXStore::NodeInfo* n, const Parcel& p) {
- status_t status = readFromParcel(&(n->name), p);
- if (status != NO_ERROR) {
- return status;
- }
- status = readFromParcel(&(n->owner), p);
- if (status != NO_ERROR) {
- return status;
- }
- return readFromParcel(&(n->attributes), p);
-}
-
-// IOMXStore::RoleInfo <-> Parcel
-
-status_t writeToParcel(const IOMXStore::RoleInfo& r, Parcel* p) {
- status_t status = writeToParcel(r.role, p);
- if (status != NO_ERROR) {
- return status;
- }
- status = writeToParcel(r.type, p);
- if (status != NO_ERROR) {
- return status;
- }
- status = p->writeBool(r.isEncoder);
- if (status != NO_ERROR) {
- return status;
- }
- status = p->writeBool(r.preferPlatformNodes);
- if (status != NO_ERROR) {
- return status;
- }
- return writeToParcel(r.nodes, p);
-}
-
-status_t readFromParcel(IOMXStore::RoleInfo* r, const Parcel& p) {
- status_t status = readFromParcel(&(r->role), p);
- if (status != NO_ERROR) {
- return status;
- }
- status = readFromParcel(&(r->type), p);
- if (status != NO_ERROR) {
- return status;
- }
- status = p.readBool(&(r->isEncoder));
- if (status != NO_ERROR) {
- return status;
- }
- status = p.readBool(&(r->preferPlatformNodes));
- if (status != NO_ERROR) {
- return status;
- }
- return readFromParcel(&(r->nodes), p);
-}
-
-// std::vector<NodeInfo> <-> Parcel
-// std::vector<RoleInfo> <-> Parcel
-
-template <typename T>
-status_t writeToParcel(const std::vector<T>& v, Parcel* p) {
- status_t status = p->writeVectorSize(v);
- if (status != NO_ERROR) {
- return status;
- }
- for (const T& x : v) {
- status = writeToParcel(x, p);
- if (status != NO_ERROR) {
- return status;
- }
- }
- return NO_ERROR;
-}
-
-template <typename T>
-status_t readFromParcel(std::vector<T>* v, const Parcel& p) {
- status_t status = p.resizeOutVector(v);
- if (status != NO_ERROR) {
- return status;
- }
- for (T& x : *v) {
- status = readFromParcel(&x, p);
- if (status != NO_ERROR) {
- return status;
- }
- }
- return NO_ERROR;
-}
-
-} // unnamed namespace
-
-////////////////////////////////////////////////////////////////////////////////
-
-class BpOMXStore : public BpInterface<IOMXStore> {
-public:
- explicit BpOMXStore(const sp<IBinder> &impl)
- : BpInterface<IOMXStore>(impl) {
- }
-
- status_t listServiceAttributes(
- std::vector<Attribute>* attributes) override {
- Parcel data, reply;
- status_t status;
- status = data.writeInterfaceToken(IOMXStore::getInterfaceDescriptor());
- if (status != NO_ERROR) {
- return status;
- }
- status = remote()->transact(LIST_SERVICE_ATTRIBUTES, data, &reply);
- if (status != NO_ERROR) {
- return status;
- }
- return readFromParcel(attributes, reply);
- }
-
- status_t getNodePrefix(std::string* prefix) override {
- Parcel data, reply;
- status_t status;
- status = data.writeInterfaceToken(IOMXStore::getInterfaceDescriptor());
- if (status != NO_ERROR) {
- return status;
- }
- status = remote()->transact(GET_NODE_PREFIX, data, &reply);
- if (status != NO_ERROR) {
- return status;
- }
- return readFromParcel(prefix, reply);
- }
-
- status_t listRoles(std::vector<RoleInfo>* roleList) override {
- Parcel data, reply;
- status_t status;
- status = data.writeInterfaceToken(IOMXStore::getInterfaceDescriptor());
- if (status != NO_ERROR) {
- return status;
- }
- status = remote()->transact(LIST_ROLES, data, &reply);
- if (status != NO_ERROR) {
- return status;
- }
- return readFromParcel(roleList, reply);
- }
-
- status_t getOmx(const std::string& name, sp<IOMX>* omx) override {
- Parcel data, reply;
- status_t status;
- status = data.writeInterfaceToken(IOMXStore::getInterfaceDescriptor());
- if (status != NO_ERROR) {
- return status;
- }
- status = writeToParcel(name, &data);
- if (status != NO_ERROR) {
- return status;
- }
- status = remote()->transact(GET_OMX, data, &reply);
- if (status != NO_ERROR) {
- return status;
- }
- return reply.readStrongBinder(omx);
- }
-
-};
-
-IMPLEMENT_META_INTERFACE(OMXStore, "android.hardware.IOMXStore");
-
-////////////////////////////////////////////////////////////////////////////////
-
-#define CHECK_OMX_INTERFACE(interface, data, reply) \
- do { if (!(data).enforceInterface(interface::getInterfaceDescriptor())) { \
- ALOGW("Call incorrectly routed to " #interface); \
- return PERMISSION_DENIED; \
- } } while (0)
-
-status_t BnOMXStore::onTransact(
- uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
- switch (code) {
- case LIST_SERVICE_ATTRIBUTES: {
- CHECK_OMX_INTERFACE(IOMXStore, data, reply);
- status_t status;
- std::vector<Attribute> attributes;
-
- status = listServiceAttributes(&attributes);
- if (status != NO_ERROR) {
- ALOGE("listServiceAttributes() fails with status %d",
- static_cast<int>(status));
- return NO_ERROR;
- }
- status = writeToParcel(attributes, reply);
- if (status != NO_ERROR) {
- ALOGE("listServiceAttributes() fails to send reply");
- return NO_ERROR;
- }
- return NO_ERROR;
- }
- case GET_NODE_PREFIX: {
- CHECK_OMX_INTERFACE(IOMXStore, data, reply);
- status_t status;
- std::string prefix;
-
- status = getNodePrefix(&prefix);
- if (status != NO_ERROR) {
- ALOGE("getNodePrefix() fails with status %d",
- static_cast<int>(status));
- return NO_ERROR;
- }
- status = writeToParcel(prefix, reply);
- if (status != NO_ERROR) {
- ALOGE("getNodePrefix() fails to send reply");
- return NO_ERROR;
- }
- return NO_ERROR;
- }
- case LIST_ROLES: {
- CHECK_OMX_INTERFACE(IOMXStore, data, reply);
- status_t status;
- std::vector<RoleInfo> roleList;
-
- status = listRoles(&roleList);
- if (status != NO_ERROR) {
- ALOGE("listRoles() fails with status %d",
- static_cast<int>(status));
- return NO_ERROR;
- }
- status = writeToParcel(roleList, reply);
- if (status != NO_ERROR) {
- ALOGE("listRoles() fails to send reply");
- return NO_ERROR;
- }
- return NO_ERROR;
- }
- case GET_OMX: {
- CHECK_OMX_INTERFACE(IOMXStore, data, reply);
- status_t status;
- std::string name;
- sp<IOMX> omx;
-
- status = readFromParcel(&name, data);
- if (status != NO_ERROR) {
- ALOGE("getOmx() fails to retrieve name");
- return NO_ERROR;
- }
- status = getOmx(name, &omx);
- if (status != NO_ERROR) {
- ALOGE("getOmx() fails with status %d",
- static_cast<int>(status));
- return NO_ERROR;
- }
- status = reply->writeStrongBinder(IInterface::asBinder(omx));
- if (status != NO_ERROR) {
- ALOGE("getOmx() fails to send reply");
- return NO_ERROR;
- }
- return NO_ERROR;
- }
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-} // namespace android
diff --git a/media/libmedia/include/media/IMediaCodecService.h b/media/libmedia/include/media/IMediaCodecService.h
deleted file mode 100644
index 59fb1c0..0000000
--- a/media/libmedia/include/media/IMediaCodecService.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 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_IMEDIACODECSERVICE_H
-#define ANDROID_IMEDIACODECSERVICE_H
-
-#include <binder/IInterface.h>
-#include <binder/IMemory.h>
-#include <binder/Parcel.h>
-#include <media/IDataSource.h>
-#include <media/IOMX.h>
-#include <media/IOMXStore.h>
-
-namespace android {
-
-class IMediaCodecService: public IInterface
-{
-public:
- DECLARE_META_INTERFACE(MediaCodecService);
-
- virtual sp<IOMX> getOMX() = 0;
- virtual sp<IOMXStore> getOMXStore() = 0;
-};
-
-class BnMediaCodecService: public BnInterface<IMediaCodecService>
-{
-public:
- virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
- uint32_t flags = 0);
-};
-
-} // namespace android
-
-#endif // ANDROID_IMEDIACODECSERVICE_H
diff --git a/media/libmedia/include/media/IOMXStore.h b/media/libmedia/include/media/IOMXStore.h
deleted file mode 100644
index 628db70..0000000
--- a/media/libmedia/include/media/IOMXStore.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_IOMXSTORE_H_
-
-#define ANDROID_IOMXSTORE_H_
-
-#include <media/IOMX.h>
-#include <android/hardware/media/omx/1.0/IOmxStore.h>
-
-#include <binder/IInterface.h>
-#include <binder/IBinder.h>
-
-#include <vector>
-#include <string>
-
-namespace android {
-
-using hardware::media::omx::V1_0::IOmxStore;
-
-class IOMXStore : public IInterface {
-public:
- DECLARE_META_INTERFACE(OMXStore);
-
- struct Attribute {
- std::string key;
- std::string value;
- };
-
- struct NodeInfo {
- std::string name;
- std::string owner;
- std::vector<Attribute> attributes;
- };
-
- struct RoleInfo {
- std::string role;
- std::string type;
- bool isEncoder;
- bool preferPlatformNodes;
- std::vector<NodeInfo> nodes;
- };
-
- virtual status_t listServiceAttributes(
- std::vector<Attribute>* attributes) = 0;
-
- virtual status_t getNodePrefix(std::string* prefix) = 0;
-
- virtual status_t listRoles(std::vector<RoleInfo>* roleList) = 0;
-
- virtual status_t getOmx(const std::string& name, sp<IOMX>* omx) = 0;
-};
-
-
-////////////////////////////////////////////////////////////////////////////////
-
-class BnOMXStore : public BnInterface<IOMXStore> {
-public:
- virtual status_t onTransact(
- uint32_t code, const Parcel &data, Parcel *reply,
- uint32_t flags = 0);
-};
-
-} // namespace android
-
-#endif // ANDROID_IOMX_H_
diff --git a/media/libmediametrics/MediaAnalyticsItem.cpp b/media/libmediametrics/MediaAnalyticsItem.cpp
index f968c09..f7df2b4 100644
--- a/media/libmediametrics/MediaAnalyticsItem.cpp
+++ b/media/libmediametrics/MediaAnalyticsItem.cpp
@@ -279,8 +279,10 @@
prop = &mProps[i];
} else {
if (i == mPropSize) {
- growProps();
- // XXX: verify success
+ if (growProps() == false) {
+ ALOGE("failed allocation for new props");
+ return NULL;
+ }
}
i = mPropCount++;
prop = &mProps[i];
@@ -312,41 +314,54 @@
// set the values
void MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr name, int32_t value) {
Prop *prop = allocateProp(name);
- prop->mType = kTypeInt32;
- prop->u.int32Value = value;
+ if (prop != NULL) {
+ prop->mType = kTypeInt32;
+ prop->u.int32Value = value;
+ }
}
void MediaAnalyticsItem::setInt64(MediaAnalyticsItem::Attr name, int64_t value) {
Prop *prop = allocateProp(name);
- prop->mType = kTypeInt64;
- prop->u.int64Value = value;
+ if (prop != NULL) {
+ prop->mType = kTypeInt64;
+ prop->u.int64Value = value;
+ }
}
void MediaAnalyticsItem::setDouble(MediaAnalyticsItem::Attr name, double value) {
Prop *prop = allocateProp(name);
- prop->mType = kTypeDouble;
- prop->u.doubleValue = value;
+ if (prop != NULL) {
+ 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
- prop->mType = kTypeCString;
- prop->u.CStringValue = strdup(value);
+ if (prop != NULL) {
+ prop->mType = kTypeCString;
+ prop->u.CStringValue = strdup(value);
+ }
}
void MediaAnalyticsItem::setRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
Prop *prop = allocateProp(name);
- prop->mType = kTypeRate;
- prop->u.rate.count = count;
- prop->u.rate.duration = duration;
+ if (prop != NULL) {
+ 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;
@@ -361,6 +376,9 @@
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;
@@ -375,6 +393,9 @@
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;
@@ -391,6 +412,9 @@
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;
@@ -585,7 +609,7 @@
}
}
-void MediaAnalyticsItem::growProps(int increment)
+bool MediaAnalyticsItem::growProps(int increment)
{
if (increment <= 0) {
increment = kGrowProps;
@@ -599,6 +623,10 @@
}
mProps = ni;
mPropSize = nsize;
+ return true;
+ } else {
+ ALOGW("MediaAnalyticsItem::growProps fails");
+ return false;
}
}
@@ -963,32 +991,26 @@
int nattr = incoming->mPropCount;
for (int i = 0 ; i < nattr; i++ ) {
Prop *iprop = &incoming->mProps[i];
- Prop *oprop = findProp(iprop->mName);
const char *p = iprop->mName;
size_t len = strlen(p);
- char semantic = p[len-1];
+
+ // should ignore a zero length name...
+ if (len == 0) {
+ continue;
+ }
+
+ Prop *oprop = findProp(iprop->mName);
if (oprop == NULL) {
// no oprop, so we insert the new one
oprop = allocateProp(p);
- copyProp(oprop, iprop);
- } else {
- // merge iprop into oprop
- switch (semantic) {
- case '<': // first aka keep old)
- /* nop */
- break;
-
- default: // default is 'last'
- case '>': // last (aka keep new)
- copyProp(oprop, iprop);
- break;
-
- case '+': /* sum */
- // XXX validate numeric types, sum in place
- break;
-
+ if (oprop != NULL) {
+ copyProp(oprop, iprop);
+ } else {
+ ALOGW("dropped property '%s'", iprop->mName);
}
+ } else {
+ copyProp(oprop, iprop);
}
}
diff --git a/media/libmediametrics/include/MediaAnalyticsItem.h b/media/libmediametrics/include/MediaAnalyticsItem.h
index dd7452f..5f9b916 100644
--- a/media/libmediametrics/include/MediaAnalyticsItem.h
+++ b/media/libmediametrics/include/MediaAnalyticsItem.h
@@ -243,7 +243,7 @@
enum {
kGrowProps = 10
};
- void growProps(int increment = kGrowProps);
+ bool growProps(int increment = kGrowProps);
size_t findPropIndex(const char *name, size_t len);
Prop *findProp(const char *name);
Prop *allocateProp(const char *name);
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 246c746..8645680 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -729,25 +729,13 @@
mExtractorDeathListener = new ServiceDeathNotifier(binder, p, MEDIAEXTRACTOR_PROCESS_DEATH);
binder->linkToDeath(mExtractorDeathListener);
- if (property_get_bool("persist.media.treble_omx", true)) {
- // Treble IOmx
- sp<IOmx> omx = IOmx::getService();
- if (omx == nullptr) {
- ALOGE("Treble IOmx not available");
- return NULL;
- }
- mCodecDeathListener = new ServiceDeathNotifier(omx, p, MEDIACODEC_PROCESS_DEATH);
- omx->linkToDeath(mCodecDeathListener, 0);
- } else {
- // Legacy IOMX
- binder = sm->getService(String16("media.codec"));
- if (binder == NULL) {
- ALOGE("codec service not available");
- return NULL;
- }
- mCodecDeathListener = new ServiceDeathNotifier(binder, p, MEDIACODEC_PROCESS_DEATH);
- binder->linkToDeath(mCodecDeathListener);
+ sp<IOmx> omx = IOmx::getService();
+ if (omx == nullptr) {
+ ALOGE("IOmx service is not available");
+ return NULL;
}
+ mCodecDeathListener = new ServiceDeathNotifier(omx, p, MEDIACODEC_PROCESS_DEATH);
+ omx->linkToDeath(mCodecDeathListener, 0);
if (!p->hardwareOutput()) {
Mutex::Autolock l(mLock);
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index 6400481..f2565dd 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -450,27 +450,14 @@
}
sCameraChecked = true;
- if (property_get_bool("persist.media.treble_omx", true)) {
- // Treble IOmx
- sp<IOmx> omx = IOmx::getService();
- if (omx == nullptr) {
- ALOGE("Treble IOmx not available");
- return NO_INIT;
- }
- mCodecDeathListener = new ServiceDeathNotifier(omx, listener,
- MediaPlayerService::MEDIACODEC_PROCESS_DEATH);
- omx->linkToDeath(mCodecDeathListener, 0);
- } else {
- // Legacy IOMX
- binder = sm->getService(String16("media.codec"));
- if (binder == NULL) {
- ALOGE("Unable to connect to media codec service");
- return NO_INIT;
- }
- mCodecDeathListener = new ServiceDeathNotifier(binder, listener,
- MediaPlayerService::MEDIACODEC_PROCESS_DEATH);
- binder->linkToDeath(mCodecDeathListener);
+ sp<IOmx> omx = IOmx::getService();
+ if (omx == nullptr) {
+ ALOGE("IOmx service is not available");
+ return NO_INIT;
}
+ mCodecDeathListener = new ServiceDeathNotifier(omx, listener,
+ MediaPlayerService::MEDIACODEC_PROCESS_DEATH);
+ omx->linkToDeath(mCodecDeathListener, 0);
return OK;
}
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 4729d59..94e3395 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -49,9 +49,6 @@
static const int kHighWaterMarkMs = 5000; // 5secs
static const int kHighWaterMarkRebufferMs = 15000; // 15secs
-static const int kLowWaterMarkKB = 40;
-static const int kHighWaterMarkKB = 200;
-
NuPlayer::GenericSource::GenericSource(
const sp<AMessage> ¬ify,
bool uidValid,
@@ -62,6 +59,11 @@
mAudioLastDequeueTimeUs(0),
mVideoTimeUs(0),
mVideoLastDequeueTimeUs(0),
+ mPrevBufferPercentage(-1),
+ mPollBufferingGeneration(0),
+ mSentPauseOnBuffering(false),
+ mAudioDataGeneration(0),
+ mVideoDataGeneration(0),
mFetchSubtitleDataGeneration(0),
mFetchTimedTextDataGeneration(0),
mDurationUs(-1ll),
@@ -77,7 +79,7 @@
ALOGV("GenericSource");
CHECK(mediaClock != NULL);
- mBufferingMonitor = new BufferingMonitor(notify);
+ getDefaultBufferingSettings(&mBufferingSettings);
resetDataSource();
}
@@ -95,14 +97,7 @@
mOffset = 0;
mLength = 0;
mStarted = false;
- mStopRead = true;
-
- if (mBufferingMonitorLooper != NULL) {
- mBufferingMonitorLooper->unregisterHandler(mBufferingMonitor->id());
- mBufferingMonitorLooper->stop();
- mBufferingMonitorLooper = NULL;
- }
- mBufferingMonitor->stop();
+ mPreparing = false;
mIsDrmProtected = false;
mIsDrmReleased = false;
@@ -114,6 +109,7 @@
const sp<IMediaHTTPService> &httpService,
const char *url,
const KeyedVector<String8, String8> *headers) {
+ Mutex::Autolock _l(mLock);
ALOGV("setDataSource url: %s", url);
resetDataSource();
@@ -132,6 +128,7 @@
status_t NuPlayer::GenericSource::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();
@@ -146,6 +143,7 @@
}
status_t NuPlayer::GenericSource::setDataSource(const sp<DataSource>& source) {
+ Mutex::Autolock _l(mLock);
ALOGV("setDataSource (source: %p)", source.get());
resetDataSource();
@@ -154,6 +152,7 @@
}
sp<MetaData> NuPlayer::GenericSource::getFileFormatMeta() const {
+ Mutex::Autolock _l(mLock);
return mFileMeta;
}
@@ -268,12 +267,36 @@
status_t NuPlayer::GenericSource::getDefaultBufferingSettings(
BufferingSettings* buffering /* nonnull */) {
- mBufferingMonitor->getDefaultBufferingSettings(buffering);
+ buffering->mInitialBufferingMode = BUFFERING_MODE_TIME_ONLY;
+ buffering->mRebufferingMode = BUFFERING_MODE_TIME_ONLY;
+ buffering->mInitialWatermarkMs = kHighWaterMarkMs;
+ buffering->mRebufferingWatermarkLowMs = kLowWaterMarkMs;
+ buffering->mRebufferingWatermarkHighMs = kHighWaterMarkRebufferMs;
+
+ ALOGV("getDefaultBufferingSettings{%s}", buffering->toString().string());
return OK;
}
status_t NuPlayer::GenericSource::setBufferingSettings(const BufferingSettings& buffering) {
- return mBufferingMonitor->setBufferingSettings(buffering);
+ ALOGV("setBufferingSettings{%s}", buffering.toString().string());
+
+ if (buffering.IsSizeBasedBufferingMode(buffering.mInitialBufferingMode)
+ || buffering.IsSizeBasedBufferingMode(buffering.mRebufferingMode)
+ || (buffering.IsTimeBasedBufferingMode(buffering.mRebufferingMode)
+ && buffering.mRebufferingWatermarkLowMs > buffering.mRebufferingWatermarkHighMs)) {
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock _l(mLock);
+ mBufferingSettings = buffering;
+ if (mBufferingSettings.mInitialBufferingMode == BUFFERING_MODE_NONE) {
+ mBufferingSettings.mInitialWatermarkMs = BufferingSettings::kNoWatermark;
+ }
+ if (mBufferingSettings.mRebufferingMode == BUFFERING_MODE_NONE) {
+ mBufferingSettings.mRebufferingWatermarkLowMs = BufferingSettings::kNoWatermark;
+ mBufferingSettings.mRebufferingWatermarkHighMs = INT32_MAX;
+ }
+ return OK;
}
status_t NuPlayer::GenericSource::startSources() {
@@ -309,6 +332,7 @@
status_t NuPlayer::GenericSource::setBuffers(
bool audio, Vector<MediaBuffer *> &buffers) {
+ Mutex::Autolock _l(mLock);
if (mIsSecure && !audio && mVideoTrack.mSource != NULL) {
return mVideoTrack.mSource->setBuffers(buffers);
}
@@ -316,13 +340,10 @@
}
bool NuPlayer::GenericSource::isStreaming() const {
+ Mutex::Autolock _l(mLock);
return mIsStreaming;
}
-void NuPlayer::GenericSource::setOffloadAudio(bool offload) {
- mBufferingMonitor->setOffloadAudio(offload);
-}
-
NuPlayer::GenericSource::~GenericSource() {
ALOGV("~GenericSource");
if (mLooper != NULL) {
@@ -333,6 +354,7 @@
}
void NuPlayer::GenericSource::prepareAsync() {
+ Mutex::Autolock _l(mLock);
ALOGV("prepareAsync: (looper: %d)", (mLooper != NULL));
if (mLooper == NULL) {
@@ -434,7 +456,7 @@
}
if (mVideoTrack.mSource != NULL) {
- sp<MetaData> meta = doGetFormatMeta(false /* audio */);
+ sp<MetaData> meta = getFormatMeta_l(false /* audio */);
sp<AMessage> msg = new AMessage;
err = convertMetaDataToMessage(meta, &msg);
if(err != OK) {
@@ -468,47 +490,39 @@
}
if (mIsStreaming) {
- if (mBufferingMonitorLooper == NULL) {
- mBufferingMonitor->prepare(mCachedSource, mDurationUs, mBitrate,
- mIsStreaming);
-
- mBufferingMonitorLooper = new ALooper;
- mBufferingMonitorLooper->setName("GSBMonitor");
- mBufferingMonitorLooper->start();
- mBufferingMonitorLooper->registerHandler(mBufferingMonitor);
- }
-
- mBufferingMonitor->ensureCacheIsFetching();
- mBufferingMonitor->restartPollBuffering();
+ mCachedSource->resumeFetchingIfNecessary();
+ mPreparing = true;
+ schedulePollBuffering();
} else {
notifyPrepared();
}
+
+ if (mAudioTrack.mSource != NULL) {
+ postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
+ }
+
+ if (mVideoTrack.mSource != NULL) {
+ postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
+ }
}
void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) {
if (err != OK) {
- {
- sp<DataSource> dataSource = mDataSource;
- sp<NuCachedSource2> cachedSource = mCachedSource;
- sp<DataSource> httpSource = mHttpSource;
- {
- Mutex::Autolock _l(mDisconnectLock);
- mDataSource.clear();
- mCachedSource.clear();
- mHttpSource.clear();
- }
- }
- mBitrate = -1;
+ mDataSource.clear();
+ mCachedSource.clear();
+ mHttpSource.clear();
- mBufferingMonitor->cancelPollBuffering();
+ mBitrate = -1;
+ mPrevBufferPercentage = -1;
+ ++mPollBufferingGeneration;
}
notifyPrepared(err);
}
void NuPlayer::GenericSource::start() {
+ Mutex::Autolock _l(mLock);
ALOGI("start");
- mStopRead = false;
if (mAudioTrack.mSource != NULL) {
postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
}
@@ -518,28 +532,27 @@
}
mStarted = true;
-
- (new AMessage(kWhatStart, this))->post();
}
void NuPlayer::GenericSource::stop() {
+ Mutex::Autolock _l(mLock);
mStarted = false;
}
void NuPlayer::GenericSource::pause() {
+ Mutex::Autolock _l(mLock);
mStarted = false;
}
void NuPlayer::GenericSource::resume() {
+ Mutex::Autolock _l(mLock);
mStarted = true;
-
- (new AMessage(kWhatResume, this))->post();
}
void NuPlayer::GenericSource::disconnect() {
sp<DataSource> dataSource, httpSource;
{
- Mutex::Autolock _l(mDisconnectLock);
+ Mutex::Autolock _l(mLock);
dataSource = mDataSource;
httpSource = mHttpSource;
}
@@ -558,7 +571,24 @@
return OK;
}
+void NuPlayer::GenericSource::sendCacheStats() {
+ int32_t kbps = 0;
+ status_t err = UNKNOWN_ERROR;
+
+ if (mCachedSource != NULL) {
+ err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
+ }
+
+ if (err == OK) {
+ sp<AMessage> notify = dupNotify();
+ notify->setInt32("what", kWhatCacheStats);
+ notify->setInt32("bandwidth", kbps);
+ notify->post();
+ }
+}
+
void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
+ Mutex::Autolock _l(mLock);
switch (msg->what()) {
case kWhatPrepareAsync:
{
@@ -627,6 +657,8 @@
track->mSource = source;
track->mSource->start();
track->mIndex = trackIndex;
+ ++mAudioDataGeneration;
+ ++mVideoDataGeneration;
int64_t timeUs, actualTimeUs;
const bool formatChange = true;
@@ -644,68 +676,19 @@
break;
}
- case kWhatStart:
- case kWhatResume:
- {
- mBufferingMonitor->restartPollBuffering();
- break;
- }
-
- case kWhatGetFormat:
- {
- onGetFormatMeta(msg);
- break;
- }
-
- case kWhatGetSelectedTrack:
- {
- onGetSelectedTrack(msg);
- break;
- }
-
- case kWhatGetTrackInfo:
- {
- onGetTrackInfo(msg);
- break;
- }
-
- case kWhatSelectTrack:
- {
- onSelectTrack(msg);
- break;
- }
-
- case kWhatSeek:
- {
- onSeek(msg);
- break;
- }
-
case kWhatReadBuffer:
{
onReadBuffer(msg);
break;
}
- case kWhatPrepareDrm:
+ case kWhatPollBuffering:
{
- 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();
- sp<AMessage> response = new AMessage;
- response->setInt32("status", status);
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
+ int32_t generation;
+ CHECK(msg->findInt32("generation", &generation));
+ if (generation == mPollBufferingGeneration) {
+ onPollBuffering();
+ }
break;
}
@@ -820,34 +803,11 @@
}
sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
- sp<AMessage> msg = new AMessage(kWhatGetFormat, this);
- msg->setInt32("audio", audio);
-
- sp<AMessage> response;
- sp<RefBase> format;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findObject("format", &format));
- return static_cast<MetaData*>(format.get());
- } else {
- return NULL;
- }
+ Mutex::Autolock _l(mLock);
+ return getFormatMeta_l(audio);
}
-void NuPlayer::GenericSource::onGetFormatMeta(const sp<AMessage>& msg) const {
- int32_t audio;
- CHECK(msg->findInt32("audio", &audio));
-
- sp<AMessage> response = new AMessage;
- sp<MetaData> format = doGetFormatMeta(audio);
- response->setObject("format", format);
-
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
-}
-
-sp<MetaData> NuPlayer::GenericSource::doGetFormatMeta(bool audio) const {
+sp<MetaData> NuPlayer::GenericSource::getFormatMeta_l(bool audio) {
sp<IMediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
if (source == NULL) {
@@ -859,6 +819,7 @@
status_t NuPlayer::GenericSource::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).
@@ -884,10 +845,30 @@
status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
- // start pulling in more buffers if we only have one (or no) buffer left
+ // start pulling in more buffers if cache is running low
// so that decoder has less chance of being starved
- if (track->mPackets->getAvailableBufferCount(&finalResult) < 2) {
- postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
+ 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);
+ int64_t restartBufferingMarkUs =
+ mBufferingSettings.mRebufferingWatermarkHighMs * 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) {
+ mCachedSource->resumeFetchingIfNecessary();
+ sendCacheStats();
+ mSentPauseOnBuffering = true;
+ sp<AMessage> notify = dupNotify();
+ notify->setInt32("what", kWhatPauseOnBufferingStart);
+ notify->post();
+ }
+ }
}
if (result != OK) {
@@ -907,7 +888,6 @@
CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
if (audio) {
mAudioLastDequeueTimeUs = timeUs;
- mBufferingMonitor->updateDequeuedBufferTime(timeUs);
} else {
mVideoLastDequeueTimeUs = timeUs;
}
@@ -932,43 +912,18 @@
}
status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
+ Mutex::Autolock _l(mLock);
*durationUs = mDurationUs;
return OK;
}
size_t NuPlayer::GenericSource::getTrackCount() const {
+ Mutex::Autolock _l(mLock);
return mSources.size();
}
sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const {
- sp<AMessage> msg = new AMessage(kWhatGetTrackInfo, this);
- msg->setSize("trackIndex", trackIndex);
-
- sp<AMessage> response;
- sp<RefBase> format;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findObject("format", &format));
- return static_cast<AMessage*>(format.get());
- } else {
- return NULL;
- }
-}
-
-void NuPlayer::GenericSource::onGetTrackInfo(const sp<AMessage>& msg) const {
- size_t trackIndex;
- CHECK(msg->findSize("trackIndex", &trackIndex));
-
- sp<AMessage> response = new AMessage;
- sp<AMessage> format = doGetTrackInfo(trackIndex);
- response->setObject("format", format);
-
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
-}
-
-sp<AMessage> NuPlayer::GenericSource::doGetTrackInfo(size_t trackIndex) const {
+ Mutex::Autolock _l(mLock);
size_t trackCount = mSources.size();
if (trackIndex >= trackCount) {
return NULL;
@@ -1018,35 +973,7 @@
}
ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const {
- sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, this);
- msg->setInt32("type", type);
-
- sp<AMessage> response;
- int32_t index;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("index", &index));
- return index;
- } else {
- return -1;
- }
-}
-
-void NuPlayer::GenericSource::onGetSelectedTrack(const sp<AMessage>& msg) const {
- int32_t tmpType;
- CHECK(msg->findInt32("type", &tmpType));
- media_track_type type = (media_track_type)tmpType;
-
- sp<AMessage> response = new AMessage;
- ssize_t index = doGetSelectedTrack(type);
- response->setInt32("index", index);
-
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
-}
-
-ssize_t NuPlayer::GenericSource::doGetSelectedTrack(media_track_type type) const {
+ Mutex::Autolock _l(mLock);
const Track *track = NULL;
switch (type) {
case MEDIA_TRACK_TYPE_VIDEO:
@@ -1073,38 +1000,9 @@
}
status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select, int64_t timeUs) {
+ Mutex::Autolock _l(mLock);
ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex);
- sp<AMessage> msg = new AMessage(kWhatSelectTrack, this);
- msg->setInt32("trackIndex", trackIndex);
- msg->setInt32("select", select);
- msg->setInt64("timeUs", timeUs);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err == OK && response != NULL) {
- CHECK(response->findInt32("err", &err));
- }
-
- return err;
-}
-
-void NuPlayer::GenericSource::onSelectTrack(const sp<AMessage>& msg) {
- int32_t trackIndex, select;
- int64_t timeUs;
- CHECK(msg->findInt32("trackIndex", &trackIndex));
- CHECK(msg->findInt32("select", &select));
- CHECK(msg->findInt64("timeUs", &timeUs));
-
- sp<AMessage> response = new AMessage;
- status_t err = doSelectTrack(trackIndex, select, timeUs);
- response->setInt32("err", err);
-
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
-}
-
-status_t NuPlayer::GenericSource::doSelectTrack(size_t trackIndex, bool select, int64_t timeUs) {
if (trackIndex >= mSources.size()) {
return BAD_INDEX;
}
@@ -1196,46 +1094,11 @@
}
status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs, MediaPlayerSeekMode mode) {
- sp<AMessage> msg = new AMessage(kWhatSeek, this);
- msg->setInt64("seekTimeUs", 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 NuPlayer::GenericSource::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, (MediaPlayerSeekMode)mode);
- response->setInt32("err", err);
-
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
-}
-
-status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs, MediaPlayerSeekMode mode) {
- mBufferingMonitor->updateDequeuedBufferTime(-1ll);
-
- // If the Widevine source is stopped, do not attempt to read any
- // more buffers.
- //
- // TODO: revisit after widevine is removed. May be able to
- // combine mStopRead with mStarted.
- if (mStopRead) {
- return INVALID_OPERATION;
- }
+ Mutex::Autolock _l(mLock);
+ ALOGV("seekTo: %lld, %d", (long long)seekTimeUs, mode);
if (mVideoTrack.mSource != NULL) {
+ ++mVideoDataGeneration;
+
int64_t actualTimeUs;
readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, mode, &actualTimeUs);
@@ -1246,6 +1109,7 @@
}
if (mAudioTrack.mSource != NULL) {
+ ++mAudioDataGeneration;
readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs, MediaPlayerSeekMode::SEEK_CLOSEST);
mAudioLastDequeueTimeUs = seekTimeUs;
}
@@ -1260,12 +1124,8 @@
mFetchTimedTextDataGeneration++;
}
- // If currently buffering, post kWhatBufferingEnd first, so that
- // NuPlayer resumes. Otherwise, if cache hits high watermark
- // before new polling happens, no one will resume the playback.
- mBufferingMonitor->stopBufferingIfNecessary();
- mBufferingMonitor->restartPollBuffering();
-
+ ++mPollBufferingGeneration;
+ schedulePollBuffering();
return OK;
}
@@ -1368,9 +1228,29 @@
return ab;
}
-void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) {
- Mutex::Autolock _l(mReadBufferLock);
+int32_t NuPlayer::GenericSource::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 NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) {
if ((mPendingReadBufferTypes & (1 << trackType)) == 0) {
mPendingReadBufferTypes |= (1 << trackType);
sp<AMessage> msg = new AMessage(kWhatReadBuffer, this);
@@ -1383,25 +1263,13 @@
int32_t tmpType;
CHECK(msg->findInt32("trackType", &tmpType));
media_track_type trackType = (media_track_type)tmpType;
+ mPendingReadBufferTypes &= ~(1 << trackType);
readBuffer(trackType);
- {
- // only protect the variable change, as readBuffer may
- // take considerable time.
- Mutex::Autolock _l(mReadBufferLock);
- mPendingReadBufferTypes &= ~(1 << trackType);
- }
}
void NuPlayer::GenericSource::readBuffer(
media_track_type trackType, int64_t seekTimeUs, MediaPlayerSeekMode mode,
int64_t *actualTimeUs, bool formatChange) {
- // Do not read data if Widevine source is stopped
- //
- // TODO: revisit after widevine is removed. May be able to
- // combine mStopRead with mStarted.
- if (mStopRead) {
- return;
- }
Track *track;
size_t maxBuffers = 1;
switch (trackType) {
@@ -1445,10 +1313,12 @@
options.setNonBlocking();
}
+ int32_t generation = getDataGeneration(trackType);
for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
Vector<MediaBuffer *> mediaBuffers;
status_t err = NO_ERROR;
+ mLock.unlock();
if (couldReadMultiple) {
err = track->mSource->readMultiple(
&mediaBuffers, maxBuffers - numBuffers, &options);
@@ -1459,11 +1329,21 @@
mediaBuffers.push_back(mbuf);
}
}
+ mLock.lock();
options.clearNonPersistent();
size_t id = 0;
size_t count = mediaBuffers.size();
+
+ // in case track has been changed since we don't have lock for some time.
+ if (generation != getDataGeneration(trackType)) {
+ for (; id < count; ++id) {
+ mediaBuffers[id]->release();
+ }
+ break;
+ }
+
for (; id < count; ++id) {
int64_t timeUs;
MediaBuffer *mbuf = mediaBuffers[id];
@@ -1474,10 +1354,8 @@
}
if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
mAudioTimeUs = timeUs;
- mBufferingMonitor->updateQueuedTime(true /* isAudio */, timeUs);
} else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
mVideoTimeUs = timeUs;
- mBufferingMonitor->updateQueuedTime(false /* isAudio */, timeUs);
}
queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track);
@@ -1524,6 +1402,39 @@
break;
}
}
+
+ if (mIsStreaming
+ && (trackType == MEDIA_TRACK_TYPE_VIDEO || trackType == MEDIA_TRACK_TYPE_AUDIO)) {
+ status_t finalResult;
+ int64_t durationUs = track->mPackets->getBufferedDurationUs(&finalResult);
+
+ int64_t markUs = (mPreparing ? mBufferingSettings.mInitialWatermarkMs
+ : mBufferingSettings.mRebufferingWatermarkHighMs) * 1000ll;
+ if (finalResult == ERROR_END_OF_STREAM || durationUs >= markUs) {
+ if (mPreparing || mSentPauseOnBuffering) {
+ Track *counterTrack =
+ (trackType == MEDIA_TRACK_TYPE_VIDEO ? &mAudioTrack : &mVideoTrack);
+ if (counterTrack->mSource != NULL) {
+ durationUs = counterTrack->mPackets->getBufferedDurationUs(&finalResult);
+ }
+ if (finalResult == ERROR_END_OF_STREAM || durationUs >= markUs) {
+ if (mPreparing) {
+ notifyPrepared();
+ mPreparing = false;
+ } else {
+ sendCacheStats();
+ mSentPauseOnBuffering = false;
+ sp<AMessage> notify = dupNotify();
+ notify->setInt32("what", kWhatResumeOnBufferingEnd);
+ notify->post();
+ }
+ }
+ }
+ return;
+ }
+
+ postReadBuffer(trackType);
+ }
}
void NuPlayer::GenericSource::queueDiscontinuityIfNeeded(
@@ -1541,160 +1452,7 @@
}
}
-NuPlayer::GenericSource::BufferingMonitor::BufferingMonitor(const sp<AMessage> ¬ify)
- : mNotify(notify),
- mDurationUs(-1ll),
- mBitrate(-1ll),
- mIsStreaming(false),
- mAudioTimeUs(0),
- mVideoTimeUs(0),
- mPollBufferingGeneration(0),
- mPrepareBuffering(false),
- mBuffering(false),
- mPrevBufferPercentage(-1),
- mOffloadAudio(false),
- mFirstDequeuedBufferRealUs(-1ll),
- mFirstDequeuedBufferMediaUs(-1ll),
- mlastDequeuedBufferMediaUs(-1ll) {
- getDefaultBufferingSettings(&mSettings);
-}
-
-NuPlayer::GenericSource::BufferingMonitor::~BufferingMonitor() {
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::getDefaultBufferingSettings(
- BufferingSettings *buffering /* nonnull */) {
- buffering->mInitialBufferingMode = BUFFERING_MODE_TIME_ONLY;
- buffering->mRebufferingMode = BUFFERING_MODE_TIME_THEN_SIZE;
- buffering->mInitialWatermarkMs = kHighWaterMarkMs;
- buffering->mRebufferingWatermarkLowMs = kLowWaterMarkMs;
- buffering->mRebufferingWatermarkHighMs = kHighWaterMarkRebufferMs;
- buffering->mRebufferingWatermarkLowKB = kLowWaterMarkKB;
- buffering->mRebufferingWatermarkHighKB = kHighWaterMarkKB;
-
- ALOGV("BufferingMonitor::getDefaultBufferingSettings{%s}",
- buffering->toString().string());
-}
-
-status_t NuPlayer::GenericSource::BufferingMonitor::setBufferingSettings(
- const BufferingSettings &buffering) {
- ALOGV("BufferingMonitor::setBufferingSettings{%s}",
- buffering.toString().string());
-
- Mutex::Autolock _l(mLock);
- if (buffering.IsSizeBasedBufferingMode(buffering.mInitialBufferingMode)
- || (buffering.IsTimeBasedBufferingMode(buffering.mRebufferingMode)
- && buffering.mRebufferingWatermarkLowMs > buffering.mRebufferingWatermarkHighMs)
- || (buffering.IsSizeBasedBufferingMode(buffering.mRebufferingMode)
- && buffering.mRebufferingWatermarkLowKB > buffering.mRebufferingWatermarkHighKB)) {
- return BAD_VALUE;
- }
- mSettings = buffering;
- if (mSettings.mInitialBufferingMode == BUFFERING_MODE_NONE) {
- mSettings.mInitialWatermarkMs = BufferingSettings::kNoWatermark;
- }
- if (!mSettings.IsTimeBasedBufferingMode(mSettings.mRebufferingMode)) {
- mSettings.mRebufferingWatermarkLowMs = BufferingSettings::kNoWatermark;
- mSettings.mRebufferingWatermarkHighMs = INT32_MAX;
- }
- if (!mSettings.IsSizeBasedBufferingMode(mSettings.mRebufferingMode)) {
- mSettings.mRebufferingWatermarkLowKB = BufferingSettings::kNoWatermark;
- mSettings.mRebufferingWatermarkHighKB = INT32_MAX;
- }
- return OK;
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::prepare(
- const sp<NuCachedSource2> &cachedSource,
- int64_t durationUs,
- int64_t bitrate,
- bool isStreaming) {
- Mutex::Autolock _l(mLock);
- prepare_l(cachedSource, durationUs, bitrate, isStreaming);
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::stop() {
- Mutex::Autolock _l(mLock);
- prepare_l(NULL /* cachedSource */, -1 /* durationUs */,
- -1 /* bitrate */, false /* isStreaming */);
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::cancelPollBuffering() {
- Mutex::Autolock _l(mLock);
- cancelPollBuffering_l();
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::restartPollBuffering() {
- Mutex::Autolock _l(mLock);
- if (mIsStreaming) {
- cancelPollBuffering_l();
- onPollBuffering_l();
- }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::stopBufferingIfNecessary() {
- Mutex::Autolock _l(mLock);
- stopBufferingIfNecessary_l();
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::ensureCacheIsFetching() {
- Mutex::Autolock _l(mLock);
- ensureCacheIsFetching_l();
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::updateQueuedTime(bool isAudio, int64_t timeUs) {
- Mutex::Autolock _l(mLock);
- if (isAudio) {
- mAudioTimeUs = timeUs;
- } else {
- mVideoTimeUs = timeUs;
- }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::setOffloadAudio(bool offload) {
- Mutex::Autolock _l(mLock);
- mOffloadAudio = offload;
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::updateDequeuedBufferTime(int64_t mediaUs) {
- Mutex::Autolock _l(mLock);
- if (mediaUs < 0) {
- mFirstDequeuedBufferRealUs = -1ll;
- mFirstDequeuedBufferMediaUs = -1ll;
- } else if (mFirstDequeuedBufferRealUs < 0) {
- mFirstDequeuedBufferRealUs = ALooper::GetNowUs();
- mFirstDequeuedBufferMediaUs = mediaUs;
- }
- mlastDequeuedBufferMediaUs = mediaUs;
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::prepare_l(
- const sp<NuCachedSource2> &cachedSource,
- int64_t durationUs,
- int64_t bitrate,
- bool isStreaming) {
-
- mCachedSource = cachedSource;
- mDurationUs = durationUs;
- mBitrate = bitrate;
- mIsStreaming = isStreaming;
- mAudioTimeUs = 0;
- mVideoTimeUs = 0;
- mPrepareBuffering = (cachedSource != NULL);
- cancelPollBuffering_l();
- mOffloadAudio = false;
- mFirstDequeuedBufferRealUs = -1ll;
- mFirstDequeuedBufferMediaUs = -1ll;
- mlastDequeuedBufferMediaUs = -1ll;
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::cancelPollBuffering_l() {
- mBuffering = false;
- ++mPollBufferingGeneration;
- mPrevBufferPercentage = -1;
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::notifyBufferingUpdate_l(int32_t percentage) {
+void NuPlayer::GenericSource::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
@@ -1707,106 +1465,28 @@
mPrevBufferPercentage = percentage;
- ALOGV("notifyBufferingUpdate_l: buffering %d%%", percentage);
+ ALOGV("notifyBufferingUpdate: buffering %d%%", percentage);
- sp<AMessage> msg = mNotify->dup();
- msg->setInt32("what", kWhatBufferingUpdate);
- msg->setInt32("percentage", percentage);
- msg->post();
+ sp<AMessage> notify = dupNotify();
+ notify->setInt32("what", kWhatBufferingUpdate);
+ notify->setInt32("percentage", percentage);
+ notify->post();
}
-void NuPlayer::GenericSource::BufferingMonitor::startBufferingIfNecessary_l() {
- if (mPrepareBuffering) {
- return;
- }
-
- if (!mBuffering) {
- ALOGD("startBufferingIfNecessary_l");
-
- mBuffering = true;
-
- ensureCacheIsFetching_l();
- sendCacheStats_l();
-
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatPauseOnBufferingStart);
- notify->post();
- }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::stopBufferingIfNecessary_l() {
- if (mPrepareBuffering) {
- ALOGD("stopBufferingIfNecessary_l, mBuffering=%d", mBuffering);
-
- mPrepareBuffering = false;
-
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatPrepared);
- notify->setInt32("err", OK);
- notify->post();
-
- return;
- }
-
- if (mBuffering) {
- ALOGD("stopBufferingIfNecessary_l");
- mBuffering = false;
-
- sendCacheStats_l();
-
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatResumeOnBufferingEnd);
- notify->post();
- }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::sendCacheStats_l() {
- int32_t kbps = 0;
- status_t err = UNKNOWN_ERROR;
-
- if (mCachedSource != NULL) {
- err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
- }
-
- if (err == OK) {
- sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", kWhatCacheStats);
- notify->setInt32("bandwidth", kbps);
- notify->post();
- }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::ensureCacheIsFetching_l() {
- if (mCachedSource != NULL) {
- mCachedSource->resumeFetchingIfNecessary();
- }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::schedulePollBuffering_l() {
+void NuPlayer::GenericSource::schedulePollBuffering() {
sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
msg->setInt32("generation", mPollBufferingGeneration);
// Enquires buffering status every second.
msg->post(1000000ll);
}
-int64_t NuPlayer::GenericSource::BufferingMonitor::getLastReadPosition_l() {
- if (mAudioTimeUs > 0) {
- return mAudioTimeUs;
- } else if (mVideoTimeUs > 0) {
- return mVideoTimeUs;
- } else {
- return 0;
- }
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::onPollBuffering_l() {
+void NuPlayer::GenericSource::onPollBuffering() {
status_t finalStatus = UNKNOWN_ERROR;
int64_t cachedDurationUs = -1ll;
ssize_t cachedDataRemaining = -1;
if (mCachedSource != NULL) {
- cachedDataRemaining =
- mCachedSource->approxDataRemaining(&finalStatus);
+ cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus);
if (finalStatus == OK) {
off64_t size;
@@ -1824,157 +1504,49 @@
}
if (finalStatus != OK) {
- ALOGV("onPollBuffering_l: EOS (finalStatus = %d)", finalStatus);
+ ALOGV("onPollBuffering: EOS (finalStatus = %d)", finalStatus);
if (finalStatus == ERROR_END_OF_STREAM) {
- notifyBufferingUpdate_l(100);
+ notifyBufferingUpdate(100);
}
- stopBufferingIfNecessary_l();
return;
}
if (cachedDurationUs >= 0ll) {
if (mDurationUs > 0ll) {
- int64_t cachedPosUs = getLastReadPosition_l() + cachedDurationUs;
+ int64_t cachedPosUs = getLastReadPosition() + cachedDurationUs;
int percentage = 100.0 * cachedPosUs / mDurationUs;
if (percentage > 100) {
percentage = 100;
}
- notifyBufferingUpdate_l(percentage);
+ notifyBufferingUpdate(percentage);
}
- ALOGV("onPollBuffering_l: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f);
-
- if (mPrepareBuffering) {
- if (cachedDurationUs > mSettings.mInitialWatermarkMs * 1000) {
- stopBufferingIfNecessary_l();
- }
- } else if (mSettings.IsTimeBasedBufferingMode(mSettings.mRebufferingMode)) {
- if (cachedDurationUs < mSettings.mRebufferingWatermarkLowMs * 1000) {
- // Take into account the data cached in downstream components to try to avoid
- // unnecessary pause.
- if (mOffloadAudio && mFirstDequeuedBufferRealUs >= 0) {
- int64_t downStreamCacheUs =
- mlastDequeuedBufferMediaUs - mFirstDequeuedBufferMediaUs
- - (ALooper::GetNowUs() - mFirstDequeuedBufferRealUs);
- if (downStreamCacheUs > 0) {
- cachedDurationUs += downStreamCacheUs;
- }
- }
-
- if (cachedDurationUs < mSettings.mRebufferingWatermarkLowMs * 1000) {
- startBufferingIfNecessary_l();
- }
- } else if (cachedDurationUs > mSettings.mRebufferingWatermarkHighMs * 1000) {
- stopBufferingIfNecessary_l();
- }
- }
- } else if (cachedDataRemaining >= 0
- && mSettings.IsSizeBasedBufferingMode(mSettings.mRebufferingMode)) {
- ALOGV("onPollBuffering_l: cachedDataRemaining %zd bytes",
- cachedDataRemaining);
-
- if (cachedDataRemaining < (mSettings.mRebufferingWatermarkLowKB << 10)) {
- startBufferingIfNecessary_l();
- } else if (cachedDataRemaining > (mSettings.mRebufferingWatermarkHighKB << 10)) {
- stopBufferingIfNecessary_l();
- }
+ ALOGV("onPollBuffering: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f);
}
- schedulePollBuffering_l();
-}
-
-void NuPlayer::GenericSource::BufferingMonitor::onMessageReceived(const sp<AMessage> &msg) {
- switch (msg->what()) {
- case kWhatPollBuffering:
- {
- int32_t generation;
- CHECK(msg->findInt32("generation", &generation));
- Mutex::Autolock _l(mLock);
- if (generation == mPollBufferingGeneration) {
- onPollBuffering_l();
- }
- break;
- }
- default:
- TRESPASS();
- break;
- }
+ schedulePollBuffering();
}
// Modular DRM
status_t NuPlayer::GenericSource::prepareDrm(
- const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId, sp<ICrypto> *crypto)
-{
+ const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId, sp<ICrypto> *outCrypto) {
+ Mutex::Autolock _l(mLock);
ALOGV("prepareDrm");
- 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->setPointer("uuid", (void*)UUID);
- msg->setPointer("drmSessionId", (void*)&sessionId);
- msg->setPointer("crypto", (void*)crypto);
-
- sp<AMessage> response;
- status_t status = msg->postAndAwaitResponse(&response);
-
- if (status == OK && response != NULL) {
- CHECK(response->findInt32("status", &status));
- ALOGV_IF(status == OK, "prepareDrm: mCrypto: %p (%d)", crypto->get(),
- (*crypto != NULL ? (*crypto)->getStrongCount() : 0));
- ALOGD("prepareDrm ret: %d ", status);
- } else {
- ALOGE("prepareDrm err: %d", status);
- }
-
- return status;
-}
-
-status_t NuPlayer::GenericSource::releaseDrm()
-{
- ALOGV("releaseDrm");
-
- sp<AMessage> msg = new AMessage(kWhatReleaseDrm, this);
-
- // synchronous call to update the source states before the player proceedes with crypto cleanup
- sp<AMessage> response;
- status_t status = msg->postAndAwaitResponse(&response);
-
- if (status == OK && response != NULL) {
- ALOGD("releaseDrm ret: OK ");
- } else {
- ALOGE("releaseDrm err: %d", status);
- }
-
- return status;
-}
-
-status_t NuPlayer::GenericSource::onPrepareDrm(const sp<AMessage> &msg)
-{
- ALOGV("onPrepareDrm ");
-
mIsDrmProtected = false;
mIsDrmReleased = false;
mIsSecure = false;
- uint8_t *uuid;
- Vector<uint8_t> *drmSessionId;
- sp<ICrypto> *outCrypto;
- CHECK(msg->findPointer("uuid", (void**)&uuid));
- CHECK(msg->findPointer("drmSessionId", (void**)&drmSessionId));
- CHECK(msg->findPointer("crypto", (void**)&outCrypto));
-
status_t status = OK;
- sp<ICrypto> crypto = NuPlayerDrm::createCryptoAndPlugin(uuid, *drmSessionId, status);
+ sp<ICrypto> crypto = NuPlayerDrm::createCryptoAndPlugin(uuid, drmSessionId, status);
if (crypto == NULL) {
- ALOGE("onPrepareDrm: createCrypto failed. status: %d", status);
+ ALOGE("prepareDrm: createCrypto failed. status: %d", status);
return status;
}
- ALOGV("onPrepareDrm: createCryptoAndPlugin succeeded for uuid: %s",
+ ALOGV("prepareDrm: createCryptoAndPlugin succeeded for uuid: %s",
DrmUUID::toHexString(uuid).string());
*outCrypto = crypto;
@@ -1983,14 +1555,14 @@
if (mMimes.size() == 0) {
status = UNKNOWN_ERROR;
- ALOGE("onPrepareDrm: Unexpected. Must have at least one track. status: %d", status);
+ 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("onPrepareDrm: requiresSecureDecoderComponent mime: %s isSecure: %d",
+ ALOGV("prepareDrm: requiresSecureDecoderComponent mime: %s isSecure: %d",
mime, mIsSecure);
// Checking the member flags while in the looper to send out the notification.
@@ -2004,18 +1576,27 @@
FLAG_CAN_SEEK_FORWARD |
FLAG_CAN_SEEK);
+ if (status == OK) {
+ ALOGV("prepareDrm: mCrypto: %p (%d)", outCrypto->get(),
+ (*outCrypto != NULL ? (*outCrypto)->getStrongCount() : 0));
+ ALOGD("prepareDrm ret: %d ", status);
+ } else {
+ ALOGE("prepareDrm err: %d", status);
+ }
return status;
}
-status_t NuPlayer::GenericSource::onReleaseDrm()
-{
+status_t NuPlayer::GenericSource::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("onReleaseDrm: mIsDrmProtected is reset.");
+ ALOGV("releaseDrm: mIsDrmProtected is reset.");
} else {
- ALOGE("onReleaseDrm: mIsDrmProtected is already false.");
+ ALOGE("releaseDrm: mIsDrmProtected is already false.");
}
return OK;
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 8188a14..f4debc1 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -86,13 +86,11 @@
virtual bool isStreaming() const;
- virtual void setOffloadAudio(bool offload);
-
// Modular DRM
virtual void signalBufferReturned(MediaBuffer *buffer);
virtual status_t prepareDrm(
- const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId, sp<ICrypto> *crypto);
+ const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId, sp<ICrypto> *outCrypto);
virtual status_t releaseDrm();
@@ -114,17 +112,10 @@
kWhatSendTimedTextData,
kWhatChangeAVSource,
kWhatPollBuffering,
- kWhatGetFormat,
- kWhatGetSelectedTrack,
- kWhatSelectTrack,
- kWhatSeek,
kWhatReadBuffer,
kWhatStart,
kWhatResume,
kWhatSecureDecodersInstantiated,
- // Modular DRM
- kWhatPrepareDrm,
- kWhatReleaseDrm,
};
struct Track {
@@ -133,84 +124,6 @@
sp<AnotherPacketSource> mPackets;
};
- // Helper to monitor buffering status. The polling happens every second.
- // When necessary, it will send out buffering events to the player.
- struct BufferingMonitor : public AHandler {
- public:
- explicit BufferingMonitor(const sp<AMessage> ¬ify);
-
- void getDefaultBufferingSettings(BufferingSettings *buffering /* nonnull */);
- status_t setBufferingSettings(const BufferingSettings &buffering);
-
- // Set up state.
- void prepare(const sp<NuCachedSource2> &cachedSource,
- int64_t durationUs,
- int64_t bitrate,
- bool isStreaming);
- // Stop and reset buffering monitor.
- void stop();
- // Cancel the current monitor task.
- void cancelPollBuffering();
- // Restart the monitor task.
- void restartPollBuffering();
- // Stop buffering task and send out corresponding events.
- void stopBufferingIfNecessary();
- // Make sure data source is getting data.
- void ensureCacheIsFetching();
- // Update media time of just extracted buffer from data source.
- void updateQueuedTime(bool isAudio, int64_t timeUs);
-
- // Set the offload mode.
- void setOffloadAudio(bool offload);
- // Update media time of last dequeued buffer which is sent to the decoder.
- void updateDequeuedBufferTime(int64_t mediaUs);
-
- protected:
- virtual ~BufferingMonitor();
- virtual void onMessageReceived(const sp<AMessage> &msg);
-
- private:
- enum {
- kWhatPollBuffering,
- };
-
- sp<AMessage> mNotify;
-
- sp<NuCachedSource2> mCachedSource;
- int64_t mDurationUs;
- int64_t mBitrate;
- bool mIsStreaming;
-
- int64_t mAudioTimeUs;
- int64_t mVideoTimeUs;
- int32_t mPollBufferingGeneration;
- bool mPrepareBuffering;
- bool mBuffering;
- int32_t mPrevBufferPercentage;
-
- mutable Mutex mLock;
-
- BufferingSettings mSettings;
- bool mOffloadAudio;
- int64_t mFirstDequeuedBufferRealUs;
- int64_t mFirstDequeuedBufferMediaUs;
- int64_t mlastDequeuedBufferMediaUs;
-
- void prepare_l(const sp<NuCachedSource2> &cachedSource,
- int64_t durationUs,
- int64_t bitrate,
- bool isStreaming);
- void cancelPollBuffering_l();
- void notifyBufferingUpdate_l(int32_t percentage);
- void startBufferingIfNecessary_l();
- void stopBufferingIfNecessary_l();
- void sendCacheStats_l();
- void ensureCacheIsFetching_l();
- int64_t getLastReadPosition_l();
- void onPollBuffering_l();
- void schedulePollBuffering_l();
- };
-
Vector<sp<IMediaSource> > mSources;
Track mAudioTrack;
int64_t mAudioTimeUs;
@@ -221,6 +134,13 @@
Track mSubtitleTrack;
Track mTimedTextTrack;
+ 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;
@@ -243,17 +163,14 @@
sp<DataSource> mHttpSource;
sp<MetaData> mFileMeta;
bool mStarted;
- bool mStopRead;
+ bool mPreparing;
int64_t mBitrate;
- sp<BufferingMonitor> mBufferingMonitor;
uint32_t mPendingReadBufferTypes;
sp<ABuffer> mGlobalTimedText;
- mutable Mutex mReadBufferLock;
- mutable Mutex mDisconnectLock;
+ mutable Mutex mLock;
sp<ALooper> mLooper;
- sp<ALooper> mBufferingMonitorLooper;
void resetDataSource();
@@ -265,21 +182,6 @@
void finishPrepareAsync();
status_t startSources();
- void onGetFormatMeta(const sp<AMessage>& msg) const;
- sp<MetaData> doGetFormatMeta(bool audio) const;
-
- void onGetTrackInfo(const sp<AMessage>& msg) const;
- sp<AMessage> doGetTrackInfo(size_t trackIndex) const;
-
- void onGetSelectedTrack(const sp<AMessage>& msg) const;
- ssize_t doGetSelectedTrack(media_track_type type) const;
-
- void onSelectTrack(const sp<AMessage>& msg);
- status_t doSelectTrack(size_t trackIndex, bool select, int64_t timeUs);
-
- void onSeek(const sp<AMessage>& msg);
- status_t doSeek(int64_t seekTimeUs, MediaPlayerSeekMode mode);
-
void onPrepareAsync();
void fetchTextData(
@@ -314,6 +216,15 @@
void queueDiscontinuityIfNeeded(
bool seeking, bool formatChange, media_track_type trackType, Track *track);
+ void schedulePollBuffering();
+ void onPollBuffering();
+ void notifyBufferingUpdate(int32_t percentage);
+
+ void sendCacheStats();
+
+ 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;
@@ -322,8 +233,6 @@
Vector<String8> mMimes;
status_t checkDrmInfo();
- status_t onPrepareDrm(const sp<AMessage> &msg);
- status_t onReleaseDrm();
DISALLOW_EVIL_CONSTRUCTORS(GenericSource);
};
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 2b09479..d9fdfe3 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -28,8 +28,6 @@
#include <media/stagefright/ACodec.h>
-#include <binder/MemoryDealer.h>
-
#include <media/stagefright/foundation/avc_utils.h>
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/foundation/ABuffer.h>
@@ -575,8 +573,6 @@
memset(&mLastNativeWindowCrop, 0, sizeof(mLastNativeWindowCrop));
changeState(mUninitializedState);
-
- mTrebleFlag = false;
}
ACodec::~ACodec() {
@@ -828,11 +824,7 @@
status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) {
CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
- if (getTrebleFlag()) {
- CHECK(mAllocator[portIndex] == NULL);
- } else {
- CHECK(mDealer[portIndex] == NULL);
- }
+ CHECK(mAllocator[portIndex] == NULL);
CHECK(mBuffers[portIndex].isEmpty());
status_t err;
@@ -874,7 +866,10 @@
}
}
- size_t alignment = MemoryDealer::getAllocationAlignment();
+ size_t alignment = 32; // This is the value currently returned by
+ // MemoryDealer::getAllocationAlignment().
+ // TODO: Fix this when Treble has
+ // MemoryHeap/MemoryDealer.
ALOGV("[%s] Allocating %u buffers of size %zu (from %u using %s) on %s port",
mComponentName.c_str(),
@@ -896,18 +891,15 @@
}
if (mode != IOMX::kPortModePresetSecureBuffer) {
- if (getTrebleFlag()) {
- mAllocator[portIndex] = TAllocator::getService("ashmem");
- if (mAllocator[portIndex] == nullptr) {
- ALOGE("hidl allocator on port %d is null",
- (int)portIndex);
- return NO_MEMORY;
- }
- } else {
- size_t totalSize = def.nBufferCountActual *
- (alignedSize + alignedConvSize);
- mDealer[portIndex] = new MemoryDealer(totalSize, "ACodec");
+ mAllocator[portIndex] = TAllocator::getService("ashmem");
+ if (mAllocator[portIndex] == nullptr) {
+ ALOGE("hidl allocator on port %d is null",
+ (int)portIndex);
+ return NO_MEMORY;
}
+ // TODO: When Treble has MemoryHeap/MemoryDealer, we should
+ // specify the heap size to be
+ // def.nBufferCountActual * (alignedSize + alignedConvSize).
}
const sp<AMessage> &format =
@@ -936,23 +928,55 @@
: new SecureBuffer(format, native_handle, bufSize);
info.mCodecData = info.mData;
} else {
- if (getTrebleFlag()) {
+ bool success;
+ auto transStatus = mAllocator[portIndex]->allocate(
+ bufSize,
+ [&success, &hidlMemToken](
+ bool s,
+ hidl_memory const& m) {
+ success = s;
+ hidlMemToken = m;
+ });
+
+ if (!transStatus.isOk()) {
+ ALOGE("hidl's AshmemAllocator failed at the "
+ "transport: %s",
+ transStatus.description().c_str());
+ return NO_MEMORY;
+ }
+ if (!success) {
+ return NO_MEMORY;
+ }
+ hidlMem = mapMemory(hidlMemToken);
+ if (hidlMem == nullptr) {
+ return NO_MEMORY;
+ }
+ err = mOMXNode->useBuffer(
+ portIndex, hidlMemToken, &info.mBufferID);
+
+ if (mode == IOMX::kPortModeDynamicANWBuffer) {
+ VideoNativeMetadata* metaData = (VideoNativeMetadata*)(
+ (void*)hidlMem->getPointer());
+ metaData->nFenceFd = -1;
+ }
+
+ info.mCodecData = new SharedMemoryBuffer(
+ format, hidlMem);
+ info.mCodecRef = hidlMem;
+
+ // if we require conversion, allocate conversion buffer for client use;
+ // otherwise, reuse codec buffer
+ if (mConverter[portIndex] != NULL) {
+ CHECK_GT(conversionBufferSize, (size_t)0);
bool success;
- auto transStatus = mAllocator[portIndex]->allocate(
- bufSize,
+ mAllocator[portIndex]->allocate(
+ conversionBufferSize,
[&success, &hidlMemToken](
bool s,
hidl_memory const& m) {
success = s;
hidlMemToken = m;
});
-
- if (!transStatus.isOk()) {
- ALOGE("hidl's AshmemAllocator failed at the "
- "transport: %s",
- transStatus.description().c_str());
- return NO_MEMORY;
- }
if (!success) {
return NO_MEMORY;
}
@@ -960,67 +984,8 @@
if (hidlMem == nullptr) {
return NO_MEMORY;
}
- err = mOMXNode->useBuffer(
- portIndex, hidlMemToken, &info.mBufferID);
- } else {
- mem = mDealer[portIndex]->allocate(bufSize);
- if (mem == NULL || mem->pointer() == NULL) {
- return NO_MEMORY;
- }
-
- err = mOMXNode->useBuffer(
- portIndex, mem, &info.mBufferID);
- }
-
- if (mode == IOMX::kPortModeDynamicANWBuffer) {
- VideoNativeMetadata* metaData = (VideoNativeMetadata*)(
- getTrebleFlag() ?
- (void*)hidlMem->getPointer() : mem->pointer());
- metaData->nFenceFd = -1;
- }
-
- if (getTrebleFlag()) {
- info.mCodecData = new SharedMemoryBuffer(
- format, hidlMem);
- info.mCodecRef = hidlMem;
- } else {
- info.mCodecData = new SharedMemoryBuffer(
- format, mem);
- info.mCodecRef = mem;
- }
-
- // if we require conversion, allocate conversion buffer for client use;
- // otherwise, reuse codec buffer
- if (mConverter[portIndex] != NULL) {
- CHECK_GT(conversionBufferSize, (size_t)0);
- if (getTrebleFlag()) {
- bool success;
- mAllocator[portIndex]->allocate(
- conversionBufferSize,
- [&success, &hidlMemToken](
- bool s,
- hidl_memory const& m) {
- success = s;
- hidlMemToken = m;
- });
- if (!success) {
- return NO_MEMORY;
- }
- hidlMem = mapMemory(hidlMemToken);
- if (hidlMem == nullptr) {
- return NO_MEMORY;
- }
- info.mData = new SharedMemoryBuffer(format, hidlMem);
- info.mMemRef = hidlMem;
- } else {
- mem = mDealer[portIndex]->allocate(
- conversionBufferSize);
- if (mem == NULL|| mem->pointer() == NULL) {
- return NO_MEMORY;
- }
- info.mData = new SharedMemoryBuffer(format, mem);
- info.mMemRef = mem;
- }
+ info.mData = new SharedMemoryBuffer(format, hidlMem);
+ info.mMemRef = hidlMem;
} else {
info.mData = info.mCodecData;
info.mMemRef = info.mCodecRef;
@@ -1581,11 +1546,7 @@
}
}
- if (getTrebleFlag()) {
- mAllocator[portIndex].clear();
- } else {
- mDealer[portIndex].clear();
- }
+ mAllocator[portIndex].clear();
return err;
}
@@ -3781,6 +3742,8 @@
} else {
mFps = (double)framerate;
}
+ // propagate framerate to the output so that the muxer has it
+ outputFormat->setInt32("frame-rate", (int32_t)mFps);
video_def->xFramerate = (OMX_U32)(mFps * 65536);
video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
@@ -6249,13 +6212,8 @@
if (mDeathNotifier != NULL) {
if (mCodec->mOMXNode != NULL) {
- if (mCodec->getTrebleFlag()) {
- auto tOmxNode = mCodec->mOMXNode->getHalInterface();
- tOmxNode->unlinkToDeath(mDeathNotifier);
- } else {
- sp<IBinder> binder = IInterface::asBinder(mCodec->mOMXNode);
- binder->unlinkToDeath(mDeathNotifier);
- }
+ auto tOmxNode = mCodec->mOMXNode->getHalInterface();
+ tOmxNode->unlinkToDeath(mDeathNotifier);
}
mDeathNotifier.clear();
}
@@ -6403,8 +6361,7 @@
componentName = matchingCodecs[matchIndex];
OMXClient client;
- bool trebleFlag;
- if (client.connect(owners[matchIndex].c_str(), &trebleFlag) != OK) {
+ if (client.connect(owners[matchIndex].c_str()) != OK) {
mCodec->signalError(OMX_ErrorUndefined, NO_INIT);
return false;
}
@@ -6417,7 +6374,6 @@
androidSetThreadPriority(tid, prevPriority);
if (err == OK) {
- mCodec->setTrebleFlag(trebleFlag);
break;
} else {
ALOGW("Allocating component '%s' failed, try next one.", componentName.c_str());
@@ -6439,17 +6395,9 @@
}
mDeathNotifier = new DeathNotifier(notify);
- if (mCodec->getTrebleFlag()) {
- auto tOmxNode = omxNode->getHalInterface();
- if (!tOmxNode->linkToDeath(mDeathNotifier, 0)) {
- mDeathNotifier.clear();
- }
- } else {
- if (IInterface::asBinder(omxNode)->linkToDeath(mDeathNotifier) != OK) {
- // This was a local binder, if it dies so do we, we won't care
- // about any notifications in the afterlife.
- mDeathNotifier.clear();
- }
+ auto tOmxNode = omxNode->getHalInterface();
+ if (!tOmxNode->linkToDeath(mDeathNotifier, 0)) {
+ mDeathNotifier.clear();
}
notify = new AMessage(kWhatOMXMessageList, mCodec);
@@ -7856,11 +7804,7 @@
mCodec->mBuffers[kPortIndexOutput].size());
err = FAILED_TRANSACTION;
} else {
- if (mCodec->getTrebleFlag()) {
- mCodec->mAllocator[kPortIndexOutput].clear();
- } else {
- mCodec->mDealer[kPortIndexOutput].clear();
- }
+ mCodec->mAllocator[kPortIndexOutput].clear();
}
if (err == OK) {
@@ -8462,12 +8406,4 @@
return OK;
}
-void ACodec::setTrebleFlag(bool trebleFlag) {
- mTrebleFlag = trebleFlag;
-}
-
-bool ACodec::getTrebleFlag() const {
- return mTrebleFlag;
-}
-
} // namespace android
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index 4feba37..54265a4 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -24,7 +24,6 @@
#include <media/IMediaCodecList.h>
#include <media/IMediaPlayerService.h>
-#include <media/IMediaCodecService.h>
#include <media/MediaCodecInfo.h>
#include <media/stagefright/foundation/ADebug.h>
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 25656c3..648aa77 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -40,13 +40,23 @@
namespace android {
+NuMediaExtractor::Sample::Sample()
+ : mBuffer(NULL),
+ mSampleTimeUs(-1ll) {
+}
+
+NuMediaExtractor::Sample::Sample(MediaBuffer *buffer, int64_t timeUs)
+ : mBuffer(buffer),
+ mSampleTimeUs(timeUs) {
+}
+
NuMediaExtractor::NuMediaExtractor()
: mTotalBitrate(-1ll),
mDurationUs(-1ll) {
}
NuMediaExtractor::~NuMediaExtractor() {
- releaseTrackSamples();
+ releaseAllTrackSamples();
for (size_t i = 0; i < mSelectedTracks.size(); ++i) {
TrackInfo *info = &mSelectedTracks.editItemAt(i);
@@ -288,7 +298,8 @@
return OK;
}
-status_t NuMediaExtractor::selectTrack(size_t index) {
+status_t NuMediaExtractor::selectTrack(size_t index,
+ int64_t startTimeUs, MediaSource::ReadOptions::SeekMode mode) {
Mutex::Autolock autoLock(mLock);
if (mImpl == NULL) {
@@ -311,31 +322,56 @@
sp<IMediaSource> source = mImpl->getTrack(index);
if (source == nullptr) {
+ ALOGE("track %zu is empty", index);
return ERROR_MALFORMED;
}
status_t ret = source->start();
if (ret != OK) {
+ ALOGE("track %zu failed to start", index);
return ret;
}
+ sp<MetaData> meta = source->getFormat();
+ if (meta == NULL) {
+ ALOGE("track %zu has no meta data", index);
+ return ERROR_MALFORMED;
+ }
+
+ const char *mime;
+ if (!meta->findCString(kKeyMIMEType, &mime)) {
+ ALOGE("track %zu has no mime type in meta data", index);
+ return ERROR_MALFORMED;
+ }
+ ALOGV("selectTrack, track[%zu]: %s", index, mime);
+
mSelectedTracks.push();
TrackInfo *info = &mSelectedTracks.editItemAt(mSelectedTracks.size() - 1);
info->mSource = source;
info->mTrackIndex = index;
+ if (!strncasecmp(mime, "audio/", 6)) {
+ info->mTrackType = MEDIA_TRACK_TYPE_AUDIO;
+ info->mMaxFetchCount = 64;
+ } else if (!strncasecmp(mime, "video/", 6)) {
+ info->mTrackType = MEDIA_TRACK_TYPE_VIDEO;
+ info->mMaxFetchCount = 8;
+ } else {
+ info->mTrackType = MEDIA_TRACK_TYPE_UNKNOWN;
+ info->mMaxFetchCount = 1;
+ }
info->mFinalResult = OK;
- info->mSample = NULL;
- info->mSampleTimeUs = -1ll;
+ releaseTrackSamples(info);
info->mTrackFlags = 0;
- const char *mime;
- CHECK(source->getFormat()->findCString(kKeyMIMEType, &mime));
-
if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
info->mTrackFlags |= kIsVorbis;
}
+ if (startTimeUs >= 0) {
+ fetchTrackSamples(info, startTimeUs, mode);
+ }
+
return OK;
}
@@ -366,12 +402,7 @@
TrackInfo *info = &mSelectedTracks.editItemAt(i);
- if (info->mSample != NULL) {
- info->mSample->release();
- info->mSample = NULL;
-
- info->mSampleTimeUs = -1ll;
- }
+ releaseTrackSamples(info);
CHECK_EQ((status_t)OK, info->mSource->stop());
@@ -380,79 +411,136 @@
return OK;
}
-void NuMediaExtractor::releaseTrackSamples() {
- for (size_t i = 0; i < mSelectedTracks.size(); ++i) {
- TrackInfo *info = &mSelectedTracks.editItemAt(i);
+void NuMediaExtractor::releaseOneSample(TrackInfo *info) {
+ if (info == NULL || info->mSamples.empty()) {
+ return;
+ }
- if (info->mSample != NULL) {
- info->mSample->release();
- info->mSample = NULL;
+ auto it = info->mSamples.begin();
+ if (it->mBuffer != NULL) {
+ it->mBuffer->release();
+ }
+ info->mSamples.erase(it);
+}
- info->mSampleTimeUs = -1ll;
+void NuMediaExtractor::releaseTrackSamples(TrackInfo *info) {
+ if (info == NULL) {
+ return;
+ }
+
+ auto it = info->mSamples.begin();
+ while (it != info->mSamples.end()) {
+ if (it->mBuffer != NULL) {
+ it->mBuffer->release();
}
+ it = info->mSamples.erase(it);
}
}
-ssize_t NuMediaExtractor::fetchTrackSamples(
+void NuMediaExtractor::releaseAllTrackSamples() {
+ for (size_t i = 0; i < mSelectedTracks.size(); ++i) {
+ releaseTrackSamples(&mSelectedTracks.editItemAt(i));
+ }
+}
+
+ssize_t NuMediaExtractor::fetchAllTrackSamples(
int64_t seekTimeUs, MediaSource::ReadOptions::SeekMode mode) {
TrackInfo *minInfo = NULL;
ssize_t minIndex = -1;
for (size_t i = 0; i < mSelectedTracks.size(); ++i) {
TrackInfo *info = &mSelectedTracks.editItemAt(i);
+ fetchTrackSamples(info, seekTimeUs, mode);
- if (seekTimeUs >= 0ll) {
- info->mFinalResult = OK;
-
- if (info->mSample != NULL) {
- info->mSample->release();
- info->mSample = NULL;
- info->mSampleTimeUs = -1ll;
- }
- } else if (info->mFinalResult != OK) {
+ if (info->mSamples.empty()) {
continue;
}
- if (info->mSample == NULL) {
- MediaSource::ReadOptions options;
- if (seekTimeUs >= 0ll) {
- options.setSeekTo(seekTimeUs, mode);
- }
- status_t err = info->mSource->read(&info->mSample, &options);
-
- if (err != OK) {
- CHECK(info->mSample == NULL);
-
- info->mFinalResult = err;
-
- if (info->mFinalResult != ERROR_END_OF_STREAM) {
- ALOGW("read on track %zu failed with error %d",
- info->mTrackIndex, err);
- }
-
- info->mSampleTimeUs = -1ll;
- continue;
- } else {
- CHECK(info->mSample != NULL);
- CHECK(info->mSample->meta_data()->findInt64(
- kKeyTime, &info->mSampleTimeUs));
- }
- }
-
- if (minInfo == NULL || info->mSampleTimeUs < minInfo->mSampleTimeUs) {
+ if (minInfo == NULL) {
minInfo = info;
minIndex = i;
+ } else {
+ auto it = info->mSamples.begin();
+ auto itMin = minInfo->mSamples.begin();
+ if (it->mSampleTimeUs < itMin->mSampleTimeUs) {
+ minInfo = info;
+ minIndex = i;
+ }
}
}
return minIndex;
}
+void NuMediaExtractor::fetchTrackSamples(TrackInfo *info,
+ int64_t seekTimeUs, MediaSource::ReadOptions::SeekMode mode) {
+ if (info == NULL) {
+ return;
+ }
+
+ MediaSource::ReadOptions options;
+ if (seekTimeUs >= 0ll) {
+ options.setSeekTo(seekTimeUs, mode);
+ info->mFinalResult = OK;
+ releaseTrackSamples(info);
+ } else if (info->mFinalResult != OK || !info->mSamples.empty()) {
+ return;
+ }
+
+ status_t err = OK;
+ Vector<MediaBuffer *> mediaBuffers;
+ if (info->mSource->supportReadMultiple()) {
+ options.setNonBlocking();
+ err = info->mSource->readMultiple(&mediaBuffers, info->mMaxFetchCount, &options);
+ } else {
+ MediaBuffer *mbuf = NULL;
+ err = info->mSource->read(&mbuf, &options);
+ if (err == OK && mbuf != NULL) {
+ mediaBuffers.push_back(mbuf);
+ }
+ }
+
+ info->mFinalResult = err;
+ if (err != OK && err != ERROR_END_OF_STREAM) {
+ ALOGW("read on track %zu failed with error %d", info->mTrackIndex, err);
+ size_t count = mediaBuffers.size();
+ for (size_t id = 0; id < count; ++id) {
+ MediaBuffer *mbuf = mediaBuffers[id];
+ if (mbuf != NULL) {
+ mbuf->release();
+ }
+ }
+ return;
+ }
+
+ size_t count = mediaBuffers.size();
+ bool releaseRemaining = false;
+ for (size_t id = 0; id < count; ++id) {
+ int64_t timeUs;
+ MediaBuffer *mbuf = mediaBuffers[id];
+ if (mbuf == NULL) {
+ continue;
+ }
+ if (releaseRemaining) {
+ mbuf->release();
+ continue;
+ }
+ if (mbuf->meta_data()->findInt64(kKeyTime, &timeUs)) {
+ info->mSamples.emplace_back(mbuf, timeUs);
+ } else {
+ mbuf->meta_data()->dumpToLog();
+ info->mFinalResult = ERROR_MALFORMED;
+ mbuf->release();
+ releaseRemaining = true;
+ }
+ }
+}
+
status_t NuMediaExtractor::seekTo(
int64_t timeUs, MediaSource::ReadOptions::SeekMode mode) {
Mutex::Autolock autoLock(mLock);
- ssize_t minIndex = fetchTrackSamples(timeUs, mode);
+ ssize_t minIndex = fetchAllTrackSamples(timeUs, mode);
if (minIndex < 0) {
return ERROR_END_OF_STREAM;
@@ -464,7 +552,7 @@
status_t NuMediaExtractor::advance() {
Mutex::Autolock autoLock(mLock);
- ssize_t minIndex = fetchTrackSamples();
+ ssize_t minIndex = fetchAllTrackSamples();
if (minIndex < 0) {
return ERROR_END_OF_STREAM;
@@ -472,28 +560,26 @@
TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
- info->mSample->release();
- info->mSample = NULL;
- info->mSampleTimeUs = -1ll;
+ releaseOneSample(info);
return OK;
}
-status_t NuMediaExtractor::appendVorbisNumPageSamples(TrackInfo *info, const sp<ABuffer> &buffer) {
+status_t NuMediaExtractor::appendVorbisNumPageSamples(MediaBuffer *mbuf, const sp<ABuffer> &buffer) {
int32_t numPageSamples;
- if (!info->mSample->meta_data()->findInt32(
+ if (!mbuf->meta_data()->findInt32(
kKeyValidSamples, &numPageSamples)) {
numPageSamples = -1;
}
- memcpy((uint8_t *)buffer->data() + info->mSample->range_length(),
+ memcpy((uint8_t *)buffer->data() + mbuf->range_length(),
&numPageSamples,
sizeof(numPageSamples));
uint32_t type;
const void *data;
size_t size, size2;
- if (info->mSample->meta_data()->findData(kKeyEncryptedSizes, &type, &data, &size)) {
+ if (mbuf->meta_data()->findData(kKeyEncryptedSizes, &type, &data, &size)) {
// Signal numPageSamples (a plain int32_t) is appended at the end,
// i.e. sizeof(numPageSamples) plain bytes + 0 encrypted bytes
if (SIZE_MAX - size < sizeof(int32_t)) {
@@ -511,9 +597,9 @@
int32_t zero = 0;
memcpy(adata, data, size);
memcpy(adata + size, &zero, sizeof(zero));
- info->mSample->meta_data()->setData(kKeyEncryptedSizes, type, adata, newSize);
+ mbuf->meta_data()->setData(kKeyEncryptedSizes, type, adata, newSize);
- if (info->mSample->meta_data()->findData(kKeyPlainSizes, &type, &data, &size2)) {
+ if (mbuf->meta_data()->findData(kKeyPlainSizes, &type, &data, &size2)) {
if (size2 != size) {
return ERROR_MALFORMED;
}
@@ -526,7 +612,7 @@
// append sizeof(numPageSamples) to plain sizes.
int32_t int32Size = sizeof(numPageSamples);
memcpy(adata + size, &int32Size, sizeof(int32Size));
- info->mSample->meta_data()->setData(kKeyPlainSizes, type, adata, newSize);
+ mbuf->meta_data()->setData(kKeyPlainSizes, type, adata, newSize);
}
return OK;
@@ -535,7 +621,7 @@
status_t NuMediaExtractor::readSampleData(const sp<ABuffer> &buffer) {
Mutex::Autolock autoLock(mLock);
- ssize_t minIndex = fetchTrackSamples();
+ ssize_t minIndex = fetchAllTrackSamples();
if (minIndex < 0) {
return ERROR_END_OF_STREAM;
@@ -543,7 +629,8 @@
TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
- size_t sampleSize = info->mSample->range_length();
+ auto it = info->mSamples.begin();
+ size_t sampleSize = it->mBuffer->range_length();
if (info->mTrackFlags & kIsVorbis) {
// Each sample's data is suffixed by the number of page samples
@@ -556,14 +643,14 @@
}
const uint8_t *src =
- (const uint8_t *)info->mSample->data()
- + info->mSample->range_offset();
+ (const uint8_t *)it->mBuffer->data()
+ + it->mBuffer->range_offset();
- memcpy((uint8_t *)buffer->data(), src, info->mSample->range_length());
+ memcpy((uint8_t *)buffer->data(), src, it->mBuffer->range_length());
status_t err = OK;
if (info->mTrackFlags & kIsVorbis) {
- err = appendVorbisNumPageSamples(info, buffer);
+ err = appendVorbisNumPageSamples(it->mBuffer, buffer);
}
if (err == OK) {
@@ -576,7 +663,7 @@
status_t NuMediaExtractor::getSampleTrackIndex(size_t *trackIndex) {
Mutex::Autolock autoLock(mLock);
- ssize_t minIndex = fetchTrackSamples();
+ ssize_t minIndex = fetchAllTrackSamples();
if (minIndex < 0) {
return ERROR_END_OF_STREAM;
@@ -591,14 +678,14 @@
status_t NuMediaExtractor::getSampleTime(int64_t *sampleTimeUs) {
Mutex::Autolock autoLock(mLock);
- ssize_t minIndex = fetchTrackSamples();
+ ssize_t minIndex = fetchAllTrackSamples();
if (minIndex < 0) {
return ERROR_END_OF_STREAM;
}
TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
- *sampleTimeUs = info->mSampleTimeUs;
+ *sampleTimeUs = info->mSamples.begin()->mSampleTimeUs;
return OK;
}
@@ -608,14 +695,14 @@
*sampleMeta = NULL;
- ssize_t minIndex = fetchTrackSamples();
+ ssize_t minIndex = fetchAllTrackSamples();
if (minIndex < 0) {
return ERROR_END_OF_STREAM;
}
TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
- *sampleMeta = info->mSample->meta_data();
+ *sampleMeta = info->mSamples.begin()->mBuffer->meta_data();
return OK;
}
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
index 5f50e46..cd07262 100644
--- a/media/libstagefright/OMXClient.cpp
+++ b/media/libstagefright/OMXClient.cpp
@@ -25,7 +25,6 @@
#include <cutils/properties.h>
#include <binder/IServiceManager.h>
-#include <media/IMediaCodecService.h>
#include <media/stagefright/OMXClient.h>
#include <media/IOMX.h>
@@ -37,71 +36,22 @@
OMXClient::OMXClient() {
}
-status_t OMXClient::connect() {
- return connect("default", nullptr);
-}
-
-status_t OMXClient::connect(bool* trebleFlag) {
- if (property_get_bool("persist.media.treble_omx", true)) {
- if (trebleFlag != nullptr) {
- *trebleFlag = true;
- }
- return connectTreble();
- }
- if (trebleFlag != nullptr) {
- *trebleFlag = false;
- }
- return connectLegacy();
-}
-
-status_t OMXClient::connect(const char* name, bool* trebleFlag) {
- if (property_get_bool("persist.media.treble_omx", true)) {
- if (trebleFlag != nullptr) {
- *trebleFlag = true;
- }
- return connectTreble(name);
- }
- if (trebleFlag != nullptr) {
- *trebleFlag = false;
- }
- return connectLegacy();
-}
-
-status_t OMXClient::connectLegacy() {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> codecbinder = sm->getService(String16("media.codec"));
- sp<IMediaCodecService> codecservice = interface_cast<IMediaCodecService>(codecbinder);
-
- if (codecservice.get() == NULL) {
- ALOGE("Cannot obtain IMediaCodecService");
- return NO_INIT;
- }
-
- mOMX = codecservice->getOMX();
- if (mOMX.get() == NULL) {
- ALOGE("Cannot obtain mediacodec IOMX");
- return NO_INIT;
- }
-
- return OK;
-}
-
-status_t OMXClient::connectTreble(const char* name) {
+status_t OMXClient::connect(const char* name) {
using namespace ::android::hardware::media::omx::V1_0;
if (name == nullptr) {
name = "default";
}
sp<IOmx> tOmx = IOmx::getService(name);
if (tOmx.get() == nullptr) {
- ALOGE("Cannot obtain Treble IOmx.");
+ ALOGE("Cannot obtain IOmx service.");
return NO_INIT;
}
if (!tOmx->isRemote()) {
- ALOGE("Treble IOmx is in passthrough mode.");
+ ALOGE("IOmx service running in passthrough mode.");
return NO_INIT;
}
mOMX = new utils::LWOmx(tOmx);
- ALOGI("Treble IOmx obtained");
+ ALOGI("IOmx service obtained");
return OK;
}
@@ -109,4 +59,8 @@
mOMX.clear();
}
+sp<IOMX> OMXClient::interface() {
+ return mOMX;
+}
+
} // namespace android
diff --git a/media/libstagefright/OmxInfoBuilder.cpp b/media/libstagefright/OmxInfoBuilder.cpp
index 063d13e..1cd8873 100644
--- a/media/libstagefright/OmxInfoBuilder.cpp
+++ b/media/libstagefright/OmxInfoBuilder.cpp
@@ -24,8 +24,6 @@
#include <utils/Log.h>
#include <cutils/properties.h>
-#include <binder/IServiceManager.h>
-#include <media/IMediaCodecService.h>
#include <media/stagefright/foundation/MediaDefs.h>
#include <media/stagefright/OmxInfoBuilder.h>
#include <media/stagefright/ACodec.h>
@@ -35,7 +33,6 @@
#include <android/hardware/media/omx/1.0/IOmxNode.h>
#include <media/stagefright/omx/OMXUtils.h>
-#include <media/IOMXStore.h>
#include <media/IOMX.h>
#include <media/omx/1.0/WOmx.h>
@@ -48,10 +45,24 @@
namespace android {
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using namespace ::android::hardware::media::omx::V1_0;
+
namespace /* unnamed */ {
+bool hasPrefix(const hidl_string& s, const char* prefix) {
+ return strncmp(s.c_str(), prefix, strlen(prefix)) == 0;
+}
+
+struct HidlStringCompare {
+ bool operator()(const hidl_string& lhs, const hidl_string& rhs) const {
+ return strcmp(lhs.c_str(), rhs.c_str()) < 0;
+ }
+};
+
status_t queryCapabilities(
- const IOMXStore::NodeInfo& node, const char* mime, bool isEncoder,
+ const IOmxStore::NodeInfo& node, const char* mime, bool isEncoder,
MediaCodecInfo::CapabilitiesWriter* caps) {
sp<ACodec> codec = new ACodec();
status_t err = codec->queryCapabilities(
@@ -62,14 +73,13 @@
for (const auto& attribute : node.attributes) {
// All features have an int32 value except
// "feature-bitrate-modes", which has a string value.
- if ((attribute.key.compare(0, 8, "feature-") == 0) &&
- (attribute.key.compare(8, 15, "bitrate-modes")
- != 0)) {
- // If this attribute.key is a feature that is not a bitrate
- // control, add an int32 value.
+ if (hasPrefix(attribute.key, "feature-") &&
+ !hasPrefix(attribute.key, "feature-bitrate-modes")) {
+ // If this attribute.key is a feature that is not bitrate modes,
+ // add an int32 value.
caps->addDetail(
attribute.key.c_str(),
- attribute.value == "1" ? 1 : 0);
+ hasPrefix(attribute.value, "1") ? 1 : 0);
} else {
// Non-feature attributes
caps->addDetail(
@@ -85,138 +95,61 @@
}
status_t OmxInfoBuilder::buildMediaCodecList(MediaCodecListWriter* writer) {
- bool treble;
- sp<IOMX> omx;
- std::vector<IOMXStore::RoleInfo> roles;
+ hidl_vec<IOmxStore::RoleInfo> roles;
- treble = property_get_bool("persist.media.treble_omx", true);
- if (treble) {
- using namespace ::android::hardware::media::omx::V1_0;
- using ::android::hardware::hidl_vec;
- using ::android::hardware::hidl_string;
-
- // Obtain IOmxStore
- sp<IOmxStore> omxStore = IOmxStore::getService();
+ // Obtain IOmxStore
+ sp<IOmxStore> omxStore = IOmxStore::tryGetService();
+ if (omxStore == nullptr) {
+ omxStore = IOmxStore::tryGetService("vendor");
if (omxStore == nullptr) {
- ALOGE("Cannot connect to an IOmxStore instance.");
- return NO_INIT;
+ omxStore = IOmxStore::tryGetService("platform");
+ if (omxStore == nullptr) {
+ ALOGE("Cannot find an IOmxStore service.");
+ return NO_INIT;
+ }
}
+ }
- // List service attributes (global settings)
- Status status;
- hidl_vec<IOmxStore::ServiceAttribute> serviceAttributes;
- auto transStatus = omxStore->listServiceAttributes(
- [&status, &serviceAttributes]
- (Status inStatus, const hidl_vec<IOmxStore::ServiceAttribute>&
- inAttributes) {
- status = inStatus;
- serviceAttributes = inAttributes;
- });
- if (!transStatus.isOk()) {
- ALOGE("Fail to obtain global settings from IOmxStore.");
- return NO_INIT;
- }
- if (status != Status::OK) {
- ALOGE("IOmxStore reports parsing error.");
- return NO_INIT;
- }
- for (const auto& p : serviceAttributes) {
- writer->addGlobalSetting(
- p.key.c_str(), p.value.c_str());
- }
+ // List service attributes (global settings)
+ Status status;
+ hidl_vec<IOmxStore::ServiceAttribute> serviceAttributes;
+ auto transStatus = omxStore->listServiceAttributes(
+ [&status, &serviceAttributes] (
+ Status inStatus,
+ const hidl_vec<IOmxStore::ServiceAttribute>& inAttributes) {
+ status = inStatus;
+ serviceAttributes = inAttributes;
+ });
+ if (!transStatus.isOk()) {
+ ALOGE("Fail to obtain global settings from IOmxStore.");
+ return NO_INIT;
+ }
+ if (status != Status::OK) {
+ ALOGE("IOmxStore reports parsing error.");
+ return NO_INIT;
+ }
+ for (const auto& p : serviceAttributes) {
+ writer->addGlobalSetting(
+ p.key.c_str(), p.value.c_str());
+ }
- // List roles and convert to IOMXStore's format
- transStatus = omxStore->listRoles(
- [&roles]
- (const hidl_vec<IOmxStore::RoleInfo>& inRoleList) {
- roles.reserve(inRoleList.size());
- for (const auto& inRole : inRoleList) {
- IOMXStore::RoleInfo role;
- role.role = inRole.role;
- role.type = inRole.type;
- role.isEncoder = inRole.isEncoder;
- role.preferPlatformNodes = inRole.preferPlatformNodes;
- std::vector<IOMXStore::NodeInfo>& nodes =
- role.nodes;
- nodes.reserve(inRole.nodes.size());
- for (const auto& inNode : inRole.nodes) {
- IOMXStore::NodeInfo node;
- node.name = inNode.name;
- node.owner = inNode.owner;
- std::vector<IOMXStore::Attribute>& attributes =
- node.attributes;
- attributes.reserve(inNode.attributes.size());
- for (const auto& inAttr : inNode.attributes) {
- IOMXStore::Attribute attr;
- attr.key = inAttr.key;
- attr.value = inAttr.value;
- attributes.push_back(std::move(attr));
- }
- nodes.push_back(std::move(node));
- }
- roles.push_back(std::move(role));
- }
- });
- if (!transStatus.isOk()) {
- ALOGE("Fail to obtain codec roles from IOmxStore.");
- return NO_INIT;
- }
- } else {
- // Obtain IOMXStore
- sp<IServiceManager> sm = defaultServiceManager();
- if (sm == nullptr) {
- ALOGE("Cannot obtain the default service manager.");
- return NO_INIT;
- }
- sp<IBinder> codecBinder = sm->getService(String16("media.codec"));
- if (codecBinder == nullptr) {
- ALOGE("Cannot obtain the media codec service.");
- return NO_INIT;
- }
- sp<IMediaCodecService> codecService =
- interface_cast<IMediaCodecService>(codecBinder);
- if (codecService == nullptr) {
- ALOGE("Wrong type of media codec service obtained.");
- return NO_INIT;
- }
- omx = codecService->getOMX();
- if (omx == nullptr) {
- ALOGE("Cannot connect to an IOMX instance.");
- }
- sp<IOMXStore> omxStore = codecService->getOMXStore();
- if (omxStore == nullptr) {
- ALOGE("Cannot connect to an IOMXStore instance.");
- return NO_INIT;
- }
-
- // List service attributes (global settings)
- std::vector<IOMXStore::Attribute> serviceAttributes;
- status_t status = omxStore->listServiceAttributes(&serviceAttributes);
- if (status != OK) {
- ALOGE("Fail to obtain global settings from IOMXStore.");
- return NO_INIT;
- }
- for (const auto& p : serviceAttributes) {
- writer->addGlobalSetting(
- p.key.c_str(), p.value.c_str());
- }
-
- // List roles
- status = omxStore->listRoles(&roles);
- if (status != OK) {
- ALOGE("Fail to obtain codec roles from IOMXStore.");
- return NO_INIT;
- }
+ transStatus = omxStore->listRoles(
+ [&roles] (
+ const hidl_vec<IOmxStore::RoleInfo>& inRoleList) {
+ roles = inRoleList;
+ });
+ if (!transStatus.isOk()) {
+ ALOGE("Fail to obtain codec roles from IOmxStore.");
+ return NO_INIT;
}
// Convert roles to lists of codecs
- // codec name -> index into swCodecs
- std::map<std::string, std::unique_ptr<MediaCodecInfoWriter> >
- swCodecName2Info;
- // codec name -> index into hwCodecs
- std::map<std::string, std::unique_ptr<MediaCodecInfoWriter> >
- hwCodecName2Info;
+ // codec name -> index into swCodecs/hwCodecs
+ std::map<hidl_string,
+ std::unique_ptr<MediaCodecInfoWriter>,
+ HidlStringCompare>
+ swCodecName2Info, hwCodecName2Info;
// owner name -> MediaCodecInfo
// This map will be used to obtain the correct IOmx service(s) needed for
// creating IOmxNode instances and querying capabilities.
@@ -230,10 +163,10 @@
// If preferPlatformNodes is true, hardware nodes must be added after
// platform (software) nodes. hwCodecs is used to hold hardware nodes
// that need to be added after software nodes for the same role.
- std::vector<const IOMXStore::NodeInfo*> hwCodecs;
+ std::vector<const IOmxStore::NodeInfo*> hwCodecs;
for (const auto& node : role.nodes) {
const auto& nodeName = node.name;
- bool isSoftware = nodeName.compare(0, 10, "OMX.google") == 0;
+ bool isSoftware = hasPrefix(nodeName, "OMX.google");
MediaCodecInfoWriter* info;
if (isSoftware) {
auto c2i = swCodecName2Info.find(nodeName);
diff --git a/media/libstagefright/codecs/amrnb/dec/Android.bp b/media/libstagefright/codecs/amrnb/dec/Android.bp
index d266dc2..b493e21 100644
--- a/media/libstagefright/codecs/amrnb/dec/Android.bp
+++ b/media/libstagefright/codecs/amrnb/dec/Android.bp
@@ -114,6 +114,8 @@
srcs: ["test/amrnbdec_test.cpp"],
+ cflags: ["-Wall", "-Werror"],
+
local_include_dirs: ["src"],
static_libs: [
diff --git a/media/libstagefright/codecs/amrnb/enc/Android.bp b/media/libstagefright/codecs/amrnb/enc/Android.bp
index 6dc2dc1..1e8fd31 100644
--- a/media/libstagefright/codecs/amrnb/enc/Android.bp
+++ b/media/libstagefright/codecs/amrnb/enc/Android.bp
@@ -126,6 +126,8 @@
srcs: ["test/amrnb_enc_test.cpp"],
+ cflags: ["-Wall", "-Werror"],
+
local_include_dirs: ["src"],
static_libs: ["libstagefright_amrnbenc"],
diff --git a/media/libstagefright/codecs/amrwb/Android.bp b/media/libstagefright/codecs/amrwb/Android.bp
index b932ccc..14a73d6 100644
--- a/media/libstagefright/codecs/amrwb/Android.bp
+++ b/media/libstagefright/codecs/amrwb/Android.bp
@@ -69,6 +69,8 @@
srcs: ["test/amrwbdec_test.cpp"],
+ cflags: ["-Wall", "-Werror"],
+
static_libs: [
"libstagefright_amrwbdec",
"libsndfile",
diff --git a/media/libstagefright/codecs/amrwbenc/SampleCode/Android.bp b/media/libstagefright/codecs/amrwbenc/SampleCode/Android.bp
index d52fed3..81b3f69 100644
--- a/media/libstagefright/codecs/amrwbenc/SampleCode/Android.bp
+++ b/media/libstagefright/codecs/amrwbenc/SampleCode/Android.bp
@@ -4,6 +4,8 @@
srcs: ["AMRWB_E_SAMPLE.c"],
+ cflags: ["-Wall", "-Werror"],
+
arch: {
arm: {
instruction_set: "arm",
diff --git a/media/libstagefright/codecs/avcdec/Android.bp b/media/libstagefright/codecs/avcdec/Android.bp
index 44f5e4f..3b2602d 100644
--- a/media/libstagefright/codecs/avcdec/Android.bp
+++ b/media/libstagefright/codecs/avcdec/Android.bp
@@ -8,6 +8,12 @@
static_libs: ["libavcdec"],
srcs: ["SoftAVCDec.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-variable",
+ ],
+
include_dirs: [
"external/libavc/decoder",
"external/libavc/common",
diff --git a/media/libstagefright/codecs/avcenc/Android.bp b/media/libstagefright/codecs/avcenc/Android.bp
index 7a8e1b7..4a0411e 100644
--- a/media/libstagefright/codecs/avcenc/Android.bp
+++ b/media/libstagefright/codecs/avcenc/Android.bp
@@ -33,6 +33,11 @@
},
},
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-variable",
+ ],
ldflags: ["-Wl,-Bsymbolic"],
compile_multilib: "32",
}
diff --git a/media/libstagefright/codecs/hevcdec/Android.bp b/media/libstagefright/codecs/hevcdec/Android.bp
index e63a2f8..f19ba00 100644
--- a/media/libstagefright/codecs/hevcdec/Android.bp
+++ b/media/libstagefright/codecs/hevcdec/Android.bp
@@ -8,6 +8,12 @@
static_libs: ["libhevcdec"],
srcs: ["SoftHEVC.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-variable",
+ ],
+
include_dirs: [
"external/libhevc/decoder",
"external/libhevc/common",
diff --git a/media/libstagefright/codecs/m4v_h263/enc/Android.bp b/media/libstagefright/codecs/m4v_h263/enc/Android.bp
index 7c5c61c..8a3fe34 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/Android.bp
+++ b/media/libstagefright/codecs/m4v_h263/enc/Android.bp
@@ -111,6 +111,8 @@
"-DOSCL_EXPORT_REF=",
"-DOSCL_IMPORT_REF=",
"-DBX_RC",
+ "-Wall",
+ "-Werror",
],
sanitize: {
diff --git a/media/libstagefright/codecs/mp3dec/Android.bp b/media/libstagefright/codecs/mp3dec/Android.bp
index 32c0753..5a0e282 100644
--- a/media/libstagefright/codecs/mp3dec/Android.bp
+++ b/media/libstagefright/codecs/mp3dec/Android.bp
@@ -127,6 +127,8 @@
"test/mp3reader.cpp",
],
+ cflags: ["-Wall", "-Werror"],
+
local_include_dirs: [
"src",
"include",
diff --git a/media/libstagefright/codecs/mpeg2dec/Android.bp b/media/libstagefright/codecs/mpeg2dec/Android.bp
index 0520559..9b8a188 100644
--- a/media/libstagefright/codecs/mpeg2dec/Android.bp
+++ b/media/libstagefright/codecs/mpeg2dec/Android.bp
@@ -8,6 +8,12 @@
static_libs: ["libmpeg2dec"],
srcs: ["SoftMPEG2.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-variable",
+ ],
+
include_dirs: [
"external/libmpeg2/decoder",
"external/libmpeg2/common",
diff --git a/media/libstagefright/codecs/on2/enc/Android.bp b/media/libstagefright/codecs/on2/enc/Android.bp
index 5c9872a..b21ffa1 100644
--- a/media/libstagefright/codecs/on2/enc/Android.bp
+++ b/media/libstagefright/codecs/on2/enc/Android.bp
@@ -11,6 +11,8 @@
"SoftVP9Encoder.cpp",
],
+ cflags: ["-Wall", "-Werror"],
+
include_dirs: [
"frameworks/av/media/libstagefright/include",
"frameworks/native/include/media/openmax",
diff --git a/media/libstagefright/codecs/on2/h264dec/Android.bp b/media/libstagefright/codecs/on2/h264dec/Android.bp
index 6d558b6..0984283 100644
--- a/media/libstagefright/codecs/on2/h264dec/Android.bp
+++ b/media/libstagefright/codecs/on2/h264dec/Android.bp
@@ -96,6 +96,8 @@
},
},
+ cflags: ["-Wall", "-Werror"],
+
include_dirs: [
"frameworks/av/media/libstagefright/include",
"frameworks/native/include/media/openmax",
@@ -133,5 +135,7 @@
srcs: ["source/DecTestBench.c"],
+ cflags: ["-Wall", "-Werror"],
+
shared_libs: ["libstagefright_soft_h264dec"],
}
diff --git a/media/libstagefright/filters/Android.bp b/media/libstagefright/filters/Android.bp
index e944224..64a6197 100644
--- a/media/libstagefright/filters/Android.bp
+++ b/media/libstagefright/filters/Android.bp
@@ -13,8 +13,12 @@
"ZeroFilter.cpp",
],
- include_dirs: [
- "frameworks/native/include/media/openmax",
+ header_libs: [
+ "media_plugin_headers",
+ ],
+
+ export_include_dirs: [
+ ".",
],
cflags: [
diff --git a/media/libstagefright/flac/dec/Android.bp b/media/libstagefright/flac/dec/Android.bp
index bbbd8c0..581e51b 100644
--- a/media/libstagefright/flac/dec/Android.bp
+++ b/media/libstagefright/flac/dec/Android.bp
@@ -1,4 +1,4 @@
-cc_library_shared {
+cc_library {
name: "libstagefright_flacdec",
vendor_available: true,
vndk: {
@@ -27,7 +27,13 @@
},
},
- static_libs: ["libFLAC"],
+ static: {
+ whole_static_libs: ["libFLAC"],
+ },
+
+ shared: {
+ static_libs: ["libFLAC"],
+ },
shared_libs: [
"liblog",
diff --git a/media/libstagefright/include/OmxNodeOwner.h b/media/libstagefright/include/OmxNodeOwner.h
deleted file mode 100644
index 64ec7f7..0000000
--- a/media/libstagefright/include/OmxNodeOwner.h
+++ /dev/null
@@ -1,37 +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 OMX_NODE_OWNER_H_
-
-#define OMX_NODE_OWNER_H_
-
-namespace android {
-
-struct OMXNodeInstance;
-
-/**
- * This struct is needed to separate OMX from OMXNodeInstance.
- *
- * TODO: This might not be needed after Treble transition is complete.
- */
-struct OmxNodeOwner {
- virtual status_t freeNode(const sp<OMXNodeInstance> &instance) = 0;
- virtual ~OmxNodeOwner() {}
-};
-
-}
-
-#endif // OMX_NODE_OWNER_H_
diff --git a/media/libstagefright/include/media/stagefright/ACodec.h b/media/libstagefright/include/media/stagefright/ACodec.h
index 424246d..d1a9d25 100644
--- a/media/libstagefright/include/media/stagefright/ACodec.h
+++ b/media/libstagefright/include/media/stagefright/ACodec.h
@@ -95,11 +95,6 @@
static status_t getOMXChannelMapping(size_t numChannels, OMX_AUDIO_CHANNELTYPE map[]);
- // Save the flag.
- void setTrebleFlag(bool trebleFlag);
- // Return the saved flag.
- bool getTrebleFlag() const;
-
protected:
virtual ~ACodec();
@@ -233,9 +228,7 @@
sp<IOMX> mOMX;
sp<IOMXNode> mOMXNode;
int32_t mNodeGeneration;
- bool mTrebleFlag;
sp<TAllocator> mAllocator[2];
- sp<MemoryDealer> mDealer[2];
bool mUsingNativeWindow;
sp<ANativeWindow> mNativeWindow;
diff --git a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
index 2902682..5af0745 100644
--- a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
@@ -17,6 +17,8 @@
#ifndef NU_MEDIA_EXTRACTOR_H_
#define NU_MEDIA_EXTRACTOR_H_
+#include <list>
+#include <media/mediaplayer.h>
#include <media/stagefright/foundation/ABase.h>
#include <media/IMediaExtractor.h>
#include <media/MediaSource.h>
@@ -67,7 +69,9 @@
status_t getFileFormat(sp<AMessage> *format) const;
- status_t selectTrack(size_t index);
+ status_t selectTrack(size_t index, int64_t startTimeUs = -1ll,
+ MediaSource::ReadOptions::SeekMode mode =
+ MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
status_t unselectTrack(size_t index);
status_t seekTo(
@@ -75,8 +79,12 @@
MediaSource::ReadOptions::SeekMode mode =
MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
+ // Each selected track has a read pointer.
+ // advance() advances the read pointer with the lowest timestamp.
status_t advance();
+ // readSampleData() reads the sample with the lowest timestamp.
status_t readSampleData(const sp<ABuffer> &buffer);
+
status_t getSampleTrackIndex(size_t *trackIndex);
status_t getSampleTime(int64_t *sampleTimeUs);
status_t getSampleMeta(sp<MetaData> *sampleMeta);
@@ -96,12 +104,20 @@
kMaxTrackCount = 16384,
};
+ struct Sample {
+ Sample();
+ Sample(MediaBuffer *buffer, int64_t timeUs);
+ MediaBuffer *mBuffer;
+ int64_t mSampleTimeUs;
+ };
+
struct TrackInfo {
sp<IMediaSource> mSource;
size_t mTrackIndex;
+ media_track_type mTrackType;
+ size_t mMaxFetchCount;
status_t mFinalResult;
- MediaBuffer *mSample;
- int64_t mSampleTimeUs;
+ std::list<Sample> mSamples;
uint32_t mTrackFlags; // bitmask of "TrackFlags"
};
@@ -117,16 +133,23 @@
int64_t mTotalBitrate; // in bits/sec
int64_t mDurationUs;
- ssize_t fetchTrackSamples(
+ ssize_t fetchAllTrackSamples(
+ int64_t seekTimeUs = -1ll,
+ MediaSource::ReadOptions::SeekMode mode =
+ MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
+ void fetchTrackSamples(
+ TrackInfo *info,
int64_t seekTimeUs = -1ll,
MediaSource::ReadOptions::SeekMode mode =
MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
- void releaseTrackSamples();
+ void releaseOneSample(TrackInfo *info);
+ void releaseTrackSamples(TrackInfo *info);
+ void releaseAllTrackSamples();
bool getTotalBitrate(int64_t *bitRate) const;
status_t updateDurationAndBitrate();
- status_t appendVorbisNumPageSamples(TrackInfo *info, const sp<ABuffer> &buffer);
+ status_t appendVorbisNumPageSamples(MediaBuffer *mbuf, const sp<ABuffer> &buffer);
DISALLOW_EVIL_CONSTRUCTORS(NuMediaExtractor);
};
diff --git a/media/libstagefright/include/media/stagefright/OMXClient.h b/media/libstagefright/include/media/stagefright/OMXClient.h
index b1864b8..e7b9be5 100644
--- a/media/libstagefright/include/media/stagefright/OMXClient.h
+++ b/media/libstagefright/include/media/stagefright/OMXClient.h
@@ -18,25 +18,19 @@
#define OMX_CLIENT_H_
-#include <media/IOMX.h>
-
namespace android {
+class IOMX;
+
class OMXClient {
public:
OMXClient();
- status_t connect();
- status_t connect(bool* trebleFlag);
- status_t connect(const char* name, bool* trebleFlag = nullptr);
+ status_t connect(const char* name = "default");
- status_t connectLegacy();
- status_t connectTreble(const char* name = "default");
void disconnect();
- sp<IOMX> interface() {
- return mOMX;
- }
+ sp<IOMX> interface();
private:
sp<IOMX> mOMX;
diff --git a/media/libstagefright/omx/Android.bp b/media/libstagefright/omx/Android.bp
index a464681..8539864 100644
--- a/media/libstagefright/omx/Android.bp
+++ b/media/libstagefright/omx/Android.bp
@@ -9,8 +9,6 @@
"FrameDropper.cpp",
"GraphicBufferSource.cpp",
"BWGraphicBufferSource.cpp",
- "OMX.cpp",
- "OMXStore.cpp",
"OMXMaster.cpp",
"OMXNodeInstance.cpp",
"OMXUtils.cpp",
@@ -121,6 +119,7 @@
cfi: true,
},
},
+ cflags: ["-Wall", "-Werror"],
}
//###############################################################################
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
deleted file mode 100644
index 09c4019..0000000
--- a/media/libstagefright/omx/OMX.cpp
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <inttypes.h>
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "OMX"
-#include <utils/Log.h>
-
-#include <dlfcn.h>
-
-#include <media/stagefright/omx/OMX.h>
-#include <media/stagefright/omx/OMXNodeInstance.h>
-#include <media/stagefright/omx/BWGraphicBufferSource.h>
-#include <media/stagefright/omx/OMXMaster.h>
-#include <media/stagefright/omx/OMXUtils.h>
-#include <media/stagefright/foundation/ADebug.h>
-
-namespace android {
-
-// node ids are created by concatenating the pid with a 16-bit counter
-static size_t kMaxNodeInstances = (1 << 16);
-
-OMX::OMX() : mMaster(new OMXMaster), mParser() {
-}
-
-OMX::~OMX() {
- delete mMaster;
- mMaster = NULL;
-}
-
-void OMX::binderDied(const wp<IBinder> &the_late_who) {
- sp<OMXNodeInstance> instance;
-
- {
- Mutex::Autolock autoLock(mLock);
-
- ssize_t index = mLiveNodes.indexOfKey(the_late_who);
-
- if (index < 0) {
- ALOGE("b/27597103, nonexistent observer on binderDied");
- android_errorWriteLog(0x534e4554, "27597103");
- return;
- }
-
- instance = mLiveNodes.editValueAt(index);
- mLiveNodes.removeItemsAt(index);
- }
-
- instance->onObserverDied();
-}
-
-status_t OMX::listNodes(List<ComponentInfo> *list) {
- list->clear();
-
- OMX_U32 index = 0;
- char componentName[256];
- while (mMaster->enumerateComponents(
- componentName, sizeof(componentName), index) == OMX_ErrorNone) {
- list->push_back(ComponentInfo());
- ComponentInfo &info = *--list->end();
-
- info.mName = componentName;
-
- Vector<String8> roles;
- OMX_ERRORTYPE err =
- mMaster->getRolesOfComponent(componentName, &roles);
-
- if (err == OMX_ErrorNone) {
- for (OMX_U32 i = 0; i < roles.size(); ++i) {
- info.mRoles.push_back(roles[i]);
- }
- }
-
- ++index;
- }
-
- return OK;
-}
-
-status_t OMX::allocateNode(
- const char *name, const sp<IOMXObserver> &observer,
- sp<IOMXNode> *omxNode) {
- Mutex::Autolock autoLock(mLock);
-
- omxNode->clear();
-
- if (mLiveNodes.size() == kMaxNodeInstances) {
- return NO_MEMORY;
- }
-
- sp<OMXNodeInstance> instance = new OMXNodeInstance(this, observer, name);
-
- OMX_COMPONENTTYPE *handle;
- OMX_ERRORTYPE err = mMaster->makeComponentInstance(
- name, &OMXNodeInstance::kCallbacks,
- instance.get(), &handle);
-
- if (err != OMX_ErrorNone) {
- ALOGE("FAILED to allocate omx component '%s' err=%s(%#x)", name, asString(err), err);
-
- return StatusFromOMXError(err);
- }
- instance->setHandle(handle);
-
- // Find quirks from mParser
- const auto& codec = mParser.getCodecMap().find(name);
- if (codec == mParser.getCodecMap().cend()) {
- ALOGW("Failed to obtain quirks for omx component '%s' from XML files",
- name);
- } else {
- uint32_t quirks = 0;
- for (const auto& quirk : codec->second.quirkSet) {
- if (quirk == "requires-allocate-on-input-ports") {
- quirks |= OMXNodeInstance::
- kRequiresAllocateBufferOnInputPorts;
- }
- if (quirk == "requires-allocate-on-output-ports") {
- quirks |= OMXNodeInstance::
- kRequiresAllocateBufferOnOutputPorts;
- }
- }
- instance->setQuirks(quirks);
- }
-
- mLiveNodes.add(IInterface::asBinder(observer), instance);
- IInterface::asBinder(observer)->linkToDeath(this);
-
- *omxNode = instance;
-
- return OK;
-}
-
-status_t OMX::freeNode(const sp<OMXNodeInstance> &instance) {
- if (instance == NULL) {
- return OK;
- }
-
- {
- Mutex::Autolock autoLock(mLock);
- ssize_t index = mLiveNodes.indexOfKey(IInterface::asBinder(instance->observer()));
- if (index < 0) {
- // This could conceivably happen if the observer dies at roughly the
- // same time that a client attempts to free the node explicitly.
-
- // NOTE: it's guaranteed that this method is called at most once per
- // instance.
- ALOGV("freeNode: instance already removed from book-keeping.");
- } else {
- mLiveNodes.removeItemsAt(index);
- IInterface::asBinder(instance->observer())->unlinkToDeath(this);
- }
- }
-
- CHECK(instance->handle() != NULL);
- OMX_ERRORTYPE err = mMaster->destroyComponentInstance(
- static_cast<OMX_COMPONENTTYPE *>(instance->handle()));
- ALOGV("freeNode: handle destroyed: %p", instance->handle());
-
- return StatusFromOMXError(err);
-}
-
-status_t OMX::createInputSurface(
- sp<IGraphicBufferProducer> *bufferProducer,
- sp<IGraphicBufferSource> *bufferSource) {
- if (bufferProducer == NULL || bufferSource == NULL) {
- ALOGE("b/25884056");
- return BAD_VALUE;
- }
-
- sp<GraphicBufferSource> graphicBufferSource = new GraphicBufferSource();
- status_t err = graphicBufferSource->initCheck();
- if (err != OK) {
- ALOGE("Failed to create persistent input surface: %s (%d)",
- strerror(-err), err);
- return err;
- }
-
- *bufferProducer = graphicBufferSource->getIGraphicBufferProducer();
- *bufferSource = new BWGraphicBufferSource(graphicBufferSource);
-
- return OK;
-}
-
-} // namespace android
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 015a148..ff58eb6 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -344,7 +344,7 @@
////////////////////////////////////////////////////////////////////////////////
OMXNodeInstance::OMXNodeInstance(
- OmxNodeOwner *owner, const sp<IOMXObserver> &observer, const char *name)
+ Omx *owner, const sp<IOMXObserver> &observer, const char *name)
: mOwner(owner),
mHandle(NULL),
mObserver(observer),
diff --git a/media/libstagefright/omx/OMXStore.cpp b/media/libstagefright/omx/OMXStore.cpp
deleted file mode 100644
index 345336d..0000000
--- a/media/libstagefright/omx/OMXStore.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "OMXStore"
-#include <utils/Log.h>
-
-#include <media/stagefright/omx/OMXUtils.h>
-#include <media/stagefright/omx/OMX.h>
-#include <media/stagefright/omx/OMXStore.h>
-#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
-
-#include <map>
-#include <string>
-
-namespace android {
-
-namespace {
- struct RoleProperties {
- std::string type;
- bool isEncoder;
- bool preferPlatformNodes;
- std::multimap<size_t, IOMXStore::NodeInfo> nodeList;
- };
-} // Unnamed namespace
-
-OMXStore::OMXStore(
- const char* owner,
- const char* const* searchDirs,
- const char* mainXmlName,
- const char* performanceXmlName,
- const char* profilingResultsXmlPath) {
- MediaCodecsXmlParser parser(
- searchDirs,
- mainXmlName,
- performanceXmlName,
- profilingResultsXmlPath);
- mParsingStatus = parser.getParsingStatus();
-
- const auto& serviceAttributeMap = parser.getServiceAttributeMap();
- mServiceAttributeList.reserve(serviceAttributeMap.size());
- for (const auto& attributePair : serviceAttributeMap) {
- Attribute attribute;
- attribute.key = attributePair.first;
- attribute.value = attributePair.second;
- mServiceAttributeList.push_back(std::move(attribute));
- }
-
- const auto& roleMap = parser.getRoleMap();
- mRoleList.reserve(roleMap.size());
- for (const auto& rolePair : roleMap) {
- RoleInfo role;
- role.role = rolePair.first;
- role.type = rolePair.second.type;
- role.isEncoder = rolePair.second.isEncoder;
- // TODO: Currently, preferPlatformNodes information is not available in
- // the xml file. Once we have a way to provide this information, it
- // should be parsed properly.
- role.preferPlatformNodes = rolePair.first.compare(0, 5, "audio") == 0;
- std::vector<NodeInfo>& nodeList = role.nodes;
- nodeList.reserve(rolePair.second.nodeList.size());
- for (const auto& nodePair : rolePair.second.nodeList) {
- NodeInfo node;
- node.name = nodePair.second.name;
- node.owner = owner;
- std::vector<Attribute>& attributeList = node.attributes;
- attributeList.reserve(nodePair.second.attributeList.size());
- for (const auto& attributePair : nodePair.second.attributeList) {
- Attribute attribute;
- attribute.key = attributePair.first;
- attribute.value = attributePair.second;
- attributeList.push_back(std::move(attribute));
- }
- nodeList.push_back(std::move(node));
- }
- mRoleList.push_back(std::move(role));
- }
-
- mPrefix = parser.getCommonPrefix();
-}
-
-status_t OMXStore::listServiceAttributes(std::vector<Attribute>* attributes) {
- *attributes = mServiceAttributeList;
- return mParsingStatus;
-}
-
-status_t OMXStore::getNodePrefix(std::string* prefix) {
- *prefix = mPrefix;
- return mParsingStatus;
-}
-
-status_t OMXStore::listRoles(std::vector<RoleInfo>* roleList) {
- *roleList = mRoleList;
- return mParsingStatus;
-}
-
-status_t OMXStore::getOmx(const std::string& name, sp<IOMX>* omx) {
- *omx = new OMX();
- return NO_ERROR;
-}
-
-OMXStore::~OMXStore() {
-}
-
-} // namespace android
-
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/1.0/Omx.h b/media/libstagefright/omx/include/media/stagefright/omx/1.0/Omx.h
index a6a9d3e..baa7b81 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/1.0/Omx.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/1.0/Omx.h
@@ -20,13 +20,13 @@
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
-#include <media/stagefright/omx/OMXNodeInstance.h>
#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
#include <android/hardware/media/omx/1.0/IOmx.h>
namespace android {
struct OMXMaster;
+struct OMXNodeInstance;
namespace hardware {
namespace media {
@@ -50,10 +50,9 @@
using ::android::wp;
using ::android::OMXMaster;
-using ::android::OmxNodeOwner;
using ::android::OMXNodeInstance;
-struct Omx : public IOmx, public hidl_death_recipient, public OmxNodeOwner {
+struct Omx : public IOmx, public hidl_death_recipient {
Omx();
virtual ~Omx();
@@ -68,8 +67,8 @@
// Method from hidl_death_recipient
void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
- // Method from OmxNodeOwner
- virtual status_t freeNode(sp<OMXNodeInstance> const& instance) override;
+ // Method for OMXNodeInstance
+ status_t freeNode(sp<OMXNodeInstance> const& instance);
protected:
OMXMaster* mMaster;
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/OMX.h b/media/libstagefright/omx/include/media/stagefright/omx/OMX.h
deleted file mode 100644
index 594b4c0..0000000
--- a/media/libstagefright/omx/include/media/stagefright/omx/OMX.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_OMX_H_
-#define ANDROID_OMX_H_
-
-#include <media/IOMX.h>
-#include <utils/threads.h>
-#include <utils/KeyedVector.h>
-#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
-#include "OmxNodeOwner.h"
-
-namespace android {
-
-struct OMXMaster;
-struct OMXNodeInstance;
-
-class OMX : public BnOMX,
- public OmxNodeOwner,
- public IBinder::DeathRecipient {
-public:
- OMX();
-
- virtual status_t listNodes(List<ComponentInfo> *list);
-
- virtual status_t allocateNode(
- const char *name, const sp<IOMXObserver> &observer,
- sp<IOMXNode> *omxNode);
-
- virtual status_t createInputSurface(
- sp<IGraphicBufferProducer> *bufferProducer,
- sp<IGraphicBufferSource> *bufferSource);
-
- virtual void binderDied(const wp<IBinder> &the_late_who);
-
- virtual status_t freeNode(const sp<OMXNodeInstance>& instance);
-
-protected:
- virtual ~OMX();
-
-private:
- Mutex mLock;
- OMXMaster *mMaster;
- MediaCodecsXmlParser mParser;
-
- KeyedVector<wp<IBinder>, sp<OMXNodeInstance> > mLiveNodes;
-
- OMX(const OMX &);
- OMX &operator=(const OMX &);
-};
-
-} // namespace android
-
-#endif // ANDROID_OMX_H_
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h b/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h
index 1065ca5..c436121 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/OMXNodeInstance.h
@@ -25,9 +25,9 @@
#include <utils/threads.h>
#include <utils/KeyedVector.h>
#include <utils/SortedVector.h>
-#include "OmxNodeOwner.h"
#include <android/hidl/memory/1.0/IMemory.h>
+#include <media/stagefright/omx/1.0/Omx.h>
namespace android {
class GraphicBuffer;
@@ -35,11 +35,12 @@
class IOMXObserver;
struct OMXMaster;
class OMXBuffer;
-typedef hidl::memory::V1_0::IMemory IHidlMemory;
+using IHidlMemory = hidl::memory::V1_0::IMemory;
+using hardware::media::omx::V1_0::implementation::Omx;
struct OMXNodeInstance : public BnOMXNode {
OMXNodeInstance(
- OmxNodeOwner *owner, const sp<IOMXObserver> &observer, const char *name);
+ Omx *owner, const sp<IOMXObserver> &observer, const char *name);
void setHandle(OMX_HANDLETYPE handle);
@@ -122,7 +123,7 @@
Mutex mLock;
- OmxNodeOwner *mOwner;
+ Omx *mOwner;
OMX_HANDLETYPE mHandle;
sp<IOMXObserver> mObserver;
sp<CallbackDispatcher> mDispatcher;
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/OMXStore.h b/media/libstagefright/omx/include/media/stagefright/omx/OMXStore.h
deleted file mode 100644
index e00d713..0000000
--- a/media/libstagefright/omx/include/media/stagefright/omx/OMXStore.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_OMXSTORE_H_
-#define ANDROID_OMXSTORE_H_
-
-#include <media/IOMXStore.h>
-#include <media/IOMX.h>
-#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
-
-#include <vector>
-#include <string>
-
-namespace android {
-
-class OMXStore : public BnOMXStore {
-public:
- OMXStore(
- const char* owner = "default",
- const char* const* searchDirs
- = MediaCodecsXmlParser::defaultSearchDirs,
- const char* mainXmlName
- = MediaCodecsXmlParser::defaultMainXmlName,
- const char* performanceXmlName
- = MediaCodecsXmlParser::defaultPerformanceXmlName,
- const char* profilingResultsXmlPath
- = MediaCodecsXmlParser::defaultProfilingResultsXmlPath);
-
- status_t listServiceAttributes(
- std::vector<Attribute>* attributes) override;
-
- status_t getNodePrefix(std::string* prefix) override;
-
- status_t listRoles(std::vector<RoleInfo>* roleList) override;
-
- status_t getOmx(const std::string& name, sp<IOMX>* omx) override;
-
- ~OMXStore() override;
-
-protected:
- status_t mParsingStatus;
- std::string mPrefix;
- std::vector<Attribute> mServiceAttributeList;
- std::vector<RoleInfo> mRoleList;
-};
-
-} // namespace android
-
-#endif // ANDROID_OMXSTORE_H_
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index 8092887..86c7211 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -25,11 +25,9 @@
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
-#include <binder/MemoryDealer.h>
#include <cutils/properties.h>
#include <media/DataSource.h>
#include <media/IMediaHTTPService.h>
-#include <media/IMediaCodecService.h>
#include <media/MediaExtractor.h>
#include <media/MediaSource.h>
#include <media/OMXBuffer.h>
@@ -71,7 +69,7 @@
/////////////////////////////////////////////////////////////////////
Harness::Harness()
- : mInitCheck(NO_INIT), mUseTreble(false) {
+ : mInitCheck(NO_INIT) {
mInitCheck = initOMX();
}
@@ -83,21 +81,12 @@
}
status_t Harness::initOMX() {
- if (property_get_bool("persist.media.treble_omx", true)) {
- using namespace ::android::hardware::media::omx::V1_0;
- sp<IOmx> tOmx = IOmx::getService();
- if (tOmx == nullptr) {
- return NO_INIT;
- }
- mOMX = new utils::LWOmx(tOmx);
- mUseTreble = true;
- } else {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder = sm->getService(String16("media.codec"));
- sp<IMediaCodecService> service = interface_cast<IMediaCodecService>(binder);
- mOMX = service->getOMX();
- mUseTreble = false;
+ using namespace ::android::hardware::media::omx::V1_0;
+ sp<IOmx> tOmx = IOmx::getService();
+ if (tOmx == nullptr) {
+ return NO_INIT;
}
+ mOMX = new utils::LWOmx(tOmx);
return mOMX != 0 ? OK : NO_INIT;
}
@@ -225,25 +214,19 @@
for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
Buffer buffer;
buffer.mFlags = 0;
- if (mUseTreble) {
- bool success;
- auto transStatus = mAllocator->allocate(def.nBufferSize,
- [&success, &buffer](
- bool s,
- hidl_memory const& m) {
- success = s;
- buffer.mHidlMemory = m;
- });
- EXPECT(transStatus.isOk(),
- "Cannot call allocator");
- EXPECT(success,
- "Cannot allocate memory");
- err = mOMXNode->useBuffer(portIndex, buffer.mHidlMemory, &buffer.mID);
- } else {
- buffer.mMemory = mDealer->allocate(def.nBufferSize);
- CHECK(buffer.mMemory != NULL);
- err = mOMXNode->useBuffer(portIndex, buffer.mMemory, &buffer.mID);
- }
+ bool success;
+ auto transStatus = mAllocator->allocate(def.nBufferSize,
+ [&success, &buffer](
+ bool s,
+ hidl_memory const& m) {
+ success = s;
+ buffer.mHidlMemory = m;
+ });
+ EXPECT(transStatus.isOk(),
+ "Cannot call allocator");
+ EXPECT(success,
+ "Cannot allocate memory");
+ err = mOMXNode->useBuffer(portIndex, buffer.mHidlMemory, &buffer.mID);
EXPECT_SUCCESS(err, "useBuffer");
@@ -312,13 +295,11 @@
return OK;
}
- if (mUseTreble) {
- mAllocator = IAllocator::getService("ashmem");
- EXPECT(mAllocator != nullptr,
- "Cannot obtain hidl AshmemAllocator");
- } else {
- mDealer = new MemoryDealer(16 * 1024 * 1024, "OMXHarness");
- }
+ mAllocator = IAllocator::getService("ashmem");
+ EXPECT(mAllocator != nullptr,
+ "Cannot obtain hidl AshmemAllocator");
+ // TODO: When Treble has MemoryHeap/MemoryDealer, we should specify the heap
+ // size to be 16 * 1024 * 1024.
sp<CodecObserver> observer = new CodecObserver(this, ++mCurGeneration);
diff --git a/media/libstagefright/omx/tests/OMXHarness.h b/media/libstagefright/omx/tests/OMXHarness.h
index 4fc0f79..dca787c 100644
--- a/media/libstagefright/omx/tests/OMXHarness.h
+++ b/media/libstagefright/omx/tests/OMXHarness.h
@@ -93,8 +93,6 @@
Condition mMessageAddedCondition;
int32_t mLastMsgGeneration;
int32_t mCurGeneration;
- bool mUseTreble;
- sp<MemoryDealer> mDealer;
sp<IAllocator> mAllocator;
status_t initOMX();
diff --git a/media/mtp/Android.bp b/media/mtp/Android.bp
index 543ad5c..acea373 100644
--- a/media/mtp/Android.bp
+++ b/media/mtp/Android.bp
@@ -19,6 +19,7 @@
srcs: [
"MtpDataPacket.cpp",
"MtpDebug.cpp",
+ "MtpDescriptors.cpp",
"MtpDevHandle.cpp",
"MtpDevice.cpp",
"MtpDeviceInfo.cpp",
diff --git a/media/mtp/MtpDatabase.h b/media/mtp/MtpDatabase.h
index c7021df..2395f4f 100644
--- a/media/mtp/MtpDatabase.h
+++ b/media/mtp/MtpDatabase.h
@@ -104,7 +104,7 @@
virtual MtpProperty* getDevicePropertyDesc(MtpDeviceProperty property) = 0;
virtual MtpResponseCode moveObject(MtpObjectHandle handle, MtpObjectHandle newParent,
- MtpString& newPath) = 0;
+ MtpStorageID newStorage, MtpString& newPath) = 0;
virtual void sessionStarted() = 0;
diff --git a/media/mtp/MtpDescriptors.cpp b/media/mtp/MtpDescriptors.cpp
new file mode 100644
index 0000000..d9b6060
--- /dev/null
+++ b/media/mtp/MtpDescriptors.cpp
@@ -0,0 +1,260 @@
+/*
+ * 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.
+ */
+
+#include "MtpDescriptors.h"
+
+namespace android {
+
+const struct usb_interface_descriptor mtp_interface_desc = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0,
+ .bNumEndpoints = 3,
+ .bInterfaceClass = USB_CLASS_STILL_IMAGE,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 1,
+ .iInterface = 1,
+};
+
+const struct usb_interface_descriptor ptp_interface_desc = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0,
+ .bNumEndpoints = 3,
+ .bInterfaceClass = USB_CLASS_STILL_IMAGE,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 1,
+};
+
+const struct usb_endpoint_descriptor_no_audio fs_sink = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = MAX_PACKET_SIZE_FS,
+};
+
+const struct usb_endpoint_descriptor_no_audio fs_source = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 2 | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = MAX_PACKET_SIZE_FS,
+};
+
+const struct usb_endpoint_descriptor_no_audio intr = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 3 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = MAX_PACKET_SIZE_EV,
+ .bInterval = 6,
+};
+
+const struct usb_endpoint_descriptor_no_audio hs_sink = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = MAX_PACKET_SIZE_HS,
+};
+
+const struct usb_endpoint_descriptor_no_audio hs_source = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 2 | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = MAX_PACKET_SIZE_HS,
+};
+
+const struct usb_endpoint_descriptor_no_audio ss_sink = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = MAX_PACKET_SIZE_SS,
+};
+
+const struct usb_endpoint_descriptor_no_audio ss_source = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 2 | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = MAX_PACKET_SIZE_SS,
+};
+
+const struct usb_ss_ep_comp_descriptor ss_sink_comp = {
+ .bLength = sizeof(ss_sink_comp),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bMaxBurst = 6,
+};
+
+const struct usb_ss_ep_comp_descriptor ss_source_comp = {
+ .bLength = sizeof(ss_source_comp),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bMaxBurst = 6,
+};
+
+const struct usb_ss_ep_comp_descriptor ss_intr_comp = {
+ .bLength = sizeof(ss_intr_comp),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+};
+
+const struct func_desc mtp_fs_descriptors = {
+ .intf = mtp_interface_desc,
+ .sink = fs_sink,
+ .source = fs_source,
+ .intr = intr,
+};
+
+const struct func_desc mtp_hs_descriptors = {
+ .intf = mtp_interface_desc,
+ .sink = hs_sink,
+ .source = hs_source,
+ .intr = intr,
+};
+
+const struct ss_func_desc mtp_ss_descriptors = {
+ .intf = mtp_interface_desc,
+ .sink = ss_sink,
+ .sink_comp = ss_sink_comp,
+ .source = ss_source,
+ .source_comp = ss_source_comp,
+ .intr = intr,
+ .intr_comp = ss_intr_comp,
+};
+
+const struct func_desc ptp_fs_descriptors = {
+ .intf = ptp_interface_desc,
+ .sink = fs_sink,
+ .source = fs_source,
+ .intr = intr,
+};
+
+const struct func_desc ptp_hs_descriptors = {
+ .intf = ptp_interface_desc,
+ .sink = hs_sink,
+ .source = hs_source,
+ .intr = intr,
+};
+
+const struct ss_func_desc ptp_ss_descriptors = {
+ .intf = ptp_interface_desc,
+ .sink = ss_sink,
+ .sink_comp = ss_sink_comp,
+ .source = ss_source,
+ .source_comp = ss_source_comp,
+ .intr = intr,
+ .intr_comp = ss_intr_comp,
+};
+
+const struct functionfs_strings mtp_strings = {
+ .header = {
+ .magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
+ .length = htole32(sizeof(mtp_strings)),
+ .str_count = htole32(1),
+ .lang_count = htole32(1),
+ },
+ .lang0 = {
+ .code = htole16(0x0409),
+ .str1 = STR_INTERFACE,
+ },
+};
+
+const struct usb_os_desc_header mtp_os_desc_header = {
+ .interface = htole32(1),
+ .dwLength = htole32(sizeof(usb_os_desc_header) + sizeof(usb_ext_compat_desc)),
+ .bcdVersion = htole16(1),
+ .wIndex = htole16(4),
+ .bCount = htole16(1),
+ .Reserved = htole16(0),
+};
+
+const struct usb_ext_compat_desc mtp_os_desc_compat = {
+ .bFirstInterfaceNumber = 0,
+ .Reserved1 = htole32(1),
+ .CompatibleID = { 'M', 'T', 'P' },
+ .SubCompatibleID = {0},
+ .Reserved2 = {0},
+};
+
+const struct usb_ext_compat_desc ptp_os_desc_compat = {
+ .bFirstInterfaceNumber = 0,
+ .Reserved1 = htole32(1),
+ .CompatibleID = { 'P', 'T', 'P' },
+ .SubCompatibleID = {0},
+ .Reserved2 = {0},
+};
+
+const struct desc_v2 mtp_desc_v2 = {
+ .header = {
+ .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
+ .length = htole32(sizeof(struct desc_v2)),
+ .flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
+ FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC,
+ },
+ .fs_count = 4,
+ .hs_count = 4,
+ .ss_count = 7,
+ .os_count = 1,
+ .fs_descs = mtp_fs_descriptors,
+ .hs_descs = mtp_hs_descriptors,
+ .ss_descs = mtp_ss_descriptors,
+ .os_header = mtp_os_desc_header,
+ .os_desc = mtp_os_desc_compat,
+};
+
+const struct desc_v2 ptp_desc_v2 = {
+ .header = {
+ .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
+ .length = htole32(sizeof(struct desc_v2)),
+ .flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
+ FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC,
+ },
+ .fs_count = 4,
+ .hs_count = 4,
+ .ss_count = 7,
+ .os_count = 1,
+ .fs_descs = ptp_fs_descriptors,
+ .hs_descs = ptp_hs_descriptors,
+ .ss_descs = ptp_ss_descriptors,
+ .os_header = mtp_os_desc_header,
+ .os_desc = ptp_os_desc_compat,
+};
+
+const struct desc_v1 mtp_desc_v1 = {
+ .header = {
+ .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC),
+ .length = htole32(sizeof(struct desc_v1)),
+ .fs_count = 4,
+ .hs_count = 4,
+ },
+ .fs_descs = mtp_fs_descriptors,
+ .hs_descs = mtp_hs_descriptors,
+};
+
+const struct desc_v1 ptp_desc_v1 = {
+ .header = {
+ .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC),
+ .length = htole32(sizeof(struct desc_v1)),
+ .fs_count = 4,
+ .hs_count = 4,
+ },
+ .fs_descs = ptp_fs_descriptors,
+ .hs_descs = ptp_hs_descriptors,
+};
+
+}; // namespace android
diff --git a/media/mtp/MtpDescriptors.h b/media/mtp/MtpDescriptors.h
new file mode 100644
index 0000000..cfc3930
--- /dev/null
+++ b/media/mtp/MtpDescriptors.h
@@ -0,0 +1,96 @@
+/*
+ * 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 MTP_DESCRIPTORS_H
+#define MTP_DESCRIPTORS_H
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/functionfs.h>
+#include <sys/endian.h>
+
+namespace android {
+
+constexpr int MAX_PACKET_SIZE_FS = 64;
+constexpr int MAX_PACKET_SIZE_HS = 512;
+constexpr int MAX_PACKET_SIZE_SS = 1024;
+constexpr int MAX_PACKET_SIZE_EV = 28;
+
+struct func_desc {
+ struct usb_interface_descriptor intf;
+ struct usb_endpoint_descriptor_no_audio sink;
+ struct usb_endpoint_descriptor_no_audio source;
+ struct usb_endpoint_descriptor_no_audio intr;
+} __attribute__((packed));
+
+struct ss_func_desc {
+ struct usb_interface_descriptor intf;
+ struct usb_endpoint_descriptor_no_audio sink;
+ struct usb_ss_ep_comp_descriptor sink_comp;
+ struct usb_endpoint_descriptor_no_audio source;
+ struct usb_ss_ep_comp_descriptor source_comp;
+ struct usb_endpoint_descriptor_no_audio intr;
+ struct usb_ss_ep_comp_descriptor intr_comp;
+} __attribute__((packed));
+
+struct desc_v1 {
+ struct usb_functionfs_descs_head_v1 {
+ __le32 magic;
+ __le32 length;
+ __le32 fs_count;
+ __le32 hs_count;
+ } __attribute__((packed)) header;
+ struct func_desc fs_descs, hs_descs;
+} __attribute__((packed));
+
+struct desc_v2 {
+ struct usb_functionfs_descs_head_v2 header;
+ // The rest of the structure depends on the flags in the header.
+ __le32 fs_count;
+ __le32 hs_count;
+ __le32 ss_count;
+ __le32 os_count;
+ struct func_desc fs_descs, hs_descs;
+ struct ss_func_desc ss_descs;
+ struct usb_os_desc_header os_header;
+ struct usb_ext_compat_desc os_desc;
+} __attribute__((packed));
+
+// OS descriptor contents should not be changed. See b/64790536.
+static_assert(sizeof(struct desc_v2) == sizeof(usb_functionfs_descs_head_v2) +
+ 16 + 2 * sizeof(struct func_desc) + sizeof(struct ss_func_desc) +
+ sizeof(usb_os_desc_header) + sizeof(usb_ext_compat_desc),
+ "Size of mtp descriptor is incorrect!");
+
+#define STR_INTERFACE "MTP"
+struct functionfs_lang {
+ __le16 code;
+ char str1[sizeof(STR_INTERFACE)];
+} __attribute__((packed));
+
+struct functionfs_strings {
+ struct usb_functionfs_strings_head header;
+ struct functionfs_lang lang0;
+} __attribute__((packed));
+
+extern const struct desc_v2 mtp_desc_v2;
+extern const struct desc_v2 ptp_desc_v2;
+extern const struct desc_v1 mtp_desc_v1;
+extern const struct desc_v1 ptp_desc_v1;
+extern const struct functionfs_strings mtp_strings;
+
+}; // namespace android
+
+#endif // MTP_DESCRIPTORS_H
diff --git a/media/mtp/MtpFfsHandle.cpp b/media/mtp/MtpFfsHandle.cpp
index 965985d..cb9827f 100644
--- a/media/mtp/MtpFfsHandle.cpp
+++ b/media/mtp/MtpFfsHandle.cpp
@@ -20,13 +20,10 @@
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
-#include <linux/usb/ch9.h>
-#include <linux/usb/functionfs.h>
#include <memory>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/endian.h>
#include <sys/eventfd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
@@ -36,6 +33,7 @@
#include <unistd.h>
#include "PosixAsyncIO.h"
+#include "MtpDescriptors.h"
#include "MtpFfsHandle.h"
#include "mtp.h"
@@ -45,11 +43,6 @@
constexpr char FFS_MTP_EP_OUT[] = "/dev/usb-ffs/mtp/ep2";
constexpr char FFS_MTP_EP_INTR[] = "/dev/usb-ffs/mtp/ep3";
-constexpr int MAX_PACKET_SIZE_FS = 64;
-constexpr int MAX_PACKET_SIZE_HS = 512;
-constexpr int MAX_PACKET_SIZE_SS = 1024;
-constexpr int MAX_PACKET_SIZE_EV = 28;
-
constexpr unsigned AIO_BUFS_MAX = 128;
constexpr unsigned AIO_BUF_LEN = 16384;
@@ -61,234 +54,6 @@
struct timespec ZERO_TIMEOUT = { 0, 0 };
-struct func_desc {
- struct usb_interface_descriptor intf;
- struct usb_endpoint_descriptor_no_audio sink;
- struct usb_endpoint_descriptor_no_audio source;
- struct usb_endpoint_descriptor_no_audio intr;
-} __attribute__((packed));
-
-struct ss_func_desc {
- struct usb_interface_descriptor intf;
- struct usb_endpoint_descriptor_no_audio sink;
- struct usb_ss_ep_comp_descriptor sink_comp;
- struct usb_endpoint_descriptor_no_audio source;
- struct usb_ss_ep_comp_descriptor source_comp;
- struct usb_endpoint_descriptor_no_audio intr;
- struct usb_ss_ep_comp_descriptor intr_comp;
-} __attribute__((packed));
-
-struct desc_v1 {
- struct usb_functionfs_descs_head_v1 {
- __le32 magic;
- __le32 length;
- __le32 fs_count;
- __le32 hs_count;
- } __attribute__((packed)) header;
- struct func_desc fs_descs, hs_descs;
-} __attribute__((packed));
-
-struct desc_v2 {
- struct usb_functionfs_descs_head_v2 header;
- // The rest of the structure depends on the flags in the header.
- __le32 fs_count;
- __le32 hs_count;
- __le32 ss_count;
- __le32 os_count;
- struct func_desc fs_descs, hs_descs;
- struct ss_func_desc ss_descs;
- struct usb_os_desc_header os_header;
- struct usb_ext_compat_desc os_desc;
-} __attribute__((packed));
-
-const struct usb_interface_descriptor mtp_interface_desc = {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = 0,
- .bNumEndpoints = 3,
- .bInterfaceClass = USB_CLASS_STILL_IMAGE,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 1,
- .iInterface = 1,
-};
-
-const struct usb_interface_descriptor ptp_interface_desc = {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = 0,
- .bNumEndpoints = 3,
- .bInterfaceClass = USB_CLASS_STILL_IMAGE,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 1,
-};
-
-const struct usb_endpoint_descriptor_no_audio fs_sink = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 1 | USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = MAX_PACKET_SIZE_FS,
-};
-
-const struct usb_endpoint_descriptor_no_audio fs_source = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 2 | USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = MAX_PACKET_SIZE_FS,
-};
-
-const struct usb_endpoint_descriptor_no_audio intr = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 3 | USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = MAX_PACKET_SIZE_EV,
- .bInterval = 6,
-};
-
-const struct usb_endpoint_descriptor_no_audio hs_sink = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 1 | USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = MAX_PACKET_SIZE_HS,
-};
-
-const struct usb_endpoint_descriptor_no_audio hs_source = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 2 | USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = MAX_PACKET_SIZE_HS,
-};
-
-const struct usb_endpoint_descriptor_no_audio ss_sink = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 1 | USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = MAX_PACKET_SIZE_SS,
-};
-
-const struct usb_endpoint_descriptor_no_audio ss_source = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 2 | USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = MAX_PACKET_SIZE_SS,
-};
-
-const struct usb_ss_ep_comp_descriptor ss_sink_comp = {
- .bLength = sizeof(ss_sink_comp),
- .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
- .bMaxBurst = 6,
-};
-
-const struct usb_ss_ep_comp_descriptor ss_source_comp = {
- .bLength = sizeof(ss_source_comp),
- .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
- .bMaxBurst = 6,
-};
-
-const struct usb_ss_ep_comp_descriptor ss_intr_comp = {
- .bLength = sizeof(ss_intr_comp),
- .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
-};
-
-const struct func_desc mtp_fs_descriptors = {
- .intf = mtp_interface_desc,
- .sink = fs_sink,
- .source = fs_source,
- .intr = intr,
-};
-
-const struct func_desc mtp_hs_descriptors = {
- .intf = mtp_interface_desc,
- .sink = hs_sink,
- .source = hs_source,
- .intr = intr,
-};
-
-const struct ss_func_desc mtp_ss_descriptors = {
- .intf = mtp_interface_desc,
- .sink = ss_sink,
- .sink_comp = ss_sink_comp,
- .source = ss_source,
- .source_comp = ss_source_comp,
- .intr = intr,
- .intr_comp = ss_intr_comp,
-};
-
-const struct func_desc ptp_fs_descriptors = {
- .intf = ptp_interface_desc,
- .sink = fs_sink,
- .source = fs_source,
- .intr = intr,
-};
-
-const struct func_desc ptp_hs_descriptors = {
- .intf = ptp_interface_desc,
- .sink = hs_sink,
- .source = hs_source,
- .intr = intr,
-};
-
-const struct ss_func_desc ptp_ss_descriptors = {
- .intf = ptp_interface_desc,
- .sink = ss_sink,
- .sink_comp = ss_sink_comp,
- .source = ss_source,
- .source_comp = ss_source_comp,
- .intr = intr,
- .intr_comp = ss_intr_comp,
-};
-
-#define STR_INTERFACE "MTP"
-const struct {
- struct usb_functionfs_strings_head header;
- struct {
- __le16 code;
- const char str1[sizeof(STR_INTERFACE)];
- } __attribute__((packed)) lang0;
-} __attribute__((packed)) strings = {
- .header = {
- .magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
- .length = htole32(sizeof(strings)),
- .str_count = htole32(1),
- .lang_count = htole32(1),
- },
- .lang0 = {
- .code = htole16(0x0409),
- .str1 = STR_INTERFACE,
- },
-};
-
-struct usb_os_desc_header mtp_os_desc_header = {
- .interface = htole32(1),
- .dwLength = htole32(sizeof(usb_os_desc_header) + sizeof(usb_ext_compat_desc)),
- .bcdVersion = htole16(1),
- .wIndex = htole16(4),
- .bCount = htole16(1),
- .Reserved = htole16(0),
-};
-
-struct usb_ext_compat_desc mtp_os_desc_compat = {
- .bFirstInterfaceNumber = 0,
- .Reserved1 = htole32(1),
- .CompatibleID = { 'M', 'T', 'P' },
- .SubCompatibleID = {0},
- .Reserved2 = {0},
-};
-
-struct usb_ext_compat_desc ptp_os_desc_compat = {
- .bFirstInterfaceNumber = 0,
- .Reserved1 = htole32(1),
- .CompatibleID = { 'P', 'T', 'P' },
- .SubCompatibleID = {0},
- .Reserved2 = {0},
-};
-
struct mtp_device_status {
uint16_t wLength;
uint16_t wCode;
@@ -357,58 +122,38 @@
}
bool MtpFfsHandle::initFunctionfs() {
- ssize_t ret;
- struct desc_v1 v1_descriptor;
- struct desc_v2 v2_descriptor;
-
- v2_descriptor.header.magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2);
- v2_descriptor.header.length = htole32(sizeof(v2_descriptor));
- v2_descriptor.header.flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
- FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC;
- v2_descriptor.fs_count = 4;
- v2_descriptor.hs_count = 4;
- v2_descriptor.ss_count = 7;
- v2_descriptor.os_count = 1;
- v2_descriptor.fs_descs = mPtp ? ptp_fs_descriptors : mtp_fs_descriptors;
- v2_descriptor.hs_descs = mPtp ? ptp_hs_descriptors : mtp_hs_descriptors;
- v2_descriptor.ss_descs = mPtp ? ptp_ss_descriptors : mtp_ss_descriptors;
- v2_descriptor.os_header = mtp_os_desc_header;
- v2_descriptor.os_desc = mPtp ? ptp_os_desc_compat : mtp_os_desc_compat;
-
if (mControl < 0) { // might have already done this before
mControl.reset(TEMP_FAILURE_RETRY(open(FFS_MTP_EP0, O_RDWR)));
if (mControl < 0) {
PLOG(ERROR) << FFS_MTP_EP0 << ": cannot open control endpoint";
- goto err;
+ return false;
}
-
- ret = TEMP_FAILURE_RETRY(::write(mControl, &v2_descriptor, sizeof(v2_descriptor)));
- if (ret < 0) {
- v1_descriptor.header.magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC);
- v1_descriptor.header.length = htole32(sizeof(v1_descriptor));
- v1_descriptor.header.fs_count = 4;
- v1_descriptor.header.hs_count = 4;
- v1_descriptor.fs_descs = mPtp ? ptp_fs_descriptors : mtp_fs_descriptors;
- v1_descriptor.hs_descs = mPtp ? ptp_hs_descriptors : mtp_hs_descriptors;
- PLOG(ERROR) << FFS_MTP_EP0 << "Switching to V1 descriptor format";
- ret = TEMP_FAILURE_RETRY(::write(mControl, &v1_descriptor, sizeof(v1_descriptor)));
- if (ret < 0) {
- PLOG(ERROR) << FFS_MTP_EP0 << "Writing descriptors failed";
- goto err;
- }
- }
- ret = TEMP_FAILURE_RETRY(::write(mControl, &strings, sizeof(strings)));
- if (ret < 0) {
- PLOG(ERROR) << FFS_MTP_EP0 << "Writing strings failed";
- goto err;
+ if (!writeDescriptors()) {
+ closeConfig();
+ return false;
}
}
-
return true;
+}
-err:
- closeConfig();
- return false;
+bool MtpFfsHandle::writeDescriptors() {
+ ssize_t ret = TEMP_FAILURE_RETRY(::write(mControl,
+ &(mPtp ? ptp_desc_v2 : mtp_desc_v2), sizeof(desc_v2)));
+ if (ret < 0) {
+ PLOG(ERROR) << FFS_MTP_EP0 << "Switching to V1 descriptor format";
+ ret = TEMP_FAILURE_RETRY(::write(mControl,
+ &(mPtp ? ptp_desc_v1 : mtp_desc_v1), sizeof(desc_v1)));
+ if (ret < 0) {
+ PLOG(ERROR) << FFS_MTP_EP0 << "Writing descriptors failed";
+ return false;
+ }
+ }
+ ret = TEMP_FAILURE_RETRY(::write(mControl, &mtp_strings, sizeof(mtp_strings)));
+ if (ret < 0) {
+ PLOG(ERROR) << FFS_MTP_EP0 << "Writing strings failed";
+ return false;
+ }
+ return true;
}
void MtpFfsHandle::closeConfig() {
diff --git a/media/mtp/MtpFfsHandle.h b/media/mtp/MtpFfsHandle.h
index 2f90bd1..2347000 100644
--- a/media/mtp/MtpFfsHandle.h
+++ b/media/mtp/MtpFfsHandle.h
@@ -42,11 +42,14 @@
};
template <class T> class MtpFfsHandleTest;
+template <class T> class MtpFfsHandleTest_testControl_Test;
class MtpFfsHandle : public IMtpHandle {
- template <class T> friend class android::MtpFfsHandleTest;
+ template <class T> friend class MtpFfsHandleTest;
+ template <class T> friend class MtpFfsHandleTest_testControl_Test;
protected:
bool initFunctionfs();
+ bool writeDescriptors();
void closeConfig();
void closeEndpoints();
void advise(int fd);
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 236f3a9..a0944a9 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <android-base/logging.h>
#include <android-base/properties.h>
#include <chrono>
#include <dirent.h>
@@ -99,16 +100,12 @@
};
MtpServer::MtpServer(MtpDatabase* database, bool ptp,
- int fileGroup, int filePerm, int directoryPerm,
const MtpString& deviceInfoManufacturer,
const MtpString& deviceInfoModel,
const MtpString& deviceInfoDeviceVersion,
const MtpString& deviceInfoSerialNumber)
: mDatabase(database),
mPtp(ptp),
- mFileGroup(fileGroup),
- mFilePermission(filePerm),
- mDirectoryPermission(directoryPerm),
mDeviceInfoManufacturer(deviceInfoManufacturer),
mDeviceInfoModel(deviceInfoModel),
mDeviceInfoDeviceVersion(deviceInfoDeviceVersion),
@@ -1002,12 +999,9 @@
}
if (format == MTP_FORMAT_ASSOCIATION) {
- mode_t mask = umask(0);
- int ret = mkdir((const char *)path, mDirectoryPermission);
- umask(mask);
- if (ret && ret != -EEXIST)
+ int ret = makeFolder((const char *)path);
+ if (ret)
return MTP_RESPONSE_GENERAL_ERROR;
- chown((const char *)path, getuid(), mFileGroup);
// SendObject does not get sent for directories, so call endSendObject here instead
mDatabase->endSendObject(path, handle, MTP_FORMAT_ASSOCIATION, MTP_RESPONSE_OK);
@@ -1068,28 +1062,39 @@
path += "/";
path += info.mName;
- result = mDatabase->moveObject(objectHandle, parent, path);
+ result = mDatabase->moveObject(objectHandle, parent, storageID, path);
if (result != MTP_RESPONSE_OK)
return result;
if (info.mStorageID == storageID) {
ALOGV("Moving file from %s to %s", (const char*)fromPath, (const char*)path);
if (rename(fromPath, path)) {
- ALOGE("rename() failed from %s to %s", (const char*)fromPath, (const char*)path);
+ PLOG(ERROR) << "rename() failed from " << fromPath << " to " << path;
result = MTP_RESPONSE_GENERAL_ERROR;
}
} else {
ALOGV("Moving across storages from %s to %s", (const char*)fromPath, (const char*)path);
- if (copyFile(fromPath, path)) {
- result = MTP_RESPONSE_GENERAL_ERROR;
+ if (format == MTP_FORMAT_ASSOCIATION) {
+ int ret = makeFolder((const char *)path);
+ ret += copyRecursive(fromPath, path);
+ if (ret) {
+ result = MTP_RESPONSE_GENERAL_ERROR;
+ } else {
+ deletePath(fromPath);
+ }
} else {
- deletePath(fromPath);
+ if (copyFile(fromPath, path)) {
+ result = MTP_RESPONSE_GENERAL_ERROR;
+ } else {
+ deletePath(fromPath);
+ }
}
}
// If the move failed, undo the database change
if (result != MTP_RESPONSE_OK)
- if (mDatabase->moveObject(objectHandle, info.mParent, fromPath) != MTP_RESPONSE_OK)
+ if (mDatabase->moveObject(objectHandle, info.mParent, info.mStorageID,
+ fromPath) != MTP_RESPONSE_OK)
ALOGE("Couldn't undo failed move");
return result;
@@ -1148,8 +1153,15 @@
}
ALOGV("Copying file from %s to %s", (const char*)fromPath, (const char*)path);
- if (copyFile(fromPath, path)) {
- result = MTP_RESPONSE_GENERAL_ERROR;
+ if (format == MTP_FORMAT_ASSOCIATION) {
+ int ret = makeFolder((const char *)path);
+ if (ret) {
+ result = MTP_RESPONSE_GENERAL_ERROR;
+ }
+ } else {
+ if (copyFile(fromPath, path)) {
+ result = MTP_RESPONSE_GENERAL_ERROR;
+ }
}
mDatabase->endSendObject(path, handle, format, result);
@@ -1188,10 +1200,10 @@
result = MTP_RESPONSE_GENERAL_ERROR;
goto done;
}
- fchown(mfr.fd, getuid(), mFileGroup);
+ fchown(mfr.fd, getuid(), FILE_GROUP);
// set permissions
mask = umask(0);
- fchmod(mfr.fd, mFilePermission);
+ fchmod(mfr.fd, FILE_PERM);
umask(mask);
if (initialData > 0) {
diff --git a/media/mtp/MtpServer.h b/media/mtp/MtpServer.h
index aafc753..0204b09 100644
--- a/media/mtp/MtpServer.h
+++ b/media/mtp/MtpServer.h
@@ -43,12 +43,6 @@
// appear as a PTP device
bool mPtp;
- // group to own new files and folders
- int mFileGroup;
- // permissions for new files and directories
- int mFilePermission;
- int mDirectoryPermission;
-
// Manufacturer to report in DeviceInfo
MtpString mDeviceInfoManufacturer;
// Model to report in DeviceInfo
@@ -105,7 +99,6 @@
public:
MtpServer(MtpDatabase* database, bool ptp,
- int fileGroup, int filePerm, int directoryPerm,
const MtpString& deviceInfoManufacturer,
const MtpString& deviceInfoModel,
const MtpString& deviceInfoDeviceVersion,
diff --git a/media/mtp/MtpUtils.cpp b/media/mtp/MtpUtils.cpp
index 036ffe7..3f5648b 100644
--- a/media/mtp/MtpUtils.cpp
+++ b/media/mtp/MtpUtils.cpp
@@ -20,6 +20,7 @@
#include <android-base/unique_fd.h>
#include <dirent.h>
#include <fcntl.h>
+#include <string>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -29,6 +30,8 @@
#include "MtpUtils.h"
+using namespace std;
+
namespace android {
constexpr unsigned long FILE_COPY_SIZE = 262144;
@@ -88,6 +91,60 @@
tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
}
+int makeFolder(const char *path) {
+ mode_t mask = umask(0);
+ int ret = mkdir((const char *)path, DIR_PERM);
+ umask(mask);
+ if (ret && ret != -EEXIST) {
+ PLOG(ERROR) << "Failed to create folder " << path;
+ ret = -1;
+ } else {
+ chown((const char *)path, getuid(), FILE_GROUP);
+ }
+ return ret;
+}
+
+/**
+ * Copies target path and all children to destination path.
+ *
+ * Returns 0 on success or a negative value indicating number of failures
+ */
+int copyRecursive(const char *fromPath, const char *toPath) {
+ int ret = 0;
+ string fromPathStr(fromPath);
+ string toPathStr(toPath);
+
+ DIR* dir = opendir(fromPath);
+ if (!dir) {
+ PLOG(ERROR) << "opendir " << fromPath << " failed";
+ return -1;
+ }
+ if (fromPathStr[fromPathStr.size()-1] != '/')
+ fromPathStr += '/';
+ if (toPathStr[toPathStr.size()-1] != '/')
+ toPathStr += '/';
+
+ struct dirent* entry;
+ while ((entry = readdir(dir))) {
+ const char* name = entry->d_name;
+
+ // ignore "." and ".."
+ if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
+ continue;
+ }
+ string oldFile = fromPathStr + name;
+ string newFile = toPathStr + name;
+
+ if (entry->d_type == DT_DIR) {
+ ret += makeFolder(newFile.c_str());
+ ret += copyRecursive(oldFile.c_str(), newFile.c_str());
+ } else {
+ ret += copyFile(oldFile.c_str(), newFile.c_str());
+ }
+ }
+ return ret;
+}
+
int copyFile(const char *fromPath, const char *toPath) {
auto start = std::chrono::steady_clock::now();
@@ -96,7 +153,7 @@
PLOG(ERROR) << "Failed to open copy from " << fromPath;
return -1;
}
- android::base::unique_fd toFd(open(toPath, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR));
+ android::base::unique_fd toFd(open(toPath, O_CREAT | O_WRONLY, FILE_PERM));
if (toFd == -1) {
PLOG(ERROR) << "Failed to open copy to " << toPath;
return -1;
@@ -121,23 +178,17 @@
}
auto end = std::chrono::steady_clock::now();
std::chrono::duration<double> diff = end - start;
- LOG(INFO) << "Copied a file with MTP. Time: " << diff.count() << " s, Size: " << length <<
+ LOG(DEBUG) << "Copied a file with MTP. Time: " << diff.count() << " s, Size: " << length <<
", Rate: " << ((double) length) / diff.count() << " bytes/s";
+ chown(toPath, getuid(), FILE_GROUP);
return ret == -1 ? -1 : 0;
}
void deleteRecursive(const char* path) {
- char pathbuf[PATH_MAX];
- size_t pathLength = strlen(path);
- if (pathLength >= sizeof(pathbuf) - 1) {
- LOG(ERROR) << "path too long: " << path;
+ string pathStr(path);
+ if (pathStr[pathStr.size()-1] != '/') {
+ pathStr += '/';
}
- strcpy(pathbuf, path);
- if (pathbuf[pathLength - 1] != '/') {
- pathbuf[pathLength++] = '/';
- }
- char* fileSpot = pathbuf + pathLength;
- int pathRemaining = sizeof(pathbuf) - pathLength - 1;
DIR* dir = opendir(path);
if (!dir) {
@@ -153,19 +204,12 @@
if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
continue;
}
-
- int nameLength = strlen(name);
- if (nameLength > pathRemaining) {
- LOG(ERROR) << "path " << path << "/" << name << " too long";
- continue;
- }
- strcpy(fileSpot, name);
-
+ pathStr.append(name);
if (entry->d_type == DT_DIR) {
- deleteRecursive(pathbuf);
- rmdir(pathbuf);
+ deleteRecursive(pathStr.c_str());
+ rmdir(pathStr.c_str());
} else {
- unlink(pathbuf);
+ unlink(pathStr.c_str());
}
}
closedir(dir);
diff --git a/media/mtp/MtpUtils.h b/media/mtp/MtpUtils.h
index a2bb7e1..b7c72f5 100644
--- a/media/mtp/MtpUtils.h
+++ b/media/mtp/MtpUtils.h
@@ -17,13 +17,21 @@
#ifndef _MTP_UTILS_H
#define _MTP_UTILS_H
+#include "private/android_filesystem_config.h"
+
#include <stdint.h>
namespace android {
+constexpr int FILE_GROUP = AID_MEDIA_RW;
+constexpr int FILE_PERM = 0664;
+constexpr int DIR_PERM = 0775;
+
bool parseDateTime(const char* dateTime, time_t& outSeconds);
void formatDateTime(time_t seconds, char* buffer, int bufferLength);
+int makeFolder(const char *path);
+int copyRecursive(const char *fromPath, const char *toPath);
int copyFile(const char *fromPath, const char *toPath);
void deleteRecursive(const char* path);
void deletePath(const char* path);
diff --git a/media/mtp/OWNERS b/media/mtp/OWNERS
new file mode 100644
index 0000000..219307b
--- /dev/null
+++ b/media/mtp/OWNERS
@@ -0,0 +1 @@
+zhangjerry@google.com
diff --git a/media/mtp/tests/MtpFfsHandle_test.cpp b/media/mtp/tests/MtpFfsHandle_test.cpp
index 8d7301d..9c916b7 100644
--- a/media/mtp/tests/MtpFfsHandle_test.cpp
+++ b/media/mtp/tests/MtpFfsHandle_test.cpp
@@ -25,6 +25,7 @@
#include <unistd.h>
#include <utils/Log.h>
+#include "MtpDescriptors.h"
#include "MtpFfsHandle.h"
#include "MtpFfsCompatHandle.h"
@@ -66,8 +67,8 @@
handle = std::make_unique<T>();
EXPECT_EQ(pipe(fd), 0);
- handle->mControl.reset(fd[0]);
- control.reset(fd[1]);
+ control.reset(fd[0]);
+ handle->mControl.reset(fd[1]);
EXPECT_EQ(pipe(fd), 0);
EXPECT_EQ(fcntl(fd[0], F_SETPIPE_SZ, 1048576), 1048576);
@@ -83,7 +84,7 @@
intr.reset(fd[0]);
handle->mIntr.reset(fd[1]);
- handle->start();
+ EXPECT_EQ(handle->start(), 0);
}
~MtpFfsHandleTest() {
@@ -94,6 +95,16 @@
typedef ::testing::Types<MtpFfsHandle, MtpFfsCompatHandle> mtpHandles;
TYPED_TEST_CASE(MtpFfsHandleTest, mtpHandles);
+TYPED_TEST(MtpFfsHandleTest, testControl) {
+ EXPECT_TRUE(this->handle->writeDescriptors());
+ struct desc_v2 desc;
+ struct functionfs_strings strings;
+ EXPECT_EQ(read(this->control, &desc, sizeof(desc)), (long)sizeof(desc));
+ EXPECT_EQ(read(this->control, &strings, sizeof(strings)), (long)sizeof(strings));
+ EXPECT_TRUE(std::memcmp(&desc, &mtp_desc_v2, sizeof(desc)) == 0);
+ EXPECT_TRUE(std::memcmp(&strings, &mtp_strings, sizeof(strings)) == 0);
+}
+
TYPED_TEST(MtpFfsHandleTest, testRead) {
EXPECT_EQ(write(this->bulk_out, dummyDataStr.c_str(), TEST_PACKET_SIZE), TEST_PACKET_SIZE);
char buf[TEST_PACKET_SIZE + 1];
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 906e05a..89e5d77 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1224,6 +1224,12 @@
bool force = !outputDesc->isActive() &&
(outputDesc->getPatchHandle() == AUDIO_PATCH_HANDLE_NONE);
+ // requiresMuteCheck is false when we can bypass mute strategy.
+ // It covers a common case when there is no materially active audio
+ // and muting would result in unnecessary delay and dropped audio.
+ const uint32_t outputLatencyMs = outputDesc->latency();
+ bool requiresMuteCheck = outputDesc->isActive(outputLatencyMs * 2); // account for drain
+
// increment usage count for this stream on the requested output:
// NOTE that the usage count is the same for duplicated output and hardware output which is
// necessary for a correct control of hardware output routing by startOutput() and stopOutput()
@@ -1247,29 +1253,44 @@
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i);
if (desc != outputDesc) {
+ // An output has a shared device if
+ // - managed by the same hw module
+ // - supports the currently selected device
+ const bool sharedDevice = outputDesc->sharesHwModuleWith(desc)
+ && (desc->supportedDevices() & device) != AUDIO_DEVICE_NONE;
+
// force a device change if any other output is:
// - managed by the same hw module
- // - has a current device selection that differs from selected device.
// - supports currently selected device
+ // - has a current device selection that differs from selected device.
// - has an active audio patch
// In this case, the audio HAL must receive the new device selection so that it can
- // change the device currently selected by the other active output.
- if (outputDesc->sharesHwModuleWith(desc) &&
+ // change the device currently selected by the other output.
+ if (sharedDevice &&
desc->device() != device &&
- desc->supportedDevices() & device &&
desc->getPatchHandle() != AUDIO_PATCH_HANDLE_NONE) {
force = true;
}
// wait for audio on other active outputs to be presented when starting
// a notification so that audio focus effect can propagate, or that a mute/unmute
// event occurred for beacon
- uint32_t latency = desc->latency();
- if (shouldWait && desc->isActive(latency * 2) && (waitMs < latency)) {
- waitMs = latency;
+ const uint32_t latencyMs = desc->latency();
+ const bool isActive = desc->isActive(latencyMs * 2); // account for drain
+
+ if (shouldWait && isActive && (waitMs < latencyMs)) {
+ waitMs = latencyMs;
}
+
+ // Require mute check if another output is on a shared device
+ // and currently active to have proper drain and avoid pops.
+ // Note restoring AudioTracks onto this output needs to invoke
+ // a volume ramp if there is no mute.
+ requiresMuteCheck |= sharedDevice && isActive;
}
}
- uint32_t muteWaitMs = setOutputDevice(outputDesc, device, force, 0, NULL, address);
+
+ const uint32_t muteWaitMs =
+ setOutputDevice(outputDesc, device, force, 0, NULL, address, requiresMuteCheck);
// handle special case for sonification while in call
if (isInCall()) {
@@ -1294,6 +1315,14 @@
if (waitMs > muteWaitMs) {
*delayMs = waitMs - muteWaitMs;
}
+
+ // FIXME: A device change (muteWaitMs > 0) likely introduces a volume change.
+ // A volume change enacted by APM with 0 delay is not synchronous, as it goes
+ // via AudioCommandThread to AudioFlinger. Hence it is possible that the volume
+ // change occurs after the MixerThread starts and causes a stream volume
+ // glitch.
+ //
+ // We do not introduce additional delay here.
}
return NO_ERROR;
@@ -4812,21 +4841,24 @@
bool force,
int delayMs,
audio_patch_handle_t *patchHandle,
- const char* address)
+ const char *address,
+ bool requiresMuteCheck)
{
ALOGV("setOutputDevice() device %04x delayMs %d", device, delayMs);
AudioParameter param;
uint32_t muteWaitMs;
if (outputDesc->isDuplicated()) {
- muteWaitMs = setOutputDevice(outputDesc->subOutput1(), device, force, delayMs);
- muteWaitMs += setOutputDevice(outputDesc->subOutput2(), device, force, delayMs);
+ muteWaitMs = setOutputDevice(outputDesc->subOutput1(), device, force, delayMs,
+ nullptr /* patchHandle */, nullptr /* address */, requiresMuteCheck);
+ muteWaitMs += setOutputDevice(outputDesc->subOutput2(), device, force, delayMs,
+ nullptr /* patchHandle */, nullptr /* address */, requiresMuteCheck);
return muteWaitMs;
}
// no need to proceed if new device is not AUDIO_DEVICE_NONE and not supported by current
// output profile
if ((device != AUDIO_DEVICE_NONE) &&
- ((device & outputDesc->supportedDevices()) == 0)) {
+ ((device & outputDesc->supportedDevices()) == AUDIO_DEVICE_NONE)) {
return 0;
}
@@ -4840,7 +4872,14 @@
if (device != AUDIO_DEVICE_NONE) {
outputDesc->mDevice = device;
}
- muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
+
+ // if the outputs are not materially active, there is no need to mute.
+ if (requiresMuteCheck) {
+ muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
+ } else {
+ ALOGV("%s: suppressing checkDeviceMuteStrategies", __func__);
+ muteWaitMs = 0;
+ }
// Do not change the routing if:
// the requested device is AUDIO_DEVICE_NONE
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 7ba0669..1b0c315 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -300,7 +300,8 @@
bool force = false,
int delayMs = 0,
audio_patch_handle_t *patchHandle = NULL,
- const char* address = NULL);
+ const char *address = nullptr,
+ bool requiresMuteCheck = true);
status_t resetOutputDevice(const sp<AudioOutputDescriptor>& outputDesc,
int delayMs = 0,
audio_patch_handle_t *patchHandle = NULL);
diff --git a/services/mediaanalytics/MediaAnalyticsService.cpp b/services/mediaanalytics/MediaAnalyticsService.cpp
index c7f9270..f08be50 100644
--- a/services/mediaanalytics/MediaAnalyticsService.cpp
+++ b/services/mediaanalytics/MediaAnalyticsService.cpp
@@ -299,6 +299,8 @@
bool finalizing = item->getFinalized();
+ Mutex::Autolock _l(mLock);
+
// if finalizing, we'll remove it
MediaAnalyticsItem *oitem = findItem(mOpen, item, finalizing | forcenew);
if (oitem != NULL) {
@@ -609,10 +611,9 @@
// XXX: rewrite this to manage persistence, etc.
// insert appropriately into queue
+// caller should hold mLock
void MediaAnalyticsService::saveItem(List<MediaAnalyticsItem *> *l, MediaAnalyticsItem * item, int front) {
- Mutex::Autolock _l(mLock);
-
// adding at back of queue (fifo order)
if (front) {
l->push_front(item);
@@ -682,6 +683,7 @@
}
// find the incomplete record that this will overlay
+// caller should hold mLock
MediaAnalyticsItem *MediaAnalyticsService::findItem(List<MediaAnalyticsItem*> *theList, MediaAnalyticsItem *nitem, bool removeit) {
if (nitem == NULL) {
return NULL;
@@ -689,8 +691,6 @@
MediaAnalyticsItem *item = NULL;
- Mutex::Autolock _l(mLock);
-
for (List<MediaAnalyticsItem *>::iterator it = theList->begin();
it != theList->end(); it++) {
MediaAnalyticsItem *tmp = (*it);
@@ -711,10 +711,9 @@
// delete the indicated record
+// caller should hold mLock
void MediaAnalyticsService::deleteItem(List<MediaAnalyticsItem *> *l, MediaAnalyticsItem *item) {
- Mutex::Autolock _l(mLock);
-
for (List<MediaAnalyticsItem *>::iterator it = l->begin();
it != l->end(); it++) {
if ((*it)->getSessionID() != item->getSessionID())
diff --git a/services/mediacodec/Android.mk b/services/mediacodec/Android.mk
index faeb0a7..d4bae2b 100644
--- a/services/mediacodec/Android.mk
+++ b/services/mediacodec/Android.mk
@@ -1,28 +1,11 @@
LOCAL_PATH := $(call my-dir)
-# service library
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := MediaCodecService.cpp
-LOCAL_SHARED_LIBRARIES := \
- libmedia_omx \
- libbinder \
- libgui \
- libutils \
- liblog \
- libstagefright_omx \
- libstagefright_xmlparser
-LOCAL_MODULE:= libmediacodecservice
-LOCAL_VENDOR_MODULE := true
-LOCAL_32_BIT_ONLY := true
-include $(BUILD_SHARED_LIBRARY)
-
# service executable
include $(CLEAR_VARS)
LOCAL_REQUIRED_MODULES_arm := mediacodec.policy
LOCAL_SRC_FILES := main_codecservice.cpp
LOCAL_SHARED_LIBRARIES := \
libmedia_omx \
- libmediacodecservice \
libbinder \
libutils \
libgui \
diff --git a/services/mediacodec/MediaCodecService.cpp b/services/mediacodec/MediaCodecService.cpp
deleted file mode 100644
index 6b510c6..0000000
--- a/services/mediacodec/MediaCodecService.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 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_TAG "MediaCodecService"
-//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-
-#include "MediaCodecService.h"
-
-namespace android {
-
-sp<IOMX> MediaCodecService::getOMX() {
-
- Mutex::Autolock autoLock(mOMXLock);
-
- if (mOMX.get() == NULL) {
- mOMX = new OMX();
- }
-
- return mOMX;
-}
-
-sp<IOMXStore> MediaCodecService::getOMXStore() {
-
- Mutex::Autolock autoLock(mOMXStoreLock);
-
- if (mOMXStore.get() == NULL) {
- mOMXStore = new OMXStore();
- }
-
- return mOMXStore;
-}
-
-status_t MediaCodecService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
- uint32_t flags)
-{
- return BnMediaCodecService::onTransact(code, data, reply, flags);
-}
-
-} // namespace android
diff --git a/services/mediacodec/MediaCodecService.h b/services/mediacodec/MediaCodecService.h
deleted file mode 100644
index 9301135..0000000
--- a/services/mediacodec/MediaCodecService.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 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_MEDIA_CODEC_SERVICE_H
-#define ANDROID_MEDIA_CODEC_SERVICE_H
-
-#include <binder/BinderService.h>
-#include <media/IMediaCodecService.h>
-#include <media/stagefright/omx/OMX.h>
-#include <media/stagefright/omx/OMXStore.h>
-
-namespace android {
-
-class MediaCodecService : public BinderService<MediaCodecService>,
- public BnMediaCodecService
-{
- friend class BinderService<MediaCodecService>; // for MediaCodecService()
-public:
- MediaCodecService() : BnMediaCodecService() { }
- virtual ~MediaCodecService() { }
- virtual void onFirstRef() { }
-
- static const char* getServiceName() { return "media.codec"; }
-
- virtual sp<IOMX> getOMX();
-
- virtual sp<IOMXStore> getOMXStore();
-
- virtual status_t onTransact(uint32_t code, const Parcel& data,
- Parcel* reply, uint32_t flags);
-
-private:
- Mutex mOMXLock;
- sp<IOMX> mOMX;
- Mutex mOMXStoreLock;
- sp<IOMXStore> mOMXStore;
-};
-
-} // namespace android
-
-#endif // ANDROID_MEDIA_CODEC_SERVICE_H
diff --git a/services/mediacodec/main_codecservice.cpp b/services/mediacodec/main_codecservice.cpp
index 79d6da5..62c3dac 100644
--- a/services/mediacodec/main_codecservice.cpp
+++ b/services/mediacodec/main_codecservice.cpp
@@ -28,7 +28,6 @@
#include <android-base/logging.h>
// from LOCAL_C_INCLUDES
-#include "MediaCodecService.h"
#include "minijail.h"
#include <hidl/HidlTransportSupport.h>
@@ -46,10 +45,7 @@
int main(int argc __unused, char** argv)
{
LOG(INFO) << "mediacodecservice starting";
- bool treble = property_get_bool("persist.media.treble_omx", true);
- if (treble) {
- android::ProcessState::initWithDriver("/dev/vndbinder");
- }
+ android::ProcessState::initWithDriver("/dev/vndbinder");
signal(SIGPIPE, SIG_IGN);
SetUpMinijail(kSystemSeccompPolicyPath, kVendorSeccompPolicyPath);
@@ -59,25 +55,20 @@
::android::hardware::configureRpcThreadpool(64, false);
sp<ProcessState> proc(ProcessState::self());
- if (treble) {
- using namespace ::android::hardware::media::omx::V1_0;
- sp<IOmxStore> omxStore = new implementation::OmxStore();
- if (omxStore == nullptr) {
- LOG(ERROR) << "Cannot create IOmxStore HAL service.";
- } else if (omxStore->registerAsService() != OK) {
- LOG(ERROR) << "Cannot register IOmxStore HAL service.";
- }
- sp<IOmx> omx = new implementation::Omx();
- if (omx == nullptr) {
- LOG(ERROR) << "Cannot create IOmx HAL service.";
- } else if (omx->registerAsService() != OK) {
- LOG(ERROR) << "Cannot register IOmx HAL service.";
- } else {
- LOG(INFO) << "Treble OMX service created.";
- }
+ using namespace ::android::hardware::media::omx::V1_0;
+ sp<IOmxStore> omxStore = new implementation::OmxStore();
+ if (omxStore == nullptr) {
+ LOG(ERROR) << "Cannot create IOmxStore HAL service.";
+ } else if (omxStore->registerAsService() != OK) {
+ LOG(ERROR) << "Cannot register IOmxStore HAL service.";
+ }
+ sp<IOmx> omx = new implementation::Omx();
+ if (omx == nullptr) {
+ LOG(ERROR) << "Cannot create IOmx HAL service.";
+ } else if (omx->registerAsService() != OK) {
+ LOG(ERROR) << "Cannot register IOmx HAL service.";
} else {
- MediaCodecService::instantiate();
- LOG(INFO) << "Non-Treble OMX service created.";
+ LOG(INFO) << "IOmx HAL service created.";
}
ProcessState::self()->startThreadPool();
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
index 438a332..dd71ed7 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
@@ -19,6 +19,7 @@
setpriority: 1
sigaltstack: 1
clone: 1
+sched_setscheduler: 1
lseek: 1
newfstatat: 1
faccessat: 1
diff --git a/services/medialog/Android.bp b/services/medialog/Android.bp
new file mode 100644
index 0000000..29e6dfc
--- /dev/null
+++ b/services/medialog/Android.bp
@@ -0,0 +1,22 @@
+cc_library_shared {
+ name: "libmedialogservice",
+
+ srcs: [
+ "IMediaLogService.cpp",
+ "MediaLogService.cpp",
+ ],
+
+ shared_libs: [
+ "libaudioutils",
+ "libbinder",
+ "liblog",
+ "libnbaio",
+ "libnblog",
+ "libutils",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+}
diff --git a/services/medialog/Android.mk b/services/medialog/Android.mk
deleted file mode 100644
index 4f2630e..0000000
--- a/services/medialog/Android.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := MediaLogService.cpp IMediaLogService.cpp
-
-LOCAL_SHARED_LIBRARIES := libbinder libutils liblog libnbaio libnblog libaudioutils
-
-LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-
-LOCAL_MODULE:= libmedialogservice
-
-LOCAL_C_INCLUDES := $(call include-path-for, audio-utils)
-
-LOCAL_CFLAGS := -Werror -Wall
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index f996f74..5518453 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -151,7 +151,7 @@
return nullptr;
} else {
sp<AAudioServiceEndpointMMAP> endpointMMap = new AAudioServiceEndpointMMAP();
- ALOGE("AAudioEndpointManager.openEndpoint(),created MMAP %p", endpointMMap.get());
+ ALOGD("AAudioEndpointManager.openEndpoint(), created MMAP %p", endpointMMap.get());
endpoint = endpointMMap;
aaudio_result_t result = endpoint->open(request);