Google Glassの新機能をハックする


はじめに
GoogleGlassの新型(V2)の目玉の一つにイヤホン(Earbud)のサポートがあります。
このイヤホン、実は両耳タイプも存在しているのですが、Explore招待プログラムの時期には発売されておらず、なんとか新型の入手に成功できたものの、同時購入することができずに悔しい思いをされている方も多いのではないかと思います。また標準添付のイヤホンもGlassのロゴをあしらったお洒落なデザインで見た目はかなりクールなのですが、実際に使ってみると装着感がいまひとつで常時着けて使うのには残念な品物でした。

そこでGlassに自分好みのイヤホンを付けられるようにしてみましたので、その方法についてレポートいたします。

免責事項
この記事に書かれている内容は技術的な参考資料として記載しています。
端末等の破損や作業上の事故について弊社および記事作成者は責任を持ちません。
実施にあたっては各自の判断において行うようにしてください。

1.イヤホンをサポートする仕掛け
Glassにイヤホンを差し込む場所は充電やUSBデバッグを行うための端子で、もともとは通信を行うためのものです。同じような使い方ができるものにスマートフォンがありますが、新型Glass(V2)にも同様にUSB回路をアナログ的に切り替えられるスイッチが入っており、USB通信とイヤホンの信号を切り替えられるようになりました。

またカーネルソースを調べるとUSB機能を切り替えるコードが見つかりました。

arch/arm/mach-omap2/notel-usb-mux.c

static void sync_usb_mux_mode(struct usb_mux_device_info *di)
{
  enum usb_mux_mode mode;

~~~~~~
~~~~~~
  if (di->force_usb || di->usb_online)
    mode = USB_MUX_MODE_USB;
  else
    mode = di->req_mode;

  dev_warn(di->dev, "Setting MUX mode to %s\n", str_for_mode(mode));
  switch (mode) {
    case USB_MUX_MODE_FLOATING:
      gpio_set_value(di->gpio_cb1, 0);
      gpio_set_value(di->gpio_cb0, 0);
      break;

    case USB_MUX_MODE_USB:
      gpio_set_value(di->gpio_cb1, 0);
      gpio_set_value(di->gpio_cb0, 1);
      break;

    case USB_MUX_MODE_TTY:
      gpio_set_value(di->gpio_cb1, 1);
      gpio_set_value(di->gpio_cb0, 0);
      break;

    case USB_MUX_MODE_AUDIO:
      gpio_set_value(di->gpio_cb1, 1);
      gpio_set_value(di->gpio_cb0, 1);
      break;

    default:
      dev_err(di->dev, "Invalid USB MUX mode requested: %d\n", mode);
      goto error;
  }

  di->cur_mode = mode;

error:
return;
}

この部分はsysfsから設定されるようになっていてフレームワーク側から切り替えを行っているようです。
もうお気づきかと思いますが、上記コードからGlassにはイヤホン以外にもシリアルポートも付くことが見て取れます。もしシリアルポートへの切り替えができればカーネルデバッグに役立つはずですが、しかし切り替えはフレームワーク側で行っているためこの部分からは推察することができません。今後の調査が必要かと思います。


2.市販のアダプタは使えるか?
ちょうど手元に愛用PHSに添付されていた変換アダプタがあり、機能的に類似していることから試しに接続してみましたが、標準添付イヤホンのように音声が切り替わらず骨伝導スピーカから音声が出続けました。また近所の百均で売っている変換アダプタも同様でした。どうやら日本国内で流通している規格とは違うもののようです。


3.解析してみる
コネクタ部分はUSBのMicro-Bタイプなので変換アダプタに繋いで回路を調べてみました。
標準添付のイヤホンはD+とGND間の抵抗が40Ωだったのでここがダイナミックスピーカを使った音声系だと判ります。それ以外にIDとGND間にも回路抵抗があり、この部分が外付けアクセサリを識別する仕掛けのようです。


今度は日本国内で入手できる変換アダプタです。


同じようにD+/D-とGNDがヘッドホン端子に繋がっているのでこの部分は等価の回路です。
ところがIDとGND間の抵抗値が異なります。

標準添付のイヤホン 1MΩ
国内のもの 287K-303KΩ

USB関連の文献を探してみるとGlassの添付品は"Audio Type 1"、日本国内で流通しているものは"Audio Cradle"に準拠したものであることが判りました。

3. 改造
標準添付品との差異が判ればあとは改造するのみです。
今回は百均のSeriaさんで売っている変換アダプタを使いました。このシリーズの変換アダプタはUSB側のコネクタが分解できるようになっていていまして、百均USBハッカー御用達の商品となっています。

慎重にピンセットでUSBコネクタ側のケースを開けるとコネクタ部分に抵抗が付いているのを見ることができます。
この抵抗を1MΩに交換します。端子部分が細かいのでショートしないように気を付けてください。

交換が終わったらステレオヘッドホンを繋いでGlassと接続します。
今まで鳴っていた骨伝導スピーカからの音が止まりヘッドホンの両耳から操作音が出ていれば成功です。
なお必ずステレオヘッドホンを使用してください、モノラルタイプは右側の回路が短絡して故障の原因となります。またGlassは外部マイクをサポートしないのでマイク付きのものを使用してもマイクは動作しません。

まとめ
今後、音楽再生アプリが使えるようになればGlassで快適に音楽が楽しめるようになるでしょう。
1500ドルもする開発デバイスが百均の商品でハックできるなんて面白いですね。
次回はGlassをAndroidっぽく使う方法についてレポートする予定です。


おまけ: Glassの隠しモード
カーネルコードを追っていると次のような保守用コードが見つかりました。
USBコネクタのID端子とVBUSを短絡したケーブルを接続すると強制的にfastbootに移行するようです。
通常動作中でもお構いなしに強制的シャットダウンしてしまうので恐ろしくて実験できませんが、たぶん文鎮化したGlassを復旧する目的のために実装されたものとだ思われます。

arch/arm/mach-omap2/notel-usb-mux.c

#define FACTORY_CABLE_VOLTAGE_THRESHOLD 4200 /* millivolts */
#define CABLE_SHUTDOWN_INTERVAL     30000 /* msec */

static void sync_usb_mux_mode(struct usb_mux_device_info *di)
{
 enum usb_mux_mode mode;
 int id_voltage;

 /* check for factory cable */
 id_voltage = voltage_id(0, 0);
 if (notle_factorycable_bootmode) {
  /* schedule a shutdown if factory cable removed */
  if (id_voltage < FACTORY_CABLE_VOLTAGE_THRESHOLD) {
     schedule_delayed_work(&di->shutdown_work, msecs_to_jiffies(CABLE_SHUTDOWN_INTERVAL));
  }
 } else {
  if (id_voltage > FACTORY_CABLE_VOLTAGE_THRESHOLD) {
    kernel_restart("bootloader");
  }
 }

ブランド戦略部 中村和貴