關於Websockets的篇章, 有興趣的朋友歡迎參考:
而這一篇章的主題主要是來分享如何透過websockets傳遞音檔並進行解碼, 我們都知道聲音的運算在Python的世界裡通常會轉成numpy或者是torch.Tensor這樣的資料結構來進行語音辨識、VAD、人聲分離…相關的語音計算, 但這會牽涉到音訊的編碼與解碼, 對於一般工程背景的開發者來說會相對較為複雜一些, 我們會嘗試著以較為基本知識的角度來進行傳輸層的說明與分析作法。
那麼首先在進入主題之前, 我們非常推薦您閱讀「【Python 軍火庫 - websockets】雙向溝通的渠道」, 因為當我們掌握了基本的傳輸方式之後, 之後的難題僅是編碼與解碼的過程, 所以請嘗試著根據說明搭建起websockets的傳輸與接收框架吧!
那麼關於編碼與解碼就會面臨到兩個問題了, 究竟是要Client端解碼後送到後端,還是後端再進行解碼呢?
那麼我們今天的主題就先來談談第一種,從Client端對音檔解碼之後傳送到後端的過程吧!
對於Client端來說,要進行音訊的讀取勢必會需要一些好用的套件,包括soundfile、pydub、…等,那我們就先用soundfile這個套件來進行示範吧!
關於soundfile我們先來簡單的說明一下, 它提供了對各種音頻文件格式的支持,這個模組的主要目的是簡化在 Python 中處理音頻文件的任務,使用戶能夠輕鬆地讀取和編寫不同格式的音頻數據。
安裝的部分:
# 記得安裝一下ffmpeg,我們的底層端會透過ffmpeg進行音訊處理
apt install ffmpeg
# 透過pip安裝soundfile套件
pip install soundfile
正式進入音訊解碼片段,以下是片段示範,透過soundfile音訊解碼後成numpy資料再轉成bytes進行傳送:
import asyncio
import websockets
import soundfile as sf
async def client():
async with websockets.connect(
'ws://0.0.0.0:8766',
ping_interval=None,
) as websocket: # noqa
sound_file = 'test.wav'
print(f'Sending {sound_file}')
chunk_size = 4096
# 讀取音檔並解碼成numpy再轉成bytes送websockets
with sf.SoundFile(sound_file, 'r') as file:
while True:
data = file.read(chunk_size, dtype='float32')
if data.size == 0:
break
chunk = data.tobytes()
await websocket.send(chunk)
await websocket.send('Done')
asyncio.run(client())
Server端的部分則是將接收到的bytes資料透過numpy的轉換轉成陣列結構, 後續我們可以進行語音辨識、VAD、去背景噪音…等音訊處理的作業。
import asyncio
import websockets
import numpy as np
async def server(websocket, path):
while True:
try:
message = await websocket.recv()
if message == 'Done':
return None
# 轉換成numpy資料型態準備進行後續運算
array = np.frombuffer(message, dtype=np.float32)
print(len(array))
except websockets.exceptions.ConnectionClosedOK:
print("Client disconnected")
break
async def main():
async with websockets.serve(server, "0.0.0.0", 8766):
print('start server: 0.0.0.0:8766')
await asyncio.Future() # run forever
asyncio.run(main())
我們可以接收到的資料長度如下:
音訊又是一門不同境界的學問, 不過我們也不要氣餒,所有跟程式有關的運作都離不開一些共同的核心邏輯,只要我們按部就班,打好基礎耐心學習,相信總有一天會將所有知識點融會貫通,也希望這個篇章能夠讓您學習到如何透過websockets來傳遞音訊並進行運算處理。
對了,今天的方式主要是透過Client端進行音訊解碼的動作,這樣的方式雖然簡單,但額外的傳輸成本較大,因此我們會在「【💎Python 軍火庫 - websockets】傳送/接收音檔並轉換成numpy(進階篇)」教您如何在Server端進行解碼,而Client端只要將檔案原封不動的傳送即可。