jack_capture not working in a bash script but working outside of it

Support & discussion regarding DAWs and MIDI sequencers.

Moderators: MattKingUSA, khz

Post Reply
User avatar
unfa
Established Member
Posts: 129
Joined: Tue May 17, 2011 10:43 am
Location: Warsaw, Poland
Has thanked: 1 time
Been thanked: 19 times
Contact:

jack_capture not working in a bash script but working outside of it

Post by unfa »

Hey!

I'm working on a way to capture multichannel audio with OBS video capture, working around some inherent problems (I need PCM 32-bit float, not AAC audio). I've created a nice bash script that monitors changes in a directory and starts recording when a new file is created there. Then monitors that files's size and if it doesn't change for 1 second, it stops the recording.

Everything seems like working like a charm, except fro the most important part. jack_capture quits every time when the script runs it, immediatly after or a second later. It managed to capture a tiny amount of audio (18 kB, 6 kB) but then immediately quits.

Looks like something is calling it to stop, but I've checked and I don't see anything that could do it in my script.

Here's the full script:

Code: Select all

#!/bin/bash

#define the root dir of the project
BASE_DIR="/unfa/Projects/YouTube/Studio"

audio_capture(){
    cd "$BASE_DIR/Capture" # go to the Capture directory
    
    while [ True ]; do
        # wait until a new mkv file is created in the Capture directory
        echo "waiting for capture to start"
        
        watch -n0,1 -g "ls -t *.mkv | head -n 1"
        
        # once it is, start recording to a WAV file with the same name as the newest mkv file
        #channels:
        # 1 - raw mic input
        # 2 - processed mic input
        # 3,4 - raw audio 
        # 5,6 - master, before the limiter
        
        echo "starting capture"
        
        jack_capture -V -c 6 -b 32 -f wav -p "system:capture_1" -p "Non-Mixer/Vox:out-1" -p "Non-Mixer/Audio:out-*" -p "Non-Mixer/MASTER:out-*" -fn "$(ls -t *.mkv | head -n 1 | cut -d'.' -f-1).wav" &
                
        pid_cap=$! # store the capture process PID
        
        echo "capture PID is $pid_cap"
        
        A="10000" # initilize with 0
        
        while [ True ]; do
            echo "checking if capture has stopped"
            B=$A
            sleep 5s # wait - this will let the process skip smome hard disk write hiccups and also give us some backup post-roll
            A=$(du "$(ls -t *.mkv | head -n 1)" | cut -f 1) # get teh size in bytes of the newest MKV file in dir
            if [ $A -eq $B ]; then #if the sizedidn't change recently
                echo "stopping capture"
                kill $pid_cap
                break
            fi;
        done
    done
}

