BETA

古いAndroidとラズパイで多機能モニターを作る

投稿日:2019-02-22
最終更新:2019-02-23
※この記事は外部サイト(https://www.rocher.kyoto.jp/arbr/?p=1472)からのクロス投稿です

目的

以前作った店の呼び出しブザーは押されたらline&メール通知を飛ばすようになっている。ただし、押した側からみるとなんの反応も無いため動作しているか不安。なので、googleクラウドで合成させた音声を古いAndroidで流すようにした。(+画面でメッセージ表示)

なお、この記事を書いている段階ではエミュレータで動いたのみ。実機は古すぎて現行のAndroidStudioで素直にビルドできていない。ビルドする方法を調べてから再挑戦。

環境

呼出側

開発環境

  • OS Centos7
  • python 3.7.0
  • the Cloud Client Libraries for the Cloud Text-to-Speech API のアルファ版(ドキュメントが古いだけかも)

想定環境

  • raspberry pi typeB
  • python 3.7.0
  • the Cloud Client Libraries for the Cloud Text-to-Speech API のアルファ版(ドキュメントが古いだけかも

触った限り、本番環境用のraspberry pi typeBで動作はするもののCloud Text-to-Speech APIの呼出が重い。10文字程度で3秒ほど。gRPCの接続/暗号化処理周りでcpuがいっぱいいっぱいになっている模様で端末能力の問題と思う。

呼び出される側(android)

開発環境

  • android studio 3.3.1
  • Androidバージョン 4.2.2
  • compileSdkVersion/targetSdkVersion 28
  • com.nanohttpd:nanohttpd-webserver:2.1.1

想定環境

  • IS11PT
  • Androidバージョン2.3.4

想定端末が古すぎるので開発環境を簡単に整えられなかったので、まずは新しめ(といっても8年ぐらい前)の端末で作成。

呼出側機能

概要

googleのText-to-Speech API を呼び出して、requestでAndroid内に起動させているnanohttpsにpostをするのみ。Text-to-Speech APIはほぼドキュメントどおり。requestのファイルのところはパラメータにMIMEタイプまでしていしてやらないとAndroid側で使っっているnanohttpdでファイルをよみ込めなかったので注意。

ソース

#!/usr/bin/env python3  
# coding: utf-8  
import requests  

from google.cloud import texttospeech  

def make_voice(current_time):  
    _make_voice(current_time,"少々お待ちください")  

def _make_voice(current_time,msg):  
    file_name = 'output.mp3'  
    client = texttospeech.TextToSpeechClient()  
    synthesis_input = texttospeech.types.SynthesisInput(text=msg)  

    voice = texttospeech.types.VoiceSelectionParams(  
        language_code='ja-JP',  
        ssml_gender=texttospeech.enums.SsmlVoiceGender.NEUTRAL)  
    audio_config = texttospeech.types.AudioConfig(  
        audio_encoding=texttospeech.enums.AudioEncoding.MP3)  

    response = client.synthesize_speech(synthesis_input, voice, audio_config)  

    with open('output.mp3', 'wb') as out:  
        out.write(response.audio_content)  

    url = 'http://127.0.0.1:8081/msg/'  
    files = {'file': (file_name,open(file_name, 'rb'),'audio/mpeg')}  
    payload = {"message" :  msg}  
    r = requests.post(url ,files=files ,params=payload)  
    print(r)  
if __name__ == '__main__':  
    make_voice( '2019/02/12 固定' )

呼び出される側

概要

内部で立ち上げているnanohttpdで情報(リクエスト)を受け取って、音声再生し画面にメッセージを出しておく。ちなみに、古いバージョンで動かそうとしてたので文法が古いものから新しいものまで混在しているので適宜読み替えてください。

package jp.co.epea.monitor;  

import android.media.MediaPlayer;  
import android.os.Handler;  
import android.widget.TextView;  


import java.io.IOException;  
import java.util.HashMap;  
import java.util.Map;  

import fi.iki.elonen.NanoHTTPD;  

import static fi.iki.elonen.NanoHTTPD.Response.Status.NOT_FOUND;  
import static fi.iki.elonen.NanoHTTPD.Response.Status.OK;  

public class MoniterServer extends NanoHTTPD {  
    private Handler handler;  
    private TextView textView;  

    public MoniterServer(Handler handler, TextView textView) {  
        super(8080);  
        this.handler = handler;  
        this.textView = textView;  

    }  

    @Override  
    public Response serve(IHTTPSession session) {  
        Method method = session.getMethod();  
        String uri = session.getUri();  

        System.out.println(method + " '" + uri + "' ");  
        if (uri.equals("/msg/")) {  
            final String msg = session.getParms().get("message");  


            Map<String, String> files = new HashMap<>();  
            try {  
                session.parseBody(files);  
            } catch (IOException ioe) {  
                return new NanoHTTPD.Response(NOT_FOUND, MIME_HTML, "none");  
            } catch (ResponseException re) {  
                return new Response(re.getStatus(), MIME_PLAINTEXT, re.getMessage());  
            }  

            MediaPlayer player = new MediaPlayer();  
            try {  
                player.setDataSource(files.get("file"));  
                player.prepare();  
                player.start();  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  

            handler.post(new Runnable() {  
                @Override  
                public void run() {  
                    textView.setText(msg);  
                }  
            });  
            return new NanoHTTPD.Response(OK, MIME_HTML, "ok");  
        } else if (uri.equals("/clear/")) {  
            handler.post(new Runnable() {  
                @Override  
                public void run() {  
                    textView.setText("");  
                }  
            });  
            return new NanoHTTPD.Response(OK, MIME_HTML, "ok");  
        }  
        return new NanoHTTPD.Response(NOT_FOUND, MIME_HTML, "none");  
    }  
}

いつもどおり関係ないけど

そういえば嫁のサイトをazureにも置きました

技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
駆け出しエンジニアからエキスパートまで全ての方々のアウトプットを歓迎しております!
or 外部アカウントで 登録 / ログイン する
クランチについてもっと詳しく

この記事が掲載されているブログ

@qPkJnEPdYTMgQPdyの技術ブログ

よく一緒に読まれる記事

0件のコメント

ブログ開設 or ログイン してコメントを送ってみよう
目次をみる
技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
or 外部アカウントではじめる
10秒で技術ブログが作れます!