14eaa2938084353a54dc259466172909329a048ccChris Watkins/*
24eaa2938084353a54dc259466172909329a048ccChris Watkins * Copyright 2015, The Android Open Source Project
34eaa2938084353a54dc259466172909329a048ccChris Watkins *
44eaa2938084353a54dc259466172909329a048ccChris Watkins * Licensed under the Apache License, Version 2.0 (the "License");
54eaa2938084353a54dc259466172909329a048ccChris Watkins * you may not use this file except in compliance with the License.
64eaa2938084353a54dc259466172909329a048ccChris Watkins * You may obtain a copy of the License at
74eaa2938084353a54dc259466172909329a048ccChris Watkins *
84eaa2938084353a54dc259466172909329a048ccChris Watkins *     http://www.apache.org/licenses/LICENSE-2.0
94eaa2938084353a54dc259466172909329a048ccChris Watkins *
104eaa2938084353a54dc259466172909329a048ccChris Watkins * Unless required by applicable law or agreed to in writing, software
114eaa2938084353a54dc259466172909329a048ccChris Watkins * distributed under the License is distributed on an "AS IS" BASIS,
124eaa2938084353a54dc259466172909329a048ccChris Watkins * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134eaa2938084353a54dc259466172909329a048ccChris Watkins * See the License for the specific language governing permissions and
144eaa2938084353a54dc259466172909329a048ccChris Watkins * limitations under the License.
154eaa2938084353a54dc259466172909329a048ccChris Watkins */
164eaa2938084353a54dc259466172909329a048ccChris Watkins
174eaa2938084353a54dc259466172909329a048ccChris Watkins//#define LOG_NDEBUG 0
184eaa2938084353a54dc259466172909329a048ccChris Watkins#define LOG_TAG "JMediaDataSource-JNI"
194eaa2938084353a54dc259466172909329a048ccChris Watkins#include <utils/Log.h>
204eaa2938084353a54dc259466172909329a048ccChris Watkins
214eaa2938084353a54dc259466172909329a048ccChris Watkins#include "android_media_MediaDataSource.h"
224eaa2938084353a54dc259466172909329a048ccChris Watkins
234eaa2938084353a54dc259466172909329a048ccChris Watkins#include "android_runtime/AndroidRuntime.h"
244eaa2938084353a54dc259466172909329a048ccChris Watkins#include "android_runtime/Log.h"
254eaa2938084353a54dc259466172909329a048ccChris Watkins#include "jni.h"
264eaa2938084353a54dc259466172909329a048ccChris Watkins#include "JNIHelp.h"
274eaa2938084353a54dc259466172909329a048ccChris Watkins
284eaa2938084353a54dc259466172909329a048ccChris Watkins#include <binder/MemoryDealer.h>
29cad52fe423734c12aea2b8e90a2c15952777b536Wei Jia#include <drm/drm_framework_common.h>
304eaa2938084353a54dc259466172909329a048ccChris Watkins#include <media/stagefright/foundation/ADebug.h>
314eaa2938084353a54dc259466172909329a048ccChris Watkins#include <nativehelper/ScopedLocalRef.h>
324eaa2938084353a54dc259466172909329a048ccChris Watkins
334eaa2938084353a54dc259466172909329a048ccChris Watkinsnamespace android {
344eaa2938084353a54dc259466172909329a048ccChris Watkins
354eaa2938084353a54dc259466172909329a048ccChris WatkinsJMediaDataSource::JMediaDataSource(JNIEnv* env, jobject source)
364eaa2938084353a54dc259466172909329a048ccChris Watkins    : mJavaObjStatus(OK), mSizeIsCached(false), mCachedSize(0), mMemory(NULL) {
374eaa2938084353a54dc259466172909329a048ccChris Watkins    mMediaDataSourceObj = env->NewGlobalRef(source);
384eaa2938084353a54dc259466172909329a048ccChris Watkins    CHECK(mMediaDataSourceObj != NULL);
394eaa2938084353a54dc259466172909329a048ccChris Watkins
404eaa2938084353a54dc259466172909329a048ccChris Watkins    ScopedLocalRef<jclass> mediaDataSourceClass(env, env->GetObjectClass(mMediaDataSourceObj));
414eaa2938084353a54dc259466172909329a048ccChris Watkins    CHECK(mediaDataSourceClass.get() != NULL);
424eaa2938084353a54dc259466172909329a048ccChris Watkins
43bc10185fa1669a151568feb72277785d323fc344Chong Zhang    mReadMethod = env->GetMethodID(mediaDataSourceClass.get(), "readAt", "(J[BII)I");
444eaa2938084353a54dc259466172909329a048ccChris Watkins    CHECK(mReadMethod != NULL);
454eaa2938084353a54dc259466172909329a048ccChris Watkins    mGetSizeMethod = env->GetMethodID(mediaDataSourceClass.get(), "getSize", "()J");
464eaa2938084353a54dc259466172909329a048ccChris Watkins    CHECK(mGetSizeMethod != NULL);
474eaa2938084353a54dc259466172909329a048ccChris Watkins    mCloseMethod = env->GetMethodID(mediaDataSourceClass.get(), "close", "()V");
484eaa2938084353a54dc259466172909329a048ccChris Watkins    CHECK(mCloseMethod != NULL);
494eaa2938084353a54dc259466172909329a048ccChris Watkins
504eaa2938084353a54dc259466172909329a048ccChris Watkins    ScopedLocalRef<jbyteArray> tmp(env, env->NewByteArray(kBufferSize));
514eaa2938084353a54dc259466172909329a048ccChris Watkins    mByteArrayObj = (jbyteArray)env->NewGlobalRef(tmp.get());
524eaa2938084353a54dc259466172909329a048ccChris Watkins    CHECK(mByteArrayObj != NULL);
534eaa2938084353a54dc259466172909329a048ccChris Watkins
544eaa2938084353a54dc259466172909329a048ccChris Watkins    sp<MemoryDealer> memoryDealer = new MemoryDealer(kBufferSize, "JMediaDataSource");
554eaa2938084353a54dc259466172909329a048ccChris Watkins    mMemory = memoryDealer->allocate(kBufferSize);
564eaa2938084353a54dc259466172909329a048ccChris Watkins    if (mMemory == NULL) {
574eaa2938084353a54dc259466172909329a048ccChris Watkins        ALOGE("Failed to allocate memory!");
584eaa2938084353a54dc259466172909329a048ccChris Watkins    }
594eaa2938084353a54dc259466172909329a048ccChris Watkins}
604eaa2938084353a54dc259466172909329a048ccChris Watkins
614eaa2938084353a54dc259466172909329a048ccChris WatkinsJMediaDataSource::~JMediaDataSource() {
624eaa2938084353a54dc259466172909329a048ccChris Watkins    JNIEnv* env = AndroidRuntime::getJNIEnv();
634eaa2938084353a54dc259466172909329a048ccChris Watkins    env->DeleteGlobalRef(mMediaDataSourceObj);
644eaa2938084353a54dc259466172909329a048ccChris Watkins    env->DeleteGlobalRef(mByteArrayObj);
654eaa2938084353a54dc259466172909329a048ccChris Watkins}
664eaa2938084353a54dc259466172909329a048ccChris Watkins
674eaa2938084353a54dc259466172909329a048ccChris Watkinssp<IMemory> JMediaDataSource::getIMemory() {
684eaa2938084353a54dc259466172909329a048ccChris Watkins    Mutex::Autolock lock(mLock);
694eaa2938084353a54dc259466172909329a048ccChris Watkins    return mMemory;
704eaa2938084353a54dc259466172909329a048ccChris Watkins}
714eaa2938084353a54dc259466172909329a048ccChris Watkins
724eaa2938084353a54dc259466172909329a048ccChris Watkinsssize_t JMediaDataSource::readAt(off64_t offset, size_t size) {
734eaa2938084353a54dc259466172909329a048ccChris Watkins    Mutex::Autolock lock(mLock);
744eaa2938084353a54dc259466172909329a048ccChris Watkins
754eaa2938084353a54dc259466172909329a048ccChris Watkins    if (mJavaObjStatus != OK || mMemory == NULL) {
764eaa2938084353a54dc259466172909329a048ccChris Watkins        return -1;
774eaa2938084353a54dc259466172909329a048ccChris Watkins    }
784eaa2938084353a54dc259466172909329a048ccChris Watkins    if (size > kBufferSize) {
794eaa2938084353a54dc259466172909329a048ccChris Watkins        size = kBufferSize;
804eaa2938084353a54dc259466172909329a048ccChris Watkins    }
814eaa2938084353a54dc259466172909329a048ccChris Watkins
824eaa2938084353a54dc259466172909329a048ccChris Watkins    JNIEnv* env = AndroidRuntime::getJNIEnv();
834eaa2938084353a54dc259466172909329a048ccChris Watkins    jint numread = env->CallIntMethod(mMediaDataSourceObj, mReadMethod,
84bc10185fa1669a151568feb72277785d323fc344Chong Zhang            (jlong)offset, mByteArrayObj, (jint)0, (jint)size);
854eaa2938084353a54dc259466172909329a048ccChris Watkins    if (env->ExceptionCheck()) {
864eaa2938084353a54dc259466172909329a048ccChris Watkins        ALOGW("An exception occurred in readAt()");
874eaa2938084353a54dc259466172909329a048ccChris Watkins        LOGW_EX(env);
884eaa2938084353a54dc259466172909329a048ccChris Watkins        env->ExceptionClear();
894eaa2938084353a54dc259466172909329a048ccChris Watkins        mJavaObjStatus = UNKNOWN_ERROR;
904eaa2938084353a54dc259466172909329a048ccChris Watkins        return -1;
914eaa2938084353a54dc259466172909329a048ccChris Watkins    }
924eaa2938084353a54dc259466172909329a048ccChris Watkins    if (numread < 0) {
93bc10185fa1669a151568feb72277785d323fc344Chong Zhang        if (numread != -1) {
94bc10185fa1669a151568feb72277785d323fc344Chong Zhang            ALOGW("An error occurred in readAt()");
95bc10185fa1669a151568feb72277785d323fc344Chong Zhang            mJavaObjStatus = UNKNOWN_ERROR;
96bc10185fa1669a151568feb72277785d323fc344Chong Zhang            return -1;
97bc10185fa1669a151568feb72277785d323fc344Chong Zhang        } else {
98bc10185fa1669a151568feb72277785d323fc344Chong Zhang            // numread == -1 indicates EOF
99bc10185fa1669a151568feb72277785d323fc344Chong Zhang            return 0;
100bc10185fa1669a151568feb72277785d323fc344Chong Zhang        }
1014eaa2938084353a54dc259466172909329a048ccChris Watkins    }
1024eaa2938084353a54dc259466172909329a048ccChris Watkins    if ((size_t)numread > size) {
1034eaa2938084353a54dc259466172909329a048ccChris Watkins        ALOGE("readAt read too many bytes.");
1044eaa2938084353a54dc259466172909329a048ccChris Watkins        mJavaObjStatus = UNKNOWN_ERROR;
1054eaa2938084353a54dc259466172909329a048ccChris Watkins        return -1;
1064eaa2938084353a54dc259466172909329a048ccChris Watkins    }
1074eaa2938084353a54dc259466172909329a048ccChris Watkins
1084eaa2938084353a54dc259466172909329a048ccChris Watkins    ALOGV("readAt %lld / %zu => %d.", (long long)offset, size, numread);
1094eaa2938084353a54dc259466172909329a048ccChris Watkins    env->GetByteArrayRegion(mByteArrayObj, 0, numread, (jbyte*)mMemory->pointer());
1104eaa2938084353a54dc259466172909329a048ccChris Watkins    return numread;
1114eaa2938084353a54dc259466172909329a048ccChris Watkins}
1124eaa2938084353a54dc259466172909329a048ccChris Watkins
1134eaa2938084353a54dc259466172909329a048ccChris Watkinsstatus_t JMediaDataSource::getSize(off64_t* size) {
1144eaa2938084353a54dc259466172909329a048ccChris Watkins    Mutex::Autolock lock(mLock);
1154eaa2938084353a54dc259466172909329a048ccChris Watkins
1164eaa2938084353a54dc259466172909329a048ccChris Watkins    if (mJavaObjStatus != OK) {
1174eaa2938084353a54dc259466172909329a048ccChris Watkins        return UNKNOWN_ERROR;
1184eaa2938084353a54dc259466172909329a048ccChris Watkins    }
1194eaa2938084353a54dc259466172909329a048ccChris Watkins    if (mSizeIsCached) {
1207c7fef1585b7ec36d181b0f797f2713cb2dde291Lajos Molnar        *size = mCachedSize;
1217c7fef1585b7ec36d181b0f797f2713cb2dde291Lajos Molnar        return OK;
1224eaa2938084353a54dc259466172909329a048ccChris Watkins    }
1234eaa2938084353a54dc259466172909329a048ccChris Watkins
1244eaa2938084353a54dc259466172909329a048ccChris Watkins    JNIEnv* env = AndroidRuntime::getJNIEnv();
1254eaa2938084353a54dc259466172909329a048ccChris Watkins    *size = env->CallLongMethod(mMediaDataSourceObj, mGetSizeMethod);
1264eaa2938084353a54dc259466172909329a048ccChris Watkins    if (env->ExceptionCheck()) {
1274eaa2938084353a54dc259466172909329a048ccChris Watkins        ALOGW("An exception occurred in getSize()");
1284eaa2938084353a54dc259466172909329a048ccChris Watkins        LOGW_EX(env);
1294eaa2938084353a54dc259466172909329a048ccChris Watkins        env->ExceptionClear();
1304eaa2938084353a54dc259466172909329a048ccChris Watkins        // After returning an error, size shouldn't be used by callers.
1314eaa2938084353a54dc259466172909329a048ccChris Watkins        *size = UNKNOWN_ERROR;
1324eaa2938084353a54dc259466172909329a048ccChris Watkins        mJavaObjStatus = UNKNOWN_ERROR;
1334eaa2938084353a54dc259466172909329a048ccChris Watkins        return UNKNOWN_ERROR;
1344eaa2938084353a54dc259466172909329a048ccChris Watkins    }
1354eaa2938084353a54dc259466172909329a048ccChris Watkins
1364eaa2938084353a54dc259466172909329a048ccChris Watkins    // The minimum size should be -1, which indicates unknown size.
1374eaa2938084353a54dc259466172909329a048ccChris Watkins    if (*size < 0) {
1384eaa2938084353a54dc259466172909329a048ccChris Watkins        *size = -1;
1394eaa2938084353a54dc259466172909329a048ccChris Watkins    }
1404eaa2938084353a54dc259466172909329a048ccChris Watkins
1414eaa2938084353a54dc259466172909329a048ccChris Watkins    mCachedSize = *size;
1424eaa2938084353a54dc259466172909329a048ccChris Watkins    mSizeIsCached = true;
1434eaa2938084353a54dc259466172909329a048ccChris Watkins    return OK;
1444eaa2938084353a54dc259466172909329a048ccChris Watkins}
1454eaa2938084353a54dc259466172909329a048ccChris Watkins
1464eaa2938084353a54dc259466172909329a048ccChris Watkinsvoid JMediaDataSource::close() {
1474eaa2938084353a54dc259466172909329a048ccChris Watkins    Mutex::Autolock lock(mLock);
1484eaa2938084353a54dc259466172909329a048ccChris Watkins
1494eaa2938084353a54dc259466172909329a048ccChris Watkins    JNIEnv* env = AndroidRuntime::getJNIEnv();
1504eaa2938084353a54dc259466172909329a048ccChris Watkins    env->CallVoidMethod(mMediaDataSourceObj, mCloseMethod);
1514eaa2938084353a54dc259466172909329a048ccChris Watkins    // The closed state is effectively the same as an error state.
1524eaa2938084353a54dc259466172909329a048ccChris Watkins    mJavaObjStatus = UNKNOWN_ERROR;
1534eaa2938084353a54dc259466172909329a048ccChris Watkins}
1544eaa2938084353a54dc259466172909329a048ccChris Watkins
155fbc164ba3c2105265b031503bdfebdbcd7256fbeWei Jiauint32_t JMediaDataSource::getFlags() {
156fbc164ba3c2105265b031503bdfebdbcd7256fbeWei Jia    return 0;
157fbc164ba3c2105265b031503bdfebdbcd7256fbeWei Jia}
158fbc164ba3c2105265b031503bdfebdbcd7256fbeWei Jia
15973c74698d094e57af60d55afc790a72a966ae263Marco NelissenString8 JMediaDataSource::toString() {
16073c74698d094e57af60d55afc790a72a966ae263Marco Nelissen    return String8::format("JMediaDataSource(pid %d, uid %d)", getpid(), getuid());
16173c74698d094e57af60d55afc790a72a966ae263Marco Nelissen}
16273c74698d094e57af60d55afc790a72a966ae263Marco Nelissen
163cad52fe423734c12aea2b8e90a2c15952777b536Wei Jiasp<DecryptHandle> JMediaDataSource::DrmInitialization(const char * /* mime */) {
164cad52fe423734c12aea2b8e90a2c15952777b536Wei Jia    return NULL;
165cad52fe423734c12aea2b8e90a2c15952777b536Wei Jia}
166cad52fe423734c12aea2b8e90a2c15952777b536Wei Jia
1674eaa2938084353a54dc259466172909329a048ccChris Watkins}  // namespace android
168