Go Back   Home > Forums > >
Home Forums Rules Articles diyAudio Store Blogs Gallery Wiki Register Donations FAQ Calendar Search Today's Posts Mark Forums Read

PC Based Computer music servers, crossovers, and equalization

A bash-script-based streaming audio system client controller for gstreamer
A bash-script-based streaming audio system client controller for gstreamer
Please consider donating to help us continue to serve you.

Ads on/off / Custom Title / More PMs / More album space / Advanced printing & mass image saving
Reply
 
Thread Tools Search this Thread
Old 12th July 2016, 05:36 PM   #21
CharlieLaub is offline CharlieLaub  United States
diyAudio Member
 
Join Date: Mar 2007
Location: California
Quote:
Originally Posted by 3ll3d00d View Post
wouldn't you want those env vars to be managed on the client as they might be client specific values?
Not sure what you mean by "managed on the client". In the example I gave:
Code:
ssh user@host ARG1="value1" ARG2="value2" /bin/bash << ENDSSH
  # commands to run on remote host
  # ARG1 and ARG2 are now environmental variables within the ssh session on the client
  lines of code that are run on the client go here...
ENDSSH
ARG1 and ARG2 become environmental variables on the client within and for the duration of that ssh session only.
__________________
Visit my Audio Web Page <<--CLICK TO LEARN MORE-->> Get my LADSPA plugins
  Reply With Quote
Old 12th July 2016, 09:49 PM   #22
CharlieLaub is offline CharlieLaub  United States
diyAudio Member
 
Join Date: Mar 2007
Location: California
At this time everything seems to be working to the point that I can start explaining more about the system setup.

Each system that the user would like to control gets its own directory. There is a configuration file in the directory where the user describes the connections to the system, etc. Here is the prototype for this configuration file that I am currently using to test the code:
Code:
AUDIO_SOURCE=alsasrc device='dsnoop:0,1' #gstreamer source string
AUDIO_SOURCE_CAPS=audio/x-raw,format=S16LE,rate=48000,channels=2
PORT=1234             #port on clients where RTP stream will be directed 
STREAM_BITS=16        #sets bit depth of stream and playback
STREAM_RATE=48000     #sets sample rate of stream and playback
VOLUME_TRIM_DB=0      #used to adjust system volume in 1dB steps
#describe first client in the system
CLIENT=192.168.10.111, mono  #one line per client indicating IP and channel
ACCESS=ssh pi@192.168.10.111 USER="pi" LADSPA_PATH="/usr/local/lib/ladspa:/usr/lib/ladspa" TERM="xterm" COLUMNS="141"
ALSA_SINK=hw:1,0
LATENCY=500
PATH=gstreamer
OTHER_COMMAND_ON_LAUNCH=~/Laub-Woofer/junk.sh
#describe next client in the system
CLIENT=192.168.10.112, stereo
ACCESS=ssh pi@192.168.10.112
ALSA_SINK=hw:1,0
LATENCY=500
PATH=gstreamer
Recall that this is a system that uses gstreamer to stream audio over your LAN (a WiFi or wired connection) from a main "server" computer where your player resides to one or more "client" computers. Each system can be comprised of one or more clients. The input signal is assumed to be stereo audio. I make use of ALSA and its "loopback" feature to facilitate input on the "server" and output on the "client". Currently the system assumes that the input and stream formats do not change and are known in advance, meaning that bit-perfect playback is not possible except for audio that is already in the same format as the input and stream.

