Skip to content
October 6, 2017 / ftth

Generating multichannel audio samples from gstreamer using AudioChannelPosition in Python

For test purposes it can be useful to generate samples with multiple audio channels, with a different sound per channel to identify it easily. This is something that can be achieved with the audiointerleave plugin, but defining the channel-positions property cannot be done on the command-line.

My goal was to generate a tone of specific frequency for each channel (for a given target channel count), then feed it to a target channel encoded with aac (using fdkaacenc) and save it as m4a file.

The supported channel configuration were found in the fdkaacenc source code. Note that 8 channels does not seem to be supported with the current version of fdk-aac included in gstreamer (8 channels seems to require v0.1.4).

I didn’t find any available example program explaining how to achieve this in python, so i’m sharing it:

Opening one of the m4a file with audacity shows that each channel got a different sound:

Capture d'écran de 2017-10-06 18-29-19

Interestingly, one can see that LFE channel is filtering the input (applying a low pass filter), which makes sense since LFE is for the subwoofer.

Advertisements
September 26, 2017 / ftth

Gstreamer/python: ‘Iterator’ object is not iterable error

While working on a python gstreamer program (through gobject introspection bindings), i encountered the following error (which was a bit confusing) when trying to iterate over all elements inside a pipeline :

python /tmp/test.py 
Traceback (most recent call last):
 File "/tmp/test.py", line 14, in iterate
 for e in p.iterate_elements():
TypeError: 'Iterator' object is not iterable

The reason is that the bindings generated by gobject-introspection do not map the Gst.Iterator object returned by the method iterate_elements() to a python iterator.

Here is  a test program:

import gi
gi.require_version("Gst", "1.0")
from gi.repository import GObject, Gst, GLib
Gst.init(None)

pipeline = "videotestsrc is-live=true ! queue ! fakesink"

p = Gst.parse_launch(pipeline)

def iterate():
    for e in p.iterate_elements():
        print(e.get_name())

GObject.idle_add(iterate)
ml = GObject.MainLoop()
ml.run()

This can be fixed by installing gst-python which overrides the auto-generated bindings, among other things adding the __iter__ method on top of the Gst.Iterator object to fix native python iteration.

July 21, 2017 / ftth

Chromium opening folders with Audacious on Arch

When installing audacious on Arch linux, trying to locate a downloaded file in the file manager will open the audacious music player.

This happens because the audacious.desktop file provided by the upstream source package does register the “inode/directory” mime type. The mime apps specs state that if multiple apps register the same mime type, the opener app (e.g. xdg-open, as used by Chromium or Firefox) will use the first found (in that case, audacious, probably because of the alphabetical sort).

This can be checked by running

$ xdg-mime query default inode/directory
audacious.desktop

To fix this, you can add the following to /etc/xdg/mimeapps.list (as described in the Arch wiki):

[Default Applications]
inode/directory=org.gnome.Nautilus.desktop

From now on, nautilus will open folders by default:

$ xdg-mime query default inode/directory
org.gnome.Nautilus.desktop
July 4, 2017 / ftth

Displaying a host IP pre-logon on Arch

Sometimes it’s useful to be able to determine a system’s IP address directly from the terminal, prior to logon.

To do that, you can create a dedicated systemd unit file (e.g. /lib/systemd/system/display_ip_on_logon.service):

[Unit]
Description=Update /etc/issue with ip address
After=network.target

[Service]
ExecStart=/usr/local/bin/update_etc_issue

[Install]
WantedBy=multi-user.target

The script would be pretty straightforward:

#!/bin/bash#
while true
    do IP=$(/sbin/ip route get 1 | cut -d " " -f7)
    printf "ubicast mediacoder $HOSTNAME $IP\n\n" > /etc/issue
    sleep 30
done

That way, when connecting a display to the system, just type any key on the keyboard and the logon banner will show the host IP.

Do not forget to:

