日別アーカイブ: 2019年2月22日

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

目的

以前作った店の呼び出しブザーは押されたら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
  • SHL22
  • Androidバージョン 4.2.2
  • compileSdkVersion/targetSdkVersion 28
  • minSdkVersion 16 (開発端末がこの時代の)
  • 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にも置きました