IT干货网

java之RTP音频流播放器

lori 2024年06月20日 编程设计 81 0

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 等外部库吗?

请您参考如下方法:

您可以使用 FFmpeg 通过 RTP 协议(protocol)传输单个音频流。这里有更多信息:

https://trac.ffmpeg.org/wiki/StreamingGuide#StreamingasimpleRTPaudiostreamfromFFmpeg

FFmpeg can stream a single stream using the ​RTP protocol. In order to avoid buffering problems on the other hand, the streaming should be done through the -re option, which means that the stream will be streamed in real-time (i.e. it slows it down to simulate a live streaming ​source.

For example the following command will generate a signal, and will stream it to the port 1234 on localhost:

ffmpeg -re -f lavfi -i aevalsrc="sin(400*2*PI*t)" -ar 8000 -f mulaw -f rtp rtp://127.0.0.1:1234 To play the stream with ffplay (which has some caveats, see above), run the command:

ffplay rtp://127.0.0.1:1234 Note that rtp by default uses UDP, which, for large streams, can cause packet loss. See the "point to point" section in this document for hints if this ever happens to you.


评论关闭
IT干货网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!