Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f5b4285d15 | |||
| 248e7c9ae4 |
@@ -79,8 +79,8 @@ android {
|
|||||||
applicationId "com.ariacockpit"
|
applicationId "com.ariacockpit"
|
||||||
minSdkVersion rootProject.ext.minSdkVersion
|
minSdkVersion rootProject.ext.minSdkVersion
|
||||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||||
versionCode 509
|
versionCode 600
|
||||||
versionName "0.0.5.9"
|
versionName "0.0.6.0"
|
||||||
// Fallback fuer Libraries mit Product Flavors
|
// Fallback fuer Libraries mit Product Flavors
|
||||||
missingDimensionStrategy 'react-native-camera', 'general'
|
missingDimensionStrategy 'react-native-camera', 'general'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,10 @@ class PcmStreamPlayerModule(reactContext: ReactApplicationContext) : ReactContex
|
|||||||
private const val MAX_PREROLL_SECONDS = 10.0
|
private const val MAX_PREROLL_SECONDS = 10.0
|
||||||
// Stille am Stream-Anfang, damit AudioTrack sauber anfaehrt und die
|
// Stille am Stream-Anfang, damit AudioTrack sauber anfaehrt und die
|
||||||
// ersten Samples nicht abgeschnitten werden (XTTS-Warmup + play()-Latenz).
|
// ersten Samples nicht abgeschnitten werden (XTTS-Warmup + play()-Latenz).
|
||||||
private const val LEADING_SILENCE_SECONDS = 0.2
|
private const val LEADING_SILENCE_SECONDS = 0.3
|
||||||
|
// Stille am Ende — puffert das Hardware-Flushen damit die letzten
|
||||||
|
// echten Samples garantiert ausgespielt werden bevor stop() kommt.
|
||||||
|
private const val TRAILING_SILENCE_SECONDS = 0.3
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getName() = "PcmStreamPlayer"
|
override fun getName() = "PcmStreamPlayer"
|
||||||
@@ -109,9 +112,9 @@ class PcmStreamPlayerModule(reactContext: ReactApplicationContext) : ReactContex
|
|||||||
val t = track ?: return@Thread
|
val t = track ?: return@Thread
|
||||||
try {
|
try {
|
||||||
// Leading-Silence in den Buffer — gibt AudioTrack Zeit anzufahren.
|
// Leading-Silence in den Buffer — gibt AudioTrack Zeit anzufahren.
|
||||||
val silenceBytes = ((sampleRate * channels * 2) * LEADING_SILENCE_SECONDS).toInt() and 0x7FFFFFFE
|
val leadingBytes = ((sampleRate * channels * 2) * LEADING_SILENCE_SECONDS).toInt() and 0x7FFFFFFE
|
||||||
if (silenceBytes > 0) {
|
if (leadingBytes > 0) {
|
||||||
val silence = ByteArray(silenceBytes)
|
val silence = ByteArray(leadingBytes)
|
||||||
var silOff = 0
|
var silOff = 0
|
||||||
while (silOff < silence.size && !writerShouldStop) {
|
while (silOff < silence.size && !writerShouldStop) {
|
||||||
val w = t.write(silence, silOff, silence.size - silOff)
|
val w = t.write(silence, silOff, silence.size - silOff)
|
||||||
@@ -120,8 +123,23 @@ class PcmStreamPlayerModule(reactContext: ReactApplicationContext) : ReactContex
|
|||||||
}
|
}
|
||||||
bytesBuffered += silence.size
|
bytesBuffered += silence.size
|
||||||
}
|
}
|
||||||
while (!writerShouldStop) {
|
// Bei preroll=0: play() SOFORT nach Leading-Silence aufrufen,
|
||||||
val data = queue.poll(50, java.util.concurrent.TimeUnit.MILLISECONDS) ?: run {
|
// nicht erst bei Ankunft des ersten echten Chunks. Android's
|
||||||
|
// AudioTrack haelt den Play-State und wartet auf neue Samples.
|
||||||
|
// So verschluckt es keine Worte wenn der erste Chunk erst
|
||||||
|
// nach play()-Startup-Latenz eintrifft.
|
||||||
|
if (prerollBytes == 0 && !playbackStarted) {
|
||||||
|
try {
|
||||||
|
t.play()
|
||||||
|
playbackStarted = true
|
||||||
|
Log.i(TAG, "Playback sofort gestartet (preroll=0, ${bytesBuffered}B silence)")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.w(TAG, "play() sofort failed: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mainLoop@ while (!writerShouldStop) {
|
||||||
|
val data = queue.poll(50, java.util.concurrent.TimeUnit.MILLISECONDS)
|
||||||
|
if (data == null) {
|
||||||
if (endRequested) {
|
if (endRequested) {
|
||||||
// Falls wir vor Pre-Roll enden (kurzer Text): trotzdem abspielen
|
// Falls wir vor Pre-Roll enden (kurzer Text): trotzdem abspielen
|
||||||
if (!playbackStarted) {
|
if (!playbackStarted) {
|
||||||
@@ -133,10 +151,10 @@ class PcmStreamPlayerModule(reactContext: ReactApplicationContext) : ReactContex
|
|||||||
Log.w(TAG, "play() fallback failed: ${e.message}")
|
Log.w(TAG, "play() fallback failed: ${e.message}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return@Thread
|
break@mainLoop
|
||||||
}
|
}
|
||||||
null
|
continue@mainLoop
|
||||||
} ?: continue
|
}
|
||||||
|
|
||||||
// Pre-Roll Check: play() erst wenn genug gepuffert
|
// Pre-Roll Check: play() erst wenn genug gepuffert
|
||||||
if (!playbackStarted && bytesBuffered + data.size >= prerollBytes) {
|
if (!playbackStarted && bytesBuffered + data.size >= prerollBytes) {
|
||||||
@@ -157,6 +175,19 @@ class PcmStreamPlayerModule(reactContext: ReactApplicationContext) : ReactContex
|
|||||||
}
|
}
|
||||||
bytesBuffered += data.size
|
bytesBuffered += data.size
|
||||||
}
|
}
|
||||||
|
// Trailing-Silence damit die letzten echten Samples garantiert
|
||||||
|
// durch das Hardware-Buffering kommen bevor stop() sie abschneidet
|
||||||
|
val trailingBytes = ((sampleRate * channels * 2) * TRAILING_SILENCE_SECONDS).toInt() and 0x7FFFFFFE
|
||||||
|
if (trailingBytes > 0 && !writerShouldStop) {
|
||||||
|
val silence = ByteArray(trailingBytes)
|
||||||
|
var silOff = 0
|
||||||
|
while (silOff < silence.size && !writerShouldStop) {
|
||||||
|
val w = t.write(silence, silOff, silence.size - silOff)
|
||||||
|
if (w <= 0) break
|
||||||
|
silOff += w
|
||||||
|
}
|
||||||
|
bytesBuffered += silence.size
|
||||||
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.w(TAG, "Writer-Thread Fehler: ${e.message}")
|
Log.w(TAG, "Writer-Thread Fehler: ${e.message}")
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "aria-cockpit",
|
"name": "aria-cockpit",
|
||||||
"version": "0.0.5.9",
|
"version": "0.0.6.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"android": "react-native run-android",
|
"android": "react-native run-android",
|
||||||
|
|||||||
Reference in New Issue
Block a user