Android 开发 如何实现高质量的录音

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 开发 如何实现高质量的录音相关的知识,希望对你有一定的参考价值。

最近在做K歌软件 但是录音的质量不是很好 有杂音 请问怎么才能提高录音质量 怎么去除杂音 或者有没有这方面的开源框架啊 请教 急急急

在移动APP开发中,每逢APP应用设计到多媒体开发的时候,都会让很多的程序员头疼不已,而且项目的开发进度会放慢、项目
的难度也会加大蛮多,同时APP的测试也会增加。android中的多媒体开发,有音频的播放、音频的录制、视频的播放、视频的录制
等,虽然Android的SDK中提供了一些基础的开发API类,如音频的录制就提供了两种方式:AudioRecord录制音频和MediaRecorder录
制音频。AudioRecord类相对于MediaRecorder来说,更加接近底层,为我们封装的方法也更少。然而实现一个AudioRecord的音频录
制程序也很简单。
一、AudioRecord实现录制音频:
package com.hb56.MyAndroidUtil;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Intent;
import android.hardware.Camera.AutoFocusCallback;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

/**
* 该实例中,我们使用AudioRecord类来完成我们的音频录制程序
* AudioRecord类,我们可以使用三种不同的read方法来完成录制工作,
* 每种方法都有其实用的场合
* 一、实例化一个AudioRecord类我们需要传入几种参数
* 1、Audiosource:这里可以是MediaRecorder.AudioSource.MIC
* 2、SampleRateInHz:录制频率,可以为8000hz或者11025hz等,不同的硬件设备这个值不同
* 3、ChannelConfig:录制通道,可以为AudioFormat.CHANNEL_CONFIGURATION_MONO和AudioFormat.CHANNEL_CONFIGURATION_STEREO
* 4、AudioFormat:录制编码格式,可以为AudioFormat.ENCODING_16BIT和8BIT,其中16BIT的仿真性比8BIT好,但是需要消耗更多的电量和存储空间
* 5、BufferSize:录制缓冲大小:可以通过getMinBufferSize来获取
* 这样我们就可以实例化一个AudioRecord对象了
* 二、创建一个文件,用于保存录制的内容
* 同上篇
* 三、打开一个输出流,指向创建的文件
* DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)))
* 四、现在就可以开始录制了,我们需要创建一个字节数组来存储从AudioRecorder中返回的音频数据,但是
* 注意,我们定义的数组要小于定义AudioRecord时指定的那个BufferSize
* short[]buffer = new short[BufferSize/4];
* startRecording();
* 然后一个循环,调用AudioRecord的read方法实现读取
* 另外使用MediaPlayer是无法播放使用AudioRecord录制的音频的,为了实现播放,我们需要
* 使用AudioTrack类来实现
* AudioTrack类允许我们播放原始的音频数据
*
*
* 一、实例化一个AudioTrack同样要传入几个参数
* 1、StreamType:在AudioManager中有几个常量,其中一个是STREAM_MUSIC;
* 2、SampleRateInHz:最好和AudioRecord使用的是同一个值
* 3、ChannelConfig:同上
* 4、AudioFormat:同上
* 5、BufferSize:通过AudioTrack的静态方法getMinBufferSize来获取
* 6、Mode:可以是AudioTrack.MODE_STREAM和MODE_STATIC,关于这两种不同之处,可以查阅文档
* 二、打开一个输入流,指向刚刚录制内容保存的文件,然后开始播放,边读取边播放
*
* 实现时,音频的录制和播放分别使用两个AsyncTask来完成
*/
/**
* 利用AudioRecord类实现自己的音频录制程序
* com.hb56.MyAndroidUtil.AudioRecord
*
* @author Admin-zhangyx
*
* create at 2014-10-16 下午2:03:13
*/
public class AudioRecordActivity extends Activity
private TextView stateView;
private Button btnStart, btnStop, btnPlay, btnFinish;
private RecordTask recorder;
private PlayTask player;
private File audioFile;
private boolean isRecording = true, isPlaying = false; // 标记
private int frequence = 8000; // 录制频率,单位hz.这里的值注意了,写的不好,可能实例化AudioRecord对象的时候,会出错。我开始写成11025就不行。这取决于硬件设备
private int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;
private int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;

public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.my_audio_record);
stateView = (TextView) this.findViewById(R.id.view_state);
stateView.setText("准备开始");
btnStart = (Button) this.findViewById(R.id.btn_start);
btnStop = (Button) this.findViewById(R.id.btn_stop);
btnPlay = (Button) this.findViewById(R.id.btn_play);
btnFinish = (Button) this.findViewById(R.id.btn_finish);
btnFinish.setText("停止播放");
btnStop.setEnabled(false);
btnPlay.setEnabled(false);
btnFinish.setEnabled(false);

