[Сценарий] Google Home в качестве терминала

Не требует установки программ или изменения файлов

Модераторы: immortal, newz20

Аватара пользователя
Gelezako
Сообщения: 963
Зарегистрирован: Чт июн 02, 2016 9:33 pm
Благодарил (а): 205 раз
Поблагодарили: 106 раз
Контактная информация:

Re: Google Home в качестве терминала

Сообщение Gelezako » Пн май 21, 2018 5:24 pm

directman66 писал(а):
Пн май 21, 2018 5:16 pm
Notifier установился? Как сервис висит? Случает порт?
На сколько я понял из кода всё что делает Notifier дак это предоставлять урл к мп3 для того что бы отсылать его на гугл хоум для воспроизведения. Ещё он может синтезировтаь мп3 из текста. Если вместо этого я буду использовать потоковое радио с МЖД, то Notifier тут как бы не нужен. Есть проблема именно работы гугл хоум как терминал для воспроизведения. Поправьте если я что-то не так понял.
фанат Мажордомо
тематический блог http://blog.gelezako.com
плейлист про Мажордомо на ютубе https://www.youtube.com/playlist?list=P ... EdBGtX084E
directman66
Сообщения: 2801
Зарегистрирован: Пн дек 26, 2016 9:51 am
Откуда: Екатеринбург
Благодарил (а): 380 раз
Поблагодарили: 693 раза
Контактная информация:

Re: Google Home в качестве терминала

Сообщение directman66 » Пн май 21, 2018 7:19 pm

Без notifier вы не сможете ничего отправить на колонку, не разве что через bubbleUpnp. Сервис notifier выпольняет эмуляцию телефона на базе android и может давать команду воспроизвести mp3 или аудио-поток. Есть и другие подобные проекты, но у меня заработал только этот.
Если вам помогло данное сообщение, не поленитесь нажать кнопку "спасибо".
CONNECT | Оборудование | Блог | Дополнения | Email | Telegram
Аватара пользователя
Gelezako
Сообщения: 963
Зарегистрирован: Чт июн 02, 2016 9:33 pm
Благодарил (а): 205 раз
Поблагодарили: 106 раз
Контактная информация:

Re: Google Home в качестве терминала

Сообщение Gelezako » Пн май 21, 2018 7:29 pm

directman66 писал(а):
Пн май 21, 2018 7:19 pm
Сервис notifier выпольняет эмуляцию телефона на базе android и может давать команду воспроизвести mp3 или аудио-поток.
Очень сильно сомневаюсь что сервис эмулирует андроид. Всё что он делает дак это формирует HTTP ссылку на аудио-поток, которую можно скормить Google Home. Эмулировать Android тут нет необходимости, это уж очень геморно было бы.
фанат Мажордомо
тематический блог http://blog.gelezako.com
плейлист про Мажордомо на ютубе https://www.youtube.com/playlist?list=P ... EdBGtX084E
directman66
Сообщения: 2801
Зарегистрирован: Пн дек 26, 2016 9:51 am
Откуда: Екатеринбург
Благодарил (а): 380 раз
Поблагодарили: 693 раза
Контактная информация:

Re: Google Home в качестве терминала

Сообщение directman66 » Пн май 21, 2018 8:24 pm

Если почитать код, там вроде используется библиотека node-castv2-client https://github.com/thibauts/node-castv2 ... s/media.js
Если вам помогло данное сообщение, не поленитесь нажать кнопку "спасибо".
CONNECT | Оборудование | Блог | Дополнения | Email | Telegram
Аватара пользователя
Gelezako
Сообщения: 963
Зарегистрирован: Чт июн 02, 2016 9:33 pm
Благодарил (а): 205 раз
Поблагодарили: 106 раз
Контактная информация:

Re: Google Home в качестве терминала

Сообщение Gelezako » Пн май 21, 2018 8:59 pm

