我想我已經找到了解決方案。如果其他感興趣的人可以自己嘗試這種方式,並使用他們的設備型號和SDK版本報告結果,我將不勝感激。
我已經看過類似的帖子,但是我認爲我會發布它,因爲它更新,似乎可以在較新版本的SDK上工作 - 到目前爲止它適用於運行Android 2.3.6的Nexus One。
該解決方案依賴於將輸入流緩衝到本地文件(我在外部存儲器上有此文件,但它也可能放置在內部存儲上),並將該文件的描述符提供給MediaPlayer實例。
在一些的AsyncTask,做AudioPlayback的doInBackground方法如下運行:
@Override
protected
Void doInBackground(LibraryItem... params)
{
...
MediaPlayer player = new MediaPlayer();
setListeners(player);
try {
_remoteStream = getMyInputStreamSomehow();
File tempFile = File.createTempFile(...);
tempFile.deleteOnExit();
_localInStream = new FileInputStream(tempFile);
_localOutStream = new FileOutputStream(tempFile);
int buffered = bufferMedia(
_remoteStream, _localOutStream, BUFFER_TARGET_SIZE // = 128KB for instance
);
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.setDataSource(_localInStream.getFD());
player.prepareAsync();
int streamed = 0;
while (buffered >= 0) {
buffered = bufferMedia(
_remoteStream, _localOutStream, BUFFER_TARGET_SIZE
);
}
}
catch (Exception exception) {
// Handle errors as you see fit
}
return null;
}
的bufferMedia方法緩衝器的nbytes字節或直到達到輸入的末尾:
private
int bufferMedia(InputStream inStream, OutputStream outStream, int nBytes)
throws IOException
{
final int BUFFER_SIZE = 8 * (1 << 10);
byte[] buffer = new byte[BUFFER_SIZE]; // TODO: Do static allocation instead
int buffered = 0, read = -1;
while (buffered < nBytes) {
read = inStream.read(buffer);
if (read == -1) {
break;
}
outStream.write(buffer, 0, read);
outStream.flush();
buffered += read;
}
if (read == -1 && buffered == 0) {
return -1;
}
return buffered;
}
的setListeners方法爲各種MediaPlayer事件設置處理程序。最重要的是在播放完成時調用OnCompletionListener,其中 被調用。在緩衝區不足(由於暫時的網絡連接緩慢)的情況下,播放器 將到達本地文件的末尾並轉換到PlaybackCompleted狀態。我通過比較_localInStream的 位置和輸入流的大小來識別這些情況。如果位置是較小的,則播放現在真正完成 和我重置的MediaPlayer:
private
void setListeners(MediaPlayer player)
{
// Set some other listeners as well
player.setOnSeekCompleteListener(
new MediaPlayer.OnSeekCompleteListener()
{
@Override
public
void onSeekComplete(MediaPlayer mp)
{
mp.start();
}
}
);
player.setOnCompletionListener(
new MediaPlayer.OnCompletionListener()
{
@Override
public
void onCompletion(MediaPlayer mp)
{
try {
long bytePosition = _localInStream.getChannel().position();
int timePosition = mp.getCurrentPosition();
int duration = mp.getDuration();
if (bytePosition < _track.size) {
mp.reset();
mp.setDataSource(_localInStream.getFD());
mp.prepare();
mp.seekTo(timePosition);
} else {
mp.release();
}
} catch (IOException exception) {
// Handle errors as you see fit
}
}
}
);
}
我無法驗證這是否有所作爲,但如果幸運的話,MediaPlayer Uri可能會支持身份驗證「https:// username:password @ server.com/stream.data」。如果您的身份驗證與默認身份驗證有所不同,那麼這顯然是不可行的。 – harism 2012-01-10 20:01:52
不,認證不是基於密碼的。 – smichak 2012-01-10 23:31:44