Monday, November 30, 2009

video player demo in android

In this post, I'll show some basic operations in android with a simple video player. The demo shows how to:

Use explicit intent
List video files with ListView, ContentProvider & MediaProvider
Retrieve data from another Activity with startActivityForResult
Play video file with VideoView

Basically, the demo is composed of two activities. The first activity (Main) is a video player with a button on it. When you click the button, the second activity(VideoSelector) shows and lists video files available on the device. Then, after you pick a video from the list, you return to Main activiry and it starts playing the video you selected.

1. Use explicit intent
On android, an intent can be implicit or explicit. An explicit intent clearly designates the component to start. Because explicit intent uses the name of target component, it's usually used inside an application. On contrast, implicit intent specifies desired action, and let the system to pick the best match component.
In our demo, we want to use the VideoSelector to select a video file, rather than the system built-in media selector, so we use explicit intent to start activity. To create explicit intent, we just need to pass the designated component class name to intent, as shown below.

Intent i = new Intent();
i.setClass(v.getContext(), VideoSelector.class);
startActivityForResult(i, 0);

The use of startActivityForResult will be explained later.

2. List video files
Android provides a ListActivity class to list data provided by a ContentProvider. We can take advantage of it to list video files available on current device rather than start from scratch. To use it, we simply make it the base class for our activity, meanwhile, add a ListView with id "@android:id/list" in the activity's layout. And the final thing we need to do is set the datasource for the list with setListAdapter method.
Android also provides a MediaProvider that can list all video files. It's the default provider when we use ContentResolver to query MediaStore.Video.Media.EXTERNAL_CONTENT_URI.

3. Get data from another activity & play video
After we select a video from the list, information of the video such as its path should be passed to the main activity for playing. The recommended way is passing it via intent object. Previously, we start the VideoSelector with startActivityForResult in Main. Being started this way, when the VideoSelector is finished, the onActivityResult method of Main will be fired. So, we need to store the selected video's path in the intent to be passed to Main. Then retrieve it in Main. As shown below:

@Override
protected void onListItemClick(ListView l, View v, int position, long id)
{ // in VideoSelector.java
String filePath = mCursor.getString(mCursor.getColumnIndex(MediaStore.Video.Media.DATA));
mCursor.moveToPosition(position);
Intent result = new Intent();
result.putExtra(FILE_PATH, filePath);
setResult(RESULT_OK, result);
finish();
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// in Main.java
super.onActivityResult(requestCode, resultCode, data);
if (RESULT_OK == resultCode) {
Bundle bd = data.getExtras();
String path = bd.getString(VideoSelector.FILE_PATH);
m_vvPlayer.setVideoPath(path);
m_vvPlayer.start();
}
}

To download full source code for this demo, you can download them from this page:
http://code.google.com/p/rxwen-blog-stuff/source/browse/#svn/trunk/android/mplayer
or with following svn command:
svn co https://rxwen-blog-stuff.googlecode.com/svn/trunk/android/mplayer

Thursday, November 26, 2009

adb for remote connections

The adb tool in android sdk is convenient utility for debugging and control android emulators. One of its powerful features is it can forward a tcp port on local machine to an emulator running on the same machine.
After you run the adb forward tcp:hostport tcp:emuport command, your android running in emulator can listen on emuport and communicate with external applications running on host machine. From the external application's point of view, it's connecting to hostport rather than emuport. The adb is responsible for forwarding messages between the two.
But adb has a limitation of only accepting connections from the same machine, you can't connect from a machine that adb isn't running on. This limitation makes it a little bit inconvenient to do network programming. Especially on windows, if you want to use wireshark to capture the packages between emulator and external app. By default, wireshark isn't able to capture loopback packages on windows. So, we change the behavior of adb to accept remote connections.
(Another way to overcome this is instead of capturing network package on host side, we can use tcpdump on emulator side. For example, use "/data/tcpdump -s 1500 -vv -w /data/net.pcap udp port 5060" to capture all packages for udp port 5060 and save them in /data/net.pcap file. The -s parameter specifies the size of each packet whose default value is 68, too small to get some useful information truncated. The /data/net.pcap file can also be examined with wireshark.)

