How to play streaming music file from cloud storage service? - android

I want to play a music file which will be retrieved from a cloud storage service (such as Google drive or Mega.nz). I shared the file so anyone who have the link can access to it.
I'm using MediaPlayer class to handle this playback. So when I tried a direct link something like this, it worked well. But when I tried with a link from Google Drive, such as this, it didn't work.
Here is some code which I used to play the music file:
MusicPlayerFragment class
public class MusicPlayerFragment extends Fragment {
private MusicPlayer musicPlayer;
boolean isPlaying;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View layout = inflater.inflate(R.layout.fragment_music_player, container, false);
final ImageButton buttonPlayPause = layout.findViewById(R.id.button_play_pause);
buttonPlayPause.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!isPlaying) {
musicPlayer.play();
buttonPlayPause.setImageResource(R.drawable.baseline_pause_24);
isPlaying = true;
}
else {
musicPlayer.pause();
buttonPlayPause.setImageResource(R.drawable.baseline_play_arrow_24);
isPlaying = false;
}
}
});
return layout;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
musicPlayer = new MusicPlayer();
musicPlayer.loadMedia("http://ssaurel.com/tmp/mymusic.mp3"); //work on physical device
//musicPlayer.loadMedia("https://drive.google.com/file/d/1Tj0a5f4dUMNnlPILr3vZzpPOwHKsP3Va/view?usp=sharing"); //doesn't work at all
}
}
MusicPlayer class
public class MusicPlayer{
private MediaPlayer mediaPlayer;
public void loadMedia(String url) {
if (mediaPlayer == null) {
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
}
});
try {
mediaPlayer.setDataSource(url);
mediaPlayer.prepareAsync();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void play() {
if (mediaPlayer != null && !mediaPlayer.isPlaying()) {
mediaPlayer.start();
}
}
public void pause() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
}
public void reset() {
if (mediaPlayer != null) {
mediaPlayer.reset();
}
}
public void release() {
if (mediaPlayer != null) {
mediaPlayer.release();
}
}
}
I'm working with SQL Server too, which will store data of the music and URL to that music file to play. But since it didn't work so there are 2 things I'm wondering:
1st: Where am I wrong in here? In my opinion, I'm suspecting that I'm not using the setDataSource(url) method in the correct way.
2nd: Is the URL of Google Drive in the right format to use? If it is not the right format to use with any (overloaded) setDataSource() method, then how can I store a music file with the right URL format it needs? (the right format like this, I think: "http://domain/path/audiofilename.mp3"). I'm accessing the database on local machine.

You have the answer hidden in your question itself. When you're passing the direct download link to the music, it works, meaning, you need to use something that will be able to directly download the file.
When you give the Google Drive link, you don't give the complete address of the file, instead, you go on the page which tells you to manually download the file.
You should use something like FirebaseStorage to store the songs, so you'll be able to get the direct download links of those songs.

Related

Android Media player onClick issue

I'm using MediaPlayer for playing sounds onClick. Until the sound is finished the click event is not play the sound again. How can it play the sound again on click, when the sound is currently playing?
final MediaPlayer mistake = MediaPlayer.create(getActivity(), R.raw.mistake);
tv_mistake.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mistake.start();
}
});
You must create a new MediaPlayer object to play the sound again like so.
tv_mistake.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mistake != null) {
mistake.release();
mistake = MediaPlayer.create(getActivity(), R.raw.mistake);
}
mistake.start();
}
});
You can read more about MediaPlayer in the following links.
Also a quite similar question
MediaPlayer, MediaPlayer Tutorial, MediaPlayer Tutorial From Google
Most of the errors in MediaPlayer comes due to improper handling of different states of its object.
You should release MediaPlayer object after completing playback or before calling start() again.
It is also recommended that once a MediaPlayer object is no longer being used, call release() immediately so that resources used by the internal player engine associated with the MediaPlayer object can be released immediately.
Create a MediaPlayer object as:
Mediaplayer mediaPlayer = null;
And call playMistakeSound() on button click:
tv_mistake.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
playMistakeSound()
}
});
Implement playMistakeSound() as:
void playMistakeSound() {
try {
// releases MediaPlayer object before calling create() again while previous is still playing
if (mediaPlayer != null){
mediaPlayer.reset();
mediaPlayer.release();
mediaPlayer = null;
}
mediaPlayer = MediaPlayer.create(getActivity() /*Context*/, R.raw.mistake);
// this will release MediaPlayer as soon as it completes
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
if (mp != null) {
mp.reset();
mp.release();
mediaPlayer = null;
}
}
});
mediaPlayer.start();
} catch (Exception e) {
// log exception and handle
e.printStackTrace();
}
}

