sound fixes

This commit is contained in:
emdee@spm.plastiras.org 2024-02-10 23:52:50 +00:00
parent 31bed51455
commit ac6999924f
32 changed files with 765 additions and 113 deletions

View file

@ -3,9 +3,9 @@ import time
import threading
import itertools
from tox_wrapper.toxav_enums import *
from tox_wrapper.tests import support_testing as ts
from tox_wrapper.tests.support_testing import LOG_ERROR, LOG_WARN, LOG_INFO, LOG_DEBUG, LOG_TRACE
from toxygen_wrapper.toxav_enums import *
from toxygen_wrapper.tests import support_testing as ts
from toxygen_wrapper.tests.support_testing import LOG_ERROR, LOG_WARN, LOG_INFO, LOG_DEBUG, LOG_TRACE
with ts.ignoreStderr():
import pyaudio
@ -14,7 +14,7 @@ from av.call import Call
import common.tox_save
from utils import ui as util_ui
import tox_wrapper.tests.support_testing as ts
import toxygen_wrapper.tests.support_testing as ts
from middleware.threads import invoke_in_main_thread
from middleware.threads import BaseThread
@ -38,10 +38,10 @@ class AV(common.tox_save.ToxAvSave):
s = settings
if 'video' not in s:
LOG.warn("AV.__init__ 'video' not in s" )
LOG.debug(f"AV.__init__ {s!r}" )
LOG.debug(f"AV.__init__ {s}" )
elif 'device' not in s['video']:
LOG.warn("AV.__init__ 'device' not in s.video" )
LOG.debug(f"AV.__init__ {s['video']!r}" )
LOG.debug(f"AV.__init__ {s['video']}" )
self._calls = {} # dict: key - friend number, value - Call instance
@ -71,12 +71,15 @@ class AV(common.tox_save.ToxAvSave):
# was iOutput = self._settings._args.audio['output']
iInput = self._settings['audio']['input']
self.lPaSampleratesI = ts.lSdSamplerates(iInput)
if not self.lPaSampleratesI: LOG.warn(f"empty self.lPaSampleratesI iInput={iInput}")
iOutput = self._settings['audio']['output']
self.lPaSampleratesO = ts.lSdSamplerates(iOutput)
if not self.lPaSampleratesO: LOG.warn(f"empty self.lPaSampleratesO iOutput={iOutput}")
global oPYA
oPYA = self._audio = pyaudio.PyAudio()
def stop(self):
LOG_DEBUG(f"AV.CA stop {self._video_thread}")
self._running = False
self.stop_audio_thread()
self.stop_video_thread()
@ -126,8 +129,7 @@ class AV(common.tox_save.ToxAvSave):
self._audio_krate_tox_audio if audio_enabled else 0,
self._audio_krate_tox_video if video_enabled else 0)
except Exception as e:
LOG.debug(f"AV accept_call error from {friend_number} {self._running}" +
f"{e}")
LOG.debug(f"AV accept_call error from {friend_number} {self._running} {e}")
raise
if audio_enabled:
# may raise
@ -194,26 +196,34 @@ class AV(common.tox_save.ToxAvSave):
LOG_WARN(f"start_audio_thread device={iInput}")
return
LOG_DEBUG(f"start_audio_thread device={iInput}")
lPaSamplerates = ts.lSdSamplerates(iInput)
lPaSamplerates = ts.lSdSamplerates(iInput)
if not(len(lPaSamplerates)):
e = f"No supported sample rates for device: audio[input]={iInput!r}"
e = f"No sample rates for device: audio[input]={iInput}"
LOG_ERROR(f"start_audio_thread {e}")
#?? dunno - cancel call?
return
if not self._audio_rate_pa in lPaSamplerates:
LOG_WARN(f"{self._audio_rate_pa} not in {lPaSamplerates!r}")
if False:
self._audio_rate_pa = oPYA.get_device_info_by_index(iInput)['defaultSampleRate']
else:
LOG_WARN(f"Setting audio_rate to: {lPaSamplerates[0]}")
self._audio_rate_pa = lPaSamplerates[0]
#?? dunno - cancel call? - no let the user do it
# return
# just guessing here in case that's a false negative
lPaSamplerates = [round(oPYA.get_device_info_by_index(iInput)['defaultSampleRate'])]
if lPaSamplerates and self._audio_rate_pa in lPaSamplerates:
pass
elif lPaSamplerates:
LOG_WARN(f"{self._audio_rate_pa} not in {lPaSamplerates}")
self._audio_rate_pa = lPaSamplerates[0]
LOG_WARN(f"Setting audio_rate to: {lPaSamplerates[0]}")
elif 'defaultSampleRate' in oPYA.get_device_info_by_index(iInput):
self._audio_rate_pa = oPYA.get_device_info_by_index(iInput)['defaultSampleRate']
else:
LOG_WARN(f"{self._audio_rate_pa} not in {lPaSamplerates}")
# a float is in here - must it be int?
if type(self._audio_rate_pa) == float:
self._audio_rate_pa = round(self._audio_rate_pa)
try:
LOG_DEBUG( f"start_audio_thread framerate: {self._audio_rate_pa}" \
+f" device: {iInput}"
+f" supported: {lPaSamplerates!r}")
+f" supported: {lPaSamplerates}")
if self._audio_rate_pa not in lPaSamplerates:
LOG_WARN(f"PAudio sampling rate was {self._audio_rate_pa} changed to {lPaSamplerates[0]}")
LOG_DEBUG(f"lPaSamplerates={lPaSamplerates}")
self._audio_rate_pa = lPaSamplerates[0]
if bSTREAM_CALLBACK:
@ -256,9 +266,10 @@ class AV(common.tox_save.ToxAvSave):
# raise RuntimeError(e)
return
else:
LOG_DEBUG(f"start_audio_thread {self._audio_stream!r}")
LOG_DEBUG(f"start_audio_thread {self._audio_stream}")
def stop_audio_thread(self):
LOG_DEBUG(f"stop_audio_thread {self._audio_stream}")
if self._audio_thread is None:
return
@ -279,11 +290,11 @@ class AV(common.tox_save.ToxAvSave):
s = self._settings
if 'video' not in s:
LOG.warn("AV.__init__ 'video' not in s" )
LOG.debug(f"start_video_thread {s!r}" )
LOG.debug(f"start_video_thread {s}" )
raise RuntimeError("start_video_thread not 'video' in s)" )
elif 'device' not in s['video']:
LOG.error("start_video_thread not 'device' in s['video']" )
LOG.debug(f"start_video_thread {s['video']!r}" )
LOG.debug(f"start_video_thread {s['video']}" )
raise RuntimeError("start_video_thread not 'device' ins s['video']" )
self._video_width = s['video']['width']
self._video_height = s['video']['height']
@ -321,6 +332,7 @@ class AV(common.tox_save.ToxAvSave):
self._video_thread.start()
def stop_video_thread(self) -> None:
LOG_DEBUG(f"stop_video_thread {self._video_thread}")
if self._video_thread is None:
return
@ -331,7 +343,6 @@ class AV(common.tox_save.ToxAvSave):
try:
if not self._video_thread.is_alive(): break
except:
# AttributeError: 'NoneType' object has no attribute 'join'
break
i = i + 1
else:
@ -349,12 +360,20 @@ class AV(common.tox_save.ToxAvSave):
if self._out_stream is None:
# was iOutput = self._settings._args.audio['output']
iOutput = self._settings['audio']['output']
if not rate in self.lPaSampleratesO:
LOG.warn(f"{rate} not in {self.lPaSampleratesO!r}")
if False:
rate = oPYA.get_device_info_by_index(iOutput)['defaultSampleRate']
if self.lPaSampleratesO and rate in self.lPaSampleratesO:
pass
elif self.lPaSampleratesO:
LOG.warn(f"{rate} not in {self.lPaSampleratesO}")
LOG.warn(f"Setting audio_rate to: {self.lPaSampleratesO[0]}")
rate = self.lPaSampleratesO[0]
elif 'defaultSampleRate' in oPYA.get_device_info_by_index(iOutput):
rate = round(oPYA.get_device_info_by_index(iOutput)['defaultSampleRate'])
LOG.warn(f"Setting rate to {rate} empty self.lPaSampleratesO")
else:
LOG.warn(f"Using rate {rate} empty self.lPaSampleratesO")
if type(rate) == float:
rate = round(rate)
try:
with ts.ignoreStderr():
self._out_stream = oPYA.open(format=pyaudio.paInt16,
@ -372,7 +391,7 @@ class AV(common.tox_save.ToxAvSave):
return
iOutput = self._settings['audio']['output']
LOG.debug(f"audio_chunk output_device_index={iOutput} rate={rate} channels={channels_count}")
#trace LOG.debug(f"audio_chunk output_device_index={iOutput} rate={rate} channels={channels_count}")
self._out_stream.write(samples)
# AV sending
@ -389,7 +408,6 @@ class AV(common.tox_save.ToxAvSave):
for friend_num in self._calls:
if self._calls[friend_num].out_audio:
try:
# app.av.calls ERROR Error send_audio: One of the frame parameters was invalid. E.g. the resolution may be too small or too large, or the audio sampling rate may be unsupported
# app.av.calls ERROR Error send_audio audio_send_frame: This client is currently not in a call with the friend.
self._toxav.audio_send_frame(friend_num,
pcm,
@ -402,7 +420,8 @@ class AV(common.tox_save.ToxAvSave):
# invoke_in_main_thread(util_ui.message_box,
# str(e),
# util_ui.tr("Error send_audio audio_send_frame"))
pass
# raise #? stop ? endcall?
self.stop_audio_thread()
def send_audio(self) -> None:
"""