Use of sound files in TTS on Marshmallow (Android 6) fails with permission issues

杀马特。学长 韩版系。学妹 提交于 2021-02-07 06:48:31

问题


Using addSpeech() in android TTS, you can link a certain text to a sound file. Then, the TTS engine plays the file instead of synthesizing the sound of the text (also in question at Android TTS(Text to Speech)'s addSpeech() and speak() can't play a sound file in the external storage from marshmallow(api 23) above, with Google TTS ). This is not working in Android 6.0 with TTS version 3.9.14 (and 3.10.10). So far, I did not see ant post with an answer as to why this is not working in Android 6.0. So I thought I'll provide more data on the issue that could help someone figure out the issue. (I had added this to the question in the link above, but moderators deleted it saying this is not an answer. They did not suggest a way to add more data like this except saying ask another question. Hence this question. In reality this is additional data on the same question that is not answered yet). so here goes.

In the manifest I have provided both read and write permissions to the app using TTS (which in turn uses Media Player) to play the voice files provided.

android:targetSdkVersion="22"
...
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Note that this works fine up to Android 5.0, but fails on android 6.0 (except when files in res/raw are used as voice files). Also when it fails it seems to give slightly different error in logcat depending on whether the voice file is on internal or external storage.

  1. When the voice file in res/raw folder, TTS works fine playing the required voice file using the resource id (addSpeech (word, pkgName, resId))

  2. When the voice file is located on external storage (/storage/sdcard0/pkgName/soundFiles/.. playing using TTS gives the EACCES failure log (for both amr and mp3 files).

    09-08 16:57:17.514 1549-7830/? D/MediaPlayer: create failed: 
    java.io.FileNotFoundException: /storage/emulated/0/pkgName/soundFiles/voice1.amr: open failed: EACCES (Permission denied)
    at libcore.io.IoBridge.open(IoBridge.java:487)
    at java.io.FileInputStream.(FileInputStream.java:76)
    at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1115)
    at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1066)
    at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1003)
    at android.media.MediaPlayer.setDataSource(MediaPlayer.java:983)
    at android.media.MediaPlayer.create(MediaPlayer.java:890
    at android.speech.tts.AudioPlaybackQueueItem.run(AudioPlaybackQueueItem.java:58)
    at android.speech.tts.AudioPlaybackHandler$MessageLoop.run(AudioPlaybackHandler.java:134)
    at java.lang.Thread.run(Thread.java:818)
    Caused by: android.system.ErrnoException: open failed: EACCES (Permission denied)
    at libcore.io.Posix.open(Native Method)
    at libcore.io.BlockGuardOs.open(BlockGuardOs.java:186)
    at libcore.io.IoBridge.open(IoBridge.java:473)
    at java.io.FileInputStream.(FileInputStream.java:76)
    at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1115)
    at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1066)
    at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1003)
    at android.media.MediaPlayer.setDataSource(MediaPlayer.java:983)
    at android.media.MediaPlayer.create(MediaPlayer.java:890)
    at android.speech.tts.AudioPlaybackQueueItem.run(AudioPlaybackQueueItem.java:58)
    at android.speech.tts.AudioPlaybackHandler$MessageLoop.run(AudioPlaybackHandler.java:134)
    at java.lang.Thread.run(Thread.java:818
    
  3. When the voice file is located on internal storage (/data/.../pkgName/soundFiles/.. playing the word using TTS gives the following error log (for both amr and mp3 files).

    09-08 17:24:23.103 1549-32732/? D/MediaPlayer: create failed: 
    java.io.IOException: setDataSource failed.
    at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1120)
    at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1066)
    at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1003)
    at android.media.MediaPlayer.setDataSource(MediaPlayer.java:983)
    at android.media.MediaPlayer.create(MediaPlayer.java:890)
    at android.speech.tts.AudioPlaybackQueueItem.run(AudioPlaybackQueueItem.java:58)        
    at android.speech.tts.AudioPlaybackHandler$MessageLoop.run(AudioPlaybackHandler.java:134)
    at java.lang.Thread.run(Thread.java:818)
    

As an experiment, created a MediaPlayer object in the same class where TTS is being used and played the same sound files that are failing with TTS. They played fine without any issue. So it looks like only the instantiation of MediaPlayer within TTS is having file permission issues.

Any help is appreciated.

Edit: Please note, runtime permissions have been granted, so this is not the issue. The problem is limited to the Google Text to Speech engine. Other engines work correctly.


回答1:


I'm the guy who posted the link below you mentioned. Android TTS(Text to Speech)'s addSpeech() and speak() can't play a sound file in the external storage from marshmallow(api 23) above, with Google TTS

Thank you for all the experiments. I agree with you that the mediaplayer in TTS can't read the audio files in the internal/external storage.

At that time, I set my target device at 22 or something to avoid the issue using MODE_WORLD_READABLE. Now that it's impossible to set the target so low, the best option I can think of is to make a function that works as 'addSpeech()' yourself. It's not that hard to play an audio file instead of a certain text with MediaPlayer. The tricky part, however, is about how to deal with 'utteranceId' in your workaround if you need it.

One of the options is you place 'playSilentUtterance(final long durationInMs, final int queueMode, final String utteranceId)' in your MediaPlayer onCompleteListener so that it can trigger the utteranceId you want. You can put a very short time like 100millisec in durationInMs.

I hope this helps anyone who is stuck with the issue, and hopefully Google resolves this issue.

  • I'm asking Google to check into this issue in the link below. Please support me if you want this issue to be resolved at the api level. https://issuetracker.google.com/issues/152671139



回答2:


I think it fails because you have to add runtime permissions(like you need to ask permission while user using that feature ) in android phones above lollipop 5.1 OS,

https://developer.android.com/training/permissions/requesting.html

Check this link for the best understanding of this problem. And if need to know how it can be done simply just check this code below.

https://www.androidhive.info/2016/11/android-working-marshmallow-m-runtime-permissions/

here is the code:

if (ContextCompat.checkSelfPermission(thisActivity,
        Manifest.permission.WRITE_EXTERNAL_STORAGE)
    != PackageManager.PERMISSION_GRANTED) {

    // Should we show an explanation?
    if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
            Manifest.permission.WRITE_EXTERNAL_STORAGE)) {

        // Show an explanation to the user *asynchronously* -- don't block
        // this thread waiting for the user's response! After the user
        // sees the explanation, try again to request the permission.

    } else {

        // No explanation needed, we can request the permission.

        ActivityCompat.requestPermissions(thisActivity,
                new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE);

        // MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE is an
        // app-defined int constant. The callback method gets the
        // result of the request.
    }
}


来源:https://stackoverflow.com/questions/46127460/use-of-sound-files-in-tts-on-marshmallow-android-6-fails-with-permission-issue

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!