@mentra/acs-meeting 3.2.0-dev.136 → 3.2.0-dev.153

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,4 @@
1
+ import AVFoundation
1
2
  import Foundation
2
3
 
3
4
  /// Downmix/resample PCM16 to 48 kHz mono ~20 ms blocks for ACS raw outgoing audio.
@@ -63,6 +64,54 @@ final class PcmBridge {
63
64
 
64
65
  static let targetRate = 48_000
65
66
 
67
+ static func audioBuffer(pcm16Le data: Data, sampleRate: Int, channels: Int) -> AVAudioPCMBuffer? {
68
+ guard channels > 0, data.count >= channels * MemoryLayout<Int16>.size else { return nil }
69
+ guard let format = AVAudioFormat(
70
+ commonFormat: .pcmFormatInt16,
71
+ sampleRate: Double(sampleRate),
72
+ channels: AVAudioChannelCount(channels),
73
+ interleaved: false
74
+ ) else { return nil }
75
+ let frameCount = data.count / (channels * MemoryLayout<Int16>.size)
76
+ guard let buffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: AVAudioFrameCount(frameCount)),
77
+ let destinations = buffer.int16ChannelData else { return nil }
78
+ buffer.frameLength = AVAudioFrameCount(frameCount)
79
+ data.withUnsafeBytes { raw in
80
+ let samples = raw.bindMemory(to: Int16.self)
81
+ for frame in 0 ..< frameCount {
82
+ for channel in 0 ..< channels {
83
+ destinations[channel][frame] = samples[frame * channels + channel]
84
+ }
85
+ }
86
+ }
87
+ return buffer
88
+ }
89
+
90
+ static func pcm16Data(from buffer: AVAudioPCMBuffer) -> Data? {
91
+ let frames = Int(buffer.frameLength)
92
+ let channels = Int(buffer.format.channelCount)
93
+ guard frames > 0, channels > 0 else { return nil }
94
+
95
+ var output = [Int16](repeating: 0, count: frames * channels)
96
+ if let sources = buffer.int16ChannelData {
97
+ for frame in 0 ..< frames {
98
+ for channel in 0 ..< channels {
99
+ output[frame * channels + channel] = sources[channel][frame]
100
+ }
101
+ }
102
+ } else if let sources = buffer.floatChannelData {
103
+ for frame in 0 ..< frames {
104
+ for channel in 0 ..< channels {
105
+ let clipped = max(-1.0, min(1.0, sources[channel][frame]))
106
+ output[frame * channels + channel] = Int16(clipped * Float(Int16.max))
107
+ }
108
+ }
109
+ } else {
110
+ return nil
111
+ }
112
+ return output.withUnsafeBufferPointer { Data(buffer: $0) }
113
+ }
114
+
66
115
  static func toMono(_ pcm16Le: Data, sampleRate: Int, channels: Int) -> Data {
67
116
  let samples = pcm16Le.withUnsafeBytes { Array($0.bindMemory(to: Int16.self)) }
68
117
  let mono: [Int16]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mentra/acs-meeting",
3
- "version": "3.2.0-dev.136",
3
+ "version": "3.2.0-dev.153",
4
4
  "description": "MentraOS native ACS Teams meeting module (WHEP decode → ACS raw media)",
5
5
  "main": "build/index.js",
6
6
  "react-native": "src/index.ts",