systemctl daemon-reload
systemctl enable display_ip_on_logon.service
systemctl start display_ip_on_logon.service
July 1, 2017 / ftth

Running pulseaudio system-wide with pacmd on Arch

While pulseaudio is, by default, run for each user session (socket-activated, or manually started with systemctl –user start pulseaudio), some scenarios can require having an always-running, system-wide pulseaudio instance. The official documentation on freedesktop.org describes how to achieve that and the drawbacks it implies.

Below are the instructions that worked for me on Arch (July 2017).

1. Create the systemd unit file

Put this in e.g. /usr/lib/systemd/system/pulseaudio.service

[Unit]
Description=PulseAudio system server

[Service]
ExecStart=/usr/bin/pulseaudio --system --disallow-exit --log-target=journal
#ExecStart=/usr/bin/pulseaudio --system --disallow-exit --disallow-module-loading --log-target=journal
ExecReload=/bin/kill -HUP $MAINPID

[Install]
WantedBy=multi-user.target

2. Create a dbus policy file

Put this in /usr/share/dbus-1/system.d; note that a reboot is required (or you can also try systemctl restart dbus && systemctl restart polkit && systemctl restart systemd-logind) :

<?xml version="1.0"?> <!--*-nxml-*-->
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
 "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
    <policy group="pulse">
        <allow own="org.pulseaudio.Server"/>
    </policy>

    <policy context="default">
        <allow send_destination="org.pulseaudio.Server"/>
        <allow receive_sender="org.pulseaudio.Server"/>
    </policy>
</busconfig>

3. Create the users and groups

Since the daemon will not be run by users anymore, it needs it’s own user and groups.

groupadd --system pulse
groupadd --system pulse-access
useradd --system -g pulse -G audio -d /var/run/pulse -m pulse
usermod -G video,wheel,pulse-access myuser
echo "default-server = /var/run/pulse/native" >> /etc/pulse/client.conf
echo "autospawn = no" >> /etc/pulse/client.conf
systemctl daemon-reload
systemctl enable pulseaudio
systemctl start pulseaudio

At this point, pulseaudio should work already (try gst-launch pulsesrc ! fakesink -v to check).

4. Enable –disallow-module-loading

The official documentation states: “If the system-wide mode is enabled it is advisable to disable module loading during runtime by passing –disallow-module-loading to the daemon, to inhibit the user from loading arbitrary modules with potentially vulnerable code into the daemon. However, this might break some modules like module-hal-detect which will load a sound driver module each time HAL signals that a new sound card became available in the system.”

I first tried to run with –disallow-module-loading, and the alsa configuration was messed up; even aplay -l or arecord -l were failing. The trick seems to be to add –disallow-module-loading only after a first successful use.

5. Disable –disallow-module-loading to use pacmd

This was the hardest to figure out: if you want pacmd to work, you cannot run pulseaudio with –disallow-module-loading (which is recommended by the official documentation), or you will get:

$ sudo PULSE_RUNTIME_PATH=/var/run/pulse -u pulse pacmd
Daemon not responding.

As long as –disallow-module-loading is not in the ExecStart line of the systemd unit file, pacmd will work using:

sudo PULSE_RUNTIME_PATH=/var/run/pulse -u pulse pacmd

It is recommended, once the /etc/pulse/system.pa finalized, to re-add the –disallow-module-loading switch.

 

April 30, 2017 / ftth

Installing Ubuntu 16.04 alone on a 2006 MacBook

This aging device has an unsupported OS, and you can’t even upgrade your web browser anymore, which means that Linux is the last breath for it. I didn’t expect it to be so difficult, but it eventually panned out.

Current Linux distros USB sticks won’t be detected by the bootloader (hold the alt key after power) of the venerable 2006 MacBook (A1181 ref, CPU is a Core 2 T7200). The reason seems to be that, regardless of CPU 64 bit support, the EFI implementation of these early mactels is 32-bit only, not to mention many other apple-specific quircks which prevent compatibility. In the past, Ubuntu did have a mac-specific release, which vanished in the meantime.

