An easy way to play streaming audio using MPMoviePlayerController

Every once in a while, you find the need to play some steaming audio file in your app. Of course, you can use the new AVPlayer class that is available in iOS 4 and later to do so. Or you can check out this AudioStreamer written by Matt Gallagher. They both will get the work done and provide you with plenty of extra good stuff such as streaming multiple audio files. However, if the only need is to simply play a single audio file online, you have a better choice, that is to use the MPMoviePlayerController (available in iOS 2 and later). Guess what, it also comes with a nice basic graphical audio controls (play/pause, duration, progress bar) so that you don’t have to write yourself!

All you have to do is to add the MediaPlayer framework in your project and import the related header files. And then you set it up as follows:

MPMoviePlayerController* moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL: audioURL];
[moviePlayer.view  setFrame:CGRectMake()]; // some rect area where you want the audio controls to live
[viewController.view addSubview:moviePlayer.view];
[moviePlayer prepareToPlay];

* Please note that, in iOS 4 when you call initWithContentURL: method, the prepareToPlay method will be called automatically but only for the first time. However, in iOS 5 you will need to call prepareToPlay manually to make it work, otherwise, the audio controls will not show up properly.

Also, if you need to change the contentURL for the moviePlayer to play another file, do:

moviePlayer.contentURL = newURL;
[moviePlayer prepareToPlay]; // make sure to call this every time you change the url!

One last note, the property shouldAutoplay is set to be NO by default in iOS 4. You will have to manually set it to NO in iOS 5 if you don’t what the player to start play automatically.


i-JDSP PZPlacement Demo

It has been a while since my last post. Basically, I decided to switch my thesis project from VirtualEar to i-JDSP. And as a result, I have been busy adding new features and functions to the i-JDSP software with a focus on perfecting the UIs and the users’ overall experience. The Pole Zero Placement block is the most recent addition to the new feature sets of i-JDSP. It enables the user to enter and move the poles and zeros representing a filter by touch and drag-and-drop. The frequency response of the filter is, at the same time, dynamically displayed to reflect those changes.


Solving the mystery among AVAudioPlayer, AVAudioRecorder and AVAudioSession

Lately I’ve been heavily developing my thesis project – VirtualEar for some audio signal processing. One of its basic tasks is to be able to record a sound and play the sound back. However, such a task may not be so simple as you think. In fact, it could be so frustrating that it might be running happily in your simulator but crashing on your actual device, which is what happened to me.

Well, not exactly. I want to keep simple things simple, so I use AVAudioRecorder in one viewcontroller for recording and AVAudioPlayer in another viewcontroller for playing. Everything worked fine in the simulator until I installed it on my phone. My AVAudioPlayer won’t playback the recorded sound. And the worst part is, it didn’t crash and not even an error message!

At first, I thought it was something wrong with the phone. And it turned out to be not the case as I downloaded and installed the sample code avTouch from Apple and it worked fine on my phone. Then I thought will it be the file format? So I replaced the sound in the sample project with my sound and everything was fine again.

Hmmm, I really need some error message here. So I carefully read through Apple’s documentation and found this delegate method of AVAudioPlayer:

- (void)playerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error
	NSLog(@"ERROR IN DECODE: %@\n", error);

I quickly run the app again and this time it returns me with “audioPlayer couldn’t play the file /localhost/var/mobile/XXXX”. That’s not very helpful but we’re getting something. To make sure the file does exist, I sshed to the phone directory and it’s there.

Time to turn to our good friend Google again. I searched the keyword “avaudioplayer won’t play”. There were not many related links to it but I did find one post talking about the activity setting with AVAudioSession. I almost forget about AVAudioSession!

AVAudioSession is a singleton object that you employ to set the audio context for your application.

I recall using AVAudioSession in my recorder viewcontroller to create a context for my AVAudioRecorder but not for AVAudioPlayer.

It might be something wrong in my AVAudioSession settings. I scrutinized my code again for the setting part and there it was:

[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryRecord error:nil];

I didn’t tell it to be able to playback! No wonder it won’t play. So thrilled, I changed the line to this:

[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];

Bingo! My phone is singing happily and I can finally go to bed peacefully.


i-JDSP Frequency Response Demo

I just made a second demo video for iJDSP for the upcoming Frontiers in Education (FIE) 2010 Conference, Washington DC. The demo is mainly about the newly added filter frequency response block, where users can choose different filter designs (including low pass, high pass and band pass) by changing the according coefficients.

The block utilizes a convenient library Core Plot for plotting figures. The framework is still under development and if you’re interested you can check out some examples on their wiki page. However, some of the codes are outdated and you can’t find any new tutorials on line. For basic plotting it is very easy to use, but if you want to do some customization like adding title and custom labels, your best bet is to see the source code yourself. I’m still exploring and will post some of my codes in the future if anyone is interested.


i-JDSP Demo

After one month of coding and half jar of white tea, i-JDSP is finally coming together. The whole process is purely fun, especially for the early stage interface and architecture design part. I consider it as a marriage between electrical engineering and computer science as I can finally apply some of my knowledge in EE to CS and vice versa.

