기초공사 (html,css,javascript)
목소리인증 - 디자인 전 코드 본문
//
<%@ page language="java" pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<style type="text/css">
.panel {
margin:0 auto;
}
/* 화자등록과 화자인증만 적용 */
.l-btn {
overflow:visible;
/* background:#e9d9ff; */
}
/******화자등록 / 화자인증 button *******/
/* Ripple Out */
@-webkit-keyframes hvr-ripple-out_border {
100% {
top: -12px;
right: -12px;
bottom: -12px;
left: -12px;
opacity: 0;
}
}
@keyframes hvr-ripple-out_border {
100% {
top: -12px;
right: -12px;
bottom: -12px;
left: -12px;
opacity: 0;
}
}
/*인증시작 버튼 */
.hvr-ripple-out {
display: inline-block;
vertical-align: middle;
-webkit-transform: perspective(1px) translateZ(0);
transform: perspective(1px) translateZ(0);
padding:1em;
margin:0.4em;
box-shadow: 0 0 1px rgba(0, 0, 0, 0);
/* position: relative; */
background:#fafafa;
}
/* on을 넣었다빼는것으로. */
.hvr-ripple-out.on {
background:#5f4bef;
color:#fff;
/* animation:hvr-ripple-out_border 1s infinite; */
}
</style>
<style type="text/css">
/* MIC */
#micbox {
/* width: 200px; */
height: 200px;
position: relative;
}
#circle1 {
width: 200px;
height: 200px;
border-radius: 50%;
/* border: 1px solid green; */
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
/* transition: all 0.3s ease; */
}
#circle2 {
width: 200px;
height: 200px;
border-radius: 50%;
/* background-color: #3153af; */
background-color:#2e517b;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
transition: all 0.1s ease;
}
#circle3 {
width: 100px;
height:100px;
border-radius: 50%;
border: 5px solid #c7e0f5;
background-color: #fff;
background-image: url('/VOIS/sttsv-visualizer/img/mic.svg');
background-repeat:no-repeat;
background-size:40%;
background-position: center;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
/* transition: all 0.3s ease; */
}
/* progressbar */
.add-progress{
display: flex;
flex-direction: row;
}
.border {
width: 100%;
border-color: lightgray;
border-style: solid;
border-radius: 15px;
background-color: lightgray;
}
.progress-bar {
height: 18px;
border-radius: 15px;
/* animation: widthsize 3s ease-out infinite; */
}
.success{
width: 50%;
background: linear-gradient(to right, #78F5F5, #3057FA);
transition: all 0.5s ease-out;
}
/* @keyframes widthsize {
from {width: 0%}
to {width: 100%}
} */
</style>
<div class="easyui-layout" >
<div class="easyui-panel" title="목소리인증" style="width: 70%;height:800px; max-width: 70%; padding: 30px 30px;">
<div data-options="region:'north'" style="height:70px">
<ul style="display: block; float: left; margin: 10px 10px;">
<!-- 고객ID -->
<li style="float:left; margin-right:10px;">
<input class="easyui-textbox" id="s_SpeakerId" value="" />
</li>
<li style="float:left;">
<input class="easyui-textbox" value="0" id='s_Threshold' label="옵셋" disabled="true" labelAlign="right" labelWidth="50" />
</li>
</ul>
</div>
<div data-options="region:'center'" style="margin-top:30px; text-align:center;">
<div class="micbox-button">
<div id="micbox">
<div id="circle1">
<div id="circle2"></div>
<div id="circle3"></div>
</div>
</div>
</div>
<a href="#" class="easyui-linkbutton short hvr-ripple-out" onclick="start_verify_short()" style="padding:20px; margin:0 10px;">인증시작</a>
<a href="#" class="easyui-linkbutton stop" onclick="stop_verify_short()" style="padding:20px 35px; margin:0 10px;">중단</a>
<!--
<div class="bar" style="width:100%; float:left;">
<div id = "enrollprogressbar" class="easyui-progressbar first-progressbar" data-options="value:50" style="margin-top:40px;"></div>
</div>
-->
<div class="parse_pending border" style="margin-top: 40px;">
<div class="progress-bar success">
</div>
</div>
</div>
</div>
</div><!--easyui-layout -->
<script type="text/javascript">
// 페이지 로딩 완료 후 호출 메소드
function loadBody() {
initGrid();
}
// 컨트롤초기화
function initGrid() {
$btTextbox.create("#s_SpeakerId", $btTextbox.options({
label : '고객ID',
labelWidth : 50,
width : 150,
prompt: "고객ID 입력"
}));
$btTextbox.create("#s_Name", $btTextbox.options({
label : '고객명',
labelWidth : 50,
width : 200,
prompt: "고객명 입력"
}));
$btTextbox.create("#s_TellNum", $btTextbox.options({
label : '착신번호',
labelWidth : 60,
width : 200,
prompt: "착신번호 입력",
//전화번호 입력시 자동하이픈 삽입
inputEvents:$.extend({},$.fn.textbox.defaults.inputEvents,{
keyup:function(e){
$(this).val( $(this).val().replace(/[^0-9]/g, "").replace(/(^02|^0505|^1[0-9]{3}|^0[0-9]{2})([0-9]+)?([0-9]{4})$/,"$1-$2-$3").replace("--", "-") );
}
})
}));
}
// 인증시작 : short term
function start_verify_short()
{
if($('#s_SpeakerId').textbox('getValue') == ""){
alert("고객ID를 입력해주세요");
return;
};
// 통화번호 부여
dataRow = $btData.getRows("SC3000S3000", "selectTelSeq", "__", {});
dataTeLSeq = dataRow[0].seq;
start_Recording(true); // true = 최초실행
start_timer = setInterval(() => {
send_Recording();
}, interval_verify);
$('.hvr-ripple-out').addClass('on');
}
</script>
<!-- 화자등록, 화자인증 -->
<script type="text/javascript">
var interval_verify = 1200; //1000 -> 1200 (음성파일이 1초미만이라 살짝 늘려 수정함)
var start_timer;
var send_timer;
var dataTeLSeq = 0; //통화번호 (저장전부안함으로수정)
function stop_verify_short(){
stop_verify();
$('.hvr-ripple-out').removeClass('on');
}
//등록취소
function stop_verify(){
clearInterval(start_timer); //타이머해제하고
clearInterval(send_timer);
if (rec == null) {
return;
}
rec.stop(); // short term 레코드 초기화(누적은 진행됨)
javascriptNode.disconnect(); // 볼륨 측정을 중단합니다.
console.log("Recording stopped");
}
function send_Recording(){
clearInterval(start_timer); //타이머해제하고
clearInterval(send_timer);
var jParams = { telSeq : dataTeLSeq };
if(jParams)
{
$btData.delete("SC3000S3000", "deleteVAbyTelSeq", "__", jParams );
$btData.delete("SC3000S3000", "deleteUVbyTelSeq", "__", jParams );
}
rec.exportWAV(createDownloadLink);
}
// 화장인증
function createDownloadLink(blob) {
//업로드 및 다운로드 중에 사용할 .wav 파일 이름(확장자 제외)
var x = new Date();
let offset = x.getTimezoneOffset() * 60000; //ms단위라 60000곱해줌
let dateOffset = new Date(x.getTime() - offset);
var filename = dateOffset.toISOString();
var fd=new FormData();
fd.append("group" , "VIP");
fd.append("speaker" , $("#s_SpeakerId").val());
fd.append("telno" , $("#s_TellNum").val());
fd.append("speakernm" , $("#s_Name").val());// 이름
fd.append("voiceseq" , "");
fd.append("telseq" , dataTeLSeq); // 통화번호
fd.append("voice" , blob, filename+".wav"); //(이름, 값, 파일이름)
var xhr = new XMLHttpRequest();
//verify
fd.append("threshold", $("#s_Threshold").val());
console.log("threshold : " + $("#s_Threshold").val());
xhr.open("POST",url_verify);
xhr.addEventListener("readystatechange", function() {
if(this.readyState === 4){
return_data = JSON.parse(this.responseText);
console.log(this.responseText);
if(return_data.score){
show_verify_percent(0);
console.log("return_data.score="+return_data.score);
if(return_data.score > 0) {
let thisscore = return_data.score *4; //본인이어도 -15~25 정도로만 점수가 나오므로 *4 해줌..
show_verify_percent(thisscore);
}
}else{
if(return_data.status == "FAIL"){
alert("return_data.status == FAIL,"+return_data.errorMessage);
stop_verify();
}
}
}
});
xhr.send(fd);
stop_verify();
start_Recording(false); // 두번째 실행
send_timer = setInterval(() => {
send_Recording();
}, interval_verify);
};
//progressbar
function show_verify_percent(score)
{
let setscore = Math.ceil(score); //올림
if(setscore > 100) setscore = 100;
//$('#enrollprogressbar').progressbar('setValue', setscore);
$('.success').css("width", setscore + "%");
}
</script>
<script src="/VOIS/js/recorder.js"></script>
<script>
// 홈페이지를 이용하여 서비스를 호출한다
var url_enroll = "/VOIS/ossm/enroll.do"; //등록 주소
var url_verify = "/VOIS/ossm/verifyOneSec.do"; //인증 주소
var url_disenroll = "/VOIS/ossm/disenroll.do"; //등록 삭제 주소
var url_recording = "/VOIS/ossm/recording.do"; //상담 파일 업로드
var gumStream; //stream from getUserMedia()
var rec; //Recorder.js object
var input; //MediaStreamAudioSourceNode we'll be recording
function start_Recording(bStart)
{
console.log("1--------------------------<Recording started>");
var constraints = { audio:{echoCancellation: false, noiseSuppression: false, autoGainControl: false, mozNoiseSuppression: false, mozAutoGainControl: false}, video:false }
// navigator.mediaDevices.getUserMedia(constraints)는 사용자의 오디오 미디어 가져옴
// constraints 객체를 통해 오디오 설정을 지정
navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
console.log("getUserMedia() success, stream created, initializing Recorder.js ...");
//미디어 스트림을 성공적으로 가져오면 AudioContext를 생성
audioContext = new AudioContext({sampleRate: 16000});
gumStream = stream;
// 오디오 스트림 소스를 생성
input = audioContext.createMediaStreamSource(stream);
/* Create an analyser node */
analyser = audioContext.createAnalyser();
input.connect(analyser);
/* Create a script processor node */
javascriptNode = audioContext.createScriptProcessor(2048, 1, 1);
/* Connect the script processor node */
analyser.connect(javascriptNode);
javascriptNode.connect(audioContext.destination);
//Recorder 객체를 생성하고 녹음을 시작
rec = new Recorder(input,{numChannels:1});
rec.record();
/* Respond to the audio process event. */
javascriptNode.onaudioprocess = function() {
var array = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(array);
var values = 0;
var length = array.length;
for (var i = 0; i < length; i++) {
values += array[i];
}
var average = values / length;
/* Normalize the volume */
var volume = Math.floor((average / 128) * 100); // 정규화 계수를 255에서 128로 변경 //동일한 입력 볼륨에 대해 더 높은 출력 볼륨이 측정
//console.log(volume);
drawMic(volume);
}
}).catch(function(err) {
$(".stop").trigger("click");
alert("마이크를 연결 해주세요");
console.log("getUserMedia() fails");
});
}
//button animation
/* $('.short').click(function(){
$(this).addClass('active');
});
$('.stop').click(function(){
$('.short').removeClass('active');
}); */
/* $('#circle3').click(function() {
var AudioData = Math.floor(Math.random() * 101);
drawMic(AudioData);
}); */
drawMic(30);
/* visualizer */
function drawMic(inputData)
{
if(inputData < 0){
inputData = 0;
}
var inCircle_W_H = 100 /2 ; //circle3의 정사이즈 너비,높이값 / 2
var percentage;
if (inputData === 0) {
percentage = inCircle_W_H; //circle3 너비,높이값인 100
} else if (inputData >= 100) {
percentage = 99;
}
else {
percentage = inCircle_W_H + (inputData * ((100-inCircle_W_H)/100)); //circle3 너비,높이값인 65 + (inputdata) * ((100-65)/100)
}
$("#circle2").css('width', percentage + '%');
$("#circle2").css('height', percentage + '%');
//console.log("inputData:" + inputData + " percent:" + percentage + "%");
}
</script>
여기에서 on클래스를 추가삭제는 알았는데
function stop_verify( )
함수에 넣으니
on의속(바탕색)성이 자꾸 사라져서 디버깅을 보니 stop_verify();가 곳곳에 있다보니 나왔다 사라지고 했다.
그래서 따로 함수를 만들어서 function stop_verify_short()를 만들어서 stop_verify(); 을 호출하고,
중단버튼을 클릭 할때만 $('.hvr-ripple-out').removeClass('on')이것이 적용하도록 했다.
안선임이 도와줌;;
function stop_verify_short(){
stop_verify();
$('.hvr-ripple-out').removeClass('on');
}