Merge pull request #581 from obrand/strings

New remote sound plugin
This commit is contained in:
macdonst
2012-05-28 06:15:07 -07:00
4 changed files with 337 additions and 3 deletions

View File

@@ -0,0 +1,36 @@
# RemoteSound plugin for Phonegap (Android) #
By Olivier Brand
## Adding the Plugin to your project ##
1. To install the plugin, move `Resources.js` to your project's www folder and include a reference to it
in your html files.
<script src="RemoteSound.js"></script>
2. Create a folder called 'com/phonegap/plugin/remotesound' within your project's src folder.
3. And copy the java file into that new folder.
<pre>
mkdir -p <your_project>/src/com/phonegap/plugin/remotesound
cp ./ResourcesPlugin.java <your_project>/src/com/phonegap/plugin/remotesound
</pre>
4. Add a plugin line to `res/xml/plugins.xml`
&lt;plugin name="RemoteSound" value="com.phonegap.plugin.remotesound.RemoteSoundPlugin" /&gt;
## Using the plugin ##
<pre>
<!-- Play a sound -->
window.plugins.remotesound.playRemoteSound({
'soundURL': 'http://myserver/sounds/mysound.wav'
});
<!-- Load remote sounds -->
window.plugins.remotesound.playRemoteSound({
'soundURLs': ['http://myserver/sounds/mysound.wav', 'http://myserver/sounds/mysound2.wav']
});
</pre>

View File

@@ -0,0 +1,48 @@
/*
* RemoteSound
* Implements the javascript access to the phonegap plugin for playing and loading remote sounds
* @author Olivier Brand
*/
/**
* @return the deviceInfo class instance
*/
var RemoteSound = function() {
};
/**
* Play a sound. Parameter is a URI called "soundName"
*
* @param successCallback
* The callback which will be called when directory listing is
* successful
* @param failureCallback
* The callback which will be called when directory listing encouters
* an error
*/
RemoteSound.prototype.playRemoteSound = function(params, successCallback,
failureCallback) {
return cordova.exec(successCallback, failureCallback, 'RemoteSound',
'playRemoteSound', [ params ], true);
};
/**
* Load and cache remote sounds. Parameter is a JSON Array of URLs pointing to sound assets
*
* @param successCallback
* The callback which will be called when directory listing is
* successful
* @param failureCallback
* The callback which will be called when directory listing encouters
* an error
*/
RemoteSound.prototype.loadRemoteSounds = function(params, successCallback,
failureCallback) {
return cordova.exec(successCallback, failureCallback, 'RemoteSound',
'loadRemoteSounds', [ params ], true);
};
cordova.addConstructor(function() {
cordova.addPlugin('remotesound', new RemoteSound());
});

View File

