'startRecording() call from uninitialized AudioRecord

i need some help i am trying to record voice through Audio record using foreground service which continue record voice on background.but problem is that when i set Boot Compeleted Receiver in my app and after reboot my phone i start my Service from on Receieved method of BroadcastReceiver and recording voice again. but when i call startRecording method it throughs exception. i cant understand why it throughs exception. when i start service from app its behaviour good. but its throughs exception when i start from Broadcast. If enyone have knowledge about Audio Record guide me plz where i make mistake. thanks below is my code

class WhistelReceiver : BroadcastReceiver() {
  override fun onReceive(p0: Context?, p1: Intent?) {
        Log.d("TAG", "onReceived: ===>")
            if (p0!=null && p1!=null){
//                android.os.Debug.waitForDebugger()
                Log.d("TAG", "WhistleReceiver ===>not null")
                if (p1.action==Intent.ACTION_BOOT_COMPLETED){
                        Log.d("TAG", "onReceived: ===>boot")
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            Log.d("TAG", "onReceived:    start_Service: ")
            val serviceIntent = Intent(context, WhistelDetectService::class.java)
            ContextCompat.startForegroundService(context, serviceIntent)
        } else {
            val serviceIntent = Intent(context, WhistelDetectService::class.java)
            context.startService(serviceIntent)
        }
            }
        }
    }
}
class WhistelDetectService : Service() {


    private val CHANNEL_ID = "Whistle"
    private var manager: NotificationManager? = null
    private var serviceChannel: NotificationChannel? = null
    private var notification: Notification? = null
    private  var notificationLayout: RemoteViews? = null
    private var Close = "Close"
    private var  whistelDetector : WhistelDetector? = null
    override fun onBind(intent: Intent?): IBinder? {
        return null
    }

    override fun onCreate() {
        super.onCreate()
         whistelDetector = WhistelDetector(applicationContext)
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        if (intent!!.action != null) {
            when (intent.action) {
                Close -> {
                    SharedPref.stopServicePrefValue(applicationContext)
                    stopSelf()
                    Toast.makeText(applicationContext, "stopService", Toast.LENGTH_SHORT).show()
                }
            }

        } else {
            create_Notification_Channel()
            Start_Service()
        }

        return START_STICKY
    }

    private fun create_Notification_Channel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            serviceChannel = NotificationChannel(
                CHANNEL_ID,
                "appChannel",
                NotificationManager.IMPORTANCE_LOW
            )
            serviceChannel!!.setDescription("no sound")
            serviceChannel!!.setSound(null, null)
            serviceChannel!!.enableLights(false)
            serviceChannel!!.setLightColor(Color.BLUE)
            serviceChannel!!.enableVibration(false)
            manager = getSystemService(NotificationManager::class.java)
            manager!!.createNotificationChannel(serviceChannel!!)
        }
    }
    fun Start_Service() {
        val close = Intent(this, WhistelDetectService::class.java)
        close.action = Close
        notificationLayout = RemoteViews(packageName, R.layout.notification_layout)
        notificationLayout!!.setOnClickPendingIntent(
            R.id.close,
            PendingIntent.getService(this, 0, close, PendingIntent.FLAG_UPDATE_CURRENT)
        )
        notification = NotificationCompat.Builder(this, CHANNEL_ID)
            .setSmallIcon(R.mipmap.ic_launcher) //                .setStyle(new NotificationCompat.DecoratedCustomViewStyle())
            .setContent(notificationLayout).setOngoing(true)
            .build()
        whistelDetector!!.startRecording()
        startForeground(1, notification)
    }


    override fun onDestroy() {
        super.onDestroy()
        whistelDetector!!.stopRecording()

    }
}

below is my recording manger class

class WhistelDetector(val context: Context) {
    private var recordingThread: Thread? = null
    var TAG = "RecordingManager"
    var frameByteSize = 2048 // for 1024 fft size (16bit sample size)
    var whistelCount = 1
    private val recordingInProgress = AtomicBoolean(false)
    private val BUFFER_SIZE_FACTOR = 2

    private val SAMPLING_RATE_IN_HZ = 44100

    private val CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_DEFAULT

    private val AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT
    private var recorder: AudioRecord? = null

    private val BUFFER_SIZE = AudioRecord.getMinBufferSize(
        SAMPLING_RATE_IN_HZ,
        CHANNEL_CONFIG, AUDIO_FORMAT
    ) * BUFFER_SIZE_FACTOR

    fun startRecording() {
        if (ActivityCompat.checkSelfPermission(
                context,
                Manifest.permission.RECORD_AUDIO
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            Log.d(TAG, "startRecording: not graunted premission")
            return
        }
        try {
            recorder = AudioRecord(
                MediaRecorder.AudioSource.MIC,
                SAMPLING_RATE_IN_HZ,
                CHANNEL_CONFIG,
                AUDIO_FORMAT,
                BUFFER_SIZE
            )

            Log.d(TAG, "startRecording:  graunted premission")
            if (recorder?.state == STATE_INITIALIZED) {
                Log.d(TAG, "startRecording:==>  recording start")
                listingVoice(recorder!!)
            } else {
 ==> recorder?.state is not initialized when start service from receiver
                Log.d(TAG, "startRecording:  not intilize")
            }
        } catch (e: Exception) {
            e.printStackTrace()
            Log.d(TAG, "startRecording: ${e.message}")
        }
    }

    private fun listingVoice(recorder: AudioRecord) {
        recorder.startRecording()
        recordingInProgress.set(true)
        recordingThread = Thread(RecordingRunnable(context), "Recording Thread")
        recordingThread!!.start()
    }

    fun stopRecording() {
        if (null == recorder) {
            return
        }
        recordingInProgress.set(false)
        recorder!!.stop()
        recorder!!.release()
        recorder = null
        recordingThread = null
    }


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source