4
8

More than 1 year has passed since last update.

Raspberry Piでインターホンの音を検知してLINEに通知する (2)PyAudio録音時の警告・エラーに対処する

Last updated at Posted at 2022-02-23

「インターホンの音を検知してLINE通知することで、どこにいてもイヤホンをしていても来客に気づきたい」と考えて作成したものをまとめています。
前回「(1)インターホンの音を録音する」では、Raspberry PiとPyAudioモジュールを使ってインターホンの音を録音しました。
しかし、その際に警告やエラーが出ることを説明しました。
今回は、これらへの対処方法をまとめます。特にエラー対処は実際に運用する際に重要です。

なかなか解決方法が見つからなかったので需要があるかなあと思う反面、
調べきれていないとも感じている箇所です(実際、どれも根本的な解決ではない)。

装置:Raspberry Pi 4
マイク:共立プロダクツ MI-305 [USBマイク]
プログラム言語:Python3 (PyAudioモジュールを使用。 PyAudio Documentation)

下記のプログラムを念頭に話を進めます。(今回は.wavに保存するところは省略)

overflow_and_ALSAerror.py
import pyaudio
import wave
input_device_index = 2 # 前回確認したデバイス番号
CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 1 # モノラル入力 # 前回確認したmaxInputChannelsが上限
RATE = 44100
RECORD_SECONDS = 5

p = pyaudio.PyAudio()
stream = p.open(format=FORMAT,
                channels=CHANNELS,
                input_device_index = input_device_index,
                rate=RATE,
                input=True,
                frames_per_buffer=CHUNK)
print("Recording...")
frames = []
for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
    data = stream.read(CHUNK)
    frames.append(data)
print("Done!")
stream.stop_stream()
stream.close()
p.terminate()

OSError: [Errno -9981] Input overflowed

上記を実行した際、

OSError: [Errno -9981] Input overflowed

が表示されることがあり、その場合は

CHUNK = 1024 * 4 # または、*8, *16, ...

のようにCHUNKを増やせば防げることは前回の通り。
しかしCHUNKを大きくしても、何度も繰り返すとたまに出現し、録音が止まる。
今回のように24時間動作していてほしい場合には致命的。

そこで、PyAudioのdocumentationを参考に、下記のように書き換える。

wo_overflow.py
import pyaudio
import wave
input_device_index = 2 # 前回確認したデバイス番号
CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 1 # モノラル入力 # 前回確認したmaxInputChannelsが上限
RATE = 44100
RECORD_SECONDS = 5

p = pyaudio.PyAudio()
stream = p.open(format=FORMAT,
                channels=CHANNELS,
                input_device_index = input_device_index,
                rate=RATE,
                input=True,
                frames_per_buffer=CHUNK)
print("Recording...")
frames = []
for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
    # ↓↓↓ここを変更
    data = stream.read(CHUNK, exception_on_overflow=False)
    # ↑↑↑
    frames.append(data)
print("Done!")
stream.stop_stream()
stream.close()
p.terminate()

stream.readの引数にexception_on_overflow=Falseを加えることで、overflow時のOS Errorを出さないようにする(デフォルトではTrue)。
これでOSError: [Errno -9981] Input overflowedは出ないはず。
ただ、overflowしていることには変わりがないので、その瞬間は切り取られたような音声データになっている(と思う)。
まずはCHUNKを大きくして、ある程度は安定に録音できるようにしてからこの対処をすべきか。

ALSA関連の警告

冒頭のコードを実行した際、

ALSA lib confmisc.c:1281:(snd_func_refer) Unable to find definition 'cards.bcm2835_hdmi.pcm.front.0:CARD=0'

で始まる警告がたたみかけてくることは前回の通り(最後にほぼ全文を載せておく)。
録音に問題はないのだが、1画面に収まらない量の警告なのでどうにかしたい。

調べたら、下記のページが役に立ちそう。
PyAudio working, but spits out error messages each time
質問に対していくつか解決策が寄せられているが、
「All of the above is true and a good solution. I just came here to suggest a nicer way of re-using the error handler code:」
で始まる回答を使用してみた。configファイル系をいじらなくて良さそうなのと、nicer wayということなので。

error_hider.py
from ctypes import *
from contextlib import contextmanager
import pyaudio

ERROR_HANDLER_FUNC = CFUNCTYPE(None, c_char_p, c_int, c_char_p, c_int, c_char_p)

def py_error_handler(filename, line, function, err, fmt):
    pass

c_error_handler = ERROR_HANDLER_FUNC(py_error_handler)

@contextmanager
def noalsaerr():
    asound = cdll.LoadLibrary('libasound.so')
    asound.snd_lib_error_set_handler(c_error_handler)
    yield
    asound.snd_lib_error_set_handler(None)
wo_ALSAerror.py
import pyaudio
import wave

from error_hider import noalsaerr # ↑のコードをimport

input_device_index = 2 # 前回確認したデバイス番号
CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 1 # モノラル入力 # 前回確認したmaxInputChannelsが上限
RATE = 44100
RECORD_SECONDS = 5

# ↓↓↓ここを変更
with noalsaerr():
    p = pyaudio.PyAudio()
# ↑↑↑
stream = p.open(format=FORMAT,
                channels=CHANNELS,
                input_device_index = input_device_index,
                rate=RATE,
                input=True,
                frames_per_buffer=CHUNK)
