===== Broadcast audio-video ===== ==== alsa sound ==== # list usb devices sudo usermod -a -G audio utilisateur1 sudo apt-get install alsa-base alsa-utils # alsa-base est déjà la version la plus récente apt install v4l-utils v4l2-ctl --all # show webcams v4l2-ctl --all | grep "Pixel Format" #== Pixel Format : 'YUYV' (YUYV 4:2:2) amixer info #== Card default 'b1'/'bcm2835 HDMI 1' #== Mixer name : 'Broadcom Mixer' #== Components : '' #== Controls : 2 #== Simple ctrls : 1 amixer -D pulse set Master toggle # toggle sound on/off amixer -D pulse set Master 100% unmute arecord -l # show microphones (so here we can access to **plughw:2,0**) arecord -l #== **** Liste des Périphériques Matériels CAPTURE **** #== carte 2: Silver [Classic Silver], périphérique 0: USB Audio [USB Audio] #== Sous-périphériques: 1/1 #== Sous-périphérique #0: subdevice #0 #== This means that the built-in microphone is located on hardware 1, periph 0 arecord -L # show audio devices #== null #== default #== jack #== pulse #== usbstream:CARD=b1 #== usbstream:CARD=Headphones #== hw:CARD=Silver,DEV=0 #== plughw:CARD=Silver,DEV=0 #== sysdefault:CARD=Silver #== front:CARD=Silver,DEV=0 #== dsnoop:CARD=Silver,DEV=0 #== usbstream:CARD=Silver arecord -D plughw:2,0 test.wav #== Capture WAVE 'test.wav' : Signed 16 bit Little Endian, Fréquence 8000 Hz, Mono arecord --device=hw:2,0 --format S16_LE --rate 44100 -c1 test.wav -V mono #== Capture WAVE 'test.wav' Mono # show audio devices cat /proc/asound/cards #== 0 [b1 ]: bcm2835_hdmi - bcm2835 HDMI 1 #== 1 [Headphones ]: bcm2835_headpho - bcm2835 Headphones #== 2 [Silver ]: USB-Audio - Classic Silver #== Guillemot Corporation Classic Silver at usb-0000:01:00.0-1.2, high speed usb-devices | grep Product #== S: Product=xHCI Host Controller #== S: Product=USB2.0 Hub #== S: Product=Classic Silver #== S: Product=USB Receiver #== S: Product=xHCI Host Controller # pactl list | grep alsa.card_name #== alsa.card_name = "bcm2835 HDMI 1" #== alsa.card_name = "bcm2835 Headphones" #== alsa.card_name = "Classic Silver" #== Store the settings so that they persist on reboot. sudo alsactl store ==== ffmpeg & fswebcam webcam ==== #== list devices v4l2-ctl --list-devices #== list formats for each device v4l2-ctl --list-formats-ext #== list device capabilities ffmpeg -f v4l2 -list_formats all -i /dev/video0 [video4linux2,v4l2 @ 0xaaaaf383c060] Raw: yuyv422: YUYV 4:2:2 : 640x480 352x288 320x240 176x144 160x120 #== simple encode for 30 seconds ffmpeg -f v4l2 -framerate 25 -video_size 320x240 -i /dev/video0 -t 00:00:30 output.mkv #== take a picture ffmpeg -f v4l2 -video_size 1280x720 -i /dev/video0 -frames 1 out.jpg ffmpeg -f v4l2 -video_size 640x480 -i /dev/video0 -frames 1 out.jpg fswebcam -d v4l2:/dev/video0 -r 640x480 --jpeg 85 -D 1 --no-banner webcam.jpg ==== vlc broadcast ==== cvlc v4l2:///dev/video0:chroma=h264 :input-slave=alsa://hw:1,0 --sout '#transcode{acodec=mpga,ab=128,channels=2,samplerate=44100,threads=4,audio-sync=1}:standard{access=http,mux=ts,mime=video/ts,dst=:8080}' # Send mp3 via UDP cvlc test.mp3 --sout=udp://192.168.1.12:1234 # Receive UDP cvlc udp://@0.0.0.0:1234 # get webcam image vlc -vvv avcapture:// # on macos vlc -vvv v4l2:///dev/video0 # on linux # record audio flux for 10 seconds vlc test.mp3 --sout "#duplicate{dst=std{access=file,mux=raw,dst=OUT.mp3}" --stop-time 10 vlc://quit # vlc http://:8080/stream.wmv cvlc v4l2:///dev/video0 :v4l2-standard= :input-slave=alsa://hw:0,0 :live-caching=300 :sout="#transcode{vcodec=WMV2, vb=800, scale=1, acodec=wma2, ab=128, channels=2, samplerate=44100}:http{dst=:8080/stream.wmv}" ==== ffmpeg broadcast ==== # example # envoyer le son de la webcam à dest.local:1234 ffmpeg -re -f alsa -i plughw:2,0 -acodec libmp3lame -ar 11025 -f rtp rtp://dest.local:1234 # recevoir le son sur le port 1234 ffplay rtp://192.168.1.1:1234 ffplay -f alsa -i plughw:2,0 -acodec pcm_s16le -ac 1 -ar 96000 ==== VOIP proxy SIP ==== * [[https://x0r.fr/blog/37]] * {{ :perso:diy:siproxd-0.8.3.tar.gz |siproxd-0.8.3.tar.gz}} ==== HackerShackOfficial / Smart-Doorbell ==== * [[https://www.minimachines.net/actu/sonnettepi-88354|SonnettePi]] * [[https://www.hackster.io/hackershack/smart-doorbell-video-intercom-system-e5aa61|Hacker Shack - Smart Doorbell]] ############# # User Parameters ############# # Doorbell pin DOORBELL_PIN = 26 # Number of seconds to keep the call active DOORBELL_SCREEN_ACTIVE_S = 60 # ID of the JITSI meeting room JITSI_ID = None # If None, the program generates a random UUID # JITSI_ID = "hackershackdoorbellexample" # Path to the SFX file RING_SFX_PATH = None # If None, no sound effect plays # RING_SFX_PATH = "/home/pi/ring.wav" # Enables email notifications ENABLE_EMAIL = False # Email you want to send the notification from (only works with gmail) FROM_EMAIL = 'sender@gmail.com' # You can generate an app password here to avoid storing your password in plain text # this should also come from an environment variable # https://support.google.com/accounts/answer/185833?hl=en FROM_EMAIL_PASSWORD = 'password' # Email you want to send the update to TO_EMAIL = 'receiver@gmail.com' ############# # Program ############# import time import os import signal import subprocess import smtplib import uuid from email.MIMEMultipart import MIMEMultipart from email.MIMEText import MIMEText from email.MIMEImage import MIMEImage try: import RPi.GPIO as GPIO except RuntimeError: print("Error importing RPi.GPIO. This is probably because you need superuser. Try running again with 'sudo'.") def show_screen(): os.system("tvservice -p") os.system("xset dpms force on") def hide_screen(): os.system("tvservice -o") def send_email_notification(chat_url): if ENABLE_EMAIL: sender = EmailSender(FROM_EMAIL, FROM_EMAIL_PASSWORD) email = Email( sender, 'Video Doorbell', 'Notification: A visitor is waiting', 'A video doorbell caller is waiting on the virtual meeting room. Meet them at %s' % chat_url ) email.send(TO_EMAIL) def ring_doorbell(pin): SoundEffect(RING_SFX_PATH).play() chat_id = JITSI_ID if JITSI_ID else str(uuid.uuid4()) video_chat = VideoChat(chat_id) send_email_notification(video_chat.get_chat_url()) show_screen() video_chat.start() time.sleep(DOORBELL_SCREEN_ACTIVE_S) video_chat.end() hide_screen() class SoundEffect: def __init__(self, filepath): self.filepath = filepath def play(self): if self.filepath: subprocess.Popen(["aplay", self.filepath]) class VideoChat: def __init__(self, chat_id): self.chat_id = chat_id self._process = None def get_chat_url(self): return "http://meet.jit.si/%s" % self.chat_id def start(self): if not self._process and self.chat_id: self._process = subprocess.Popen(["chromium-browser", "-kiosk", self.get_chat_url()]) else: print("Can't start video chat -- already started or missing chat id") def end(self): if self._process: os.kill(self._process.pid, signal.SIGTERM) class EmailSender: def __init__(self, email, password): self.email = email self.password = password class Email: def __init__(self, sender, subject, preamble, body): self.sender = sender self.subject = subject self.preamble = preamble self.body = body def send(self, to_email): msgRoot = MIMEMultipart('related') msgRoot['Subject'] = self.subject msgRoot['From'] = self.sender.email msgRoot['To'] = to_email msgRoot.preamble = self.preamble msgAlternative = MIMEMultipart('alternative') msgRoot.attach(msgAlternative) msgText = MIMEText(self.body) msgAlternative.attach(msgText) smtp = smtplib.SMTP('smtp.gmail.com', 587) smtp.starttls() smtp.login(self.sender.email, self.sender.password) smtp.sendmail(self.sender.email, to_email, msgRoot.as_string()) smtp.quit() class Doorbell: def __init__(self, doorbell_button_pin): self._doorbell_button_pin = doorbell_button_pin def run(self): try: print("Starting Doorbell...") hide_screen() self._setup_gpio() print("Waiting for doorbell rings...") self._wait_forever() except KeyboardInterrupt: print("Safely shutting down...") finally: self._cleanup() def _wait_forever(self): while True: time.sleep(0.1) def _setup_gpio(self): GPIO.setmode(GPIO.BCM) GPIO.setup(self._doorbell_button_pin, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) GPIO.add_event_detect(self._doorbell_button_pin, GPIO.RISING, callback=ring_doorbell, bouncetime=2000) def _cleanup(self): GPIO.cleanup(self._doorbell_button_pin) show_screen() if __name__ == "__main__": doorbell = Doorbell(DOORBELL_PIN) doorbell.run() # Smart-Doorbell A wifi-connected raspberry pi doorbell with video chat Github repository for the Smart Doorbell Hackershack video This project was run on a Raspberry Pi 3 with Raspbian Buster. The video call wasn't as smooth as I would've liked, so it would probably be better to run this on a Pi 4. However, I haven't run this on the Pi 4, so I can't guarantee that it works. ## Instructions ### Enable the Camera Enable the camera with raspi-config In the terminal, type: ``` sudo raspi-config ``` Navigate to `Interfacing Options` Navigate to `camera` Select `yes` and reboot Test that the camera is working by running the following command in the terminal to save an image to your home directory ``` sudo raspistill -o test.jpg ``` ### Enable the Microphone Open the sound input settings ``` alsamixer -c l ``` Press `F4` to open the capture settings and bump the level up to 100. Press `Esc` to exit. Test the audio capture with the following command: ``` arecord --device=hw:1,0 --format S16_LE --rate 44100 -c1 test.wav -V mono ``` press `control-c` to stop. It will generate a audio file in your local directory called `test.wav` You can play the file with ``` aplay test.wav ``` Store the settings so that they persist on reboot ``` sudo alsactl store ``` ### Enable Video Calls Visit [Jitsi Meet](https://meet.jit.si/) and configure the site to use your camera/microphone My settings were: ``` Camera: mmal service 16.1 Microphone: USB PnP Sound Device, USB Audio-Default Audio Device ``` ### Download the Code I navigated to the repo from my Raspberry Pi in the browser and clicked "Download Zip". I extracted the package to my home directory and them moved the doorbell.py file to `/home/pi/doorbell.py`. You can test that the program works by running ``` python doorbell.py ``` from `/home/pi`. To edit the file, install vim and open the file ``` apt-get install vim vim doorbell.py ``` press, `i` to enter edit mode then make your changes. To exit, press `esc` then upper-case `ZZ` to save. The variables for the code are documented at the top. Feel free to change any of these for your program. ### Rotate the Screen Open the boot.txt file with vim ``` sudo vim /boot/config.txt ``` press `i` to enter insert mode then add a line ``` display_rotate=1 ``` press `esc` then `ZZ` to save and exit. Reboot. ### Start the Program on Boot Create a autostart directory ``` mkdir /home/pi/.config/autostart ``` Create a file to run the doorbell program ``` vim /home/pi/.config/autostart/doorbell.desktop ``` press `i`, then add the following to the file ``` [Desktop Entry] Type=Application Name=Doorbell Exec=python /home/pi/doorbell ``` press `esc` and `ZZ` to save and exit. *WARNING: This will make your local display unusable. Make sure you have a way to connect to the pi through VNC or SSH to remove this file if you want to stop the program from starting at boot. Reboot. If you have any issues getting the doorbell to start, please leave an issue on this repository and the community will help you get it working.