headerphoto

Using GStreamer and Python to Record Audio

Posted by Tim Freund Thu, 29 Jan 2009 03:45:00 GMT

I have a project idea that involves recording audio from USB powered microphones, and I wanted to create a quick sketch of a program to judge the difficulty of doing that with Python. Short answer? It's really easy. If you're impatient, you can download this sample script.

For those of you still reading, I'll explain the process in a little more detail. The GStreamer library handles all sorts of media input and output, and there are bindings written for Python. This seemed like an excellent avenue for my project, but I had some trouble getting started.

I discovered Jokosher after a bit of searching. It is a multi-track recording application written with Python and GStreamer. I was able to use the debug output of Jokosher to figure out what an appropriate GStreamer pipeline would look like to capture audio from my microphone, and I was able to see how D-Bus can be used to determine the ALSA card identifier for any given sound device.

This web cam tutorial was also helpful, as it demonstrated how to properly close a GStreamer pipeline.

Of course, after my proof of concept was done I stumbled across this documentation for GStreamer's Python bindings.

I will excerpt the interesting bits of the script here, but don't forget that you can download the entire thing.

List Sound Cards and Get Their ALSA ID

    def list_capture_devices():
    bus = dbus.SystemBus()
    hal_manager = bus.get_object("org.freedesktop.Hal", "/org/freedesktop/Hal/Manager")
    hal_manager = dbus.Interface(hal_manager, "org.freedesktop.Hal.Manager")

    devices = hal_manager.FindDeviceStringMatch("alsa.type", "capture")

    identifiers = []

    for dev in devices:
        device = bus.get_object("org.freedesktop.Hal", dev)

        card = device.GetAllProperties(dbus_interface="org.freedesktop.Hal.Device")
        if card["alsa.card"] not in identifiers:
            print "%d. %s" % (card["alsa.card"], card["alsa.card_id"])
            identifiers.append(card["alsa.card"])

    return identifiers

Start (and Stop) a GStreamer Pipeline

def record(device_id, capture_path):
    pipeline = gst.parse_launch("""alsasrc device=hw:%d ! audioconvert ! level name=recordlevel interval=10000000 ! audioconvert ! flacenc ! filesink location=%s""" % (device_id, capture_path))
    pipeline.set_state(gst.STATE_PLAYING)

    print "recording, press enter to stop"
    sys.stdin.readline()

    pipeline.set_state(gst.STATE_NULL)
    time.sleep(5)

With as easy as this seems, maybe we really will import antigravity one day.

Bookmark and Share

Posted in ,

Evolution of an Android Application: Day 4

Posted by Tim Freund Mon, 26 Jan 2009 05:07:00 GMT

This is a small detour from the planned discussion the different approaches available for making HTTP requests. I needed an easy topic since it has been so long since I last found time to work on the application.

Those who have seen Rhymote in action know that it is pretty ugly, and I want to change that. In addition to being ugly, the buttons are so small that I can easily hit the wrong one. Right now the application uses text on a standard Android button to crudely imitate the buttons of a media player. Using legitimate media player icons would make the app look much nicer. For those who haven't seen the app in its ugly form, take a look:

http://achievewith.us/images/evolution_of_an_android/day_01_initial_ui.jpg

Find or Design Icons

Android applications can use images as icons. The standard image format is PNG, and images can be placed in the res/drawable directory of your project.

Since I am a programmer and not a designer, I chose to look for appropriate open source icons. The Tango Icon Library is a great looking icon set, the icons are available in a scalable format, and the set is available under a Creative Commons license. Awesome.

I tried to use the SVG icons directly, but that didn't work. Instead, I used Inkscape to export the SVG icons as appropriately sized PNG files. For reference, I made the icons approximately 100 pixels tall.

Update The Layout

The button definitions in the layout file now look something like this:

<ImageButton android:id="@+id/previous"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/media_skip_backward"></ImageButton>

Unfortunately the buttons still had the default white background. When we finally get around to displaying album art, transparent button backgrounds will allow that album art to be seen. To achieve this, I made a small (10x10) transparent PNG file with no content. We can then set the android:background attribute of the ImageButton to achieve the desired effect.

<ImageButton android:id="@+id/previous"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/media_skip_backward"
    android:background="@drawable/transparent"></ImageButton>

