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.
Posted in Open Source, Python
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:
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:
Posted in Android, Open Source
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.
Posted in Open Source, Python
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.
Posted in Android, Open Source
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.
I checked the box next to Unknown Sources
While I was still on the Applications screen of the Settings
program, I selected Development and checked the box next to USB
Debugging.
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.
Posted in Android, Open Source
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.
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
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.
Posted in Android, Open Source
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.
Posted in Open Source, Python, TurboGears
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.
Posted in Open Source
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.
Posted in Open Source
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.
Posted in Open Source