AndroidにLinux環境を構築してHaruziraと通信しよう! (2019/01/25 new)
環境構築の概要
AndroidにLinux Terminal環境を導入して、Haruzira SDKのSample Programを動作させるための環境構築手順について説明します。
このTipsでは、Linux Terminalに「Termux」を利用し、PythonやRubyを導入します。
大まかな手順の流れは、次のようになります。
- Termuxのインストール
- TermuxにSSHDを導入(省略可能)
- Pythonのインストール
- Rubyのインストール
なお、今回はAndroidスマートフォン上にインストールしていますが、Androidタブレッド等でも動作可能だと思います。
また、この記事で筆者が利用したAnrdroidのバージョンは「7.0」ですが、Termuxが導入できれば他のバージョンでも大丈夫です。
動作確認に必要な環境(Termux利用時)
Server |
Windows 10(Anniversary Update以降)が動作するDeviceまたは仮想PC UWPアプリHaruziraを動作させる |
---|---|
Client |
Termuxが動作するAndroid Device pythonまたはrubyプログラムを動作させる |
Termuxの導入
Termuxは、Android上で動作するLinuxパッケージコレクションを含むTerminal Emulationです。
Google Playからインストールできます。
Termux
1.Termuxのインストール完了後、gitをインストールし、パッケージを最新の状態に更新
apt install git
apt update
apt upgrade
2.Termuxが割り当てるストレージ(Storage)の設定
termux-setup-storage
3.設定を行ったストレージ状態を確認(homeディレクトリは、/data/data/com.termux/files/home)
ls -l ~/storage/
total 0
lrwxrwxrwx 1 u0_a114 u0_a114 24 Jan 11 13:32 dcim -> /storage/emulated/0/DCIM
lrwxrwxrwx 1 u0_a114 u0_a114 28 Jan 11 13:32 downloads -> /storage/emulated/0/Download
lrwxrwxrwx 1 u0_a114 u0_a114 48 Jan 11 13:32 external-1 -> /storage/61DC-DB25/Android/data/com.termux/files
lrwxrwxrwx 1 u0_a114 u0_a114 26 Jan 11 13:32 movies -> /storage/emulated/0/Movies
lrwxrwxrwx 1 u0_a114 u0_a114 25 Jan 11 13:32 music -> /storage/emulated/0/Music
lrwxrwxrwx 1 u0_a114 u0_a114 28 Jan 11 13:32 pictures -> /storage/emulated/0/Pictures
lrwxrwxrwx 1 u0_a114 u0_a114 19 Jan 11 13:32 shared -> /storage/emulated/0
SDカードと内部ストレージは、次のように割り当てられます。
PCからプログラムファイルなどを転送する場合は、これらのディレクトリに保存するようにします。
- SDカード: ~/storage/external-1
- 内部ストレージ: ~/storage/shared
PCと接続した場合のSDカード割り当ては、次のようになります。
デバイス名/SDカード/Android/data/com.termux
4.Termux上のエディタ
Termux上で設定ファイル等の編集を行う場合は、viがインストール済みなのでviを利用するのが簡単です。
日本語ファイルも問題なく編集できます。(viが苦手なユーザーは、emacsのインストールも可能です)
なお、AndroidシステムとTermux間でのクリップボードを経由した、データのやり取りはできませんでした。(Copy and Pastなど)
WEBで調べたコマンドなどを貼り付けたい場合は、一旦テキストファイルに落とすか、またはSSHDサーバーを起動し、PC等からSSHでリモート接続を行い操作したほうが快適になります。
SSHDの導入
Termux上にSSHDを起動することで、PC等から安全にリモート接続することができます。
SSHを利用しない場合は、この作業は不要なので読み飛ばして構いません。
今回は、前回の記事で構築したWSL環境を利用して公開鍵の作成などを行います。
PC側で鍵を生成しておき管理すると、PowerShellやコマンドプロンプトなどをSSHクライアントにする場合に便利です。(Termux上で生成しても構いません)
1.Termuxにopensshをインストール
apt install openssh
2.WSLで秘密鍵と公開鍵を生成(現状、最も安全性の高いEd25519で生成)
鍵ファイルの生成先と、鍵にするパスフレーズ(passphrase)を尋ねてくるので設定する。
(生成先はデフォルト(/home/xxxx/.ssh/id_ed25519)のままで問題ない)
ssh-keygen -t ed25519
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/sms/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/sms/.ssh/id_ed25519.
Your public key has been saved in /home/sms/.ssh/id_ed25519.pub.
The key fingerprint is:
SHA256:6pRdPxxxxxxxx......... sms@myhost
The key's randomart image is:
+--[ED25519 256]--+
|o.o . |
|+ = o . . o |
|E. o * + Z + . |
|. . * A & . |
| + W % * |
| o . * = = o |
| + . = . + |
| . . o o |
| |
+----[SHA256]-----+
次の鍵ファイルが、/home/xxxx/.ssh配下に生成されます。
秘密鍵:id_ed25519(SSHクライアント側で使用)
公開鍵:id_ed25519.pub(SSHDサーバー側で使用)
3.公開鍵をTermuxに転送
WSL上の公開鍵ファイルを、Windows10のフォルダに一時コピー後、Androidのストレージに転送します。
(可能であれば、Androidデバイスを直接マウントし転送しても構わない)
また、Termux上で公開鍵の設定完了後、WSL上の./ssh/配下と一時コピーしたフォルダ配下の公開鍵ファイル(id_ed25519.pub)は、安全のために削除して下さい。
cp ~/.ssh/id_ed25519.pub /mnt/d/work
上記一時フォルダからPC\デバイス名\SDカード\Android\data\com.termux\filesへ転送します。
4.Termux上に公開鍵を設定し、パーミッション(Permission)を変更
cat ~/storage/external-1/id_ed25519.pub >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
5.WSLから転送したファイルを削除
rm ~/storage/external-1/id_ed25519.pub
6.SSHDサーバーの起動(sshd)と停止(pkill sshd)
sshd
pkill sshd
7.SSHクライアントからの接続(WSLをクライアントにする)
TermuxのIP addressを、次のコマンド等で事前に確認しておきます「ifconfig wlan0」。
また、Termux上のSSHDサーバーのポート番号は、8022です。
接続時、鍵生成時に使用したパスフレーズを尋ねてくるので入力して下さい。
ssh 192.168.1.2 -p 8022
8.SSHクライアントからの接続(PowerShellやコマンドプロンプトをクライアントにする)
Windows10 Fall Creators Update以降は、OpenSSHクライアントがインストール済みです。秘密鍵ファイルのみ次のフォルダにコピーして下さい。
C:\users\ユーザー名\.ssh\id_ed25519
.sshフォルダが無い場合は作成する。
接続方法は、上記WSLでの接続と同じ。
Pythonの導入
Pythonの導入手順について説明します。
今回は、趣味的な利用を想定しているので、Termux上にpyenvは導入しません。
また、aptコマンドでインストールを行うので、最新のバージョンを利用したい場合は、再インストールを行う方法で十分だと思います。
Androidで本格的な開発を行うユーザーは少ないと思うのですが、興味があれば挑戦してみて下さい。
1.aptでインストールしバージョンを確認
apt install python
python -V
Python 3.7.2
2.依存ライブラリなどのインストール(numpyインストール時にエラーが発生するため)
apt install python-dev fftw
apt install clang libc++
pip install wheel
3.pipのインストール状態を確認
pip list
Package Version
------------ -------
pip 18.1
setuptools 40.6.2
whell 0.32.3
Rubyの導入
Rubyの導入手順について説明します。
Pythonと同様に、今回は趣味的な利用を想定しているので、Termux上にrbenvは導入しません。
また、aptコマンドでインストールを行うので、最新のバージョンを利用したい場合は、再インストールを行う方法で十分だと思います。
Androidで本格的な開発を行うユーザーは少ないと思うのですが、興味があれば挑戦してみて下さい。
1.aptでrbenvをインストールしバージョンを確認
apt install ruby
ruby -v
ruby 2.5.3p105 (2018-10-18 revision 65156) [aarch64-linux-android]
2.gemの状態を確認
gem list
*** LOCAL GEMS ***
bigdecimal (default: 1.3.4)
cmath (default: 1.0.0)
csv (default: 1.0.0)
date (default: 1.0.0)
did_you_mean (1.2.0)
:
Sample Programの概要
今回作成するSample Programについて説明します。(PythonとRubyで共通)
前回のWSL導入Tipsで記載したSample Programと同様に、文字列を宛先に送信しますが、次のようなシナリオでプログラムを作成します。
- 複数言語で送信する(日本語、英語、フランス語)
- 言語毎に性別を変更する
- 言語毎に2回再生を繰り返す
- 言語毎の送信は、各言語の再生終了後に行う(読み上げ完了メッセージ受信後)
なお、最も簡単なSammple Programに関しては、前回の記事を参考にして下さい。
Sample Programを実行している様子を動画にしたので参考にして下さい。
動画サイズ: 約3.47MB
プログラムの実行前準備
①システムの言語設定で、英語とフランス語を追加する。
(追加済みの場合は、不要)
追加方法がわからない場合は、Haruzira User's Manualを参考にして下さい。
Haruzira User's Manual - 言語の追加方法
①Haruziraの設定「読み上げ全般設定」で読み上げ変換タイプが「SSMLに変換」になっていることを確認する。
(既定値ではSSML変換となる)
②Server側でHaruziraを起動し、リモート読み上げ画面でServerを起動する。
(既定値のPort番号(46000)で受信する場合は、特別な設定は不要です。)
Python Sample Program
先ずは、haruzira_sdkをインストールしましょう。
1.haruzira_sdkのインストール
(haruzira_sdk, numpy, pycryptoがインストールされる)
pip install haruzira_sdk
pip list
Package Version
------------ -------
haruzira-sdk 2.1.0
numpy 1.16.0
pip 18.1
pycrypto 2.6.1
setuptools 40.6.2
wheel 0.32.3
2.ソースコードの作成
send_multi_langs.py(メインプログラム)
# coding: utf-8
import time
import threading
from haruzirasdk import hz_client_tcp_communication as hzcomm
import multi_langs_msg as langs
#variable for an event.
comp_evt = threading.Event()
#region Define for callback functions.
#
# An event for the message of 'Speech Completion Notice'.
#
# submit result
# time stamp
def rcv_notify_complete_speech(result, time_stamp):
#print("{0:s}:result[0x{1:02x}], time stamp[{2:s}]".format(strings["rec_comp"], result, time_stamp))
print("recieved notify complete speech. time stamp[{0:s}]".format(time_stamp))
comp_evt.set()
#endregion
#A list for creating instances of the MultiLangsMsg class.
msgs = []
#create instance and initialize.
#Japanese.
msgs.append(langs.MultiLangsMsg("この電車は、まもなく新宿駅に停車します。", 0x0411, hzcomm.HzSpeechGender.Female))
#English(u.s).
msgs.append(langs.MultiLangsMsg("This train will soon stop at Shinjuku Station.", 0x0409, hzcomm.HzSpeechGender.Male))
#French.
msgs.append(langs.MultiLangsMsg("Ce train s'arrêtera bientôt à la gare de Shinjuku.", 0x0040c, hzcomm.HzSpeechGender.Female))
#Initialize haruzira sdk.
clt_tcp_comm = hzcomm.ClientTcpCommunication()
clt_tcp_comm.ServerPortNo = 46000 #port number for access point
clt_tcp_comm.ServerIP = "192.168.1.7" #ip address for access point
clt_tcp_comm.evNotifyCompleteSpeech = rcv_notify_complete_speech
try:
for msg in msgs:
comp_evt.clear()
clt_tcp_comm.ReqSendDataText = msg.get_message()
clt_tcp_comm.ReqSendDataSpeechLocaleId = msg.get_locale()
clt_tcp_comm.ReqSendDataSpeechGender = msg.get_gender().value
clt_tcp_comm.ReqSendDataSpeechRepeat = 1
timestamp = clt_tcp_comm.sendSpeechDataEx()
if(timestamp is not None):
print("time stamp[{0:s}]".format(timestamp))
else:
print("send error")
#wait for receiving 'Speech Completion Notice' message.
comp_evt.wait(20)
except Exception as ex:
pass
finally:
#close receiving listener.
clt_tcp_comm.cancelAsynchronousListener()
- 4,5行目:Haruzira SDKとMultiLangsMsgクラスを参照するための宣言。
- 8行目:イベント制御変数の宣言。
- 16-19行目:読み上げ完了通知(Speech Completion Notice)メッセージ受信時のCallback関数定義。
- 22-30行目:MultiLangsMsgクラスのインスタンスを生成及び初期化しリストに格納。(日本語、英語、フランス語の送信データを生成)
- 32-35行目:通信クラスのインスタンスを生成し、宛先情報を設定。
- 36行目:読み上げ完了通知受信時のCallback関数の設定。
- 39行目:送信するメッセージ数分ループ。
- 40行目:イベント状態のクリア。
- 41行目:送信メッセージの設定。
- 42行目:ロケールIDの設定。
- 43行目:読み上げる音声の性別設定。
- 44行目:読み上げリピート回数の設定。(繰返したい回数 - 1)
- 45行目:送信処理。(送信が成功した場合は、送信時のタイムスタンプが返る)
- 46-49行目:送信結果の判定。
- 51行目:読み上げ完了通知を受信するまで次のメッセージ送信を待機。(デッドロックを防止するため20秒でタイムアウト。この値は、再生するメッセージの長さとリピート回数を考慮する。)
- 52-53行目:例外発生時の処理。passは何も処理をしないでスルーする。エラーを表示したい場合はprint(ex)等で表示する。
- 54-56行目:プログラム終了時にリスナースレッドを停止する。(Pythonの場合は、必須処理)
multi_langs_msg.py(言語毎の送信メッセージ設定クラス)
# coding: utf-8
from haruzirasdk import hz_client_tcp_communication as hzcomm
class MultiLangsMsg(object):
#
# Construct
#
# a messsage text
# locale ID(language code)
# gender(HzSpeechGender)
def __init__(self, msg = None, locale = None, gender = None):
self.__msg = ""
self.__locale = 0x0409
self.__gender = hzcomm.HzSpeechGender.Female
if(msg is not None):
self.__msg = msg
if(locale is not None):
self.__locale = locale
if(gender is not None):
self.__gender = gender
#region define accessor
def get_message(self):
return self.__msg
def set_message(self, value):
self.__msg = value
def get_locale(self):
return self.__locale
def set_locale(self, value):
self.__locale = value
def get_gender(self):
return self.__gender
def set_gender(self, value):
self.__gender = value
#endregion
- 4行目以降:MultiLangsMsgクラス定義。
- 12-21行目:コンストラクタ処理。(引数省略に対応)
- 23-41行目:read/write用のaccessor(プロパティ)定義。(送信メッセージ、ロケールID、性別)
3.プログラムの実行手順
①34,35行目のIP addressとPort番号を、環境に合わせて編集して下さい。
②Sample Programの実行
ファイアーウォールの許可を求められた場合は、許可して下さい。
python send_multi_langs.py
time stamp[15:18:10]
recieved notify complete speech. time stamp[15:18:10]
time stamp[15:18:25]
recieved notify complete speech. time stamp[15:18:25]
time stamp[15:18:42]
recieved notify complete speech. time stamp[15:18:42]
③Server側で受信に成功すると、送信した言語毎の文字列が再生されます。
Ruby Sample Program
先ずは、haruzira_sdkをインストールしましょう。
1.haruzira_sdkのインストールとインストール状態の確認
gem install haruzira_sdk
gem list haruzira_sdk
*** LOCAL GEMS ***
haruzira_sdk (2.1.0)
2.ソースコードの作成
SendMultiLangs.rb(メインプログラム)
#!/usr/bin/ruby
# -*- coding: utf-8 -*-
require "timeout"
require "haruzira_sdk"
require "./MultiLangsMsg"
class SendMessage
@@msgs = []
@@msgs.push(MultiLangsMsg.new("この電車は、まもなく新宿駅に停車します。", 0x0411, HzSpeechGender::Female))
@@msgs.push(MultiLangsMsg.new("This train will soon stop at Shinjuku Station.", 0x0409, HzSpeechGender::Male))
@@msgs.push(MultiLangsMsg.new("Ce train s'arrêtera bientôt à la gare de Shinjuku.", 0x040c, HzSpeechGender::Female))
def initialize(ip, port)
@clt_tcp_comm = ClientTcpCommunication.new
@clt_tcp_comm.ServerPortNo = port #port number for access point
@clt_tcp_comm.ServerIP = ip #ip address for access point
@queWaitNotifyCompleteSpeech = Queue.new
###############################################################
# call back functions for haruzirasdk. called when occurred events on a network communication.
###############################################################
#
# notify when received a 'speech completion notice' message.
#
# submit result
# time stamp
@clt_tcp_comm.EvNotifyCompeteSpeech = lambda{|result, time_stamp|
puts("recieved notify complete speech. time stamp[%s]" % [time_stamp])
@queWaitNotifyCompleteSpeech.push("OK")
}
#end define call back function
end
#
# waiting for response within timeout limit.
#
# timeout value to wait for response.
# message queue object
def queuePopWithTimeout(t_val, que)
ret = false
begin
Timeout.timeout(t_val) do
qret = que.pop
end
ret = true
rescue Timeout::Error => ex
puts("occurred timeout in waiting for response.")
ret = false
ensure
return ret
end
end
#
# send messages.
#
def text2speech()
begin
for msg in @@msgs
@queWaitNotifyCompleteSpeech.clear
@clt_tcp_comm.ReqSendDataText = msg.msg
@clt_tcp_comm.ReqSendDataSpeechLocaleId = msg.locale
@clt_tcp_comm.ReqSendDataSpeechGender = msg.gender
@clt_tcp_comm.ReqSendDataSpeechRepeat = 1
timestamp = @clt_tcp_comm.sendSpeechDataEx()
if(timestamp != nil)
puts("time stamp#{timestamp}")
end
queuePopWithTimeout(20, @queWaitNotifyCompleteSpeech)
end
rescue Exception => ex
puts(ex)
ensure
end
end
end
#========== main routine ===================
sendMsg = SendMessage.new("192.168.1.7", 46000)
sendMsg.text2speech()
- 4,5行目:Haruzira SDKとMultiLangsMsgクラスを参照するための宣言。
- 7-78行目:メッセージ送信制御クラス(SendMessageクラス)。
- 22-30行目:MultiLangsMsgクラスのインスタンスを生成及び初期化し配列に格納。(日本語、英語、フランス語の送信データを生成)
- 13-32行目:コンストラクタ処理定義。
- 14-16行目:通信クラスのインスタンスを生成し、宛先情報を設定。
- 17行目:読み上げ完了通知の受信待ちに使用するメッセージキューの生成。
- 27-30行目:読み上げ完了通知(Speech Completion Notice)メッセージ受信時のCallback関数定義。(lambda利用)
- 40-53行目:メッセージキューの処理メソッド。
- 58-76行目:メッセージ送信処理メソッド。
- 60行目:送信するメッセージ数分ループ。
- 61行目:イベント状態のクリア。
- 62行目:送信メッセージの設定。
- 63行目:ロケールIDの設定。
- 64行目:読み上げる音声の性別設定。
- 65行目:読み上げリピート回数の設定。(繰返したい回数 - 1)
- 66行目:送信処理。(送信が成功した場合は、送信時のタイムスタンプが返る)
- 67-69行目:送信結果の判定。
- 70行目:読み上げ完了通知を受信するまで次のメッセージ送信を待機。(デッドロックを防止するため20秒でタイムアウト。この値は、再生するメッセージの長さとリピート回数を考慮する。)
- 72-73行目:例外発生時の処理。エラーを表示する。
- 74-75行目:実行を保証する処理を定義する。(このプログラムでは何もしない)
- 81行目:SendMesssageクラスのインスタンス生成。(宛先のIP addressとポート番号を引数に指定)
- 82行目:メッセージ送信処理。
MultiLangsMsg.rb(言語毎の送信メッセージ設定クラス)
#!/usr/bin/ruby
# -*- coding: utf-8 -*-
require "haruzira_sdk"
class MultiLangsMsg
#
# Construct
#
# a messsage text
# locale ID(language code)
# gender(HzSpeechGender)
def initialize(pmsg = nil, plocale = nil, pgender = nil)
@msg = ""
@locale = 0x0409
@gender = HzSpeechGender::Female
if (pmsg != nil)
@msg = pmsg
end
if (plocale != nil)
@locale = plocale
end
if (pgender != nil)
@gender = pgender
end
end
attr_accessor :msg, :locale, :gender
end
- 5行目以降:MultiLangsMsgクラス定義。
- 13-26行目:コンストラクタ処理。(引数省略に対応)
- 28行目:read/write用のaccessor(プロパティ)定義。(送信メッセージ、ロケールID、性別)
3.プログラムの実行手順
①81行目のIP addressとPort番号を、環境に合わせて編集して下さい。
②Sample Programの実行
ファイアーウォールの許可を求められた場合は、許可して下さい。
ruby SendMutliLangs.rb
time stamp[15:19:44]
recieved notify complete speech. time stamp[15:19:44]
time stamp[15:19:59]
recieved notify complete speech. time stamp[15:19:59]
time stamp[15:20:13]
recieved notify complete speech. time stamp[15:20:13]
③Server側で受信に成功すると、送信した言語毎の文字列が再生されます。
なお、次の様なwarning messageが表示される場合は、改行コードをCRLFからLFに変更してみて下さい。
warning: shebang line ending with \r may cause problems
まとめ
Termuxを利用することで、AndroidにLinux環境を簡単に構築できるようになりました。
ソケット通信やスレッド制御にも対応しているようなので、Sample ProgramのようにHaruzura SDKでも動作します。
本格的な開発環境には向いていませんが、Haruziraのようにネットワークに対応したアプリで遊んでみるのも面白いと思います。
また、TermuxはSSHにも対応しています。SSHDサーバーを起動すれば、PC等からTermuxへリモート接続して操作することも可能です。
次回以降も、SDKの機能を紹介しながら、WSLやAndroid等を利用したSample Programを紹介していく予定です。