gx_sound_player の紹介と ROS パッケージのリリース手順

# 概要

この記事では自作パッケージの [gx_sound_player](https://github.com/groove-x/gx_sound) の紹介と、ROS パッケージを debian パッケージとしてリリースする手順について紹介しています。

ROS でオーディオファイルを再生する場合は [sound_play](http://wiki.ros.org/ja/sound_play) というパッケージを使うのが一般的だと思います。この sound_play では、トピックを送ったタイミングでオーディオを再生したり、繰り返し再生や停止ができるのですが、シンプルな API しか提供されていないため、予め決められたタイミングでオーディオ再生をさせるのが難しいです。例えば、何らかの動きに合わせてタイミング通りに音を再生したり、短い間隔で連続して音を再生するようなユースケースでは、ちょっと使いづらさがあると思います。
そこで、 [actionlib](http://wiki.ros.org/ja/actionlib) の API で、時刻を指定してオーディオを再生するためのパッケージを [gx_sound_player](https://github.com/groove-x/gx_sound) として公開しました。

※ ちなみに sound_play も actionlib の API を持っているようです。ドキュメントには載ってないけど[ソースコード](https://github.com/ros-drivers/audio_common/blob/master/sound_play/scripts/soundplay_node.py#L402)には含まれていました。

※ gx_sound_player の gx は [GROOVE X 株式会社](http://www.groove-x.com/) の略称 "GX" のことです。 

# gx_sound_player の使い方

gx_sound_player では WAV もしくは OGG 形式のファイルを再生することができます。内部的には Python から `aplay` や `ogg123` コマンドを叩いているだけなので、コマンドから再生できる形式のファイルなら同様の拡張できそうです。 

## インストール

kinetic の場合は apt でインストール可能です。

```bash
$ sudo apt install ros-kinetic-gx-sound
```

kinetic 以外の場合は github からクローンして使ってください。

```bash
$ cd path_to_your/catkin_ws/src
$ git clone https://github.com/groove-x/gx_sound.git
$ cd ../
$ catkin_make
```

## ノードの起動

`sound_player.launch` でノードが起動できます。

```bash
$ roslaunch gx_sound_player sound_player.launch
```

`device_name` でオーディオの再生デバイスを指定することもできます。

```bash
$ roslaunch gx_sound_player sound_player.launch device_name:="デバイス名(default, plughw:1,0 など)"
```

## オーディオの再生

Python から `SimpleActionClient` を使って、1秒おきにオーディオファイルを再生するサンプルです。

```py
#! /usr/bin/env python
# -*- coding: utf-8 -*-

import actionlib
import os
import rospy

from gx_sound_msgs.msg import SoundRequestAction, SoundRequestGoal


def main():
    rospy.init_node('sound_request_client_node')
    client = actionlib.SimpleActionClient('/gx_sound_player/sound_player/sound_request', SoundRequestAction)
    client.wait_for_server()
    rospy.loginfo("connected to actionlib server")

    base_dir = os.path.dirname(os.path.abspath(__file__))
    now = rospy.Time.now()

    # 3秒後に audio3.wav を再生
    goal1 = SoundRequestGoal(stamp=now + rospy.Duration(3.0), file=os.path.join(base_dir, "audio3.wav"))
    # 2秒後に audio2.wav を再生
    goal2 = SoundRequestGoal(stamp=now + rospy.Duration(2.0), file=os.path.join(base_dir, "audio2.wav"))
    # 1秒後に audio1.wav を再生
    goal3 = SoundRequestGoal(stamp=now + rospy.Duration(1.0), file=os.path.join(base_dir, "audio1.wav"))

    rospy.loginfo("send request")
    # 時刻順に送信しなくても時刻順に再生される
    client.send_goal(goal1)
    client.send_goal(goal2)
    client.send_goal(goal3)
    rospy.loginfo("waiting for result")
    client.wait_for_result(rospy.Duration.from_sec(5.0))


if __name__ == '__main__':
    main()
```

`SoundRequestGoal` の `file` に再生したいオーディオファイルのパスを、 `stamp` に再生したい時刻を設定して、sound_player の ActionServer に送ってあげることで、指定時刻になるとオーディオファイルが再生されます。`SoundRequestGoal` の送信順は必ずしも時刻順である必要はなく、任意の順序で送信可能です。また、`stamp` に過去の時刻を設定すると即座に再生されます。前の時刻のオーディオの再生が終わる前に、次のリクエストの時刻になってしまった場合は、前のオーディオ再生はキャンセルされます。

使い方としては、特定の日時にタイマーを鳴らしてあげるとか、ダンスの動きに合わせて声を出すとか、色々考えられますね。

再生周りの挙動は用途に応じて変えたいケースもあると思うので、launch ファイルから変更できるようにしたいなーと思っています。

# debian パッケージとしてのリリース手順

gx_sound_player を公開するにあたって、パッケージを apt で簡単にインストールしてもらえるようリリース作業を行ったので、その際の手順をご紹介します。

## 依存パッケージを rosdep に登録

gx_sound_player は vorbis-tools という debian パッケージに依存しているのですが、この vorbis-tools が rosdep (ROS でシステムの提供するパッケージの依存関係を解決するためのツール) で定義されていなかったため、 [rosdep の更新の PR](https://github.com/ros/rosdistro/pull/16447) を送りました。

```diff:rosdep/base.yaml
+vorbis-tools:
+  arch: [vorbis-tools]
+  debian: [vorbis-tools]
+  fedora: [vorbis-tools]
+  gentoo: [media-sound/vorbis-tools]
+  ubuntu: [vorbis-tools]
```

[gx_sound_player の package.xml](https://github.com/groove-x/gx_sound/blob/master/gx_sound_player/package.xml) には `<exec_depend>vorbis-tools</exec_depend>` のように vorbis-tools への依存が定義されているのですが、その vorbis-tools が各 Linux のディストリビューションにおいて何と言うパッケージ名で提供されているかを定義しています。

## リリース用のリポジトリを作成

パッケージのリポジトリのURL に `-release` をつけた、[リリース用のリポジトリ](https://github.com/groove-x/gx_sound-release)を事前に作成しておきます。パッケージの URL が `https://github.com/groove-x/gx_sound` ならば作成すべきリポジトリは `gx_sound-release` (URL は `https://github.com/groove-x/gx_sound-release`) です。
ちなみに、リポジトリ作成の際に README.md の作成を選択しておくと後の手順がスムーズです。

このリポジトリは後述する `bloom-release` の際に勝手にブランチが作られたり push されたりするので、特に何か作業をしてあげる必要はありません。

## リリース準備

リリースしたいパッケージのリポジトリで `catkin_generate_changelog` コマンドと `catkin_prepare_release` コマンドを順に実行して、`CHANGELOG.rst` の作成(or更新)とバージョン名のタグの作成を行います。

`catkin_generate_changelog` コマンドを実行すると、リポジトリ内のパッケージ(複数ある場合はその全て)に `CHANGELOG.rst` が生成もしくは更新されるので、内容を適宜編集し、変更内容をコミットします。

その後 `catkin_prepare_release` コマンドを実行すると、パッケージのパッチバージョンを上げるコミットとリモートリポジトリへの push が行われます。もし `0.1.0` → `0.2.0` のようにマイナーバージョンを上げたい場合は `catkin_prepare_release --bump minor` のように明示的に指定してあげます。

## bloom-release

`bloom-release` コマンドを使うと、リリースのための情報の集約、リポジトリのアップデート、本家の rosdistro への PR 作成等をまとめて行ってくれます。初回と2回目以降で手順が異なるので、注意が必要です。

### 初回

初回のリリース作業時はパッケージ内容の詳細についてダイアログ形式で答えていく必要があります。通常の ROS パッケージならば、以下に記した部分だけを入力すれば、他はデフォルト値で大丈夫なはずです。
詳細な情報については[本家のチュートリアル](http://wiki.ros.org/bloom/Tutorials/FirstTimeRelease) が非常に分かりやすいです。

```bash
$ bloom-release --rosdistro "ROSのディストリビューション(kinetic など)" --track "ROSのディストリビューション(kinetic など)" "パッケージ名(gx_sound など)" --edit

(中略)

Repository Name:       # デフォルト値の upstream で大丈夫

# 答える
Upstream Repository URI: "github のリポジトリのパス (https://github.com/groove-x/gx_sound.git) など"

Upstream VCS Type:     # デフォルト値の git を使う
Version:               # デフォルト値の :{auto} にしておけば、カイアhつブランチから推定してくれる
Release Tag:           # git のタグを 0.2.0 のようにデフォルト通り運用しているならば、デフォルト値の :{version} で大丈夫
Upstream Devel Branch: #　デフォルト値の None にしておけば、デフォルトのブランチ(通常は master)が使われる 
ROS Distro:            # デフォルトで kinetic って入ってました
Patches Directory:     # None で大丈夫
Release Repository Push URL: # None で大丈夫

(中略)

# rosdistro へのコミット内容に付加的な情報を追加するかいくつか質問されるので、答えられそうならば y を選択します
# 情報があったほうが親切ですが、分からなければ一旦は n にしておいても大丈夫かと
# ドキュメントの情報
Would you like to add documentation information for this repository? [Y/n]?
# ソースの情報 (github へのリンク)
Would you like to add source information for this repository? [Y/n]?
# パッケージのメンテナンス状況
Would you like to add a maintenance status for this repository? [Y/n]? 

(中略)

<== Pull request opened at: https://github.com/ros/rosdistro/pull/xxxxx
```

上記を完了すると、[rosdistro への PR](https://github.com/ros/rosdistro/pull/16444) が自動的に作成されます。特に問題点がなければ数日以内にマージされますが、PR にコメントがつく場合もあるので、その場合は github 上で対応してください。

マージ後、実際に debian パッケージとして配信されるまでは、2週間〜1ヶ月程度かかるようです。

### 2回目以降

2回目以降は、初回に入力した内容がそのまま使われるので、ほとんどダイアログへの回答は不要です。

```bash
$ bloom-release --rosdistro "ROSのディストリビューション(kinetic など)" --track "ROSのディストリビューション(kinetic など)" "パッケージ名(gx_sound など)"

(中略)
<== Pull request opened at: https://github.com/ros/rosdistro/pull/yyyyy
```

こちらも初回同様に rosdistro に PR が作成されてマージされれば、更新内容がそのうち debian パッケージとして配信されます。

# まとめ

この記事では gx_sound_player の紹介と、ROS パッケージを debian パッケージとしてリリースする手順について紹介しました。皆さんも便利なパッケージを作った際は是非リリースして、多くの人に使ってもらえるようにすると良いと思います。

gx_sound_player への改善要望や PR はいつでも大歓迎です！気づいた点がありましたら、是非フィードバックをお願いします！