# -*-coding:Latin-1 -*
"""fonction client du chat vocal (protocole UDP)"""
import socket
import time
import threading
import os

#modules complémentaires
import pymedia.audio.sound as sound
import pymedia.audio.acodec as acodec
import pyaudio

#modules perso
from anason import AnaSon
from lecture import Lecture


port = 6660
frequence = 22050
#param d'encodage/decodage
cparams= { 'id': acodec.getCodecID( 'mp3' ),
           'bitrate': 32000,
           'sample_rate': frequence,
           'channels': 1 }
taille_paquets = 1024
debug = False

######### Fils secondaires #########

class ThreadReception(threading.Thread):
    """fil gerant la reception du son"""
    def __init__(self, cnn, pseudo):
        """création du fil reception"""
        self.Terminated = False
        threading.Thread.__init__(self)
        self.cnn = cnn
        self.essais = 0
        self.connectes = {}
        self.pseudo = pseudo
        
    def run(self):
        """reception: tourne en boucle tant que la connexion est active"""
        time.sleep(0.1)
        while not self.Terminated:
            try:
                fr, adresse = self.cnn.recvfrom(taille_paquets)
                #print("recu {}".format(len(fr)))

                #les 4 premiers caracteres sont le pseudo de l'expediteur   
                expediteur = fr[:4]
                donnee = fr[4:]

                if expediteur == self.pseudo:
                    #si l'expediteur a le meme pseudo
                    expediteur[3] = "0" 
                 
                if not expediteur in self.connectes.keys():
                    #nouveau connecte
                    try:
                       fil = Lecture(expediteur, cparams, debug)
                       fil.start()
                       self.connectes[expediteur] = fil
                       print("\n -> Connecte a {}".format(expediteur))
                    except KeyboardInterrupt:
                       print("{} - Erreur de reception".format(expediteur))
                else: 
                   if donnee:       
                      self.connectes[expediteur].lire(donnee)
                
                self.essais = 0
            except IOError, e: 
               if e.errno == 10022:    
                   time.sleep(.003)
                   self.essais += 1
                   if self.essais == 200:
                      print("pas de reception")
                      self.Terminated = True

                      
    def stop(self):
        """Fermeture du fil Reception"""
        print("Fermeture du fil Reception\n")
        for elt in self.connectes.values():
            elt.stop()
            
        self.Terminated = True
        self.cnn.close()
        
        
#fin du fil reception


class ThreadEmission(threading.Thread):
    """fil gerant l'emission du son"""
    def __init__(self, cnn, pseudo, hote):
        """création du fil emission"""
        self.Terminated = False
        threading.Thread.__init__(self)
        self.cnn = cnn
        self.pseudo = pseudo
        self.hote = hote
        
        #flux microphone:
        self.stream = pyaudio.PyAudio().open(format = pyaudio.paInt16,    
                                             channels = 1,
                                             rate = frequence,
                                             input = True,
                                             frames_per_buffer = 1024)
        #encodage:
        self.ac = acodec.Encoder( cparams )

        #parametres de traitement du son:
        self.ana = AnaSon()
        #on recupere les parametres enregistres si possible
        self.ana = self.ana.recup()

    def run(self):
       """emission: tourne en boucle tant que la connexion est active"""
       #on affiche les parametres du micro
       print(self.ana)
       while not self.Terminated:
              #son = micro.getData()
              son = self.stream.read(1024)
              if son and len(son):
                  son_traite = self.ana.traitement(son)
                  if son_traite:
                     son_encode = self.ac.encode(son_traite)
                
                     for fr in son_encode:
                         if len(fr) < (taille_paquets - 6):
                             #on ajoute le pseudo au debut du paquet
                             envoi = self.pseudo + fr
                             #print("envoi {}".format(len(fr)))
                             self.cnn.sendto(envoi, (self.hote, port))
                         else:
                             print("1 paquet trop volumineux")
              else:
                  #si pas de son, on attend un peu
                  time.sleep(.003)
                  
    def stop(self):
       """Fermeture thread emission"""
       print("\nFermeture du fil Emission\n")
       self.Terminated = True
       #micro.stop()
       self.stream.close()
       self.cnn.close()
        
#fin du fil emission        

#objet client:
class ClientVoc():
    """client pour le chat vocal"""
    def __init__(self):
        """création du client"""
        self.pseudo = ""
        self.hote = ""
        self.port = 6660
        
        ###parametrage du socket udp###
        self.cnn = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.connecte = False

    def idClient(self):
        """recupere et met en forme l'identifiant du client"""
        while True:
            pseudo = raw_input("Pseudo (4 car. maximum) > ")
            if len(pseudo) > 0 and len(pseudo) <= 4:
                break                      
        if pseudo[:3]=="dbg":
            pseudo = pseudo[3:]
            debug = True
        while len(pseudo) < 4:
            pseudo += " " 
        self.pseudo = pseudo    

    def ipServeur(self):
        """recupere l'ip du destinataire"""
        hote=raw_input("Ip > ")
        if len(hote) == 0:
            hote="localhost"
        self.hote = hote
        
    def creerClient(self):
        """demarre une instance client pour le chat vocal"""
        if len(self.pseudo) > 0 and len(self.hote) > 0 :
            self.thE = ThreadEmission(self.cnn, self.pseudo, self.hote)
            self.thR = ThreadReception(self.cnn, self.pseudo)
            self.thE.start()
            self.thR.start()
            self.connecte = True
            print("\n\n*Connexion etablie\n")
        else:
            print("pseudo du client et/ou adresse du serveur non definis")  

    def quitterChat(self):
        """quitte la session de chat"""
        self.thE.stop()
        self.thR.stop()
        self.cnn.close()
        print("*Fin de la communication\n")             
            
### fil principal ###
if __name__ == "__main__":
   # si lancement direct:
   c = ClientVoc()
   c.idClient()
   c.ipServeur()
   c.creerClient()
   os.system("pause")
   c.quitterChat()



