pyvoice
index
/Compile/gyach-pyvoice/pyvoice/pyvoice.py

# -*- coding: ISO-8859-1 -*-

 
Modules
            
GDK
binascii
copy
os
pytsp
random
socket
string
struct
sys
time
 
Functions
            
_(somestr)
Used internally. Gettext support 'place-holding' method. Method is replaced 
by the graphical user interface with a REAL gettext support method.
build_rec_packet(data64)
Builds appropriate packets for sending recorded TrueSpeech data ('data65') from 
the microphone.  Returns a string containing the formatted packet, or an 
empty string '' if the length of 'data64' is not appropriate. This method encodes
the TrueSpeech data into the appropriate RTP-format packet, generally 
either 112 or 90 bytes in length, depending on the 'byte model' we use. 
The default is to create packets of 112 bytes.
 
Here we build the packet of recorded TrueSpeech data to be sent to the voice chat
server.  Not including UDP headers, the RTP packets size of sent sound is always 
exactly 112 bytes or 90 bytes.   Here's the structure  (112-byte packet):
        First 2 bytes:  '\x80\xac' (first packet) or  '\x80\x22' (all others)
        Packet sequence number: in hex, padded to 2 bytes
        Packet time stamp: in hex, multiple of 10, padded to 4 bytes
        4-byte voice server 'nick name' assigned to us (synchronization source ID)
        2-byte delimiter: '\x00\x02' - the start of the RTP 'payload'
        96 bytes of TrueSpeech data  (a multiple of 32) 
        2-byte footer: '\xff'+[any_hex_char]   ex: '\xff\xef'
        
        * For 90-byte packets, we send 64 bytes of TrueSpeech data in the 'payload'
           instead of 96.
Here's an example RTP Sound packet:
 
"     mBRQZb,YZp񼥀y4pAQ+R{ӊ&+7qd5 8HU w
 
\x80\x22\x00\x0d\x00\x00\x16\x80\x09\x6d\xb6\xc7\x00\x02\xa1\x42\x52\x51\x5a\x62\x2c\x59\x19\x17\xba\x5a\x85\xbf\x98\x70\xa4\x90\xf1\xbc\xa5\x80\xfa\xda\xf4\xd1\x79\x9d\x34\x8d\x70\x9d\xdb\xc2\x41\x51\x2b\xb9\x52\x7b\xd3\x8a\x02\x26\x2b\x37\x10\x1b\xc5\x71\x64\xcf\x35\xaf\x0b\xb0\xb4\x38\x8c\x48\x55\x00\x0b\x77\xff\xe1
 
The total packet size sent to Yahoo, including UDP headers (handled by Python) and 
our RTP packet is  156  bytes, according to Ethereal - for the 112-byte 
packet model....total TCP size for 90-byte model: 124 bytes.  8-)
close_sound()
Used internally by the graphical user interface.  This method MUST be called by 
the graphical user interface as the LAST method called in the pyvoice library to 
uninitiate the PyTSP library used by pyvoice and close/free the sound device(s).
create_ip_from_hex(somes)
Creates an IP address from a 4-byte hex string.  This
method determines the IP address of the server Yahoo
is telling us to forward our connection to.  This method
converts strings like '\xd8mv\x91' to '216.109.118.145', 
'B\xdaF'' to '66.218.70.39', etc.  This method takes 
one argument: A 4-byte hex string.  This method is called by
'parse_server_redirection' to find the redirected IP address.
dbprint(some_str)
 Used internally. Prints debugging information to stdout.
doMicTest(*args)
Used internally by the pyvoice.py library to run a microphone test.  The method 
pretends that we are connected to Yahoo, records a few seconds of sound, then 
plays it back on the sound device. This method is access by the thread launched 
in 'startMicTest'.  No sound data is sent to the Yahoo voice chat servers.
do_server_redirect()
Used internally to handle our voice chat server redirection, when we first attempt 
to login to one TCP server and Yahoo! forwards us to another TCP voice chat server.
extract_tsp_sound(some_packet)
        Used internally to extract TrueSpeech data from a RTP-over-UDP packet 
        received from the Yahoo! UDP voice chat server.  Each sound packet should 
        be a total of 112 bytes in length, hold 96 bytes of TrueSpeech data.  This 
        method extracts the 96 bytes of sound and adds it to the sound buffer 
        to be played on the sound device.  This method also uses information in the 
        packet to determine who is talking.
 
        The sound packet looks something like this:
        \x80"   0\x00\x19\x06\xe0       \xc64j\x00\x02\xd5d\x1b\xbd5\xe4\xf0\x14\xdd\x1f\x01\x8f.\x01^\x9e\x19z j\xf4\xdc\xa1\xca\xdd<2\x83\xbf\x8c\xc9\x02y\x15l\xb3\xb4\xa7\x13\xf2\x15\x0f\xfa\x06\x989_*\x1a\x9c\xdcu\xc2\x0c?{C\x9b \xc1a\x1c\xa5\xed\xd7\x11m!\x99\xc5\xa1l\x18\x00\x8b
\x8b\xa7\xc0\xd1\x13\xdd\xadu6\xfc\xca\xf8\x06\xdc\x8c\xbb=\xcb\x15\x90\xd3\xff\xf7\x00 \x06dns-0
 
        Anything starting with '\x' is an escape character.  The RTP header is between the 
        '\x80' and the '\x00\x02' (12 bytes).  The payload (the tsp sound) starts 
        immediately after the '\x00\x02' and ends with the last '\xff'.  And, the tsp sound 
        should be exactly 96 bytes once extracted. Trying to play sounds of other sizes 
        has only resulted in garbled junk sound for me, even though the TrueSpeech codec 
        'tries' to play it, it just makes a bunch of noise.  So we will only play sounds that are 
        96 bytes once extracted.  Escape characters in python are much like escape characters
        in C...in Python: \xff = \ff in C, \x02 in Python = \02 in C, etc.
 
        Also, the length of the data sent to the TrueSpeech codec (through pytsp) must 
        be a multiple of 32  (96, 120, 240, 480, etc.).  It is not recommended to send 
        less than 240 bytes to pytsp,  since it won't sound like much.  Values between 960 and 
        1920+ seem best.  If we send data to truespeech codec when the length is NOT
        a multiple of 32, the sound we hear comes out very garbled and junky.
 
        Each packet also contains the short 'voice chat nick name' of the Yahoo user who is currently 
        talking:  this 'nick name' always starts at exactly the 9th byte and goes all the way up to the 
        '\x00\x02' (which denotes start of TSP sound).  The 'chat nick name' (officially called 
        the RTP synchronization source ID) is always 4 bytes exactly.
