PDA

Voir la version complète : Chat vocal en python



olinox14
29/01/2014, 17h57
Bonsoir chers canards,

Voilou, on est sur un projet de chat vocal en python, et je commence à m'arracher les cheveux à l'envers. Oui oui, en passant la main par mon tr... hors sujet? ok

Voilà donc le concept:

Un serveur + des clients
le tout connecté en tcp via des sockets, et la donnée audio acquise à l'aide du module pyaudio (et traitée au moyen du module audioop)

En réseau local (entre ma tour et mon ordi portable quoi), ça marche du tonnerre de dieu

MAIS le problème (car il y en a un):

C'est qu'à distance, c'est plutôt le tonnerre de dieu qu'on entend.

En fait la communication passe, mais avec écho, parasites, son faible et tutti quanti

Enfin voilà, je ne suis pas un expert du réseau, loin de là, et je ne sais pas si c'est un problème de ports, d'encodage du son, de débit, ou autre...

Pour info: l'émission se fait actuellement en 16bits, 44100Hz (on a aussi essayé 48000), en mono, et les "frames par buffer" (je sais pas trop comment traduire ça), sont à 1024

Bonne soirée, et merci d'avance!!! :)

Tomaka17
29/01/2014, 18h05
J'imagine que si t'as plusieurs clients, tu additionnes les voix entre elles ? C'est peut être à ce niveau-là qu'est le bug.
Je ne sais pas comment le code est organisé, mais tu associes peut être les mauvaises données à la mauvaise personne, d'où l'écho (input lu deux fois) ou les parasites (buffer pollué).

Ce sont juste des suppositions, difficile de t'aider sans le code source.

olinox14
30/01/2014, 09h23
Merci à toi!
je peux poster le code, mais je doute que ça vienne de là... Comme je disais, tout ça fonctionne très bien en réseau local (sur ma box), mais assez mal en connexion internet :huh:

en gros, le client fonctionne sur 2 threads:
- 1 de réception des données envoyées par le serveur
- 1 d'émission vers le serveur des données acquises depuis le microphone

Le serveur quant à lui, ouvre un thread par client, consistant à recevoir les données émises par ce client, et à les envoyer à tous les autres clients

Donc à aucun moment les données ne sont traitées, additionnées, compressées, converties ou quoi que ce soit, sauf au moment de l'acquisition depuis le microphone...
:sad:

Dois-je poster le code source de tout ça? C'est assez long...

Metalink
30/01/2014, 17h31
Justement si c'est pas compressé, c'est pas trop gros pour passer par le net ?
Parce que je sais que quand j'ai dev' mon petit MMO en Java l'année dernière, envoyer et recevoir à 60FPS marchait nickel en local, par contre sur le net j'ai du limiter les envois toutes les 200ms (totalement arbitraire) et ça passait nickel ;)

Tomaka17
30/01/2014, 18h11
En principe on utilise UDP et non pas TCP pour tout ce qui est multimedia, parce qu'on s'en fout qu'il y ait de temps en temps quelques octets incorrects sur un flux de 88ko/s.

Si t'avais des saccades, de la neige, ou bien des petits morceaux de son qui se répètent en boucle (comme quand un jeu vidéo crash), je veux bien que ce soit une question de débit.
Mais un écho ou un son trop faible ce sont quand même des trucs très spécifiques qui indiquent pour moi que les échantillons ne sont pas les mêmes que ce qu'a enregistré le micro. Peut être que le buffer est lu avant que les données ne soient écrites, peut être un problème de synchronisation entre threads, je sais pas.

Après il faut que tu débug, par exemple en envoyant une valeur fixe et en regardant quelles sont les données reçues par l'autre client.
Ou bien en générant volontairement un lag (tu fais un "if (random() < 0.02) time.sleep(1)" à un endroit du client).
Il faudrait que tu trouves ce qui cause exactement le problème, le fait que ça ne marche pas via internet est trop vague.

olinox14
31/01/2014, 10h25
D'abord, merci pour vos conseils, que je suivrais avec joie dès que j'aurai à nouveau l'occasion de tester tout ça...
D'ici là:
Metalink: Oui effectivement, le problème pourrait venir de là, le coup de la limite des délais d'envois, ça pourrait se tenter (je sais pas ce que ça va donner sur un chat vocal en revanche)

Tomaka: en verité je te le dis: je n'y connais rien (du tout) en réseaux :huh:. j'ai dit tcp, au final j'en sais trop rien, voilà le code d'initialisation des sockets:


s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(5)


pour ce qui est du debug, je suis d'accord avec toi, mais le fait que le problème soit exclusivement sur internet et pas en réseau local me semblait indiquer plutôt un problème lié au débit, ou au moins lié au réseau lui-même

Je vais faire comme tu dis et envoyer une valeur fixe, on verra bien ce qui se passe avec ça

Je vais aussi essayer de vérifier l'état de la connexion internet en communication, et de modérer le débit de données en compressant les données sonores...

Je vous tiens au jus!
Bonne journée! ;)

Tomaka17
31/01/2014, 12h21
Je crois que SOCK_STREAM c'est TCP et SOCK_DGRAM c'est UDP.

La différence c'est qu'en UDP il n'y a pas de contrôle d'erreur et donc tu n'as pas la garantie de tout recevoir ni de recevoir dans le bon ordre (par contre je crois que ce que tu reçois est forcément exact, tu n'as pas d'octet incorrect par exemple). Normalement les erreurs ne sont pas si fréquentes que ça, donc ce n'est pas un problème.

Les applications complexes utilisent généralement deux sockets : une TCP et une UDP (d'ailleurs, on dit un ou une ? je sais jamais). La première pour tout ce qui est indispensable (par exemple le titre de la chanson ou le login/mot de passe) et la deuxième pour les données qui peuvent être perdues sans conséquence.
Par exemple dans un FPS les positions des adversaires sont envoyées en UDP aussi. S'il y a un lag et des packets non reçus, tu n'as plus d'info sur ce qu'ils font, et au moment où les packets reviennent tu les vois se téléporter sur une courte distance.

olinox14
31/01/2014, 14h06
Au top, je savais rien de tout ça!
je vais me pencher sur la question, ça pourrait être une piste d'amélioration oui
merci à toi!

olinox14
03/02/2014, 17h57
Bon, petit up pour ceux que ça intéresse:

après un paquet de tests, c'est bien un souci de débit
les sockets communiquent des données binaires, et ces données ne sont absolument pas compressées
en limitant la fréquence à 22050 Hz, on arrive au mieux à du 40ko la seconde, cad encore plus de 4 fois le débit sortant recommandé par skype
et contrairement à skype, mon serveur est en local et il devra traiter jusqu'à 4 flux sortants en simultané!

la meilleure solution que j'ai trouvée pour l'instant, c'est de convertir ça en mp3 à l'aide de pymedia, ce qui me permettrait de diviser jusqu'à presque 10 fois le volume de données, seulement j'ai d'une part:
- un pymedia auquel je ne comprend pas encore tout et qui prend un fichier wav en entrée
- des sockets qui s'échangent de la donnée binaire...

et je n'ai pas encore trouvé comment faire la jonction entre l'un et l'autre :sad:
Comment remplacer le fichier wav en entrée par un flux audio?
(la fonction d'encodage est dispo ici (http://pymedia.org/tut/src/recode_audio.py.html))

Et comment échanger ce "flux" mp3 ou je ne sais quoi, via des sockets? :huh:

Ps: la deuxième piste d'amélioration vient de ce que disait Tomaka17 au sujet du protocole UDP, j'ai pas encore réussi à mettre ça en place...

Bonne soirée à tous!