HOME > Various Tips > 音声合成の活用 > AndroidにLinux環境構築


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プログラムを動作させる







android termux




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を紹介していく予定です。







更新履歴

2019.01.28

 
  • 「Sample Programの概要」に実行時の動画を追加

2019.01.25: 新規追加