The meaning and use of each line is as follows:
  • AUDIO_SOURCE - this defines where to get the audio input. The string is input in gstreamer format exactly as it will be used in the gstreamer pipeline. Here I use the "dsnoop" ALSA device, which allows multiple simultaneous connections to a device.
  • AUDIO_SOURCE_CAPS - "caps" is short of capabilities and defines the sample rate, bit depth, etc. of the input.
  • PORT - the stream is sent to a port at the client's IP address. This defines the destination port for all clients in this system. Typically port 1234 is used, commonly used for UDP data.
  • STREAM_BITS and STREAM_RATE - this sets the bit depth and sample rate for the audio stream. Bit depths can be one of 16 or 24 bits. This is because RTP is used to send time-synchronized data packets and only these bit depths can be accommodated by RTP. The stream rate can be any integer rate but since there is no resampling in the client pipeline you need to choose a rate supported by your client's output device (e.g. DAC) if you want it to function.
  • VOLUME_TRIM_DB - I included this feature to allow the volume of an entire system to be adjusted, e.g. because for the same player volume setting it is too loud or too soft compared to other systems, etc. The current range is +6dB to -30dB in 1dB steps.
  • CLIENT - the CLIENT keyword begins the description of client related parameters. Prior to the first client keyword all the parameters related to the source computer. On the client line the IP address of the client is provided (assumed to be static) and, separated by a comma, the channel assignment for this client is provided. Channel can be one of stereo, left, right, or mono (stereo mixed down to one channel).
  • ACCESS - this string defines how to connect to the client. I am assuming an ssh connection. I have tested the system both with ssh using pre-generated shared public keys and the sshpass program. Sshpass is very simple to use but exposes the password because it must be stated in the access string in plain text. The access text also includes any environmental variables that need to be set in the ssh session. I have provided a few that helped my client application (see below) launch properly.
  • ALSA_SINK - since we know the input format and the audio stream format the client's gstreamer pipeline can mostly be autogenerated except for the output. Here the user is providing the ALSA device to which the decoded audio stream should be sent.
  • LATENCY - on each client the incoming RTP data must be buffered. The buffer size (in milliseconds) of the client can be independently set of other clients. This can be adjusted to trim out delay between clients to balance out their own inherent latencies. Here 500 msec is very generous because I am using a WiFi connection. This can be less than 100 msec over WiFi or perhaps 20msec or less if streaming over a wired LAN.
  • PATH - when logging into each client via ssh to launch the gstreamer pipeline, the user can cause the code to first cd to this directory. The path can be absolute or relative to the login directory. At this time, the directory must already exist.
  • OTHER_COMMAND_ON_LAUNCH - the user can supply a list of comma separated commands that will be run when the gstreamer pipeline is launched when streaming to the client starts up. For example, in my system I process the audio on each client using ecasound. Ecasound implements a crossover in the client. It's then directed by ecasound to DACs connected to the client. I use this field to specify a shell script that contains the ecasound command string.
  • OTHER_COMMAND_ON_TERMINATE - (not shown) like OTHER_COMMAND_ON_LAUNCH, this allows the user to specify commands that will be run on the client but these are run when the gstreamer pipeline is terminated when the system is "turned off" by the user from the server side. Commands that might be incorporated into OTHER_COMMAND_ON_LAUNCH and OTHER_COMMAND_ON_TERMINATE include setting the client's GPIO pins to a high or low state. These can be connected to relays that might turn on/off amplifiers, mute loudspeaker relays, illuminate an LED, or whatever you might find useful.

With the above command set, the user will be able to turn a system on or off remotely, that is through an easy to use text-based command interface that I will describe later. As part of turn on audio is streamed to a set of clients but the exact syntax of how this is done via gstreamer is hidden from the user. Because each system can be comprised of any number of clients, this is a very flexible setup in terms of what kind of systems can be controlled.

I will post more after some further development and coding.
__________________
Visit my Audio Web Page <<--CLICK TO LEARN MORE-->> Get my LADSPA plugins

Last edited by CharlieLaub; 12th July 2016 at 09:55 PM.
  Reply With Quote
Old 12th July 2016, 10:14 PM   #23
3ll3d00d is offline 3ll3d00d  United Kingdom
diyAudio Member
 
3ll3d00d's Avatar
 
Join Date: Jan 2014
Quote:
Originally Posted by CharlieLaub View Post
Not sure what you mean by "managed on the client". In the example I gave:
Code:
ssh user@host ARG1="value1" ARG2="value2" /bin/bash << ENDSSH
  # commands to run on remote host
  # ARG1 and ARG2 are now environmental variables within the ssh session on the client
  lines of code that are run on the client go here...
ENDSSH
ARG1 and ARG2 become environmental variables on the client within and for the duration of that ssh session only.
As in your control script could just SSH over to the client, source a config file from some conventional location and then execute. Arguably this simplifies the control script as no longer has to worry about parsing parameters/vars.
  Reply With Quote