getEnableAutoChange()
Returns a boolean showing whether or not pY! Voice will automatically change voice 
chat rooms when the configuration file has changed.
getTCPOnly()
Returns a boolean showing whether or not we are using strictly TCP sockets for communications.
get_abc_len(letterS)
 Used internally. Letter to hex number mapping. Returns a string.
get_abc_num_len(numberS)
 Used internally. Hex number to letter mapping. Returns a string.
get_best_padding(suggest)
 Used internally to get a recommended packet padding size.
get_chat_room_name()
Used internally by the graphical user interface get the current voice chat room 
name.  Returns a string.
get_chat_status()
Gets the Yahoo! voice chat connection status:
        0=not connected at all
        1=connecting/logging in
        2=full connected
get_configuration_file()
Used internally as a central method for returning the name of the PyVoice library
configuration file, usually of the form '/tmp/pyvoice_chat_start_[unix-username]'.  
This is the same configuration file that must be written to 
by the Yahoo chat client (probably GYach Enhanced).  If written to correctly 
by the Yahoo chat client, the file should be formed as follows:
        [CHAT USER NAME]
        [CHAT ROOM NAME]
        [CHAT ROOM SERIAL NUMBER]
        [CHAT ROOM COOKIE]
get_esd_info()
 Used internally. Returns a string containing the PyESD library information.
get_esd_sversion()
 Used internally. Returns a string containing the PyESound version.
get_esd_version()
 Used internally. Returns a string containing the PyESD version.
get_esd_volume()
Used internally by the graphical user interface to get the current playback volume 
on the ESound sound daemon.  Returns an 'int':  the 'accuracy' of which is not 
yet known.  This value is polled constantly by the graphical user interface for 
on-screen volume display.
get_hex_len(hexchar)
 Used internally. Char to hex number mapping. Returns a string.
get_hex_num_len(hexnum)
 Used internally. Hex number to char mapping. Returns a string.
get_is_recording()
Used internally by the graphical user interface and the pyvoice.py library 
to determine if we are recording/sending sound out. Returns an int:
        0=Not recording/sending anything at all
        1=Attempting to record/send but failing
        2=Recording/sending successfully
get_padding(str_len)
Used internally by various methods to get needed packet padding.
Packets sent to yahoo must always be a length that is a multiple of 4, so 
this method returns necessary padding.
As far as I can see, this padding is just 'junk characters'. This method 
returns a string of length 'str_len' containing 'junk characters'.
get_pyvoice_error()
Returns a string containing the last error message.  This is monitored 
by the graphical user interface and shown to the user as-needed.
get_pyvoice_stats()
Returns a string containing useful statistics about the current pY! Voice Chat session.
get_rand_sound_card()
Used interally to return a random sound card name to Yahoo's servers.
get_requested_chat_room()
Used internally by the Graphical User Interface to compare the current 
voice chat room we are in to the chat room the Yahoo! chat client 
(probably GYach Enhanced) is in.  If the current room does not match 
the room that the Yahoo! chat client is in, the Graphical User Interface 
stops the current voice chat connection and reconnects to the right 
voice chat room by calling 'stopPyVoice()' followed by 'startPyVoice()'.
This method returns a string and is polled at regular intervals by the 
user interface.
get_room_length(room_len)
Internally used method to get the room length of 'room_len'.  This method returns 
a single character whose hexidemal value is equal to the length of 'room_len'.
get_sound_engine_info()
Returns a string containing information about PyTSP, PyESD, and ESound.
get_stats_for_user(mvar)
Returns a string containing the number of audio packets sent by the selected 
user in the voice chat room.
get_tsp_info()
 Used internally. Returns a string containing the PyTSP library information.
get_tsp_version()
 Used internally. Returns a string containing the PyTSP version.
get_users_in_room()
Used internally by the graphical user interface get a list of Yahoo! usernames
currently in the Yahoo voice chat room.  Returns a list.  This method may 
return a empty list [] or a list with duplicate usernames.  It is the job of the 
graphical user interface to handle the elimination of duplicate usernames.
get_vchat_server_list()
This method returns a list of known voice chat 
servers to be listed in the Graphical User Interface for
user selection.  This method takes no arguments 
and returns a python list of IP addresses.
get_voice_server()
Used internally by the graphical user interface to get the name of the name of the 
voice chat server currently being used for initial TCP connections to Yahoo! Returns 
a string.  This method does NOT return the name of any TCP servers we may have 
been re-directed to.
get_who_is_talking()
Used internally by the graphical user interface get the username of the 
Yahoo! user who is currently speaking.  Returns a string. This method may 
return an empty string '' if nobody is currently speaking or if the
username of the user speaking could not be determined.
get_y_exe()
The method 'get_y_exe' is used for creating random, appropriate 'exe' 
values to make it harder for Yahoo! to block us as a 'foreign' chat 
application (if they ever decide to do that.), used internally.
example,  known to work:  YAHJVOX
get_yah_sig()
Used interally to return a random 'application signature' to Yahoo! during 
the login process of 'send_pager_auth'.
guess_whose_talking(pack_part)
 Used internally.  Makes a logical, usually accurate guess at who is speaking if 
