轉(zhuǎn)載請表明出處:https://blog.csdn.net/stormxiaofeng/article/details/80598126
在前三篇得基礎(chǔ)上,這次研究了組播功能。非常感謝https://blog.csdn.net/jspping/article/details/64438515得貢獻(xiàn)!
組播也就是通過MulticastSocket來進(jìn)行開發(fā),與DatagramSocket比較相類似,這次依然是用兩個線程進(jìn)行實現(xiàn),發(fā)送線程MultiSendThread和接收線程MultiReceiveThread。廢話不多說,開始碼:
(一)MultiSendThread:
(1)初始化MuticastSocket
// 偵聽的端口
try {
? ? multicastSocket = new MulticastSocket(8082);
? ? // 使用D類地址,該地址為發(fā)起組播的那個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;
? ? }
? ? //聲學(xué)回聲消除器 AcousticEchoCanceler 消除了從遠(yuǎn)程捕捉到音頻信號上的信號的作用
? ? if (AcousticEchoCanceler.isAvailable()) {
? ? ? ? aec = AcousticEchoCanceler.create(audioRec.getAudioSessionId());
? ? ? ? if (aec != null) {
? ? ? ? ? ? aec.setEnabled(true);
? ? ? ? }
? ? }
? ? //自動增益控制 AutomaticGainControl 自動恢復(fù)正常捕獲的信號輸出
? ? 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)開始錄制,并實時發(fā)送出去
@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);
? ? ? ? ? ? ? ? ? ? // 發(fā)送的端口號
? ? ? ? ? ? ? ? ? ? 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
// 接收數(shù)據(jù)時需要指定監(jiān)聽的端口號
try {
? ? multicastSocket = new MulticastSocket(10001);
? ? // 創(chuàng)建組播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)開始接收,并進(jìn)行實時播放
@Override
public void run() {
? ? if (multicastSocket == null)
? ? ? ? return;
? ? //從文件流讀數(shù)據(jù)
? ? audioTrk.play();
? ? // 包長
? ? while (true) {
? ? ? ? try {
? ? ? ? ? ? // 數(shù)據(jù)報
? ? ? ? ? ? DatagramPacket datagramPacket = new DatagramPacket(buffer, buffer.length);
? ? ? ? ? ? // 接收數(shù)據(jù),同樣會進(jìn)入阻塞狀態(tài)
? ? ? ? ? ? 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;
? ? }
}