Expose viewer wake signals and complete audio independently on Android
This commit is contained in:
1 parent
9fb4823df0
commit
a538f99bf0
3 files changed
+42
-9
No files matched your search
@@ -215,10 +215,14 @@ object NativeLib {
|
||||
fun streamTxStats(id: Long): LongArray? = nativeStreamTxStats(id)
|
||||
fun streamSetAudioEnabled(id: Long, enabled: Boolean): Boolean = nativeStreamSetAudioEnabled(id, enabled)
|
||||
fun streamStop(id: Long) { nativeStreamStop(id) }
|
||||
fun streamPull(id: Long, positionUs: Long = -1, wantVideo: Boolean = true, audioAheadUs: Long = 80000): ByteArray? =
|
||||
nativeStreamPull(id, positionUs, wantVideo, audioAheadUs)
|
||||
fun streamPull(id: Long, positionUs: Long = -1, video: Int = 1, audioAheadUs: Long = 80000, records: Int = 1): ByteArray? =
|
||||
nativeStreamPull(id, positionUs, video, audioAheadUs, records)
|
||||
fun streamStatus(id: Long): LongArray? = nativeStreamStatus(id)
|
||||
fun streamResync(id: Long): Boolean = nativeStreamResync(id)
|
||||
external fun streamSignalCreate(id: Long): Long
|
||||
external fun streamSignalNotify(handle: Long)
|
||||
external fun streamSignalWait(handle: Long, timeoutMs: Int): Int
|
||||
external fun streamSignalClose(handle: Long)
|
||||
fun streamPlaybackCreate(id: Long, pts: Long, audio: Boolean): Long = nativeStreamPlaybackCreate(id, pts, audio)
|
||||
fun streamPlaybackFeed(handle: Long, pts: Long, packet: ByteArray): Int = nativeStreamPlaybackFeed(handle, pts, packet)
|
||||
fun streamPlaybackPull(handle: Long, frames: Int, limit: Long): ShortArray? = nativeStreamPlaybackPull(handle, frames, limit)
|
||||
@@ -227,6 +231,7 @@ object NativeLib {
|
||||
nativeStreamPlaybackUpdate(handle, now, played, ready, guard, starved)
|
||||
fun streamPlaybackFinish(handle: Long) { nativeStreamPlaybackFinish(handle) }
|
||||
fun streamPlaybackEmpty(handle: Long): Boolean = nativeStreamPlaybackEmpty(handle)
|
||||
fun streamPlaybackNeedsInput(handle: Long): Boolean = nativeStreamPlaybackNeedsInput(handle)
|
||||
fun streamPlaybackClose(handle: Long) { nativeStreamPlaybackClose(handle) }
|
||||
fun streamOpusCreate(encode: Boolean): Long = nativeStreamOpusCreate(encode)
|
||||
fun streamOpusEncode(handle: Long, pcm: ShortArray, compressor: RadioCompressorSettings): ByteArray? =
|
||||
@@ -241,7 +246,7 @@ object NativeLib {
|
||||
private external fun nativeStreamTxStats(id: Long): LongArray?
|
||||
private external fun nativeStreamSetAudioEnabled(id: Long, enabled: Boolean): Boolean
|
||||
private external fun nativeStreamStop(id: Long)
|
||||
private external fun nativeStreamPull(id: Long, position: Long, wantVideo: Boolean, audioAhead: Long): ByteArray?
|
||||
private external fun nativeStreamPull(id: Long, position: Long, video: Int, audioAhead: Long, records: Int): ByteArray?
|
||||
private external fun nativeStreamStatus(id: Long): LongArray?
|
||||
private external fun nativeStreamResync(id: Long): Boolean
|
||||
private external fun nativeStreamPlaybackCreate(id: Long, pts: Long, audio: Boolean): Long
|
||||
@@ -252,6 +257,7 @@ object NativeLib {
|
||||
guard: Long, starved: Boolean): LongArray?
|
||||
private external fun nativeStreamPlaybackFinish(handle: Long)
|
||||
private external fun nativeStreamPlaybackEmpty(handle: Long): Boolean
|
||||
private external fun nativeStreamPlaybackNeedsInput(handle: Long): Boolean
|
||||
private external fun nativeStreamPlaybackClose(handle: Long)
|
||||
private external fun nativeStreamOpusCreate(encode: Boolean): Long
|
||||
private external fun nativeStreamOpusEncode(handle: Long, pcm: ShortArray, compressor: Boolean, maxGainDb: Int, riseRate: Int): ByteArray?
|
||||
|
||||
@@ -76,7 +76,7 @@ internal object StreamAudioMixer {
|
||||
/** Независимые Opus/SoundTouch, темп и PTS. Video worker и mixer сериализуют только свой DSP.
|
||||
* Каждый 10ms блок общего выхода отражён в своей шкале, включая тишину при starvation/hold.
|
||||
* Reset создаёт новый Input с новой origin; AudioTrack и остальные источники продолжают играть. */
|
||||
internal class StreamMixedPlayback(val id: Long, pts: Long, private val audioEnabled: Boolean) {
|
||||
internal class StreamMixedPlayback(val id: Long, pts: Long, private val audioEnabled: Boolean, private val wake: () -> Unit) {
|
||||
private val lock = Any()
|
||||
private var handle = NativeLib.streamPlaybackCreate(id, pts, audioEnabled).also { check(it != 0L) }
|
||||
private val timeline = StreamMixTimeline()
|
||||
@@ -91,6 +91,7 @@ internal class StreamMixedPlayback(val id: Long, pts: Long, private val audioEna
|
||||
|
||||
val leadUs: Long get() = if (audioEnabled) StreamAudioMixer.output.leadUs else 0
|
||||
val empty: Boolean get() = synchronized(lock) { handle == 0L || NativeLib.streamPlaybackEmpty(handle) }
|
||||
val needsInput: Boolean get() = synchronized(lock) { handle != 0L && NativeLib.streamPlaybackNeedsInput(handle) }
|
||||
val drained: Boolean get() = synchronized(lock) {
|
||||
!audioEnabled || (ended && (endFrame?.let { timeline.played(StreamAudioMixer.output.played) >= it }
|
||||
?: (timeline.frames == 0L && NativeLib.streamPlaybackEmpty(handle))))
|
||||
@@ -123,9 +124,11 @@ internal class StreamMixedPlayback(val id: Long, pts: Long, private val audioEna
|
||||
if (ended && endFrame == null && NativeLib.streamPlaybackEmpty(handle)) endFrame = timeline.frames + count
|
||||
if (count < buffer.frames) NativeLib.streamPlaybackSilence(handle, buffer.frames - count)
|
||||
timeline.append(firstOutputFrame, buffer.frames)
|
||||
wake()
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
outputFailure = e.message ?: "Audio mixing failed"
|
||||
wake()
|
||||
LogManager.addLog("ERROR", "stream", "mixer input failed id=$id: ${e.message}")
|
||||
false
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user