Mediaplayerのソースとして任意のストリームを使用します
-
26-10-2019 - |
質問
Mediaplayerオブジェクトのデータソースとして任意のinputstreamを使用したいと思います。
この理由は、私が使用している入力ストリームが実際にリモートサーバー上のメディアリソースへの承認されたHTTPS接続であるためです。その場合、URLを渡すには、認証が必要であるため、明らかに機能しません。ただし、認証を個別に行い、リソースに入力ストリームを取得することができます。問題が発生したらどうすればよいですか?
名前付きパイプを使用して、そのファイリングエクスプトターをMediaplayerのSetDataresourceメソッドに渡すオプションについて考えました。 Androidで名前のパイプを作成する方法はありますか(NDKを使用せずに)?
他の提案は大歓迎です。
解決 2
別の解決策は、LocalHostでプロキシHTTPサーバーを起動することです。メディアプレーヤーは、SetDataSource(コンテキストコンテキスト、URI URI)でこのサーバーに接続します。このソリューションは以前よりもうまく機能し、再生がグリッチになることはありません。
他のヒント
解決策を見つけたと思います。興味のある他の人が自分でこれを試して、デバイスモデルとSDKバージョンで結果を報告するなら、私はそれを感謝します。
私はこれに直接対応する同様の投稿を見てきましたが、とにかく新しいバージョンのSDKで動作するように見えるので、とにかく投稿すると思いました - これまでのところ、Android 2.3.6を実行しているNexus Oneで動作します。
ソリューションは、入力ストリームをローカルファイルにバッファリングすることに依存しています(外部ストレージにこのファイルがありますが、おそらくIntenalストレージにも配置することができます)。
以下は、Audioplaybackを行うAsynctaskの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イベントのハンドラーを設定します。最も重要なのは、再生が完了したときに呼び出されるoncomplediotionListenerです。バッファーアンダーランの場合(たとえば、一時的な遅いネットワーク接続により)、プレーヤーはローカルファイルの終わりに到達し、再生コンプレット状態にトランジットします。 _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
}
}
}
);
}