Thứ Năm, 12 tháng 12, 2013

Sự khác nhau giữa Service và IntentService

Service is a base class of service implementation. However, according to my understanding, it's not a best choice to begin with. Service class is run in the application's main thread which may reduce the application performance. Thus, IntentService, which is a direct subclass of Service is borned to make things easier. In my opinion, the main concern of IntentService class is about the thread, but there are also other differences out there.
Differences
  1. Service class uses the application's main thread, while IntentService creates a worker thread and uses that thread to run the service.
  2. IntentService creates a queue that passes one intent at a time to onHandleIntent(). Thus, implementing a multi-thread should be made by extending Service class directly.
  3. Service class needs a manual stop using stopSelf(). Meanwhile, IntentService automatically stops itself when there is no intent in queue. 
  4. IntentService implements onBind() that returns null. This means that the IntentService can not be bound by default.
  5. IntentService implements onStartCommand() that sends Intent to queue and to onHandleIntent().
In brief, there are only two things to do to use IntentService. Firstly, to implement the constructor. And secondly, to implement onHandleIntent(). For other callback methods, the super is needed to be called so that it can be tracked properly.

Thứ Hai, 25 tháng 11, 2013

Dùng google translate để dịch trong android

package com.example.studyenglish;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;

import org.apache.http.ParseException;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;







/**
 *
 * @author Code4LifeVn
 */
public class TestTranslate {
   
    private final String googleTranslatorURL = "http://translate.google.com/translate_a/t?";
    private LANGUAGE srcLang = LANGUAGE.AUTO;
    private LANGUAGE destLang = LANGUAGE.VIETNAMESE;
    private String userAgent = "Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Mobile/7A341 Safari/528.16";

