Source for file mime.audio.php
Documentation is available at mime.audio.php
* @author xing <xing@synapse.plus.com>
* created Thursday May 08, 2008
* @subpackage liberty_mime_handler
* This is the name of the plugin - max char length is 16
* As a naming convention, the liberty mime handler definition should start with:
define( 'PLUGIN_MIME_GUID_AUDIO', 'mimeaudio' );
// Set of functions and what they are called in this paricular plugin
// Use the GUID as your namespace
'preload_function' => 'mime_audio_preload',
'verify_function' => 'mime_default_verify',
'store_function' => 'mime_audio_store',
'update_function' => 'mime_audio_update',
'load_function' => 'mime_audio_load',
'download_function' => 'mime_default_download',
'expunge_function' => 'mime_default_expunge',
// Brief description of what the plugin does
'title' => 'Listen to uploaded Audio files',
'description' => 'This plugin will extract as much information about an uploaded audio file as possible and allow you to listen to it on the website using a streaming player.',
// Templates to display the files
'view_tpl' => 'bitpackage:liberty/mime/audio/view.tpl',
'inline_tpl' => 'bitpackage:liberty/mime/audio/inline.tpl',
'storage_tpl' => 'bitpackage:liberty/mime/audio/storage.tpl',
'attachment_tpl' => 'bitpackage:liberty/mime/audio/attachment.tpl',
'edit_tpl' => 'bitpackage:liberty/mime/audio/edit.tpl',
// url to page with options for this plugin
// This should be the same for all mime plugins
// Set this to TRUE if you want the plugin active right after installation
'auto_activate' => FALSE,
// Help page on bitweaver.org
//'help_page' => 'LibertyMime+Audio+Plugin',
// this should pick up all audio
* mime_audio_preload This function is loaded on every page load before anything happens and is used to load required scripts.
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
$gBitThemes->loadJavascript( UTIL_PKG_PATH. "javascript/flv_player/swfobject.js", FALSE, 25 );
* Store the data in the database
* @param array $pStoreRow File data needed to store details in the database - sanitised and generated in the verify function
* @return TRUE on success, FALSE on failure - $pStoreRow['errors'] will contain reason
// this will set the correct pluign guid, even if we let default handle the store process
$pStoreRow['log'] = array();
// if storing works, we process the audio
// if it all goes tits up, we'll know why
$pStoreRow['errors'] = $pStoreRow['log'];
* @param array $pStoreRow
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
if( BitBase::verifyId( $pStoreRow['attachment_id'] )) {
$pStoreRow['log'] = array();
// set the correct pluign guid, even if we let default handle the store process
// remove the entire directory
$pStoreRow['unlink_dir'] = TRUE;
// if storing works, we process the audio
// if it all goes tits up, we'll know why
$pStoreRow['errors'] = $pStoreRow['log'];
// if there was no upload we'll process the file parameters
if( empty( $pStoreRow['upload'] ) && !empty( $pParams['meta'] )) {
// update our local version of the file
$verted = dirname( $file ). '/bitverted.mp3';
$verted = dirname( $file ). '/bitverted.m4a';
// update audio tags of converted and original file (ignore errors since these might be m4a)
// finally we update the meta table data
if( !LibertyMime::storeMetaData( $pStoreRow['attachment_id'], 'ID3', $pParams['meta'] )) {
$log['store_meta'] = "There was a problem storing the meta data in the database";
$pStoreRow['errors'] = $log;
* Load file data from the database
* @param array $pFileHash Contains all file information
* @param array $pPrefs Attachment preferences taken liberty_attachment_prefs
* @param array $pParams Parameters for loading the plugin - e.g.: might contain values from the view page
* @return TRUE on success, FALSE on failure - ['errors'] will contain reason for failure
global $gLibertySystem, $gBitThemes;
// don't load a mime image if we don't have an image for this file
// fetch meta data from the db
$ret['meta'] = LibertyMime::getMetaData( $pFileHash['attachment_id'], "ID3" );
if( !empty( $ret['storage_path'] )) {
// we need some javascript for the player:
* @param array $pParamHash
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
// audio conversion can take a while
ini_set( "max_execution_time", "1800" );
$source = STORAGE_PKG_PATH. $pParamHash['upload']['dest_branch']. $pParamHash['upload']['name'];
if( @BitBase::verifyId( $pParamHash['attachment_id'] )) {
$pattern = "#.*\.(mp3|m4a)$#i";
// make a copy of the original maintaining the original extension
$dest_file = $destPath. '/bitverted.'. preg_replace( $pattern, "$1", strtolower( $pParamHash['upload']['name'] ));
if( !is_file( $dest_file ) && !link( $source, $dest_file )) {
copy( $source, $dest_file );
// TODO: have a better mechanism of converting audio to mp3. ffmpeg works well as long as the source is 'perfect'
// there are many audiofiles that can't be read by ffmpeg but by other tools like flac, faac, oggenc
// mplayer is very good, but has a lot of dependencies and not many servers have it installed
// also, using mplayer is a 2 step process: decoding and encoding
// if we convert audio, we always make an mp3
$dest_file = $destPath. '/bitverted.mp3';
// fall back to using slower mplayer / lame combo
// if the conversion was successful, we'll copy the tags to the new mp3 file and import data to meta tables
$log['success'] = 'Successfully converted to mp3 audio';
// now that we have a new mp3 file, we might as well copy the tags accross in case someone downloads it
// we silence this since this will spew lots of ugly errors when using UTF-8 and some odd character in the file ID
$meta = @$getID3->analyze( $source );
getid3_lib::CopyTagsToComments( $meta );
// write tags to new mp3 file
$log['tagging'] = $errors;
// getID3 returns everything in subarrays - we want to store everything in [0]
foreach( $meta['comments'] as $key => $comment ) {
$store[$key] = $comment[0];
$store['playtimeseconds'] = $meta['playtime_seconds'];
$store['playtimestring'] = $meta['playtime_string'];
// make sure we remove previous entries first
LibertyMime::expungeMetaData( $pParamHash['attachment_id'] );
if( !LibertyMime::storeMetaData( $pParamHash['attachment_id'], 'ID3', $store )) {
$log['store_meta'] = "There was a problem storing the meta data in the database";
// if we have an image in the id3v2 tag, we might as well do something with it
// we'll simply use the first image we can find in the file
if( !empty( $meta['id3v2']['APIC'][0]['data'] )) {
$image = $meta['id3v2']['APIC'][0];
} elseif( !empty( $meta['id3v2']['PIC'][0]['data'] )) {
$image = $meta['id3v2']['PIC'][0];
// write the image to temp file for us to process
if( $fp = fopen( $tmpfile, 'w' )) {
fwrite( $fp, $image['data'] );
$fileHash['type'] = $image['mime'];
$fileHash['source_file'] = $tmpfile;
$fileHash['dest_branch'] = $pParamHash['upload']['dest_branch'];
if( !empty( $tmpfile ) && is_file( $tmpfile )) {
// TODO: when tags package is enabled add an option to add tags
// recommended tags might be artist and album
// TODO: fetch album cover from amazon.com or musicbrainz.org
// fetch lyrics from lyricwiki.org
//$item->mLogs['audio_converter'] = "Audio file was successfully converted to MP3.";
$pParamHash['log'] = array_merge( $pParamHash['log'], $log );
* mime_audio_converter_mplayer_lame will decode the audio to wav using mplayer and then encode to mp3 using lame
* @param array $pParamHash file information
* @param array $pSource source file
* @param array $pDest destination file
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
if( !empty( $pParamHash ) && !empty( $pSource ) && is_file( $pSource ) && !empty( $pDest )) {
// confirm that both applications are available
// we will decode the audio file using mplayer and encode using lame
$mplayer_params = " -quiet -vo null -vc dummy -af volume=0,resample=44100:0:1 -ao pcm:waveheader:file='$pSource.wav' '$pSource' ";
$lame_params = $gBitSystem->getConfig( "mime_audio_lame_options", " -b ". ( $gBitSystem->getConfig( 'mime_audio_bitrate', 64000 ) / 1000 )). " '$pSource.wav' '$pDest' ";
$command = "$mplayer $mplayer_params && $lame $lame_params";
// remove the temporary wav file again
// make sure the conversion was successfull
// remove unsuccessfully converted file
$log['message'] = 'ERROR: The audio you uploaded could not be converted by mplayer and lame. DEBUG OUTPUT: '. nl2br( $debug );
// write error message to error file
fwrite( $h, "$command\n\n$mm\n\n$ll\n\n$debug" );
$pParamHash['log'] = array_merge( $pParamHash['log'], $log );
* mime_audio_converter_ffmpeg
* @param array $pParamHash file information
* @param array $pSource source file
* @param array $pDest destination file
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
if( !empty( $pParamHash ) && !empty( $pSource ) && is_file( $pSource ) && !empty( $pDest )) {
// these are set in the liberty plugin admin screen
// set up parameters to convert audio
" -acodec ". $gBitSystem->getConfig( 'ffmpeg_mp3_lib', 'libmp3lame' ).
" -ab ". trim( $gBitSystem->getConfig( 'mime_audio_bitrate', 64000 ). 'b' ).
" -ar ". trim( $gBitSystem->getConfig( 'mime_audio_samplerate', 22050 )).
// make sure the conversion was successfull
// remove unsuccessfully converted file
$log['message'] = 'ERROR: The audio you uploaded could not be converted by ffmpeg. DEBUG OUTPUT: '. nl2br( $debug );
// write error message to error file
fwrite( $h, "$ffmpeg $params\n\n$ff\n\n$debug" );
$pParamHash['log'] = array_merge( $pParamHash['log'], $log );
* mime_audio_update_tags will update the tags of a given audio file
* @param array $pFile absolute path to file
* @param array $pMetaData Hash of data that should be passed to the file.
* @return NULL on success, String of errors on failure
// we need to initiate getID3 for the writer to work
// Initialize getID3 tag-writing module
$tagwriter = new getid3_writetags();
$tagwriter->filename = $pFile;
$tagwriter->tagformats = array( 'id3v1', 'id3v2.3' );
$tagwriter->overwrite_tags = TRUE;
$tagwriter->tag_encoding = "UTF-8";
// prepare meta data for storing
foreach( $pMetaData as $key => $data ) {
$tagwriter->tag_data = $write;
if( !$tagwriter->WriteTags() ) {
$ret = 'Failed to write tags!<br />'. implode( '<br /><br />', $tagwriter->errors );
|