Stream AAC on Android - android

I'm working on an app for a client that requires streaming of an AAC audio stream. Unfortunately, there's nothing I can do about the stream format on the server. I'm working on Android and have discovered that Android's media player does not support raw AAC streams (which is what I'm getting). I found a project on Google Code that supports it (I tested it with the stream) but it's GPL'ed and that doesn't work for my client. I don't have much experience with this sort of thing so forgive me if my ideas aren't great. I know Android can play AAC encoded content if it is in an MP4 wrapper so I had thought about creating an MP4 wrapper on the fly on the client-side or perhaps even just doing some conversion to another format on the fly. Are these reasonable options? Does anybody have better suggestions?
Thanks in advance!
Edit To rephrase, is it possible to put a raw AAC stream from a web server in an MP4 container in real time? If so, does anybody know of resources to help me with the process?

I'm wondering if you ever came up with a solution for this problem? I'm in a similar situation. We have a web service generating AAC files, though not raw, they have the ADTS header. Android 2.2 can't play these files, though android 2.1 can, oddly enough. It seems to be a problem rooted to android switching to stagefright libraries for media playback in 2.2.
The AAC files do play fine when wrapped in an MP4 container. We've accomplish this on the server side very easily using FAAC (I realize this doesn't help you in your situation). We are still investigating licensing issues with using an mp4 container though. Does this require royalties?
To answer my own question...a lawyer has confirmed that using an mp4 container for an AAC file does not require licensing.

I TRIED ACCDECODER by Google for 4 motnhs it did work well. I found it and in 2 days I could did it works! :) I found it and saw it on the last Google I/O 2017
I can suggest to use EXOPLAYER INSTEAD MEDIAPLAYER. It is a better and improve way. I had the same problem using just MediaPlayer, but short time ago I found Exoplayer, now I do not have problem to Play audio streaming Acc, mp3, mpeg, etc. I can give a couple links to check it.
ExoPlayer is an open source project that is not part of the Android framework and is distributed separately from the Android SDK. ExoPlayer’s standard audio and video components are built on Android’s MediaCodec API, which was released in Android 4.1 (API level 16). Because ExoPlayer is a library, you can easily take advantage of new features as they become available by updating your app.
ExoPlayer supports features like Dynamic adaptive streaming over HTTP (DASH), SmoothStreaming and Common Encryption, which are not supported by MediaPlayer. It's designed to be easy to customize and extend.
This is almost the same like MediaPlayer because Exoplayer extend from it. You can see a lot of differences and an easy way to implement it. If you need more help let me know :)
For example you have this:
Media Player mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource("http://your.url.com"); //add you url address
...
mediaPlayer.prepare();
mediaPlayer.start();
In Exoplayer you need it:
// Create the player
player = ExoPlayerFactory.newSimpleInstance(this, trackSelector, loadControl);
simpleExoPlayerView = new SimpleExoPlayerView(this);
simpleExoPlayerView = (SimpleExoPlayerView) findViewById(R.id.player_view);
//Set media controller
simpleExoPlayerView.setUseController(true);
simpleExoPlayerView.requestFocus();
// Bind the player to the view.
simpleExoPlayerView.setPlayer(player);
ExoPlayer example code:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private SimpleExoPlayerView simpleExoPlayerView;
private SimpleExoPlayer player;
private ExoPlayer.EventListener exoPlayerEventListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v(TAG,"portrait detected...");
setContentView(R.layout.activity_main);
// 1. Create a default TrackSelector
Handler mainHandler = new Handler();
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveVideoTrackSelection.Factory(bandwidthMeter);
TrackSelector trackSelector = new DefaultTrackSelector(mainHandler, videoTrackSelectionFactory);
// 2. Create a default LoadControl
LoadControl loadControl = new DefaultLoadControl();
// 3. Create the player
player = ExoPlayerFactory.newSimpleInstance(this, trackSelector, loadControl);
simpleExoPlayerView = new SimpleExoPlayerView(this);
simpleExoPlayerView = (SimpleExoPlayerView) findViewById(R.id.player_view);
//Set media controller
simpleExoPlayerView.setUseController(true);
simpleExoPlayerView.requestFocus();
// Bind the player to the view.
simpleExoPlayerView.setPlayer(player);
//CHOOSE CONTENT: Livestream links may be out of date so find any m3u8 files online and replace:
//VIDEO FROM SD CARD:
// String urimp4 = "/FileName.mp4";
// Uri mp4VideoUri = Uri.parse(Environment.getExternalStorageDirectory().getAbsolutePath()+urimp4);
//yachts livestream m3m8 file:
Uri mp4VideoUri =Uri.parse("http://your.url.com");
//Random livestream file:
// Uri mp4VideoUri =Uri.parse("http://your.url.com");
//Sports livestream file:
// Uri mp4VideoUri =Uri.parse("http://your.url.com");
// Measures bandwidth during playback. Can be null if not required.
DefaultBandwidthMeter bandwidthMeterA = new DefaultBandwidthMeter();
//Produces DataSource instances through which media data is loaded.
// DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(this, Util.getUserAgent(this, "exoplayer2example"), bandwidthMeterA);
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(loopingSource);
player.addListener(new ExoPlayer.EventListener() {
#Override
public void onLoadingChanged(boolean isLoading) {
Log.v(TAG,"Listener-onLoadingChanged...");
}
#Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
Log.v(TAG,"Listener-onPlayerStateChanged...");
}
#Override
public void onTimelineChanged(Timeline timeline, Object manifest) {
Log.v(TAG,"Listener-onTimelineChanged...");
}
#Override
public void onPlayerError(ExoPlaybackException error) {
Log.v(TAG,"Listener-onPlayerError...");
player.stop();
player.prepare(loopingSource);
player.setPlayWhenReady(true);
}
#Override
public void onPositionDiscontinuity() {
Log.v(TAG,"Listener-onPositionDiscontinuity...");
}
});
player.setPlayWhenReady(true);
}//End of onCreate
#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();
}
}
It was a short example, If you are looking for something else or need more help let me know! I am here! I would like to help because I know how it feels when you are googling and searching and anything it is showing up! :) Take care!!

