win10系统禁用音频服务器,win10未安装音频设备怎么办|win10声音找不到音频设备解决方法...

win10旗舰版系统没有声音,喇叭小红叉,打开播放设备控制面板显示未安装音频设备。出现未安装音频设备的原因可能是windows audio音频服务被禁用,没有正确安装声卡驱动导致检测不到声卡,以及声卡出现了问题。下面小编跟大家介绍win10系统找不到音频设备的解决方法。

8500b3e773015cab020b81edb15bc413.png

一、针对Windows Audio服务被禁用的解决方法

1、同时按“Windows 徽标键+R键”,打开运行框;

79c21c26856dae17ebe7e67e9bed24c4.png

2、输入“services.msc”按回车,快速调出“服务”;

ed306f3b10a7f59fab1bc4457784fa01.png

3、找到“Windows Audio”服务,双击;

d7189bf98f4993a986bb0cca8d668a1d.png

4、查看“Windows Audio”服务状态,若服务状态为停止状态,点击“启动”启动服务,并将启动类型设置成“自动”。

32b697acd6b236da7a3dcad3e9d6bd1d.png

二、未正确安装声卡驱动,导致未正常检测到声卡

1、右键开始--设备管理器,查看是否有与音频相关的其他设备Audio。

72051411af0d9917eeb7b2ed8d56b515.png

2、若出现未正确识别的设备,请重新安装声卡驱动。

三、电脑禁用声卡的情况

1、部分联想电脑可在Bios中禁用声卡,可以进入Bios,依次找到“Devices”-“Audio Setup”;

d7101758511ed6283e016ac41c0a3fce.png

2、在“Audio Setup”上点击Enter按键,查看“Onboard Audio Controller”选项的状态,是否为“Disabled”,若是此状态,请在此选项敲击回车(Enter)按键,选择“Enabled”。

18ff1c664fe3e520303f50faa85f5736.png

win10系统未安装音频设备的解决方法就是这样子,有遇到这个问题的用户可以参考上面的方法来解决。

