python-sounddevice icon indicating copy to clipboard operation
python-sounddevice copied to clipboard

sounddevice.PortAudioError : Error opening Stream : Device unavailable [PaErrorCode -9985]

Open TylerBerrymanBrash opened this issue 11 months ago • 2 comments
trafficstars

I am trying to run a python script on boot using a systemd service on a Raspberry Pi4. The python script runs fine via the terminal, but flags a few errors (see attached image) when run via systemd. The python script opens an audio stream using the sounddevice library. I noticed that the device indexes are different when the python script is run via the terminal and via systemd. So I tried hardcoding the device index for the input stream, but that has not worked.

import sounddevice as sd
import numpy as np
import time
from pvrecorder import PvRecorder
import wave
import struct
import pydub
import requests
import uuid_utils as uuid

speaking_status = False
end = time.time() +10
start = time.time() 
length = 0
timer = 0
Audio_file = "YOW.wav"
sound_threshold = 10
audio_timeout = 3
IATA_Code = "YOW"

devices = PvRecorder.get_available_devices()
print

for i in range(len(devices)):
    print("index : %d, device name: %s" % (i, devices[i]))
    
sd.default.device = 2,1    
print("SoundDevice Indexes:" + str(sd.query_devices()))
#print("SoundDevice Default Device:" + str(sd.default()))

recorder = PvRecorder(device_index = 12, frame_length=512)
print("Selected device:" + recorder.selected_device)
audio = []

def print_sound(indata, outdata, frames, t, status):
    global start
    global end
    global length
    global timer
    global speaking_status
    global Audio_file
    global sound_threshold
    global audio_timeout
    i = 0
    
    volume_norm = np.linalg.norm(indata)*10
    #print(volume_norm)
    
    if (volume_norm > sound_threshold and speaking_status==False):
        print("Recording")
        start = time.time()
        speaking_status=True
        recorder.start()
    elif (volume_norm > sound_threshold and speaking_status==True):
        start = time.time()
        frame = recorder.read()
        audio.extend(frame)
        print("Volume:" + str(volume_norm))
    else:
        end = time.time()
    timer = end-start
    
    if (timer > audio_timeout and speaking_status==True):
        recorder.stop()
        speaking_status=False
        print("Stop Recording Audio")
        volume_norm = 0
        
        headers = {
        'Content-Type': 'application/json; charset=utf-8',
        }
        
        content_type = {
        'Content-Type': 'audio/mpeg',
        }

        json_data = {
            'query': {
                'filename': Audio_mp3,
            },
        }
        
        try:
            with open(Audio_mp3, "rb") as file_data:
                 print("Uploading Audio File to AWS S3 Bucket")
                 put_response = requests.put(received_upload_link, data=file_data, headers=content_type)
                 print("HTTP Response:" + str(put_response.status_code))
        except Exception as e:
                print("An exception occured:", e)

with sd.Stream(callback=print_sound):
    while True:
        sd.sleep(1000)

PXL_20241118_181206850 (1)

TylerBerrymanBrash avatar Nov 19 '24 15:11 TylerBerrymanBrash

Is it possible that PvRecorder takes over the input device and therefore makes it unavailable?

Could you try it with an OutputStream instead of a Stream?

mgeier avatar Nov 21 '24 19:11 mgeier

Issue was the input devices do not have the same device index when the python script is running in the terminal or when it is running with systemd. A few print statements showed the differences in device indexes. Another approach that worked for me was to get the specific device ID for the device name and plug that into the PvRecorder initiation.

TylerBerrymanBrash avatar Nov 28 '24 19:11 TylerBerrymanBrash