April 2012

Full-duplex streaming between sound cards with GStreamer

Some may recall my old set up I used to record the AWNOI net. A bit fiddly, but it worked, and worked well. However the machine I used was short-lived. Basically, I wanted to stream in both directions between a sound device connected to a HF radio transceiver, and a USB wireless headset, with a feed being recorded to disk.

The problem with newer sound devices is the rather limited sync range possible with the modern audio CODECs. Many will not do sample rates that aren’t a multiple of 44.1kHz or 48kHz, and I have a headset that won’t record any other sample rate other than 16kHz. ALSA’s plug: doesn’t play nice with JACK, and I shelved the whole project for later.

Well, tonight I did some tinkering with gstreamer to see if it could do the routing I needed. Certainly all the building blocks were there, I just had to get the pipeline right. A bit of jiggling of parameters, and I managed to get audio going in both directions, and to a RIFF wave file to boot. I’ve put it in a shell script for readability/maintainability:

#!/bin/sh
# GStreamer bi-directional full-duplex audio routing script
# Stuart Longland VK4MSL

CAPT_BUFTIME=50000
CAPT_LATTIME=25000
PLAY_BUFTIME=20000
PLAY_LATTIME=1000

STREAM_FMT=audio/x-raw-int,channels=1,width=16,depth=16,rate=16000
OUTPUT_FMT=audio/x-raw-int,channels=2,width=16,depth=16,rate=16000
OUTPUT="${1:-out.wav}"

HEADSET_DEV=hw:Headset
HEADSET_CAPT_FMT=audio/x-raw-int,channels=1,width=16,depth=16,rate=16000
HEADSET_CAPT_BUFTIME=${CAPT_BUFTIME}
HEADSET_CAPT_LATTIME=${CAPT_LATTIME}
HEADSET_PLAY_FMT=audio/x-raw-int,channels=2,width=16,depth=16,rate=48000
HEADSET_PLAY_BUFTIME=${PLAY_BUFTIME}
HEADSET_PLAY_LATTIME=${PLAY_LATTIME}

SNDCARD_DEV=hw:NVidia
SNDCARD_CAPT_FMT=audio/x-raw-int,channels=2,width=16,depth=16,rate=48000
SNDCARD_CAPT_BUFTIME=${CAPT_BUFTIME}
SNDCARD_CAPT_LATTIME=${CAPT_LATTIME}
SNDCARD_PLAY_FMT=audio/x-raw-int,channels=2,width=16,depth=16,rate=48000
SNDCARD_PLAY_BUFTIME=${PLAY_BUFTIME}
SNDCARD_PLAY_LATTIME=${PLAY_LATTIME}

exec    gst-launch-0.10 \
    alsasrc device=${HEADSET_DEV} \
            name=headset-capt \
            slave-method=resample \
            buffer-time=${HEADSET_CAPT_BUFTIME} \
            latency-time=${HEADSET_CAPT_LATTIME} \
        ! ${HEADSET_CAPT_FMT} \
        ! audioresample \
        ! audioconvert \
        ! ${STREAM_FMT} \
        ! queue \
        ! tee name=headset \
        ! audioresample \
        ! audioconvert \
        ! ${SNDCARD_PLAY_FMT} \
        ! alsasink device=${SNDCARD_DEV} \
            name=sndcard-play \
            buffer-time=${SNDCARD_PLAY_BUFTIME} \
            latency-time=${SNDCARD_PLAY_LATTIME} \
    alsasrc device=${SNDCARD_DEV} \
            name=sndcard-capt \
            slave-method=resample \
            buffer-time=${SNDCARD_CAPT_BUFTIME} \
            latency-time=${SNDCARD_CAPT_LATTIME} \
        ! ${SNDCARD_CAPT_FMT} \
        ! audioresample \
        ! audioconvert \
        ! ${STREAM_FMT} \
        ! queue \
        ! tee name=soundcard \
        ! audioresample \
        ! audioconvert \
        ! ${HEADSET_PLAY_FMT} \
        ! alsasink device=${HEADSET_DEV} \
            name=headset-play \
            buffer-time=${HEADSET_PLAY_BUFTIME} \
            latency-time=${HEADSET_PLAY_LATTIME} \
    interleave name=recorder-in \
        ! audioconvert \
        ! audioresample \
        ! ${OUTPUT_FMT} \
        ! wavenc \
        ! filesink location="${OUTPUT}" \
    headset. \
        ! queue \
        ! recorder-in.sink1 \
    soundcard. \
        ! queue \
        ! recorder-in.sink0

