diff --git a/app/build.gradle b/app/build.gradle
index ed7b587..b2c81b5 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -108,6 +108,9 @@ dependencies {
// For building media playback UIs
implementation "androidx.media3:media3-ui:$media3_version"
+ // audio mixer for karaoke
+ implementation("com.github.ZeroOneZeroR:android_audio_mixer:v1.1")
+
implementation libs.androidx.core.ktx
implementation libs.androidx.appcompat
implementation libs.material
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a263724..13931c7 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -3,6 +3,7 @@
xmlns:tools="http://schemas.android.com/tools">
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -36,27 +75,74 @@ class KaraokePlayerActivity : WokaBaseActivity() {
insets
}
+ window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
+
val windowInsetsController =
WindowCompat.getInsetsController(window, window.decorView)
windowInsetsController.hide(WindowInsetsCompat.Type.systemBars())
karaokePlayerData = intent.getParcelableExtra(EXTRA_KARAOKE_DATA)
+ networkCallback = object : ConnectivityManager.NetworkCallback(){
+ override fun onAvailable(network: Network) {
+ super.onAvailable(network)
+ runOnUiThread {
+ if (playbackState == PlayBackState.STOPPED){
+ binding.playerView.show()
+ binding.errorView.hide()
+ playVideo()
+ }
+ }
+ }
+ }
+
player = ExoPlayer.Builder(this).build()
binding.playerView.player = player
+ recordingState = RecordingState.NOT_RECORDING
+ recordingOutputPath = "${externalCacheDir?.absolutePath}/karaoke.3gp"
+
+ addListeners()
+
playVideo()
initViews()
clickEvents()
+ registerLaunchers()
+
+ }
+
+ override fun onStart() {
+ super.onStart()
+ if (player?.isPlaying == false){
+ player?.play()
+ }
+ }
+
+ override fun onStop() {
+ super.onStop()
+ if (player?.isPlaying == true){
+ player?.pause()
+ }
}
override fun onDestroy() {
super.onDestroy()
+ window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
+
player?.stop()
player?.release()
+
+ recorder?.release()
+
+ audioPlayer?.release()
+ audioPlayer = null
+
+ (getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager).unregisterNetworkCallback(
+ networkCallback
+ )
}
private fun initViews(){
@@ -70,6 +156,77 @@ class KaraokePlayerActivity : WokaBaseActivity() {
playerView.findViewById(R.id.player_controller_close_btn).setOnClickListener {
onBackPressedDispatcher.onBackPressed()
}
+
+ retryBtn.setOnClickListener {
+ binding.playerView.show()
+ binding.errorView.hide()
+ playVideo()
+ }
+
+ closeBtn.setOnClickListener {
+ onBackPressedDispatcher.onBackPressed()
+ }
+
+ recordBtn.setOnClickListener {
+ startStopRecording()
+ }
+
+ audioBtn.setOnClickListener {
+ playStopPlayingAudio()
+ }
+ }
+ }
+
+ private fun registerLaunchers(){
+ permissionLauncher = registerForActivityResult(
+ ActivityResultContracts.RequestPermission()
+ ) { isGranted ->
+ if (isGranted) {
+ startStopRecording()
+ }else{
+ toast(getString(R.string.permission_deniedd))
+ }
+ }
+ }
+
+ private fun playStopPlayingAudio(){
+ when (recordingState) {
+ RecordingState.NOT_RECORDING -> {
+ if (audioPlayer != null){
+ audioPlayer?.release()
+ audioPlayer = null
+ }
+
+ audioPlayer = MediaPlayer().apply {
+ try {
+ setDataSource(this@KaraokePlayerActivity, Uri.parse(recordingOutputPath))
+ prepare()
+ start()
+
+ recordingState = RecordingState.PLAYING_AUDIO
+
+ setOnCompletionListener {
+ audioPlayer?.release()
+ audioPlayer = null
+
+ recordingState = RecordingState.NOT_RECORDING
+ }
+ }catch (e: Exception) {
+ Log.d(TAG, "setupAudioPlayer: $e")
+ toast(getString(R.string.something_went_wrong))
+ }
+ }
+ }
+ RecordingState.RECORDING -> {
+ toast(getString(R.string.recording_audio))
+ }
+ RecordingState.PLAYING_AUDIO -> {
+ if (audioPlayer?.isPlaying == true){
+ audioPlayer?.pause()
+ }else{
+ audioPlayer?.start()
+ }
+ }
}
}
@@ -81,4 +238,72 @@ class KaraokePlayerActivity : WokaBaseActivity() {
player?.play()
}
+ private fun addListeners(){
+ player?.addListener(object : Player.Listener{
+ override fun onIsPlayingChanged(isPlaying: Boolean) {
+ super.onIsPlayingChanged(isPlaying)
+ playbackState = if (isPlaying){
+ binding.playerView.show()
+ binding.errorView.hide()
+ PlayBackState.PLAY
+ }else{
+ PlayBackState.PAUSED
+ }
+ }
+
+ override fun onPlayerError(error: PlaybackException) {
+ super.onPlayerError(error)
+ playbackState = PlayBackState.STOPPED
+ binding.playerView.hide()
+ binding.errorView.show()
+ }
+ })
+
+ (getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager).registerNetworkCallback(
+ NetworkRequest.Builder()
+ .build(),
+ networkCallback
+ )
+ }
+
+ private fun startStopRecording() {
+ if (ActivityCompat.checkSelfPermission(
+ this,
+ Manifest.permission.RECORD_AUDIO
+ ) != PackageManager.PERMISSION_GRANTED
+ ) {
+ permissionLauncher.launch(Manifest.permission.RECORD_AUDIO)
+ return
+ }
+
+ if (recordingState == RecordingState.NOT_RECORDING){
+ recorder = MediaRecorder().apply {
+ setAudioSource(MediaRecorder.AudioSource.MIC)
+ setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP)
+ setOutputFile(recordingOutputPath)
+ setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB)
+
+ try {
+ prepare()
+ start()
+ toast(getString(R.string.recording_started))
+ recordingState = RecordingState.RECORDING
+ } catch (e: Exception) {
+ toast(getString(R.string.something_went_wrong))
+ }
+ }
+ }else if (recordingState == RecordingState.RECORDING){
+ stopRecording()
+ }
+ }
+
+ private fun stopRecording() {
+ recorder?.apply {
+ stop()
+ release()
+ recordingState = RecordingState.NOT_RECORDING
+ toast(getString(R.string.recording_stopped))
+ }
+ recorder = null
+ }
}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_karaoke_playerr.xml b/app/src/main/res/layout/activity_karaoke_playerr.xml
index 5b80706..fa55911 100644
--- a/app/src/main/res/layout/activity_karaoke_playerr.xml
+++ b/app/src/main/res/layout/activity_karaoke_playerr.xml
@@ -7,13 +7,110 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".karaoke.player.KaraokePlayerActivity">
-
-
+
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
SING AGAIN
SING
SING NOW
+ Start Recording
+ Download Recording
+ Play Recording
+ Permission Denied.
+ Recording Started
+ Recording Stopped.
+ Recording
+ No recording found
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index 5f9745f..a916c7c 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -19,6 +19,9 @@ dependencyResolutionManagement {
maven {
url 'https://mvn.jwplayer.com/content/repositories/releases/'
}
+ maven{
+ url = uri("https://jitpack.io")
+ }
}
}