Changing audio button from play to pause when clicked and vice versa

I want a play button in my app that when clicked plays the audio and changes to pause, and when the pause button is clicked the audio stops and the button changes to play again and so on. But the button is not working as expected. Please help. I'm adding my java code below.
public class surah extends AppCompatActivity {
MediaPlayer mp = new MediaPlayer();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_surah);
mp=MediaPlayer.create(surah.this, R.raw.surahkahf);
final ImageView audio = (ImageView)findViewById(R.id.btn);
audio.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(mp.isPlaying()){
mp.stop();
audio.setBackgroundResource(R.drawable.play);
try {
mp.prepare();
}catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else {
mp.start();
audio.setImageResource(R.drawable.pause);
}
}
});
}
}
Use audio.setImageResource(R.drawable.play) instead of audio.setBackgroundResource(R.drawable.play). Use mp.pause() instead of mp.stop();
First, as aborocz mentions in comments, you probably intend to pause playback instead of stop it, so the method you want to use is pause(). In that case you would not need to prepare the MediaPlayer again, and it will start from the same place it was paused when playback is resumed.
Second, the isPlaying() method is not particularly appropriate for this purpose. There are race conditions that prevent the desired behavior. From the Android MediaPlayer documentation:
Note that the transition from the Started state to the Paused state
and vice versa happens asynchronously in the player engine. It may
take some time before the state is updated in calls to isPlaying(),
and it can be a number of seconds in the case of streamed content.
Instead, store your own boolean value.
public class surah extends AppCompatActivity {
private MediaPlayer mp;
private boolean isMediaPlaying = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_surah);
mp = MediaPlayer.create(surah.this, R.raw.surahkahf);
final ImageView audio = (ImageView)findViewById(R.id.btn);
audio.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (isMediaPlaying) {
mp.pause();
audio.setBackgroundResource(R.drawable.play);
isMediaPlaying = false;
} else {
mp.start();
audio.setImageResource(R.drawable.pause);
isMediaPlaying = true;
}
}
});
}
}

Why do .ogg files loop?

In the following class the playback of the .ogg file is triggered.
public class HomeScreenFragment extends Fragment {
...
private AudioPlayer mPlayer = new AudioPlayer();
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
...
mStandbyButton = (Button)v.findViewById(R.id.standby_button);
mStandbyButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mPlayer.play(getActivity());
}
});
}
public void onDestroy() {
super.onDestroy();
mPlayer.stop();
}
}
Despite of using the setOnCompletionListener() the files keep on looping unlike .wav
public class AudioPlayer {
private MediaPlayer mPlayer;
public void stop() {
if(mPlayer != null) {
mPlayer.release();
mPlayer = null;
}
}
public void play(Context c) {
stop();
mPlayer = MediaPlayer.create(c, R.raw.hassium);
mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
stop();
}
});
mPlayer.start();
}
}
How to ensure they don't loop once playback is completed?
I could possibly work with .wav files but curious as to why this happens and if possible prevent them from looping.
Searching shows that there may be ANDROID_LOOP in ogg metadata: ANDROID_LOOP = true -- how to avoid MediaPlayer looping audios with this metadata tag
Related tickets in Google Code:
MediaPlayer setLooping(false) does not work for ogg files
Should document ANDROID_LOOP flag for OGG files
You can try to use MediaPlayer.setLooping(false) to see if it can help

Media Player start stop start