    public String translate(String query) throws MalformedURLException, IOException, ParseException {
        URL url = new URL(this.buildURLRequestWith(query));
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.addRequestProperty("User-Agent", this.userAgent);
        conn.setRequestMethod("GET");
        conn.setConnectTimeout(30000);
        conn.connect();

        InputStream inputStream = conn.getInputStream();
        BufferedReader bis = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
        String respContent = bis.readLine();
        inputStream.close();
        bis.close();
        conn.disconnect();

        StringBuilder contentBuilder = new StringBuilder();

        try {
        JSONObject jsonData = new JSONObject(respContent);
        JSONArray sentences = (JSONArray) jsonData.get("sentences");
   JSONObject jsondetail = sentences.getJSONObject(0);
   contentBuilder.append(jsondetail.get("trans"));
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

        return contentBuilder.toString().trim().replace(" .", ". ");
    }

    private String buildURLRequestWith(String query) {
        StringBuilder urlBuilder = new StringBuilder();
        urlBuilder.append(this.googleTranslatorURL);
        urlBuilder.append("client=webapp");
        urlBuilder.append("&sl=auto");
        urlBuilder.append("&tl=").append(this.destLang);
        urlBuilder.append("&hl=").append(this.srcLang);
        urlBuilder.append("&sc=1");
        String queryEncoded = "";
        try {
            queryEncoded = URLEncoder.encode(query, "UTF-8");
            System.out.print(queryEncoded);
        } catch (Exception e) {
        }
        urlBuilder.append("&q=").append(queryEncoded);
        return urlBuilder.toString();
    }

    public LANGUAGE getSrcLang() {
        return srcLang;
    }

    public void setSrcLang(LANGUAGE srcLang) {
        this.srcLang = srcLang;
    }

    public LANGUAGE getDestLang() {
        return destLang;
    }

    public void setDestLang(LANGUAGE destLang) {
        this.destLang = destLang;
    }

    public String getUserAgent() {
        return userAgent;
    }

    public void setUserAgent(String userAgent) {
        this.userAgent = userAgent;
    }
   
    public static enum LANGUAGE {
        ENGLISH("en"),
        VIETNAMESE("vi"),
        AUTO("auto");
       
        private String lang = "";
        private LANGUAGE(String lang) {
            this.lang = lang;
        }
        @Override
        public String toString() {
            return this.lang;
        }
    }
       
}

Cách dùng:
TestTranslate translator = new TestTranslate();
       translator.setSrcLang(LANGUAGE.ENGLISH);
       translator.setDestLang(LANGUAGE.VIETNAMESE);
       String data = null;      
try {
data = translator.translate(url);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (org.apache.http.ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

Thứ Bảy, 23 tháng 11, 2013

How to copy files in 'assets' to sdcard?

private void copyAssets() {
    AssetManager assetManager = getAssets();
    String[] files = null;
    try {
        files = assetManager.list("");
    } catch (IOException e) {
        Log.e("tag", "Failed to get asset file list.", e);
    }
    for(String filename : files) {
        InputStream in = null;
        OutputStream out = null;
        try {
          in = assetManager.open(filename);
          File outFile = new File(getExternalFilesDir(null), filename);
          out = new FileOutputStream(outFile);
          copyFile(in, out);
          in.close();
          in = null;
          out.flush();
          out.close();
          out = null;
        } catch(IOException e) {
            Log.e("tag", "Failed to copy asset file: " + filename, e);
        }       
    }
}
private void copyFile(InputStream in, OutputStream out) throws IOException {
    byte[] buffer = new byte[1024];
    int read;
    while((read = in.read(buffer)) != -1){
      out.write(buffer, 0, read);
    }
}
Reference : Move file using Java

Thứ Sáu, 22 tháng 11, 2013

Play audio file from the assets directory

public void playBeep() {
    try {

        if (m.isPlaying()) {
            m.stop();
            m.release();
            m = new MediaPlayer();
        }
        AssetFileDescriptor descriptor = getAssets().openFd("beepbeep.mp3");
        m.setDataSource(descriptor.getFileDescriptor(), descriptor.getStartOffset(), descriptor.getLength());
        descriptor.close();

        m.prepare();
        m.setVolume(1f, 1f);
        m.setLooping(true);
        m.start();
    } catch (Exception e) {
    }
Your version would work if you had only one file in the assets directory. The asset directory contents are not actually 'real files' on disk. All of them are put together one after another. So, if you do not specify where to start and how many bytes to read, the player will read up to the end (that is, will keep playing all the files in assets directory)

Thứ Hai, 18 tháng 11, 2013

Listen Scroll in webview

package com.example.studyenglish;

import android.content.Context;
import android.util.AttributeSet;
import android.webkit.WebView;

public class ObservableWebView extends WebView
{
    private OnScrollChangedCallback mOnScrollChangedCallback;

    public ObservableWebView(final Context context)
    {
        super(context);
    }

    public ObservableWebView(final Context context, final AttributeSet attrs)
    {
        super(context, attrs);
    }

    public ObservableWebView(final Context context, final AttributeSet attrs, final int defStyle)
    {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onScrollChanged(final int l, final int t, final int oldl, final int oldt)
    {
        super.onScrollChanged(l, t, oldl, oldt);
        if(mOnScrollChangedCallback != null) mOnScrollChangedCallback.onScroll(l, t);
    }

    public OnScrollChangedCallback getOnScrollChangedCallback()
    {
        return mOnScrollChangedCallback;
    }

    public void setOnScrollChangedCallback(final OnScrollChangedCallback onScrollChangedCallback)
    {
        mOnScrollChangedCallback = onScrollChangedCallback;
    }

    /**
     * Impliment in the activity/fragment/view that you want to listen to the webview
     */
    public static interface OnScrollChangedCallback
    {
        public void onScroll(int l, int t);
    }
}


wv = (ObservableWebView) findViewById(R.id.scorllableWebview); wv.setOnScrollChangedCallback(new OnScrollChangedCallback(){ public void onScroll(int l, int t){ //Do stuff Log.d(TAG,"We Scrolled etc..."); } });

Thứ Tư, 6 tháng 11, 2013

Code import file database từ bên ngoài trong android

package com.example.studyenglish;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.channels.FileChannel;
import java.util.ArrayList;



import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Environment;
import android.util.Log;

public class DataEnglish extends SQLiteOpenHelper{

    //The Android's default system path of your application database.
    private static String DB_PATH ;

    private static String DB_NAME = "test";

    private SQLiteDatabase myDataBase;

    private final Context myContext;

    /**
     * Constructor
     * Takes and keeps a reference of the passed context in order to access to the application assets and resources.
     * @param context
     */
    public DataEnglish(Context context) {

    super(context, DB_NAME, null, 2);
    DB_PATH = context.getApplicationInfo().dataDir + "/databases/";
    Log.d("phanbom","Link toi thu muc databases"+DB_PATH );
        this.myContext = context;
    }

  /**
     * Creates a empty database on the system and rewrites it with your own database.
     * */
    public void createDataBase() throws IOException{

    boolean dbExist = checkDataBase();
        Log.d("phanbom","Check db ton tai:"+dbExist);
    if(dbExist){
    //do nothing - database already exist
    }else{

    //By calling this method and empty database will be created into the default system path
               //of your application so we are gonna be able to overwrite that database with our database.
        this.getReadableDatabase();

        try {

    copyDataBase();

    } catch (IOException e) {

        throw new Error("Error copying database");

        }
    }

    }

    /**
     * Check if the database already exist to avoid re-copying the file each time you open the application.
     * @return true if it exists, false if it doesn't
     */
    private boolean checkDataBase(){

    SQLiteDatabase checkDB = null;

    try{
    String myPath = DB_PATH + DB_NAME;
    checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);

    }catch(SQLiteException e){

    //database does't exist yet.

    }

    if(checkDB != null){

    checkDB.close();

    }

    return checkDB != null ? true : false;
    }

    /**
     * Copies your database from your local assets-folder to the just created empty database in the
     * system folder, from where it can be accessed and handled.
     * This is done by transfering bytestream.
     * */
    private void copyDataBase() throws IOException{
        Log.d("phanbom","Vao ham copyDataBase()" );
    //Open your local db as the input stream
    InputStream myInput = myContext.getAssets().open(DB_NAME);
        Log.d("phanbom","Copy file from asset local" );
    // Path to the just created empty db
    String outFileName = DB_PATH + DB_NAME ;

    //Open the empty db as the output stream
    OutputStream myOutput = new FileOutputStream(outFileName);
        Log.d("phanbom","open system file" );
    //transfer bytes from the inputfile to the outputfile
    byte[] buffer = new byte[1024];
    int length;
    while ((length = myInput.read(buffer))>0){
    myOutput.write(buffer, 0, length);
    }

    //Close the streams
    myOutput.flush();
    myOutput.close();
    myInput.close();

    }

    public void openDataBase() throws SQLException{

    //Open the database
        String myPath = DB_PATH + DB_NAME ;
    myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
    }

    @Override
public synchronized void close() {

       if(myDataBase != null)
       myDataBase.close();

       super.close();

}

@Override
public void onCreate(SQLiteDatabase db) {

}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
         
}

        // Add your public helper methods to access and get content from the database.
       // You could return cursors by doing "return myDataBase.query(....)" so it'd be easy
       // to you to create adapters for your views.
public void getCategory(){


   // Select All Query
   String selectQuery = "SELECT * FROM stream";

 
   Cursor cursor = myDataBase.rawQuery(selectQuery, null);
   Log.d("phanbom","Da query bang stream" );
   // looping through all rows and adding to list
   if (cursor.moveToFirst()) {
       do {
   
       } while (cursor.moveToNext());
   }
   // return contact list

}
}

Day la mot phien ban ngan hon
  package com.javatarts.basketballgm.data;
 
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
 
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
 
public class AssetDatabaseOpenHelper {
 
private static final String DB_NAME = "asset.db";
 
private Context context;
 
public AssetDatabaseOpenHelper(Context context) {
this.context = context;
}
 
public SQLiteDatabase openDatabase() {
File dbFile = context.getDatabasePath(DB_NAME);
 
if (!dbFile.exists()) {
try {
copyDatabase(dbFile);
} catch (IOException e) {
throw new RuntimeException("Error creating source database", e);
}
}
 
return SQLiteDatabase.openDatabase(dbFile.getPath(), null, SQLiteDatabase.OPEN_READONLY);
}
 
private void copyDatabase(File dbFile) throws IOException {
InputStream is = context.getAssets().open(DB_NAME);
OutputStream os = new FileOutputStream(dbFile);
 
byte[] buffer = new byte[1024];
while (is.read(buffer) > 0) {
os.write(buffer);
}
 
os.flush();
os.close();
is.close();
}
 
}

Thứ Tư, 16 tháng 10, 2013

Các loại lỗi trong mediaplayer

/* ------------------------------------------------------------------
 * Copyright (C) 1998-2009 PacketVideo
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 * -------------------------------------------------------------------
 */

/**
 *  @file pv_return_codes.h
 *  @brief This file defines the general return and event codes to be used by PVMF elements.
 *         Theses base-level codes are unique. Error codes are negative values and informational
 *         codes are positive values.
 *  NOTE: If you add any new event, update the PVMFStatusToString method as well.
 */

#ifndef PVMF_RETURN_CODES_H_INCLUDED
#define PVMF_RETURN_CODES_H_INCLUDED

#ifndef OSCL_BASE_H_INCLUDED
#include "oscl_base.h"
#endif


typedef int32 PVMFStatus;

// Return codes
/*
 Return code for general success
 */
const PVMFStatus PVMFSuccess = 1;
/*
 Return code for pending completion
 */
const PVMFStatus PVMFPending = 0;
/*
 Return code for never set
 */
const PVMFStatus PVMFNotSet = 2;


// Error codes (negative values)

/*
 Definition of first error event in range (not an actual error code).
 */
const PVMFStatus PVMFErrFirst = (-1);
/*
 Return code for general failure
 */
const PVMFStatus PVMFFailure = (-1);
/*
 Error due to cancellation
 */
const PVMFStatus PVMFErrCancelled = (-2);
/*
 Error due to no memory being available
 */
const PVMFStatus PVMFErrNoMemory = (-3);
/*
 Error due to request not being supported
 */
const PVMFStatus PVMFErrNotSupported = (-4);
/*
 Error due to invalid argument
 */
const PVMFStatus PVMFErrArgument = (-5);
/*
 Error due to invalid resource handle being specified
 */
const PVMFStatus PVMFErrBadHandle = (-6);
/*
 Error due to resource already exists and another one cannot be created
 */
const PVMFStatus PVMFErrAlreadyExists = (-7);
/*
 Error due to resource being busy and request cannot be handled
 */
const PVMFStatus PVMFErrBusy = (-8);
/*
 Error due to resource not ready to accept request
 */
const PVMFStatus PVMFErrNotReady = (-9);
/*
 Error due to data corruption being detected
 */
const PVMFStatus PVMFErrCorrupt = (-10);
/*
 Error due to request timing out
 */
const PVMFStatus PVMFErrTimeout = (-11);
/*
 Error due to general overflow
 */
const PVMFStatus PVMFErrOverflow = (-12);
/*
 Error due to general underflow
 */
const PVMFStatus PVMFErrUnderflow = (-13);
/*
 Error due to resource being in wrong state to handle request
 */
const PVMFStatus PVMFErrInvalidState = (-14);
/*
 Error due to resource not being available
 */
const PVMFStatus PVMFErrNoResources = (-15);
/*
 Error due to invalid configuration of resource
 */
const PVMFStatus PVMFErrResourceConfiguration = (-16);
/*
 Error due to general error in underlying resource
 */
const PVMFStatus PVMFErrResource = (-17);
/*
 Error due to general data processing
 */
const PVMFStatus PVMFErrProcessing = (-18);
/*
 Error due to general port processing
 */
const PVMFStatus PVMFErrPortProcessing = (-19);
/*
 Error due to lack of authorization to access a resource.
 */
const PVMFStatus PVMFErrAccessDenied = (-20);
/*
 Error due to the lack of a valid license for the content
 */
const PVMFStatus PVMFErrLicenseRequired = (-21);
/*
 Error due to the lack of a valid license for the content.  However
 a preview is available.
 */
const PVMFStatus PVMFErrLicenseRequiredPreviewAvailable = (-22);
/*
 Error due to the download content length larger than the maximum request size
 */
const PVMFStatus PVMFErrContentTooLarge = (-23);
/*
 Error due to a maximum number of objects in use
 */
const PVMFStatus PVMFErrMaxReached = (-24);
/*
 Return code for low disk space
 */
const PVMFStatus PVMFLowDiskSpace = (-25);
/*
 Error due to the requirement of user-id and password input from app for HTTP basic/digest authentication
 */
const PVMFStatus PVMFErrHTTPAuthenticationRequired = (-26);
/*
 PVMFMediaClock specific error. Callback has become invalid due to change in direction of NPT clock.
*/
const PVMFStatus PVMFErrCallbackHasBecomeInvalid = (-27);
/*
 PVMFMediaClock specific error. Callback is called as clock has stopped.
*/
const PVMFStatus PVMFErrCallbackClockStopped = (-28);
/*
 Error due to missing call for ReleaseMatadataValue() API
 */
const PVMFStatus PVMFErrReleaseMetadataValueNotDone = (-29);
/*
 Error due to the redirect error
*/
const PVMFStatus PVMFErrRedirect = (-30);
/*
 Error if a given method or API is not implemented. This is NOT the same as PVMFErrNotSupported.
*/
const PVMFStatus PVMFErrNotImplemented = (-31);
/*
 Error: the video container is not valid for progressive playback.
 */
const PVMFStatus PVMFErrContentInvalidForProgressivePlayback = (-32);
/*
 Placeholder for last event in range.
 */
const PVMFStatus PVMFErrLast = (-100);
/*
 Macro to tell if a value is in PVMFErr range
 */
#define IsPVMFErrCode(s) ((PVMFErrLast<=s)&&(s<=PVMFErrFirst))

// Informational codes (positive values)

const PVMFStatus PVMFInfoFirst = 10;

/*
 Notification that a port was created
 */
const PVMFStatus PVMFInfoPortCreated = 10;
/*
 Notification that a port was deleted
 */
const PVMFStatus PVMFInfoPortDeleted = 11;
/*
 Notification that a port was connected
 */
const PVMFStatus PVMFInfoPortConnected = 12;
/*
 Notification that a port was disconnected
 */
const PVMFStatus PVMFInfoPortDisconnected = 13;
/*
 Notification that an overflow occurred (not fatal error)
 */
const PVMFStatus PVMFInfoOverflow = 14;
/*
 Notification that an underflow occurred (not fatal error)
 */
const PVMFStatus PVMFInfoUnderflow = 15;
/*
 Notification that a processing failure occurred (not fatal error)
 */
const PVMFStatus PVMFInfoProcessingFailure = 16;
/*
 Notification that end of data stream has been reached
 */
const PVMFStatus PVMFInfoEndOfData = 17;
/*
 Notification that a data buffer has been created
 */
const PVMFStatus PVMFInfoBufferCreated = 18;
/*
 Notification that buffering of data has started
 */
const PVMFStatus PVMFInfoBufferingStart = 19;
/*
 Notification for data buffering level status
 */
const PVMFStatus PVMFInfoBufferingStatus = 20;
/*
 Notification that data buffering has completed
 */
const PVMFStatus PVMFInfoBufferingComplete = 21;
/*
 Notification that data is ready for use
 */
const PVMFStatus PVMFInfoDataReady = 22;
/*
 Notification for position status
 */
const PVMFStatus PVMFInfoPositionStatus = 23;
/*
 Notification for node state change
 */
const PVMFStatus PVMFInfoStateChanged = 24;
/*
 Notification that data was discarded during synchronization.
 */
const PVMFStatus PVMFInfoDataDiscarded = 25;
/*
 Notification that error handling has started
 */
const PVMFStatus PVMFInfoErrorHandlingStart = 26;
/*
 Notification that error handling has completed
 */
const PVMFStatus PVMFInfoErrorHandlingComplete = 27;
/*
 Notification from a remote source
 */
const PVMFStatus PVMFInfoRemoteSourceNotification = 28;
/*
 Notification that license acquisition has started.
 */
const PVMFStatus PVMFInfoLicenseAcquisitionStarted = 29;
/*
 Notification that download content length is available
 */
const PVMFStatus PVMFInfoContentLength = 30;
/*
 Notification that downloaded content reaches the maximum request size, and will
 be truncated, especially for the case of unavailable content length
 */
const PVMFStatus PVMFInfoContentTruncated = 31;
/*
 Notification that source format is not supported, typically sent
 during protocol rollover
 */
const PVMFStatus PVMFInfoSourceFormatNotSupported = 32;
/*
 Notification that a clip transition has occurred while playing a playlist
 */
const PVMFStatus PVMFInfoPlayListClipTransition = 33;
/*
 Notification that content type for download or HTTP streaming is available
 */
const PVMFStatus PVMFInfoContentType = 34;
/*
 Notification that paticular track is disable. This one is on a per track basis.
 */
const PVMFStatus PVMFInfoTrackDisable = 35;
/*
 Notification that unexpected data has been obtained, especially for download,
 when client receives from server more data than requested in content-length header
 */
const PVMFStatus PVMFInfoUnexpectedData = 36;
/*
 Notification that server discnnect happens after download is complete
 */
const PVMFStatus PVMFInfoSessionDisconnect = 37;
/*
 Notification that new meadi stream has been started
 */
const PVMFStatus PVMFInfoStartOfData = 38;
/*
 Notification that node has processed a command with ReportObserver marker info
 */
const PVMFStatus PVMFInfoReportObserverRecieved = 39;
/*
 Notification that meta data is available with source node
 */
const PVMFStatus PVMFInfoMetadataAvailable = 40;
/*
 Notification that duration is available with source node
 */
const PVMFStatus PVMFInfoDurationAvailable = 41;
/*
 Notification that Change Position request not supported
 */
const PVMFStatus PVMFInfoChangePlaybackPositionNotSupported = 42;
/*
 Notification that the content is poorly inter-leaved
 */
const PVMFStatus PVMFInfoPoorlyInterleavedContent = 43;
/*
 Notification for actual playback position after repositioning
 */
const PVMFStatus PVMFInfoActualPlaybackPosition = 44;
/*
 Notification that the live buffer is empty
 */
const PVMFStatus PVMFInfoLiveBufferEmpty = 45;
/*
 Notification that a server has responded with 200 OK to a Playlist play request
 */
const PVMFStatus PVMFInfoPlayListSwitch = 46;
/*
 Notification of configuration complete
 */
const PVMFStatus PVMFMIOConfigurationComplete = 47;
/*
 Notification that the video track is falling behind
 */
const PVMFStatus PVMFInfoVideoTrackFallingBehind = 48;
/*
 Notification that memory is not available for new RTP packets
 */
const PVMFStatus PVMFInfoSourceOverflow = 49;
/*
 Notification for Media data length in shoutcast session
 */
const PVMFStatus PVMFInfoShoutcastMediaDataLength = 50;
/*
 Notification for clip bitrate in shoutcast session
 */
const PVMFStatus PVMFInfoShoutcastClipBitrate = 51;
/*
 Notification for shoutcast session
 */
const PVMFStatus PVMFInfoIsShoutcastSesssion = 52;
/*
 Placeholder for end of range
 */
const PVMFStatus PVMFInfoLast = 100;
/*
 Macro to tell if a code is in PVMFInfo range
 */
#define IsPVMFInfoCode(s) ((PVMFInfoFirst<=s)&&(s<=PVMFInfoLast))

// Convert a PVMFStatus code to a string that can be used in logs.
// @param status code.
// @return a human readable string representing the status.
OSCL_IMPORT_REF const char *PVMFStatusToString(const PVMFStatus status);

#endif