directman66 писал(а):
Пн май 21, 2018 8:24 pm
Если почитать код, там вроде используется библиотека node-castv2-client https://github.com/thibauts/node-castv2 ... s/media.js
а какое отношение эта библиотека имеет к Андроиду? Если прочитать описание:
СпойлерПоказать
This module implements a Chromecast client over the new (CASTV2) protocol. A sender app for the DefaultMediaReceiver application is provided, as well as an Application base class and implementations of the basic protocols (see the controllers directory) that should make implementing custom senders a breeze.
то можно понять что это имплементация протокола CASTV2, который работает в Chromecast.
За это сообщение автора Gelezako поблагодарил:
directman66 (Пн май 21, 2018 9:07 pm)
Рейтинг: 1.16%
фанат Мажордомо
тематический блог http://blog.gelezako.com
плейлист про Мажордомо на ютубе https://www.youtube.com/playlist?list=P ... EdBGtX084E
dilligaf
Сообщения: 2
Зарегистрирован: Пт июн 01, 2018 11:26 pm
Благодарил (а): 0
Поблагодарили: 0

Re: Google Home в качестве терминала

Сообщение dilligaf » Пт июн 01, 2018 11:30 pm

Добрый день.
В обработчик before say не передается значение $filename.
В итоге yandex tts говорит, а на google-home уходит пустой url. Подскажите, есть решение?
skysilver
Сообщения: 3006
Зарегистрирован: Чт авг 21, 2014 8:28 am
Откуда: Киров, Россия
Благодарил (а): 400 раз
Поблагодарили: 1753 раза
Контактная информация:

Re: Google Home в качестве терминала

Сообщение skysilver » Пт июн 01, 2018 11:35 pm

dilligaf писал(а):
Пт июн 01, 2018 11:30 pm
Добрый день.
В обработчик before say не передается значение $filename.
В итоге yandex tts говорит, а на google-home уходит пустой url. Подскажите, есть решение?
Имя файла получают так:

Код: Выделить всё

$filename       = md5($message) . '_yandex.mp3';
MajorDoMo (GitHub) на Cubietruck. ОС Debian 7 (wheezy) (kernel 3.4.105) с переносом на HDD.
Мой CONNECT | Блоги | Telegram
dilligaf
Сообщения: 2
Зарегистрирован: Пт июн 01, 2018 11:26 pm
Благодарил (а): 0
Поблагодарили: 0

Re: Google Home в качестве терминала

Сообщение dilligaf » Пт июн 01, 2018 11:41 pm

Спасибо, да! Заменил на md5($ph), получилось
directman66
Сообщения: 2801
Зарегистрирован: Пн дек 26, 2016 9:51 am
Откуда: Екатеринбург
Благодарил (а): 380 раз
Поблагодарили: 693 раза
Контактная информация:

Re: Google Home в качестве терминала

Сообщение directman66 » Чт июн 21, 2018 6:35 am

Может у кого есть возможность портировать проект node.js https://github.com/noelportugal/google-home-notifier в части отправки mp3 контента на устройство? Сейчас хотелось бы научиться использовать колонку google home без установки доп. сервисов.

Протокол, который используется в google-home-notifier описан в проекте https://github.com/thibauts/node-castv2-client

Вроде есть пример https://github.com/ChrisRidings/CastV2inPHP

В принципе и не так сложно, весь нужный нам функционал описан в файле media.js
СпойлерПоказать

Код: Выделить всё

var util                      = require('util');
var debug                     = require('debug')('castv2-client');
var RequestResponseController = require('./request-response');

function MediaController(client, sourceId, destinationId) {
  RequestResponseController.call(this, client, sourceId, destinationId, 'urn:x-cast:com.google.cast.media');

  this.currentSession = null;

  this.on('message', onmessage);
  this.once('close', onclose);

  var self = this;

  function onmessage(data, broadcast) {
    if(data.type === 'MEDIA_STATUS' && broadcast) {
      var status = data.status[0];
      // Sometimes an empty status array can come through; if so don't emit it
      if (!status) return;
      self.currentSession = status;
      self.emit('status', status);
    }
  }

  function onclose() {
    self.removeListener('message', onmessage);
    self.stop();
  }

}

