I have some mp3 files on a cloud service.The links are like that https://dns/mp3filename.mp3?dl=1. I can play the files streaming with Vlc media player and I can write the bytes in files in Java. But when I try to play the links in Android media player some times it plays some times I get error(1,-1004) that is media_error_io.
Streaming code:
mp.setDataSource(link);
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
mp.prepareAsync();
mp.setWakeMode(ctx, PowerManager.PARTIAL_WAKE_LOCK);
mp.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
}
});
I have been looking for a library but I could not found one. I just came with the idea about download the file and play it while downloading, but the media player only reads the first bytes I give it to play and called setOnCompletionListener even if the file have been completely downloaded.
That code is in a thread and it's for download the file
try {
File cacheDir = new File(ctx.getCacheDir().getPath()+"/"+"mp3s");
cacheDir.mkdir();
File tempFile = File.createTempFile("mp3" + num, ".mp3", cacheDir);
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(tempFile));
HttpURLConnection httpURLConnection = (HttpURLConnection) new URL(lien).openConnection();
httpURLConnection.setDoInput(true);
BufferedInputStream bufferedInputStream = new BufferedInputStream(httpURLConnection.getInputStream());
byte bytes[] = new byte[1048576];
int len = 0;
int nbre = 0;
int current = 0;
while ((len = bufferedInputStream.read(bytes))!=-1){
bufferedOutputStream.write(bytes,0,len);
bufferedOutputStream.flush();
nbre+= len;
current += len;
onLoadingListener.onLoading(current, httpURLConnection.getContentLength());
if(nbre >= 524288){
nbre = 0;
onReadyListener.onReady(tempFile);
}
}
bufferedOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
onReadyListener.onReady(tempFile); is callback to start the media player like that.
playerMediaDownloader.setOnReadyListener(new PlayerMediaDownloader.OnReadyListener() {
#Override
public void onReady(final File file) {
path = file.getPath();
try {
if(!playing) {
Log.d(getClass().getSimpleName(), "li ready");
mp.setDataSource(file.getPath());
mp.prepare();
mp.start();
Log.d(Player.this.getClass().getSimpleName(), "pos:"+mp.getCurrentPosition());
playing = true;
for (OnTimeChanged l : onTimeChangeds) {
l.onTimeChanged(mp.getCurrentPosition(), mp.getDuration());
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
The media player finished to play the file when it reach the 524288 bytes even if the file has been completely downloaded.
I came with another solution that is set the file file again and play it and it worked but, the sound cut a bit and it is not pretty like that.
mp.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
int currentPosition = mp.getCurrentPosition();
mp.reset();
try {
Player.this.mp.setDataSource(path);
mp.prepare();
mp.seekTo(currentPosition);
mp.start();
} catch (Exception e) {
e.printStackTrace();
}
Log.d(getClass().getSimpleName(), "fini jwe:"+mp.getCurrentPosition());
}
});
Do you have a better solution to help me make it works fine please, like playing the file asynchronously?
Related
String path ="";
mediaPlayer.setDataSource(path); //path url mp3
mediaPlayer.prepare();
textTotalDuration.setText(milliSecondsToTimer(mediaPlayer.getDuration()));
Example read all mp3 in the folder download or specific path
It will be better if you explain you question more. As far as I understand your questing, you want to loop your media player.
if you want to loop your media player then add
mediaPlayer.setLooping(true);
I think that you are asking about how to add data source path. So, if you are asking that, than try this:
String path = Environment.getExternalStorageDirectory()+"/Download/music.mp3";
mediaPlayer.setDataSource(path);
mediaPlayer.prepare();
textTotalDuration.setText(milliSecondsToTimer(mediaPlayer.getDuration()));
And if you are asking about loop media play then:
mediaPlayer.setLooping(true);
read all mp3 & m4a & wav & aac in the folder Music :
private int trackIndex = 0;
private List<String> tracks;
private MediaPlayer mediaPlayer;
private void initMediaPlayer() {
tracks = new ArrayList<>();
addTracksInDirectory("/storage/emulated/0/Music/");////path url mp3
mediaPlayer = new MediaPlayer();
setTrack(trackIndex);
}
private void setTrack(int index) {
try {
trackIndex = index;
mediaPlayer.reset();
mediaPlayer.setDataSource(tracks.get(trackIndex));
mediaPlayer.prepare();
mediaPlayer.start();
// Listen for the end of the track and play the next one
mediaPlayer.setOnCompletionListener(mediaPlayer -> {
trackIndex = (trackIndex + 1) % tracks.size();
setTrack(trackIndex);
});
} catch (IOException e) {
// Handle the error
}
}
private void addTracksInDirectory(String directoryPath) {
File directory = new File(directoryPath);
File[] files = directory.listFiles();
if (files != null) {
for (File file : files) {
if (file.isFile() && isAudioFile(file.getName())) {
tracks.add(file.getAbsolutePath());
}
}
}
}
private boolean isAudioFile(String fileName) {
String[] audioFileExtensions = {".mp3", ".m4a", ".wav", ".aac"};
for (String extension : audioFileExtensions) {
if (fileName.endsWith(extension)) {
return true;
}
}
return false;
}
First of all create a list and add all the songs.
final ArrayList<String> playList = new ArrayList<String>();
// Add yours songs to the list that needs to be played NEXT.
Now add a completion listener for the playlist, so after current song is completed it will play the next.
player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
if(playList.size() == 0) return; // played all so return.
String path = playList.remove(0); // get & remove the song from the playlist we are gonna play.
// Play the song
mediaPlayer.setDataSource(path);
mediaPlayer.prepare();
mediaPlayer.start();
}
});
I would like to create a very simple App with AndroidStudio to download an image file from the internet, but it just won't work at all. I've tried everything, checked the code, looked up similar questions on the internet, and tried with all sorts of picture sizes and formats. But I always get the error message at the bottom of the code. Here is the code:
And Second question: How could I rewrite this very same code, but with the help of an IntentService class? The answer to either one of these questions would be very appreciated.
try{
URL fileurl = new URL(urlstring);
URLConnection urlConnection = fileurl.openConnection();
urlConnection.connect();
InputStream inputStream = new BufferedInputStream(urlConnection.getInputStream(), 9200);
File downloadordner = new File(Environment.getExternalStorageDirectory(), "Download");
if(!downloadordner.exists()){
downloadordner.mkdirs();
}
File downloadedFile = new File(downloadordner, "myFirstProject" + System.currentTimeMillis()+".png");
OutputStream outputstream = new FileOutputStream(downloadedFile);
byte[] buffer = new byte[1024];
int read;
while((read = inputStream.read(buffer)) != -1){
outputstream.write(buffer, 0, read);
}
outputstream.flush();
outputstream.close();
inputStream.close();
final Bitmap bitmap = BitmapFactory.decodeFile(downloadedFile.getAbsolutePath());
runOnUiThread(new Runnable() {
#Override
public void run() {
image.setImageBitmap(bitmap);
progressDialog.dismiss();
}
});
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), "THIS IS THE ERROR MESSAGE I ALWAYS KEEP GETTING!", Toast.LENGTH_SHORT).show();
progressDialog.dismiss();
}
});
}
The "Download" String is the name of the directory in the smartphone the the picture should me stored in! I would be very glad and grateful if someone could point me out what leads to this error message! Thanx :)
I am trying to programmatically change a ringtone in API 23.
I have looked at a lot of examples on Stack Overflow and they all seem to "work" (i.e. not crash) but they do not "work" as in the mp3 doesn't become the ringtone - instead the ringtone becomes simply zero noise. So obviously /something/ happened. (no crash, now no ringtone noise)
I have split this off into a small side project to try to isolate it because it's driving me up the wall - I hope maybe you guys can see something I can't!
I have:
placed the mp3 in \res\raw
I have verified I can play the mp3 fine with this code
MediaPlayer mPlayer = MediaPlayer.create(me, R.raw.meepmeep);
mPlayer.start();
added <uses-permission android:name="android.permission.WRITE_SETTINGS"/> to the manifest
managed the api 22 permission scenario in java
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.System.canWrite(this)) {
new AlertDialog.Builder(this)
.setMessage("Please Assign Meep Meep Write Permissions")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_WRITE_SETTINGS);
intent.setData(Uri.parse("package:" + getPackageName()));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
startActivity(intent);
} catch (Exception e) {
Log.e("MainActivity", "error starting permission intent", e);
}
}
})
.show();
return;
}
used a method to carefully fetch the mp3 path from the assets folder
public String LoadFile(String fileName, boolean loadFromRawFolder) throws IOException
{
InputStream iS;
if (loadFromRawFolder)
{
int rID = resources.getIdentifier("meep.example.com.meep:raw/"+fileName, null, null);
iS = resources.openRawResource(rID);
}
else
{
iS = resources.getAssets().open(fileName);
}
byte[] buffer = new byte[iS.available()];
iS.read(buffer);
ByteArrayOutputStream oS = new ByteArrayOutputStream();
oS.write(buffer);
oS.close();
iS.close();
return oS.toString();
}
tried to carefully copy the file to the local storage (as a desperate attempt to get it to work as well as tried to assign it from the raw assets lib
String path = "";
try {
LoadFile("meepmeep", true);
} catch (IOException e) {
//display an error toast message
Toast toast = Toast.makeText(me, "File: not found!", Toast.LENGTH_LONG);
toast.show();
}
//copy file to device
File newSoundFile = new File(path);
//Uri mUri = Uri.parse("android.resource://meep.example.com.meep/R.raw.meepmeep");
Uri mUri = MediaStore.Audio.Media.getContentUriForPath(newSoundFile.getAbsolutePath());
ContentResolver mCr = getContentResolver();
AssetFileDescriptor soundFile;
try {
soundFile= mCr.openAssetFileDescriptor(mUri, "r");
try {
byte[] readData = new byte[1024];
FileInputStream fis = soundFile.createInputStream();
FileOutputStream fos = new FileOutputStream(newSoundFile);
int i = fis.read(readData);
while (i != -1) {
fos.write(readData, 0, i);
i = fis.read(readData);
}
fos.close();
} catch (IOException io) {
}
} catch (FileNotFoundException e) {
soundFile=null;
}
ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.DATA, newSoundFile.getAbsolutePath());
values.put(MediaStore.MediaColumns.TITLE, "Meep Meep");
values.put(MediaStore.MediaColumns.MIME_TYPE, "audio/mp3");
values.put(MediaStore.MediaColumns.SIZE, newSoundFile.length());
values.put(MediaStore.Audio.Media.ARTIST, "RoadRunner");
//values.put(MediaStore.Audio.Media.DURATION, 230);
values.put(MediaStore.Audio.Media.IS_RINGTONE, true);
values.put(MediaStore.Audio.Media.IS_NOTIFICATION, true);
values.put(MediaStore.Audio.Media.IS_ALARM, true);
values.put(MediaStore.Audio.Media.IS_MUSIC, false);
//Insert it into the database
Uri uri = MediaStore.Audio.Media.getContentUriForPath(newSoundFile.getAbsolutePath());
Uri newUri = mCr.insert(uri, values);
try {
RingtoneManager.setActualDefaultRingtoneUri(
me,
RingtoneManager.TYPE_RINGTONE,
newUri
);
}
catch (Throwable t){
setMessage("meepmeep error");
}
setMessage("meepmeep set");
}
but nothing seems to work. It always fails becuase either soundFile= mCr.openAssetFileDescriptor(mUri, "r"); returns null or if I decline to use that code block and try to change ringtone direct from \res\raw\ folder then it simply gives a blank sound for ringtone.
I am totally stuck for ideas?
My app uses the serialization to store data. Save() function is called in Activity the onStop() method. Since the data was small, everything was fine. Today serialization takes a time, and I was surpised to find a way to corrupt the data.
If I exit from the app by Home button, then quickly manually kill the app form backround activities screen (on long home button tap), my data seems to be lost. I think its because app was written to file and was interrupted.
Is there an opportunity to forbide to kill the process until my save() method works? I was thinking to rewrite serialisation by myself, and it can be faster in times, but as I understand sometimes this problem will happen again.
Thank you.
// Activity code:
#Override
protected void onStop(){
try {
ms.save();
} catch (IOException e) {
e.printStackTrace();
}
super.onStop();
}
// Singleton save fucntion
public void save() throws IOException {
Runnable r = new Runnable()
{
#Override
public void run()
{
try {
FileOutputStream fos;
ObjectOutputStream os;
if (data != null){
fos = context.openFileOutput("Data.dat", Context.MODE_PRIVATE);
os = new ObjectOutputStream(fos);
os.writeObject(data);
os.flush();
os.close();
fos.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
};
Thread t = new Thread(r);
t.start();
}
Ok, I got it using the IntentService in Background. Thanks to RyanB for the help.
save() in Singleton:
Intent mServiceIntent = new Intent(context, ServiceDatastore.class);
mServiceIntent.setData(Uri.parse("dsf"));
context.startService(mServiceIntent);
ServiceDatastore.java
#Override
protected void onHandleIntent(Intent workIntent) {
final int myID = 1234;
Intent intent = new Intent(); // empty Intent to do nothing in case we click on notification.
PendingIntent pendIntent = PendingIntent.getActivity(this, 0, intent, 0);
Notification notice = new Notification(R.drawable.icon, getString(R.string.saving), System.currentTimeMillis());
notice.setLatestEventInfo(this, "Saving...", "", pendIntent);
notice.flags |= Notification.FLAG_NO_CLEAR;
startForeground(myID, notice);
try {
Singleton ms = Singleton.getInstance(this);
FileOutputStream fos;
ObjectOutputStream os;
//copy settings
if (ms.data != null) {
fos = this.openFileOutput("Data.dat", Context.MODE_PRIVATE);
os = new ObjectOutputStream(fos);
os.writeObject(ms.data);
os.flush();
os.close();
fos.close();
}
}
catch (Exception e){
e.printStackTrace();
}
stopForeground(true); // to kill the process if the app was killed.
}
The requirements: ensure that the PDF document is deleted from the device after the user has left the PDF viewing screen
The problem: on certain devices (Samsung 4.4.2 and Samsung 4.1.2 for sure, but not Asus 4.2.1) only the first time that the PDF is requested after restarting the application an error message is displayed stating "This document cannot be opened". Thereafter the PDF will load normally. I'm thinking this is a timing issue due to processes that need to be started the first time, but are running after the first attempted load.
The code: note that createFile() is called first, then startActivityForIntentResult()
private File file;
private ArrayList<Uri> uriList = new ArrayList<Uri>();
private void createFile() {
int fileNameLength = pdfFileName[0].length();
String fileName = pdfFileName[0].substring(0, fileNameLength - 4) + DateTime.now();
String fileExtension = pdfFileName[0].substring(fileNameLength - 4, fileNameLength);
byte[] content = Base64.decodeBase64(pdfData[0].getBytes());
BufferedOutputStream outputStream = null;
try {
File path = new File(getExternalFilesDir(null).getAbsolutePath(), "temp");
if (!path.exists()) {
path.mkdirs();
}
file = new File(path, fileName + fileExtension);
outputStream = new BufferedOutputStream(new FileOutputStream(file));
outputStream.write(content);
file.deleteOnExit();
uriList.add(Uri.fromFile(file));
}
catch (FileNotFoundException ex) {
ex.printStackTrace();
}
catch (IOException ex) {
ex.printStackTrace();
}
finally {
try {
if (outputStream != null) {
outputStream.flush();
outputStream.close();
}
}
catch (IOException ex) {
ex.printStackTrace();
}
}
}
private static int REQUEST_CODE = 1;
private Intent intent;
private void startActivityForIntentResult() {
if (file.exists()) {
Uri targetUri = uriList.get(0);
intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(targetUri, "application/pdf");
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
try {
startActivityForResult(intent, REQUEST_CODE);
}
catch (ActivityNotFoundException e) {
toastTitle = "Error Displaying PDF";
toastMessage = "Please make sure you have an application for viewing PDFs installed on your device and try again.";
toast = new GenericCustomToast();
toast.show(toastTitle, toastMessage, QueryForPDF.this);
}
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (resultCode == RESULT_CANCELED && requestCode == REQUEST_CODE) {
if(!file.delete()) {
file.delete();
}
}
searchAgain();
}
#Override
public void onBackPressed() {
super.onBackPressed();
if(!file.delete()) {
file.delete();
}
searchAgain();
}
#Override
public void onStop() {
super.onStop();
if(!file.delete()) {
file.delete();
}
}
#Override
public void onDestroy() {
super.onDestroy();
if(!file.delete()) {
file.delete();
}
}
EDIT: I have also tried implementing a callback to be absolutely certain that createFile() has finished it's work. I even tried adding delays (of different time increments) as well as adding (the completely unnecessary) flags for Intent.FLAG_GRANT_READ_URI_PERMISSION, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, and Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION.
I still don't know why this works, but here's the solution in case anyone else runs into this issue:
It's the directory where the file is created. For some reason on the two Samsung devices there was something different in how the files were either accessed or created versus the Asus device. So File path = new File(getExternalFilesDir(null).getAbsolutePath(), "temp"); becomes File path = new File(getExternalCacheDir().getAbsolutePath()); and the problem goes away.