For this small amount of work, we get an application that looks much better than before:

http://achievewith.us/images/evolution_of_an_android/day_04_new_buttons.jpg Bookmark and Share

Posted in ,

Writing an SFTP Server in Python

Posted by Tim Freund Tue, 13 Jan 2009 05:47:00 GMT

There's nothing more relaxing than to sit down and write an implementation of a commonly available network service in your favorite scripting language. OK, so maybe writing an SFTP server in Python wasn't the most relaxing thing I could have done this evening, but the Paramiko library made it pretty darn easy, and I had a lot of fun because the work moved so quickly.

Did I mention how quickly the development went? 284 lines, including the license and a demo configuration file. And people wonder why I enjoy Python programming so much.

But Why?

Most code is written to scratch an itch, and this code was no different. We write a number of scheduled jobs at work that upload or download files from SFTP servers. We needed a way to test the jobs, but we didn't want to set up operating system accounts on our servers to run the tests.

My minimal implementation of an SFTP service allows us to test many job configurations with one SFTP service running as an unprivileged user. The user accounts are optionally chroot'ed into their "home" directory, so it appears as if they are connecting to a server that has the exact same file hierarchy that is present on the production file servers.

To play around with the code yourself, you can install Paramiko and clone the Simple SFTP Server Mercurial repository. If you don't have Mercurial installed, you can always download the script straight out of the repository.

The code works, but it is minimally functional: it only does what we needed it to do at work. No worries, though. It is licensed under the MIT license, so you are free to do with it what you please. Patches are accepted if you are feeling generous.

Bookmark and Share

Posted in ,

Evolution of an Android Application: Day 3

Posted by Tim Freund Wed, 07 Jan 2009 04:32:00 GMT

Where we last left off, Rhymote worked, but it was painfully slow. All of the network communication takes place in the UI thread, and that's a big problem. An application has 5 seconds to respond to a UI event, and if the click handler isn't done in that amount of time, the user will be asked if they'd like to terminate the application. The exact error message will look something like this:

Sorry!  Activity Rhymote
(in application Rhymote)
is not responding.

Even though Rhymote is only making one HTTP request per button press, that can put us over the 5 second limit. The HTTP requests return quickly in the emulator, but the phone is a totally different world.

A partial solution to the problem is threading. We want to start a new thread of execution separate from the UI to handle time intensive work. These time intensive tasks can then update the UI if necessary once they are done. If you are at all experienced with Java threading, you will already know how to create a Runnable object and pass that Runnable to a Thread. If you are new here, follow this cheat sheet:

package com.example.androidapp;

public class WebRequestRunnable implements Runnable {
    public void run(){
        // do resource intensive stuff here...
        // create an http request and read the results
    }
}

and

package com.example.androidapp;

public class Application {
    ...
    private OnClickListener mButtonListener = new OnClickListener() {
        public void onClick(View v) {
            WebRequestRunnable wrr = new WebRequestRunnable();
            Thread t = new Thread(wrr);
            t.start();
        }
    }
}

More information about this basic pattern can be found at the following Android resource pages:

Although the application no longer hangs when responding to a button press, there is still a latency problem. The HTTP request that was taking 5+ seconds to execute in the UI thread is now taking 5+ seconds to execute in a second thread. Two potential issues come to mind:

  • The Apache Commons HttpClient code is really slow
  • I'm doing something foolish in my code

I learned long ago to never blame another programmer or library without some very solid evidence. When in doubt, it is probably my own fault. Next time we will attempt to find the most efficient way to deal with the required network requests.

Bookmark and Share

Posted in ,

Evolution of an Android Application: Day 2

Posted by Tim Freund Fri, 19 Dec 2008 06:31:00 GMT

I'm still working on the Rhymote project.

I sat down with the intent of immediately putting the code on my phone, but it was just so ugly that I had to spend about 30 minutes cleaning things up. Let that be a lesson: late night programming can be fun, but it isn't always productive.

Configuring the G1 for Deployment

First I opened the Settings program and choose Applications.

http://achievewith.us/images/evolution_of_an_android/day_02_applications.jpg

I checked the box next to Unknown Sources

http://achievewith.us/images/evolution_of_an_android/day_02_unknown_sources.jpg