How to modify adb behavior
If we run netstat command on host side, we can find out that adb server process binds to the loopback address. So it can't be accessed via external address.
The adb register a port forwarding information through install_listener function. And install_listener calls local_name_to_fd function to bind to a local address. Inside local_name_to_fd, it starts a tcp server through socket_loopback_server. To change this, we can use socket_inaddr_any_server which binds to all ipaddresses. In this way, the adb server can forward a request from remote machine to emulator.

How to compile
In order to get the modified adb, we need to compile it. To do so, we first need to download all of anroid's source code. Then, at the root of andoird source directory, run ./build/envsetup.sh. Finally, run make adb.

Downloads
http://rxwen-blog-stuff.googlecode.com/files/tcpdump.zip
http://rxwen-blog-stuff.googlecode.com/files/adb-linux.zip
http://rxwen-blog-stuff.googlecode.com/files/adb-windows.zip

Reference
howto build SDK

Update:
Modified adb v1.0.31 can be downloaded at: https://drive.google.com/#folders/0B9fylkYUFfYTTGJKN0tURzJFelE

An basic introduction to SIP

What is SIP
SIP Protocol is one of widely used signaling protocol, with the main purpose of, as its name is abbreviated for, initialization session between several participants. Due to its nature, it's mainly used in VOIP, IM applications.

Basics of SIP
Because SIP is always mentioned together with other multimedia application protocols such as SDP, RTP. They are so mixed up that easily confuse beginners, like me. To make things clear, it's necessary to know SIP has nothing to do with those protocols. It can be used independently with SDP and RTP. SIP is just being lucky to be employed to work with them in many situations.
In short, their relationship is:
SDP describes the capabilities and preferences of a participant. Usually, it's included in the payload of SIP message.
SIP is the message flow that enable two or more participants to negotiate, setup, modify and terminate a session.
RTP is the protocol for transferring audio or video data after the session has been established, it usually relies on the information contains in SDP.

SIP is a text based protocol with request/response transaction model, similar to HTTP. Unlike HTTP, whose request and response always comes in pairs, SIP's request and response doesn't hold a one on one relationship. A SIP transaction may have multiple request and multiple response.
The format of SIP message is similar to HTTP's too. A message is composed of a start-line(includes method, request-uri and sip-version), several headers and a message body.
Like SMTP, the recipient of a message doesn't have to be directly accessible to the sender. A message may hop several times before it reaches the destination with the help of Proxy Server.

To better understand SIP protocol, the document SIP Protocol Structure through an Example provides a thorough illustration and it's good material for getting start.

SIP Libraries
PJSIP is a powerful sip library implemented in c. Besides SIP, it also support SDP, and has strong multi-media processing capability. It exposes APIs at different layers so that users can pick either a convenient or flexible API set at their will. It's also a highly portable library can run many operating systems, including windows and linux. The best thing is it has complete document which is rare in open source project.
MJSIP is a java based sip library with SDP, RTP supporting. It's also a convenient and complete solution for building VOIP application. But I'd say the library still have room to improve the quality, for there are some apparent spelling mistakes.
OSIP is part of of gnu project, implemented in c. By following the "do one thing, and do it well" philosophy, it solely focus on SIP and is a light weight, fast library.

References:
http://www.ietf.org/rfc/rfc3261.txt
http://en.wikipedia.org/wiki/Session_Description_Protocol
http://en.wikipedia.org/wiki/Real-time_Transport_Protocol

Wednesday, November 18, 2009

how to make presentation

As an IT guy, there are times we need to make technical presentation. How to do it well? I'm no expert in presentation at all, but I'd like to share my two cents through my experience.

Face your audience
It's extremely important to face your audience directly during representation. How boring it is to have a full room of guys watching you talking to a computer. Try to make contact with your audience, and know if they are confusing.

Know your audience
To know the level of your audience helps achieve a good presentation. Knowing them well means we can talk to them at appropriate level, neither too sophisticated nor trivial. And the best bet is to assume they have least experience in related fields if you can't know them well in advance.

Practice
It's never too silly to ask some of your friends to be your first audience and practice. This is your best chance to get the most objective feedback from your audience. Practice and stick to what you practiced during the actual presentation.

Prepare cue cards
Prepare some cue cards about important points of the presentation. They will be of great help when you forget something, and they also help you timing your presentation better.