Old 12th July 2016, 10:25 PM   #24
CharlieLaub is offline CharlieLaub  United States
diyAudio Member
 
Join Date: Mar 2007
Location: California
Quote:
Originally Posted by 3ll3d00d View Post
As in your control script could just SSH over to the client, source a config file from some conventional location and then execute. Arguably this simplifies the control script as no longer has to worry about parsing parameters/vars.
Yeah, I tried to source .bashrc from the home directory on the client in a couple of different ways but could not get that to work. I don't think that more than a couple environmental parameters need to be passed so my way is lightweight enough not to be a burden. I'll stick with my current method for now, although I may revisit the issue. If you can point me to some concrete examples that would be helpful.
__________________
Visit my Audio Web Page <<--CLICK TO LEARN MORE-->> Get my LADSPA plugins
  Reply With Quote
Old 14th July 2016, 03:16 PM   #25
3ll3d00d is offline 3ll3d00d  United Kingdom
diyAudio Member
 
3ll3d00d's Avatar
 
Join Date: Jan 2014
Quote:
Originally Posted by CharlieLaub View Post
Yeah, I tried to source .bashrc from the home directory on the client in a couple of different ways but could not get that to work. I don't think that more than a couple environmental parameters need to be passed so my way is lightweight enough not to be a burden. I'll stick with my current method for now, although I may revisit the issue. If you can point me to some concrete examples that would be helpful.
ssh'ing into a box results in a non interactive shell so that won't typically load .bashrc, an answer like Why does an SSH remote command get fewer environment variables then when run manually? - Stack Overflow gives a decent summary of the situation and some of the answers give some typical solutions.

Personally I tend to try to avoid this sort of issue with 2 complementary approaches.

Firstly I tend to refactor my profiles (.bash_profile, .bashrc, /etc/profile etc, the precise files in play might vary with distro) so that both the .bashrc and the .bash_profile source a common file that define the important env vars.

For example, a simple setup is;

.bash_profile
Code:
. ~/.bash_common
.bashrc
Code:
. ~/.bash_common
.bash_common
Code:
# machine agnostic config
. ~/.core_envrc

# machine specific config if present
[ -e ~/.bash_machine ] && . ~/.bash_machine
Generally this is backed by a master config tree that is then sync'ed across a set of machines which means you could always source those locally before you execute a command on that particular remote machine.

Secondly you can write script that can load it's own env, for example you might include a snippet like in a script to ensure it always has that same set of environment variables. IME this is generally a problem with cron which may get an even more cutdown env

Code:
[[ -z "${SOME_VAR_NAME}" && -f "${HOME}/.bash_common" ]] && . "${HOME}/.bash_common"
  Reply With Quote
Old 14th July 2016, 03:42 PM   #26
CharlieLaub is offline CharlieLaub  United States
diyAudio Member
 
Join Date: Mar 2007
Location: California
Quote:
Originally Posted by 3ll3d00d View Post
ssh'ing into a box results in a non interactive shell so that won't typically load .bashrc, an answer like Why does an SSH remote command get fewer environment variables then when run manually? - Stack Overflow gives a decent summary of the situation and some of the answers give some typical solutions.

Personally I tend to try to avoid this sort of issue with 2 complementary approaches.

Firstly I tend to refactor my profiles (.bash_profile, .bashrc, /etc/profile etc, the precise files in play might vary with distro) so that both the .bashrc and the .bash_profile source a common file that define the important env vars.

For example, a simple setup is;

.bash_profile
Code:
. ~/.bash_common
.bashrc
Code:
. ~/.bash_common
.bash_common
Code:
# machine agnostic config
. ~/.core_envrc

# machine specific config if present
[ -e ~/.bash_machine ] && . ~/.bash_machine
Generally this is backed by a master config tree that is then sync'ed across a set of machines which means you could always source those locally before you execute a command on that particular remote machine.

Secondly you can write script that can load it's own env, for example you might include a snippet like in a script to ensure it always has that same set of environment variables. IME this is generally a problem with cron which may get an even more cutdown env

