1+ package com.audiowaveform
2+
3+ import android.Manifest
4+ import android.app.Activity
5+ import android.content.pm.PackageManager
6+ import android.media.MediaMetadataRetriever
7+ import android.media.MediaRecorder
8+ import android.os.Build
9+ import android.util.Log
10+ import androidx.annotation.RequiresApi
11+ import androidx.core.app.ActivityCompat
12+ import com.facebook.react.bridge.Arguments
13+ import com.facebook.react.bridge.Promise
14+ import java.io.IOException
15+ import java.lang.IllegalStateException
16+ import kotlin.math.log10
17+
18+ private const val RECORD_AUDIO_REQUEST_CODE = 1001
19+
20+ class AudioRecorder {
21+ private var permissions = arrayOf(Manifest .permission.RECORD_AUDIO )
22+ private var useLegacyNormalization = false
23+
24+ private fun isPermissionGranted (activity : Activity ? ): Int? {
25+ return activity?.let { ActivityCompat .checkSelfPermission(it, permissions[0 ]) }
26+ }
27+
28+ fun checkPermission (activity : Activity ? , promise : Promise ): String {
29+ val permissionResponse = isPermissionGranted(activity)
30+ if (permissionResponse == = PackageManager .PERMISSION_GRANTED ) {
31+ promise.resolve(" granted" )
32+ return " granted"
33+ } else {
34+ promise.resolve(" denied" )
35+ return " denied"
36+ }
37+ }
38+
39+ fun getPermission (activity : Activity ? , promise : Promise ): String {
40+ val permissionResponse = isPermissionGranted(activity)
41+ if (permissionResponse == = PackageManager .PERMISSION_GRANTED ) {
42+ promise.resolve(" granted" );
43+ return " granted"
44+ } else {
45+ activity?.let {
46+ ActivityCompat .requestPermissions(
47+ it, permissions,
48+ RECORD_AUDIO_REQUEST_CODE
49+ )
50+ }
51+ return " denied"
52+ }
53+ }
54+
55+ fun getDecibel (recorder : MediaRecorder ? ): Double? {
56+ if (useLegacyNormalization) {
57+ val db = 20 * log10((recorder?.maxAmplitude?.toDouble() ? : (0.0 / 32768.0 )))
58+ if (db == Double .NEGATIVE_INFINITY ) {
59+ Log .e(Constants .LOG_TAG , " Microphone might be turned off" )
60+ } else {
61+ return db
62+ }
63+ return db;
64+ } else {
65+ return recorder?.maxAmplitude?.toDouble() ? : 0.0
66+ }
67+ }
68+
69+ fun initRecorder (
70+ path : String ,
71+ recorder : MediaRecorder ? ,
72+ encoder : Int ,
73+ outputFormat : Int ,
74+ sampleRate : Int ,
75+ bitRate : Int? ,
76+ promise : Promise
77+ ) {
78+ recorder?.apply {
79+ setAudioSource(MediaRecorder .AudioSource .MIC )
80+ setOutputFormat(getOutputFormat(outputFormat))
81+ setAudioEncoder(getEncoder(encoder))
82+ setAudioSamplingRate(sampleRate)
83+ if (bitRate != null ) {
84+ setAudioEncodingBitRate(bitRate)
85+ }
86+ setOutputFile(path)
87+ try {
88+ prepare()
89+ promise.resolve(true )
90+ } catch (e: IOException ) {
91+ Log .e(Constants .LOG_TAG , " Failed to stop initialize recorder" )
92+ }
93+ }
94+ }
95+
96+ fun stopRecording (recorder : MediaRecorder ? , path : String , promise : Promise ) {
97+ try {
98+ recorder?.apply {
99+ stop()
100+ reset()
101+ release()
102+ }
103+ val tempArrayForCommunication : MutableList <String > = mutableListOf ()
104+ val duration = getDuration(path)
105+ tempArrayForCommunication.add(path)
106+ tempArrayForCommunication.add(duration)
107+ promise.resolve(Arguments .fromList(tempArrayForCommunication))
108+ } catch (e: IllegalStateException ) {
109+ Log .e(Constants .LOG_TAG , " Failed to stop recording" )
110+ }
111+ }
112+
113+ private fun getDuration (path : String ): String {
114+ val mediaMetadataRetriever = MediaMetadataRetriever ()
115+ try {
116+ mediaMetadataRetriever.setDataSource(path)
117+ val duration = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever .METADATA_KEY_DURATION )
118+ return duration ? : " -1"
119+ } catch (e: Exception ) {
120+ Log .e(Constants .LOG_TAG , " Failed to get recording duration" )
121+ } finally {
122+ mediaMetadataRetriever.release()
123+ }
124+ return " -1"
125+ }
126+
127+ fun startRecorder (recorder : MediaRecorder ? , useLegacy : Boolean , promise : Promise ) {
128+ try {
129+ useLegacyNormalization = useLegacy
130+ recorder?.start()
131+ promise.resolve(true )
132+ } catch (e: IllegalStateException ) {
133+ Log .e(Constants .LOG_TAG , " Failed to start recording" )
134+ }
135+ }
136+
137+ @RequiresApi(Build .VERSION_CODES .N )
138+ fun pauseRecording (recorder : MediaRecorder ? , promise : Promise ) {
139+ try {
140+ recorder?.pause()
141+ promise.resolve(false )
142+ } catch (e: IllegalStateException ) {
143+ Log .e(Constants .LOG_TAG , " Failed to pause recording" )
144+ }
145+ }
146+
147+ @RequiresApi(Build .VERSION_CODES .N )
148+ fun resumeRecording (recorder : MediaRecorder ? , promise : Promise ) {
149+ try {
150+ recorder?.resume()
151+ promise.resolve(true )
152+ } catch (e: IllegalStateException ) {
153+ Log .e(Constants .LOG_TAG , " Failed to resume recording" )
154+ }
155+ }
156+
157+ private fun getEncoder (encoder : Int ): Int {
158+ return when (encoder) {
159+ Constants .acc -> MediaRecorder .AudioEncoder .AAC
160+ Constants .aac_eld -> MediaRecorder .AudioEncoder .AAC_ELD
161+ Constants .he_aac -> MediaRecorder .AudioEncoder .HE_AAC
162+ Constants .amr_nb -> MediaRecorder .AudioEncoder .AMR_NB
163+ Constants .amr_wb -> MediaRecorder .AudioEncoder .AMR_WB
164+ Constants .opus -> {
165+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .Q ) {
166+ MediaRecorder .AudioEncoder .OPUS
167+ } else {
168+ Log .e(Constants .LOG_TAG , " Minimum android Q is required, Setting Acc encoder." )
169+ MediaRecorder .AudioEncoder .AAC
170+ }
171+ }
172+ Constants .vorbis -> MediaRecorder .AudioEncoder .VORBIS
173+ else -> MediaRecorder .AudioEncoder .AAC
174+ }
175+ }
176+
177+ private fun getOutputFormat (format : Int ): Int {
178+ return when (format) {
179+ Constants .mpeg4 -> MediaRecorder .OutputFormat .MPEG_4
180+ Constants .three_gpp -> MediaRecorder .OutputFormat .THREE_GPP
181+ Constants .ogg -> {
182+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .Q ) {
183+ MediaRecorder .OutputFormat .OGG
184+ } else {
185+ Log .e(Constants .LOG_TAG , " Minimum android Q is required, Setting Acc encoder." )
186+ MediaRecorder .OutputFormat .MPEG_4
187+ }
188+ }
189+ Constants .amr_wb -> MediaRecorder .OutputFormat .AMR_WB
190+ Constants .amr_nb -> MediaRecorder .OutputFormat .AMR_NB
191+ Constants .webm -> MediaRecorder .OutputFormat .WEBM
192+ Constants .mpeg_2_ts -> {
193+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .O ) {
194+ MediaRecorder .OutputFormat .MPEG_2_TS
195+ } else {
196+ Log .e(Constants .LOG_TAG , " Minimum android Q is required, Setting MPEG_4 output format." )
197+ MediaRecorder .OutputFormat .MPEG_4
198+ }
199+ }
200+ Constants .aac_adts -> MediaRecorder .OutputFormat .AAC_ADTS
201+ else -> MediaRecorder .OutputFormat .MPEG_4
202+ }
203+ }
204+ }
0 commit comments