package com.example.demoapplication; import android.Manifest; // 录音权限相关 import android.content.pm.PackageManager; // 权限检查相关 import android.media.AudioFormat; // 音频格式定义 import android.media.AudioRecord; // 音频录制功能 import android.media.MediaRecorder; // 媒体录制配置 import android.os.Bundle; // Activity生命周期数据 import android.os.Handler; // 线程通信机制 import android.os.Looper; // 主线程消息循环 import android.os.Message; // 消息传递对象 import android.widget.Button; // UI按钮控件 import android.widget.Toast; // 短时提示信息 import androidx.annotation.NonNull; // 非空注解 import androidx.appcompat.app.AppCompatActivity; // 兼容Activity基类 import androidx.core.app.ActivityCompat; // 动态权限请求 import androidx.core.content.ContextCompat; // 权限状态查询 import java.io.BufferedReader; // 文本流读取 import java.io.BufferedWriter; // 文本流写入 import java.io.IOException; // IO异常处理 import java.io.InputStreamReader; // 字节转字符流 import java.io.OutputStreamWriter; // 字节转字符流 import java.net.ServerSocket; // 服务端监听套接字 import java.net.Socket; // 客户端连接套接字 import java.util.concurrent.ExecutorService; // 线程池管理 import java.util.concurrent.Executors; // 线程池工厂 import java.util.concurrent.ScheduledExecutorService; // 定时任务调度 import java.util.concurrent.TimeUnit; // 时间单位定义 import android.util.Base64; // Base64编码 import org.json.JSONException; import org.json.JSONObject; // JSON对象 public class MainActivity extends AppCompatActivity { private Button startRecordButton; // 开始录音按钮 private Button stopRecordButton; // 停止录音按钮 private Button uploadButton; // 上传文件按钮 private AudioRecord audioRecord; // 音频录制对象 private static final int SAMPLE_RATE = 44100; // 采样率:44.1kHz private static final int BUFFER_SIZE; // 缓冲区大小 static { // 使用更安全的缓冲区大小计算方式 int minBufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT); // 确保缓冲区大小是帧大小的整数倍(2通道*2字节) BUFFER_SIZE = ((minBufferSize / (2 * 2)) + 1) * (2 * 2); } private ScheduledExecutorService scheduler; // 录音定时器 private boolean isRecording = false; // 录音状态标志 private static final int PERMISSION_REQUEST_CODE = 1; // 权限请求码 private final ExecutorService executorService = Executors.newCachedThreadPool(); // 通用线程池 private ServerSocket serverSocket; // TCP服务端Socket private volatile boolean isServerRunning = true; // 服务运行状态 private Socket clientSocket; // 当前客户端连接 // 主线程消息处理器 private Handler handler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(@NonNull Message msg) { switch (msg.what) { case 0x11: // 客户端连接成功 Toast.makeText(MainActivity.this, "客户端已连接", Toast.LENGTH_SHORT).show(); break; case 0x12: // 数据接收完成 Toast.makeText(MainActivity.this, "开始录音", Toast.LENGTH_SHORT).show(); break; case 0x13: // 上传错误 Toast.makeText(MainActivity.this, "录音数据已发送", Toast.LENGTH_SHORT).show(); break; case 0x14: // 自定义消息类型,用于停止录音提示 Toast.makeText(MainActivity.this, "停止录音", Toast.LENGTH_SHORT).show(); break; case 0x15: // 接收到控制指令 Toast.makeText(MainActivity.this, "收到控制指令:" + msg.obj.toString(), Toast.LENGTH_SHORT).show(); break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initViews(); // 初始化视图组件 checkPermissions(); // 检查权限状态 setupClickListeners(); // 设置点击事件监听 startServer(30000); // 启动TCP服务器,监听30000端口 } /** * 视图初始化方法 * 绑定布局中的UI组件并设置初始状态 */ private void initViews() { startRecordButton = findViewById(R.id.startRecordButton); stopRecordButton = findViewById(R.id.stopRecordButton); uploadButton = findViewById(R.id.uploadButton); stopRecordButton.setEnabled(false); // 初始禁用停止按钮 uploadButton.setEnabled(false); // 初始禁用上传按钮 } /** * 权限检查方法 * 如果授予录音权限则发起请求 */ private void checkPermissions() { if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, PERMISSION_REQUEST_CODE); } } /** * 按钮点击事件绑定 * 设置各按钮的响应逻辑 */ private void setupClickListeners() { startRecordButton.setOnClickListener(v -> startRecording()); // 开始录音 stopRecordButton.setOnClickListener(v -> stopRecording()); // 停止录音 uploadButton.setOnClickListener(v -> uploadRecording()); // 上传录音 } /** * 开始录音方法 * 初始化AudioRecord并启动录制 */ private void startRecording() { // 添加状态检查和异常处理 if (isRecording || audioRecord != null) { return; // 防止重复启动 } try { audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, BUFFER_SIZE); if (audioRecord.getState() != AudioRecord.STATE_INITIALIZED) { throw new IllegalStateException("AudioRecord初始化失败"); } audioRecord.startRecording(); isRecording = true; startRecordButton.setEnabled(false); stopRecordButton.setEnabled(true); uploadButton.setEnabled(false); // 创建定时任务发送音频数据 scheduler = Executors.newSingleThreadScheduledExecutor(); scheduler.scheduleAtFixedRate(this::uploadAudioData, 0, 160, TimeUnit.MILLISECONDS); handler.sendEmptyMessage(0x12); // 发送开始录音的消息 // 添加发送 { "type": "startRecorder", "data": null } 的逻辑 if (clientSocket != null && !clientSocket.isClosed()) { try { JSONObject startPacket = new JSONObject(); startPacket.put("type", "startRecorder"); startPacket.put("data", JSONObject.NULL); // 设置 data 为 null BufferedWriter writer = new BufferedWriter( new OutputStreamWriter(clientSocket.getOutputStream(), "UTF-8")); writer.write(startPacket.toString()); writer.write("\n\n"); // 双换行作为结束标识 writer.flush(); } catch (IOException | JSONException e) { e.printStackTrace(); Message msg = handler.obtainMessage(0x13, e.getMessage()); handler.sendMessage(msg); } } else { Toast.makeText(this, "客户端连接", Toast.LENGTH_SHORT).show(); } } catch (Exception e) { e.printStackTrace(); Toast.makeText(this, "录音启动失败: " + e.getMessage(), Toast.LENGTH_LONG).show(); releaseAudioResources(); } } /** * 停止录音方法 * 释放录音资源并清理状态 */ private void stopRecording() { isRecording = false; releaseAudioResources(); stopRecordButton.setEnabled(false); uploadButton.setEnabled(true); handler.sendEmptyMessage(0x14); // 发送停止录音的消息 // 添加发送 { "type": "stopRecor", "data": null } 的逻辑 if (clientSocket != null && !clientSocket.isClosed()) { try { JSONObject stopPacket = new JSONObject(); stopPacket.put("type", "stopRecor"); stopPacket.put("data", JSONObject.NULL); // 设置 data 为 null BufferedWriter writer = new BufferedWriter( new OutputStreamWriter(clientSocket.getOutputStream(), "UTF-8")); writer.write(stopPacket.toString()); writer.write("\n\n"); // 双换行作为结束标识 writer.flush(); } catch (IOException | JSONException e) { e.printStackTrace(); Message msg = handler.obtainMessage(0x13, e.getMessage()); handler.sendMessage(msg); } } } /** * 释放音频资源 */ private void releaseAudioResources() { if (audioRecord != null) { try { audioRecord.stop(); } catch (IllegalStateException e) { // 忽略可能的非法状态异常 } try { audioRecord.release(); } finally { audioRecord = null; } } if (scheduler != null) { try { scheduler.shutdownNow(); } finally { scheduler = null; } } } /** * 实时上传音频数据 * 将当前缓冲区数据通过Socket发送给客户端,并添加Base64编码的JSON格式数据 */ private void uploadAudioData() { if (!isRecording || clientSocket == null || clientSocket.isClosed()) return; byte[] buffer = new byte[BUFFER_SIZE]; try { int bytesRead = audioRecord.read(buffer, 0, BUFFER_SIZE); if (bytesRead > 0) { // 使用固定大小缓冲区确保完整性 byte[] validData = new byte[bytesRead]; System.arraycopy(buffer, 0, validData, 0, bytesRead); // 将音频数据转换为Base64编码字符串 String base64Data = Base64.encodeToString(validData, Base64.DEFAULT); // 构建JSON格式字符串 JSONObject json = new JSONObject(); json.put("type", "recording"); json.put("data", base64Data); // 获取输出流并发送数据 BufferedWriter writer = new BufferedWriter( new OutputStreamWriter(clientSocket.getOutputStream(), "UTF-8")); writer.write(json.toString()); writer.write("\n\n"); // 添加双换行作为结束标识 writer.flush(); handler.sendEmptyMessage(0x13); // 发送录音数据的消息 } } catch (IOException | JSONException e) { Message msg = handler.obtainMessage(0x13, e.getMessage()); handler.sendMessage(msg); } catch (Exception e) { e.printStackTrace(); Message msg = handler.obtainMessage(0x13, "音频读取异常: " + e.getMessage()); handler.sendMessage(msg); } } /** * 上传完整录音文件(当前使用) * 提示该模式下为实时传输无需手动上传 */ private void uploadRecording() { // 可选:上传录音完整文件逻辑,如有需要可添加实现 Toast.makeText(this, "该模式下无需上传文件,已实时发送", Toast.LENGTH_SHORT).show(); } /** * 启动TCP服务器 * 在指定端口监听客户端连接 * * @param port 监听端口号 */ private void startServer(int port) { executorService.execute(() -> { try { serverSocket = new ServerSocket(port); while (isServerRunning) { Socket socket = serverSocket.accept(); clientSocket = socket; handler.sendEmptyMessage(0x11); // 发送客户端连接成功的消息 // 启动双向通信处理 executorService.execute(() -> startCommunication(socket)); } } catch (IOException e) { e.printStackTrace(); runOnUiThread(() -> Toast.makeText(MainActivity.this, "服务器启动失败: " + e.getMessage(), Toast.LENGTH_LONG).show()); } }); } /** * 启动双向通信 * 处理客户端的连接和数据交互 * * @param socket 客户端Socket连接 */ private void startCommunication(Socket socket) { try { BufferedReader reader = new BufferedReader( new InputStreamReader(socket.getInputStream(), "UTF-8")); StringBuilder packetBuilder = new StringBuilder(); int c; while ((c = reader.read()) != -1) { char ch = (char) c; packetBuilder.append(ch); // 检测到连续两个换行符,表示一个完整的数据包结束 if (packetBuilder.length() >= 2 && packetBuilder.charAt(packetBuilder.length() - 2) == '\n' && packetBuilder.charAt(packetBuilder.length() - 1) == '\n') { String packet = packetBuilder.toString().trim(); // 去除首尾空白字符 packetBuilder.setLength(0); // 清空构建器 if (!packet.isEmpty()) { try { JSONObject jsonObject = new JSONObject(packet); handleReceivedPacket(jsonObject); // 处理接收到的数据包 } catch (JSONException e) { e.printStackTrace(); } } } } } catch (IOException e) { e.printStackTrace(); runOnUiThread(() -> Toast.makeText(MainActivity.this, "通信中断: " + e.getMessage(), Toast.LENGTH_SHORT).show()); } finally { try { socket.close(); } catch (IOException ignored) {} // 重置客户端socket if (socket == clientSocket) { clientSocket = null; } } } /** * 处理接收到的数据包 * 根据数据包类型执行相应操作 * * @param jsonObject 接收到的JSON数据包 */ private void handleReceivedPacket(JSONObject jsonObject) { try { String type = jsonObject.getString("type"); Object data = jsonObject.opt("data"); // 发送消息到主线程进行Toast显示 Message msg = handler.obtainMessage(0x15, type + ": " + data.toString()); handler.sendMessage(msg); // 根据不同类型执行不同操作 switch (type) { case "start_recording": if (!isRecording) { runOnUiThread(this::startRecording); } break; case "stop_recording": if (isRecording) { runOnUiThread(this::stopRecording); } break; case "ping": sendResponse("pong"); // 发送pong响应 break; // 可以添加更多类型的处理 } } catch (JSONException e) { e.printStackTrace(); } } /** * 发送响应数据包 * 使用统一的JSON格式并通过双换行结尾 * * @param responseType 响应类型 */ private void sendResponse(String responseType) { if (clientSocket == null || clientSocket.isClosed()) return; try { JSONObject response = new JSONObject(); response.put("type", responseType); response.put("data", ""); BufferedWriter writer = new BufferedWriter( new OutputStreamWriter(clientSocket.getOutputStream(), "UTF-8")); writer.write(response.toString()); writer.write("\n\n"); writer.flush(); } catch (JSONException | IOException e) { e.printStackTrace(); } } /** * 发送特定类型的数据包 * 用于发送控制指令或其他消息 * * @param type 数据包类型 * @param data 数据内容 */ private void sendDataPacket(String type, Object data) { if (clientSocket == null || clientSocket.isClosed()) return; try { JSONObject packet = new JSONObject(); packet.put("type", type); packet.put("data", data); BufferedWriter writer = new BufferedWriter( new OutputStreamWriter(clientSocket.getOutputStream(), "UTF-8")); writer.write(packet.toString()); writer.write("\n\n"); writer.flush(); } catch (JSONException | IOException e) { e.printStackTrace(); } } @Override protected void onDestroy() { super.onDestroy(); isServerRunning = false; try { if (serverSocket != null) serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } executorService.shutdownNow(); if (audioRecord != null) { audioRecord.release(); audioRecord = null; } if (scheduler != null) { scheduler.shutdownNow(); } try { if (clientSocket != null && !clientSocket.isClosed()) clientSocket.close(); } catch (IOException e) { e.printStackTrace(); } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (requestCode == PERMISSION_REQUEST_CODE) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { Toast.makeText(this, "权限已授予", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "录音权限被拒绝", Toast.LENGTH_SHORT).show(); } } super.onRequestPermissionsResult(requestCode, permissions, grantResults); } } 生成能接收音频并且USB插拔记录python脚本
最新发布
06-26
<think>我们有一个Android应用,它通过TCP服务器发送实时音频数据(以JSON格式,包含Base64编码的音频数据)和接收控制指令。现在需要编写一个Python脚本,该脚本能够:1.连接到Android设备的TCP服务器(假设设备IP和端口已知)。2.接收音频数据包,解码Base64并保存为PCM文件(或实时播放)。3.同时,该脚本还需要能够发送控制指令(如开始录音、停止录音)。4.另外,要求记录USB插拔事件(在Windows上,可以使用pywin32或wmi库来监控设备事件)。但是,由于问题中要求生成一个能接收音频并且记录USB插拔的Python脚本,我们需要注意:-接收音频和监控USB是两个相对独立的功能,我们可以使用多线程或异步方式来实现。-对于USB插拔记录,在Windows上可以使用WMI模块来监听Win32_DeviceChangeEvent事件。我们将分为两个部分:1.TCP客户端:用于连接Android应用,发送控制指令,接收音频数据并保存。2.USB监控:使用WMI监听USB设备插拔事件,并记录到日志。由于WMI是Windows特有的,所以这个脚本只能在Windows上运行。步骤:1.创建TCP客户端线程,连接服务器,接收数据并处理。2.创建WMI事件监听线程,监听USB插拔事件。注意:由于我们同时需要处理网络事件和WMI事件,我们可以使用两个线程分别运行。代码结构:-主程序启动两个线程:一个用于TCP通信,一个用于USB监控。-TCP客户端线程:连接服务器循环接收数据(注意:数据包以两个换行符结束)解析JSON,如果是音频数据,则解码Base64并写入文件(或播放)同时,可以提供一个简单的命令行界面来发送控制指令(例如,按回车发送开始或停止指令)-USB监控线程:使用WMI监听Win32_DeviceChangeEvent,根据事件类型记录插拔事件。由于我们可能需要从命令行发送指令,所以可以在TCP客户端线程中增加一个输入循环(使用另一个线程或使用非阻塞输入)。但是,为了简化,我们可以将TCP客户端的发送指令部分放在主线程中,而接收放在子线程中。同时,我们也可以在主线程中监听用户输入。另一种方案:使用三个线程(接收TCP数据、发送TCP指令、监控USB),主线程用于协调。这里我们采用:-主线程:启动其他线程,并提供一个简单的命令行菜单供用户发送指令。-TCP接收线程:专门接收数据并处理。-USB监控线程:监听USB事件。注意:由于网络接收是阻塞的,我们需要在TCP接收线程中循环接收数据。同时,我们使用一个标志来停止线程。我们将编写以下代码:1.导入必要的库:socket,threading,json,base64,time,wmi,queue(用于线程间通信,但这里我们简单打印日志)2.定义TCPClient类,包含连接、接收循环、发送方法等。3.定义USBMontior类,用于监听USB事件。4.主函数:创建TCPClient实例并启动接收线程,创建USBMontior并启动线程,然后主线程提供命令行菜单。注意:由于我们可能需要同时处理多个任务,且命令行输入是阻塞的,所以我们将接收和USB监控放在后台线程,主线程用于发送命令。由于问题中要求记录USB插拔,我们将USB事件打印到控制台并写入日志文件。另外,音频数据接收后,我们可以将其保存为PCM文件(如audio.pcm),然后可以使用工具播放(如Audacity,导入原始数据,格式为16位PCM,单声道,44100Hz)。实现细节:-TCP数据包以两个换行符结束,所以我们需要在接收数据时缓冲直到遇到两个连续的换行符。代码示例:注意:由于WMI监听会阻塞,所以我们在单独的线程中运行。我们使用一个全局事件来控制程序退出(如KeyboardInterrupt)。由于代码较长,我们将分块编写。步骤:1.导入模块2.定义TCPClient3.定义USBMontior4.主程序考虑到代码的复杂性,我们将尽量保持简洁。注意:WMI事件监听在Windows上需要管理员权限。下面开始编写代码。</think>以下是一个完整的Python脚本,用于接收Android设备发送的音频数据并记录USB插拔事件。该脚本包含TCP客户端、音频数据处理和USB设备监控功能: ```python import socket import threading import json import base64 import time import logging from datetime import datetime import subprocess import sys import wave # 配置日志记录 logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler('audio_usb_monitor.log'), logging.StreamHandler(sys.stdout) ] ) class AudioReceiver: def __init__(self, host, port): self.host = host self.port = port self.client_socket = None self.running = False self.audio_file = None self.wave_file = None def connect(self): """连接到Android TCP服务器""" try: self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.client_socket.connect((self.host, self.port)) logging.info(f"已连接到服务器 {self.host}:{self.port}") return True except Exception as e: logging.error(f"连接失败: {str(e)}") return False def start_recording(self, filename="audio_output.pcm"): """开始接收和保存音频数据""" self.running = True self.audio_file = open(filename, 'wb') # 创建WAV文件 wav_filename = filename.replace('.pcm', '.wav') self.wave_file = wave.open(wav_filename, 'wb') self.wave_file.setnchannels(1) # 单声道 self.wave_file.setsampwidth(2) # 16位样本 self.wave_file.setframerate(44100) # 44.1kHz采样率 # 启动接收线程 threading.Thread(target=self._receive_data, daemon=True).start() def _receive_data(self): """接收和处理音频数据""" buffer = b"" while self.running: try: data = self.client_socket.recv(4096) if not data: logging.warning("服务器断开连接") break buffer += data # 查双换行符作为数据包结束标记 while b"\n\n" in buffer: packet, buffer = buffer.split(b"\n\n", 1) self._process_packet(packet.decode('utf-8')) except Exception as e: logging.error(f"接收数据错误: {str(e)}") break self.stop_recording() def _process_packet(self, packet): """处理接收到的数据包""" try: data = json.loads(packet) packet_type = data.get("type") if packet_type == "recording": # 解码Base64音频数据 audio_data = base64.b64decode(data["data"]) # 保存原始PCM数据 self.audio_file.write(audio_data) self.audio_file.flush() # 写入WAV文件 self.wave_file.writeframes(audio_data) logging.info(f"收到音频数据: {len(audio_data)}字节") elif packet_type == "startRecorder": logging.info("收到开始录音指令") elif packet_type == "stopRecor": logging.info("收到停止录音指令") self.stop_recording() except Exception as e: logging.error(f"处理数据包错误: {str(e)}") def stop_recording(self): """停止接收并关闭文件""" if self.running: self.running = False if self.audio_file: self.audio_file.close() self.audio_file = None if self.wave_file: self.wave_file.close() self.wave_file = None logging.info("音频接收已停止") def send_command(self, command_type): """发送控制命令到Android设备""" if not self.client_socket: logging.warning("连接到服务器") return try: command = json.dumps({ "type": command_type, "data": None }) + "\n\n" self.client_socket.sendall(command.encode('utf-8')) logging.info(f"已发送命令: {command_type}") except Exception as e: logging.error(f"发送命令失败: {str(e)}") def close(self): """关闭连接""" self.stop_recording() if self.client_socket: self.client_socket.close() self.client_socket = None logging.info("连接已关闭") class USBMonitor: def __init__(self): self.running = False self.last_state = self._get_usb_devices() def _get_usb_devices(self): """获取当前连接的USB设备列表(Linux/MacOS)""" try: result = subprocess.check_output(["lsusb"]).decode('utf-8') return [line.strip() for line in result.split('\n') if line] except: try: # 尝试MacOS系统命令 result = subprocess.check_output(["system_profiler", "SPUSBDataType"]).decode('utf-8') return [line.strip() for line in result.split('\n') if "Product ID" in line] except: logging.error("不支持的操作系统,无法获取USB设备") return [] def start_monitoring(self): """开始监控USB设备变化""" self.running = True threading.Thread(target=self._monitor_loop, daemon=True).start() def _monitor_loop(self): """USB监控循环""" logging.info("开始监控USB设备...") while self.running: current_state = self._get_usb_devices() # 检测新设备 new_devices = [dev for dev in current_state if dev not in self.last_state] for dev in new_devices: logging.info(f"USB设备插入: {dev}") self._log_event("INSERT", dev) # 检测移除设备 removed_devices = [dev for dev in self.last_state if dev not in current_state] for dev in removed_devices: logging.info(f"USB设备拔出: {dev}") self._log_event("REMOVE", dev) self.last_state = current_state time.sleep(1) # 每秒检查一次 def _log_event(self, event_type, device_info): """记录USB事件到日志文件""" with open("usb_events.log", "a") as f: timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") f.write(f"{timestamp} - {event_type} - {device_info}\n") def stop_monitoring(self): """停止USB监控""" self.running = False logging.info("USB监控已停止") def main(): # 配置服务器信息 SERVER_IP = "192.168.1.100" # 替换为Android设备的IP地址 SERVER_PORT = 30000 # 创建音频接收器 audio_receiver = AudioReceiver(SERVER_IP, SERVER_PORT) # 创建USB监控器 usb_monitor = USBMonitor() if audio_receiver.connect(): # 启动USB监控 usb_monitor.start_monitoring() # 启动音频接收 audio_receiver.start_recording() try: # 主循环 while True: print("\n===== 控制菜单 =====") print("1. 发送开始录音指令") print("2. 发送停止录音指令") print("3. 退出程序") choice = input("请选择操作: ") if choice == "1": audio_receiver.send_command("start_recording") elif choice == "2": audio_receiver.send_command("stop_recording") elif choice == "3": break else: print("无效选择,请重新输入") time.sleep(0.5) except KeyboardInterrupt: pass finally: # 清理资源 audio_receiver.close() usb_monitor.stop_monitoring() logging.info("程序已退出") if __name__ == "__main__": main() ``` ### 代码功能说明 1. **AudioReceiver类**: - 负责与Android设备建立TCP连接 - 接收JSON格式的音频数据包(Base64编码) - 解码音频数据并保存为PCM和WAV格式文件 - 处理控制指令(开始/停止录音) - 支持发送控制命令到Android设备 2. **USBMonitor类**: - 监控USB设备插拔事件 - 使用`lsusb`(Linux)或`system_profiler`(MacOS)获取USB设备列表 - 检测设备变化并记录到日志文件 - 支持后台线程持续监控 3. **主程序功能**: - 提供交互式控制菜单 - 同时运行音频接收和USB监控 - 支持手动发送控制命令 - 日志记录所有操作和事件 ### 使用说明 1. **准备工作**: - 确保Android设备和运行此脚本的电脑在同一局域网 - 获取Android设备的IP地址并更新脚本中的`SERVER_IP` - 在Android应用上启动TCP服务器(端口30000) 2. **运行脚本**: ```bash python audio_usb_monitor.py ``` 3. **功能操作**: - 选择1:发送开始录音指令到Android设备 - 选择2:发送停止录音指令 - 选择3:退出程序 4. **生成文件**: - `audio_output.pcm`:原始PCM音频数据 - `audio_output.wav`:WAV格式音频文件(可直接播放) - `usb_events.log`:USB设备插拔记录 - `audio_usb_monitor.log`:程序运行日志 ### 注意事项 1. **平台兼容性**: - USB监控功能目前支持Linux和MacOS - Windows系统需要修改USB检测方法(可使用pywin32) 2. **音频播放**: - 可以使用Audacity导入PCM文件(设置:单声道,16位,44100Hz) - WAV文件可直接用媒体播放器打开 3. **网络要求**: - 确保防火墙允许30000端口的TCP连接 - Android设备需保持唤醒状态防止网络断开 4. **错误处理**: - 脚本包含全面的错误处理和日志记录 - 网络断开时会自动重试并记录错误 这个脚本提供了完整的解决方案,可以同时接收Android设备发送的实时音频数据,并监控USB设备的插拔状态,所有操作都有详细日志记录。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值