# find out the location of the webcam by it's name
webcam="/dev/"$(file /dev/v4l/by-id/*C920* | cut -d ' ' -f 5 | cut -c 7-)

echo "Logitech C920 is $webcam"

#recall webcam settings
uvcdynctrl -d $webcam -L "$BASE_DIR/Configuration/uvdynctrl/C920.uvcdynctrl"

# run Non Mixer for audio controls
non-mixer "$BASE_DIR/Configuration/Non Mixer/Capture Mixer 01" &

pid_non=$!

# run Carla for audio processing
carla "$BASE_DIR/Configuration/Carla/Carla 01.carxp" &

pid_carla=$!

# run Open Broadcasting Software
obs &

pid_obs=$!

echo "OBS PID: $pid_obs"

# run guvcview in control panel mode
guvcview -z -d $webcam &

pid_guvc=$!

sleep 3s # wait until all windows are already created

# get windows IDs

wid_obs=$(xdotool search --onlyvisible --name "OBS")
wid_non=$(xdotool search --onlyvisible --name "Non Mixer")
wid_guvc=$(xdotool search --onlyvisible --name "Guvcview")
wid_carla=$(xdotool search --onlyvisible --name "Carla")


# set window states

wmctrl -r "OBS" -b remove,maximized_vert
wmctrl -r "OBS" -b add,maximized_horz
wmctrl -r "Non Mixer" -b add,below
wmctrl -r "Guvcview" -b add,below

# rearange windows

xdotool windowmove $wid_obs  0 0;       xdotool windowsize $wid_obs  1920 650

xdotool windowmove $wid_non  0 750;     xdotool windowsize $wid_non  800 300
xdotool windowmove $wid_non  0 750

xdotool windowmove $wid_guvc 807 465;   xdotool windowsize $wid_guvc 800 600
xdotool windowmove $wid_guvc 807 465


xdotool windowminimize $wid_carla # minimize Carla window
xdotool windowfocus $wid_obs # focus OBS window


# capture audio
audio_capture &

pid_audio=$!

wait $pid_obs

# Once OBS exits, all other will be killed

kill $pid_audio
kill $pid_non
kill $pid_guvc
kill $pid_carla
Here's the audio related part that's failing:

Code: Select all

audio_capture(){
    cd "$BASE_DIR/Capture" # go to the Capture directory
    
    while [ True ]; do
        # wait until a new mkv file is created in the Capture directory
        echo "waiting for capture to start"
        
        watch -n0,1 -g "ls -t *.mkv | head -n 1"
        
        # once it is, start recording to a WAV file with the same name as the newest mkv file
        #channels:
        # 1 - raw mic input
        # 2 - processed mic input
        # 3,4 - raw audio 
        # 5,6 - master, before the limiter
        
        echo "starting capture"
        
        jack_capture -V -c 6 -b 32 -f wav -p "system:capture_1" -p "Non-Mixer/Vox:out-1" -p "Non-Mixer/Audio:out-*" -p "Non-Mixer/MASTER:out-*" -fn "$(ls -t *.mkv | head -n 1 | cut -d'.' -f-1).wav" &
                
        pid_cap=$! # store the capture process PID
        
        echo "capture PID is $pid_cap"
        
        A="10000" # initilize with 0
        
        while [ True ]; do
            echo "checking if capture has stopped"
            B=$A
            sleep 5s # wait - this will let the process skip soem hard disk write hiccups and also give us some backup post-roll
            A=$(du "$(ls -t *.mkv | head -n 1)" | cut -f 1) # get teh size in bytes of the newest MKV file in dir
            if [ $A -eq $B ]; then #if the sizedidn't change recently
                echo "stopping capture"
                kill $pid_cap
                break
            fi;
        done
    done
}
Specifically this line:

Code: Select all

jack_capture -V -c 6 -b 32 -f wav -p "system:capture_1" -p "Non-Mixer/Vox:out-1" -p "Non-Mixer/Audio:out-*" -p "Non-Mixer/MASTER:out-*" -fn "$(ls -t *.mkv | head -n 1 | cut -d'.' -f-1).wav" &
The strange thing is it works fine if I run alone in a terminal. But it doesn't if it's run inside the script.
It exits without reporting any specific errors right after writing a header to the WAV file and behaves like someone pressed Enter or Ctrl+C in the terminal. It once managed to capture a few seconds before closing, but that's it.

I wondered if this isn't somehow OBS console output feeding to that shell (crazy idea, but that's something), so I tried redirecting /dev/null to jack_capture stdin to avoid something like this, but still no go. Verbose output makes jack_capture say this:

Code: Select all

    main() find default file format
    main() find filename
    main() init jack 1
    buf_size_in_bytes: 6152
    main() init buffers
    bufinit1. sizeof(long): 8, sizeof(float): 4, sizeof(double):8, sizeof(int):4, sizeof(void*):8
    >>> Warning. Could not set higher priority for a SCHED_FIFO process using setpriority().
    main() Open soundfile and setup disk callback.
    main() Init waiting.
    main() Init jack 2.
    main() Everything initialized.  8
    main() Start meterbridge.
    main() Print some info.  42
    >>> Recording to "2017-06-15 21-28-37.wav". Press <Return> or <Ctrl-C> to stop.
    main() Start helper thread.  7
    main() Wait.
    main() Stop recording and clean up.  52
    connection thread finished
    disk thread finished  7
      |"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""|
    00:|-  |  9:02  00:|  ||
    01:|  |  7
    02:|  |
    03:|  |
    04:|  |
    05:|  |
    Buffer: 4.01s./4.01s  Time: 0.00m.  DHP: [ ]  Overruns: 0  Xruns: 0
    Finished.
Running a simple

Code: Select all

jack_capture
command with no parameters yields the same result.

I wonder why this isn't working.

PS: I've now run it in it's own terminal by accident adding the "&" symbol from the script and it also failed. Could it be that jack_captured can't stand being a background process?
User avatar
autostatic
Established Member
Posts: 1994
Joined: Wed Dec 09, 2009 5:26 pm
Location: Beverwijk, The Netherlands
Has thanked: 32 times
Been thanked: 104 times
Contact:

Re: jack_capture not working in a bash script but working outside of it

Post by autostatic »

Capturing stops after having captured 10000 bytes. You should rewrite the routine where you check if the latest MKV file has changed recently.
tramp
Established Member
Posts: 2335
Joined: Mon Jul 01, 2013 8:13 am
Has thanked: 9 times
Been thanked: 454 times

Re: jack_capture not working in a bash script but working outside of it

Post by tramp »

You may try screen, so replace
unfa wrote:jack_capture -V -c 6 -b 32 -f wav -p "system:capture_1" -p "Non-Mixer/Vox:out-1" -p "Non-Mixer/Audio:out-*" -p "Non-Mixer/MASTER:out-*" -fn "$(ls -t *.mkv | head -n 1 | cut -d'.' -f-1).wav" &
with

Code: Select all

screen jack_capture -V -c 6 -b 32 -f wav -p "system:capture_1" -p "Non-Mixer/Vox:out-1" -p "Non-Mixer/Audio:out-*" -p "Non-Mixer/MASTER:out-*" -fn "$(ls -t *.mkv | head -n 1 | cut -d'.' -f-1).wav"
to let jack_capture run in it's own sub-shell instead as background process.
On the road again.
Post Reply