Skip to content

stream.write takes too long (longer that real audio data duration) #10

@el07694

Description

@el07694

I have this pyaudio Process:

class Child_Proc(Process):

    def __init__(self, to_emitter, from_mother):
        try:
            super().__init__()
            self.daemon = False
            self.to_emitter = to_emitter
            self.data_from_mother = from_mother
            self.stream = None

        except Exception as e:
            try:
                error_message = str(traceback.format_exc())
                to_emitter.put({"type": "error", "error_message": error_message})
            except Exception as e:
                pass

    def run(self):
        try:
            self.fetch_output_devices()
            self.bit_rate = 128 * 1024  # 128 kb/sec
            self.packet_time = 125
            self.packet_size = 1024
            self.new_sample_rate = 44800
            self.TIME_WINDOW = 3000

            self.format = pyaudio.paInt16
            self.channels = 2

            if self.secondary_output_device_name != "Καμία συσκευή αναπαραγωγής ήχου":
                for output_device in self.output_devices:
                    if (self.secondary_output_device_name == output_device[2]):
                        self.output_device_index = output_device[1]
                        self.stream = self.p.open(format=pyaudio.paInt16, channels=self.channels, rate=self.new_sample_rate,output=True, output_device_index=self.output_device_index,frames_per_buffer=int(self.new_sample_rate * 0.125))
                        self.stream.start_stream()
            while(True):
                data = self.data_from_mother.get()

                slice = None
                if data["type"] == "slice":
                    slice = data["slice"]
                    chunk_number = data["chunk_number"]
                elif data["type"] == "update-sound-device":
                    try:
                        self.stream.stop_stream()
                        self.stream.close()
                        self.stream = None
                    except:
                        pass
                    self.fetch_output_devices()
                    if self.secondary_output_device_name != "Καμία συσκευή αναπαραγωγής ήχου":
                        for output_device in self.output_devices:
                            if (self.secondary_output_device_name == output_device[2]):
                                self.output_device_index = output_device[1]
                                self.stream = self.p.open(format=pyaudio.paInt16, channels=self.channels, rate=self.new_sample_rate,output=True, output_device_index=self.output_device_index,frames_per_buffer=int(self.new_sample_rate * 0.125))
                                self.stream.start_stream()
                if slice is not None:
                    if self.stream is not None:
                        self.stream.write(slice.raw_data)
                        print("Secondary-slice-pyaudio out: " + str(time.time())+" chunk_number: "+str(chunk_number))
                else:
                    slice = AudioSegment.silent(125)
                    self.stream.write(slice.raw_data)
        except:
            error_message = str(traceback.format_exc())
            self.to_emitter.send({"type": "error", "error_message": error_message})

    def fetch_output_devices(self):
        try:
            self.database_functions = database_functions
            self.primary_output_device_name = self.database_functions.read_setting("primary_output_device_name")["value"]
            self.primary_output_device_number = int(self.database_functions.read_setting("primary_output_device_number")["value"])

            self.secondary_output_device_name = self.database_functions.read_setting("secondary_output_device_name")["value"]
            self.secondary_output_device_number = int(self.database_functions.read_setting("secondary_output_device_number")["value"])


            self.p = pyaudio.PyAudio()
            self.info = self.p.get_host_api_info_by_index(0)
            self.numdevices = self.info.get('deviceCount')

            self.output_devices = [[0, -1, "Καμία συσκευή αναπαραγωγής ήχου"]]

            api_info, api_index = self.get_api_info(self.p)
            api_name = api_info['name']
            PREFERRED_HOST_API_NAME = 'Windows WASAPI'
            if api_name != PREFERRED_HOST_API_NAME:
                print(f'[WARNING] "{PREFERRED_HOST_API_NAME}" not available on this system, '
                      f'going with "{api_name}" instead')

            numdevices = api_info.get('deviceCount')

            counter = 1
            for i in range(0, self.numdevices):
                dev_info = self.p.get_device_info_by_host_api_device_index(0, i)
                if dev_info.get('maxOutputChannels') > 0:
                    device_name_cropped = str(dev_info.get('name'))
                    for j in range(0, numdevices):
                        one_dev_info = self.p.get_device_info_by_host_api_device_index(api_index, j)
                        if one_dev_info.get('maxOutputChannels') > 0:
                            one_device_name = str(one_dev_info.get('name'))
                            if device_name_cropped in one_device_name:
                                device_name_cropped = one_device_name
                                break

                    self.output_devices.append([counter, i, device_name_cropped])
                    counter += 1


        except:
            error_message = traceback.format_exc()
            self.to_emitter.send({"type": "error", "error_message": error_message})

    def get_api_info(self, p):
        try:
            PREFERRED_HOST_API_NAME = 'Windows WASAPI'
            api_info, api_index = None, 0
            for i in range(p.get_host_api_count()):
                current_api_info = p.get_host_api_info_by_index(i)
                if i == 0:
                    api_info = current_api_info
                else:
                    if current_api_info['name'] == PREFERRED_HOST_API_NAME:
                        api_info, api_index = current_api_info, i
                        break
            return api_info, api_index
        except:
            error_message = traceback.format_exc()
            self.to_emitter.send({"type": "error", "error_message": error_message})

Every AudioSegment slice has 0.125 second duration.

But the execution of stream.write takes longer 0.140 second so i have a progressive increase delay in sound output.
What can i do?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions