android pcm数据格式,android 实时PCM数据编码成AAC

获取PCM流

package com.ff.aac.audio;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.InputStream;

import java.io.OutputStream;

import java.util.ArrayList;

import java.util.Arrays;

import java.util.List;

import com.ff.aac.jni.AacEncoder;

import android.media.AudioRecord;

import android.media.MediaRecorder.AudioSource;

import android.os.SystemClock;

import android.util.Log;

/**

* 音频发送封装类

*/

public class DAudioRecord implements Runnable{

private final String TAG="DAudioRecord";

private int mFrequency;//采样率

private int mChannel;//声道

private int mSampBit;//采样精度

private AacEncoder encoder;

private AudioRecord mAudioRecord;

private boolean recordTag;

private int minBufferSize;

public DAudioRecord(int frequency,int channel,int sampbit){

this.mFrequency = frequency;

this.mChannel = channel;

this.mSampBit = sampbit;

}

public void init(){

if(mAudioRecord != null){

release();

}

try {

minBufferSize = AudioRecord.getMinBufferSize(mFrequency, mChannel, mSampBit);

mAudioRecord = new AudioRecord(AudioSource.MIC, mFrequency, mChannel, mSampBit, minBufferSize);

Log.i(TAG, "minBufferSize = " + minBufferSize);

} catch (Exception e) {

Log.i(TAG, "创建录音器出错");

}

}

public void startRecord(AacEncoder encoder){

this.recordTag = true;

this.encoder = encoder;

new Thread(this).start();

}

public void stopRecord(){

this.recordTag = false;

}

public void release(){

if(mAudioRecord != null){

try {

mAudioRecord.stop();

mAudioRecord.release();

encoder.stopSendRecodData();

} catch (Exception e) {

Log.i(TAG, "关闭录音出错");

}finally{

mAudioRecord = null;

encoder = null;

System.gc();

}

}

}

@Override

public void run() {

try {

boolean b = true;

while (b && recordTag) {

if(mAudioRecord.getState() == AudioRecord.STATE_INITIALIZED){

mAudioRecord.startRecording();

b = false;

}

Log.i(TAG, "录音开始初始化");

SystemClock.sleep(10);

}

byte[] audioData = new byte[512]; // 640

byte[] audioData1 = new byte[2048]; // inputSamples = 1024, maxOutputBytes = 768 ,maxInputBytes = 2048 (jni 中编码aac中获取到的信息)

int i = 0;

while (recordTag) {

int size = mAudioRecord.read(audioData, 0,audioData.length);

if (size == audioData.length) {

Log.i("AAC_JNI", "录音" + size);

for(int j = 0; j < size; j++){

audioData1[j + i * 512] = audioData[j];

}

i++;

if(i == 4){

this.encoder.sendRecordData(audioData1);

i = 0;

}

}

}

} catch (Exception e) {

Log.i(TAG, "录音过程出错 " + e.getMessage());

}

}

}

jni中结构体

struct AacDecoderInfo{

faacEncHandle hEncoder;

char* pcmBuffer;

char* aacBuffer;

int maxInputBytes;

int maxOutputBytes;

int bitSize;

int inputSamples;

FILE* ftOutFile;

};

struct AacDecoderInfo *aacDecoderInfo;jni中进行实时编码

JNIEXPORT void JNICALL Java_com_ff_aac_jni_AacEncoder_initAACEncoder

