google-home-notifierの「Error: getaddrinfo -3008」に対処する

# はじめに

[緊急地震速報をGoogle Homeでアナウンスしてみよう](https://qiita.com/hideo-works/items/1d7851fe600b2f90f7a0) と、Ubuntu14.04でgoogle-home-notifierを実行したところ、

```
Error: getaddrinfo -3008
```

が発生しました。以下、その時に行った内容のメモ書きになります。

# browser.js の修正 :confounded:

いつものアレだ と、[google-home-notifier](https://github.com/noelportugal/google-home-notifier) の [After "npm install"](https://github.com/noelportugal/google-home-notifier#after-npm-install) に従い、node_modules/mdns/lib/browser.js へ `{families:[4]}` を追加しました。

```diff:browser.js.diff
--- browser.js	(revision x)
+++ browser.js	(working copy)
@@ -116,7 +116,7 @@
 
 Browser.defaultResolverSequence = [
   rst.DNSServiceResolve()
-, 'DNSServiceGetAddrInfo' in dns_sd ? rst.DNSServiceGetAddrInfo() : rst.getaddrinfo()
+, 'DNSServiceGetAddrInfo' in dns_sd ? rst.DNSServiceGetAddrInfo() : rst.getaddrinfo({families:[4]})
 , rst.makeAddressesUnique()
 ];
```

ところが、結果は変わらず、エラー発生。Raspberry Piなどでは改善したのだけど...、違うのか。

[Raspberry PI 2 getaddrinfo 3008 error #130](https://github.com/agnat/node_mdns/issues/130) 内のコメントにあった `{families:[0]}` なども試してみましたが、これもダメ...。

# IPアドレスを指定 :anguished:

node_modules/google-home-notifier/google-home-notifier.js を確認してみると、Google HomeのIPアドレスを指定すれば、mdnsを使わないことが分かりました。実際、

```js
const googlehome = require('google-home-notifier')

googlehome.device('Google-Home', 'ja'); 
googlehome.ip('192.168.xxx.xxx'); //Google HomeのIPアドレスを指定
googlehome.notify('こんにちは。私はグーグルホームです。', function(res) {
  console.log(res);
});
```

といった感じにすれば、エラーは回避できました。でも、できればIPアドレスは指定したくない...。

# google-home-notifier.js の修正 :grinning:

結局のところ、Google HomeのIPアドレスを別の方法で取得すればよいのか、ということで、[Google Homeの名前とIPアドレスを検出する方法](https://www.gesource.jp/weblog/?p=8082) を参考にしました（ありがとうございます）。そちらでは [multicast-dns](https://github.com/mafintosh/multicast-dns) を利用していたので、node_modules/google-home-notifier/google-home-notifier.js を以下のように修正しました。

```diff:google-home-notifier.js.diff
--- google-home-notifier.js	(revision x)
+++ google-home-notifier.js	(working copy)
@@ -1,7 +1,6 @@
 var Client = require('castv2-client').Client;
 var DefaultMediaReceiver = require('castv2-client').DefaultMediaReceiver;
-var mdns = require('mdns');
-var browser = mdns.createBrowser(mdns.tcp('googlecast'));
+var mdns = require('multicast-dns')()
 var deviceAddress;
 var language;
 
@@ -25,17 +24,28 @@
 
 var notify = function(message, callback) {
   if (!deviceAddress){
-    browser.start();
-    browser.on('serviceUp', function(service) {
-      console.log('Device "%s" at %s:%d', service.name, service.addresses[0], service.port);
-      if (service.name.includes(device.replace(' ', '-'))){
-        deviceAddress = service.addresses[0];
+    mdns.on('response', function (response) {
+      var name = '';
+      var ip = '';
+      for (const additional of response.additionals) {
+        if (additional.type == 'TXT') name = additional.name;
+        if (additional.type == 'A') ip = additional.data;
+      }
+      console.log('Device "%s" at %s', name, ip);
+      if (name.includes(device.replace(' ', '-'))){
+        deviceAddress = ip;
         getSpeechUrl(message, deviceAddress, function(res) {
           callback(res);
         });
+        mdns.destroy();
       }
-      browser.stop();
     });
+
+    mdns.query('_googlecast._tcp.local', 'PTR');
+
+    setTimeout(function () {
+      mdns.destroy();
+    }, 2500);
   }else {
     getSpeechUrl(message, deviceAddress, function(res) {
       callback(res);
```

とりあえずはこの修正で動いているようです（IPアドレスを指定することなく）。最初に応答のあったGoogle Homeのみに通知しているので、オリジナルとは動作が異なる気がしますが...。

# おわりに

今回は場当たり的な対処しか行わなかったので、時間が出来たら根本の原因を調査してみようと思います（調査ってどうやるのだろう...）。