raspberrypi2+DACでMPDサーバを作成する。
今回は作成済みレイヤの使用方法ではなく、レイヤを作成する方法をまとめてみる。 作成済みレイヤの使用方法はこちら
機能
- windows10で共有しているフォルダから音楽ファイルを参照
- MPDサーバで音楽ファイルを再生
- SYSTEMDを使用
- ネットワーク設定にはconnmanを使用
DAC
今回はこのDACを使用する。
システム構成
ネットワークを含めたシステムの構成を 図 1 に示す。
図 1:システム構成
yocto環境
作業に使用するレイヤのブランチとバージョンを 表 1 に示す。
表 1: レイヤのブランチとバージョン
レイヤ | ブランチ | バージョン | URL |
---|---|---|---|
poky | krogoth | 2.1 | git://git.yoctoproject.org/poky.git |
meta-openembedded | krogoth | 2.1 | git://git.openembedded.org/meta-openembedded |
meta-raspberrypi | master | - | git://git.yoctoproject.org/meta-raspberrypi |
meta-hifiberry-rpi | master | - | https://github.com/mickey-happygolucky/meta-hifiberry-rpi.git |
作業ディレクトリ
作業は~/work/yocto/rpi
で行う。
ディレクトリの構成
\~/work/yocto/rpi以下の構成を以下に示す。
. ├── build └── poky ├── meta-openembedded ├── meta-raspberrypi └── meta-hifiberry-rpi
poky以下は追加するレイヤのみ記載している。
ベース環境の作成
ベース環境の手順を示す。
- 作業ディレクトリ(\~/work/yocto/rpi)の作成
- pokyのダウンロード
- meta-openembeddedのダウンロード
- meta-raspberrypiのダウンロード
- meta-hifiberryp-rpiのダウンロード
下記のように実行する。
$ mkdir mkdir -p ~/work/yocto/rpi && cd ~/work/yocto/rpi $ git clone git://git.yoctoproject.org/poky.git -b krogoth && cd poky $ git clone git://git.openembedded.org/meta-openembedded -b krogoth $ git clone git://git.yoctoproject.org/meta-raspberrypi $ git clone https://github.com/mickey-happygolucky/meta-hifiberry-rpi.git
MPD用レイヤ
MPDサーバ向けのレイヤとしてmeta-mpd-server
を作成する。
下記のコマンドを実行し作業用のディレクトリを作成する。
$ mkdir -p ~/work/yocto/rpi/poky/meta-mpd-server
layer.conf
レイヤとしてbitbakeに認識させるためにはlayer.confが必要になる。
layer.confはmeta-mpd-server/conf以下に配置される必要がある。
下記の要領でまず、空のlayer.confファイルを作成する。
$ mkdir -p ~/work/yocto/rpi/poky/meta-mpd-server/conf $ touch ~/work/yocto/rpi/poky/meta-mpd-server/conf/layer.conf
layer.confをエディタで開き コード 1 の内容にに編集し、保存する。
# We have a conf and classes directory, append to BBPATH BBPATH .= ":${LAYERDIR}" # We have a recipes directory containing .bb and .bbappend files, add to BBFILES BBFILES += "${LAYERDIR}/recipes*/*/*.bb \ ${LAYERDIR}/recipes*/*/*.bbappend" BBFILE_COLLECTIONS += "mpd-server" BBFILE_PATTERN_mpd-server := "^${LAYERDIR}/" BBFILE_PRIORITY_mpd-server = "10" LAYERDEPENDS_mpd-server = "raspberrypi"
LAYERDEPENDS_mpd-server = "raspberrypi"
の行で、meta-mpd-serverがmeta-raspberrypiに依存していることを明示している。
この時点でmeta-mpd-serverは以下のような構成になる。
./meta-mpd-server └── conf └── layer.conf
ネットワーク設定
今回はサーバマシンなので、IPアドレスを固定で割り振りたい。 OSイメージがbitbakeで生成された時点で静的なIPアドレスを設定されるようにレシピを作成する。
レシピ名はconnman-ipv4-conf.bb
とする。レシピは役割ごとに分類されたフォルダに配置する。connman-ipv4-conf.bbは以下のように配置する。
recipes-connectivity └── connman └── connman-ipv4-conf.bb
下記のようにコマンドを実行し空のレシピファイルを作成する。
$ mkdir -p ~/work/yocto/rpi/poky/meta-mpd-server/recipes-connectivity/connman $ touch ~/work/yocto/rpi/poky/meta-mpd-server/recipes-connectivity/connman/connman-ipv4-conf.bb
エディタでconnman-ipv4-conf.bbを開き、コード 2 の内容に編集し保存する。
SUMMARY = "Connman config to static IPv4 address setup wired interface" DESCRIPTION = "ConnMan configuration to set up to Wired network interface" LICENSE = "MIT" LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302" FILES_${PN} = "${localstatedir}/*" # IP Address / subnet mask # CONNMAN_IPv4 = xxx.xxx.xxx.xxx/xxx.xxx.xxx.xxx IPv4CFGF = "${D}${localstatedir}/lib/connman/wired.config" do_install() { if [ -n "${CONNMAN_IPv4}" ] ; then install -d ${D}${localstatedir}/lib/connman echo "[global]" > ${IPv4CFGF} echo "Name = Wired" >> ${IPv4CFGF} echo "Description = Wired network configuration" >> ${IPv4CFGF} echo "" >> ${IPv4CFGF} echo "[service_ether]" >> ${IPv4CFGF} echo "Type = ethernet" >> ${IPv4CFGF} echo "IPv4 = ${CONNMAN_IPv4}" >> ${IPv4CFGF} if [ -n "${CONNMAN_IPv4_NS}" ] ; then echo "Nameservers = ${CONNMAN_IPv4_NS}" \ >> ${D}${localstatedir}/lib/connman/wired.config fi else install -d ${D}${localstatedir}/lib/connman touch ${D}${localstatedir}/dummy fi }
このレシピによって、RPi2上に/lib/connman/wired.configが作成され、有線接続のネットワーク設定が行われる。
固定IPアドレスを指定するには、local.confに下記のように記述する。
CONNMAN_IPv4 = 192.168.1.100/255.255.255.0
この例ではIPアドレス192.168.1.100、サブネットマスク255.255.255.0に設定している。
共有フォルダ設定
Windows 10の共有フォルダ
Windows10の共有フォルダをマウントするには下記のようにする。
$ mount -t cifs -ousername=USERNAME,password=PASSWORD,vers=3.0 //machine_name/shared_folder /mnt/point
ポイントはvers=3.0で、これをオプションに指定しないと、下記のようにエラーになってしまう。
mount: mounting //machine_name/shared_folder on /mnt/point failed: Input/output error
vers=
の指定は、jethroのcifs-utilsでは認識されないため、少なくともWindows10の共有フォルダをマウントしたい場合は、krogothかmasterを使用する必要がある。
Windows8については筆者の環境がないため試せないが、もしかすると状況は同じかもしれない。
Windows7に関してはvers=
は必要なかった。
共有フォルダ設定レシピ
OSイメージがbitbakeで生成された時点で指定の共有フォルダがマウントされるようにレシピを作成する。
レシピ名はcifs-mount-networkd.bb
とする。
cifs-mount-networkd.bbは以下のように配置する。
recipes-connectivity └── samba └── cifs-mount-networkd.bb
下記のようにコマンドを実行し空のレシピファイルを作成する。
$ mkdir -p ~/work/yocto/rpi/poky/meta-mpd-server/recipes-connectivity/samba $ touch ~/work/yocto/rpi/poky/meta-mpd-server/recipes-connectivity/samba/cifs-mount-networkd.bb
エディタでcifs-mount-networkd.bbを開き、コード 3 の内容に編集し保存する。
SUMMARY = "Mount CIFS at boot" DESCRIPTION = "Generate a mount unit file to mount remote via cifs at boot." LICENSE = "MIT" LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302" inherit systemd MOUNT_NAME = "${@ '${CIFS_MOUNT_DIR}'.replace('/', '-')[1:]}" CIFS_MOUNT_UNIT = "${D}${sysconfdir}/systemd/system/${MOUNT_NAME}.mount" SYSTEMD_SERVICE_${PN} = "${MOUNT_NAME}.mount" do_install() { if [ -n "${CIFS_SHARED_DIR}" -a -n ${CIFS_MOUNT_DIR} ] ; then install -d ${D}${sysconfdir}/systemd/system if [ ${CIFS_SEC_NTLM} = "1" ] ; then SEC=",sec=ntlm" else SEC="" fi if [ -n ${CIFS_VERS} ] ; then VERS=",vers=${CIFS_VERS}" else VERS="" fi echo "[Unit]" > ${CIFS_MOUNT_UNIT} echo "Description=Mount Share at boot" >> ${CIFS_MOUNT_UNIT} echo "Requires=connman.service" >> ${CIFS_MOUNT_UNIT} echo "After=connman-wait-online.service" >> ${CIFS_MOUNT_UNIT} echo "" >> ${CIFS_MOUNT_UNIT} echo "[Mount]" >> ${CIFS_MOUNT_UNIT} echo "What=${CIFS_SHARED_DIR}" >> ${CIFS_MOUNT_UNIT} echo "Where=${CIFS_MOUNT_DIR}" >> ${CIFS_MOUNT_UNIT} echo "Options=username=${CIFS_USER},password=${CIFS_PASSWD},iocharset=utf8,rw,x-systemd.automount${SEC}${VERS}" >> ${CIFS_MOUNT_UNIT} echo "Type=cifs" >> ${CIFS_MOUNT_UNIT} echo "TimeoutSec=30" >> ${CIFS_MOUNT_UNIT} echo "" >> ${CIFS_MOUNT_UNIT} echo "[Install]" >> ${CIFS_MOUNT_UNIT} echo "WantedBy=multi-user.target" >> ${CIFS_MOUNT_UNIT} fi }
共有フォルダをマウントするにはlocal.confに下記のように記述する。
CIFS_SHARED_DIR = "//machine_name/shared_folder" CIFS_MOUNT_DIR = "/mnt/point" CIFS_USER = "USERNAME" CIFS_PASSWD = "PASSWORD" CIFS_VERS = "3.0"
CIFS_VERSによりオプションにvers=
を設定する。
cifs-mount-networkd.bbでは、複数の共有フォルダのマウントを指定することはできない。
MPD設定
MPDのサウンドデバイスの設定を既存から、DAC向けに変更する必要がある。 そのためにはmpd.confの記述を変更する必要があるが、mpd.confのインストールはmpd_0.19.10.bbで行っている。
bbappendを使用すると既存のレシピを直接変更せずに挙動を変更することができる。
ここではmpd_%.bbappend
を作成する。%
はバージョンをワイルドカード指定している。
bbappendは元になるbbと同じ構成になるように配置する。
mpd_%.bbappend
は以下のようになる。
recipes-multimedia └── musicpd └── mpd_%.bbappend
下記のようにコマンドを実行し空のレシピファイルを作成する。
$ mkdir -p ~/work/yocto/rpi/poky/meta-mpd-server/recipes-multimedia/musicpd $ touch ~/work/yocto/rpi/poky/meta-mpd-server/recipes-multimedia/musicpd/mpd_%.bbappend
エディタでmpd_%.bbappendを開き、コード 4 の内容に編集し保存する。
SYSTEMD_SERVICE_${PN}_remove = "mpd.socket" FILES_${PN} += "${systemd_unitdir}/system/mpd.socket" PACKAGECONFIG_append = " id3tag" do_install_append() { if [ "${HIFIBERRY_DIGI}" = "1" ] ; then echo 'audio_output {' >> ${D}/${sysconfdir}/mpd.conf echo ' type "alsa"' >> ${D}/${sysconfdir}/mpd.conf echo ' name "MyAlsa"' >> ${D}/${sysconfdir}/mpd.conf echo ' device "hw:0,0"' >> ${D}/${sysconfdir}/mpd.conf echo ' mixer_control "Digital"' >> ${D}/${sysconfdir}/mpd.conf echo '}' >> ${D}/${sysconfdir}/mpd.conf fi if [ "${HIFIBERRY_DAC}" = "1" -o "${HIFIBERRY_DACPLUS}" = "1" ] ; then echo 'audio_output {' >> ${D}/${sysconfdir}/mpd.conf echo ' type "alsa"' >> ${D}/${sysconfdir}/mpd.conf echo ' name "MyAlsa"' >> ${D}/${sysconfdir}/mpd.conf echo ' device "hw:0,0"' >> ${D}/${sysconfdir}/mpd.conf echo '}' >> ${D}/${sysconfdir}/mpd.conf fi }
PACKAGECONFIG_append = " id3tag"
の行がないとmp3ファイルが正しくDBに登録されない。
これは、mp3タグの解析が有効にならないため。
音源ディレクトリの設定
mpdはmpd.confのmusic_directoryで指定されたディレクトリ以下にある音楽ファイルを再生する。
このディレクトリをマウント済みのWindowsの共有フォルダを参照する。
mpd_0.19.bbにより、music_directoryは/var/lib/mpd/music
に設定されている。
今回は共有フォルダをマウントしている/mnt/nas
のシンボリックリンクを/var/lib/mpd/music
に作成するアプローチを取る。
そのためのレシピmpd-musicdir_0.1.bb
を作成する。
レシピの構成
レシピの構成は以下のようになる。
recipes-multimedia └── musicpd ├── mpd-musicdir │ ├── mpd-musicdir.service │ └── replace-mpd-musicdir.sh └── mpd-musicdir_0.1.bb
シンボリックリンクの作成はreplace-mpd-musicdir.sh
で行う。
そして、システム起動時にmpd-musicdir.service
により、replace-mpd-musicdir.sh
を実行するようにしている。
下記の要領で空のファイルを作成する。
$ mkdir -p ~/work/yocto/rpi/poky/meta-mpd-server/recipes-multimedia/musicpd/mpd-musicdir $ touch ~/work/yocto/rpi/poky/meta-mpd-server/recipes-multimedia/musicpd/mpd-musicdir_0.1.bb $ touch ~/work/yocto/rpi/poky/meta-mpd-server/recipes-multimedia/musicpd/mpd-musicdir/mpd-musicdir.service $ touch ~/work/yocto/rpi/poky/meta-mpd-server/recipes-multimedia/musicpd/mpd-musicdir/replace-mpd-musicdir.sh
まず、エディタでmpd-musicdir_0.1.bbを開き コード 5 の内容に編集、保存する。
SUMMARY = "Replace mpd music directory." DESCRIPTION = "Generate a unit file to replace music directory." LICENSE = "MIT" LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302" inherit systemd RDPENDS = "mpd" SRC_URI = "file://mpd-musicdir.service \ file://replace-mpd-musicdir.sh \ " FILES_${PN} = "${sysconfdir}/systemd/system/* \ ${bindir}/* \ " CIFS_MOUNT_NAME = "${@ '${CIFS_MOUNT_DIR}'.replace('/', '-')[1:]}" MPD_MUSICDIR_UNIT = "${D}${sysconfdir}/systemd/system/mpd-musicdir.service" SYSTEMD_SERVICE_${PN} = "mpd-musicdir.service" do_install() { if [ -n "${MPD_MUSIC_DIR}" ] ; then install -d ${D}${sysconfdir}/systemd/system install -m 0644 ${WORKDIR}/mpd-musicdir.service ${D}${sysconfdir}/systemd/system if [ -n "${CIFS_MOUNT_NAME}" ] ; then sed -i 's|Before=mpd.service|Before=mpd.service\nAfter=${CIFS_MOUNT_NAME}.mount|' \ ${MPD_MUSICDIR_UNIT} fi install -d ${D}${bindir} install -m 0755 ${WORKDIR}/replace-mpd-musicdir.sh ${D}${bindir} sed -i -e 's|MPD_MUSIC_DIR_SRC=""|MPD_MUSIC_DIR_SRC="${MPD_MUSIC_DIR}"|' \ ${D}${bindir}//replace-mpd-musicdir.sh fi }
次に、mpd-musicdir.serviceをエディタで コード 6 の内容に編集する。
[Unit] Description="Replace MPD Musid Directory" Before=mpd.service [Service] Type=oneshot ExecStart=/usr/bin/replace-mpd-musicdir.sh [Install] WantedBy=multi-user.target
最後に、replace-mpd-musicdir.shをエディタで コード 7 のように編集する。
#!/bin/sh MPD_MUSIC_DIR_SRC="" MPD_MUSIC_DIR_DST="/var/lib/mpd/music" if [ -d ${MPD_MUSIC_DIR_DST} ] ; then rmdir ${MPD_MUSIC_DIR_DST} fi if [ -d "${MPD_MUSIC_DIR_SRC}" ] ; then ln -s "${MPD_MUSIC_DIR_SRC}" "${MPD_MUSIC_DIR_DST}" else echo "${MPD_MUSIC_DIR_SRC} is not directory." exit 1 fi echo "done."
bitbakeの準備
OSイメージを作成するためにbitbakeを実行するが、その前に書きコマンドでbitbakeを実行するために必要な設定を行う。
$ cd ~/work/yocto/rpi $ source poky/oe-init-build-env build
実行後、buildディレクトリが生成され、自動的に移動される。
生成されたbuildディレクトリは以下のような構成になっている。
./build └── conf ├── bblayers.conf ├── local.conf └── templateconf.cfg
conf以下のファイルは自動生成されたもので、この内、bblayers.confとlocal.confは修正する必要がある。
bblayers.conf
bblayers.confはbitbakeがビルド対象とするレイヤを定義する。
MPDサーバをビルドするため、自動生成されたbblayers.confを コード 8 の内容にまるごと置き換える。
# POKY_BBLAYERS_CONF_VERSION is increased each time build/conf/bblayers.conf # changes incompatibly POKY_BBLAYERS_CONF_VERSION = "2" BBPATH = "${TOPDIR}" BBFILES ?= "" LAYERSTOP = "${TOPDIR}/.." BBLAYERS ?= " \ ${LAYERSTOP}/poky/meta \ ${LAYERSTOP}/poky/meta-poky \ ${LAYERSTOP}/poky/meta-yocto-bsp \ ${LAYERSTOP}/poky/meta-raspberrypi \ ${LAYERSTOP}/poky/meta-mpd-server \ ${LAYERSTOP}/poky/meta-hifiberry-rpi \ ${LAYERSTOP}/poky/meta-openembedded/meta-oe \ ${LAYERSTOP}/poky/meta-openembedded/meta-python \ ${LAYERSTOP}/poky/meta-openembedded/meta-networking \ ${LAYERSTOP}/poky/meta-openembedded/meta-multimedia \ "
local.conf
local.confはターゲットマシンの設定やインストールするレシピの追加、その他様々な設定を記述することができる。
通常は、自動生成されたものにマシンの設定とレシピの追加を行うことが多い。
自動生成されたlocal.confの先頭の方に コード 9 の内容を追加する。
MACHINE ?= "raspberrypi2" BB_NUMBER_THREADS ?= "${@oe.utils.cpu_count()}" PARALLEL_MAKE ?= "-j ${@oe.utils.cpu_count()}" GPU_MEM = "128" DL_DIR ?= "${HOME}/work/yocto/downloads" # use systemd instead of sysvinit DISTRO_FEATURES_append = " systemd" VIRTUAL-RUNTIME_init_manager = "systemd" DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit" VIRTUAL-RUNTIME_initscripts = "" # # systemd-timesyncd NTP_SERVER = "ntp.nict.jp" ## cifs mount IMAGE_INSTALL_append = " cifs-utils cifs-mount-networkd" CIFS_SHARED_DIR = "//192.168.1.60/Music" CIFS_MOUNT_DIR = "/mnt/nas" CIFS_USER = "USERNAME" CIFS_PASSWD = "PASSWORD" CIFS_VERS = "3.0" # mpd LICENSE_FLAGS_WHITELIST = "commercial" IMAGE_INSTALL_append = " mpd" # connman IMAGE_INSTALL_append = " connman \ connman-wait-online \ connman-ipv4-conf \ " # static IPv4 address for connman CONNMAN_IPv4 = "192.168.1.55/255.255.255.0" CONNMAN_IPv4_NS = "192.168.1.1" # Enable I2C ENABLE_I2C = "1" # DAC S/PDIF HIFIBERRY_DIGI = "1" # MPD Music Directory IMAGE_INSTALL_append = " mpd-musicdir" MPD_MUSIC_DIR = "/mnt/nas" # misc IMAGE_INSTALL_append = " alsa-utils file"
bitbakeの実行
下記の要領で、bitbakeを実行する。
$ cd ~/work/yocto/rpi/build $ bitbake rpi-basic-image
下記のディレクトリに、OSイメージファイルrpi-basic-image-raspberrypi2.rpi-sdimg
が生成される。
build/tmp/deploy/images/raspberrypi2
イメージの書き込み
ddコマンドでrpi-basic-image-raspberrypi2.rpi-sdimg
をSDカードに書き込む。
sudo dd if=tmp/deploy/images/raspberrypi2/rpi-basic-image-raspberrypi2.rpi-sdimg of=/dev/sdb bs=40M
起動
イメージを書き込んだSDカードをRPi2に挿入し電源をONする。
connman-wait-online.serviceについて
本来であれば、connman.incの下記の行によってサービスがenableされ、システム起動時に実行されるようになるはずだが、
SYSTEMD_SERVICE_${PN}-wait-online = "connman-wait-online.service"
現状では、おそらくpokyの不具合によりdisabledの状態になっている。
そのため、下記のようにして、connman-wait-online.serviceをenableする必要がある。
$ systemctl enable connman-wait-online.service $ sync
connman-wait-online.serviceが実行されないと起動時の共有フォルダのマウントに失敗するため、 MPDも意図したとおり音楽ファイルを参照できない。
connman-wait-online.serviceをenableしたあと、RPi2を再起動する。