redrom
redrom

Reputation: 11642

Cordova media, how to get callback for loop playing?

I have following Angular JS service which is accessing to the cordova media plugin.

MediaSrv.loadMedia(filePath, mediaSuccess, null, status).then(function(media, status, test, status1){
                    media.play({ numberOfLoops: 999 });
                    media.setVolume(volume);
                    $scope.selectedSounds[index].state = 1;
                    $scope.selectedSounds[index].mediaInstance = media;
                    $scope.someSoundsArePlaying = true;
                });

I would like to ask, how can i do loop playing of the selected file which can be stopped after passing mediaInstance to stop function?

I tried mediaSuccess Callback and status CallBack but it does not work properly.

Service is following:

'use strict';

angular.module('MaxRelax')
  .factory('MediaSrv', function($q, $ionicPlatform, $window){
        var service = {
            loadMedia: loadMedia,
            getStatusMessage: getStatusMessage,
            getErrorMessage: getErrorMessage
        };

        function loadMedia(src, onError, onStatus, onStop){
            var defer = $q.defer();
            $ionicPlatform.ready(function(){
                var mediaSuccess = function(){
                    if(onStop){onStop();}
                };
                var mediaError = function(err){
                    _logError(src, err);
                    if(onError){onError(err);}
                };
                var mediaStatus = function(status){
                    console.log(status);
                    if(onStatus){onStatus(status);}
                };

                if($ionicPlatform.is('android')){src = '/android_asset/www/' + src;}
                defer.resolve(new $window.Media(src, mediaSuccess, mediaError, mediaStatus));
            });
            return defer.promise;
        }

        function _logError(src, err){
            console.error('media error', {
                code: err.code,
                message: getErrorMessage(err.code)
            });
        }

        function getStatusMessage(status){
            if(status === 0){return 'Media.MEDIA_NONE';}
            else if(status === 1){return 'Media.MEDIA_STARTING';}
            else if(status === 2){return 'Media.MEDIA_RUNNING';}
            else if(status === 3){return 'Media.MEDIA_PAUSED';}
            else if(status === 4){return 'Media.MEDIA_STOPPED';}
            else {return 'Unknown status <'+status+'>';}
        }

        function getErrorMessage(code){
            if(code === 1){return 'MediaError.MEDIA_ERR_ABORTED';}
            else if(code === 2){return 'MediaError.MEDIA_ERR_NETWORK';}
            else if(code === 3){return 'MediaError.MEDIA_ERR_DECODE';}
            else if(code === 4){return 'MediaError.MEDIA_ERR_NONE_SUPPORTED';}
            else {return 'Unknown code <'+code+'>';}
        }

        return service;
    });

Many, many thanks for any help.

EDIT:

Playing of the item is processed by the following method:

  $scope.playSelectedItem = function(index) {
            try {
                var fileName = $scope.selectedSounds[index].file;
                var volume = $scope.selectedSounds[index].defaultVolume;
                var filePath  = "sounds/" +fileName+".mp3";
                console.log(filePath);
                MediaSrv.loadMedia(
                    filePath,
                    function onError(err){ console.log('onError', MediaSrv.getErrorMessage(err)); },
                    function onStatus(status){ console.log('onStatus', MediaSrv.getStatusMessage(status)); },
                    function onStop(){ console.log('onStop'); myMedia.play(); }
                ).then(function(media){
                    myMedia = media;
                    media.play({ numberOfLoops: 999 });
                    media.setVolume(volume);
                    $scope.selectedSounds[index].state = 1;
                    $scope.selectedSounds[index].mediaInstance = media;
                    $scope.someSoundsArePlaying = true;
                });
            } catch(e) {
                alert(JSON.stringify(e));
                console.log(e);
                $scope.showAlert("Error", "Error during the playing item");
            }
        };

Stopping:

$scope.stopSelectedItem = function(index) {
            try {
                var leng = 0;
                if($scope.selectedSounds[index].state == 1) {
                    var mediaInstance = $scope.selectedSounds[index].mediaInstance;
                    mediaInstance.stop();
                    $scope.selectedSounds[index].state = 0;
                    $scope.selectedSounds[index].mediaInstance = "";
                    myMedia.stop();
                }

                angular.forEach($scope.selectedSounds, function loadMedia(selectedSound, idx){
                    if($scope.selectedSounds[idx].state == 1) {
                        leng ++;
                    }
                });

                if(leng <= 0) {
                    $scope.someSoundsArePlaying = false;
                    console.log("No sound are playing");
                }
                if(leng > 0) {
                    $scope.someSoundsArePlaying = true;
                    console.log("Some sound are playing");
                }
                console.log("Leng is:");
                console.log(leng);
            } catch(e) {
                alert(JSON.stringify(e));
                console.log(e);
                $scope.showAlert("Error", "Cannot stop playing of item");
            }
        };

