Skip to content

Commit

Permalink
Harmonize with application (#2)
Browse files Browse the repository at this point in the history
* ⚡ Improve performance of play view

* 🍻 Prevent user from recording when playing

Improve ui also

* 🐛 Fix recording lagging when multiple instances
  • Loading branch information
Haransis authored Jan 17, 2021
1 parent 2675dc4 commit 25529e2
Show file tree
Hide file tree
Showing 21 changed files with 452 additions and 98 deletions.
16 changes: 16 additions & 0 deletions .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion app/src/main/java/fr/haran/example/PlayActivity.kt

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions app/src/main/java/fr/haran/example/RecActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ class RecActivity : AppCompatActivity(), DefaultRecorderController.InformationRe
recorderController?.prepareRecorder()
}

//TODO have the amplitudes used in player take the same format as the recorder

override fun onDestroy() {
super.onDestroy()
recorderController?.let {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,35 +15,38 @@ class DefaultPlayerController(var controllingView: ControllingView):
private val mediaPlayer = MediaPlayer()
private val handler = Handler()
private var isPrepared = false
private lateinit var runnable: Runnable
private var runnable: Runnable = object: Runnable {
override fun run() {
controllingView.updatePlayerPercent(
mediaPlayer.duration,
mediaPlayer.currentPosition
)
playerListener.onDurationProgress(
this@DefaultPlayerController,
mediaPlayer.duration,
mediaPlayer.currentPosition
)

if (mediaPlayer.isPlaying)
handler.postDelayed(this, INTERVAL)
}
}
private lateinit var playerListener: PlayerListener

override fun preparePlayer(){
controllingView.attachPlayerController(this)
mediaPlayer.prepareAsync()
mediaPlayer.setOnPreparedListener{ isPrepared = true }
runnable = object: Runnable {
override fun run() {
controllingView.updatePlayerPercent(
mediaPlayer.duration,
mediaPlayer.currentPosition
)
playerListener.onDurationProgress(
this@DefaultPlayerController,
mediaPlayer.duration,
mediaPlayer.currentPosition
)

if (mediaPlayer.isPlaying)
handler.postDelayed(this, INTERVAL)
}
}
mediaPlayer.setOnCompletionListener {
playerListener.onComplete(this)
handler.removeCallbacks(runnable)
}
}

fun attachPlayerController(){
controllingView.attachPlayerController(this)
}

override fun isPlaying(): Boolean{
return mediaPlayer.isPlaying
}
Expand Down Expand Up @@ -82,11 +85,8 @@ class DefaultPlayerController(var controllingView: ControllingView):
}

override fun toggle() {
if(mediaPlayer.isPlaying){
pause()
} else {
play()
}
if (mediaPlayer.isPlaying) pause()
else play()
}

override fun destroyPlayer() {
Expand All @@ -96,7 +96,7 @@ class DefaultPlayerController(var controllingView: ControllingView):
}

private fun resetMediaPlayer() {
//if (mediaPlayer.isPlaying) mediaPlayer.stop()
if (mediaPlayer.isPlaying) mediaPlayer.stop()
mediaPlayer.reset()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class DefaultRecorderController(var recPlayerView: RecPlayerView, var defaultPat
private var playerController: DefaultPlayerController = DefaultPlayerController(recPlayerView).apply {
setPlayerListener()
}

private var runnable = object: Runnable {
override fun run() {
val currentTime = SystemClock.uptimeMillis()
Expand Down Expand Up @@ -115,7 +116,8 @@ class DefaultRecorderController(var recPlayerView: RecPlayerView, var defaultPat
RECORDER_SAMPLERATE, RECORDER_CHANNELS,
RECORDER_AUDIO_ENCODING, bufferSize
)
setAudioEffects()
// This call was too long for just a recording
//setAudioEffects()
recorder!!.startRecording()
isRecording = true
recordingThread.start()
Expand Down Expand Up @@ -198,20 +200,19 @@ class DefaultRecorderController(var recPlayerView: RecPlayerView, var defaultPat
} catch (e: IOException) {
e.printStackTrace()
}
handler.post { recPlayerView.onRecordComplete() }
rawToWave(File(pcmPath), File(wavPath))
playerController.addAudioFileUri(recPlayerView.context, Uri.parse("file://$wavPath"))
handler.post { recPlayerView.onRecordComplete() }
}

override fun stopRecording(delete: Boolean) {
Log.d(TAG, "stopRecording: $amplitudes")
if (delete)
deleteExpiredRecordings()

if (isRecording)
recorderListener.onComplete(this)

//recordingThread.interrupt()

recorder?.let {
isRecording = false
it.stop()
Expand Down Expand Up @@ -293,6 +294,13 @@ class DefaultRecorderController(var recPlayerView: RecPlayerView, var defaultPat
}
return bytes
}

fun restoreStateOnNewRecView(){
playerController.controllingView = recPlayerView
playerController.attachPlayerController()
recPlayerView.setAmplitudes(amplitudes.toTypedArray())
recPlayerView.onRecordComplete()
}

@Throws(IOException::class)
private fun writeInt(output: DataOutputStream, value: Int) {
Expand Down
14 changes: 7 additions & 7 deletions soundwave/src/main/java/fr/haran/soundwave/ui/PlayerView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ open class PlayerView(context: Context, attrs: AttributeSet) : ConstraintLayout(
else (duration - currentPosition).toLong() )
}

override fun attachPlayerController(controller: PlayerController){
playerController = controller
override fun attachPlayerController(playerController: PlayerController){
this.playerController = playerController
}

@SuppressLint("InflateParams")
Expand All @@ -90,8 +90,8 @@ open class PlayerView(context: Context, attrs: AttributeSet) : ConstraintLayout(
soundWaveView = view.findViewById<SoundWaveView>(
R.id.sound_wave_view
).apply{
playedColor = secondaryColor
nonPlayedColor = mainColor
playedColor = mainColor
nonPlayedColor = secondaryColor
isDb = this@PlayerView.isDb
setOnTouchListener(this@PlayerView)
}
Expand All @@ -113,13 +113,13 @@ open class PlayerView(context: Context, attrs: AttributeSet) : ConstraintLayout(

private fun setSoundWaveColor(){
if (this::soundWaveView.isInitialized){
soundWaveView.nonPlayedColor = mainColor
soundWaveView.playedColor = secondaryColor
soundWaveView.nonPlayedColor = secondaryColor
soundWaveView.playedColor = mainColor
}
}

override fun setAmplitudes(amplitudes: Array<Double>){
soundWaveView.amplitudes = amplitudes
soundWaveView.amplitudes = amplitudes.toList()
}

override fun <T>setText(title: T){
Expand Down
55 changes: 48 additions & 7 deletions soundwave/src/main/java/fr/haran/soundwave/ui/RecPlayerView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,28 @@ import android.app.Activity
import android.content.Context
import android.content.pm.PackageManager
import android.content.res.ColorStateList
import android.graphics.drawable.Drawable
import android.icu.text.SimpleDateFormat
import android.os.CountDownTimer
import android.util.AttributeSet
import android.util.Log
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.widget.ImageView
import android.widget.ProgressBar
import android.widget.TextView
import androidx.annotation.ColorRes
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.Group
import androidx.core.app.ActivityCompat
import androidx.core.content.ContentProviderCompat.requireContext
import androidx.core.content.ContextCompat
import androidx.vectordrawable.graphics.drawable.Animatable2Compat
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.shape.CornerFamily
import com.google.android.material.shape.ShapeAppearanceModel
import fr.haran.soundwave.R
import fr.haran.soundwave.controller.PlayerController
import fr.haran.soundwave.controller.RecorderController
Expand All @@ -40,10 +48,12 @@ ControllingView, View.OnTouchListener{
private lateinit var timerTv: TextView
private lateinit var recView: RecView
private lateinit var recordFab: FloatingActionButton
private lateinit var stopFab: FloatingActionButton
private lateinit var stopText: TextView
private lateinit var playFab: FloatingActionButton
private lateinit var recordAgainFab: FloatingActionButton
private lateinit var controlButtons: Group
private lateinit var loader: ProgressBar
private lateinit var loader: ImageView
private lateinit var recorder: RecorderController
private lateinit var player: PlayerController
private var alreadyRecorded = false
Expand Down Expand Up @@ -92,22 +102,31 @@ ControllingView, View.OnTouchListener{
}
}
}
stopFab = view.findViewById<FloatingActionButton>(R.id.stop).apply{
imageTintList = ColorStateList.valueOf(recordColor)
setOnClickListener {
recorder.stopRecording(false)
}
}
stopText = view.findViewById(R.id.stop_text)
controlButtons = view.findViewById(R.id.control_buttons)
recordAgainFab = view.findViewById<FloatingActionButton>(R.id.record_again).apply {
imageTintList = ColorStateList.valueOf(recordColor)
foregroundTintList = ColorStateList.valueOf(recordColor)
setOnClickListener {
recorder.toggle()
alreadyRecorded = false
if (::player.isInitialized && player.isPlaying())
player.destroyPlayer()
if (::player.isInitialized) player.destroyPlayer()
recorder.toggle()
}
}
playFab = view.findViewById<FloatingActionButton>(R.id.play).apply {
imageTintList = ColorStateList.valueOf(recordColor)
foregroundTintList = ColorStateList.valueOf(recordColor)
setOnClickListener {
player.toggle()
if (::player.isInitialized){
player.toggle()
toggleRecordAgain(player.isPlaying())
}
}
}
timerTv = view.findViewById<TextView>(R.id.timer).apply {
Expand All @@ -119,6 +138,12 @@ ControllingView, View.OnTouchListener{
setRecViewSamples()
}

private fun toggleRecordAgain(deactivate: Boolean) {
recordAgainFab.imageTintList = ColorStateList.valueOf(if (deactivate) playColor else recordColor)
recordAgainFab.foregroundTintList = ColorStateList.valueOf(if (deactivate) playColor else recordColor)
recordAgainFab.isClickable = !deactivate
}

private fun setRecViewColor() {
if (this::recView.isInitialized){
recView.recordColor = this.recordColor
Expand Down Expand Up @@ -156,6 +181,10 @@ ControllingView, View.OnTouchListener{
override fun setAmplitudes(amplitudes: Array<Double>) {
}

fun setAmplitudes(amplitudes: Array<Int>) {
recView.drawAmplitudes(amplitudes)
}

override fun onPlay() {
playFab.setImageResource(R.drawable.ic_pause)
recView.isPlaying = true
Expand All @@ -178,21 +207,33 @@ ControllingView, View.OnTouchListener{

fun addLoader(){
recordFab.visibility = View.INVISIBLE
controlButtons.visibility = View.GONE
loader.visibility = View.VISIBLE
val animated = AnimatedVectorDrawableCompat.create(context, R.drawable.loader)
animated?.registerAnimationCallback(object : Animatable2Compat.AnimationCallback() {
override fun onAnimationEnd(drawable: Drawable?) {
loader.post { animated.start() }
}
})
}

fun onRecordComplete() {
countDown.cancel()
if (::countDown.isInitialized)
countDown.cancel()
recordFab.setImageResource(R.drawable.ic_check)
stopFab.visibility = View.GONE
stopText.visibility = View.GONE
recordFab.visibility = View.VISIBLE
controlButtons.visibility = View.VISIBLE
loader.visibility = View.GONE
alreadyRecorded = true
}

fun onStart() {
recordFab.setImageResource(R.drawable.ic_stop)
recordFab.visibility = View.INVISIBLE
controlButtons.visibility = View.GONE
stopFab.visibility = View.VISIBLE
stopText.visibility = View.VISIBLE
}

fun startCountDown(){
Expand Down
12 changes: 10 additions & 2 deletions soundwave/src/main/java/fr/haran/soundwave/ui/RecView.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package fr.haran.soundwave.ui

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
Expand All @@ -14,7 +13,7 @@ import kotlin.properties.Delegates


private const val TAG = "RecView"
private const val MAX_AMPLITUDE = -Short.MIN_VALUE*2
const val MAX_AMPLITUDE = -Short.MIN_VALUE*2
private const val STROKE_WIDTH = 3F
class RecView(context: Context, attrs: AttributeSet): View(context, attrs) {

Expand Down Expand Up @@ -59,6 +58,7 @@ class RecView(context: Context, attrs: AttributeSet): View(context, attrs) {
}
}
initializePaint(recordPaint, recordColor)
playPaint.strokeWidth = STROKE_WIDTH + 0.3F //TODO choose value
initializePaint(playPaint, playColor)
}

Expand Down Expand Up @@ -125,6 +125,14 @@ class RecView(context: Context, attrs: AttributeSet): View(context, attrs) {
invalidate()
}

fun drawAmplitudes(amplitudes: Array<Int>){
waveForm.reset()
waveForm.moveTo(0F, origin.toFloat())
for (index in amplitudes.indices)
waveForm.lineTo(index * barWidth, origin + amplitudes[index] * barHeight)
invalidate()
}

fun resetAmplitudes() {
waveForm.reset()
waveForm.moveTo(0F, origin.toFloat())
Expand Down
Loading

0 comments on commit 25529e2

Please sign in to comment.