android_media_AmrInputStream.cpp revision f013e1afd1e68af5e3b868c26a653bbfb39538f8
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 <media/mediarecorder.h> 22f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project#include <stdio.h> 23f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project#include <assert.h> 24f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project#include <limits.h> 25f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project#include <unistd.h> 26f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project#include <fcntl.h> 27f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project#include <utils/threads.h> 28f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 29f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project#include "jni.h" 30f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project#include "JNIHelp.h" 31f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project#include "android_runtime/AndroidRuntime.h" 32f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project#include "gsmamr_encoder_wrapper.h" 33f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 34f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 35f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project// ---------------------------------------------------------------------------- 36f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 37f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Projectusing namespace android; 38f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 39f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project// Corresponds to max bit rate of 12.2 kbps. 40f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Projectstatic const int aMaxOutputBufferSize = 32; 41f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 42f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Projectstatic const int SAMPLES_PER_FRAME = 8000 * 20 / 1000; 43f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 44f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 45f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project// 46f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project// helper function to throw an exception 47f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project// 48f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Projectstatic void throwException(JNIEnv *env, const char* ex, const char* fmt, int data) { 49f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project if (jclass cls = env->FindClass(ex)) { 50f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project char msg[1000]; 51f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project sprintf(msg, fmt, data); 52f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project env->ThrowNew(cls, msg); 53f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project env->DeleteLocalRef(cls); 54f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project } 55f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project} 56f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 57f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Projectstatic jint android_media_AmrInputStream_GsmAmrEncoderNew 58f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project (JNIEnv *env, jclass clazz) { 59f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project CPvGsmAmrEncoder* gae = new CPvGsmAmrEncoder(); 60f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project if (gae == NULL) { 61f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project throwException(env, "java/lang/IllegalStateException", 62f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project "new CPvGsmAmrEncoder() failed", 0); 63f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project } 64f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project return (jint)gae; 65f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project} 66f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 67f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Projectstatic void android_media_AmrInputStream_GsmAmrEncoderInitialize 68f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project (JNIEnv *env, jclass clazz, jint gae) { 69f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project // set input parameters 70f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project TEncodeProperties encodeProps; 71f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project encodeProps.iInBitsPerSample = 16; 72f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project encodeProps.iInSamplingRate = 8000; 73f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project encodeProps.iInClockRate = 1000; 74f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project encodeProps.iInNumChannels = 1; 75f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project encodeProps.iInInterleaveMode = TEncodeProperties::EINTERLEAVE_LR; 76f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project encodeProps.iMode = CPvGsmAmrEncoder::GSM_AMR_12_2; 77f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project encodeProps.iBitStreamFormatIf2 = false; 78f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project encodeProps.iAudioObjectType = 0; 79f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project encodeProps.iOutSamplingRate = encodeProps.iInSamplingRate; 80f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project encodeProps.iOutNumChannels = encodeProps.iInNumChannels; 81f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project encodeProps.iOutClockRate = encodeProps.iInClockRate; 82f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 83f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project if (int rtn = ((CPvGsmAmrEncoder*)gae)-> 84f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project InitializeEncoder(aMaxOutputBufferSize, &encodeProps)) { 85f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project throwException(env, "java/lang/IllegalArgumentException", 86f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project "CPvGsmAmrEncoder::InitializeEncoder failed %d", rtn); 87f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project } 88f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project} 89f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 90f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Projectstatic jint android_media_AmrInputStream_GsmAmrEncoderEncode 91f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project (JNIEnv *env, jclass clazz, 92f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project jint gae, jbyteArray pcm, jint pcmOffset, jbyteArray amr, jint amrOffset) { 93f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 94f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project // set up input stream 95f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project jbyte inBuf[SAMPLES_PER_FRAME*2]; 96f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project TInputAudioStream in; 97f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project in.iSampleBuffer = (uint8*)inBuf; 98f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project env->GetByteArrayRegion(pcm, pcmOffset, sizeof(inBuf), inBuf); 99f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project in.iSampleLength = sizeof(inBuf); 100f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project in.iMode = CPvGsmAmrEncoder::GSM_AMR_12_2; 101f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project in.iStartTime = 0; 102f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project in.iStopTime = 0; 103f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 104f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project // set up output stream 105f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project jbyte outBuf[aMaxOutputBufferSize]; 106f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project int32 sampleFrameSize[1] = { 0 }; 107f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project TOutputAudioStream out; 108f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project out.iBitStreamBuffer = (uint8*)outBuf; 109f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project out.iNumSampleFrames = 0; 110f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project out.iSampleFrameSize = sampleFrameSize; 111f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project out.iStartTime = 0; 112f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project out.iStopTime = 0; 113f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 114f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project // encode 115f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project if (int rtn = ((CPvGsmAmrEncoder*)gae)->Encode(in, out)) { 116f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project throwException(env, "java/io/IOException", "CPvGsmAmrEncoder::Encode failed %d", rtn); 117f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project return -1; 118f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project } 119f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 120f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project // validate one-frame assumption 121f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project if (out.iNumSampleFrames != 1) { 122f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project throwException(env, "java/io/IOException", 123f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project "CPvGsmAmrEncoder::Encode more than one frame returned %d", out.iNumSampleFrames); 124f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project return 0; 125f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project } 126f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 127f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project // copy result 128f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project int length = out.iSampleFrameSize[0]; 129f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 130f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project // The 1st byte of PV AMR frames are WMF (Wireless Multimedia Forum) 131f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project // bitpacked, i.e.; 132f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project // [P(4) + FT(4)]. Q=1 for good frame, P=padding bit, 0 133f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project // Here we are converting the header to be as specified in Section 5.3 of 134f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project // RFC 3267 (AMR storage format) i.e. 135f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project // [P(1) + FT(4) + Q(1) + P(2)]. 136f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project if (length > 0) { 137f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project outBuf[0] = (outBuf[0] << 3) | 0x4; 138f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project } 139f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 140f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project env->SetByteArrayRegion(amr, amrOffset, length, outBuf); 141f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 142f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project return length; 143f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project} 144f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 145f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Projectstatic void android_media_AmrInputStream_GsmAmrEncoderCleanup 146f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project (JNIEnv *env, jclass clazz, jint gae) { 147f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project if (int rtn = ((CPvGsmAmrEncoder*)gae)->CleanupEncoder()) { 148f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project throwException(env, "java/lang/IllegalStateException", 149f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project "CPvGsmAmrEncoder::CleanupEncoder failed %d", rtn); 150f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project } 151f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project} 152f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 153f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Projectstatic void android_media_AmrInputStream_GsmAmrEncoderDelete 154f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project (JNIEnv *env, jclass clazz, jint gae) { 155f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project delete (CPvGsmAmrEncoder*)gae; 156f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project} 157f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 158f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project// ---------------------------------------------------------------------------- 159f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 160f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Projectstatic JNINativeMethod gMethods[] = { 161f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project {"GsmAmrEncoderNew", "()I", (void*)android_media_AmrInputStream_GsmAmrEncoderNew}, 162f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project {"GsmAmrEncoderInitialize", "(I)V", (void*)android_media_AmrInputStream_GsmAmrEncoderInitialize}, 163f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project {"GsmAmrEncoderEncode", "(I[BI[BI)I", (void*)android_media_AmrInputStream_GsmAmrEncoderEncode}, 164f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project {"GsmAmrEncoderCleanup", "(I)V", (void*)android_media_AmrInputStream_GsmAmrEncoderCleanup}, 165f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project {"GsmAmrEncoderDelete", "(I)V", (void*)android_media_AmrInputStream_GsmAmrEncoderDelete}, 166f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project}; 167f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 168f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 169f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Projectint register_android_media_AmrInputStream(JNIEnv *env) 170f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project{ 171f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project const char* const kClassPathName = "android/media/AmrInputStream"; 172f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project jclass clazz; 173f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 174f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project clazz = env->FindClass(kClassPathName); 175f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project if (clazz == NULL) { 176f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project LOGE("Can't find %s", kClassPathName); 177f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project return -1; 178f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project } 179f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 180f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project return AndroidRuntime::registerNativeMethods(env, 181f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project kClassPathName, gMethods, NELEM(gMethods)); 182f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project} 183f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 184f013e1afd1e68af5e3b868c26a653bbfb39538f8The Android Open Source Project 185