개발 커뮤니티를 돌아다니던 중 흥미로운 것을 발견하여 기록해 놓습니다. 이름하여 FlexJS! 이름이 모든것을 말해주는 듯 합니다. node.js나 angular.js 등등 수많은 쩜제이에스(.js) 프레임워크들 처럼 "flexjs는 javascript와 flex에 관련된 그 무언가가 아닐까?" 라는 생각이 드는군요. FlexJS개발자리더 Alex씨가 설명하기를 MXML/AS3 작업물을 Flash나 AIR플랫폼이 아닌 순수 브라우저에서 Flash없이 돌린다는 것입니다. 아래 Workflow를 보시면 ActionScript코드를 JavaScript로 바꿔준다는 걸 알수 있습니다.
2014년 초부터 시작한 프로젝트인듯 하고, 현재(2014년11월) 버전 0.0.2가 나와있습니다. 홈페이지에 보면a next-generation Flex SDK 이 문구가 가장 가슴에 팍 꽂히네요. 하지만 퍼포먼스가 얼마나 나와주고, 지원속성들을 얼마나 잘 받쳐줄지 걱정부터 앞서네요. ㅠㅠ
Wowza Streaming Engine uses named stream types to control the different types of streaming (live, VOD, chat, remote recording, and so on.). Stream types are automatically configured when you create different application types and configure their options in Wowza Streaming Engine Manager. You can also edit the Streams/StreamType property in Application.xml using a text editor to change the stream type for an application. The following table shows the stream types and their uses.
Stream type
Description
default
VOD
file
VOD
live
Publish and play live content (best for one-to-many streaming of live events)
live-lowlatency
Publish and play live content (best for one-to-one or one-to-few video/audio chat applications)
live-record
Same as live - in addition content is recorded
live-record-lowlatency
Same as live-lowlatency - in addition content is recorded
liverepeater-edge
Publish and play live content across multiple Wowza servers in an origin/edge configuration (used to configure edge application)
liverepeater-edge-lowlatency
Publish and play live content across multiple Wowza servers in an origin/edge configuration (used to configure edge application when latency is important)
liverepeater-edge-origin
Publish and play live content across multiple Wowza servers in an origin/edge/edge configuration (used to configure a middle-edge application)
record
Video recoring
rtp-live
Re-stream RTSP/RTP, native RTP, or MPEG-TS streams
rtp-live-lowlatency
Re-stream RTSP/RTP, native RTP, or MPEG-TS streams when latency is important
rtp-live-record
Same as rtp-live - in addition content is recorded
rtp-live-record-lowlatency
Same as rtp-live-lowlatency - in addition content is recorded
shuotcast
Re-stream SHOUTcast/Icecast MP3 or AAC+ audio streams
shoutcast-record
Same as shoutcast - in addition content is recorded
Each stream type exposes properties that are used for tuning the stream type. For example, the stream type definitionsfor live and live-lowlatency differ only in the tuning that's accomplished through the stream properties. Defined properties for a stream type can be overridden on a per-application basis by defining new property values on an application's Propertiestab in the Streaming Engine manager or by editing the Streams/Properties container in Application.xml.
This is the simplest webcam recording application to Wowza with Flex. Almost source code is from the example based on Flash provided by Wowza.([install-dir]/examples/WebcamRecording/FlashRTMPPlayer11)
Don't forget to configure the Application.xml and to make Application directory first. And recorded files should be located in the [install-dir]/content folder unless you have changed the Application.xml /Streams .
패턴인식(Pattern Recognition)의 한 분야인 음성인식은 오늘날(현 2014년) 많이 대중화가 되어있고, 다양한 분야에서 활용되고 있습니다. 음성인식에서 두각을 나타내고있는 여러 대기업들중 Google에서 제공하는 STT(Speech To Text)의 활용법에 대해 간단히 정리한 내용입니다. 글쓴이는 음성인식 분야에 무지하며, 이를 참조해서 읽어주세요.
인식률은 사람의 성별, 사용된 마이크, 주변 잡음, 인식할 단어의 수, 얼마나 문법적으로 올바른 문장을 발화하는가 등 다양한 요소에 의해서 좌우됩니다. 따라서 인식 성능이 얼마나 나올 것인가를 결정하려면 이러한 조건들이 명확하게 알아야하고, 그 후에야 대강의 성능을 예측하여 볼 수 있습니다.
2011년 Google이 자사 브라우저 Chrome 버전11.0.696.16 Beta 버전부터 HTML5 Speech Input API Specification를 지원하였습니다. 이는 다른 미들웨어(Flash, ActiveX)의 도움없이 브라우저에서 마이크로부터의 input을 캡쳐해 낼수 있게됩니다. x-webkit-speech라는 이름으로 input태그에 아래와같이 x-webkit-speech속성만 추가하시면, 음성인식 샘플테스트를 해보실 수 있습니다. 아래 마이크를 클릭하시고 말해보세요~(크롬에서만 동작)
테그의 속성하나만을 추가해도 음성인식이 되는 매력적인 기능이지만 슬프게도 2014년 4월 현재, 다른 브라우저의 지원이 부족하고, 태그의 속성으로만 사용할 수 있기에 확정성이 용이하지 못하였습니다. 이러한 이유로x-webkit-speech의 사용은 점점 사라져 가는 추세입니다. 대신 자바스크립트API인 Web Speech API가 등장하게 됩니다.
② New Approach : Web Speech API
2013년 Chrome 버전25 부터 Web Speech API Specification를 지원하게 됩니다. 음성을 텍스트포멧으로 변환(Speech To Text, 이하 STT)이 순수 웹브라우저만으로 가능해 졌습니다.
google.co.kr 이 아닌 google.com으로 접속하시면 다음과 같이 'OK Google'이라고 말하세요. 라는 문구를 검색어 창에서 확인하실 수 있습니다. Apple의 Siri와 같이, Chrome브라우저에서 음성명령만으로 검색이 가능해졌습니다. 단, 아직 베타버전이어서 한국어 지원을 하지 않습니다.
2. 어떻게 동작하는가
Google Speech API는 크게 두가지 형태로 디자인 되었습니다.
첫째, 크롬브라우저에 음성엔진이 built-in
둘째, 구글서버로 음성Data를 보내고 feedback받는 형태
두개지 방법에는 장단점이 있습니다. 크롬브라우저 자체 내에 음성인식엔진이 내장되어 있는경우 서버를 거치지 않기때문에 속도가 빠름니다. 서버를 거치게 될 경우, 내장엔진에 저장되어있는 data보다 훨씬 방대한 data가 저장되어 있기때문에, 내장음성엔진에 비해 정확도가 더 높다고합니다.
Chromium-dev에 가입하셨다면 Google Developers Console로 가보면 Speech API가 보일것입니다. STATUS를 ON으로 바꿔주세요. 하루 50번의 요청제한이 있습니다. 단, 요청횟수를 더 늘릴 수도 있습니다.
③ key만들기
④ Google서버로 요청
Google Speech API를 이용하시려면, HTTP POST 요청을 합니다. Google Speech API v2버전에서는 다음의 두가지 data형식을 인식할 수 있습니다. 클라이언트가 어떤 언어로 되어있든, Google서버에 요청시 아래의 형태를 맞추셔야합니다.
Data 인코딩 정보
1. FLAC
Flac file; 44100Hz 32bit float, exported with Audacity. Check the audio folder in this repository for some hilarious examples.
Channels : 2
Sample Rate : 44100
Precision : 32-bit
Sample Encoding: 32-bit Float
2. 16-bit PCM
The following audio options are confirmed working for 16-bit PCM sample encoding:
Channels : 1
Sample Rate : 16000
Precision : 16-bit
Sample Encoding: 16-bit Signed Integer PCM
요청 Header정보
1. Flac
Content-Type: audio/x-flac; rate=44100;
FLAC파일의 rate와 똑같이 맞춰주셔야 합니다. 일반적으로 44100Hz로 맞추지만, 다른 rate도 지원을 합니다.
2. 16-bit PCM
Content-Type: audio/l16; rate=16000;
16bit signed-integer로 인코딩된 파일은 44100Hz 혹은 16000Hz를 지원합니다.
※주의 :오디오 캡처할때 rate와 header의 rate는 같아야 합니다!
HOST 주소
https://www.google.com/speech-api/v2/recognize
KEY값
AIzaSyCnl6MRydhw_5fLXIdASxkLJzcJh5iX0M4
위의 키값은 위에서 언급한 Google Hotword Chrome Extension에서 쓰이는 키값으로, 소스코드에서 추출한 키값입니다. Google Developers Console에서 생성된 키값을 입력하여도 되고, Google Hotword Chrome Extension에서 추출한 키값을 입력하셔도 됩니다. 다만, 생성한 키값은 하루 50회 이용제한이 있고, Google Hotword Chrome Extension에서 추출한 키값은 이용제한이 없습니다.
2014년 5월. 위의 키값은 더이상 동작하지 않습니다. Google에서 막아놓은듯 합니다. 그리고 v1버전도 어쩌다 동작할 때도 있는듯 하고, 직접 추출된 50회 이용제한 Key값또한 50회 이상 되고 있군요. 하루중 몇번씩 되었다 안되었다 하는.... ㅠㅠ
LANG값
var langs =
[['Afrikaans', ['af-ZA']],
['Bahasa Indonesia',['id-ID']],
['Bahasa Melayu', ['ms-MY']],
['Català', ['ca-ES']],
['Čeština', ['cs-CZ']],
['Deutsch', ['de-DE']],
['English', ['en-AU', 'Australia'],
['en-CA', 'Canada'],
['en-IN', 'India'],
['en-NZ', 'New Zealand'],
['en-ZA', 'South Africa'],
['en-GB', 'United Kingdom'],
['en-US', 'United States']],
['Español', ['es-AR', 'Argentina'],
['es-BO', 'Bolivia'],
['es-CL', 'Chile'],
['es-CO', 'Colombia'],
['es-CR', 'Costa Rica'],
['es-EC', 'Ecuador'],
['es-SV', 'El Salvador'],
['es-ES', 'España'],
['es-US', 'Estados Unidos'],
['es-GT', 'Guatemala'],
['es-HN', 'Honduras'],
['es-MX', 'México'],
['es-NI', 'Nicaragua'],
['es-PA', 'Panamá'],
['es-PY', 'Paraguay'],
['es-PE', 'Perú'],
['es-PR', 'Puerto Rico'],
['es-DO', 'República Dominicana'],
['es-UY', 'Uruguay'],
['es-VE', 'Venezuela']],
['Euskara', ['eu-ES']],
['Français', ['fr-FR']],
['Galego', ['gl-ES']],
['Hrvatski', ['hr_HR']],
['IsiZulu', ['zu-ZA']],
['Íslenska', ['is-IS']],
['Italiano', ['it-IT', 'Italia'],
['it-CH', 'Svizzera']],
['Magyar', ['hu-HU']],
['Nederlands', ['nl-NL']],
['Norsk bokmål', ['nb-NO']],
['Polski', ['pl-PL']],
['Português', ['pt-BR', 'Brasil'],
['pt-PT', 'Portugal']],
['Română', ['ro-RO']],
['Slovenčina', ['sk-SK']],
['Suomi', ['fi-FI']],
['Svenska', ['sv-SE']],
['Türkçe', ['tr-TR']],
['български', ['bg-BG']],
['Pусский', ['ru-RU']],
['Српски', ['sr-RS']],
['한국어', ['ko-KR']],
['中文', ['cmn-Hans-CN', '普通话 (中国大陆)'],
['cmn-Hans-HK', '普通话 (香港)'],
['cmn-Hant-TW', '中文 (台灣)'],
['yue-Hant-HK', '粵語 (香港)']],
['日本語', ['ja-JP']],
['Lingua latīna', ['la']]];
Request 예제 (Flex로 만든 예제, Google서버로 요청하는 부분입니다.)
.
.
.
var PATH:String = "https://www.google.com/speech-api/v2/recognize?output=json&lang=ko-kr&key=AIzaSyCnl6MRydhw_5fLXIdASxkLJzcJh5iX0M4";
Google Speech API는 무료이지만 공식적인 API(Official Public API)는 아닙니다. 말인즉 공식적인 API가 아니므로, Google은 사전예고없이 API를 바꿔버리면 예상치 못한 여러 에로사항이 생길 가능성이 다분합니다. 한가지 예로2012년 Google의 일방적(?)인 Google Weather API차단으로 이를 이용해 날씨서비스를 하던 많은 기업들이, 다른 Weather API로 갈아탓더랬습니다. (stackoverflow) 또한 위에서 업급했던 것처럼, 개발과 개인에게만 사용을 허가합니다.
5. 흥미로운 음성 엔진들
① Sphinx(100% Open Source Toolkit For Speech Recognition)
CMUPhinx는 미국 펜실베이니아에 위치한 카네기멜론대학(Carnegie Mellon University)의 Sphinx그룹과 Sun Microsystems연구소, Mitsubishi Electric Research Labs (MERL), and Hewlett Packard (HP)들이 협력해서 연구개발중인 음성엔진입니다. (소스코드, Tutorial)
② MIT의 WAMI
WAMI는 MIT 연구실에서 만든 iPhone, iPod Touch 모바일 웹브라우저에서 음성인식을 하는 toolkit입니다. 이것도 역시 오픈소스입니다.
크로스 브라우징 Google STT 구현을 위해, 마이크Input을 Flex로 받아와서 처리를 해보았습니다.
7. 끝으로...(Graphic User Interface -> Voice User Interface)
후드래빗님의 의견처럼 '음성인식 기술이 새로운 인터페이스로 자리잡고 있다' 에 100% 동의합니다. 아니면 '이미 자리잡았다' 가 될 수도 있겠네요. Warable Device, 자동차, 의료, 스마트TV, 게임, 교육 등등 다양한 분야에 활용되고 있습니다. MS의 코타나, 구글의 Now, 애플의 Siri 등 공룡기업들의 '개인비서' 서비스가 강세를 보이는 가운데, 우리나라에서도 음성인식 기술에 대한 연구가 활발하게 진행중입니다. 대표적으로 2010년 네이버는 음성검색엔진을 자체 기술로 개발하기시작한 이래로, 현재는 Google음성엔진에 못지않은 음성인식률을 보이고 있습니다. '다음'은 음성 검색 서비스 강화를 위해 음성인식 전문기업 '다이알로이드'를 인수하고, 최근(2014년2월)에 '다음'은 국내최초로 국내최초로 '모바일 음성 인식 API' 를 공개하기도 하였습니다.
인공지능과 Voice User Interface의 끝을 보여주는 영화 'her'
끝으로 우리나라가 IT강국이라 하지만, 순수 '대한민국 소프트웨어 기술'이라 내세울 만한 것 하나 없는 이 현실에서, 소수의 우리나라 음성인식 기술자분들의 노고에 감사를 드립니다~
sendResult는 Flex의 Responder 클래스와 짝을 이룹니다. NetConnection클래스의 call()함수로 서버측 메소드를 호출 할 경우, 서버측에서 클라이언트로 결과를 반환 해야 하는 경우 유용합니다. 클라이언트쪽에서는 Responder클래스를 이용해 응답을 받습니다.
두번째, 미디어 서버를 통해 SO에 연결(connect)된 모든 Client들에게 Data를 공유하는 방법입니다.
1. SharedObject에 연결된 다른 클라이언트의 함수 호출해 보기
SharedObject.send()함수를 통해 SO에 연결된 모든 Client들의 함수를 호출하는 예제입니다. 서버측 코딩은 필요없고, [Install-dir]/applications/Tutorial3 폴더만 생성해 주시면 됩니다. 브라우져를 여러개 띄워두신다음 테스트 해보시면 됩니다. 이해를 위해 최소한의 코드만으로 만든 예제입니다. so=SharedObject.getRemote("soName", nc.uri,false); 의 'soName'은 SO를 구분짓는 이름이며, 이 이름에 묶여있는 SO에 연결된 클라이언트의 함수는 호출됩니다. 그리고 호출된 함수의 접근제한자는 public 이어야 합니다.
호출될 수 있는 함수를 여러개 만들어 보는 예제입니다. Object객체를 하나 만들어 주고, 그 객체의 속성에 함수를 넣어주고 SO의 client를 Object로 지정해주시면 됩니다. 이 예제또한 서버코딩이 필요없고, 예제 실행을 위해서는 [Install-dir]/applications/Tutorial4 폴더를 생성해 주어야 합니다.
SharedObject를 이용해서 서버측에서 시간을 구한 후, SharedObject에 연결된 모든 클라이언트들에게 현재 시간을 알려주는 예제입니다. 서버사이드에서의 SO객체생성이 필요하며, setProperty() 함수를 이용해서 Data를 동기화 합니다. SO객체에 SyncEvent를 리스닝 하고있다, 동기화가 일어나면 SyncEvent가 송출되어 서버의 시간을 뿌려줍니다. 예제실행을 위해 서버측 모듈설정이 필요합니다.