Archive for ‘Tutorial’ Category
Browse:
Tutorial »
Subcategories:

So over christmas holidays I spent about 5 days to perfect my raspberry pi based internet radio player.Screen Shot 2015-01-21 at 9.05.44 AM Screen Shot 2015-01-21 at 9.06.13 AM

You’ll need the following hardware:

  1. Raspberry Pi model B
  2. USB Wifi dongle (something that works with Raspbian would be nice). I got this one (http://www.adafruit.com/products/1030) from Adafruit.
  3. SD card (I’m using a 16GB card, but I think 8GB should be good to start with)
  4. Bluetooth 4.0 dongle. I’m using this one from ASUS (http://www.asus.com/ca-en/Networking/USBBT400/) that seems to work fine in Linux/Raspbian
  5. PiTFT resistive touch screen assembled from Adafruit (http://www.adafruit.com/products/1601)
  6. Pack of 20 tactile buttons from Adafruit (http://www.adafruit.com/products/1489) for the above screen (You need to solder these in…..very simple)
  7. Appropriate power USB power supply. Again I’m using the one from Adafruit (http://www.adafruit.com/products/501)
  8. Standard A to micro-B USB cable (http://www.adafruit.com/products/592)
  9. (optional) PiTFT Enclosure from Adafruit (http://www.adafruit.com/products/1892). Highly recommended as it looks really nice and clean.

 

The screen (PiTFT) comes pre-assembled so all you need to do is solder the 4 buttons on the bottom. This literally takes 5 minutes (8 solder points if you’re keeping track). Once that’s done plugin the screen onto the Pi.

Now grab a copy of the custom Raspbian image off Adafruits website (I’ve grabbed the 9/18/2014 image from http://adafruit-download.s3.amazonaws.com/PiTFT28R_raspbian140909_2014_09_18.zip). There might be a newer one out by the time you read this. Note that this image is only for TFT resistive touch screen NOT the capacitive screen. Unzip the above file (you’ll get a .img file) and burn it onto a SD card (mine is 16GB) following the instructions at http://elinux.org/RPi_Easy_SD_Card_Setup.

I’m plugging in the USB wifi and USB Bluetooth devices into the PI. Also plugin a wired ethernet connection (hopefully you have DHCP on it).

Let’s ssh to the Pi to get it setup (IP is on the PiTFT). I’m logging in as user pi (password raspberry……make sure you change it) and immediately switching to root.

At this point (as root) do the following tasks by running “raspy-config” and using the screenshots as reference:

  1. Expand the file system and reboot.
    Screen Shot 2015-01-21 at 9.27.59 AM
  2. Change the “pi” user passwordScreen Shot 2014-12-29 at 7.47.36 PM
  3. (Optional) Change the internationalization options.Screen Shot 2014-12-29 at 7.47.43 PM Screen Shot 2014-12-29 at 7.47.49 PM Screen Shot 2014-12-29 at 7.51.52 PMNOTE: On the following screen I leave en_GB.UTF-8 as default, although I live in Canada. But I do select _CA and _US as well.Screen Shot 2014-12-29 at 7.52.32 PMBack to main screen and we go back to Internationalization options to change the timezone.Screen Shot 2014-12-29 at 7.54.24 PM Screen Shot 2014-12-29 at 7.56.21 PM Screen Shot 2014-12-29 at 7.55.01 PM
  4. At this point you can also change the Hostname (Under advanced). Once you’ve done that, reboot for good measure and login using “pi” and sudo -i to get to root. Next we want to configure the WIFI USB device.

Now that we have the basics configured, before we install the wifi config tool, it’s a great time to take a break and do a “apt-get update ; apt-get upgrade” cycle. Next we want to make sure that both our USB dongles are detected (WIFI, Bluetooth) by doing “lsusb”.

Screen Shot 2014-12-29 at 8.21.25 PM

We now install wicd-curses using “apt-get install wicd-curses”. Then we run it and not touch anything, you need to press the right keys here. First right off the back press P(references). Note that It’s CAPITAL P.

 

Screen Shot 2014-12-29 at 8.22.10 PM Screen Shot 2014-12-29 at 8.29.52 PM

Once things are setup like the above picture, press F10 key to save it. You might lose connection, just wait until ssh times out and re-ssh back in and sudo -i as well. Now we need to get back into wicd-curses (if the connection dropped) and find the SSID for our WIFI. Once there DO NOT press ENTER. Highlight the entry by using the cursor keys (up,down) and press the RIGHT cursor key (—>) to open the prefs for that SSID. NOTE: the WPA ½ entry has been changed as well.

 

Screen Shot 2014-12-29 at 8.39.10 PM

Press F10 to save. You might get disconnected (you’ll see the WIFI LEDS flashing). If you got timed out, relogin and sudo -i to get root. reboot NOW. Now we need to disconnect the wired connection. This will force the system to turn on WIFI. Once the machine is booted (it might take a bit longer, since we have to wait for wired DHCP to time out), you’ll find the WIFI IP on the TFT.

SSH to the IP and get root shell. We now need to configure bluetooth. Follow along with the pics below. First though we need to install a bunch of stuff with “apt-get install bluetooth bluez bluez-utils bluez-alsa” command. Remove unnecessary services that got installed (scanner, printer, avahi) and disable their autostart.

Screen Shot 2014-12-29 at 9.11.44 PM
Add the following Disable/Enable block (2 lines) to the [General] section of /etc/bluetooth/audio.conf file.
Screen Shot 2014-12-29 at 9.14.21 PM
Okay we need to reboot now and once back in continue as root. First we make sure our BT device is initialized.
Screen Shot 2014-12-29 at 9.22.32 PM
Then we turn on the BT speaker (BeatsPill) and put it in discover mode (hold the b button until the bluetooth LED on the back starts flashing…..might have to push the b button once before). Then we go on to discover the device.
Screen Shot 2014-12-29 at 9.23.18 PM
Note it’s address. We will need to copy and paste it into the next few commands. Put the following in /etc/asound.conf paying attention to replace the MAC address of the BD device with the correct one you copied in the last step.
Screen Shot 2014-12-30 at 12.36.55 AMScreen Shot 2014-12-29 at 9.25.46 PM
Once we get the output 1 from the last command it means that the device is trusted now and Linux will try to auto connect to it if the BT speaker is on when the machine is rebooted. You’ll also hear a beep when the bluetooth-agent command successfully connects. In the last step I’m just trying to establish an audio connection by restarting the bluetooth daemon (make it forget the connection) and using bluez-test-audio to connect back to the speaker. Again you’ll hear a beep when the Pi connects.
Screen Shot 2014-12-29 at 9.28.25 PM
Now we need to install mpd, mpc and the curses based ncmpcpp by using “apt-get install mpd mpc ncmpcpp”.
Once that’s done copy /etc/mpd.conf to /etc/mpd.conf.old and create /etc/mpd.conf with the following content:
# An example configuration file for MPD
# See the mpd.conf man page for a more detailed description of each parameter.
# Files and directories #######################################################
#
# This setting controls the top directory which MPD will search to discover the
# available audio files and add them to the daemon's online database. This 
# setting defaults to the XDG directory, otherwise the music directory will be
# be disabled and audio files will only be accepted over ipc socket (using
# file:// protocol) or streaming files over an accepted protocol.
#
music_directory	"/var/lib/mpd/music"
#
# This setting sets the MPD internal playlist directory. The purpose of this
# directory is storage for playlists created by MPD. The server will use 
# playlist files not created by the server but only if they are in the MPD
# format. This setting defaults to playlist saving being disabled.
#
playlist_directory	"/var/lib/mpd/playlists"
#
# This setting sets the location of the MPD database. This file is used to
# load the database at server start up and store the database while the 
# server is not up. This setting defaults to disabled which will allow
# MPD to accept files over ipc socket (using file:// protocol) or streaming
# files over an accepted protocol.
#
db_file	"/var/lib/mpd/tag_cache"
# 
# These settings are the locations for the daemon log files for the daemon.
# These logs are great for troubleshooting, depending on your log_level
# settings.
#
# The special value "syslog" makes MPD use the local syslog daemon. This
# setting defaults to logging to syslog, otherwise logging is disabled.
#
log_file	"/var/log/mpd/mpd.log"
#
# This setting sets the location of the file which stores the process ID
# for use of mpd --kill and some init scripts. This setting is disabled by
# default and the pid file will not be stored.
#
pid_file	"/var/run/mpd/pid"
#
# This setting sets the location of the file which contains information about
# most variables to get MPD back into the same general shape it was in before
# it was brought down. This setting is disabled by default and the server 
# state will be reset on server start up.
#
state_file	"/var/lib/mpd/state"
#
# The location of the sticker database.  This is a database which
# manages dynamic information attached to songs.
#
sticker_file                   "/var/lib/mpd/sticker.sql"
#
###############################################################################
# General music daemon options ################################################
#
# This setting specifies the user that MPD will run as. MPD should never run as
# root and you may use this setting to make MPD change its user ID after
# initialization. This setting is disabled by default and MPD is run as the
# current user.
#
user	"mpd"
#
# This setting specifies the group that MPD will run as. If not specified
# primary group of user specified with "user" setting will be used (if set).
# This is useful if MPD needs to be a member of group such as "audio" to
# have permission to use sound card.
#
#group                          "nogroup"
#
# This setting sets the address for the daemon to listen on. Careful attention
# should be paid if this is assigned to anything other then the default, any.
# This setting can deny access to control of the daemon. Choose any if you want
# to have mpd listen on every address
#
# For network
#bind_to_address	"any"
bind_to_address	“127.0.0.1"
#
# And for Unix Socket
#bind_to_address	"/var/run/mpd/socket"
#
# This setting is the TCP port that is desired for the daemon to get assigned
# to.
#
port	"6600"
#
# This setting controls the type of information which is logged. Available 
# setting arguments are "default", "secure" or "verbose". The "verbose" setting
# argument is recommended for troubleshooting, though can quickly stretch
# available resources on limited hardware storage.
#
#log_level	"default"
#
# If you have a problem with your MP3s ending abruptly it is recommended that 
# you set this argument to "no" to attempt to fix the problem. If this solves
# the problem, it is highly recommended to fix the MP3 files with vbrfix
# (available as vbrfix in the debian archive), at which
# point gapless MP3 playback can be enabled.
#
gapless_mp3_playback	"yes"
#
# This setting enables MPD to create playlists in a format usable by other
# music players.
#
#save_absolute_paths_in_playlists	"no"
#
# This setting defines a list of tag types that will be extracted during the 
# audio file discovery process. Optionally, 'comment' can be added to this
# list.
#
#metadata_to_use	"artist,album,title,track,name,genre,date,composer,performer,disc"
#
# This setting enables automatic update of MPD's database when files in 
# music_directory are changed.
#
auto_update    "yes"
#
# Limit the depth of the directories being watched, 0 means only watch
# the music directory itself.  There is no limit by default.
#
#auto_update_depth "3"
#
###############################################################################
# Symbolic link behavior ######################################################
#
# If this setting is set to "yes", MPD will discover audio files by following 
# symbolic links outside of the configured music_directory.
#
follow_outside_symlinks	"yes"
#
# If this setting is set to "yes", MPD will discover audio files by following
# symbolic links inside of the configured music_directory.
#
follow_inside_symlinks	"yes"
#
###############################################################################
# Zeroconf / Avahi Service Discovery ##########################################
#
# If this setting is set to "yes", service information will be published with
# Zeroconf / Avahi.
#
zeroconf_enabled	"yes"
#
# The argument to this setting will be the Zeroconf / Avahi unique name for
# this MPD server on the network.
#
zeroconf_name	"iradio"
#
###############################################################################
# Permissions #################################################################
#
# If this setting is set, MPD will require password authorization. The password
# can setting can be specified multiple times for different password profiles.
#
#password                        "password@read,add,control,admin"
#
# This setting specifies the permissions a user has who has not yet logged in. 
#
#default_permissions             "read,add,control,admin"
#
###############################################################################
# Input #######################################################################
#
input {
        plugin "curl"
#       proxy "proxy.isp.com:8080"
#       proxy_user "user"
#       proxy_password "password"
}
#
###############################################################################
# Audio Output ################################################################

# MPD supports various audio output types, as well as playing through multiple 
# audio outputs at the same time, through multiple audio_output settings 
# blocks. Setting this block is optional, though the server will only attempt
# autodetection for one sound card.
#
# See <http://mpd.wikia.com/wiki/Configuration#Audio_Outputs> for examples of 
# other audio outputs.
#
# An example of an ALSA output THIS IS THE DEFAULT:
#
audio_output {
type	"alsa"
name	"My ALSA Device"
device	"hw:0,0"	# optional
format	"44100:16:2"	# optional
mixer_device	"default"	# optional
mixer_control	"PCM"	# optional
mixer_index	"0"	# optional
}
#
# Example for Bluetooth A2DP
#
audio_output {
type            "alsa"
name            "ALSA"
format          "44100:16:2"    # optional
#options         "dev=dmixer"
device          "bluetooth"
}
#
# Enable FIFO Pipe for ncmpcpp Visualizer
#
audio_output {
    type                    "fifo"
    name                    "iradio"
    path                    "/tmp/mpd.fifo"
    format                  "44100:16:1"
}
#
# Example for USB class complaint Audio Card
#
#audio_output {
#	type	"alsa"
#	name	"Output"
#	device	"hw:0,0"	# optional
#	dsd_usb	"no"
#}
#
# An example of an OSS output:
#
#audio_output {
#	type	"oss"
#	name	"My OSS Device"
#	device	"/dev/dsp"	# optional
#	format	"44100:16:2"	# optional
#	mixer_device	"/dev/mixer"	# optional
#	mixer_control	"PCM"	# optional
#}
#
# An example of a shout output (for streaming to Icecast):
#
#audio_output {
#	type	"shout"
#	encoding	"ogg"	# optional
#	name	"My Shout Stream"
#	host	"localhost"
#	port	"8000"
#	mount	"/mpd.ogg"
#	password	"hackme"
#	quality	"5.0"
#	bitrate	"128"
#	format	"44100:16:1"
#	protocol	"icecast2"	# optional
#	user	"source"	# optional
#	description	"My Stream Description"	# optional
#	genre	"jazz"	# optional
#	public	"no"	# optional
#	timeout	"2"	# optional
#}
#
# An example of a recorder output:
#
#audio_output {
#       type            "recorder"
#       name            "My recorder"
#       encoder         "vorbis"                # optional, vorbis or lame
#       path            "/var/lib/mpd/recorder/mpd.ogg"
##      quality         "5.0"                   # do not define if bitrate is defined
#       bitrate         "128"                   # do not define if quality is defined
#       format          "44100:16:1"
#}
#
# An example of a httpd output (built-in HTTP streaming server):
#
#audio_output {
#	type	"httpd"
#	name	"My HTTP Stream"
#	encoder	"vorbis"	# optional, vorbis or lame
#	port	"8000"
#	quality	"5.0"	# do not define if bitrate is defined
#	bitrate	"128"	# do not define if quality is defined
#	format	"44100:16:1"
#}
#
# An example of a pulseaudio output (streaming to a remote pulseaudio server)
#
#audio_output {
#	type	"pulse"
#	name	"My Pulse Output"
#	server	"remote_server"	# optional
#	sink	"remote_server_sink"	# optional
#}
#
## Example "pipe" output:
#
#audio_output {
#	type	"pipe"
#	name	"my pipe"
#	command	"aplay -f cd 2>/dev/null"
## Or if you're want to use AudioCompress
#	command	"AudioCompress -m | aplay -f cd 2>/dev/null"
## Or to send raw PCM stream through PCM:
#	command	"nc example.org 8765"
#	format	"44100:16:2"
#}
#
## An example of a null output (for no audio output):
#
#audio_output {
#	type	"null"
#	name	"My Null Output"
#}
#
# This setting will change all decoded audio to be converted to the specified
# format before being passed to the audio outputs. By default, this setting is
# disabled.
#
#audio_output_format	"44100:16:2"
#
# If MPD has been compiled with libsamplerate support, this setting specifies 
# the sample rate converter to use.  Possible values can be found in the 
# mpd.conf man page or the libsamplerate documentation. By default, this is
# setting is disabled.
#
#samplerate_converter	"Fastest Sinc Interpolator"
#
###############################################################################
# Volume control mixer ########################################################
#
# These are the global volume control settings. By default, this setting will
# be detected to the available audio output device, with preference going to 
# hardware mixing. Hardware and software mixers for individual audio_output
# sections cannot yet be mixed.
#
# An example for controlling an ALSA, OSS or Pulseaudio mixer; If this
# setting is used other sound applications will be affected by the volume
# being controlled by MPD.
#
#mixer_type	"hardware"
#
# An example for controlling all mixers through software. This will control
# all controls, even if the mixer is not supported by the device and will not
# affect any other sound producing applications.
#
#mixer_type	"software"
#
# This example will not allow MPD to touch the mixer at all and will disable
# all volume controls.
#
#mixer_type	"disabled"
#mixer_type	"none"
#
###############################################################################
# Normalization automatic volume adjustments ##################################
#
# This setting specifies the type of ReplayGain to use. This setting can have
# the argument "album" or "track". See <http://www.replaygain.org> for more
# details. This setting is disabled by default.
#
#replaygain	"album"
#
# This setting sets the pre-amp used for files that have ReplayGain tags. By
# default this setting is disabled.
#
#replaygain_preamp	"0"
#
# This setting enables on-the-fly normalization volume adjustment. This will
# result in the volume of all playing audio to be adjusted so the output has 
# equal "loudness". This setting is disabled by default.
#
volume_normalization	"no"
#
###############################################################################
# MPD Internal Buffering ######################################################
#
# This setting adjusts the size of internal decoded audio buffering. Changing
# this may have undesired effects. Don't change this if you don't know what you
# are doing.
#
audio_buffer_size	"2048"
#
# This setting controls the percentage of the buffer which is filled before 
# beginning to play. Increasing this reduces the chance of audio file skipping, 
# at the cost of increased time prior to audio playback.
#
buffer_before_play	"20%"
#
###############################################################################
# Resource Limitations ########################################################
#
# These settings are various limitations to prevent MPD from using too many
# resources. Generally, these settings should be minimized to prevent security
# risks, depending on the operating resources.
#
#connection_timeout	"60"
#max_connections	"10"
#max_playlist_length	"16384"
#max_command_list_size	"2048"
#max_output_buffer_size	"8192"
#
###############################################################################
# Character Encoding ##########################################################
#
# If file or directory names do not display correctly for your locale then you 
# may need to modify this setting. After modification of this setting mpd 
# --create-db must be run to change the database.
#
filesystem_charset	"UTF-8"
#
# This setting controls the encoding that ID3v1 tags should be converted from.
#
id3v1_encoding	"UTF-8"
#
###############################################################################
# SIDPlay decoder #############################################################
#
# songlength_database:
#  Location of your songlengths file, as distributed with the HVSC.
#  The sidplay plugin checks this for matching MD5 fingerprints.
#  See http://www.c64.org/HVSC/DOCUMENTS/Songlengths.faq
#
# default_songlength:
#  This is the default playing time in seconds for songs not in the
#  songlength database, or in case you're not using a database.
#  A value of 0 means play indefinitely.
#
# filter:
#  Turns the SID filter emulation on or off.
#
#decoder {
#       plugin                  "sidplay"
#       songlength_database     "/media/C64Music/DOCUMENTS/Songlengths.txt"
#       default_songlength      "120"
#       filter "true"
#}
#
###############################################################################

There are 3 audio_output sections for the internal headphone jack, bluetooth audio and a third one for ncmpcpp’s spectrum analyzer (although I don’t use it in this project).

Next we need a playlist file in m3u format. You’ll find a good one below (contains di.fm, sky.fm, CBC and somafm AAC links). Copy this into /var/lib/mpd/playlist/something.m3u (remember the filename since we will then use mpc to load it):


http://pub6.di.fm/di_00sclubhits_aac
http://pub6.di.fm/di_ambient_aac
http://pub6.di.fm/di_bassnjackinhouse_aac
http://pub6.di.fm/di_bassline_aac
http://pub6.di.fm/di_bigbeat_aac
http://pub6.di.fm/di_bigroomhouse_aac
http://pub6.di.fm/di_breaks_aac
http://pub6.di.fm/di_chillhop_aac
http://pub6.di.fm/di_chilloutdreams_aac
http://pub6.di.fm/di_chillout_aac
http://pub6.di.fm/di_chillstep_aac
http://pub6.di.fm/di_chiptunes_aac
http://pub6.di.fm/di_classiceurodance_aac
http://pub6.di.fm/di_classiceurodisco_aac
http://pub6.di.fm/di_classictrance_aac
http://pub6.di.fm/di_classicvocaltrance_aac
http://pub6.di.fm/di_clubdubstep_aac
http://pub6.di.fm/di_club_aac
http://pub6.di.fm/di_cosmicdowntempo_aac
http://pub6.di.fm/di_darkdnb_aac
http://pub6.di.fm/di_darkpsytrance_aac
http://pub6.di.fm/di_deephouse_aac
http://pub6.di.fm/di_deepnudisco_aac
http://pub6.di.fm/di_deeptech_aac
http://pub6.di.fm/di_discohouse_aac
http://pub6.di.fm/di_djmixes_aac
http://pub6.di.fm/di_downtempolounge_aac
http://pub6.di.fm/di_drumandbass_aac
http://pub6.di.fm/di_drumstep_aac
http://pub6.di.fm/di_dub_aac
http://pub6.di.fm/di_dubstep_aac
http://pub6.di.fm/di_ebm_aac
http://pub6.di.fm/di_eclectronica_aac
http://pub6.di.fm/di_electro_aac
http://pub6.di.fm/di_electronicpioneers_aac
http://pub6.di.fm/di_electronics_aac
http://pub6.di.fm/di_electropop_aac
http://pub6.di.fm/di_electroswing_aac
http://pub6.di.fm/di_epictrance_aac
http://pub6.di.fm/di_eurodance_aac
http://pub6.di.fm/di_funkyhouse_aac
http://pub6.di.fm/di_futuregarage_aac
http://pub6.di.fm/di_futuresynthpop_aac
http://pub6.di.fm/di_gabber_aac
http://pub6.di.fm/di_glitchhop_aac
http://pub6.di.fm/di_goapsy_aac
http://pub6.di.fm/di_handsup_aac
http://pub6.di.fm/di_hardcore_aac
http://pub6.di.fm/di_harddance_aac
http://pub6.di.fm/di_hardstyle_aac
http://pub6.di.fm/di_hardtechno_aac
http://pub6.di.fm/di_house_aac
http://pub6.di.fm/di_jungle_aac
http://pub6.di.fm/di_latinhouse_aac
http://pub6.di.fm/di_liquiddnb_aac
http://pub6.di.fm/di_liquiddubstep_aac
http://pub6.di.fm/di_lounge_aac
http://pub6.di.fm/di_mainstage_aac
http://pub6.di.fm/di_minimal_aac
http://pub6.di.fm/di_moombahton_aac
http://pub6.di.fm/di_nightcore_aac
http://pub6.di.fm/di_nudisco_aac
http://pub6.di.fm/di_oldschoolacid_aac
http://pub6.di.fm/di_oldschoolhouse_aac
http://pub6.di.fm/di_oldschoolrave_aac
http://pub6.di.fm/di_classictechno_aac
http://pub6.di.fm/di_progressive_aac
http://pub6.di.fm/di_progressivepsy_aac
http://pub6.di.fm/di_psybient_aac
http://pub6.di.fm/di_psychill_aac
http://pub6.di.fm/di_russianclubhits_aac
http://pub6.di.fm/di_scousehouse_aac
http://pub6.di.fm/di_soulfulhouse_aac
http://pub6.di.fm/di_spacemusic_aac
http://pub6.di.fm/di_techhouse_aac
http://pub6.di.fm/di_techno_aac
http://pub6.di.fm/di_trance_aac
http://pub6.di.fm/di_trap_aac
http://pub6.di.fm/di_tribalhouse_aac
http://pub6.di.fm/di_ukgarage_aac
http://pub6.di.fm/di_umfradio_aac
http://pub6.di.fm/di_undergroundtechno_aac
http://pub6.di.fm/di_vocalchillout_aac
http://pub6.di.fm/di_vocallounge_aac
http://pub6.di.fm/di_vocaltrance_aac
http://pub7.radiotunes.com/radiotunes_00srnb_aac
http://pub7.radiotunes.com/radiotunes_60srock_aac
http://pub7.radiotunes.com/radiotunes_80sdance_aac
http://pub7.radiotunes.com/radiotunes_80srock_aac
http://pub7.radiotunes.com/radiotunes_hit90s_aac
http://pub7.radiotunes.com/radiotunes_90srnb_aac
http://pub7.radiotunes.com/radiotunes_beatles_aac
http://pub7.radiotunes.com/radiotunes_altrock_aac
http://pub7.radiotunes.com/radiotunes_rtambient_aac
http://pub7.radiotunes.com/radiotunes_americansongbook_aac
http://pub7.radiotunes.com/radiotunes_baroque_aac
http://pub7.radiotunes.com/radiotunes_bebop_aac
http://pub7.radiotunes.com/radiotunes_hit60s_aac
http://pub7.radiotunes.com/radiotunes_the80s_aac
http://pub7.radiotunes.com/radiotunes_bossanova_aac
http://pub7.radiotunes.com/radiotunes_cafedeparis_aac
http://pub7.radiotunes.com/radiotunes_rtchillout_aac
http://pub7.radiotunes.com/radiotunes_guitar_aac
http://pub7.radiotunes.com/radiotunes_classicalperiod_aac
http://pub7.radiotunes.com/radiotunes_classicalpianotrios_aac
http://pub7.radiotunes.com/radiotunes_christmas_aac
http://pub7.radiotunes.com/radiotunes_classicrap_aac
http://pub7.radiotunes.com/radiotunes_classicmotown_aac
http://pub7.radiotunes.com/radiotunes_classicrock_aac
http://pub7.radiotunes.com/radiotunes_clubbollywood_aac
http://pub7.radiotunes.com/radiotunes_christian_aac
http://pub7.radiotunes.com/radiotunes_country_aac
http://pub7.radiotunes.com/radiotunes_dancehits_aac
http://pub7.radiotunes.com/radiotunes_datempolounge_aac
http://pub7.radiotunes.com/radiotunes_davekoz_aac
http://pub7.radiotunes.com/radiotunes_discoparty_aac
http://pub7.radiotunes.com/radiotunes_downtempolounge_aac
http://pub7.radiotunes.com/radiotunes_dreamscapes_aac
http://pub7.radiotunes.com/radiotunes_edmfest_aac
http://pub7.radiotunes.com/radiotunes_eurodance_aac
http://pub7.radiotunes.com/radiotunes_hardrock_aac
http://pub7.radiotunes.com/radiotunes_hit70s_aac
http://pub7.radiotunes.com/radiotunes_holidaysmoothjazz_aac
http://pub7.radiotunes.com/radiotunes_indierock_aac
http://pub7.radiotunes.com/radiotunes_israelihits_aac
http://pub7.radiotunes.com/radiotunes_jazzclassics_aac
http://pub7.radiotunes.com/radiotunes_jpop_aac
http://pub7.radiotunes.com/radiotunes_lounge_aac
http://pub7.radiotunes.com/radiotunes_lovemusic_aac
http://pub7.radiotunes.com/radiotunes_meditation_aac
http://pub7.radiotunes.com/radiotunes_mellowjazz_aac
http://pub7.radiotunes.com/radiotunes_mellowsmoothjazz_aac
http://pub7.radiotunes.com/radiotunes_metal_aac
http://pub7.radiotunes.com/radiotunes_modernblues_aac
http://pub7.radiotunes.com/radiotunes_modernrock_aac
http://pub7.radiotunes.com/radiotunes_classical_aac
http://pub7.radiotunes.com/radiotunes_soundtracks_aac
http://pub7.radiotunes.com/radiotunes_mozart_aac
http://pub7.radiotunes.com/radiotunes_nature_aac
http://pub7.radiotunes.com/radiotunes_newage_aac
http://pub7.radiotunes.com/radiotunes_oldies_aac
http://pub7.radiotunes.com/radiotunes_oldschoolfunknsoul_aac
http://pub7.radiotunes.com/radiotunes_pianojazz_aac
http://pub7.radiotunes.com/radiotunes_popchristmas_aac
http://pub7.radiotunes.com/radiotunes_poppunk_aac
http://pub7.radiotunes.com/radiotunes_poprock_aac
http://pub7.radiotunes.com/radiotunes_reggaeton_aac
http://pub7.radiotunes.com/radiotunes_relaxation_aac
http://pub7.radiotunes.com/radiotunes_relaxingambientpiano_aac
http://pub7.radiotunes.com/radiotunes_relaxingexcursions_aac
http://pub7.radiotunes.com/radiotunes_romantica_aac
http://pub7.radiotunes.com/radiotunes_romantic_aac
http://pub7.radiotunes.com/radiotunes_rootsreggae_aac
http://pub7.radiotunes.com/radiotunes_russiandance_aac
http://pub7.radiotunes.com/radiotunes_russianpop_aac
http://pub7.radiotunes.com/radiotunes_salsa_aac
http://pub7.radiotunes.com/radiotunes_ska_aac
http://pub7.radiotunes.com/radiotunes_slowjams_aac
http://pub7.radiotunes.com/radiotunes_smoothbossanova_aac
http://pub7.radiotunes.com/radiotunes_smoothjazz247_aac
http://pub7.radiotunes.com/radiotunes_smoothjazz_aac
http://pub7.radiotunes.com/radiotunes_smoothlounge_aac
http://pub7.radiotunes.com/radiotunes_softrock_aac
http://pub7.radiotunes.com/radiotunes_solopiano_aac
http://pub7.radiotunes.com/radiotunes_tophits_aac
http://pub7.radiotunes.com/radiotunes_uptemposmoothjazz_aac
http://pub7.radiotunes.com/radiotunes_urbanjamz_aac
http://pub7.radiotunes.com/radiotunes_urbanpophits_aac
http://pub7.radiotunes.com/radiotunes_vocalchillout_aac
http://pub7.radiotunes.com/radiotunes_vocallounge_aac
http://pub7.radiotunes.com/radiotunes_vocalnewage_aac
http://pub7.radiotunes.com/radiotunes_vocalsmoothjazz_aac
http://pub7.radiotunes.com/radiotunes_world_aac
http://3023.live.streamtheworld.com:80/CBC_70S001_H_SC
http://9223.live.streamtheworld.com:80/CBC_80S001_H_SC
http://6093.live.streamtheworld.com:80/CBC_90S001_H_SC
http://6693.live.streamtheworld.com:3690/CBC_90S001_H_SC
http://1721.live.streamtheworld.com:80/CBC_ABORIG_H_SC
http://3163.live.streamtheworld.com:80/CBC_ADLTAL_H_SC
http://5853.live.streamtheworld.com:80/CBC_ADLTPO_H_SC
http://2903.live.streamtheworld.com:80/CBC_ALTCRY_H_SC
http://9233.live.streamtheworld.com:80/CBC_AMBIEN_H_SC
http://3143.live.streamtheworld.com:80/CBC_BAROQU_H_SC
http://2073.live.streamtheworld.com:80/CBC_BLCLAS_H_SC
http://2083.live.streamtheworld.com:80/CBC_BLUES1_H_SC
http://9213.live.streamtheworld.com:80/CBC_CANCOM_H_SC
http://1521.live.streamtheworld.com:80/CBC_CANSON_H_SC
http://4293.live.streamtheworld.com:80/CBC_CLSCRY_H_SC
http://1451.live.streamtheworld.com:3690/CBC_CLSCRY_H_SC
http://2953.live.streamtheworld.com:80/CBC_CONTRY_H_SC
http://2933.live.streamtheworld.com:80/CBC_ECLASS_H_SC
http://2062.live.streamtheworld.com:80/CBC_ELECTR_H_SC
http://2903.live.streamtheworld.com:80/CBC_GGSAMP_H_SC
http://2903.live.streamtheworld.com:80/CBC_HAROCK_H_SC
http://3023.live.streamtheworld.com:80/CBC_HIPHOP_H_SC
http://3163.live.streamtheworld.com:80/CBC_INDIE1_H_SC
http://2773.live.streamtheworld.com:80/CBC_JAZCDN_H_SC
http://2793.live.streamtheworld.com:80/CBC_JAZMAS_H_SC
http://2093.live.streamtheworld.com:80/CBC_JAZSMO_H_SC
http://2773.live.streamtheworld.com:80/CBC_JAZSON_H_SC
http://3413.live.streamtheworld.com:80/CBC_JUKEBO_H_SC
http://3153.live.streamtheworld.com:80/CBC_MODMAS_H_SC
http://3163.live.streamtheworld.com:80/CBC_OPERAT_H_SC
http://3153.live.streamtheworld.com:80/CBC_ORCHES_H_SC
http://3023.live.streamtheworld.com:80/CBC_PIANO1_H_SC
http://9233.live.streamtheworld.com:80/CBC_POP040_H_SC
http://1651.live.streamtheworld.com:80/CBC_R1_CGY_H_SC
http://2953.live.streamtheworld.com:80/CBC_R1_CHR_H_SC
http://3373.live.streamtheworld.com:80/CBC_R1_COR_H_SC
http://2073.live.streamtheworld.com:80/CBC_R1_EDM_H_SC
http://2783.live.streamtheworld.com:80/CBC_R1_EKW_H_SC
http://2913.live.streamtheworld.com:80/CBC_R1_FRD_H_SC
http://2893.live.streamtheworld.com:80/CBC_R1_GBA_H_SC
http://2093.live.streamtheworld.com:80/CBC_R1_GFA_H_SC
http://3383.live.streamtheworld.com:80/CBC_R1_HFX_H_SC
http://3593.live.streamtheworld.com:80/CBC_R1_INK_H_SC
http://1661.live.streamtheworld.com:80/CBC_R1_IQA_H_SC
http://3143.live.streamtheworld.com:80/CBC_R1_KAM_H_SC
http://9453.live.streamtheworld.com:80/CBC_R1_KEL_H_SC
http://3143.live.streamtheworld.com:80/CBC_R1_LDN_H_SC
http://1531.live.streamtheworld.com:80/CBC_R1_MCT_H_SC
http://6093.live.streamtheworld.com:80/CBC_R1_MTL_H_SC
http://3903.live.streamtheworld.com:3690/CBC_R1_MTL_H_SC
http://1591.live.streamtheworld.com:80/CBC_R1_N_MTL_H_SC
http://1671.live.streamtheworld.com:80/CBC_R1_OTT_H_SC
http://9453.live.streamtheworld.com:80/CBC_R1_PRG_H_SC
http://2953.live.streamtheworld.com:80/CBC_R1_QQU_H_SC
http://9453.live.streamtheworld.com:80/CBC_R1_REG_H_SC
http://3143.live.streamtheworld.com:80/CBC_R1_SNB_H_SC
http://6733.live.streamtheworld.com:80/CBC_R1_SNF_H_SC
http://2963.live.streamtheworld.com:3690/CBC_R1_SNF_H_SC
http://5463.live.streamtheworld.com:80/CBC_R1_SSK_H_SC
http://5463.live.streamtheworld.com:80/CBC_R1_SUD_H_SC
http://6093.live.streamtheworld.com:80/CBC_R1_SYD_H_SC
http://6693.live.streamtheworld.com:3690/CBC_R1_SYD_H_SC
http://1671.live.streamtheworld.com:80/CBC_R1_TBA_H_SC
http://6693.live.streamtheworld.com:80/CBC_R1_TOR_H_SC
http://1451.live.streamtheworld.com:3690/CBC_R1_TOR_H_SC
http://3903.live.streamtheworld.com:80/CBC_R1_VCR_H_SC
http://6093.live.streamtheworld.com:3690/CBC_R1_VCR_H_SC
http://1651.live.streamtheworld.com:80/CBC_R1_VIC_H_SC
http://2093.live.streamtheworld.com:80/CBC_R1_WDR_H_SC
http://1671.live.streamtheworld.com:80/CBC_R1_WHS_H_SC
http://1661.live.streamtheworld.com:80/CBC_R1_WPG_H_SC
http://2953.live.streamtheworld.com:80/CBC_R1_YKN_H_SC
http://1651.live.streamtheworld.com:80/CBC_R2CLAS_H_SC
http://9433.live.streamtheworld.com:80/CBC_R2_EDM_H_SC
http://3143.live.streamtheworld.com:80/CBC_R2_HFX_H_SC
http://8653.live.streamtheworld.com:80/CBC_R2_IET_H_SC
http://5523.live.streamtheworld.com:80/CBC_R2_IPT_H_SC
http://2073.live.streamtheworld.com:80/CBC_R2_TOR_H_SC
http://2793.live.streamtheworld.com:80/CBC_R2_VCR_H_SC
http://3023.live.streamtheworld.com:80/CBC_R2_WPG_H_SC
http://1942.live.streamtheworld.com:80/CBC_RBSOUL_H_SC
http://2973.live.streamtheworld.com:80/CBC_ROCK01_H_SC
http://2093.live.streamtheworld.com:80/CBC_ROCKCL_H_SC
http://1952.live.streamtheworld.com:80/CBC_SINSON_H_SC
http://2773.live.streamtheworld.com:80/CBC_WORLDM_H_SC
http://ice.somafm.com/bagel-64.aac
http://ice.somafm.com/beatblender-64.aac
http://uwstream2.somafm.com:2000
http://ice.somafm.com/bootliquor-64.aac
http://uwstream2.somafm.com:8048
http://ice.somafm.com/brfm-64.aac
http://ice.somafm.com/christmas-64.aac
http://ice.somafm.com/cliqhop-64.aac
http://ice.somafm.com/covers-64.aac
http://ice.somafm.com/deepspaceone-64.aac
http://ice.somafm.com/defcon-64.aac
http://uwstream2.somafm.com:8906
http://ice.somafm.com/digitalis-64.aac
http://ice.somafm.com/doomed-64.aac
http://uwstream2.somafm.com:8100
http://ice.somafm.com/dronezone-64.aac
http://ice.somafm.com/dubstep-64.aac
http://uwstream2.somafm.com:5106
http://ice.somafm.com/earwaves-64.aac
http://ice.somafm.com/folkfwd-64.aac
http://xstream1.somafm.com:3000
http://ice.somafm.com/groovesalad-64.aac
http://xstream1.somafm.com:8504
http://ice.somafm.com/illstreet-64.aac
http://xstream1.somafm.com:8070
http://ice.somafm.com/indiepop-64.aac
http://ice.somafm.com/jollysoul-64.aac
http://uwstream2.somafm.com:8808
http://ice.somafm.com/lush-64.aac
http://ice.somafm.com/missioncontrol-64.aac
http://ice.somafm.com/poptron-64.aac
http://xstream1.somafm.com:9010
http://ice.somafm.com/secretagent-64.aac
http://ice.somafm.com/sf1033-64.aac
http://ice.somafm.com/sonicuniverse-64.aac
http://xstream1.somafm.com:8200
http://ice.somafm.com/spacestation-64.aac
http://uwstream2.somafm.com:8854
http://ice.somafm.com/suburbsofgoa-64.aac
http://ice.somafm.com/thetrip-64.aac
http://uwstream2.somafm.com:2406
http://ice.somafm.com/u80s-64.aac
http://ice.somafm.com/xmasinfrisko-64.aac
http://ice.somafm.com/xmasrocks-64.aac

One last file we need to get setup is /etc/default/bluetooth and then we reboot (and make sure your BT speaker is in BT mode…..on the pill you need to press the big b button so the bluetooth LED turns on in the back).

Screen Shot 2014-12-29 at 10.09.06 PM

If you’ve made it this far, during the Pi boot cycle the Beatspill should have beeped signifying a bluetooth connection. Hopefully :-). If it doesn’t take the next step with the mpc commands. If it still doesn’t work after the mpc commands (to get mpd playing some streams) then something has gone wrong. You need to troubleshoot.
Now login and get to root shell and follow along for a quick audio test using mpc command.
Screen Shot 2014-12-30 at 11.45.47 AM
Hopefully you got everything working with BT and you’re hearing music now. If not, stop and do some googling. For sake of completeness I’ve put the commands I usually use to troubleshoot. Basically find the Beatspill MAC address, try connecting to it (mine barfs in the picture below since it’s already connected), disconnect and reconnect. Kick mpd since it can loose it’s mind if you take the audio interface away. Once mpd has restarted, get mpc to kick off the tunes by tuning into item 99 from the playlist (yeah I like the 80’s).
Screen Shot 2014-12-30 at 11.52.25 AM
Next we need to install python-pip (to get the “pip” command). Use “apt-get install python-pip” to install it (don’t worry about version 2.6 install of python, python 2.7 will still be the default).
Screen Shot 2014-12-30 at 3.04.15 PM
Okay, this next bit is a bit hairy. You need to follow it right until I finish editing /etc/modprobe.d/raspi-blacklist.conf and only then do you reboot……If you reboot like the picture shows below, you’ll end up with a white screen on the PiTFT. The Pi is still working, so worst case, put up with the white PiTFT screen, ssh, and make the three changes to the three files in /etc and give it another reboot…..and viola, PiTFT should be back and good to go. So lets update everything by doing the 3 commands in the below picture. REMEMBER DO NOT REBOOT…..KEEP GOING AND EDIT THE NEXT 3 FILES, THEN REBOOT.
Screen Shot 2014-12-30 at 2.51.49 PM Screen Shot 2014-12-29 at 11.39.14 PM
Add ipv6, stmpe_device, gpio_backlight_device, gpio_keys, gpio_keys_device and btusb to /etc/modules to make the kernel load them. We need these for later when we play around with the buttons using triggerhappy service. You don’t strictly need ipv6, but heck it might be useful later.
Screen Shot 2014-12-30 at 11.29.30 AM
Next we set the options for the modules we’re loading. If your took the reboot too soon and you screen went white the problem is this file. Note that I’ve commented the first line and put in the second line (I believe adafruit had their TFT named in their kernel module, but after the kernel update — above — the new module has pitft instead. There are some comments in there as well to explain the GPIO button assignment and it’s interface with triggerhappy (later).
Screen Shot 2014-12-31 at 4.09.58 PM
This file just needs a single comment. You’ll see later why we need this.
Screen Shot 2014-12-30 at 11.33.21 AM
Okay….still with me…..good. Now we need to configure the triggerhappy service so it can respond to the four PiTFT buttons.
Screen Shot 2014-12-30 at 12.44.21 PM
I’ve configured the buttons as (from left to right):
  1. shutdown -h now
  2. mpc play and start the pygame graphical UI (does not come up at boot. Only when you press this button). More on this later, below.
  3. mpc play and mpc prev. This button starts playing and then goes to the previous playlist item (previous radio station). The mpc play is not crucial. I just have it there to force start mpd if it’s not already playing something.
  4. mpc play and mpc next. This button starts playing and then goes to the next playlist item (next radio station). The mpc play is not crucial. I just have it there to force start mpd if it’s not already playing something.

If you want to configure your own commands you need the appropriate KEY_XXXX kernel strings and the key numbers are at this website (https://github.com/torvalds/linux/blob/master/include/uapi/linux/input.h). The numbers are options in /etc/modprobe.d/adafruit.conf file and the corresponding KEY_XXXX entries end up in /etc/triggerhappy/triggers.d/mpc.conf. More info on gpio_keys_device module is here (https://github.com/notro/fbtft_tools/wiki/gpio_keys_device). A good reference for triggerhappy and other PiTFT stuff is here (https://github.com/notro/fbtft/wiki/FBTFT-shield-image), under triggerhappy (thd) heading. Also check out the man pages for thd.

We also need to modify the system startup script for triggerhappy so that it starts as user root (by default it starts as nobody). If we don’t do this we will not be able to run our nice ui python file later on from the buttons. Make the changes to DAEMON_ARGS variable (I’ve commented the original in the pic below), change “nobody” to “root”.
Screen Shot 2014-12-30 at 3.29.49 PM
In the next step we’ll reconfigure the init process to bypass login on console 1 (on PiTFT) and disable all the other consoles (we’re not using them and they waste memory). Once login has been bypassed we can freely run ncmpcpp on the PiTFT during boot. For this we need to create two files in /root. First /root/.ncmpcpp/config and then a shell script (don’t forget to chmod 700 it so you can execute it) called ncmpcpp.sh which we’ll call from /etc/inittab later.
Screen Shot 2014-12-30 at 1.02.11 PMScreen Shot 2014-12-30 at 1.06.32 PM
Note: MAKE SURE YOU “chmod 700 /root/ncmpcpp.sh”, otherwise you could end up with a infinite boot loop which is not fun.
Screen Shot 2014-12-30 at 1.13.58 PM
The contents of my /etc/inittab are here (be extremely careful when changing things in here).

# /etc/inittab: init(8) configuration.
# $Id: inittab,v 1.91 2002/01/25 13:35:21 miquels Exp $
# The default runlevel.
id:2:initdefault:
# Boot-time system configuration/initialization script.
# This is run first except when booting in emergency (-b) mode.
si::sysinit:/etc/init.d/rcS
# What to do in single-user mode.
~~:S:wait:/sbin/sulogin
# /etc/init.d executes the S and K scripts upon change
# of runlevel.
#
# Runlevel 0 is halt.
# Runlevel 1 is single-user.
# Runlevels 2-5 are multi-user.
# Runlevel 6 is reboot.
l0:0:wait:/etc/init.d/rc 0
l1:1:wait:/etc/init.d/rc 1
l2:2:wait:/etc/init.d/rc 2
l3:3:wait:/etc/init.d/rc 3
l4:4:wait:/etc/init.d/rc 4
l5:5:wait:/etc/init.d/rc 5
l6:6:wait:/etc/init.d/rc 6
# Normally not reached, but fallthrough in case of emergency.
z6:6:respawn:/sbin/sulogin
# What to do when CTRL-ALT-DEL is pressed.
ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now
# Action on special keypress (ALT-UpArrow).
#kb::kbrequest:/bin/echo "Keyboard Request--edit /etc/inittab to let this work."
# What to do when the power fails/returns.
pf::powerwait:/etc/init.d/powerfail start
pn::powerfailnow:/etc/init.d/powerfail now
po::powerokwait:/etc/init.d/powerfail stop
# /sbin/getty invocations for the runlevels.
#
# The "id" field MUST be the same as the last
# characters of the device (after "tty").
#
# Format:
#  :::
#
# Note that on most Debian systems tty7 is used by the X Window System,
# so if you want to add more getty's go ahead but skip tty7 if you run X.
#
1:2345:respawn:/sbin/getty  --skip-login --login-program /root/ncmpcpp.sh 38400 tty1 
#1:2345:respawn:/sbin/getty --autologin pi --noclear 38400 tty1 
#1:2345:respawn:/sbin/getty --noclear 38400 tty1 
#2:23:respawn:/sbin/getty 38400 tty2
#3:23:respawn:/sbin/getty 38400 tty3
#4:23:respawn:/sbin/getty 38400 tty4
#5:23:respawn:/sbin/getty 38400 tty5
#6:23:respawn:/sbin/getty 38400 tty6
# Example how to put a getty on a serial line (for a terminal)
#
#T0:23:respawn:/sbin/getty -L ttyS0 9600 vt100
#T1:23:respawn:/sbin/getty -L ttyS1 9600 vt100
# Example how to put a getty on a modem line.
#
#T3:23:respawn:/sbin/mgetty -x0 -s 57600 ttyS3
#Spawn a getty on Raspberry Pi serial line
#T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100

Now, once more, before we reboot and screw it all up make sure you can run /root/ncmpcpp from command line ssh. You should see a clock. Press “q” to exit. Good…..now reboot and hopefully if you didn’t screwup you should see a nice console screen with the clock on you PiTFT.

IMG_1467

 

I’m playing something here. You will need to give Wifi a chance to get settled before pressing the previous/next buttons (3rd and 4th buttons from the left).

Now lets move onto getting the second button to work (i.e. the nice pygame gui). The original source for this came from https://github.com/ISO-B/pmb-pitft. I’ve done a bunch of changes, since I use the Pi for radio only and radio stations do not adhere to the Artist – Title standard. You can use the original code, but since the program is not getting the right info the last.fm pics and the info are wrong. The other change I’ve done is show the artist picture from last.fm if the album information is missing — which is the case when you’re playing internet radio. Almost all radio stations I’ve come across show Artist – Song Title, not Album Name.
You can download my version (https://dl.dropboxusercontent.com/u/3665206/pmb-pitft.tgz) as a tar file and open it up in /home/pi/ folder using “tar -zxvf ./pmb-pitft.tgz” (assuming the file is in /home/pi to start the tar extraction).
You’ll also need the pylast library to get lastfm information, so lets install it using “apt-get install python-pylast”. Once that’s done edit the ui.py file (in /home/pi/pmb-pitft/pmb-pitft folder) and change the API_KEY, API_SECRET, username and password to your accounts credentials (API_KEY and API_SECRET are at http://www.last.fm/api/account once you login to your account).
Screen Shot 2014-12-30 at 3.16.25 PM
Now let’s make sure the extraction went okay. Assuming you’ve followed my instructions if you issue “/usr/bin/python /home/pi/pmb-pitft/pmb-pitft/ui.py” from /home/pi folder, you should see a nice gui on pitft like below.
IMG_1469
Make sure this command works, since our 2nd button on pitft is hardwired to run this command when you press it.
Okay assuming you’re still with me. One more thing we need to do is to change the console fonts to make the ncmpcpp “clock” screen a bit better looking. This is the standard procedure that’s explained in other places as well (adafruit). You need to run the command “dpkg-reconfigure console-setup” and follow the screens.
Screen Shot 2014-12-30 at 3.48.46 PM Screen Shot 2014-12-30 at 3.48.52 PM Screen Shot 2014-12-30 at 3.49.10 PM Screen Shot 2014-12-30 at 3.49.19 PM
Once this process finishes, you’ll end up with a clock startup screen like this.
IMG_1470
And again from left to right the buttons will do “Shutdown -h now”, pygame ui, Previous Song, Next Song. As I type this I’m getting bad sectors on the Pi (cheap SD card I guess), so I’m off to backup everything. You should do the same RIGHT NOW :-).
At this point you can go off exploring (You did create a backup right?). I would check out adafruits page on pitft resistive (https://learn.adafruit.com/adafruit-pitft-28-inch-resistive-touchscreen-display-raspberry-pi?view=all) and start paying attention about halfway down the page around “sudo reboot and look at the console output” paragraph (Just search for it on the page), where it starts talking about calibrating the screen for X and stuff. Frankly I found the default calibration pretty good.
For a really good web interface that literally takes 2 minutes to setup check out ympd (http://www.ympd.org/). It’s so simple (specially if you grab the precompiled executable), no configuration, no rocket science……oh and did I say it looks great :-).
ympd_playlist

Proving the Network is Not the Problem With iperf – Packet Life

datePosted on 15:35, November 24th, 2013 by Many Ayromlou

Proving the Network is Not the Problem With iperf – Packet Life: “When an application fails to perform as expected, the network is often the first thing blamed. I suppose this is because end users typically view the network as the sole limiting factor with regard to throughput, unaware of the intricacies of application, database, and storage performance. For some reason, the burden of proof always seems to fall onto networkers to demonstrate that the network is not at fault before troubleshooting can begin elsewhere. This article demonstrates how to simulate user traffic between two given points on a network and measure the achievable throughput.”

(Via.)

Streaming 1080P video using Raspberry Pi (or BeagleBone Black)

datePosted on 21:24, November 9th, 2013 by Many Ayromlou

I’ve finally got this project to a point were I can do a write up on it. The following hardware is needed:

  1. Raspberry Pi 512K version (or BeagleBone Black)
  2. Logitech C920 Webcam
  3. 16 GB micro SDHC card (can probably do it on 8GB too)
  4. Wireless dongle supported by linux (I’m using a TrendNet TEW-645UB which was pretty much plug and play)

The goal of this project is to get the following installed and configured:

  1. CRTMP streaming server
  2. C920 install and config (v4l2), ffmpeg installation, boneCV installation from Derek Molloy’s site
  3. configuring ddclient for dynamic DNS (optional)
  4. putting it all together and creating a webpage with embedded JWplayer to view the stream

UPDATE: Sound works now on BeagleBone Black. On Raspberry you will run into alsa buffer xruns. See below for updated streamVideoRTSP script.

What I still need to figure out is the sound off the camera. At the moment I got buttery smooth 1080P video off the Pi (on wired or wireless connection) running at 5Mb/s but the sound is yet to come.

0) Preparation:

So to prepare you need to get linux installed on your Pi or BBB (BeagleBone Black). I used the latest raspbian for the PI and BeageBone Black Ubuntu Raring 13.04 for BBB. Get it installed onto your SD card. If you use a larger than 8GB SD card you can follow the procedure below to expand the partition from 8GB to whatever your SD card can hold (mine is a 16GB card) (NOTE: almost all commands need to be executed as root so do a sudo -i to start with):

  • Use fdisk to see the partition table
    root@debian-armhf:/# fdisk /dev/mmcblk0
    
    Command (m for help): p
    
    Disk /dev/mmcblk0: 3947 MB, 3947888640 bytes
    4 heads, 16 sectors/track, 120480 cylinders, total 7710720 sectors
    Units = sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 512 bytes
    I/O size (minimum/optimal): 512 bytes / 512 bytes
    Disk identifier: 0x80000000
    
            Device Boot      Start         End      Blocks   Id  System
    /dev/mmcblk0p1   *        2048        4095        1024    1  FAT12
    /dev/mmcblk0p2            4096     3751935     1873920   83  Linux
  • In this case we’re expanding partition 2 by first deleting it and without writing the partition table recreating it to span the entire disk (and then writing the new partition table to SD card). This in effect expands the partition. We will expand the filesystem after reboot.
    Command (m for help): d
    Partition number (1-4): 2
    
    Command (m for help): p
    
    Disk /dev/mmcblk0: 3947 MB, 3947888640 bytes
    4 heads, 16 sectors/track, 120480 cylinders, total 7710720 sectors
    Units = sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 512 bytes
    I/O size (minimum/optimal): 512 bytes / 512 bytes
    Disk identifier: 0x80000000
    
            Device Boot      Start         End      Blocks   Id  System
    /dev/mmcblk0p1   *        2048        4095        1024    1  FAT12
    
    Command (m for help): 
    Command (m for help): n
    Partition type:
       p   primary (1 primary, 0 extended, 3 free)
       e   extended
    Select (default p): p
    Partition number (1-4, default 2): 2
    First sector (4096-7710719, default 4096): 
    Using default value 4096
    Last sector, +sectors or +size{K,M,G} (4096-7710719, default 7710719): 
    Using default value 7710719
    
    Command (m for help): p
    
    Disk /dev/mmcblk0: 3947 MB, 3947888640 bytes
    4 heads, 16 sectors/track, 120480 cylinders, total 7710720 sectors
    Units = sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 512 bytes
    I/O size (minimum/optimal): 512 bytes / 512 bytes
    Disk identifier: 0x80000000
    
            Device Boot      Start         End      Blocks   Id  System
    /dev/mmcblk0p1   *        2048        4095        1024    1  FAT12
    /dev/mmcblk0p2            4096     7710719     3853312   83  Linux
    
    Command (m for help): 
    Command (m for help): w
    
    The partition table has been altered!
    
    Calling ioctl() to re-read partition table.
    
    WARNING: Re-reading the partition table failed with error 16: Device or resource busy.
    The kernel still uses the old table. The new table will be used at
    the next reboot or after you run partprobe(8) or kpartx(8)
    Syncing disks.
    root@debian-armhf:/# reboot
  • Once you’re back from reboot we need to expand the filesystem to cover the new partition. Don’t forget to sudo -i to become root.
    root@debian-armhf:/# df
    Filesystem     1K-blocks   Used Available Use% Mounted on
    rootfs           1811704 740184    977824  44% /
    /dev/root        1811704 740184    977824  44% /
    devtmpfs          253920      0    253920   0% /dev
    tmpfs              50816    216     50600   1% /run
    tmpfs               5120      0      5120   0% /run/lock
    tmpfs             101620      0    101620   0% /run/shm
    /dev/mmcblk0p1      1004    474       530  48% /boot/uboot
    root@debian-armhf:/# 
    
    root@debian-armhf:/# resize2fs /dev/mmcblk0p2 
    resize2fs 1.42.5 (29-Jul-2012)
    Filesystem at /dev/mmcblk0p2 is mounted on /; on-line resizing required
    old_desc_blocks = 1, new_desc_blocks = 1
    The filesystem on /dev/mmcblk0p2 is now 963328 blocks long.
    
    root@debian-armhf:/# df
    Filesystem     1K-blocks   Used Available Use% Mounted on
    rootfs           3761680 741096   2851404  21% /
    /dev/root        3761680 741096   2851404  21% /
    devtmpfs          253920      0    253920   0% /dev
    tmpfs              50816    216     50600   1% /run
    tmpfs               5120      0      5120   0% /run/lock
    tmpfs             101620      0    101620   0% /run/shm
    /dev/mmcblk0p1      1004    474       530  48% /boot/uboot
    root@debian-armhf:/# 

1) CRTMP Server installation

CRTMP server is a streaming media server very similar to wowza. I use this to point ffmpeg at and to get playback on JWplayer. Grab the source code and follow the instructions for installing it on Ubuntu from http://wiki.rtmpd.com/quickbuild. You will need to create your build environment before you start building so do the command below to setup your environment and get the prerequisites installed:

  • Install needed packages
    root@ubuntu-armhf:/# apt-get install g++ subversion cmake make libssl-dev
  • Run these two additional commands
    root@ubuntu-armhf:/# apt-get install libcurl4-openssl-dev pkg-config
    root@ubuntu-armhf:/# pkg-config openssl --cflags --libs
  • Make sure that the last commands output was “-lssl -lcrypto”
  • Fetch the latest repo version of CRTMP
    cd /opt
    svn co --username anonymous --password "" https://svn.rtmpd.com/crtmpserver/trunk crtmpserver
    cd /crtmpserver/builders/cmake/cmake_find_modules
  • Edit the file Find_openssl.cmake and add the following path to the PATHS section of ssl, crypto and z sections above /usr/lib64 line:
    /usr/lib/arm-linux-gnueabihf
  • Edit the file Find_pcap.cmake and add the following path to the PATHS section of pcap sections above /usr/lib64 line:
    /usr/lib/arm-linux-gnueabihf
  • Edit the file Find_dl.cmake and add the following path to the PATHS section of dl sections above /usr/lib64 line:
    /usr/lib/arm-linux-gnueabihf
  • Edit the file Find_lua.cmake and add the following path to the PATHS section of lua sections above /usr/lib64 line:
    /usr/lib/arm-linux-gnueabihf
  • Might have to do this if locale is giving you grief (Note: I’ve picked en_CA since I live in Canada, you need to pick the right one for your country/region):
    root@ubuntu-armhf:/opt/crtmpserver/builders/cmake/cmake_find_modules# sudo locale-gen en_CA en_CA.UTF-8
    
    Generating locales...
    
    en_CA.ISO-8859-1... done
    
    en_CA.UTF-8... done
    
    Generation complete.
    
    root@ubuntu-armhf:/opt/crtmpserver/builders/cmake/cmake_find_modules# dpkg-reconfigure locales
    
    Generating locales...
    
    en_CA.ISO-8859-1... up-to-date
    
    en_CA.UTF-8... up-to-date
    
    en_US.UTF-8... done
    
    Generation complete.
  • Start building crtmp
    root@ubuntu-armhf:/opt/crtmpserver/builders/cmake# ./run
    
  • This process will take a while……go have a couple of coffee’s and/or snacks

Once this process is finished you’ll end up with the executable in /opt/crtmpserver/builders/cmake/crtmpserver, but that’s not how you run it. First you need a config file — you can edit crtmpserver.lua in /opt/crtmpserver/builders/cmake/crtmpserver or save a copy of the original and create a new one with the content from below (I’ve just cleaned up the original a tiny bit).

-- Start of the configuration. This is the only node in the config file. 
-- The rest of them are sub-nodes
configuration=
{
	-- if true, the server will run as a daemon.
	-- NOTE: all console appenders will be ignored if this is a daemon
	daemon=false,
	-- the OS's path separator. Used in composing paths
	pathSeparator="/",

	-- this is the place where all the logging facilities are setted up
	-- you can add/remove any number of locations

	logAppenders=
	{
		{
			-- name of the appender. Not too important, but is mandatory
			name="console appender",
			-- type of the appender. We can have the following values:
			-- console, coloredConsole and file
			-- NOTE: console appenders will be ignored if we run the server
			-- as a daemon
			type="coloredConsole",
			-- the level of logging. 6 is the FINEST message, 0 is FATAL message.
			-- The appender will "catch" all the messages below or equal to this level
			-- bigger the level, more messages are recorded
			level=6
		},
		{
			name="file appender",
			type="file",
			level=6,
			-- the file where the log messages are going to land
			fileName="/tmp/crtmpserver",
			--newLineCharacters="\r\n",
			fileHistorySize=10,
			fileLength=1024*256,
			singleLine=true
		}
	},

	-- this node holds all the RTMP applications
	applications=
	{
		-- this is the root directory of all applications
		-- usually this is relative to the binary execuable
		rootDirectory="applications",

		--this is where the applications array starts
		{
			-- The name of the application. It is mandatory and must be unique 
			name="appselector",
			-- Short description of the application. Optional
			description="Application for selecting the rest of the applications",

			-- The type of the application. Possible values are:
			-- dynamiclinklibrary - the application is a shared library
			protocol="dynamiclinklibrary",
			-- the complete path to the library. This is optional. If not provided, 
			-- the server will try to load the library from here
			-- //lib.{so|dll|dylib}
			-- library="/some/path/to/some/shared/library.so"

			-- Tells the server to validate the clien's handshake before going further. 
			-- It is optional, defaulted to true
			validateHandshake=false,
			-- this is the folder from where the current application gets it's content.
			-- It is optional. If not specified, it will be defaulted to:
			-- //mediaFolder
			-- mediaFolder="/some/directory/where/media/files/are/stored"
			-- the application will also be known by that names. It is optional
			--aliases=
			--{
			--	"simpleLive",
			--	"vod",
			--	"live",
			--},
			-- This flag designates the default application. The default application
			-- is responsable of analyzing the "connect" request and distribute 
			-- the future connection to the correct application.
			default=true,
			acceptors = 
			{
				{
					ip="0.0.0.0",
					port=1935,
					protocol="inboundRtmp"
				},
				{
					ip="0.0.0.0",
					port=8081,
					protocol="inboundRtmps",
					sslKey="server.key",
					sslCert="server.crt"
				},
				{
					ip="0.0.0.0",
					port=8080,
					protocol="inboundRtmpt"
                },
			}
		},
		{
			description="FLV Playback Sample",
			name="flvplayback",
			protocol="dynamiclinklibrary",
			aliases=
			{
				"simpleLive",
				"vod",
				"live",
				"WeeklyQuest",
				"SOSample",
				"oflaDemo",
			},
			acceptors = 
			{
				{
					ip="0.0.0.0",
					port=6666,
					protocol="inboundLiveFlv",
					waitForMetadata=true,
				},
				{
					ip="0.0.0.0",
					port=9999,
					protocol="inboundTcpTs"
				},
				{
					ip="0.0.0.0",
					port=10000,
					protocol="inboundUdpTs"
				},
				--[[{
					ip="0.0.0.0",
					port=7654,
					protocol="inboundRawHttpStream",
					crossDomainFile="/tmp/crossdomain.xml"
				}, ]]--
				{
					ip="0.0.0.0",
					port=554,
					protocol="inboundRtsp"
				},
			},
			externalStreams = 
			{
				--[[
				{
					uri="rtsp://fms20.mediadirect.ro/live2/realitatea/realitatea",
					localStreamName="rtsp_test",
					forceTcp=true
				},
				{
					uri="rtmp://edge01.fms.dutchview.nl/botr/bunny",
					localStreamName="rtmp_test",
					swfUrl="http://www.example.com/example.swf",
					pageUrl="http://www.example.com/",
					tcUrl="rtmp://edge01.fms.dutchview.nl/botr/bunny", --this one is usually required and should have the same value as the uri
					emulateUserAgent="MAC 10,1,82,76",
				}
				{
                        		uri="rtsp://animalhousenc.dvrdns.org:554/streaming/channels/0",
                        		localStreamName="PoolSide",
                        		forceTcp=true
                		},
               		 	{
                       			 uri="rtsp://animalhousenc.dvrdns.org:556/streaming/channels/0",
                       			 localStreamName="BoneYard",
                       			 forceTcp=true
                		},
                		{
                       			 uri="rtsp://animalhousenc.dvrdns.org:557/streaming/channels/0",
                       			 localStreamName="BigPool",
                       			 forceTcp=true
                		},
               		 	{
                       			 uri="rtsp://192.168.1.186:554/mpeg4/media.amp?videocodec=h264&streamprofile=high",
                       			 localStreamName="nerd",
                       			 forceTcp=true
                		}, 
               		 	{
                       			 uri="rtsp://192.168.1.190:554/0",
                       			 localStreamName="leopard",
                       			 forceTcp=true
                		}, ]]--
			},
			validateHandshake=false,
			--enableCheckBandwidth=true,
			--[[authentication=
			{
				rtmp={
					type="adobe",
					encoderAgents=
					{
						"FMLE/3.0 (compatible; FMSc/1.0)",
						"My user agent",
					},
					usersFile="users.lua"
				},
				rtsp={
					usersFile="users.lua"
				}
			}, --]]
			mediaStorage = {
			--[[	namedStorage1={
					--this storage contains all properties with their
					--default values. The only mandatory property is
					--mediaFolder
					description="Some storage",
					mediaFolder="/Volumes/Storage/media/",
					metaFolder="/tmp/metadata",
					enableStats=false,
					clientSideBuffer=15,
					keyframeSeek=false,
					seekGranularity=0.1,
				},
				namedStorage2={
					mediaFolder="/Volumes/Storage/media/mp4",
					metaFolder="/tmp/metadata",
					seekGranularity=0.2,
					enableStats=true,
				},
				namedStorage3={
					mediaFolder="/Volumes/Storage/media/flv",
					metaFolder="/tmp/metadata",
				},
				{
					--this one doesn't have a name
					mediaFolder="/Volumes/Storage/media/mp3",
				} --]]
			},
		},
		{
			name="samplefactory",
			description="asdsadasdsa",
			protocol="dynamiclinklibrary",
			aliases=
			{
				"httpOutboundTest"
			},
			acceptors = 
			{
				{
					ip="0.0.0.0",
					port=8989,
					protocol="httpEchoProtocol"
				},
				{
					ip="0.0.0.0",
					port=8988,
					protocol="echoProtocol"
				}
			},
			validateHandshake=false,
			--default=true,
		},
		{
			name="vptests",
			description="Variant protocol tests",
			protocol="dynamiclinklibrary",
			aliases=
			{
				"vptests_alias1",
				"vptests_alias2",
				"vptests_alias3",
			},
			acceptors = 
			{
				{
					ip="0.0.0.0",
					port=1111,
					protocol="inboundHttpXmlVariant"
				}
			},
			validateHandshake=false,
			--default=true,
		},
		{
			name="admin",
			description="Application for administering",
			protocol="dynamiclinklibrary",
			aliases=
			{
				"admin_alias1",
				"admin_alias2",
				"admin_alias3",
			},
			acceptors = 
			{
				{
					ip="0.0.0.0",
					port=1112,
					protocol="inboundJsonCli",
					useLengthPadding=true
				},
			},
			validateHandshake=false,
			--default=true,
		},
		{
			name="proxypublish",
			description="Application for forwarding streams to another RTMP server",
			protocol="dynamiclinklibrary",
			acceptors =
			{
				{	
					ip="0.0.0.0",
					port=6665,
					protocol="inboundLiveFlv"
				},
			},
			abortOnConnectError=true,
			targetServers = 
			{
				--[[{
					targetUri="rtmp://x.xxxxxxx.fme.ustream.tv/ustreamVideo/xxxxxxx",
					targetStreamName="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
					localStreamName="stream1",
					emulateUserAgent="FMLE/3.0 (compatible; FMSc/1.0 http://www.rtmpd.com)"
				}]]--,
				--[[{
					targetUri="rtmp://gigi:spaima@localhost/vod",
					targetStreamType="live", -- (live, record or append)
					emulateUserAgent="My user agent",
					localStreamName="stream1",
					keepAlive=true
				},]]--
			},
			externalStreams = 
			{
				--[[{
					uri="rtsp://fms20.mediadirect.ro/live2/realitatea/realitatea",
					localStreamName="stream1",
					forceTcp=true,
					keepAlive=true
				},]]--
			},
			validateHandshake=false,
			--default=true,
		},
		{
			name="stresstest",
			description="Application for stressing a streaming server",
			protocol="dynamiclinklibrary",
			targetServer="localhost",
			targetApp="vod",
			active=false,
			--[[streams = 
			{
				"lg00","lg01","lg02","lg03","lg04","lg05","lg06","lg07","lg08",
				"lg09","lg10","lg11","lg12","lg13","lg14","lg15","lg16","lg17",
				"lg18","lg19","lg20","lg21","lg22","lg23","lg24","lg25","lg26",
				"lg27","lg28","lg29","lg30","lg31","lg32","lg33","lg34","lg35",
				"lg36","lg37","lg38","lg39","lg40","lg41","lg42","lg43","lg44",
				"lg45","lg46","lg47","lg48","lg49"
			},]]--
			streams = 
			{
				"mp4:lg.mp4"
			},
			numberOfConnections=10,
			randomAccessStreams=false
		},
		--[[{
			name="vmapp",
			description="An application demonstrating the use of virtual machines",
			protocol="dynamiclinklibrary",
			vmType="lua",
			script="flvplayback.lua",
			aliases=
			{
				"flvplayback1",
				"vod1"
			},
			acceptors=
			{
				{
					ip="0.0.0.0",
					port=6544,
					protocol="inboundTcpTs"
				}
			}
		},]]--
		--#INSERTION_MARKER# DO NOT REMOVE THIS. USED BY appscaffold SCRIPT.
	}
}

Once you have this saved (or modified yours to look like this you can go ahead and try to start the server with the following command (NOTE: you need to be in the cmake directory (rather than crtmpserver) and reference the files with partial paths……not sure why…..something to do with cmake base directory).

cd /opt/crtmpserver/builders/cmake/
./crtmpserver/crtmpserver ./crtmpserver/crtmpserver.lua

You should get output similar this this

/crtmpserver/src/crtmpserver.cpp:216 C++ RTMP Media Server (www.rtmpd.com) version 1.1_rc1 build 808 - Gladiator - (built on 2013-09-28T21:19:24.000)
/crtmpserver/src/crtmpserver.cpp:219 OS files descriptors count limits: 4096/4096
/crtmpserver/src/crtmpserver.cpp:221 Initialize I/O handlers manager: epoll without timerfd_XXXX support
/crtmpserver/src/crtmpserver.cpp:224 Configure modules
/crtmpserver/src/crtmpserver.cpp:230 Plug in the default protocol factory
/crtmpserver/src/crtmpserver.cpp:237 Configure factories
/thelib/src/configuration/module.cpp:97 Loaded factory from application samplefactory
/crtmpserver/src/crtmpserver.cpp:243 Configure acceptors
/thelib/src/netio/epoll/iohandlermanager.cpp:120 Handlers count changed: 0->1 IOHT_ACCEPTOR
/thelib/src/netio/epoll/iohandlermanager.cpp:120 Handlers count changed: 1->2 IOHT_ACCEPTOR
/thelib/src/netio/epoll/iohandlermanager.cpp:120 Handlers count changed: 2->3 IOHT_ACCEPTOR
/thelib/src/netio/epoll/iohandlermanager.cpp:120 Handlers count changed: 3->4 IOHT_ACCEPTOR
/thelib/src/netio/epoll/iohandlermanager.cpp:120 Handlers count changed: 4->5 IOHT_ACCEPTOR
/thelib/src/netio/epoll/iohandlermanager.cpp:120 Handlers count changed: 5->6 IOHT_ACCEPTOR
/thelib/src/netio/epoll/iohandlermanager.cpp:120 Handlers count changed: 6->7 IOHT_UDP_CARRIER
/thelib/src/netio/epoll/iohandlermanager.cpp:120 Handlers count changed: 7->8 IOHT_ACCEPTOR
/thelib/src/netio/epoll/iohandlermanager.cpp:120 Handlers count changed: 8->9 IOHT_ACCEPTOR
/thelib/src/netio/epoll/iohandlermanager.cpp:120 Handlers count changed: 9->10 IOHT_ACCEPTOR
/thelib/src/netio/epoll/iohandlermanager.cpp:120 Handlers count changed: 10->11 IOHT_ACCEPTOR
/thelib/src/netio/epoll/iohandlermanager.cpp:120 Handlers count changed: 11->12 IOHT_ACCEPTOR
/crtmpserver/src/crtmpserver.cpp:249 Configure instances
/crtmpserver/src/crtmpserver.cpp:255 Start I/O handlers manager: epoll without timerfd_XXXX support
/crtmpserver/src/crtmpserver.cpp:258 Configure applications
/thelib/src/configuration/module.cpp:177 Application admin instantiated
/thelib/src/configuration/module.cpp:177 Application appselector instantiated
/thelib/src/configuration/module.cpp:177 Application flvplayback instantiated
/thelib/src/netio/epoll/iohandlermanager.cpp:120 Handlers count changed: 12->13 IOHT_TIMER
/thelib/src/configuration/module.cpp:177 Application proxypublish instantiated
/thelib/src/netio/epoll/iohandlermanager.cpp:120 Handlers count changed: 13->14 IOHT_TIMER
/thelib/src/configuration/module.cpp:177 Application samplefactory instantiated
/thelib/src/configuration/module.cpp:177 Application stresstest instantiated
/thelib/src/configuration/module.cpp:177 Application vptests instantiated
/crtmpserver/src/crtmpserver.cpp:264 Install the quit signal
/crtmpserver/src/crtmpserver.cpp:275 
+-----------------------------------------------------------------------------+
|                                                                     Services|
+---+---------------+-----+-------------------------+-------------------------+
| c |      ip       | port|   protocol stack name   |     application name    |
+---+---------------+-----+-------------------------+-------------------------+
|tcp|        0.0.0.0| 1112|           inboundJsonCli|                    admin|
+---+---------------+-----+-------------------------+-------------------------+
|tcp|        0.0.0.0| 1935|              inboundRtmp|              appselector|
+---+---------------+-----+-------------------------+-------------------------+
|tcp|        0.0.0.0| 8081|             inboundRtmps|              appselector|
+---+---------------+-----+-------------------------+-------------------------+
|tcp|        0.0.0.0| 8080|             inboundRtmpt|              appselector|
+---+---------------+-----+-------------------------+-------------------------+
|tcp|        0.0.0.0| 6666|           inboundLiveFlv|              flvplayback|
+---+---------------+-----+-------------------------+-------------------------+
|tcp|        0.0.0.0| 9999|             inboundTcpTs|              flvplayback|
+---+---------------+-----+-------------------------+-------------------------+
|udp|        0.0.0.0|10000|             inboundUdpTs|              flvplayback|
+---+---------------+-----+-------------------------+-------------------------+
|tcp|        0.0.0.0|  554|              inboundRtsp|              flvplayback|
+---+---------------+-----+-------------------------+-------------------------+
|tcp|        0.0.0.0| 6665|           inboundLiveFlv|             proxypublish|
+---+---------------+-----+-------------------------+-------------------------+
|tcp|        0.0.0.0| 8989|         httpEchoProtocol|            samplefactory|
+---+---------------+-----+-------------------------+-------------------------+
|tcp|        0.0.0.0| 8988|             echoProtocol|            samplefactory|
+---+---------------+-----+-------------------------+-------------------------+
|tcp|        0.0.0.0| 1111|    inboundHttpXmlVariant|                  vptests|
+---+---------------+-----+-------------------------+-------------------------+
/crtmpserver/src/crtmpserver.cpp:276 GO! GO! GO! (2368)

So far so good……the server is up and running now. You can stop it using Ctrl-C. Lets continue…….

2) C920 install and config (v4l2), ffmpeg installation, boneCV installation from Derek Molloy’s site

Logitec C920 is a really nice camera. Bit on the expensive side, but incredibly capable as we’ll see. I came across a post from Derek Molloy where he talks about UDP streaming h.264 streams off the C920 using a beagle board. That’s when I discovered the magic of this little camera. You see, the camera can provide image data via usb just like any other camera, but it also has the built in capability of producing a 3.5 Mb/s CBR video stream encoded in h.264 in either 640×480, 1280×720 or 1920×1080. I literally jumped out of my seat when I read this and picked one up from the local Best Buy (about $100). So now to get this signal in we need some of the tools that come with v4l (video4linux) utility package. Here is how you go about it:

  • First we need to install v4l-utils, ffmpeg and git (need git to grab the code in next step)
    apt-get install v4l-utils ffmpeg git
  • Then we need to pull down some code Derek has modified (and or written) from his git repo
    cd /opt
    git clone git://github.com/derekmolloy/boneCV
    
  • Next we need to get into the boneCV directory and recompile Derek’s capture.c program
    cd /opt/boneCV
    gcc -o capture capture.c
  • Now that we have the fresh capture program maybe we should stop and let me explain. capture.c is a V4L2 video capture example, modified by Derek Molloy for the Logitech C920 camera. He’s added the -F mode for H264 capture and associated help detail, plus an option to allow capture to capture infinite number of frames. Before we continue to the next step it’s worth trying to visualize the chain we’re trying to create. Capture (capture.c) will be called to put the camera in -F mode (1080p h.264 pre-encoded 3.5Mb/s CBR stream over USB) and to continuously pass the frames to a pipe which will feed avconv (a program that comes with ffmpeg) that will not touch the video encoding of the file but will transmit it to a RTSP destination (our crtmp streaming server). Once the stream is runnning we will use JWplayer to view the RTMP stream. The reason I decided to use JWplayer is that various incarnations of VLC say they support RTMP, but their implementation is really bad. For the longest time while using VLC to view the stream (I think it was version 2.1.x and 2.2.x nightly builds) I had freezes and breakups in the stream and I thought the poor Pi was not doing it’s job. NO, it was the player, the Pi (and Beagle Board Black) worked wonderfully. So now we need to modify the streamVideoRTSP file Derek has to look like the following (might want to save the original as .bak or something).
    #!/bin/bash
    echo "Video Streaming for the Beaglebone - derekmolloy.ie"
    echo "Piping the output of capture to avconv"
    #1080P mode 
    v4l2-ctl --set-fmt-video=width=1920,height=1080,pixelformat=1
    #720P mode
    #v4l2-ctl --set-fmt-video=width=1280,height=720,pixelformat=1
    
    # Pipe the output of capture into avconv/ffmpeg
    # capture "-F"   My H264 passthrough mode
    #         "-o"   Output the video (to be passed to avconv via pipe)
    #         "-c0"  Capture 0 frames, which means infinite frames in my program
    # avconv "-i -"  Take the input from the pipe
    #        "-vcodec copy" Do not transcode the video
    
    #1080P mode
    ./capture -F -o -c0|avconv -re -i - -f alsa -ac 2 -i hw:1,0 -strict experimental -threads 0 -acodec aac -ab 64k -ac 2 -vcodec copy -f  rtsp -metadata title=teststream rtsp://127.0.01:554/live
    #720P mode
    #./capture -f -o -c0|avconv -re -i - -f alsa -ac 2 -i hw:1,0 -strict experimental -threads 0 -acodec aac -ab 64k -ac 2 -vcodec copy -f  rtsp -metadata title=teststream rtsp://127.0.01:554/live
     

3) Configuring ddclient for dynamic DNS (optional)

This is totally optional and has no effect on the final product (makes life a bit simpler). I’m just going to provide the bare minimum explanation and my config. This process is very dependant on your DNS provider (if you have one), my example config is for my provider easydns.com. Your mileage will vary :-).

  • First we need to get ddclient program installed (this is one of dynamic dns tools available in linux)
    apt-get install ddclient
  • Then we need to edit the config file located in /etc called ddclient.conf. Here is mine which is specific for easydns.com. YOU WILL HAVE TO MODIFY THIS TO SUITE YOUR DNS PROVIDER.
    
    # Configuration file for ddclient generated by debconf
    #
    # /etc/ddclient.conf
    # updates internet ip on wired
    protocol=easydns,
    # Use this is you want to register the interface ip address (ie: You're not behind a NAT or you don't care)
    use=if, if=eth0,
    # Use this is you want to register your external ip address (ie: You're behind a NAT and want to register your outside IP address not the internal 192.168.x.x one)
    #use=web, web=checkip.dyndns.com/, web-skip='IP Address' 
    server=members.easydns.com,
    login=easydnsuserid,
    password='easydnspassword',
    hostname.domain.com
    
  • If you’ve enabled two factor authentication on easyDNS (or maybe even if you have not) there is a token that you’ll need to get called “Dynamic Authentication Token”. You can grab yours under the dynamic records page by enabling “Dynamic Authentication Token” and vieing your code. I will use XXXXXXXXXXXXXXXX as my code in the following example (NOTE: server and password clauses need to be changed):
    
    # Configuration file for ddclient generated by debconf
    #
    # /etc/ddclient.conf
    # updates internet ip on wired
    protocol=easydns,
    # Use this is you want to register the interface ip address (ie: You're not behind a NAT or you don't care)
    use=if, if=eth0,
    # Use this is you want to register your external ip address (ie: You're behind a NAT and want to register your outside IP address not the internal 192.168.x.x one)
    #use=web, web=checkip.dyndns.com/, web-skip='IP Address' 
    server=api.cp.easydns.com,
    login=easydnsuserid,
    password='XXXXXXXXXXXXXXXX',
    hostname.domain.com
    
  • Once the config is there we can restart the ddclient service
    service ddclient restart
  • If you want to check/test/debug your ddclient config, first stop the daemon that’s running in the backgroud, start it from command line in forground like below
    service ddclient stop
    ddclient -daemon=0 -debug -verbose -noquiet

4) Putting it all together and creating a webpage with embedded JWplayer to view the stream

So now you need to grab JWplayer (the free version) install it (copy the jwplayer folder) into a folder on your webserver (I copied mine into a folder of my blog server). The main file here is the HTML file that has the specifications for the stream in it. You need to create this to suite your need (ie: if you have dynamic DNS use the DNS name or if you don’t use the IP address of the Pi/BeagleBoard. Your mileage will vary :-).

Screen Shot 2013-11-09 at 4.42.17 PM

The above code is an example you will need to sustitute your own data to get it to work. We need two ssh windows off the Pi (one to run the crtmpserver and the other to start capturing and feeding it via streamVideoRTSP script. So go ahead start crtmp (see above….we did this as a test in step 1) and in the other window start streamVideoRTSP script. Those two windows should look like this:

Screen Shot 2013-11-09 at 4.59.39 PM

That’s pretty much it. If you now load the html file for jwplayer and press play (assuming you’ve done everything correctly) the stream should start playing in about 4-5 seconds. The encoding delay in the entire chain is about 2-3 seconds, the quality (considering it’s a webcam feeding a $35 computer) is really good and given proper power the Pi can steam this 1080p/30 stream without a issue. Just for the fun of it I also (at the same time) tried to feed the crtmp server (on the pi) a seperate quarter rez HD stream (640×360) encoded by ffmpeg on my desktop and yep, no problems (although the Pi is on medium overclocking settings). These RTMP streams can also be very easily scaled by passing them to larger crtmp installations and/or ustream/wowza for rebroadcast. Below you’ll find a bunch of ffmpeg command line entries I used for this second stream and also a quick (optional) write up on how I got the wireless dongle from Trendnet to work and configured from CLI.

./ffmpeg -re -i /Volumes/Qmultimedia/1217209\(73\).avi -vcodec libx264  -b 500000 -s 640x360 -strict experimental -g 25 -me_method zero -acodec aac -ab 96000 -ar 48000 -ac 2 -vbsf h264_mp4toannexb -f mpegts -metadata title=xxx udp://192.168.1.69:10000?pkt_size=1316
./ffmpeg -re -i /Volumes/Qmultimedia/1217209\(73\).avi -vcodec libx264  -b 500000 -s 640x360 -strict experimental -g 25 -me_method zero -acodec aac -ab 96000 -ar 48000 -ac 2 -f flv rtmp://192.168.1.69:1935/live/xxx
./ffmpeg -re -i /Volumes/Qmultimedia/1217209\(73\).avi -vcodec libx264  -b 500000 -s 640x360 -strict experimental -g 25 -me_method zero -acodec aac -ab 96000 -ar 48000 -ac 2 -f rtsp -metadata title=xxx rtsp://192.168.1.69:554/live

For wireless I’m using a TrendNet TEW-645UB which is directly supported under linux. Initially I used wpa_cli to get things configured and once the system was configured I massaged the files a bit. Here is a log of the whole thing:

root@picrtmp:~# lsusb
Bus 001 Device 002: ID 0424:9512 Standard Microsystems Corp. 
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. 
Bus 001 Device 004: ID 157e:3013 TRENDnet 
Bus 001 Device 006: ID 046d:082d Logitech, Inc. 
root@picrtmp:~# wpa_cli 
wpa_cli v1.0
Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi> and contributors

This program is free software. You can distribute it and/or modify it
under the terms of the GNU General Public License version 2.

Alternatively, this software may be distributed under the terms of the
BSD license. See README and COPYING for more details.

Selected interface 'wlan0'

Interactive mode

> scan
OK
CTRL-EVENT-SCAN-RESULTS 
> scan_results
bssid / frequency / signal level / flags / ssid
7c:d1:c3:zz:yy:xx	2411	-50	[WPA2-PSK-CCMP][ESS]	Nerdlogger
7c:d1:c3:zz:yy:xx	2412	-51	[WPA2-PSK-CCMP][ESS]	MaNiAc 2Ghz
8c:7c:b5:zz:yy:xx	2437	-64	[WPA-PSK-CCMP][ESS]	PS3-3313551
> add_network
0
> set_network 0 ssid "Nerdlogger"
OK
> set_network 0 psk "supersecretpassword"
OK
> enable_network 0
OK
> add_network
1
> set_network 1 ssid "MaNiAc 2Ghz"
OK
> set_network 1 psk "supersecretpassword"
OK
> enable_network 1
OK
> save_config
OK
> quit
> 
root@picrtmp:~# iwconfig
wlan0     IEEE 802.11bgn  ESSID:"MaNiAc 2Ghz"  
          Mode:Managed  Frequency:2.412 GHz  Access Point: 7C:D1:C3:CA:0F:7A   
          Bit Rate=43.3 Mb/s   Tx-Power=20 dBm   
          Retry  long limit:7   RTS thr:off   Fragment thr:off
          Encryption key:off
          Power Management:on
          Link Quality=59/70  Signal level=-51 dBm  
          Rx invalid nwid:0  Rx invalid crypt:0  Rx invalid frag:0
          Tx excessive retries:0  Invalid misc:1   Missed beacon:0

lo        no wireless extensions.

eth0      no wireless extensions.

root@picrtmp:~# ifconfig
eth0      Link encap:Ethernet  HWaddr b8:27:eb:37:a6:b3  
          inet addr:192.168.1.189  Bcast:192.168.1.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:10397 errors:0 dropped:1 overruns:0 frame:0
          TX packets:5361 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:726543 (709.5 KiB)  TX bytes:918179 (896.6 KiB)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

wlan0     Link encap:Ethernet  HWaddr 00:14:d1:cc:16:d2  
          inet addr:192.168.1.69  Bcast:192.168.1.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:1389 errors:0 dropped:41 overruns:0 frame:0
          TX packets:36 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:466517 (455.5 KiB)  TX bytes:4773 (4.6 KiB)

root@picrtmp:~# cat /etc/network/interfaces 
auto lo

iface lo inet loopback
auto eth0
iface eth0 inet dhcp

auto wlan0
allow-hotplug wlan0
iface wlan0 inet manual
	wpa-driver wext
	wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf

iface default inet dhcp

iface work inet dhcp

iface home inet static
	address 192.168.1.69
	netmask 255.255.255.0
	network 192.168.1.0
	broadcast 192.168.1.255
	gateway 192.168.1.1
	dns-nameservers 192.168.1.1

root@picrtmp:~# cat /etc/wpa_supplicant/wpa_supplicant.conf 
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
	ssid="Nerdlogger"
	psk="supersecretpassword"
	id_str="work"
}

network={
	ssid="MaNiAc 2Ghz"
	psk="supersecretpassword"
	id_str="home"
}

root@picrtmp:~# 

Turn Your FreeNAS Box Into the Ultimate Anonymous Downloading Machine

datePosted on 15:56, December 10th, 2012 by Many Ayromlou

Turn Your FreeNAS Box Into the Ultimate Anonymous Downloading Machine:

Here’s how to turn your FreeNAS box into the ultimate downloading machine so you can download safely and monitor its activity from anywhere.

(Via lifehacker.com)

Everything you ever needed to know about OSX launchd

datePosted on 14:22, July 31st, 2012 by Many Ayromlou

Great in-depth article by Nathan Grigg. Everything you ever wanted to know about launchd and how job scheduling can be easily done under OSX.

If you try to install Ubuntu 10.10 under parallels desktop 6.0 on OSX — atleast as of the writing of this article — you’ll soon discover that although your entire installation is done in a high (eg: 1920×1080) resolution, as soon as the install is done and you reboot, your VM is stuck at 1024×768. You can install the parallel tools using the menu option and it still won’t help — although it helps with 3D (ie: compiz). Under Gnomes System/Preferences/Monitors the highest resolution available is 1024×768 :-(. After searching around the net for the past week or so and trying just about every remedy — which did not work — I was about to give up, then I found the magic command that “makes it go” :-).

I’ve now got Ubuntu 10.10 running with PT/compiz under parallels 6.0 @ 1920×1080. No problem. Normally if you go inside ~/.config/ directory (.config folder under your home directory) you’ll notice that there is no “monitors.xml” file in there. That’s the per user X config file that gets the ball rolling. Generating the file is really easy. Open a teminal and issue the following command:

xrandr

This will generate (hopefully) the following output:

Note that 1024×768 is the default. Now if you go inside ~/.config/ directory you’ll find a “monitors.xml” file (below). Once you’ve got this file you can go to System/Preferences/Monitors and choose the higher resolution options (eg:1920×1080). The xrandr command should generate the file for you. If it doesn’t (not sure why), here is my version for parallel 6.0. I think it’s pretty generic so you should be able to cut and paste the content:

<monitors version="1">
  <configuration>
      <clone>no</clone>
      <output name="default">
          <vendor>???</vendor>
          <product>0x0000</product>
          <serial>0x00000000</serial>
          <width>1920</width>
          <height>1200</height>
          <rate>60</rate>
          <x>0</x>
          <y>0</y>
          <rotation>normal</rotation>
          <reflect_x>no</reflect_x>
          <reflect_y>no</reflect_y>
          <primary>no</primary>
      </output>
  </configuration>
</monitors>

Fixing Plymouth (boot splash) in Ubuntu 10.10 aka. Maverick Meerkat

datePosted on 14:10, November 1st, 2010 by Many Ayromlou

If you’ve recently installed Ubuntu 10.10 and have installed Nvidia and/or ATI drivers — or installed ubuntu under emulation — you’ll end up with a (butt) ugly splash screen. In my case under parallel 6.0 I ended up with a text boot screen that just read “Ubuntu 10.10″……Ughhh. Here is a quick tutorial on how to get a nice splash restored. This procedure also works in 10.04. Keep in mind that I’m doing everything with 1280×1024 screen size. your mileage might vary (ie: you might want 1024×768). You’ll need to get a terminal session opened for this:

  • Get the nice splash screen installed
    sudo apt-get install v86d
  • Edit your grub config file and add the following
    sudo vi /etc/default/grub
  • Look for this line:
    GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
  • and replace it with this (note: 1280×1024 screen res…..your mileage might vary):
    GRUB_CMDLINE_LINUX_DEFAULT="quiet splash nomodeset video=uvesafb:mode_option=1280x1024-24,mtrr=3,scroll=ywrap"
  • Still in the same file look for this line:
    #GRUB_GFXMODE=640x480
  • and replace it with this (note: 1280×1024 screen res…..your mileage might vary):
    GRUB_GFXMODE=1280x1024

Your /etc/default/grub file should look like this once you’re done (partial screenshot):

  • Save the file and issue the following command to start editing /etc/initramfs-tools/modules file:
    sudo vi /etc/initramfs-tools/modules
  • The file should be mostly commented out. At the end of the file insert the following line (note: 1280×1024 screen res…..your mileage might vary):
    uvesafb mode_option=1280x1024-24 mtrr=3 scroll=ywrap

Your /etc/initramfs-tools/modules file should look like this once you’re done:

  • Save the file and issue the following command:
    echo FRAMEBUFFER=y | sudo tee /etc/initramfs-tools/conf.d/splash
  • Finally issue the following two command to update grub:
    sudo update-grub2
    sudo update-initramfs -u

Reboot and Enjoy :-)

It’s been a while since I’ve had the pleasure (read: pain) of working with Sloowaris, but now that we have two 48TB Sun X4540 Thumpers in house, I have to…..Uggghhhh :-). Here are some notes:

  • Remember sudo -i does not work. Use “su -” to get the root environment through ssh (login as regular user).
  • The machine has 6 Controllers with 8 Disks each for a total of 48 disks.
  • To find out all the disks that are available on your system and their Labels…..root # format
    Searching for disks...done

    AVAILABLE DISK SELECTIONS:

  • To see the status of the zpool runroot # zpool status
    pool: pool1
    state: ONLINE
    status: The pool is formatted using an older on-disk format. The pool can
    still be used, but some features are unavailable.
    action: Upgrade the pool using 'zpool upgrade'. Once this is done, the
    pool will no longer be accessible on older software versions.
    scrub: none requested
    config:

    NAME STATE READ WRITE CKSUM
    pool1 ONLINE 0 0 0
    raidz1 ONLINE 0 0 0
    c0t3d0 ONLINE 0 0 0
    c1t3d0 ONLINE 0 0 0
    c2t3d0 ONLINE 0 0 0
    c3t3d0 ONLINE 0 0 0
    c4t3d0 ONLINE 0 0 0
    raidz1 ONLINE 0 0 0
    c5t3d0 ONLINE 0 0 0
    c0t7d0 ONLINE 0 0 0
    c1t7d0 ONLINE 0 0 0
    c2t7d0 ONLINE 0 0 0
    c3t7d0 ONLINE 0 0 0
    spares
    c4t7d0 AVAIL
    c5t7d0 AVAIL

    errors: No known data errors

  • Our zpool is at version 10 and the latest is version 15, so we upgrade:root # zpool upgrade
    This system is currently running ZFS pool version 15.

    The following pools are out of date, and can be upgraded. After being
    upgraded, these pools will no longer be accessible by older software versions.

    VER POOL
    --- ------------
    10 pool1

    Use 'zpool upgrade -v' for a list of available versions and their associated
    features.
    root # zpool upgrade -v
    This system is currently running ZFS pool version 15.

    The following versions are supported:

    VER DESCRIPTION
    --- --------------------------------------------------------
    1 Initial ZFS version
    2 Ditto blocks (replicated metadata)
    3 Hot spares and double parity RAID-Z
    4 zpool history
    5 Compression using the gzip algorithm
    6 bootfs pool property
    7 Separate intent log devices
    8 Delegated administration
    9 refquota and refreservation properties
    10 Cache devices
    11 Improved scrub performance
    12 Snapshot properties
    13 snapused property
    14 passthrough-x aclinherit
    15 user/group space accounting
    For more information on a particular version, including supported releases, see:

    http://www.opensolaris.org/os/community/zfs/version/N

    Where 'N' is the version number.
    root #
    root # zpool upgrade pool1
    This system is currently running ZFS pool version 15.

    Successfully upgraded 'pool1' from version 10 to version 15

  • zpools are like autonomous raid subsystems that will eventually be added into a pool (which is similar to a LV). There are 3 types of pools raidz (raid-5 like), raidz2 (raid-6 like) and mirror.
  • C0T0D0 and C1T0D0 are kinda special and can’t be included in a zpool…..something about SVM metadb…..blahblahblah. Leave it out.root # metadb -i
    flags first blk block count
    a m p luo 16 8192 /dev/dsk/c0t0d0s7
    a p luo 8208 8192 /dev/dsk/c0t0d0s7
    a p luo 16400 8192 /dev/dsk/c0t0d0s7
    a p luo 16 8192 /dev/dsk/c1t0d0s7
    a p luo 8208 8192 /dev/dsk/c1t0d0s7
    a p luo 16400 8192 /dev/dsk/c1t0d0s7
    r - replica does not have device relocation information
    o - replica active prior to last mddb configuration change
    u - replica is up to date
    l - locator for this replica was read successfully
    c - replica's location was in /etc/lvm/mddb.cf
    p - replica's location was patched in kernel
    m - replica is master, this is replica selected as input
    W - replica has device write errors
    a - replica is active, commits are occurring to this replica
    M - replica had problem with master blocks
    D - replica had problem with data blocks
    F - replica had format problems
    S - replica is too small to hold current data base
    R - replica had device read errors
  • The following commands created the extra zpools needed:root # zpool add pool1 raidz1 c2t0d0 c3t0d0 c4t0d0 c5t0d0 c0t1d0
    root # zpool add pool1 raidz1 c1t1d0 c2t1d0 c3t1d0 c4t1d0 c5t1d0
    root # zpool add pool1 raidz1 c0t2d0 c1t2d0 c2t2d0 c3t2d0 c4t2d0
    root # zpool add pool1 raidz1 c1t4d0 c2t4d0 c3t4d0 c4t4d0 c5t4d0
    root # zpool add pool1 raidz1 c0t5d0 c2t5d0 c3t5d0 c4t5d0 c5t5d0
    root # zpool add pool1 raidz1 c0t6d0 c1t6d0 c3t6d0 c4t6d0 c5t6d0
  • This leaves the following 4 disks to be added to spare:root # zpool add pool1 spare c5t2d0 c0t4d0 c1t5d0 c2t6d0
  • Now for the fun part…..finding out what the heck all this did to the system:root # zpool status
    pool: pool1
    state: ONLINE
    scrub: none requested
    config:

    NAME STATE READ WRITE CKSUM
    pool1 ONLINE 0 0 0
    raidz1 ONLINE 0 0 0
    c0t3d0 ONLINE 0 0 0
    c1t3d0 ONLINE 0 0 0
    c2t3d0 ONLINE 0 0 0
    c3t3d0 ONLINE 0 0 0
    c4t3d0 ONLINE 0 0 0
    raidz1 ONLINE 0 0 0
    c5t3d0 ONLINE 0 0 0
    c0t7d0 ONLINE 0 0 0
    c1t7d0 ONLINE 0 0 0
    c2t7d0 ONLINE 0 0 0
    c3t7d0 ONLINE 0 0 0
    raidz1 ONLINE 0 0 0
    c2t0d0 ONLINE 0 0 0
    c3t0d0 ONLINE 0 0 0
    c4t0d0 ONLINE 0 0 0
    c5t0d0 ONLINE 0 0 0
    c0t1d0 ONLINE 0 0 0
    raidz1 ONLINE 0 0 0
    c1t1d0 ONLINE 0 0 0
    c2t1d0 ONLINE 0 0 0
    c3t1d0 ONLINE 0 0 0
    c4t1d0 ONLINE 0 0 0
    c5t1d0 ONLINE 0 0 0
    raidz1 ONLINE 0 0 0
    c0t2d0 ONLINE 0 0 0
    c1t2d0 ONLINE 0 0 0
    c2t2d0 ONLINE 0 0 0
    c3t2d0 ONLINE 0 0 0
    c4t2d0 ONLINE 0 0 0
    raidz1 ONLINE 0 0 0
    c1t4d0 ONLINE 0 0 0
    c2t4d0 ONLINE 0 0 0
    c3t4d0 ONLINE 0 0 0
    c4t4d0 ONLINE 0 0 0
    c5t4d0 ONLINE 0 0 0
    raidz1 ONLINE 0 0 0
    c0t5d0 ONLINE 0 0 0
    c2t5d0 ONLINE 0 0 0
    c3t5d0 ONLINE 0 0 0
    c4t5d0 ONLINE 0 0 0
    c5t5d0 ONLINE 0 0 0
    raidz1 ONLINE 0 0 0
    c0t6d0 ONLINE 0 0 0
    c1t6d0 ONLINE 0 0 0
    c3t6d0 ONLINE 0 0 0
    c4t6d0 ONLINE 0 0 0
    c5t6d0 ONLINE 0 0 0
    spares
    c4t7d0 AVAIL
    c5t7d0 AVAIL
    c5t2d0 AVAIL
    c0t4d0 AVAIL
    c1t5d0 AVAIL
    c2t6d0 AVAIL

    errors: No known data errors
    root # zpool list
    NAME SIZE USED AVAIL CAP HEALTH ALTROOT
    pool1 36.2T 222K 36.2T 0% ONLINE -
    root # zfs list
    NAME USED AVAIL REFER MOUNTPOINT
    pool1 161K 28.5T 28.8K /vol1

  • To create a CX special mount point we do:root # zfs create pool1/CX
    root # zfs list
    NAME USED AVAIL REFER MOUNTPOINT
    pool1 201K 28.5T 28.8K /vol1
    pool1/CX 33.6K 28.5T 33.6K /vol1/CX
  • When compiling iRODS on X4540 you might/will get an error like “make: Fatal error in reader: config/config.mk………Unexpected end of line seen“. This is caused because by default the system is configured for Sun’s make command (in /usr/ccs/bin/make) rather than the gnu make command which resides in /usr/sfw/bin/gmake under Solaris 10. To fix this add /usr/sfw/bin in front of your $PATH variable, export it and use gmake instead of make (read the INSTALL.txt file that comes with iRODS to find out how you can do the steps manually instead of using irodssetup command).

Writing Moblin (and Ubuntu) USB images using dd in OSX

datePosted on 15:52, May 20th, 2009 by Many Ayromlou

I came across this problem this morning, while writing the newly downloaded moblin USB image file. The concept is straight forward, plugin a 1GB+ USB stick into a functioning Linux or Windows box, make sure the stick is not mounted and use dd to write the disk image to the stick. Under OSX however the instructions for unmounting are slightly different, so here are the quick steps:

  1. Download the desired .img file
  2. Open a Terminal (under Utilities)
  3. Run diskutil list to get the current list of devices
  4. Insert your flash media
  5. Run diskutil list again and determine the device node assigned to your flash media (e.g. /dev/disk2)
  6. Run diskutil unmountDisk /dev/diskN (replace N with the disk number from the last command; in the previous example, N would be 2)
  7. Execute sudo dd if=/path/to/downloaded.img of=/dev/diskN bs=1m (replace /path/to/downloaded.img with the path where the image file is located.
  8. Run diskutil eject /dev/diskN and remove your flash media when the command completes

That should do it…..

Okay so I’ve been playing around with openfiler for the past couple of months. We’re trying to setup a Student homedirectory NAS device and have a mirror machine that would take over if our primary dies. Our machines are hand built 13-TB NAS servers using 16 x 1TB Seagate disks and a 16 channel sata2 raid controller from 3Ware. There are several problems that one needs to overcome in this type of setup so I will try to cover it, bit by bit as I finish confirming it at work. As I said we’re using a Super Micro case and motherboard (Dual Quadcore Xeon) and we’ve stuffed a 16 channel 3ware 9650 controller in there. The first issue we had was with hardware and the fact that we had some screwy new firmware on the controller that was not working nicely with our 16 x 1TB seagate drives. We downgraded the firmware and got the machine to post. Then we created a (roughly) 14 TB container in raid-6 mode (16 drives, less 2). We further devided up the space into a 20GB boot partition (using the bios setting in 3ware bios) and a giant (rougly) 13TB partition that will hold our student data. The 20 GB partition will later on hold our swap space and non essential (frequently updated) folders under /var (lock, log, etc.)

We have physically 2 separate machines that are exact copies of each other hardware-wise. The plan initiallly was to use DRBD and heartbeat service to create a High availability NAS cluster, but since we are tying to authenticate (for smb) with our Windows system, we could not get that configuration working (and frankly I still don’t trust DRBD, as good as it is). So we decided to create two USB sticks images. One for master and another for slave. The master will be a machine enrolled into our Active directory domain and the slave will be a passive (private) rsync server. The master USB image is configured with all the AD stuff and two interfaces. One interface serves as the NAS and another runs rsync against our slave/rsync server. When/If the master fails (ie: motherboard failure) beyond recognition, we simply plug the master USB stick into our slave machine and reboot it. Since the machines are exact copies of one another the (old slave) will now be master and once the (old) master is fixed, it will become the new slave/rsync server. Real simple.

So here is Chapter one – How do you get Openfiler 2.3 to boot off a USB stick:

Before you start you’ll need the following:

  1. Four USB Sticks 2GB+ that are the same brand, size.
  2. Openfiler 2.3 install CD
  3. A non openfiler rescue disk (I used a Ubuntu LiveCD) used to fix (reinstall) grub on the USB stick.

Insert your USB stick, and boot from the OpenFiler 2.3 installation CD. At the boot prompt, type expert (for text mode type expert text, I used graphical mode). Manually configure your partitions. I just had one 2Gb partition (ext2) on /. I used ext2 since it has no journal and won’t constantly write to the USB stick. No Swap partition at this point. After the install I noticed that something between 600 and 700 Mb was used for the system, so you might be able to use about 200-300Mb for swap if really needed (however, I doubt the use for a swap partition, as USB storage is really slow). The installer will breeze through to the end. Note that it is realllyyy slow. It took more than an hour on my config. Reboot at the end and get the OF2.3 CD booting again in rescue mode by typing “linux rescue” at the prompt. Once you’re at the prompt mount the USB stick manually (fdisk -l might help as it will print out info about all the disks). My USB stick was /dev/sdc, hence the commands below:

mount /dev/sdc1 /mnt/source
chroot /mnt/source

Now you’ve got the partition mounted and your shell chrooted to the root of the USB stick. We next copy the initrd on the USB stick into a temporary directory (on the stick) and uncompress it so we can modify it. You need to do this so that grub can initialize the bootloader ram disk off the USB stick (ie: makes OF installation bootable from USB).

cp /boot/initrd-2.X.X.img /tmp/initrd.gz
gunzip /tmp/initrd.gz
mkdir /tmp/a
cd /tmp/a
cpio -i < /tmp/initrd

At this point we need to edit the “init” file (text file containing kernel module listings that are required during boot). I used vi to do this, not sure if there is another editor available during rescue mode. Find the line containing “insmod /lib/sd_mod.ko” and insert the following snippet under it:

insmod /lib/sr_mod.ko
insmod /lib/ehci-hcd.ko
insmod /lib/uhci-hcd.ko
sleep 5
insmod /lib/usb-storage.ko
sleep 8

Save the file and follow along with the following commands to physically copy the appropriate kernel modules to the temp directory.

cd /lib/modules/insert-kernel-folder-here-or-just-use-TAB-key/kernel/drivers
cp usb/storage/usb-storage.ko /tmp/a/lib
cp usb/host/ehci-hcd.ko /tmp/a/lib
cp usb/host/uhci-hcd.ko /tmp/a/lib
cp scsi/sr_mod.ko /tmp/a/lib
cd /tmp/a
find . | cpio -c -o | gzip -9 > /boot/usbinitrd.img

IMPORTANT – Now adjust grub config (/boot/grub/grub.conf) to reflect the change to initrd filename. You should also repeat this on kernel upgrades (but then again, never touch a working system ;)).
Reboot.

More than likely it’s a no go, since the installer did not install grub properly. Now take out your Ubuntu (or other favourite rescue CD) out and boot from it. Don’t use the OF2.3 CD in rescue mode…..IT DOES NOT WORK. Once booted, mount the USB stick on the system and use the following commands to re-install grub:

mount /dev/sdc1 /mnt/source
grub-install --root-directory=/mnt/source /dev/sdc

Reboot and you should be good to go (you will get a couple of Errors during boot about modules already loaded stuff…..ignore). At some point you do want to move some of those auxiliary directories (/tmp/ /var/log /var/lock and others) and swap file off the stick and onto the 20GB portion of our raid-6 we prepped earlier on. Below you find the fdisk -l listing of that “logical disk” (/dev/sdb in our system):

Disk /dev/sdb: 21.4 GB, 21474835968 bytes
255 heads, 63 sectors/track, 2610 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot Start End Blocks Id System
/dev/sdb1 1 609 4891761 83 Linux
/dev/sdb2 610 621 96390 83 Linux
/dev/sdb3 622 671 401625 83 Linux
/dev/sdb4 672 2610 15575017+ 5 Extended
/dev/sdb5 672 673 16033+ 83 Linux
/dev/sdb6 674 2610 15558921 82 Linux swap / Solaris

here is a breakdown of what goes where (/dev/sdb6 is obviously swap which was prepared with “mkswap” command):

tmpfs /tmp tmpfs defaults,noatime 0 0
tmpfs /var/tmp tmpfs defaults,noatime 0 0
/dev/sdb1 /var/log ext2 defaults 1 1
/dev/sdb2 /var/run ext2 defaults 1 1
/dev/sdb3 /var/cache ext2 defaults 1 1
/dev/sdb5 /var/lock ext2 defaults 1 1
/dev/sdb6 swap swap defaults 0 0

You need to make the above changes to your USB stick’s /etc/fstab, but before rebooting you need to use “cp -a” command to copy all the folders from the appropriate location on the USB stick to the above partitions (by mounting the partitions temporarily/one-at-a-time), just to make sure no process would go crazy if it didn’t find the lock directory (or cache, run, etc.).

Next we want to make four copies of this stick. You can use a Mac or Win (using rawrite) or better yet Linux. It’s important that the stick your copying is not booted. Use the Ubuntu/whatever CD you used ealier and boot it into rescue mode. Go to command line and use “dd” command to create three more copies of the stick you just preped.

Two copies (one for safe keeping) will become your Master USB sticks to boot the machine in Master mode (as described earlier in this article). The other two copies (one for safe keeping) will become your Slave sticks.

NOTES:

These notes have nothing to do with the installation. I’m just putting them down here for safe keeping. Only use these if you’re in trouble.

– If you want to create a “Home Share” and you don’t get the “Make Home Share” button on the interface, something has gone wrong with one of the xml config files. No worries, find and edit the file /opt/openfiler/etc/homespath.xml . Inside it will look something like this:
<?xml version="1.0"?>
<homespath value="/mnt/bigvg/studentvol/studenthome/"/>

This is where the problem is. The php code that drives the interface for sharing thinks that there already is a “homes” directory defined, but you know that’s not the case. Since only one homes entry is allowed, the web interface will not give you the option to make your new share the “Home Share”. To fix this we need to take out what’s inside the quotes as the value of homespath. So once that’s done the file will look like this:
<?xml version="1.0"?>
<homespath value=""/>

Save this file and go back to the share tab in the web interface and you will now get a “Make Home Share” button again.

– If you have upgraded to a Windows 2008 R2 (Win2k8 r2) AD domain and you’re getting authentication errors when accessing your openfiler shares (although everything was working fine under R1) like the ones below:
/var/log/messages shows:

Nov 16 08:42:02 openfiler winbindd[3316]: [2009/11/16 08:42:02, 0] rpc_client/cli_pipe.c:rpc_api_pipe(789)
Nov 16 08:42:02 openfiler winbindd[3316]: rpc_api_pipe: Remote machine dc.domain.tld pipe \NETLOGON fnum 0x4005 returned critical error. Error was NT_STATUS_PIPE_DISCONNECTED

and
/var/log/samba/winbind.log shows:

[2009/11/16 08:43:12, 1] winbindd/winbindd_util.c:trustdom_recv(269)
Could not receive trustdoms

then your problem (more than likely) is the version of Samba that comes with openfiler 2.3. You need to upgrade to 3.4.5. Run “conary updateall” or do “System Update” from the interface, let it update everything and reboot your machine. Once your machine is back up, leave the AD domain and rejoin it and everything should be fine.

– If you’re having problems accessing a samba share you just created on your brand new openfiler, you might want to check the following. Lets say you have a Volume Group called “bigvg” and a Volume inside that called “studentvol” where you have a share called “test”. If you’re having problems accessing the share by just using something like smb://openfiler-servername/test you might want to try connecting to the following instead:
smb://openfiler-servername/bigvg.studentvol.test
This is because by default openfiler tries to be smart and adds the volume group and volume name infront of the sharename you give it. Now, if you have a small installation this can be a pain. The easy way to fix this is to use the “Override SMB/Rsync share name:” field under the “Shares/Edit share” screen. I tend to use the same sharename I initially used (ie: “test” in this case), just to keep it simple. The only thing to remember here is that you want to make sure you don’t override with a duplicate name…..that’s gonna blowup real good.

– Couple of useful commands for Samba troubleshooting…..
To see a list of shares on your openfiler server (note that the unix command will give you those long sharenames:
Unix: smbclient -L OpenfilerServername -U domainloginid
Win: net view \\OpenfilerServername

– There is another issue with this master/slave setup and that is UID/GID synchronization for samba. This comes into play since we’re rsyncing our files from master to slave. This process also transfers their respective UID/GID to the slave machine. If the master fails, our procedure is to turn if off and reboot the slave using the masters USB stick. This works, but all those rsync’ed UID/GID’s will not match when the slave machine is booted using the masters USB stick (samba voodoo that translates windows UID/GID’s to linux UID/GID is kinda random)…..UNLESS YOU DO THE FOLLOWING (taken from Samba How-To):

The idmap_rid facility is a new tool that, unlike native winbind, creates a predictable mapping of MS Windows SIDs to UNIX UIDs and GIDs. The key benefit of this method of implementing the Samba IDMAP facility is that it eliminates the need to store the IDMAP data in a central place. The downside is that it can be used only within a single ADS domain and is not compatible with trusted domain implementations.

This alternate method of SID to UID/GID mapping can be achieved using the idmap_rid plug-in. This plug-in uses the RID of the user SID to derive the UID and GID by adding the RID to a base value specified. This utility requires that the parameter “allow trusted domains = No” be specified, as it is not compatible with multiple domain environments. The idmap uid and idmap gid ranges must be specified.

The idmap_rid facility can be used both for NT4/Samba-style domains and Active Directory. To use this with an NT4 domain, do not include the realm parameter; additionally, the method used to join the domain uses the net rpc join process.

An example smb.conf file for and ADS domain environment is shown below:
# Global parameters
[global]workgroup = KPAK
netbios name = BIGJOE
realm = CORP.KPAK.COM
server string = Office Server
security = ADS
allow trusted domains = No
idmap backend = idmap_rid:KPAK=500-100000000
idmap uid = 500-100000000
idmap gid = 500-100000000
template shell = /bin/bash
winbind use default domain = Yes
winbind enum users = No
winbind enum groups = No
winbind nested groups = Yes
printer admin = "Domain Admins"

In a large domain with many users it is imperative to disable enumeration of users and groups. For example, at a site that has 22,000 users in Active Directory the winbind-based user and group resolution is unavailable for nearly 12 minutes following first startup of winbind. Disabling enumeration resulted in instantaneous response. The disabling of user and group enumeration means that it will not be possible to list users or groups using the getent passwd and getent group commands. It will be possible to perform the lookup for individual users, as shown in the following procedure.

The use of this tool requires configuration of NSS as per the native use of winbind. Edit the /etc/nsswitch.conf so it has the following parameters:
...
passwd: files winbind
shadow: files winbind
group: files winbind
...
hosts: files wins
...

The following procedure can use the idmap_rid facility:

1. Create or install an smb.conf file with the above configuration.
2. Edit the /etc/nsswitch.conf file as shown above.
3. Execute:
root# net ads join -UAdministrator%password
Using short domain name -- KPAK
Joined 'BIGJOE' to realm 'CORP.KPAK.COM'

An invalid or failed join can be detected by executing:
root# net ads testjoin
BIGJOE$@'s password:
[2004/11/05 16:53:03, 0] utils/net_ads.c:ads_startup(186)
ads_connect: No results returned
Join to domain is not valid

The specific error message may differ from the above because it depends on the type of failure that may have occurred. Increase the log level to 10, repeat the test, and then examine the log files produced to identify the nature of the failure.
4. Start the nmbd, winbind, and smbd daemons in the order shown.
5. Validate the operation of this configuration by executing:
root# getent passwd administrator
administrator:x:1000:1013:Administrator:/home/BE/administrator:/bin/bash

Please note that the update version of SAMBA that gets installed after you do “conary updateall” (see above) has a option for this under “Advance” tab of the Accounts section.

12Next