android蓝牙耳机录音并播放(二)

秦宏盛
2023-12-01

Github下载

package com.example.superb.yy4;

import android.content.Context;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;

/**

  • Function:判断录音权限,兼容android6.0以下以及以上系统
  • @author xuzhuyun
  • @date 2018/5/10
    */

public class CheckAudioPermission {
/**
* 音频获取源
/
public static int audioSource = MediaRecorder.AudioSource.MIC;
/
*
* 设置音频采样率,44100是目前的标准,但是某些设备仍然支持22050,16000,11025
*/
public static int sampleRateInHz = 44100;

/**
 * 设置音频的录制的声道CHANNEL_IN_STEREO为双声道,CHANNEL_CONFIGURATION_MONO为单声道
 */
public static int channelConfig = AudioFormat.CHANNEL_IN_STEREO;
/**
 * 音频数据格式:PCM 16位每个样本。保证设备支持。PCM 8位每个样本。不一定能得到设备支持。
 */
public static int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
/**
 * 缓冲区字节大小
 */
public static int bufferSizeInBytes = 0;

public static AudioRecord audioRecord;


/**
 * 判断是是否有录音权限.
 */
public static boolean isHasPermission(final Context context) {
    bufferSizeInBytes = 0;
    bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz,
            channelConfig, audioFormat);
    if (audioRecord == null) {
        audioRecord = new AudioRecord(audioSource, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes);

    }
    //开始录制音频
    try {
        // 防止某些手机崩溃,例如联想
        audioRecord.startRecording();
    } catch (IllegalStateException e) {
        e.printStackTrace();
    }

    /**
     * 根据开始录音判断是否有录音权限s
     */
    if (audioRecord.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING) {
        return false;
    }
    audioRecord.stop();
    //释放资源
    audioRecord.release();
    audioRecord = null;

    return true;
}

}

package com.example.superb.yy5;

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;

/**

  • desc:测试录音权限.

  • steps:

  • 检测是否有权限–有--执行相关操作

  • –无权限–

  • –判断系统版本

  • –小于6.0 直接获取

  • –大于6.0 动态申请权限

  • –对申请结果的处理回调

  • –允许

  • –拒绝

  • test:

  • test1 build.gradle minsdk <23 真机android7.1 清单文件中配置了录音权限

  • test2 build.gradle minsdk >=23 真机android7.1 清单文件中配置了录音权限

  • @author xuzhuyun

  • @date 2018/5/10
    */
    public class Main2Activity extends AppCompatActivity {
    private static final String TAG = “MainActivity”;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main2);
    //检测是否有录音权限
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
    != PackageManager.PERMISSION_GRANTED) {
    Log.i(TAG, “默认无录音权限”);
    if (Build.VERSION.SDK_INT >= 23) {
    Log.i(TAG, “系统版本不低于android6.0 ,需要动态申请权限”);
    requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO}, 1001);
    }
    } else {
    Log.i(TAG, “默认有录音权限”);
    }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
    @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == 1001) {
    //方式一校验
    boolean isHasAudioPermission = CheckAudioPermission.isHasPermission(this);
    Log.i(TAG, “申请权限完毕,当前录音权限:” + isHasAudioPermission);
    //方式二校验
    int result = 0;
    for (int i = 0; i < grantResults.length; i++) {
    if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
    result++;
    }
    }
    if (result != permissions.length) {
    //没有权限
    Log.i(TAG, “onRequestPermissionsResult: 申请权限完毕,当前录音权限:false”);
    return;
    }
    //有权限
    Log.i(TAG, “onRequestPermissionsResult: 申请后,是否有权限:true”);
    }
    }

    public void ccc(View view) {
    startActivity(new Intent(this,MainActivity.class));

    }
    }

package com.example.superb.yy5;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

public class MainActivity extends Activity {

//耳机

//耳机

PipedInputStream in;
boolean isRrcord;
mAudio mm ;
mAudioPlayer m;

TextView T1,T2;
Button btn;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    btn=findViewById(R.id.search_close_btn);

