Implement Audio Segmentation for VAD Pipeline

Resolved 💬 2 comments Opened Oct 20, 2025 by sanchitmonga22 Closed Oct 20, 2025

Priority

HIGH

Context

Audio Segmentation splits continuous audio streams into speech segments for processing. The iOS SDK has AudioSegmentation infrastructure. The Kotlin SDK is missing this capability.

Current State

  • Status: Infrastructure does not exist
  • Impact: VAD cannot efficiently process audio streams
  • iOS Has: Complete AudioSegmentation with buffer management

iOS Reference Implementation

  • Service: sdk/runanywhere-swift/Sources/RunAnywhere/Infrastructure/Audio/AudioSegmentation.swift

iOS Architecture Pattern

public final class AudioSegmentation {
    public func segment(audioStream: AsyncStream<Data>) -> AsyncStream<AudioSegment>
    
    public struct AudioSegment {
        public let data: Data
        public let startTime: TimeInterval
        public let duration: TimeInterval
    }
}

Implementation Plan

1. Define Common Interfaces (commonMain)

// commonMain/kotlin/com/runanywhere/sdk/infrastructure/audio/AudioSegmentation.kt
class AudioSegmentation(
    private val configuration: SegmentationConfiguration
) {
    
    fun segment(audioStream: Flow<ByteArray>): Flow<AudioSegment> = flow {
        var buffer = ByteArrayBuffer()
        var startTime = 0L
        
        audioStream.collect { chunk ->
            buffer.append(chunk)
            
            // Check if we have enough data for a segment
            if (buffer.size >= configuration.minSegmentSize) {
                val segment = AudioSegment(
                    data = buffer.toByteArray(),
                    startTime = startTime,
                    duration = calculateDuration(buffer.size, configuration.sampleRate)
                )
                
                emit(segment)
                buffer.clear()
                startTime += segment.duration
            }
        }
        
        // Emit remaining buffer
        if (buffer.size > 0) {
            emit(AudioSegment(
                data = buffer.toByteArray(),
                startTime = startTime,
                duration = calculateDuration(buffer.size, configuration.sampleRate)
            ))
        }
    }
    
    private fun calculateDuration(bytes: Int, sampleRate: Int): Long {
        val samplesPerSecond = sampleRate * 2 // 16-bit = 2 bytes per sample
        return (bytes.toLong() * 1000) / samplesPerSecond
    }
}

data class AudioSegment(
    val data: ByteArray,
    val startTime: Long,
    val duration: Long
)

data class SegmentationConfiguration(
    val minSegmentSize: Int = 8000, // ~500ms at 16kHz
    val maxSegmentSize: Int = 48000, // ~3s at 16kHz
    val sampleRate: Int = 16000
)

private class ByteArrayBuffer {
    private val buffer = mutableListOf<Byte>()
    
    fun append(data: ByteArray) {
        buffer.addAll(data.toList())
    }
    
    fun toByteArray(): ByteArray = buffer.toByteArray()
    
    fun clear() {
        buffer.clear()
    }
    
    val size: Int get() = buffer.size
}

Files to Create/Modify

New Files (commonMain)

  • [ ] infrastructure/audio/AudioSegmentation.kt
  • [ ] infrastructure/audio/models/AudioSegment.kt
  • [ ] infrastructure/audio/models/SegmentationConfiguration.kt

Testing Requirements

  • [ ] Unit tests for segmentation logic
  • [ ] Buffer overflow tests
  • [ ] Duration calculation tests
  • [ ] Stream processing tests

Success Criteria

  • [ ] Correctly segments audio streams
  • [ ] Accurate duration calculations
  • [ ] Proper buffer management
  • [ ] No memory leaks

Estimated Effort

3-5 days

Dependencies

  • Depends on: #153 (Audio Capture Infrastructure)

🤖 Generated with Claude Code

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