美文网首页Android UDP语音对讲研究
(四)Android基于UDP的多客户端语音通信

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

作者: 孖彧 | 来源:发表于2019-10-11 17:41 被阅读0次

    转载请表明出处: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;

        }

    }

    相关文章

      网友评论

        本文标题:(四)Android基于UDP的多客户端语音通信

        本文链接:https://www.haomeiwen.com/subject/wqjxmctx.html