all other parsing methods have failed.  Accepts a string.  Returns a string.
ignore_user(mname)
Used internally by the graphical user interface to place a user on ignore, where 
'mname' is the name of the Yahoo user to be ignored.  This method then 
sends a UDP packet using the method 'send_ignoreon_packet' to inform the 
Yahoo voice server that we no longer wish to receive sound from user  
'mname'.  (This feature should be considered experimental.)  As a backup, if Yahoo 
fails to honor our 'ignore' request, PyVoice will make every attempt to avoid 
playing sound from ignored users even if it is sent to us from the Yahoo voice 
server.
is_mic_test()
Used internally by the pyvoice.py library to distinguish between whether 
we are truly recording/sending data to Yahoo or conducting a local microphone 
test.  Returns an int: 0=not a mic test, 1=is a mic test.
load_ignore_list()
Used internally to load the list of ignored users from the file ~/.pyvoice_ignore .  This method 
also merges in the list of GYach Enhanced ignored users from the file ~/.yahoorc/gyach/ignore 
if the file exists and is readable.  This method is called automatically and does not throw an 
exception. This method does not return a value.
open_sound()
Used internally by the graphical user interface.  This method MUST be called by 
the graphical user interface before anything else to initiate the PyTSP library 
used by pyvoice and prepare the sound device. No sound should be 
played or recorded before this method is called, which means no UDP or TCP 
connections should be initiated before this method is called.
open_tcp(some_srv='66.218.70.37', which_socket=0)
Used internally to open a TCP socket to a Yahoo voice 
server on port 5001. This method should never raise an exception.
Returns 1 if successful, 0 on failure (error messages are saved for retrieval if 
failure occurs.)
open_udp(*args)
Used internally to open a UDP socket to a Yahoo voice 
server on port 5000. This method should never raise an exception.
Returns 1 if successful, 0 on failure (error messages are saved for retrieval if 
failure occurs.)
parse_member_list(data)
Internal method for parsing a list of members in the current voice chat room. 
This method also parse new, single-user 'join' packets, adding all newly found 
users to the list of room members. 
 
Here's part of a sample chat list:
\x00\x00\x00\x00\x9d+\x14\x01\x11dizstudrocczfemz@\x00\x00\x9d9\x04\x01\x0eoooooooh_lila@\x00\x00\x00\x00\x00\x9d;\xe4\x01\x0ccharlavoz03
 
Voice chat room 'join' packets let us know that we are connected to voice chat 
and have 'list' of voice chat users.
 
For private conferences and PM conferences, the Yahoo! usernames in the member 
list are of the structure:  'username@123.60.20.5:5000'.
parse_server_redirection(data)
Internal method called when Yahoo's TCP server sends us a packet redirecting us 
to another TCP voice chat server.  This method parses the packet for the 1 special
character that is mapped to a Yahoo TCP server IP address.  If the redirection 
is unknown or appear bogus, the connection is stopped.  Otherwise, 
a new connection is made the the TCP server we have been forwarded to.
Sometimes, we can be redirected to up to 3-4 servers, apparently for Yahoo's 
load-balancing attempts.  This method calls 'do_server_redirect' to make a new 
connection to the TCP server we have been redirected to.  This method 
calls the 'create_ip_from_hex' method to convert a 4-byte hex string 
provided by Yahoo into the IP address we are forwared to.
parse_synch_id(data)
Internal method for parsing the 'chat_name_nick' (the RTP synchronization source 
ID) we are assigned from Yahoo's TCP server.  This 4-byte ID is needed for 
connecting and communicated via RTP over Yahoo's UDP server.
parse_user_leave(data)
Internal method that parses TCP packets sent from Yahoo informing us that a user 
has left the voice chat room.  The packet will provide the 4-byte synchronization source 
ID of the user who has left.  This method takes care of removing the exiting user from 
the list of chat room members.  This method does NOT clear 'ignored' users from the 
ignore list.
 
Example Yahoo TCP 'user has left' packet:
\x00T\x00\x00\x81\xc8\x00D\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x82\xcb\x00\x0c\x01\x00\xda\x14\x81\x00\xda\x14
 
The 'gone' ID comes right after the '\x82\xcb\x00\x0c', 
So this 'gone' ID is '\x01\x00\xda\x14'
pop_error(errm)
 Used internally. Sets the current error message.
processTCPData(which_socket=0)
Used internally by a thread to handle data received from a Yahoo! TCP socket.
processUDPData()
Used internally by a thread to handle data received from a Yahoo! UDP socket.
Generally, RTP data is handled here.
read_config()
Used internally to read the voice chat configuraton file created by GYach Enhanced
when we enter a new room that allows voice chat.
recordForSend(*args)
Used internally by the pyvoice.py library.  It is accessed by the thread launched from 
'recording_on'.  It polls the microphone, recording sound and encoding it to 
TrueSpeech.  TrueSpeech sound is then added to a sound buffer to be sent 
to the Yahoo voice chat UDP server by another thread.
recordSend(*args)
Used internally by the pyvoice.py library.  This method is launched as a thread 
from 'recordForSend'.  It checks the sound buffer at intervals.  If 
a sufficient amount of recorded TrueSpeech sound is 
available to be sent to Yahoo, this method encodes the data into RTP-format 
using 'build_rec_packet' and forwards the data on to Yahoo's voice chat server 
for other users to hear.  This thread quits automatically when the user has 
stopped recording/sending sound from the microphone.
 
