Media Sample Using PhoneGap* compatible API: Recording and Playback on Mobile Devices

Table of Content

  1. Introduction
  2. Setting Up the Development Environment
  3. Design Considerations
  4. Developing and Testing for Android Devices using Eclipse and adb
  5. Debugging and Testing on Apple iOS* Device using XCode* IDE
  6. Issues Encountered

The source code for this sample can be found here: https://github.com/gomobile/sample-phonegap-audio or download the Intel(R) XDK to check out all the HTML5 Samples.

Introduction

This article describes the design and implementation of a simple Media sample application using PhoneGap* compatible API. The app demonstrates the use of Apache Cordova* (PhoneGap) 2.0 Media object. The UI is very straightforward. Although the PhoneGap Media object API is fully documented online at PhoneGap Media API website, getting the app working on both Google Android* and Apple iOS* devices is not trivial. We will discuss the issues encountered in this article. The primary development machines used for this app are a Windows 7* OS x64 laptop and an Apple Mac* 10.5 notebook for testing.

The requirements for the Media sample program are:

  • Use of the PhoneGap compatible Media object 
  • Recording the sound through device microphone
  • Playback newly recorded sound as well as old recording 
  • Support Android* devices 
  • Support Apple iOS* devices 

The final app is looks like below and the recorded sound is in .wav format because PhoneGap only supports .wav format on iOS devices.

Media Sample 

Setting Up the Development Environment

  1. For Android development: we used a Windows 7* x64 laptop and installed the following tools according to the Cordova/PhoneGap Getting Started article for Android*.

    Preparing the Android phone for testing: see instructions on setting up the Android devices for development.

  2. For iOS* development: we used an Apple Mac running Leopard Mac OS X* and installed the following tools according to the PhoneGap's Getting Started Guide for iOS*.
    • Apple XCode* 4.3 and above
    • XCode command line tools
    • To develop for an iOS device requires that you access an account at https://developer.apple.com/programs/ios/. After you create an account, you will be able to deploy the app onto the iOS device from XCode. This makes it much easier on testing/debugging.
    • PhoneGap for iOS

    Preparing the iOS device, an Apple iPad* tablet, for testing: nothing.

Design Considerations

First of all, this app is for demonstrating the PhoneGap media object functionality. The UI should be simple and clear. All the buttons need to be in a good state when app starts. The [Play] button should be enabled only when there is a recorded audio file.

Second, the app limits the recording time to 10ms because it is a demo app only.

Last, the goal is to have one code base that supports multiple platforms using PhoneGap. But because of differences of media support and file system between iOS* and Android*, you will find several places where specific code is implemented for a specific platform.

Developing and Testing for Android Devices using Eclipse and adb

For debugging within Eclipse, both Eclipse and adb are used. When using Eclipse, use "tag:web" to filter out the non-relevant messages for this specific sample. You can use other filtering as well.

Media Sample

For debugging using "adb", the instructions are below. This method can be used for debugging with Android Emulator and as well as Android devices.

  • Add any debug code like "console.log('*** before calling event xxxx');" in the app
  • Open a command window
  • Type: adb devices to get the device names
  • Type: adb -s [device-name] logcat to display the debug messages, such as:

    D/CordovaLog( 9946): onDeviceReady: Record with PhoneGap version: 2.0.0

    D/CordovaLog( 9946): file:///android_asset/www/index.html: Line 46 : onDeviceReady: Record with PhoneGap version: 2.0.0

    I/Web Console( 9946): onDeviceReady: Record with PhoneGap version: 2.0.0 at file:///android_asset/www/index.html:46

    D/CordovaLog( 9946): *** phoneCheck.android: android

    D/CordovaLog( 9946): file:///android_asset/www/index.html: Line 48 : *** phoneCheck.android: android

    I/Web Console( 9946): *** phoneCheck.android: android at file:///android_asset/www/index.html:48

    D/CordovaLog( 9946): *** phoneCheck.ios: null

    D/CordovaLog( 9946): file:///android_asset/www/index.html: Line 49 : *** phoneCheck.ios: null 

The media recording is also dealing with the file system of the device, and the file system is different from platform to platform. The following code in deviceCheck.js is used to check the platform:

var phoneCheck = {
    ios: ua.match(/(iphone|ipod|ipad)/i),
    blackberry: ua.match(/blackberry/i), // not used in this sample
    android: ua.match(/android/i),
    windows7: ua.match(/windows phone os 7.5/i) // not used in this sample
};

