Merge "Use a status_t return type for GL functors"
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 30be7fa..52a9293 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -4,19 +4,18 @@
LOCAL_SRC_FILES:= \
stagefright.cpp \
+ jpeg.cpp \
SineSource.cpp
LOCAL_SHARED_LIBRARIES := \
libstagefright libmedia libmedia_native libutils libbinder libstagefright_foundation \
- libskia libgui
+ libjpeg libgui
LOCAL_C_INCLUDES:= \
- $(JNI_H_INCLUDE) \
frameworks/base/media/libstagefright \
frameworks/base/media/libstagefright/include \
$(TOP)/frameworks/native/include/media/openmax \
- external/skia/include/core \
- external/skia/include/images \
+ external/jpeg \
LOCAL_CFLAGS += -Wno-multichar
@@ -38,7 +37,6 @@
libstagefright liblog libutils libbinder libstagefright_foundation
LOCAL_C_INCLUDES:= \
- $(JNI_H_INCLUDE) \
frameworks/base/media/libstagefright \
$(TOP)/frameworks/native/include/media/openmax
@@ -62,7 +60,6 @@
libstagefright liblog libutils libbinder libstagefright_foundation
LOCAL_C_INCLUDES:= \
- $(JNI_H_INCLUDE) \
frameworks/base/media/libstagefright \
$(TOP)/frameworks/native/include/media/openmax
@@ -87,7 +84,6 @@
libstagefright liblog libutils libbinder libstagefright_foundation
LOCAL_C_INCLUDES:= \
- $(JNI_H_INCLUDE) \
frameworks/base/media/libstagefright \
$(TOP)/frameworks/native/include/media/openmax
@@ -111,7 +107,6 @@
libstagefright_foundation libmedia libmedia_native
LOCAL_C_INCLUDES:= \
- $(JNI_H_INCLUDE) \
frameworks/base/media/libstagefright \
$(TOP)/frameworks/native/include/media/openmax
@@ -135,7 +130,6 @@
libmedia libmedia_native libgui libcutils libui
LOCAL_C_INCLUDES:= \
- $(JNI_H_INCLUDE) \
frameworks/base/media/libstagefright \
$(TOP)/frameworks/native/include/media/openmax
@@ -160,7 +154,6 @@
libmedia libmedia_native libgui libcutils libui
LOCAL_C_INCLUDES:= \
- $(JNI_H_INCLUDE) \
frameworks/base/media/libstagefright \
$(TOP)/frameworks/native/include/media/openmax
diff --git a/cmds/stagefright/codec.cpp b/cmds/stagefright/codec.cpp
index fea62cc..cf2909e 100644
--- a/cmds/stagefright/codec.cpp
+++ b/cmds/stagefright/codec.cpp
@@ -28,6 +28,7 @@
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaCodecList.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/NuMediaExtractor.h>
#include <gui/SurfaceComposerClient.h>
@@ -36,7 +37,9 @@
fprintf(stderr, "usage: %s [-a] use audio\n"
"\t\t[-v] use video\n"
"\t\t[-p] playback\n"
- "\t\t[-S] allocate buffers from a surface\n", me);
+ "\t\t[-S] allocate buffers from a surface\n"
+ "\t\t[-D] decrypt input buffers\n",
+ me);
exit(1);
}
@@ -63,7 +66,8 @@
const char *path,
bool useAudio,
bool useVideo,
- const android::sp<android::Surface> &surface) {
+ const android::sp<android::Surface> &surface,
+ bool decryptInputBuffers) {
using namespace android;
static int64_t kTimeout = 500ll;
@@ -109,13 +113,31 @@
state->mNumBuffersDecoded = 0;
state->mIsAudio = isAudio;
- state->mCodec = MediaCodec::CreateByType(
- looper, mime.c_str(), false /* encoder */);
+ if (decryptInputBuffers && !isAudio) {
+ static const MediaCodecList *list = MediaCodecList::getInstance();
+
+ ssize_t index =
+ list->findCodecByType(mime.c_str(), false /* encoder */);
+
+ CHECK_GE(index, 0);
+
+ const char *componentName = list->getCodecName(index);
+
+ AString fullName = componentName;
+ fullName.append(".secure");
+
+ state->mCodec = MediaCodec::CreateByComponentName(
+ looper, fullName.c_str());
+ } else {
+ state->mCodec = MediaCodec::CreateByType(
+ looper, mime.c_str(), false /* encoder */);
+ }
CHECK(state->mCodec != NULL);
err = state->mCodec->configure(
- format, isVideo ? surface : NULL, 0 /* flags */);
+ format, isVideo ? surface : NULL,
+ decryptInputBuffers ? MediaCodec::CONFIGURE_FLAG_SECURE : 0);
CHECK_EQ(err, (status_t)OK);
@@ -202,12 +224,24 @@
err = extractor->getSampleTime(&timeUs);
CHECK_EQ(err, (status_t)OK);
+ uint32_t bufferFlags = 0;
+
+ uint32_t sampleFlags;
+ err = extractor->getSampleFlags(&sampleFlags);
+ CHECK_EQ(err, (status_t)OK);
+
+ if (sampleFlags & NuMediaExtractor::SAMPLE_FLAG_ENCRYPTED) {
+ CHECK(decryptInputBuffers);
+
+ bufferFlags |= MediaCodec::BUFFER_FLAG_ENCRYPTED;
+ }
+
err = state->mCodec->queueInputBuffer(
index,
0 /* offset */,
buffer->size(),
timeUs,
- 0 /* flags */);
+ bufferFlags);
CHECK_EQ(err, (status_t)OK);
@@ -341,9 +375,10 @@
bool useVideo = false;
bool playback = false;
bool useSurface = false;
+ bool decryptInputBuffers = false;
int res;
- while ((res = getopt(argc, argv, "havpS")) >= 0) {
+ while ((res = getopt(argc, argv, "havpSD")) >= 0) {
switch (res) {
case 'a':
{
@@ -369,6 +404,12 @@
break;
}
+ case 'D':
+ {
+ decryptInputBuffers = true;
+ break;
+ }
+
case '?':
case 'h':
default:
@@ -440,7 +481,8 @@
player->stop();
player->reset();
} else {
- decode(looper, argv[0], useAudio, useVideo, surface);
+ decode(looper, argv[0],
+ useAudio, useVideo, surface, decryptInputBuffers);
}
if (playback || (useSurface && useVideo)) {
diff --git a/cmds/stagefright/jpeg.cpp b/cmds/stagefright/jpeg.cpp
new file mode 100644
index 0000000..7e859c3
--- /dev/null
+++ b/cmds/stagefright/jpeg.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2012 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 <errno.h>
+#include <setjmp.h>
+#include <stdio.h>
+
+extern "C" {
+#include "jpeglib.h"
+}
+
+static inline uint8_t from565to8(uint16_t p, int start, int bits) {
+ uint8_t c = (p >> start) & ((1 << bits) - 1);
+ return (c << (8 - bits)) | (c >> (bits - (8 - bits)));
+}
+
+struct sf_jpeg_error_mgr {
+ struct jpeg_error_mgr jerr;
+ jmp_buf longjmp_buffer;
+};
+
+void sf_jpeg_error_exit(j_common_ptr cinfo) {
+ struct sf_jpeg_error_mgr *sf_err = (struct sf_jpeg_error_mgr *)cinfo->err;
+ longjmp(sf_err->longjmp_buffer, 0);
+}
+
+int writeJpegFile(const char *filename, uint8_t *frame, int width, int height) {
+ struct sf_jpeg_error_mgr sf_err;
+ struct jpeg_compress_struct cinfo;
+ uint8_t row_data[width * 3];
+ JSAMPROW row_pointer = row_data;
+ FILE *f;
+
+ f = fopen(filename, "w");
+ if (!f) {
+ return -errno;
+ }
+
+ cinfo.err = jpeg_std_error(&sf_err.jerr);
+ sf_err.jerr.error_exit = sf_jpeg_error_exit;
+ if (setjmp(sf_err.longjmp_buffer)) {
+ jpeg_destroy_compress(&cinfo);
+ fclose(f);
+ return -1;
+ }
+
+ jpeg_create_compress(&cinfo);
+ jpeg_stdio_dest(&cinfo, f);
+
+ cinfo.image_width = width;
+ cinfo.image_height = height;
+ cinfo.input_components = 3;
+ cinfo.in_color_space = JCS_RGB;
+
+ jpeg_set_defaults(&cinfo);
+ jpeg_set_quality(&cinfo, 80, TRUE);
+
+ jpeg_start_compress(&cinfo, TRUE);
+
+ for (int row = 0; row < height; row++) {
+ uint16_t *src = (uint16_t *)(frame + row * width * 2);
+ uint8_t *dst = row_data;
+ for (int col = 0; col < width; col++) {
+ dst[0] = from565to8(*src, 11, 5);
+ dst[1] = from565to8(*src, 5, 6);
+ dst[2] = from565to8(*src, 0, 5);
+ dst += 3;
+ src++;
+ }
+ jpeg_write_scanlines(&cinfo, &row_pointer, 1);
+ }
+
+ jpeg_finish_compress(&cinfo);
+ jpeg_destroy_compress(&cinfo);
+
+ fclose(f);
+ return 0;
+}
diff --git a/cmds/stagefright/jpeg.h b/cmds/stagefright/jpeg.h
new file mode 100644
index 0000000..ce86cf2
--- /dev/null
+++ b/cmds/stagefright/jpeg.h
@@ -0,0 +1,6 @@
+#ifndef _STAGEFRIGHT_JPEG_H_
+#define _STAGEFRIGHT_JPEG_H_
+
+int writeJpegFile(const char *filename, uint8_t *frame, int width, int height);
+
+#endif
diff --git a/cmds/stagefright/sf2.cpp b/cmds/stagefright/sf2.cpp
index 64df5d1..3bbfbdc 100644
--- a/cmds/stagefright/sf2.cpp
+++ b/cmds/stagefright/sf2.cpp
@@ -287,6 +287,11 @@
msg->setInt32("channel-count", numChannels);
msg->setInt32("sample-rate", sampleRate);
+
+ int32_t isADTS;
+ if (meta->findInt32(kKeyIsADTS, &isADTS) && isADTS != 0) {
+ msg->setInt32("is-adts", true);
+ }
}
uint32_t type;
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index dab2e0f..d70c862 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -24,6 +24,7 @@
#include <string.h>
#include <unistd.h>
+#include "jpeg.h"
#include "SineSource.h"
#include <binder/IServiceManager.h>
@@ -49,8 +50,6 @@
#include <media/stagefright/MPEG4Writer.h>
#include <private/media/VideoFrame.h>
-#include <SkBitmap.h>
-#include <SkImageEncoder.h>
#include <fcntl.h>
@@ -787,16 +786,9 @@
VideoFrame *frame = (VideoFrame *)mem->pointer();
- SkBitmap bitmap;
- bitmap.setConfig(
- SkBitmap::kRGB_565_Config, frame->mWidth, frame->mHeight);
-
- bitmap.setPixels((uint8_t *)frame + sizeof(VideoFrame));
-
- CHECK(SkImageEncoder::EncodeFile(
- "/sdcard/out.jpg", bitmap,
- SkImageEncoder::kJPEG_Type,
- SkImageEncoder::kDefaultQuality));
+ CHECK_EQ(writeJpegFile("/sdcard/out.jpg",
+ (uint8_t *)frame + sizeof(VideoFrame),
+ frame->mWidth, frame->mHeight), 0);
}
{
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 7df6668..5bfb65b 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -354,7 +354,6 @@
audio_format_t format,
uint32_t channelMask,
int frameCount,
- uint32_t flags,
audio_io_handle_t input);
audio_io_handle_t getInput_l();
status_t restoreRecord_l(audio_track_cblk_t*& cblk);
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 0f39cf3..8239b0e 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -43,6 +43,14 @@
public:
DECLARE_META_INTERFACE(AudioFlinger);
+ // or-able bits shared by createTrack and openRecord, but not all combinations make sense
+ enum {
+ TRACK_DEFAULT = 0, // client requests a default AudioTrack
+ TRACK_TIMED = 1, // client requests a TimedAudioTrack
+ TRACK_FAST = 2, // client requests a fast AudioTrack
+ };
+ typedef uint32_t track_flags_t;
+
/* create an audio track and registers it with AudioFlinger.
* return null if the track cannot be created.
*/
@@ -53,10 +61,9 @@
audio_format_t format,
uint32_t channelMask,
int frameCount,
- uint32_t flags,
+ track_flags_t flags,
const sp<IMemory>& sharedBuffer,
audio_io_handle_t output,
- bool isTimed,
int *sessionId,
status_t *status) = 0;
@@ -67,7 +74,7 @@
audio_format_t format,
uint32_t channelMask,
int frameCount,
- uint32_t flags,
+ track_flags_t flags,
int *sessionId,
status_t *status) = 0;
diff --git a/include/media/ICrypto.h b/include/media/ICrypto.h
new file mode 100644
index 0000000..916abe0
--- /dev/null
+++ b/include/media/ICrypto.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2012 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 <binder/IInterface.h>
+#include <media/stagefright/foundation/ABase.h>
+
+#ifndef ANDROID_ICRYPTO_H_
+
+#define ANDROID_ICRYPTO_H_
+
+namespace android {
+
+struct ICrypto : public IInterface {
+ DECLARE_META_INTERFACE(Crypto);
+
+ virtual status_t initialize() = 0;
+ virtual status_t terminate() = 0;
+
+ virtual status_t setEntitlementKey(
+ const void *key, size_t keyLength) = 0;
+
+ virtual status_t setEntitlementControlMessage(
+ const void *msg, size_t msgLength) = 0;
+
+ // "dstData" is in media_server's address space (but inaccessible).
+ virtual ssize_t decryptVideo(
+ const void *iv, size_t ivLength,
+ const void *srcData, size_t srcDataSize,
+ void *dstData, size_t dstDataOffset) = 0;
+
+ // "dstData" is in the calling process' address space.
+ virtual ssize_t decryptAudio(
+ const void *iv, size_t ivLength,
+ const void *srcData, size_t srcDataSize,
+ void *dstData, size_t dstDataSize) = 0;
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(ICrypto);
+};
+
+struct BnCrypto : public BnInterface<ICrypto> {
+ virtual status_t onTransact(
+ uint32_t code, const Parcel &data, Parcel *reply,
+ uint32_t flags = 0);
+};
+
+} // namespace android
+
+#endif // ANDROID_ICRYPTO_H_
+
diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h
index 4f46fcd..76c45a0 100644
--- a/include/media/IMediaPlayerService.h
+++ b/include/media/IMediaPlayerService.h
@@ -31,6 +31,7 @@
namespace android {
+struct ICrypto;
class IMediaRecorder;
class IOMX;
struct IStreamSource;
@@ -47,6 +48,7 @@
virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat) = 0;
virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat) = 0;
virtual sp<IOMX> getOMX() = 0;
+ virtual sp<ICrypto> makeCrypto() = 0;
// codecs and audio devices usage tracking for the battery app
enum BatteryDataBits {
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index a295e9a..be1b2fc 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -26,8 +26,6 @@
#include <OMX_Core.h>
#include <OMX_Video.h>
-#include "jni.h"
-
namespace android {
class IMemory;
diff --git a/include/media/JetPlayer.h b/include/media/JetPlayer.h
index 38a3e44..0616bf0 100644
--- a/include/media/JetPlayer.h
+++ b/include/media/JetPlayer.h
@@ -18,7 +18,6 @@
#define JETPLAYER_H_
#include <utils/threads.h>
-#include <nativehelper/jni.h>
#include <libsonivox/jet.h>
#include <libsonivox/eas_types.h>
@@ -40,7 +39,7 @@
static const int JET_NUMQUEUEDSEGMENT_UPDATE = 3;
static const int JET_PAUSE_UPDATE = 4;
- JetPlayer(jobject javaJetPlayer,
+ JetPlayer(void *javaJetPlayer,
int maxTracks = 32,
int trackBufferSize = 1200);
~JetPlayer();
@@ -75,7 +74,7 @@
jetevent_callback mEventCallback;
- jobject mJavaJetPlayerRef;
+ void* mJavaJetPlayerRef;
Mutex mMutex; // mutex to sync the render and playback thread with the JET calls
pid_t mTid;
Condition mCondition;
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index fa1a416..7d7af63 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -89,6 +89,10 @@
kPortIndexOutput = 1
};
+ enum {
+ kFlagIsSecure = 1,
+ };
+
struct BufferInfo {
enum Status {
OWNED_BY_US,
@@ -118,6 +122,7 @@
sp<FlushingState> mFlushingState;
AString mComponentName;
+ uint32_t mFlags;
uint32_t mQuirks;
sp<IOMX> mOMX;
IOMX::node_id mNode;
@@ -176,7 +181,8 @@
status_t setupAACCodec(
bool encoder,
- int32_t numChannels, int32_t sampleRate, int32_t bitRate);
+ int32_t numChannels, int32_t sampleRate, int32_t bitRate,
+ bool isADTS);
status_t selectAudioPortFormat(
OMX_U32 portIndex, OMX_AUDIO_CODINGTYPE desiredFormat);
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index 72ac56a..0fc88e1 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -27,18 +27,21 @@
struct ABuffer;
struct ACodec;
struct AMessage;
+struct ICrypto;
struct SoftwareRenderer;
struct SurfaceTextureClient;
struct MediaCodec : public AHandler {
enum ConfigureFlags {
CONFIGURE_FLAG_ENCODE = 1,
+ CONFIGURE_FLAG_SECURE = 2,
};
enum BufferFlags {
BUFFER_FLAG_SYNCFRAME = 1,
BUFFER_FLAG_CODECCONFIG = 2,
BUFFER_FLAG_EOS = 4,
+ BUFFER_FLAG_ENCRYPTED = 8,
};
static sp<MediaCodec> CreateByType(
@@ -137,11 +140,13 @@
kFlagStickyError = 8,
kFlagDequeueInputPending = 16,
kFlagDequeueOutputPending = 32,
+ kFlagIsSecure = 64,
};
struct BufferInfo {
void *mBufferID;
sp<ABuffer> mData;
+ sp<ABuffer> mEncryptedData;
sp<AMessage> mNotify;
bool mOwnedByClient;
};
@@ -165,6 +170,8 @@
int32_t mDequeueOutputTimeoutGeneration;
uint32_t mDequeueOutputReplyID;
+ sp<ICrypto> mCrypto;
+
MediaCodec(const sp<ALooper> &looper);
static status_t PostAndAwaitResponse(
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index c3ccb56..639446e 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -128,6 +128,12 @@
kKeyTextFormatData = 'text', // raw data
kKeyRequiresSecureBuffers = 'secu', // bool (int32_t)
+
+ kKeyScrambling = 'scrm', // int32_t
+ kKeyEMM = 'emm ', // raw data
+ kKeyECM = 'ecm ', // raw data
+
+ kKeyIsADTS = 'adts', // bool (int32_t)
};
enum {
diff --git a/include/media/stagefright/NuMediaExtractor.h b/include/media/stagefright/NuMediaExtractor.h
index 96efdff..07c7be5 100644
--- a/include/media/stagefright/NuMediaExtractor.h
+++ b/include/media/stagefright/NuMediaExtractor.h
@@ -31,6 +31,11 @@
struct MediaSource;
struct NuMediaExtractor : public RefBase {
+ enum SampleFlags {
+ SAMPLE_FLAG_SYNC = 1,
+ SAMPLE_FLAG_ENCRYPTED = 2,
+ };
+
NuMediaExtractor();
status_t setDataSource(const char *path);
@@ -46,6 +51,7 @@
status_t readSampleData(const sp<ABuffer> &buffer);
status_t getSampleTrackIndex(size_t *trackIndex);
status_t getSampleTime(int64_t *sampleTimeUs);
+ status_t getSampleFlags(uint32_t *sampleFlags);
protected:
virtual ~NuMediaExtractor();
@@ -61,7 +67,9 @@
status_t mFinalResult;
MediaBuffer *mSample;
int64_t mSampleTimeUs;
- uint32_t mFlags; // bitmask of "TrackFlags"
+ uint32_t mSampleFlags;
+
+ uint32_t mTrackFlags; // bitmask of "TrackFlags"
};
sp<MediaExtractor> mImpl;
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 7c612ba..7d51dee 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -238,7 +238,11 @@
void setComponentRole();
void setAMRFormat(bool isWAMR, int32_t bitRate);
- status_t setAACFormat(int32_t numChannels, int32_t sampleRate, int32_t bitRate);
+
+ status_t setAACFormat(
+ int32_t numChannels, int32_t sampleRate, int32_t bitRate,
+ bool isADTS);
+
void setG711Format(int32_t numChannels);
status_t setVideoPortFormatType(
diff --git a/include/media/stagefright/SurfaceMediaSource.h b/include/media/stagefright/SurfaceMediaSource.h
index 54baab6..936b057 100644
--- a/include/media/stagefright/SurfaceMediaSource.h
+++ b/include/media/stagefright/SurfaceMediaSource.h
@@ -111,7 +111,7 @@
// Make sure this is called when the mutex is locked
virtual status_t onFrameReceivedLocked();
- virtual status_t setScalingMode(int mode) { } // no op for encoding
+ virtual status_t setScalingMode(int mode) { return OK; } // no op for encoding
virtual int query(int what, int* value);
// Just confirming to the ISurfaceTexture interface as of now
diff --git a/include/media/stagefright/foundation/AString.h b/include/media/stagefright/foundation/AString.h
index 55ade64..0f8f1e1 100644
--- a/include/media/stagefright/foundation/AString.h
+++ b/include/media/stagefright/foundation/AString.h
@@ -73,6 +73,7 @@
int compare(const AString &other) const;
bool startsWith(const char *prefix) const;
+ bool endsWith(const char *suffix) const;
void tolower();
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index 51c8b68..bdb1a1c 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -21,6 +21,7 @@
#include <stdlib.h>
#include <string.h>
#include <new>
+#include <time.h>
#include <audio_effects/effect_visualizer.h>
@@ -47,9 +48,9 @@
VISUALIZER_STATE_ACTIVE,
};
-// maximum number of reads from same buffer before resetting capture buffer. This means
+// maximum time since last capture buffer update before resetting capture buffer. This means
// that the framework has stopped playing audio and we must start returning silence
-#define MAX_STALL_COUNT 10
+#define MAX_STALL_TIME_MS 1000
struct VisualizerContext {
const struct effect_interface_s *mItfe;
@@ -59,7 +60,7 @@
uint8_t mState;
uint8_t mCurrentBuf;
uint8_t mLastBuf;
- uint8_t mStallCount;
+ struct timespec mBufferUpdateTime;
uint8_t mCaptureBuf[2][VISUALIZER_CAPTURE_SIZE_MAX];
};
@@ -72,7 +73,7 @@
pContext->mCaptureIdx = 0;
pContext->mCurrentBuf = 0;
pContext->mLastBuf = 1;
- pContext->mStallCount = 0;
+ pContext->mBufferUpdateTime.tv_sec = 0;
memset(pContext->mCaptureBuf[0], 0x80, VISUALIZER_CAPTURE_SIZE_MAX);
memset(pContext->mCaptureBuf[1], 0x80, VISUALIZER_CAPTURE_SIZE_MAX);
}
@@ -321,6 +322,11 @@
if (pContext->mCaptureIdx == pContext->mCaptureSize) {
pContext->mCurrentBuf ^= 1;
pContext->mCaptureIdx = 0;
+
+ // update last buffer update time stamp
+ if (clock_gettime(CLOCK_MONOTONIC, &pContext->mBufferUpdateTime) < 0) {
+ pContext->mBufferUpdateTime.tv_sec = 0;
+ }
}
if (inBuffer->raw != outBuffer->raw) {
@@ -453,16 +459,25 @@
pContext->mCaptureSize);
// if audio framework has stopped playing audio although the effect is still
// active we must clear the capture buffer to return silence
- if (pContext->mLastBuf == pContext->mCurrentBuf) {
- if (pContext->mStallCount < MAX_STALL_COUNT) {
- if (++pContext->mStallCount == MAX_STALL_COUNT) {
+ if ((pContext->mLastBuf == pContext->mCurrentBuf) &&
+ (pContext->mBufferUpdateTime.tv_sec != 0)) {
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+ time_t secs = ts.tv_sec - pContext->mBufferUpdateTime.tv_sec;
+ long nsec = ts.tv_nsec - pContext->mBufferUpdateTime.tv_nsec;
+ if (nsec < 0) {
+ --secs;
+ nsec += 1000000000;
+ }
+ uint32_t deltaMs = secs * 1000 + nsec / 1000000;
+ if (deltaMs > MAX_STALL_TIME_MS) {
+ ALOGV("capture going to idle");
+ pContext->mBufferUpdateTime.tv_sec = 0;
memset(pContext->mCaptureBuf[pContext->mCurrentBuf ^ 1],
0x80,
pContext->mCaptureSize);
}
}
- } else {
- pContext->mStallCount = 0;
}
pContext->mLastBuf = pContext->mCurrentBuf;
} else {
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 21e8f29..c8e1dc7 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -17,6 +17,7 @@
IAudioFlingerClient.cpp \
IAudioTrack.cpp \
IAudioRecord.cpp \
+ ICrypto.cpp \
AudioRecord.cpp \
AudioSystem.cpp \
mediaplayer.cpp \
@@ -43,7 +44,9 @@
IEffectClient.cpp \
AudioEffect.cpp \
Visualizer.cpp \
- MemoryLeakTrackUtil.cpp
+ MemoryLeakTrackUtil.cpp \
+ SoundPool.cpp \
+ SoundPoolThread.cpp
LOCAL_SHARED_LIBRARIES := \
libui libcutils libutils libbinder libsonivox libicuuc libexpat \
@@ -55,7 +58,6 @@
LOCAL_MODULE:= libmedia
LOCAL_C_INCLUDES := \
- $(JNI_H_INCLUDE) \
$(call include-path-for, graphics corecg) \
$(TOP)/frameworks/native/include/media/openmax \
external/icu4c/common \
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 05ade75..70ec593 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -201,7 +201,7 @@
// create the IAudioRecord
status = openRecord_l(sampleRate, format, channelMask,
- frameCount, flags, input);
+ frameCount, input);
if (status != NO_ERROR) {
return status;
}
@@ -458,7 +458,6 @@
audio_format_t format,
uint32_t channelMask,
int frameCount,
- uint32_t flags,
audio_io_handle_t input)
{
status_t status;
@@ -471,7 +470,7 @@
sampleRate, format,
channelMask,
frameCount,
- ((uint16_t)flags) << 16,
+ IAudioFlinger::TRACK_DEFAULT,
&mSessionId,
&status);
@@ -778,7 +777,7 @@
// following member variables: mAudioRecord, mCblkMemory and mCblk.
// It will also delete the strong references on previous IAudioRecord and IMemory
result = openRecord_l(cblk->sampleRate, mFormat, mChannelMask,
- mFrameCount, mFlags, getInput_l());
+ mFrameCount, getInput_l());
if (result == NO_ERROR) {
result = mAudioRecord->start(0); // callback thread hasn't changed
}
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 50fbf36..bafde3a 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -803,16 +803,19 @@
}
}
+ IAudioFlinger::track_flags_t trackFlags = IAudioFlinger::TRACK_DEFAULT;
+ if (mIsTimed) {
+ trackFlags |= IAudioFlinger::TRACK_TIMED;
+ }
sp<IAudioTrack> track = audioFlinger->createTrack(getpid(),
streamType,
sampleRate,
format,
channelMask,
frameCount,
- ((uint16_t)flags) << 16,
+ trackFlags,
sharedBuffer,
output,
- mIsTimed,
&mSessionId,
&status);
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index 07b12e4..ce10c8e 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -87,10 +87,9 @@
audio_format_t format,
uint32_t channelMask,
int frameCount,
- uint32_t flags,
+ track_flags_t flags,
const sp<IMemory>& sharedBuffer,
audio_io_handle_t output,
- bool isTimed,
int *sessionId,
status_t *status)
{
@@ -103,10 +102,9 @@
data.writeInt32(format);
data.writeInt32(channelMask);
data.writeInt32(frameCount);
- data.writeInt32(flags);
+ data.writeInt32((int32_t) flags);
data.writeStrongBinder(sharedBuffer->asBinder());
data.writeInt32((int32_t) output);
- data.writeInt32(isTimed);
int lSessionId = 0;
if (sessionId != NULL) {
lSessionId = *sessionId;
@@ -136,7 +134,7 @@
audio_format_t format,
uint32_t channelMask,
int frameCount,
- uint32_t flags,
+ track_flags_t flags,
int *sessionId,
status_t *status)
{
@@ -688,15 +686,14 @@
audio_format_t format = (audio_format_t) data.readInt32();
int channelCount = data.readInt32();
size_t bufferCount = data.readInt32();
- uint32_t flags = data.readInt32();
+ track_flags_t flags = (track_flags_t) data.readInt32();
sp<IMemory> buffer = interface_cast<IMemory>(data.readStrongBinder());
audio_io_handle_t output = (audio_io_handle_t) data.readInt32();
- bool isTimed = data.readInt32();
int sessionId = data.readInt32();
status_t status;
sp<IAudioTrack> track = createTrack(pid,
(audio_stream_type_t) streamType, sampleRate, format,
- channelCount, bufferCount, flags, buffer, output, isTimed, &sessionId, &status);
+ channelCount, bufferCount, flags, buffer, output, &sessionId, &status);
reply->writeInt32(sessionId);
reply->writeInt32(status);
reply->writeStrongBinder(track->asBinder());
@@ -710,7 +707,7 @@
audio_format_t format = (audio_format_t) data.readInt32();
int channelCount = data.readInt32();
size_t bufferCount = data.readInt32();
- uint32_t flags = data.readInt32();
+ track_flags_t flags = (track_flags_t) data.readInt32();
int sessionId = data.readInt32();
status_t status;
sp<IAudioRecord> record = openRecord(pid, input,
diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp
new file mode 100644
index 0000000..827d7af
--- /dev/null
+++ b/media/libmedia/ICrypto.cpp
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2012 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 "ICrypto"
+#include <utils/Log.h>
+
+#include <binder/Parcel.h>
+#include <media/ICrypto.h>
+#include <media/stagefright/foundation/ADebug.h>
+
+namespace android {
+
+enum {
+ INITIALIZE = IBinder::FIRST_CALL_TRANSACTION,
+ TERMINATE,
+ SET_ENTITLEMENT_KEY,
+ SET_ECM,
+ DECRYPT_VIDEO,
+ DECRYPT_AUDIO,
+};
+
+struct BpCrypto : public BpInterface<ICrypto> {
+ BpCrypto(const sp<IBinder> &impl)
+ : BpInterface<ICrypto>(impl) {
+ }
+
+ virtual status_t initialize() {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
+ remote()->transact(INITIALIZE, data, &reply);
+
+ return reply.readInt32();
+ }
+
+ virtual status_t terminate() {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
+ remote()->transact(TERMINATE, data, &reply);
+
+ return reply.readInt32();
+ }
+
+ virtual status_t setEntitlementKey(
+ const void *key, size_t keyLength) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
+ data.writeInt32(keyLength);
+ data.write(key, keyLength);
+ remote()->transact(SET_ENTITLEMENT_KEY, data, &reply);
+
+ return reply.readInt32();
+ }
+
+ virtual status_t setEntitlementControlMessage(
+ const void *msg, size_t msgLength) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
+ data.writeInt32(msgLength);
+ data.write(msg, msgLength);
+ remote()->transact(SET_ECM, data, &reply);
+
+ return reply.readInt32();
+ }
+
+ virtual ssize_t decryptVideo(
+ const void *iv, size_t ivLength,
+ const void *srcData, size_t srcDataSize,
+ void *dstData, size_t dstDataOffset) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
+ if (iv == NULL) {
+ if (ivLength > 0) {
+ return -EINVAL;
+ }
+
+ data.writeInt32(-1);
+ } else {
+ data.writeInt32(ivLength);
+ data.write(iv, ivLength);
+ }
+
+ data.writeInt32(srcDataSize);
+ data.write(srcData, srcDataSize);
+
+ data.writeIntPtr((intptr_t)dstData);
+ data.writeInt32(dstDataOffset);
+
+ remote()->transact(DECRYPT_VIDEO, data, &reply);
+
+ return reply.readInt32();
+ }
+
+ virtual ssize_t decryptAudio(
+ const void *iv, size_t ivLength,
+ const void *srcData, size_t srcDataSize,
+ void *dstData, size_t dstDataSize) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
+ if (iv == NULL) {
+ if (ivLength > 0) {
+ return -EINVAL;
+ }
+
+ data.writeInt32(-1);
+ } else {
+ data.writeInt32(ivLength);
+ data.write(iv, ivLength);
+ }
+
+ data.writeInt32(srcDataSize);
+ data.write(srcData, srcDataSize);
+ data.writeInt32(dstDataSize);
+
+ remote()->transact(DECRYPT_AUDIO, data, &reply);
+
+ ssize_t res = reply.readInt32();
+
+ if (res <= 0) {
+ return res;
+ }
+
+ reply.read(dstData, res);
+
+ return res;
+ }
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(BpCrypto);
+};
+
+IMPLEMENT_META_INTERFACE(Crypto, "android.hardware.ICrypto");
+
+////////////////////////////////////////////////////////////////////////////////
+
+status_t BnCrypto::onTransact(
+ uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
+ switch (code) {
+ case INITIALIZE:
+ {
+ CHECK_INTERFACE(ICrypto, data, reply);
+ reply->writeInt32(initialize());
+
+ return OK;
+ }
+
+ case TERMINATE:
+ {
+ CHECK_INTERFACE(ICrypto, data, reply);
+ reply->writeInt32(terminate());
+
+ return OK;
+ }
+
+ case SET_ENTITLEMENT_KEY:
+ {
+ CHECK_INTERFACE(ICrypto, data, reply);
+
+ size_t keyLength = data.readInt32();
+ void *key = malloc(keyLength);
+ data.read(key, keyLength);
+
+ reply->writeInt32(setEntitlementKey(key, keyLength));
+
+ free(key);
+ key = NULL;
+
+ return OK;
+ }
+
+ case SET_ECM:
+ {
+ CHECK_INTERFACE(ICrypto, data, reply);
+
+ size_t msgLength = data.readInt32();
+ void *msg = malloc(msgLength);
+ data.read(msg, msgLength);
+
+ reply->writeInt32(setEntitlementControlMessage(msg, msgLength));
+
+ free(msg);
+ msg = NULL;
+
+ return OK;
+ }
+
+ case DECRYPT_VIDEO:
+ {
+ CHECK_INTERFACE(ICrypto, data, reply);
+
+ void *iv = NULL;
+
+ int32_t ivLength = data.readInt32();
+ if (ivLength >= 0) {
+ iv = malloc(ivLength);
+ data.read(iv, ivLength);
+ }
+
+ size_t srcDataSize = data.readInt32();
+ void *srcData = malloc(srcDataSize);
+ data.read(srcData, srcDataSize);
+
+ void *dstData = (void *)data.readIntPtr();
+ size_t dstDataOffset = data.readInt32();
+
+ reply->writeInt32(
+ decryptVideo(
+ iv,
+ ivLength < 0 ? 0 : ivLength,
+ srcData,
+ srcDataSize,
+ dstData,
+ dstDataOffset));
+
+ free(srcData);
+ srcData = NULL;
+
+ if (iv != NULL) {
+ free(iv);
+ iv = NULL;
+ }
+
+ return OK;
+ }
+
+ case DECRYPT_AUDIO:
+ {
+ CHECK_INTERFACE(ICrypto, data, reply);
+
+ void *iv = NULL;
+
+ int32_t ivLength = data.readInt32();
+ if (ivLength >= 0) {
+ iv = malloc(ivLength);
+ data.read(iv, ivLength);
+ }
+
+ size_t srcDataSize = data.readInt32();
+ void *srcData = malloc(srcDataSize);
+ data.read(srcData, srcDataSize);
+
+ size_t dstDataSize = data.readInt32();
+ void *dstData = malloc(dstDataSize);
+
+ ssize_t res =
+ decryptAudio(
+ iv,
+ ivLength < 0 ? 0 : ivLength,
+ srcData,
+ srcDataSize,
+ dstData,
+ dstDataSize);
+
+ reply->writeInt32(res);
+
+ if (res > 0) {
+ reply->write(dstData, res);
+ }
+
+ free(dstData);
+ dstData = NULL;
+
+ free(srcData);
+ srcData = NULL;
+
+ if (iv != NULL) {
+ free(iv);
+ iv = NULL;
+ }
+
+ return OK;
+ }
+
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+} // namespace android
+
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index 9b8d7c3..7e6d54b 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -18,7 +18,6 @@
#include <stdint.h>
#include <sys/types.h>
#include <binder/Parcel.h>
-#include <SkBitmap.h>
#include <media/IMediaMetadataRetriever.h>
#include <utils/String8.h>
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index f5fccef..9120617 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -20,6 +20,7 @@
#include <binder/Parcel.h>
#include <binder/IMemory.h>
+#include <media/ICrypto.h>
#include <media/IMediaPlayerService.h>
#include <media/IMediaRecorder.h>
#include <media/IOMX.h>
@@ -36,6 +37,7 @@
CREATE_MEDIA_RECORDER,
CREATE_METADATA_RETRIEVER,
GET_OMX,
+ MAKE_CRYPTO,
ADD_BATTERY_DATA,
PULL_BATTERY_DATA
};
@@ -111,6 +113,13 @@
return interface_cast<IOMX>(reply.readStrongBinder());
}
+ virtual sp<ICrypto> makeCrypto() {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
+ remote()->transact(MAKE_CRYPTO, data, &reply);
+ return interface_cast<ICrypto>(reply.readStrongBinder());
+ }
+
virtual void addBatteryData(uint32_t params) {
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
@@ -191,6 +200,12 @@
reply->writeStrongBinder(omx->asBinder());
return NO_ERROR;
} break;
+ case MAKE_CRYPTO: {
+ CHECK_INTERFACE(IMediaPlayerService, data, reply);
+ sp<ICrypto> crypto = makeCrypto();
+ reply->writeStrongBinder(crypto->asBinder());
+ return NO_ERROR;
+ } break;
case ADD_BATTERY_DATA: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
uint32_t params = data.readInt32();
diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp
index 7fa6bb7..52aee49 100644
--- a/media/libmedia/JetPlayer.cpp
+++ b/media/libmedia/JetPlayer.cpp
@@ -30,7 +30,7 @@
static const S_EAS_LIB_CONFIG* pLibConfig = NULL;
//-------------------------------------------------------------------------------------------------
-JetPlayer::JetPlayer(jobject javaJetPlayer, int maxTracks, int trackBufferSize) :
+JetPlayer::JetPlayer(void *javaJetPlayer, int maxTracks, int trackBufferSize) :
mEventCallback(NULL),
mJavaJetPlayerRef(javaJetPlayer),
mTid(-1),
diff --git a/media/libmedia/SoundPool.cpp b/media/libmedia/SoundPool.cpp
new file mode 100644
index 0000000..306c57d
--- /dev/null
+++ b/media/libmedia/SoundPool.cpp
@@ -0,0 +1,908 @@
+/*
+ * Copyright (C) 2007 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 "SoundPool"
+#include <utils/Log.h>
+
+//#define USE_SHARED_MEM_BUFFER
+
+// XXX needed for timing latency
+#include <utils/Timers.h>
+
+#include <media/AudioTrack.h>
+#include <media/mediaplayer.h>
+
+#include <system/audio.h>
+
+#include "SoundPool.h"
+#include "SoundPoolThread.h"
+
+namespace android
+{
+
+int kDefaultBufferCount = 4;
+uint32_t kMaxSampleRate = 48000;
+uint32_t kDefaultSampleRate = 44100;
+uint32_t kDefaultFrameCount = 1200;
+
+SoundPool::SoundPool(int maxChannels, audio_stream_type_t streamType, int srcQuality)
+{
+ ALOGV("SoundPool constructor: maxChannels=%d, streamType=%d, srcQuality=%d",
+ maxChannels, streamType, srcQuality);
+
+ // check limits
+ mMaxChannels = maxChannels;
+ if (mMaxChannels < 1) {
+ mMaxChannels = 1;
+ }
+ else if (mMaxChannels > 32) {
+ mMaxChannels = 32;
+ }
+ ALOGW_IF(maxChannels != mMaxChannels, "App requested %d channels", maxChannels);
+
+ mQuit = false;
+ mDecodeThread = 0;
+ mStreamType = streamType;
+ mSrcQuality = srcQuality;
+ mAllocated = 0;
+ mNextSampleID = 0;
+ mNextChannelID = 0;
+
+ mCallback = 0;
+ mUserData = 0;
+
+ mChannelPool = new SoundChannel[mMaxChannels];
+ for (int i = 0; i < mMaxChannels; ++i) {
+ mChannelPool[i].init(this);
+ mChannels.push_back(&mChannelPool[i]);
+ }
+
+ // start decode thread
+ startThreads();
+}
+
+SoundPool::~SoundPool()
+{
+ ALOGV("SoundPool destructor");
+ mDecodeThread->quit();
+ quit();
+
+ Mutex::Autolock lock(&mLock);
+
+ mChannels.clear();
+ if (mChannelPool)
+ delete [] mChannelPool;
+ // clean up samples
+ ALOGV("clear samples");
+ mSamples.clear();
+
+ if (mDecodeThread)
+ delete mDecodeThread;
+}
+
+void SoundPool::addToRestartList(SoundChannel* channel)
+{
+ Mutex::Autolock lock(&mRestartLock);
+ if (!mQuit) {
+ mRestart.push_back(channel);
+ mCondition.signal();
+ }
+}
+
+void SoundPool::addToStopList(SoundChannel* channel)
+{
+ Mutex::Autolock lock(&mRestartLock);
+ if (!mQuit) {
+ mStop.push_back(channel);
+ mCondition.signal();
+ }
+}
+
+int SoundPool::beginThread(void* arg)
+{
+ SoundPool* p = (SoundPool*)arg;
+ return p->run();
+}
+
+int SoundPool::run()
+{
+ mRestartLock.lock();
+ while (!mQuit) {
+ mCondition.wait(mRestartLock);
+ ALOGV("awake");
+ if (mQuit) break;
+
+ while (!mStop.empty()) {
+ SoundChannel* channel;
+ ALOGV("Getting channel from stop list");
+ List<SoundChannel* >::iterator iter = mStop.begin();
+ channel = *iter;
+ mStop.erase(iter);
+ mRestartLock.unlock();
+ if (channel != 0) {
+ Mutex::Autolock lock(&mLock);
+ channel->stop();
+ }
+ mRestartLock.lock();
+ if (mQuit) break;
+ }
+
+ while (!mRestart.empty()) {
+ SoundChannel* channel;
+ ALOGV("Getting channel from list");
+ List<SoundChannel*>::iterator iter = mRestart.begin();
+ channel = *iter;
+ mRestart.erase(iter);
+ mRestartLock.unlock();
+ if (channel != 0) {
+ Mutex::Autolock lock(&mLock);
+ channel->nextEvent();
+ }
+ mRestartLock.lock();
+ if (mQuit) break;
+ }
+ }
+
+ mStop.clear();
+ mRestart.clear();
+ mCondition.signal();
+ mRestartLock.unlock();
+ ALOGV("goodbye");
+ return 0;
+}
+
+void SoundPool::quit()
+{
+ mRestartLock.lock();
+ mQuit = true;
+ mCondition.signal();
+ mCondition.wait(mRestartLock);
+ ALOGV("return from quit");
+ mRestartLock.unlock();
+}
+
+bool SoundPool::startThreads()
+{
+ createThreadEtc(beginThread, this, "SoundPool");
+ if (mDecodeThread == NULL)
+ mDecodeThread = new SoundPoolThread(this);
+ return mDecodeThread != NULL;
+}
+
+SoundChannel* SoundPool::findChannel(int channelID)
+{
+ for (int i = 0; i < mMaxChannels; ++i) {
+ if (mChannelPool[i].channelID() == channelID) {
+ return &mChannelPool[i];
+ }
+ }
+ return NULL;
+}
+
+SoundChannel* SoundPool::findNextChannel(int channelID)
+{
+ for (int i = 0; i < mMaxChannels; ++i) {
+ if (mChannelPool[i].nextChannelID() == channelID) {
+ return &mChannelPool[i];
+ }
+ }
+ return NULL;
+}
+
+int SoundPool::load(const char* path, int priority)
+{
+ ALOGV("load: path=%s, priority=%d", path, priority);
+ Mutex::Autolock lock(&mLock);
+ sp<Sample> sample = new Sample(++mNextSampleID, path);
+ mSamples.add(sample->sampleID(), sample);
+ doLoad(sample);
+ return sample->sampleID();
+}
+
+int SoundPool::load(int fd, int64_t offset, int64_t length, int priority)
+{
+ ALOGV("load: fd=%d, offset=%lld, length=%lld, priority=%d",
+ fd, offset, length, priority);
+ Mutex::Autolock lock(&mLock);
+ sp<Sample> sample = new Sample(++mNextSampleID, fd, offset, length);
+ mSamples.add(sample->sampleID(), sample);
+ doLoad(sample);
+ return sample->sampleID();
+}
+
+void SoundPool::doLoad(sp<Sample>& sample)
+{
+ ALOGV("doLoad: loading sample sampleID=%d", sample->sampleID());
+ sample->startLoad();
+ mDecodeThread->loadSample(sample->sampleID());
+}
+
+bool SoundPool::unload(int sampleID)
+{
+ ALOGV("unload: sampleID=%d", sampleID);
+ Mutex::Autolock lock(&mLock);
+ return mSamples.removeItem(sampleID);
+}
+
+int SoundPool::play(int sampleID, float leftVolume, float rightVolume,
+ int priority, int loop, float rate)
+{
+ ALOGV("play sampleID=%d, leftVolume=%f, rightVolume=%f, priority=%d, loop=%d, rate=%f",
+ sampleID, leftVolume, rightVolume, priority, loop, rate);
+ sp<Sample> sample;
+ SoundChannel* channel;
+ int channelID;
+
+ Mutex::Autolock lock(&mLock);
+
+ if (mQuit) {
+ return 0;
+ }
+ // is sample ready?
+ sample = findSample(sampleID);
+ if ((sample == 0) || (sample->state() != Sample::READY)) {
+ ALOGW(" sample %d not READY", sampleID);
+ return 0;
+ }
+
+ dump();
+
+ // allocate a channel
+ channel = allocateChannel_l(priority);
+
+ // no channel allocated - return 0
+ if (!channel) {
+ ALOGV("No channel allocated");
+ return 0;
+ }
+
+ channelID = ++mNextChannelID;
+
+ ALOGV("play channel %p state = %d", channel, channel->state());
+ channel->play(sample, channelID, leftVolume, rightVolume, priority, loop, rate);
+ return channelID;
+}
+
+SoundChannel* SoundPool::allocateChannel_l(int priority)
+{
+ List<SoundChannel*>::iterator iter;
+ SoundChannel* channel = NULL;
+
+ // allocate a channel
+ if (!mChannels.empty()) {
+ iter = mChannels.begin();
+ if (priority >= (*iter)->priority()) {
+ channel = *iter;
+ mChannels.erase(iter);
+ ALOGV("Allocated active channel");
+ }
+ }
+
+ // update priority and put it back in the list
+ if (channel) {
+ channel->setPriority(priority);
+ for (iter = mChannels.begin(); iter != mChannels.end(); ++iter) {
+ if (priority < (*iter)->priority()) {
+ break;
+ }
+ }
+ mChannels.insert(iter, channel);
+ }
+ return channel;
+}
+
+// move a channel from its current position to the front of the list
+void SoundPool::moveToFront_l(SoundChannel* channel)
+{
+ for (List<SoundChannel*>::iterator iter = mChannels.begin(); iter != mChannels.end(); ++iter) {
+ if (*iter == channel) {
+ mChannels.erase(iter);
+ mChannels.push_front(channel);
+ break;
+ }
+ }
+}
+
+void SoundPool::pause(int channelID)
+{
+ ALOGV("pause(%d)", channelID);
+ Mutex::Autolock lock(&mLock);
+ SoundChannel* channel = findChannel(channelID);
+ if (channel) {
+ channel->pause();
+ }
+}
+
+void SoundPool::autoPause()
+{
+ ALOGV("autoPause()");
+ Mutex::Autolock lock(&mLock);
+ for (int i = 0; i < mMaxChannels; ++i) {
+ SoundChannel* channel = &mChannelPool[i];
+ channel->autoPause();
+ }
+}
+
+void SoundPool::resume(int channelID)
+{
+ ALOGV("resume(%d)", channelID);
+ Mutex::Autolock lock(&mLock);
+ SoundChannel* channel = findChannel(channelID);
+ if (channel) {
+ channel->resume();
+ }
+}
+
+void SoundPool::autoResume()
+{
+ ALOGV("autoResume()");
+ Mutex::Autolock lock(&mLock);
+ for (int i = 0; i < mMaxChannels; ++i) {
+ SoundChannel* channel = &mChannelPool[i];
+ channel->autoResume();
+ }
+}
+
+void SoundPool::stop(int channelID)
+{
+ ALOGV("stop(%d)", channelID);
+ Mutex::Autolock lock(&mLock);
+ SoundChannel* channel = findChannel(channelID);
+ if (channel) {
+ channel->stop();
+ } else {
+ channel = findNextChannel(channelID);
+ if (channel)
+ channel->clearNextEvent();
+ }
+}
+
+void SoundPool::setVolume(int channelID, float leftVolume, float rightVolume)
+{
+ Mutex::Autolock lock(&mLock);
+ SoundChannel* channel = findChannel(channelID);
+ if (channel) {
+ channel->setVolume(leftVolume, rightVolume);
+ }
+}
+
+void SoundPool::setPriority(int channelID, int priority)
+{
+ ALOGV("setPriority(%d, %d)", channelID, priority);
+ Mutex::Autolock lock(&mLock);
+ SoundChannel* channel = findChannel(channelID);
+ if (channel) {
+ channel->setPriority(priority);
+ }
+}
+
+void SoundPool::setLoop(int channelID, int loop)
+{
+ ALOGV("setLoop(%d, %d)", channelID, loop);
+ Mutex::Autolock lock(&mLock);
+ SoundChannel* channel = findChannel(channelID);
+ if (channel) {
+ channel->setLoop(loop);
+ }
+}
+
+void SoundPool::setRate(int channelID, float rate)
+{
+ ALOGV("setRate(%d, %f)", channelID, rate);
+ Mutex::Autolock lock(&mLock);
+ SoundChannel* channel = findChannel(channelID);
+ if (channel) {
+ channel->setRate(rate);
+ }
+}
+
+// call with lock held
+void SoundPool::done_l(SoundChannel* channel)
+{
+ ALOGV("done_l(%d)", channel->channelID());
+ // if "stolen", play next event
+ if (channel->nextChannelID() != 0) {
+ ALOGV("add to restart list");
+ addToRestartList(channel);
+ }
+
+ // return to idle state
+ else {
+ ALOGV("move to front");
+ moveToFront_l(channel);
+ }
+}
+
+void SoundPool::setCallback(SoundPoolCallback* callback, void* user)
+{
+ Mutex::Autolock lock(&mCallbackLock);
+ mCallback = callback;
+ mUserData = user;
+}
+
+void SoundPool::notify(SoundPoolEvent event)
+{
+ Mutex::Autolock lock(&mCallbackLock);
+ if (mCallback != NULL) {
+ mCallback(event, this, mUserData);
+ }
+}
+
+void SoundPool::dump()
+{
+ for (int i = 0; i < mMaxChannels; ++i) {
+ mChannelPool[i].dump();
+ }
+}
+
+
+Sample::Sample(int sampleID, const char* url)
+{
+ init();
+ mSampleID = sampleID;
+ mUrl = strdup(url);
+ ALOGV("create sampleID=%d, url=%s", mSampleID, mUrl);
+}
+
+Sample::Sample(int sampleID, int fd, int64_t offset, int64_t length)
+{
+ init();
+ mSampleID = sampleID;
+ mFd = dup(fd);
+ mOffset = offset;
+ mLength = length;
+ ALOGV("create sampleID=%d, fd=%d, offset=%lld, length=%lld", mSampleID, mFd, mLength, mOffset);
+}
+
+void Sample::init()
+{
+ mData = 0;
+ mSize = 0;
+ mRefCount = 0;
+ mSampleID = 0;
+ mState = UNLOADED;
+ mFd = -1;
+ mOffset = 0;
+ mLength = 0;
+ mUrl = 0;
+}
+
+Sample::~Sample()
+{
+ ALOGV("Sample::destructor sampleID=%d, fd=%d", mSampleID, mFd);
+ if (mFd > 0) {
+ ALOGV("close(%d)", mFd);
+ ::close(mFd);
+ }
+ mData.clear();
+ delete mUrl;
+}
+
+status_t Sample::doLoad()
+{
+ uint32_t sampleRate;
+ int numChannels;
+ audio_format_t format;
+ sp<IMemory> p;
+ ALOGV("Start decode");
+ if (mUrl) {
+ p = MediaPlayer::decode(mUrl, &sampleRate, &numChannels, &format);
+ } else {
+ p = MediaPlayer::decode(mFd, mOffset, mLength, &sampleRate, &numChannels, &format);
+ ALOGV("close(%d)", mFd);
+ ::close(mFd);
+ mFd = -1;
+ }
+ if (p == 0) {
+ ALOGE("Unable to load sample: %s", mUrl);
+ return -1;
+ }
+ ALOGV("pointer = %p, size = %u, sampleRate = %u, numChannels = %d",
+ p->pointer(), p->size(), sampleRate, numChannels);
+
+ if (sampleRate > kMaxSampleRate) {
+ ALOGE("Sample rate (%u) out of range", sampleRate);
+ return - 1;
+ }
+
+ if ((numChannels < 1) || (numChannels > 2)) {
+ ALOGE("Sample channel count (%d) out of range", numChannels);
+ return - 1;
+ }
+
+ //_dumpBuffer(p->pointer(), p->size());
+ uint8_t* q = static_cast<uint8_t*>(p->pointer()) + p->size() - 10;
+ //_dumpBuffer(q, 10, 10, false);
+
+ mData = p;
+ mSize = p->size();
+ mSampleRate = sampleRate;
+ mNumChannels = numChannels;
+ mFormat = format;
+ mState = READY;
+ return 0;
+}
+
+
+void SoundChannel::init(SoundPool* soundPool)
+{
+ mSoundPool = soundPool;
+}
+
+// call with sound pool lock held
+void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftVolume,
+ float rightVolume, int priority, int loop, float rate)
+{
+ AudioTrack* oldTrack;
+ AudioTrack* newTrack;
+ status_t status;
+
+ { // scope for the lock
+ Mutex::Autolock lock(&mLock);
+
+ ALOGV("SoundChannel::play %p: sampleID=%d, channelID=%d, leftVolume=%f, rightVolume=%f,"
+ " priority=%d, loop=%d, rate=%f",
+ this, sample->sampleID(), nextChannelID, leftVolume, rightVolume,
+ priority, loop, rate);
+
+ // if not idle, this voice is being stolen
+ if (mState != IDLE) {
+ ALOGV("channel %d stolen - event queued for channel %d", channelID(), nextChannelID);
+ mNextEvent.set(sample, nextChannelID, leftVolume, rightVolume, priority, loop, rate);
+ stop_l();
+ return;
+ }
+
+ // initialize track
+ int afFrameCount;
+ int afSampleRate;
+ audio_stream_type_t streamType = mSoundPool->streamType();
+ if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
+ afFrameCount = kDefaultFrameCount;
+ }
+ if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
+ afSampleRate = kDefaultSampleRate;
+ }
+ int numChannels = sample->numChannels();
+ uint32_t sampleRate = uint32_t(float(sample->sampleRate()) * rate + 0.5);
+ uint32_t totalFrames = (kDefaultBufferCount * afFrameCount * sampleRate) / afSampleRate;
+ uint32_t bufferFrames = (totalFrames + (kDefaultBufferCount - 1)) / kDefaultBufferCount;
+ uint32_t frameCount = 0;
+
+ if (loop) {
+ frameCount = sample->size()/numChannels/
+ ((sample->format() == AUDIO_FORMAT_PCM_16_BIT) ? sizeof(int16_t) : sizeof(uint8_t));
+ }
+
+#ifndef USE_SHARED_MEM_BUFFER
+ // Ensure minimum audio buffer size in case of short looped sample
+ if(frameCount < totalFrames) {
+ frameCount = totalFrames;
+ }
+#endif
+
+ // mToggle toggles each time a track is started on a given channel.
+ // The toggle is concatenated with the SoundChannel address and passed to AudioTrack
+ // as callback user data. This enables the detection of callbacks received from the old
+ // audio track while the new one is being started and avoids processing them with
+ // wrong audio audio buffer size (mAudioBufferSize)
+ unsigned long toggle = mToggle ^ 1;
+ void *userData = (void *)((unsigned long)this | toggle);
+ uint32_t channels = (numChannels == 2) ?
+ AUDIO_CHANNEL_OUT_STEREO : AUDIO_CHANNEL_OUT_MONO;
+
+ // do not create a new audio track if current track is compatible with sample parameters
+#ifdef USE_SHARED_MEM_BUFFER
+ newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
+ channels, sample->getIMemory(), AUDIO_POLICY_OUTPUT_FLAG_NONE, callback, userData);
+#else
+ newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
+ channels, frameCount, AUDIO_POLICY_OUTPUT_FLAG_NONE, callback, userData,
+ bufferFrames);
+#endif
+ oldTrack = mAudioTrack;
+ status = newTrack->initCheck();
+ if (status != NO_ERROR) {
+ ALOGE("Error creating AudioTrack");
+ goto exit;
+ }
+ ALOGV("setVolume %p", newTrack);
+ newTrack->setVolume(leftVolume, rightVolume);
+ newTrack->setLoop(0, frameCount, loop);
+
+ // From now on, AudioTrack callbacks received with previous toggle value will be ignored.
+ mToggle = toggle;
+ mAudioTrack = newTrack;
+ mPos = 0;
+ mSample = sample;
+ mChannelID = nextChannelID;
+ mPriority = priority;
+ mLoop = loop;
+ mLeftVolume = leftVolume;
+ mRightVolume = rightVolume;
+ mNumChannels = numChannels;
+ mRate = rate;
+ clearNextEvent();
+ mState = PLAYING;
+ mAudioTrack->start();
+ mAudioBufferSize = newTrack->frameCount()*newTrack->frameSize();
+ }
+
+exit:
+ ALOGV("delete oldTrack %p", oldTrack);
+ delete oldTrack;
+ if (status != NO_ERROR) {
+ delete newTrack;
+ mAudioTrack = NULL;
+ }
+}
+
+void SoundChannel::nextEvent()
+{
+ sp<Sample> sample;
+ int nextChannelID;
+ float leftVolume;
+ float rightVolume;
+ int priority;
+ int loop;
+ float rate;
+
+ // check for valid event
+ {
+ Mutex::Autolock lock(&mLock);
+ nextChannelID = mNextEvent.channelID();
+ if (nextChannelID == 0) {
+ ALOGV("stolen channel has no event");
+ return;
+ }
+
+ sample = mNextEvent.sample();
+ leftVolume = mNextEvent.leftVolume();
+ rightVolume = mNextEvent.rightVolume();
+ priority = mNextEvent.priority();
+ loop = mNextEvent.loop();
+ rate = mNextEvent.rate();
+ }
+
+ ALOGV("Starting stolen channel %d -> %d", channelID(), nextChannelID);
+ play(sample, nextChannelID, leftVolume, rightVolume, priority, loop, rate);
+}
+
+void SoundChannel::callback(int event, void* user, void *info)
+{
+ SoundChannel* channel = static_cast<SoundChannel*>((void *)((unsigned long)user & ~1));
+
+ channel->process(event, info, (unsigned long)user & 1);
+}
+
+void SoundChannel::process(int event, void *info, unsigned long toggle)
+{
+ //ALOGV("process(%d)", mChannelID);
+
+ Mutex::Autolock lock(&mLock);
+
+ AudioTrack::Buffer* b = NULL;
+ if (event == AudioTrack::EVENT_MORE_DATA) {
+ b = static_cast<AudioTrack::Buffer *>(info);
+ }
+
+ if (mToggle != toggle) {
+ ALOGV("process wrong toggle %p channel %d", this, mChannelID);
+ if (b != NULL) {
+ b->size = 0;
+ }
+ return;
+ }
+
+ sp<Sample> sample = mSample;
+
+// ALOGV("SoundChannel::process event %d", event);
+
+ if (event == AudioTrack::EVENT_MORE_DATA) {
+
+ // check for stop state
+ if (b->size == 0) return;
+
+ if (mState == IDLE) {
+ b->size = 0;
+ return;
+ }
+
+ if (sample != 0) {
+ // fill buffer
+ uint8_t* q = (uint8_t*) b->i8;
+ size_t count = 0;
+
+ if (mPos < (int)sample->size()) {
+ uint8_t* p = sample->data() + mPos;
+ count = sample->size() - mPos;
+ if (count > b->size) {
+ count = b->size;
+ }
+ memcpy(q, p, count);
+// ALOGV("fill: q=%p, p=%p, mPos=%u, b->size=%u, count=%d", q, p, mPos, b->size, count);
+ } else if (mPos < mAudioBufferSize) {
+ count = mAudioBufferSize - mPos;
+ if (count > b->size) {
+ count = b->size;
+ }
+ memset(q, 0, count);
+// ALOGV("fill extra: q=%p, mPos=%u, b->size=%u, count=%d", q, mPos, b->size, count);
+ }
+
+ mPos += count;
+ b->size = count;
+ //ALOGV("buffer=%p, [0]=%d", b->i16, b->i16[0]);
+ }
+ } else if (event == AudioTrack::EVENT_UNDERRUN) {
+ ALOGV("process %p channel %d EVENT_UNDERRUN", this, mChannelID);
+ mSoundPool->addToStopList(this);
+ } else if (event == AudioTrack::EVENT_LOOP_END) {
+ ALOGV("End loop %p channel %d count %d", this, mChannelID, *(int *)info);
+ }
+}
+
+
+// call with lock held
+bool SoundChannel::doStop_l()
+{
+ if (mState != IDLE) {
+ setVolume_l(0, 0);
+ ALOGV("stop");
+ mAudioTrack->stop();
+ mSample.clear();
+ mState = IDLE;
+ mPriority = IDLE_PRIORITY;
+ return true;
+ }
+ return false;
+}
+
+// call with lock held and sound pool lock held
+void SoundChannel::stop_l()
+{
+ if (doStop_l()) {
+ mSoundPool->done_l(this);
+ }
+}
+
+// call with sound pool lock held
+void SoundChannel::stop()
+{
+ bool stopped;
+ {
+ Mutex::Autolock lock(&mLock);
+ stopped = doStop_l();
+ }
+
+ if (stopped) {
+ mSoundPool->done_l(this);
+ }
+}
+
+//FIXME: Pause is a little broken right now
+void SoundChannel::pause()
+{
+ Mutex::Autolock lock(&mLock);
+ if (mState == PLAYING) {
+ ALOGV("pause track");
+ mState = PAUSED;
+ mAudioTrack->pause();
+ }
+}
+
+void SoundChannel::autoPause()
+{
+ Mutex::Autolock lock(&mLock);
+ if (mState == PLAYING) {
+ ALOGV("pause track");
+ mState = PAUSED;
+ mAutoPaused = true;
+ mAudioTrack->pause();
+ }
+}
+
+void SoundChannel::resume()
+{
+ Mutex::Autolock lock(&mLock);
+ if (mState == PAUSED) {
+ ALOGV("resume track");
+ mState = PLAYING;
+ mAutoPaused = false;
+ mAudioTrack->start();
+ }
+}
+
+void SoundChannel::autoResume()
+{
+ Mutex::Autolock lock(&mLock);
+ if (mAutoPaused && (mState == PAUSED)) {
+ ALOGV("resume track");
+ mState = PLAYING;
+ mAutoPaused = false;
+ mAudioTrack->start();
+ }
+}
+
+void SoundChannel::setRate(float rate)
+{
+ Mutex::Autolock lock(&mLock);
+ if (mAudioTrack != NULL && mSample != 0) {
+ uint32_t sampleRate = uint32_t(float(mSample->sampleRate()) * rate + 0.5);
+ mAudioTrack->setSampleRate(sampleRate);
+ mRate = rate;
+ }
+}
+
+// call with lock held
+void SoundChannel::setVolume_l(float leftVolume, float rightVolume)
+{
+ mLeftVolume = leftVolume;
+ mRightVolume = rightVolume;
+ if (mAudioTrack != NULL)
+ mAudioTrack->setVolume(leftVolume, rightVolume);
+}
+
+void SoundChannel::setVolume(float leftVolume, float rightVolume)
+{
+ Mutex::Autolock lock(&mLock);
+ setVolume_l(leftVolume, rightVolume);
+}
+
+void SoundChannel::setLoop(int loop)
+{
+ Mutex::Autolock lock(&mLock);
+ if (mAudioTrack != NULL && mSample != 0) {
+ uint32_t loopEnd = mSample->size()/mNumChannels/
+ ((mSample->format() == AUDIO_FORMAT_PCM_16_BIT) ? sizeof(int16_t) : sizeof(uint8_t));
+ mAudioTrack->setLoop(0, loopEnd, loop);
+ mLoop = loop;
+ }
+}
+
+SoundChannel::~SoundChannel()
+{
+ ALOGV("SoundChannel destructor %p", this);
+ {
+ Mutex::Autolock lock(&mLock);
+ clearNextEvent();
+ doStop_l();
+ }
+ // do not call AudioTrack destructor with mLock held as it will wait for the AudioTrack
+ // callback thread to exit which may need to execute process() and acquire the mLock.
+ delete mAudioTrack;
+}
+
+void SoundChannel::dump()
+{
+ ALOGV("mState = %d mChannelID=%d, mNumChannels=%d, mPos = %d, mPriority=%d, mLoop=%d",
+ mState, mChannelID, mNumChannels, mPos, mPriority, mLoop);
+}
+
+void SoundEvent::set(const sp<Sample>& sample, int channelID, float leftVolume,
+ float rightVolume, int priority, int loop, float rate)
+{
+ mSample = sample;
+ mChannelID = channelID;
+ mLeftVolume = leftVolume;
+ mRightVolume = rightVolume;
+ mPriority = priority;
+ mLoop = loop;
+ mRate =rate;
+}
+
+} // end namespace android
diff --git a/media/libmedia/SoundPool.h b/media/libmedia/SoundPool.h
new file mode 100644
index 0000000..002b045
--- /dev/null
+++ b/media/libmedia/SoundPool.h
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2007 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 SOUNDPOOL_H_
+#define SOUNDPOOL_H_
+
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Vector.h>
+#include <utils/KeyedVector.h>
+#include <media/AudioTrack.h>
+
+namespace android {
+
+static const int IDLE_PRIORITY = -1;
+
+// forward declarations
+class SoundEvent;
+class SoundPoolThread;
+class SoundPool;
+
+// for queued events
+class SoundPoolEvent {
+public:
+ SoundPoolEvent(int msg, int arg1=0, int arg2=0) :
+ mMsg(msg), mArg1(arg1), mArg2(arg2) {}
+ int mMsg;
+ int mArg1;
+ int mArg2;
+ enum MessageType { INVALID, SAMPLE_LOADED };
+};
+
+// callback function prototype
+typedef void SoundPoolCallback(SoundPoolEvent event, SoundPool* soundPool, void* user);
+
+// tracks samples used by application
+class Sample : public RefBase {
+public:
+ enum sample_state { UNLOADED, LOADING, READY, UNLOADING };
+ Sample(int sampleID, const char* url);
+ Sample(int sampleID, int fd, int64_t offset, int64_t length);
+ ~Sample();
+ int sampleID() { return mSampleID; }
+ int numChannels() { return mNumChannels; }
+ int sampleRate() { return mSampleRate; }
+ audio_format_t format() { return mFormat; }
+ size_t size() { return mSize; }
+ int state() { return mState; }
+ uint8_t* data() { return static_cast<uint8_t*>(mData->pointer()); }
+ status_t doLoad();
+ void startLoad() { mState = LOADING; }
+ sp<IMemory> getIMemory() { return mData; }
+
+ // hack
+ void init(int numChannels, int sampleRate, audio_format_t format, size_t size, sp<IMemory> data ) {
+ mNumChannels = numChannels; mSampleRate = sampleRate; mFormat = format; mSize = size; mData = data; }
+
+private:
+ void init();
+
+ size_t mSize;
+ volatile int32_t mRefCount;
+ uint16_t mSampleID;
+ uint16_t mSampleRate;
+ uint8_t mState : 3;
+ uint8_t mNumChannels : 2;
+ audio_format_t mFormat;
+ int mFd;
+ int64_t mOffset;
+ int64_t mLength;
+ char* mUrl;
+ sp<IMemory> mData;
+};
+
+// stores pending events for stolen channels
+class SoundEvent
+{
+public:
+ SoundEvent() : mChannelID(0), mLeftVolume(0), mRightVolume(0),
+ mPriority(IDLE_PRIORITY), mLoop(0), mRate(0) {}
+ void set(const sp<Sample>& sample, int channelID, float leftVolume,
+ float rightVolume, int priority, int loop, float rate);
+ sp<Sample> sample() { return mSample; }
+ int channelID() { return mChannelID; }
+ float leftVolume() { return mLeftVolume; }
+ float rightVolume() { return mRightVolume; }
+ int priority() { return mPriority; }
+ int loop() { return mLoop; }
+ float rate() { return mRate; }
+ void clear() { mChannelID = 0; mSample.clear(); }
+
+protected:
+ sp<Sample> mSample;
+ int mChannelID;
+ float mLeftVolume;
+ float mRightVolume;
+ int mPriority;
+ int mLoop;
+ float mRate;
+};
+
+// for channels aka AudioTracks
+class SoundChannel : public SoundEvent {
+public:
+ enum state { IDLE, RESUMING, STOPPING, PAUSED, PLAYING };
+ SoundChannel() : mAudioTrack(NULL), mState(IDLE), mNumChannels(1),
+ mPos(0), mToggle(0), mAutoPaused(false) {}
+ ~SoundChannel();
+ void init(SoundPool* soundPool);
+ void play(const sp<Sample>& sample, int channelID, float leftVolume, float rightVolume,
+ int priority, int loop, float rate);
+ void setVolume_l(float leftVolume, float rightVolume);
+ void setVolume(float leftVolume, float rightVolume);
+ void stop_l();
+ void stop();
+ void pause();
+ void autoPause();
+ void resume();
+ void autoResume();
+ void setRate(float rate);
+ int state() { return mState; }
+ void setPriority(int priority) { mPriority = priority; }
+ void setLoop(int loop);
+ int numChannels() { return mNumChannels; }
+ void clearNextEvent() { mNextEvent.clear(); }
+ void nextEvent();
+ int nextChannelID() { return mNextEvent.channelID(); }
+ void dump();
+
+private:
+ static void callback(int event, void* user, void *info);
+ void process(int event, void *info, unsigned long toggle);
+ bool doStop_l();
+
+ SoundPool* mSoundPool;
+ AudioTrack* mAudioTrack;
+ SoundEvent mNextEvent;
+ Mutex mLock;
+ int mState;
+ int mNumChannels;
+ int mPos;
+ int mAudioBufferSize;
+ unsigned long mToggle;
+ bool mAutoPaused;
+};
+
+// application object for managing a pool of sounds
+class SoundPool {
+ friend class SoundPoolThread;
+ friend class SoundChannel;
+public:
+ SoundPool(int maxChannels, audio_stream_type_t streamType, int srcQuality);
+ ~SoundPool();
+ int load(const char* url, int priority);
+ int load(int fd, int64_t offset, int64_t length, int priority);
+ bool unload(int sampleID);
+ int play(int sampleID, float leftVolume, float rightVolume, int priority,
+ int loop, float rate);
+ void pause(int channelID);
+ void autoPause();
+ void resume(int channelID);
+ void autoResume();
+ void stop(int channelID);
+ void setVolume(int channelID, float leftVolume, float rightVolume);
+ void setPriority(int channelID, int priority);
+ void setLoop(int channelID, int loop);
+ void setRate(int channelID, float rate);
+ audio_stream_type_t streamType() const { return mStreamType; }
+ int srcQuality() const { return mSrcQuality; }
+
+ // called from SoundPoolThread
+ void sampleLoaded(int sampleID);
+
+ // called from AudioTrack thread
+ void done_l(SoundChannel* channel);
+
+ // callback function
+ void setCallback(SoundPoolCallback* callback, void* user);
+ void* getUserData() { return mUserData; }
+
+private:
+ SoundPool() {} // no default constructor
+ bool startThreads();
+ void doLoad(sp<Sample>& sample);
+ sp<Sample> findSample(int sampleID) { return mSamples.valueFor(sampleID); }
+ SoundChannel* findChannel (int channelID);
+ SoundChannel* findNextChannel (int channelID);
+ SoundChannel* allocateChannel_l(int priority);
+ void moveToFront_l(SoundChannel* channel);
+ void notify(SoundPoolEvent event);
+ void dump();
+
+ // restart thread
+ void addToRestartList(SoundChannel* channel);
+ void addToStopList(SoundChannel* channel);
+ static int beginThread(void* arg);
+ int run();
+ void quit();
+
+ Mutex mLock;
+ Mutex mRestartLock;
+ Condition mCondition;
+ SoundPoolThread* mDecodeThread;
+ SoundChannel* mChannelPool;
+ List<SoundChannel*> mChannels;
+ List<SoundChannel*> mRestart;
+ List<SoundChannel*> mStop;
+ DefaultKeyedVector< int, sp<Sample> > mSamples;
+ int mMaxChannels;
+ audio_stream_type_t mStreamType;
+ int mSrcQuality;
+ int mAllocated;
+ int mNextSampleID;
+ int mNextChannelID;
+ bool mQuit;
+
+ // callback
+ Mutex mCallbackLock;
+ SoundPoolCallback* mCallback;
+ void* mUserData;
+};
+
+} // end namespace android
+
+#endif /*SOUNDPOOL_H_*/
diff --git a/media/libmedia/SoundPoolThread.cpp b/media/libmedia/SoundPoolThread.cpp
new file mode 100644
index 0000000..ba3b482
--- /dev/null
+++ b/media/libmedia/SoundPoolThread.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2007 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 "SoundPoolThread"
+#include "utils/Log.h"
+
+#include "SoundPoolThread.h"
+
+namespace android {
+
+void SoundPoolThread::write(SoundPoolMsg msg) {
+ Mutex::Autolock lock(&mLock);
+ while (mMsgQueue.size() >= maxMessages) {
+ mCondition.wait(mLock);
+ }
+
+ // if thread is quitting, don't add to queue
+ if (mRunning) {
+ mMsgQueue.push(msg);
+ mCondition.signal();
+ }
+}
+
+const SoundPoolMsg SoundPoolThread::read() {
+ Mutex::Autolock lock(&mLock);
+ while (mMsgQueue.size() == 0) {
+ mCondition.wait(mLock);
+ }
+ SoundPoolMsg msg = mMsgQueue[0];
+ mMsgQueue.removeAt(0);
+ mCondition.signal();
+ return msg;
+}
+
+void SoundPoolThread::quit() {
+ Mutex::Autolock lock(&mLock);
+ if (mRunning) {
+ mRunning = false;
+ mMsgQueue.clear();
+ mMsgQueue.push(SoundPoolMsg(SoundPoolMsg::KILL, 0));
+ mCondition.signal();
+ mCondition.wait(mLock);
+ }
+ ALOGV("return from quit");
+}
+
+SoundPoolThread::SoundPoolThread(SoundPool* soundPool) :
+ mSoundPool(soundPool)
+{
+ mMsgQueue.setCapacity(maxMessages);
+ if (createThreadEtc(beginThread, this, "SoundPoolThread")) {
+ mRunning = true;
+ }
+}
+
+SoundPoolThread::~SoundPoolThread()
+{
+ quit();
+}
+
+int SoundPoolThread::beginThread(void* arg) {
+ ALOGV("beginThread");
+ SoundPoolThread* soundPoolThread = (SoundPoolThread*)arg;
+ return soundPoolThread->run();
+}
+
+int SoundPoolThread::run() {
+ ALOGV("run");
+ for (;;) {
+ SoundPoolMsg msg = read();
+ ALOGV("Got message m=%d, mData=%d", msg.mMessageType, msg.mData);
+ switch (msg.mMessageType) {
+ case SoundPoolMsg::KILL:
+ ALOGV("goodbye");
+ return NO_ERROR;
+ case SoundPoolMsg::LOAD_SAMPLE:
+ doLoadSample(msg.mData);
+ break;
+ default:
+ ALOGW("run: Unrecognized message %d\n",
+ msg.mMessageType);
+ break;
+ }
+ }
+}
+
+void SoundPoolThread::loadSample(int sampleID) {
+ write(SoundPoolMsg(SoundPoolMsg::LOAD_SAMPLE, sampleID));
+}
+
+void SoundPoolThread::doLoadSample(int sampleID) {
+ sp <Sample> sample = mSoundPool->findSample(sampleID);
+ status_t status = -1;
+ if (sample != 0) {
+ status = sample->doLoad();
+ }
+ mSoundPool->notify(SoundPoolEvent(SoundPoolEvent::SAMPLE_LOADED, sampleID, status));
+}
+
+} // end namespace android
diff --git a/media/libmedia/SoundPoolThread.h b/media/libmedia/SoundPoolThread.h
new file mode 100644
index 0000000..d388388
--- /dev/null
+++ b/media/libmedia/SoundPoolThread.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007 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 SOUNDPOOLTHREAD_H_
+#define SOUNDPOOLTHREAD_H_
+
+#include <utils/threads.h>
+#include <utils/Vector.h>
+#include <media/AudioTrack.h>
+
+#include "SoundPool.h"
+
+namespace android {
+
+class SoundPoolMsg {
+public:
+ enum MessageType { INVALID, KILL, LOAD_SAMPLE };
+ SoundPoolMsg() : mMessageType(INVALID), mData(0) {}
+ SoundPoolMsg(MessageType MessageType, int data) :
+ mMessageType(MessageType), mData(data) {}
+ uint16_t mMessageType;
+ uint16_t mData;
+};
+
+/*
+ * This class handles background requests from the SoundPool
+ */
+class SoundPoolThread {
+public:
+ SoundPoolThread(SoundPool* SoundPool);
+ ~SoundPoolThread();
+ void loadSample(int sampleID);
+ void quit();
+ void write(SoundPoolMsg msg);
+
+private:
+ static const size_t maxMessages = 5;
+
+ static int beginThread(void* arg);
+ int run();
+ void doLoadSample(int sampleID);
+ const SoundPoolMsg read();
+
+ Mutex mLock;
+ Condition mCondition;
+ Vector<SoundPoolMsg> mMsgQueue;
+ SoundPool* mSoundPool;
+ bool mRunning;
+};
+
+} // end namespace android
+
+#endif /*SOUNDPOOLTHREAD_H_*/
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index ba5c776..675c563 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -7,6 +7,7 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ Crypto.cpp \
MediaRecorderClient.cpp \
MediaPlayerService.cpp \
MetadataRetrieverClient.cpp \
@@ -38,12 +39,11 @@
libstagefright_rtsp \
LOCAL_C_INCLUDES := \
- $(JNI_H_INCLUDE) \
$(call include-path-for, graphics corecg) \
$(TOP)/frameworks/base/media/libstagefright/include \
$(TOP)/frameworks/base/media/libstagefright/rtsp \
$(TOP)/frameworks/native/include/media/openmax \
- $(TOP)/external/tremolo/Tremolo
+ $(TOP)/external/tremolo/Tremolo \
LOCAL_MODULE:= libmediaplayerservice
diff --git a/media/libmediaplayerservice/Crypto.cpp b/media/libmediaplayerservice/Crypto.cpp
new file mode 100644
index 0000000..e02035f
--- /dev/null
+++ b/media/libmediaplayerservice/Crypto.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2012 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 "Crypto"
+#include <utils/Log.h>
+
+#include "Crypto.h"
+
+#include <media/stagefright/MediaErrors.h>
+
+namespace android {
+
+Crypto::Crypto() {
+}
+
+Crypto::~Crypto() {
+}
+
+status_t Crypto::initialize() {
+ return ERROR_UNSUPPORTED;
+}
+
+status_t Crypto::terminate() {
+ return ERROR_UNSUPPORTED;
+}
+
+status_t Crypto::setEntitlementKey(
+ const void *key, size_t keyLength) {
+ return ERROR_UNSUPPORTED;
+}
+
+status_t Crypto::setEntitlementControlMessage(
+ const void *msg, size_t msgLength) {
+ return ERROR_UNSUPPORTED;
+}
+
+ssize_t Crypto::decryptVideo(
+ const void *iv, size_t ivLength,
+ const void *srcData, size_t srcDataSize,
+ void *dstData, size_t dstDataOffset) {
+ return ERROR_UNSUPPORTED;
+}
+
+ssize_t Crypto::decryptAudio(
+ const void *iv, size_t ivLength,
+ const void *srcData, size_t srcDataSize,
+ void *dstData, size_t dstDataSize) {
+ return ERROR_UNSUPPORTED;
+}
+
+} // namespace android
diff --git a/media/libmediaplayerservice/Crypto.h b/media/libmediaplayerservice/Crypto.h
new file mode 100644
index 0000000..9855496
--- /dev/null
+++ b/media/libmediaplayerservice/Crypto.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012 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 CRYPTO_H_
+
+#define CRYPTO_H_
+
+#include <media/ICrypto.h>
+#include <utils/threads.h>
+
+namespace android {
+
+struct Crypto : public BnCrypto {
+ Crypto();
+
+ virtual status_t initialize();
+ virtual status_t terminate();
+
+ virtual status_t setEntitlementKey(
+ const void *key, size_t keyLength);
+
+ virtual status_t setEntitlementControlMessage(
+ const void *msg, size_t msgLength);
+
+ virtual ssize_t decryptVideo(
+ const void *iv, size_t ivLength,
+ const void *srcData, size_t srcDataSize,
+ void *dstData, size_t dstDataOffset);
+
+ virtual ssize_t decryptAudio(
+ const void *iv, size_t ivLength,
+ const void *srcData, size_t srcDataSize,
+ void *dstData, size_t dstDataSize);
+
+protected:
+ virtual ~Crypto();
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(Crypto);
+};
+
+} // namespace android
+
+#endif // CRYPTO_H_
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 840e475..123d07f 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -70,6 +70,8 @@
#include <OMX.h>
+#include "Crypto.h"
+
namespace android {
sp<MediaPlayerBase> createAAH_TXPlayer();
sp<MediaPlayerBase> createAAH_RXPlayer();
@@ -292,6 +294,16 @@
return mOMX;
}
+sp<ICrypto> MediaPlayerService::makeCrypto() {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mCrypto == NULL) {
+ mCrypto = new Crypto;
+ }
+
+ return mCrypto;
+}
+
status_t MediaPlayerService::AudioCache::dump(int fd, const Vector<String16>& args) const
{
const size_t SIZE = 256;
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index d4e0eb1..b08dd6c 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -240,6 +240,7 @@
virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat);
virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat);
virtual sp<IOMX> getOMX();
+ virtual sp<ICrypto> makeCrypto();
virtual status_t dump(int fd, const Vector<String16>& args);
@@ -419,6 +420,7 @@
SortedVector< wp<MediaRecorderClient> > mMediaRecorderClients;
int32_t mNextConnId;
sp<IOMX> mOMX;
+ sp<ICrypto> mCrypto;
};
// ----------------------------------------------------------------------------
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 1600141..5733229 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -125,6 +125,11 @@
msg->setInt32("channel-count", numChannels);
msg->setInt32("sample-rate", sampleRate);
+
+ int32_t isADTS;
+ if (meta->findInt32(kKeyIsADTS, &isADTS) && isADTS != 0) {
+ msg->setInt32("is-adts", true);
+ }
}
int32_t maxInputSize;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index e5ad4b7..db2beda 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -427,24 +427,34 @@
sp<IMemory> mem = mDealer[portIndex]->allocate(def.nBufferSize);
CHECK(mem.get() != NULL);
- IOMX::buffer_id buffer;
+ BufferInfo info;
+ info.mStatus = BufferInfo::OWNED_BY_US;
uint32_t requiresAllocateBufferBit =
(portIndex == kPortIndexInput)
? OMXCodec::kRequiresAllocateBufferOnInputPorts
: OMXCodec::kRequiresAllocateBufferOnOutputPorts;
- if (mQuirks & requiresAllocateBufferBit) {
+ if (portIndex == kPortIndexInput && (mFlags & kFlagIsSecure)) {
+ mem.clear();
+
+ void *ptr;
+ err = mOMX->allocateBuffer(
+ mNode, portIndex, def.nBufferSize, &info.mBufferID,
+ &ptr);
+
+ info.mData = new ABuffer(ptr, def.nBufferSize);
+ } else if (mQuirks & requiresAllocateBufferBit) {
err = mOMX->allocateBufferWithBackup(
- mNode, portIndex, mem, &buffer);
+ mNode, portIndex, mem, &info.mBufferID);
} else {
- err = mOMX->useBuffer(mNode, portIndex, mem, &buffer);
+ err = mOMX->useBuffer(mNode, portIndex, mem, &info.mBufferID);
}
- BufferInfo info;
- info.mBufferID = buffer;
- info.mStatus = BufferInfo::OWNED_BY_US;
- info.mData = new ABuffer(mem->pointer(), def.nBufferSize);
+ if (mem != NULL) {
+ info.mData = new ABuffer(mem->pointer(), def.nBufferSize);
+ }
+
mBuffers[portIndex].push(info);
}
}
@@ -840,7 +850,13 @@
|| !msg->findInt32("sample-rate", &sampleRate)) {
err = INVALID_OPERATION;
} else {
- err = setupAACCodec(encoder, numChannels, sampleRate, bitRate);
+ int32_t isADTS;
+ if (!msg->findInt32("is-adts", &isADTS)) {
+ isADTS = 0;
+ }
+
+ err = setupAACCodec(
+ encoder, numChannels, sampleRate, bitRate, isADTS != 0);
}
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)) {
err = setupAMRCodec(encoder, false /* isWAMR */, bitRate);
@@ -934,7 +950,11 @@
status_t ACodec::setupAACCodec(
bool encoder,
- int32_t numChannels, int32_t sampleRate, int32_t bitRate) {
+ int32_t numChannels, int32_t sampleRate, int32_t bitRate, bool isADTS) {
+ if (encoder && isADTS) {
+ return -EINVAL;
+ }
+
status_t err = setupRawAudioFormat(
encoder ? kPortIndexInput : kPortIndexOutput,
sampleRate,
@@ -1021,7 +1041,11 @@
profile.nChannels = numChannels;
profile.nSampleRate = sampleRate;
- profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
+
+ profile.eAACStreamFormat =
+ isADTS
+ ? OMX_AUDIO_AACStreamFormatMP4ADTS
+ : OMX_AUDIO_AACStreamFormatMP4FF;
return mOMX->setParameter(
mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
@@ -2653,6 +2677,12 @@
observer->setNotificationMessage(notify);
mCodec->mComponentName = componentName;
+ mCodec->mFlags = 0;
+
+ if (componentName.endsWith(".secure")) {
+ mCodec->mFlags |= kFlagIsSecure;
+ }
+
mCodec->mQuirks = quirks;
mCodec->mOMX = omx;
mCodec->mNode = node;
@@ -2701,6 +2731,7 @@
mCodec->mNode = NULL;
mCodec->mOMX.clear();
mCodec->mQuirks = 0;
+ mCodec->mFlags = 0;
mCodec->mComponentName.clear();
mCodec->changeState(mCodec->mUninitializedState);
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 7d7bd7d..8948abb 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -57,7 +57,6 @@
avc_utils.cpp \
LOCAL_C_INCLUDES:= \
- $(JNI_H_INCLUDE) \
$(TOP)/frameworks/base/include/media/stagefright/timedtext \
$(TOP)/frameworks/native/include/media/hardware \
$(TOP)/frameworks/native/include/media/openmax \
@@ -69,7 +68,6 @@
LOCAL_SHARED_LIBRARIES := \
libbinder \
libcamera_client \
- libchromium_net \
libcrypto \
libcutils \
libdl \
@@ -102,14 +100,18 @@
libstagefright_httplive \
libstagefright_id3 \
libFLAC \
- libstagefright_chromium_http \
+
+ifneq ($(TARGET_BUILD_PDK), true)
+LOCAL_STATIC_LIBRARIES += \
+ libstagefright_chromium_http
+LOCAL_SHARED_LIBRARIES += \
+ libchromium_net
+LOCAL_CPPFLAGS += -DCHROMIUM_AVAILABLE=1
+endif
LOCAL_SHARED_LIBRARIES += libstlport
include external/stlport/libstlport.mk
-# TODO: Chromium is always available, so this flag can be removed.
-LOCAL_CPPFLAGS += -DCHROMIUM_AVAILABLE=1
-
LOCAL_SHARED_LIBRARIES += \
libstagefright_enc_common \
libstagefright_avc_common \
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index a9e7f36..42b5c7e 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -22,10 +22,14 @@
#include "include/SoftwareRenderer.h"
+#include <binder/IServiceManager.h>
#include <gui/SurfaceTextureClient.h>
+#include <media/ICrypto.h>
+#include <media/IMediaPlayerService.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/ACodec.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
@@ -528,6 +532,12 @@
info.mOwnedByClient = false;
CHECK(msg->findBuffer(name.c_str(), &info.mData));
+ if (portIndex == kPortIndexInput
+ && (mFlags & kFlagIsSecure)) {
+ info.mEncryptedData =
+ new ABuffer(info.mData->capacity());
+ }
+
buffers->push_back(info);
}
@@ -742,6 +752,59 @@
format->setInt32("encoder", true);
}
+ if (flags & CONFIGURE_FLAG_SECURE) {
+ mFlags |= kFlagIsSecure;
+
+ sp<IServiceManager> sm = defaultServiceManager();
+
+ sp<IBinder> binder =
+ sm->getService(String16("media.player"));
+
+ sp<IMediaPlayerService> service =
+ interface_cast<IMediaPlayerService>(binder);
+
+ CHECK(service != NULL);
+
+ mCrypto = service->makeCrypto();
+
+ status_t err = mCrypto->initialize();
+
+ if (err == OK) {
+ sp<ABuffer> emm;
+ if (format->findBuffer("emm", &emm)) {
+ err = mCrypto->setEntitlementKey(
+ emm->data(), emm->size());
+ }
+ }
+
+ if (err == OK) {
+ sp<ABuffer> ecm;
+ if (format->findBuffer("ecm", &ecm)) {
+ CHECK_EQ(ecm->size(), 80u);
+
+ // bytes 16..47 of the original ecm stream data.
+ err = mCrypto->setEntitlementControlMessage(
+ ecm->data() + 16, 32);
+ }
+ }
+
+ if (err != OK) {
+ ALOGE("failed to instantiate crypto service.");
+
+ mCrypto.clear();
+
+ setState(INITIALIZED);
+
+ sp<AMessage> response = new AMessage;
+ response->setInt32("err", UNKNOWN_ERROR);
+
+ response->postReply(mReplyID);
+ break;
+ }
+ } else {
+ mFlags &= ~kFlagIsSecure;
+ }
+
mCodec->initiateConfigureComponent(format);
break;
}
@@ -983,7 +1046,10 @@
for (size_t i = 0; i < srcBuffers.size(); ++i) {
const BufferInfo &info = srcBuffers.itemAt(i);
- dstBuffers->push_back(info.mData);
+ dstBuffers->push_back(
+ (portIndex == kPortIndexInput
+ && (mFlags & kFlagIsSecure))
+ ? info.mEncryptedData : info.mData);
}
(new AMessage)->postReply(replyID);
@@ -1037,10 +1103,15 @@
}
void MediaCodec::setState(State newState) {
- if (newState == UNINITIALIZED) {
+ if (newState == INITIALIZED) {
delete mSoftRenderer;
mSoftRenderer = NULL;
+ if (mCrypto != NULL) {
+ mCrypto->terminate();
+ mCrypto.clear();
+ }
+
mNativeWindow.clear();
mOutputFormat.clear();
@@ -1150,6 +1221,43 @@
info->mData->meta()->setInt32("csd", true);
}
+ if (mFlags & kFlagIsSecure) {
+ uint8_t iv[16];
+ memset(iv, 0, sizeof(iv));
+
+ ssize_t outLength;
+
+ if (mFlags & kFlagIsSoftwareCodec) {
+ outLength = mCrypto->decryptAudio(
+ (flags & BUFFER_FLAG_ENCRYPTED) ? iv : NULL,
+ (flags & BUFFER_FLAG_ENCRYPTED) ? sizeof(iv) : 0,
+ info->mEncryptedData->base() + offset,
+ size,
+ info->mData->base(),
+ info->mData->capacity());
+ } else {
+ outLength = mCrypto->decryptVideo(
+ (flags & BUFFER_FLAG_ENCRYPTED) ? iv : NULL,
+ (flags & BUFFER_FLAG_ENCRYPTED) ? sizeof(iv) : 0,
+ info->mEncryptedData->base() + offset,
+ size,
+ info->mData->base(),
+ 0 /* offset */);
+ }
+
+ if (outLength < 0) {
+ return outLength;
+ }
+
+ if ((size_t)outLength > info->mEncryptedData->capacity()) {
+ return -ERANGE;
+ }
+
+ info->mData->setRange(0, outLength);
+ } else if (flags & BUFFER_FLAG_ENCRYPTED) {
+ return -EINVAL;
+ }
+
reply->setBuffer("buffer", info->mData);
reply->post();
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index afd4763..224ec33 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -107,6 +107,11 @@
msg->setInt32("channel-count", numChannels);
msg->setInt32("sample-rate", sampleRate);
+
+ int32_t isADTS;
+ if (meta->findInt32(kKeyIsADTS, &isADTS)) {
+ msg->setInt32("is-adts", true);
+ }
}
int32_t maxInputSize;
@@ -232,6 +237,20 @@
msg->setBuffer("csd-1", buffer);
}
+ if (meta->findData(kKeyEMM, &type, &data, &size)) {
+ sp<ABuffer> emm = new ABuffer(size);
+ memcpy(emm->data(), data, size);
+
+ msg->setBuffer("emm", emm);
+ }
+
+ if (meta->findData(kKeyECM, &type, &data, &size)) {
+ sp<ABuffer> ecm = new ABuffer(size);
+ memcpy(ecm->data(), data, size);
+
+ msg->setBuffer("ecm", ecm);
+ }
+
*format = msg;
return OK;
@@ -267,13 +286,14 @@
info->mFinalResult = OK;
info->mSample = NULL;
info->mSampleTimeUs = -1ll;
- info->mFlags = 0;
+ info->mSampleFlags = 0;
+ info->mTrackFlags = 0;
const char *mime;
CHECK(source->getFormat()->findCString(kKeyMIMEType, &mime));
if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
- info->mFlags |= kIsVorbis;
+ info->mTrackFlags |= kIsVorbis;
}
return OK;
@@ -288,6 +308,7 @@
info->mSample = NULL;
info->mSampleTimeUs = -1ll;
+ info->mSampleFlags = 0;
}
}
}
@@ -306,6 +327,7 @@
info->mSample->release();
info->mSample = NULL;
info->mSampleTimeUs = -1ll;
+ info->mSampleFlags = 0;
}
} else if (info->mFinalResult != OK) {
continue;
@@ -323,11 +345,25 @@
info->mFinalResult = err;
info->mSampleTimeUs = -1ll;
+ info->mSampleFlags = 0;
continue;
} else {
CHECK(info->mSample != NULL);
CHECK(info->mSample->meta_data()->findInt64(
kKeyTime, &info->mSampleTimeUs));
+
+ info->mSampleFlags = 0;
+
+ int32_t val;
+ if (info->mSample->meta_data()->findInt32(
+ kKeyIsSyncFrame, &val) && val != 0) {
+ info->mSampleFlags |= SAMPLE_FLAG_SYNC;
+ }
+
+ if (info->mSample->meta_data()->findInt32(
+ kKeyScrambling, &val) && val != 0) {
+ info->mSampleFlags |= SAMPLE_FLAG_ENCRYPTED;
+ }
}
}
@@ -371,7 +407,7 @@
size_t sampleSize = info->mSample->range_length();
- if (info->mFlags & kIsVorbis) {
+ if (info->mTrackFlags & kIsVorbis) {
// Each sample's data is suffixed by the number of page samples
// or -1 if not available.
sampleSize += sizeof(int32_t);
@@ -387,7 +423,7 @@
memcpy((uint8_t *)buffer->data(), src, info->mSample->range_length());
- if (info->mFlags & kIsVorbis) {
+ if (info->mTrackFlags & kIsVorbis) {
int32_t numPageSamples;
if (!info->mSample->meta_data()->findInt32(
kKeyValidSamples, &numPageSamples)) {
@@ -430,4 +466,17 @@
return OK;
}
+status_t NuMediaExtractor::getSampleFlags(uint32_t *sampleFlags) {
+ ssize_t minIndex = fetchTrackSamples();
+
+ if (minIndex < 0) {
+ return ERROR_END_OF_STREAM;
+ }
+
+ TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
+ *sampleFlags = info->mSampleFlags;
+
+ return OK;
+}
+
} // namespace android
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 8b6e9d5..9769f21 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -515,7 +515,12 @@
CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
- status_t err = setAACFormat(numChannels, sampleRate, bitRate);
+ int32_t isADTS;
+ if (!meta->findInt32(kKeyIsADTS, &isADTS)) {
+ isADTS = false;
+ }
+
+ status_t err = setAACFormat(numChannels, sampleRate, bitRate, isADTS);
if (err != OK) {
CODEC_LOGE("setAACFormat() failed (err = %d)", err);
return err;
@@ -3386,11 +3391,17 @@
}
}
-status_t OMXCodec::setAACFormat(int32_t numChannels, int32_t sampleRate, int32_t bitRate) {
- if (numChannels > 2)
+status_t OMXCodec::setAACFormat(
+ int32_t numChannels, int32_t sampleRate, int32_t bitRate, bool isADTS) {
+ if (numChannels > 2) {
ALOGW("Number of channels: (%d) \n", numChannels);
+ }
if (mIsEncoder) {
+ if (isADTS) {
+ return -EINVAL;
+ }
+
//////////////// input port ////////////////////
setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
@@ -3445,7 +3456,9 @@
&profile, sizeof(profile));
if (err != OK) {
- CODEC_LOGE("setParameter('OMX_IndexParamAudioAac') failed (err = %d)", err);
+ CODEC_LOGE("setParameter('OMX_IndexParamAudioAac') failed "
+ "(err = %d)",
+ err);
return err;
}
} else {
@@ -3459,13 +3472,19 @@
profile.nChannels = numChannels;
profile.nSampleRate = sampleRate;
- profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
+
+ profile.eAACStreamFormat =
+ isADTS
+ ? OMX_AUDIO_AACStreamFormatMP4ADTS
+ : OMX_AUDIO_AACStreamFormatMP4FF;
err = mOMX->setParameter(
mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
if (err != OK) {
- CODEC_LOGE("setParameter('OMX_IndexParamAudioAac') failed (err = %d)", err);
+ CODEC_LOGE("setParameter('OMX_IndexParamAudioAac') failed "
+ "(err = %d)",
+ err);
return err;
}
}
diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp
index 6d345bb..9df15eb 100644
--- a/media/libstagefright/TimedEventQueue.cpp
+++ b/media/libstagefright/TimedEventQueue.cpp
@@ -31,10 +31,6 @@
#include <media/stagefright/foundation/ADebug.h>
-#ifdef ANDROID_SIMULATOR
-#include <jni.h>
-#endif
-
namespace android {
TimedEventQueue::TimedEventQueue()
@@ -193,27 +189,10 @@
// static
void *TimedEventQueue::ThreadWrapper(void *me) {
-#ifdef ANDROID_SIMULATOR
- // The simulator runs everything as one process, so any
- // Binder calls happen on this thread instead of a thread
- // in another process. We therefore need to make sure that
- // this thread can do calls into interpreted code.
- // On the device this is not an issue because the remote
- // thread will already be set up correctly for this.
- JavaVM *vm;
- int numvms;
- JNI_GetCreatedJavaVMs(&vm, 1, &numvms);
- JNIEnv *env;
- vm->AttachCurrentThread(&env, NULL);
-#endif
-
androidSetThreadPriority(0, ANDROID_PRIORITY_FOREGROUND);
static_cast<TimedEventQueue *>(me)->threadEntry();
-#ifdef ANDROID_SIMULATOR
- vm->DetachCurrentThread();
-#endif
return NULL;
}
diff --git a/media/libstagefright/chromium_http/Android.mk b/media/libstagefright/chromium_http/Android.mk
index e37b4a8..d595686 100644
--- a/media/libstagefright/chromium_http/Android.mk
+++ b/media/libstagefright/chromium_http/Android.mk
@@ -1,5 +1,6 @@
LOCAL_PATH:= $(call my-dir)
+ifneq ($(TARGET_BUILD_PDK), true)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
@@ -8,7 +9,6 @@
support.cpp
LOCAL_C_INCLUDES:= \
- $(JNI_H_INCLUDE) \
frameworks/base/media/libstagefright \
$(TOP)/frameworks/native/include/media/openmax \
external/chromium \
@@ -22,3 +22,4 @@
LOCAL_MODULE:= libstagefright_chromium_http
include $(BUILD_STATIC_LIBRARY)
+endif
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC.cpp b/media/libstagefright/codecs/aacdec/SoftAAC.cpp
index ea6c360..90f96c6 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC.cpp
@@ -23,6 +23,7 @@
#include "pvmp4audiodecoder_api.h"
#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/hexdump.h>
namespace android {
@@ -42,6 +43,7 @@
OMX_COMPONENTTYPE **component)
: SimpleSoftOMXComponent(name, callbacks, appData, component),
mConfig(new tPVMP4AudioDecoderExternal),
+ mIsADTS(false),
mDecoderBuf(NULL),
mInputBufferCount(0),
mUpsamplingFactor(2),
@@ -140,7 +142,12 @@
aacParams->nAACtools = 0;
aacParams->nAACERtools = 0;
aacParams->eAACProfile = OMX_AUDIO_AACObjectMain;
- aacParams->eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF;
+
+ aacParams->eAACStreamFormat =
+ mIsADTS
+ ? OMX_AUDIO_AACStreamFormatMP4ADTS
+ : OMX_AUDIO_AACStreamFormatMP4FF;
+
aacParams->eChannelMode = OMX_AUDIO_ChannelModeStereo;
if (!isConfigured()) {
@@ -215,6 +222,15 @@
return OMX_ErrorUndefined;
}
+ if (aacParams->eAACStreamFormat == OMX_AUDIO_AACStreamFormatMP4FF) {
+ mIsADTS = false;
+ } else if (aacParams->eAACStreamFormat
+ == OMX_AUDIO_AACStreamFormatMP4ADTS) {
+ mIsADTS = true;
+ } else {
+ return OMX_ErrorUndefined;
+ }
+
return OMX_ErrorNone;
}
@@ -299,8 +315,35 @@
mNumSamplesOutput = 0;
}
- mConfig->pInputBuffer = inHeader->pBuffer + inHeader->nOffset;
- mConfig->inputBufferCurrentLength = inHeader->nFilledLen;
+ if (mIsADTS) {
+ // skip 30 bits, aac_frame_length follows.
+ // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll?????
+
+ const uint8_t *adtsHeader = inHeader->pBuffer + inHeader->nOffset;
+
+ CHECK_GE(inHeader->nFilledLen, 7);
+
+ bool protectionAbsent = (adtsHeader[1] & 1);
+
+ unsigned aac_frame_length =
+ ((adtsHeader[3] & 3) << 11)
+ | (adtsHeader[4] << 3)
+ | (adtsHeader[5] >> 5);
+
+ CHECK_GE(inHeader->nFilledLen, aac_frame_length);
+
+ size_t headerSize = (protectionAbsent ? 7 : 9);
+
+ mConfig->pInputBuffer = (UChar *)adtsHeader + headerSize;
+ mConfig->inputBufferCurrentLength = aac_frame_length - headerSize;
+
+ inHeader->nOffset += headerSize;
+ inHeader->nFilledLen -= headerSize;
+ } else {
+ mConfig->pInputBuffer = inHeader->pBuffer + inHeader->nOffset;
+ mConfig->inputBufferCurrentLength = inHeader->nFilledLen;
+ }
+
mConfig->inputBufferMaxLength = 0;
mConfig->inputBufferUsedLength = 0;
mConfig->remainderBits = 0;
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC.h b/media/libstagefright/codecs/aacdec/SoftAAC.h
index 963fd27..da0b8ed 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC.h
+++ b/media/libstagefright/codecs/aacdec/SoftAAC.h
@@ -49,6 +49,7 @@
};
tPVMP4AudioDecoderExternal *mConfig;
+ bool mIsADTS;
void *mDecoderBuf;
size_t mInputBufferCount;
diff --git a/media/libstagefright/foundation/AString.cpp b/media/libstagefright/foundation/AString.cpp
index 61b76cf..dee786d 100644
--- a/media/libstagefright/foundation/AString.cpp
+++ b/media/libstagefright/foundation/AString.cpp
@@ -310,6 +310,16 @@
return !strncmp(mData, prefix, strlen(prefix));
}
+bool AString::endsWith(const char *suffix) const {
+ size_t suffixLen = strlen(suffix);
+
+ if (mSize < suffixLen) {
+ return false;
+ }
+
+ return !strcmp(mData + mSize - suffixLen, suffix);
+}
+
AString StringPrintf(const char *format, ...) {
va_list ap;
va_start(ap, format);
diff --git a/media/libstagefright/httplive/Android.mk b/media/libstagefright/httplive/Android.mk
index a5990c3..90cb448 100644
--- a/media/libstagefright/httplive/Android.mk
+++ b/media/libstagefright/httplive/Android.mk
@@ -8,7 +8,6 @@
M3UParser.cpp \
LOCAL_C_INCLUDES:= \
- $(JNI_H_INCLUDE) \
$(TOP)/frameworks/base/media/libstagefright \
$(TOP)/frameworks/native/include/media/openmax \
$(TOP)/external/openssl/include
diff --git a/media/libstagefright/matroska/Android.mk b/media/libstagefright/matroska/Android.mk
index e67da4c..2cccb4f 100644
--- a/media/libstagefright/matroska/Android.mk
+++ b/media/libstagefright/matroska/Android.mk
@@ -5,7 +5,6 @@
MatroskaExtractor.cpp
LOCAL_C_INCLUDES:= \
- $(JNI_H_INCLUDE) \
$(TOP)/external/libvpx/mkvparser \
$(TOP)/frameworks/native/include/media/openmax \
diff --git a/media/libstagefright/mpeg2ts/Android.mk b/media/libstagefright/mpeg2ts/Android.mk
index ac4c2a1..eaa139d 100644
--- a/media/libstagefright/mpeg2ts/Android.mk
+++ b/media/libstagefright/mpeg2ts/Android.mk
@@ -10,7 +10,6 @@
MPEG2TSExtractor.cpp \
LOCAL_C_INCLUDES:= \
- $(JNI_H_INCLUDE) \
$(TOP)/frameworks/base/media/libstagefright \
$(TOP)/frameworks/native/include/media/openmax
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index d708ba6..e1ac53c 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -117,6 +117,12 @@
mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
+ int32_t scrambling;
+ if (buffer->meta()->findInt32("scrambling", &scrambling)
+ && scrambling != 0) {
+ mediaBuffer->meta_data()->setInt32(kKeyScrambling, scrambling);
+ }
+
*out = mediaBuffer;
return OK;
}
diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
index 083c7ef..d20ecb6 100644
--- a/media/libstagefright/omx/Android.mk
+++ b/media/libstagefright/omx/Android.mk
@@ -1,8 +1,6 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_C_INCLUDES += $(JNI_H_INCLUDE)
-
LOCAL_SRC_FILES:= \
OMX.cpp \
OMXMaster.cpp \
diff --git a/media/libstagefright/omx/tests/Android.mk b/media/libstagefright/omx/tests/Android.mk
index 07d47a8..6aa7470 100644
--- a/media/libstagefright/omx/tests/Android.mk
+++ b/media/libstagefright/omx/tests/Android.mk
@@ -8,7 +8,6 @@
libstagefright libbinder libmedia libutils libstagefright_foundation
LOCAL_C_INCLUDES := \
- $(JNI_H_INCLUDE) \
frameworks/base/media/libstagefright \
$(TOP)/frameworks/native/include/media/openmax
diff --git a/media/libstagefright/rtsp/Android.mk b/media/libstagefright/rtsp/Android.mk
index b3bc37c..e0fe59b 100644
--- a/media/libstagefright/rtsp/Android.mk
+++ b/media/libstagefright/rtsp/Android.mk
@@ -18,7 +18,6 @@
ASessionDescription.cpp \
LOCAL_C_INCLUDES:= \
- $(JNI_H_INCLUDE) \
$(TOP)/frameworks/base/media/libstagefright/include \
$(TOP)/frameworks/native/include/media/openmax \
$(TOP)/external/openssl/include
@@ -45,7 +44,6 @@
libstagefright_rtsp
LOCAL_C_INCLUDES:= \
- $(JNI_H_INCLUDE) \
frameworks/base/media/libstagefright \
$(TOP)/frameworks/native/include/media/openmax
diff --git a/media/libstagefright/timedtext/Android.mk b/media/libstagefright/timedtext/Android.mk
index d2d5f7b..58ef9e3 100644
--- a/media/libstagefright/timedtext/Android.mk
+++ b/media/libstagefright/timedtext/Android.mk
@@ -11,7 +11,6 @@
LOCAL_CFLAGS += -Wno-multichar
LOCAL_C_INCLUDES:= \
- $(JNI_H_INCLUDE) \
$(TOP)/frameworks/base/include/media/stagefright/timedtext \
$(TOP)/frameworks/base/media/libstagefright
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index e92e69c..c5ad0f5 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -442,11 +442,9 @@
audio_format_t format,
uint32_t channelMask,
int frameCount,
- // FIXME dead, remove from IAudioFlinger
- uint32_t flags,
+ IAudioFlinger::track_flags_t flags,
const sp<IMemory>& sharedBuffer,
audio_io_handle_t output,
- bool isTimed,
int *sessionId,
status_t *status)
{
@@ -504,6 +502,7 @@
}
ALOGV("createTrack() lSessionId: %d", lSessionId);
+ bool isTimed = (flags & IAudioFlinger::TRACK_TIMED) != 0;
track = thread->createTrack_l(client, streamType, sampleRate, format,
channelMask, frameCount, sharedBuffer, lSessionId, isTimed, &lStatus);
@@ -4676,8 +4675,7 @@
audio_format_t format,
uint32_t channelMask,
int frameCount,
- // FIXME dead, remove from IAudioFlinger
- uint32_t flags,
+ IAudioFlinger::track_flags_t flags,
int *sessionId,
status_t *status)
{
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index d1950a3..795807d 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -87,10 +87,9 @@
audio_format_t format,
uint32_t channelMask,
int frameCount,
- uint32_t flags,
+ IAudioFlinger::track_flags_t flags,
const sp<IMemory>& sharedBuffer,
audio_io_handle_t output,
- bool isTimed,
int *sessionId,
status_t *status);
@@ -101,7 +100,7 @@
audio_format_t format,
uint32_t channelMask,
int frameCount,
- uint32_t flags,
+ IAudioFlinger::track_flags_t flags,
int *sessionId,
status_t *status);