Я передаю микрофонный вход с сервера C через сокет. Я знаю, что поток работает, потому что он работает с клиентом C, и я получаю правильные значения на своем Android-клиенте.
Я передаю 1024 floatarray. Один поплавок - 4 байта. Поэтому я получил входящий поток с 4096 байтами на кадр. Я получаю поплавки из этих байтов, и я знаю, что эти поплавки - это те, которые я отправил, чтобы эта часть работала.
Теперь я хочу получить этот поток непосредственно на динамики телефонов, используя AudioTrack. Я попытался ввести байты, которые я получил напрямую: просто шум. Я попытался вернуть его в массив байтов, все тот же. Я попытался сделать это плавающим на короткое (потому что AudioTrack берет байты или короткие). Я мог бы получить что-то, что могло бы быть моим микрофонным входом (стуком), но очень колючим и очень лаконичным. Я бы понял, было ли отставание между кадрами, но я не могу даже получить один ясный звук. Тем не менее, я могу выпустить звук греха, который я создаю локально и помещаю в этот shortarray. Теперь я задаюсь вопросом, есть ли у меня некоторые проблемы в моем коде, которые вы видите, потому что я их не вижу.
Что я делаю: я помещаю 4 байта в массив байтов. Я получаю поплавок. Как только я получаю один фрейм в моем массиве с плавающей точкой (я контролирую это с помощью bool, не очень хорошо, но он должен работать) Я положил его в свой shortarray и позволил audiotrack воспроизводить его. Это двойное кастинг может быть медленным, но я делаю это, потому что его ближайший я получил, чтобы играть фактический ввод.
Edit: Я проверил endianess, сравнив поплавки, у них есть правильные значения между -1 и 1 и те же, что и я. Поскольку я не изменяю endianess при кастинге для float, я не понимаю, почему пересылка массива 4096 байт в AudioTrack напрямую не работает. В многопоточности может быть что-то не так, но я не понимаю, что это может быть.
Изменить 2:. Я обнаружил небольшую проблему - я reset j в 1023. Но это отсутствие плавающей точки не должно было быть проблемой. То, что я сделал, кроме этого, заключалось в том, чтобы поместить метод, который взял поток из сокета в другой поток, вместо того, чтобы называть его в async-задаче. Это заставило его работать, теперь я могу понять звуки микрофона. Тем не менее качество очень плохое - может быть причина для этого в коде? Также я получил задержку около 10 секунд. Только около половины секунды вызвано WLAN, поэтому я задаюсь вопросом, может ли это быть ошибкой кода. Любые дальнейшие мысли оцениваются.
Редактировать 3: Я играл с кодом и реализовал в комментариях несколько идей greenapps. С новой структурой потоков я столкнулся с проблемой не получения звука. Вроде бы. Я не понимаю, как это возможно, поэтому я переключился обратно. Другие вещи, которые я пытался сделать, чтобы потоки были более легкими, не имели никакого эффекта. У меня задержка, и у меня очень плохое качество (я могу определить удары, но я не могу понять голоса). Я понял, что что-то может быть неправильно с моими конвертированиями, поэтому я помещаю байты, которые я получаю из сокета прямо в AudioTrack - ничего, кроме уродливого пульсирующего статического шума. Теперь я еще более смущен, так как этот точный поток по-прежнему работает с клиентом C. Я верну отчет, если найду решение, но все равно приветствуем любую помощь.
Изменить 4. Я должен добавить, что я могу воспроизводить микрофонные входы из другого приложения для Android, где я отправляю этот вход напрямую в виде байтов (я бы исключил материал для создания плавающих элементов и поместил байты, которые я получаю напрямую audioTrack в моем коде игрока).
Также мне показалось, что это может быть проблемой, что упомянутый floatarray, который передается сервером C, поступает с 64-битной машины, а телефон 32 бит. Может быть, это проблема, так или иначе, хотя я просто потоки с плавающей запятой, как 4 байта?
Или, еще одна моя мысль: базовый формат чисел байтов, которые я получаю, является float. Какой формат ожидает AudioTrack? Даже если положить только байты - мне нужно было бы сместить этот float в int и отбросить его обратно в байты или что-то в этом роде?
новый код:
public class PCMSocket {
AudioTrack audioTrack;
boolean doStop = false;
int musicLength = 4096;
byte[] music;
Socket socket;
short[] buffer = new short[4096];
float[] fmusic = new float[1024];
WriteToAudio writeThread;
ReadFromSocket readThread;
public PCMSocket()
{
}
public void start()
{
doStop = false;
readThread = new ReadFromSocket();
readThread.start();
}
public class ReadFromSocket extends Thread
{
public void run()
{
doStop=true;
InetSocketAddress address = new InetSocketAddress("xxx.xxx.xxx.x", 8000);
socket = new Socket();
int timeout = 6000;
try {
socket.connect(address, timeout);
} catch (IOException e2) {
e2.printStackTrace();
}
musicLength = 1024;
InputStream is = null;
try {
is = socket.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
BufferedInputStream bis = new BufferedInputStream(is);
DataInputStream dis = new DataInputStream(bis);
try{
int minSize =AudioTrack.getMinBufferSize( 44100, AudioFormat.CHANNEL_CONFIGURATION_STEREO, AudioFormat.ENCODING_PCM_16BIT );
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 44100,
AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT, minSize,
AudioTrack.MODE_STREAM);
audioTrack.play();
} catch (Throwable t)
{
t.printStackTrace();
doStop = true;
}
writeThread = new WriteToAudio();
readThread.start();
int i = 0;
int j=0;
try {
if(dis.available()>0)Log.d("PCMSocket", "receiving");
music = new byte[4];
while (dis.available() > 0)
{
music[i]=0;
music[i] = dis.readByte();
if(i==3)
{
int asInt = 0;
asInt = ((music[0] & 0xFF) << 0)
| ((music[1] & 0xFF) << 8)
| ((music[2] & 0xFF) << 16)
| ((music[3] & 0xFF) << 24);
float asFloat = 0;
asFloat = Float.intBitsToFloat(asInt);
fmusic[j]=asFloat;
}
i++;
j++;
if(i==4)
{
music = new byte[4];
i=0;
}
if(j==1024)
{
j=0;
if(doStop)doStop=false;
}
}
} catch (IOException e) {
e.printStackTrace();
}
try {
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
};
public class WriteToAudio extends Thread
{
public void run()
{
while(true){
while(!doStop)
{
try{
writeSamples(fmusic);
}catch(Exception e)
{
e.printStackTrace();
}
doStop = true;
}
}
}
};
public void writeSamples(float[] samples)
{
fillBuffer( samples );
audioTrack.write( buffer, 0, samples.length );
}
private void fillBuffer( float[] samples )
{
if( buffer.length < samples.length )
buffer = new short[samples.length];
for( int i = 0; i < samples.length; i++ )
{
buffer[i] = (short)(samples[i] * Short.MAX_VALUE);
}
}
}
старый код:
public class PCMSocket {
AudioTrack audioTrack;
WriteToAudio thread;
boolean doStop = false;
int musicLength = 4096;
byte[] music;
Socket socket;
short[] buffer = new short[4096];
float[] fmusic = new float[1024];
public PCMSocket()
{
}
public void start()
{
doStop = false;
new GetStream().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private class GetStream extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... values) {
PCMSocket.this.getSocket();
return null;
}
@Override
protected void onPreExecute() {
}
@Override
protected void onPostExecute(Void result)
{
return;
}
@Override
protected void onProgressUpdate(Void... values) {
}
}
private void getSocket()
{
doStop=true;
InetSocketAddress address = new InetSocketAddress("xxx.xxx.xxx.x", 8000);
socket = new Socket();
int timeout = 6000;
try {
socket.connect(address, timeout);
} catch (IOException e2) {
e2.printStackTrace();
}
musicLength = 1024;
InputStream is = null;
try {
is = socket.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
BufferedInputStream bis = new BufferedInputStream(is);
DataInputStream dis = new DataInputStream(bis);
try{
int minSize =AudioTrack.getMinBufferSize( 44100, AudioFormat.CHANNEL_CONFIGURATION_STEREO, AudioFormat.ENCODING_PCM_16BIT );
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 44100,
AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT, minSize,
AudioTrack.MODE_STREAM);
audioTrack.play();
} catch (Throwable t)
{
t.printStackTrace();
doStop = true;
}
thread = new WriteToAudio();
thread.start();
int i = 0;
int j=0;
try {
if(dis.available()>0)Log.d("PCMSocket", "receiving");
music = new byte[4];
while (dis.available() > 0)
{
music[i]=0;
music[i] = dis.readByte();
if(i==3)
{
int asInt = 0;
asInt = ((music[0] & 0xFF) << 0)
| ((music[1] & 0xFF) << 8)
| ((music[2] & 0xFF) << 16)
| ((music[3] & 0xFF) << 24);
float asFloat = 0;
asFloat = Float.intBitsToFloat(asInt);
fmusic[j]=asFloat;
}
i++;
j++;
if(i==4)
{
music = new byte[4];
i=0;
}
if(j==1023)
{
j=0;
if(doStop)doStop=false;
}
}
} catch (IOException e) {
e.printStackTrace();
}
try {
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public class WriteToAudio extends Thread
{
public void run()
{
while(true){
while(!doStop)
{
try{
writeSamples(fmusic);
}catch(Exception e)
{
e.printStackTrace();
}
doStop = true;
}
}
}
};
public void writeSamples(float[] samples)
{
fillBuffer( samples );
audioTrack.write( buffer, 0, samples.length );
}
private void fillBuffer( float[] samples )
{
if( buffer.length < samples.length )
buffer = new short[samples.length*4];
for( int i = 0; i < samples.length; i++ )
{
buffer[i] = (short)(samples[i] * Short.MAX_VALUE);
}
}
}