一、遇到問題
- 使用RK3399的開發(fā)板,跑Android8.1系統(tǒng)
- 一開始插上外置的USB麥克風(fēng)的時(shí)候,無法使用
二、分析問題
- 查看USB麥克風(fēng)拔插過程的debug打印日志
- 插入U(xiǎn)SB麥克風(fēng)后,adb 查詢當(dāng)前聲卡信息
cat cards
三、解決問題
- 通過分析發(fā)現(xiàn),USB麥克風(fēng)設(shè)備沒有枚舉出來,節(jié)點(diǎn)都沒掛載上去
- 這時(shí)候就懷疑是硬件問題,
USB麥克風(fēng)設(shè)備故障
,或者USB供電不足
,或者USB布線問題
- 通過交叉實(shí)驗(yàn),
拔插不同的USB口
,更換RK3399開發(fā)板
,更換USB麥克風(fēng)
- 最后確認(rèn)是
USB麥克風(fēng)設(shè)備故障
,更換USB麥克風(fēng)后,再cat cards
就能查詢出USB-AUDIO設(shè)備
文章來源:http://www.zghlxwxcb.cn/news/detail-490521.html
- 使用USB麥克風(fēng)設(shè)備
- 首先需要正常識(shí)別到該USB-AUDIO設(shè)備
- 其次Android系統(tǒng)會(huì)自動(dòng)切換MIC錄音源
- 如果沒有插入U(xiǎn)SB麥克風(fēng)設(shè)備,則Android系統(tǒng)使用主板上模擬MIC
- 如果插入U(xiǎn)SB麥克風(fēng)設(shè)備,則Android系統(tǒng)就會(huì)切換到USB麥克風(fēng)
四、錄音源碼分析
-
audioSource
: MediaRecorder.AudioSource.CAMCORDER, MediaRecorder.AudioSource.MIC 等 -
sampleRateInHz
: 常用的有: 8000,11025,16000,22050,44100,96000;44100Hz是唯一可以保證兼容所有Android手機(jī)的采樣率 -
channelConfig
:AudioFormat.CHANNEL_CONFIGURATION_DEFAULT
,常用的是CHANNEL_IN_MONO
(單通道)CHANNEL_IN_STEREO
(雙通道) -
audioFormat
: AudioFormat.ENCODING_PCM_16BIT, 測試中要捕獲PCM數(shù)據(jù) -
bufferSizeInBytes
: 由AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat)
獲得
public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)
AudioRecord.startRecording();
AudioRecord.stop();
AudioRecord.read(byte[] audioData, int offsetInBytes, int sizeInBytes);
public class AudioCapturer {
private static final String TAG = "AudioCapturer";
private static final int DEFAULT_SOURCE = MediaRecorder.AudioSource.MIC;
private static final int DEFAULT_SAMPLE_RATE = 44100;
private static final int DEFAULT_CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_STEREO;
private static final int DEFAULT_AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
private AudioRecord mAudioRecord;
private int mMinBufferSize = 0;
private Thread mCaptureThread;
private boolean mIsCaptureStarted = false;
private volatile boolean mIsLoopExit = false;
private OnAudioFrameCapturedListener mAudioFrameCapturedListener;
public interface OnAudioFrameCapturedListener {
public void onAudioFrameCaptured(byte[] audioData);
}
public boolean isCaptureStarted() {
return mIsCaptureStarted;
}
public void setOnAudioFrameCapturedListener(OnAudioFrameCapturedListener listener) {
mAudioFrameCapturedListener = listener;
}
public boolean startCapture() {
return startCapture(DEFAULT_SOURCE, DEFAULT_SAMPLE_RATE, DEFAULT_CHANNEL_CONFIG,
DEFAULT_AUDIO_FORMAT);
}
public boolean startCapture(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat) {
if (mIsCaptureStarted) {
Log.e(TAG, "Capture already started !");
return false;
}
mMinBufferSize = AudioRecord.getMinBufferSize(sampleRateInHz,channelConfig,audioFormat);
if (mMinBufferSize == AudioRecord.ERROR_BAD_VALUE) {
Log.e(TAG, "Invalid parameter !");
return false;
}
Log.d(TAG , "getMinBufferSize = "+mMinBufferSize+" bytes !");
mAudioRecord = new AudioRecord(audioSource,sampleRateInHz,channelConfig,audioFormat,mMinBufferSize);
if (mAudioRecord.getState() == AudioRecord.STATE_UNINITIALIZED) {
Log.e(TAG, "AudioRecord initialize fail !");
return false;
}
mAudioRecord.startRecording();
mIsLoopExit = false;
mCaptureThread = new Thread(new AudioCaptureRunnable());
mCaptureThread.start();
mIsCaptureStarted = true;
Log.d(TAG, "Start audio capture success !");
return true;
}
public void stopCapture() {
if (!mIsCaptureStarted) {
return;
}
mIsLoopExit = true;
try {
mCaptureThread.interrupt();
mCaptureThread.join(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
if (mAudioRecord.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) {
mAudioRecord.stop();
}
mAudioRecord.release();
mIsCaptureStarted = false;
mAudioFrameCapturedListener = null;
Log.d(TAG, "Stop audio capture success !");
}
private class AudioCaptureRunnable implements Runnable {
@Override
public void run() {
while (!mIsLoopExit) {
byte[] buffer = new byte[mMinBufferSize];
int ret = mAudioRecord.read(buffer, 0, mMinBufferSize);
if (ret == AudioRecord.ERROR_INVALID_OPERATION) {
Log.e(TAG , "Error ERROR_INVALID_OPERATION");
}
else if (ret == AudioRecord.ERROR_BAD_VALUE) {
Log.e(TAG , "Error ERROR_BAD_VALUE");
}
else {
if (mAudioFrameCapturedListener != null) {
mAudioFrameCapturedListener.onAudioFrameCaptured(buffer);
}
Log.d(TAG , "OK, Captured "+ret+" bytes !");
}
SystemClock.sleep(10);
}
}
}
}
五、播放源碼分析
-
streamType
:-
AudioManager.STREAM_VOCIE_CALL
:電話聲音 -
AudioManager.STREAM_SYSTEM
:系統(tǒng)聲音 -
AudioManager.STREAM_RING
:鈴聲 -
AudioManager.STREAM_MUSCI
:音樂聲 -
AudioManager.STREAM_ALARM
:警告聲 -
AudioManager.STREAM_NOTIFICATION
:通知聲
-
-
sampleRateInHz
: 常用的有: 8000,11025,16000,22050,44100,96000;44100Hz是唯一可以保證兼容所有Android手機(jī)的采樣率 -
channelConfig
:AudioFormat.CHANNEL_CONFIGURATION_DEFAULT
,常用的是CHANNEL_IN_MONO
(單通道) -
audioFormat
: AudioFormat.ENCODING_PCM_16BIT, 測試中要捕獲PCM數(shù)據(jù) -
bufferSizeInBytes
: 由AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat)
獲得 -
mode
:-
AudioTrack.MODE_STATIC
,一次性將所有的數(shù)據(jù)都寫入播放緩沖區(qū),簡單高效 -
AudioTrack.MODE_STREAM
,按照一定的時(shí)間間隔不間斷地寫入音頻數(shù)據(jù)
-
public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, int mode)
AudioTrack.play();
AudioTrack.stop();
import android.util.Log;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
public class AudioPlayer {
private static final String TAG = "AudioPlayer";
private static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_MUSIC;
private static final int DEFAULT_SAMPLE_RATE = 44100;
private static final int DEFAULT_CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_STEREO;
private static final int DEFAULT_AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
private static final int DEFAULT_PLAY_MODE = AudioTrack.MODE_STREAM;
private boolean mIsPlayStarted = false;
private int mMinBufferSize = 0;
private AudioTrack mAudioTrack;
public boolean startPlayer() {
return startPlayer(DEFAULT_STREAM_TYPE,DEFAULT_SAMPLE_RATE,DEFAULT_CHANNEL_CONFIG,DEFAULT_AUDIO_FORMAT);
}
public boolean startPlayer(int streamType, int sampleRateInHz, int channelConfig, int audioFormat) {
if (mIsPlayStarted) {
Log.e(TAG, "Player already started !");
return false;
}
mMinBufferSize = AudioTrack.getMinBufferSize(sampleRateInHz,channelConfig,audioFormat);
if (mMinBufferSize == AudioTrack.ERROR_BAD_VALUE) {
Log.e(TAG, "Invalid parameter !");
return false;
}
Log.d(TAG , "getMinBufferSize = "+mMinBufferSize+" bytes !");
mAudioTrack = new AudioTrack(streamType,sampleRateInHz,channelConfig,audioFormat,mMinBufferSize,DEFAULT_PLAY_MODE);
if (mAudioTrack.getState() == AudioTrack.STATE_UNINITIALIZED) {
Log.e(TAG, "AudioTrack initialize fail !");
return false;
}
mIsPlayStarted = true;
Log.d(TAG, "Start audio player success !");
return true;
}
public int getMinBufferSize() {
return mMinBufferSize;
}
public void stopPlayer() {
if (!mIsPlayStarted) {
return;
}
if (mAudioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
mAudioTrack.stop();
}
mAudioTrack.release();
mIsPlayStarted = false;
Log.d(TAG, "Stop audio player success !");
}
public boolean play(byte[] audioData, int offsetInBytes, int sizeInBytes) {
if (!mIsPlayStarted) {
Log.e(TAG, "Player not started !");
return false;
}
if (sizeInBytes < mMinBufferSize) {
Log.e(TAG, "audio data is not enough !");
return false;
}
if (mAudioTrack.write(audioData,offsetInBytes,sizeInBytes) != sizeInBytes) {
Log.e(TAG, "Could not write all the samples to the audio device !");
}
mAudioTrack.play();
Log.d(TAG , "OK, Played "+sizeInBytes+" bytes !");
return true;
}
}
六、參考
- Jhuster/Android
- android 采集PCM音頻數(shù)據(jù)并播放(支持USB攝像頭MIC)
覺得好,就一鍵三連唄(點(diǎn)贊+收藏+關(guān)注)文章來源地址http://www.zghlxwxcb.cn/news/detail-490521.html
到了這里,關(guān)于Android 使用外置USB麥克風(fēng)MIC錄音遇到問題并解決(含錄音播放源碼)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!