Saving a Recording

0
187

Let’s now save your recording on the device. In the following examples, we are saving the audio files on the SD card. Your application needs permission to write to external storage. If you do not have this permission, AIR will throw a runtime error:

<uses-permission android:name=
“android.permission.WRITE_EXTERNAL_STORAGE”/>

The BLOB type

At the time of this writing, there is no native library in which to save an MP3 file that can be played back into the application at runtime. As an alternative, you can save the bytes in an SQLite database as BLOB data. The BLOB type is raw binary data that stores information exactly as it was input.

In this section, we will compress the file to reduce its size. First, let’s create a database and a table to store the audio files:

import flash.data.SQLConnection;
import flash.events.SQLEvent;
import flash.data.SQLStatement;
import flash.errors.SQLError;
import flash.filesystem.File;
var connection:SQLConnection;
// open connection to database
connection = new SQLConnection();
connection.addEventListener(SQLEvent.OPEN, openDatabase);
var file:File = File.documentsDirectory.resolvePath(“Dictaphone.db”);
connection.open(file);

function openDatabase(event:SQLEvent) {
connection.removeEventListener(SQLEvent.OPEN, openDatabase);
createTable();
}
// create or open table
function createTable():void {
var statement:SQLStatement = new SQLStatement();
statement.sqlConnection = connection;
var request:String =
“CREATE TABLE IF NOT EXISTS mySounds (” +
“id INTEGER PRIMARY KEY AUTOINCREMENT, ” +
“audio BLOB )”;
statement.text = request;
try {
statement.execute();
} catch(error:SQLError) {
trace(error.message, error.details);
}
}

Now we’ll compress the audio and save it in the database. Here we are using ZLIB compression, which provides good results but is somewhat slow to execute:

import flash.utils.CompressionAlgorithm;
var statement:SQLStatement;
function saveItem():void {
// compress the bytes
bytes.position = 0;
bytes.compress(CompressionAlgorithm.ZLIB);
var command:String =
“INSERT INTO mySounds(audio) VALUES (?)”;
statement = new SQLStatement();
statement.sqlConnection = connection;
statement.text = command;
statement.parameters[0] = bytes;
try {
statement.execute();
} catch(error:SQLError) {
trace(error.message, error.details);
}
}

Retrieve the first audio item from the database, and decompress it to use it:

import flash.data.SQLResult;
function getItem(id:Number):ByteArray {
var command:String = “SELECT * FROM mySounds WHERE id=:id;”
var statement:SQLStatement = new SQLStatement();
statement.sqlConnection = connection;
statement.text = command;
statement.parameters[“:id”] = id;
statement.execute(1);
var result:SQLResult = statement.getResult();
if (result.data != null) {
return result.data[0];
}
return new ByteArray();
}
// to read the data back, decompress it
bytes = getItem(1).audio;
bytes.uncompress(CompressionAlgorithm.ZLIB);
bytes.position = 0;
// play audio

Use the bytes to play the audio in a Sound object, as in the previous example.

WAV files

You can save your recording as a WAV file on your device. Download the Adobe.audio.format.WAVWriter class from the audio_sampler.zip file located at http://www.adobe.com/devnet/air/flex/articles/using_mic_api.html, and import it to your project.

In this example, we are encoding our previous recording as a WAV file and saving it on the SD card in a directory called mySounds.

import com.adobe.audio.format.WAVWriter;
import flash.filesystem.File;
import flash.filesystem.FileStream;
import flash.filesystem.FileMode;
function saveWav(bytes:ByteArray):void {
// point to mySounds directory on the SD card.
var directory:File = File.documentsDirectory.resolvePath(“mySounds”);
// if directory does not exist yet, create it
if (!directory.exists) {
directory.createDirectory();
}
// create name of a new wav file
var file:File = directory.resolvePath(“mySound.wav”);
// create an instance of the WAVWriter class and set properties
var wav:WAVWriter = new WAVWriter();
wav.numOfChannels = 1; // mono
wav.sampleBitRate = 16; // or 8
wav.samplingRate = 44100; // or 22000
// rewind to the beginning of the ByteArray
bytes.position = 0;
// create stream as conduit to copy data and write file
var stream:FileStream = new FileStream();
stream.open(file, FileMode.WRITE);
// convert byteArray to WAV format and close stream
wav.processSamples(stream, bytes, 44100, 1);
stream.close();
}

Open source libraries

The current native libraries cannot load a WAV file dynamically or encode a ByteAr ray as an MP3 file. As an alternative, you can try some of the available open source libraries.

For instance, Shine, written by Gabriel Bouvigné, is an Alchemy/Flash MP3 encoder (see https://github.com/kikko/Shine-MP3-Encoder-on-AS3-Alchemy and http://code.google.com/p/flash-kikko/):

import fr.kikko.lab.ShineMP3Encoder;
encoder = new ShineMP3Encoder(bytes);
encoder.addEventListener(Event.COMPLETE, onEncoding);
encoder.addEventListener(ProgressEvent.PROGRESS, onProgress);
encoder.addEventListener(ErrorEvent.ERRROR, onError);
encoder.start();
file.save(mp3Encoder.mp3Data, “recording.mp3”);

In addition, the following WAV decoders are also available:

  • AS3WavSound (http://www.ohloh.net/p/as3wavsound)
  • standingwave3 (http://maxl0rd.github.com/standingwave3/)
  • Ogg/Vorbis (http://vorbis.com/software/
  • Tonfall (http://code.google.com/p/tonfall/; this is also an encoder)

Saving to a remote server

If you have access to a streaming media server such as Flash Media Server, you can save and stream audio to the device. The microphone can be attached to a NetStream for uploading. Audio data can also be streamed from the server and played back using a Video object.

Two compression codecs are available:

import flash.media.soundCodec;
mic.codec = SoundCodec.NELLYMOSER; // default
mic.coder = SoundCodec.SPEEX;

If you are using this technology, urge your audience to use a WiFi connection over 3G unless they have a flat-fee data plan.