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"> - - + + > + + + + + + + +