    T1=findViewById(R.id.dddd);
    isRrcord = false;

}
public void btnclick(View v){
    if (isRrcord){
        isRrcord = false;
        mm.stopRecord();m.stopPlay();
        btn.setText("开始");
        T1.setText("点击开始");

    }else{
        isRrcord = true;
        startRecord();

        btn.setText("停止");

        T1.setText("点击停止");

    }
}


private void startRecord(){
    in = new PipedInputStream();
    new Thread(new Runnable() {

        @Override
        public void run() {
            try {
                mm = new mAudio(MainActivity.this, in);
                mm.StartAudioData();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }).start();
    new Thread(new Runnable() {
        @Override
        public void run() {
            byte[] buffer = new byte[1024];
            PipedOutputStream pout = new PipedOutputStream();
            m = new mAudioPlayer(MainActivity.this);
            try {
                m.setOutputStream(pout);
                new Thread(new Runnable() {

                    @Override
                    public void run() {
                        // TODO Auto-generated method stub
                        m.startPlayAudio();
                    }
                }).start();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            int size = 0 ;
            try {
                while (true){
                    while (in.available()>0){
                        size = in.read(buffer);
                        pout.write(buffer, 0, size);
                    }
                }

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }).start();
}

}

package com.example.superb.yy5;

import android.content.Context;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.util.Log;

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

/*

  • To getaudio or play audio

  • */
    public class mAudio {
    //
    private int SAMPLE_RATE_HZ = 16000;
    private AudioManager mAudioManager;
    //
    private AudioRecord audioRecord;
    private Context context;
    private boolean isRecording = false ;
    private PipedOutputStream outstream ;//利用管道传输数据
    public mAudio(Context context , PipedInputStream instream) throws IOException {
    this.context = context;
    //初始化管道流 用于向外传输数据
    outstream = new PipedOutputStream();
    outstream.connect(instream);
    }
    public void StartAudioData(){//得到录音数据
    int frequency = 11025;

     mAudioManager = (AudioManager)context.getSystemService(context.AUDIO_SERVICE);
    

    // mAudioManager.setMode(AudioManager.MODE_NORMAL);
    // mAudioManager.setRingerMode(AudioManager.RINGER_MODE_VIBRATE);
    //MODE_IN_COMMUNICATION
    mAudioManager.setBluetoothScoOn(true);

     //frequency采样率:音频的采样频率,每秒钟能够采样的次数,采样率越高,音质越高。
     // 给出的实例是44100、22050、11025但不限于这几个参数。
     // 例如要采集低质量的音频就可以使用4000、8000等低采样率。
     @SuppressWarnings("deprecation")
     int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_STEREO;//立体声录制通道
     int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
     //编码制式和采样大小:采集来的数据当然使用PCM编码(脉冲代码调制编码,
     // 即PCM编码。PCM通过抽样、量化、编码三个步骤将连续变化的模拟信号转换为数字编码。) android支持的采样大小16bit 或者8bit。
     // 当然采样大小越大,那么信息量越多,音质也越高,
     // 现在主流的采样大小都是16bit,在低质量的语音传输的时候8bit足够了。
     //
     int buffersize = AudioRecord.getMinBufferSize(frequency, channelConfiguration, audioEncoding);
    

    //采集数据需要的缓冲区的大小,如果不知道最小需要的大小可以在getMinBufferSize()查看。
    //手机VOICE_RECOGNITION
    if(!mAudioManager.isBluetoothScoAvailableOffCall()){
    Log.d(“dddddddddd”, “系统不支持蓝牙录音”);
    return;
    }

    // mAudioManager.setBluetoothScoOn(true); //打开SCO}
    //蓝牙录音的关键,启动SCO连接,耳机话筒才起作用
    //mAudioManager.startBluetoothSco();
    //蓝牙SCO连接建立需要时间,连接建立后会发出ACTION_SCO_AUDIO_STATE_CHANGED消息,通过接收该消息而进入后续逻辑。
    //也有可能此时SCO已经建立,则不会收到上述消息,可以startBluetoothSco()前先stopBluetoothSco()
    // if (AudioManager.SCO_AUDIO_STATE_CONNECTED == state) {
    // mAudioManager.setBluetoothScoOn(true); //打开SCO}
    // }

    // mAudioManager.setBluetoothScoOn(true); //打开SCO}

//VOICE_COMMUNICATION

audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,frequency, channelConfiguration, audioEncoding, buffersize);
//audioRecord = new AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION,frequency, channelConfiguration, audioEncoding, buffersize);
// 耳机
// buffersize = AudioRecord.getMinBufferSize(SAMPLE_RATE_HZ,
// AudioFormat.CHANNEL_IN_MONO,
// AudioFormat.ENCODING_PCM_16BIT) * 2;
//
// int audiosource = MediaRecorder.AudioSource.VOICE_RECOGNITION;
// audioRecord = new AudioRecord(audiosource,
// SAMPLE_RATE_HZ,
// AudioFormat.CHANNEL_IN_MONO,
// AudioFormat.ENCODING_PCM_16BIT,
// buffersize);
// audioRecord = new AudioRecord(audiosource,
// SAMPLE_RATE_HZ,
// AudioFormat.CHANNEL_IN_MONO,
// AudioFormat.ENCODING_PCM_16BIT,
// buffersize);

    //音频源:指的是从哪里采集音频。这里我们当然是从麦克风采集音频,所以此参数的值为MIC

    //frequency采样率:音频的采样频率,每秒钟能够采样的次数,采样率越高,音质越高。
    // 给出的实例是44100、22050、11025但不限于这几个参数。
    // 例如要采集低质量的音频就可以使用4000、8000等低采样率。
    byte[]buffer  = new byte[buffersize];
    audioRecord.startRecording();//开始录音
    isRecording = true;
    int bufferReadSize = 1024;
    mAudioManager.startBluetoothSco();

    while (isRecording){
        audioRecord.read(buffer, 0, bufferReadSize);
        try {
            outstream.write(buffer, 0, bufferReadSize);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
public void stopRecord(){//停止录音
  //  mAudioManager.setMode(AudioManager.MODE_NORMAL);
    isRecording = false;
    audioRecord.stop();
    mAudioManager.startBluetoothSco();
    try {
        outstream.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

}

package com.example.superb.yy5;

import android.content.Context;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

public class mAudioPlayer {
private Context context;
private PipedInputStream instream;
private boolean isPlaying ;
private AudioTrack audioplayer;
private AudioManager mAudioManager;

private byte[] buffer;
public mAudioPlayer(Context context) {
    isPlaying = false;
    instream = null;
    //初始化播音类

   this.context=context;
    mAudioManager = (AudioManager)context.getSystemService(context.AUDIO_SERVICE);
    mAudioManager.setRingerMode(AudioManager.RINGER_MODE_VIBRATE);
    mAudioManager.setMode(AudioManager.MODE_RINGTONE);
    mAudioManager.setBluetoothA2dpOn(false);
    int bufsize = AudioTrack.getMinBufferSize(11025, AudioFormat.CHANNEL_CONFIGURATION_STEREO,
            AudioFormat.ENCODING_PCM_16BIT);
    audioplayer = new AudioTrack(AudioManager.STREAM_VOICE_CALL, 11025, AudioFormat.CHANNEL_CONFIGURATION_STEREO,
            AudioFormat.ENCODING_PCM_16BIT, bufsize,AudioTrack.MODE_STREAM);
}
//设置管道流,用于接受音频数据
public void setOutputStream(PipedOutputStream out) throws IOException{
    instream = new PipedInputStream(out);

}
public void startPlayAudio(){ //调用之前先调用setOutputStream 函数
    isPlaying = true;
    audioplayer.play();//开始接受数据流播放
    buffer = new byte[1024];
 //   mAudioManager.stopBluetoothSco();
    while (instream!=null&&isPlaying){
        try {
            while (instream.available()>0){
                int size = instream.read(buffer);
                audioplayer.write(buffer, 0
                        , size);//不断播放数据
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
public void stopPlay(){//停止播放
    isPlaying = false ;
  mAudioManager.setMode(AudioManager.MODE_NORMAL);

mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
try {
instream.close();
} catch (IOException e) {
e.printStackTrace();
}
audioplayer.stop();
}

}

 类似资料: