diff --git a/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/MediaManager.java b/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/MediaManager.java index 197da2e..4fa775e 100644 --- a/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/MediaManager.java +++ b/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/MediaManager.java @@ -406,6 +406,7 @@ public final class MediaManager { // .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) // .build(); final JavaAudioDeviceModule javaAudioDeviceModule = JavaAudioDeviceModule.builder(this.context) + // 设置声音配置:采样播放(不会影响传输) // .setSampleRate(48000) // .setSampleRate(mediaAudioProperties.getSampleRate()) // .setAudioFormat(AudioFormat.ENCODING_PCM_16BIT) diff --git a/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/audio/MixerProcesser.java b/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/audio/MixerProcesser.java index b9ca4b0..899913b 100644 --- a/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/audio/MixerProcesser.java +++ b/taoyao-client-android/taoyao/media/src/main/java/com/acgist/taoyao/media/audio/MixerProcesser.java @@ -105,6 +105,7 @@ public class MixerProcesser extends Thread implements JavaAudioDeviceModule.Samp this.audioSource = MediaRecorder.AudioSource.MIC; this.channelCount = channelCount; this.channelConfig = AudioFormat.CHANNEL_IN_MONO; +// this.channelConfig = AudioFormat.CHANNEL_IN_STEREO; this.audioRecord = new AudioRecord.Builder() .setAudioFormat( new AudioFormat.Builder() @@ -147,8 +148,10 @@ public class MixerProcesser extends Thread implements JavaAudioDeviceModule.Samp byte[] localData = null; byte[] remoteData = null; byte[] recordData = null; + int mixLocal, mixRemote, mixValue; JavaAudioDeviceModule.AudioSamples local = null; JavaAudioDeviceModule.AudioSamples remote = null; + final ByteBuffer mixBuffer = ByteBuffer.allocateDirect(2); // 采集数据大小:采样频率 / (一千毫秒 / 回调频率毫秒) * 通道数量 * 采样数据大小 final ByteBuffer byteBuffer = ByteBuffer.allocateDirect(this.sampleRate / (1000 / 10) * this.channelCount * 2); while(!this.close) { @@ -185,11 +188,36 @@ public class MixerProcesser extends Thread implements JavaAudioDeviceModule.Samp mixData = new byte[mixDataLength]; } // 如果多路远程声音变小:(remote * 远程路数 + local) / (远程路数 + 1) - for (int index = 0; index < mixDataLength; index++) { + for (int index = 0; index < mixDataLength; index += 2) { // -0x8000 ~ 0x7FFF; - mixData[index] = (byte) (((localData[index] + remoteData[index]) & 0x7FFF) / 2); +// mixData[index] = (byte) (localData[index] + remoteData[index]); +// mixData[index] = (byte) (((localData[index] + remoteData[index]) & 0x7FFF) / 2); // mixData[index] = (byte) (((localData[index] + remoteData[index]) & 0xFFFF) / 2); // mixData[index] = (byte) (((localData[index] + remoteData[index] * remoteCount) & 0xFFFF) / (1 + remoteCount)); + mixBuffer.clear(); + mixBuffer.put(localData[index + 1]); + mixBuffer.put(localData[index]); + mixBuffer.flip(); + mixLocal = mixBuffer.getShort(); + mixBuffer.flip(); + mixBuffer.put(remoteData[index + 1]); + mixBuffer.put(remoteData[index]); + mixBuffer.flip(); + mixRemote = mixBuffer.getShort(); + mixValue = mixLocal + mixRemote; + if(mixValue > Short.MAX_VALUE) { + mixValue = Short.MAX_VALUE; + } + if(mixValue < Short.MIN_VALUE) { + mixValue = Short.MIN_VALUE; + } + // 不能使用下面这个 +// mixValue = mixValue & 0xFFFF; + mixBuffer.flip(); + mixBuffer.putShort((short) mixValue); + mixBuffer.flip(); + mixData[index + 1] = mixBuffer.get(); + mixData[index] = mixBuffer.get(); } pts += mixData.length * (1_000_000 / local.getSampleRate() / 2); this.recordClient.onPcm(pts, mixData); diff --git a/taoyao-signal-server/taoyao-server/src/test/java/com/acgist/taoyao/AudioMixerTest.java b/taoyao-signal-server/taoyao-server/src/test/java/com/acgist/taoyao/AudioMixerTest.java index dfea486..aa41ca1 100644 --- a/taoyao-signal-server/taoyao-server/src/test/java/com/acgist/taoyao/AudioMixerTest.java +++ b/taoyao-signal-server/taoyao-server/src/test/java/com/acgist/taoyao/AudioMixerTest.java @@ -2,6 +2,7 @@ package com.acgist.taoyao; import java.io.File; import java.io.IOException; +import java.nio.ByteBuffer; import java.nio.file.Files; import java.nio.file.Paths; @@ -13,16 +14,40 @@ public class AudioMixerTest { public void testMixer() throws IOException { // ffmpeg -i audio.mp3 -f s32le audio.pcm // ffplay -i audio.pcm -f s32le -ar 48000 -ac 1 - final File fileA = new File("D:\\tmp\\mixer\\1.pcm"); - final File fileB = new File("D:\\tmp\\mixer\\2.pcm"); + final File fileA = new File("C:\\Users\\acgis\\桌面\\1.pcm"); + final File fileB = new File("C:\\Users\\acgis\\桌面\\2.pcm"); final byte[] bytesA = Files.readAllBytes(fileA.toPath()); final byte[] bytesB = Files.readAllBytes(fileB.toPath()); final int length = Math.min(bytesA.length, bytesB.length); final byte[] target = new byte[length]; - for (int i = 0; i < length; i++) { - target[i] = (byte) (((bytesA[i] + bytesB[i]) & 0xFFFF) / 2); + final ByteBuffer buffer = ByteBuffer.allocateDirect(2); + for (int i = 0; i < length; i += 2) { + buffer.clear(); + buffer.put(bytesA[i + 1]); + buffer.put(bytesA[i]); + buffer.flip(); + int mixA = buffer.getShort(); + buffer.flip(); + buffer.put(bytesB[i + 1]); + buffer.put(bytesB[i]); + buffer.flip(); + int mixB = buffer.getShort(); + int mix = mixA + mixB; + if(mix > Short.MAX_VALUE) { + mix = Short.MAX_VALUE; + } + if(mix < Short.MIN_VALUE) { + mix = Short.MIN_VALUE; + } + // 不能使用下面这个 +// mix = mix & 0xFFFF; + buffer.flip(); + buffer.putShort((short) mix); + buffer.flip(); + target[i + 1] = buffer.get(); + target[i] = buffer.get(); } - Files.write(Paths.get("D:\\tmp\\mixer\\3.pcm"), target); + Files.write(Paths.get("C:\\Users\\acgis\\桌面\\3.pcm"), target); } }