Code:
[[ -z "${SOME_VAR_NAME}" && -f "${HOME}/.bash_common" ]] && . "${HOME}/.bash_common"
I'm trying to develop a self-contained application. I do not want a user to have to go and edit various files on each client for it to work. An approach like your "refactored" files that refer to bashrc_common that must be implemented on or distributed to every client is not something I fine attractive and would just ask the user to do more setup work, requires them to customize their machines, etc. Also, I believe that your last bit of code is sourcing the bash_common file that you create - sourcing doesn't seem to work inside my here-document.

The way I do it now allows env vars for clients to be set as needed from the server side. This also localizes the user interaction to the configuration file on the server. The ssh session gets a subset of the usual env vars by default and the user only needs to supply a couple of additional ones as part of the ssh command string.

I appreciate your advice but I do not see how your approach is reducing barriers for the user or is in any way more powerful or capable than what I am doing.
__________________
Visit my Audio Web Page <<--CLICK TO LEARN MORE-->> Get my LADSPA plugins
  Reply With Quote
Old 14th July 2016, 04:45 PM   #27
3ll3d00d is offline 3ll3d00d  United Kingdom
diyAudio Member
 
3ll3d00d's Avatar
 
Join Date: Jan 2014
Quote:
Originally Posted by CharlieLaub View Post
Also, I believe that your last bit of code is sourcing the bash_common file that you create - sourcing doesn't seem to work inside my here-document.
you can source files within a here doc used with ssh, hard to say why it's not working for you though.

Quote:
Originally Posted by CharlieLaub View Post
The way I do it now allows env vars for clients to be set as needed from the server side. This also localizes the user interaction to the configuration file on the server. The ssh session gets a subset of the usual env vars by default and the user only needs to supply a couple of additional ones as part of the ssh command string.

I appreciate your advice but I do not see how your approach is reducing barriers for the user or is in any way more powerful or capable than what I am doing.
IME approaches become useful as the number of vars goes up and/or when the values you want to pass around don't play nice with bash (e.g. when special characters are involved and you have to be able to escape them properly, the rules for which can get quite messy). If you don't have that sort of complexity to deal with then all you have, with this sort of solution, is more invasive/complex config to manage with no meaningful benefit (and hence not worth the effort).
  Reply With Quote
Old 14th July 2016, 05:53 PM   #28
CharlieLaub is offline CharlieLaub  United States
diyAudio Member
 
Join Date: Mar 2007
Location: California
Quote:
Originally Posted by 3ll3d00d View Post
you can source files within a here doc used with ssh, hard to say why it's not working for you though.


IME approaches become useful as the number of vars goes up and/or when the values you want to pass around don't play nice with bash (e.g. when special characters are involved and you have to be able to escape them properly, the rules for which can get quite messy). If you don't have that sort of complexity to deal with then all you have, with this sort of solution, is more invasive/complex config to manage with no meaningful benefit (and hence not worth the effort).
I agree with you. I don't expect that there will be anything more than plain text as the env var content. I also only expect the user to set a couple, since most are provided in the (non interactive) set of ssh env vars.

It would be nice to source the bashrc file. I will have to go back and take a look at this again. I believe I simple put
Code:
source ~/.bashrc
. It's possible that the home directory was not set, meaning the "~" would have failed. Not sure, since by that time I had figured out what the problem was (some env vars not set) and was just looking for some way to fix that.

If you think that sourcing bashrc in the here-document should work, I will just plug away at that and see if I can get it to work. I'm just hacking here, in no shape or form am I an accomplished bash programmer! In fact once this is working I would love for someone of that skill level to take a look at it for any massive security holes, or ways in which the code could be condensed or improved.

I pretty much have all the bits and pieces working now, and hopefully I will get it all put together in the next week or so. About the only thing I will improve at this point is the plain text terminal interface, where I would like to use some tput commands to improve the presentation, etc.
__________________
Visit my Audio Web Page <<--CLICK TO LEARN MORE-->> Get my LADSPA plugins
  Reply With Quote
Old 17th July 2016, 05:25 PM   #29
CharlieLaub is offline CharlieLaub  United States
diyAudio Member
 
Join Date: Mar 2007
Location: California
Update:
Success! I now have everything working including the user interface for system launch/termiante, etc. I plan to keep testing and improving the code over the next week or so. I would like to implement the text interface in a different way using tput. It's currently just outputting info as plain text which is probably fine, but could be made to look a little better.

