Category Archives: Linux

Linux related posts

Playing with ALSA loopback devices

Looping back is always an interesting thing to play with. It comes with its own set of applications, ranging from testing & debugging to replicating & integration. It has been used in various fields including hardware and software. At hardware level, we often short the Rx (receive) & Tx (transmit) lines to do the loopback in devices like serial, network, etc. In software, we do it using pipes, files, etc. However, an even more interesting crop is the concept of virtual devices doing loopback. We had talked about virtual video loopback devices in the previous article “Simultaneous Access to Single Camera“. Similarly, we can have virtual audio loopback devices.

snd-aloop is the kernel module for setting up virtual audio loopback devices.

$ sudo modprobe snd-aloop

creates two devices 0 & 1 under a new “Loopback” card for both playback & capturing, as shown below, respectively:

Playback Devices

Capture Devices

In the above images, the card 2 is the loopback card. It may vary depending on which is the next free available card number. Moreover, each of the two devices under it, has 8 subdevices, which would be accessed using the format hw:c,d,s, where c stands for card number, d for device number, and s for subdevice number, e.g. hw:2,0,0

Now in this, whatever audio is played back into hw:2,0,s could be captured from hw:2,1,s and viceversa, s ranging from 0 to 7. For example, audio played back into hw:2,0,4 could be captured from hw:2,1,4; audio played back into hw:2,1,7 could be captured from hw:2,0,7 – these are what are the loopbacks. A simple experiment could demonstrate the same.

Start recording audio from hw:2,1,4:

$ arecord -D hw:2,1,4 -f S16_LE -c 2 -r 48000 recorded.wav

Note that providing the sample format, channel count, frame rate in recording ensures that playback picks up the same settings – this is because there is no real hardware underneath it is just a virtual loopback connection.

And in parallel (from another shell) play an audio from audio.wav into hw:2,0,4:

$ aplay -D hw:2,0,4 audio.wav

And you’d find that recorded audio contains the played one – a loopback in action. You may play the recorded audio as follows:

$ aplay recorded.wav

This would play on your system’s default speaker.

Also, note that there may be problem in just playing any audio.wav file because of the mismatched audio format etc support. For that, just record a new wave file with your speech using the following command:

$ arecord -f S16_LE -c 2 -r 48000 audio.wav

This would record from your system’s default mic.

Interestingly, audio loopback could also be achieved in user space using alsaloop from alsa-utils package. Here is a demo of the same. From the output of aplay -l, hw:1,0 is the analog out (speaker). Note that hw:1,0 is same as hw:1,0,0. Find the equivalent on your system. And, now let’s loopback the virtual audio capture device hw:2,1,4 to this:

alsaloop -C hw:2,1,4 -P hw:1,0

On another shell, do the earlier playing:

$ aplay -D hw:2,0,4 audio.wav

This time you should be able to hear the audio.wav directly through system’s default speaker – again a loopback in action – rather two loopbacks in action: audio.wav -> hw:2,0,4 -> (loopback through snd-aloop driver) -> hw:2,1,4 -> (loopback through alsaloop app) -> hw:1,0 -> heard on speaker.

www.pdf24.org    Send article as PDF   

Simultaneous Access to Single Camera

There are many devices, accessing which is meaningful, only when accessed by one user at a time. Examples include a serial port, a camera, … To illustrate it further, think through as what would happen if two applications (aka users) read from the same serial port simultaneously. Some data would go to one user and some to the other, making both data meaningless. That is why, in such cases it is recommended to use only one application at a time for that particular device. A similar scenario would happen even with camera capturing. To avoid such undesired results, many a times the corresponding device framework marks the device busy if it is being used – thus ensuring that only one application is using it at a time.

In general, this mutually exclusive device usage is fine. But, what if two applications want to access the same data simultaneously. That is a problem. But even if the device is allowed to be accessed simultaneously, it does not solve the problem, as the data would get split, unlike in the storage devices like EEPROM, hard disk. One way to solve such a problem is by mirroring the data, and the mutually exclusiveness also would not be hampered. For that, we would need an intermediate application which would actually read from the device and then mirror the read data into as many virtual devices as needed. With such an arrangement, many applications can actually get the same camera feed, say for different processings.

Here is the outline of how to achieve this for a v4l2 (video for linux 2) compatible camera:

