(四)Android基于UDP的多客户端语音通信

转载请表明出处:https://blog.csdn.net/stormxiaofeng/article/details/80598126

在前三篇得基础上,这次研究了组播功能。非常感谢https://blog.csdn.net/jspping/article/details/64438515得贡献!

组播也就是通过MulticastSocket来进行开发,与DatagramSocket比较相类似,这次依然是用两个线程进行实现,发送线程MultiSendThread和接收线程MultiReceiveThread。废话不多说,开始码:

(一)MultiSendThread:

(1)初始化MuticastSocket

 


 
// 侦听的端口
try {
    multicastSocket = new MulticastSocket(8082);
    // 使用D类地址,该地址为发起组播的那个ip段,即侦听10001的套接字
    address = InetAddress.getByName("239.0.0.1");
} catch (IOException e) {
    e.printStackTrace();
}

(2)初始化AudioRecord

 

protected LinkedList<byte[]> mRecordQueue;
int minBufferSize;
private static AcousticEchoCanceler aec;
private static AutomaticGainControl agc;
private static NoiseSuppressor nc;
AudioRecord audioRec;
byte[] buffer;

@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
private void initAudio() {
    //播放的采样频率 和录制的采样频率一样
    int sampleRate = 44100;
    //和录制的一样的
    int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
    //录音用输入单声道  播放用输出单声道
    int channelConfig = AudioFormat.CHANNEL_IN_MONO;

    minBufferSize = AudioRecord.getMinBufferSize(
            sampleRate,
            channelConfig, AudioFormat.ENCODING_PCM_16BIT);
    System.out.println("****RecordMinBufferSize = " + minBufferSize);
    audioRec = new AudioRecord(
            MediaRecorder.AudioSource.MIC,
            sampleRate,
            channelConfig,
            audioFormat,
            minBufferSize);
    buffer = new byte[minBufferSize];

    if (audioRec == null) {
        return;
    }
    //声学回声消除器 AcousticEchoCanceler 消除了从远程捕捉到音频信号上的信号的作用
    if (AcousticEchoCanceler.isAvailable()) {
        aec = AcousticEchoCanceler.create(audioRec.getAudioSessionId());
        if (aec != null) {
            aec.setEnabled(true);
        }
    }

    //自动增益控制 AutomaticGainControl 自动恢复正常捕获的信号输出
    if (AutomaticGainControl.isAvailable()) {
        agc = AutomaticGainControl.create(audioRec.getAudioSessionId());
        if (agc != null) {
            agc.setEnabled(true);
        }
    }

    //噪声抑制器 NoiseSuppressor 可以消除被捕获信号的背景噪音
    if (NoiseSuppressor.isAvailable()) {
        nc = NoiseSuppressor.create(audioRec.getAudioSessionId());
        if (nc != null) {
            nc.setEnabled(true);
        }
    }
    mRecordQueue = new LinkedList<byte[]>();
}

(3)开始录制,并实时发送出去

 

@Override
public void run() {
    if (multicastSocket == null)
        return;
    try {
        audioRec.startRecording();
        while (true) {
            try {
                byte[] bytes_pkg = buffer.clone();
                if (mRecordQueue.size() >= 2) {
                    int length = audioRec.read(buffer, 0, minBufferSize);
                    // 组报
                    DatagramPacket datagramPacket = new DatagramPacket(buffer, length);
                    // 向组播ID,即接收group /239.0.0.1  端口 10001
                    datagramPacket.setAddress(address);
                    // 发送的端口号
                    datagramPacket.setPort(10001);
                    System.out.println("AudioRTwritePacket = " + datagramPacket.getData().toString());

                    multicastSocket.send(datagramPacket);
                }
                mRecordQueue.add(bytes_pkg);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

(二)MultiReceiveThread

(1)初始化MulticastSocket

 

// 接收数据时需要指定监听的端口号
try {
    multicastSocket = new MulticastSocket(10001);
    // 创建组播ID地址
    InetAddress address = InetAddress.getByName("239.0.0.1");
    // 加入地址
    multicastSocket.joinGroup(address);
} catch (IOException e) {
    e.printStackTrace();
}

(2)初始化AudioTrack

 

byte[] buffer;
AudioTrack audioTrk;

private void initAudioTracker() {
    //扬声器播放
    int streamType = AudioManager.STREAM_MUSIC;
    //播放的采样频率 和录制的采样频率一样
    int sampleRate = 44100;
    //和录制的一样的
    int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
    //流模式
    int mode = AudioTrack.MODE_STREAM;
    //录音用输入单声道  播放用输出单声道
    int channelConfig = AudioFormat.CHANNEL_OUT_MONO;
    int recBufSize = AudioTrack.getMinBufferSize(
            sampleRate,
            channelConfig,
            audioFormat);
    System.out.println("****playRecBufSize = " + recBufSize);
    audioTrk = new AudioTrack(
            streamType,
            sampleRate,
            channelConfig,
            audioFormat,
            recBufSize,
            mode);
    audioTrk.setStereoVolume(AudioTrack.getMaxVolume(),
            AudioTrack.getMaxVolume());
    buffer = new byte[recBufSize];

}

(3)开始接收,并进行实时播放

 

@Override
public void run() {
    if (multicastSocket == null)
        return;
    //从文件流读数据
    audioTrk.play();
    // 包长
    while (true) {
        try {
            // 数据报
            DatagramPacket datagramPacket = new DatagramPacket(buffer, buffer.length);
            // 接收数据,同样会进入阻塞状态
            multicastSocket.receive(datagramPacket);
           audioTrk.write(datagramPacket.getData(), 0, datagramPacket.getLength());
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

(三)开始测试

 

MultiSendThread multiSendThread;
MultiReceiverThread multiReceiverThread;

@OnClick({R.id.btnSend, R.id.btnReceive})
public void onViewClicked(View view) {
    switch (view.getId()) {
        case R.id.btnSend:
            if (multiSendThread == null) {
                multiSendThread = new MultiSendThread();
            }
            new Thread(multiSendThread).start();
            break;
        case R.id.btnReceive:
            if (multiReceiverThread == null) {
                multiReceiverThread = new MultiReceiverThread();
            }
            new Thread(multiReceiverThread).start();
            break;
    }
}

 

 

 

展开阅读全文
©️2020 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值