Friday, January 29, 2016

Multiroom Audio using MPD, Pulseaudio and Bluetooth


Almost all my activities (for example cooking, working on projects or playing games) have one thing in common: Theres music running in the background.
Usually this is some sort of FM radio running a local radio channel. The drawbacks are obvious: You have no control over what music is runing and the audio quality is far from great.
I started to ponder what to do about it. My requirements were simple:
  • Choose the music myself: These days, most of what i listen to is either internet radio, or a music streaming service like Spotify or Google Play Music
  • Reasonable quality: I am not an audiophile, but at least i do not want to have audible artifacts or noise when i walk past an antenna or something
  • Easy installation: I have no intent to run speaker wires to every room
  • Price: I dont want to spend hundreds of euros and for example buy Sonos speakers for all my rooms. At 230 Euros a piece, this would become really expsive really fast

Hardware

My system is built on the basis of bluetooth speakers.
I chose to use the Xiaomi Square Box for this, because it is quite cheap. But any bluetooth speaker would do. Of course the Xiaomi Box can not compete with expensive speakers like the Sonos or Bose systems, but at around 20 Euros incl. shipping, it is not bad. I even got one of these on a sale for 13 Euros incl. shipping.
The speakers have a builtin battery, so you could carry it around the house. But since i planned on just throwing this on a cupboard, i run it of a cheap phone charger.
Next thing i bought was a bluetooth dongle, which i plugged into my home server. In my case, the home server is an HP Microserver Gen8. But you could easily run this of a Rasperry Pi.

Software

For this to work, you need any current linux distribution. I amrunning Archlinux, because i like to tinker with new stuff, receive updates fast and take care of my system.
If you run some form of Ubuntu or Debian, for example Raspbian on a Raspi, the steps will be roughly the same. But since Ubuntu uses upstart where archlinux is based on systemd, you will have to improvise on that point.
To play my music, i currently use the Music Player Deamon, short MPD. The get support for spotify and the likes, i plan to change to mopidy. I just have not gotten around to it yet.
I use openHAB for my home automation, so the controls for the music will also be implemented there.

Steps to make it happen

Connecting bluetooth devices

Use bluetoothctl to turn on your bluetooth controller, pair, trust and connect to the speakers. Make sure to replace the mac address of your speakers.
% bluetoothctl
[bluetooth]# power on
Changing power on succeeded
[bluetooth]# scan on
Device A0:E9:DB:51:3B:C5 Mi Bluetooth Speaker
[bluetooth]# pair A0:E9:DB:51:3B:C5
...
[bluetooth]# trust A0:E9:DB:51:3B:C5
...
[bluetooth]# pair A0:E9:DB:51:3B:C5
...

Make sure your bluetooth controller is powered on after a reboot. On archlinux, this is done using a simple udev rule in /etc/udev/rules.d/20-bluetooth.rules containing this:
# Set bluetooth power up
ACTION=="add", SUBSYSTEM=="bluetooth", KERNEL=="hci[0-9]*", RUN+="/usr/bin/hciconfig %k up"
Make sure everything after ACTION is one line.

Pulseaudio

Enable pulseaudio as a permanently running service (not socket activated) and start it.
% systemctl --user enable pulseaudio.service
% systemctl --user start pulseaudio.service
Also make sure your user session is started on boot.
% sudo systemctl enable user@1000.service
Where 1000 is the user id of your user. You can get this id by running the program “id” as the corresponding user:
% id
uid=1000(tlan) gid=1000(tlan) groups=1000(tlan),7(lp),10(wheel),91(video),92(audio),1001(download)

(If groups does not contain audio)
% sudo gpasswd -a <username> audio
This is also the time to make sure your user is part of the group “audio” and if not, add him.
If everything went according to plan, pulseaudio should have automatically added your bluetooth devices as sinks. You can check using “pacmd”
% pacmd list-sinks
1 sink(s) available.
  * index: 1
    name: <bluez_sink.A0_E9_DB_51_3B_C5>
    driver: <module-bluez5-device.c>
    flags: HARDWARE DECIBEL_VOLUME LATENCY FLAT_VOLUME
    state: SUSPENDED
    suspend cause: IDLE
    priority: 9030
    volume: front-left: 51773 / 79% / -6.14 dB, front-right: 51773 / 79% / -6.14 dB
    balance 0.00
    base volume: 65536 / 100% / 0.00 dB
    volume steps: 65537
    muted: no
    ...
    properties:
      bluetooth.protocol = "a2dp_sink"
      device.description = "Mi Bluetooth Speaker"
      device.string = "A0:E9:DB:51:3B:C5"
      ...