EDIT2:

I finally solved it using storing myMedia instance in the simple array.

$scope.playSelectedItem = function(index) {
            try {
                var fileName = $scope.selectedSounds[index].file;
                var volume = $scope.selectedSounds[index].defaultVolume;
                var filePath  = "sounds/" +fileName+".mp3";
                console.log(filePath);
                MediaSrv.loadMedia(
                    filePath,
                    function onError(err){ console.log('onError', MediaSrv.getErrorMessage(err)); },
                    function onStatus(status){ console.log('onStatus', MediaSrv.getStatusMessage(status)); },
                    function onStop(){
                        console.log('onStop');
                        if($scope.selectedSounds[index].state == 1) {
                            console.log('For index ' +index+' is state '+$scope.selectedSounds[index].state);
                            myMedia[index].play();
                        }

                    }
                ).then(function(media){
                    myMedia[index] = media;
                    media.play({ numberOfLoops: 999 });
                    media.setVolume(volume);
                    $scope.selectedSounds[index].state = 1;
                    $scope.selectedSounds[index].mediaInstance = media;
                    $scope.someSoundsArePlaying = true;
                });
            } catch(e) {
                alert(JSON.stringify(e));
                console.log(e);
                $scope.showAlert("Error", "Error during the playing item");
            }
        };

Upvotes: 1

Views: 1277

Answers (1)

Lo&#239;c Knuchel
Lo&#239;c Knuchel

Reputation: 21

I'm pleased that you find my angular service usefull.

In your sample you seems to mess up with parameter order :
MediaSrv.loadMedia(filePath, mediaSuccess, null, status) vs
function loadMedia(src, onError, onStatus, onStop)

BTW, play parameter numberOfLoops does not seems to work (at least on my nexus4). If you want to loop, you will need to call play() every time the mp3 ends.

Here is a short example :

var myMedia = null;
MediaSrv.loadMedia(
    'sounds/1023.mp3', 
    function onError(err){ console.log('onError', MediaSrv.getErrorMessage(err)); },
    function onStatus(status){ console.log('onStatus', MediaSrv.getStatusMessage(status)); },
    function onStop(){ console.log('onError'); myMedia.play(); },
).then(function(media){
    myMedia = media;
    myMedia.play();
});

With this code, your sound should play, forever... To control when your sound should stop, I suggest you to add a control parameter, like this :

var myMedia = null;
var shouldPlay = false;
MediaSrv.loadMedia(
    'sounds/1023.mp3', 
    function onError(err){ console.log('onError', MediaSrv.getErrorMessage(err)); },
    function onStatus(status){ console.log('onStatus', MediaSrv.getStatusMessage(status)); },
    function onStop(){ console.log('onError'); if(shouldPlay){myMedia.play();} },
).then(function(media){
    myMedia = media;
});

function playStart(){
    shouldPlay = true;
    myMedia.play();
}
function playStop(){
    shouldPlay = false;
    myMedia.stop();
}

To play multiples files in a loop, you have to store all media references and play them successively. See there :

var shouldPlay = false;
var playingMedia = null;
var soundFiles = ['sounds/1.mp3', 'sounds/2.mp3', 'sounds/3.mp3'];
var mediaInstances = [];
var onPlayStop = function(){
    if(shouldPlay){
        if(playingMedia === null){
            playingMedia = 0;
        } else {
            playingMedia = (playingMedia+1) % mediaInstances.length;
        }
        mediaInstances[playingMedia].play();
    }
};
for(var i in soundFiles){
    MediaSrv.loadMedia(soundFiles[i], null, null, onPlayStop).then(function(media){
        mediaInstances.push(media);
    });
}

function playStart(){
    shouldPlay = true;
    onPlayStop();
}
function playStop(){
    shouldPlay = false;
    mediaInstances[playingMedia].stop();
}

I hope this will helps :D

Upvotes: 2

Related Questions