Archive for the 'Bebo' Category

A quick Flash sound player to use on Facebook and Bebo

For Doorbell on Bebo, I needed an easy way to play an arbitrary doorbell ring. Previously, I had been creating individual .swf files for each ring, and then using the <fb:swf> tag to put them on the page. I was using an AJAX callback to add them when the user clicked a doorbell. The swf was set to auto play one time after load. I had created a separate swf file for each ring using MP3 to SWF Converter. This worked fine, but I didn’t want to have to do this for each new ring. I also wanted the user to be able to click the bell to hear it, and these generated swf files only played once or in a loop, but not on a click. I searched and found FlashDevelop, an open source SWF editor. It is great because it doesn’t require purchasing the Adobe Flash IDE to work, and supports both Actionscript 2 and 3. It is a pretty good editor overall. I hadn’t spent any time with Actionscript before, but it ended up being a lot like Javascript, which I know pretty well. Most of the difficulties came with trying to understand the Flash model, rather than the language. Thankfully, there is Google. The result is a small class that can display an image as the background and can play an .mp3 over the Internet. Using passed in query params, I can control whether the image is shown, which sound to play, and whether it plays right away. Here is how it works: Query params passed in to Flash become global variables off the _root object. I prefaced mine with an “a_”, so I would know which were global variables. You can check them for null to see if they were passed in.

  // Globals passed in by query
  // a_play - if set, the mp3 will play immediately
  // a_ring - the mp3 to play
  // a_nopic - if should hide the background

First, I check to see if I should set the background image by checking for a query parm called “a_nopic”. If it is not set, I load a picture I have added to my swf library.

  if ( _root.a_nopic == null ) {
    _root.attachMovie("library.speaker.jpg", "flashBG", 0);
  }

This says that I should get that image, create a movie based on it, set it as a variable off _root called "flashBG", and put it at the bottom layer(0). Next, I create a new sound object off the _root.

  _root.firstSound = new Sound();

I load the passed in mp3, with the option to play it automatically when it is done by passing "true" as the second parameter. This is controlled by the query param "a_play". Note: the mp3's must have a sample rate of 11KHz, 22KHz, or 44.1KHz or they play too fast.

  _root.firstSound.loadSound(_root.a_ring, _root.a_play != null );

I want the user to be able to click and play the sound, so I set the onRelease function for the _root. This means that when the user releases the mouse button after clicking on the background, the sound will play. I also stop the sound before playing it, so that multiple clicks don't trigger multiple simultaneous sounds.

  _root.onRelease = function() {
    _root.firstSound.stop();
    _root.firstSound.start(0, 1);
  }

The code above is enough to do everything I needed, except for one thing. Unfortunately, the cursor doesn't change to the hand to show the user that the swf is clickable. HTML style tags have no effect, and Flash doesn't natively support changing the cursor easily. There are two ways I found to fix this:

  1. Create a custom cursor. You create a Movie based on a cursor, hide the existing system mouse, and call startDrag() to show your cursor.
      mouse.hide();
      startDrag(_root.yourCursor, true);
  2. Create a giant button that covers the whole swf. The cursor for a button is already the hand cursor.
      _root.rectangle = [Stage.width,Stage.height];
      _root.createEmptyMovieClip("button",300);
      _root.button.lineStyle(1,0x000000,0);
      _root.button.beginFill(0x00000,0);
      _root.button.lineTo(_root.rectangle[0],0);
      _root.button.lineTo(_root.rectangle[0],_root.rectangle[1]);
      _root.button.lineTo(0,_root.rectangle[1]);
      _root.button.lineTo(0,0);
      _root.button.endFill();
    
      // Handle left click
      _root.button.onRelease = function() {
        _root.firstSound.stop();
        _root.firstSound.start(0, 1);
      }

I went with the button option, since I didn't have to create my own cursor for the movie. Here is the whole script:

