Showing posts with label Android. Show all posts
Showing posts with label Android. Show all posts

Tuesday, July 23, 2013

Android - DBHelper

Android using Sqlite as primary storage for android application, below is the sample code for create, upgrade or delete database.


Usually you will require to create one Helper for 1 database, we create our first helper class name "DBHelper", this class extends SQLiteOpenHelper and you need implement at least 2 methods


  • onCreate()
  • onUpgrade()
Always create only single instance for any DBHelper to avoid open & close connection of DB.


   public static DBHelper getInstance() {
        if(instance == null) {
            instance = new UserDatabaseHelper();
        }
        return instance;
    }



After install and start the app, verify if the db created.

root@android:/data/data/com.androidtutorial/databases # ls
Songs.db
Songs.db-journal
e3 Songs.db                                                                   <
SQLite version 3.7.16 2013-03-18 11:39:23 [www.ptsoft.org] [www.ptdave.com]
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> .tables
Songs             android_metadata
sqlite> select * from Songs;
sqlite> select * from Songs;
song1
sqlite> 


The songs.db is created.


One confusing about onUpgrade, if you upgrade the db version from 2~10, don't expect onUpgrade will handle for you, you need do some checking as below.

   @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        Log.d(TAG, "onUpgrade ..." + oldVersion ); 
        oldVersion += 1;
        if(oldVersion < newVersion) {
            onUpgrade(db, oldVersion, newVersion);
        }
    }



Thursday, May 9, 2013

JNI Detaching threads (native thread exited without detaching)


Attached thread must detact before the thread exit, when involved in Android JNI programming plus dealing with multithread usually you will facing problem like "threadid=41: native thread exited without detaching". To solved this problem is possible when use 'pthread_key_create', below is how to implement.


1. We need register a function pointer do detach the thread during JNI_Onload(), function 'detach_current_thread' will called during thread exit.

static void detach_current_thread (void *env) {
  (*java_vm)->DetachCurrentThread (java_vm);
}

jint JNI_OnLoad(JavaVM *vm, void *reserved) {
  JNIEnv *env = NULL;
  java_vm = vm;
  if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
    return 0;
  } 
  pthread_key_create (&current_jni_env, detach_current_thread);
  return JNI_VERSION_1_4;
}



2. During callback to Java, we check the current_jni_env if initialized. 

static JNIEnv *get_jni_env (void) {
JNIEnv *env;
if ((env = pthread_getspecific (current_jni_env)) == NULL) {
env = attach_current_thread ();
pthread_setspecific (current_jni_env, env);
}
return env;
}

if current_jni_env is NULL, will attach thread to VM.


That all you need to solved the "thread exited without detaching" because pthread will call detach_current_thread before exit.




Saturday, November 24, 2012

Android Traceview Profile Panel Descriptions


FieldDescription
InclPercentage of time occupied by calling the method
InclusiveThe call method time (ms) (including all method calls)
ExclThe percentage of time occupied by the execution method
ExclusiveExecution method takes time (ms) (does not include sub-method calls)
Calls+Recur Calls/TotalThe number of calls and repeat calls
Time/CallThe total time (ms)

Thursday, October 25, 2012

Install Busybox for Jellyebean

1. Download files:

http://www.busybox.net/downloads/binaries/1.19.0/busybox-armv6l

2. Create dir

$ mkdir -p META-INF/com/google/android/
$ mkdir -p system/bin/busybox

You should get something like this...
.

├── META-INF
│   └── com
│       └── google
│           └── android
│               ├── update-binary
│               └── updater-script
└── system
    └── bin
        └── busybox

3. Move the file, you need 'update-binary', updater-script from other update.zip
$ mv busybox-armv6l busybox/system/bin/busybox

4. Update the updater-script with content below :
ui_print("Busybox 1.19.0 for Android 2.0-4.1 arm");
ui_print("Mounting system...");
run_program("/sbin/busybox", "mount", "/system");
ui_print("Deleting old files...");
delete("/system/bin/busybox","/system/xbin/busybox");
ui_print("Copying files...");
package_extract_dir("system", "/system");
ui_print("Fixing permissions...");
set_perm(0, 0, 06755, "/system/bin/busybox");
ui_print("Symlinking...");
symlink("/system/bin/busybox", "/system/xbin/busybox");
ui_print("Unmounting system...");
run_program("/sbin/busybox", "umount", "/system");
ui_print("Installation complete!");


5. Zip & Signed
$ keytool -genkey -v -alias mw_apk_signed_key -keyalg RSA -keysize 2048 -validity 10000 -keystore .keystore

$ jarsigner -verbose -keystore .keystore busybox.zip mw_apk_signed_key
Enter Passphrase for keystore: 
   adding: META-INF/MANIFEST.MF
   adding: META-INF/MW_APK_S.SF
   adding: META-INF/MW_APK_S.RSA
   adding: system/bin/
  signing: system/bin/busybox


6. Install
$ adb push busybox.zip /sdcard/
$ adb reboot recovery

Install the busybox.zip from recovery....

Monday, October 22, 2012

Build CM10 from source for Galaxy S2 (i9100)

1. Basic env setup is needed before head to CM site, please follow the instructions HERE to setup the build env.

2. Downloading source from github.

$ mkdir /opt/android/cm
$ cd /opt/android/cm
$ repo init -u git://github.com/CyanogenMod/android.git -b jellybean
$ repo sync -j4

3. Copy proprietary files from your device, assume you have android-sdk installed, if you don't please proceed to android.com for details.



create ~/android/system/.repo/local_manifest.xml using this content:

<?xml version="1.0" encoding="UTF-8"?>
<manifest>
  <project name="teamhacksung/buildscripts" path="buildscripts" remote="github" revision="jellybean">
    <copyfile dest="build.sh" src="build.sh" />
  </project>
</manifest>


$ repo sync -j4
$ . build/envsetup.sh


$ lunch

You're building on Linux


Lunch menu... pick a combo:
     1. full-eng
     2. full_x86-eng
     3. vbox_x86-eng
     4. mini_armv7a_neon-userdebug
     5. mini_armv7a-userdebug
     6. full_panda-userdebug
     7. cm_a700-userdebug
     8. cm_captivatemtd-userdebug
     9. cm_crespo-userdebug
     10. cm_crespo4g-userdebug
     11. cm_d2att-userdebug
     12. cm_d2spr-userdebug
     13. cm_d2tmo-userdebug
     14. cm_d2usc-userdebug
     15. cm_d2vzw-userdebug
     16. cm_endeavoru-userdebug
     17. cm_epicmtd-userdebug
     18. cm_everest-userdebug
     19. cm_evita-userdebug
     20. cm_fascinatemtd-userdebug
     21. cm_galaxysmtd-userdebug
     22. cm_galaxysbmtd-userdebug
     23. cm_grouper-userdebug
     24. cm_hercules-userdebug
     25. cm_i777-userdebug
     26. cm_i9100-userdebug
     27. cm_i9100g-userdebug
     28. cm_i9300-userdebug
     29. cm_jewel-userdebug
     30. cm_mint-userdebug
     31. cm_maguro-userdebug
     32. cm_mesmerizemtd-userdebug
     33. cm_n7000-userdebug
     34. cm_n8000-userdebug
     35. cm_n8013-userdebug
     36. cm_quincyatt-userdebug
     37. cm_quincytmo-userdebug
     38. cm_p1-userdebug
     39. cm_p1c-userdebug
     40. cm_p1l-userdebug
     41. cm_p1n-userdebug
     42. cm_p3100-userdebug
     43. cm_p3110-userdebug
     44. cm_p3113-userdebug
     45. cm_p5100-userdebug
     46. cm_p5110-userdebug
     47. cm_p5113-userdebug
     48. cm_p930-userdebug
     49. cm_p970-userdebug
     50. cm_skyrocket-userdebug
     51. cm_stingray-userdebug
     52. cm_su640-userdebug
     53. cm_tf101-userdebug
     54. cm_tf201-userdebug
     55. cm_tf300t-userdebug
     56. cm_toro-userdebug
     57. cm_toroplus-userdebug
     58. cm_t769-userdebug
     59. cm_vibrantmtd-userdebug
     60. cm_ville-userdebug
     61. cm_wingray-userdebug