For private conferences and PM conferences, the Yahoo! usernames in the member 
list are of the structure:  'username@123.60.20.5:5000', because apparently when 
in PM chat or private conference, we must send the sound to all the IP addresses 
on our list, and Yahoo's servers only act as a 'registry' for all the users in the 
conference (basically, just letting us know when people come in and leave the 
voice conference.)  This is just a GUESS on my part.  Either way, I have had 
no luck sending sound to Yahoo's servers when in 'conference' mode and others 
actually hearing it, so for 'conference' mode this application sends the sound to all 
IP addresses in the conference.  For regular chat room mode, sound is transmitted 
to one of Yahoo's UDP voice servers.  For private conferences and PMs, sound 
will be 'broadcast' to each IP address present on our list of voice chat room members.
Conference mode may mean trouble for firewall users if they don't have their 
firewall configured to send/receive UDP packets from the IP addresses of their friends 
in the private conference or PM.
recording_off(*args)
Used internally by the graphical user interface to stop recording and sending 
sound data to the Yahoo! voice chat servers.
recording_on(*args)
Used internally by the graphical user interface to start recording and sending 
sound data to the Yahoo! voice chat servers.  This method launches the 
'recordForSend' thread.
runSoundThread(*args)
Used internally by a thread to check the sound buffer for available sound to 
play to the sound device.
save_ignore_list()
Used internally to save the list of ignored users in the file ~/.pyvoice_ignore .  This method
is called automatically whenever ignore_user() or unignored_user() is called and does not
throw an exception.      This method does not return a value.
sendShuttingUp()
This basically sends the RTP packet to Yahoo's UDP server letting them know we have 
stopped talking.  The packet is always 12 bytes (not 
including UDP headers handled by Python) and is very simple in format:
 
        First 2 bytes:  '\x80\x22'
        Packet sequence number: in hex, padded to 2 bytes
        Packet time stamp: in hex, always equals 0, padded to 4 bytes
        4-byte voice server 'nick name' assigned to us (synchronization source ID)
 
        ** This packet has no RTP 'payload'.
 
Here's an example "I'm shutting up" packet:
        "T        m
 
        \x80\x22\x00\x54\x00\x00\x00\x00\x09\x6d\xb6\xc7
 
NOTE: This is very similar to the UDP 'login' string we send as our very first 
packet in the method 'sendUDPLogin'
 
The total packet size, including UDP headers (handled by Python) and our RTP 
packet above is 54 bytes according to Ethereal.
sendTCPLogin(*args)
Used internally by a thread to send our initial login string to a Yahoo! TCP 
server.  This method should not raise an exception. Returns an int: -1 or 0 
on failure, or  greater than 1 on success.
 
For a regular chat room, the login string will look something like this:
\x00\xb4\x00\x00\x81\xc9\x000\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x80\xcc\x00\x80\x00\x00\x00\x00CA!Y\x00\x01\x00\x00\x00\x00\x00\x01d\x02\x00\x02e\x02\x00\x03\x02\x0cpmokername\x03$ch/pmokername'sroom:1::1600084740\x07"6wB_.ArnJatIDY2sxrvKldFPlfO.QEPyM-\x06\x00\x05\x02\x00\x19\x08\x04\xac\x91Ha
 
For a private conference, the login string will look something like this:
\x00|\x00\x00\x81\xc9\x000\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\xcc\x00H\x00\x00\x00\x00CA!Y\x00\x01\x00\x00\x00\x00\x00\x02d\x02\x00\x02e\x02\x00\x03\x02\x07mmm__ab\x03\x10me/mmm__ab-72249\x07\x00\x06\x00\x05\x02\x00\x19\x08\x04\xac\xaf\x10\x96\x00\x1e\x04
 
Here is the basic structure of the TCP login packet:
        First 2 bytes:  denote the length of the packet (in hex)
                example: '\x00\xb4' = 180 bytes packet length
                derived from:  struct.pack("!h", 180 )  
        Next 50 bytes:  '\x00\x00\x81\xc9\x000\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
        Next 2 bytes:  '\x80\xcc'
        Next 2 bytes:  
                2 chars denoting the length of the remainder of the 
                packet (including the padding), plus 4  (for the 2 bytes above, 
                plus the 2 byte of these chars themselves.)
                example: '\x00\xb4' = 180 bytes packet length
                derived from:  struct.pack("!h", 180 )  
        Next 25 bytes:                  '\x00\x00\x00\x00CA!Y\x00\x01\x00\x00\x00\x00\x00\x01d\x02\x00\x02e\x02\x00\x03\x02'
        Next 1 bytes:  
                one char denoting the length of the username of the person logging on, the 'length' is a hex char
        Next (variable number) of bytes:  
                the username of the person logging on
        Next 1 byte: '\x03'
        Next 1 byte:  
                one char denoting the length of the FULL room name - the char is hex.
 
                For regular chat rooms, this length includes the length of 'ch/' + the length of the room name 
                + the length of '::' + the length of the chat room's 'serial number' - example: 
                the length of 'ch/pmokernameasroom:1::1600084740' .  The length of this string is 36, so the 
                hex char needed here is '$' (0x24).   In this example, the room name is
                'pmokernameasroom:1'  - regular chat rooms always are followed by a ':' and a room number.
 
                For private conference rooms, this length includes the length of 'me/' + the length of the 
                room name   (NO '::', NO 'serial number')  - example:  the length of 'me/mmm__ab-72249' is 
                16, so the hex char needed for this one is '\x10'  (0x10)
 
        Next 3 bytes:
                regular chat room:  'ch/'
                private conference or PM:  'me/'
        Next (variable number) of bytes:  
                the full name of the chat room the user is entering
                regular chat room example: 'En espanol:1'
                private conference example: 'myname-21847'
        Next 2 bytes (regular chat room only):  '::'
        Next (variable number of bytes, regular chat room only):  
                The 'serial number' of the chat room, example '1600084740'
                These serial numbers always seem to start with '16000'.
                Chat room 'serial' numbers do not appear to be used in private conferences and PM
                conferences.
        Next 1 byte: '\x07'
        Next 1 byte:
                regular chat room:  '"'   (quotation mark)
                private conference:  '\x00'   (null byte)
        Next (variable number) of bytes  (regular chat room only):
                The 'cookie' for the chat room, example: '6wB_.ArnJatIDY2sxrvKldFPlfO.QEPyM-'
                Chat room 'cookies' are for regular chat rooms online (not private conferences), and 
                seem to be 34 bytes in length, if I remember correctly.
        Last  9 bytes:  '\x06\x00\x05\x02\x00\x19\x08\x04\xac'
        Maybe be necessary:
                0-3 bytes of 'padding', since all packets must have a length that is a multiple of 4.
                The 'padding' can be junk character bytes.      
 
        * Note private conferences and PM conferences do not use chat room 'serial' numbers or 
           chat room 'cookies'.
