Agora provides spatial audio effects to give users an immersive audio experience in scenarios such as esports competitions and online conferences.
Agora provides users with local Cartesian coordinate system calculation solution:
This solution uses the AgoraLocalSpatialAudioKit class to implement spatial audio effects, and calculates the relative position of the local user and the remote user through the SDK. You need to call updateSelfPosition and updateRemotePosition to update the spatial coordinates of the local and remote users respectively, so that the local user can hear the remote user's spatial audio effects.
Agora provides media player with local Cartesian coordinate system calculation solution:
This solution calculates the relative positions of the local user and the media player through the SDK. You need to call updateSelfPosition and updatePlayerPositionInfo in the AgoraLocalSpatialAudioKit classes respectively to update the spatial coordinates of the local user and the media player, so that the local user can hear the spatial audio effect of the media player.
This solution implements spatial audio effect through the AgoraLocalSpatialAudioKit class. The API call sequence and operation steps are as follows:
Before calling other Agora APIs, call sharedEngineWithAppId and fill in your App ID to initialize the AgoraRtcEngineKit object.
Before calling other APIs of the AgoraLocalSpatialAudioKit class, call sharedLocalSpatialAudioWithConfig to initialize the AgoraLocalSpatialAudioKit object.
Call setAudioProfile to set the profile parameter to AgoraAudioProfileDefault and the scenario to AgoraAudioScenarioGameStreaming.
Call joinChannelByToken with the mediaOptions parameter to join channel (using RTC Token). Set channelProfile to AgoraChannelProfileLiveBroadcasting and clientRoleType to AgoraClientRoleBroadcaster in AgoraRtcChannelMediaOptions.
Agora subscribes to the audio streams of all remote users by default. You need to call muteAllRemoteAudioStreams(true) of AgoraRtcEngineKit to unsubscribe all remote users, otherwise the audio reception range you set in step 6 will be invalid.
Call the following method to set the audio reception range:
setMaxAudioRecvCount to set the maximum number of audio streams that a user can receive in a specified audio reception range.setAudioRecvRange to set the audio reception range (meters) of the local user.setDistanceUnit to set the length (meters) of the game engine unit distance.You need to call updateSelfPosition and updateRemotePosition to update the spatial coordinates of the local and the remote users successively, so that the local user can hear the remote user's spatial audio effects.
If you do not need to experience spatial audio effects, call clearRemotePositions to delete the spatial position information of all remote users. After the deletion, the local user cannot hear all remote users.
Call destroy of AgoraLocalSpatialAudioKit to destroy the AgoraLocalSpatialAudioKit object.
AgoraLocalSpatialAudioKit object must be destroyed before calling destroy of the AgoraRtcEngineKit.Call leaveChannel and destroy of the AgoraRtcEngineKit class to leave the channel and destroy the AgoraRtcEngineKit object.
This solution implements spatial audio effect through the updateSelfPosition and updatePlayerPositionInfo in the AgoraLocalSpatialAudioKit class. Taking the AgoraLocalSpatialAudioKit class as an example, the operation steps are as follows:
Before calling other Agora APIs, call sharedEngineWithAppId and fill in your App ID to initialize the AgoraRtcEngineKit object.
Before calling other APIs of the AgoraLocalSpatialAudioKit class, call sharedLocalSpatialAudioWithConfig to initialize the AgoraLocalSpatialAudioKit object.
Call setAudioProfile to set the profile to AgoraAudioProfileDefault and the scenario to AgoraAudioScenarioGameStreaming.
Call joinChannelByToken with the mediaOptions parameter to join channel (using RTC Token). Set channelProfile to AgoraChannelProfileLiveBroadcasting and clientRoleType to AgoraClientRoleBroadcaster in AgoraRtcChannelMediaOptions.
Agora subscribes to the audio streams of all remote users by default. You need to call muteAllRemoteAudioStreams(true) of AgoraRtcEngineKit to unsubscribe all remote users, otherwise the audio reception range you set in step 6 will be invalid.
Call the following method to set the audio reception range:
setMaxAudioRecvCount to set the maximum number of audio streams that a user can receive in a specified audio reception range.setAudioRecvRange to set the audio reception range (meters) of the local user.setDistanceUnit to set the length (meters) of the game engine unit distance.You need to call updateSelfPosition and updateRemotePosition to update the spatial coordinates of the local and the remote users successively, so that the local user can hear the remote user's spatial audio effects.
Call destroy of AgoraLocalSpatialAudioKit to destroy the AgoraLocalSpatialAudioKit object.
AgoraLocalSpatialAudioKit object must be destroyed before calling destroy of the AgoraRtcEngineKit.Call destroy of the AgoraRtcEngineKit to destroy the AgoraRtcEngineKit object.
This section shows sample code that uses the local Cartesian coordinate system calculation solution to implement the spatial audio effects for the media player:
// Swift
class SpatialAudioMain: BaseViewController {
var agoraKit: AgoraRtcEngineKit!
var mediaPlayer: AgoraRtcMediaPlayerProtocol!
var localSpatial: AgoraLocalSpatialAudioKit!
override func viewDidLoad() {
// Initialize the AgoraRtcEngineKit
agoraKit = AgoraRtcEngineKit.sharedEngine(withAppId: KeyCenter.AppId, delegate: self)
// Set the channel profile as liveBroadcasting
config.channelProfile = .liveBroadcasting
// Set the client role as the host.
agoraKit.setClientRole(.broadcaster)
// Set audio profile and scenario
agoraKit.setAudioProfile(.default, scenario: .gameStreaming)
guard let filePath = Bundle.main.path(forResource: "audiomixing", ofType: "mp3") else {return}
// Create a media player
mediaPlayer = agoraKit.createMediaPlayer(with: self)
// Opens a media resource
mediaPlayer.open(filePath, startPos: 0)
// Initialize the AgoraLocalSpatialAudioKit
let localSpatialConfig = AgoraLocalSpatialAudioConfig()
localSpatialConfig.rtcEngine = agoraKit
localSpatial = AgoraLocalSpatialAudioKit.sharedLocalSpatialAudio(with: localSpatialConfig)
// Set the audio reception range (meters)
localSpatial.setAudioRecvRange(50)
// Set the length (meters) of the game engine distance per unit.
localSpatial.setDistanceUnit(1)
// Updates the spatial position of the local user.
let pos = [NSNumber(0.0), NSNumber(0), NSNumber(0.0)]
let forward = [NSNumber(1.0), NSNumber(0.0), NSNumber(0.0)]
let right = [NSNumber(0.0), NSNumber(1.0), NSNumber(0.0)]
let up = [NSNumber(0.0), NSNumber(0.0), NSNumber(1.0)]
self.localSpatial.updateSelfPosition(pos, axisForward: forward, axisRight: right, axisUp: up)
}
override func willMove(toParent parent: UIViewController?) {
if parent == nil {
// Destroy the AgoraLocalSpatialAudioKit
AgoraLocalSpatialAudioKit.destroy()
// Destroy the AgoraRtcEngineKit object.
AgoraRtcEngineKit.destroy()
}
}
// Updates the spatial position of the media player.
func updateRemoteUserSpatialAudioPositon() {
let maxR = UIScreen.main.bounds.height / 2.0
let maxSpatailDistance = 30.0
let spatialDistance = currentDistance * maxSpatailDistance / maxR
let posForward = spatialDistance * cos(currentAngle);
let posRight = spatialDistance * sin(currentAngle);
let position = [NSNumber(value: posForward), NSNumber(value: posRight), NSNumber(0.0)]
let forward = [NSNumber(1.0), NSNumber(0.0), NSNumber(0.0)]
let positionInfo = AgoraRemoteVoicePositionInfo()
positionInfo.position = position
positionInfo.forward = forward
localSpatial.updatePlayerPositionInfo(mediaPlayer.getMediaPlayerId(), positionInfo);
}
}
Agora provides an open source sample project SpatialAudio on GitHub. You can download the sample project to try it out or refer to the source code.