class Ringer
{
    public static function main()
    {
        // Globals passed in by query
        // a_play - if set, the will play immediately
        // a_ring - the sound to play
        // a_nopic - if should hide the background

        Stage.scaleMode = "noscale";

        // background image
        if ( _root.a_nopic == null ) {
            _root.attachMovie("library.speaker.jpg", "flashBG", 0);
        }

        // sound
        _root.firstSound = new Sound(); 

        // Handle left click
        _root.onRelease = function() {
            _root.firstSound.stop();
            _root.firstSound.start(0, 1);
        }	

        // Load the passed in sound (ex ?a_ring=test.mp3)
        // Sound must be mp3, and have sample rate of 11KHz, 22KHz, or 44.1KHz
        _root.firstSound.loadSound(_root.a_ring, _root.a_play != null );

        // Create a transparent button so that the mouse cursor changes to a hand
        // Make it the size of the whole stage
        _root.rectangle = [Stage.width,Stage.height];
        _root.createEmptyMovieClip("button",300);
        _root.button.lineStyle(1,0x000000,0);
        _root.button.beginFill(0x00000,0);
        _root.button.lineTo(_root.rectangle[0],0);
        _root.button.lineTo(_root.rectangle[0],_root.rectangle[1]);
        _root.button.lineTo(0,_root.rectangle[1]);
        _root.button.lineTo(0,0);
        _root.button.endFill();

        // Handle left click
        _root.button.onRelease = function() {
            _root.firstSound.stop();
            _root.firstSound.start(0, 1);
        }
    }
}

The FBML to call it would be:

  <fb:swf swfsrc='ringer.swf' flashvars='a_ring=your.mp3&a_play=1' imgsrc='yourbg.jpg' width='50' height='50' waitforclick='false' />

Inner Circle for Bebo is released

We have finished porting Inner Circle for Facebook over to Bebo. It was much easier because of our experience porting Doorbell, and the quick updates Bebo has made to their platform to make it more compatible with Facebook. Their goal is 100% compatibility, and although there are only 4 developers, they are making good progress.

Since Bebo doesn’t support FBJS yet, we had to make some modifications to how some parts work, such as the reply page. On Facebook, we can used Ajax to update multiple parts of the page when a user creates a new reply. On Bebo, the default FBML controls only allow an update of a single tag, so we went with a full page refresh instead. Since the page is all FBML, the speed difference is pretty insignificant. Some things we are thinking about for the future are linking the Inner Circles on Bebo and Facebook together. It would be great to know what is happening with your friends on both platforms, all in one place. Anyway, if you are on Bebo, give Inner Circle for Bebo a try.

Migrating a Facebook application to Bebo

Recently, we created a Bebo version of our Doorbell application for Facebook.

Here is what I did:

  1. created a new app using the developer app. Used a new callback location.
  2. Updated my db to handle the larger sized userid and sessionkeys
  3. updated web server to handle the new callback location
  4. forked my fb source code to a new Bebo version
  5. included the new Bebo PHP library in my source files
  6. Change all $fb = new Facebook($apikey, $appsecret) to $bebo = new Bebo($apikey, $appsecret)
  7. Change all $fb->api_client calls to just $bebo-> calls, and manually tweaked the parameters to be associative arrays.
  8. Change all FBJS code to mock Ajax, where it can be, or remove otherwise
  9. go through each code path with tracing to figure out what bebo doesn't implement or implements differently.

What is nice, is that most of it just works. The tools are the same, the fb_* post variables are there. They just don't have complete parity with FB on the whole API yet, but they seem to be working on it.

The big gotchas are:

  1. The add method isn’t the same. On Bebo, it seems like a user must add your application to interact with it, and that add happens without any calls to your code. There is therefore less to handle in terms of user state than Facebook.
  2. The api calls are different. Facebook provides a nice wrapper for their REST implementation, and Bebo doesn’t have the same level of completeness in theirs. My next task is to write the same wrapper for Bebo.
  3. All callback parameters via Ajax are sent as POSTs rather than GETs regardless of how they are specified in the call.

Doorbell for Bebo is released

Since Bebo finally opened up their platform for everyone a last week, we thought it would be fun to convert Doorbell for Facebook over to it.

Bebo supports most of the Facebook API, so converting wasn’t too hard. Most of the time was finding out the places where they don’t work the same. All the same functionality described here is in Doorbell for Bebo. Anyway, if you are on Bebo, give Doorbell for Bebo a try.

« Previous Page