The main challenge we're encountering here is that pyaudio doesn't know where to find the portaudio libraries since, according to the source, it only looks in these locations for darwin platform installations:
include_dirs += ['/usr/local/include', '/usr/include']
external_libraries_path += ['/usr/local/lib', '/usr/lib']
This won't do if you're using a homebrew installation of portaudio, particularly so with Apple Silicon since there isn't a pre-built wheel in PyPi. This means setuptools/pip will need to build the package from source.
There are a few ways of configuring setuptools to use additional paths, including passing arguments, using a .pydistutils.cfg file, among others, but the second option worked for me given I'm installing pyaudio to a few Python environments.
Building off of some of the answers above, you can copy the following below to install pyaudio in one go.
# Install portaudio, will print list of paths where it's been installed if already done
brew list portaudio || brew install portaudio
# Link portaudio, will print a warning if already linked
brew link portaudio
# Create a pydistutils config file with the portaudio lib paths set correctly (no copying/pasting paths required)
cat <<EOF >> .pydistutils.cfg
[build_ext]
include_dirs=`brew --prefix portaudio`/include/
library_dirs=`brew --prefix portaudio`/lib/
EOF
# install (build) package with pip
python -m pip install pyaudio
All we're doing is telling setuptools to also look for C/C++ headers where portaudio has been installed by homebrew.