Record sound and display volume on Android By TMarcelin Tutorials - March 2, 2022 Comments: 0 Views: 687 If you've ever recorded audio messages, you've seen the interface animate based on the volume of your voice. Let's repeat this effect: Microphone access To start recording inside an Android app, you must first give it access to this functionality. Let's create a tag in the Android manifest uses-permissionand specify the permission RECORD_AUDIO: <uses-permission android:name="android.permission.RECORD_AUDIO" /> We also have to request it at runtime with ActivityCompat.requestPermission: ActivityCompat.requestPermissions( this, arrayOf(android.Manifest.permission.RECORD_AUDIO), 777, ) Sound recording Let's create a class to record sound RecordController. It should have two main methods: startand stop. The AAC codec is well suited for voice recording: fun start() { Log.d(TAG, "Start") audioRecorder = MediaRecorder().apply{ setAudioSource(MediaRecorder.AudioSource.MIC) setOutputFormat(MediaRecorder.OutputFormat.AAC_ADTS) setAudioEncoder(MediaRecorder.AudioEncoder.AAC) setOutputFile(getAudioPath()) prepare() start() } } We will record audio in a temporary directory: private fun getAudioPath(): String { return "${context.cacheDir.absolutePath}${File.pathSeparator}${System.currentTimeMillis()}.wav" } After the end of the recording, you need to apply to the media recorder stopand release: fun stop() { audioRecorder?.let { Log.d(TAG, "Stop") it.stop() it.release() } audioRecorder = null } To work with a state, it is necessary to receive it somehow. To do this, we will make a function that will say whether a recording is currently being made: fun isAudioRecording() = audioRecorder != null Record button Now let's make a record button. Create a new Viewone and position it in the center of the screen. Why is it not a button, Viewhuh? Because we will animate it now and we do not need the standard visual effects of clicking, shadows and other things. <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="<http://schemas.android.com/apk/res/android>" xmlns:app="<http://schemas.android.com/apk/res-auto>" xmlns:tools="<http://schemas.android.com/tools>" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <View android:id="@+id/start_button" android:layout_width="100dp" android:layout_height="100dp" android:background="@drawable/oval" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> By clicking on the button, we will execute methods startor stop. On the first click, we start recording, and on the second click, we stop it, so we take the state from the recorder, depending on which we apply the necessary logic: private fun onButtonclicked() { if (recordController.isAudioRecording()) { recordController.stop() } else { recordController.start() } } If we run the application now, the button will be clicked and even audio recording will work, but this is not visually displayed in any way. Volume Now let's do the recording volume tracking. Let's add the corresponding function: fun getVolume() = audioRecorder?.maxAmplitude ?: 0 This function returns the maximum value since the last call.At the beginning of the recording, we activate the timer to poll the volume. Let it take data every 100 ms: private fun onButtonclicked() { if (recordController.isAudioRecording()) { recordController.stop() countDownTimer?.cancel() countDownTimer = null } else { recordController.start() countDownTimer = object : CountDownTimer(60_000, 100) { override fun onTick(p0: Long) { val volume = recordController.getVolume() Log.d(TAG, "Volume = $volume") handleVolume(volume) } override fun onFinish() { } }.apply{ start() } } } Animation Now let's solve the following problem: when the button is pressed, it is not visually clear whether the recording is in progress and how loudly. Let's create a method handleVolumethat reacts to the volume and changes the size of the button. There Vieware many ways to animate, the simplest is this animate, which allows you to set simple animations very conveniently.How big should the button be? MediaRecorderreturns the volume value as a 16-bit int with a maximum value of 32767. Let's calculate how far we are from this limit in order to proportionally increase the button: private fun handleVolume(volume: Int) { val scale = min(8.0, volume / MAX_RECORD_AMPLITUDE + 1.0).toFloat() Log.d(TAG, "Scale = $scale") audioButton.animate() .scaleX(scale) .scaleY(scale) .setInterpolator(interpolator) .duration= VOLUME_UPDATE_DURATION } Interestingly, this animation works automatically: if we run several times in a loop animate, then the overlay will not occur, each new animation will complete the previous one. Just remember to end recording and animation in methods onDestroyor onpausein case of screen rotation or other events related to Activity.For a more lively animation, let's use OvershootInterpolator'om, it allows you to go beyond the limits of the available range: the button will seem to pulsate, briefly going beyond the upper limit Everything turned out to be quite simple. Instead of resizing, you can draw a volume histogram or something else that comes to your mind or your designer The source code is available at the link .
Android studio. Kotlin. Saving the file in the public Download folder In working on my project, I spent most of the time figuring out how to correctly save the file to a February 28, 2022 Tutorials
Mobile sound - what determines the quality When it comes to quality portable audio, hi-fi audio players immediately come to mind. The February 24, 2022 Blog
Online radio for Android: step by step guide In this tutorial, I'll walk you through building your own Android radio app. I'll start right away February 22, 2022 Tutorials