Which would you like? [full-eng] 26


I pick (26cd vemd), i9100...., wait until the repo synced.



$ cd device/samsung/i9100/
$ ./proprietary-files.sh



3. Build.
$ cd ../../..
$ . /build.sh i9100
$ cd out/target/product/i9100/
$ adb push cm-10-20121021-UNOFFICIAL-i9100.zip /sdcard/
$ adb reboot recovery

Flash the update with CWM-Recovery.

END.

Friday, October 19, 2012

Android profiling with ARM Streamline

Configs :



1. Getting kernel source for Nexus S.
$mkdir ~/android
$cd android
$ git clone https://android.googlesource.com/kernel/samsung.git

2. Checkout the source.

$ git branch -r
  origin/HEAD -> origin/master
  origin/android-samsung-2.6.35-gingerbread
  origin/android-samsung-3.0-ics-mr1
  origin/android-samsung-3.0-jb
  origin/master

$git checkout android-samsung-2.6.35-gingerbread origin/android-samsung-2.6.35-gingerbread



3. Export prebuild toolchanin & build vars...
$export PATH=<SDK_PATH>/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin:$PATH

$export ARCH=arm
$export SUBARCH=arm
$export CROSS_COMPILE=arm-eabi-




4. Compile kernel and gator module.

$ make herring_defconfig

arch/arm/configs/herring_defconfig:323:warning: override: reassigning to symbol LOCALVERSION_AUTO
arch/arm/configs/herring_defconfig:333:warning: override: reassigning to symbol NET_ACTIVITY_STATS
#
# configuration written to .config
#
#herring_defconfig is config for NEXUS S, use 'make help' to find out your device config

$nano .config
Ensure the parameters below is set.
  • CONFIG_PROFILING=y
  • CONFIG_FTRACE=y 
  • CONFIG_ENABLE_DEFAULT_TRACERS=y


$ make -j4 CROSS_COMPILT=arm-eabi- uImage
  CHK     include/linux/version.h
  CHK     include/generated/utsrelease.h