At this point the concept is proven and I am very happy to see that my effort has come to fruition.
__________________
Visit my Audio Web Page <<--CLICK TO LEARN MORE-->> Get my LADSPA plugins
  Reply With Quote
Old 17th July 2016, 11:07 PM   #30
CharlieLaub is offline CharlieLaub  United States
diyAudio Member
 
Join Date: Mar 2007
Location: California
Here are some more usage details. The help screen shows some of the different ways that the streaming audio controller software can be used:

Code:
       *** GSASysCon: the Gsreamer Streaming Audio System Controller ***
      A bash-script-based streaming audio system controller for gstreamer

Help and Usage Information:

Usage:
  GSASysCon.sh                                  :run-once mode
  GSASysCon.sh (update_interval)                :continuous update mode
  GSASysCon.sh -a | -auto (system_number)       :automated mode
  GSASysCon.sh -h | --help                      :prints this help
  GSASysCon.sh -c | --copyright                 :prints (C) info
  GSASysCon.sh -v | --version                   :prints version info

Required parameters are shown within parenthesis.

Run-Once Mode:
In this mode the system status is displayed and the user can choose one action
to take. After performing the action the progam prints the new status and exits.
If no user input is received for some time the progam automatically exits.

Run-Continuous Mode:
In this mode the system status is continuously displayed after update_interval 
seconds have elapsed without user input. Like with run-once mode, the user can
choose an action to take. Following the action, the system status is again
displayed. The user must manually exit by typing x at the prompt.

Automated Mode:
This functions like run-once mode. Rather than getting the desired action from
the user, the action is specified on the command line. Actions can only consist
of turning a system on or off, so the only permissible input is a system number.

The progam lists the systems that have been registered, and their status. The
status is either 'OFF' or the elapsed up time of the system. Toggling a system
on and off is performed by entering the system number. The system number is 
automatically generated by arranging the systems in alphabetical order.
The status screen shows a list of the systems that are registered within GSASysCon. The output (for just one registered system) is shown below:

Code:
   #       STATUS        SYSTEM NAME
----------------------------------------------------------
   1   2hours,14mins     main system
----------------------------------------------------------
Enter a system number to toggle it ON/OFF, x to exit
I can control my audio system from a variety of devices. I use a 10" android tablet to run an mpd client (MPD Droid IIRC) and then I use an ssh client to access the server and run GSASysCon. Turning a system ON or OFF is as easy as typing its number into the GSASysCon interface. I can have any number of mpd and GSASysCon interfaces running on different devices, so that I can control any audio system in my home from which ever one is closest to where I happen to be at the time.

Because GSASysCon has an automatic mode it could be run as a cron job to turn a system on at a preset time, for instance as an alarm clock. Likewise, a cron job could shutdown all the systems at some time, e.g. after you fall asleep. It can be called from script, so automated audio on/off switching can be wrapped into other applications without the need for user input.
__________________
Visit my Audio Web Page <<--CLICK TO LEARN MORE-->> Get my LADSPA plugins
  Reply With Quote

Reply


A bash-script-based streaming audio system client controller for gstreamerHide this!Advertise here!
Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
New BeagleBone based Audio System dogrocket Vendor's Bazaar 3 1st April 2016 04:02 AM
XMOS audio streaming controller GB interest heartwinter Group Buys 12 13th July 2015 04:30 PM
USB streaming controller arjunm009 Digital Line Level 2 12th May 2015 04:38 AM
First audio project, Wall controller for room audio system, looking for guidance, Chrisdvip Construction Tips 2 10th June 2013 05:47 AM
Audio System Controller happyboy Analog Line Level 9 12th September 2012 09:12 AM


New To Site? Need Help?

All times are GMT. The time now is 09:10 AM.


Search Engine Optimisation provided by DragonByte SEO (Pro) - vBulletin Mods & Addons Copyright © 2018 DragonByte Technologies Ltd.
Resources saved on this page: MySQL 14.29%
vBulletin Optimisation provided by vB Optimise (Pro) - vBulletin Mods & Addons Copyright © 2018 DragonByte Technologies Ltd.
Copyright ©1999-2018 diyAudio
Wiki