(Optional, to set an upper limit for the volume)
% pacmd set-sink-volume bluez_sink.A0_E9_DB_51_3B_C5 50000
By setting the sink volume a bit under the maximum value of 65k and controlling the volume in my player software independently from pulseaudio, i effectively limit the maximum volume that can be set to not overload my speakers.
Add the line “load-module module-switch-on-connect” to /etc/pulse/default.pa to make sure pulseaudio automatically connects to your speakers after a reboot.
You should now be able to play music and hear it out of your bluetooth speakers. If you do not specify a sink, pulseaudio will output everything using the default sink.

MPD

I installed MPD and created the configuration files for each room in ~/.config/mpd:
% touch kitchen.{conf,database,log,pid}
Set up everything needed in the conf file. Make sure the files, especially the pid file, are unique for each configuration.  Change the paths to music and playlists to your needs
music_directory "/media/virtual/Music/mp3" 
playlist_directory "/media/virtual/Music/playlist"
db_file "~/.config/mpd/kitchen.database" 
log_file "~/.config/mpd/kitchen.log" 
pid_file "~/.config/mpd/kitchen.pid" 
 
port "6600" 
 
audio_output { 
 type "pulse" 
 name "Kitchen" 
 sink "bluez_sink.A0_E9_DB_51_3B_C5" 
}
Every instance of MPD has its own database. If you dont want this, see the Archwiki: Music Player Daemon – Satellite_setup.
The I created a special parameterized systemd unit in ~/.config/systemd/user/mpd@.service to run multiple MPDs with a custom configuration each
Description=Music Player Daemon
After=network.target sound.target

[Service]
ExecStart=/usr/bin/mpd --no-daemon %h/.config/mpd/%I.conf

[Install]
WantedBy=default.target
Then, have systemd reload config files, enable an instance of this configuration and start it
% systemctl --user daemon-reload
% systemctl --user enable mpd@kitchen
% systemctl --user start mpd@kitchen
You should now be able to play music using mpd to your bluetooth speakers. Use any MPD client to test this.

OpenHAB

OpenHAB comes with a binding for MPD. Bindings are plugins, that extend openHABs features for IoT devices. I use the binding to start/stop the music and control the volume.
Unfortunately, the plugin does not have features builtin to control playlists. So i decided just to use the exec-Binding, which allows you to run system commands, and the mpc client to load playlists.
Alternatively, i could have used a WebView, to display some sort of Webinterface for MPD in an iframe. But since right now, i only need to choose between two different playlists, i did not bother.
OpenHAB users will be familiar with the configuration layout, so i will just post the config files here and not go into much detail:
 % cat Music.items configurations/items raspberrypi Switch Mpd_Kitchen_StartStop "Start/Stop" (Kitchen,Radio) { mpd="ON:kitchen:play, OFF:kitchen:stop" }
Dimmer Mpd_Kitchen_VolumeControl "Volume [%d%%]" (Kitchen,Radio) { mpd="INCREASE:kitchen:volume_increase, DECREASE:kitchen:volume_decrease, PERCENT:kitchen:volume" }
String Mpd_Kitchen_Channel_Selection "Sender" (Kitchen,Radio) { autoupdate="false" }
String Mpd_Kitchen_Channel (Kitchen,Radio) { exec=">[CLEAR:mpc -h tlan-server.local -p 6600 clear] >[1LIVE:mpc -h tlan-server.local -p 6600 load 1live] >[WMW:mpc -h tlan-server.local -p 6600 load wmw]" }

 % cat default.sitemap
....
Frame label="Musik" { 
 Switch item=Mpd_Kitchen_StartStop 
 Slider item=Mpd_Kitchen_VolumeControl 
 Switch item=Mpd_Kitchen_Channel_Selection mappings=[ "1live"="Eins Live", "wmw"="WMW"]
}
....
 
 % cat Musik.rules configurations/rules raspberrypi import org.openhab.core.library.types.*