(JNIEnv *env, jobject obj){

unsigned long sampleRate = 8000;

unsigned int numChannels = 1;

unsigned long inputSamples;

unsigned long maxOutputBytes;

faacEncHandle hEncoder = faacEncOpen(sampleRate, numChannels, &inputSamples, &maxOutputBytes);

LOGD("inputSamples = %d, maxOutputBytes = %d, sampleRate = %d", inputSamples, maxOutputBytes);

faacEncConfigurationPtr pConfigPtr;

pConfigPtr = faacEncGetCurrentConfiguration(hEncoder);

if(!pConfigPtr){

LOGD("faacEncGetCurrentConfiguration ERROR!");

faacEncClose(hEncoder);

hEncoder = NULL;

return;

}

pConfigPtr->inputFormat = FAAC_INPUT_16BIT;//输入数据类型

pConfigPtr->outputFormat = 1; //0-Raw ; 1-ADTS

pConfigPtr->bitRate = 8000;

//pConfigPtr->useTns= 0;//瞬时噪声定形(temporal noise shaping,TNS)滤波器

//pConfigPtr->useLfe= 0;//低频效果

pConfigPtr->aacObjectType= LOW; //编码类型

pConfigPtr->shortctl=SHORTCTL_NORMAL;

pConfigPtr->quantqual=20;

pConfigPtr->mpegVersion = MPEG2;

int nRetVal = faacEncSetConfiguration(hEncoder, pConfigPtr);

LOGD("nRetVal = %d", nRetVal);

int nPCMBitSize = 16; // 量化位数

int m_nMaxInputBytes = inputSamples * nPCMBitSize / 8;

LOGD("m_nMaxInputBytes = %d", m_nMaxInputBytes);

char pbPCMBuffer[m_nMaxInputBytes]; // 读取PCM数据

char pbAACBuffer[maxOutputBytes];

FILE* fpOut = fopen("/storage/emulated/0/t/pcm2aac.aac", "wb");

aacDecoderInfo = malloc(sizeof(struct AacDecoderInfo));

aacDecoderInfo->hEncoder = hEncoder;

aacDecoderInfo->pcmBuffer = pbPCMBuffer;

aacDecoderInfo->aacBuffer = pbAACBuffer;

aacDecoderInfo->maxInputBytes = m_nMaxInputBytes;

aacDecoderInfo->maxOutputBytes = maxOutputBytes;

aacDecoderInfo->bitSize = nPCMBitSize;

aacDecoderInfo->inputSamples = inputSamples;

aacDecoderInfo->ftOutFile = fpOut;

isRecord = true;

}

/*

* http://blog.csdn.net/jwzhangjie/article/details/8782656 (如果不这样设置将导致编码失败)

*

* */

size_t read_int16(int16_t *outbuf, size_t num, unsigned char *inputbuf){

size_t i = 0 , j = 0;

unsigned char bufi[8];

while(i < num){

memcpy(bufi, inputbuf+j, (aacDecoderInfo->bitSize / 8));

j+= (aacDecoderInfo->bitSize / 8);

int16_t s = ((int16_t*)bufi)[0];

outbuf[i] = s;

i++;

}

return 0;

}

JNIEXPORT void JNICALL Java_com_ff_aac_jni_AacEncoder_sendRecordData

(JNIEnv *env, jobject obj, jbyteArray arr){

LOGD("sendRecordData isRecord = %d", isRecord);

jsize size = (*env)->GetArrayLength(env, arr);

LOGD("sendRecordData arr size = %d", size);

int inputSamples = size / (aacDecoderInfo->bitSize / 8);

LOGD("sendRecordData intputSamples = %d, default intputSamples = %d", inputSamples, aacDecoderInfo->inputSamples);

memset(aacDecoderInfo->aacBuffer, 0, aacDecoderInfo->maxOutputBytes);

char* cArr = (*env)->GetByteArrayElements(env,arr,false);

int pumbuff_size = size / (aacDecoderInfo->bitSize / 8);

int pumBuf[pumbuff_size];

read_int16(pumBuf, size, cArr);

int nRetVal = faacEncEncode(aacDecoderInfo->hEncoder, pumBuf, inputSamples, aacDecoderInfo->aacBuffer, aacDecoderInfo->maxOutputBytes);

LOGD("sendRecordData nRetVal = %d", nRetVal);

(*env)->ReleaseByteArrayElements(env, arr, cArr, 0);

fwrite(aacDecoderInfo->aacBuffer, 1, nRetVal, aacDecoderInfo->ftOutFile);

}

JNIEXPORT void JNICALL Java_com_ff_aac_jni_AacEncoder_stopSendRecodData

(JNIEnv *env, jobject obj){

fclose(aacDecoderInfo->ftOutFile);

faacEncClose(aacDecoderInfo->hEncoder);

free(aacDecoderInfo);

}java 调用

int frequency = 8000;

int channel = AudioFormat.CHANNEL_IN_MONO;

int sampbit = AudioFormat.ENCODING_PCM_16BIT;

