Введение
Однажды я смотрел какой-то старый фильм. Герой воспользовался телефоном: снял трубку, попросил оператора набрать номер друга и стал беседовать. Мне очень понравилась простота, с которой был сделан звонок, и внешний вид телефона. Я решил собрать такой телефон сам. Поднимаешь трубку, говоришь, кому позвонить, голос распознаётся, имя отыскивается в адресной книжке, и совершается VoIP звонок.В этом посте я расскажу про детали проекта: про устройство на базе Android, про IOIO Board, про вырезание по дереву и по пластику.
Результат
Чтобы лучше понять почему я принял те или иные решения, стоит сперва посмотреть на результат работы:Процесс создания
Компоненты
После небольшого исследования, я решил использовать следующие компоненты:
Старый телефон как корпус устройства. Меня очень привлекла эстетика старого телефона. Я нашел довольно дешевый телефон и корпус со звоноком на eBay.
Archos 28 как «мозг» устройства. Меня привлекла небольшая цена и наличие основных компонентов: внутренняя память, Wi-Fi, микрофон и звуковой выход и 800Mhz процессора.
Читатель спросит: почему бы не решить задачу микроконтроллером и набором модулей? Мне показалось дешевле и проще использовать этот телефон: всё, что надо уже собрано на одной плате, плюс ОС Android предоставляет неплохой уровень абстракции. Устройство должно работать круглые сутки, так что проблем с энергопотреблением не возникает.
IOIO Board для взаимодействия с «железом». Эта штука подключается к устройству по USB и распознаётся телефоном как «включен режим дебага». Есть небольшое API, которое позволяет из любой Android программы читать состояние линии (как цифровой, так и аналоговой), и генерировать на линии сигнал (цифровой и PWM).
Читатель спросит: почему бы не использовать Android ADK? Увы, поддержка ADK была добавлена лишь в Android 2.3. Мой телефон работает на 2.2.
Железо, дерево и пластик
Сперва, я разобрал телефонный аппарат и очистил его от древней грязи. Устройство было выпущено в конце 1910-х, так что грязи там было достаточно. Я использовал тёплый мыльный раствор воды для дерева и WD-40 для металла. Вот составные части:
Вторым шагом была подготовка Archos 28. Хотя этот аппарат и не предназначен для паяльника любителя, вывести линии для кнопки питания, микрофона, наушников и Wi-Fi антенны оказалось не очень сложно. Держатель трубки старинного аппарата содержал нехитрый механизм, замыкающий линию на землю, если трубка снята. Немного возни, и вот результат:
Аппарат Archos 28, увы, не очень влезал в старинную коробку. Пришлось использовать Dremel, чтобы вырезать небольшой желоб для телефона, сделать дырки для проводов и прикрутить крышку на петли:
В какой-то момент я обнаружил, что мой рабочий стол напоминал стол Путешественника во Времени, только что вернувшегося в свой XIX век из нашего XXI-ого:
Мне очень хотелось сохранить оригинальный звонок. Устройство звонка не позволяло практически никакой модификации: старинные электромагниты и конденсатор занимали почти всё место в корпусе. Поэтому я решил сделать свой механизм звонка. Металлический шарик, который ударяет по звонку, был закреплён на подвижной платформе. Платформа качалась туда-сюда от движения маленького электромотора на оси которого был приделан небольшой эллипс. Наверное, это нагляднее на схеме:
Я использовал Inkscape для создания чертежа. Надо сказать, что пользоваться Inkscape мне показалось сущей мукой. Надеюсь, что где-то есть не очень дорогие аналоги.
Когда чертёж был готов, я использовал службу Ponoko, чтобы вырезать детали из пластика. Пара недель, и детали приходят:
Немного клея и эти компоненты навсегда превратятся в механизм звонка:
Сборка микросхемы
Схема оказалось крайне простая: телефон был соединён USB кабелем с IOIO Board. Сама плата была соединена напрямую с контактом стойки телефона (чтобы знать повешена ли трубка) и через TS1220-600T – с моторчиком (чтобы звонить). Вот как это выглядело в сборке:
Можно представить, как это помещалось в корпус:
Надо отметить, что когда эта конструкция помещалась в копрус, качество Wi-Fi соединения сильно падало. Поэтому мне пришлось купить и припаять внешнюю Wi-Fi антенну. На Archos 28 очень хорошо обозначен UF.L порт. Вот как система выглядела в корпусе:
Вот как вывелись провода:
Программное обеспечение
Основные компоненты
CMU Sphinx – это открытый проект университета Карнеги–Мелон. Система состоит из двух частей: код и файлы с произношением и моделью языка. Код компилируется в библиотеку для андроида. На сайте проекта есть отличный пример использования распознавателя голоса.У всех своё произношение. К счастью, CMU Sphinx можно научить именно своему. Прочитав 20 предложений и прогнав их через определённую программу можно существенно улучшить качество распознания. Более того, можно предложить распознавателю модель языка. Это что-то вроде контракта, где ты обещаешь говорить лишь определённые слова и фразы. В моём случае основной фразой была «call [name]», где [name] это один из элементов данного списка. Наличие такой модели существенно улучшает качество распознания.
Читатель спросит: почему не Google Voice? Он, увы чрезвычайно плохо понимает моё произношение и ужасно распознаёт имена.
Читатель спросит: почему не использовать специальный чип? Я долго размышлял над этим подходом, смотрел на решения Sensory, но уж больно дорого вышло. То есть проблем не меньше, чем с CMU Sphinx, качество сравнимое, а деньги платить надо.
"Нет генератору голоса" – к этому выводу я пришел попробовав несколько разных продуктов. Во всех, увы, голос получался уж очень ненатуральный. Мёртвый какой-то. Пришлось попросить живого человека прочитать все возможные фразы, которые может сказать мне телефон. Более того, я попросил прочитать каждую фразу несколько раз. Программа случайно выбирает вариант фразы, создавая, таким образом очень сильную иллюзию живого человека.
PJSIP – это открытая реализация SIP-стека. Грубо говоря открытая библиотека VoIP. Тут всё просто: берёшь, компилируешь и используешь. Мне очень помог проект CSipSimple разобраться в API библиотеки и правильно встроить в своё приложение.
Читатель спросит: почему не использовать Skype? Я так сначала и хотел. И даже подписался на Skype Developer Program. Но, увы, лицензионное соглашение Skype Developer Program не позволяет запускать их продукт на любом устройстве, управляемым ОС Android. Когда я это узнал, да и когда писал этот пост, я громко ругался довольно неприличными словами.
Читатель спросит: почему не использовать стек встроенный в Android? Ответ прост: поддержка SIP была добавлена только в Android 2.3. Моё устройство работает на 2.2.
Алгоритм работы
Когда снята трубка:- Подождать секунду
- Сказать «Number, please!»
- Начать распознавать голос
- Если распознана фраза «call [name]», идти дальше, иначе сказать «Sorry, I didn't get that» и перейти к 3
- Сказать «Calling [name]...»
- Начать распознавать голос
- Если распознана фраза «no» или «stop» перейти к 2, иначе идти дальше
- Набрать номер
- Сказать «Call placed»
- Ждать, пока звонок не завершиться
- Сказать «Call terminated»
При входящем вызове звенеть пока либо не снимут трубку, либо не закончат звонок на том конце, либо не пройдёт 20 секунд. Звенеть по схеме: звонок – перерыв – звонок.
Формат приложения
Наиболее естественным мне показалось сделать службу, которая исполняет всю логику, и обычное приложение, которое лишь показывает текущий статус. Служба стартует либо со стартом устройства, либо со стартом приложения. Исходный код можно найти в проекте на Google Code.
Заключение
Телефон неплохо распознаёт мой голос, звонит и даже принимает вызовы. Я буду рад ответить на любые вопросы, выслушать критику и предложения.