import org.openhab.core.persistence.*
import org.openhab.model.script.actions.*
import org.joda.time.DateTime
import java.lang.Thread

rule "Change channel"
when
 Item Mpd_Kitchen_Channel_Selection received command
then
 var channel = receivedCommand

 sendCommand( "Mpd_Kitchen_StartStop", "OFF")
 Thread::sleep(50)
 sendCommand( "Mpd_Kitchen_Channel", "CLEAR")
 Thread::sleep(50)

 switch channel {
 case '1live': sendCommand( "Mpd_Kitchen_Channel", "1LIVE")
 case 'wmw': sendCommand( "Mpd_Kitchen_Channel", "WMW")
 }

 Thread::sleep(50)
 sendCommand( "Mpd_Kitchen_StartStop", "ON")

end
Some notes:
  • Since (i think) openHAB processes events asynchronously, i had to add some Thread::sleep between commands to MPD
  • MPD behaved kind of strange when just loading playlists. So to make sure i dont mix up my playlists, i first stop music playback, then clear the current playlist, load the new playlist, and turn playback back on. This happens fast enough so you do not notice it, but fixed a lot of weirdness when controlling it.

Conclusion

Right now, i only have one speaker connected. But adding more is just a matter of connecting, copying configuration files and starting services. Controlling it is easy enough, everybody on my house can handle it.
Everything works great!

Further steps

As mentioned before, to support streaming services like spotify etc. i am going to switch to mopidy, although i will have to check how different the configuration will be.
Since the server is available as a bluetooth device, you can connect your smartphone to it and have sound from your phone come out of your speaker in any room. I am still looking nito what it would take to have an easy interface to choose which input to send to which output.
Since the bluetooth speakers are just regular pulseaudio sinks, you can send other stuff to them. For example, i installed espeak, a text-to-speech software. With it, you can have the server tell you “Hey, you’ve got mail!’ whenever a new email arrives.
Or, going further down the home automation route: You could for example use the openHAB weather binding check for rain and if rain is expected, warn you to close the windows in rooms where windows are open.
If you used bluetooth speakers which also offer handsfree features and have a microphone, you could even built something like an always listening voice assistant.

Wednesday, January 27, 2016

Can MS Certificate Services be a Subordinate Enterprise CA beneath a Root CA created with OpenSSL


Yes this is possible, if you consider a few additional configuration entries for the openssl config file.

Suppose a scenario where you want to deploy a multi-tiered certificate authority, using open ssl on a non-networked (offline) device to store your top level Root Certificate Authority (a linux box perhaps).
The device would remain offline to mitigate the network attack vector to steal the private key of the top level Root CA.
Subsequently, a MS Enterprise Subordinate Certificate Authority would be certified in the certificate chain to certify downstream certificates.

The Microsoft Certificate Authority expects valid AIA and CDP locations in the root CA certificate.
These url locations should be entered in the openssl configuration file before creation of the root CA or certification of the MS subordinate enterprise CA.

Setting up a certificate authority with openssl is beyond the scope op this tutorial, but there is a very good tutorial on the subject hosted at https://jamielinux.com/docs/openssl-certificate-authority/index.html

This tutorial assumes that you have set up a Root certificate authority with openssl according above tutorial up until verifying the root certificate, keeping in mind the following additions to the openssl.cnf config file.

As per the tutorial, the openssl config file would reside on the following location: /root/ca/openssl.cnf

Under the [ v3_ca ] and the [ v3_intermediate_ca ] sections the following two lines need to be added:
(these are the valid AIA and CDP locations that the Microsoft CA expects to be present)

authorityInfoAccess = caIssuers;URI:http://root-ca.mydomain.local/root.pem
crlDistributionPoints = URI:http://root-ca.mydomain.local/root.crl

Note that these two files will need to be present on your MS webserver before completion of your certificate signing request from your MS Enterprise Subordinate CA, or else the completion of the certificate signing request will fail because the MS Enterprise Subordinate CA fails to verify the validity of the Root CA Certificate and the Subordinate certificate.

Windows 2012 R2 RDS - Configure RDS Certificates with own Enterprise CA