sendTCPLogout()
 Used internally for sending the 'logout' string when we ask to disconnect from the voice server
 
The 'logout' packet is always exactly 60 bytes and is pretty straight forward.
 Examples:
 
   \x00\x3c\x00\x00\x81\xc9\x000\x07=f\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81\xcb\x00\x08\x07=f\x0b
 
   \x00\x3c\x00\x00\x81\xc9\x000\x06#2\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81\xcb\x00\x08\x06#2\x01
sendUDPLogin()
Used internally by a running thread to handle logging into the Yahoo UDP 
voice chat server. 
 
Here is our initial, first RTP packet communication with Yahoo's UDP server.
The UDP 'login' string is always 12 bytes (not including the UDP headers 
handled by Python).  Here is the structure of the 12-byte UDP packet:
        First 2 bytes: '\x80\xa2'
        RTP packet seqence: in hex, always 1, padded to 2 bytes ('\x00\x01')
        RTP packet time stamp: in hex, always 0, padded to 4 bytes ('\x00\x00\x00\x00')
        4-byte voice server 'nick name' assigned to us (synchronization source ID)
 
        ** This packet has no RTP 'payload'.
        
Example RTP login packet: 
        \x80\xa2\x00\x01\x00\x00\x00\x00\xef\xb0\xc7\x22
send_ignoreoff_packet(rtpkey)
This method sends a very simple packet to Yahoo's voice TCP server informing 
Yahoo that we want to UN-ignore the Yahoo user with the 4-byte synchronization 
source ID 'rtpkey'.  If all goes well, Yahoo will start sending us sound again 
from the user we wish to un-ignore. This feature should be considered experimental.
Possible problem: If Yahoo! fails to un-ignore or un-mute the user 'rtpkey', we may 
find that the user is on 'mute' until we logoff then log back on to Yahoo!
 
The packet sent is always 76 bytes in length.  Here is the format:
        First 8 bytes:  '\x00L\x00\x00\x81\xc9\x000'
        Next 4 bytes:  Our 4-byte synchronization source ID  'chat_name_nick'
        Next 44 bytes:  '\x00\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xd5\x00\x00\x00$\x00\x00\x00\x00\x00\x01\x1b4\x80\xcc\x00\x18'
        Next 4 bytes:  The 4-byte synchronization source ID of the user to be un-ignored
        Last 16 bytes:  'CA!Y\x00\x0f\x00\x00\x00\x00\x00 \x0e\x02\x00\x00'
 
Here is an example 'ignore' off packet:
\x00L\x00\x00\x81\xc9\x000\x04%\x8e=\x00\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xd5\x00\x00\x00$\x00\x00\x00\x00\x00\x01\x1b4\x80\xcc\x00\x18\x03\xaeA\xadCA!Y\x00\x0f\x00\x00\x00\x00\x00 \x0e\x02\x00\x00
send_ignoreon_packet(rtpkey)
This method sends a very simple packet to Yahoo's voice TCP server informing 
Yahoo that we want to ignore the Yahoo user with the 4-byte synchronization 
source ID 'rtpkey'.  If all goes well, Yahoo will stop sending us sound from the 
user we wish to ignore.  This feature should be considered experimental.
 
The packet sent is always 76 bytes in length.  Here is the format:
        First 8 bytes:  '\x00L\x00\x00\x81\xc9\x000'
        Next 4 bytes:  Our 4-byte synchronization source ID  'chat_name_nick'
        Next 44 bytes:  '\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xd5\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\xb74\x80\xcc\x00\x18'
        Next 4 bytes:  The 4-byte synchronization source ID of the user to be ignored
        Last 16 bytes:  'CA!Y\x00 \x00\x00\x00\x00\x00\x04\x0e\x02\x00\x00'
 
Here is an example 'ignore' on packet:
\x00L\x00\x00\x81\xc9\x000\x04%\x8e=\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xd5\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\xb74\x80\xcc\x00\x18\x03\xaeA\xadCA!Y\x00 \x00\x00\x00\x00\x00\x04\x0e\x02\x00\x00
send_pager_auth()
Used internally.  During the login process Yahoo asks us to provide information
about our Yahoo! chat client and our audio setup.  This method provides that 
information to the Yahoo TCP connection. The name of our application is the 
'exe' value we send.  
 
Strangely enough - the 'exe' value must be ANYTHING but 'YPAGER'. 
I believe users of YahElite and Y!mLite report this same problem. The method 
'get_y_exe' is used for creating random, appropriate 'exe' values to make it 
harder for Yahoo! to block us as a 'foreign' chat application (if they 
ever decide to do that.)
send_udp_ack_keepalive(data)
Internal method to send a 'keep-alive' string back to Yahoo's UDP server when Yahoo 'pings' us or 
asks 'are you still there?'  
 
This happens when somebody stops talking (sometimes 
WHILE somebody is talking also). Yahoo kind of sends 
a 12-byte packet that let's us know they stopped talking and asks
"do you read me?".  If we fail to respond to enough of these 
packets, Yahoo will boot us from the voice server after about 10-15
minutes.  The response is simple:
 
We get sent a packet that looks something like:
\x80\xa2\x00\x01\x07?r\xcb\x00\x00\x00\x00
 
        Format:
        First 2 bytes: ''
        Next 2 bytes: Packet sequence number (ex: '\x00\x01')
        Next 4 bytes: Packet time stamp (ex: '\x07?r\xcb')
        Last 4 bytes: Null bytes (usually) - '\x00\x00\x00\x00'
 
        * This packet has no RTP 'payload'.
        * It is an 'empty' RTP packet with just the basic RTP header.
 
