AudioRecorder 소개
AudioRecorder는 마이크를 통해 입력된 소리 신호를 오디오 데이터로 녹음하는데 필요한 기능을 제공하는 오브젝트입니다. 오디오 데이터는 wav, ogg, mp3, AMR_NB, AMR_WB 형식의 파일로 저장할 수 있는데 사용자가 별도로 형식을 설정하지 않으면 안드로이드 환경에서는 mp3, iOS에서는 wav로 자동 설정됩니다.
오디오 녹음하기
AudioRecorder 오브젝트의 기능을 사용해 간단한 녹음기를 구현합니다. 기본적인 오디오 녹음의 절차는 크게 오디오 포맷 설정과 녹음의 두 단계로 나눌 수 있습니다.
오디오 파일의 포맷 설정은 audioformat, samplerate, channelconfig 속성을 사용합니다. 필요에 따라 원하는 속성값을 입력합니다. 속성을 설정하지 않으면 안드로이드의 경우는 mp3, 8000 Hz, mono로 설정되고, iOS의 경우는 wav, 8000 Hz, mono로 설정됩니다.
설정은 audioformat, channelconfig, samplerate 속성을 사용하고 녹음은 recordingStart, recordingStop, pause, resume 메소드를 사용합니다. 기능 구현시 필요에 따라 속성 및 메소드를 적절히 조합해서 사용할 수 있습니다.
예제
다음은 녹음, 일시 중지, 멈춤 기능을 구현한 녹음기 예제입니다.
Record 버튼을 터치하면 녹음이 시작되고 Stop 버튼을 터치하면 녹음이 종료됩니다. 녹음을 종료하면 오디오 파일이 생성되고 하단에 파일 목록이 표시됩니다. 녹음 중 Pause 버튼을 터치하면 녹음이 일시 정지되며 Resume 버튼을 터치하면 녹음이 다시 시작됩니다.
Pause / Resume 기능은 iOS 환경에서만 지원되므로 안드로이드 환경에서는 사용할 수 없습니다.
오디오 파일 이름을 두 번 터치하면 파일은 삭제됩니다. Form을 종료시키면 저장된 오디오 파일이 모두 삭제됩니다.
예제에서 사용한 핵심 기능
- AudioRecorder > audiofile 속성
오디오 데이터를 저장할 파일명을 설정하는 속성입니다. 인수로 경로와 함께 파일명을 입력합니다.
OS | Alias 경로 | 실제 경로 |
---|---|---|
Android | %USERAPP% | /data/data/{PackageName}/files/NEXACRO/ |
%SD_CARD% | /mnt/sdcard (Android v4.0 이하) /storage/emulated/0 (Android v4.1 이상) | |
%INSTALLROOT% | %USERAPP% | |
iOS | %USERAPP% | /Library/Caches/nexacro/ |
%SD_CARD% | 미지원 | |
%INSTALLROOT% | %USERAPP% |
- AudioRecorder > recordingStart 메소드
오디오 데이터의 녹음을 시작하는 메소드입니다.
- AudioRecorder > recordingStop 메소드
오디오 데이터의 녹음을 중지하는 메소드입니다.
- AudioRecorder > pause 메소드
오디오 데이터의 녹음을 일시 중지하는 메소드입니다. iOS 넥사크로 브라우저 환경에서만 지원되는 기능입니다.
- AudioRecorder > resume 메소드
일시 중지된 오디오 데이터의 녹음을 다시 시작하는 메소드입니다. iOS 넥사크로 브라우저 환경에서만 지원되는 기능입니다.
- AudioRecorder > onrecording 이벤트
오디오 데이터를 녹음중일 때 발생하는 이벤트입니다.
- AudioRecorder > onstop 이벤트
오디오 데이터의 녹음이 종료되었을 때 발생하는 이벤트입니다.
- AudioRecorder > onerror 이벤트
오디오 데이터의 녹음이 실패했을 때 발생하는 이벤트입니다.
예제 구현 방법
1
화면 구성하기
AudioRecorder 오브젝트를 추가합니다. 추가된 오브젝트는 Invisible Object 창에서 확인할 수 있습니다.
현재 녹음중인 파일 정보와 녹음 진행 시간을 표시할 Static 컴포넌트, 녹음/일시 중지/멈춤 기능을 수행할 Button 컴포넌트 저장한 녹음 파일과 리스트를 관리할 Grid 컴포넌트와 Dataset, VirtualFile 오브젝트를 예제의 그림과 같이 적절히 배치합니다.
화면 구성을 위해 사용한 컴포넌트 및 오브젝트는 다음과 같습니다.
컴포넌트/오브젝트 | ID |
---|---|
AudioRecorder | AudioRecorder00 |
Static | stt_filepath_title |
stt_filepath | |
stt_time | |
Button | btn_record |
btn_pause | |
btn_stop | |
Grid | grd_filelist |
Dataset | ds_filelist |
VirtualFile | VirtualFile00 |
GroupBox | GroupBox00 |
2
전역 변수 선언하기
녹음기의 상태 정보를 관리하기 위해 enum 타입의 변수, 타이머 정보를 관리할 변수 그리고 파일 경로 및 이름을 관리할 변수를 전역으로 선언합니다.
eStatus = { RECORD: 0, STOP: 1, PAUSE: 2, }; var eRecordStatus = eStatus; var tMin=0, tSec=0, tMSec=0; var keepgoing=false; var DIRECTORY = "%USERAPP%File/"; var FILE_NAME = "Rec"; var FILE_COUNT = 0; var strOS = nexacro.System.osversion; if(!strOS.toLowerCase().search(/android/)) { strOS = "ANDROID"; } else if(!strOS.toLowerCase().search(/ios/)) { strOS = "IOS"; }
3
사용자 함수 작성하기
녹음이 진행된 시간을 사용자가 보기 편하도록 분, 초, 밀리 초로 변환하여 Static 컴포넌트에 표시해주는 timer 메소드를 다음과 같이 작성합니다. timer 메소드는 ontimer 이벤트를 통해 주기적으로 호출됩니다.
this.timer = function(keepgoing) { if(keepgoing) { tMSec += 1; if (tMSec == 100) { tMSec = 0; tSec += 1; } if (tSec == 60) { tSec = 0; tMin += 1; } strSec = ""+ tSec; strMin = ""+ tMin; strMSec = ""+ tMSec; if (strSec.length != 2) { strSec = "0"+ tSec; } if (strMin.length != 2) { strMin = "0"+ tMin; } if (strMSec.length != 2) { strMSec = "0"+ tMSec; } this.stt_time.set_text(strMin +":"+ strSec +":"+ strMSec); } }
시간 관련 변수 및 타이머를 초기화시키는 initVar 메소드를 다음과 같이 작성합니다.
this.initVar = function() { tMin=0; tSec=0; tMSec=0; keepgoing=false; this.stt_time.set_text("00:00:00"); this.killTimer(0); }
녹음기 상태에 따라 Button 컴포넌트의 상태를 변경해주는 changeStatus 메소드를 다음과 같이 작성합니다.
this.changeStatus = function(status) { switch(status) { case eStatus.RECORD: eRecordStatus = eStatus.RECORD; if (strOS == "IOS") { this.btn_record.set_visible(false); this.btn_pause.set_visible(true); } else { this.btn_record.set_enable(false); } this.btn_stop.set_enable(true); break; case eStatus.PAUSE: eRecordStatus = eStatus.PAUSE; this.btn_record.set_visible(false); this.btn_pause.set_visible(true); this.btn_stop.set_enable(true); break; case eStatus.STOP: eRecordStatus = eStatus.STOP; if (strOS == "IOS") { this.btn_record.set_visible(true); this.btn_pause.set_visible(false); } else { this.btn_record.set_enable(true); } this.btn_stop.set_enable(false); break; } }
4
Form 이벤트 함수 작성하기
Form의 onload 이벤트 함수를 다음과 같이 작성합니다. 이전에 녹음된 오디오 파일이 있으면 그 목록을 Grid에 출력합니다.
this.example_audiorecorder_01_onload = function(obj:nexacro.Form,e:nexacro.LoadEventInfo) { this.VirtualFile00.getFileList(DIRECTORY, ".mp3", VirtualFile.findFileOnly); };
Form의 ontimer 이벤트 함수를 다음과 같이 작성합니다. 이벤트가 발생할 때마다 timer 메소드를 호출하여 진행 시간을 갱신합니다.
this.example_audiorecorder_01_ontimer = function(obj:nexacro.Form,e:nexacro.TimerEventInfo) { if(e.timerid == 0) { this.timer(true); } };
Form의 onbeforeclose 이벤트 함수를 다음과 같이 작성합니다. Form이 종료될 때 생성된 오디오 파일을 삭제합니다.
this.example_audiorecorder_01_onbeforeclose = function(obj:nexacro.Form,e:nexacro.CloseEventInfo) { for(var i=0; i<FILE_COUNT; i++) { this.VirtualFile00.remove(DIRECTORY + FILE_NAME + i +".mp3"); } this.VirtualFile00.getFileList(DIRECTORY, ".mp3", VirtualFile.findFileOnly); };
5
AudioRecorder 오브젝트 이벤트 함수 작성하기
오디오 데이터의 녹음이 종료되었을 때 발생하는 onstop 이벤트 함수를 다음과 같이 작성합니다.
this.AudioRecorder00_onstop = function(obj:nexacro.AudioRecorder,e:nexacro.AudioEventInfo) { this.initVar(); switch(e.reason) { case 4: //End of record case 5: //STOP var strFileName = FILE_NAME + FILE_COUNT + ".mp3"; var row = this.ds_filelist.addRow(); var ret = this.ds_filelist.setColumn(row, "FileName", strFileName); trace("ret = "+ ret); trace(FILE_NAME + FILE_COUNT + ".mp3"); trace("FILE_COUNT = "+ FILE_COUNT); FILE_COUNT++; break; case 6: //PAUSE break; } };
오디오 데이터의 녹음이 실패했을 때 발생하는 onerror 이벤트 함수를 다음과 같이 작성합니다.
this.AudioRecorder00_onerror = function(obj:nexacro.AudioRecorder,e:nexacro.AudioErrorEventInfo) { var strResult = "\n- AudioRecorder00_onerror" +"\n["+ e.errortype +"] "+ e.statuscode +" "+ e.errormsg; alert(strResult); switch(e.statuscode) { case "1301": //already recording break; case "1006": //play selection error (startpos >= stoppos) case "1007": //not loaded case "1009": //can't resume case "1302": //not recording this.initVar(); break; case "1306": //exist file FILE_COUNT++; this.btn_record_onclick(); break; default: break; } };
6
VirtualFile 이벤트 함수 작성하기
VirtualFile 오브젝트의 작업이 성공했을 때 발생하는 onsuccess 이벤트 함수를 다음과 같이 작성합니다.
this.VirtualFile00_onsuccess = function(obj:nexacro.VirtualFile,e:nexacro.VirtualFileEventInfo) { switch(e.reason) { case 8: //getFileList this.ds_filelist.clearData(); for(var i=0; i<e.fileattributelist.length; i++) { if(e.fileattributelist[i].filename.indexOf(FILE_NAME) > -1) { trace("e.fileattributelist["+ i +"] = "+ e.fileattributelist[i].filename); row = this.ds_filelist.addRow(); this.ds_filelist.setColumn(row, "FileName", e.fileattributelist[i].filename); FILE_COUNT++; } } break; } };
VirtualFile 오브젝트의 작업이 성공했을 때 발생하는 onerror 이벤트 함수를 다음과 같이 작성합니다.
this.VirtualFile00_onerror = function(obj:nexacro.VirtualFile,e:nexacro.VirtualFileErrorEventInfo) { var strResult = "\n- VirtualFile00_onerror" +"\n["+ e.errortype +"] "+ e.statuscode +" "+ e.errormsg; alert(strResult); };
7
Grid 컴포넌트 이벤트 함수 작성하기
Grid 컴포넌트의 Cell을 연속 터치 했을 때 발생하는 oncelldblclick 이벤트 함수를 다음과 같이 작성합니다.
this.grd_filelist_oncelldblclick = function(obj:nexacro.Grid,e:nexacro.GridClickEventInfo) { var rowPos = this.ds_filelist.rowposition; alert("grd_filelist_oncelldblclick: "+ DIRECTORY + this.ds_filelist.getColumn(rowPos, "FileName")); this.VirtualFile00.remove(DIRECTORY + this.ds_filelist.getColumn(rowPos, "FileName")); this.ds_filelist.deleteRow(rowPos); }; this.grd_filelist_oncellclick = function(obj:nexacro.Grid,e:nexacro.GridClickEventInfo) { //play? stop? };
8
Record 버튼 이벤트 함수 작성하기
Record 버튼을 터치했을 때 발생하는 onclick 이벤트 함수를 다음과 같이 작성합니다.
this.btn_record_onclick = function(obj:nexacro.Button,e:nexacro.ClickEventInfo) { this.stt_filepath.set_text(DIRECTORY + FILE_NAME + FILE_COUNT); this.AudioRecorder00.set_audiofile(this.stt_filepath.text); if(this.AudioRecorder00.recordingStart(1000)) { this.setTimer(0, 10); this.changeStatus(eStatus.RECORD); } };
9
Pause 버튼 이벤트 함수 작성하기
Pause 버튼을 터치했을 때 발생하는 onclick 이벤트 함수를 다음과 같이 작성합니다.
this.btn_pause_onclick = function(obj:nexacro.Button,e:nexacro.ClickEventInfo) { this.AudioRecorder00.pause(); this.changeStatus(eStatus.PAUSE); };
10
Stop 버튼 이벤트 함수 작성하기
Stop 버튼을 터치했을 때 발생하는 onclick 이벤트 함수를 다음과 같이 작성합니다.
this.btn_stop_onclick = function(obj:nexacro.Button,e:nexacro.ClickEventInfo) { this.AudioRecorder00.recordingStop(); this.changeStatus(eStatus.STOP); this.killTimer(0); };
11
모바일 장치에서 확인하기
Form이 로딩되면 녹음기가 출력되고 만약 기존의 녹음했던 파일이 존재하면 하단에 출력됩니다.
Record 버튼을 터치하면 녹음이 시작되고 Stop 버튼을 터치하면 녹음이 종료됩니다. 녹음을 종료하면 오디오 파일이 생성되고 하단에 표시됩니다. 녹음 중 Pause 버튼을 터치하면 녹음이 일시 정지되며 Resume 버튼을 터치하면 녹음이 다시 시작됩니다.
오디오 파일 이름을 두 번 터치하면 선택된 파일은 삭제됩니다. Form을 종료시키면 녹음에 사용된 오디오 파일 모두가 삭제됩니다.