Android是否可以在本机API中支持音频rtp读取? 我想开发一个rtp音频播放器,我尝试过:
MediaPlayer API:rtp不起作用:
package com.javacodegeeks.androidmediaplayerexample;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import android.app.Activity;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.*;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.SeekBar;
import android.widget.TextView;
//import java.lang.String;
import static android.util.Log.i;
public class AndroidMediaPlayerExample extends Activity implements MediaPlayer.OnPreparedListener {
private MediaPlayer mediaPlayer;
public TextView songName, duration;
private double timeElapsed = 0, finalTime = 0;
private int forwardTime = 2000, backwardTime = 2000;
private Handler durationHandler = new Handler();
private SeekBar seekbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//set the layout of the Activity
setContentView(R.layout.activity_main);
//initialize views
try {
initializeViews();
} catch (IOException e) {
e.printStackTrace();
}
}
public void initializeViews() throws IOException {
songName = (TextView) findViewById(R.id.songName);
//mediaPlayer = MediaPlayer.create(this, R.raw.sample_song);
//mediaPlayer = MediaPlayer.create(this, myUri);
try {
Uri myUri = Uri.parse("rtsp://192.168.1.210:5000/test"); // initialize Uri here
i("TestAudio", "URI : " + myUri.getScheme());
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource("rtsp://192.168.1.210:5000/test");
//mediaPlayer.setDataSource(getApplicationContext(), myUri);
mediaPlayer.setOnPreparedListener(this);
mediaPlayer.prepareAsync(); // used for streaming
//mediaPlayer.prepare(); //Message: Prepare failed.: status=0x1 Cause: null
/*mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
//Called when the media file is ready for playback.
mp.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
@Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
i("TestAudio","Percent : " + Integer.toString(percent));
if(percent == 100)
{
mp.start();
}
}
});
}
});*/
} catch (Exception e) {
i("TestAudio", "Message: " + e.getMessage() + " Cause: " + e.getCause());
e.printStackTrace();
}
/*finalTime = mediaPlayer.getDuration();
duration = (TextView) findViewById(R.id.songDuration);
seekbar = (SeekBar) findViewById(R.id.seekBar);
songName.setText("Sample_Song.mp3");
seekbar.setMax((int) finalTime);
seekbar.setClickable(false);*/
}
// play mp3 song
public void play(View view) {
mediaPlayer.start();
/*timeElapsed = mediaPlayer.getCurrentPosition();
seekbar.setProgress((int) timeElapsed);
durationHandler.postDelayed(updateSeekBarTime, 100);*/
}
//handler to change seekBarTime
private Runnable updateSeekBarTime = new Runnable() {
public void run() {
/*//get current position
timeElapsed = mediaPlayer.getCurrentPosition();
//set seekbar progress
seekbar.setProgress((int) timeElapsed);
//set time remaing
double timeRemaining = finalTime - timeElapsed;
duration.setText(String.format("%d min, %d sec", TimeUnit.MILLISECONDS.toMinutes((long) timeRemaining), TimeUnit.MILLISECONDS.toSeconds((long) timeRemaining) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes((long) timeRemaining))));
//repeat yourself that again in 100 miliseconds
durationHandler.postDelayed(this, 100);*/
}
};
// pause mp3 song
public void pause(View view) {
mediaPlayer.pause();
}
// go forward at forwardTime seconds
public void forward(View view) {
/*//check if we can go forward at forwardTime seconds before song endes
if ((timeElapsed + forwardTime) <= finalTime) {
timeElapsed = timeElapsed + forwardTime;
//seek to the exact second of the track
mediaPlayer.seekTo((int) timeElapsed);
}*/
}
// go backwards at backwardTime seconds
public void rewind(View view) {
/*//check if we can go back at backwardTime seconds after song starts
if ((timeElapsed - backwardTime) > 0) {
timeElapsed = timeElapsed - backwardTime;
//seek to the exact second of the track
mediaPlayer.seekTo((int) timeElapsed);
}*/
}
@Override
public void onPrepared(MediaPlayer mp) {
mp.start();
}
@Override
public void onDestroy() {
super.onDestroy();
if (mediaPlayer != null) mediaPlayer.release();
}
}
ExoPlayer API:不支持rtp和rtsp:
package com.ayalus.exoplayer2example;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Surface;
import android.widget.TextView;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.decoder.DecoderCounters;
import com.google.android.exoplayer2.source.LoopingMediaSource;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.source.hls.HlsMediaSource;
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.trackselection.TrackSelector;
import com.google.android.exoplayer2.ui.PlayerView;
import com.google.android.exoplayer2.ui.SimpleExoPlayerView;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.google.android.exoplayer2.util.Util;
import com.google.android.exoplayer2.video.VideoRendererEventListener;
/*
Created by: Ayal Fieldust
Date: 8/2017
Description:
This Example app was created to show a simple example of ExoPlayer Version 2.8.4.
There is an option to play mp4 files or live stream content.
Exoplayer provides options to play many different formats, so the code can easily be tweaked to play the requested format.
Scroll down to "ADJUST HERE:" I & II to change between sources.
Keep in mind that m3u8 files might be stale and you would need new sources.
*/
public class MainActivity extends AppCompatActivity implements VideoRendererEventListener {
private static final String TAG = "MainActivity";
private PlayerView simpleExoPlayerView;
private SimpleExoPlayer player;
private TextView resolutionTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
resolutionTextView = new TextView(this);
resolutionTextView = (TextView) findViewById(R.id.resolution_textView);
//// I. ADJUST HERE:
////CHOOSE CONTENT: LiveStream / SdCard
//
////LIVE STREAM SOURCE: * Livestream links may be out of date so find any m3u8 files online and replace:
//
//// Uri mp4VideoUri =Uri.parse("http://81.7.13.162/hls/ss1/index.m3u8"); //random 720p source
//// Uri mp4VideoUri =Uri.parse("http://54.255.155.24:1935//Live/_definst_/amlst:sweetbcha1novD235L240P/playlist.m3u8"); //Radnom 540p indian channel
// Uri mp4VideoUri =Uri.parse("http://cbsnewshd-lh.akamaihd.net/i/CBSNHD_7@199302/index_700_av-p.m3u8"); //CNBC
//Uri mp4VideoUri =Uri.parse("http://live.field59.com/wwsb/ngrp:wwsb1_all/playlist.m3u8"); //ABC NEWS
Uri mp4VideoUri =Uri.parse("rtsp://192.168.1.110/test"); //ABC NEWS
//// Uri mp4VideoUri =Uri.parse("FIND A WORKING LINK ABD PLUg INTO HERE"); //PLUG INTO HERE<------------------------------------------
//
//
////VIDEO FROM SD CARD: (2 steps. set up file and path, then change videoSource to get the file)
//// String urimp4 = "path/FileName.mp4"; //upload file to device and add path/name.mp4
//// Uri mp4VideoUri = Uri.parse(Environment.getExternalStorageDirectory().getAbsolutePath()+urimp4);
DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter(); //test
TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
TrackSelector trackSelector =
new DefaultTrackSelector(videoTrackSelectionFactory);
// 2. Create the player
player = ExoPlayerFactory.newSimpleInstance(this, trackSelector);
simpleExoPlayerView = new SimpleExoPlayerView(this);
simpleExoPlayerView = (SimpleExoPlayerView) findViewById(R.id.player_view);
int h = simpleExoPlayerView.getResources().getConfiguration().screenHeightDp;
int w = simpleExoPlayerView.getResources().getConfiguration().screenWidthDp;
Log.v(TAG, "height : " + h + " weight: " + w);
////Set media controller
simpleExoPlayerView.setUseController(false);//set to true or false to see controllers
simpleExoPlayerView.requestFocus();
// Bind the player to the view.
simpleExoPlayerView.setPlayer(player);
// Measures bandwidth during playback. Can be null if not required.
// Produces DataSource instances through which media data is loaded.
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(this, Util.getUserAgent(this, "exoplayer2example"), bandwidthMeter);
// This is the MediaSource representing the media to be played.
// MediaSource videoSource = new ExtractorMediaSource.Factory(dataSourceFactory).createMediaSource(liveStreamUri);
//// II. ADJUST HERE:
//// DefaultDataSourceFactory dataSourceFactory = new DefaultDataSourceFactory(this, Util.getUserAgent(this, "exoplayer2example"), bandwidthMeterA);
////Produces Extractor instances for parsing the media data.
// ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
//This is the MediaSource representing the media to be played:
//FOR SD CARD SOURCE:
// MediaSource videoSource = new ExtractorMediaSource(mp4VideoUri, dataSourceFactory, extractorsFactory, null, null);
//FOR LIVESTREAM LINK:
MediaSource videoSource = new HlsMediaSource(mp4VideoUri, dataSourceFactory, 1, null, null);
final LoopingMediaSource loopingSource = new LoopingMediaSource(videoSource);
// Prepare the player with the source.
player.prepare(videoSource);
player.addListener(new ExoPlayer.EventListener() {
@Override
public void onTimelineChanged(Timeline timeline, Object manifest, int reason) {
}
@Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
Log.v(TAG, "Listener-onTracksChanged... ");
}
@Override
public void onLoadingChanged(boolean isLoading) {
}
@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
Log.v(TAG, "Listener-onPlayerStateChanged..." + playbackState+"|||isDrawingCacheEnabled():"+simpleExoPlayerView.isDrawingCacheEnabled());
}
@Override
public void onRepeatModeChanged(int repeatMode) {
}
@Override
public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
}
@Override
public void onPlayerError(ExoPlaybackException error) {
Log.v(TAG, "Listener-onPlayerError...");
player.stop();
player.prepare(loopingSource);
player.setPlayWhenReady(true);
}
@Override
public void onPositionDiscontinuity(int reason) {
}
@Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
}
@Override
public void onSeekProcessed() {
}
});
player.setPlayWhenReady(true); //run file/link when ready to play.
player.setVideoDebugListener(this);
}
@Override
public void onVideoEnabled(DecoderCounters counters) {
}
@Override
public void onVideoDecoderInitialized(String decoderName, long initializedTimestampMs, long initializationDurationMs) {
}
@Override
public void onVideoInputFormatChanged(Format format) {
}
@Override
public void onDroppedFrames(int count, long elapsedMs) {
}
@Override
public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
Log.v(TAG, "onVideoSizeChanged [" + " width: " + width + " height: " + height + "]");
resolutionTextView.setText("RES:(WxH):" + width + "X" + height + "\n " + height + "p");//shows video info
}
@Override
public void onRenderedFirstFrame(Surface surface) {
}
@Override
public void onVideoDisabled(DecoderCounters counters) {
}
//-------------------------------------------------------ANDROID LIFECYCLE---------------------------------------------------------------------------------------------
@Override
protected void onStop() {
super.onStop();
Log.v(TAG, "onStop()...");
}
@Override
protected void onStart() {
super.onStart();
Log.v(TAG, "onStart()...");
}
@Override
protected void onResume() {
super.onResume();
Log.v(TAG, "onResume()...");
}
@Override
protected void onPause() {
super.onPause();
Log.v(TAG, "onPause()...");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.v(TAG, "onDestroy()...");
player.release();
}
}
AudioStream API:rtp不起作用:
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.media.*;
import android.net.rtp.*;
import android.os.StrictMode;
import android.util.Log;
import java.net.*;
import static android.util.Log.i;
public class MainActivity extends AppCompatActivity {
AudioStream audioStream;
AudioGroup audioGroup;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitNetwork().build();
StrictMode.setThreadPolicy(policy);
AudioManager audio = (AudioManager)getSystemService(AUDIO_SERVICE);
audio.setMode(AudioManager.MODE_NORMAL);
audioGroup = new AudioGroup();
audioGroup.setMode(AudioGroup.MODE_NORMAL);
InetAddress inetAddress;
i("TestSon","aaaaa");
try {
inetAddress = InetAddress.getByName("192.168.1.182");
audioStream = new AudioStream(inetAddress);
audioStream.setCodec(AudioCodec.PCMU);
audioStream.setMode(RtpStream.MODE_RECEIVE_ONLY);
InetAddress inetAddressRemote = InetAddress.getByName("192.168.1.210");
audioStream.associate(inetAddressRemote, 6000);
audioStream.join(audioGroup);
i("TestSon","Local port : " + audioStream.getLocalPort());
i("TestSon","Local address : " + audioStream.getLocalAddress());
i("TestSon","Remote port : " + audioStream.getRemotePort());
i("TestSon","Remote address : " + audioStream.getRemoteAddress());
}
catch ( UnknownHostException e ) {
i("TestSon","exception1: " + e.getMessage());
e.printStackTrace();
}
catch ( SocketException e ) {
i("TestSon","exception2: " + e.getMessage());
e.printStackTrace();
}
}
}
我应该使用像libvlc或ffmpeg这样的外部库吗?
答案 0 :(得分:0)
您可以使用FFmpeg使用RTP协议流式传输单个音频流。这里是更多信息:
https://trac.ffmpeg.org/wiki/StreamingGuide#StreamingasimpleRTPaudiostreamfromFFmpeg
FFmpeg可以使用RTP协议流式传输单个流。为了 另一方面,为了避免缓冲问题,流应该是 通过-re选项完成,这意味着流将 实时流式传输(即,它会减慢其速度以模拟直播 流源。
例如,以下命令将生成信号,并会 将其流式传输到localhost上的端口1234:
ffmpeg -re -f lavfi -i aevalsrc =“ sin(400 * 2 * PI * t)” -ar 8000 -f mulaw -f rtp rtp://127.0.0.1:1234使用ffplay播放流(具有 一些警告,请参见上文),运行命令:
ffplay rtp://127.0.0.1:1234请注意,默认情况下,rtp使用UDP, 对于大数据流,可能会导致数据包丢失。见“点对点” 本文档中的“小节”以提示您是否曾经遇到过这种情况。