Make a tape or video of your presentation/practice

Watch a video of your own presentation will be a funny thing to do. It also lets you make a better judgment of your performance and improve accordingly.

Monday, November 16, 2009

process agnostic feature

Being one of the most eye-catching terms today, android has many creative features. The most revolutionary one, in my opinion, is process agnostic. This is not a term used in official document, but I prefer to to use it since it implies this feature well enough.
One of center feature of android is the ability to easily make use of components of other applications. It's a common feature among many other systems, so how "easy" is android to distinguish it from others?
Let's first check out how others do. Generally, there are two common ways to reuse components. First, the component author can distribute the component as a library(e.g. dll, lib, so, a) that can be called by others. In this way, the reused component becomes part of the application that uses it.
android embedded componentThe second way is the shared component runs in a process, and the application wants to use it employs a IPC mechanism to communicate with the hosting process to make use of the component indirectly.
android ipcEither way, we programmers must know explicitly the way we're using. And we have to pay attention to or even control the life cycle of the hosting process.
Now let's look at what's different in android. In android, components reuse and collaboration are driven by Intent. Whenever you want to make use of another component, you need to create a intent object. And state your purpose by setting corresponding properties of the intent object. Then, you pass the intent to the application framework with startActivity, startService etc. Upon receiving an intent, the application framework determines the best component for processing the intent, and asks for the user if there are multiple components can handle the intent. After a component is identified for handling the intent, an instance of the component will run. The instance may resides in the same process or in a different process with the sender of the intent. From a user's perspective, this procedure is transparent. It doesn't make difference if the component is running in another process.
The coolest thing is android also achieves process agnostic feature for end user's experience. If you dismiss current activity, android guarantees you'll return to the previous activity you worked on. Consider the following scenario, application A is showing activity X. Then the user clicks a button on activity X and starts a new activity Y from application B which runs in a different process. If, we say, when the user is still working on activity Y, the process that application A runs in dies for some reason, the user doesn't get affected and can continue with his work until he dismiss activity Y. At this time, the ActityManager notices that activity X doesn't exist, and a new instance will be created and shown. The user will still see activity X as if nothing happened. But it's not guaranteed that activity X's state is maintained correctly unless we write code to persist and restore state at right time.
Needless to say, if components from different process need to talk to each, they still have to employ some kind of IPCs because android builds on linux and uses the same underlying process model. The great thing android does for us is it hides the IPC details from us so that we can use a consistent API with less concern about complicated IPC things.
Another benefit of this design is it'll be much easier to replace a component, even if the component is a system built-in one. For example, if your application declares an intent-filter for View action for contact, it will be considered as a valid replacement for built-in contacts application by the system. Our application isn't just a second-class citizen anymore.
The process agnostic feature ensures the openness of android, it also helps making components more loosely coupled to each other.
Besides what was mentioned, it's also important to notice that the process life cycle is managed by the system automatically. The process may still keep alive after the last activity of it has been dismissed. It's also possible that the process of an inactive activity that you haven't worked for a period of time but not yet closed is terminated by the system on demand for more resources for other processes. We know that .net framework is called a managed environment because it manages components and memories for us, android takes a larger step forward by managing process life cycle as well. In this sense, it's a super managed system.
Generally speaking, in android we mainly focus on the components and how they collaborate to accomplish our goal. Less concern need to be paid on the technology details that we can't easily ignore on other platforms.

Thursday, November 12, 2009

native and java performance on android

A lot of times when I saw someone heard that the main stream developing language on android platform is java, his first response would be "really? what about performance?". I've seen lots of similar responses when talking about c++ and c# on normal pc. Personally, I don't think argue about this question without a context makes any sense.
In most of situations, manged framework like c# and java suffice. How many times in your life do you have to implement a super powerful server that is capable of handling like one billion requests a time? Does the difference in performance really bother you? I don't think so. What play more important roles are: elegance, maintainability, clearness and number of bugs. And in a lot of situations, managed framework run at commensurate speed with c/c++ code. At least their order of growth are at the same level.
Back to the question itself. Is there significant performance difference between native and java code on android? Just see in action. The ensuing two code snippets will calculate the sum from 1 to 10,000 for 10,000 times in c and java respectively.



