Quantcast
Channel: Raspberry Pi Forums
Viewing all articles
Browse latest Browse all 1584

Python • Raspberry Pi audio recording works alone, but not when recording video at the same time

$
0
0
I have a Raspberry Pi Zero 2W wired to an Adafruit MEMS microphone with a camera attached. I tested audio recording in a separate Python program and that works perfectly:

Code:

import subprocessimport threadingimport osaudio_process = Nonestop_recording_flag = Falseaudio_filename = "test.wav"def record_audio():    global audio_process, stop_recording_flag    env = os.environ.copy()    env["HOME"] = os.path.expanduser("~")    print("Recording... Type 'stop' and press Enter to stop.")    audio_process = subprocess.Popen([        "arecord", "-D", "dmic_sv", "-c", "2", "-r", "48000",        "-f", "S32_LE", "-t", "wav", audio_filename    ], env=env)    # Wait until user types 'stop'    while not stop_recording_flag and audio_process.poll() is None:        pass    if audio_process.poll() is None:        print("Stopping recording...")        audio_process.terminate()        try:            audio_process.wait(timeout=5)        except subprocess.TimeoutExpired:            audio_process.kill()    print(f"Recording saved to {audio_filename}")def monitor_input():    global stop_recording_flag    while True:        command = input().strip().lower()        if command == "stop":            stop_recording_flag = True            breakif __name__ == "__main__":    t1 = threading.Thread(target=record_audio)    t2 = threading.Thread(target=monitor_input)    t1.start()    t2.start()    t1.join()    t2.join()
But when I tried implementing that into my main program that records audio and video, then muxes them, video works fine but there is no audio in either the audio.wav file or the video itself. I know the mic works, the muxxing works. I am fairly certain it's an issue with how I thread and start the audio recording (some parts of the code below are removed for readability):

Code:

video_selected_index = 0is_recording = Falseframerate = 30video_filename = "/home/pi/video.h264"audio_wav_filename = "/home/pi/audio.wav"final_filename = ""picam = Noneaudio_process = Noneaudio_thread = Nonevideo_thread = Nonedef record_audio():    global audio_process, is_recording    try:        print("  [record_audio] Starting audio capture, Sir.")        env = os.environ.copy()        env["HOME"] = os.path.expanduser("~")        audio_process = subprocess.Popen([            "arecord", "-D", "dmic_sv", "-c", "2", "-r", "48000",            "-f", "S32_LE", "-t", "wav", audio_wav_filename        ], env=env)        # Wait for is_recording to turn False        while is_recording:            time.sleep(0.1)        if audio_process.poll() is None:            print("  [record_audio] Terminating arecord…")            audio_process.terminate()            try:                audio_process.wait(timeout=5)            except subprocess.TimeoutExpired:                audio_process.kill()        print(f"  [record_audio] Audio saved to {audio_wav_filename}, Sir.")    except Exception as e:        print(f"  [record_audio] Exception, Sir: {e}")def start_recording(config):    """    Launch audio + video threads (non-daemon), with a slight stagger.    """    global is_recording, audio_thread, video_thread    is_recording = True    # Start UI updater thread (could remain daemon)    threading.Thread(target=recording_ui_updater, daemon=True).start()    # Create *non-daemon* threads for audio & video so they run fully    audio_thread = threading.Thread(target=record_audio, daemon=False)    video_thread = threading.Thread(target=record_video, args=(config,), daemon=False)    # Start audio first, give it time to initialize DMIC    audio_thread.start()    time.sleep(0.1)    # Now start video capture    video_thread.start()def stop_recording():    """    Signal both threads to finish, then join.    """    global is_recording    is_recording = False    print("  [stop_recording] Signaled threads to stop.")    recording_status("Muxing...")    if audio_thread:        audio_thread.join()    # Give time for OS to flush file buffers    time.sleep(0.5)  # Crucial    if video_thread:        print("  [stop_recording] Joining video thread…")        video_thread.join()    print("  [stop_recording] Threads joined, proceeding to mux.")    mux_audio_video()def show_take_video_menu():    global video_selected_index, is_recording, picam    try:        picam = Picamera2()        picam.configure(picam.create_still_configuration())        picam.start()        time.sleep(2)  # Camera warm-up    except Exception as e:        print(f"Camera initialization failed: {e}")        return    while True:        if not is_recording:            # Draw resolution menu            img = Image.new("RGB", (160, 80), "black")            draw = ImageDraw.Draw(img)            title = "Take Video"            title_width = draw.textlength(title, font=font)            draw.text(((160 - title_width) // 2, 2), title, font=font, fill="red")            for i, (label, _) in enumerate(video_resolutions):                prefix = "> " if i == video_selected_index else "  "                draw.text((10, 18 + i * 14), prefix + label, font=font, fill="red")            display.display(img)        # Button controls        if GPIO.input(21) == GPIO.LOW:  # UP            wait_for_button_release(21)            video_selected_index = (video_selected_index - 1) % len(video_resolutions)        elif GPIO.input(12) == GPIO.LOW:  # DOWN            wait_for_button_release(12)            video_selected_index = (video_selected_index + 1) % len(video_resolutions)        elif GPIO.input(16) == GPIO.LOW:  # SELECT            wait_for_button_release(16)            label, config = video_resolutions[video_selected_index]            if is_recording:                stop_recording()                continue            if label.lower() == "return":                if is_recording:                    stop_recording()                print("Exiting video menu.")                picam.close()                return            if config:                start_recording(config)        time.sleep(0.1)  # Input debounce delaydef mux_audio_video():    global final_filename, framerate    timestamp = time.strftime("%Y%m%d_%H%M%S")    final_filename = f"/home/pi/Videos/recording_{timestamp}.mp4"    subprocess.run([        "ffmpeg", "-y",        "-framerate", str(framerate),        "-i", video_filename,        "-i", audio_wav_filename,        "-metadata:s:v", "rotate=270",        "-c:v", "copy",        "-c:a", "aac",        "-shortest", final_filename    ], check=True)    print(f"Muxed to {final_filename}")

Statistics: Posted by PythoErgo — Sun Jun 01, 2025 3:56 pm



Viewing all articles
Browse latest Browse all 1584

Trending Articles