print("Recording...")
frames = []
for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
    data = stream.read(CHUNK, exception_on_overflow=False)
    frames.append(data)
print("Done!")
stream.stop_stream()
stream.close()
p.terminate()

上記を実行すると、ALSA関連の警告は消える。
"with noalsaerr():"を加えるだけなので非常に簡便。
しかし、下記のjack server関連の警告は引き続き現れる・・・。
これ以上はわからなかったのと、対処前と比べると少ない量なので、ここで妥協することにした。

Cannot connect to server socket err = No such file or directory
Cannot connect to server request channel
jack server is not running or cannot be started
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
Cannot connect to server socket err = No such file or directory
Cannot connect to server request channel
jack server is not running or cannot be started
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
Cannot connect to server socket err = No such file or directory
Cannot connect to server request channel
jack server is not running or cannot be started
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock

まとめ

今回は、Raspberry PiとPyAudioを使って録音する際に現れる、警告・エラーへの対処方法をまとめました。
特にOverflowへの対処は運用を始めてから重要さに気づきました。
どれも対症療法であるだけでなく、警告が消えきっていないところもあるので心苦しいですが、
改善が見られたので良かったです。
次回は、前回録音したデータを解析して、インターホンの検知基準を作成します。

その他の記事:
Raspberry Piでインターホンの音を検知してLINEに通知する (1)インターホンの音を録音する
Raspberry Piでインターホンの音を検知してLINEに通知する (3)検知基準を検討する
Raspberry Piでインターホンの音を検知してLINEに通知する (4)検知してLINEに通知する

参考

PyAudio documentation
PyAudio working, but spits out error messages each time

ALSA関連の警告のほぼ全文

ALSA lib confmisc.c:1281:(snd_func_refer) Unable to find definition 'cards.bcm2835_hdmi.pcm.front.0:CARD=0'
ALSA lib conf.c:4568:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:5047:(snd_config_expand) Evaluate error: No such file or directory
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM front
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.rear
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.center_lfe
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.side
ALSA lib confmisc.c:1281:(snd_func_refer) Unable to find definition 'cards.bcm2835_hdmi.pcm.surround51.0:CARD=0'
...(中略)...
ALSA lib conf.c:4568:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:5047:(snd_config_expand) Evaluate error: No such file or directory
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM surround71
ALSA lib confmisc.c:1281:(snd_func_refer) Unable to find definition 'cards.bcm2835_hdmi.pcm.iec958.0:CARD=0,AES0=4,AES1=130,AES2=0,AES3=2'
ALSA lib conf.c:4568:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:5047:(snd_config_expand) Evaluate error: No such file or directory
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM iec958
ALSA lib confmisc.c:1281:(snd_func_refer) Unable to find definition 'cards.bcm2835_hdmi.pcm.iec958.0:CARD=0,AES0=4,AES1=130,AES2=0,AES3=2'
ALSA lib conf.c:4568:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:5047:(snd_config_expand) Evaluate error: No such file or directory
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM spdif
ALSA lib confmisc.c:1281:(snd_func_refer) Unable to find definition 'cards.bcm2835_hdmi.pcm.iec958.0:CARD=0,AES0=4,AES1=130,AES2=0,AES3=2'
ALSA lib conf.c:4568:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:5047:(snd_config_expand) Evaluate error: No such file or directory
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM spdif
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.hdmi
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.hdmi
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.modem
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.modem
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.phoneline
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.phoneline
ALSA lib confmisc.c:1281:(snd_func_refer) Unable to find definition 'defaults.bluealsa.device'
ALSA lib conf.c:4568:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:5036:(snd_config_expand) Args evaluate error: No such file or directory
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM bluealsa
ALSA lib confmisc.c:1281:(snd_func_refer) Unable to find definition 'defaults.bluealsa.device'
ALSA lib conf.c:4568:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:5036:(snd_config_expand) Args evaluate error: No such file or directory
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM bluealsa
Cannot connect to server socket err = No such file or directory
Cannot connect to server request channel
jack server is not running or cannot be started
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
Cannot connect to server socket err = No such file or directory
Cannot connect to server request channel
jack server is not running or cannot be started
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
ALSA lib pcm_oss.c:377:(_snd_pcm_oss_open) Unknown field port
ALSA lib pcm_oss.c:377:(_snd_pcm_oss_open) Unknown field port
ALSA lib pcm_a52.c:823:(_snd_pcm_a52_open) a52 is only for playback
ALSA lib confmisc.c:1281:(snd_func_refer) Unable to find definition 'cards.bcm2835_hdmi.pcm.iec958.0:CARD=0,AES0=6,AES1=130,AES2=0,AES3=2'
ALSA lib conf.c:4568:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:5047:(snd_config_expand) Evaluate error: No such file or directory
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM iec958:{AES0 0x6 AES1 0x82 AES2 0x0 AES3 0x2  CARD 0}
ALSA lib pcm_usb_stream.c:486:(_snd_pcm_usb_stream_open) Invalid type for card
ALSA lib pcm_usb_stream.c:486:(_snd_pcm_usb_stream_open) Invalid type for card
Cannot connect to server socket err = No such file or directory
Cannot connect to server request channel
jack server is not running or cannot be started
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
4
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
8