Our response - The only thing we really need to do is change the 
RTP marker  '\xa2' to '\x22'  (a quotation mark).
 
So we will send back a packet that looks like (as an example):
\x80\x22\x00\x01\x07?r\xcb\x00\x00\x00\x00
 
NOTE: We will always get a similar 12-byte string sent back to us 
right after we have logged into the UDP server using method 'sendUDPlogin'.
And, we do NOT want to respond to that string.  We will only send a 
response if the string sent to us does NOT include our 'chat_nick_name' (or 
RTP synchronization ID).
setEnableAutoChange(autoval)
This method is assessed by the graphical user interface and takes on argument, 'autoval' 
(integer: 0 or 1).  If autoval is set to 1, the current voice room will not be changed 
automatically even if the configuration file suggests we should be in another voice chat room.
setTCPOnly(tcpval)
This method is assessed by the graphical user interface and takes on argument, 'tcpval' 
(integer: 0 or 1).  If tcpval is set to 1, only TCP connections will be used to communicate
with the voice servers; otherwise the connection will start with TCP, then use UDP for 
all RTP communications on port 5000.
set_debug(dbval)
Used internally by the graphical user interface to toggle debuggin on/off, 
where dbval=0 or dbval=1.
set_mute(mvar)
Toggles mute on/off, where mvar=0 or mvar=1. For muting the chat room, 
though voice data will continue to be received, just not played to the sound device.
set_voice_server(serv)
Used internally by the graphical user interface to set the selected voice chat 
server to non-null string 'serv'.
setup_esd_host(some_host)
Used internally by the graphical user interface to set the ESound host for 
sound playback.  This does NOT set the host for recording/sending sound, which 
is always 'localhost'.
spool_sound(*args)
Used internally by a thread to check the sound buffer for available sound to 
play to the sound device.  Called at intervals by the 'runSoundThread' 
method.  If an adequate amount of sound is available in the sound buffer, 
sound is fed in fragments to the sound device.  Also, this method takes 
care of closing the ESound sound device if it has been idle for a while, and 
clears the name of the Yahoo user said to be speaking if that name has 
gone 'stale' with no incoming sound from that person for several seconds, 
since Yahoo sometimes fails to tell us when a user has stopped talking. 
In addition, if this method finds sound to play to the sound device, it 
temporarily disables recording/sending of sound data to avoid the 
problem of 'snatching the mic' from another user who is already talking - 
which most civilized people consider to be rude.  Once there is no more 
sound to play, the ability to record/send sound is restored.
startMicTest(*args)
Used internally by the pyvoice.py library to launch the microphone test thread. 
This method launches a thread to handle the method 'doMicTest'.
startPyVoice(*args)
Used internally by the graphical user interface to start the login process to the 
Yahoo voice chat servers.
start_sound_spool(*args)
Used internally by a running UDP socket-reading thread.  After we have successfully 
logged into the Yahoo voice chat UDP server, this method is called to launch a thread 
which plays sound to the sound device as it is retrieved, extracted, and added 
to the sound buffer by the method 'extract_tsp_sound'.  This thread automatically 
'dies' when we disconnect from the voice servers.  This method launches a thread 
for the 'runSoundThread' method.
stopMicTest(*args)
Used internally by the pyvoice.py library to stop the microphone test.
stopPyVoice(*args)
Used internally by the graphical user interface to logout of the Yahoo! voice chat 
servers and close all sockets.  This method may also be used to close a connection 
that is in the process of 'logging in' to the voice chat servers. NOTE: This method 
does not stop playback of any remaining sound in the sound buffer. So, it is 
possible to continue hearing a few seconds of sound on the sound device after 
disconnecting from the Yahoo voice chat servers.
tcpPoll(which_socket=0)
Used internally to poll a TCP socket for incoming data.  Accessed by internal
TCP reading Threads.
tcpThreadRead(*args)
Used internally to provide the Thread functionality for handling our very first 
TCP connection to a Yahoo! voice server.
tcpThreadRead2(*args)
Used internally to handle our voice chat server redirection, when we first attempt 
to login to one TCP server and Yahoo! forwards us to another TCP voice chat server.
Closes old TCP connections and provides the Thread functionality for handling 
the server redirection.
tcp_close(which_socket=0)
Used internally to close a TCP socket. This method should never raise an exception.
tcp_recv(len, which_socket=0)
Used internally to receive data from a TCP socket.  This method should never 
raise an exception.  This method may return a string of data or an empty string ''.
tcp_send(data, which_socket=0, with_size=0)
Used internally to send data to a TCP socket. 
This method should never raise an exception.  Returns an 'int' - the 
length of the data sent, or -1 if sending fails.
udpPoll()
Used internally to poll a UDP socket for incoming data.  Accessed by internal
UDP reading Threads.
udpThreadRead(*args)
Used internally by a thread to handle connecting to and polling a Yahoo! UDP 
voice chat server.
udp_close()
Used internally to close a UDP socket. This method should never raise an exception.
udp_recv(len)
Used internally to receive data from a UDP socket.  Generally used to receive 
RTP data over Yahoo's RTP-over-UDP connections. This method should never 
raise an exception.  This method may return a tuple or an empty string ''.
udp_send(data, phost=None, pport=None)
Used internally to send data to a UDP socket. Generally this method is 
used to send RTP data to Yahoo's RTP-over-UDP connections.
This method should never raise an exception.  Returns an 'int' - the 
length of the data sent, or -1 if sending fails.
unignore_user(mname)
Used internally by the graphical user interface to remove a user from ignore, where 
'mname' is the name of the Yahoo user to be un-ignored.  This method then 
sends a UDP packet using the method 'send_ignoreoff_packet' to inform the Yahoo 
voice server that we wish to resume receiving sound from user 'mname'. (This 
should be considered experimental for now.)
update_esd_volume(*args)
user_is_ignored(mname)
Used internally by the graphical user interface and the pyvoice.py library to 
determine if the Yahoo! user 'mname' is currently on 'ignore'. Returns an int: 
0=not ignored, 1=ignored.  Currently, sound data 
from the user will continue to be received, but will not be played to the sound 
device.
 
