Using same soundcard among users with PulseAudio not in system mode

Sound on GNU/Linux never have been convenient. Right now, de facto standard is PulseAudio: yeah, made by the same people that does this nightmare of systemd. When it works it is better than just ALSA  (Advanced Linux Sound Architecture). When it doesn’t, you’re in for a headache.

Anyway, I had this situation where I wanted user whatever to be able to use the soundcard. But the soundcard was blocked and reserved by PulseAudio started by my regular user account.

First option is to make PulseAudio work as a system daemon. UNIX-style option. Quite obviously, that would be too easy to implement for these systemd people. So they implemented the option altogether advising not to use it. I did not care about the advice, though, so I tried. And then I understood why, while advising not to use it, they said they would not be accountable for problems using it. Because it is utter trash, unreliable, giving out error endless messages and, in the end, not working at all.

 So the system mode is a no-go, in the short run and definitely not in the long run either.

Alternate option is to open PulseAudio through the loopback network device. To do so, in /etc/pulse/default.pa add the TCP module with 127.0.0.1:

load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1

Obviously, by default tcpwrapper will refuse access, so you have also to add the relevant counterpart in /etc/hosts.allow :

pulseaudio-native: 127.0.0.1

From now on, after restarting PulseAudio, you should be able to access it through any user (in audio group).

Update: some comments on reddit made me think there has been a misunderstanding on the scope of this post. It is not to describe inner workings of audio on common GNU/Linux systems with PulseAudio. The following does and almost perfectly explain why I did not bother get specific on the topic :

1000px-Pulseaudio-diagram.svg.png

Creating primitive subtitle (SubRip/.srt) file from scratch

I had a video I wanted to add a few subtitles lines here and there, without much effort. I ran:

$ apt-cache search subtitle editor
aegisub - Advanced subtitle editor
aegisub-l10n - Aegisub language packages
gaupol - subtitle editor for text-based subtitle files
libsubtitleeditor-dev - subtitleeditor lib - development files
libsubtitleeditor0 - subtitleeditor lib - runtime files
subtitleeditor - Graphical subtitle editor with sound waves representation
python-aeidon - reading, writing and manipulating text-based subtitle files
gnome-subtitles - Subtitle editor for the GNOME Desktop environment

and installed a few of them.

I was quite a disappointing experience. These softwares are more or less working but none was easy and fast enough to use for me not to prefer just using mpv and emacs, viewing with mpv and typing relevant lines in a text file with  timestamps.

Some of these softwares looked almost ok but adding new lines that was generally inconvenient (not able to insert at the exact place the playthrough is paused, or supposed to be able to but simple not working).

So, yeah, I got the simple way and built a file like :

1:01:01 adjkajdalm kadmùlajpod jaaaaaaaa aaaaaaaa aaaaaaaaaaaaaaaaaaa aaaaaaaaaaaa
11:01:01 adjkajdalm kadmùlajp odjaaaaaaaaa aaaaaaaaaaaaaaaaaa
111:01:01 adjkajda

And wrote a fast primitive script as follows:

#!/usr/bin/perl
use strict;
my $file = "THIS";
open(IN, "< $file.txt"); # input
open(OUT, "> $file.srt");
my $count = 0;
while (<IN>) {
 next if /^\s$/; #skip empty
 $count++;
 print OUT "$count\n";
 if (/^(\d{1,3})\:(\d{2}):(\d{2})\s/) { # extract time HH:MM:SS
 my ($h, $m, $s) = ($1, $2, $3);
 s/^$h:$m:$s\s//g; # remove the time from the line
 my $duration = 3; # 3 sec average duration 
 $duration = 5 if length($_) > 34; # 5 for almost two lines
 $duration = 2 if length($_) < 15; # 2 when very short
 
 my ($hplus, $mplus) = ($h, $m);
 my $splus = ($s + $duration);
 if ($splus > 60) { $mplus = ($m + 1); $splus = ($splus - 60); }
 if ($mplus > 60) { $hplus = ($h + 1); $mplus = ($mplus - 60); }
 
 print OUT sprintf("%02d:%02d:%02d,000 --> %02d:%02d:%02d,000",
 $h, $m, $s,
 $hplus, $mplus, $splus)."\n";
 } else {
 print "$count TIME ?\n"; 
 }
 print OUT $_;
 print OUT "\n";
}
close(IN);
close(OUT);
#EOF

