🎙️

PycordでDiscordの音声を拾ってみる

2022/12/27に公開

Pycordにはボイスチャンネルの音声を録音する機能がある。

https://guide.pycord.dev/voice/receiving

この機能で参加させた音声チャンネル内の音声を sink というオブジェクトに溜めファイルに変換することができるのだが、今回、ボットAが参加したチャンネル音声をボットBが参加している別のチャンネルに転送するみたいなことをしたかったため、ライブラリ内部でどんなことしているかを覗いてみた。

Pycordのstart_recording の内部を見てみるとrecv_audioをスレッドで実行していそうである。

self.decoder = opus.DecodeManager(self)
self.decoder.start()
self.recording = True
self.sink = sink
sink.init(self)

t = threading.Thread(
   target=self.recv_audio,
   args=(
   sink,
   callback,
   *args,
   ),
)
t.start()

recv_audioはソケットからデータを拾っており、unpack_audioで音声データを取り出し、
OpusのデコーダーでPCMデータに変換している。 PCMのフォーマットは16-bit 48KHz ステレオ。

while self.recording:
   ready, _, err = select.select([self.socket], [], [self.socket], 0.01)
   if not ready:
   if err:
       print(f"Socket error: {err}")
   continue

   try:
   data = self.socket.recv(4096)
   except OSError:
   self.stop_recording()
   continue

   self.unpack_audio(data)

デコーダーはrecv_decoded_audioを呼び出しているのでこのメソッドをいじれば音声データをとりだせそうである。
Discordの音声データは発話したユーザー毎にやってくるのでこの音声データをMixして、転送すれば良さそう。

とりあえず、下記のような転送ボットを作ってみたが、PCM音声の合成の処理をもう少し上手くしないとちょっと音声が不安定になりそう。
https://github.com/eeharumt/voice-transfar_py

Discussion