Data
             ACCEL_LOCKED = 4
ACCEL_MASK = 7
ACCEL_SIGNAL_VISIBLE = 2
ACCEL_VISIBLE = 1
ANCHOR_CENTER = 0
ANCHOR_E = 8
ANCHOR_EAST = 8
ANCHOR_N = 1
ANCHOR_NE = 3
ANCHOR_NORTH = 1
ANCHOR_NORTH_EAST = 3
ANCHOR_NORTH_WEST = 2
ANCHOR_NW = 2
ANCHOR_S = 4
ANCHOR_SE = 6
ANCHOR_SOUTH = 4
ANCHOR_SOUTH_EAST = 6
ANCHOR_SOUTH_WEST = 5
ANCHOR_SW = 5
ANCHOR_W = 7
ANCHOR_WEST = 7
APP_PAINTABLE = 524288
ARROW_DOWN = 1
ARROW_LEFT = 2
ARROW_RIGHT = 3
ARROW_UP = 0
BASIC = 262144
BUTTONBOX_DEFAULT_STYLE = 0
BUTTONBOX_EDGE = 2
BUTTONBOX_END = 4
BUTTONBOX_SPREAD = 1
BUTTONBOX_START = 3
CALENDAR_NO_MONTH_CHANGE = 4
CALENDAR_SHOW_DAY_NAMES = 2
CALENDAR_SHOW_HEADING = 1
CALENDAR_SHOW_WEEK_NUMBERS = 8
CALENDAR_WEEK_START_MONDAY = 16
CAN_DEFAULT = 8192
CAN_FOCUS = 2048
CELL_EMPTY = 0
CELL_PIXMAP = 2
CELL_PIXTEXT = 3
CELL_TEXT = 1
CELL_WIDGET = 4
CENTIMETERS = 2
COMPOSITE_CHILD = 131072
CONNECTED = 4
CONSTRUCTED = 8
CORNER_BOTTOM_LEFT = 1
CORNER_BOTTOM_RIGHT = 3
CORNER_TOP_LEFT = 0
CORNER_TOP_RIGHT = 2
CTREE_EXPANDER_CIRCULAR = 3
CTREE_EXPANDER_NONE = 0
CTREE_EXPANDER_SQUARE = 1
CTREE_EXPANDER_TRIANGLE = 2
CTREE_EXPANSION_COLLAPSE = 2
CTREE_EXPANSION_COLLAPSE_RECURSIVE = 3
CTREE_EXPANSION_EXPAND = 0
CTREE_EXPANSION_EXPAND_RECURSIVE = 1
CTREE_EXPANSION_TOGGLE = 4
CTREE_EXPANSION_TOGGLE_RECURSIVE = 5
CTREE_LINES_DOTTED = 2
CTREE_LINES_NONE = 0
CTREE_LINES_SOLID = 1
CTREE_LINES_TABBED = 3
CTREE_POS_AFTER = 2
CTREE_POS_AS_CHILD = 1
CTREE_POS_BEFORE = 0
CURVE_TYPE_FREE = 2
CURVE_TYPE_LINEAR = 0
CURVE_TYPE_SPLINE = 1
DESTROYED = 1
DEST_DEFAULT_ALL = 7
DEST_DEFAULT_DROP = 4
DEST_DEFAULT_HIGHLIGHT = 2
DEST_DEFAULT_MOTION = 1
DIRECTION_LEFT = 0
DIRECTION_RIGHT = 1
DIR_DOWN = 3
DIR_LEFT = 4
DIR_RIGHT = 5
DIR_TAB_BACKWARD = 1
DIR_TAB_FORWARD = 0
DIR_UP = 2
EXPAND = 1
FALSE = 0
FILL = 4
FILL_X = 2
FILL_Y = 4
FLOATING = 2
HAS_DEFAULT = 16384
HAS_FOCUS = 4096
HAS_GRAB = 32768
INCHES = 1
JUSTIFY_CENTER = 2
JUSTIFY_FILL = 3
JUSTIFY_LEFT = 0
JUSTIFY_RIGHT = 1
LEFT_RIGHT = 1
MAPPED = 128
MATCH_ALL = 0
MATCH_ALL_TAIL = 1
MATCH_EXACT = 4
MATCH_HEAD = 2
MATCH_LAST = 5
MATCH_TAIL = 3
MENU_DIR_CHILD = 1
MENU_DIR_NEXT = 2
MENU_DIR_PARENT = 0
MENU_DIR_PREV = 3
MENU_FACTORY_MENU = 0
MENU_FACTORY_MENU_BAR = 1
MENU_FACTORY_OPTION_MENU = 2
NO_WINDOW = 32
ORIENTATION_HORIZONTAL = 0
ORIENTATION_VERTICAL = 1
PACK_END = 1
PACK_EXPAND = 1
PACK_START = 0
PARENT_SENSITIVE = 1024
PATH_CLASS = 2
PATH_PRIO_APPLICATION = 8
PATH_PRIO_GTK = 4
PATH_PRIO_HIGHEST = 15
PATH_PRIO_LOWEST = 0
PATH_PRIO_MASK = 15
PATH_PRIO_RC = 12
PATH_WIDGET = 0
PATH_WIDGET_CLASS = 1
PIXELS = 0
PIXELS_METRIC = 0
POINTS_METRIC = 1
POLICY_ALWAYS = 0
POLICY_AUTOMATIC = 1
POLICY_NEVER = 2
POS_BOTTOM = 3
POS_LEFT = 0
POS_RIGHT = 1
POS_TOP = 2
PREVIEW_COLOR = 0
PREVIEW_GRAYSCALE = 1
PROGRESS_BOTTOM_TO_TOP = 2
PROGRESS_CONTINUOUS = 0
PROGRESS_DISCRETE = 1
PROGRESS_LEFT_TO_RIGHT = 0
PROGRESS_RIGHT_TO_LEFT = 1
PROGRESS_TOP_TO_BOTTOM = 3
RC_STYLE = 65536
REALIZED = 64
RECEIVES_DEFAULT = 1048576
RELIEF_HALF = 1
RELIEF_NONE = 2
RELIEF_NORMAL = 0
RESIZE_IMMEDIATE = 2
RESIZE_PARENT = 0
RESIZE_QUEUE = 1
SCROLL_JUMP = 5
SCROLL_NONE = 0
SCROLL_PAGE_BACKWARD = 3
SCROLL_PAGE_FORWARD = 4
SCROLL_STEP_BACKWARD = 1
SCROLL_STEP_FORWARD = 2
SELECTION_BROWSE = 1
SELECTION_EXTENDED = 3
SELECTION_MULTIPLE = 2
SELECTION_SINGLE = 0
SENSITIVE = 512
SHADOW_ETCHED_IN = 3
SHADOW_ETCHED_OUT = 4
SHADOW_IN = 1
SHADOW_NONE = 0
SHADOW_OUT = 2
SHRINK = 2
SIDE_BOTTOM = 1
SIDE_LEFT = 2
SIDE_RIGHT = 3
SIDE_TOP = 0
SORT_ASCENDING = 0
SORT_DESCENDING = 1
SPIN_END = 5
SPIN_HOME = 4
SPIN_PAGE_BACKWARD = 3
SPIN_PAGE_FORWARD = 2
SPIN_STEP_BACKWARD = 1
SPIN_STEP_FORWARD = 0
SPIN_USER_DEFINED = 6
STATE_ACTIVE = 1
STATE_INSENSITIVE = 4
STATE_NORMAL = 0
STATE_PRELIGHT = 2
STATE_SELECTED = 3
TARGET_SAME_APP = 1
TARGET_SAME_WIDGET = 2
TOOLBAR_BOTH = 2
TOOLBAR_CHILD_BUTTON = 1
TOOLBAR_CHILD_RADIOBUTTON = 3
TOOLBAR_CHILD_SPACE = 0
TOOLBAR_CHILD_TOGGLEBUTTON = 2
TOOLBAR_CHILD_WIDGET = 4
TOOLBAR_ICONS = 0
TOOLBAR_SPACE_EMPTY = 0
TOOLBAR_SPACE_LINE = 1
TOOLBAR_TEXT = 1
TOPLEVEL = 16
TOP_BOTTOM = 0
TREE_VIEW_ITEM = 1
TREE_VIEW_LINE = 0
TROUGH_END = 2
TROUGH_JUMP = 3
TROUGH_NONE = 0
TROUGH_START = 1
TRUE = 1
UPDATE_ALWAYS = 0
UPDATE_CONTINUOUS = 0
UPDATE_DELAYED = 2
UPDATE_DISCONTINUOUS = 1
UPDATE_IF_VALID = 1
VISIBILITY_FULL = 2
VISIBILITY_NONE = 0
VISIBILITY_PARTIAL = 1
VISIBLE = 256
WINDOW_DIALOG = 1
WINDOW_POPUP = 2
WINDOW_TOPLEVEL = 0
WIN_POS_CENTER = 1
WIN_POS_MOUSE = 2
WIN_POS_NONE = 0
__file__ = './pyvoice.py'
__name__ = 'pyvoice'
allow_vol_update = 0
audio_packets = 0
audio_packets_S = 0
can_record = 0
chat_connect_status = 0
chat_cookie = ''
chat_name_nick = ''
chat_name_nicks = {}
chat_room = ''
chat_serial = ''
chat_user = ''
debug_on = 0
eighty_byte_model = 0
empty_buffer = 0
error_msg = ''
esd_volume = 0
gtk_version = (1, 2, 10)
gyach_ignore_file = '/root/.yahoorc/gyach/ignore'
hex_len_map = {1: '\x01', 2: '\x02', 3: '\x03', 4: '\x04', 5: '\x05', 6: '\x06', 7: '\x07', 8: '\x08', 9: '\t', 10: '\n', ...}
hex_len_map_num = {'\x01': 1, '\x02': 2, '\x03': 3, '\x04': 4, '\x05': 5, '\x06': 6, '\x07': 7, '\x08': 8, '\t': 9, '\n': 10, ...}
ignored_users = {}
ii = 'z'
is_recording = 0
last_login_string = ''
letter_len = 256
letter_len_map = {1: 'A', 2: 'B', 3: 'C', 4: 'D', 5: 'E', 6: 'F', 7: 'G', 8: 'H', 9: 'I', 10: 'J', ...}
letter_len_map_num = {'A': 1, 'B': 2, 'C': 3, 'D': 4, 'E': 5, 'F': 6, 'G': 7, 'H': 8, 'I': 9, 'J': 10, ...}
mic_test = 0
no_auto_server_change = 0
on_mute = 0
poll_connection = 1
pygtk_version = (0, 6, 9)
pyvoice_ignore_file = '/root/.pyvoice_ignore'
r_starttime = 0
record_sequence = 1
record_time = 0
rsound_data = ''
sdivider = '@'
snd_buflimit = 2048
sound_cut1 = 1568
sound_cut2 = 1824
sound_data = ''
sound_spool_started = 0
tcp_data = None
tcp_data2 = None
tcp_not_udp = 0
tcp_socket = None
tcp_socket2 = None
tcp_socket3 = None
total_packets = 0
total_packets_S = 0
udp_socket = None
user_stats = {}
vchat_port = 5001
vchat_port_udp = 5000
vchat_server = '66.218.70.37'
vchat_server2 = ''
vchat_udp_server = ''
who_is_talking = ''
who_is_talking_expire = 1088722794.8653581