It requires $file to be set accordingly to the name given to the input text file, obviously.

When satisfied with the written .srt, it’s convenient to embed it in the end file:

ffmpeg -i infile.mp4 -f srt -i infile.srt -c:v copy -c:a copy -c:s mov_text outfile.mp4

 

Creating an mp4 with black screen and silent audio (with ffmpeg)

Assuming you have a  black PNG image named blck.png, you can make it a mp4 video:

ffmpeg -loop 1 -i blck.png -t 900 -r 1 -c:v libx264 blck.mp4

And if you want to concatenate it with other mp4 (see previous post), it also needs to include a sound track. So, assuming your main files are in 48000hz (otherwise adjust), you can add it with the command:

ffmpeg -f lavfi -i anullsrc=r=48000 -i blck.mp4 -to 00:15:00 -c:v copy -c:a aac -strict experimental blck-snd.mp4

(note : -to needs to be set to the expected time, option -shortest fails)

 

 

Concatenating mp4 videos (with ffmpeg)

mp4 cannot be concatenated directly. But fmpeg (and so avconv I guess) can by the way of intermediary mpeg transport streams.

Here’s a dirty bash script that does that assuming you want to concat files named like MYFILE-1.mp4 MYFILE-2.mp4. Then you would just execute the script with MYFILE- as argument.

#!/bin/bash
echo $1
[ ! -e "$1"1.*4 ] && echo "nothing for $1""1.mp4" && exit

list=""
for i in `seq 1 20`; do
[ ! -e "$1"$i.*4 ] && continue
echo "$1$i.mp4 exists, creating $1$i.ts"
ffmpeg -i "$1"$i.*4 -c copy -bsf:v h264_mp4toannexb -f mpegts "$1"$i.ts
list="$list|$1"$i".ts"
done

echo "##########################################"
list=`echo "$list" | cut -c 2-`
echo "concat of $list"
ffmpeg -i "concat:$list" -c copy -bsf:a aac_adtstoasc "$1""F.mp4"
rm -f "$1"*.ts

# let user manually remove source files after checks
# EOF

Getting correct delays for subtitles

In 2010, I posted a couple of articles regarding videos and subtitles. Today I submitted a feature request to smplayer so they include within the player the ability to save in the subtitle file the custom delay we may have selected.

Basically, it would implies for smplayer to simply do something like with libsubtitles-perl‘s subs:

subs -i -b 00:00:16.5 Boardwalk.Empire.S01E10.480p.HDTV_en.srt

I sure hope they’ll implement that soon. Should not be too complicated while at the same time very convenient as, most of the time, issues with downloaded subtitles are delay-related.

Accessing video/audio from a computer with a Freebox (using UPnP)

Nowadays, you would think having a network device like a TV box accessing data from your unix-based system easy going. I mean, we have NFS, Samba all-right, how hard could that be to devise an interface to access at least one of the many network shares, provided a user/password or based on it’s IP?

But no, it won’t work that way. It’s supposedly too complex, so instead, people promotes zeroconf and such, stuff supposed to work out-of-the-box that actually may not work at all. For instance, to access movies/music from your computer with your Freebox HD (TV box) v5, and I assume it’s the same with many similar boxes from others ISP, you can forget about using NFS/SMB/http or whatever protocol you already had working or think easy to put in motion. No, you’ll have to use UPnP, standing for Universal Plug and Play, words that truly often refers to Plug and Pray instead.

From the computer…

So, let’s go getting our hands dirty. The setup I’m working with is quite simple: a Freebox HD v5, a single computer with a single user having some videos, some with subtitles (mostly .srt), and audio files. It’s basic but it took me a while to figure it out.

I did test plenty of UPnP servers. I tried Mediatomb but it did not work – plus the gothic interface seemed weird. I tried XBMC and it worked nicely but only to show empty folders, and no obvious way to have it up without the CPU consuming interface. Then I installed MythTV and I did not even understood how it is supposed to work in regard of UPnP.

So I tried minidlna, the lightweight one I avoided from the start because it’s not known to properly support subtitles files. And, tada!, it actually works almost out-of-the-box. Yeah, almost. That’s the funny thing, even if you claim to aim zeroconf, when it comes to share files, at some point you’re still in need to list what you actually wanna share. Whatever. So I did apt-got minidlna. Then I edited /etc/default/minidlna:

