Saturday, May 21, 2011

Handling incoming call interruption in BlackBerry audio player

Last week I spent two days to fix an issue of blackberry audio player: the audio stream need to pause the player during incoming call interruption, and resume when call is finished.
At the beginning, I feel it is easy to fix, because I fixed this kind of issue many times before for blackberry platform.
So I just program based on my old experiences, but it did not working.

My Mistake
At first I use BlackBerry API PhoneListener to register the call interruption event. But it did not work, I found some issues:
- If you use PhoneListener, the application will prompt use to agree to use Phone API, which is annoying.
- When you delete the application, you have to restart the phone.
- The application can get the incoming call event via callIncoming() method, but some time the application get exception;
- The application get the call end event via callDisconnected() method, but when you call MMAPI player play() method, it always throws MediaException.
  It seems the application the the event earlier than the voice call app release the resource.
- I found the Phone already stop the media player before it send the incoming call event the the application, so you have to use a workaround to deal with this issue.
I tried the different workarounds, but none of them working, it seems the PhoneListener solution is not reliable, and even not working. I don't remember why it works before.
maybe because of current phone is 5.0 while before are 4.3 or 4.6? Actually I don't know.

New solution
After I googled and I found a really simple solution: handle the DEVICE_AVAILABLE and DEVICE_UNAVAILABLE event in the playerListener. Based on this article:
The DEVICE_UNAVAILABLE event occurs when there is an incoming call. The DEVICE_AVAILABLE event occurs when the call is ended.
So all you need to do is pause the player in DEVICE_UNAVAILABLE, and resume when DEVICE_AVAILABLE event comes.
Code snippet like this:
playerUpdate(Player player, String event, Object eventData) 
{
    ...

    if(event == PlayerListener.DEVICE_UNAVAILABLE)
    {
        if(player.getState() == Player.STARTED)
        {
              player.stop();
              bPausedByIncomingCall = true;
        } 
    }
    else if(event == PlayerListener.DEVICE_AVAILABLE)
    { 
        if(bPausedByIncomingCall)
        {
            player.start();
            bPausedByIncomingCall = false;
        }

    }

   ...
}
The solution is very easy and it really works. I tested it when the DEVICE_UNAVAILABLE event comes, the player is still playing, which means the event is sent before the incoming call interruption.

Retrospection
I checked the MMAPI API and Blackberry API document, I found this event is not new (Blackberry support this since 4.0!), but I did not notice this until now. Why I did not notice these two events before? I did not find them in the books, nor I did not heard from them from previous colleagues. This is my another blind spot and it exposed my ignorance of MMAPI. This issue tells me: sometime your old experience is unreliable; you still need to empty your mind, like Andy Hunt said: always have beginner's mind!

4 comments:

  1. Thanks Steve.. It is really a quality post.

    ReplyDelete
  2. I am a very beginner for mobile platform. working since last 3 years and passionate towards mobile gaming. I have an idea of making a game engine.. Can you give me some inputs which may help me to start with..

    ReplyDelete
  3. Thank Steve! You really saved my neck with this one. I also tried to use the PhoneListener without any luck. Listening for device_unavailable/device_available in the PlayerListener worked like a charm!

    ReplyDelete
  4. Thank you, great and informative post, this will save me a lot of time.

    ReplyDelete