first try

This commit is contained in:
pi
2025-10-21 12:29:15 +02:00
parent b583bb29f9
commit c329ce9279

View File

@@ -12,17 +12,19 @@ import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.example.babyphone.R;
public class MainActivity extends AppCompatActivity {
private static final int SAMPLE_RATE = 44100;
@@ -42,23 +44,23 @@ public class MainActivity extends AppCompatActivity {
Button startStreamButton = findViewById(R.id.startStreamButton);
startStreamButton.setOnClickListener(v -> {
if (!isStreaming) {
if (checkPermissions()) {
startStreaming();
startStreamButton.setText("Stop Streaming");
if (!isStreaming) {
if (checkPermissions()) {
startStreaming();
startStreamButton.setText("Stop Streaming");
}
} else {
stopStreaming();
startStreamButton.setText("Start Streaming");
}
} else {
stopStreaming();
startStreamButton.setText("Start Streaming");
}
});
});
}
private boolean checkPermissions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.RECORD_AUDIO}, 1);
new String[]{Manifest.permission.RECORD_AUDIO}, 1);
return false;
}
}
@@ -78,65 +80,81 @@ public class MainActivity extends AppCompatActivity {
// Thread: Neue Clients annehmen
clientListenerThread = new Thread(() -> {
while (isStreaming) {
try {
Socket client = serverSocket.accept();
synchronized (clients) {
clients.add(client);
}
showToast("Neuer Client: " + client.getInetAddress());
} catch (IOException e) {
if (isStreaming) {
showToast("Fehler beim Client-Connect: " + e.getMessage());
while (isStreaming) {
try {
Socket client = serverSocket.accept();
synchronized (clients) {
clients.add(client);
}
showToast("Neuer Client: " + client.getInetAddress());
} catch (IOException e) {
if (isStreaming) {
showToast("Fehler beim Client-Connect: " + e.getMessage());
}
}
}
}
});
});
clientListenerThread.start();
// Thread: Audio aufnehmen und an alle Clients senden
// Thread: Audio aufnehmen und an alle Clients senden (mit µ-law)
recordingThread = new Thread(() -> {
int minBufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT);
int minBufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT);
AudioRecord recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,
SAMPLE_RATE,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT,
minBufferSize);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.RECORD_AUDIO},
1001);
return;
}
byte[] buffer = new byte[minBufferSize];
AudioRecord recorder = null;
try {
recorder = new AudioRecord(
MediaRecorder.AudioSource.MIC,
SAMPLE_RATE,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT,
minBufferSize
);
} catch (SecurityException e) {
e.printStackTrace();
return;
}
recorder.startRecording();
byte[] pcmBuffer = new byte[minBufferSize];
recorder.startRecording();
while (isStreaming) {
int read = recorder.read(buffer, 0, buffer.length);
if (read > 0) {
synchronized (clients) {
Iterator<Socket> iterator = clients.iterator();
while (iterator.hasNext()) {
Socket client = iterator.next();
try {
OutputStream out = client.getOutputStream();
out.write(buffer, 0, read);
} catch (IOException e) {
// Verbindung verloren entfernen
while (isStreaming) {
int read = recorder.read(pcmBuffer, 0, pcmBuffer.length);
if (read > 0) {
// PCM → µ-Law konvertieren
byte[] muLawData = pcm16ToMuLaw(pcmBuffer, read);
synchronized (clients) {
Iterator<Socket> iterator = clients.iterator();
while (iterator.hasNext()) {
Socket client = iterator.next();
try {
client.close();
} catch (IOException ignored) {
OutputStream out = client.getOutputStream();
out.write(muLawData, 0, muLawData.length);
} catch (IOException e) {
try {
client.close();
} catch (IOException ignored) {}
iterator.remove();
showToast("Client getrennt");
}
iterator.remove();
showToast("Client getrennt");
}
}
}
}
}
recorder.stop();
recorder.release();
});
recorder.stop();
recorder.release();
});
recordingThread.start();
}
@@ -147,11 +165,10 @@ public class MainActivity extends AppCompatActivity {
// Schließe alle Clients
synchronized (clients) {
for (Socket client : clients) {
try {
client.close();
} catch (IOException ignored) {
try {
client.close();
} catch (IOException ignored) {}
}
}
clients.clear();
}
@@ -168,4 +185,30 @@ public class MainActivity extends AppCompatActivity {
private void showToast(String msg) {
runOnUiThread(() -> Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show());
}
// ========================
// PCM16 → µ-Law Umwandlung
// ========================
private static byte linearToMuLawSample(short sample) {
final int MU = 255;
int sign = (sample >> 8) & 0x80;
if (sign != 0) sample = (short) -sample;
if (sample > 32635) sample = 32635;
sample = (short) (sample + 132);
int exponent = 7;
for (int expMask = 0x4000; (sample & expMask) == 0 && exponent > 0; exponent--, expMask >>= 1) {}
int mantissa = (sample >> ((exponent == 0) ? 4 : (exponent + 3))) & 0x0F;
int muLawByte = ~(sign | (exponent << 4) | mantissa);
return (byte) muLawByte;
}
private static byte[] pcm16ToMuLaw(byte[] pcmData, int length) {
ByteArrayOutputStream baos = new ByteArrayOutputStream(length / 2);
ByteBuffer bb = ByteBuffer.wrap(pcmData, 0, length).order(ByteOrder.LITTLE_ENDIAN);
while (bb.remaining() > 1) {
short sample = bb.getShort();
baos.write(linearToMuLawSample(sample));
}
return baos.toByteArray();
}
}