B4J Question <SOLVED> Cloud Text-To-Speech - Unable to save as an MP3 file in Release mode

Ralph Parkhurst

Member
Licensed User
I am using the Cloud Text-To-Speech library here: Cloud Text-To-Speech b4xlib in a B4J project (v8.90)

After getting the sample project in the above link (post #1) working correctly, I changed one line to implement the convertToMp3 method, which is supposed to save the audio file to an MP3 file.

B4X:
Sub btnPlay_Click
    If txtSpeak.Text<>"" Then
        'cTTS.Speak(txtSpeak.Text)
        cTTS.convertTomp3(txtSpeak.Text,File.DirApp,"CloudTTS.mp3")
    End If
End Sub

This change works perfectly in Debug mode, but in Release mode the file is not created - instead the text is spoken aloud via the PC's speakers and a file is created containing the txtSpeak.text as part of the filename.

Is there a step I am missing? Any help would be warmly appreciated - thank you.
 

Ralph Parkhurst

Member
Licensed User
I have now identified that the issue was that the JobDone routine was not being called within the library itself, when running in release mode. . I have been able to get it working properly through some changes to two subroutines:

Sub JobDone:
Sub JobDone (Job As HttpJob)

    If Job.Tag="ListAllAvailableVoices" Then
        'For listing the available voices
        If Job.Success Then
            Try
                Dim jsonParser As JSONParser
                jsonParser.Initialize(Job.GetString)
                Dim mapVoiceData As Map=jsonParser.NextObject
                CallSubDelayed2(CloudTTS_Parent, CloudTTS_Event_Name & "_AvailableVoices", mapVoiceData)
            Catch
                CallSubDelayed2(CloudTTS_Parent, CloudTTS_Event_Name & "_AvailableVoices", Null)
            End Try
        Else
            CallSubDelayed2(CloudTTS_Parent, CloudTTS_Event_Name & "_AvailableVoices", Null)
        End If
    Else If Job.Tag="speak" Then
        'For speaking the text
        If Job.Success Then
            Try
                Dim jsonParser As JSONParser
                jsonParser.Initialize(Job.GetString)
                Dim strAudio As String=jsonParser.NextObject.Get("audioContent")
                
                Dim su As StringUtils ' jStringUtils
                Dim decoded() As Byte = su.DecodeBase64(strAudio)            'Now save the mp3
        
                #IF B4A
                    Dim out As OutputStream = File.OpenOutput(File.DirInternal, "CloudTTS.mp3", False)
                #Else IF B4J
                Dim out As OutputStream = File.OpenOutput(File.DirApp, getFileName(strPrevToSpeak)&" "&LanguageCode&"-"&LanguageName&".mp3", False)
                #End If
                out.WriteBytes(decoded, 0, decoded.Length)
                out.Close
                
                'Now, play the audio
                #IF B4A
                    audio.Load(File.DirInternal, "CloudTTS.mp3")
                #Else IF B4J
                audio=AudioClip_Static.NewAudioClip2(File.DirApp, getFileName(strPrevToSpeak)&" "&LanguageCode&"-"&LanguageName&".mp3")
                    audio.SetCompleteListener(Me, "audio")
                #End If
                audio.Play
                CallSubDelayed(CloudTTS_Parent, CloudTTS_Event_Name & "_StartedSpeaking")
            Catch
                CallSubDelayed2(CloudTTS_Parent, CloudTTS_Event_Name & "_onError", LastException.Message)
            End Try
        Else
            CallSubDelayed2(CloudTTS_Parent, CloudTTS_Event_Name & "_onError", Job.ErrorMessage)
        End If
    Else If Job.Tag="ConvertToMP3" Then
        'For creating an MP3
        If Job.Success Then
            Try
                Dim jsonParser As JSONParser
                jsonParser.Initialize(Job.GetString)
                Dim strAudio As String=jsonParser.NextObject.Get("audioContent")
                
                Dim su As StringUtils ' jStringUtils
                Dim decoded() As Byte = su.DecodeBase64(strAudio)            'Now save the mp3
        
                Dim out As OutputStream = File.OpenOutput(fd, fn, False)
                out.WriteBytes(decoded, 0, decoded.Length)
                out.Close
            Catch
                CallSubDelayed2(CloudTTS_Parent, CloudTTS_Event_Name & "_onError", LastException.Message)
            End Try
        Else
            CallSubDelayed2(CloudTTS_Parent, CloudTTS_Event_Name & "_onError", Job.ErrorMessage)
        End If
        audio_Complete
    End If
    Job.Release
End Sub

Sub ConvertToMP3:
Sub ConvertToMP3(toSpeak As String, fileDir As String, fileName As String)
    fd=fileDir
    fn=fileName
    strPrevToSpeak=toSpeak
    Dim mapReq As Map:mapReq.Initialize
        
    mapReq.Put("audioConfig", CreateMap("audioEncoding":"MP3", "effectsProfileId":"large-home-entertainment-class-device", "speakingRate":speed))
    mapReq.Put("input", CreateMap("text":toSpeak))
    mapReq.Put("voice", CreateMap("languageCode":LanguageCode, "name":LanguageName, "ssmlGender":LanguageGender))
    
    Dim json As JSONGenerator:json.Initialize(mapReq)
    
    Dim job As HttpJob:job.Initialize("speak", Me) 'name is empty as it is no longer needed
    job.Tag="ConvertToMP3"
    job.PostString("https://texttospeech.googleapis.com/v1/text:synthesize?key="&API_KEY, json.ToString)
    job.GetRequest.SetContentType("application/json; charset=utf-8")
End Sub

I present this workaround in case any one else has the same problem. This worked for me (and it also allowed me to implement the effectsProfileID and speakingRate API parameters). However there is quite possibly a simpler or more elegant solution.
 
Upvote 0
Top