Now the fun begins ironing out the kinks in my data cable for the FT-897. At present, it works for receive, and seems to work for transmit. I use VOX on the radio itself and keep the headset’s microphone on mute when I don’t want to transmit.

At present, I was getting a bit of distorted audio coming back through the headset when I transmitted, almost certainly RF-pickup in the cable and line-in circuitry of the computer’s sound card. I’ll have to see if I can filter it out, but the real test will be seeing if such distortion is present on the outgoing signal — or rather, if it’s significantly audible to be a problem.

Inside the GL4Ever Flytouch III

Well, it’s been a while since I touched this tablet.  I basically chucked it in a corner in disgust after it shat itself rather unceremoniously on the trip before we even got to the NSW/Victorian border.  By “shat” itself, I mean corrupting files on the internal microSD card, intermittent device resets, display flickers, all the hallmarks of a dry joint.

The seller on eBay that sold me the device have been completely unresponsive as to the problems, so looks like I kissed about $250 goodbye.  Ahh well, such is life.  They are still being sold on eBay, but buyer beware, they are cheap, and it’s pot luck whether yours is cheerful, or nasty like mine.  If you want something reliable, look elsewhere.

Having made this mistake, well, I’m looking to make lemonade from the lemon.  First step, was to figure out what on earth I had.  So out with the screwdriver.

You’ll notice on the top and bottom of the unit, there are four small plugs concealing screws.  These hold the LCD screen assembly in place.  Undo these, then you need to carefully work your way around and release the clips that hold the LCD screen assembly.  Do not try to detach the LCD touch panel from the LCD!  I initially couldn’t get it to budge, so I tried doing exactly this in the hunt for possible hidden screws (there were none).  This was the end result:

Shattered Flytouch III touch panel

Why one should not try to detach the touch panel.

Never mind I say… the unit was just about destined for the bin as it was.  External USB HID devices work for what I’m after, but it’ll mean any touch-related fun is out unless I can pick up a replacement 4-wire panel.  Element14 and RS have them at >$80, to which I say, bugger it, I’ll do without.

Having pulled the unit apart, the main PCB is held to the back shell by a few screws, one thing is immediately apparent.  The whole device is based on what looks to be a fairly generic System-on-Module based around the Vimicro VC0882BCXA System-on-Chip, and the Vimicro VC7822EL companion chip.

Flytouch III PCB

Top left is a Wifi module based on the Realtek RTL8111, and to the right, the GPS module (which hooks to one of the serial ports from what I recall).  Down the bottom of the image are the USB ports.  Near the HDMI socket is a Silicon Image SiI9022ACNU HDMI transmitter.

The system on module looks interesting, and I’m curious to find out more about it, as for hobby projects, the pins are not too small to deal with using a soldering iron.  The OS and boot loader exist on the microSD card.  I tried putting a 16GB card in, but evidently I wasn’t getting the partition table right as it wouldn’t boot.  I haven’t tried hooking up a serial port as yet, so it’s hard to know what is wrong.  Some research indicates that ttyS0 lurks on this board just near the aforementioned microSD socket:

The system on module within the Flytouch III

The system on module within the Flytouch III

I haven’t spotted the bad joints that were giving me grief. In fact, having gotten it out of the case, I find the top USB port (flakey from day one) seems to be behaving, and I’ve had no issues with it running with the case apart.  Otherwise I’d be running a soldering iron over a few joints just to make sure everything was right.

Next step?  Well for now, I’ll put it back together (minus touchscreen) and put it aside.  I’ll have a look at tacking a connector onto those serial pins, with a level shifter so I can interact with the serial console.

Having gotten bootloader access, I should be able to debug the SD card cloning issue, then I can have a close gander at what the current u-boot and kernel are doing to tickle the hardware.  End game?  Well, Android isn’t much use without a touch screen, so I’ll be probably hacking together a Gentoo-based environment with some amateur radio related software.  We shall see.