@ -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 tox ygen _wrapper. toxav_enums import *
from tox ygen _wrapper. tests import support_testing as ts
from tox ygen _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 tox ygen _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 s upported s ample rates for device: audio[input]={ iInput !r }"
e = f " No s ample 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 :
"""