diff --git a/app/build.gradle b/app/build.gradle
index a6f97f1..e3b0bc4 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -5,7 +5,7 @@ android {
compileSdk 34
defaultConfig {
- applicationId "de.rochefort.childmonitor"
+ applicationId "com.example.childmonitor_multiple"
minSdkVersion 21
targetSdkVersion 34
versionCode 14
@@ -21,7 +21,7 @@ android {
dependencies {
}
- namespace 'de.rochefort.childmonitor'
+ namespace 'com.example.childmonitor_multiple'
lint {
abortOnError true
warning 'MissingTranslation'
diff --git a/app/src/main/kotlin/de/rochefort/childmonitor/AudioCodecDefines.kt b/app/src/main/kotlin/com/example/childmonitor_multiple/AudioCodecDefines.kt
similarity index 92%
rename from app/src/main/kotlin/de/rochefort/childmonitor/AudioCodecDefines.kt
rename to app/src/main/kotlin/com/example/childmonitor_multiple/AudioCodecDefines.kt
index 3e75cf0..0c797e2 100644
--- a/app/src/main/kotlin/de/rochefort/childmonitor/AudioCodecDefines.kt
+++ b/app/src/main/kotlin/com/example/childmonitor_multiple/AudioCodecDefines.kt
@@ -14,10 +14,9 @@
* You should have received a copy of the GNU General Public License
* along with Child Monitor. If not, see .
*/
-package de.rochefort.childmonitor
+package com.example.childmonitor_multiple
import android.media.AudioFormat
-import de.rochefort.childmonitor.audio.G711UCodec
object AudioCodecDefines {
const val FREQUENCY = 8000
diff --git a/app/src/main/kotlin/de/rochefort/childmonitor/DiscoverActivity.kt b/app/src/main/kotlin/com/example/childmonitor_multiple/DiscoverActivity.kt
similarity index 99%
rename from app/src/main/kotlin/de/rochefort/childmonitor/DiscoverActivity.kt
rename to app/src/main/kotlin/com/example/childmonitor_multiple/DiscoverActivity.kt
index 1f46d62..56d2cb2 100644
--- a/app/src/main/kotlin/de/rochefort/childmonitor/DiscoverActivity.kt
+++ b/app/src/main/kotlin/com/example/childmonitor_multiple/DiscoverActivity.kt
@@ -14,7 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with Child Monitor. If not, see .
*/
-package de.rochefort.childmonitor
+package com.example.childmonitor_multiple
import android.app.Activity
import android.content.Intent
diff --git a/app/src/main/kotlin/de/rochefort/childmonitor/ListenActivity.kt b/app/src/main/kotlin/com/example/childmonitor_multiple/ListenActivity.kt
similarity index 97%
rename from app/src/main/kotlin/de/rochefort/childmonitor/ListenActivity.kt
rename to app/src/main/kotlin/com/example/childmonitor_multiple/ListenActivity.kt
index 34b8417..73b2f1e 100644
--- a/app/src/main/kotlin/de/rochefort/childmonitor/ListenActivity.kt
+++ b/app/src/main/kotlin/com/example/childmonitor_multiple/ListenActivity.kt
@@ -14,7 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with Child Monitor. If not, see .
*/
-package de.rochefort.childmonitor
+package com.example.childmonitor_multiple
import android.app.Activity
import android.content.ComponentName
@@ -28,7 +28,7 @@ import android.util.Log
import android.widget.TextView
import android.widget.Toast
import androidx.core.content.ContextCompat
-import de.rochefort.childmonitor.ListenService.ListenBinder
+import com.example.childmonitor_multiple.ListenService.ListenBinder
class ListenActivity : Activity() {
// Don't attempt to unbind from the service unless the client has received some
diff --git a/app/src/main/kotlin/de/rochefort/childmonitor/ListenService.kt b/app/src/main/kotlin/com/example/childmonitor_multiple/ListenService.kt
similarity index 99%
rename from app/src/main/kotlin/de/rochefort/childmonitor/ListenService.kt
rename to app/src/main/kotlin/com/example/childmonitor_multiple/ListenService.kt
index 5074ca8..9e5bc38 100644
--- a/app/src/main/kotlin/de/rochefort/childmonitor/ListenService.kt
+++ b/app/src/main/kotlin/com/example/childmonitor_multiple/ListenService.kt
@@ -14,7 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with Child Monitor. If not, see .
*/
-package de.rochefort.childmonitor
+package com.example.childmonitor_multiple
import android.app.Notification
import android.app.NotificationChannel
diff --git a/app/src/main/kotlin/de/rochefort/childmonitor/MonitorActivity.kt b/app/src/main/kotlin/com/example/childmonitor_multiple/MonitorActivity.kt
similarity index 98%
rename from app/src/main/kotlin/de/rochefort/childmonitor/MonitorActivity.kt
rename to app/src/main/kotlin/com/example/childmonitor_multiple/MonitorActivity.kt
index 9a48546..f87d778 100644
--- a/app/src/main/kotlin/de/rochefort/childmonitor/MonitorActivity.kt
+++ b/app/src/main/kotlin/com/example/childmonitor_multiple/MonitorActivity.kt
@@ -14,7 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with Child Monitor. If not, see .
*/
-package de.rochefort.childmonitor
+package com.example.childmonitor_multiple
import android.app.Activity
import android.content.ComponentName
@@ -28,7 +28,7 @@ import android.util.Log
import android.widget.TextView
import android.widget.Toast
import androidx.core.content.ContextCompat
-import de.rochefort.childmonitor.MonitorService.MonitorBinder
+import com.example.childmonitor_multiple.MonitorService.MonitorBinder
class MonitorActivity : Activity() {
private val connection: ServiceConnection = object : ServiceConnection {
diff --git a/app/src/main/kotlin/de/rochefort/childmonitor/MonitorService.kt b/app/src/main/kotlin/com/example/childmonitor_multiple/MonitorService.kt
similarity index 72%
rename from app/src/main/kotlin/de/rochefort/childmonitor/MonitorService.kt
rename to app/src/main/kotlin/com/example/childmonitor_multiple/MonitorService.kt
index 2719783..60b6d49 100644
--- a/app/src/main/kotlin/de/rochefort/childmonitor/MonitorService.kt
+++ b/app/src/main/kotlin/com/example/childmonitor_multiple/MonitorService.kt
@@ -14,7 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with Child Monitor. If not, see .
*/
-package de.rochefort.childmonitor
+package com.example.childmonitor_multiple
import android.app.Notification
import android.app.NotificationChannel
@@ -62,11 +62,11 @@ class MonitorService : Service() {
val bufferSize = AudioRecord.getMinBufferSize(frequency, channelConfiguration, audioEncoding)
val audioRecord: AudioRecord = try {
AudioRecord(
- MediaRecorder.AudioSource.MIC,
- frequency,
- channelConfiguration,
- audioEncoding,
- bufferSize
+ MediaRecorder.AudioSource.MIC,
+ frequency,
+ channelConfiguration,
+ audioEncoding,
+ bufferSize
)
} catch (e: SecurityException) {
// This should never happen, we asked for permission before
@@ -91,6 +91,64 @@ class MonitorService : Service() {
audioRecord.stop()
}
}
+ private fun handleMultiClientStreaming(serverSocket: ServerSocket, clients: MutableList) {
+ val frequency: Int = AudioCodecDefines.FREQUENCY
+ val channelConfiguration: Int = AudioCodecDefines.CHANNEL_CONFIGURATION_IN
+ val audioEncoding: Int = AudioCodecDefines.ENCODING
+ val bufferSize = AudioRecord.getMinBufferSize(frequency, channelConfiguration, audioEncoding)
+
+ val audioRecord = AudioRecord(
+ MediaRecorder.AudioSource.MIC,
+ frequency,
+ channelConfiguration,
+ audioEncoding,
+ bufferSize
+ )
+
+ val pcmBufferSize = bufferSize * 2
+ val pcmBuffer = ShortArray(pcmBufferSize)
+ val ulawBuffer = ByteArray(pcmBufferSize)
+
+ try {
+ audioRecord.startRecording()
+ Log.i(TAG, "Mehrere Clients aktiv – Aufnahme gestartet.")
+
+ while (!Thread.currentThread().isInterrupted && !serverSocket.isClosed) {
+ val read = audioRecord.read(pcmBuffer, 0, bufferSize)
+ if (read > 0) {
+ val encoded: Int = AudioCodecDefines.CODEC.encode(pcmBuffer, read, ulawBuffer, 0)
+
+ synchronized(clients) {
+ val iterator = clients.iterator()
+ while (iterator.hasNext()) {
+ val client = iterator.next()
+ try {
+ val out = client.getOutputStream()
+ out.write(ulawBuffer, 0, encoded)
+ } catch (e: IOException) {
+ try { client.close() } catch (ignored: IOException) {}
+ iterator.remove()
+ Log.w(TAG, "Client getrennt: ${client.inetAddress}")
+ }
+ }
+ }
+ }
+ }
+ } catch (e: Exception) {
+ Log.e(TAG, "Streaming-Fehler", e)
+ } finally {
+ audioRecord.stop()
+ audioRecord.release()
+ synchronized(clients) {
+ clients.forEach {
+ try { it.close() } catch (_: IOException) {}
+ }
+ clients.clear()
+ }
+ Log.i(TAG, "Audioaufnahme beendet, alle Clients getrennt.")
+ }
+ }
+
override fun onCreate() {
Log.i(TAG, "ChildMonitor start")
@@ -130,15 +188,25 @@ class MonitorService : Service() {
// Register the service so that parent devices can
// locate the child device
registerService(localPort)
- serverSocket.accept().use { socket ->
- Log.i(TAG, "Connection from parent device received")
+ val clients = mutableListOf()
+
+// Thread zum Akzeptieren neuer Clients
+ Thread {
+ try {
+ while (!Thread.currentThread().isInterrupted) {
+ val client = serverSocket.accept()
+ client.tcpNoDelay = true
+ synchronized(clients) { clients.add(client) }
+ Log.i(TAG, "Neuer Client verbunden: ${client.inetAddress}")
+ }
+ } catch (e: IOException) {
+ Log.e(TAG, "Client-Akzeptierungsfehler: ${e.message}")
+ }
+ }.start()
+
+// Aufnahme und Verteilung starten
+ handleMultiClientStreaming(serverSocket, clients)
- // We now have a client connection.
- // Unregister so no other clients will
- // attempt to connect
- unregisterService()
- serviceConnection(socket)
- }
}
} catch (e: Exception) {
if (this.connectionToken == currentToken) {
@@ -195,7 +263,7 @@ class MonitorService : Service() {
}
}
nsdManager.registerService(
- serviceInfo, NsdManager.PROTOCOL_DNS_SD, registrationListener)
+ serviceInfo, NsdManager.PROTOCOL_DNS_SD, registrationListener)
}
private fun unregisterService() {
@@ -209,9 +277,9 @@ class MonitorService : Service() {
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val serviceChannel = NotificationChannel(
- CHANNEL_ID,
- "Foreground Service Channel",
- NotificationManager.IMPORTANCE_DEFAULT
+ CHANNEL_ID,
+ "Foreground Service Channel",
+ NotificationManager.IMPORTANCE_DEFAULT
)
this.notificationManager.createNotificationChannel(serviceChannel)
}
@@ -222,9 +290,9 @@ class MonitorService : Service() {
// Set the info for the views that show in the notification panel.
val b = NotificationCompat.Builder(this, CHANNEL_ID)
b.setSmallIcon(R.drawable.listening_notification) // the status icon
- .setOngoing(true)
- .setTicker(text) // the status text
- .setContentTitle(text) // the label of the entry
+ .setOngoing(true)
+ .setTicker(text) // the status text
+ .setContentTitle(text) // the label of the entry
return b.build()
}
diff --git a/app/src/main/kotlin/de/rochefort/childmonitor/StartActivity.kt b/app/src/main/kotlin/com/example/childmonitor_multiple/StartActivity.kt
similarity index 98%
rename from app/src/main/kotlin/de/rochefort/childmonitor/StartActivity.kt
rename to app/src/main/kotlin/com/example/childmonitor_multiple/StartActivity.kt
index e4b9d89..621aab7 100644
--- a/app/src/main/kotlin/de/rochefort/childmonitor/StartActivity.kt
+++ b/app/src/main/kotlin/com/example/childmonitor_multiple/StartActivity.kt
@@ -14,7 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with Child Monitor. If not, see .
*/
-package de.rochefort.childmonitor
+package com.example.childmonitor_multiple
import android.Manifest
import android.app.Activity
diff --git a/app/src/main/kotlin/de/rochefort/childmonitor/VolumeHistory.kt b/app/src/main/kotlin/com/example/childmonitor_multiple/VolumeHistory.kt
similarity index 97%
rename from app/src/main/kotlin/de/rochefort/childmonitor/VolumeHistory.kt
rename to app/src/main/kotlin/com/example/childmonitor_multiple/VolumeHistory.kt
index 8ee200d..872b134 100644
--- a/app/src/main/kotlin/de/rochefort/childmonitor/VolumeHistory.kt
+++ b/app/src/main/kotlin/com/example/childmonitor_multiple/VolumeHistory.kt
@@ -14,7 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with Child Monitor. If not, see .
*/
-package de.rochefort.childmonitor
+package com.example.childmonitor_multiple
import android.os.Handler
import android.os.Looper
diff --git a/app/src/main/kotlin/de/rochefort/childmonitor/VolumeView.kt b/app/src/main/kotlin/com/example/childmonitor_multiple/VolumeView.kt
similarity index 98%
rename from app/src/main/kotlin/de/rochefort/childmonitor/VolumeView.kt
rename to app/src/main/kotlin/com/example/childmonitor_multiple/VolumeView.kt
index 148a7c0..e7ff342 100644
--- a/app/src/main/kotlin/de/rochefort/childmonitor/VolumeView.kt
+++ b/app/src/main/kotlin/com/example/childmonitor_multiple/VolumeView.kt
@@ -14,7 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with Child Monitor. If not, see .
*/
-package de.rochefort.childmonitor
+package com.example.childmonitor_multiple
import android.content.Context
import android.graphics.Canvas
diff --git a/app/src/main/kotlin/de/rochefort/childmonitor/audio/G711UCodec.kt b/app/src/main/kotlin/com/example/childmonitor_multiple/audio/G711UCodec.kt
similarity index 98%
rename from app/src/main/kotlin/de/rochefort/childmonitor/audio/G711UCodec.kt
rename to app/src/main/kotlin/com/example/childmonitor_multiple/audio/G711UCodec.kt
index 4099a96..d571966 100644
--- a/app/src/main/kotlin/de/rochefort/childmonitor/audio/G711UCodec.kt
+++ b/app/src/main/kotlin/com/example/childmonitor_multiple/audio/G711UCodec.kt
@@ -16,7 +16,7 @@
* Taken from https://android.googlesource.com/platform/external/nist-sip/+/6f95fdeab4481188b6260041b41d1db12b101266/src/com/android/sip/media/G711UCodec.java
* Adopted to the needs of the Child Monitor project.
*/
-package de.rochefort.childmonitor.audio
+package com.example.childmonitor_multiple
/**
* G.711 codec. This class provides u-law conversion.
diff --git a/app/src/main/res/layout/activity_discover.xml b/app/src/main/res/layout/activity_discover.xml
index 9808555..dd317e9 100644
--- a/app/src/main/res/layout/activity_discover.xml
+++ b/app/src/main/res/layout/activity_discover.xml
@@ -8,7 +8,7 @@
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
- tools:context="de.rochefort.childmonitor.MonitorActivity" >
+ tools:context="com.example.childmonitor_multiple.MonitorActivity" >
+ tools:context="com.example.childmonitor_multiple.MonitorActivity" >
+ tools:context="com.example.childmonitor_multiple.MonitorActivity" >
+ tools:context="com.example.childmonitor_multiple.MonitorActivity">
-
diff --git a/app/src/main/res/layout/activity_monitor.xml b/app/src/main/res/layout/activity_monitor.xml
index c8de77c..cabfd84 100644
--- a/app/src/main/res/layout/activity_monitor.xml
+++ b/app/src/main/res/layout/activity_monitor.xml
@@ -9,7 +9,7 @@
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:keepScreenOn="true"
- tools:context="de.rochefort.childmonitor.MonitorActivity" >
+ tools:context="com.example.childmonitor_multiple.MonitorActivity" >
+ tools:context="com.example.childmonitor_multiple.MonitorActivity" >
+ tools:context="com.example.childmonitor_multiple.StartActivity" >