So here’s a little about i-JDSP. i-JDSP is an iPhone/iPad based interactive digital signal processing (DSP) laboratory designed to help engineering students better understand the fundamental concepts of signal processing. It is implemented in Objective-C and C as a native Cocoa Touch application based on the previous online laboratory Java-DSP (JDSP) developed at Arizona State University. It offers basic signal processing simulation functions as FFT, filtering, frequency response and etc. with convenient graphical user interface and multi-touch programming experience. All simulations can be visually established by forming interactive block diagrams through multi-touch and drag-and-drop.

Yesterday I put together an alpha testing video for i-JDSP on Vimeo. It only has a few basic functions right now and has several bugs, but still I think it’s pretty awesome. So here it is:-)


Private Methods in Objective-C — the Use of Extensions

Although there is no such thing as a private method in Objective-C. Sometimes, you’ll find situations where you want to hide some of the functions from the public world.


are like “anonymous” categories, except that the methods they declare must be implemented in the main @implementation block for the corresponding class.

What exactly does “anonymous” mean?? I’ll show you an example below. So in your header file:

@interface YourObject : NSObject
    NSString* string; // instance variable
- (NSString*)string; // public function

// Declare your private methods here
@interface YourObject ()
- (void)yourPrivateMethod;

In the implementation:

@implementation YourObject
- (NSString*)string
   return string;

- (void)yourPrivateMethod
    // definition here

Remember, these private methods MUST be implemented in the main @implementation block of the corresponding class. This way, unlike using normal Categories, the compiler will yell at you if you forget to implement them.


Building static library for iPhone – An example of building Boost

In one of my iPhone projects, I want to link against to the Boost C++ Libraries. Many of the classes in Boost can be used as “header only” classes, such as uBLAS. However, if you want to use any of the compiled libraries (see the complete library list here), you may want to configure and compile it yourself like me, especially if you want it to work on iPhone.

Generally, to compile and link to any static third party libraries for the iPhone, you need to do the following:

  • build the library as a static lib for the different platforms (armv6 and i386 at the least)
  • use lipo to create a universal library from the individual static libraries built above
  • drag and drop the universal lib into your xcode project
  • drag and drop the header files into your xcode project
  • After hours of googling, I managed to successfully compile Boost. Here are my steps. I am using Mac OS 10.6.4, Xcode 3.2.3, iPhone SDK 4.0 and Boost 1.42.

    Step 1

    Download Boost 1.42 from the link above and extract it.

    Step 2

    Creata a user-config.jam file in your home directory(in Terminal: $touch ~/user-config.jam). Edit it so it has the following content:

    using darwin : 4.2.1~iphone
       : /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc-4.2 -arch armv7 -mthumb -fvisibility=hidden -fvisibility-inlines-hidden
       : <striper>
       : <architecture>arm <target-os>iphone <macosx-version>iphone-3.2
    using darwin : 4.2.1~iphonesim
       : /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/gcc-4.2 -arch i386 -fvisibility=hidden -fvisibility-inlines-hidden
       : <striper>
       : <architecture>x86 <target-os>iphone <macosx-version>iphonesim-3.2

    Step 3

    Navigate to your downloaded boost directory and make sure file boost_1_42_0/tools/build/v2/tools/darwin.jam has the following code:

    ## The MacOSX versions we can target.
    .macosx-versions =
        10.6 10.5 10.4 10.3 10.2 10.1
        iphone-4.0 iphonesim-4.0
        iphone-3.2 iphonesim-3.2
        iphone-3.1.3 iphonesim-3.1.3
        iphone-3.1.2 iphonesim-3.1.2
        iphone-3.1 iphonesim-3.1
        iphone-3.0 iphonesim-3.0
        iphone-2.2.1 iphonesim-2.2.1
        iphone-2.2 iphonesim-2.2
        iphone-2.1 iphonesim-2.1
        iphone-2.0 iphonesim-2.0

    Step 4

    In your boost directory, in Terminal run


    or if you want to build specific libraries run

    ./ --with-libraries=yourlibname

    Step 5

    To build for the iPhone Device, run

    ./bjam --prefix=path/for/iphonedev toolset=darwin architecture=arm target-os=iphone macosx-version=iphone-3.2 define=_LITTLE_ENDIAN link=static install

    To build for the simulator, run

    ./bjam --prefix=path/for/iphonesim toolset=darwin architecture=x86 target-os=iphone macosx-version=iphonesim-3.2 link=static install

    Modify the path/for/iphonedev, path/for/iphonesim to where you want to store the files. If everything went ok, you should see files fly by on the screen and something says”patience”.

    Step 6

    It turns out you can use lipo to combine those separate iphone device and iphone simulator libraries into a single universal library. Copy those separate files, navigate to the directory and type

    lipo -create libboost_yourlibname_iphone.a libboost_yourlibname_iphonesimulator.a -output libboost_yourlibname_iphone_universal.a