remove unused append(_ data: Data) overload from AudioBuffer
Only one append path exists now: append(from:count:), which is what the IO proc callback uses. The Data-based overload had no callers in source and added a dead code path to maintain. Also resolves CoreAudio.AudioBuffer name collision in tests via typealias. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -82,16 +82,6 @@ public class AudioBuffer {
|
|||||||
availableBytes += count
|
availableBytes += count
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Appends audio data from a Data value. Delegates to the raw pointer
|
|
||||||
/// path; prefer append(from:count:) when you already have a pointer to
|
|
||||||
/// avoid creating a Data object.
|
|
||||||
public func append(_ data: Data) {
|
|
||||||
data.withUnsafeBytes { bytes in
|
|
||||||
guard let baseAddress = bytes.baseAddress else { return }
|
|
||||||
append(from: baseAddress, count: bytes.count)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extracts all complete chunks currently available in the buffer.
|
/// Extracts all complete chunks currently available in the buffer.
|
||||||
public func processChunks() -> [AudioPacket] {
|
public func processChunks() -> [AudioPacket] {
|
||||||
var packets: [AudioPacket] = []
|
var packets: [AudioPacket] = []
|
||||||
|
|||||||
@@ -3,6 +3,10 @@ import XCTest
|
|||||||
|
|
||||||
@testable import AudioTeeCore
|
@testable import AudioTeeCore
|
||||||
|
|
||||||
|
// CoreAudio defines its own AudioBuffer struct, which collides with ours.
|
||||||
|
// Explicit module qualification avoids ambiguity in tests that import both.
|
||||||
|
private typealias AudioBuffer = AudioTeeCore.AudioBuffer
|
||||||
|
|
||||||
final class AudioBufferTests: XCTestCase {
|
final class AudioBufferTests: XCTestCase {
|
||||||
|
|
||||||
// MARK: - Helpers
|
// MARK: - Helpers
|
||||||
@@ -32,6 +36,14 @@ final class AudioBufferTests: XCTestCase {
|
|||||||
return Data(repeating: byte, count: count)
|
return Data(repeating: byte, count: count)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Appends Data to an AudioBuffer via the raw pointer path,
|
||||||
|
/// matching how processAudio() calls append(from:count:).
|
||||||
|
private func appendData(_ data: Data, to buffer: AudioBuffer) {
|
||||||
|
data.withUnsafeBytes { bytes in
|
||||||
|
buffer.append(from: bytes.baseAddress!, count: bytes.count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Basic append + processChunks
|
// MARK: - Basic append + processChunks
|
||||||
|
|
||||||
func testSingleChunkExtraction() {
|
func testSingleChunkExtraction() {
|
||||||
@@ -40,9 +52,8 @@ final class AudioBufferTests: XCTestCase {
|
|||||||
let buffer = AudioBuffer(format: format, chunkDuration: 0.1)
|
let buffer = AudioBuffer(format: format, chunkDuration: 0.1)
|
||||||
let chunkSize = 3200 // 16000 * 0.1 * 2
|
let chunkSize = 3200 // 16000 * 0.1 * 2
|
||||||
|
|
||||||
// Append exactly one chunk worth of data via Data path
|
|
||||||
let data = makeData(byte: 0xAB, count: chunkSize)
|
let data = makeData(byte: 0xAB, count: chunkSize)
|
||||||
buffer.append(data)
|
appendData(data, to: buffer)
|
||||||
|
|
||||||
let packets = buffer.processChunks()
|
let packets = buffer.processChunks()
|
||||||
XCTAssertEqual(packets.count, 1)
|
XCTAssertEqual(packets.count, 1)
|
||||||
@@ -56,7 +67,7 @@ final class AudioBufferTests: XCTestCase {
|
|||||||
let chunkSize = 3200
|
let chunkSize = 3200
|
||||||
|
|
||||||
// Append 2.5 chunks worth
|
// Append 2.5 chunks worth
|
||||||
buffer.append(makeData(byte: 0x01, count: chunkSize * 2 + chunkSize / 2))
|
appendData(makeData(byte: 0x01, count: chunkSize * 2 + chunkSize / 2), to: buffer)
|
||||||
|
|
||||||
let packets = buffer.processChunks()
|
let packets = buffer.processChunks()
|
||||||
// Should get 2 complete chunks, remainder stays in buffer
|
// Should get 2 complete chunks, remainder stays in buffer
|
||||||
@@ -71,30 +82,12 @@ final class AudioBufferTests: XCTestCase {
|
|||||||
let chunkSize = 3200
|
let chunkSize = 3200
|
||||||
|
|
||||||
// Append less than one chunk
|
// Append less than one chunk
|
||||||
buffer.append(makeData(byte: 0xFF, count: chunkSize - 1))
|
appendData(makeData(byte: 0xFF, count: chunkSize - 1), to: buffer)
|
||||||
|
|
||||||
let packets = buffer.processChunks()
|
let packets = buffer.processChunks()
|
||||||
XCTAssertEqual(packets.count, 0)
|
XCTAssertEqual(packets.count, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Zero-copy append(from:count:)
|
|
||||||
|
|
||||||
func testZeroCopyAppend() {
|
|
||||||
let format = makeFormat()
|
|
||||||
let buffer = AudioBuffer(format: format, chunkDuration: 0.1)
|
|
||||||
let chunkSize = 3200
|
|
||||||
|
|
||||||
// Simulate what processAudio does: pass a raw pointer directly
|
|
||||||
let source = makeData(byte: 0xCD, count: chunkSize)
|
|
||||||
source.withUnsafeBytes { bytes in
|
|
||||||
buffer.append(from: bytes.baseAddress!, count: bytes.count)
|
|
||||||
}
|
|
||||||
|
|
||||||
let packets = buffer.processChunks()
|
|
||||||
XCTAssertEqual(packets.count, 1)
|
|
||||||
XCTAssertEqual(packets[0].data, source)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Wrap-around
|
// MARK: - Wrap-around
|
||||||
|
|
||||||
func testWrapAroundWrite() {
|
func testWrapAroundWrite() {
|
||||||
@@ -104,12 +97,11 @@ final class AudioBufferTests: XCTestCase {
|
|||||||
let format = makeFormat(sampleRate: 8000)
|
let format = makeFormat(sampleRate: 8000)
|
||||||
let buffer = AudioBuffer(format: format, chunkDuration: 0.3)
|
let buffer = AudioBuffer(format: format, chunkDuration: 0.3)
|
||||||
let chunkSize = 4800 // 8000 * 0.3 * 2
|
let chunkSize = 4800 // 8000 * 0.3 * 2
|
||||||
let maxBuffer = 160000 // 8000 * 2 * 10
|
|
||||||
|
|
||||||
// Write 33 chunks (158400 bytes), drain them all.
|
// Write 33 chunks (158400 bytes), drain them all.
|
||||||
// writeIndex = 158400, readIndex = 158400. 1600 bytes remain before boundary.
|
// writeIndex = 158400, readIndex = 158400. 1600 bytes remain before boundary.
|
||||||
for _ in 0..<33 {
|
for _ in 0..<33 {
|
||||||
buffer.append(makeData(byte: 0x00, count: chunkSize))
|
appendData(makeData(byte: 0x00, count: chunkSize), to: buffer)
|
||||||
}
|
}
|
||||||
let drained = buffer.processChunks()
|
let drained = buffer.processChunks()
|
||||||
XCTAssertEqual(drained.count, 33)
|
XCTAssertEqual(drained.count, 33)
|
||||||
@@ -123,7 +115,7 @@ final class AudioBufferTests: XCTestCase {
|
|||||||
wrappingData.append(makeData(byte: 0xAA, count: 1600)) // fills to boundary
|
wrappingData.append(makeData(byte: 0xAA, count: 1600)) // fills to boundary
|
||||||
wrappingData.append(makeData(byte: 0xBB, count: 3200)) // wraps to start
|
wrappingData.append(makeData(byte: 0xBB, count: 3200)) // wraps to start
|
||||||
XCTAssertEqual(wrappingData.count, chunkSize)
|
XCTAssertEqual(wrappingData.count, chunkSize)
|
||||||
buffer.append(wrappingData)
|
appendData(wrappingData, to: buffer)
|
||||||
|
|
||||||
let packets = buffer.processChunks()
|
let packets = buffer.processChunks()
|
||||||
XCTAssertEqual(packets.count, 1)
|
XCTAssertEqual(packets.count, 1)
|
||||||
@@ -139,7 +131,7 @@ final class AudioBufferTests: XCTestCase {
|
|||||||
|
|
||||||
// Write and drain 33 chunks. Both indices land at 158400.
|
// Write and drain 33 chunks. Both indices land at 158400.
|
||||||
for _ in 0..<33 {
|
for _ in 0..<33 {
|
||||||
buffer.append(makeData(byte: 0x00, count: chunkSize))
|
appendData(makeData(byte: 0x00, count: chunkSize), to: buffer)
|
||||||
}
|
}
|
||||||
_ = buffer.processChunks()
|
_ = buffer.processChunks()
|
||||||
|
|
||||||
@@ -151,43 +143,13 @@ final class AudioBufferTests: XCTestCase {
|
|||||||
var crossBoundaryData = Data()
|
var crossBoundaryData = Data()
|
||||||
crossBoundaryData.append(makeData(byte: 0xCC, count: 1600))
|
crossBoundaryData.append(makeData(byte: 0xCC, count: 1600))
|
||||||
crossBoundaryData.append(makeData(byte: 0xDD, count: 3200))
|
crossBoundaryData.append(makeData(byte: 0xDD, count: 3200))
|
||||||
buffer.append(crossBoundaryData)
|
appendData(crossBoundaryData, to: buffer)
|
||||||
|
|
||||||
let packets = buffer.processChunks()
|
let packets = buffer.processChunks()
|
||||||
XCTAssertEqual(packets.count, 1)
|
XCTAssertEqual(packets.count, 1)
|
||||||
XCTAssertEqual(packets[0].data, crossBoundaryData)
|
XCTAssertEqual(packets[0].data, crossBoundaryData)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testZeroCopyAppendWrapAround() {
|
|
||||||
// Verify that the raw-pointer append path also wraps correctly,
|
|
||||||
// since it has its own copy logic separate from the Data-based path.
|
|
||||||
let format = makeFormat(sampleRate: 8000)
|
|
||||||
let buffer = AudioBuffer(format: format, chunkDuration: 0.3)
|
|
||||||
let chunkSize = 4800
|
|
||||||
|
|
||||||
// Position writeIndex at 158400 via write + drain
|
|
||||||
for _ in 0..<33 {
|
|
||||||
let data = makeData(byte: 0x00, count: chunkSize)
|
|
||||||
data.withUnsafeBytes { bytes in
|
|
||||||
buffer.append(from: bytes.baseAddress!, count: bytes.count)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ = buffer.processChunks()
|
|
||||||
|
|
||||||
// Write a wrapping chunk via the raw-pointer path
|
|
||||||
var wrappingData = Data()
|
|
||||||
wrappingData.append(makeData(byte: 0xEE, count: 1600))
|
|
||||||
wrappingData.append(makeData(byte: 0xFF, count: 3200))
|
|
||||||
|
|
||||||
wrappingData.withUnsafeBytes { bytes in
|
|
||||||
buffer.append(from: bytes.baseAddress!, count: bytes.count)
|
|
||||||
}
|
|
||||||
|
|
||||||
let packets = buffer.processChunks()
|
|
||||||
XCTAssertEqual(packets.count, 1)
|
|
||||||
XCTAssertEqual(packets[0].data, wrappingData)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Overflow guard
|
// MARK: - Overflow guard
|
||||||
|
|
||||||
func testOverflowPreventsWrite() {
|
func testOverflowPreventsWrite() {
|
||||||
@@ -196,10 +158,10 @@ final class AudioBufferTests: XCTestCase {
|
|||||||
let maxBuffer = 160000
|
let maxBuffer = 160000
|
||||||
|
|
||||||
// Fill the buffer completely
|
// Fill the buffer completely
|
||||||
buffer.append(makeData(byte: 0x01, count: maxBuffer))
|
appendData(makeData(byte: 0x01, count: maxBuffer), to: buffer)
|
||||||
|
|
||||||
// Try to append more — should be silently rejected (overflow guard)
|
// Try to append more — should be silently rejected (overflow guard)
|
||||||
buffer.append(makeData(byte: 0x02, count: 100))
|
appendData(makeData(byte: 0x02, count: 100), to: buffer)
|
||||||
|
|
||||||
// Drain and verify we only got the original data
|
// Drain and verify we only got the original data
|
||||||
let packets = buffer.processChunks()
|
let packets = buffer.processChunks()
|
||||||
@@ -222,7 +184,7 @@ final class AudioBufferTests: XCTestCase {
|
|||||||
// Simulate many small IO callbacks building up to one chunk
|
// Simulate many small IO callbacks building up to one chunk
|
||||||
let callbackSize = 320 // 10 callbacks to fill one chunk
|
let callbackSize = 320 // 10 callbacks to fill one chunk
|
||||||
for i in 0..<10 {
|
for i in 0..<10 {
|
||||||
buffer.append(makeData(byte: UInt8(i), count: callbackSize))
|
appendData(makeData(byte: UInt8(i), count: callbackSize), to: buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
let packets = buffer.processChunks()
|
let packets = buffer.processChunks()
|
||||||
@@ -242,7 +204,7 @@ final class AudioBufferTests: XCTestCase {
|
|||||||
let format = makeFormat()
|
let format = makeFormat()
|
||||||
let buffer = AudioBuffer(format: format, chunkDuration: 0.1)
|
let buffer = AudioBuffer(format: format, chunkDuration: 0.1)
|
||||||
|
|
||||||
buffer.append(makeData(byte: 0x00, count: 3200))
|
appendData(makeData(byte: 0x00, count: 3200), to: buffer)
|
||||||
let packets = buffer.processChunks()
|
let packets = buffer.processChunks()
|
||||||
|
|
||||||
XCTAssertEqual(packets[0].duration, 0.1, accuracy: 0.001)
|
XCTAssertEqual(packets[0].duration, 0.1, accuracy: 0.001)
|
||||||
|
|||||||
Reference in New Issue
Block a user