While I was still on the Applications screen of the Settings program, I selected Development and checked the box next to USB Debugging.

http://achievewith.us/images/evolution_of_an_android/day_02_usb_debugging.jpg

Configuring my Computer for Deployment

Since I am developing the software on Ubuntu, I also need to configure udev to recognize the phone as more than just a USB drive:

# echo "SUBSYSTEM=="usb", SYSFS{idVendor}=="0bb4", MODE="0666"" > /etc/udev/rules.d/50-android.rules

Developers who are using Windows or OS X do not need to worry about similar changes for their operating system.

Deploying the Application

Then I plugged the phone in and ran:

$ adb -d install ~/workspace/Rhymote/bin/Rhymote.apk

The application works on the real device just like in the emulator, except for one painful difference: it is terribly slow. Slow enough that the system asks if I would like to terminate the application while the OnClickListeners are firing. That's not so great.

Since this is kind of a hack-and-slash project, I just create a BasicHttpRequest object right in the listener, fire it off, and wait for the response. That worked great in the emulator, but I guess I need to make the HTTP request in the background when I am running on a real phone.

I could have learned all about that if took the time to read the docs up front, but that's OK. I'm happy to have something that works, even if it isn't working great, and I know what I can learn next.

Bookmark and Share

Posted in ,

Evolution of an Android Application: Day 1

Posted by Tim Freund Wed, 17 Dec 2008 03:04:00 GMT

Programmers are supposed to be lazy right? Here is the scene for one of my lazy moments: my home office contains a desk and a futon in opposite corners. I often want to change music on my desktop PC while reading on the futon. Most people would just get up to change the music without much thought, but I'd much rather use my G1 as a remote control for Rhythmbox. This will be my first Android project, and it shouldn't be too much to handle for a newbie like myself.

I started the Rhymote project yesterday, and I am writing these posts to keep track of all the hurdles I encounter along the way. Although the project could end up doing all sorts of neat stuff, all I really want to do is a handful of operations:

  • Play/Pause
  • Next track
  • Previous track
  • Volume adjustments

I have a tendency to over-engineer solutions, so I'm going to explicitly avoid anything that smacks of over ambitious design. Quick and dirty is the name of the game. The code will grow up if it holds my interest for long enough.

Here's the gear I am working with:

  • Ubuntu 8.10
  • Rhythmbox 0.11.6
  • Eclipse 3.4
  • Android SDK + Eclipse Plug-in
  • T-Mobile G1

All of the code that I write throughout the series can be found in this repository.

Prerequisite: Put Rhythmbox on the Network

Rhythmbox isn't on the network by default, and I needed to change that if I was going to have any luck with this project. In the spirit of quick and dirty, I wrote a WSGI application that wraps rhythmbox-client. This solution will evolve as the android application evolves, but it is tangential to the process of Android application development. If I do anything particularly interesting with Rhythmbox, I'll be sure to write it up separately.

Start an Android Project

I write Java in Eclipse most of the day, so I felt pretty comfortable starting the Android portion of the Rhymote project. I followed along with the Hello Android tutorial, and it wasn't long before the string "Hello Android" was staring back at me from the emulator.

Create a User Interface

The first thing I needed was a UI, and building fat client user interfaces is foreign territory for me. Oh, what's that? Android uses XML to define screen layouts? Maybe this won't be so bad after all. Remember, I did say I am a Java developer by day.

http://achievewith.us/images/evolution_of_an_android/day_01_initial_ui.jpg

Make no mistakes, my UI is ugly. Did I mention that I don't write much UI code at my day job?

Find the System Log

http://achievewith.us/images/evolution_of_an_android/day_01_exception.jpg

I spotted the commons-httpclient code in the API, and decided to code up a client in an OnClickListener for each of my buttons.

After deploying the code and watching the application crash, I was left scratching my head. Where can I see the logs? Fortunately the command adb logcat is the Android equivalent of tail -f, and I was able to pinpoint the problem with my HTTP client code.

Discover Permissions

The exception I found was a little strange:

E/AndroidRuntime( 6490): Caused by: java.net.SocketException: unknown error E/AndroidRuntime( 6490): at org.apache.harmony.luni.platform.OSNetworkSystem.createSocketImpl(Native Method) E/AndroidRuntime( 6490): at org.apache.harmony.luni.platform.OSNetworkSystem.createSocket(OSNetworkSystem.java:79) E/AndroidRuntime( 6490): at org.apache.harmony.luni.net.PlainSocketImpl2.create(PlainSocketImpl2.java:59) E/AndroidRuntime( 6490): at java.net.Socket.checkClosedAndCreate(Socket.java:763) E/AndroidRuntime( 6490): at java.net.Socket.connect(Socket.java:910) E/AndroidRuntime( 6490): at org.apache.http.conn.scheme.PlainSocketFactory.connectSocket(PlainSocketFactory.java:117) E/AndroidRuntime( 6490): at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:129) E/AndroidRuntime( 6490): at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164) E/AndroidRuntime( 6490): at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119) E/AndroidRuntime( 6490): at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:348) E/AndroidRuntime( 6490): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555) E/AndroidRuntime( 6490): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:509) E/AndroidRuntime( 6490): at us.achievewith.Rhymote.Rhymote$1.onClick(Rhymote.java:60) E/AndroidRuntime( 6490): ... 23 more

I was expecting something along the lines of Connection Refused or Unknown Host, but unknown error was a little vague to be of much use. It was already late, and I foolishly struggled with the error for a while before letting Google Search work its magic, and that's when I learned about permissions.

Android applications don't just get free reign over the system without first asking for permissions to do most anything that interacts with the system at large or other systems. The following line cleared up the exception once it was added to the AndroidManifest.xml file:

<uses-permission android:name="android.permission.INTERNET"/>

One more run through the emulator, and I was able to start and stop my music. At this point it was 3:00 AM, and I decided that putting the code on the phone could wait.

Bookmark and Share

Posted in ,

FPyS, A Python Client for Amazon FPS

Posted by Tim Freund Mon, 10 Dec 2007 06:56:00 GMT

Earlier today I posted a note in the Amazon Developer Forums about FPyS, my attempt at a Python library for the Amazon Flexible Payment Service. It's rough, very rough, but it is a decent start at a fully featured FPS library. The library provides enough functionality to run FPeS, but not much beyond that.

For the curious, the demo application is a TurboGears application that allows people to select and purchase full sized images from a thumbnail gallery. The application is configured to process payments through the Amazon FPS Sandbox, so any completed transactions are drawn from imaginary credit cards. With that in mind, I'd like to welcome anybody to attempt a sale. The more the merrier, as it will cost us nothing and help to find bugs in the library.

Bookmark and Share

Posted in , ,

Configurable TurboGears Testing

Posted by Tim Freund Sat, 23 Dec 2006 08:06:54 GMT

A whole flurry of changes were committed to the TurboGears project today, and many of the changes will make testing TurboGears applications easier. I am partial to one ticket in particular, since I wrote it. This is my first applied patch for the TurboGears project, so I am quite happy about that.

A project can now use a test.cfg to define test specific settings for TurboGears applications. In addition, an application's app.cfg file will be parsed before unit tests will run. I was prompted to write the patch when I ran into issues with the default test configuration while testing GOODCalc.

Bookmark and Share

Posted in

Jython BuildBot

Posted by Tim Freund Tue, 12 Dec 2006 06:49:00 GMT

We have put up a preliminary BuildBot instance for the Jython project. The following things remain on the TODO list before we'd call it "production":

  • Run the unit tests. Currently the process only builds.
  • Add an extra step to one of our slaves to upload successful builds to http://jython.achievewith.us/nightly
  • Set up the master to watch the subversion repository. Builds are currently run once every 24 hours, but it would be nice to kick off a build after each commit as well.
  • Style the waterfall to better match jython.org

We will soon be seeking volunteers to host build slaves, but in the mean time you can check out the progress via the built-in waterfall display.

Bookmark and Share

Posted in

Proofread Typo Themes 4.0

Posted by Tim Freund Fri, 28 Jul 2006 06:51:00 GMT

All themes in the Proofread Typo Themes repository should now work with Typo 4.0. Most themes needed an update to their sidebar rendering and their head elements, but bash, sed, and emacs made short work of the task.

For those of you who like numbers, that’s 82 themes ready for your Typo 4.0 powered blog.

Browse the themes.

Bug reports for the themes.

Bug reports for the catalog.

Bookmark and Share

Posted in

Older posts: 1 2