util.inherits(MediaController, RequestResponseController);

MediaController.prototype.getStatus = function(callback) {
  var self = this;

  this.request({ type: 'GET_STATUS' }, function(err, response) {
    if(err) return callback(err);
    var status = response.status[0];
    self.currentSession = status;
    callback(null, status);
  });
};

MediaController.prototype.load = function(media, options, callback) {
  if(typeof options === 'function' || typeof options === 'undefined') {
    callback = options;
    options = {};
  }

  var data = { type: 'LOAD' };

  data.autoplay = (typeof options.autoplay !== 'undefined')
    ? options.autoplay
    : false;

  data.currentTime = (typeof options.currentTime !== 'undefined')
    ? options.currentTime
    : 0;

  data.activeTrackIds = (typeof options.activeTrackIds !== 'undefined')
    ? options.activeTrackIds
    : [];

  data.repeatMode = (typeof options.repeatMode === "string" && 
    typeof options.repeatMode !== 'undefined')
    ? options.repeatMode
    : "REPEAT_OFF";
    
  data.media = media;

  this.request(data, function(err, response) {
    if(err) return callback(err);
    if(response.type === 'LOAD_FAILED') {
      return callback(new Error('Load failed'));
    }
    if(response.type === 'LOAD_CANCELLED') {
      return callback(new Error('Load cancelled'));
    }
    var status = response.status[0];
    callback(null, status);
  });
};

function noop() {}

MediaController.prototype.sessionRequest = function(data, callback) {
  data.mediaSessionId = this.currentSession.mediaSessionId;
  callback = callback || noop;

  this.request(data, function(err, response) {
    if(err) return callback(err);
    var status = response.status[0];
    callback(null, status);
  });
};

MediaController.prototype.play = function(callback) {
  this.sessionRequest({ type: 'PLAY' }, callback);
};

MediaController.prototype.pause = function(callback) {
  this.sessionRequest({ type: 'PAUSE' }, callback);
};

MediaController.prototype.stop = function(callback) {
  this.sessionRequest({ type: 'STOP' }, callback);
};

MediaController.prototype.seek = function(currentTime, callback) {  
  var data = {
    type: 'SEEK',
    currentTime: currentTime
  };

  this.sessionRequest(data, callback);
};

//Load a queue of items to play (playlist)
//See https://developers.google.com/cast/docs/reference/chrome/chrome.cast.media.QueueLoadRequest
MediaController.prototype.queueLoad = function(items, options, callback) {

  if(typeof options === 'function' || typeof options === 'undefined') {
    callback = options;
    options = {};
  }

  var data = { type: 'QUEUE_LOAD' };

  //REPEAT_OFF, REPEAT_ALL, REPEAT_SINGLE, REPEAT_ALL_AND_SHUFFLE
  data.repeatMode = (typeof options.repeatMode === "string" && 
    typeof options.repeatMode !== 'undefined')
    ? options.repeatMode
    : "REPEAT_OFF";

  data.currentTime = (typeof options.currentTime !== 'undefined')
    ? options.currentTime
    : 0;

  data.startIndex = (typeof options.startIndex !== 'undefined')
    ? options.startIndex
    : 0;

  data.items = items;

  this.request(data, function(err, response) {
    if(err) return callback(err);
    if(response.type === 'LOAD_FAILED') {
      return callback(new Error('queueLoad failed'));
    }
    if(response.type === 'LOAD_CANCELLED') {
      return callback(new Error('queueLoad cancelled'));
    }
    var status = response.status[0];
    callback(null, status);
  });
};

