python操作麥克風(fēng)方式
更新時間:2026年01月17日 09:19:06 作者:AI算法網(wǎng)奇
文章總結(jié):作者分享了麥克風(fēng)測試的個人經(jīng)驗,包括使用websockerserver.py和pyaudio_client.py進行麥克風(fēng)讀取的方法,希望對大家有所幫助,并鼓勵大家支持腳本之家
查詢麥克風(fēng)
import sounddevice as sd
# 1. 查看所有主機API
print("=== All Host APIs ===")
for i, h in enumerate(sd.query_hostapis()):
print(f"HostAPI {i}: {h['name']}")
print("\n=== All Devices ===")
# 2. 查看所有設(shè)備
for i, d in enumerate(sd.query_devices()):
hostapi = sd.query_hostapis(d['hostapi'])
device_type = []
if d['max_input_channels'] > 0:
device_type.append("Input")
if d['max_output_channels'] > 0:
device_type.append("Output")
print(f"Device {i}: {d['name']}")
print(f" HostAPI: {hostapi['name']}")
print(f" Type: {', '.join(device_type)}")
print(f" Input channels: {d['max_input_channels']}")
print(f" Output channels: {d['max_output_channels']}")
print()
# 3. 嘗試使用默認設(shè)備
print("\n=== Testing Default Devices ===")
print(f"Default input device: {sd.default.device[0]}")
print(f"Default output device: {sd.default.device[1]}")
# 4. 直接使用默認輸入設(shè)備
try:
def audio_callback(indata, frames, time, status):
if status:
print(f"Status: {status}")
print(f"Audio shape: {indata.shape}")
with sd.InputStream(samplerate=16000, channels=1, dtype='int16', blocksize=320, callback=audio_callback):
input("?? Recording with default device... Press Enter to stop\n")
except Exception as e:
print(f"Error: {e}")
# 5. 或者,列出所有輸入設(shè)備
print("\n=== All Input Devices ===")
input_devices = []
for i, d in enumerate(sd.query_devices()):
if d['max_input_channels'] > 0:
hostapi = sd.query_hostapis(d['hostapi'])
input_devices.append((i, d, hostapi['name']))
print(f"Device {i}: {d['name']}")
print(f" HostAPI: {hostapi['name']}")
print(f" Channels: {d['max_input_channels']}")
# 6. 選擇一個可用的輸入設(shè)備
if input_devices:
print("\n=== Try using first available input device ===")
mic_index = input_devices[0][0]
device_info = input_devices[0][1]
channels = min(1, device_info['max_input_channels']) # 使用單聲道更通用
try:
with sd.InputStream(device=mic_index, samplerate=16000, channels=channels, dtype='int16', blocksize=320, callback=lambda indata, frames, time, status: print(f"Audio shape: {indata.shape}")):
input(f"?? Recording with {device_info['name']}... Press Enter to stop\n")
except Exception as e:
print(f"Error with device {mic_index}: {e}")
else:
print("No input devices found at all!")測試麥克風(fēng)
import sounddevice as sd
import numpy as np
# 直接使用設(shè)備10
mic_index = 10
print("Testing microphone...")
def callback(indata, frames, time, status):
volume = np.linalg.norm(indata) * 10
print(f"Microphone level: {volume:.2f}", end='\r')
# 嘗試不同的參數(shù)組合
settings_to_try = [
{'samplerate': 16000, 'channels': 1, 'dtype': 'int16'},
{'samplerate': 44100, 'channels': 1, 'dtype': 'float32'},
{'samplerate': 48000, 'channels': 1, 'dtype': 'int16'},
]
for i, settings in enumerate(settings_to_try):
print(f"\nTry {i+1}: {settings}")
try:
with sd.InputStream(
device=mic_index,
callback=callback,
**settings
):
input(f"Settings {i+1} working! Press Enter to stop...\n")
break
except Exception as e:
print(f"Failed: {e}")讀取麥克風(fēng)
import sounddevice as sd
import numpy as np
from scipy import signal
mic_index = 10
target_samplerate = 16000 # 目標(biāo)采樣率
original_samplerate = 44100 # 設(shè)備支持的采樣率
print(f"Recording at {original_samplerate}Hz, resampling to {target_samplerate}Hz")
def callback(indata, frames, time, status):
"""接收44100Hz音頻,重采樣到16000Hz"""
if status:
print(status)
# 如果是立體聲,轉(zhuǎn)換為單聲道
if indata.shape[1] > 1:
audio = np.mean(indata, axis=1)
else:
audio = indata.flatten()
# 重采樣到16000Hz
num_samples = int(len(audio) * target_samplerate / original_samplerate)
resampled = signal.resample(audio, num_samples)
print(f"Original: {len(audio)} samples, Resampled: {len(resampled)} samples", end='\r')
with sd.InputStream(device=mic_index, samplerate=original_samplerate, channels=1, dtype='float32', callback=callback):
input("Recording and resampling... Press Enter to stop\n")web socker server.py
import asyncio
import websockets
import json
import numpy as np
from datetime import datetime
import time
async def handle_audio_client(websocket, path):
"""處理音頻客戶端連接"""
client_id = id(websocket)
client_ip = websocket.remote_address[0]
print(f"\n? Client {client_id} connected from {client_ip}")
try:
# 1. 接收音頻格式信息
try:
format_msg = await asyncio.wait_for(websocket.recv(), timeout=5.0)
if isinstance(format_msg, str):
format_data = json.loads(format_msg)
print(f"?? Audio format: {format_data}")
# 發(fā)送確認
await websocket.send(json.dumps({'status': 'ready', 'message': 'Start sending audio!'}))
except asyncio.TimeoutError:
print("?? No format received, assuming default settings")
# 2. 實時接收音頻數(shù)據(jù)
print("?? Listening for audio data...")
print("-" * 60)
packet_count = 0
total_bytes = 0
start_time = time.time()
last_print_time = time.time()
try:
while True:
try:
# 接收數(shù)據(jù)(設(shè)置超時)
message = await asyncio.wait_for(websocket.recv(), timeout=2.0)
packet_count += 1
if isinstance(message, bytes):
# 音頻數(shù)據(jù)
data_size = len(message)
total_bytes += data_size
# 解析音頻數(shù)據(jù)
try:
audio_data = np.frombuffer(message, dtype=np.float32)
# 計算實時統(tǒng)計
if len(audio_data) > 0:
# 計算音量
rms = np.sqrt(np.mean(audio_data ** 2))
max_val = np.max(np.abs(audio_data))
# 轉(zhuǎn)換為分貝
if rms > 0:
db = 20 * np.log10(rms)
else:
db = -100
# 創(chuàng)建音量可視化
bars = max(0, min(int((db + 60) / 3), 20))
volume_bar = "█" * bars + "?" * (20 - bars)
# 每秒更新顯示
current_time = time.time()
if current_time - last_print_time >= 0.1: # 每0.1秒更新一次
elapsed = current_time - start_time
data_rate = total_bytes / elapsed / 1024 # KB/s
print(f"\r?? Packets: {packet_count:4d} | "
f"Rate: {data_rate:5.1f} KB/s | "
f"RMS: {rms:6.4f} | "
f"dB: {db:6.1f} | "
f"Volume: [{volume_bar}]", end="", flush=True)
last_print_time = current_time
except Exception as e:
print(f"\n?? Audio processing error: {e}")
elif isinstance(message, str):
print(f"\n?? Message: {message}")
except asyncio.TimeoutError:
# 超時,檢查連接是否還活著
try:
await websocket.ping()
continue
except:
break
except websockets.exceptions.ConnectionClosed:
print(f"\n?? Client disconnected normally")
except Exception as e:
print(f"\n? Error: {e}")
finally:
# 連接結(jié)束,顯示統(tǒng)計
elapsed = time.time() - start_time
if elapsed > 0:
print(f"\n" + "=" * 60)
print(f"?? Connection Statistics:")
print(f" Client ID: {client_id}")
print(f" Duration: {elapsed:.1f} seconds")
print(f" Packets received: {packet_count}")
print(f" Total data: {total_bytes / 1024:.1f} KB")
print(f" Average rate: {total_bytes / elapsed / 1024:.1f} KB/s")
print(f" Packets/sec: {packet_count / elapsed:.1f}")
print("=" * 60)
async def main():
server = await websockets.serve(handle_audio_client, "0.0.0.0", 8765, ping_interval=10, ping_timeout=20, max_size=10 * 1024 * 1024)
print(f"? Server running on ws://0.0.0.0:8765")
print(f"?? Ready to receive audio streams")
print(f"?? Press Ctrl+C to stop\n")
await server.wait_closed()
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
print("\n?? Server stopped")audio_client.py
import asyncio
import websockets
import sounddevice as sd
import numpy as np
import json
import threading
import queue
import time
print("?? WebSocket Audio Streaming Client")
print("=" * 60)
class WorkingClient:
def __init__(self):
self.server_url = "ws://localhost:8765"
self.device_index = 1
self.sample_rate = 44100
self.channels = 1
self.dtype = 'float32'
self.blocksize = 1024
# 音頻隊列
self.audio_queue = queue.Queue(maxsize=50)
# 控制標(biāo)志
self.running = True
self.is_recording = False
def start_audio_capture(self):
"""啟動音頻采集 - 在單獨的線程中運行"""
print(f"?? Opening microphone (device {self.device_index})...")
def callback(indata, frames, time_info, status):
if status:
print(f"?? Audio status: {status}")
# 檢查音頻是否有效
if np.any(indata):
# 計算音量
volume = np.linalg.norm(indata)
# 只將有聲音的數(shù)據(jù)放入隊列
if volume > 0.52: # 音量閾值
try:
# 復(fù)制數(shù)據(jù)并放入隊列
audio_copy = indata.copy()
self.audio_queue.put(audio_copy, timeout=0.01)
# 顯示音量(每20個包顯示一次)
if hasattr(callback, 'counter'):
callback.counter += 1
else:
callback.counter = 0
if callback.counter % 20 == 0:
print(f"\r?? Mic level: {volume:.4f} | Queue: {self.audio_queue.qsize()}", end="")
except queue.Full:
# 隊列滿了,清空并重新開始
try:
self.audio_queue.get_nowait()
except:
pass
try:
# 創(chuàng)建音頻流
self.stream = sd.InputStream(device=self.device_index, samplerate=self.sample_rate, channels=self.channels, dtype=self.dtype, blocksize=self.blocksize, callback=callback)
self.stream.start()
self.is_recording = True
print("? Microphone is ready! Speak now...")
return True
except Exception as e:
print(f"? Failed to open microphone: {e}")
return False
async def connect_and_stream(self):
"""連接服務(wù)器并發(fā)送音頻"""
print(f"\n?? Connecting to server...")
try:
# 連接WebSocket
async with websockets.connect(self.server_url, ping_interval=10, ping_timeout=20) as websocket:
print("? Connected to server!")
# 發(fā)送音頻格式
await websocket.send(json.dumps({'type': 'audio_format', 'samplerate': self.sample_rate, 'channels': self.channels, 'dtype': self.dtype, 'blocksize': self.blocksize}))
# 等待服務(wù)器響應(yīng)
response = await websocket.recv()
print(f"?? Server: {response}")
# 開始流式傳輸
print("\n" + "=" * 50)
print("?? Streaming audio to server...")
print("?? Speak into your microphone!")
print("?? Press Ctrl+C to stop")
print("=" * 50 + "\n")
packet_count = 0
last_display_time = time.time()
# 主發(fā)送循環(huán)
while self.running:
try:
# 從隊列獲取音頻數(shù)據(jù)(非阻塞)
if not self.audio_queue.empty():
audio_data = self.audio_queue.get_nowait()
# 發(fā)送音頻數(shù)據(jù)
await websocket.send(audio_data.tobytes())
packet_count += 1
# 每秒顯示一次統(tǒng)計
current_time = time.time()
if current_time - last_display_time >= 1.0:
queue_size = self.audio_queue.qsize()
print(f"\r?? Packets: {packet_count:4d} | "
f"Queue: {queue_size:2d} | "
f"Sample: {audio_data[0, 0]:7.4f}...", end="")
last_display_time = current_time
else:
# 隊列為空,短暫等待
await asyncio.sleep(0.01)
# 偶爾發(fā)送ping保持連接
if packet_count > 0 and packet_count % 100 == 0:
await websocket.ping()
except queue.Empty:
# 隊列空,短暫等待
await asyncio.sleep(0.01)
except Exception as e:
print(f"\n?? Streaming error: {e}")
break
print(f"\n?? Stopped. Total packets sent: {packet_count}")
except Exception as e:
print(f"? Connection error: {e}")
async def run(self):
"""運行客戶端"""
try:
# 啟動音頻采集
if not self.start_audio_capture():
return
# 連接并流式傳輸
await self.connect_and_stream()
except KeyboardInterrupt:
print("\n?? Stopped by user")
except Exception as e:
print(f"\n? Error: {e}")
finally:
# 清理
self.running = False
if hasattr(self, 'stream'):
self.stream.stop()
self.stream.close()
print("?? Microphone closed")
# 運行客戶端
async def main():
client = WorkingClient()
await client.run()
if __name__ == "__main__":
asyncio.run(main())總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Python requests模塊基礎(chǔ)使用方法實例及高級應(yīng)用(自動登陸,抓取網(wǎng)頁源碼)實例詳解
這篇文章主要介紹了Python requests模塊基礎(chǔ)使用方法實例及高級應(yīng)用(自動登陸,抓取網(wǎng)頁源碼,Cookies)實例詳解,需要的朋友可以參考下2020-02-02
Python2和Python3中print的用法示例總結(jié)
在Python 3中接觸的第一個很大的差異就是縮進是作為語法的一部分,這和C++等其他語言確實很不一樣,所以要小心,其中python3和python2中print的用法有很多不同,這篇文章主要給大家介紹了關(guān)于Python2和Python3中print用法的相關(guān)資料,需要的朋友可以參考下。2017-10-10
Python數(shù)據(jù)結(jié)構(gòu)與算法之圖的最短路徑(Dijkstra算法)完整實例
這篇文章主要介紹了Python數(shù)據(jù)結(jié)構(gòu)與算法之圖的最短路徑(Dijkstra算法),結(jié)合完整實例形式分析了Python圖的最短路徑算法相關(guān)原理與實現(xiàn)技巧,需要的朋友可以參考下2017-12-12
使用Python按類型/名稱/日期自動歸類5000個文件的代碼實現(xiàn)
文章介紹了使用Python自動化文件管理方案,通過按文件類型、日期歸檔和智能重命名等功能,大幅提高了文件管理的效率和可復(fù)用性,測試結(jié)果顯示,自動化方案相比傳統(tǒng)方法和商業(yè)軟件,耗時更短、內(nèi)存占用更低,文章還提供了詳細的代碼實現(xiàn)步驟和效率對比,需要的朋友可以參考下2026-01-01

