Program odtwarzający audio w Phonegap

W tutorialu stworzymy prosty odtwarzacz audio. Wykorzystam tym razem jQuery Mobile, aby nie zaprzątać sobie głowy interfejsem użytkownika. Będziemy wykorzystywać obiekt Media oraz w późniejszym etapie również File.

Utwórzmy zatem w Eclipse nowy projekt Phonegap (tak jak poprzednio). Jedyną różnicą jest to, że tym razem zaznaczamy "Include jQuery Mobile in project" oraz wybieramy "use built-in jquery mobile". Nowy projekt z jquery mobile Do wygenerowanego kodu dodajemy linie załączające jquery mobile. Samo jquery mobile powinno zostać automatycznie umieszczone w katalogu assets/www/jquery.mobile projektu. Usuwamy też wygenerowany kod z ostatniego znacznika script i z sekcji body. Tworzymy i załączamy do strony nowy plik player.js, w którym znajdować się będzie cała logika aplikacji.
<!DOCTYPE HTML>
<html>
  <head>
    <meta name="viewport" content="width=320; user-scalable=no" />
    <meta http-equiv="Content-type" content="text/html; charset=utf-8">
    <title>Simple Audio Player</title>
		<link rel="stylesheet" href="jquery.mobile/jquery.mobile-1.1.0.css" type="text/css">
      <script type="text/javascript" src="jquery.mobile/jquery-1.7.2.min"></script>
      <script type="text/javascript" src="jquery.mobile/jquery.mobile-1.1.0.js"></script>
	  <script type="text/javascript" charset="utf-8" src="cordova.js"></script>
	  <script type="text/javascript" charset="utf-8" src="player.js"></script>  
  </head>
  <body>
   
  </body>
</html>
Kod html, którego będziemy używać wygląda następująco. Po więcej informacji na temat użytej składni odsyłam na stronę jQuery Mobile.
<body>
   <div data-role="page" id="page">
   	<div data-role="header" data-nobackbtn="true">
    	<h1>Simple Audio Player</h1>
    </div> 
    <div data-role="content" id="content-manual">
    
        <div data-role="button" id="play">Play</div>
        <div data-role="button" id="pause">Pause</div>
        <div data-role="button" id="stop">Stop</div>    
    
        <div class="ui-grid-a">
            <div class="ui-block-a">Current: <span id="position">0 sec</span></div>
            <div class="ui-block-b">Total: <span id="duration">0</span> sec</div>
        </div>

    </div>
   </div>
  </body>
Javascript zawarty w pliku player.js jest zaczerpnięty z dokumentacji phonegap.
// Audio player
var audio_file = null;
var mediaTimer = null;
// duration of media
var dur = -1;
// need to know when paused or not
var is_paused = false;

//set audio position on page
function setAudioPosition(position) {
    $("#position").html(position + " sec");
}

//onSuccess callback
function onSuccess() {
    setAudioPosition(dur);
    clearInterval(mediaTimer);
    mediaTimer = null;
    if(audio_file !== null) audio_file.release();
    audio_file = null;
    is_paused = false;
    dur = -1;
}

//onError callback 
function onError(error) {
    alert('code: '    + error.code    + '\n' + 'message: ' + error.message + '\n');
    clearInterval(mediaTimer);
    mediaTimer = null;
    audio_file = null;
    is_paused = false;
    setAudioPosition("0");
}

function playAudio(src) {
    if (audio_file === null) {
        $("#dur").html("0");
        $("#position").html("Loading...");
        
        // Create Media object from src
        audio_file = new Media(src, onSuccess, onError);       
        // Play audio
        audio_file.play();
    } else {
        if (is_paused) {
            is_paused = false;
            audio_file.play();
        }
    }

    // Update audio_file position every second
    if (mediaTimer === null) {
        mediaTimer = setInterval(function() {
            audio_file.getCurrentPosition(
                    // success callback
                    function(position) {
                        if (position > -1) {
                            setAudioPosition(Math.round(position));
                            if (dur <= 0) {
                                dur = audio_file.getDuration();                             
                                if (dur > 0) {
                                    dur = Math.round(dur);
                                    $("#duration").html(dur);
                                }
                            }                                                      
                        }
                    },
                    // error callback
                    function(e) {
                        alert("Error getting pos=" + e);
                    }
            );
        }, 1000);
    }
}

//Pause audio
function pauseAudio() {
    if (is_paused) return;
    if (audio_file) {
        is_paused = true;
        audio_file.pause();
    }
}