1 #include
2 #include
3
4 int main ( int argc, char *argv[] )
5 {
6 int i = 0, j = 0;
7 FILE *f = fopen("/data/perf_c.log", "a");
8
9 int rc = 0;
10
11 time_t t;
12 time(&t);
13 fprintf(f, "Start on: %s\n", ctime(&t));
14
15 for(i = 0; i < 10000; ++i)
16 {
17 for(j = 0; j < 10000; ++j)
18 rc += j;
19 rc = 0;
20 }
21
22 time(&t);
23 fprintf(f, "End on: %s\n", ctime(&t));
24 return 0;
25 } // ---------- end of function main ----------




1 package com.rmd;
2
3 import java.io.FileNotFoundException;
4 import java.io.FileOutputStream;
5 import java.io.PrintStream;
6 import java.text.SimpleDateFormat;
7 import java.util.Date;
8
9 import android.app.Activity;
10 import android.content.Context;
11 import android.os.Bundle;
12 import android.util.Log;
13
14 public class main extends Activity {
15 /** Called when the activity is first created. */
16 @Override
17 public void onCreate(Bundle savedInstanceState) {
18 Log.v("perf_test", "before loop");
19 try {
20 FileOutputStream fos = this.openFileOutput(
21 "perf_java.log", Context.MODE_APPEND);
22 int rc = 0, i, j;
23 PrintStream ps = new PrintStream(fos);
24 Date dt = new Date();
25 SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");
26 ps.printf("start on\t" + sdf.format(dt) + "\n");
27 for (i = 0; i < 10000; ++i) {
28 for(j = 0; j < 10000; ++j)
29 rc += j;
30 rc = 0;
31 }
32 dt = new Date();
33 ps.printf("end on\t\t" + sdf.format(dt) + "\n");
34 ps.close();
35 } catch (FileNotFoundException ex) {
36 Log.e("log_perf_test", "can't open file\n" + ex.getMessage());
37 }
38 Log.v("perf_test", "after loop");
39
40 super.onCreate(savedInstanceState);
41 setContentView(R.layout.main);
42 }
43 }




Having run these applications on android 1.5, we got following result:

start on: Wed Nov 11 12:13:51 2009
end on: Wed Nov 11 12:13:59 2009
total: 8 secs

start on 2009/11/11 09:12:30
end on 2009/11/11 09:13:27
total: 57 secs

The java app has been compiled in release mode for better optimization. And GC should not kick in since I only used auto variables in the sample. So I really didn't expect to see such a huge difference.
Though the performance diffs a lot, I still consider java to be the first priority choice when developing user applications. It has very convenient APIs, powerful presentation framework and great debugging support. And we still can turn to native code for extremely performance sensitive components which java can't satisfy. The official document also states that the performance of native method is 10-100X fater than java, and it suggests use native methods for performance optimization.

Wednesday, November 11, 2009

logging in android

Android provides a set of powerful log utilities to make our developing life easier. If you've ever used the OutputDebugString function and the DebugView on windows, you'll find they works very similar to android's counterpart in the sense of user experience. We can start the application normally, then start DDMS at anytime we want to view the application's log message.
How to use the logging system
The android logging system defines a set of APIs to be used in our code. These functions have similar signature but different verbosity level.Only error, warning and info logs are always kept. Verbose and debug are intended for using in development stage only.
To use them, we just need to add a function call to Log API in the place in our code that we have interests with desired message. The first argument tag identifies the caller. It's a good practice to define a constant string for this tag. Use hard coded string within the function call directly makes our code harder to maintain.

Performance concern
The android logging system is so powerful and user friendly that we can easily make excessive use of it in our code. But does it bring any performance penalty to our application? Let's try out this with an experiment. The idea is pretty simple, we'll make a loop of 10,000 iteration and perform logging in each iteration. And we'll record the time before and after the loop in a log file (/data/data/package_name/files/log_perf.log).
The code snippet below does this. It exercises the logging loop each time we click on a button.

package com.rmd;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.Date;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class main extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

