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 Projectstatic jint android_media_AmrInputStream_GsmAmrEncoderNew 53f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project (JNIEnv *env, jclass clazz) { 5449b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong GsmAmrEncoderState* gae = new GsmAmrEncoderState(); 55f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project if (gae == NULL) { 5615dd15fd572df6b6f785dff75f66e9b99f40322aElliott Hughes jniThrowRuntimeException(env, "Out of memory"); 57f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project } 58f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project return (jint)gae; 59f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project} 60f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 61f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Projectstatic void android_media_AmrInputStream_GsmAmrEncoderInitialize 62f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project (JNIEnv *env, jclass clazz, jint gae) { 6349b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong GsmAmrEncoderState *state = (GsmAmrEncoderState *) gae; 6449b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong int32_t nResult = AMREncodeInit(&state->mEncState, &state->mSidState, false); 6549b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong if (nResult != OK) { 6615dd15fd572df6b6f785dff75f66e9b99f40322aElliott Hughes jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", 6749b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong "GsmAmrEncoder initialization failed %d", nResult); 68f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project } 69f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project} 70f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 71f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Projectstatic jint android_media_AmrInputStream_GsmAmrEncoderEncode 72f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project (JNIEnv *env, jclass clazz, 73f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project jint gae, jbyteArray pcm, jint pcmOffset, jbyteArray amr, jint amrOffset) { 74f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 7549b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong jbyte inBuf[BYTES_PER_FRAME]; 7649b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong jbyte outBuf[MAX_OUTPUT_BUFFER_SIZE]; 77f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 7849b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong env->GetByteArrayRegion(pcm, pcmOffset, sizeof(inBuf), inBuf); 7949b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong GsmAmrEncoderState *state = (GsmAmrEncoderState *) gae; 8049b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong int32_t length = AMREncode(state->mEncState, state->mSidState, 8149b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong (Mode) MR122, 8249b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong (int16_t *) inBuf, 8349b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong (unsigned char *) outBuf, 8449b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong (Frame_Type_3GPP*) &state->mLastModeUsed, 8549b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong AMR_TX_WMF); 8649b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong if (length < 0) { 8715dd15fd572df6b6f785dff75f66e9b99f40322aElliott Hughes jniThrowExceptionFmt(env, "java/io/IOException", 8849b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong "Failed to encode a frame with error code: %d", length); 8949b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong return -1; 90f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project } 91f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 92f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project // The 1st byte of PV AMR frames are WMF (Wireless Multimedia Forum) 93f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project // bitpacked, i.e.; 94f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project // [P(4) + FT(4)]. Q=1 for good frame, P=padding bit, 0 95f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project // Here we are converting the header to be as specified in Section 5.3 of 96f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project // RFC 3267 (AMR storage format) i.e. 97f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project // [P(1) + FT(4) + Q(1) + P(2)]. 98f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project if (length > 0) { 99f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project outBuf[0] = (outBuf[0] << 3) | 0x4; 100f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project } 101f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 102f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project env->SetByteArrayRegion(amr, amrOffset, length, outBuf); 103f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 104f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project return length; 105f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project} 106f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 107f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Projectstatic void android_media_AmrInputStream_GsmAmrEncoderCleanup 108f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project (JNIEnv *env, jclass clazz, jint gae) { 10949b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong GsmAmrEncoderState *state = (GsmAmrEncoderState *)gae; 11049b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong AMREncodeExit(&state->mEncState, &state->mSidState); 11149b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong state->mEncState = NULL; 11249b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong state->mSidState = NULL; 113f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project} 114f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 115f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Projectstatic void android_media_AmrInputStream_GsmAmrEncoderDelete 116f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project (JNIEnv *env, jclass clazz, jint gae) { 11749b6fbaebd5413b92c6dcff423da95d5525455eeJames Dong delete (GsmAmrEncoderState*)gae; 118f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project} 119f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 120f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project// ---------------------------------------------------------------------------- 121f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 122f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Projectstatic JNINativeMethod gMethods[] = { 123f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project {"GsmAmrEncoderNew", "()I", (void*)android_media_AmrInputStream_GsmAmrEncoderNew}, 124f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project {"GsmAmrEncoderInitialize", "(I)V", (void*)android_media_AmrInputStream_GsmAmrEncoderInitialize}, 125f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project {"GsmAmrEncoderEncode", "(I[BI[BI)I", (void*)android_media_AmrInputStream_GsmAmrEncoderEncode}, 126f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project {"GsmAmrEncoderCleanup", "(I)V", (void*)android_media_AmrInputStream_GsmAmrEncoderCleanup}, 127f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project {"GsmAmrEncoderDelete", "(I)V", (void*)android_media_AmrInputStream_GsmAmrEncoderDelete}, 128f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project}; 129f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 130f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 131f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Projectint register_android_media_AmrInputStream(JNIEnv *env) 132f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project{ 133f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project const char* const kClassPathName = "android/media/AmrInputStream"; 134f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 135f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project return AndroidRuntime::registerNativeMethods(env, 136f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project kClassPathName, gMethods, NELEM(gMethods)); 137f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project} 138