//Stop audio
function stopAudio() {
    if (audio_file) {
        audio_file.stop();
        audio_file.release();
        audio_file = null;
    }
    if (mediaTimer) {
        clearInterval(mediaTimer);
        mediaTimer = null;
    }
    is_paused = false;
    dur = 0;
}

$('#page').live('pageinit',function() {

    $("#play").on('tap', function() {    
        var src = 'http://designconcept.webdev20.pl/arts/audiovisual_media_queries/music/fl1.mp3';
        
        // local (on device): copy file to project's /assets folder:
        //var src = '/android_asset/fl1.mp3';
        
        playAudio(src);
    });

    $("#pause").on('tap', function() {
        pauseAudio();
    });
    
    $("#stop").on('tap', function() {
        stopAudio();
    });
});
Rozbudujemy teraz odtwarzacz o listę plików muzycznych na urządzeniu. Po kliknięciu na nazwę pliku rozpocznie się odtwarzanie wybranego utworu. Wykorzystamy do tego File. Dodatkowy kod javascript w pliku to
var files_arr = [], extensions = ['.mp3', '.ogg', '.wav', '.m4a'];
function getFiles(path, recursive, level) {
    if(level === undefined) {
       level = 0;
	}
    var directoryEntry = new DirectoryEntry('', path);
    if(!directoryEntry.isDirectory) {
       return null;
    }
    var directoryReader = directoryEntry.createReader();
    directoryReader.readEntries(
       function(entries) {
          var ext;
          for(var i = 0; i < entries.length; i++) {
             if(entries[i].name === '.')
                continue;
             ext = entries[i].name.substring(entries[i].name.lastIndexOf('.'));
             if(entries[i].isDirectory === true && recursive === true)
                getFiles(entries[i].fullPath, recursive, ++level);
             else if(entries[i].isFile === true && $.inArray(ext, extensions) >= 0)
             {
            	app_name = entries[i].name;
            	app_fullpath = entries[i].fullPath;
            	files_arr.push({'app_name':app_name, 'app_fullpath':app_fullpath});
             }
          }
       },
       function(error) {
          console.log('Unable to read the directory. Error code: ' + error.code);
       }
    );
}
function fileslist() {
	window.requestFileSystem(
	 LocalFileSystem.PERSISTENT,
	 0,
	 function(fileSystem){
	    var root = fileSystem.root;
	    files_arr = [];
	    getFiles(root.fullPath, true);
	 },
	 function(error){
	    alert('File System Error: ' + error.code);
	 }
	 );
}
//Wait for device API libraries to load
document.addEventListener("deviceready", onDeviceReady, false);

// device APIs are available
function onDeviceReady() {
	fileslist();
	var $ul = $('#files');
	for(var i=0; i<files_arr.length;i++) {
		$ul.append('<li><a href="#" data-src="'+files_arr[i].app_fullpath+'">'+files_arr[i].app_name+'</a></li>');
	}
	$('#files').listview('refresh');
	$('#files li a').on('click', function() {
		playAudio($(this).data('src'));
		return false;
	});
}
Natomiast w pliku index.html wystarczy dopisać do diva o id content:
<ul id="files" data-role="listview" data-inset="true">
</ul>
W liście tej będziemy wyświetlać nazwy plików muzycznych z urządzenia. Ważne jest aby wszelkie działania wykonywać jeśli api są już załadowane i urządzenie jest gotowe czyli w zdarzeniu deviceready. Funkcja getFiles rekursywnie przechodzi przez podkatalogi podanej ścieżki i zapisuje nazwy oraz ścieżki do plików muzycznych w tablicy. Po zapisaniu wszystkich plików dodajemy je do naszej listy ul i ją odświeżamy. Ponadto do każdego elementu a listy dodajemy zdarzenie click wywołujące odtwarzanie utworu dla określonej ścieżki. Pliki index.html i player.js można pobrać stąd. Simple Audio Player w emulatorze Dodatkowe wskazówki i materiały:
Debugowanie aplikacji
Jeśli chcemy testować działania na systemie plików na emulatorze musimy wgrać jakieś pliki do katalogu storage/sdcard emulatora. W tym celu należy uruchomić emulator. Przejść na perspektywę DDMS w Eclipse (Window > Open Perspective > DDMS). Potem wejść na zakładkę File Explorer i dodać do katalogu storage/sdcard jakieś pliki z dysku. W tym celu zaznaczamy katalog sdcard i klikamy ikonę "Push a file onto the device". DDMS File Explorer Jeśli chcesz dowiedzieć się więcej na temat Phonegap i Androida polecam zapoznanie się z ebookiem Phonegap dla Androida od podstaw.