make[1]: `include/generated/mach-types.h' is up to date.
  CALL    scripts/checksyscalls.sh
  CHK     include/generated/compile.h
  Kernel: arch/arm/boot/Image is ready
  SHIPPED arch/arm/boot/compressed/lib1funcs.S
  AS      arch/arm/boot/compressed/lib1funcs.o
  LD      arch/arm/boot/compressed/vmlinux
  OBJCOPY arch/arm/boot/zImage
  Kernel: arch/arm/boot/zImage is ready
  UIMAGE  arch/arm/boot/uImage
Image Name:   Linux-2.6.35.7-gf5f63ef
Created:      Thu Sep 27 13:36:20 2012
Image Type:   ARM Linux Kernel Image (uncompressed)
Data Size:    3017840 Bytes = 2947.11 kB = 2.88 MB
Load Address: 30008000
Entry Point:  30008000
  Image arch/arm/boot/uImage is ready


5. Build Gator module

Install DS-5 module for Eclipse, detail please refer to HERE.

or

Download DS-5 from http://www.arm.com/products/tools/software-tools/ds-5/index.php



6. After install.....go Eclipse Help-> ARM Extras, explore pop out.....
navigate to 'driver-src', extract 'gator-driver.tar.gz'.. to kernel dir.

$ cd gator-driver/
$ make -C path/to/kernel  M=`pwd`  modules
$ cd ..
$ adb pull /sdcard/init.rc /path/to/sdk/tools/

7. go Eclipse Help-> ARM Extras, explore pop out.....
navigate to 'daemon-src'.

$ mkdir /path/to/arm/gator/android
$ cp /path/to/arm/gator/daemon-src/gator-daemon/gator-daemon.tar.gz /path/to/arm/gator/android/
$ tar -zxvf gator-daemon.tar.gz
$ mv gator-daemon jni

$ ndk-build
Compile++ thumb  : gatord <= CapturedXML.cpp
Compile++ thumb  : gatord <= Child.cpp
Compile++ thumb  : gatord <= Collector.cpp
Compile++ thumb  : gatord <= ConfigurationXML.cpp
Compile++ thumb  : gatord <= Fifo.cpp
Compile++ thumb  : gatord <= LocalCapture.cpp
Compile++ thumb  : gatord <= Logging.cpp
Compile++ thumb  : gatord <= main.cpp
Compile++ thumb  : gatord <= OlySocket.cpp
Compile++ thumb  : gatord <= OlyUtility.cpp
Compile++ thumb  : gatord <= Sender.cpp
Compile++ thumb  : gatord <= SessionData.cpp
Compile++ thumb  : gatord <= SessionXML.cpp
Compile++ thumb  : gatord <= StreamlineSetup.cpp
Compile thumb  : gatord <= mxml-attr.c
Compile thumb  : gatord <= mxml-entity.c
Compile thumb  : gatord <= mxml-file.c
Compile thumb  : gatord <= mxml-get.c
Compile thumb  : gatord <= mxml-index.c
Compile thumb  : gatord <= mxml-node.c
Compile thumb  : gatord <= mxml-private.c
Compile thumb  : gatord <= mxml-search.c
Compile thumb  : gatord <= mxml-set.c
Compile thumb  : gatord <= mxml-string.c
StaticLibrary  : libstdc++.a
Executable     : gatord
Install        : gatord => libs/armeabi/gatord

8.  Copy gatord to device.
# adb push gatord /sdcard/
# adb push gator.ko /sdcard/
# adb shell

# su
# mount -o remount,rw -t yaffs2 /dev/block/mtdblock4 /system
# mv /sdcard/gatord /system/xbin/
# mv /sdcard/gator.ko /system/xbin/


# mount -o ro,remount -t yaffs2 /dev/block/mtdblock4 /system
# sync
# reboot


9. After device boot up.

# adb shell 
# su
# gatord &

10.  Profiling Android phone with Streamline
Streamline supports connection to your target using Ethernet. Using the Android Debug Bridge (ADB) utility, it is possible to forward a TCP port from the target to your PC localhost over a USB connection. ADB can also be configured to work over Ethernet or Wi-Fi. For more information about the Android SDK and ADB setup, see the Android website. Once ADB is set up, forward the Streamline port to your localhost using the following command:

# adb forward tcp:8080 tcp:8080

Now run DS-5 on your PC and open the Streamline Data View. If it is not visible from the Window->Show View menu, select Window->Show View->Other; find “ARM Streamline” in the dialog box and open “ARM Streamline Data”. Enter the device’s Ethernet address in the Capture Options dialog box of the ARM Streamline Data view in Eclipse or DS-5. If you use the Android Debug Bridge (ADB) over USB to forward the port, enter localhost in the Address field.


[src] :
1. http://blogs.arm.com/software-enablement/682-setting-up-android-mobile-phone-to-use-arm-streamline-for-profiling/
2. http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0482d/BABECIDJ.html
3. http://source.android.com/source/building-kernels.html

Compile Android Kernel

1. First thing is find out kernel version used for your device, assume you already downloaded the source from AOSP.

$ cd /android/android-2.3.6_r0.9/device/samsung/crespo

$ git log kernel
commit c85d206feeedd1ee1c69d0e0fe9e529897a5288b
Author: JP Abgrall <jpa@google.com>
Date:   Tue Aug 2 13:47:09 2011 -0700

    kernel + wifi update: gpu only
   
      21fb4cb gpu: pvr: Update to DDK 1.6.16.4131.1.1
   
    Change-Id: I9d728a27256486ba0d2e39211d06ef7f2ebeab6b
    Signed-off-by: JP Abgrall <jpa@google.com>

commit 7af59186753f2c08ed4123e0d2693d0e11f48410
Author: Simon Wilson <simonwilson@google.com>
Date:   Wed Jun 8 19:15:05 2011 -0700

    update kernel
   
    3cc95e3 net: Reorder incoming packets in PPPoLAC and PPPoPNS.
    3128bc4 jbd2: fix fsync() tid wraparound bug
   
    Change-Id: If6a22a320491d52ccbe6abb97acf5e97886fe144

commit 7643328cd8f7eabbf2fed86899b1758308bb747a
Author: JP Abgrall <jpa@google.com>
Date:   Thu May 26 19:50:48 2011 -0700

    Revert "Custom kernel with data-usage support and persistence."
   
    This reverts commit 6a0bcab7b1eb1ca53dd26127ed623e23eeff70a9.

commit 6a0bcab7b1eb1ca53dd26127ed623e23eeff70a9
Author: JP Abgrall <jpa@google.com>
Date:   Thu May 26 19:50:27 2011 -0700

    Custom kernel with data-usage support and persistence.
   
    This is for a one-time build of Gingerbread MR3.
    Not for release.
   
    This kernel is based on
      https://partner.source.android.com/g/gitweb?p=kernel%2Fprivate%2Fsamsung.git;a=shortlog;h=refs%2Fheads%2Fandroid-samsung-2.6.35-gingerbread
       at commit 807fb588280ee28833ea7838e6fa79b9b14f66c1
   
     with the needed iface_stat, udp, ... changes on top:
       https://review.source.android.com/#change,21605
       https://review.source.android.com/#change,21093
   
   
    Change-Id: I558a7f14258c3d6c497995880356bc5a4106de62
    Signed-off-by: JP Abgrall <jpa@google.com>

commit 830fe0120276f51fc9bf5872ff190bae6839eb4b
Author: Simon Wilson <simonwilson@google.com>
Date:   Thu May 26 16:28:34 2011 -0700

    update kernel
   
    807fb58 net: wimax: wimax_status mismatch fixed.
   
    Change-Id: Ide8950f3f5db57e25e4b0682e181c8cb95717cd4

commit 794ceba05495001fe2bf495b23a76acb5263da17
Author: Simon Wilson <simonwilson@google.com>
Date:   Wed May 25 14:47:58 2011 -0700

    update kernel


The log should contain notes of the commit SHA1 for the appropriate kernel project. Keep this value at hand so that you can use it in a later step.


2. Downloading sources

$ git clone https://android.googlesource.com/kernel/samsung.git
$ cd samsung/

Display the branch

$ git branch -a
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/android-samsung-2.6.35-gingerbread
  remotes/origin/android-samsung-3.0-ics-mr1
  remotes/origin/android-samsung-3.0-jb
  remotes/origin/master
$ git checkout -b android-samsung-2.6.35-gingerbread origin/android-samsung-2.6.35-gingerbread


Checking out files: 100% (33879/33879), done.
Branch android-samsung-2.6.35-gingerbread set up to track remote branch android-samsung-2.6.35-gingerbread from origin.
Switched to a new branch 'android-samsung-2.6.35-gingerbread'


3. Assume Android-NDK is installed , if not please refer to NDK install page.

4. Setup Env

$export PATH=<android source>/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin:$PATH
$export ARCH=arm
$export SUBARCH=arm
$export CROSS_COMPILE=arm-eabi-


4. Setup default config

$ make herring_defconfig
  HOSTCC  scripts/basic/fixdep
  HOSTCC  scripts/basic/docproc
  HOSTCC  scripts/basic/hash
  HOSTCC  scripts/kconfig/conf.o
scripts/kconfig/conf.c: In function ‘conf_sym’:
scripts/kconfig/conf.c:159:6: warning: variable ‘type’ set but not used [-Wunused-but-set-variable]
scripts/kconfig/conf.c: In function ‘conf_choice’:
scripts/kconfig/conf.c:231:6: warning: variable ‘type’ set but not used [-Wunused-but-set-variable]
scripts/kconfig/conf.c:307:9: warning: ignoring return value of ‘fgets’, declared with attribute warn_unused_result [-Wunused-result]
scripts/kconfig/conf.c: In function ‘conf_askvalue’:
scripts/kconfig/conf.c:105:8: warning: ignoring return value of ‘fgets’, declared with attribute warn_unused_result [-Wunused-result]
  HOSTCC  scripts/kconfig/kxgettext.o
  SHIPPED scripts/kconfig/zconf.tab.c
  SHIPPED scripts/kconfig/lex.zconf.c
  SHIPPED scripts/kconfig/zconf.hash.c
  HOSTCC  scripts/kconfig/zconf.tab.o
  HOSTLD  scripts/kconfig/conf
arch/arm/configs/herring_defconfig:323:warning: override: reassigning to symbol LOCALVERSION_AUTO
arch/arm/configs/herring_defconfig:333:warning: override: reassigning to symbol NET_ACTIVITY_STATS
#
# configuration written to .config
#





5. Compile
$ make -j4
.........

  CC      arch/arm/boot/compressed/decompress.o
  SHIPPED arch/arm/boot/compressed/lib1funcs.S
  AS      arch/arm/boot/compressed/lib1funcs.o
  CC      crypto/ansi_cprng.mod.o
  CC      drivers/net/wireless/bcm4329/bcm4329.mod.o
  CC      drivers/scsi/scsi_wait_scan.mod.o
  LD [M]  crypto/ansi_cprng.ko
  LD [M]  drivers/net/wireless/bcm4329/bcm4329.ko
  LD [M]  drivers/scsi/scsi_wait_scan.ko
  AS      arch/arm/boot/compressed/piggy.gzip.o
  LD      arch/arm/boot/compressed/vmlinux
  OBJCOPY arch/arm/boot/zImage
  Kernel: arch/arm/boot/zImage is ready

 $ cp arch/arm/boot/zImage ../../../android/android-2.3.6_r0.9/device/samsung/crespo/kernel

6. Flash to device....
$ cd <android src>
$ make -j4
$ fastboot flash -w

Compile Android Error



find: `frameworks/base/frameworks/base/docs/html': No such file or directory
find: `out/target/common/docs/gen': No such file or directory
find: `frameworks/base/frameworks/base/docs/html': No such file or directory
find: `out/target/common/docs/gen': No such file or directory
find: `frameworks/base/frameworks/base/docs/html': No such file or directory
find: `out/target/common/docs/gen': No such file or directory
find: `frameworks/base/frameworks/base/docs/html': No such file or directory
find: `out/target/common/docs/gen': No such file or directory
find: `frameworks/base/frameworks/base/docs/html': No such file or directory
find: `out/target/common/docs/gen': No such file or directory
Install: out/host/linux-x86/framework/apicheck.jar
Install: out/host/linux-x86/framework/clearsilver.jar
Install: out/host/linux-x86/framework/droiddoc.jar
Install: out/host/linux-x86/lib/libneo_util.so
Install: out/host/linux-x86/lib/libneo_cs.so
Install: out/host/linux-x86/lib/libneo_cgi.so
Install: out/host/linux-x86/lib/libclearsilver-jni.so
Copying: out/target/common/obj/JAVA_LIBRARIES/core_intermediates/emma_out/lib/classes-jarjar.jar
Install: out/host/linux-x86/framework/dx.jar
Install: out/host/linux-x86/bin/dx
host C++: libutils <= frameworks/base/libs/utils/RefBase.cpp
<command-line>:0:0: warning: "_FORTIFY_SOURCE" redefined [enabled by default]
<built-in>:0:0: note: this is the location of the previous definition
frameworks/base/libs/utils/RefBase.cpp: In member function ‘void android::RefBase::weakref_type::trackMe(bool, bool)’:
frameworks/base/libs/utils/RefBase.cpp:483:67: error: passing ‘const android::RefBase::weakref_impl’ as ‘this’ argument of ‘void android::RefBase::weakref_impl::trackMe(bool, bool)’ discards qualifiers [-fpermissive]
make: *** [out/host/linux-x86/obj/STATIC_LIBRARIES/libutils_intermediates/RefBase.o] Error 1



 # gedit frameworks/base/libs/utils/Android.mk
Add '-fpermissive' after  "LOCAL_CFLAGS += -DLIBUTILS_NATIVE=1 $(TOOL_CFLAGS) ".
LOCAL_CFLAGS += -DLIBUTILS_NATIVE=1 $(TOOL_CFLAGS) -fpermissive

# make -j4

Until another error came up.

# gedit  /build/core/combo/HOST_linux-x86.mk

Add ' -U_FORTIFY_SOURCE' to line " HOST_GLOBAL_CFLAGS    += -D_FORTIFY_SOURCE=0".

 HOST_GLOBAL_CFLAGS
    += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0


repo forall -c 'git tag -d android-2.3.3_r1 && git fetch' 

# make -j4 


$ fastboot flashall -w
--------------------------------------------
Bootloader Version...: I9020XXKA3
Baseband Version.....: I9020XXKF1
Serial Number........: 36300317D10EC
--------------------------------------------
checking product...
OKAY [  0.001s]
checking version-bootloader...
OKAY [  0.001s]
checking version-baseband...
OKAY [  0.001s]
sending 'boot' (2936 KB)...
OKAY [  0.445s]
writing 'boot'...
OKAY [  0.379s]
sending 'recovery' (3176 KB)...
OKAY [  0.483s]
writing 'recovery'...
OKAY [  0.407s]
sending 'system' (107922 KB)...
OKAY [ 16.756s]
writing 'system'...
OKAY [ 15.917s]
erasing 'userdata'...
OKAY [  0.204s]
formatting 'userdata' partition...
Erase successful, but not automatically formatting.
Can't determine partition type.
OKAY [  0.001s]
erasing 'cache'...
OKAY [  2.009s]
formatting 'cache' partition...
Erase successful, but not automatically formatting.
Can't determine partition type.
OKAY [  0.001s]
rebooting...



Monday, September 24, 2012

Android busybox install



$ wget http://www.busybox.net/downloads/binaries/latest/busybox-armv6l
--2012-09-24 14:02:42--  http://www.busybox.net/downloads/binaries/latest/busybox-armv6l
Resolving www.busybox.net (www.busybox.net)... 140.211.167.224
Connecting to www.busybox.net (www.busybox.net)|140.211.167.224|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1085140 (1.0M) [text/plain]
Saving to: `busybox-armv6l'

