在Marshmallow(Android 6)上使用TTS中的声音文件失败,并出现权限问题

时间:2017-09-09 05:35:37

标签: android media-player text-to-speech android-6.0-marshmallow google-text-to-speech

在android TTS中使用addSpeech(),您可以将某个文本链接到声音文件。然后,TTS引擎播放文件而不是合成文本的声音(也在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处有问题)。这在使用TTS版本3.9.14(和3.10.10)的Android 6.0中不起作用。 到目前为止,我没有看到ant post的答案,为什么这在Android 6.0中不起作用。所以我想我会提供更多有关这个问题的数据,可以帮助有人找出问题所在。 (我已将此添加到上面链接中的问题,但主持人删除了它说这不是答案。他们没有建议添加更多这样的数据,除了说另一个问题。因此这个问题。实际上这是关于尚未回答的同一问题的其他数据)。所以这里。

在清单中,我使用TTS(后者又使用Media Player)为应用程序提供了读取和写入权限,以播放所提供的语音文件。

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

请注意,这适用于Android 5.0,但在Android 6.0上失败(除非将res / raw中的文件用作语音文件)。此外,当它失败时,似乎在logcat中给出略有不同的错误,具体取决于语音文件是在内部存储还是外部存储。

  1. 当res / raw文件夹中的语音文件时,TTS使用资源ID(addSpeech(word,pkgName,resId))正常播放所需的语音文件

  2. 当语音文件位于外部存储器上时(/ storage / sdcard0 / pkgName / soundFiles / ..使用TTS播放会给出EACCES失败日志(对于amr和mp3文件)。

    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. 当语音文件位于内部存储器上时(/ data /.../pkgName/soundFiles/ ..使用TTS播放单词会出现以下错误日志(对于amr和mp3文件)。

    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)
    
  4. 作为一项实验,在使用TTS的同一个类中创建了一个MediaPlayer对象,并播放了与TTS失败的相同声音文件。没有任何问题他们打得很好。所以看起来只有TTS中MediaPlayer的实例化才有文件权限问题。

    感谢任何帮助。

    编辑:请注意,已授予运行时权限,因此这不是问题。问题仅限于Google Text to Speech引擎。其他引擎工作正常。

2 个答案:

答案 0 :(得分:0)

我是发布您提到的以下链接的人。 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

感谢您的所有实验。我同意您的意见,即TTS中的媒体播放器无法读取内部/外部存储中的音频文件。

那时,我使用MODE_WORLD_READABLE将目标设备设置为22或类似的值以避免出现此问题。 既然不可能将目标设置得如此之低,那么我能想到的最好的选择就是自己创建一个功能为“ addSpeech()”的函数。 使用MediaPlayer播放音频文件而不是播放特定文本并不难。但是,棘手的部分是有关在需要时如何处理'utteranceId'的问题。

其中一个选项是将“ playSilentUtterance(final long durationInMs,final int queueMode,final String utteranceId)”放置在MediaPlayer的onCompleteListener中,以便它可以触发所需的utteranceId。您可以在durationInMs中放置一个非常短的时间,例如100millisec。

我希望这对遇到问题的所有人有所帮助,并希望Google解决该问题。

答案 1 :(得分:-1)

我认为它失败是因为你必须在棒棒糖5.1操作系统上面的Android手机中添加运行时权限(就像你需要在用户使用该功能时询问权限),

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

检查此链接以便最好地了解此问题。 如果需要知道如何完成,只需查看下面的代码即可。

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

这是代码:

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.
    }
}