[Из песочницы] Голосовое управление мультимедиа центром
В этой статье хотелось бы описать свой опыт по применению web speech api в браузере Google Chrome для реализации голосового поиска и автоматического воспроизведения видеороликов с канала Youtube. Для демонстрации данного функционала нам понадобиться сделать следующие шаги:
- Установить набор: Apache2, PHP5(пакет curl обязательно).
- Иметь в наличии мультимедиа центр Dune HD или установить XBMC и настроить его для работы в сети INTERNET.
- Получить Youtube API Key для выполнения поисковых запросов.
Как сделать все вышеперечисленное, здесь описывать не буду, так как на эти темы полно статей. Принцип реализации такой:
- Распознаем фразу с помощью скрипта, написанного на JavaScript — работать будет только в Google Chrome.
- Ищем ролики, соответствующие поисковому запросу.
- Получаем прямые ссылки на ролики.
- Создаем плейлист из ссылок и названий роликов.
- Отправляем плейлист для воспроизведения на устройство.
Топология сети: Internet приходит в wan порт Wi-Fi роутера, а к нему подключаются:
- устройство, с которого будем управлять (планшет, смартфон, ноутбук).
- компьютер с web сервером Apache (если управление будет производится с него, то первое устройство может отсутствовать).
- собственно сам мультимедиа центр (программный — XBMC, или аппаратный — Dune HD).
Умный Дом
<script language="javascript" type="text/javascript">
/* Создание нового объекта XMLHttpRequest для общения с Web-сервером */
var xmlHttp = false;
/*@cc_on @*/
/*@if (@_jscript_version >= 5)
try {
xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e2) {
xmlHttp = false;
}
}
@end @*/
if (!xmlHttp && typeof XMLHttpRequest != 'undefined') {
xmlHttp = new XMLHttpRequest();
}
</script>
Кликни на микрофон чтобы начать раздавать команды.
Командуй!
Голос не обнаружен.
Микрофон не найден.
Твой браузер не поддерживает Web Speech API.
<script>
var start_button = document.getElementById('start_button'),
recognizing = false, // флаг идет ли распознование
final_transcript = '';
// проверяем поддержку speach api
if (!('webkitSpeechRecognition' in window)) {
start_button.style.display = "none";
showInfo("info_upgrade");
} else { /* инициализируем api */
/* создаем объект */
var recognition = new webkitSpeechRecognition();
/* базовые настройки объекта */
recognition.lang = 'ru'; // язык, который будет распозноваться. Значение - lang code
recognition.continuous = true; // не хотим чтобы когда пользователь прикратил говорить, распознование закончилось
/* метод вызывается когда начинается распознование */
recognition.onstart = function() {
recognizing = true;
showInfo('info_speak_now'); // меняем инфо текст
start_button.style.background = 'url(images/mic-animate.gif)'; // меняем вид кнопки
};
/* обработчик ошибок */
recognition.onerror = function(event) {
if (event.error == 'no-speech') {
start_button.style.background = 'url(images/mic.gif)';
showInfo('info_no_speech');
}
if (event.error == 'audio-capture') {
start_button.style.background = 'url(images/mic.gif)';
showInfo('info_no_microphone');
}
};
/* метод вызывается когда распознование закончено */
recognition.onend = function() {
recognizing = false;
recognition.start();
start_button.style.background = 'url(images/mic.gif)';
showInfo('info_start');
};
/*
метод вызывается после каждой сказанной фразы. Параметра event используем атрибуты:
- resultIndex - нижний индекс в результирующем массиве
- results - массив всех результатов в текущей сессии
*/
recognition.onresult = function(event) {
/*
обход результирующего массива
*/
for (var i = event.resultIndex; i < event.results.length; ++i) {
/* если фраза финальная (уже откорректированная) сохраняем в конечный результат */
if (event.results[i].isFinal) {
final_transcript += event.results[i][0].transcript.toLowerCase();
}
}
final_span.innerHTML = final_transcript;
var newText2 = final_transcript.replace(/(^\s+|\s+$)/g,'');
var url = "/voice_search.php?q=" + encodeURI(newText2);
xmlHttp.open("GET", url, true);
xmlHttp.send(null);
final_transcript = ''; // очищаем рапознанный текст
};
}
/* показ нужного сообщения */
function showInfo(id) {
var messages = document.querySelectorAll('p');
for(i=0; i
Для полноценной работы скрипта, нужно еще создать папку images и положить в неё картинки с микрофончиками, которые можно взять здесь и здесь.
Данный скрипт делает всего два действия — распознает фразу и отправляет её AJAX запросом PHP скрипту. Также необходимо обратить внимание на то, что кодировка во всех скриптах должна быть UTF-8 (если делаете в Windows, то UTF-8 без ВОМ).
video: $id; no mp4-stream.");
return false;
}
}
if(isset($_GET['q']) == false or $_GET['q']=="" )
{
$url = "https://www.googleapis.com/youtube/v3/search?part=snippet&q=голосовое%20управление%20телевизором&type=video&maxResults=10&key=Youtube_API_key";
}
else
{
$url = "https://www.googleapis.com/youtube/v3/search?part=snippet&q=".urlencode($_GET['q'])."&type=video&maxResults=10&key=Youtube_API_key";
}
$res = json_decode(send_req($url));
if(isset($res->items) == false or ($res->items)=="" )
{
$info="похоже что-то пошло не так!";
send_info($info);
}
else
{
$res = $res->items;
//print_r($res);
$fp = fopen('play_list.m3u', 'w+t');
$start="#EXTM3U\r\n";
fwrite($fp, $start);
foreach ($res as $searchResult)
{
$title=($searchResult->snippet->title);
$videoId = ($searchResult->id->videoId) ;
$clip_url = get_video_url($videoId);
if(isset($clip_url) == false or $clip_url=="")
{
$info="клип не найден!";
send_info($info);
}
else
{
$clip="#EXTINF:-1,$title\r\n$clip_url\r\n";
fwrite($fp, $clip);
}
}
fclose($fp);
$info="плейлист создан";
send_info($info);
//url для Dune HD
$url="http://ip_addr_dune/cgi-bin/do?cmd=start_file_playback&media_url=http://server_ip/play_list.m3u";
//url для XBMC
$url="http://логин:пароль@ip-адрес:8080/jsonrpc?request={"jsonrpc":"2.0","id":"1","method":"Player.Open","params":{"item":{"file":"http://server_ip/play_list.m3u"}}}";
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER,true);
$out = curl_exec($curl);
curl_close($curl);
}
?>
В данном скрипте в самом конце нужно будет отредактировать $url под настройки вашего мультимедиа центра и удалить лишний, а также исправить текст server_ip на ip адрес вашего Apache сервера и вставить свой Youtube_API_Key. Что происходит здесь: из скрипта распознавания речи сюда приходит текст распознанной фразы, далее с помощью Youtube API v3 производится поиск видео роликов подходящих под поисковой запрос, получив ссылки на ролики, мы пропускаем их через цикл, в котором извлекаются полные пути до видеофайлов, которые и записываются в плейлист play_list.m3u. Данный скрипт не претендует на идеальный код, так как написан чисто в ознакомительных целях, поэтому всевозможные проверки здесь отсутствуют.
Вот и всё, теперь заходим на наш web сервер по его ip адресу. Можно заходить с любого устройства: планшет, смартфон, ноутбук, единственное, что я заметил — в последнее время на смартфонах с Android, скрипт распознавания речи при отсутствии её, отправляет фразу повторно, с чем это связанно пока не понятно, но раньше такого не было.
На основе данного материала можно сделать еще много интересных вещей, таких как голосовой поиск музыки в VK и управления 1-wire устройствами. В общем пробуйте, если что не получится, то спрашивайте с удовольствием отвечу на все ваши вопросы.
P.S.: Статья написана по материалам:
W3C Web Speech API
YouTube api v3
Скрипт получения прямых ссылок взят из приложения YouTube для Dune HD и немного доработан под свои нужды. Для тех, кто хочет просто попробовать управлять мультимедиа центрами, без написания скриптов — можно почитать здесь. Результат моей работы на YouTube