If you are planning to configure Windows 2012 R2 Remote Desktop Services in your environment and are planning to sign your own x509 certificates for it, then be advised that this is not as straight forward as creating a web server certificate.

You will need to create a new (duplicated from workstation) certificate template, and modify the template's settings to incorporate the correct extensions when enrolling for a new certificate via this template.

Certificates in a Windows 2012 R2 Remote Desktop Services deployment, are typically implemented either via Powershell or the RDS deployment properties management console in Windows 2012 R2.
For simplification of this tutorial, we will be using the management console instead of Powershell.

RDS deployment properties management console

As prerequisite for this tutorial, it is assumed that you already have an enterprise certificate authority, and remote desktop services deployement installed on your network.

Our first step will be the creation of a new certificate template, modified to enroll correct certificates for our RDS deployment.

Open your Certificate Authority management snap-in from your Enterprise CA on your network, right click certificate templates and select manage.


In the certificate templates console, scroll down until you find the 'Workstation Authentication' template.  Right click it and select Duplicate Template.


On the General tab of the new template, change the template display name to RDS Certificate Template and mark the checkbox to publish the certificate in Active Directory.



On the Request Handling tab, select 'allow private key to be exported'.


On the Extensions tab, select Application Policies and select Edit.


Add Server Authentication to the list.


On the Subject Name tab, select 'Supply in the request'.


Accept the resulting message.


Close the new template now by selecting ok, and close your Certificates Templates Console.

Go back to the certificate authority management snap-in and right click Certificate Templates, New, Certificate Template to issue:

Select the new RDS Certificate Template and click ok.


The new certificate template is now added to your Enterprise Certification Authority, and can now be used to enroll correct certificates for usage with Remote Desktop Services.


For proof of concept, we will enroll a certificate using this template on our Remote Desktop Broker Server.

Log in to your Remote Desktop Broker server, in my case, rdbroker01.
Open a management console by right clicking start, then run, type mmc and press enter.
Click File - Add/Remove Snap-in...


Select the Certificates snap-in and click add.


Select computer account and click next.

Select local computer and click finish.



Now we have the Certificates Store of the local computer open, we will be requesting a new certificate from within this console to our enterprise CA.

Under Certificates, Personal, right click the certificates folder and select all tasks, request new certificate.


Click next on the certificate enrollment window.


Make sure Active Directory Enrollment Policy is highlighted, and click next.


Select RDS Certificate Template, and click the link to configure additional information for enrollment.


On the certificate properties window, add a common name for the certificate, this may be your FQDN of your RDS broker server, subsequently, add alternative dns names for other roles that u might be hosting on the same server like your RDS web access, or if you are planning to use this certificate also on the other servers in your deployment, add the FQDN's of the other servers as DNS entries.


On the General tab, fill in a descriptive name for the certificate that you are enrolling, after this, select ok to close the certificate properties window.


Now click the Enroll button to request your certificate to the Enterprise CA.


The Certificate Enrollment process should complete successfully, click finish to close the enrollment window.



In our Certificate Management Snap-in we can verify that our new certificate is enrolled and available to us.  If it is not displayed at first, then press F5 to refresh and make it visible.



We now need to export the certificate and the private key to import it again via our RDS management console.
Right click the certificate, select all tasks and click export.


Click next on the certificate export wizard.


Select yes, export the private key and click next.


Accept the default settings in this window and click next.


Set a password to protect your private key.


Set the filename to where you want to export the certificate.


Click finish to complete the certificate export.


Now that we have the exported certificate ready, we can finish the certificate installation on our Remote Desktop Management console.
Open Server Manager, and open Remote Desktop Services in the left pane, then click tasks, and edit deployment properties.


Go to certificates, highlight the role for which u want to deploy your certificate, and click select existing certificate.


Select, choose a different certificate, browse for your certificate, enter your certificate password, and select to allow the certificate to be added to the trusted root certification authorities store.  After that confirm with ok.


Click apply to apply the certificate.  After this action, the status will show OK and the level will be Trusted.

Monday, January 25, 2016

Publish Offline Certificates and CRLs to Active Directory


Before publishing your offline Root CA cert, check the extensions on the Root CA server, esp on the CRL Distrisbution Point (CDP) extensions.

