功能介绍

在用户使用 “一起看”、“一起听” 等互动娱乐类应用时,如果需要在通话过程中播放音效或音乐文件等,而且让房间内的其他成员也听到声音,需要使用混音功能。混音功能可以将麦克风采集的音频数据与音频文件、PCM 音频数据等合并为一路音频流后,发布到房间内。本文将介绍如何使用混音功能。

功能变更日志
  1. 自客户端 SDK 3.32 起,支持对音乐文件的声道进行设置。
  2. 自客户端 SDK 3.36 起,全平台支持在线音频文件混音。
  3. 自客户端 SDK 3.38 起,支持调整音视频通话中使用的音频文件的播放速度。
  4. 自客户端 SDK 3.45.4 起,支持获取混音音频文件的实际播放时长,即歌曲不受停止、跳转、倍速、卡顿影响的播放时长。
  5. 自客户端 SDK 3.54 起,Native 平台废弃原有的混音类,分为音效混音和音乐混音,支持分别控制。
功能使用

RTC SDK 提供了音效混音类和音乐混音类。
一般来说,对于短时间的音效(比如小于 20s),可以使用音效类;对于较长的音频或 PCM 数据,可以使用音乐类。

类和初始化

参见下表:

AndroidiOSmacOSWindowsWeb
初始化音效管理类getAudioEffectPlayergetAudioEffectPlayergetAudioEffectPlayergetAudioEffectPlayergetAudioMixingManager
音效混音管理类IAudioEffectPlayerByteRTCAudioEffectPlayerByteRTCAudioEffectPlayerIAudioEffectPlayerAudioMixingManager
初始化音乐管理类getMediaPlayergetMediaPlayergetMediaPlayergetMediaPlayergetAudioMixingManager
音乐混音管理类IMediaPlayerByteRTCMediaPlayerByteRTCMediaPlayerIMediaPlayerAudioMixingManager
播放本地音频/音效文件

参考以下顺序,调用 API 实现此功能:

以下接口在音效管理类和音乐管理类中都有。
对同一个音频文件进行操作时,混音 ID 应保持一致

步骤调用目标接口
1设置回调句柄setEventHandler
2(可选)预加载音乐文件preload
3播放音乐文件start
4暂停播放pause
5恢复播放resume
6停止播放stop

除以上功能以外,RTC SDK 还支持调整音频播放音量和声道,设置音乐播放进度等功能。

播放 PCM 音频数据

此功能仅在音乐管理类中实现。

参考以下顺序,调用 API 实现此功能:

步骤调用目标Android 接口
1设置回调句柄setEventHandler
2启动 PCM 音频数据混音openWithCustomSource
3周期性推送 PCM 音频数据,以开始播放pushExternalAudioFrame
4结束 PCM 音频数据混音stop
示例代码

以 objective-C 为例,介绍播放 PCM 音频的相关功能。

启动混音
	- (void)startAudioMixing {
		// playerId must be in range of [0,3]
	    ByteRTCMediaPlayer *mediaPlayer = [self.rtcKit getMediaPlayer:playerId];
		ByteRTCMediaPlayerCustomSource* source = [[ByteRTCMediaPlayerCustomSource alloc] init];
		source.mode = ByteRTCMediaPlayerCustomSourceModePush;
		source.type = ByteRTCMediaPlayerCustomSourceStreamTypeRaw;
		source.provider = NULL;
		ByteRTCMediaPlayerConfig *config = [[ByteRTCMediaPlayerConfig alloc] init];
		config.type = ByteRTCAudioMixingTypePlayout;;
	    int ret = [mediaPlayer openWithCustomSource:source config:config];
	}
Objective-C
播放混音

以下示例代码以 ttplayer 的数据为例,说明 SDK 要求的数据处理方式。

	/// Deal with PCM data
	/// @param inouts PCM data in float
	/// @param samples number of samples
	- (void)processAudio:(float **)inouts samples:(int)samples {
	    
	    // Number of channels. If the number is more than 2, cut it down to 2.
	    int channelsCount = _channels;
	    int samplerate = _samplerate;
	    
	    int length = samples * channelsCount;
	    if (self.length < length) {
	        if (self.length > 0) {
	            self.length = 0;
	            delete [] (buffer);
	        }
	        buffer = new int16_t[length*2];
	        self.length = length*2;
	    }
	// If the data is in a non-interleaved format, convert it to an interleaved format.
	    for (int i = 0; i < channelsCount; i++) {
	        int offset = i;
	        float *dataList = inouts[i];
	        for (int j = 0; j < samples; j++) {
	            float data = dataList[j];
	// convert to int16
	            int value = data * INT16_MAX;
	            if(value > INT16_MAX){
	                value = INT16_MAX;
	            } else if(value < INT16_MIN){
	                value = INT16_MIN;
	            }
	            buffer[offset] = value;
	            offset += _channels;
	        }
	    }
	    
	    ByteRTCAudioFrame *frame = [[ByteRTCAudioFrame alloc] init];
	    frame.buffer = [NSData dataWithBytes:buffer length:length*2]; // Using class methods that do not participate in buffer lifecycle management.
	    
	    frame.samples = samples;
	    frame.channel = (ByteRTCAudioChannel)channelsCount;
	    frame.sampleRate = (ByteRTCAudioSampleRate)samplerate;
	    
	    ByteRTCMediaPlayer *mediaPlayer = [self.rtcKit getMediaPlayer:playerId];
	    [mediaPlayer pushExternalAudioFrame:frame];
	}
Objective-C
调整混音音量
	- (void)setAudioMixingVolume:(int)Volume {
	    ByteRTCMediaPlayer *mediaPlayer = [self.rtcKit getMediaPlayer:playerId];
	    [mediaPlayer setVolume:volume type:ByteRTCAudioMixingTypePlayout];
	}
Objective-C
结束混音
	- (void)stopAudioMixing {
	    ByteRTCMediaPlayer *mediaPlayer = [self.rtcKit getMediaPlayer:playerId];
	    [mediaPlayer stop];
	}
Objective-C
注意事项
  1. 如果频繁播放同一文件时,建议调用 preload 预加载音频文件,可以减少 CPU 占用。如果已预加载,确保播放时传入的 ID 与预加载时的一致;如果不再需要播放后,可以调用 unload 清理内存空间。
  2. 所有的混音相关设置都必须在开始播放以后,停止播放之前进行,否则不生效,包括但不限于设置播放音量,设置播放起始位置等。
  3. 只有移动端有 setVolumeAll 接口,可以调节全部混音音量,PC端只能通过setVolume 接口调节指定混音音量。
  4. 已知问题:RTC SDK 3.52 以下的版本,混音播放 24kHz 的 mp3 文件会崩溃。原因是仅支持以下采样率的音频文件:8kHz、16kHz、22.05kHz、32kHz、44.1kHz、48kHz、64kHz、96kHz、192kHz。如果你希望播放 24kHz 采样率的音频文件,使用 RTC SDK 3.52 及以上版本。