100%[=========================================================================================================================>] 1,085,140    447K/s   in 2.4s  

2012-09-24 14:02:46 (447 KB/s) - `busybox-armv6l' saved [1085140/1085140]


$ adb push busybox-armv6l /data/local/busybox
7761 KB/s (1085140 bytes in 0.136s)
$ adb shell
$ su
cd # cd /data/local/
# chmod 755 busybox
# ./busybox
BusyBox v1.19.0 (2011-08-14 23:46:58 CDT) multi-call binary.
Copyright (C) 1998-2011 Erik Andersen, Rob Landley, Denys Vlasenko
and others. Licensed under GPLv2.
See source distribution for full notice.

Usage: busybox [function] [arguments]...
   or: busybox --list[-full]
   or: function [arguments]...

BusyBox is a multi-call binary that combines many common Unix
utilities into a single executable.  Most people will create a
link to busybox for each function they wish to use and BusyBox
will act like whatever it was invoked as.

Currently defined functions:
[, [[, acpid, add-shell, addgroup, adduser, adjtimex, arp, arping, ash,
awk, base64, basename, beep, blkid, blockdev, bootchartd, brctl,
bunzip2, bzcat, bzip2, cal, cat, catv, chat, chattr, chgrp, chmod,
chown, chpasswd, chpst, chroot, chrt, chvt, cksum, clear, cmp, comm,
cp, cpio, crond, crontab, cryptpw, cttyhack, cut, date, dc, dd,
deallocvt, delgroup, deluser, depmod, devmem, df, dhcprelay, diff,
dirname, dmesg, dnsd, dnsdomainname, dos2unix, du, dumpkmap,
dumpleases, echo, ed, egrep, eject, env, envdir, envuidgid, ether-wake,
expand, expr, fakeidentd, false, fbset, fbsplash, fdflush, fdformat,
fdisk, fgconsole, fgrep, find, findfs, flock, fold, free, freeramdisk,
fsck, fsck.minix, fsync, ftpd, ftpget, ftpput, fuser, getopt, getty,
grep, groups, gunzip, gzip, halt, hd, hdparm, head, hexdump, hostid,
hostname, httpd, hush, hwclock, id, ifconfig, ifdown, ifenslave,
ifplugd, ifup, inetd, init, insmod, install, ionice, iostat, ip,
ipaddr, ipcalc, ipcrm, ipcs, iplink, iproute, iprule, iptunnel,
kbd_mode, kill, killall, killall5, klogd, last, less, linux32, linux64,
linuxrc, ln, loadfont, loadkmap, logger, login, logname, logread,
losetup, lpd, lpq, lpr, ls, lsattr, lsmod, lspci, lsusb, lzcat, lzma,
lzop, lzopcat, makedevs, makemime, man, md5sum, mdev, mesg, microcom,
mkdir, mkdosfs, mke2fs, mkfifo, mkfs.ext2, mkfs.minix, mkfs.vfat,
mknod, mkpasswd, mkswap, mktemp, modinfo, modprobe, more, mount,
mountpoint, mpstat, mt, mv, nameif, nbd-client, nc, netstat, nice,
nmeter, nohup, nslookup, ntpd, od, openvt, passwd, patch, pgrep, pidof,
ping, ping6, pipe_progress, pivot_root, pkill, pmap, popmaildir,
poweroff, powertop, printenv, printf, ps, pscan, pstree, pwd, pwdx,
raidautorun, rdate, rdev, readahead, readlink, readprofile, realpath,
reboot, reformime, remove-shell, renice, reset, resize, rev, rm, rmdir,
rmmod, route, rpm, rpm2cpio, rtcwake, run-parts, runlevel, runsv,
runsvdir, rx, script, scriptreplay, sed, sendmail, seq, setarch,
setconsole, setfont, setkeycodes, setlogcons, setserial, setsid,
setuidgid, sh, sha1sum, sha256sum, sha512sum, showkey, slattach, sleep,
smemcap, softlimit, sort, split, start-stop-daemon, stat, strings,
stty, su, sulogin, sum, sv, svlogd, swapoff, swapon, switch_root, sync,
sysctl, syslogd, tac, tail, tar, tcpsvd, tee, telnet, telnetd, test,
tftp, tftpd, time, timeout, top, touch, tr, traceroute, traceroute6,
true, tty, ttysize, tunctl, ubiattach, ubidetach, ubimkvol, ubirmvol,
ubirsvol, ubiupdatevol, udhcpc, udhcpd, udpsvd, umount, uname,
unexpand, uniq, unix2dos, unlzma, unlzop, unxz, unzip, uptime, users,
usleep, uudecode, uuencode, vconfig, vi, vlock, volname, wall, watch,
watchdog, wc, wget, which, who, whoami, whois, xargs, xz, xzcat, yes,
zcat, zcip

# mount -o remount,rw -t yaffs2 /dev/block/mtdblock4 /system
# mkdir /system/xbin
mkdir failed for /system/xbin, File exists
# /data/local/busybox cp /data/local/busybox /system/xbin
# /data/local/busybox cp /data/local/busybox /system/bin
# cd /system/xbin
# busybox --install .
# mount -o ro,remount -t yaffs2 /dev/block/mtdblock4 /system
# sync
# reboot

Downgrade Nexus S from 4.0 to 2.3

Android 4.1 might too heavy for Nexus S hardware, below is howto downgrade the rom to ver 2.3.

Please note that all data on the phone will erase....

1. Download the image from google site.

2. Extract the file....

$cd /tmp/

$ tar -zxvf soju-grk39f-factory-5ab09c98.tgz
soju-grk39f/
soju-grk39f/bootloader-crespo-i9020xxka3.img
soju-grk39f/flash-base.sh
soju-grk39f/image-soju-grk39f.zip
soju-grk39f/radio-crespo-i9020xxkf1.img
soju-grk39f/flash-all.sh

3. Switch off  the phone, holding the vol up & power button at the same time until you see the bootloader screen.

4. Assume you have android-sdk installed, if not please refer to http://developer.android.com/sdk/installing/index.html for installation.

$cd soju-grk39f

$ ./flash-all.sh 
sending 'bootloader' (1536 KB)...
OKAY [  0.226s]
writing 'bootloader'...
OKAY [  0.344s]
finished. total time: 0.570s
rebooting into bootloader...
OKAY [  0.001s]
finished. total time: 0.001s
sending 'radio' (12288 KB)...
OKAY [  1.803s]
writing 'radio'...
OKAY [  1.680s]
finished. total time: 3.483s
rebooting into bootloader...
OKAY [  0.001s]
finished. total time: 0.001s
archive does not contain 'boot.sig'
archive does not contain 'recovery.sig'
archive does not contain 'system.sig'
--------------------------------------------
Bootloader Version...: I9020XXKA3
Baseband Version.....: I9020XXKF1
Serial Number........: 363003C175D100EC
--------------------------------------------
checking product...
OKAY [  0.001s]
checking version-bootloader...
OKAY [  0.001s]
checking version-baseband...
OKAY [  0.001s]
sending 'boot' (2936 KB)...
OKAY [  0.417s]
writing 'boot'...
OKAY [  0.383s]
sending 'recovery' (3176 KB)...
OKAY [  0.459s]
writing 'recovery'...
OKAY [  0.411s]
sending 'system' (188235 KB)...
OKAY [ 27.062s]
writing 'system'...
OKAY [ 23.307s]
erasing 'userdata'...
OKAY [  0.203s]
formatting 'userdata' partition...
Erase successful, but not automatically formatting.
Can't determine partition type.
OKAY [  0.001s]
erasing 'cache'...
OKAY [  2.017s]
formatting 'cache' partition...
Erase successful, but not automatically formatting.
Can't determine partition type.
OKAY [  0.001s]
rebooting...

finished. total time: 54.268s



DONE....

Saturday, September 22, 2012

Root Nexus S

1. Switch off the phone.

2. Holding the POWER & VOL UP button until you see the bootloader screen.

3. Install USB driver, follow the instruction on 'Installing SDK'.

4. Download files

$ wget http://www.androidmi.com/uploadfile/2010/1217/20101217063436958.zip
$ wget http://www.androidmi.com/uploadfile/2010/1217/20101217063339991.rar
$ wget http://www.androidmi.com/uploadfile/2010/1217/20101217063614166.rar

5. Unzip all downloaded files.


drwxrwxr-x  5 user user    4096 Sep 22 17:13 ./
drwxrwxrwt 22 root root    4096 Sep 22 16:59 ../
drwxrwxr-x  2 user user    4096 Sep 22 17:05 app/
drwxrwxr-x  2 user user    4096 Sep 22 17:05 bin/
drwxrwxr-x  3 user user    4096 Sep 22 17:05 META-INF/
-rw-rw-r--  1 user user 4087808 Sep 22 16:39 recovery-clockwork-herring.img
-rw-rw-r--  1 user user 2949120 Dec 17  2010 rootboot.img


6. $ fastboot flash recovery recovery-clockwork-herring.img
sending 'recovery' (3992 KB)...
OKAY [  0.590s]
writing 'recovery'...
OKAY [  0.507s]
finished. total time: 1.098s


7. Flash the rooted boot image.
$ fastboot flash boot rootboot.img 
sending 'boot' (2880 KB)...
OKAY [  0.426s]
writing 'boot'...
OKAY [  0.377s]
finished. total time: 0.802s

8. Install su & SuperUser.apk

$ adb remount
remount succeeded
$ adb push bin/su /system/bin/
638 KB/s (26248 bytes in 0.040s)
$ adb push app/Superuser.apk /system/app/
678 KB/s (27688 bytes in 0.039s)
$ adb shell chmod 6755 /system/bin/su
$ adb reboot

9. Enter recovery mode again,install the superroot.apk




Update for TWRP recovery 



Follow step 1~3 above.

4. $fastboot flash recovery twrp-crespo-2.0.0RC0.img

5. Reboot to recovery boot

6. Mount sdcard, copy SuperUser.zip and unmount.

7. Back to main menu, INSTALL > select SuperUser.zip and install, after install reboot the phone.








Tuesday, September 4, 2012

Android NDK assert.h problems

Usually program will crash due to SIGSEGV signal after assert() is called, by default NDEBUG is define, you may turn off by add the flag (LOCAL_CFLAGS += -UNDEBUG) during compilation but not work for my case.

I found another solution is using __android_log_assert, simply define as below & replace assert() with assert3.

#define assert3(e) ((e) ? (void)0 : __android_log_assert(0,TAGS,"%s(%s:%d) >> %s ",__func__ ,__FILE__, __LINE__, #e))

Thursday, August 23, 2012

install and run an app on multiple devices with a single click under eclipse


If you using eclipse, just do below:
  1. open 'project properties' dialog.
  2. under 'Run/Debug settings', select your project and edit.
  3. another dialog should pop up, select 'target' tab, select 'Launch on all compatible devics/AVD's '.
  4. Apply and you should get all of devices install when Run/Debug.

Sunday, August 12, 2012

Speex AEC with Android

Below is a piece of working code to demo Speex AEC with using OpenSL ES.


#include <assert.h>
#include <jni.h>
#include <string.h>
#include <pthread.h>

// for native audio
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>

// for native asset manager
#include <sys/types.h>
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
#include <android/log.h>

#include <speex/speex_echo.h>
#include <speex/speex_preprocess.h>
#include <speex/speex_jitter.h>

#include "ndk_Audio.h"

static const char hello[] =
#include "hello_clip.h"
;

#define LOGINFO(x...) __android_log_print(ANDROID_LOG_INFO,"NativeAudio",x)



// engine interfaces
static SLObjectItf engineObject = NULL;
static SLEngineItf engineEngine;

// output mix interfaces
static SLObjectItf outputMixObject = NULL;

// buffer queue player interfaces
static SLObjectItf bqPlayerObject = NULL;
static SLPlayItf bqPlayerPlay;
static SLAndroidSimpleBufferQueueItf playerBufferQueue;
static SLEffectSendItf bqPlayerEffectSend;
static SLMuteSoloItf bqPlayerMuteSolo;
static SLVolumeItf bqPlayerVolume;



// recorder interfaces
static SLObjectItf recorderObject = NULL;
static SLRecordItf recorderRecord;
static SLAndroidSimpleBufferQueueItf recorderBufferQueue;


// 5 seconds of recorded audio at 16 kHz mono, 16-bit signed little endian
//#define RECORDER_FRAMES (16000 * 5)
//static short recorderBuffer[RECORDER_FRAMES];
static unsigned recorderSize = 0;
static SLmilliHertz recorderSR;

// pointer and size of the next player buffer to enqueue, and number of remaining buffers
static short *nextBuffer;
static unsigned nextSize;
static int nextCount;

///loopback
static short doLoopback = 0;
static SLuint32 rxBufCount = 2;
static SLuint32 txBufCount = 2;
static SLuint32 bufSizeInFrames = 320;
static SLuint32 channels = 1;
static SLuint32 sampleRate = 8000;
static SLuint32 freeBufCount = 0;
static SLuint32 bufSizeInBytes = 0;

static char **rxBuffers;
static char **txBuffers;
static char **freeBuffers;

// Buffer indices
static SLuint32 rxFront;    // oldest recording
static SLuint32 rxRear;     // next to be recorded
static SLuint32 txFront;    // oldest playing
static SLuint32 txRear;     // next to be played
static SLuint32 freeFront;  // oldest free
static SLuint32 freeRear;   // next to be freed


static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

//end

//speex
int useSpeex=0;
int filter_len;
SpeexEchoState *echo_state;
SpeexPreprocessState * preprocess_state;
static char **aecBuffers;
static int aecFront;
static int aecRear;
static int aecBufCount = 4;

void printIndices() {
LOGINFO("rxFront : %d, rxRear : %d, txFront : %d, txRear : %d, freeFront : %d, freeRear : %d",
rxFront, rxRear, txFront, txRear, freeFront, freeRear);
}


void initSpeex() {

LOGINFO("initSpeex()");
filter_len = 5 * bufSizeInFrames;
echo_state = speex_echo_state_init(bufSizeInFrames, filter_len);
preprocess_state = speex_preprocess_state_init(bufSizeInFrames, sampleRate);
speex_preprocess_ctl(preprocess_state, SPEEX_PREPROCESS_SET_ECHO_STATE, echo_state);
speex_echo_ctl(echo_state, SPEEX_ECHO_SET_SAMPLING_RATE, &sampleRate);

int sizeInBytes = channels * bufSizeInFrames * sizeof(short);

// Initialize buffers
aecBuffers = (char **) calloc(aecBufCount+1, sizeof(char *));
unsigned j;
for (j = 0; j < aecBufCount; ++j) {
aecBuffers[j] = (char *) malloc(sizeInBytes);
}
}


void speexClean() {

if(NULL != echo_state) speex_echo_state_destroy(echo_state);
if(NULL != preprocess_state)speex_preprocess_state_destroy(preprocess_state);

}


// this callback handler is called every time a buffer finishes playing
void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
{
LOGINFO("bqPlayerCallback");
    assert(bq == playerBufferQueue);
    assert(NULL == context);

    SLresult result;

    if(doLoopback) {
    pthread_mutex_lock(&mutex);
    printIndices();
// Get the buffer that just finished playing
assert(txFront <= txBufCount);
assert(txRear <= txBufCount);
assert(txFront != txRear);
char *buffer = txBuffers[txFront];
if (++txFront > txBufCount) {
txFront = 0;
}
printIndices();


// First try to enqueue the free buffer for recording
result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, buffer, bufSizeInBytes);


if (SL_RESULT_SUCCESS == result) {

// There was room in the record queue, update our model of it
assert(rxFront <= rxBufCount);
assert(rxRear <= rxBufCount);
SLuint32 rxRearNext = rxRear+1;
if (rxRearNext > rxBufCount) {
rxRearNext = 0;
}
assert(rxRearNext != rxFront);
rxBuffers[rxRear] = buffer;
rxRear = rxRearNext;
} else {

// Here if record queue is full
assert(SL_RESULT_BUFFER_INSUFFICIENT == result);

// Instead enqueue the free buffer on the free queue
assert(freeFront <= freeBufCount);
assert(freeRear <= freeBufCount);
SLuint32 freeRearNext = freeRear+1;
if (freeRearNext > freeBufCount) {
freeRearNext = 0;
}
// There must always be room in the free queue
assert(freeRearNext != freeFront);
freeBuffers[freeRear] = buffer;
freeRear = freeRearNext;
}
printIndices();

pthread_mutex_unlock(&mutex);
    } else {
    // for streaming playback, replace this test by logic to find and fill the next buffer
if (--nextCount > 0 && NULL != nextBuffer && 0 != nextSize) {
SLresult result;
// enqueue another buffer
result = (*playerBufferQueue)->Enqueue(playerBufferQueue, nextBuffer, nextSize);
// the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,
// which for this code example would indicate a programming error
assert(SL_RESULT_SUCCESS == result);
}
    }

}


// this callback handler is called every time a buffer finishes recording
void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
{
LOGINFO("bqRecorderCallback");

    assert(bq == recorderBufferQueue);
    assert(NULL == context);

    SLresult result;

if(doLoopback) {

pthread_mutex_lock(&mutex);
printIndices();
// We should only be called when a recording buffer is done
assert(rxFront <= rxBufCount);
assert(rxRear <= rxBufCount);
assert(rxFront != rxRear);
char *buffer = rxBuffers[rxFront];

// Remove buffer from record queue
if (++rxFront > rxBufCount) {
rxFront = 0;
}
printIndices();

if(useSpeex){
spx_int16_t *rec = buffer;
speex_echo_capture(echo_state, rec, buffer);
}


// Enqueue the just-filled buffer for the player
result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, bufSizeInBytes);

if(useSpeex){
speex_echo_playback(echo_state, buffer);
}


if (SL_RESULT_SUCCESS == result) {

// There was room in the play queue, update our model of it
assert(txFront <= txBufCount);
assert(txRear <= txBufCount);
SLuint32 txRearNext = txRear+1;
if (txRearNext > txBufCount) {
txRearNext = 0;
}
assert(txRearNext != txFront);
txBuffers[txRear] = buffer;
txRear = txRearNext;
} else {

// Here if record has a filled buffer to play, but play queue is full.
assert(SL_RESULT_BUFFER_INSUFFICIENT == result);
write(1, "?", 1);

// We could either try again later, or discard. For now we discard and re-use buffer.
// Enqueue this same buffer for the recorder to fill again.
result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, buffer, bufSizeInBytes);
assert(SL_RESULT_SUCCESS == result);

// Update our model of the record queue
SLuint32 rxRearNext = rxRear+1;
if (rxRearNext > rxBufCount) {
rxRearNext = 0;
}
assert(rxRearNext != rxFront);
rxBuffers[rxRear] = buffer;
rxRear = rxRearNext;
}
printIndices();

pthread_mutex_unlock(&mutex);
} else {

}

}

void createEngine(){
SLresult result;

// create engine
result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
assert(SL_RESULT_SUCCESS == result);
LOGINFO("createEngine::slCreateEngine : %d", result);

// realize the engine
result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
assert(SL_RESULT_SUCCESS == result);
LOGINFO("createEngine::Realize : %d", result);

// get the engine interface, which is needed in order to create other objects
result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
assert(SL_RESULT_SUCCESS == result);
LOGINFO("createEngine::GetInterface-SL_IID_ENGINE : %d", result);
}


void createOutputMix(){
SLresult result;

// create output mix
/*const SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB};
const SLboolean req[1] = {SL_BOOLEAN_FALSE};*/
result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL);
assert(SL_RESULT_SUCCESS == result);
LOGINFO("createEngine::CreateOutputMix : %d", result);

// realize the output mix
result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
assert(SL_RESULT_SUCCESS == result);
LOGINFO("createEngine::Realize : %d", result);
}


void createPlayer() {
    SLresult result;

    // configure audio source
    SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, rxBufCount};
    SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, channels, SL_SAMPLINGRATE_8,
        SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,
        (channels == 1 ? SL_SPEAKER_FRONT_CENTER :
                (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT))
        , SL_BYTEORDER_LITTLEENDIAN};
    SLDataSource audioSrc = {&loc_bufq, &format_pcm};

    // configure audio sink
    SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
    SLDataSink audioSnk = {&loc_outmix, NULL};

    // create audio player
    const SLInterfaceID ids[3] = {SL_IID_BUFFERQUEUE, SL_IID_EFFECTSEND,
            /*SL_IID_MUTESOLO,*/ SL_IID_VOLUME};
    const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE,
            /*SL_BOOLEAN_TRUE,*/ SL_BOOLEAN_TRUE};
    result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk,
            3, ids, req);

    LOGINFO("createBufferQueueAudioPlayer::CreateAudioPlayer : %d", result);

    assert(SL_RESULT_SUCCESS == result);

    // realize the player
    result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
    assert(SL_RESULT_SUCCESS == result);
    LOGINFO("createBufferQueueAudioPlayer::Realize : %d", result);

    // get the play interface
    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
    assert(SL_RESULT_SUCCESS == result);
    LOGINFO("createBufferQueueAudioPlayer::GetInterface-SL_IID_PLAY : %d", result);

    // get the buffer queue interface
    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,
            &playerBufferQueue);
    assert(SL_RESULT_SUCCESS == result);
    LOGINFO("createBufferQueueAudioPlayer::GetInterface-SL_IID_BUFFERQUEUE : %d", result);

    // register callback on the buffer queue
    result = (*playerBufferQueue)->RegisterCallback(playerBufferQueue, bqPlayerCallback, NULL);
    assert(SL_RESULT_SUCCESS == result);

    LOGINFO("createBufferQueueAudioPlayer::RegisterCallback : %d", result);

    // get the effect send interface
    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_EFFECTSEND,
            &bqPlayerEffectSend);
    assert(SL_RESULT_SUCCESS == result);
    LOGINFO("createBufferQueueAudioPlayer::GetInterface-SL_IID_EFFECTSEND : %d", result);

#if 0   // mute/solo is not supported for sources that are known to be mono, as this is
    // get the mute/solo interface
    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_MUTESOLO, &bqPlayerMuteSolo);
    assert(SL_RESULT_SUCCESS == result);
    LOGINFO("createBufferQueueAudioPlayer::GetInterface-SL_IID_MUTESOLO : %d", result);
#endif

    // get the volume interface
    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);
    assert(SL_RESULT_SUCCESS == result);
    LOGINFO("createBufferQueueAudioPlayer::GetInterface-SL_IID_VOLUME : %d", result);

    if(!doLoopback) {
    // set the player's state to playing
result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
assert(SL_RESULT_SUCCESS == result);
LOGINFO("createBufferQueueAudioPlayer::SetPlayState-SL_PLAYSTATE_PLAYING : %d", result);

    }


}


short createRecorder() {

SLresult result;

// configure audio source
SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, SL_DEFAULTDEVICEID_AUDIOINPUT, NULL};
SLDataSource audioSrc = {&loc_dev, NULL};

// configure audio sink
SLDataLocator_AndroidSimpleBufferQueue loc_bq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, txBufCount};
/*SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, channels, SL_SAMPLINGRATE_16, SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,
SL_SPEAKER_FRONT_CENTER, SL_BYTEORDER_LITTLEENDIAN};*/
SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, channels, SL_SAMPLINGRATE_8,
       SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,
       (channels == 1 ? SL_SPEAKER_FRONT_CENTER :
               (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT))
       , SL_BYTEORDER_LITTLEENDIAN};
SLDataSink audioSnk = {&loc_bq, &format_pcm};

// create audio recorder
// (requires the RECORD_AUDIO permission)
const SLInterfaceID id[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
const SLboolean req[1] = {SL_BOOLEAN_TRUE};
result = (*engineEngine)->CreateAudioRecorder(engineEngine, &recorderObject, &audioSrc,
&audioSnk, 1, id, req);
LOGINFO("createAudioRecorder::CreateAudioRecorder : %d", result);

if (SL_RESULT_SUCCESS != result) {
return 0;
}

// realize the audio recorder
result = (*recorderObject)->Realize(recorderObject, SL_BOOLEAN_FALSE);
if (SL_RESULT_SUCCESS != result) {
return 0;
}

LOGINFO("createAudioRecorder::CreateAudioRecorder : %d", result);



    // get the record interface
    result = (*recorderObject)->GetInterface(recorderObject, SL_IID_RECORD, &recorderRecord);
    assert(SL_RESULT_SUCCESS == result);
    LOGINFO("createAudioRecorder::GetInterface-SL_IID_RECORD : %d", result);

    // get the buffer queue interface
    result = (*recorderObject)->GetInterface(recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
            &recorderBufferQueue);
    assert(SL_RESULT_SUCCESS == result);
    LOGINFO("createAudioRecorder::GetInterface-SL_IID_ANDROIDSIMPLEBUFFERQUEUE : %d", result);

    // register callback on the buffer queue
    result = (*recorderBufferQueue)->RegisterCallback(recorderBufferQueue, bqRecorderCallback,
            NULL);
    assert(SL_RESULT_SUCCESS == result);
    LOGINFO("createAudioRecorder::RegisterCallback : %d", result);

    // Enqueue some empty buffers for the recorder
    if( doLoopback == 1) {
    unsigned j;
for (j = 0; j < rxBufCount; ++j) {

// allocate a free buffer
assert(freeFront != freeRear);
char *buffer = freeBuffers[freeFront];
if (++freeFront > freeBufCount) {
freeFront = 0;
}

// put on record queue
SLuint32 rxRearNext = rxRear + 1;
if (rxRearNext > rxBufCount) {
rxRearNext = 0;
}
assert(rxRearNext != rxFront);
rxBuffers[rxRear] = buffer;
rxRear = rxRearNext;
result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue,
buffer, bufSizeInBytes);
assert(SL_RESULT_SUCCESS == result);
}
    }

    if(!doLoopback) {
    // Kick off the recorder
result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_RECORDING);
assert(SL_RESULT_SUCCESS == result);
    }


    return 1;

}


void startPlayNRecord() {
SLresult result;
result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_RECORDING);
assert(SL_RESULT_SUCCESS == result);
result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
assert(SL_RESULT_SUCCESS == result);
}



void Java_ndk_Audio_createEngine
  (JNIEnv* env, jclass clazz)
{
    createEngine();

    createOutputMix();

    initSpeex();

}





void Java_ndk_Audio_createBufferQueueAudioPlayer
  (JNIEnv* env, jclass clazz){

createPlayer();

}


jboolean Java_ndk_Audio_createAudioRecorder (JNIEnv* env, jclass clazz)
{
return (createRecorder() == 0) ? JNI_TRUE : JNI_FALSE;
}


void Java_ndk_Audio_startRecording(JNIEnv* env, jclass clazz)
{/*
    SLresult result;

    // in case already recording, stop recording and clear buffer queue
    result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_STOPPED);
    assert(SL_RESULT_SUCCESS == result);
    result = (*recorderBufferQueue)->Clear(recorderBufferQueue);
    assert(SL_RESULT_SUCCESS == result);

    // the buffer is not valid for playback yet
    recorderSize = 0;

    // enqueue an empty buffer to be filled by the recorder
    // (for streaming recording, we would enqueue at least 2 empty buffers to start things off)
    result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, recorderBuffer,
            RECORDER_FRAMES * sizeof(short));
    // the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,
    // which for this code example would indicate a programming error
    assert(SL_RESULT_SUCCESS == result);

    // start recording
    result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_RECORDING);
    assert(SL_RESULT_SUCCESS == result);

*/}


void Java_ndk_Audio_startPlaying (JNIEnv* env, jclass clazz) {/*
if (recorderSR == SL_SAMPLINGRATE_16) {
unsigned i;
for (i = 0; i < recorderSize; i += 2 * sizeof(short)) {
recorderBuffer[i >> 2] = recorderBuffer[i >> 1];
}
recorderSR = SL_SAMPLINGRATE_8;
recorderSize >>= 1;
}
nextBuffer = recorderBuffer;
nextSize = recorderSize;

nextCount = 2;
if (nextSize > 0) {
// here we only enqueue one buffer because it is a long clip,
// but for streaming playback we would typically enqueue at least 2 buffers to start
SLresult result;
result = (*playerBufferQueue)->Enqueue(playerBufferQueue, nextBuffer, nextSize);
if (SL_RESULT_SUCCESS != result) {
}
}
*/}


void lpPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
{
LOGINFO("lpPlayerCallback");
    assert(bq == playerBufferQueue);
    assert(NULL == context);

}


// this callback handler is called every time a buffer finishes recording
void lpRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
{
LOGINFO("lpRecorderCallback");

    assert(bq == recorderBufferQueue);
    assert(NULL == context);

}


void Java_ndk_Audio_startLoopback (JNIEnv* env, jclass clazz)
{

if(useSpeex) initSpeex();

doLoopback=1;

freeBufCount = rxBufCount + txBufCount;
bufSizeInBytes = channels * bufSizeInFrames * sizeof(short);

// Initialize free buffers
freeBuffers = (char **) calloc(freeBufCount+1, sizeof(char *));
unsigned j;
for (j = 0; j < freeBufCount; ++j) {
freeBuffers[j] = (char *) malloc(bufSizeInBytes);
}
freeFront = 0;
freeRear = freeBufCount;
freeBuffers[j] = NULL;

// Initialize record queue
rxBuffers = (char **) calloc(rxBufCount+1, sizeof(char *));
rxFront = 0;
rxRear = 0;

// Initialize play queue
txBuffers = (char **) calloc(txBufCount+1, sizeof(char *));
txFront = 0;
txRear = 0;

printIndices();

SLresult result;

createEngine();

createOutputMix();

createPlayer();

createRecorder();

startPlayNRecord();

do {
usleep(1000);
write(1, ".", 1);
SLBufferQueueState playerBQState;
result = (*playerBufferQueue)->GetState(playerBufferQueue, &playerBQState);
assert(SL_RESULT_SUCCESS == result);
SLAndroidSimpleBufferQueueState recorderBQState;
result = (*recorderBufferQueue)->GetState(recorderBufferQueue, &recorderBQState);
assert(SL_RESULT_SUCCESS == result);
} while (doLoopback == 1);

speexClean();
}

void Java_ndk_Audio_stopLoopback (JNIEnv* env, jclass clazz)
{
doLoopback = 0;
}


void Java_ndk_Audio_clean(JNIEnv* env, jclass clazz) {
if (NULL != bqPlayerObject) {
(*bqPlayerObject)->Destroy(bqPlayerObject);
}
if (NULL != recorderObject) {
(*recorderObject)->Destroy(recorderObject);
}
(*outputMixObject)->Destroy(outputMixObject);
(*engineObject)->Destroy(engineObject);

}


void Java_ndk_Audio_useSpeex (JNIEnv* env, jclass clazz, jint use) {

useSpeex = use;

}


Leave your comment if you have any questions regarding code above.