Back to Blog

How to Mute Audio and Adjust Volume During a Video Call in Android Using the Agora SDK

How to Mute Audio and Adjust Volume During a Video Call in Android Using the Agora SDK

Boemo is a software developer who embraces innovative approaches. He likes diving deep into complex concepts in order to learn and write articles that can help the reader understand complex methodologies in a simple and fun way.


Agora has many features that enhance video call quality and convenience. Muting audio and adjusting the video call’s volume are features that are necessary for any video call app.

In this tutorial, you will learn how to mute Agora video call audio and adjust the video call’s volume in Android using the Agora SDK.

Prerequisites and requirements

  • An Agora developer account (see How to Get Started with Agora).
  • Knowledge of how to create a live-streaming Android application using Agora. Check out the tutorial here.
  • Basic knowledge of Android development.
  • Android Studio.
  • An Android device.

Adding dependencies in Gradle

Before we start coding, add the following dependencies in your build.gradle file in the app module, and sync to download the Agora third-party library. Ensure that you always use the latest Agora library version:

implementation 'com.yanzhenjie:permission:2.0.3'
implementation 'io.agora.rtc:full-sdk:3.5.0'

Adding permissions in the Manifest.xml file

Add the following permissions in the Manifest.xml file:

<uses-permission android:name="android.permission.CAMERA" />
 <uses-permission android:name="android.permission.INTERNET" />
 <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 <uses-permission android:name="android.permission.RECORD_AUDIO" />
view raw permissions.xml hosted with ❤ by GitHub

Creating an instance of the RtcEngine

Now, let’s create an RtcEngine instance by initializing the RtcEngine and passing the IRtcEngineEventHandler and your App ID to the create method. IRtcEngineEventHandler is an abstract class that provides the default implementation. We will use this object instance later to invoke the adjustPlaybackSignalVolume()method, which adjusts the volume of the video call:

try {
 mRtcEngine = RtcEngine.create(getBaseContext(), getString(R.string.agora_app_id), mRtcEventHandler);
} catch (Exception e) {
 Log.e(LOG_TAG, Log.getStackTraceString(e));
 throw new RuntimeException("fatal error\n" + Log.getStackTraceString(e));
}
view raw rtcengine.java hosted with ❤ by GitHub

Setting up the video call profile

Next, add the following code which sets the profile, orientation, and video configuration of the video call. Set the Channel profile as CHANNEL_PROFILE_COMMUNICATION. This enables all video call participants to send and receive voice and video in a one-to-one call:

mRtcEngine.setChannelProfile(Constants.CHANNEL_PROFILE_COMMUNICATION);
mRtcEngine.enableVideo();
mRtcEngine.setVideoEncoderConfiguration(new VideoEncoderConfiguration(VideoEncoderConfiguration.VD_640x480, VideoEncoderConfiguration.FRAME_RATE.FRAME_RATE_FPS_30,
 VideoEncoderConfiguration.STANDARD_BITRATE,
 VideoEncoderConfiguration.ORIENTATION_MODE.ORIENTATION_MODE_FIXED_PORTRAIT));
view raw profile.java hosted with ❤ by GitHub

Adjusting the volume during a video call by dragging the SeekBar

A SeekBar is a ProgressBar that can be dragged left and right by a thumb. We will use the SeekBar to adjust the volume of the audio file being played or the video call’s volume.

Let’s start by creating a SeekBar object and calling the setOnSeekBarChangeListener:

SeekBar seekBar=(SeekBar)findViewById(R.id.seekBar);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
view raw onSeekbar.java hosted with ❤ by GitHub

To adjust the video call’s volume, we will use the adjustPlaybackSignalVolume() method and pass the progress value of the SeekBar to the adjustPlaybackSignalVolume() method. This method changes the volume of the video call.

The volume range of the Agora video call is from 0 to 100. The default volume is 100.

The onProgressChanged() method tracks changes made on the SeekBar when the user drags the SeekBar:

@Override
 public void onProgressChanged(SeekBar seekBar, int progress,
 boolean fromUser) {
 mRtcEngine.adjustPlaybackSignalVolume(progress);
 }

Next, implement the necessary methods of the SeekBar.OnSeekBarChangeListener interface. The onStartTrackingTouch() function adds a notification that the SeekBar has started tracking the user’s touch:

@Override
 public void onStartTrackingTouch(SeekBar seekBar) {
 }
view raw mStart.java hosted with ❤ by GitHub

The onStopTrackingTouch() function adds a notification that the SeekBar has stopped tracking the user’s touch:

@Override
 public void onStopTrackingTouch(SeekBar seekBar) {
 }
});