// 在这里我们创建一个文件,用于保存录制内容
File fpath = new File(Environment.getExternalStorageDirectory()
.getAbsolutePath() + "/data/files/");
fpath.mkdirs();// 创建文件夹
try
// 创建临时文件,注意这里的格式为.pcm
audioFile = File.createTempFile("recording", ".pcm", fpath);
catch (IOException e)
// TODO Auto-generated catch block
e.printStackTrace();



public void onClick(View v)
int id = v.getId();
switch (id)
case R.id.btn_start:
// 开始录制

// 这里启动录制任务
recorder = new RecordTask();
recorder.execute();

break;
case R.id.btn_stop:
// 停止录制
this.isRecording = false;
// 更新状态
// 在录制完成时设置,在RecordTask的onPostExecute中完成
break;
case R.id.btn_play:

player = new PlayTask();
player.execute();
break;

http://www.2cto.com/kf/201503/382894.html追问

我是问怎提高录音质量 有杂音啊 不是问怎么录音

参考技术A 如果你有一台Android设备,就会注意到当你按下增大或降低音量按钮时,你所控制的不同音量设置取决于你正在运行的应用程序。在通话中,你控制的是输入语音流的音量;在视频播放器中,你控制的是视频音频的音量;在主屏幕上,你控制的是铃声的音量。Android为不同的目的提供不同音频流。当我们在游戏中播放音频时,可使用类来输出音效和音乐到特定的音乐流。
不过,在我们想播放音效或音乐之前,需要确定音量按钮控制了正确的音频流。为此,我们使用Context接口的另一个方法:context.setVolumeControlStream(AudioManager.STREAM_MUSIC);一如既往,Context的实现仍然由我们的活动来负责。调用该方法之后,音量按钮就控制了该音乐流,后面我们就可使用它来输出我们的音效和音乐。在活动的生命周期内我们只需要调用该方法一次,最好是在Activity.onCreate()方法中调用它。首先我们要分清音乐流和音效的不同。后者一般是存储在内存中且其长度不会超过几秒钟。Android系统给我们提供了一个SoundPool类,使用它可以很容易实现音效播放。我们可以很简单地初始化一个新的SoundPool实例,如下所示:SoundPool soundPool = new SoundPool(20, AudioManager.STREAM_MUSIC, 0);第一个参数指定在同一时刻我们最多能播放多少个音效。这并不是说我们不能加载更多的音效文件,它只不过是限制可同时播放的音效个数。第二个参数指定了SoundPool使用什么音频流来输出该音频。我们在这里选择音乐流,同时也已经为它设置好音量控件。最后一个参数现在没有使用,它应该为默认值0.为了从一个音频文件加载音效到堆内存中,我们可使用SoundPool.load()方法。所有的文件都存储在assets/目录下,因此我们需要重载SoundPool.load()方法。所有的文件都存储在assets/目录下,因此我们需要重载SoundPool.load()方法来获得一个AssetFileDescriptor。我们怎么获得AssetFileDescriptor呢?使用AssetManager。这里我们使用SoundPool从assets/目录加载一个名为explosion.ogg的OGG文件:AssetFileDescriptor descriptor = assetManager.openFd("explosion.ogg");int explosionId = soundPool.load(descriptor, 1);通过AssetManager.openFd()方法可直接获得AssetFileDescriptor,而通过SoundPool可很容易地加载音效,第二个参数用于指定该音效的优先级。这个参数目前未使用,为了以后的兼容应设置为1.SoundPool.load()方法将返回一个整型值,它将作为一个句柄用于加载的音效。当我们想播放音效时,只需要指定该句柄,SoundPool就知道该播放哪个音频。soundPool.play(explosionId, 1.0f, 1.0f, 0, 0, 1);第一个参数是从SoundPool.load()方法接受句柄。接下来两个参数分别用于指定左右通道的音量,其值应该从0(静音)到1(最大)接下来两个参数我们很少使用,其中第一个参数是优先级,目前没有使用,并且应该设置为0.而另一个参数用于指定音效循环播放的频率,一般不建议循环播放音效,因此设置为0。最后一个参数是播放速率,将其设置为大于1时,音效播放的速度将会比其在录制时快;而将它设置为小于1时,播放该音效就会比较慢。当我们不再需要一个音效并希望释放内存时,可使用SoundPool.unload()方法:soundPool.unload(explosionId);我们只需要将从SoundPool.load()方法接收的音效句柄传入即可,该方法会将音效从内存卸载。当我们完成所有的音效输出且不再需要SoundPool时,需要调用SoundPool.release()方法来释放SoundPool所占用的所有资源。当然,在释放之后,我们不能再使用SoundPool,而且SoundPool所加载的所有音效也会被释放。现在编写一个简单的测试活动,每当单击屏幕时它就播放一个爆炸音效。代码如下:[java] view plaincopypackage org.example.ch04_android_basics; import java.io.IOException; import android.app.Activity; import android.content.res.AssetFileDescriptor; import android.content.res.AssetManager; import android.media.AudioManager; import android.media.SoundPool; import android.os.Bundle; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.widget.TextView; public class SoundPoolTest extends Activity implements OnTouchListener SoundPool soundPool; int explosionId = -1; @Override protected void onCreate(Bundle savedInstanceState) // TODO Auto-generated method stub super.onCreate(savedInstanceState); TextView textView = new TextView(this); textView.setOnTouchListener(this); setContentView(textView); setVolumeControlStream(AudioManager.STREAM_MUSIC); soundPool = new SoundPool(20, AudioManager.STREAM_MUSIC, 0); try AssetManager assetManager = getAssets(); AssetFileDescriptor descriptor = assetManager .openFd("explosion.ogg"); explosionId = soundPool.load(descriptor, 1); catch(IOException e) textView.setText("Couldn't load sound effect from asset, " + e.getMessage()); @Override public boolean onTouch(View v, MotionEvent event) // TODO Auto-generated method stub if(event.getAction() == MotionEvent.ACTION_UP) if(explosionId != -1) soundPool.play(explosionId, 1, 1, 0, 0, 1); return true; @Override protected void onPause() // TODO Auto-generated method stub super.onPause(); soundPool.release();