Button btn = (Button) this.findViewById(R.id.btnGenerateLog);
btn.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
System.gc();
try {
FileOutputStream fos = v.getContext().openFileOutput("log_perf.log",
Context.MODE_APPEND);
PrintStream ps = new PrintStream(fos);
Date dt = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");
ps.printf("start on\t" + sdf.format(dt) + "\n");
for (int i = 0; i < 10000; ++i) {
Log.v("log_perf_test", "hello raymond");
}
dt = new Date();
ps.printf("end on\t\t" + sdf.format(dt) + "\n");
ps.close();
} catch (FileNotFoundException ex) {
Log.e("log_perf_test", "can't open file\n" + ex.getMessage());
}
}
});
}
}

After we downloaded the apk file to the emulator, we'll run the application five times in different circumstances, with and without DDMS running to see if there is any difference.

-- DDMS turned off --
start on 2009/11/09 09:33:11
end on 2009/11/09 09:33:12
start on 2009/11/09 09:33:17
end on 2009/11/09 09:33:18
start on 2009/11/09 09:33:20
end on 2009/11/09 09:33:21
start on 2009/11/09 09:33:30
end on 2009/11/09 09:33:31
start on 2009/11/09 09:33:33
end on 2009/11/09 09:33:34

-- DDMS truned on --
start on 2009/11/09 09:33:59
end on 2009/11/09 09:34:02
start on 2009/11/09 09:34:05
end on 2009/11/09 09:34:08
start on 2009/11/09 09:34:11
end on 2009/11/09 09:34:14
start on 2009/11/09 09:34:17
end on 2009/11/09 09:34:20
start on 2009/11/09 09:35:06
end on 2009/11/09 09:35:10

-- /sbin/adbd killed --
start on 2009/11/09 09:35:53
end on 2009/11/09 09:35:54
start on 2009/11/09 09:35:57
end on 2009/11/09 09:35:59
start on 2009/11/09 09:36:01
end on 2009/11/09 09:36:02
start on 2009/11/09 09:36:05
end on 2009/11/09 09:36:06
start on 2009/11/09 09:36:08
end on 2009/11/09 09:36:09

From the log file above, we can see that the loop takes about 1 second to finish without DDMS running or having adbd process killed. And the loop takes about 3 seconds to finish if DDMS is running and capturing log message. On average, Log.v function runs at the level of tenth of millisecond. So, I tend to believe we don't need to bother much about performance penalty. It's more important to have correct logic and easier debugging facility.

Monday, November 9, 2009

native programming on android

Besides programming with java, we're also able to do native programming with c or c++ on android platform.
To do so, we need a cross compiler target on arm processor for our working platform( windows or linux). So I downloaded Sourcery G++ Lite 2009q3-68 for ARM EABI, the tool chain for arm. If you're careful enough, you would have noticed my mistake which took me a day to figure out. Unfortunately, I downloaded the wrong tool chain. The correct one is Sourcery G++ Lite 2009q3-67 for ARM GNU/Linux. This toolchain is used for target platform that runs linux operating system. If I were patient enough to read the getting started guide for the toolchain, I would found out that the first toolchain is for platforms that don't have operating system, and the second one is for linux.
From the embarrassing story, you may tell I'm still a freshman on embedded system. Surely I am. In the last embedded project I worked on, there is already a toolchain and building system up and running built by my experienced colleagues. So I don't need to care about this. Anyway, this frustrating but finally success experience gains me a lot.

Ensuing content is about the steps to build and run hello world with the toolchain.
  1. download the right toolchain and extract the package
  2. add bin to path environment variable for easier access to the toolchain
  3. add below source code

  4.         #include    "stdio.h"

    int main ( int argc, char *argv[] )
    {
    printf("hello world!");
    return 0;
    } // ---------- end of function main ----------

  5. compile the code with arm-none-linux-gnueabi-gcc h.c -static. -static argument is necessary here because android uses a different c library with this toolchain. we must link the application statically against c lib, otherwise, the application will fail to run on android emulator.
  6. download the application to emulator with: adb push hello /data/
  7. log onto emulator with: adb shell
  8. add execution permission to the application with: chmod 777 /data/hello
  9. run the application /data/hello and we get desired output

Note, because we statically linked the c library so we used the c lib provided in the codesourcery arm toolchain rather than the custom Bionic c lib comes with ndk.


Update: native programming with android building system