Android 实时录音和回放,边录音边播放 (KTV回音效果)

1、AndioRecord类介绍

  AndioRecord类的主要功能是让各种JAVA应用能够管理音频资源,以便它们通过此类能够录制平台的声音输入硬件所收集的声音。此功能的实现就是通过”pulling同步reading读取)AudioRecord对象的声音数据来完成的。在录音过程中,应用所需要做的就是通过后面三个类方法中的一个去及时地获取AudioRecord对象的录音数据. AudioRecord类提供的三个获取声音数据的方法分别是read(byte[], int, int), read(short[], int, int), read(ByteBuffer, int)。 无论选择使用那一个方法都必须事先设定方便用户的声音数据的存储格式。然后再使用AudioTrack实时回放声音即可。黄参消痔膏

  下面是使用AudioRecord的过程中,可能会遇到的返回值,对于定位问题的原因很有用,解析很简单,我就不翻译了。

 

2、AudioRecord初始化

复制代码
 
 
//Edited by mythou
//http://www.cnblogs.com/mythou/
// AudioRecord 得到录制最小缓冲区的大小
m_in_buf_size = AudioRecord.getMinBufferSize(8000,
                AudioFormat.CHANNEL_CONFIGURATION_MONO,
                AudioFormat.ENCODING_PCM_16BIT);

// 实例化播放音频对象
m_in_rec = new AudioRecord(MediaRecorder.AudioSource.MIC, 8000,
                AudioFormat.CHANNEL_CONFIGURATION_MONO,
                AudioFormat.ENCODING_PCM_16BIT, m_in_buf_size);
复制代码

  AudioRecord的初始化参数比较多,需要注意设置。这几个参数都是标准的声音采集的参数,下面我针对这几个参数做个介绍,实际使用的时候,你可以根据你的情况设置。

AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)

  AudioRecord构造参数的参数解析,可以根据实际情况调整:

audioSource 音频源:指的是从哪里采集音频。这里我们是从麦克风采集音频,所以此参数的值为MIC。可以参考MediaRecorder.AudioSource类,查看其他音频源。
sampleRateInHz 采样率:音频的采样频率,每秒钟能够采样的次数,采样率越高,音质越高。给出的实例是44100、22050、11025但不限于这几个参数。例如要采集低质量的音频就可以使用4000、8000等低采样率。
channelConfig 声道设置:android支持双声道立体声和单声道。MONO单声道,STEREO立体声
audioFormat 编码制式和采样大小:采集来的数据当然使用PCM编码(脉冲代码调制编码,即PCM编码。PCM通过抽样、量化、编码三个步骤将连续变化的模拟信号转换为数字编码。) android支持的采样大小16bit 或者8bit。当然采样大小越大,那么信息量越多,音质也越高,现在主流的采样大小都是16bit,在低质量的语音传输的时候8bit 足够了。
bufferSizeInBytes 采集数据需要的缓冲区的大小,如果不知道最小需要的大小可以在getMinBufferSize()查看。

  上面是针对AudioRecord的初始化参数做了详细阐述,这个对于使用AudioRecord十分重要,也影响了录音和后期播放的效果,所以在你使用AudioRecord进行录音前,请仔细熟悉上面参数。

 

3、录音

复制代码
    
//Edited by mythou
//http://www.cnblogs.com/mythou/
     //    录音线程
    class recordSound implements Runnable
    {
        @Override
        public void run()
        {
            Log.d(TAG, "........recordSound run()......");
            byte[] bytes_pkg;
            // 开始录音
            m_in_rec.startRecording();

            while (flag)
            {
                m_in_rec.read(m_in_bytes, 0, m_in_buf_size);
                bytes_pkg = m_in_bytes.clone();
                Log.i(TAG, "........recordSound bytes_pkg==" + bytes_pkg.length);
                if (m_in_q.size() >= 2)
                {
                    m_in_q.removeFirst();
                }
                m_in_q.add(bytes_pkg);
            }
        }

    }
复制代码

  这里录音使用的是read()方法来读取录音的数据,并且把录音放到一个独立线程执行,读取到的录音数据,放入到队列里面,供播放线程使用。下面我们看看播放线程:

 

4、播放录音

复制代码
//Edited by mythou
//http://www.cnblogs.com/mythou/
     //播放线程
    class playRecord implements Runnable
    {
        @Override
        public void run()
        {
            Log.d(TAG, "........playRecord run()......");
            byte[] bytes_pkg = null;
            // 开始播放
            m_out_trk.play();

            while (flag)
            {
                try
                {
                    m_out_bytes = m_in_q.getFirst();
                    bytes_pkg = m_out_bytes.clone();
                    m_out_trk.write(bytes_pkg, 0, bytes_pkg.length);
                } 
                catch (Exception e)
                {
                    e.printStackTrace();
                }
            }
        }
    }
复制代码

  播放录音和录音过程大致一样,都是一个独立线程,这里需要注意的是,录音和播放都是开了独立的线程,而不是放在UI线程执行,至于原因不用我多说,大家应该都明白。

 

 5、解决异常

  下面把我调试过程中遇到的一个问题分享一下:

