使用 sip.js 从 SIP 通话中录制麦克风和音频
Record mic and audio from SIP call using sip.js
晚上好堆栈溢出!
我的一个项目真的需要帮助,我正在使用 sip.js 和 VoIP 来真正呼叫 phone 号码。
目标
我想允许用户录制音频和微博phone并将数据保存在服务器上(以 base64 编码或作为文件)。所以在谈话之后我可以再次听到谈话并将其用于我的目的(员工培训)。
问题
我听不到说话人的声音,它来自 -HTML 标签(使用 sip.js 插件)。截至目前,我还没有找到任何方法可以通过此音频标签成功保存声音流。
到目前为止我做了什么
我已经成功地找到了如何使用名为 AudioRecorder 的插件录制 microphone 的音频,它允许我通过 microphone 录制音频并保存它。我稍微更改了代码,以便将其保存为 base64 编码。这一切都按预期工作,尽管我只能听到我自己的声音,而不是我正在与之交谈的人。
因为我成功录制了自己的声音,所以我查看了 AudioRecorder 插件并尝试反转插件以从音频标签录制。我在 AudioRecorder 中找到了 "createMediaStreamSource" 函数,我想使用它不起作用的 -tag (正如我所怀疑的那样,因为它本身的 -tag 不是一个流(我理解)。
代码
我基本上是使用 sip.js 插件通过以下代码建立对 phone 号码的调用(仅使用示例,匹配我的代码,因为我的原始代码包含一些添加的不需要在此处显示的值):
// Create a user agent called bob, connect, and register to receive invitations.
var userAgent = new SIP.UA({
uri: 'bob@example.com',
wsServers: ['wss://sip-ws.example.com'],
register: true
});
var options = { media: { constraints: { audio: true, video: false }, render: { remote: document.getElementById("audio") } } };
然后我使用内置邀请功能调用一个 phone 号码,剩下的由它完成。音频和微型 phone 现已启动并且 运行。
userAgent.invite("+4512345678", options);
我现在可以和我最好的新朋友鲍勃聊天了。但是我现在除了自己的声音之外还不能录。
下一步是什么?
我真的很想了解如何录制 "Bob" 的声音并存储它,最好与我自己的声音放在同一个文件中。如果我必须录制两个单独的文件并同步播放它们,我不会介意,但如果愿意的话。
我知道这可能只是求助,没有显示我自己尝试做的任何真实代码,但我不得不承认我只是摆弄了几个小时的代码,但没有任何好的结果,现在我在尖叫求救。
提前感谢大家,对于错误的语法和(错误的)语言使用,我们深表歉意。
好的,所以我终于找到了解决问题的方法,虽然我想在这里分享。
我解决这个问题的方法是在麦克风的 "normal" 录音脚本中添加一行简单的代码。录制麦克风音频的脚本是:
window.AudioContext = window.AudioContext || window.webkitAudioContext;
var audioGlobalContext = new AudioContext();
var audioOutputAnalyser
var inputPoint = null,
audioRecorder = null;
var recording = false;
// Controls the start and stop of recording
function toggleRecording( e ) {
if (recording == true) {
recording = false;
audioRecorder.stop();
audioRecorder.getBuffers( gotBuffers );
console.log("Stop recording");
} else {
if (!audioRecorder)
return;
recording = true;
audioRecorder.clear();
audioRecorder.record();
console.log("Start recording");
}
}
function gotBuffers(buffers) {
audioRecorder.exportWAV(doneEncoding);
}
function doneEncoding(blob) {
document.getElementById("outputAudio").pause();
Recorder.setupDownload(blob);
}
function gotAudioMicrophoneStream(stream) {
var source = audioGlobalContext.createMediaStreamSource(stream);
source.connect(inputPoint);
}
function initAudio() {
if (!navigator.getUserMedia)
navigator.getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
if (!navigator.cancelAnimationFrame)
navigator.cancelAnimationFrame = navigator.webkitCancelAnimationFrame || navigator.mozCancelAnimationFrame;
if (!navigator.requestAnimationFrame)
navigator.requestAnimationFrame = navigator.webkitRequestAnimationFrame || navigator.mozRequestAnimationFrame;
inputPoint = audioGlobalContext.createGain();
navigator.getUserMedia({
"audio": {
"mandatory": {
"googEchoCancellation": "true",
"googAutoGainControl": "false",
"googNoiseSuppression": "true",
"googHighpassFilter": "false"
},
"optional": []
},
}, gotAudioMicrophoneStream, function(e) {
alert('Error recording microphone');
console.log(e);
});
var analyserNode = audioGlobalContext.createAnalyser();
analyserNode.fftSize = 2048;
inputPoint.connect(analyserNode);
var zeroGain = audioGlobalContext.createGain();
zeroGain.gain.value = 0.0;
inputPoint.connect(zeroGain);
zeroGain.connect(audioGlobalContext.destination);
audioRecorder = new Recorder(inputPoint);
}
window.addEventListener('load', initAudio );
我正在寻找将音频标签声音转换为音频源的函数是 createMediaElementSource()
所以我所做的就是添加这个函数:
function gotAudioOutputStream() {
var source = audioGlobalContext.createMediaElementSource(document.getElementById("outputAudio"));
source.connect(inputPoint);
source.connect(audioGlobalContext.destination);
}
并且在 navigator.getUserMedia 之后的 initAudio() 函数中添加了对该函数的调用。完成的代码(HTML)看起来像这样
window.AudioContext = window.AudioContext || window.webkitAudioContext;
var audioGlobalContext = new AudioContext();
var audioOutputAnalyser
var inputPoint = null,
audioRecorder = null;
var recording = false;
// Controls the start and stop of recording
function toggleRecording( e ) {
if (recording == true) {
recording = false;
audioRecorder.stop();
audioRecorder.getBuffers( gotBuffers );
console.log("Stop recording");
} else {
if (!audioRecorder)
return;
recording = true;
audioRecorder.clear();
audioRecorder.record();
console.log("Start recording");
}
}
function gotBuffers(buffers) {
audioRecorder.exportWAV(doneEncoding);
}
function doneEncoding(blob) {
document.getElementById("outputAudio").pause();
Recorder.setupDownload(blob);
}
function gotAudioMicrophoneStream(stream) {
var source = audioGlobalContext.createMediaStreamSource(stream);
source.connect(inputPoint);
}
function gotAudioOutputStream() {
var source = audioGlobalContext.createMediaElementSource(document.getElementById("outputAudio"));
source.connect(inputPoint);
source.connect(audioGlobalContext.destination);
}
function initAudio() {
if (!navigator.getUserMedia)
navigator.getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
if (!navigator.cancelAnimationFrame)
navigator.cancelAnimationFrame = navigator.webkitCancelAnimationFrame || navigator.mozCancelAnimationFrame;
if (!navigator.requestAnimationFrame)
navigator.requestAnimationFrame = navigator.webkitRequestAnimationFrame || navigator.mozRequestAnimationFrame;
inputPoint = audioGlobalContext.createGain();
navigator.getUserMedia({
"audio": {
"mandatory": {
"googEchoCancellation": "true",
"googAutoGainControl": "false",
"googNoiseSuppression": "true",
"googHighpassFilter": "false"
},
"optional": []
},
}, gotAudioMicrophoneStream, function(e) {
alert('Error recording microphone');
console.log(e);
});
gotAudioOutputStream();
var analyserNode = audioGlobalContext.createAnalyser();
analyserNode.fftSize = 2048;
inputPoint.connect(analyserNode);
var zeroGain = audioGlobalContext.createGain();
zeroGain.gain.value = 0.0;
inputPoint.connect(zeroGain);
zeroGain.connect(audioGlobalContext.destination);
audioRecorder = new Recorder(inputPoint);
}
window.addEventListener('load', initAudio );
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Audio Recorder</title>
<script src="assets/js/AudioRecorder/js/recorderjs/recorder.js"></script>
<script src="assets/js/AudioRecorder/js/main.js"></script>
</head>
<body>
<audio id="outputAudio" autoplay="true" src="test.mp3" type="audio/mpeg"></audio>
<audio id="playBack"></audio>
<div id="controls">
<img id="record" src="assets/js/AudioRecorder/img/mic128.png" onclick="toggleRecording(this);">
</div>
</body>
</html>
这会记录您的声音和来自音频元素标签的声音。简单的。希望所有和我有同样问题的人 "rewind" 你对音频 API 的看法会有所帮助。
上面显示的代码片段需要 Recorder.js 才能工作。
晚上好堆栈溢出! 我的一个项目真的需要帮助,我正在使用 sip.js 和 VoIP 来真正呼叫 phone 号码。
目标
我想允许用户录制音频和微博phone并将数据保存在服务器上(以 base64 编码或作为文件)。所以在谈话之后我可以再次听到谈话并将其用于我的目的(员工培训)。
问题
我听不到说话人的声音,它来自 -HTML 标签(使用 sip.js 插件)。截至目前,我还没有找到任何方法可以通过此音频标签成功保存声音流。
到目前为止我做了什么
我已经成功地找到了如何使用名为 AudioRecorder 的插件录制 microphone 的音频,它允许我通过 microphone 录制音频并保存它。我稍微更改了代码,以便将其保存为 base64 编码。这一切都按预期工作,尽管我只能听到我自己的声音,而不是我正在与之交谈的人。
因为我成功录制了自己的声音,所以我查看了 AudioRecorder 插件并尝试反转插件以从音频标签录制。我在 AudioRecorder 中找到了 "createMediaStreamSource" 函数,我想使用它不起作用的 -tag (正如我所怀疑的那样,因为它本身的 -tag 不是一个流(我理解)。
代码
我基本上是使用 sip.js 插件通过以下代码建立对 phone 号码的调用(仅使用示例,匹配我的代码,因为我的原始代码包含一些添加的不需要在此处显示的值):
// Create a user agent called bob, connect, and register to receive invitations.
var userAgent = new SIP.UA({
uri: 'bob@example.com',
wsServers: ['wss://sip-ws.example.com'],
register: true
});
var options = { media: { constraints: { audio: true, video: false }, render: { remote: document.getElementById("audio") } } };
然后我使用内置邀请功能调用一个 phone 号码,剩下的由它完成。音频和微型 phone 现已启动并且 运行。
userAgent.invite("+4512345678", options);
我现在可以和我最好的新朋友鲍勃聊天了。但是我现在除了自己的声音之外还不能录。
下一步是什么?
我真的很想了解如何录制 "Bob" 的声音并存储它,最好与我自己的声音放在同一个文件中。如果我必须录制两个单独的文件并同步播放它们,我不会介意,但如果愿意的话。
我知道这可能只是求助,没有显示我自己尝试做的任何真实代码,但我不得不承认我只是摆弄了几个小时的代码,但没有任何好的结果,现在我在尖叫求救。
提前感谢大家,对于错误的语法和(错误的)语言使用,我们深表歉意。
好的,所以我终于找到了解决问题的方法,虽然我想在这里分享。
我解决这个问题的方法是在麦克风的 "normal" 录音脚本中添加一行简单的代码。录制麦克风音频的脚本是:
window.AudioContext = window.AudioContext || window.webkitAudioContext;
var audioGlobalContext = new AudioContext();
var audioOutputAnalyser
var inputPoint = null,
audioRecorder = null;
var recording = false;
// Controls the start and stop of recording
function toggleRecording( e ) {
if (recording == true) {
recording = false;
audioRecorder.stop();
audioRecorder.getBuffers( gotBuffers );
console.log("Stop recording");
} else {
if (!audioRecorder)
return;
recording = true;
audioRecorder.clear();
audioRecorder.record();
console.log("Start recording");
}
}
function gotBuffers(buffers) {
audioRecorder.exportWAV(doneEncoding);
}
function doneEncoding(blob) {
document.getElementById("outputAudio").pause();
Recorder.setupDownload(blob);
}
function gotAudioMicrophoneStream(stream) {
var source = audioGlobalContext.createMediaStreamSource(stream);
source.connect(inputPoint);
}
function initAudio() {
if (!navigator.getUserMedia)
navigator.getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
if (!navigator.cancelAnimationFrame)
navigator.cancelAnimationFrame = navigator.webkitCancelAnimationFrame || navigator.mozCancelAnimationFrame;
if (!navigator.requestAnimationFrame)
navigator.requestAnimationFrame = navigator.webkitRequestAnimationFrame || navigator.mozRequestAnimationFrame;
inputPoint = audioGlobalContext.createGain();
navigator.getUserMedia({
"audio": {
"mandatory": {
"googEchoCancellation": "true",
"googAutoGainControl": "false",
"googNoiseSuppression": "true",
"googHighpassFilter": "false"
},
"optional": []
},
}, gotAudioMicrophoneStream, function(e) {
alert('Error recording microphone');
console.log(e);
});
var analyserNode = audioGlobalContext.createAnalyser();
analyserNode.fftSize = 2048;
inputPoint.connect(analyserNode);
var zeroGain = audioGlobalContext.createGain();
zeroGain.gain.value = 0.0;
inputPoint.connect(zeroGain);
zeroGain.connect(audioGlobalContext.destination);
audioRecorder = new Recorder(inputPoint);
}
window.addEventListener('load', initAudio );
我正在寻找将音频标签声音转换为音频源的函数是 createMediaElementSource()
所以我所做的就是添加这个函数:
function gotAudioOutputStream() {
var source = audioGlobalContext.createMediaElementSource(document.getElementById("outputAudio"));
source.connect(inputPoint);
source.connect(audioGlobalContext.destination);
}
并且在 navigator.getUserMedia 之后的 initAudio() 函数中添加了对该函数的调用。完成的代码(HTML)看起来像这样
window.AudioContext = window.AudioContext || window.webkitAudioContext;
var audioGlobalContext = new AudioContext();
var audioOutputAnalyser
var inputPoint = null,
audioRecorder = null;
var recording = false;
// Controls the start and stop of recording
function toggleRecording( e ) {
if (recording == true) {
recording = false;
audioRecorder.stop();
audioRecorder.getBuffers( gotBuffers );
console.log("Stop recording");
} else {
if (!audioRecorder)
return;
recording = true;
audioRecorder.clear();
audioRecorder.record();
console.log("Start recording");
}
}
function gotBuffers(buffers) {
audioRecorder.exportWAV(doneEncoding);
}
function doneEncoding(blob) {
document.getElementById("outputAudio").pause();
Recorder.setupDownload(blob);
}
function gotAudioMicrophoneStream(stream) {
var source = audioGlobalContext.createMediaStreamSource(stream);
source.connect(inputPoint);
}
function gotAudioOutputStream() {
var source = audioGlobalContext.createMediaElementSource(document.getElementById("outputAudio"));
source.connect(inputPoint);
source.connect(audioGlobalContext.destination);
}
function initAudio() {
if (!navigator.getUserMedia)
navigator.getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
if (!navigator.cancelAnimationFrame)
navigator.cancelAnimationFrame = navigator.webkitCancelAnimationFrame || navigator.mozCancelAnimationFrame;
if (!navigator.requestAnimationFrame)
navigator.requestAnimationFrame = navigator.webkitRequestAnimationFrame || navigator.mozRequestAnimationFrame;
inputPoint = audioGlobalContext.createGain();
navigator.getUserMedia({
"audio": {
"mandatory": {
"googEchoCancellation": "true",
"googAutoGainControl": "false",
"googNoiseSuppression": "true",
"googHighpassFilter": "false"
},
"optional": []
},
}, gotAudioMicrophoneStream, function(e) {
alert('Error recording microphone');
console.log(e);
});
gotAudioOutputStream();
var analyserNode = audioGlobalContext.createAnalyser();
analyserNode.fftSize = 2048;
inputPoint.connect(analyserNode);
var zeroGain = audioGlobalContext.createGain();
zeroGain.gain.value = 0.0;
inputPoint.connect(zeroGain);
zeroGain.connect(audioGlobalContext.destination);
audioRecorder = new Recorder(inputPoint);
}
window.addEventListener('load', initAudio );
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Audio Recorder</title>
<script src="assets/js/AudioRecorder/js/recorderjs/recorder.js"></script>
<script src="assets/js/AudioRecorder/js/main.js"></script>
</head>
<body>
<audio id="outputAudio" autoplay="true" src="test.mp3" type="audio/mpeg"></audio>
<audio id="playBack"></audio>
<div id="controls">
<img id="record" src="assets/js/AudioRecorder/img/mic128.png" onclick="toggleRecording(this);">
</div>
</body>
</html>
这会记录您的声音和来自音频元素标签的声音。简单的。希望所有和我有同样问题的人 "rewind" 你对音频 API 的看法会有所帮助。
上面显示的代码片段需要 Recorder.js 才能工作。