Muting the video call

To mute the video call we have to set the volume to 0 using the adjustPlaybackSignalVolume() and adjustAudioMixingVolume() methods. Both of these methods must be used when muting the video call’s audio, and they can be called before or after joining a video call:

public void muteAudio(View view) {
 mRtcEngine.adjustAudioMixingVolume(0);
 mRtcEngine.adjustPlaybackSignalVolume(0);
}
view raw muteAudio.java hosted with ❤ by GitHub

Integrating the mute and adjust volume features with the Agora Video Call SDK

You have learned how to mute and adjust the volume using the Agora SDK methods in the previous sections. The following code block of the Mute class shows you how to integrate the mute and adjust volume features in a video streaming application:

public class Mute extends AppCompatActivity{
private RtcEngine mRtcEngine;
int volume=0;
private IAudioEffectManager audioEffectManager;
SeekBar seekBar;
// Permissions
private static final int PERMISSION_REQ_ID = 22;
private static final String[] REQUESTED_PERMISSIONS = {Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA};
private static final String LOG_TAG = MainActivity.class.getSimpleName();
// Handle SDK Events
private final IRtcEngineEventHandler mRtcEventHandler = new IRtcEngineEventHandler() {
@Override
public void onUserJoined(final int uid, int elapsed) {
runOnUiThread(new Runnable() {
@Override
public void run() {
// set first remote user to the main bg video container
setupRemoteVideoStream(uid);
}
});
}
// remote user has left channel
@Override
public void onUserOffline(int uid, int reason) { // Tutorial Step 7
runOnUiThread(new Runnable() {
@Override
public void run() {
onRemoteUserLeft();
}
});
}
// remote user has toggled their video
@Override
public void onRemoteVideoStateChanged(final int uid, final int state, int reason, int elapsed) {
runOnUiThread(new Runnable() {
@Override
public void run() {
onRemoteUserVideoToggle(uid, state);
}
});
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mute);
if (checkSelfPermission(REQUESTED_PERMISSIONS[0], PERMISSION_REQ_ID) &&
checkSelfPermission(REQUESTED_PERMISSIONS[1], PERMISSION_REQ_ID)) {
initAgoraEngine();
}
seekBar=(SeekBar)findViewById(R.id.seekBar);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
mRtcEngine.adjustPlaybackSignalVolume(progress);
// progress= volume
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
}
private void initAgoraEngine() {
try {
mRtcEngine = RtcEngine.create(getBaseContext(), getString(R.string.agora_app_id), mRtcEventHandler);
} catch (Exception e) {
Log.e(LOG_TAG, Log.getStackTraceString(e));
throw new RuntimeException("fatal error\n" + Log.getStackTraceString(e));
}
setupSession();
}
private void setupSession() {
mRtcEngine.setChannelProfile(Constants.CHANNEL_PROFILE_COMMUNICATION);
mRtcEngine.enableVideo();
mRtcEngine.setVideoEncoderConfiguration(new VideoEncoderConfiguration(VideoEncoderConfiguration.VD_640x480, VideoEncoderConfiguration.FRAME_RATE.FRAME_RATE_FPS_30,
VideoEncoderConfiguration.STANDARD_BITRATE,
VideoEncoderConfiguration.ORIENTATION_MODE.ORIENTATION_MODE_FIXED_PORTRAIT));
}
private void setupLocalVideoFeed() {
// setup the container for the local user
FrameLayout videoContainer = findViewById(R.id.floating_video_container);
SurfaceView videoSurface = RtcEngine.CreateRendererView(getBaseContext());
videoSurface.setZOrderMediaOverlay(true);
videoContainer.addView(videoSurface);
mRtcEngine.setupLocalVideo(new VideoCanvas(videoSurface, VideoCanvas.RENDER_MODE_FIT, 0));
}
private void setupRemoteVideoStream(int uid) {
// setup ui element for the remote stream
FrameLayout videoContainer = findViewById(R.id.bg_video_container);
// ignore any new streams that join the session
if (videoContainer.getChildCount() >= 1) {
return;
}
SurfaceView videoSurface = RtcEngine.CreateRendererView(getBaseContext());
videoContainer.addView(videoSurface);
mRtcEngine.setupRemoteVideo(new VideoCanvas(videoSurface, VideoCanvas.RENDER_MODE_FIT, uid));
mRtcEngine.setRemoteSubscribeFallbackOption(Constants.STREAM_FALLBACK_OPTION_AUDIO_ONLY);
}
// join the channel when user clicks UI button
public void onjoinChannelClicked(View view) {
mRtcEngine.joinChannel(null, "test-channel", "Extra Optional Data", 0); // if you do not specify the uid, Agora will assign one.
setupLocalVideoFeed();
findViewById(R.id.joinBtn).setVisibility(View.GONE); // set the join button hidden
}
private void leaveChannel() {
mRtcEngine.leaveChannel();
}
private void removeVideo(int containerID) {
FrameLayout videoContainer = findViewById(containerID);
videoContainer.removeAllViews();
}
private void onRemoteUserVideoToggle(int uid, int state) {
FrameLayout videoContainer = findViewById(R.id.bg_video_container);
SurfaceView videoSurface = (SurfaceView) videoContainer.getChildAt(0);
videoSurface.setVisibility(state == 0 ? View.GONE : View.VISIBLE);
// add an icon to let the other user know remote video has been disabled
if(state == 0){
ImageView noCamera = new ImageView(this);
noCamera.setImageResource(R.drawable.video_disabled);
videoContainer.addView(noCamera);
} else {
ImageView noCamera = (ImageView) videoContainer.getChildAt(1);
if(noCamera != null) {
videoContainer.removeView(noCamera);
}
}
}
private void onRemoteUserLeft() {
removeVideo(R.id.bg_video_container);
}
public boolean checkSelfPermission(String permission, int requestCode) {
Log.i(LOG_TAG, "checkSelfPermission " + permission + " " + requestCode);
if (ContextCompat.checkSelfPermission(this,
permission)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
REQUESTED_PERMISSIONS,
requestCode);
return false;
}
return true;
}
@Override
public void onRequestPermissionsResult(int requestCode,
@NonNull String permissions[], @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
Log.i(LOG_TAG, "onRequestPermissionsResult " + grantResults[0] + " " + requestCode);
switch (requestCode) {
case PERMISSION_REQ_ID: {
if (grantResults[0] != PackageManager.PERMISSION_GRANTED || grantResults[1] != PackageManager.PERMISSION_GRANTED) {
Log.i(LOG_TAG, "Need permissions " + Manifest.permission.RECORD_AUDIO + "/" + Manifest.permission.CAMERA);
break;
}
initAgoraEngine();
break;
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
leaveChannel();
RtcEngine.destroy();
mRtcEngine = null;
}
public void muteAudio(View view) {
mRtcEngine.adjustAudioMixingVolume(0);
mRtcEngine.adjustPlaybackSignalVolume(0);
}
private void preloadAudioEffect(){
// Gets the global audio effect manager.
audioEffectManager = mRtcEngine.getAudioEffectManager();
int id = 0;
audioEffectManager.preloadEffect(id++, Environment.getExternalStorageDirectory().getPath()+"/Song/Caiiro.mp3");
audioEffectManager.playEffect(
0, // The sound ID of the audio effect file to be played.
Environment.getExternalStorageDirectory().getPath()+"/Song/Caiiro.mp3", // The file path of the audio effect file.
-1, // The number of playback loops. -1 means an infinite loop.
1, // pitch The pitch of the audio effect. The value ranges between 0.5 and 2. The default value is 1 (no change to the pitch). The lower the value, the lower the pitch.
0.0, // Sets the spatial position of the effect. 0 means the effect shows ahead.
volume, // Sets the volume. The value ranges between 0 and 100. 100 is the original volume.
true, // Sets whether to publish the audio effect.
0 // Start position
);
// Pauses all audio effects.
audioEffectManager.pauseAllEffects();
}
}
view raw mute.java hosted with ❤ by GitHub

If you are not familiar with building a one-to-one video call app using the Agora SDK, check this tutorial on GitHub written by Hermes. The above code follows the concepts taught in that tutorial.

Testing the app demo

Summary

In this tutorial we have learned how to:

  • Track the user’s touch using a SeekBar
  • Adjust Agora video call volume
  • Mute audio during a video call

Conclusion

Yay! you now know how to mute audio and adjust the volume using the Agora SDK.

Thank you for reading. You can learn more about how to adjust the volume here, and you can check out more Agora features on GitHub here. If you want to copy or reference the SDK I was using, check it on GitHub here.

Other resources

If you get confused in the process, you can check out Agora’s documentation. You can also join Agora’s Slack channel here.

RTE Telehealth 2023
Join us for RTE Telehealth - a virtual webinar where we’ll explore how AI and AR/VR technologies are shaping the future of healthcare delivery.

Learn more about Agora's video and voice solutions

Ready to chat through your real-time video and voice needs? We're here to help! Current Twilio customers get up to 2 months FREE.

Complete the form, and one of our experts will be in touch.

Try Agora for Free

Sign up and start building! You don’t pay until you scale.
Try for Free