+ Download the v4l2loopback driver from https://github.com/umlaeute/v4l2loopback
+ Compile it using the corresponding kernel version, where the camera is attached. On an x86 system, typically typing make should do.
+ Load the v4l2loopback driver (v4l2loopback.ko file) w/ appropriate options. A typical way:

$ sudo insmod v4l2loopback.ko devices=2

Assuming an existing /dev/video0 for the camera, this would create two loopback video device file entries video1 & vide2. Refer to https://github.com/umlaeute/v4l2loopback/README.md for more options. Whatever is fed into these device files, comes out as their output.

+ Feeding a video test source (Ancient Doordarshan Screen) into the loopback video device files, using gst-launch application (just for testing):

$ gst-launch-1.0 videotestsrc ! tee name=t ! queue ! v4l2sink device=/dev/video1 t. ! queue ! v4l2sink device=/dev/video2

+ Open cheese or any such application to view video test screen from the video1 & video2 device files

+ Time to mirror the video0 stream to video1 & video2. Use the gst-launch application, as follows:

$ gst-launch-1.0 v4l2src device=/dev/video0 ! tee name=t ! queue ! v4l2sink device=/dev/video1 t. ! queue ! v4l2sink device=/dev/video2

+ Now, video1 & video2 are mirrors of video0. Go ahead and enjoy using video1 & video2. An example:

$ gst-launch-1.0 v4l2src device=/dev/video1 ! xvimagesink
www.pdf24.org    Send article as PDF   

Working with multiple Python environments

With the ample use of Python in applications all over, it is a common requirement that different applications need different combinations & conflicting versions of Python modules. Rather than having separate (real or virtual) machines with different installations for the different applications, it can be simply achieved using the Python’s virtualenv module. Here’s a quick summary of how to do it in Linux.

Install the python-virtualenv package, either using the package installer, or using pip of the desired python version:

$ sudo pip3 install virtualenv

Create a directory with the desired virtual environment, with or without the system wide installed packages, and the desired python version, as follows:

$ virtualenv --system-site-packages -p python3 ./venv

Or,

$ virtualenv --no-site-packages -p python3 ./venv

Here, venv (in the current directory) is the directory created with the desired virtual environment. Now, time to activate the virtual environment:

$ . ./venv/bin/activate

Now onwards, this shell’s prompt would be prefixed by (venv) indicating the virtual environment it is using. Whatever local done on this shell is specific only to this virtual environment, it being stored in this virtual environment’s directory. So, whatever pip installs (w/o sudo) are required for an application to run, can be done here independent of any external environment – even independent of the system wide installed packages, in case the virtual environment was created without them. All such installs would be local only to this environment without affecting the external environment.

Now the desired application, needing this environment, may be run in this environment.

Once done with the virtual environment, it can be deactivated as follows:

(venv) $ deactivate

It can be activated & deactivated as & when desired. Why just one? One may have any number of different virtual environments created and activated in parallel, just using separate directories and on separate shells – no need of separate machines.

www.pdf24.org    Send article as PDF   

Working with multiple Java versions

With ever growing use of Java in multi-platform applications, it is a common problem that different applications need different versions of Java. That means, we need to have multiple versions of Java installed on a system, and keep on switching between them.

But how? By adjusting the JAVA_HOME variable!!! This overall cumbersome looking task has been made quite trivial by using the Java environment manager (jenv) from Gildas Cuisinier. Overall installation & usage instructions on various platforms are given on its home page, as well as on its github repo. However, here’s a quick summary for Linux bash environment:

  • Download jenv in your desired location, say in the hidden .jenv directory under your home:
$ git clone https://github.com/jenv/jenv ~/.jenv
  • Add the jenv script in the execution path, basically add the following line in ~/.bash_profie or ~/.profile:
export PATH=${PATH}:~/.jenv/bin
  • Then, add jenv’s initialization, i.e. add the following line in ~/.bashrc:
eval "$(jenv init -)"
  • Now, logout and login back for all the settings to take effect. And after logging in, if the system has a pre-installed Java version,
$ jenv versions

