So, for what it's worth, I've so far gotten decent audio/video synchronization with the following ffmpeg invocation:
The key ingredient for achieving decent synchronization seems to be -use_wallclock_as_timestamps on both alsa and v4l2, and -copyts at the end.
Code:
#!/usr/bin/env bash
echo "enter title"
read TITLE
v4l2-ctl --set-fmt-video=width=640,height=480,pixelformat=YUYV -d /dev/video3
ffmpeg -f v4l2 -framerate 20 -thread_queue_size 1024 -use_wallclock_as_timestamps 1 -i /dev/video3 \
-f alsa -thread_queue_size 1024 -use_wallclock_as_timestamps 1 -i default \
-c:v libx264 -preset ultrafast \
-c:a aac -copyts \
~/$TITLE.mp4