START_DAEMON="yes"
USER="thisguy"
GROUP="thisguy"

As there’s only one legit user on this box, I wanted the daemon to be able to access his files with no specific consideration for privileges/ownership. I implied doing then:

chown thisguy.thisguy /var/lib/minidlna -Rv

Then I modified /etc/minidlna.conf as follows:

media_dir=V,/home/thisguy/Films
media_dir=A,/home/thisguy/Musique
media_dir=P,/home/thisguy/Photos

log_level=info
network_interface=eth0
friendly_name=thisserver
inotify=yes

… to the box

I restarted the daemon (and made sure it’s included in /etc/rc2.d). And that’s all (I modified also the firewall setup but I’m not sure that’s relevant considering that UPnP implies that it advertises itself to other devices when it’s up and not the other way around – so firewall is an issue only if you have one that blocks connections from the inside to the outside).

By that’s all, I meant: it was enough to get access to movies on the Freebox HD for the first time; but not with the subtitles.

I googled around: the minidlna version I had was supposed to properly give access to .srt along with videos. The Freebox HD itself supports .srt files with the same name of the video, when you access video over an USB device. But apparently plenty of implementations of UPnP have no consideration for subtitle files and the Freebox’s one is probably one such. So having separate .srt or .sub or whatever is a no-go.

Then, I gave a try to Matroska files (.mkv) despite the fact that I always had bad experience with it. Most notably, I usually implies videos costing tons of CPU time to decode and render and videos players usually fail to properly keep video in sync with audio – yeah, that’s really nasty. But Matroska allows to embed subtitles in the file without touching the video stream, which is neat. So I did that. Long story short, Matroska files, 9 times out of 10, freeze the Freebox HD: and I’m talking about Matroska files that are not bigger than the original .avi that run well on the very same Freebox, and I’m talking about Matroska files that run well on the computer with VLC or mplayer. So that’s a no-go too.

So I ended with the worse solution: altering original files, with mencoder to incrust subtitles within. Yeah, it’s kind of definitive and if you don’t want to spend hours of CPU time to do it, it implies quality loss. But, at least, it works. So here it goes, I wrote the following script to ease the process, assuming that video files along with .srt where originally on an USB device called HERMES and then copied to thisguys home:

#!/bin/bash

DEST=/home/thisguy/Films
ORIG=/media/HERMES

# go thru the list of videos
find $ORIG -name "*.avi" -or -name "*.mpg" -or -name "*.mp4" |
while read video; do
  # find out basename
  basename=${video%.*}
  format=${video##*.}
  endname=`basename "$basename"`-WS.$format

  echo $endname

  # use french subtitles in priority over english
  subtitle=0
  if [ -r "$basename"_en.srt ]; then subtitle="$basename"_en.srt; fi
  if [ -r "$basename"_fr.srt ]; then subtitle="$basename"_fr.srt; fi
  if [ -r "$basename".srt ]; then subtitle="$basename".srt; fi

  # no valid subtitle found at this point? skip the video
  if [ ! -r "$subtitle" ]; then continue; fi

  # now create to relevant directory if missing
  enddir=`dirname "$basename" | sed "s@${ORIG}@${DEST}@g;"`
  if [ ! -d "$enddir" ]; then mkdir -pv "$enddir"; fi

  # proceed only if the file is missing
  if [ -r "$enddir/$endname" ]; then continue; fi

  # if we reach this, go for it
  mencoder "$video" -subpos 92 -sub "$subtitle" -o "$enddir/$endname" -oac copy -ovc lavc

done
# EOF

Yeah. Plug and play my ass.

Switching from one to another soundcard using PulseAudio in KDE

Ever found yourself in the situation where you have some kind of home cinema connected to your mainboard soundcard and headphones connected through their specific USB soundcard? It gets tremendously painy to handle if you regularly want to switch from the home cinema to the headphones without really unswitching anything.

I wrote a very basic script that, from two active soundcards, it keeps only one active and switch from one to another each time it is called. Note the script will not handle more than two cards. If you have more, you’ll have to hardcode them with the hash $cards_to_ignore.

Obviously, you can easily add keyboard shorcuts adding a new entry with kmenuedit.