2018-11-14 16:59:14 +09:00
|
|
|
import { Component } from "react";
|
|
|
|
import * as _VAD from "vad.js/lib/vad.js";
|
2018-11-19 16:41:05 +09:00
|
|
|
import Percentage from "./percentage";
|
2018-11-15 17:36:28 +09:00
|
|
|
import Kaburi from "./kaburi";
|
2018-11-14 16:59:14 +09:00
|
|
|
|
|
|
|
export default class extends Component {
|
|
|
|
state = {
|
|
|
|
audioContext: new AudioContext(),
|
|
|
|
audioStream: null,
|
|
|
|
left: null,
|
2018-11-15 16:41:30 +09:00
|
|
|
right: null,
|
|
|
|
activity: []
|
2018-11-14 16:59:14 +09:00
|
|
|
};
|
|
|
|
|
|
|
|
componentDidMount() {
|
|
|
|
const audioContext = this.state.audioContext;
|
|
|
|
const leftNode = audioContext.createGain();
|
|
|
|
const rightNode = audioContext.createGain();
|
|
|
|
const splitter = audioContext.createChannelSplitter(2);
|
|
|
|
|
|
|
|
splitter.connect(
|
|
|
|
leftNode,
|
|
|
|
0
|
|
|
|
);
|
|
|
|
splitter.connect(
|
|
|
|
rightNode,
|
|
|
|
1
|
|
|
|
);
|
|
|
|
|
2018-11-15 17:36:28 +09:00
|
|
|
const putKaburi = () => {
|
|
|
|
if (this.state.left !== null && this.state.right !== null) {
|
|
|
|
this.setState({
|
|
|
|
activity: [
|
|
|
|
...this.state.activity,
|
|
|
|
{
|
|
|
|
ch: "kaburi",
|
|
|
|
startTime: Math.max(this.state.left, this.state.right),
|
|
|
|
endTime: new Date().getTime()
|
|
|
|
}
|
|
|
|
]
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-11-14 16:59:14 +09:00
|
|
|
const start = stream => {
|
2018-11-15 16:41:30 +09:00
|
|
|
this.setState({ audioStream: stream });
|
2018-11-14 16:59:14 +09:00
|
|
|
audioContext.createMediaStreamSource(stream).connect(splitter);
|
|
|
|
|
|
|
|
VAD.bind({})({
|
|
|
|
source: leftNode,
|
2018-11-15 16:41:30 +09:00
|
|
|
voice_stop: () => {
|
2018-11-15 17:36:28 +09:00
|
|
|
putKaburi();
|
|
|
|
|
2018-11-15 16:41:30 +09:00
|
|
|
this.setState({
|
|
|
|
left: null,
|
|
|
|
activity: [
|
|
|
|
...this.state.activity,
|
|
|
|
{
|
|
|
|
ch: "l",
|
|
|
|
startTime: this.state.left,
|
|
|
|
endTime: new Date().getTime()
|
|
|
|
}
|
|
|
|
]
|
|
|
|
});
|
2018-11-14 16:59:14 +09:00
|
|
|
},
|
2018-11-15 16:41:30 +09:00
|
|
|
voice_start: () => {
|
|
|
|
this.setState({ left: new Date().getTime() });
|
2018-11-14 16:59:14 +09:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
VAD.bind({})({
|
|
|
|
source: rightNode,
|
2018-11-15 16:41:30 +09:00
|
|
|
voice_stop: () => {
|
2018-11-15 17:36:28 +09:00
|
|
|
putKaburi();
|
|
|
|
|
2018-11-15 16:41:30 +09:00
|
|
|
this.setState({
|
|
|
|
right: null,
|
|
|
|
activity: [
|
|
|
|
...this.state.activity,
|
|
|
|
{
|
|
|
|
ch: "r",
|
|
|
|
startTime: this.state.right,
|
|
|
|
endTime: new Date().getTime()
|
|
|
|
}
|
|
|
|
]
|
|
|
|
});
|
2018-11-14 16:59:14 +09:00
|
|
|
},
|
2018-11-15 16:41:30 +09:00
|
|
|
voice_start: () => {
|
|
|
|
this.setState({ right: new Date().getTime() });
|
2018-11-14 16:59:14 +09:00
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
navigator.mediaDevices
|
|
|
|
.getUserMedia({ audio: { echoCancellation: false } }) // モノラル防ぐ
|
|
|
|
.then(start)
|
|
|
|
.catch(console.error);
|
|
|
|
}
|
|
|
|
|
|
|
|
componentWillUnmount() {
|
|
|
|
this.state.audioStream.getTracks().forEach(t => t.stop());
|
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
|
|
|
return (
|
2018-11-15 16:41:30 +09:00
|
|
|
<div>
|
|
|
|
<dl>
|
|
|
|
<dt>左</dt>
|
|
|
|
<dd>{this.state.left && "発話中..."}</dd>
|
|
|
|
<dt>右</dt>
|
|
|
|
<dd>{this.state.right && "発話中..."}</dd>
|
|
|
|
</dl>
|
2018-11-19 16:41:05 +09:00
|
|
|
<Percentage activity={this.state.activity} />
|
2018-11-15 17:36:28 +09:00
|
|
|
<Kaburi activity={this.state.activity} />
|
2018-11-15 16:41:30 +09:00
|
|
|
</div>
|
2018-11-14 16:59:14 +09:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|