@@ -0,0 +1,250 @@
package com.phonegap.plugin.remotesound;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import org.apache.cordova.api.Plugin;
import org.apache.cordova.api.PluginResult;
import org.apache.cordova.api.PluginResult.Status;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.Context;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnPreparedListener;
/**
* The Class RemoteSoundPlugin allows to perform 2 separate actions: 1- play a
* remote sound given a URL 2- load and cache sounds given some URLs
*
* A usage where load/cache sounds is valuable is when lots of sounds, possibly
* large, needs to be pre-loaded Play sound is first checking that no other
* sound with the same name has been cached. If not, it remotely downloads it
* and cache it on the file system
*/
public class RemoteSoundPlugin extends Plugin implements OnPreparedListener, OnCompletionListener {
private MediaPlayer mp = null;
private static final int BUFFER_SIZE = 1024 * 2;
@Override
public PluginResult execute(String action, JSONArray args, String callbackId) {
PluginResult result = null;
if (action.equals("playRemoteSound")) {
JSONObject obj = null;
try {
obj = args.getJSONObject(0);
String soundURL = obj.has("soundURL") ? obj.getString("soundURL") : null;
if (soundURL != null) {
this.playSound(soundURL);
}
} catch (JSONException jsonEx) {
result = new PluginResult(Status.JSON_EXCEPTION);
}
}
if (action.equals("loadRemoteSounds")) {
JSONArray resourceNames = null;
JSONObject obj = null;
try {
obj = args.getJSONObject(0);
resourceNames = obj.has("soundURLs") ? obj.getJSONArray("soundURLs") : null;
if (resourceNames != null && resourceNames.length() > 0) {
Set<URL> resources = new HashSet<URL>(resourceNames.length());
for (int nbElem = 0; nbElem < resourceNames.length(); nbElem++) {
try {
resources.add(new URL(resourceNames.getString(nbElem)));
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
if (!resources.isEmpty()) {
downloadResources(ctx.getContext(), resources);
}
}
} catch (JSONException jsonEx) {
result = new PluginResult(Status.JSON_EXCEPTION);
}
}
return result;
}
/*
* (non-Javadoc)
*
* @see
* android.media.MediaPlayer.OnPreparedListener#onPrepared(android.media
* .MediaPlayer)
*/
public void onPrepared(MediaPlayer mediaplayer) {
if (mp != null) {
mp.start();
}
}
/*
* (non-Javadoc)
*
* @see
* android.media.MediaPlayer.OnCompletionListener#onCompletion(android.media
* .MediaPlayer)
*/
public void onCompletion(MediaPlayer mediaplayer) {
Timer endSound = new Timer();
endSound.schedule(new TimerTask() {
public void run() {
if (mp != null) {
mp.stop();
mp.release();
mp = null;
}
}
}, 200);
}
/**
* Play sound, either locally (from assets) or remotely via URL.
*
* @param soundUri
* the sound uri
*/
private void playSound(String soundUri) {
try {
mp = new MediaPlayer();
mp.setOnPreparedListener(this);
mp.setOnCompletionListener(this);
FileInputStream fis = null;
String soundName = soundUri.substring(soundUri.lastIndexOf('/') + 1);
try {
fis = ctx.getApplicationContext().openFileInput(soundName);
} catch (FileNotFoundException fne) {
downloadRemoteMedia(ctx.getApplicationContext(), soundUri, soundName);
fis = ctx.getApplicationContext().openFileInput(soundName);
}
mp.setDataSource(fis.getFD());
mp.setVolume(1.0f, 1.0f);
mp.prepare();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Download the url stream to a temporary location and then call the
*
*
* @param context
* the context
* @param mediaUrl
* the media url
* @param mediaFileName
* the media file name
* @return the file
* @throws IOException
* Signals that an I/O exception has occurred.
*/
private void downloadRemoteMedia(Context context, String mediaUrl, String mediaFileName)
throws IOException {
// File downloadingMediaFile = null;
HttpURLConnection cn = null;
FileOutputStream out = null;
InputStream stream = null;
try {
cn = (HttpURLConnection) new URL(mediaUrl).openConnection();
stream = new BufferedInputStream(cn.getInputStream(), BUFFER_SIZE);
// PRIVATE STORAGE. Automatically replace existing files
out = context.openFileOutput(mediaFileName, Context.MODE_PRIVATE);
byte buf[] = new byte[BUFFER_SIZE];
int len1 = 0;
while ((len1 = stream.read(buf)) > 0) {
out.write(buf, 0, len1);
}
out.close();
stream.close();
} finally {
if (cn != null) {
cn.disconnect();
}
try {
out.close();
} catch (IOException e) {
}
try {
stream.close();
} catch (IOException e) {
}
}
}
/**
* Download given resources.
*
* @param context
* the context
* @param resources
* the resources
* @return the number of loaded resources
*/
private Integer downloadResources(Context context, Set<URL> resources) {
int nbLoaded = 0;
for (Iterator<URL> iterator = resources.iterator(); iterator.hasNext();) {
URL url = iterator.next();
try {
downloadRemoteMedia(context, url.toString(),
url.getPath().substring(url.getPath().lastIndexOf('/') + 1));
nbLoaded++;
} catch (IOException ioex) {
ioex.printStackTrace();
}
}
return nbLoaded;
}
}

View File

@@ -23,12 +23,12 @@ var Resources = function() {
*/
Resources.prototype.getStringResources = function(params, successCallback,
failureCallback) {
return PhoneGap.exec(successCallback, failureCallback, 'Resources',
return cordova.exec(successCallback, failureCallback, 'Resources',
'getStringResources', [ params ], false);
};
PhoneGap.addConstructor(function() {
PhoneGap.addPlugin('resources', new Resources());
cordova.addConstructor(function() {
cordova.addPlugin('resources', new Resources());
});