I am making a new android sound application. I made a clickable button to play sound when I click on it. But I also want it to stop playing sound when I click for the second time. That part works fine now here is the problem, when I click again on button to play sound again, it doesn't play it, Media player is completely stopped. I was looking on forums but I can't seem to find an answer that could help me.
Here is my Activity:
MediaPlayer mpButtonClick1;
MediaPlayer mpButtonClick2;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.prvi);
final MediaPlayer mpButtonClick1 = MediaPlayer.create(this, R.raw.spalshm);
final MediaPlayer mpButtonClick2 = MediaPlayer.create(this, R.raw.splashs);
Button dugme = (Button) findViewById(R.id.dugme);
dugme.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mpButtonClick1.isPlaying()) {
mpButtonClick1.stop();
mpButtonClick1.reset();
}
else {
mpButtonClick1.start();
}
}
});
When I try to write mpButtonClick1.prepare(); I get error Unhandled Exception Type IOE exception
Try to use pause instead of stop.
Reason: if you pause the MediaPlayer, then you can resume it later. However, if you use stop, almost any other method won't work and you will have to prepare the MediaPlayer again (or create a new one).
More info: here and here
PS: don't forget to release the memory when you finish using the resources.
Try this:
You should use only one mediaplayer object
public class PlayaudioActivity extends Activity {
private MediaPlayer mp;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button b = (Button) findViewById(R.id.button1);
Button b2 = (Button) findViewById(R.id.button2);
final TextView t = (TextView) findViewById(R.id.textView1);
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
stopPlaying();
mp = MediaPlayer.create(PlayaudioActivity.this, R.raw.far);
mp.start();
}
});
b2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
stopPlaying();
mp = MediaPlayer.create(PlayaudioActivity.this, R.raw.beet);
mp.start();
}
});
}
private void stopPlaying() {
if (mp != null) {
mp.stop();
mp.release();
mp = null;
}
}
}
Change your class with below code:
remove reset();.
init well all components:
MediaPlayer mpButtonClick1;
MediaPlayer mpButtonClick2;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.prvi);
mpButtonClick1 = MediaPlayer.create(this, R.raw.spalshm);
mpButtonClick2 = MediaPlayer.create(this, R.raw.splashs);
Button dugme = (Button) findViewById(R.id.dugme);
dugme.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mpButtonClick1.isPlaying()) {
mpButtonClick1.stop();
}
else {
mpButtonClick1.start();
}
}
});
You're calling mpButtonClick1.reset() after mpButtonClick1.stop() - don't do that:
if (mpButtonClick1.isPlaying()) {
mpButtonClick1.stop();
mpButtonClick1.reset(); //<--------- calling reset(), remove this line
}
The docs for reset() say:
Resets the MediaPlayer to its uninitialized state. After calling this method, you will have to initialize it again by setting the data source and calling prepare().
Remove mpButtonClick1.reset() and it should work.
Keep in mind that MediaPlayer works as a state machine, which means that if you call methods in the wrong order, you'll get problems. Please read about MediaPlayer here and here.
Hey please use following
for stop -> media player
mp.seekTo(0);
mp.pause();
again for start just call
mp.start();
In my experience when I need to play multiple times and I may need to stop one play to start another play, (like in the case of multiple buttons), I just create another player, making sure that I release the resources for the previous one. To stop just use
mediaPlayer.stop();
But for play use something like this (adapt the logging to your specific needs) to create/recreate your player:
private boolean createMediaPlayer()
{
if (mediaPlayer!=null)
{
if(mediaPlayer.isPlaying())
{
mediaPlayer.stop();
mediaPlayer.reset();
mediaPlayer.release();
mediaPlayer=null;
}
}
mediaPlayer = new MediaPlayer();
mediaPlayer.setVolume(1f, 1f);
try
{
mediaPlayer.setAudioStreamType(Interop.PRIMARY_STREAM);
mediaPlayer.setDataSource(m_soundFile);
mediaPlayer.prepare();
return true;
// Interop.logDebug(TAG + "-loadAudio: SUCCESS" + m_soundFile);
} catch (Exception e)
{
Interop.logError(TAG + "-LoadAudio for Clic Sound: audioPlayer prepare failed for current file: " + m_soundFile);
Interop.logError(TAG + "-Exception: " , e);
return false;
}
}
and than use
if (createMediaPlayer())
mediaPlayer.start();
this will ensure proper release of the resources used by the media player.
A simple solution is to Use pause instead of stop and the seek to the beginning of the song.
I know that this question is quite old but recently while learning Android, I also got stuck at this point and found a very simple solution which I'd like to share with everyone.
Instead of trying to stop or reset the media, you can just seek back to the starting position.
mediaPlayer.seekTo(0);
For reference, I am also posting my code below:
public class MainActivity extends AppCompatActivity {
MediaPlayer mp;
public void play(View view) {
mp.start();
}
public void pause(View view) {
mp.pause();
}
public void stop(View view) {
// this seeks to the beginning of the file
mp.seekTo(0);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mp = MediaPlayer.create(this, R.raw.sample_audio);
}
}

Android: Video cannot be played from non hard-coded URL

