J'ai développé une application Java à l'aide de Java Sound API. Ce qu'il fait, c'est qu'il capture les données provenant du microphone et l'envoie sur UDP à un autre ordinateur pour y être joué. Maintenant, je reçois des problèmes de volume, de qualité et de rapidité. Je ne peux pas comprendre la source des problèmes, alors j'ai besoin d'aide pour déterminer ce qui ne va pas avec le programme.
Il semble que les problèmes de vitesse soient dus à Java Sound API Juste être ralentir. J'ai essayé le programme sans sockets UDP et il y avait le même type de retard que l'UDP n'introduit pas de retard supplémentaire dans le réseau local. Le problème d'écho disparaît lorsque le programme est utilisé avec des écouteurs. La qualité du son n'est pas trop mauvaise dans l'ensemble. Seul problème restant est le volume. P>
ci-dessous est l'expéditeur : strong> p> ci-dessous est le récepteur : fort> p>
3 Réponses :
Voice Over Network est un sujet complexe et a beaucoup de problèmes difficiles. P>
Je pense que votre problème provient de l'irrégularité de votre couche de réseau. P>
Si votre réseau n'est pas 100% Constant (il est très difficile avec les interférences d'une autre application dans le tampon de votre ordinateur / de votre boîte / etc.) Votre voix sera une petite robotique. P>
Un moyen d'éviter qu'il s'agit d'ajouter un petit tampon qui retardera la communication entre le récepteur et l'expéditeur. Si le retard est trop faible, l'effet de problème de performance continuera de se produire. Si c'est trop long, c'est trop long;) ... p>
Un autre problème qui peut survivre (le plus probable dans le réseau WAN) est la perte du paquet qui peut troubler la communication. Pour résoudre ce problème .. Je n'ai pas une bonne solution, cela dépend du réseau ou / et du cas d'utilisation. P>
Donc, je me suis débarrassé des sockets UDP et il suffit d'utiliser TargetDataline code> et
SourceDataline code> sur un tampon pour voir si le problème a été causé par des sockets UDP. Il s'avère que les sockets UDP ne provoquent pas le délai, mais c'est plutôt l'API Java Sound. J'ai besoin d'une API plus rapide | que ceux proposés par Java. Quelles sont mes alternatives? Je peux le réécrire à C ++ aussi, mais je n'ai trouvé aucune bibliothèque en C ++ pour atteindre le microphone et les haut-parleurs.
Peut-être perles ou jsyn pour la bibliothèque Java
Python est une possibilité ... mais je trouve étrange que Java ne soit pas assez rapide pour jouer au son
Je dirais que c'est assez rapide, mais j'ai besoin de quelque chose de proche en temps réel.
J'ai essayé votre code avec 2 ordinateur et cela fonctionne bien (j'ai un peu d'écho mais c'est tout))
Il y a un retard notable entre les deux. Je veux en faire presque en temps réel et me débarrasser de l'écho.
À ce moment-là, vous devriez définir le temps réel (combien de MS? Je suis d'accord, l'écho est gênant)
Certaines pensées, avec une mise en garde que je n'ai pas d'expérience directe pour essayer d'utiliser UDP. P>
Il me semble que des paquets manquants et hors de commande (supposés avec UDP) devraient être «traités» ou bien les discontinuités attendues créeraient continuellement des clics perturbateurs. Mais idk comment cela est normalement fait. Filtres? Tampon? Encapsulation des données de paquets dans Windowing (Hann ou Hamming?) Cadres pour combler les discontinuités de paquets? P>
javax.sound.samplé est assez proche du son natal. Voici un bon article à faire référence à des considérations relatives à la teneur en temps réel, à faible latence Audio basé sur Java. p>
J'ai réussi à en faire presque en temps réel avec ALSA Sound API.
Heureux d'entendre une solution a été trouvé! Comment accédez-vous à l'API ALSA? Est-ce que vous le faites via Java, par exemple, en sélectionnant des lignes alsa? (Toujours en utilisant la cibledataline / sourcecedataline?) Ou une autre manière?
Envisagez d'écrire votre solution et de la marquer comme la réponse. Ce serait une contribution précieuse.
J'utilise C à Linux (ALSA API n'est disponible que sous Linux). Le délai entre la capture audio et la lecture n'est presque pas comparé à l'API de Java Sound mais il y a du bruit à l'arrière-plan - que je ne pouvais pas me débarrasser de. Une fois que je résout le problème de bruit, je peux poster la solution ici. Mais ce n'est pas encore prêt.
J'ai également essayé d'utiliser Pullevodio pour capture et lecture. Il est beaucoup plus facile d'utiliser que d'utiliser ALSA API, mais il y a le même type de délai entre la capture et la lecture, comme il s'agit d'une API Java Sound.
Enfin, je suis capable de répondre à ma propre question ici. J'ai utilisé Le code n'est pas parfait, probablement pas un bon moyen d'utiliser Jackaudio et a des tonnes de bugs. Cependant, je pense que c'est un bon point de départ pour ceux qui sont intéressés par ce genre de choses. Pour l'utiliser, d'abord installer Faites-moi savoir s'il y a un meilleur moyen de mettre en œuvre la même fonctionnalité avec tout ensemble d'outils Disponible là-bas. P> Solution Jackaudio: strong> p> jackaudio code> serveur et fichiers de développement via le gestionnaire de packages de votre distribution. P>
Jackaudio H2>
#define ALSA_PCM_NEW_HW_PARAMS_API
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <alsa/asoundlib.h>
#define PORT 8080
int create_UDP_socket_receive()
{
struct sockaddr_in server;
int sock;
if((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("Socket");
exit(EXIT_FAILURE);
}
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
server.sin_addr.s_addr = INADDR_ANY;
if (bind(sock, (struct sockaddr *)&server, sizeof(server)) < 0)
{
perror("bind()");
exit(EXIT_FAILURE);
}
return sock;
}
int main() {
long loops;
int rc;
int size;
snd_pcm_t *handle;
snd_pcm_hw_params_t *params;
unsigned int val;
int dir;
snd_pcm_uframes_t frames;
/* Open PCM device for playback. */
rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
if (rc < 0) {
fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc));
exit(1);
}
/* Allocate a hardware parameters object. */
snd_pcm_hw_params_alloca(¶ms);
/* Fill it in with default values. */
snd_pcm_hw_params_any(handle, params);
/* Set the desired hardware parameters. */
/* Interleaved mode */
snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
/* Signed 16-bit little-endian format */
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
/* Two channels (stereo) */
snd_pcm_hw_params_set_channels(handle, params, 2);
/* 44100 bits/second sampling rate (CD quality) */
val = 44100;
snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);
/* Set period size to 32 frames. */
frames = 32;
snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);
/* Write the parameters to the driver */
rc = snd_pcm_hw_params(handle, params);
if (rc < 0) {
fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc));
exit(1);
}
/* Use a buffer large enough to hold one period */
snd_pcm_hw_params_get_period_size(params, &frames, &dir);
size = frames * 4; /* 2 bytes/sample, 2 channels */
char buffer[size];
int nread;
int socket = create_UDP_socket_receive();
snd_pcm_hw_params_get_period_time(params, &val, &dir);
while (1) {
if((nread = recvfrom(socket, buffer, sizeof(buffer), 0, NULL, NULL)) < 0)
{
perror("recvfrom()");
exit(EXIT_FAILURE);
}
// write(1, buffer, sizeof(buffer));
rc = snd_pcm_writei(handle, buffer, frames);
if (rc == -EPIPE) {
/* EPIPE means underrun */
fprintf(stderr, "underrun occurred\n");
snd_pcm_prepare(handle);
} else if (rc < 0) {
fprintf(stderr, "error from writei: %s\n", snd_strerror(rc));
} else if (rc != (int)frames) {
fprintf(stderr, "short write, write %d frames\n", rc);
}
}
snd_pcm_drain(handle);
snd_pcm_close(handle);
free(buffer);
return 0;
}