黒電話 Bluetooth ハンズフリー機化-その7
Summary
前回 黒電話でダイヤルして番号を取得できるようになったので、今回はその取得した番号にスマホから実際に電話できるようにしていきたいと思います。
Bluetooth 接続テスト
スマホとしては iPhone を用意しました。
まずはスマホと RasPi と Bluetooth 接続してみます。
Bluetooth 接続は、以前説明したとおり、BlueZ を使います。
bluetoothctl で接続
まずは BlueZ が提供している CLI ツールである bluetoothctl を使って接続してみます。
今回は、Bluetooth 接続がどんな流れで行われるのかを確認することを目的とします(ゆくゆくは、アプリから D-Bus 経由で Bluetooth 接続できるようにします)。
BlueZ は Raspberry Pi OS にはじめからインストールされています。
➜ Kurodenwa git:(master) ✗ bluetoothctl -v
bluetoothctl: 5.55
➜ Kurodenwa git:(master) ✗ /etc/init.d/bluetooth status
● bluetooth.service - Bluetooth service
Loaded: loaded (/lib/systemd/system/bluetooth.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2022-04-04 13:17:38 BST; 2 months 26 days ago
Docs: man:bluetoothd(8)
Main PID: 560 (bluetoothd)
Status: "Running"
Tasks: 1 (limit: 1598)
CPU: 125ms
CGroup: /system.slice/bluetooth.service
└─560 /usr/libexec/bluetooth/bluetoothd
もちろんデーモンも自動起動しています。
接続テスト
参考にしたサイト
nical Notes
HFP on Raspberry Pi
- power on ~ scan
➜ Projects bluetoothctl # bluetoothctl を起動 Agent registered [bluetooth]# power on Changing power on succeeded [bluetooth]# agent on Agent is already registered [bluetooth]# default-agent Default agent request successful # RasPi 側からスキャンする [bluetooth]# scan on Discovery started ... # iPhone のデバイス ID がわかる [NEW] Device XX:XX:XX:XX:XX:XX iPhone923 [bluetooth]# scan off
iPhone のデバイス ID がわかりました。
この ID をもとに接続など行うようですね。 - pair
[bluetooth]# pair XX:XX:XX:XX:XX:XX Attempting to pair with XX:XX:XX:XX:XX:XX [CHG] Device XX:XX:XX:XX:XX:XX Connected: yes Request confirmation
[agent] Confirm passkey 128871 (yes/no): yes Pairing successful
pairing できました。
- trust
ペアリングのあとは trust というステップが必要なんですね。[bluetooth]# trust XX:XX:XX:XX:XX:XX [CHG] Device XX:XX:XX:XX:XX:XX Trusted: yes Changing XX:XX:XX:XX:XX:XX trust succeeded
trust できました。 これで Raspi 側と iPhone 側とで、お互いに Bluetooth 機器としての登録が完了したようです。
- connect
実際に繋げてみます。[bluetooth]# connect XX:XX:XX:XX:XX:XX Attempting to connect to XX:XX:XX:XX:XX:XX [CHG] Device XX:XX:XX:XX:XX:XX Connected: yes Connection successful [iPhone923]#
iPhone 側でも
paspberrypi
とConnected
になりました。
ここまでで iPhone との接続が完了しました。
接続の流れもなんとなくわかりましたね。
課題の発見
今回は、bluetoothctl 側(RasPi 側)から scan しました。
この方法だと、黒電話として完成したとき、ペアリングしたい場合、黒電話の RasPi にいちいち別のコンピュータからターミナル接続して bluetoothctl を立ち上げて scan して… とすることになります(←課題)。
多分ですが、 RasPi 側を scan 待ちにして iPhone からみつけてもらう、ということもできると思います。
後ほど調べてみます。
oFono 経由で電話をかける
前回までに説明したとおり、Bluetooth 接続機能は BlueZ が、 電話機能は oFono がそれぞれ提供しています。 この状態で、oFono で電話をかければ iPhone で電話ができるはずです。
さて、どうやって oFono で電話をかければいいのでしょうか。
oFono の詳細な説明はリポジトリにある(というか、リポジトリにしかない)ので、最新版を DL してその中を漁ってみます。
まさに、手探り状態
まあ、いつもそうですが..。
サンプルコードを発見
test ディレクトリにサンプルコードがたくさん置いてあり、電話をかけるコードもありました。公式サイトではここ。
なるほど。サンプルコードから oFono サービスに D-Bus 経由で接続して、電話をかける命令を実行しているようです。
ということは、 RasPi 上に oFono のサービスが立ち上がっている必要があります。
oFono のインストール
では、RasPi に oFono をインストールします。
➜ ~ sudo apt install ofono -y
➜ ~ /etc/init.d/ofono status
● ofono.service - Telephony service
Loaded: loaded (/lib/systemd/system/ofono.service; enabled; vendor preset: enabled)
Active: active (running) since Sun 2022-07-03 14:08:34 BST; 2min 34s ago
Main PID: 14459 (ofonod)
Tasks: 1 (limit: 1598)
CPU: 106ms
CGroup: /system.slice/ofono.service
└─14459 /usr/sbin/ofonod -n
Jul 03 14:08:34 raspberrypi systemd[1]: Starting Telephony service...
Jul 03 14:08:34 raspberrypi ofonod[14459]: oFono version 1.31
Jul 03 14:08:34 raspberrypi systemd[1]: Started Telephony service.
oFono サービスが起動しました。
サンプルコードで電話をかけてみる
サンプルコード実行のため、RasPi 側でも oFono の最新のソースを取得します。
git でも取得できるので、こちらを使いました。
➜ Projects git clone git://git.kernel.org/pub/scm/network/ofono/ofono.git
➜ Projects cd ofono
➜ ofono git:(master)
RasPi と iPhone とが Bluetooth 接続されていることを確認して、 サンプルコード dial-number
を実行します。
➜ ofono git:(master) python test/dial-number 000
Using modem /hfp/org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX
/hfp/org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX/voicecall01
かかりました!
電話番号は 000
にしたので、「おかけになった電話番号は現在使われておりません…」 と自動アナウンスが流れます。
今回は音声の入出力を iPhone にしましたが、audio と書いてあるボタンを押すと RasPi も選べました。RasPi(黒電話)側でマイクとスピーカの準備が必要ですね。
プログラミング
Python のコード(test/dial-number
)を Ruby に移植して、それを黒電話が番号を検知したあとに呼び出せばよいです。
require 'timers'
require 'dbus'
require './context'
# TODO: 接続時に取得できるようにする
MODEM = "/hfp/org/bluez/hci0/dev_xx_xx_xx_xx_xx_xx"
class Dial
...
def call
return if @dial_nums.length < 3
context = Context.instance
context.notify_event Events::OUTGO
dial_str = @dial_nums.join
# 実際に電話をかける
bus = DBus::SystemBus.instance
rb_service = bus.service("org.ofono")
rb_object = rb_service.object(MODEM)
vcm = rb_object["org.ofono.VoiceCallManager"]
# puts vcm
hide_callerid = 'default'
path = vcm.Dial(dial_str, hide_callerid)
context.notify_event Events::RESPONSED
# puts path
end
...
end
前回の Dial クラスの call メソッドに処理を追加しました。
Rury の D-Bus 用ライブラリ Ruby D-Bus を使用します。
MODEM として Bluetooth の機器 ID が必要なので、iPhone の ID を直接記載しています。
そのうちアプリから RasPi とスマホとの Bluetooth 接続を実装すれば、接続するときのスマホの ID が判明しますので、その値を代入できるようにすれば良いです。その時までは直接記載しておきます。
電話番号が3桁以上あれば、正しい番号として電話を試みます。
このとき、すぐに OUTGO
イベントを発生させて context に通知します。 context では、Outgoing
状態(発信中)に遷移させます。
電話は D-Bus 経由で oFono サービスを呼び出し、 VoiceCallManager
オブジェクトに対して Dial
メソッドを実行します。このとき電話番号を渡します。
成功すると、 path
が返ります。
本来なら、電話がかからなかったケース等、異常パターンもコーディングするべきですが今回は割愛します。
このとき、RESPONSED
イベントを発生させて context に通知します。 context では、Talking
状態(通話中)に遷移させます。
状態遷移図(再掲)
今回は、簡易的に Talking
状態に遷移させました。
次回は、このあたりを説明します。
主な機能の実装状況
- 受話器の上げ下ろしの検出(フック操作)
- ダイヤル回転検出
- ダイヤル番号検出
- スマホとの Bluetooth 接続
- D-Bus 経由で接続する ←追加
- RasPi 側を Scan 待ちにする ←追加
- 着信
- 発信 ←完了
- 音声出力(スピーカ)
- 音声入力(マイク)
- ベルの鳴動
- 電池駆動
- 充電機能
Comments