should show one line with “* system (set by …”. For other Java version(s), we need to download and add.

  • In case, corresponding Java version is already downloaded & extracted, go to the next bullet. Otherwise, download the sources (.tar.gz or .bin) of various Java versions you need. Untar the .tar.gz or execute the .bin (after adding execute permissions to it). It would extract them in their corresponding folders. Shown below is one example of each.

Java Downloads

NB There are two variants of Java. One maintained by Oracle (called JDK, Java SE, …) and the other by open source community (called OpenJDK). Here are the corresponding links:

  1. JDK (Java SE, RE etc) is from Sun / Oracle (w/ Oracle Binary Code License)
  2. OpenJDK is the open source version of the above (w/ GNU General Public License version 2)
  • Now, time to add the downloaded & extracted Java version(s) using jenv add <extracted_java_folder>, e.g.
$ jenv add jdk1.6.0_45/
$ jenv add java-se-7u75-ri/

NB One may give the complete or relative path of the extracted folders. After this, the

$ jenv versions

should show something like this:

Java Versions

  • Now, switch to the desired Java version from the list using any of the following:
$ jenv local <version>

for only this current directory.

$ jenv shell <version>

for only this particular shell.

$ jenv global <version>

for globally.

$ jenv versions

should show the “*” (current setting) shifted appropriately.

www.pdf24.org    Send article as PDF   

Creating a micro SD Image

In today’s embedded world, it is very common to be creating bootable micro SDs. And then very often replicating them using raw dump of the micro SD (uSD) into an image file, say using dd command. And then creating another bootable uSD by flashing the image file into the uSD, again using dd command.

But what if one wants to create the image file by hand, rather than raw dumping from an existing uSD? Can it be done? Very well yes. And here follows the outline of the steps to follow:

First, create the image file for the appropriate size, say 1GiB:

$ dd if=/dev/zero of=file.img bs=32k count=32k

NB 1GiB has been achieved using 32 Kibi blocks of 32 KiB each, because nowadays 32KiB is quite an optimal block size in Linux.

Now, partition the image, with say 3 partitions (50MiB, 300MiB, remaining), using the GPT partition table type:

$ parted file.img mklabel gpt # Create a GPT partition table
$ parted file.img mkpart primary fat32 1MiB 51MiB # Create a partition for FAT32 fs
$ parted file.img mkpart primary 51MiB 351MiB
$ parted file.img mkpart primary 351MiB 2097151s

NB 2097151 is the last sector number in our image, but the third partition may not be able to extend till there, and the last command above may prompt for an alternative last sector. Accept it with “y”.

NB One may use any other partitioning utility like fdisk, as well.

Use the following commands to see partition details (in MiB & Byte units):

$ parted file.img unit MiB print
$ parted file.img unit B print

Here’s the expected output:

Partition Details using parted

Now, time to create filesystems on our partitions. But they are not visible as block device files. Then, how does one do it? That’s where loop device comes for rescue. Type the following commands to get the corresponding block device files:

$ sudo losetup -o 1MiB --sizelimit 50MiB -f file.img
$ sudo losetup -o 51MiB --sizelimit 300MiB -f file.img
$ sudo losetup -o 351MiB -f --sizelimit 705674752 file.img

NB 705674752 (refer to the print output above) is provided in bytes to be exact for the last partition

The three partitions would typically get available as /dev/loop0, /dev/loop1, /dev/loop2. You may verify using the following command:

$ sudo blockdev --report /dev/loop?

Here’s the expected output:

Loop (Block) Device File Details using blockdev

NB If the partition sizes are not multiple of 4096, their block size (BSZ) would reduce to 512.

Now, do all the usual partition operations. For example:

$ sudo mkfs.vfat /dev/loop0
$ sudo mkfs.ext4 /dev/loop1
$ sudo mkfs.ext4 /dev/loop2

Mount the required filesystems & copy the appropriate contents & unmount them. For example, for the first vfat filesystem:

$ sudo mount /dev/loop0 /mnt
$ sudo touch /mnt/om_arham.txt
$ sudo umount /mnt

Once done with content creation for all the filesystems, detach the loop devices:

$ sudo losetup -d /dev/loop2
$ sudo losetup -d /dev/loop1
$ sudo losetup -d /dev/loop0

All done – file.img is the desired uSD image. In fact, one may use the above learnings, to access the contents of an already existing uSD image, without raw dumping or flashing it in a uSD. Go ahead & try it out. And finally, why only an image of a uSD, you may create &/or decode any damn storage image, using just what has been learnt.

www.pdf24.org    Send article as PDF