To publish the offline Root CA cert and CRL to AD, set the "Include in all CRLs" flag in the Root CA extension properties and use the certutil -dspublish command. Do note that file share CDP (FILE://) is not supported - only LDAP:// and HTTP://. I have tried and it's not going to work. Similarly, you would need to specify where clients and servers can obtain the root cert (i.e. LDAP and/or HTTP) in the "Authority Information Access (AIA)" drop-down setting.



The "Include in all CRLs" flag specifies that the Active Directory publication location should be included in the CRL itself. It can be used by an offline CA to specify the LDAP URL for manually publishing CRLs on the Active Directory. The explicit configuration container must be explicitly set in the URL. Alternatively, the DSConfigDN value can be set in the registry by using "certutil –setreg ca\DSConfigDN CN=Configuration,DC=contoso,DC=com". Note that the last two DC values (DC=contoso,DC=com for "contoso.com") are to be replaced by your actual Domain Name.




Export out the Root CA cert and CRL files and import them into a domain member server.
To publish the Root Cert to the Root CA store on the Active Directory: certutil -f -dspublish RootCA.cer RootCA


To publish the CRL to Active Directory: certutil -f -dspublish Root-Test-CA.crl "LoneSrv1" "Root-Test-CA". The last 2 parameters to specify the containers are optional but could be needed if the offline RootCA is non-Microsoft.



How to Publish New Certificate Revocation List (CRL) from Offline Root CA to Active Directory and Inetpub


It's highly recommended when building your Microsoft PKI (Public Key Infrastructure) to have your Root CA offline after issuing the Enterprise Sub CA certificates. It's recommended to minimize the access to the Offline Root CA as much as possible. The Root CA is not a domain joined machine and can be turned off without any problem.

One of the Key issue is the CRL generated from the Root CA, you need to set the CRL interval for a large value so that we don’t need to copy the CRL to an online location frequently and do not implement delta CRLs, because the publication of each delta CRL would require access to the offline root CA in order to copy the delta CRL to an online publication location. In order to change the CRL interval you need to:





  1. Turn on the Offline Root CA and login with Admin account
  2. Open the Certification Authority Console
  3. Right Click on the "Revoked Certificates" and click Properties.
  4. Set “CRL Publish interval” to a large value (Default is 26 Weeks) and  uncheck “Publish Delta CRL” check-box.



In order to Publish a new CRL from the offline Root CA to the Enterprise Sub CA you need to do the following:

  1. Publish a new CRL on the Root CA, this can be done by Right Click the "Revoked Certificates" - All Tasks - Publish                                                                                                                                                                                                                                                          
                                                                                                                                                                     
  2. Copy the CRL file from the Root CA located under %systemroot%\system32\certsrv\certenroll to the Sub CA Server
  3. Turn off the Root CA
  4. Copy the above file to the InetPub folder (HTTP Path) in the Sub CA server which is by default located under the C:\inetpub\wwwroot\Certdata
  5. Open an Admin Command Prompt and run the following command to publish it to the Active Directory (LDAP Path).                                                                                           certutil -f -dspublish " C:\Inetpub\wwwroot\certdata\RootCA.crl


This process of renewing the CRL and publishing a new one is manually done since the Root CA is offline and thats why its better to make the CRL publish interval more than the default value so you won't do it frequently. You may also want to set an automated reminder before the next renewal date.

Sunday, January 3, 2016

HOWTO - Stream Internet Radio Stations to a Bluetooth Speaker with the Raspberry Pi



 As an ongoing effort in automating all the electronic equipment which I have in my home I was looking for a solution to stream internet radio stations from the Raspberry Pi to my home amplifier which is hooked up to a bluetooth receiver. At least then I wouldn't need to dedicate another device like my ipad or smartphone anymore as streaming source.










A quick note about pitfalls, I tried to build this solution first with the latest Raspbian Jessie image, but was quite disappointed since the support for for the bluetooth software on this image seems to be rather broken, hence I  switched back to using the Raspbian Wheezy image, which delivered me a working solution.
The Solution is built on Alsa sound and not on Pulse Audio.


Get the right hardware

To get started, you will need a compatible Bluetooth dongle for your Raspberry Pi.
My bluetooth dongle seems to have a Broadcom Chipset (bcm2046) which is fully compliant with the Bluetooth 2.1 specification according to Broadcom's website.













You can find this information as per below screenshot:

  • lsusb
  • lsusb -t





Getting Bluetooth Ready


To use our bluetooth dongle we will need to install some software packages:

  • sudo apt-get install -y bluetooth bluez-utils

After the installation of our bluetooth software modules, we need to make a modification to the following configuration file: /etc/bluetooth/audio.conf

  • sudo nano /etc/bluetooth/audio.conf

Under the [General] section insert the following line:
  • Enable=Source,Sink,Media,Socket,Control
Now reload your bluetooth configuration
  • sudo service bluetooth restart

Time to hook it up

Now it's time to connect our Raspberry Pi to our Bluetooth Speaker.

First put your Bluetooth speaker in discovery mode, then scan with the Raspberry Pi for it:
  • hcitool scan
Once that u found your Bluetooth Speaker with it's mac address: xx:xx:xx:xx:xx:xx

Pair your Bluetooth Speaker with your Raspberry Pi, you only need to do this once to get the devices to trust each other.
  • bluez-simple-agent hci0 xx:xx:xx:xx:xx:xx
If u see below error:

Creating device failed: org.bluez.Error.ConnectionAttemptFailed: Page Timeout
wake up your bluetooth receiver again, it fell asleep.

Or if u get below error:


Creating device failed: org.bluez.Error.AuthenticationRejected: Authentication Rejected
This is a bug in bluez-simple-agent. By default, bluez-simple-agent wants to use a capability called "KeyboardDisplay" but this will not work for us in this case. We need to change that to "DisplayYesNo" so that we can get a Yes/No prompt on the command line when pairing devices.

pi@raspberrypi ~ $ grep KeyboardDisplay /usr/bin/bluez-simple-agent 
 capability = "KeyboardDisplay"
pi@raspberrypi ~ $ sudo perl -i -pe 's/KeyboardDisplay/DisplayYesNo/' /usr/bin/bluez-simple-agent
pi@raspberrypi ~ $ grep DisplayYesNo /usr/bin/bluez-simple-agent
 capability = "DisplayYesNo"
pi@raspberrypi ~ $ 

This will add your Bluetooth Speaker to your Raspberry Pi's trusted Bluetooth device list so that your Raspberry Pi can connect automatically to it afterwards:

bluez-test-device trusted xx:xx:xx:xx:xx:xx yes

This will connect the audio sink of your Bluetooth Speaker to your Raspberry Pi:

bluez-test-audio connect xx:xx:xx:xx:xx:xx


Plugging the software

Now that we have connected this audio sink we need to make this audio sink available to Alsa, the audio software from the Raspberry Pi.

For this we need to create a config file:

sudo nano /etc/asound.conf

pcm.btheadset {
  type plug
    slave {
      pcm {
        type bluetooth
        device xx:xx:xx:xx:xx:xx
        profile "auto"
      }
   }
   hint {
      show on
      description "My bluetooth device"
   }
}  

ctl.btheadset {
  type bluetooth
}

This concludes the configuration of the Bluetooth and Alsa Audio software, we will be able to play music now from our Raspberry Pi to our Bluetooth Speaker.



Let's go streaming

Now to stream internet radio, we need to make use of another piece of audio software on linux called Media Player Daemon.
It's a versatile daemon which allows us to build a playlist with various sources, the media player daemon just plays this playlist.
We will make use of mpc, (media player control) to control whats happening with the media player daemon, add the various resources in the playlist, start and stop playing, and so on.

Let's first install the required software:
  • sudo apt-get install -y mpd mpc
Mpd makes use of the Alsa software to output it's audio signal, to play over the Bluetooth connection we will need to add the correct output into mpd.
  • sudo nano /etc/mpd.conf
At the output sections, add below section as output connection for mpd.

audio_output {
  type "alsa"
  name "btheadset"
  device "btheadset"
}

After adding this, reload your mpd daemon:
  • sudo service mpd restart
Everything is in place now to make our mpd daemon play internet radio streams to our bluetooth speaker, we just need to add the internet radio url's to the mpd playlist and play them.

The following is an example to play the q-music internet radio stream:







  • mpc add http://icecast-qmusic.cdp.triple-it.nl/Qmusic_be_live_32.aac
  • mpc play
To view what's in your playlist:
  • mpc playlist