SATCHのマーカーをタップしてしゃべらせる
SATCHのサンプルTOUCH MEを使います。
使用方法は、
このページ(SATCHのTOUCH MEを使ってみる)
参照
サンプルの中で、スクリーンタップに対応しているのは、TouchscreenWake.luaの中のtapFingerView()関数です。
これが機能すると、TouchMeSample.Javaコードの中の、openSatch()が呼ばれます。
このコードは、Lua --> java です。
java --> Luaは別のサンプルで...。
サンプルでは、他のサイトがオープンするようなコードになっていますが、ここを書き換て、N2 TTSにしゃべらせる文字列を渡しています。
New
文字列は、サーバーから取得するようにしました。
タップしてからしゃべるまで、1~2秒ほどタイムラグがあります。
サーバーとの通信は、Luaに書くか、java側に書くか、2とおりありますが、今回はjava(javascript)に書いています。
というわけで、SATCHのコンテンツ自体は、新規でもオリジナルのままでもいいです。
TOP
Android用サンプル
ダウンロードが完了後、通知バーに表示されるので、apkファイルをクリックしてインストール。
検出用画像のサンプル
KDDIの「N2 TTS」が必要です。インストールしておいてください。
アンドロイドで日本語音声出力(TextToSpeech):音声読み上げ
を参照。
assets¥Senarioに格納するシナリオファイルは、ご自分で作成。
プロジェクトファイル
src¥com¥kddi¥satch¥gambaemblemactivity¥GambaemblemActivity_simple.java
assets¥www¥index.html
以下のようにコードの「追加4xx」部分を修正してください。
「要修正」のところは、ご自分のdpdファイル名。
【GambaemblemspeechActivity_simple.java】
package com.kddi.satch.gambaemblemspeechActivity; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.os.Bundle; import android.os.Handler; import android.view.KeyEvent; import android.view.View; import android.widget.FrameLayout; import com.kddi.satch.LoadScenarioStatus; import com.kddi.satch.ARViewer; import android.speech.tts.TextToSpeech;//追加4tts import android.speech.tts.TextToSpeech.OnInitListener;//追加4tts public abstract class GambaemblemspeechActivity_simple extends Activity implements OnInitListener {//追加4tts implements protected abstract String getSampleScenarioName(); protected abstract String getSampleLogTag(); //add private static final String THIS_CLASS_SHORT_NAME = GambaemblemspeechActivity_simple.class.getName().replace("com.kddi.satch.gambaemblemspeech.", ""); private static final String THIS_LOGTAG = THIS_CLASS_SHORT_NAME; public TextToSpeech tts;//追加4tts protected boolean _isInitializedCorrectly; protected ARViewer _kddiComponent; protected FrameLayout _frameLayout; public void resetMembers(){ _isInitializedCorrectly = false; _frameLayout = null; _kddiComponent = null; } private static final int DIALOG_EXIT = 0; public void initComponent(){ _isInitializedCorrectly = false; _kddiComponent = new ARViewer(this); // This FrameLayout must be empty (but initialized) when you pass it to the kddiComponent.initialize() method. _frameLayout = new FrameLayout(this); _kddiComponent.initialize(_frameLayout); _isInitializedCorrectly = true; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Add null to AR Viewer Library compornent's reference. resetMembers(); } @Override public void onRestart() { super.onRestart(); } @Override public void onStart() { super.onStart(); // Create AR Viewer Library compornent. initComponent(); postInitComponent(); initContentView(); if (_isInitializedCorrectly) { // Do authorize and madia is loaded. // You must call loadScenario() method. loadScenario(); } } @Override public void onResume(){ super.onResume(); if (_isInitializedCorrectly) { // GL context is recreated and media is reloaded. _kddiComponent.onResume(); reservePlayScenario(); } } @Override public void onPause() { // When the activity is paused the GL context is destroyed, so all media is unloaded. if (_isInitializedCorrectly) { cancelReservePlayScenario(); if (_kddiComponent.checkLoadScenarioStatus() == LoadScenarioStatus.COMPLETE) { _kddiComponent.pauseScenario(); } _kddiComponent.onPause(); } super.onPause(); } @Override public void onStop() { releaseContentView(); // Destroy AR Viewer Library Objects. if (_isInitializedCorrectly){ _kddiComponent.terminate(); _kddiComponent = null; _frameLayout = null; } super.onStop(); } //追加4tts @Override public void onInit(int status) { //空 // } @Override public void onDestroy() { // Destroy AR Viewer Library Objects. if (_isInitializedCorrectly){ _frameLayout = null; _kddiComponent = null; } super.onDestroy(); resetMembers(); // forced clean //追加4tts tts.shutdown(); } @Override public boolean onKeyDown(int keyCode, KeyEvent msg){ switch(keyCode){ case android.view.KeyEvent.KEYCODE_BACK : showDialog( DIALOG_EXIT ); return true; } return false; } public void postInitComponent(){ // override this if you need to do some special handling on the component after standard initialization if (_isInitializedCorrectly) { _kddiComponent.activateAutoFocusOnDownEvent(true); } } public void initContentView(){ // override this if you need to do some special handling on the component after standard initialization if (_isInitializedCorrectly) { // you'll probably use some other UI object as the content view that itself will embed the component's frame layout -- here you can change all this // by default, the frame layout containing DFusion will be the activity content view setContentView(_frameLayout); } } public void releaseContentView(){ // override this if you need to do some special handling on the component after standard initialization if (_isInitializedCorrectly) { // do here the release of the your UI instances (if customized) } } public void loadScenario(){ ApplicationInfo appInfo = null; PackageManager packMgmr = getApplicationContext().getPackageManager(); try { appInfo = packMgmr.getApplicationInfo(getPackageName(), 0); } catch (NameNotFoundException e) { e.printStackTrace(); throw new RuntimeException("Unable to locate assets, aborting..."); } String dpdfile = appInfo.sourceDir + getSampleScenarioName(); _kddiComponent.loadScenario(dpdfile); } // Set polling rate for loading the media. private final int REPEAT_INTERVAL = 100; private Handler handler = new Handler(); private Runnable runnable = null; // private void reservePlayScenario(){ if (runnable == null){ runnable = new Runnable(){ @Override public void run(){ LoadScenarioStatus status = _kddiComponent.checkLoadScenarioStatus(); if (status == LoadScenarioStatus.CANCEL){ // cancel(appli suspend) }else if (status == LoadScenarioStatus.COMPLETE){ // Ready to play scenario _frameLayout.setVisibility(View.VISIBLE); _kddiComponent.playScenario(); }else if ( status == LoadScenarioStatus.ERROR_NETWORK_UNUSABLE || // faild to load a media becase of no network connection. status == LoadScenarioStatus.ERROR_NETWORK || // faild to load a media becase of network error. status == LoadScenarioStatus.ERROR_SOFTWAREKEY || // faild to load a media becase software key has not be found on server. status == LoadScenarioStatus.ERROR_CONTENT_STOPPED || // faild to load a media becase content has stopped. status == LoadScenarioStatus.ERROR_SERVER || // faild to load a media becase of server error. status == LoadScenarioStatus.ERROR_ETC // faild to load a media becase of another error. ){ // error }else{ handler.postDelayed(this, REPEAT_INTERVAL); } } }; handler.postDelayed(runnable, REPEAT_INTERVAL); } } // private void cancelReservePlayScenario(){ if (handler != null && runnable != null){ handler.removeCallbacks(runnable); runnable = null; } } protected Dialog onCreateDialog(int id) { Dialog dialog; switch(id) { case DIALOG_EXIT: { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setMessage( "Really want to quit the sample?" ) .setCancelable(true) .setPositiveButton("Yes", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { finish(); }}) .setNegativeButton("No", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); }}); dialog = builder.create(); break; } default: dialog = null; } return dialog; } }
package com.kddi.satch.gambaemblemspeech; import com.kddi.satch.gambaemblemspeechActivity.GambaemblemspeechActivity_simple; import android.os.Bundle; //add import android.content.Intent; import android.net.Uri; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.speech.tts.TextToSpeech;//追加4tts //追加4web import android.content.Context; import android.webkit.WebChromeClient; import android.webkit.WebView; public class GemblemspeechActivity extends GambaemblemspeechActivity_simple { private static final String THIS_CLASS_SHORT_NAME = GemblemspeechActivity.class.getName().replace("com.kddi.satch.gambaemblemspeech.", ""); private static final String THIS_LOGTAG = THIS_CLASS_SHORT_NAME; // Set AR scenario file path. private static final String SCENARIO_NAME = "/assets/Scenario/Scenario_a/gambaemblemspeech.dpd";//要修正 protected String getSampleScenarioName() { return SCENARIO_NAME; } protected String getSampleLogTag() { return THIS_LOGTAG; } //追加4web private WebView webView = null; @Override public void postInitComponent(){ super.postInitComponent(); //add if (_isInitializedCorrectly) { _kddiComponent.activateAutoFocusOnDownEvent(true); _kddiComponent.registerCommunicationCallback("openSatch", this, "openSatch"); } } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //追加4tts tts = new TextToSpeech(getApplicationContext(), this); //追加4web webView = new WebView(this); webView.setWebChromeClient(new WebChromeClient()); webView.getSettings().setJavaScriptEnabled(true); JavascriptAdapter jsobj = new JavascriptAdapter(this); webView.addJavascriptInterface(jsobj, "android_ar"); webView.loadUrl("file:///android_asset/www/index.html"); } //追加4tts public void onInit(int status) { if (status == TextToSpeech.SUCCESS) { //空 } else { // } } //add public void openSatch(String[] arrayOfString) { //追加4tts webView.loadUrl("javascript:ajax_job()"); } //add @Override public boolean onCreateOptionsMenu(Menu menu) { menu.add(Menu.NONE, Menu.FIRST, Menu.NONE, getString(R.string.setting)); return super.onCreateOptionsMenu(menu); } //add @Override public boolean onOptionsItemSelected(MenuItem item) { boolean ret = true; switch (item.getItemId()) { default: ret = super.onOptionsItemSelected(item); break; case Menu.FIRST: ret = true; Intent intent = new Intent(GemblemspeechActivity.this.getApplicationContext(), GambaemblemSetting.class); startActivity(intent); break; } return ret; } //JavaScript -> Java class JavascriptAdapter { private Context con; public JavascriptAdapter(Context con) { this.con = con; } // public void start_tts(String speec_content){ tts.speak(speec_content, TextToSpeech.QUEUE_FLUSH, null); } } }
<!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <title></title> <script src="http://code.jquery.com/jquery-1.6.1.min.js"></script> <script type="text/javascript" charset="utf-8"> function onSuccess_ajax(data, status){ information = data; android_ar.start_tts(information); } function onError_ajax(data, status){ // handle an error alert("err"); } function ajax_job(){ var formData = "data=" + "dummy"; var url_ajax = "http://wisteriahill.sakura.ne.jp/satch/call_message.php"; $.ajax({ type: "POST", url: url_ajax, cache: false, data: formData, success: onSuccess_ajax, error: onError_ajax }); return false; } </script> </head> <body </body> </html>
//使用するパッケージ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.speech.tts.TextToSpeech; import android.speech.tts.TextToSpeech.OnInitListener; import android.speech.tts.TextToSpeech.OnUtteranceCompletedListener; import java.util.HashMap; import java.util.Map; import android.widget.Toast; ・ ・ ・ ・ private TextToSpeech tts; ・ ・ ・ public void onCreate(Bundle savedInstanceState) { tts = new TextToSpeech(getApplicationContext(), new OnInitListener() { public void onInit(int status) { //スピーチ終了のリスナー tts.setOnUtteranceCompletedListener(new OnUtteranceCompletedListener() { public void onUtteranceCompleted(String utteranceId) { //To Do } }); } }); } @Override public void onInit(int status) { if (status == TextToSpeech.SUCCESS) { tts.speak("TTS準備OKです", TextToSpeech.QUEUE_FLUSH, null); } else { // } } @Override public void onDestroy() { super.onDestroy(); resetMembers(); // forced clean tts.shutdown(); } private void tts_speak(){ //N2 TTSが入っているかチェック String res = package_check("jp.kddilabs.n2tts"); if (res.equals("ok")){ String UTTERANCE_ID = "SPEECH";//ここは何でもいいです HashMap<String, String> ttsparam = new HashMap<String, String>(); ttsparam.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, UTTERANCE_ID); tts.speak("テキスト", TextToSpeech.QUEUE_FLUSH, ttsparam); }else if (res.equals("no")){ Toast.makeText(satchActivity_simple.this, "音声出力エンジンのN2 TTSがみあたりません", Toast.LENGTH_LONG).show(); } } private String package_check(String package_name){ String exist_stat = "ok"; // try { PackageManager packageManager = this.getPackageManager(); ApplicationInfo applicationInfo = packageManager.getApplicationInfo(package_name,PackageManager.GET_META_DATA); }catch(NameNotFoundException exception){ exist_stat = "no"; } return exist_stat; }