compatibility-to-childmonitor-clients #2
@@ -12,17 +12,19 @@ import android.widget.Toast;
|
|||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.core.app.ActivityCompat;
|
import androidx.core.app.ActivityCompat;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.example.babyphone.R;
|
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity {
|
public class MainActivity extends AppCompatActivity {
|
||||||
|
|
||||||
private static final int SAMPLE_RATE = 44100;
|
private static final int SAMPLE_RATE = 44100;
|
||||||
@@ -94,38 +96,54 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
});
|
});
|
||||||
clientListenerThread.start();
|
clientListenerThread.start();
|
||||||
|
|
||||||
// Thread: Audio aufnehmen und an alle Clients senden
|
// Thread: Audio aufnehmen und an alle Clients senden (mit µ-law)
|
||||||
recordingThread = new Thread(() -> {
|
recordingThread = new Thread(() -> {
|
||||||
int minBufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE,
|
int minBufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE,
|
||||||
AudioFormat.CHANNEL_IN_MONO,
|
AudioFormat.CHANNEL_IN_MONO,
|
||||||
AudioFormat.ENCODING_PCM_16BIT);
|
AudioFormat.ENCODING_PCM_16BIT);
|
||||||
|
|
||||||
AudioRecord recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,
|
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
|
||||||
|
!= PackageManager.PERMISSION_GRANTED) {
|
||||||
|
ActivityCompat.requestPermissions(this,
|
||||||
|
new String[]{Manifest.permission.RECORD_AUDIO},
|
||||||
|
1001);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioRecord recorder = null;
|
||||||
|
try {
|
||||||
|
recorder = new AudioRecord(
|
||||||
|
MediaRecorder.AudioSource.MIC,
|
||||||
SAMPLE_RATE,
|
SAMPLE_RATE,
|
||||||
AudioFormat.CHANNEL_IN_MONO,
|
AudioFormat.CHANNEL_IN_MONO,
|
||||||
AudioFormat.ENCODING_PCM_16BIT,
|
AudioFormat.ENCODING_PCM_16BIT,
|
||||||
minBufferSize);
|
minBufferSize
|
||||||
|
);
|
||||||
byte[] buffer = new byte[minBufferSize];
|
} catch (SecurityException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] pcmBuffer = new byte[minBufferSize];
|
||||||
recorder.startRecording();
|
recorder.startRecording();
|
||||||
|
|
||||||
while (isStreaming) {
|
while (isStreaming) {
|
||||||
int read = recorder.read(buffer, 0, buffer.length);
|
int read = recorder.read(pcmBuffer, 0, pcmBuffer.length);
|
||||||
if (read > 0) {
|
if (read > 0) {
|
||||||
|
// PCM → µ-Law konvertieren
|
||||||
|
byte[] muLawData = pcm16ToMuLaw(pcmBuffer, read);
|
||||||
|
|
||||||
synchronized (clients) {
|
synchronized (clients) {
|
||||||
Iterator<Socket> iterator = clients.iterator();
|
Iterator<Socket> iterator = clients.iterator();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
Socket client = iterator.next();
|
Socket client = iterator.next();
|
||||||
try {
|
try {
|
||||||
OutputStream out = client.getOutputStream();
|
OutputStream out = client.getOutputStream();
|
||||||
out.write(buffer, 0, read);
|
out.write(muLawData, 0, muLawData.length);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// Verbindung verloren – entfernen
|
|
||||||
try {
|
try {
|
||||||
client.close();
|
client.close();
|
||||||
} catch (IOException ignored) {
|
} catch (IOException ignored) {}
|
||||||
}
|
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
showToast("Client getrennt");
|
showToast("Client getrennt");
|
||||||
}
|
}
|
||||||
@@ -149,8 +167,7 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
for (Socket client : clients) {
|
for (Socket client : clients) {
|
||||||
try {
|
try {
|
||||||
client.close();
|
client.close();
|
||||||
} catch (IOException ignored) {
|
} catch (IOException ignored) {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
clients.clear();
|
clients.clear();
|
||||||
}
|
}
|
||||||
@@ -168,4 +185,30 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
private void showToast(String msg) {
|
private void showToast(String msg) {
|
||||||
runOnUiThread(() -> Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show());
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user