adding a recording audio visualizer

This commit is contained in:
tibbi
2020-03-30 19:43:45 +02:00
parent afb76aa3e2
commit dde911e1de
5 changed files with 52 additions and 8 deletions

View File

@ -40,4 +40,5 @@ android {
dependencies { dependencies {
implementation 'com.simplemobiletools:commons:5.24.4' implementation 'com.simplemobiletools:commons:5.24.4'
implementation 'org.greenrobot:eventbus:3.2.0' implementation 'org.greenrobot:eventbus:3.2.0'
implementation 'com.github.Armen101:AudioRecordView:1.0.2'
} }

View File

@ -44,10 +44,13 @@ class MainActivity : SimpleActivity() {
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
val adjustedPrimaryColor = getAdjustedPrimaryColor()
toggle_recording_button.apply { toggle_recording_button.apply {
setImageDrawable(getToggleButtonIcon()) setImageDrawable(getToggleButtonIcon())
background.applyColorFilter(getAdjustedPrimaryColor()) background.applyColorFilter(adjustedPrimaryColor)
} }
visualizer.chunkColor = adjustedPrimaryColor
} }
override fun onDestroy() { override fun onDestroy() {
@ -134,6 +137,15 @@ class MainActivity : SimpleActivity() {
fun gotStatusEvent(event: Events.RecordingStatus) { fun gotStatusEvent(event: Events.RecordingStatus) {
isRecording = event.isRecording isRecording = event.isRecording
toggle_recording_button.setImageDrawable(getToggleButtonIcon()) toggle_recording_button.setImageDrawable(getToggleButtonIcon())
if (isRecording) {
visualizer.recreate()
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun gotAmplitudeEvent(event: Events.RecordingAmplitude) {
val amplitude = event.amplitude
visualizer.update(amplitude)
} }
private fun getToggleButtonIcon(): Drawable { private fun getToggleButtonIcon(): Drawable {

View File

@ -3,4 +3,5 @@ package com.simplemobiletools.voicerecorder.models
class Events { class Events {
class RecordingDuration internal constructor(val duration: Int) class RecordingDuration internal constructor(val duration: Int)
class RecordingStatus internal constructor(val isRecording: Boolean) class RecordingStatus internal constructor(val isRecording: Boolean)
class RecordingAmplitude internal constructor(val amplitude: Int)
} }

View File

@ -28,10 +28,13 @@ import java.io.IOException
import java.util.* import java.util.*
class RecorderService : Service() { class RecorderService : Service() {
private val AMPLITUDE_UPDATE_MS = 100L
private var currFilePath = "" private var currFilePath = ""
private var duration = 0 private var duration = 0
private var isRecording = false private var isRecording = false
private var timer = Timer() private var durationTimer = Timer()
private var amplitudeTimer = Timer()
private var recorder: MediaRecorder? = null private var recorder: MediaRecorder? = null
override fun onBind(intent: Intent?): IBinder? = null override fun onBind(intent: Intent?): IBinder? = null
@ -50,8 +53,6 @@ class RecorderService : Service() {
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
stopRecording() stopRecording()
recorder?.release()
recorder = null
} }
// mp4 output format with aac encoding should produce good enough mp3 files according to https://stackoverflow.com/a/33054794/1967672 // mp4 output format with aac encoding should produce good enough mp3 files according to https://stackoverflow.com/a/33054794/1967672
@ -81,8 +82,11 @@ class RecorderService : Service() {
broadcastRecorderInfo() broadcastRecorderInfo()
startForeground(RECORDER_RUNNING_NOTIF_ID, showNotification()) startForeground(RECORDER_RUNNING_NOTIF_ID, showNotification())
timer = Timer() durationTimer = Timer()
timer.scheduleAtFixedRate(getTimerTask(), 1000, 1000) durationTimer.scheduleAtFixedRate(getDurationUpdateTask(), 1000, 1000)
amplitudeTimer = Timer()
amplitudeTimer.scheduleAtFixedRate(getAmplitudeUpdateTask(), 0, AMPLITUDE_UPDATE_MS)
} catch (e: IOException) { } catch (e: IOException) {
showErrorToast(e) showErrorToast(e)
stopRecording() stopRecording()
@ -91,7 +95,8 @@ class RecorderService : Service() {
} }
private fun stopRecording() { private fun stopRecording() {
timer.cancel() durationTimer.cancel()
amplitudeTimer.cancel()
isRecording = false isRecording = false
recorder?.apply { recorder?.apply {
@ -151,13 +156,21 @@ class RecorderService : Service() {
toast(msg, Toast.LENGTH_LONG) toast(msg, Toast.LENGTH_LONG)
} }
private fun getTimerTask() = object : TimerTask() { private fun getDurationUpdateTask() = object : TimerTask() {
override fun run() { override fun run() {
duration++ duration++
broadcastDuration() broadcastDuration()
} }
} }
private fun getAmplitudeUpdateTask() = object : TimerTask() {
override fun run() {
if (recorder != null) {
EventBus.getDefault().post(Events.RecordingAmplitude(recorder!!.maxAmplitude))
}
}
}
@TargetApi(Build.VERSION_CODES.O) @TargetApi(Build.VERSION_CODES.O)
private fun showNotification(): Notification { private fun showNotification(): Notification {
val channelId = "simple_recorder" val channelId = "simple_recorder"

View File

@ -1,10 +1,27 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout 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" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/recorder_holder" android:id="@+id/recorder_holder"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<com.visualizer.amplitude.AudioRecordView
android:id="@+id/visualizer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/recording_duration"
android:layout_marginTop="@dimen/activity_margin"
android:layout_marginEnd="@dimen/activity_margin"
android:layout_marginBottom="@dimen/activity_margin"
app:chunkAlignTo="center"
app:chunkMaxHeight="200dp"
app:chunkMinHeight="2dp"
app:chunkRoundedCorners="true"
app:chunkSoftTransition="true"
app:chunkSpace="1dp"
app:chunkWidth="3dp" />
<TextView <TextView
android:id="@+id/recording_duration" android:id="@+id/recording_duration"
android:layout_width="wrap_content" android:layout_width="wrap_content"