收音机边录边播

这篇博客介绍了如何在Android平台上实现收音机的录音功能。通过`startRadioVoice()`方法启动录音,利用`RadioInVoice`类进行录音操作,当需要停止录音时,调用`stopRadioVoice()`方法,在子线程中执行`RadioInVoice`的停止方法,确保操作的正确执行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.os.Process;
import android.util.Log;




/**
 * Created by wangfei on 2018/7/1.
 */
public class RadioInVoice {
    private static final String TAG = "RadioInVoice";
    private int bufferReadResult;
    private boolean isRecording = false;//是否录放的标记
    static final int frequencyCap = 48000;
    static final int frequencyPlay = 24000;
    static final int channelConfigurationCap = AudioFormat.CHANNEL_IN_MONO;
    static final int channelConfigurationPlay = AudioFormat.CHANNEL_OUT_STEREO;
    static final int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
    int recBufSize, playBufSize;
    AudioRecord audioRecord;
    AudioTrack audioTrack;

    public void start() {
        LogUtil.info(TAG, "RadioInVoice start");
        // 获取每一帧的字节流大小
        // 第一个参数sampleRateInHz 采样率(赫兹),只能在4000到192000的范围内取值
        // 第二个参数channelConfig 声道配置 描述音频声道的配置,例如左声道/右声道/前声道/后声道。
        // 第三个参数audioFormat 音频格式 表示音频数据的格式。注意!一般的手机设备可能只支持 16位PCM编码,如果其他的都会报错为坏值.
        recBufSize = AudioRecord.getMinBufferSize(frequencyCap, channelConfigurationCap, audioEncoding);
        playBufSize = AudioTrack.getMinBufferSize(frequencyPlay, channelConfigurationPlay, audioEncoding);
        // -----------------------------------------
        // 第一个参数audioSource 音频源
        // 第二个参数sampleRateInHz 采样率(赫兹)  与前面初始化获取每一帧流的Size保持一致
        // 第三个参数channelConfig 声道配置 描述音频声道的配置,例如左声道/右声道/前声道/后声道。   与前面初始化获取每一帧流的Size保持一致
        // 第四个参数audioFormat 音频格式  表示音频数据的格式。  与前面初始化获取每一帧流的Size保持一致
        // 第五个参数缓存区大小,基本就是上面我们配置的AudioRecord.getMinBufferSize
        // 1998 MediaRecorder.AudioSource.RADIO_TUNER(此处需底层适配)
        audioRecord = new AudioRecord(1998, frequencyCap,
                channelConfigurationCap, audioEncoding, recBufSize * 10);
        // 第一个参数 streamType:音频流类型  STREAM_ALARM、STREAM_MUSIC、STREAM_RING、STREAM_SYSTEM、STREAM_VOICE_CALL、STREAM_NOTIFICATION、STREAM_BLUETOOTH_SCO、STREAM_BLUETOOTH_SCO
        // 第二个参数 采样率 在4000到48000之间
        // 第三个参数 channelConfig:音频声道
        // 第四个参数 音频格式
        // 第五个参数 bufferSizeInBytes缓冲区大小:
        // 第六个参数 mode:音频数据载入模式
        audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, frequencyPlay, channelConfigurationPlay, audioEncoding,
                playBufSize, AudioTrack.MODE_STREAM);

        audioTrack.setStereoVolume(0.7f, 0.7f);// 设置当前音量大小
        isRecording = true;
        new RecordPlayThread().start();// 开一条线程边录边放
    }

    public void stop() {
        LogUtil.info(TAG, "RadioInVoice stop");
        if (isRecording) {
            try {
                isRecording = false;
                while (audioRecord != null) {
                    Log.d(TAG, "wait audioRecord release");
                    Thread.sleep(1000);
                }
            } catch (Throwable t) {
                Log.e(TAG, "wait audioRecord Thread exit" + t.getMessage());
            }
        }
    }

    /**
     * 是否正在录音中
     *
     * @return 录音状态
     */
    public boolean isRunning() {
        return isRecording;
    }

    class RecordPlayThread extends Thread {
        private boolean succStart = false;

        public void run() {
            Process.setThreadPriority(1000);
            try {
                byte[] buffer = new byte[recBufSize];
                while (!succStart && isRecording) {
                    audioRecord.startRecording();// 开始录制
                    if (audioRecord.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING) {
                        LogUtil.info(TAG, "RadioInVoice RecordPlayThread run startRecording fail");
                        succStart = false;
                    } else {
                        LogUtil.info(TAG, "RadioInVoice RecordPlayThread run startRecording true");
                        succStart = true;
                    }
                    Thread.sleep(1000);
                }
                audioTrack.play();// 开始播放
                while (isRecording && RadioConstants.isRadioPlay) {
                    // 添加录音条件显示 不是终止录音状态、静音状态、音源不在收音机状态
                    if (RadioConstants.isRadioPlaying) {
                        if (audioRecord.getRecordingState() == AudioRecord.RECORDSTATE_STOPPED) {
                            audioRecord.startRecording();
                        }
                        // 从MIC保存数据到缓冲区
                        bufferReadResult = audioRecord.read(buffer, 0, recBufSize);
                        if (bufferReadResult > 0) {
                            // 写入数据即播放
                            audioTrack.write(buffer, 0, bufferReadResult);
                        } else {
                            LogUtil.error(TAG, "RadioInVoice audioRecord.read error : " + bufferReadResult);
                        }
                    } else {
                        if (audioRecord.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) {
// 不允许录音时,要stop,清空缓存,否则再次播放时会播一段之前的。
                            audioRecord.stop();
                        }
                    }
                }
                if (audioTrack != null) {
                    audioTrack.stop();
                    audioTrack.release();
                    audioTrack = null;
                }
                if (audioRecord != null) {
                    audioRecord.stop();
                    audioRecord.release();
                    audioRecord = null;
                }
            } catch (Exception e) {
                LogUtil.error(TAG, "RecordPlayThread RadioInVoice:" + e.getMessage());
            } finally {
                if (audioTrack != null && audioTrack.getState() == AudioTrack.STATE_INITIALIZED) {
                    audioTrack.stop();
                    audioTrack.release();
                    audioTrack = null;
                }
                if (audioRecord != null && audioRecord.getState() == AudioRecord.STATE_INITIALIZED) {
                    audioRecord.stop();
                    audioRecord.release();
                    audioRecord = null;
                }
            }
        }
    }
}
/**
 * 开始收音机录音
 */
private void startRadioVoice() {
    if (null != mRadioCommonView) {
        if (null == mRadioInVoice) {
            mRadioInVoice = new RadioInVoice();
            mRadioInVoice.start();
        } else if (null != mRadioInVoice && !mRadioInVoice.isRunning()) {
            mRadioInVoice.start();
        }
    }
}

/**
 * 停止录音
 */
private void stopRadioVoice() {
    if (null != mRadioInVoice) {
        if (mRadioInVoice.isRunning()) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        mRadioInVoice.stop();
                    } catch (Exception e) {
                        e.printStackTrace();
                        LogUtil.error(TAG, "RecordPlayThread stopVoiceCall()" + e.getMessage());
                    }
                }
            }).start();
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值