我已成功将音频文件(3gp)上传到Google-Drive。
现在我希望能够在应用程序中播放该文件。
Google Drive API仅允许获取存储在那里的文件的输入流。
输入的所有MediaPlayer功能在我的情况下都不可用,只有InputSteam:
我知道我可以将文件从Google-Drive保存到缓存并播放,但我想避免存储处理,并动态播放文件。
我尝试搜索此问题,但发现可能使用AudioTrack(here)。也许可以使用新的Jelly-Bean功能(显示here,来自here),但我不确定它的级别是否很低。
可悲的是,使用AudioTrack我听错了声音(噪音)。
我还注意到MediaPlayer可以选择将dataSource设置为MediaDataSource(here),但不仅我不确定如何使用它,还需要API 23及更高版本。< / p>
当然,我尝试使用Google-Drive中提供的网址,但这仅用于其他目的,并且不会定向到音频文件,因此无法使用MediaPlayer。
给定一个InputStream,是否可以使用AudioTrack或其他东西来播放音频3gp文件?
是否可能有支持库解决方案?
答案 0 :(得分:2)
如果您的minSdkVersion
为23或更高,则可以use setDataSource(MediaDataSource)
并提供您自己的abstract
MediaDataSource
class的子类。
对于旧设备,您应该能够使用从ParcelFileDescriptor
创建的管道。您将拥有一个将数据写入管道末端的线程,并将FileDescriptor
(从getFileDescriptor()
)传递给玩家端setDataSource(FileDescriptor)
。
答案 1 :(得分:1)
最简单的MediaDataSource实现示例:
import android.media.MediaDataSource;
import android.os.Build;
import android.support.annotation.RequiresApi;
import java.io.IOException;
import java.io.InputStream;
@RequiresApi(api = Build.VERSION_CODES.M)
public class InputStreamMediaDataSource extends MediaDataSource {
private InputStream is;
private long streamLength = -1, lastReadEndPosition;
public InputStreamMediaDataSource(InputStream is, long streamLength) {
this.is = is;
this.streamLength = streamLength;
if (streamLength <= 0){
try {
this.streamLength = is.available(); //Correct value of InputStream#available() method not always supported by InputStream implementation!
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public synchronized void close() throws IOException {
is.close();
}
@Override
public synchronized int readAt(long position, byte[] buffer, int offset, int size) throws IOException {
if (position >= streamLength)
return -1;
if (position + size > streamLength)
size -= (position + size) - streamLength;
if (position < lastReadEndPosition) {
is.close();
lastReadEndPosition = 0;
is = getNewCopyOfInputStreamSomeHow();//new FileInputStream(mediaFile) for example.
}
long skipped = is.skip(position - lastReadEndPosition);
if (skipped == position - lastReadEndPosition) {
int bytesRead = is.read(buffer, offset, size);
lastReadEndPosition = position + bytesRead;
return bytesRead;
} else {
return -1;
}
}
@Override
public synchronized long getSize() throws IOException {
return streamLength;
}
}
要使用API&gt; = 23,您必须提供streamLength
值,如果(当)MediaPlayer返回 - 即position < lastReadEndPosition
,您必须知道如何创建{的新副本{1}}。
用法示例:
你必须创建Activity,初始化InputStream
类(有很多文件播放的例子)并且放置以下代码而不是旧的MediaPlayer
player.setDataSource("/path/to/media/file.3gp")
如果您的文件是Google云端硬盘上的对象if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
File file = new File("/path/to/media/file.3gp");//It is just an example! If you have real file on the phone memory, you don't need to wrap it to the InputStream to play it in MediaPlayer!
player.setDataSource(new InputStreamMediaDataSource(new FileInputStream(file), file.length()));
} else
player.setDataSource(this, mediaUri);
而com.google.api.services.drive.model.File
则可以
com.google.api.services.drive.Drive drive
在InputStream is = drive.getRequestFactory().buildGetRequest(new GenericUrl(file.getDownloadUrl())).execute().getContent();
的情况下,我必须在Android设备的本地主机上设置HTTP服务器(通过NanoHTTPd)并通过uri传输通过此服务器到MediaPlayer的字节流 - { {1}}
答案 2 :(得分:0)
对于任何对使用MediaDataSource实现感兴趣的人,我创建了一个可以预读并缓存数据缓冲区的人。它适用于任何InputStream,我主要创建它用于使用JCIFS SmbFile从网络文件中读取。
您可以在https://github.com/SteveGreatApe/BufferedMediaDataSource
找到它答案 3 :(得分:-1)
如果您询问媒体播放器设置我们的音频路径,这段代码可能会有所帮助。
File directory = Environment.getExternalStorageDirectory();
File file = new File( directory + "/AudioRecorder" );
String AudioSavePathInDevice = file.getAbsolutePath() + "/" + "sample.wav" ;
mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource(AudioSavePathInDevice);
mediaPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
}
mediaPlayer.start();
&#13;