I have an app that in an activity i do heavy animations and play sound i used the below code to play the sound
var musicThread:Thread? = null
fun playSound(sound:Uri) {
musicThread = Thread(Runnable {
try {
sharedPlayer.reset()
sharedPlayer = MediaPlayer.create(MyApplication.appContext,sound)
sharedPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
// sharedPlayer.prepare()
sharedPlayer.setVolume(1f, 1f)
sharedPlayer.setLooping(false)
sharedPlayer.start()
sharedPlayer.setOnCompletionListener {
it.reset()
}
} catch (e: Exception) {
e.printStackTrace()
}
runOnUiThread {
}
})
musicThread?.start()
}
fun stopSound() {
try {
if (sharedPlayer.isPlaying()) {
sharedPlayer.stop()
}
musicThread?.stop()
} catch (e: Exception) {
e.printStackTrace()
}
}
Is there any problem with it ? BTW i call playSound many times with different sound files one by one
Related
I am try to cancel to api request if user calls api to fast then only the latest api should return the result all previous requests should be discarded but this isn't working anyone knows the solution please help thanks
class CartViewModel(val store: Account) : BaseViewModel() {
private var requestCalculation: Job? = null
fun recalculate() {
requestCalculation.let {
if (it != null) {
if (it.isActive) {
requestCalculation!!.cancel()
}
}
}
requestCalculation = viewModelScope.launch(Dispatchers.IO) {
isLoading.postValue(true)
try {
val order = CCOrderManager.shared.calculateTaxesAndApplyRewards(store.id)
refreshOrder()
} catch (e: Exception) {
exception.postValue(e.localizedMessage ?: e.toString())
}
}
}
}
The order of cancellation and execution is wrong. When the function starts, requestCalculation is null, so it cannot be canceled. Make sure you start first the coroutine and cancel it later. For example:
private var requestCalculation: Job? = null
fun recalculate() {
requestCalculation = viewModelScope.launch(Dispatchers.IO) {
delay(10_000)
// do your work...
}
// now the job can be canceled
requestCalculation?.cancel()
}
Adding a check after api call this.isActive {return#launch} finally worked for me...
fun recalculate() {
calculationRequest?.cancel()
isLoading.postValue(true)
calculationRequest = viewModelScope.launch(Dispatchers.IO) {
try {
val order =
CCOrderManager.shared.calculateTaxesAndApplyRewards(store.id)
// this check is the solution *******
if (!this.isActive) {return#launch}
val catalog = CatalogManager.shared().catalog
} catch (e: Exception) {
}
}
}
There are already several questions on this topic, but I couldn't get the answer that I want.
So, I would try to provide my minimal test case here, in that case it might help others in the future.
The basic UI look as above, to reproduce the test case, firstly, we should put a MP3 file into local directory, named it as recording1.mp3.
Then click the PLAY button to play the recording1.mp3, when the mp3 is playing, click START button to start recording and click STOP to finish recording.
The core logic would looks like:
button_start_recording.setOnClickListener {
if (ContextCompat.checkSelfPermission
...
} else {
mediaRecorder?.setAudioSource(MediaRecorder.AudioSource.MIC)
mediaRecorder?.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
mediaRecorder?.setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
mediaRecorder?.setOutputFile(output)
startRecording()
}
}
private fun startRecording() {
try {
mediaRecorder?.prepare()
mediaRecorder?.start()
state = true
Toast.makeText(this, "Recording started!", Toast.LENGTH_SHORT).show()
} catch (e: IllegalStateException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
}
}
private fun startPlaying() {
try {
thread {
val playSource =
Environment.getExternalStorageDirectory().absolutePath + "/recording1.mp3"
mediaPlayer?.setDataSource(playSource)
mediaPlayer?.prepare()
mediaPlayer?.start()
}
} catch (e: IllegalStateException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
}
}
I wanna get the record that would mix the background music as the recording1.mp3 was playing and the audio was recorded. But what I got was only the recording1.mp3 sound.
I Think,change your mediaRecorder?.setoutFormat to
mediaRecorder?.setOutputFormat(MediaRecorder.OutputFormat.MPEG_2_TS)
Or
mediaRecorder?.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP)
prepare your MediaPlayer mediaPlayer?.prepare() before starting of your recording
And, play your Background music (with volume as you want) and start the recorder .
May it Works. Thanks!
During my application execution, how can I get EMUI version?
Is there any system method to get EMUI version?
It is possible through accessing system properties like:
#SuppressLint("PrivateApi")
private fun Any?.readEMUIVersion() : String {
try {
val propertyClass = Class.forName("android.os.SystemProperties")
val method: Method = propertyClass.getMethod("get", String::class.java)
var versionEmui = method.invoke(propertyClass, "ro.build.version.emui") as String
if (versionEmui.startsWith("EmotionUI_")) {
versionEmui = versionEmui.substring(10, versionEmui.length)
}
return versionEmui
} catch (e: ClassNotFoundException) {
e.printStackTrace()
} catch (e: NoSuchMethodException) {
e.printStackTrace()
} catch (e: IllegalAccessException) {
e.printStackTrace()
} catch (e: InvocationTargetException) {
e.printStackTrace()
}
return ""
}
However, this is a private Api and if it is not suitable in your case, you can possibly use this workaround (would work for EMUI 9 and 10, however definitely wouldn't for EMUI 5 or below (~android 7)):
#TargetApi(3)
fun Any?.extractEmuiVersion() : String {
return try {
val line: String = Build.DISPLAY
val spaceIndex = line.indexOf(" ")
val lastIndex = line.indexOf("(")
if (lastIndex != -1) {
line.substring(spaceIndex, lastIndex)
} else line.substring(spaceIndex)
} catch (e: Exception) { "" }
}
Any suggestions how to improve the answer are highly appreciated!
I'm new to coroutines and having a hard time figuring out how to correctly wrap an existing callback in a coroutine.
My goal is to be able to do the following:
lifecycleScope.launch {
withContext(Dispatchers.Main) {
val theResult = getPreRollAd() //1. call this suspending func and wait for result
doSomethingWithResult(theResult) //2. now that the result is returned from AdsWizz API (below), do something with it
}
}
Here is the AdsWizz API call that I'd like to "wrap":
val adReqInterface: AdRequestHandlerInterface = object :
AdRequestHandlerInterface {
override fun onResponseError(error: AdswizzSDKError) {
Timber.e("onResponseError $error")
}
override fun onResponseReady(adResponse: AdResponse) {
Timber.d( "onResponseReadySingleAd")
//this contains the url to the ad, title, etc..
!!!*** I WANT TO RETURN THE adResponse.mediaFile?.source string back to "theResult" variable above (in lifecycleScope.launch {.... )
}
}
try {
AdswizzSDK.getAdsLoader().requestAd(adReqParams, adReqInterface)
} catch (e: IllegalArgumentException) {
Timber.d( "IllegalArgumentException")
} catch (e: SecurityException) {
Timber.d( "SecurityException")
} catch (e: Exception) {
Timber.d( "other exception")
e.printStackTrace()
}
I've tried using suspendCoroutine {... to wrap but nothing is working. Really appreciate someones help re the right way to achieve this.
the right way to do it is to use suspendCancellableCoroutine. It can return a result or can be cancelled with an exception.
suspend fun getPreRollAd(): AdResponse {
return suspendCancellableCoroutine {
...
val adReqInterface: AdRequestHandlerInterface = object : AdRequestHandlerInterface {
override fun onResponseError(error: AdswizzSDKError) {
Timber.e("onResponseError $error")
it.cancel(error)
}
override fun onResponseReady(adResponse: AdResponse) {
Timber.d( "onResponseReadySingleAd")
it.resume(adResponse)
}
}
AdswizzSDK.getAdsLoader().requestAd(adReqParams, adReqInterface)
}
}
viewModelScope.launch {
val result = try {
getPreRollAd()
} catch(e: Throwable) {
null
}
...
}
I have developed Video Call but currently facing one issue of displaying user preview(own preview: Currently I have used SurfaceView to display this preview code).
Pjsip library itself using Camera API to sending frames to other user.
There is a PjCamera class in Android. Anyone know how to use that class to dispaly your own preview?
======EDIT======
if (SipManager.currentCall != null &&
SipManager.currentCall?.mVideoPreview != null) {
if (videoPreviewActive) {
Log.d(TAG, "$TAG = if")
val vidWH = VideoWindowHandle()
vidWH.handle?.setWindow(holder.surface)
val vidPrevParam = VideoPreviewOpParam()
vidPrevParam.window = vidWH
try {
SipManager.currentCall?.mVideoPreview?.start(vidPrevParam)
} catch (e: Exception) {
println(e)
}
} else {
Log.d(TAG, "$TAG = else")
try {
SipManager.currentCall?.mVideoPreview?.stop()
} catch (e: Exception) {
println(e)
}
}
}