321
This commit is contained in:
parent
04c3df3f05
commit
6718eed4e4
|
|
@ -249,6 +249,10 @@
|
|||
@section Scripts {
|
||||
<script src="~/lib/microsoft-signalr/signalr.min.js"></script>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js"></script>
|
||||
<script src='https://web.sdk.qcloud.com/trtc/webrtc/v5/dist/trtc.js'></script>
|
||||
<script src="~//js/lib-generate-test-usersig.min.js"></script>
|
||||
<script src="~//js/generateTestUserSig.js"></script>
|
||||
<script>
|
||||
let connection = null;
|
||||
let refreshDisplayInterval = null;
|
||||
|
|
@ -269,6 +273,36 @@
|
|||
let currentVolume = 1.0; // 默认音量
|
||||
let volumeBoost = 3.0; // 音量增益倍数,提高接收到的音频音量
|
||||
|
||||
const sdkAppId = 1600079538;
|
||||
const sdkSecretKey = "df2427757c0ec29ae8ca45611ddb70381144d55338e5ac73c2da27a9c32729f6";
|
||||
let userId = "监听者:" + Math.random().toString(36).substring(2, 15);
|
||||
let roomId = 8888;
|
||||
|
||||
let trtc = TRTC.create();
|
||||
|
||||
async function enterRoom() {
|
||||
try {
|
||||
trtc = TRTC.create();
|
||||
// 生成用户签名
|
||||
const { userSig } = genTestUserSig({ sdkAppId, userId, sdkSecretKey });
|
||||
// 进入房间
|
||||
await trtc.enterRoom({ sdkAppId, userId, userSig, roomId: roomId });
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function leaveRoom() {
|
||||
try {
|
||||
await trtc.exitRoom();
|
||||
trtc.destroy();
|
||||
// 更新状态指示器为红色(已断开)
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// 调试日志
|
||||
function log(message) {
|
||||
const timestamp = new Date().toLocaleTimeString();
|
||||
|
|
@ -300,9 +334,9 @@
|
|||
const alert = document.createElement("div");
|
||||
alert.className = `alert alert-${type} alert-dismissible fade show`;
|
||||
alert.innerHTML = `
|
||||
${message}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
`;
|
||||
${message}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
`;
|
||||
messageArea.appendChild(alert);
|
||||
|
||||
// 自动移除
|
||||
|
|
@ -489,12 +523,7 @@
|
|||
updateCallStatus(true);
|
||||
return;
|
||||
}
|
||||
if (isAudioStreamEnabled && callInProgress) {
|
||||
// 确保音频流开启且通话进行中
|
||||
log("接收到实时音频数据...");
|
||||
// 直接传递原始数据,让playRealTimeAudio函数内部处理
|
||||
playRealTimeAudio(audioData);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// 音频流设置更新消息
|
||||
|
|
@ -539,6 +568,7 @@
|
|||
// 当检测到新通话时,先显示确认对话框
|
||||
const confirmDialog = new bootstrap.Modal(document.getElementById('callConfirmDialog'));
|
||||
confirmDialog.show();
|
||||
enterRoom();
|
||||
return; // 等待用户确认后再继续处理
|
||||
} else {
|
||||
const indicator = document.getElementById("status-indicator");
|
||||
|
|
@ -550,6 +580,7 @@
|
|||
const confirmDialog = bootstrap.Modal.getInstance(document.getElementById('callConfirmDialog'));
|
||||
if (confirmDialog) {
|
||||
confirmDialog.hide();
|
||||
exitRoom();
|
||||
log("通话已结束,自动关闭确认对话框");
|
||||
}
|
||||
}
|
||||
|
|
@ -669,22 +700,22 @@
|
|||
const shortText = text.length > 10 ? text.substring(0, 10) : text;
|
||||
|
||||
listItem.innerHTML = `
|
||||
<div class="d-flex justify-content-between align-items-start mb-1">
|
||||
<small class="text-muted">【${shortText}】</small>
|
||||
<div class="btn-group btn-group-sm">
|
||||
<button class="btn btn-outline-primary btn-sm" onclick="playAudio('${item.recordingPath || ''}', this)">
|
||||
<i class="bi bi-play-fill"></i>
|
||||
</button>
|
||||
<button class="btn btn-outline-secondary btn-sm" onclick="downloadRecording('${item.recordingPath || ''}')">
|
||||
<i class="bi bi-download"></i>
|
||||
</button>
|
||||
<button class="btn btn-outline-danger btn-sm" onclick="deleteMonitorText('${item.id}')">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>${formattedDate}</div>
|
||||
`;
|
||||
<div class="d-flex justify-content-between align-items-start mb-1">
|
||||
<small class="text-muted">【${shortText}】</small>
|
||||
<div class="btn-group btn-group-sm">
|
||||
<button class="btn btn-outline-primary btn-sm" onclick="playAudio('${item.recordingPath || ''}', this)">
|
||||
<i class="bi bi-play-fill"></i>
|
||||
</button>
|
||||
<button class="btn btn-outline-secondary btn-sm" onclick="downloadRecording('${item.recordingPath || ''}')">
|
||||
<i class="bi bi-download"></i>
|
||||
</button>
|
||||
<button class="btn btn-outline-danger btn-sm" onclick="deleteMonitorText('${item.id}')">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>${formattedDate}</div>
|
||||
`;
|
||||
|
||||
container.appendChild(listItem);
|
||||
});
|
||||
|
|
@ -890,11 +921,11 @@
|
|||
const shortText = text.length > 5 ? text.substring(0, 5) : text;
|
||||
|
||||
listItem.innerHTML = `
|
||||
<div class="mb-1">
|
||||
<small class="text-muted">${formattedDate}</small>
|
||||
</div>
|
||||
<div>【${shortText}】</div>
|
||||
`;
|
||||
<div class="mb-1">
|
||||
<small class="text-muted">${formattedDate}</small>
|
||||
</div>
|
||||
<div>【${shortText}】</div>
|
||||
`;
|
||||
|
||||
container.appendChild(listItem);
|
||||
});
|
||||
|
|
@ -1056,7 +1087,7 @@
|
|||
|
||||
// 初始化页面
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
|
||||
|
||||
// 初始化音频上下文
|
||||
initAudioContext();
|
||||
|
||||
|
|
@ -1081,7 +1112,7 @@
|
|||
// 默认开启音频传输
|
||||
document.getElementById("audioStreaming1").checked = true;
|
||||
isAudioStreamEnabled = true;
|
||||
|
||||
|
||||
});
|
||||
|
||||
// 页面卸载前清理资源
|
||||
|
|
@ -1462,7 +1493,7 @@
|
|||
try {
|
||||
// 解析音频元数据和数据
|
||||
const { format, sampleRate, channels, data } = audioPacket;
|
||||
|
||||
|
||||
// 确保格式正确
|
||||
if (!format || !data) {
|
||||
log("音频格式或数据无效");
|
||||
|
|
@ -1516,7 +1547,7 @@
|
|||
// 创建音频源并连接
|
||||
const source = audioContext.createBufferSource();
|
||||
source.buffer = audioBuffer;
|
||||
|
||||
|
||||
// 应用音量控制
|
||||
source.connect(audioGainNode);
|
||||
if (audioGainNode) {
|
||||
|
|
@ -1575,7 +1606,7 @@
|
|||
|
||||
// 使用Web Audio API解码音频
|
||||
audioContext.decodeAudioData(
|
||||
arrayBuffer,
|
||||
arrayBuffer,
|
||||
(buffer) => {
|
||||
log("WAV数据解码成功, 时长: " + buffer.duration.toFixed(2) + "秒");
|
||||
resolve(buffer);
|
||||
|
|
@ -1647,26 +1678,26 @@
|
|||
// 创建DataView以便正确解析16位整数
|
||||
const dataView = new DataView(pcmData.buffer, pcmData.byteOffset, pcmData.byteLength);
|
||||
int16Data = new Int16Array(pcmData.length / 2);
|
||||
|
||||
|
||||
// 从小端字节序读取16位整数
|
||||
for (let i = 0; i < pcmData.length; i += 2) {
|
||||
if (i + 1 < pcmData.length) {
|
||||
int16Data[i/2] = dataView.getInt16(i, true); // true表示小端字节序
|
||||
int16Data[i / 2] = dataView.getInt16(i, true); // true表示小端字节序
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
log("创建Int16Array失败: " + e);
|
||||
|
||||
|
||||
// 备用方法
|
||||
const newBuffer = new ArrayBuffer(pcmData.length);
|
||||
const newView = new Uint8Array(newBuffer);
|
||||
newView.set(pcmData);
|
||||
const dataView = new DataView(newBuffer);
|
||||
|
||||
|
||||
int16Data = new Int16Array(pcmData.length / 2);
|
||||
for (let i = 0; i < pcmData.length; i += 2) {
|
||||
if (i + 1 < pcmData.length) {
|
||||
int16Data[i/2] = dataView.getInt16(i, true);
|
||||
int16Data[i / 2] = dataView.getInt16(i, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1674,7 +1705,7 @@
|
|||
// 创建音频缓冲区,使用实际采样率
|
||||
const audioSampleRate = sampleRate || audioContext.sampleRate;
|
||||
const buffer = audioContext.createBuffer(channels || 1, int16Data.length, audioSampleRate);
|
||||
|
||||
|
||||
// 将Int16数据转换为Float32数据并存入缓冲区
|
||||
const channelData = buffer.getChannelData(0);
|
||||
for (let i = 0; i < int16Data.length; i++) {
|
||||
|
|
@ -1771,16 +1802,16 @@
|
|||
const shortText = text.length > 10 ? text.substring(0, 10) : text;
|
||||
|
||||
listItem.innerHTML = `
|
||||
<div class="d-flex justify-content-between align-items-start mb-1">
|
||||
<small class="text-muted">【${shortText}】</small>
|
||||
<div class="btn-group btn-group-sm">
|
||||
<button class="btn btn-outline-danger btn-sm" onclick="deleteMonitorText('${listItem.dataset.id}')">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>${formattedDate} (本地)</div>
|
||||
`;
|
||||
<div class="d-flex justify-content-between align-items-start mb-1">
|
||||
<small class="text-muted">【${shortText}】</small>
|
||||
<div class="btn-group btn-group-sm">
|
||||
<button class="btn btn-outline-danger btn-sm" onclick="deleteMonitorText('${listItem.dataset.id}')">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>${formattedDate} (本地)</div>
|
||||
`;
|
||||
|
||||
// 添加到列表顶部
|
||||
if (container.firstChild) {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.3.0" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.0" />
|
||||
<PackageReference Include="NAudio" Version="2.2.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
|
|
|
|||
Binary file not shown.
7
ShengShengBuXi/wwwroot/js/clipboard.min.js
vendored
Normal file
7
ShengShengBuXi/wwwroot/js/clipboard.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
23
ShengShengBuXi/wwwroot/js/generateTestUserSig.js
Normal file
23
ShengShengBuXi/wwwroot/js/generateTestUserSig.js
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/* eslint-disable*/
|
||||
|
||||
function genTestUserSig({ sdkAppId, userId, sdkSecretKey }) {
|
||||
|
||||
const SDKAPPID = sdkAppId;
|
||||
|
||||
const EXPIRETIME = 604800;
|
||||
|
||||
const SDKSECRETKEY = sdkSecretKey;
|
||||
|
||||
// a soft reminder to guide developer to configure sdkAppId/SDKSecretKey
|
||||
if (SDKAPPID === '' || SDKSECRETKEY === '') {
|
||||
alert(
|
||||
'Please configure your SDKAPPID/SDKSECRETKEY in js/debug/GenerateTestUserSig.js'
|
||||
);
|
||||
}
|
||||
const generator = new LibGenerateTestUserSig(SDKAPPID, SDKSECRETKEY, EXPIRETIME);
|
||||
const userSig = generator.genTestUserSig(userId);
|
||||
return {
|
||||
sdkAppId: SDKAPPID,
|
||||
userSig: userSig
|
||||
};
|
||||
}
|
||||
2
ShengShengBuXi/wwwroot/js/lib-generate-test-usersig.min.js
vendored
Normal file
2
ShengShengBuXi/wwwroot/js/lib-generate-test-usersig.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
243
ShengShengBuXi/wwwroot/test.html
Normal file
243
ShengShengBuXi/wwwroot/test.html
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>WebSocket 音频播放器</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Microsoft YaHei', Arial, sans-serif;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 100vh;
|
||||
margin: 0;
|
||||
background-color: #f5f5f5;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 100%;
|
||||
max-width: 800px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
background-color: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #333;
|
||||
margin-top: 0;
|
||||
margin-bottom: 30px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.status-indicator {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
border-radius: 50%;
|
||||
margin: 20px 0;
|
||||
background-color: #e0e0e0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.status-text {
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.red {
|
||||
background-color: #ff5252;
|
||||
}
|
||||
|
||||
.green {
|
||||
background-color: #4caf50;
|
||||
}
|
||||
|
||||
.yellow {
|
||||
background-color: #FFC107;
|
||||
}
|
||||
|
||||
#status {
|
||||
padding: 10px 15px;
|
||||
border-radius: 4px;
|
||||
background-color: #f0f0f0;
|
||||
margin: 15px 0;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#audioPlayer {
|
||||
width: 100%;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.controls {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
margin-top: 20px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 12px 24px;
|
||||
font-size: 16px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
background-color: #2196F3;
|
||||
color: white;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
button:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
button:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
button:disabled {
|
||||
background-color: #cccccc;
|
||||
transform: none;
|
||||
box-shadow: none;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>WebSocket 音频播放器</h1>
|
||||
|
||||
<div id="statusIndicator" class="status-indicator red">
|
||||
<span class="status-text">未连接</span>
|
||||
</div>
|
||||
|
||||
<div id="status">等待连接...</div>
|
||||
|
||||
<audio id="audioPlayer" controls></audio>
|
||||
|
||||
<div class="controls">
|
||||
<button id="connectBtn">连接WebSocket</button>
|
||||
<button id="clearBtn">清空数据</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const statusDiv = document.getElementById('status');
|
||||
const audioPlayer = document.getElementById('audioPlayer');
|
||||
const connectBtn = document.getElementById('connectBtn');
|
||||
const clearBtn = document.getElementById('clearBtn');
|
||||
const statusIndicator = document.getElementById('statusIndicator');
|
||||
const statusText = statusIndicator.querySelector('.status-text');
|
||||
|
||||
let ws = null;
|
||||
|
||||
// 使用Blob方式处理音频数据
|
||||
let audioBlobs = [];
|
||||
|
||||
function connectWebSocket() {
|
||||
// 清空之前的数据
|
||||
audioBlobs = [];
|
||||
statusDiv.textContent = "正在连接...";
|
||||
statusIndicator.className = "status-indicator yellow";
|
||||
statusText.textContent = "连接中";
|
||||
|
||||
// 创建WebSocket连接
|
||||
ws = new WebSocket("ws://localhost:81/ws");
|
||||
ws.binaryType = "arraybuffer"; // 指定二进制数据类型
|
||||
|
||||
ws.onopen = () => {
|
||||
console.log("WebSocket 已连接");
|
||||
statusDiv.textContent = "已连接,等待音频数据...";
|
||||
connectBtn.textContent = "断开连接";
|
||||
statusIndicator.className = "status-indicator green";
|
||||
statusText.textContent = "已连接";
|
||||
};
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
// 确保我们收到的是ArrayBuffer
|
||||
if (event.data instanceof ArrayBuffer) {
|
||||
// 创建Blob对象
|
||||
const blob = new Blob([event.data], { type: 'audio/ogg; codecs=opus' });
|
||||
audioBlobs.push(blob);
|
||||
|
||||
// 创建包含所有数据的完整Blob
|
||||
const fullBlob = new Blob(audioBlobs, { type: 'audio/ogg; codecs=opus' });
|
||||
|
||||
// 更新状态显示
|
||||
statusDiv.textContent = `接收到音频数据: 共 ${audioBlobs.length} 个数据块`;
|
||||
|
||||
// 更新音频播放源
|
||||
const audioUrl = URL.createObjectURL(fullBlob);
|
||||
|
||||
// 记住当前播放位置
|
||||
const currentTime = audioPlayer.currentTime;
|
||||
const wasPlaying = !audioPlayer.paused;
|
||||
|
||||
audioPlayer.src = audioUrl;
|
||||
|
||||
// 如果正在播放,恢复播放状态和位置
|
||||
if (wasPlaying) {
|
||||
audioPlayer.currentTime = currentTime;
|
||||
audioPlayer.play().catch(e => console.error("播放错误:", e));
|
||||
}
|
||||
} else {
|
||||
console.warn("收到非二进制数据:", event.data);
|
||||
}
|
||||
};
|
||||
|
||||
ws.onclose = () => {
|
||||
console.log("WebSocket 连接关闭");
|
||||
statusDiv.textContent = "连接已关闭";
|
||||
connectBtn.textContent = "连接WebSocket";
|
||||
statusIndicator.className = "status-indicator red";
|
||||
statusText.textContent = "未连接";
|
||||
};
|
||||
|
||||
ws.onerror = (error) => {
|
||||
console.error("WebSocket 错误:", error);
|
||||
statusDiv.textContent = "连接错误";
|
||||
connectBtn.textContent = "重新连接";
|
||||
statusIndicator.className = "status-indicator red";
|
||||
statusText.textContent = "连接错误";
|
||||
};
|
||||
}
|
||||
|
||||
connectBtn.addEventListener('click', () => {
|
||||
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||
ws.close();
|
||||
} else {
|
||||
connectWebSocket();
|
||||
}
|
||||
});
|
||||
|
||||
clearBtn.addEventListener('click', () => {
|
||||
audioBlobs = [];
|
||||
audioPlayer.src = "";
|
||||
statusDiv.textContent = "数据已清空";
|
||||
});
|
||||
|
||||
// 初始连接
|
||||
connectWebSocket();
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
187
ShengShengBuXi/wwwroot/zhibo.html
Normal file
187
ShengShengBuXi/wwwroot/zhibo.html
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>录音</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Microsoft YaHei', Arial, sans-serif;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 30px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.status-indicator {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
border-radius: 50%;
|
||||
margin: 20px 0 40px;
|
||||
background-color: #e0e0e0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.status-text {
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.red {
|
||||
background-color: #ff5252;
|
||||
}
|
||||
|
||||
.green {
|
||||
background-color: #4caf50;
|
||||
}
|
||||
|
||||
.btn-group {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 12px 24px;
|
||||
font-size: 16px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
background-color: #2196F3;
|
||||
color: white;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
button:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
button:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
#start {
|
||||
background-color: #4CAF50;
|
||||
}
|
||||
|
||||
#stop {
|
||||
background-color: #f44336;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1 class="title">实时音频录制</h1>
|
||||
|
||||
<div id="statusIndicator" class="status-indicator red">
|
||||
<span class="status-text">未连接</span>
|
||||
</div>
|
||||
|
||||
<div class="btn-group">
|
||||
<button id="start" onclick="enterRoom()">启动直播</button>
|
||||
<button id="stop" onclick="leaveRoom()">关闭直播</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js"></script>
|
||||
<!-- <script src="https://www.unpkg.com/trtc-sdk-v5@5.9.1/trtc.js"></script> -->
|
||||
<script src='https://web.sdk.qcloud.com/trtc/webrtc/v5/dist/trtc.js'></script>
|
||||
<script src="/js/lib-generate-test-usersig.min.js"></script>
|
||||
<script src="/js/generateTestUserSig.js"></script>
|
||||
<script>
|
||||
/* eslint-disable*/
|
||||
const sdkAppId = 1600079538;
|
||||
const sdkSecretKey = "df2427757c0ec29ae8ca45611ddb70381144d55338e5ac73c2da27a9c32729f6";
|
||||
let userId = "主播";
|
||||
let roomId = 8888;
|
||||
|
||||
const statusIndicator = document.getElementById('statusIndicator');
|
||||
const statusText = statusIndicator.querySelector('.status-text');
|
||||
|
||||
let trtc = TRTC.create();
|
||||
|
||||
async function enterRoom() {
|
||||
try {
|
||||
trtc = TRTC.create();
|
||||
// 更新状态指示器为过渡状态
|
||||
statusIndicator.style.backgroundColor = '#FFC107';
|
||||
statusText.textContent = '连接中...';
|
||||
|
||||
// 生成用户签名
|
||||
const { userSig } = genTestUserSig({ sdkAppId, userId, sdkSecretKey });
|
||||
|
||||
// 进入房间
|
||||
await trtc.enterRoom({ sdkAppId, userId, userSig, roomId: roomId });
|
||||
|
||||
// 开启本地音频
|
||||
await trtc.startLocalAudio();
|
||||
|
||||
// 更新状态指示器为绿色(已连接)
|
||||
statusIndicator.className = 'status-indicator green';
|
||||
statusText.textContent = '直播中';
|
||||
|
||||
// 禁用启动按钮
|
||||
document.getElementById('start').disabled = true;
|
||||
|
||||
} catch (error) {
|
||||
console.error('进入房间失败:', error);
|
||||
statusIndicator.className = 'status-indicator red';
|
||||
statusText.textContent = '连接失败';
|
||||
}
|
||||
}
|
||||
|
||||
async function leaveRoom() {
|
||||
try {
|
||||
await trtc.exitRoom();
|
||||
trtc.destroy();
|
||||
// 更新状态指示器为红色(已断开)
|
||||
statusIndicator.className = 'status-indicator red';
|
||||
statusText.textContent = '未连接';
|
||||
|
||||
// 启用启动按钮
|
||||
document.getElementById('start').disabled = false;
|
||||
|
||||
} catch (error) {
|
||||
console.error('离开房间失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
$(function () {
|
||||
// 初始化时设置状态
|
||||
statusIndicator.className = 'status-indicator red';
|
||||
statusText.textContent = '未连接';
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
187
ShengShengBuXi/wwwroot/zhibo1.html
Normal file
187
ShengShengBuXi/wwwroot/zhibo1.html
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>录音</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Microsoft YaHei', Arial, sans-serif;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 30px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.status-indicator {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
border-radius: 50%;
|
||||
margin: 20px 0 40px;
|
||||
background-color: #e0e0e0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.status-text {
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.red {
|
||||
background-color: #ff5252;
|
||||
}
|
||||
|
||||
.green {
|
||||
background-color: #4caf50;
|
||||
}
|
||||
|
||||
.btn-group {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 12px 24px;
|
||||
font-size: 16px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
background-color: #2196F3;
|
||||
color: white;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
button:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
button:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
#start {
|
||||
background-color: #4CAF50;
|
||||
}
|
||||
|
||||
#stop {
|
||||
background-color: #f44336;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1 class="title">实时音频录制</h1>
|
||||
|
||||
<div id="statusIndicator" class="status-indicator red">
|
||||
<span class="status-text">未连接</span>
|
||||
</div>
|
||||
|
||||
<div class="btn-group">
|
||||
<button id="start" onclick="enterRoom()">启动直播</button>
|
||||
<button id="stop" onclick="leaveRoom()">关闭直播</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js"></script>
|
||||
<!-- <script src="https://www.unpkg.com/trtc-sdk-v5@5.9.1/trtc.js"></script> -->
|
||||
<script src='https://web.sdk.qcloud.com/trtc/webrtc/v5/dist/trtc.js'></script>
|
||||
<script src="/js/lib-generate-test-usersig.min.js"></script>
|
||||
<script src="/js/generateTestUserSig.js"></script>
|
||||
<script>
|
||||
|
||||
const statusIndicator = document.getElementById('statusIndicator');
|
||||
const statusText = statusIndicator.querySelector('.status-text');
|
||||
/* eslint-disable*/
|
||||
const sdkAppId = 1600079538;
|
||||
const sdkSecretKey = "df2427757c0ec29ae8ca45611ddb70381144d55338e5ac73c2da27a9c32729f6";
|
||||
let userId = "监听者:" + Math.random().toString(36).substring(2, 15);
|
||||
let roomId = 8888;
|
||||
|
||||
let trtc = TRTC.create();
|
||||
|
||||
async function enterRoom() {
|
||||
try {
|
||||
trtc = TRTC.create();
|
||||
// 更新状态指示器为过渡状态
|
||||
statusIndicator.style.backgroundColor = '#FFC107';
|
||||
statusText.textContent = '连接中...';
|
||||
|
||||
// 生成用户签名
|
||||
const { userSig } = genTestUserSig({ sdkAppId, userId, sdkSecretKey });
|
||||
|
||||
// 进入房间
|
||||
await trtc.enterRoom({ sdkAppId, userId, userSig, roomId: roomId });
|
||||
|
||||
// // 开启本地音频
|
||||
// await trtc.startLocalAudio();
|
||||
|
||||
// 更新状态指示器为绿色(已连接)
|
||||
statusIndicator.className = 'status-indicator green';
|
||||
statusText.textContent = '通话中';
|
||||
|
||||
// 禁用启动按钮
|
||||
document.getElementById('start').disabled = true;
|
||||
|
||||
} catch (error) {
|
||||
console.error('进入房间失败:', error);
|
||||
statusIndicator.className = 'status-indicator red';
|
||||
statusText.textContent = '连接失败';
|
||||
}
|
||||
}
|
||||
|
||||
async function leaveRoom() {
|
||||
try {
|
||||
await trtc.exitRoom();
|
||||
trtc.destroy();
|
||||
// 更新状态指示器为红色(已断开)
|
||||
statusIndicator.className = 'status-indicator red';
|
||||
statusText.textContent = '未连接';
|
||||
|
||||
// 启用启动按钮
|
||||
document.getElementById('start').disabled = false;
|
||||
|
||||
} catch (error) {
|
||||
console.error('离开房间失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
$(function () {
|
||||
// 初始化时设置状态
|
||||
statusIndicator.className = 'status-indicator red';
|
||||
statusText.textContent = '未连接';
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Loading…
Reference in New Issue
Block a user