Related

Exoplayer keeps playing the audio even when video is stopped after

I am using exoplayer and I noticed when I play a video in one activity and then switch to another by pressing on a button the video itself stops playing in order to switch to the new activity, but the audio keeps playing. If I return to the old activity and play the video again the audio is still going + I hear the audio from playing the video again and hear the audio two times now simulteanously at different times of the song.
String url = model.getVideo();
try {
BandwidthMeter bandwidthMeter= new DefaultBandwidthMeter();
TrackSelector trackSelector = new DefaultTrackSelector(new AdaptiveTrackSelection.Factory( bandwidthMeter));
holder.exoPlayer= ExoPlayerFactory.newSimpleInstance( LiFit.getContext(),trackSelector );
Uri videouri = Uri.parse(model.getVideo());
DefaultHttpDataSourceFactory dataSourceFactory = new DefaultHttpDataSourceFactory("exoplayer_video");
ExtractorsFactory extractorsFactory= new DefaultExtractorsFactory();
MediaSource mediaSource = new ExtractorMediaSource(videouri,dataSourceFactory,extractorsFactory,null,null);
holder.videoView.setPlayer(holder.exoPlayer);
holder.exoPlayer.prepare(mediaSource);
//holder.exoPlayer.setPlayWhenReady(true);
} catch (Exception e) {
//Nichts
}
This is the code I am using does somebody know a solution for this problem ?
exoplayer has a method setPlayWhenReady which can be used to play/pause the media, and a release method when the player is no longer needed.
You can use these methods when switching to another activity.

How to implement seekTo() when using HLS with the ExoPlayer

I am trying to implement a basic radio player that can pause the live stream, rewind it and then fast forward it again.
I think that this functionality should be natively supported from version 2.1 of the ExoPlayer.
However, the rewind and fast-forward controls are grayed out when streaming even though they work when playing local content.
Here is how I am creating the player:
private void initExoPlayer(){
Handler mHandler = new Handler();
String userAgent = "userAgent";
Uri uri = Uri.parse(urlSourceOfStream);
dataSourceFactory = new DefaultHttpDataSourceFactory(
userAgent, null,
DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS,
1800000,
true);
mediaSource = new ExtractorMediaSource(uri,dataSourceFactory, Mp3Extractor.FACTORY,
mHandler, null);
bandwidthMeter = new DefaultBandwidthMeter();
trackSelectionFactory =
new AdaptiveTrackSelection.Factory(bandwidthMeter);
trackSelector = new DefaultTrackSelector(trackSelectionFactory);
loadControl = new DefaultLoadControl();
exoPlayer = ExoPlayerFactory.newSimpleInstance(this, trackSelector, loadControl);
exoPlayer.prepare(mediaSource);
((SimpleExoPlayerView) findViewById(R.id.exoPlayer)).setPlayer(exoPlayer);
}
The player can pause successfully, and it seems to be caching the content as I can resume the player after it has been paused for minutes. This also indicates that there should be some cache that can allow me to rewind the content.
I've also tried using the OkHttpDataSourceFactory :
OkHttpClient client = new OkHttpClient.Builder().cache(new Cache(getFilesDir() , 1000)).build();
OkHttpDataSourceFactory okHttpDataSourceFactory = new OkHttpDataSourceFactory(client, userAgent, null);
Trying to rewind the player like this makes the player play from the live stream position and does not rewind the content:
exoPlayer.seekTo(Math.max(exoPlayer.getCurrentPosition() - 1000, 0));
My question in a nutshell: How can I rewind and fast-forward an HLS with the ExoPlayer?
Thanks in advance.
It looks like there is a bug, https://github.com/google/ExoPlayer/issues/87 discussing this, and it's been closed. But I'm not sure if its reached the v2 release, and rather it might be in the dev release, here

