我正在使用 numpy 编写一些代码,其中涉及向量、矩阵以及从向量到矩阵的函数。特别是,我有兴趣在许多向量和许多矩阵上运行这些函数,利用 numpy 的向量化功能来大幅加速 for 循环。
我注意到的是,放置这些“批量”维度的方便位置在我使用的内置 numpy 和 matplotlib 函数之间并不一致,并且对于思考此类事情相对较新,我不知道如何解释为什么是这种情况,以及它会如何影响我编写代码的方式。
例如,如果我想将一个2D向量映射到一个矩阵,如
def f(x):
return np.array([[np.sin(x[0]), np.cos(x[1]) ],
[np.cos(x[1]), np.cos(x[0]) + np.sin(x[1])]])
那么这个函数最方便的就是把批量尺寸放在最后。如果输入的形状为 (2, ...),则输出的形状为 (2, 2, ....),以便批量维度的位置保持一致,语法非常易读且直观,符合我的需求表现。由于 x 将被解释为欧几里得空间中的点的集合,因此能够仅使用
plt.scatter(*x)
在 matplotlib 之类的东西中绘制点也非常方便。
另一方面,如果我想对这批矩阵进行对角化,或者将它们与 np.matmul 等相乘,我需要将轴交换到最终的矩阵,因为这些函数都期望批量维度在前面。
我跟踪这个绝对没有问题。我真正想知道的关键是,我跳过的(小)圈子是否可以与 get f(x) 一起方便地与 numpy 函数一起工作,这是否表明我正在做一些“错误”或“在我的类方法的实际界面中,对于新用户来说不直观,尽管作为调试它们的人,这些函数本身对我来说看起来更干净。
问题似乎源于音频流与视频流的分离,并且音频流可能无法正确添加到peerConnection
function createPeerConnection() {
peerConnection = new RTCPeerConnection();
// Handle incoming remote track
peerConnection.ontrack = (event) => {
if (event.streams && event.streams[0]) {
remoteVideo.srcObject = event.streams[0];
console.log("Received remote stream:", event.streams[0]);
} else {
console.warn("No streams in ontrack event.");
}
remoteVideo.classList.add("remote-video-style");
};
// Handle ICE candidates
peerConnection.onicecandidate = (event) => {
if (event.candidate) {
socket.emit('candidate', { candidate: event.candidate });
}
};
// Add tracks from both audio and video streams if available
if (audioStream) {
audioStream.getTracks().forEach(track => peerConnection.addTrack(track, audioStream));
}
if (localStream) {
localStream.getTracks().forEach(track => peerConnection.addTrack(track, localStream));
}
}
2-当独立调用 startCamera 和 initAudioStream 时,每个都可能尝试创建并发送报价。这可能会导致信号问题,因为一个可能会覆盖另一个
还更新 startCamera 和 initAudioStream 来管理信令 同步
async function startCamera() {
try {
localStream = await navigator.mediaDevices.getUserMedia({ video: true });
cameraIcon.src = cameraIcon.getAttribute('data-show');
isCameraOn = true;
if (!peerConnection) {
createPeerConnection();
}
// Add video track to peer connection
localStream.getTracks().forEach(track => peerConnection.addTrack(track, localStream));
// Check if audio stream is also ready to send an offer
if (audioStream) {
sendOffer();
}
} catch (error) {
console.error("Error accessing camera:", error);
}
}
async function initAudioStream() {
try {
audioStream = await navigator.mediaDevices.getUserMedia({ audio: true });
audioStream.getAudioTracks()[0].enabled = !isMuted;
console.log("Audio stream initialized:", audioStream);
if (!peerConnection) {
createPeerConnection();
}
// Add audio track to peer connection
audioStream.getTracks().forEach(track => peerConnection.addTrack(track, audioStream));
// Check if video stream is also ready to send an offer
if (localStream) {
sendOffer();
}
} catch (error) {
console.error("Error accessing microphone:", error);
}
}
定义 sendOffer 函数,仅在音频和视频流都可用时创建和发送报价:
async function sendOffer() {
try {
const offer = await peerConnection.createOffer();
await peerConnection.setLocalDescription(offer);
socket.emit('offer', { type: 'offer', sdp: offer.sdp });
} catch (error) {
console.error("Error creating and sending offer:", error);
}
}
修改音频静音套接字侦听器以正确启用/禁用远程音轨:
socket.on("audio-mute", (data) => {
if (remoteVideo.srcObject && remoteVideo.srcObject.getAudioTracks().length > 0) {
remoteVideo.srcObject.getAudioTracks()[0].enabled = !data.isMuted;
console.log("Remote audio muted:", data.isMuted);
} else {
console.warn("Remote audio track not found or not initialized.");
}
});