08-06 20:08:25.032: E/AndroidRuntime(32389): FATAL EXCEPTION: Thread-2063
08-06 20:08:25.032: E/AndroidRuntime(32389): java.lang.IllegalStateException: startRecording() called on an uninitialized AudioRecord.
08-06 20:08:25.032: E/AndroidRuntime(32389):     at android.media.AudioRecord.startRecording(AudioRecord.java:540)
08-06 20:08:25.032: E/AndroidRuntime(32389):     at com.apical.AuxIn.AudioNowRecord$recordSound.run(AudioNowRecord.java:131)
08-06 20:08:25.032: E/AndroidRuntime(32389):     at java.lang.Thread.run(Thread.java:856)

  出现上面问题的原因是录音的硬件资源被申请了,但是没有释放,然后你再次申请资源,导致初始化失败。这里需要注意的是不仅仅需要调用Release()方法。还需要把AudioRecord对象置为null,否则还是释放失败。下面是Android 开发网上面的一个对于AudioRecord的释放说明。

Releases the native AudioRecord resources. The object can no longer be used and the reference should be set to null after a call to release()。

 

6、结语

  上面就是一边录音一边播放的大致代码流程,主要就是AudioRecord和AudioTrack的使用,实际使用的时候,你需要根据自己的实际情况,调试AudioRecord的音频采样参数和回放的参数,达到你想要的效果。另外这个功能也能实现KTV的回声效果。自己调试一下参数即可。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是一个使用Java对接大华SDK视频监控实时播放回放的示例代码: 1. 导入大华SDK的jar包 在项目中导入大华SDK的jar包,可以在官网下载SDK并按照文档进行安装。 2. 初始化SDK 在程序入口处初始化SDK,代码如下: ```java HCNetSDK hCNetSDK = HCNetSDK.INSTANCE; boolean initSuc = hCNetSDK.NET_DVR_Init(); if (!initSuc) { System.out.println("SDK初始化失败"); return; } ``` 3. 登录设备 使用SDK提供的登录方法登录设备,代码如下: ```java HCNetSDK.NET_DVR_DEVICEINFO_V30 deviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V30(); int lUserID = hCNetSDK.NET_DVR_Login_V30("设备IP地址", 端口号, "用户名", "密码", deviceInfo); if (lUserID < 0) { System.out.println("设备登录失败"); return; } ``` 4. 实时预览视频 使用SDK提供的预览方法进行实时预览,代码如下: ```java NativeLong lRealHandle = hCNetSDK.NET_DVR_RealPlay_V40(lUserID, previewInfo, null); if (lRealHandle.longValue() < 0) { System.out.println("预览失败"); return; } ``` 其中,previewInfo是一个NET_DVR_PREVIEWINFO结构体,可以通过以下代码进行初始化: ```java HCNetSDK.NET_DVR_PREVIEWINFO previewInfo = new HCNetSDK.NET_DVR_PREVIEWINFO(); previewInfo.lChannel = 1; // 预览的通道号 previewInfo.dwStreamType = 1; // 码流类型,1-主码流,2-子码流 previewInfo.bBlocked = true; // 是否阻塞取流 ``` 5. 停止预览 使用SDK提供的停止预览方法停止实时预览,代码如下: ```java hCNetSDK.NET_DVR_StopRealPlay(lRealHandle); ``` 6. 回放视频 使用SDK提供的回放方法进行视频回放,代码如下: ```java NativeLong lPlayHandle = hCNetSDK.NET_DVR_PlayBackByTime_V40(lUserID, playbackInfo, null); if (lPlayHandle.longValue() < 0) { System.out.println("回放失败"); return; } ``` 其中,playbackInfo是一个NET_DVR_PLAYCOND结构体,可以通过以下代码进行初始化: ```java HCNetSDK.NET_DVR_TIME startTime = new HCNetSDK.NET_DVR_TIME(); startTime.dwYear = 2022; startTime.dwMonth = 2; startTime.dwDay = 1; startTime.dwHour = 0; startTime.dwMinute = 0; startTime.dwSecond = 0; HCNetSDK.NET_DVR_TIME endTime = new HCNetSDK.NET_DVR_TIME(); endTime.dwYear = 2022; endTime.dwMonth = 2; endTime.dwDay = 1; endTime.dwHour = 23; endTime.dwMinute = 59; endTime.dwSecond = 59; HCNetSDK.NET_DVR_PLAYCOND playbackInfo = new HCNetSDK.NET_DVR_PLAYCOND(); playbackInfo.struStartTime = startTime; playbackInfo.struStopTime = endTime; playbackInfo.byDrawFrame = 1; playbackInfo.byStreamType = 0; ``` 7. 停止回放 使用SDK提供的停止回放方法停止视频回放,代码如下: ```java hCNetSDK.NET_DVR_StopPlayBack(lPlayHandle); ``` 以上是一个简单的使用Java对接大华SDK视频监控实时播放回放的示例,具体实现还需要根据自己的需求进行改进。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值