How to detect HLS video is for Live, VOD or Event in Exoplayer android

I have integrated android exoplayer in my application. I have to detect the HLS (.m3u8) stream received is for Live or VOD or Event, so depending on that controller has to be modified for the player. I have only one instance of player so that should handle all the supported media like vod or live or event.
I am looking for some debug points to know working of m3u8 parser in exoplayer so that I can able to receive this parameters.
You can use below code to play .m3u8 file:-
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
//Create the player using ExoPlayerFactory
videoPlayer = ExoPlayerFactory.newSimpleInstance(context,trackSelector);
Handler mHandler = new Handler();
String userAgent = Util.getUserAgent(context, "Exo Player");
DataSource.Factory dataSourceFactory = new DefaultHttpDataSourceFactory(
userAgent, null,
DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS,
1800000,
true);
HlsMediaSource mediaSource = new HlsMediaSource(Uri.parse(mediaUrl),dataSourceFactory, 1800000,mHandler, null);
if (mediaUrl != null) {
videoPlayer.prepare(mediaSource);
videoPlayer.setPlayWhenReady(true);
}
Live vs Event differentiation is not supported, yet. For Live vs Event you can check the current Timeline, but that's not HLS specific. For distinguish a live stream from a vod one by querying the player's duration after it is prepared. Live streams will return UNKNOWN_TIME, where-as vod streams will return the known duration of the stream.

How to get local video Uri for ExoPlayer 2.x

I have a dog.mp4 video file in res/raw folder, which I want to play with ExoPlayer. I'm trying to figure out how to get video Uri for this line of code from ExoPlayer developers guide (https://google.github.io/ExoPlayer/guide.html):
MediaSource videoSource = new ExtractorMediaSource(mp4VideoUri,
dataSourceFactory, extractorsFactory, null, null);
To get it, I use this line:
Uri mp4VideoUri = Uri.parse("android.resources://"+getPackageName()+"/"+R.raw.dog);
Also tried this syntax: android.resource://[package]/[res type]/[res name]
But SimpleExoPlayerView stays black and I get following error:
com.google.android.exoplayer2.upstream.HttpDataSource$HttpDataSourceException: Unable to connect to android.resources://lt.wilkas.deleteexoplayer/2131099648
What am I doing wrong?
Don't move your videos from raw to any another folder
Use this code to play video:
PlayerView playerView = findViewById(R.id.player_view);
SimpleExoPlayer player = ExoPlayerFactory.newSimpleInstance(this);
// Bind the player to the view.
playerView.setPlayer(player);
// Produces DataSource instances through which media data is loaded.
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(this, Util.getUserAgent(this, "yourApplicationName"));
// This is the MediaSource representing the media to be played.
MediaSource firstSource = new ExtractorMediaSource.Factory(dataSourceFactory).createMediaSource(RawResourceDataSource.buildRawResourceUri(R.raw.dog));
// Prepare the player with the source.
player.prepare(firstSource);
According to ExoPlayer 2.12 its even easier to use MediaItem.
To create it we need Uri that could be generated from RawResourceDataSource.buildRawResourceUri.
And that's it. Just set this MediaItem do prepare() and play when ready:
SimpleExoPlayer.Builder(view.context).build().apply {
val uri = RawResourceDataSource.buildRawResourceUri(R.raw.video)
setMediaItem(MediaItem.fromUri(uri))
prepare()
playWhenReady = true
}
I've found out that res/raw folder cant be used to store local videos for ExoPlayer. They should be placed in assets folder.
res/raw folder can be used to access local video file for ExoPlayer via it's URI. Here's the solution that will not give the Malformed URL exception and it works for me. You have to use RawResourceDataSource.buildRawResourceUri(R.raw.video) method of the RawResourceDataSource class. Keep in mind that i used the 2.8.0 version of ExoPlayer.
public class MainActivity extends AppCompatActivity {
PlayerView playerView;
SimpleExoPlayer simpleExoPlayer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
playerView=findViewById(R.id.playerView);
}
#Override
protected void onStart() {
simpleExoPlayer= ExoPlayerFactory.newSimpleInstance(this,new DefaultTrackSelector());
DefaultDataSourceFactory defaultDataSourceFactory=new DefaultDataSourceFactory(this, Util.getUserAgent(this,"yourApplicationName"));
simpleExoPlayer.setPlayWhenReady(true);
ExtractorMediaSource extractorMediaSource=new ExtractorMediaSource.Factory(defaultDataSourceFactory).createMediaSource(RawResourceDataSource.buildRawResourceUri(R.raw.video));
simpleExoPlayer.prepare(extractorMediaSource);
playerView.setPlayer(simpleExoPlayer);
super.onStart();
}
#Override
protected void onStop() {
playerView.setPlayer(null);
simpleExoPlayer.release();
simpleExoPlayer=null;
super.onStop();
}
}
here is the sample to load video/audio file from res/raw with ExoPlayer :
val player = ExoPlayerFactory.newSimpleInstance(context,DefaultTrackSelector())
val rawDataSource = RawResourceDataSource(context)
rawDataSource.open(DataSpec(RawResourceDataSource.buildRawResourceUri(R.raw.brown)))
val mediaSource = ExtractorMediaSource.Factory(DataSource.Factory { rawDataSource })
.createMediaSource(rawDataSource.uri)
player.playWhenReady = true
player.prepare(mediaSource)
sample copied from
This code works for me.
fun buildMediaSourceRaw() : MediaSource{
val dataSourceFactory = DefaultDataSourceFactory(context, "exoPlayer")
val uri = RawResourceDataSource.buildRawResourceUri(R.raw.my_video)
return ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(uri)
}
Then
player?.prepare(buildMediaSourceRaw())