I'm trying to stream a video and play it using VideoView. I supply the view with the source URL of the video with setVideoURI() as shown below. With a hardcoded value like urlString = "www.myvideoserver.com/videos/bigbuckbunny.mp4", the video plays fine. However, when urlString is given the value from the intent (coming from the previous activity where the user chose the video), I get the message: "Sorry, Video cannot be played". I've read that one of the common causes is video format, like it's described here and here. I'm almost certain that it is not a format issue because I can play the video when the URL is fixed (and I know this because I can see from Log.d("PVurl", urlString); that the value of urlString is exactly the same as the one I fixed it to. That is, in LogCat, I copy paste the value into the line urlString = getIntent()... // "www.myvideoserver.com/videos/bigbuckbunny.mp4", and it works but not when urlString is set to the intent return value . LogCat Errror panel gives the following:
04-13 17:35:32.786: ERROR/MediaPlayer(2620): error (1, -1007)
04-13 17:35:32.786: ERROR/MediaPlayer(2620): Error (1,-1007)
I've searched around the internet but it doesn't seem that anyone has encountered such an error code before.
I'd very much appreciate if anyone has any idea what could be the problem. Thanks!
public void playvideo () { // obtain URL of the requested video from the intent in previous activity
try
{
urlString = getIntent().getStringExtra("mypackage.fulladdr");
if (urlStr != null)
{
Log.d("PVurl", urlString);
VideoView v = (VideoView) findViewById(R.id.videoView1);
// play video
v.setVideoURI(Uri.parse(urlString));
v.setMediaController(new MediaController(this));
v.start();
v.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
showRatingDialog();
}
});
}
}
catch (Exception e)
{
Log.d("PV_TAG", +e.getMessage());
e.printStackTrace();
}
}
You haven't added the scheme which the Uri needs to find out what it is referring to (http, in your case) .
urlString = "www.myvideoserver.com/videos/bigbuckbunny.mp4" change it to urlString = "http://www.myvideoserver.com/videos/bigbuckbunny.mp4"
(1, -1007) error means:
MEDIA_ERROR_UNKNOWN - "File or network related operation errors."
this may come from a corrupt file
see also javadoc of android.media.MediaPlayer.OnErrorListener#onError
http://developer.android.com/reference/android/media/MediaPlayer.OnErrorListener.html#onError
#param what the type of error that has occurred:
MEDIA_ERROR_UNKNOWN
MEDIA_ERROR_SERVER_DIED
#param extra an extra code, specific to the error. Typically implementation dependent.
MEDIA_ERROR_IO
MEDIA_ERROR_MALFORMED
MEDIA_ERROR_UNSUPPORTED
MEDIA_ERROR_TIMED_OUT
I tried the same thing and was able to get it to work. Perhaps something else is going on in your code. Here is what I have:
// Intent to start the activity that launches the video player
Intent i = new Intent(this, ExampleActivity.class);
i.putExtra("url", "http://www.yourvideo.com/yourvid.m4v");
startActivity(i);
And here is the code that deals with the player:
private MediaController mController;
private Uri videoUri;
private int percentBuffered= 0;
private VideoView videoView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_layout);
mController = new MediaController(this);
videoView = (VideoView) findViewById(R.id.videoView1);
// access String from the intent that launched this Activity
videoUri = Uri.parse(getIntent().getStringExtra("url"));
}
#Override
public void onResume() {
super.onResume();
videoView.setOnCompletionListener(this);
try {
videoView.setVideoURI(videoUri);
mController.setMediaPlayer(videoView);
videoView.setMediaController(mController);
videoView.requestFocus();
videoView.start();
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
protected void onPause() {
super.onPause();
finish();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
mController.show();
return super.onTouchEvent(event);
}
#Override
public int getBufferPercentage() {
return percentBuffered;
}
#Override
public int getCurrentPosition() {
return videoView.getCurrentPosition();
}
#Override
public int getDuration() {
return videoView.getDuration();
}
#Override
public boolean isPlaying() {
return videoView.isPlaying();
}
#Override
public void pause() {
videoView.pause();
}
#Override
public void seekTo(int pos) {
videoView.seekTo(pos);
}
#Override
public void start() {
videoView.start();
}
#Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
percentBuffered = percent;
}
#Override
public void onCompletion(MediaPlayer mp) {
}
public boolean canPause() {
return true;
}
public boolean canSeekBackward() {
return true;
}
public boolean canSeekForward() {
return true;
}
Alright, I found the problem after many futile hours of digging through to find what MediaPlayer error(1, -1007) means.
In reality, it has to do with the rather unfortunate fact that the line
getIntent().getStringExtra("mypackage.fulladdr");
returns a string with an extra white space at the end. I think it's an implementation issue with getIntent().
Anyone knows where to report these kind of bugs, that'd be great.
Thanks to #Akhil and #javaMe for their attempts!

Categories

Resources