SoundPool在处理MP3文件或长的音频文件时会有问题,长文件的定义超过5或6秒钟。一般建议使用OGG音频文件来代替MP3文件,并尽可能使用低的采样率和持续时间,同时保持音效质量。短小的音效很时候放在Android应用程序从操作系统分配到的堆内存中,而包含较长音乐文件的大音频文件就很不适合了。为此,我们就需要将音乐以流的方式输出到音频硬件上,这就意味着每次我们只能读入一小块数据,该数据足于解码成原生的PCM数据并输出到音频芯片上。这听起来挺吓人的。不过幸运的是,我们有MediaPlayer类,它能处理的所有事情。初始化MediaPlayer类:MediaPl
参考技术B   Android 开发实现高质量录音步骤如下:
一、新建工程SoundRecoderDemo
二、main.xml(布局文件)

[html] view plaincopyprint?
<span style="font-size:16px;"><?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal" >

<Button
android:id="@+id/start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="start" />

<Button
android:id="@+id/stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="stop" />

<Button
android:id="@+id/play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="play" />

</LinearLayout></span>

三、SoundRecorderActivity(具体录音实现)

[java] view plaincopyprint?
<span style="font-size:16px;">import java.io.File;
import java.io.IOException;

import android.app.Activity;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class SoundRecorderActivity extends Activity implements OnClickListener

private Button btnStart;
private Button btnStop;
private Button btnPlay;

private MediaRecorder mMediaRecorder;
private File recAudioFile;
private MusicPlayer mPlayer;

@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

setupViews();


private void setupViews()
btnStart = (Button) findViewById(R.id.start);
btnStop = (Button) findViewById(R.id.stop);
btnPlay = (Button) findViewById(R.id.play);

btnStart.setOnClickListener(this);
btnStop.setOnClickListener(this);
btnPlay.setOnClickListener(this);

recAudioFile = new File("/mnt/sdcard", "new.amr");


@Override
public void onClick(View v)
switch (v.getId())
case R.id.start:
startRecorder();
break;
case R.id.stop:
stopRecorder();
break;
case R.id.play:
mPlayer = new MusicPlayer(SoundRecorderActivity.this);
mPlayer.playMicFile(recAudioFile);
break;
default:
break;



private void startRecorder()
mMediaRecorder = new MediaRecorder();
if (recAudioFile.exists())
recAudioFile.delete();


mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
mMediaRecorder.setOutputFile(recAudioFile.getAbsolutePath());
try
mMediaRecorder.prepare();
catch (IllegalStateException e)
e.printStackTrace();
catch (IOException e)
e.printStackTrace();


mMediaRecorder.start();


private void stopRecorder()
if (recAudioFile!=null)
mMediaRecorder.stop();
mMediaRecorder.release();


</span>