audioRecord = new DAudioRecord(frequency, channel, sampbit);

audioRecord.init();

final AacEncoder encoder = new AacEncoder();

audioRecord.startRecord(encoder);

package com.ff.aac.jni;

public class AacEncoder {

static{

System.loadLibrary("aacdec");

}

public native void initAACEncoder();

public native void sendRecordData(byte[] data);

public native void stopSendRecodData();

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Android系统自带的热点功能可以作为网络通讯的媒介,在连接到热点的设备之间传输数据。因为传输语音数据需要保证实时性和稳定性,所以在热点传输语音数据时需要考虑以下方面。 首先,需要选用适合的网络传输协议。传输语音数据需要保证实时性和稳定性,所以应该选用UDP协议而不是TCP协议。因为UDP协议没有TCP协议的握手和确认机制,可以减少传输时延,适合用于实时数据的传输。 其次,需要考虑语音编码和解码方法。选择合适的编码格式可以既保证语音质量,又减小数据量,提高传输效率。当前常用的音频编码格式有AMR、AACPCM等,不同的编码格式具有不同的特点,需要根据具体情况进行选择。 最后,需要关注网络带宽的使用情况。在热点连接的设备数量较多时,需要合理分配带宽资源,避免网络拥塞导致的延迟和数据传输中断。可以采用动态带宽分配算法,根据设备连接情况动态分配带宽,保证语音传输质量。 总之,在热点传输语音数据方面,需要选用适合的网络协议、选择合适的编码格式并关注网络带宽的使用情况,这样才能达到良好的传输效果。 ### 回答2: 安卓系统的热点传输功能是指在手机作为热点连接方式时,其他设备可以通过无线连接接入该热点并进行数据传输。而语音数据传输则指的是将人类的语音信息进行数字化处理转换可传输的数据,通过音频传输的方式进行交流。在安卓系统中,可以利用热点传输语音数据的方式进行语音通话或语音聊天等功能操作。 首先,在使用热点传输语音数据时,需要保证手机本身有语音通话的功能,可以通过内置麦克风和扬声器实现语音交流。然后,在手机设置中开启热点功能并选择“安全性较高的WPA2 PSK”方式,以加密数据传输,防止信息泄露。 对于其他设备进行连接时,需要在设备设置中找到手机的WiFi热点,输入安全密码并功连接该热点。在进行语音通话或聊天时,可以利用已经安装的通讯类应用实现,例如常用的Skype、微信、QQ等。通过这些应用,用户可以进行实时语音交流,并且可进行单人或多人语音通话,实现真正意义上的远程语音交流功能。 总之,利用安卓系统的热点传输语音数据功能,可以实现简单方便的远程语音通话和聊天,达到人与人之间的交流和沟通。当然,在进行该功能操作时,需要注意安全性以及网络稳定性,才能保证良好的使用效果。 ### 回答3: Android系统提供了多种方式来热点传输语音数据,如使用网络实时通信协议(WebRTC)库或第三方音频传输库等。其中,WebRTC库是一个Google开源的跨平台实时通信库,支持音频、视频和数据传输。使用WebRTC库,可以在应用之间通过网络热点传输语音数据,并实现高质量的音频通信。此外,第三方音频传输库也是常用的实现语音传输的方式之一,常见的有OpenSL ES和AudioTrack等,这些库提供了音频编解码、信号处理和传输等功能,可用于实现高效的音频传输和通信。 在使用这些库实现语音传输时,需要考虑以下问题: 1. 音频编码和解码:需要选择适合实际应用的音频编码格式,以确保音质和传输效率。通常使用较常见的音频编码格式,如opus或aac。 2. 网络传输:通过热点网络传输语音数据时,需要考虑带宽和延迟等问题,以便实现高效的音频通信。可以通过使用带宽自适应技术、网络拥塞控制等方式,来提高音频传输的效率。 3. 声音效果:为了实现更好的用户体验,还需要考虑音频质量和可靠性等方面的问题,如消除回声、降噪等。 总之,Android系统提供了多种方式来实现热点传输语音数据,这些方式可以根据实际需求和应用场景进行选择和使用。但无论使用何种方式,都需要考虑音质、传输效率以及用户体验等方面的问题,以便实现高效稳定的语音通信。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值