See the Pen %= penName %> by Intel IDZ (@intelidz) on CodePen

On Android devices, the PhoneGap media object has the following important behaviors that are not well documented:

  • "my_audio = new Media('myRecording100.wav', onMediaCallSuccess, onMediaCallError)":

    when "myRecording100.wav" does not exist, it will create the file; when it exists, it opens it.
  • "my_audio.stopRecord()":

    when "stopRecord()" is called, the .wav media file is moved to "/sdcard" folder.

    So when checking if previous recorded .wav exists, the code should look under "/sdcard" folder. If it does exist, it should open the file from "/sdcard/myRecording100.wav":
function playMusic() {
	if (my_audio === null) { // play existing media recorded from previous session
		
		// the existing medail should be on /sdcard/ for android. 
        if (phoneCheck.android) {
        	my_audio = new Media("/sdcard/" + mediaRecFile, onMediaCallSuccess, onMediaCallError);

            console.log("***test:  Open file:" + mediaRecFile);
        } 
        else if (phoneCheck.ios) {
            my_audio = new Media(mediaFileFullName, onMediaCallSuccess, onMediaCallError);
        }
    }
    ... ...
}

See the Pen %= penName %> by Intel IDZ (@intelidz) on CodePen

Debugging and Testing on Apple iOS* Device using XCode* IDE

You may think that once the app works on Android devices, it should be simple and quick to get it work on iOS devices. Well it is not the case for the Media sample.

First of all, recording the audio is different for Android and iOS.

For Android, we create the "my_audio = new Media()" object and use it to record like below. This is simple and straightforward.

function startRecording() {
    if (phoneCheck.android) {
        my_audio = new Media(mediaRecFile, onMediaCallSuccess, onMediaCallError);
        console.log("***test: new Media() for android ***");

        recordNow();
    }
    ... ... 
}
function recordNow() {
	if (my_audio) {
		my_audio.startRecord();
		document.getElementById('RecStatusID').innerHTML = "Status: recording";
		console.log("***test:  recording started: in startRecording()***");
	}
    ... ... 
}

See the Pen %= penName %> by Intel IDZ (@intelidz) on CodePen

But for iOS, the audio file "myRecording100.wav" can not be created by PhoneGap media.startRecording() API. It needs to be created first (or recreated if exists) by the file system. So the recording has to start in the success callback function of the file creation instead. Below is the code for that:

function onOK_GetFile(fileEntry) {
    ... ... 
	else { // record on iOS
		// create media object using full media file name 
		my_audio = new Media(mediaRecFile, onMediaCallSuccess, onMediaCallError);

		// specific for iOS device: recording start here in call-back function
		recordNow();
	}
}

function onSuccessFileSystem(fileSystem) {
	console.log("***test: fileSystem.root.name: " + fileSystem.root.name);
    ... ... 
    	fileSystem.root.getFile(mediaRecFile, { create: true, exclusive: false }, onOK_GetFile, null);
    
}

function startRecording() {
    ... ... 
    else if (phoneCheck.ios) {
    	//first create the file
    	checkFileOnly = false;
    	window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, onSuccessFileSystem, function() {
    		console.log("***test: failed in creating media file in requestFileSystem");
    	});
    	console.log("***test: new Media() for ios***");
    }
}

See the Pen %= penName %> by Intel IDZ (@intelidz) on CodePen

If you try to use the similar code based on Android for iOS, you get into the race condition situation where the file is still in the process of being created and the media oject is trying to use it for recording.

One other issue is simply just brainless during my development. I picked the iPad for testing and iPad does not have a microphone built in. Once I got a head-phone for the iPad, it worked beautifully.

Issues Encountered

  1. The HTML5 <audio> Control Is Not Supported By Hybrid

    Do not confuse this with Browser's support. Most browsers on today's mobile devices support the HTML5
  2. An issue with USB driver for Android-based Samsung Galaxy S2* smartphone: "Kies" does not start on the Windows 7 machine and Eclipse cannot detect the Android Samsung Galaxy S2 smartphone.

    The work-around is found from this msdn post by updating all the "C:\Program Files\Samsung\Kies*.config" files to remove the following line:

       <supportedRuntime version="v4.0" />
  3. The PhoneGap Media object can only record .wav format on an iOS device - this is documented on the PhoneGap media object API page. It is very easily missed.
Per informazioni complete sulle ottimizzazioni del compilatore, consultare l'Avviso sull'ottimizzazione