IM
即为Instant Message,
消息内容不大,传输快速
即时到达,实时通知
IM中语音功能简介
控制消息大小,语音时长在一分钟以内。
数据压缩,减小传输数据量
长连接接受通知,声音文件单独下载
语音功能流程
发送方:
开启录音
获取数据
编码保存
接收方
解码
接受数据
播放
需要编解码的原因:
声音原始数据非常大,不压缩传输量几乎无法接受
主要API
声音采集:
MediaRecorder:直接录制成文件并且保存起来
AudioRecord:直接把声音实时的字节数据返还给我们
声音播放:
Mediplayer:基于文件的播放
AudioTrack:提供基于字节数据播放
数据传输:
基于文件:HTTP文件上传下载
基于字节流:TCP/WebScoket
Demo
权限
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
使用文件模式录音和播放
public class RecordAudioByFileActivity extends AppCompatActivity {
private static final String TAG = RecordAudioByFileActivity.class.getSimpleName();
@BindView(R.id.tvLog)
TextView mTvLog;
@BindView(R.id.tvPressToSay)
Button mTvPressToSay;
@BindView(R.id.btnPlayAudio)
Button mBtnPlayAudio;
private ExecutorService mExecutorService;
private MediaRecorder mMediaRecorder;
private File mAudioFile;
private long mBeginRecordInMillis, mEndRecordInMillis;
// 播放状态
private volatile boolean mIsplaying;
private MediaPlayer mMediaPlayer;
public void setIsplaying(boolean isplaying) {
//设置当前播放状态
mIsplaying = isplaying;
//改变UI
mBtnPlayAudio.setText(
mIsplaying ? R.string.record_audio_stop_playing : R.string.record_audio_playing);
if (mIsplaying) {
if (mAudioFile != null) {
mExecutorService.submit(new Runnable() {
@Override
public void run() {
doPlayAudio(mAudioFile);
}
});
} else {
Toast.makeText(RecordAudioByFileActivity.this, "请先录音...",
Toast.LENGTH_SHORT).show();
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_record_audio_by_file);
ButterKnife.bind(this);
// 录音JNI函数不具备线程安全性,所以要用单线程
mExecutorService = Executors.newSingleThreadExecutor();
initUIControlerEventHandlers();
}
@Override
protected void onDestroy() {
//activity销毁后,停止后台任务,避免内存泄漏
mExecutorService.shutdownNow();
releaseRecorder();
stopPlay();
super.onDestroy();
}
@OnClick(R.id.btnPlayAudio)
void playAudioHandler() {
setIsplaying(!mIsplaying);
}
//按下说话,释放发送,所以不要使用onClciker
private void initUIControlerEventHandlers() {
mTvPressToSay.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startRecordAudio();
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
stopRecordAudio();
break;
default:
break;
}
return true;
}
});
}
/**
* 开始录音
*/
private void startRecordAudio() {
//改变UI状态,正在说话
mTvPressToSay.setText(R.string.record_audio_speaking);
//提交后台任务,执行录音
mExecutorService.submit(new Runnable() {
@Override
public void run() {
//释放之前的录音的recorder
releaseRecorder();
//执行录音逻辑,如果失败提示用户
if (!doStartRecordAudio()) {
recordFail();
}
}
});
}
/**
* 停止录音
*/
private void stopRecordAudio() {
//改变UI状态,按