I manage to play several sounds on Android (Cordova 4.1) but now I would like to dynamically change the volume of each video.
My code for playing sounds is the following:
function onDeviceReady() {
document.querySelector("#play").addEventListener("touchend", playMP3(), false);
function playMP3() {
var mp3_1 = getMediaURL("audio/sound1.mp3");
var mp3_2 = getMediaURL("audio/sound2.mp3");
media1 = new Media(mp3_1, null, mediaError);
media2 = new Media(mp3_2, null, mediaError);
media1.play();
media2.play();
}
function getMediaURL(s) {
if(device.platform.toLowerCase() === "android") return "/android_asset/www/" + s;
return s;
}
function mediaError(e) {
alert('Media Error');
alert(JSON.stringify(e));
}
}
Then I would like to control volume with something like media1.volume = 0.5; from outside the onDeviceReady function but I can't make it work...
Any idea of what I'm missing?
Finally, the whole package to play and control sounds with Cordova 4.1 and Android 4.4 wich worked for me. To set the volume call the function with something like onclick=setVolume(media1, "0.5")
Hope it can help !
var media1 = null;
var media2 = null;
//set volume of one sound
function setVolume(media, volume) {
if (media) {
media.setVolume(volume);
}
}
//play the 2 sounds at the same time
function playMP3() {
var mp3_1 = getMediaURL("audio/media1.mp3");
var mp3_2 = getMediaURL("audio/media2.mp3");
media1 = new Media(mp3gauche, null, mediaError);
media2 = new Media(mp3droite, null, mediaError);
media1.play();
media2.play();
}
//for android devices (need the Device Cordova plugin)
function getMediaURL(s) {
if(device.platform.toLowerCase() === "android") return "/android_asset/www/" + s;
return s;
}
//help to get log when errors occur
function mediaError(e) {
alert('Media Error');
alert(JSON.stringify(e));
}
//launch the 2 sounds when the device is ready
function onDeviceReady() {
document.querySelector("#playMp3").addEventListener("touchend", playMP3(), false);
}
Related
I have created an Android app from html5 and JavaScript using ionic/Cordova framework. In there I create and play an audio object as:
var myAudio = new Audio("myfile.mp3") ;
myAudio.play();
If I install the generated apk on Android API 21, audio plays fine. If I install it on API 19 it doesn't play.
Any help on this is really appreciated.
Hi did you install the cordova media plugin?
I did something like that in the past with cordova 4.0.0 (definitely worked on android 19 (4.4.2 to be accurate)):
AckSound:function(){
try{
var pathMedia;
if(device.platform ==='iOS'){
pathMedia ='';
} else {
pathMedia = app.getCordovaPath();
}
var snd =new Media(pathMedia+'mySound.mp3');
// Update media position every second
var mediaTimer = null;
mediaDuration = snd.getDuration();
console.log("mediaDuration is " + mediaDuration);
snd.play();
if(mediaTimer==null){
mediaTimer = setInterval(function () {
// get media position
snd.getCurrentPosition(
// success callback
function (position) {
if (position > 0) {
console.log((position) + " sec");
} else {
//if position isn t > 0, the file is over
snd.stop();
clearInterval(mediaTimer);
mediaTimer = null;
snd.release();
delete snd;
}
},
// error callback
function (e) {
console.log("Error getting pos=" + e);
}
);
}, 100);
};
delete snd;
} catch(err){
console.log("Error: in AudioManagement.AckSound(), Error is " + err);
}
console.log("AudioManagement.AckSound() stops");
}
},
Here is a full example: https://github.com/nyluje/TestMediaPluginCordova
I've been trying to implement the Phonegap Media plugin to playback an audio file.
I understand I'll need to refer to the correct file path (android_asset/www/...) and use an .amr file as per the docs but it's still returning with a code: 1 error, which I believe has something to do with a disruption in getting the file.
function sound(){
var backgroundMusic = null;
var musicPlaying = false;
function playAudio(){
function getPhoneGapPath() {
var devicePlatform = device.platform;
if (devicePlatform === "iOS") {
path = "";
} else if (devicePlatform === "Android" || devicePlatform === 'android') {
path = "/android_asset/www/";
}
return path;
};
var backgroundMusic = new Media(getPhoneGapPath() + 'audio/bg.amr', success, error);
function success(){
backgroundMusic.release();
alert('success');
}
function error(e){
alert(getPhoneGapPath() + 'audio/bg.amr');
alert(JSON.stringify(e));
}
if (!musicPlaying) {
backgroundMusic.play();
musicPlaying = true;
$(".audio-off").css('display', 'block');
$(".audio-on").css('display', 'none');
}
else if (musicPlaying){
backgroundMusic.stop();
musicPlaying = false;
$(".audio-on").css('display', 'block');
$(".audio-off").css('display', 'none');
};
}
$(".audio-on, .audio-off").on("touchstart", function() {
playAudio();
});
}
window.onload = function() {
document.addEventListener("deviceready", onDeviceReady, false);
}
function onDeviceReady(){
sound();
//other code...
}
After reading so many questions and tutorials I can't see where I've gone wrong. The media plugin is also definitely included in my config.xml as well.
I'm testing on my Nexus 5 with Lollipop 5.0.1.
Any help would be greatly appreciated, thanks :-)
I am building an with cordova.js library [version 3.4.1] and I would also like to debug it as web page directly using the web browser.
There are some issues in iOS emulator when loading dynamically the external cordova.js library [I have 2 version specific for android and iOS]
I have this piece of code in place to deal with this:
//check if mobile or local browser:
var isMobile = true;
if (document.URL.indexOf("local") > 0) {
isMobile = false;
}
var deviceReadyDeferred = $.Deferred();
var jqmReadyDeferred = $.Deferred();
function onDeviceReady () {
deviceReadyDeferred.resolve();
}
if (isMobile) {
$(document).bind('mobileinit', function () {
$.mobile.allowCrossDomainPages = true;
jqmReadyDeferred.resolve();
var useragent = navigator.userAgent;
var loadScript = function (url) {
url = url.replace(/\//, '\\/');
document.write('<script charset="utf-8" src="' + url + ' "><\/script>');
};
if (/Android/i.test(useragent)) {
$.getScript('js/lib/cordova_android.js', function (data, textStatus, jqxhr) {
document.addEventListener("deviceReady", onDeviceReady, false);
});
} else {
loadScript('js/lib/cordova_ios.js');
setTimeout(function () {
document.addEventListener("deviceReady", onDeviceReady, false);
}, 500);
}
});
} else {
jqmReadyDeferred.resolve();
onDeviceReady();
}
So when the page is requested with localhost... then the isMobile is set to false.
Is there a reason why iOS [6.1] does not load the external script like Android did [with jQuery getscript ] instead than the horrible hack ? I tried to debug and it seems that iOS is reporting status error 400 when requesting the script.
Followed the logic used in this other SO question:
Issue with dynamically loaded phonegap.js
UPDATE:
Following the suggestion of the accepted answer, I rewrote the whole function and now it is working well both in iOS / ANDROID and local browser:
var deviceReadyDeferred = $.Deferred();
var jqmReadyDeferred = $.Deferred();
(function () {
//check if mobile or local browser:
var isMobile = true;
var useragent = navigator.userAgent;
var cordova_js = 'cordova_';
if (/Android/i.test(useragent)) {
cordova_js += 'android.js'
} else if ((/iPhone/i.test(useragent)) || (/iPad/i.test(useragent))) {
cordova_js += 'ios.js'
} else {
// local browser testing
isMobile = false;
jqmReadyDeferred.resolve();
onDeviceReady();
}
if (isMobile) {
$(document).bind('mobileinit', function () {
$.mobile.allowCrossDomainPages = true;
jqmReadyDeferred.resolve();
var url = document.URL;
url = url.substring(0, url.lastIndexOf("/"));
$.getScript(url + '/js/lib/' + cordova_js, function (data, textStatus, jqxhr) {
document.addEventListener("deviceReady", onDeviceReady, false);
});
});
}
function onDeviceReady () {
deviceReadyDeferred.resolve();
}
})();
Your isMobile check is prone to break. Think of a remote URL like this:
http://www.somesite.com/local/foo/bar
And probably the "local" URL in iOS looks different. Try logging the document.URL in iOS to check, or maybe show it in an alert if console is not an option.
I have the following code snippet to enable extension after firefox quit,
observe: function (subject, topic, data) {
if (topic == "quit-application") {
LOG("inside quit-application Testing ");
var os = Components.classes["#mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
//os.addObserver(this, "http-on-examine-cached-response", false);
os.addObserver(this, "quit-application", false);
var appInfo = Components.classes["#mozilla.org/xre/app-info;1"]
.getService(Components.interfaces.nsIXULAppInfo);
var tempappVersion = appInfo.version;
var appVersion = tempappVersion.split(".");
// adding add-on listener dsable event on add-on for FF4 and later versions.
if (appVersion[0] >= 4) {
setAddonEnableListener();
LOG("\napp-startup Testing from javascript file....");
}
return;
}
}
And inside the setAddonEnableListener I am trying to enable the extension like this:
function setAddonEnableListener() {
try {
alert("setAddonEnableListener akbar nsListener called from ");
Components.utils.import("resource://gre/modules/AddonManager.jsm");
AddonManager.getAddonByID("somename#extension.com", function(addon)
{
if (addon.userDisabled)
addon.userDisabled = false;
});
} catch (ex) {
}
}
And I am registering the quit-application event var like this:
myModule = {
registerSelf: function (compMgr, fileSpec, location, type) {
var compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
compMgr.registerFactoryLocation(this.myCID,
this.myName,
this.myProgID,
fileSpec,
location,
type);
var catMgr = Components.classes["#mozilla.org/categorymanager;1"].getService(Components.interfaces.nsICategoryManager);
catMgr.addCategoryEntry("app-startup", this.myName, this.myProgID, true, true);
catMgr.addCategoryEntry("quit-application", this.myName, this.myProgID, true, true);
}
When Firefox quits, inside quit-application Testing message is not getting displayed. What am I doing wrong here?
There is no category quit-application. You should receive app-startup notification (or rather profile-after-change starting with Firefox 4) and register your observer for quit-application:
observe: function (subject, topic, data) {
if (topic == "app-startup" || topic == "profile-after-change") {
var observerService = Components.classes["#mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
observerService.addObserver(this, "quit-application", false);
}
else if (topic == "quit-application") {
var observerService = Components.classes["#mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
observerService.removeObserver(this, "quit-application");
...
}
}
To quote the documentation:
Unless otherwise noted you register for the topics using the nsIObserverService.
And there is no note about registration via category manager on any shutdown notifications.
Btw, I sincerely recommend XPCOMUtils for component registration. You shouldn't need to write the module definition yourself.
I'm trying to write an Android app with PhoneGap that contains multiple HTML files. In every HTML I would like to include an mp3 file that the user can play and stop. This has worked so far. The problem that I encounter is when trying to put multiple mp3 files in one file.
The thing that I would like to achieve is to put the general audio player javescript in one file and to tell in the HTML which file should be played. Is this possible and how? Thanks!
My code for one of the html files looks like this:
<script type="text/javascript" charset="utf-8" src="phonegap.js"></script>
<script type="text/javascript" charset="utf-8">
//-------------------------------------------------------------------------
// Audio player
//-------------------------------------------------------------------------
var media1 = null;
var media1Timer = null;
var audioSrc = null;
/**
* Play audio
*/
function playAudio(url) {
console.log("playAudio()");
console.log(" -- media="+media1);
//var src = "/android_asset/www/audio/01.mp3";
var src = "/android_asset/www/audio/01.mp3";
if (url) {
src = url;
}
// Stop playing if src is different from currently playing source
if (src != audioSrc) {
if (media1 != null) {
stopAudio();
media1 = null;
}
}
if (media1 == null) {
media1 = new Media(src,
function() {
console.log("playAudio():Audio Success");
},
function(err) {
console.log("playAudio():Audio Error: "+err);
setAudioStatus("Error: " + err);
},
function(status) {
console.log("playAudio():Audio Status: "+status);
setAudioStatus(Media.MEDIA_MSG[status]);
// If stopped, then stop getting current position
if (Media.MEDIA_STOPPED == status) {
clearInterval(media1Timer);
media1Timer = null;
}
});
}
audioSrc = src;
// Play audio
media1.play();
if (media1Timer == null) {
media1Timer = setInterval(
function() {
media1.getCurrentPosition(
function(position) {
console.log("Pos="+position);
if (position > -1) {
setAudioPosition((position/1000)+" sec");
}
},
function(e) {
console.log("Error getting pos="+e);
setAudioPosition("Error: "+e);
}
);
},
1000
);
}
// Get duration
var counter = 0;
var timerDur = setInterval(
function() {
counter = counter + 100;
if (counter > 2000) {
clearInterval(timerDur);
}
var dur = media1.getDuration();
if (dur > 0) {
clearInterval(timerDur);
document.getElementById('audio_duration').innerHTML = (dur/1000) + " sec";
}
}, 100);
}
/**
* Pause audio playback
*/
function pauseAudio() {
console.log("pauseAudio()");
if (media1) {
media1.pause();
}
}
/**
* Stop audio
*/
function stopAudio() {
console.log("stopAudio()");
if (media1) {
media1.stop();
}
clearInterval(media1Timer);
media1Timer = null;
}
/**
* Set audio status
*/
var setAudioStatus = function(status) {
document.getElementById('audio_status').innerHTML = status;
};
/**
* Set audio position
*/
var setAudioPosition = function(position) {
document.getElementById('audio_position').innerHTML = position;
};
</script>
</head>
<body>
<!-- Audio -->
<div id="info">
<h2>Audio</h2>
</div>
Play
Pause
Stop
</body>
You might consider using a page with a frame on it. Place your common javascript in the of the main page and then call back to parent.playAudio(src) to kick off the player from each sub-page as it's loaded into the frame.
Another possible direction is use of jqMobile. By default, jqMobile loads pages using Ajax calls..consequently, your javascript can be loaded by the very first page only...and all subsequent page loads via ajax do not totally replace the DOM...leaving your javascript in tact. I have developed a small app using phonegap and jqMobile with fairly good success.