What i want to do in my project is to play audio songs which are inside my Box account for that i am using box api . As i know we can not provide direct audio streaming for audio files in Box api for that i am trying to implement progressive download and playing audio file from sd card . i know i can play song inside on complete method of download but this is taking more time to download and than playing file . for that what i did i wrote my code for playing audio inside on progress method of downloading file but this method is getting called so many times because of that same song is playing multiple time at a time.
So is there any way to write code for progressive audio playing in Box api .if yes where should i write that ?
* Download a file and put it into the SD card. In your app, you can put the file wherever you have access to.
*/
final Box box = Box.getInstance(Constants.API_KEY);
String PATH = Environment.getExternalStorageDirectory() + "/chaseyourmusic"+folderpath;
File file = new File(PATH);
file.mkdirs();
final java.io.File destinationFile = new java.io.File(PATH + "/"
+ URLEncoder.encode(items[position].name));
/* final java.io.File destinationFile = new java.io.File(Environment.getExternalStorageDirectory() + "/"
+ URLEncoder.encode(items[position].name));*/
final ProgressDialog downloadDialog = new ProgressDialog(Browse.this);
downloadDialog.setMessage("Downloading " + items[position].name);
downloadDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
downloadDialog.setMax((int) items[position].file.getSize());
downloadDialog.setCancelable(true);
downloadDialog.show();
Toast.makeText(getApplicationContext(), "Click BACK to cancel the download.", Toast.LENGTH_SHORT).show();
final Cancelable cancelable = box.download(authToken, items[position].id, destinationFile, null, new FileDownloadListener() {
#Override
public void onComplete(final String status) {
downloadDialog.dismiss();
if (status.equals(FileDownloadListener.STATUS_DOWNLOAD_OK)) {
//Able to play audio here from sd card but this is playing after completion of download only which is taking more time .
}
else if (status.equals(FileDownloadListener.STATUS_DOWNLOAD_CANCELLED)) {
Toast.makeText(getApplicationContext(), "Download canceled.", Toast.LENGTH_LONG).show();
}
}
#Override
public void onIOException(final IOException e) {
e.printStackTrace();
downloadDialog.dismiss();
Toast.makeText(getApplicationContext(), "Download failed " + e.getMessage(), Toast.LENGTH_LONG).show();
}
#Override
public void onProgress(final long bytesDownloaded) {
downloadDialog.setProgress((int) bytesDownloaded);
//Want to write code here but this method is getting called multiple times which is creating problem in playing audio files from sd card .
}
});
downloadDialog.setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
cancelable.cancel();
}
});
Thanks
Use something like these:
http://code.google.com/p/npr-android-app/source/browse/Npr/src/org/npr/android/news/StreamProxy.java?r=41487c03f461942a5747378d197320412fe99442
http://www.java2s.com/Code/Android/File/StreamProxy.htm
Basically for progressive streaming, you proceed with the download as usual (in background) and you run a stream proxy (like a server in background) and push the data to your media player (you can use external media player or write a simple one by yourself, it is only few lines of code with Android media framework)
I have use something very similar with success.
In fact I am using the answer from this post (with minor modification)
MediaPlayer stutters at start of mp3 playback
Related
My problem is that I do not manage to create a directory on a SD card that is plugged in an Android portable device.
Below is the Java code I am trying to get to work: I am trying to create the directory sable under /storage/BF4F-1107/:
public class AnActivity extends AppCompatActivity
{
private static final int N_CREATE_DIRECTORY = 1;
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// SD card
String s_sdCardStorage = "/storage/BF4F-1107/";
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("file/*");
intent.putExtra(Intent.EXTRA_TITLE, s_destFilePath);
startActivityForResult(intent, N_CREATE_DIRECTORY);
// HERE
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
if(requestCode == N_CREATE_DIRECTORY)
{
if(data != null)
{
Uri uri = data.getData();
DocumentFile docFileSDCardStorage = DocumentFile.fromSingleUri(this, uri);
try
{
DocumentFile docFileDir = docFileSDCardStorage.createDirectory("sable");
}
catch(UnsupportedOperationException exn)
{
System.out.println(exn.getMessage());
}
}
}
}
}
What happens is:
the code in onCreate() is executed.
Then the program blocks at // HERE.
On the portable device, appears a "dialog" which shows /storage/BF4F-1107/ and a button Save which I "press".
Once "pressed", the code in onActivityResult() is executed.
But the result is that the directory sable under /storage/BF4F-1107/ is not created.
And the execution path goes through the catch clause, the exception UnsupportedOperationException is raised and null is printed at System.out.println(exn.getMessage());.
Edit 2: An empty file _storage_BF4F-1107_ is created under /storage/BF4F-1107/.
Can you help me make this code work?
Additionally, I would like the directory sable to be created silently.
I do not want to user to have to touch "Save".
I am trying to use the Storage Access Framework (https://developer.android.com/training/data-storage/shared/documents-files) because the mkdirs method of the java.io.File class doesn't work (I get permission denied exceptions) when I try to create a directory on the SD card.
Edit: my Android version is 6.0.1
Thank you.
Use ACTION_OPEN_DOCUMENT_TREE to let the user choose de SD card.
After that you can create as many files and directorys in the choosen directory.
If you only want to create one file with SAF use ACTION_CREATE_DOCUMENT where the user chooses the location and file name.
I trying to make an app, with a lot of short sounds(more than 20), using Sound Pool.
But when i load that sounds, it take like 3-10 sec to load it.
How can i improve speed of loading?
Here is Function of loading
private int loadSound(String filename) {
AssetFileDescriptor assetFileDescriptor;
try {
assetFileDescriptor = assetManager.openFd(filename);
}
catch (IOException e){
e.printStackTrace();
return -1;
}
return soundPool.load(assetFileDescriptor,1);
}
Use .OGG files at the lowest sample rate you can tolerate, like 96kb/s. This will create the smallest files so they load faster. I had a lot of problems with loading/playing sounds using .WAV files, they all went away when I converted them to .OGG files.
Do your sound loading off the main UI thread. If you need to know when the sound is loaded, use an OnLoadCompleteListener:
mSoundPool.setOnLoadCompleteListener(new OnLoadCompleteListener() {
#Override
public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
Log.d(TAG, "soundpool onLoadComplete, sampleId = " + sampleId + ", status = " + status);
// ... sound is ready to play
}
});
// sound load should happen off the UI thread
new Thread() {
#Override
public void run() {
mSoundId = mSoundPool.load(getActivity(), R.raw.sound1, 1);
// ... load other sounds here
}
}.start();
I embedded the audio files so I could use raw resource ids. If you have to load from files, grab all your filenames and send them off to a load method inside a non-UI thread.
My Android app needs to download a MP3 track and add it to the user's media library.
I haven't found any good documentation on this so I was wondering if it is as simple as storing the MP3 in the Music directory? If so, what would be the location of the user's music directory?
Use MediaScanner
String mp3path = "Your MP3 file path";
MediaScannerConnection msc = new MediaScannerConnection(yourcontext,
new MediaScannerConnection.MediaScannerConnectionClient() {
#Override
public void onScanCompleted(String path, Uri uri){
msc.disconnect();
}
#Override
public void onMediaScannerConnected() {
msc.scanFile(mp3path, null);
}
});
msc.connect();
It's just download the mp3 file just like any other file type.
you should find the directory to save by calling the Environment:
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC);
and you can use the scanFile method to give a hint for the media scanner that the new music is there:
I am writing a custom event and would like some help please. Most of what I am about to talk about is based on the help provided at Custom event listener on Android app
So here is my issue. I am writing an app that needs to download updated images from the web, store the images on the phone, then later display those images. Basically, I download any needed images during a splash screen. Then when the images are downloaded and stored, the splash screen clears and any necessary (newly downloaded) images are displayed on the screen. Here is the problem: the download process is done via an asynctask so the part where the images are loaded on to the screen can't be done inside the asynctask. It has to be done on the main UI thread. I would like to create an event and a custom event listener for the main thread to listen for that basically tells the main UI thread that it is safe to start loading the downloaded images from memory.
According to the discussion from the link above, I came up with this so far... a download listener interace
public interface DataDownloadListener {
void onDownloadStarted();
void onDownloadFinished();
}
an event class...
public class DataDownloadEvent {
ArrayList<DataDownloadListener> listeners = new ArrayList<DataDownloadListener>();
public void setOnDownload(DataDownloadListener listener){
this.listeners.add(listener);
}
}
My problem is that I don't understand where to put the last two steps in those instructions. I thought I would have to put the listener and event inside the class that actually initiates the downloads. But where? Here is my function that initiates the download and saves it to the device:
public String download(String sourceLocation) {
String filename = "";
String path = "";
try {
File externalStorageDirectory = Environment
.getExternalStorageDirectory();
URL urlTmp = new URL(sourceLocation);
filename = urlTmp.getFile()
.substring(filename.lastIndexOf("/") + 1);
path = externalStorageDirectory + PATH;
// check if the path exists
File f = new File(path);
if (!f.exists()) {
f.mkdirs();
}
filename = path + filename;
f = new File(filename);
//only perform the download if the file doesn't already exist
if (!f.exists()) {
Bitmap bitmap = BitmapFactory.decodeStream(urlTmp.openStream());
FileOutputStream fileOutputStream = new FileOutputStream(
filename);
if (bitmap != null) {
bitmap.compress(getFormat(filename), 50, fileOutputStream);
Log.d(TAG, "Saved image " + filename);
return filename;
}
}
else{
Log.d(TAG, "Image already exists: " + filename + " Not re-downloading file.");
}
} catch (MalformedURLException e) {
//bad url
} catch (IOException e) {
//save error
}
return null;
}
And the last step about registering the listener, where do I put that? The instructions say to put that somewhere during initialization. Does that mean in the onCreate method of my main activity? outside the class in the import section of the main activity? Never done a custom event before, so any help would be appreciated.
According to the discussion from the link above, I came up with this so far... a download listener interace
public interface DataDownloadListener {
void onDownloadStarted();
void onDownloadFinished();
}
an event class...
public class DataDownloadEvent {
ArrayList<DataDownloadListener> listeners = new ArrayList<DataDownloadListener>();
public void setOnDownload(DataDownloadListener listener){
this.listeners.add(listener);
}
}
Ok...
Now in your download procedure, at the start of the download, cycle all the elements on the listeners ArrayList and invoke the onDownloadStarted event to inform all your listeners that the download is just started (in this event i presume you'll need to open the splashscreen).
Always in your download procedure, at the and of the download, cycle all the elements on the listeners ArrayList and invoke the onDownloadFinished event to inform all your listeners that the download is finished (now close the splashscreen).
How to cycle listeners on download completed
foreach(DataDownloadListener downloadListener: listeners){
downloadListener.onDownloadFinished();
}
How to cycle listeners on download started
foreach(DataDownloadListener downloadListener: listeners){
downloadListener.onDownloadStarted();
}
Don't make it static if possible... In the class that you'll use to download your files, simply add what you put in your DataDownloadEvent class (listeners arrayList and facility methods for adding and removing). You have no immediate need to use a class in that way (static members I mean).
Example
public class DownloadFileClassExample{
private ArrayList<DataDownloadListener> listeners = new ArrayList<DataDownloadListener>();
public DownloadFileClassExample(){
}
public void addDownloadListener(DataDownloadListener listener){
listeners.add(listener);
}
public void removeDownloadListener(DataDownloadListener listener){
listeners.remove(listener);
}
//this is your download procedure
public void downloadFile(){...}
}
Then access you class in this way
DownloadFileClassExample example = new DownloadFileClassExample();
example.addDownloadListener(this); // if your class is implementing the **DataDownloadListener**
or use
example.addDownloadListener( new DataDownloadListener{...})
I'm trying to pause a recording on an incoming call and resume it later. i'm using the andriod mediarecorder and trying to record in MPEG4. I tried pause/resume with resetting/stopping a recording and starting it with the setOutputFile(fd), fd being the filedescriptor of the audio file that was stopped/paused and hoped it would append but i had no luck. Is there a way to achieve this or append two recordings or should i give up on mediarecorder.
code:
private MediaRecorder media_recorder;
private String file_path = null;
public void startRecording(path)
{
file_path = path
media_recorder= new MediaRecorder();
media_recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
media_recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
media_recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
media_recorder.setOputputFile(path);
media_recorder.prepare();
}
public void pauseRecording()
{
media_recorder.stop();
media_recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
media_recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
media_recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
FileOutputStream paused_file = new FileOutputStream(file_path);
media_recorder.setOutputFile(paused_file.getFD());
}
public void resumeRecording()
{
media_recorder.prepare();
media_recorder.start();
}
pauseRecording() stops the recording but resume fails with message start failed.
Simple answer for your question is NO YOU CAN'T
Once you are recording the only possible actions are stop and reset.
So try to save your Call to SDCard after you Stop , and then again start Fresh Record and Stop it. Finally Combine both Audio File into one Audio file.
Record the audio as .wav file and Combine using this format.