Creating a simple instance of ExoPlayer

I am currently looking to develop an application that utilises Dash through the ExoPlayer in Android.
To begin with I am going through the demo project however am having trouble with even creating a simple working instance of ExoPlayer that can stream mp3 or similar.
Would really appreciate any help anyone can give relating to getting a very simple exoplayer instance working from which i can adapt and build upon or if anyone has any leads for more references or guides which I can follow as there seems to be very little documentation available.
Thanks very much for all and any help!
First of all instantiate your ExoPlayer with this line:
exoPlayer = ExoPlayer.Factory.newInstance(RENDERER_COUNT, minBufferMs, minRebufferMs);
If you want to play audio only you can use these values:
RENDERER_COUNT = 1 //since you want to render simple audio
minBufferMs = 1000
minRebufferMs = 5000
Both buffer values can be tweaked according to your requirements
Now you have to create a DataSource. When you want to stream mp3 you can use the DefaultUriDataSource. You have to pass the Context and a UserAgent. To keep it simple play a local file and pass null as userAgent:
DataSource dataSource = new DefaultUriDataSource(context, null);
Then create the sampleSource:
ExtractorSampleSource sampleSource = new ExtractorSampleSource(
uri, dataSource, new Mp3Extractor(), RENDERER_COUNT, requestedBufferSize);
uri points to your file, as an Extractor you can use a simple default Mp3Extractor if you want to play mp3. requestedBufferSize can be tweaked again according to your requirements. Use 5000 for example.
Now you can create your audio track renderer using the sample source as follows:
MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource);
Finally call prepare on your exoPlayer instance:
exoPlayer.prepare(audioRenderer);
To start playback call:
exoPlayer.setPlayWhenReady(true);
Here is how you would do it using the new ExoPlayer 2 API, and the SimpleExoPlayer.
First create the player:
DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(context, bandwidthMeter);
TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
DefaultTrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
LoadControl loadControl = new DefaultLoadControl();
SimpleExoPlayer player = ExoPlayerFactory.newSimpleInstance(context, trackSelector, loadControl);
player.addListener(...); // To receive events from the player
Then create your MediaSource. For MP3 you can use ExtractorMediaSource:
ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
Uri uri = Uri.parse(mp3UriString);
Handler mainHandler = new Handler(Looper.getMainLooper());
MediaSource mediaSource = new ExtractorMediaSource(uri, dataSourceFactory, extractorsFactory, mainHandler, mediaSourceListener); // Listener defined elsewhere
Then prepare and play when ready:
player.prepare(mediaSource);
player.setPlayWhenReady(true);
For DASH you would use DashMediaSource instead of ExtractorMediaSource.
Today while working on a project, I found that this.myExoPlayer = ExoPlayerFactory.newSimpleInstance(getActivity()); and some others are now deprecated and Android studio suggested to use new way. So I did a quick Google for it but everywhere I found the old way. So I looked into the SimpleExoPlayer.java file, read some methods. So this is how you initialize simpleExoPlayer:
Activity activity = getActivity(); // if you are in a fragment
// Or, activity = YourActivity.this; if you are in an Activity
SimpleExoPlayer simpleExoPlayer = new SimpleExoPlayer.Builder(activity).build();
I hope this is helpful.

Categories

Resources