1f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project/* 2f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project** 3f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project** Copyright 2007, The Android Open Source Project 4f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project** 5f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License"); 6f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project** you may not use this file except in compliance with the License. 7f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project** You may obtain a copy of the License at 8f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project** 9f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project** http://www.apache.org/licenses/LICENSE-2.0 10f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project** 11f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project** Unless required by applicable law or agreed to in writing, software 12f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project** distributed under the License is distributed on an "AS IS" BASIS, 13f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project** See the License for the specific language governing permissions and 15f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project** limitations under the License. 16f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project*/ 17f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 18f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project#define LOG_TAG "AmrInputStream" 19f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project#include "utils/Log.h" 20f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 21f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project#include "jni.h" 22f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project#include "JNIHelp.h" 23f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project#include "android_runtime/AndroidRuntime.h" 2449b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong#include "gsmamr_enc.h" 25f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 26f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project// ---------------------------------------------------------------------------- 27f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 28f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Projectusing namespace android; 29f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 30f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project// Corresponds to max bit rate of 12.2 kbps. 3149b6fbaebd5413b92c6dcff423da95d5525455eeJames Dongstatic const int MAX_OUTPUT_BUFFER_SIZE = 32; 3249b6fbaebd5413b92c6dcff423da95d5525455eeJames Dongstatic const int FRAME_DURATION_MS = 20; 3349b6fbaebd5413b92c6dcff423da95d5525455eeJames Dongstatic const int SAMPLING_RATE_HZ = 8000; 3449b6fbaebd5413b92c6dcff423da95d5525455eeJames Dongstatic const int SAMPLES_PER_FRAME = ((SAMPLING_RATE_HZ * FRAME_DURATION_MS) / 1000); 3549b6fbaebd5413b92c6dcff423da95d5525455eeJames Dongstatic const int BYTES_PER_SAMPLE = 2; // Assume 16-bit PCM samples 3649b6fbaebd5413b92c6dcff423da95d5525455eeJames Dongstatic const int BYTES_PER_FRAME = (SAMPLES_PER_FRAME * BYTES_PER_SAMPLE); 3749b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong 3849b6fbaebd5413b92c6dcff423da95d5525455eeJames Dongstruct GsmAmrEncoderState { 3949b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong GsmAmrEncoderState() 4049b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong : mEncState(NULL), 4149b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong mSidState(NULL), 4249b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong mLastModeUsed(0) { 4349b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong } 44f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 4549b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong ~GsmAmrEncoderState() {} 46f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 4749b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong void* mEncState; 4849b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong void* mSidState; 4949b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong int32_t mLastModeUsed; 5049b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong}; 51f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 52f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project// 53f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project// helper function to throw an exception 54f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project// 55f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Projectstatic void throwException(JNIEnv *env, const char* ex, const char* fmt, int data) { 56f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project if (jclass cls = env->FindClass(ex)) { 5749b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong char msg[128]; 58f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project sprintf(msg, fmt, data); 59f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project env->ThrowNew(cls, msg); 60f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project env->DeleteLocalRef(cls); 61f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project } 62f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project} 63f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 64f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Projectstatic jint android_media_AmrInputStream_GsmAmrEncoderNew 65f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project (JNIEnv *env, jclass clazz) { 6649b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong GsmAmrEncoderState* gae = new GsmAmrEncoderState(); 67f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project if (gae == NULL) { 6849b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong throwException(env, "java/lang/RuntimeException", 6949b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong "Out of memory", 0); 70f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project } 71f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project return (jint)gae; 72f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project} 73f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 74f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Projectstatic void android_media_AmrInputStream_GsmAmrEncoderInitialize 75f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project (JNIEnv *env, jclass clazz, jint gae) { 7649b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong GsmAmrEncoderState *state = (GsmAmrEncoderState *) gae; 7749b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong int32_t nResult = AMREncodeInit(&state->mEncState, &state->mSidState, false); 7849b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong if (nResult != OK) { 79f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project throwException(env, "java/lang/IllegalArgumentException", 8049b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong "GsmAmrEncoder initialization failed %d", nResult); 81f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project } 82f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project} 83f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 84f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Projectstatic jint android_media_AmrInputStream_GsmAmrEncoderEncode 85f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project (JNIEnv *env, jclass clazz, 86f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project jint gae, jbyteArray pcm, jint pcmOffset, jbyteArray amr, jint amrOffset) { 87f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 8849b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong jbyte inBuf[BYTES_PER_FRAME]; 8949b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong jbyte outBuf[MAX_OUTPUT_BUFFER_SIZE]; 90f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 9149b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong env->GetByteArrayRegion(pcm, pcmOffset, sizeof(inBuf), inBuf); 9249b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong GsmAmrEncoderState *state = (GsmAmrEncoderState *) gae; 9349b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong int32_t length = AMREncode(state->mEncState, state->mSidState, 9449b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong (Mode) MR122, 9549b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong (int16_t *) inBuf, 9649b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong (unsigned char *) outBuf, 9749b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong (Frame_Type_3GPP*) &state->mLastModeUsed, 9849b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong AMR_TX_WMF); 9949b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong if (length < 0) { 100f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project throwException(env, "java/io/IOException", 10149b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong "Failed to encode a frame with error code: %d", length); 10249b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong return -1; 103f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project } 104f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 105f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project // The 1st byte of PV AMR frames are WMF (Wireless Multimedia Forum) 106f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project // bitpacked, i.e.; 107f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project // [P(4) + FT(4)]. Q=1 for good frame, P=padding bit, 0 108f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project // Here we are converting the header to be as specified in Section 5.3 of 109f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project // RFC 3267 (AMR storage format) i.e. 110f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project // [P(1) + FT(4) + Q(1) + P(2)]. 111f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project if (length > 0) { 112f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project outBuf[0] = (outBuf[0] << 3) | 0x4; 113f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project } 114f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 115f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project env->SetByteArrayRegion(amr, amrOffset, length, outBuf); 116f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 117f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project return length; 118f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project} 119f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 120f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Projectstatic void android_media_AmrInputStream_GsmAmrEncoderCleanup 121f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project (JNIEnv *env, jclass clazz, jint gae) { 12249b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong GsmAmrEncoderState *state = (GsmAmrEncoderState *)gae; 12349b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong AMREncodeExit(&state->mEncState, &state->mSidState); 12449b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong state->mEncState = NULL; 12549b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong state->mSidState = NULL; 126f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project} 127f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 128f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Projectstatic void android_media_AmrInputStream_GsmAmrEncoderDelete 129f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project (JNIEnv *env, jclass clazz, jint gae) { 13049b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong delete (GsmAmrEncoderState*)gae; 131f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project} 132f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 133f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project// ---------------------------------------------------------------------------- 134f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 135f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Projectstatic JNINativeMethod gMethods[] = { 136f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project {"GsmAmrEncoderNew", "()I", (void*)android_media_AmrInputStream_GsmAmrEncoderNew}, 137f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project {"GsmAmrEncoderInitialize", "(I)V", (void*)android_media_AmrInputStream_GsmAmrEncoderInitialize}, 138f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project {"GsmAmrEncoderEncode", "(I[BI[BI)I", (void*)android_media_AmrInputStream_GsmAmrEncoderEncode}, 139f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project {"GsmAmrEncoderCleanup", "(I)V", (void*)android_media_AmrInputStream_GsmAmrEncoderCleanup}, 140f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project {"GsmAmrEncoderDelete", "(I)V", (void*)android_media_AmrInputStream_GsmAmrEncoderDelete}, 141f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project}; 142f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 143f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 144f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Projectint register_android_media_AmrInputStream(JNIEnv *env) 145f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project{ 146f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project const char* const kClassPathName = "android/media/AmrInputStream"; 147f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 148f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project return AndroidRuntime::registerNativeMethods(env, 149f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project kClassPathName, gMethods, NELEM(gMethods)); 150f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project} 151f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 152f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 153