Closed satish-osi closed 2 years ago
Could you please enable SDK logging and share those logs? You can find the instructions on how to do that here: https://docs.microsoft.com/azure/cognitive-services/speech-service/how-to-use-logging#android
Could you please also include any logcat logs - particularly errors?
Hi @ralph-msft , PFA of logfile. logfile.txt
Case : Am installed application with above mentioned source code and clicked on play button and clicked on stop button. Collected log file and shared with you.
Please let me know if you need any additional information. Am glad to help you!
Hi @satish-osi,
I've tried running your code locally. I did so by arranging the callbacks behind buttons like so:
findViewById<Button>(R.id.buttonCreateSynth)?.let { button ->
button.setOnClickListener {
onCreateSynthesizerButtonClicked(button)
}
}
findViewById<Button>(R.id.buttonPlayVoice)?.let { button ->
button.setOnClickListener {
onSpeechButtonClicked(button)
}
}
findViewById<Button>(R.id.buttonStopVoice)?.let { button ->
button.setOnClickListener {
onStopButtonClicked(button)
}
}
I tapped the buttons in the following order:
buttonCreateSynth
EditText
that would allow for playback to go on long enoughbuttonPlayVoice
buttonStopVoice
(at this point I noticed some UI stuttering)I noticed too that if you let the audio play out, then it is possible to reproduce the TTS again.
I ended up commenting out the contents of your updateOutputMessage
method.
Since you use this to log things into the UI, and given the you are logging a lot of events, it seems like the UI thread gets spammed and then has a hard time registering the tap for the buttonStopVoice
.
Once you comment out the contents of the method updateOutputMessage
my reproduction of your code appears to run smoothly.
Hi @jpalvarezl , you are correct. But, as per your order,
If we click on buttonPlayVoice (step-3) again after step-4. "I noticed too that if you let the audio play out, then it is possible to reproduce the TTS again." This is even working fine for me , but it is starting form first word of sentence. We want to resume execution of TTS from where it is paused/stopped previously.
Let me know if you need any additional information.
PFA, of my entire sample app. https://drive.google.com/drive/folders/1VwPtVda82rLabnx7Kg6tCUtqqaD31oOp?usp=sharing
Ok, I think I understand better your use case.
The sample you are basing your code from I believe is meant to always reproduce the TTS audio from the top. In order to achieve that, it requests a new result each time and each time there is a new audio stream returned.
I modified the sample so that we keep track of the audio stream returned in the first result. Whenever we pause playback, we need to stop passing frames to the Android's AudioTrack
(for some reason, it doesn't seem to buffer while paused, but that could be a configuration issue on my side)
This function, is what you want to call when you want to start both reading from the stream and the playback. Notice that we check whether audioDataStream == null
, to see that we use the same audio stream later when we resume playback (we basically keep a reference to it, which is just one way to do it).
private fun startStreamPlaybackPressed() {
if (synthesizer == null) {
Log.e("TTS_SAMPLE", "Please initialize the speech synthesizer first")
return
}
val speakText = findViewById<EditText>(R.id.speakText)
audioTrack!!.play()
if (audioDataStream == null) {
singleThreadExecutor!!.execute { startAudioStream(speakText.text.toString()) }
} else {
synchronized(synchronizedObj) { stopped = false }
singleThreadExecutor!!.execute { readAudioData() }
}
}
You will need then these two additional functions:
private fun startAudioStream(content: String) {
synchronized(synchronizedObj) { stopped = false }
val result = synthesizer!!.StartSpeakingTextAsync(content).get()
audioDataStream = AudioDataStream.fromResult(result)
// Set the chunk size to 50 ms. 24000 * 16 * 0.05 / 8 = 2400
readAudioData()
Log.d("AUDIOTRACK", "Finished reading from audio stream result")
// audioDataStream!!.close()
}
private fun readAudioData() {
val buffer = ByteArray(2400)
while (!stopped) {
val len = audioDataStream!!.readData(buffer)
if (len == 0L) {
break
}
val bytesWritten = audioTrack!!.write(buffer, 0, len.toInt())
Log.d("AUDIOTRACK", "$bytesWritten bytes")
}
}
These will start or resume writing data from the audio stream into your AudioTrack
object.
Finally, pausing playback will look like this:
private fun pausePlayback() {
if (audioTrack != null) {
synchronized(synchronizedObj) { stopped = true }
audioTrack!!.pause()
}
}
I would also point out that this will only work once. You would need to implement the logic for when you are done with an audio stream, creating a new one (kind of like what you can see in the original android sample).
There will be a new public sample for Android that demonstrates how to pause an audio stream generated by TTS, expected to be available at the time of the Speech SDK 1.24.0 release.
Internal work item ref. 4454557.
Thank you @pankopon , This feature may give more value to mobile applications.
To be closed when the Speech SDK 1.24.0 release and updated samples (@jpalvarezl) are available.
Closed as the Speech SDK 1.24.0 has been released and samples are available (https://github.com/Azure-Samples/cognitive-services-speech-sdk/tree/master/samples/kotlin/android/tts-pause-example).
PFA of source code :
Android implementation of custom audio track as per the sample Android project provided in github. We are able to call .pause() method while TTS has speaking. But if we are pause() TTS and .play() method again called with 2 seconds delay it is not working. Once we use .pause() method if we called .play() for resume It is not working anymore. Please let us know how do fix this issue.