四、播放类(MusicPlayer)

[java] view plaincopyprint?
<span style="font-size:16px;">import java.io.File;

import android.content.Context;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.net.Uri;
import android.util.Log;

public class MusicPlayer
private final static String TAG = "MusicPlayer";
private static MediaPlayer mMediaPlayer;
private Context mContext;

public MusicPlayer(Context context)
mContext = context;


public void playMicFile(File file)
if (file!=null && file.exists())
Uri uri = Uri.fromFile(file);
mMediaPlayer = MediaPlayer.create(mContext, uri);
mMediaPlayer.start();
mMediaPlayer.setOnCompletionListener(new OnCompletionListener()

public void onCompletion(MediaPlayer mp)
//TODO:finish
Log.i(TAG, "Finish");

);



public void stopPlayer()
if(mMediaPlayer.isPlaying())
mMediaPlayer.stop();
mMediaPlayer.release();



</span>

五、添加录音权限

[html] view plaincopyprint?
<span style="font-size:16px;"><uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /></span>

完成,运行查看效果。

录音质量极差 - Asterisk 11

【中文标题】录音质量极差 - Asterisk 11【英文标题】:Extremely poor recording quality - Asterisk 11 【发布时间】:2017-06-12 15:52:24 【问题描述】:

我的服务器所有设置都运行良好,但是当我在做一些安全方面的事情时,我把它搞砸了,不得不重新安装所有东西。现在通话录音很可怕,听起来像这样: http://s000.tinyupload.com/download.php?file_id=58238805044662381352&t=58238805044662381352302451

在 Adob​​e Audition 中打开文件允许我调整播放速率,当我以 2X 速度播放时,听起来好一些,但仍然存在失真。失真使它听起来像机器人一样,速度较慢,并且混入了咔哒声。

我尝试过 gsm 和 wav,尝试设置音量只是因为当我将它下载到我的 PC 时真的很难听到,但在星号内播放时音量很好。我也试过升级 sox。

呼叫从 GSM 网关传入 Asterisk 11 服务器,该服务器是具有 16GB RAM、RAID 10 硬盘设置的 Dell R610,除了记录此呼叫外别无其他操作,因此不应该有任何负载问题.当我从一个电话到另一个电话时,听筒上的音频听起来很棒 在我重新安装所有东西之前,录音听起来很好,有什么提示吗?

这是拨号方案信息(但我认为它不相关,也没有完成,只是为了表明没有发生任何疯狂的事情)

[inbound-record]
exten => s,1,Set(TIMEOUT(digit)=5)
exten => s,n,Set(TIMEOUT(response)=15)
exten => s,n,Playback(press)
exten => s,n,Playback(digits/1)
exten => s,n,Read(ACCOUNTNUM,digits/1,i)
exten => s,n,System(/usr/bin/mkdir /var/lib/asterisk/sounds/outboundmsgs/$ACCOUNTNUM)
exten => s,n,Set(VOLUME(TX)=6)

exten => s,n,Set(VOLUME(RX)=9)
exten => s,n,Playback(vm-record-prepend)
exten => s,n,Record(/var/lib/asterisk/sounds/outboundmsgs/$ACCOUNTNUM/tmp_greeting:wav)
exten => s,n,Wait(2)
exten => s,n,Playback(/var/lib/asterisk/sounds/outboundmsgs/$ACCOUNTNUM/tmp_greeting)
exten => s,n,wait(2)
exten => s,n,Hangup

【问题讨论】:

这不是一个话题性问题,而且该决议对公众来说更没有用处。如果您删除它,您将通过反对票取回您失去的积分,仅供参考。 【参考方案1】:

我昨晚在 OpenVox 的技术支持下工作到午夜,我们终于找到了问题所在。新盒子上的以太网端口有些有趣,其中端口 1 只能看到插槽 1,看到我插入端口 2 的其他端口,但端口 1 也插入了 - 这有效地为其提供了 2 条具有相同 IP 的路由.....

这就是它记录速度慢 50% 的原因,因为在循环接收中,它会从端口 1、端口 2、端口 1 接收数据包,但其中只有 1 个有数据。拔掉其中一个即可解决所有问题。

【讨论】:

以上是关于Android 开发 如何实现高质量的录音的主要内容,如果未能解决你的问题,请参考以下文章

Android MP3录音实现

提高android中的录音质量?

Android上的录音播放动画

[Android]实现点击持续录音,松开结束录音,并实现随着分贝的大小改变图片

腾讯bugly干货分享Android自绘动画实现与优化实战——以Tencent OS录音机波形动

Android学习之路-录音功能实现