|
|
|
|
@ -29,6 +29,7 @@ import java.io.ByteArrayOutputStream
|
|
|
|
|
class StreamCaptureEngine( |
|
|
|
|
private val context: Context, private val id: Long, private val group: Long, |
|
|
|
|
private val initialConfig: StreamCaptureConfig, private val microphone: Boolean, private val preview: StreamPreview, |
|
|
|
|
initialAudioCompressor: RadioCompressorSettings, |
|
|
|
|
private val ready: (StreamCaptureConfig, Boolean) -> Unit, private val failure: (String) -> Unit |
|
|
|
|
) { |
|
|
|
|
private val thread = HandlerThread("stream-camera").apply { start() } |
|
|
|
|
@ -41,6 +42,7 @@ class StreamCaptureEngine(
|
|
|
|
|
private var record: AudioRecord? = null |
|
|
|
|
private var audioThread: Thread? = null |
|
|
|
|
@Volatile private var audioRunning = false |
|
|
|
|
@Volatile var audioCompressorSettings = initialAudioCompressor |
|
|
|
|
@Volatile private var stopped = false |
|
|
|
|
private var stopping = false |
|
|
|
|
private var terminalFailure = false |
|
|
|
|
@ -345,10 +347,13 @@ class StreamCaptureEngine(
|
|
|
|
|
private fun startAudio() { |
|
|
|
|
val min = AudioRecord.getMinBufferSize(48000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT) |
|
|
|
|
check(min > 0) |
|
|
|
|
val rec = AudioRecord(MediaRecorder.AudioSource.MIC, 48000, AudioFormat.CHANNEL_IN_MONO, |
|
|
|
|
val rec = AudioRecord(MediaRecorder.AudioSource.CAMCORDER, 48000, AudioFormat.CHANNEL_IN_MONO, |
|
|
|
|
AudioFormat.ENCODING_PCM_16BIT, (min * 2).coerceAtLeast(960 * 8)) |
|
|
|
|
record = rec; check(rec.state == AudioRecord.STATE_INITIALIZED) |
|
|
|
|
rec.startRecording(); audioRunning = true |
|
|
|
|
rec.startRecording(); check(rec.recordingState == AudioRecord.RECORDSTATE_RECORDING) { "CAMCORDER capture did not start" } |
|
|
|
|
audioRunning = true |
|
|
|
|
LogManager.addLog("INFO", "stream", "audio capture started id=$id source=CAMCORDER(${rec.audioSource}) " + |
|
|
|
|
"rate=${rec.sampleRate} channels=${rec.channelCount} compressor=$audioCompressorSettings") |
|
|
|
|
audioThread = Thread({ |
|
|
|
|
var opus = 0L |
|
|
|
|
try { |
|
|
|
|
@ -371,7 +376,7 @@ class StreamCaptureEngine(
|
|
|
|
|
waitingStamp = false |
|
|
|
|
val pts = (stamp.nanoTime - originNs) / 1000 - (stamp.framePosition - first) * 1_000_000 / 48000 |
|
|
|
|
check(pts >= 0 && pts > last) { "Audio timestamp discontinuity pts=$pts last=$last" }; last = pts |
|
|
|
|
val packet = NativeLib.streamOpusEncode(opus, pcm) ?: error("Opus encode failed") |
|
|
|
|
val packet = NativeLib.streamOpusEncode(opus, pcm, audioCompressorSettings) ?: error("Stream compressor/Opus encode failed") |
|
|
|
|
check(NativeLib.streamFeed(id, false, pts, false, packet) >= 0) { "Stream audio publisher detached" } |
|
|
|
|
} |
|
|
|
|
} catch (e: Exception) { if (audioRunning) handler.post { failed("audio capture: ${e.message}") } } |
|
|
|
|
|