MediaController.prototype.queueInsert = function(items, options, callback) {
  if(typeof options === 'function' || typeof options === 'undefined') {
    callback = options;
    options = {};
  }

  var data = { 
    type:             'QUEUE_INSERT',
    currentItemId:    options.currentItemId,    //Item ID to play after this request or keep same item if undefined
    currentItemIndex: options.currentItemIndex, //Item Index to play after this request or keep same item if undefined
    currentTime:      options.currentTime,      //Seek in seconds for current stream
    insertBefore:     options.insertBefore,     //ID or append if undefined
    items:            items
  };

  this.sessionRequest(data, callback);
};

MediaController.prototype.queueRemove = function(itemIds, options, callback) {
  if(typeof options === 'function' || typeof options === 'undefined') {
    callback = options;
    options = {};
  }

  var data = {
    type:             'QUEUE_REMOVE',
    currentItemId:    options.currentItemId,
    currentTime:      options.currentTime,
    itemIds:          itemIds
  };

  this.sessionRequest(data, callback);
};

MediaController.prototype.queueReorder = function(itemIds, options, callback) {
  if(typeof options === 'function' || typeof options === 'undefined') {
    callback = options;
    options = {};
  }

  var data = {
    type:             'QUEUE_REORDER',
    currentItemId:    options.currentItemId,
    currentTime:      options.currentTime,
    insertBefore:     options.insertBefore,
    itemIds:          itemIds
  };

  this.sessionRequest(data, callback);
};

MediaController.prototype.queueUpdate = function(items, options, callback) {
  if(typeof options === 'function' || typeof options === 'undefined') {
    callback = options;
    options = {};
  }

  var data = {
    type:             'QUEUE_UPDATE',
    currentItemId:    options.currentItemId,
    currentTime:      options.currentTime,
    jump:             options.jump,          //Skip or go back (if negative) number of items
    repeatMode:       options.repeatMode,
    items:            items
  };

  this.sessionRequest(data, callback);
};

module.exports = MediaController;

Также имеется задача интеграции majordomo и google assistant в идеях Разработки ядра системы MajorDoMo и звучит "Добавить поддержку Google Home без использования стороннего кода", пока набрала только 5 голосов https://connect.smartliving.ru/tasks/1.html

Просьба проголосовать за необходимый функционал.


А самое интересное, что из media.js можно сделать вывод, что протоколом castv2 предусмотрена команда добавления в очередь вопроизведения, очиста очереди!!! Также есть управление громкостью и т.д.

В общем пора создавать свой клас для управления на php.

Из того, что важно:
contentType: 'audio/mp3',
streamType: 'BUFFERED' // or LIVE


player.load(media, { autoplay: true }, function(err, status) {
Если вам помогло данное сообщение, не поленитесь нажать кнопку "спасибо".
CONNECT | Оборудование | Блог | Дополнения | Email | Telegram
directman66
Сообщения: 2801
Зарегистрирован: Пн дек 26, 2016 9:51 am
Откуда: Екатеринбург
Благодарил (а): 380 раз
Поблагодарили: 693 раза
Контактная информация:

Re: Google Home в качестве терминала

Сообщение directman66 » Чт июн 21, 2018 8:09 pm

Друзья! Google Home теперь может выступать в качестве терминала без установки доп. софта.

В терминале выбираем Chromcast/google TV, вводим ip адрес и все!!! Колонка будет штатно производить требуемый контент.

Единственный момент, пока не реализована подписка на команду say, поэтому временно осталвяем beforesay:

Код: Выделить всё

$url='http://192.168.1.39/cms/cached/voice/'.basename($filename); if((basename($filename)<>"dingdong.mp3")and (gg("NightMode.active")<>"1")) {playMedia($url,'MAIN');  sg('test.play',$url); }
____

upd: Ну или я погорячился. Один раз сработало и теперь молчит. Разбираюсь.
Последний раз редактировалось directman66 Чт июн 21, 2018 9:01 pm, всего редактировалось 2 раза.
Если вам помогло данное сообщение, не поленитесь нажать кнопку "спасибо".
CONNECT | Оборудование | Блог | Дополнения | Email | Telegram
Ответить