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