In other terms, your USB stick will only be listed by the mac bootloader if a /efi/boot/bootIA32.efi file is found on a FAT32 partition; i did try copying an Arch install media on a FAT32 stick, and it kind of works thanks to the presence of /efi/boot/bootIA32.efi (listed as bootable !) but it freezes when trying to boot the kernel. One of the ways to succeed booting is to use a pretty much obscure, apparently grub-based EFI loader, “ISO-2-USB EFI-Booter for Mac”, obtainable here (zip contains bootIA32.efi and bootX64.efi files), and to copy the iso and efi files onto a FAT32 USB stick as follows. It will enable loading a boot.iso file located next to it.

Using e.g. gparted, create a new msdos (mbr) partition table, with a single FAT32 partition; on it, create the files below (that is the entire USB drive file tree, yes, only these two files):

  • efi/boot/bootIA32.efi (copied from ISO-2-USB EFI-Booter for Mac)
  • efi/boot/boot.iso (copied from the 32 bits lubuntu iso file, renamed)

This should allow to boot the Ubuntu live USB (tested with lubuntu 16.04.2 32 bits) — remember to select the Macintosh keyboard variant during install. However, grub installation will fail; it wouldn’t boot anyway because the mac firmware expects the EFI partition (/dev/sda1) to be a specially “blessed” HFS+ partition (instead of modern/standard UEFI which expects a EF00 type FAT32 first partition); it also expects some hardcoded files to be present. This can unfortunately not be fixed using a chroot (i tried, but grub-install fails, complaining that efibootmgr is not present), so you must reboot, and manually boot. You should arrive at a failing grub console; follow the instructions here thorougly: http://heeris.id.au/2014/ubuntu-plus-mac-pure-efi-boot/#manual-boot

Once booted (that was probably a bit painful if you are not using a qwerty), continue following the instructions (reformatting /dev/sda1 to HFS+, installing grub and blessing the HFS+ partition) but replace these 2 commands to target 32 bit EFI (where the original guide targets 64 bits — also note that the vmlinuz file was not ending with .efi.signed, but that did work for me).

sudo apt-get install mactel-boot hfsprogs gdisk grub-efi-ia32
grub-install –target i386-efi –boot-directory=/boot –efi-directory=/boot/efi –bootloader-id=”$(lsb_release -ds)”
update-grub # not present in the original guide

Reboot, and you should finally boot straight to Ubuntu — albeit under a 32 bits OS. But that’s a miracle already.

All credit goes to:

February 17, 2017 / ftth

Changing mysql nice priority on Ubuntu 16.04

I wanted to prioritize mysqld, and the only sources i could find were all referring to the nice parameter to mysqld_safe in /etc/mysql/my.cnf or hacking the /etc/init/mysql.conf. None of these worked for Ubuntu 16.04.

Systemd is now the init daemon for Ubuntu, so that’s the one who is launching it now:

root@easycast-myserver:~/bench# service mysql status
● mysql.service - MySQL Community Server
 Loaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset: enabled)
 Drop-In: /etc/systemd/system/mysql.service.d
 └─override.conf
 Active: active (running) since Fri 2017-02-17 10:40:04 CET; 5min ago
 Process: 8665 ExecStartPost=/usr/share/mysql/mysql-systemd-start post (code=exited, status=0/SUCCESS)
 Process: 8655 ExecStartPre=/usr/share/mysql/mysql-systemd-start pre (code=exited, status=0/SUCCESS)
 Main PID: 8664 (mysqld)
 CGroup: /system.slice/mysql.service
 └─8664 /usr/sbin/mysqld

So dropping the following systemd Nice option on the /etc/systemd/system/mysql.service.d/override.conf file did work:

[Service]
Nice=-1

 

Just restart the services:

systemctl daemon-reload && service mysql restart