[*] 混音算法

This commit is contained in:
acgist
2023-12-06 09:07:21 +08:00
parent 988746d708
commit 8d5e415850
3 changed files with 61 additions and 7 deletions

View File

@@ -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)

View File

@@ -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);

View File

@@ -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);
}
}