@siteed/audio-studio 3.2.0-beta.1 → 3.2.0

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.
Files changed (85) hide show
  1. package/CHANGELOG.md +356 -5
  2. package/android/src/main/java/net/siteed/audiostudio/AudioStreamDecoder.kt +306 -94
  3. package/android/src/main/java/net/siteed/audiostudio/AudioStudioModule.kt +39 -6
  4. package/build/cjs/errors/AudioStreamError.js +9 -0
  5. package/build/cjs/errors/AudioStreamError.js.map +1 -1
  6. package/build/cjs/errors/AudioStreamError.test.js +22 -1
  7. package/build/cjs/errors/AudioStreamError.test.js.map +1 -1
  8. package/build/cjs/streamAudioData.js +99 -32
  9. package/build/cjs/streamAudioData.js.map +1 -1
  10. package/build/cjs/utils/audioProcessing.js +14 -10
  11. package/build/cjs/utils/audioProcessing.js.map +1 -1
  12. package/build/esm/errors/AudioStreamError.js +9 -0
  13. package/build/esm/errors/AudioStreamError.js.map +1 -1
  14. package/build/esm/errors/AudioStreamError.test.js +22 -1
  15. package/build/esm/errors/AudioStreamError.test.js.map +1 -1
  16. package/build/esm/streamAudioData.js +99 -32
  17. package/build/esm/streamAudioData.js.map +1 -1
  18. package/build/esm/utils/audioProcessing.js +14 -10
  19. package/build/esm/utils/audioProcessing.js.map +1 -1
  20. package/build/types/errors/AudioStreamError.d.ts.map +1 -1
  21. package/build/types/streamAudioData.d.ts +5 -0
  22. package/build/types/streamAudioData.d.ts.map +1 -1
  23. package/build/types/utils/audioProcessing.d.ts +2 -2
  24. package/build/types/utils/audioProcessing.d.ts.map +1 -1
  25. package/ios/AudioStreamDecoder.swift +191 -100
  26. package/ios/AudioStudioModule.swift +48 -9
  27. package/package.json +163 -146
  28. package/scripts/README.md +58 -0
  29. package/src/errors/AudioStreamError.test.ts +29 -2
  30. package/src/errors/AudioStreamError.ts +14 -0
  31. package/src/streamAudioData.ts +146 -42
  32. package/src/utils/audioProcessing.ts +25 -14
  33. package/android/src/androidTest/assets/chorus.wav +0 -0
  34. package/android/src/androidTest/assets/jfk.wav +0 -0
  35. package/android/src/androidTest/assets/osr_us_000_0010_8k.wav +0 -0
  36. package/android/src/androidTest/assets/recorder_hello_world.wav +0 -0
  37. package/android/src/androidTest/java/net/siteed/audiostudio/AudioFinalMetadataContractInstrumentedTest.kt +0 -190
  38. package/android/src/androidTest/java/net/siteed/audiostudio/AudioProcessorInstrumentedTest.kt +0 -197
  39. package/android/src/androidTest/java/net/siteed/audiostudio/AudioRecorderInstrumentedTest.kt +0 -487
  40. package/android/src/androidTest/java/net/siteed/audiostudio/AudioRecorderPerformanceInstrumentedTest.kt +0 -250
  41. package/android/src/androidTest/java/net/siteed/audiostudio/OpusRangeDecodeRegressionInstrumentedTest.kt +0 -186
  42. package/android/src/androidTest/java/net/siteed/audiostudio/integration/AudioFocusStrategyIntegrationTest.kt +0 -332
  43. package/android/src/androidTest/java/net/siteed/audiostudio/integration/BufferDurationIntegrationTest.kt +0 -324
  44. package/android/src/androidTest/java/net/siteed/audiostudio/integration/CompressedOnlyOutputTest.kt +0 -253
  45. package/android/src/androidTest/java/net/siteed/audiostudio/integration/DeviceDisconnectionFallbackTest.kt +0 -218
  46. package/android/src/androidTest/java/net/siteed/audiostudio/integration/EventEmissionIntervalTest.kt +0 -120
  47. package/android/src/androidTest/java/net/siteed/audiostudio/integration/M4aFormatTest.kt +0 -345
  48. package/android/src/androidTest/java/net/siteed/audiostudio/integration/OutputControlIntegrationTest.kt +0 -340
  49. package/android/src/androidTest/java/net/siteed/audiostudio/integration/PcmStreamingDurationTest.kt +0 -252
  50. package/android/src/androidTest/java/net/siteed/audiostudio/integration/README.md +0 -95
  51. package/android/src/androidTest/java/net/siteed/audiostudio/integration/run_integration_tests.sh +0 -43
  52. package/android/src/test/java/net/siteed/audiostudio/AndroidCallStateTest.kt +0 -37
  53. package/android/src/test/java/net/siteed/audiostudio/AndroidEventEmitterTest.kt +0 -28
  54. package/android/src/test/java/net/siteed/audiostudio/AudioFileHandlerTest.kt +0 -279
  55. package/android/src/test/java/net/siteed/audiostudio/AudioFocusStrategyTest.kt +0 -249
  56. package/android/src/test/java/net/siteed/audiostudio/AudioFormatTest.kt +0 -151
  57. package/android/src/test/java/net/siteed/audiostudio/AudioFormatUtilsTest.kt +0 -273
  58. package/android/src/test/java/net/siteed/audiostudio/DeviceDisconnectionFallbackUnitTest.kt +0 -140
  59. package/android/src/test/java/net/siteed/audiostudio/InterruptionAutoResumePolicyTest.kt +0 -49
  60. package/android/src/test/resources/chorus.wav +0 -0
  61. package/android/src/test/resources/generate_test_audio.py +0 -94
  62. package/android/src/test/resources/jfk.wav +0 -0
  63. package/android/src/test/resources/osr_us_000_0010_8k.wav +0 -0
  64. package/android/src/test/resources/recorder_hello_world.wav +0 -0
  65. package/ios/AudioStudioTests/AudioFileHandlerTests.swift +0 -338
  66. package/ios/AudioStudioTests/AudioFormatUtilsTests.swift +0 -331
  67. package/ios/AudioStudioTests/AudioStreamDecoderTests.swift +0 -128
  68. package/ios/AudioStudioTests/AudioTestHelpers.swift +0 -130
  69. package/ios/AudioStudioTests/CompressedOnlyOutputTests.swift +0 -334
  70. package/ios/AudioStudioTests/EventEmissionIntervalTests.swift +0 -105
  71. package/ios/AudioStudioTests/Info.plist +0 -22
  72. package/ios/AudioStudioTests/README.md +0 -39
  73. package/ios/AudioStudioTests/SimpleAudioTest.swift +0 -98
  74. package/ios/AudioStudioTests/TestAudioGenerator.swift +0 -75
  75. package/ios/tests/README.md +0 -41
  76. package/ios/tests/integration/buffer_and_fallback_test.swift +0 -178
  77. package/ios/tests/integration/buffer_duration_test.swift +0 -185
  78. package/ios/tests/integration/compressed_only_output_test.swift +0 -271
  79. package/ios/tests/integration/output_control_test.swift +0 -322
  80. package/ios/tests/integration/run_integration_tests.sh +0 -37
  81. package/ios/tests/opus_support_test_macos.swift +0 -154
  82. package/ios/tests/standalone/audio_processing_test.swift +0 -144
  83. package/ios/tests/standalone/audio_recording_test.swift +0 -277
  84. package/ios/tests/standalone/audio_streaming_test.swift +0 -249
  85. package/ios/tests/standalone/standalone_test.swift +0 -144
@@ -1,250 +0,0 @@
1
- package net.siteed.audiostudio
2
-
3
- import android.Manifest
4
- import android.content.Context
5
- import android.util.Log
6
- import androidx.test.ext.junit.runners.AndroidJUnit4
7
- import androidx.test.platform.app.InstrumentationRegistry
8
- import androidx.test.rule.GrantPermissionRule
9
- import expo.modules.kotlin.Promise
10
- import org.junit.After
11
- import org.junit.Assert.*
12
- import org.junit.Assume.assumeTrue
13
- import org.junit.Before
14
- import org.junit.Rule
15
- import org.junit.Test
16
- import org.junit.runner.RunWith
17
- import java.io.File
18
- import java.util.concurrent.CountDownLatch
19
- import java.util.concurrent.TimeUnit
20
- import kotlin.system.measureTimeMillis
21
-
22
- /**
23
- * Performance tests for measuring stop recording times.
24
- */
25
- @RunWith(AndroidJUnit4::class)
26
- class AudioRecorderPerformanceInstrumentedTest {
27
-
28
- @get:Rule
29
- val grantPermissionRule: GrantPermissionRule = GrantPermissionRule.grant(
30
- Manifest.permission.RECORD_AUDIO
31
- )
32
-
33
- private lateinit var context: Context
34
- private lateinit var filesDir: File
35
- private lateinit var audioRecorderManager: AudioRecorderManager
36
- private lateinit var testEventSender: TestEventSender
37
- private lateinit var permissionUtils: PermissionUtils
38
- private lateinit var audioDataEncoder: AudioDataEncoder
39
-
40
- companion object {
41
- private const val TAG = "PerformanceTest"
42
- }
43
-
44
- // Test event sender to capture events
45
- private class TestEventSender : EventSender {
46
- override fun sendExpoEvent(eventName: String, params: android.os.Bundle) {
47
- // No-op for performance tests
48
- }
49
- }
50
-
51
- @Before
52
- fun setUp() {
53
- context = InstrumentationRegistry.getInstrumentation().targetContext
54
- filesDir = context.filesDir
55
- testEventSender = TestEventSender()
56
- permissionUtils = PermissionUtils(context)
57
- audioDataEncoder = AudioDataEncoder()
58
-
59
- // Initialize AudioRecorderManager
60
- audioRecorderManager = AudioRecorderManager.initialize(
61
- context = context,
62
- filesDir = filesDir,
63
- permissionUtils = permissionUtils,
64
- audioDataEncoder = audioDataEncoder,
65
- eventSender = testEventSender,
66
- enablePhoneStateHandling = false,
67
- enableBackgroundAudio = false
68
- )
69
-
70
- // Clean up any existing audio files
71
- cleanupAudioFiles()
72
- }
73
-
74
- @After
75
- fun tearDown() {
76
- // Stop any ongoing recording
77
- if (audioRecorderManager.isRecording) {
78
- val promise = object : Promise {
79
- override fun resolve(value: Any?) {}
80
- override fun reject(code: String, message: String?, cause: Throwable?) {}
81
- }
82
- audioRecorderManager.stopRecording(promise)
83
- }
84
-
85
- // Clean up
86
- AudioRecorderManager.destroy()
87
- cleanupAudioFiles()
88
- }
89
-
90
- private fun cleanupAudioFiles() {
91
- filesDir.listFiles()?.forEach { file ->
92
- if (file.name.endsWith(".wav") || file.name.endsWith(".aac") || file.name.endsWith(".opus")) {
93
- file.delete()
94
- }
95
- }
96
- }
97
-
98
- @Test
99
- fun measureStopTime_5seconds() {
100
- runPerformanceTest(5_000L, "5 second recording")
101
- }
102
-
103
- @Test
104
- fun measureStopTime_30seconds() {
105
- runPerformanceTest(30_000L, "30 second recording")
106
- }
107
-
108
- @Test
109
- fun measureStopTime_1minute() {
110
- runPerformanceTest(60_000L, "1 minute recording")
111
- }
112
-
113
- @Test
114
- fun measureStopTime_2minutes() {
115
- runPerformanceTest(120_000L, "2 minute recording")
116
- }
117
-
118
- @Test
119
- fun measureStopTime_5minutes() {
120
- assumeLongPerformanceTestsEnabled()
121
- runPerformanceTest(300_000L, "5 minute recording")
122
- }
123
-
124
- @Test
125
- fun measureStopTime_10minutes() {
126
- assumeLongPerformanceTestsEnabled()
127
- runPerformanceTest(600_000L, "10 minute recording")
128
- }
129
-
130
- @Test
131
- fun measureStopTime_15minutes() {
132
- assumeLongPerformanceTestsEnabled()
133
- runPerformanceTest(900_000L, "15 minute recording")
134
- }
135
-
136
- private fun assumeLongPerformanceTestsEnabled() {
137
- val enabled = InstrumentationRegistry.getArguments()
138
- .getString("runLongPerformanceTests")
139
- ?.equals("true", ignoreCase = true) == true
140
-
141
- assumeTrue(
142
- "Long physical-device performance benchmarks are opt-in. " +
143
- "Run with -Pandroid.testInstrumentationRunnerArguments.runLongPerformanceTests=true",
144
- enabled
145
- )
146
- }
147
-
148
- private fun runPerformanceTest(recordingDurationMs: Long, testName: String) {
149
- val recordingOptions = mapOf(
150
- "sampleRate" to 44100,
151
- "channels" to 1,
152
- "encoding" to "pcm_16bit",
153
- "interval" to 1000,
154
- "enableProcessing" to false,
155
- "showNotification" to false,
156
- "output" to mapOf(
157
- "primary" to mapOf("enabled" to true),
158
- "compressed" to mapOf("enabled" to false)
159
- )
160
- )
161
-
162
- // Start recording
163
- val startLatch = CountDownLatch(1)
164
- audioRecorderManager.startRecording(recordingOptions, object : Promise {
165
- override fun resolve(value: Any?) {
166
- startLatch.countDown()
167
- }
168
- override fun reject(code: String, message: String?, cause: Throwable?) {
169
- fail("Start recording failed: $message")
170
- }
171
- })
172
-
173
- assertTrue("Recording should start", startLatch.await(5, TimeUnit.SECONDS))
174
- assertTrue("Recording should be active", audioRecorderManager.isRecording)
175
-
176
- // Record for specified duration
177
- Thread.sleep(recordingDurationMs)
178
-
179
- // Measure stop time
180
- val stopLatch = CountDownLatch(1)
181
- var fileSize = 0L
182
- var stopResult: Map<String, Any>? = null
183
-
184
- val stopDuration = measureTimeMillis {
185
- audioRecorderManager.stopRecording(object : Promise {
186
- override fun resolve(value: Any?) {
187
- when (value) {
188
- is android.os.Bundle -> {
189
- fileSize = value.getLong("size", 0)
190
- stopResult = bundleToMap(value)
191
- }
192
- is Map<*, *> -> {
193
- @Suppress("UNCHECKED_CAST")
194
- stopResult = value as? Map<String, Any>
195
- fileSize = (stopResult?.get("size") as? Long) ?: 0
196
- }
197
- }
198
- stopLatch.countDown()
199
- }
200
- override fun reject(code: String, message: String?, cause: Throwable?) {
201
- fail("Stop recording failed: $message")
202
- }
203
- })
204
-
205
- assertTrue("Stop should complete", stopLatch.await(10, TimeUnit.SECONDS))
206
- }
207
-
208
- // Log results
209
- val fileSizeMB = fileSize / (1024.0 * 1024.0)
210
- Log.i(TAG, """
211
- Performance Test: $testName
212
- - Recording Duration: ${recordingDurationMs}ms
213
- - Stop Duration: ${stopDuration}ms
214
- - File Size: ${"%.2f".format(fileSizeMB)}MB
215
- - Performance: ${if (stopDuration < getTargetTime(recordingDurationMs)) "PASS" else "FAIL"}
216
- """.trimIndent())
217
-
218
- println("""
219
- Performance Test: $testName
220
- - Recording Duration: ${recordingDurationMs}ms
221
- - Stop Duration: ${stopDuration}ms
222
- - File Size: ${"%.2f".format(fileSizeMB)}MB
223
- - Performance: ${if (stopDuration < getTargetTime(recordingDurationMs)) "PASS" else "FAIL"}
224
- """.trimIndent())
225
-
226
- assertFalse("Recording should not be active", audioRecorderManager.isRecording)
227
- }
228
-
229
- private fun getTargetTime(recordingDurationMs: Long): Long {
230
- return when {
231
- recordingDurationMs <= 5_000 -> 100
232
- recordingDurationMs <= 30_000 -> 150
233
- recordingDurationMs <= 60_000 -> 200
234
- recordingDurationMs <= 300_000 -> 500
235
- else -> 750
236
- }
237
- }
238
-
239
- private fun bundleToMap(bundle: android.os.Bundle): Map<String, Any> {
240
- val map = mutableMapOf<String, Any>()
241
- for (key in bundle.keySet()) {
242
- val value = bundle.get(key)
243
- when (value) {
244
- is android.os.Bundle -> map[key] = bundleToMap(value)
245
- else -> value?.let { map[key] = it }
246
- }
247
- }
248
- return map
249
- }
250
- }
@@ -1,186 +0,0 @@
1
- package net.siteed.audiostudio
2
-
3
- import android.Manifest
4
- import android.os.Build
5
- import androidx.test.ext.junit.runners.AndroidJUnit4
6
- import androidx.test.platform.app.InstrumentationRegistry
7
- import androidx.test.rule.GrantPermissionRule
8
- import expo.modules.kotlin.Promise
9
- import org.junit.After
10
- import org.junit.Assert.assertEquals
11
- import org.junit.Assert.assertTrue
12
- import org.junit.Assume.assumeTrue
13
- import org.junit.Before
14
- import org.junit.Rule
15
- import org.junit.Test
16
- import org.junit.runner.RunWith
17
- import java.io.File
18
- import java.net.URI
19
- import java.util.concurrent.CountDownLatch
20
- import java.util.concurrent.TimeUnit
21
- import kotlin.math.abs
22
-
23
- /**
24
- * Device-only regression skeleton for compressed Opus range decode. It records a
25
- * short Opus-only file, then verifies the range loader reports metadata and byte
26
- * length from final target-converted PCM rather than source decoder output.
27
- */
28
- @RunWith(AndroidJUnit4::class)
29
- class OpusRangeDecodeRegressionInstrumentedTest {
30
- @get:Rule
31
- val grantPermissionRule: GrantPermissionRule = GrantPermissionRule.grant(Manifest.permission.RECORD_AUDIO)
32
-
33
- private val context = InstrumentationRegistry.getInstrumentation().targetContext
34
- private val filesDir = context.filesDir
35
- private lateinit var audioRecorderManager: AudioRecorderManager
36
-
37
- @Before
38
- fun setUp() {
39
- assumeTrue("Opus MediaCodec recording requires Android Q+", Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
40
- audioRecorderManager = AudioRecorderManager.initialize(
41
- context = context,
42
- filesDir = filesDir,
43
- permissionUtils = PermissionUtils(context),
44
- audioDataEncoder = AudioDataEncoder(),
45
- eventSender = object : EventSender {
46
- override fun sendExpoEvent(eventName: String, params: android.os.Bundle) = Unit
47
- },
48
- enablePhoneStateHandling = false,
49
- enableBackgroundAudio = false
50
- )
51
- cleanupGeneratedAudio()
52
- }
53
-
54
- @After
55
- fun tearDown() {
56
- if (::audioRecorderManager.isInitialized && audioRecorderManager.isRecording) {
57
- runCatching { stopRecordingSync() }
58
- }
59
- AudioRecorderManager.destroy()
60
- cleanupGeneratedAudio()
61
- }
62
-
63
- @Test
64
- fun loadAudioRange_returnsTargetPcmMetadataForGeneratedOpusRecording() {
65
- startRecordingSync(
66
- mapOf(
67
- "sampleRate" to 48_000,
68
- "channels" to 1,
69
- "encoding" to "pcm_16bit",
70
- "interval" to 100,
71
- "showNotification" to false,
72
- "output" to mapOf(
73
- "primary" to mapOf("enabled" to false),
74
- "compressed" to mapOf(
75
- "enabled" to true,
76
- "format" to "opus"
77
- )
78
- )
79
- )
80
- )
81
- Thread.sleep(RECORDING_DURATION_MS + 250L)
82
- val opusFile = resolveCompressedFile(stopRecordingSync())
83
-
84
- val audioData = AudioProcessor(filesDir).loadAudioRange(
85
- fileUri = opusFile.absolutePath,
86
- startTimeMs = 0,
87
- endTimeMs = REQUESTED_RANGE_MS,
88
- config = DecodingConfig(
89
- targetSampleRate = TARGET_SAMPLE_RATE,
90
- targetChannels = TARGET_CHANNELS,
91
- targetBitDepth = TARGET_BIT_DEPTH,
92
- normalizeAudio = false
93
- )
94
- )
95
-
96
- val decoded = requireNotNull(audioData) { "Opus range should decode without BufferOverflowException" }
97
- assertEquals("sampleRate should describe final converted PCM", TARGET_SAMPLE_RATE, decoded.sampleRate)
98
- assertEquals("channels should describe final converted PCM", TARGET_CHANNELS, decoded.channels)
99
- assertEquals("bitDepth should describe final converted PCM", TARGET_BIT_DEPTH, decoded.bitDepth)
100
-
101
- val expectedBytes = TARGET_SAMPLE_RATE * TARGET_CHANNELS * (TARGET_BIT_DEPTH / 8) * REQUESTED_RANGE_MS / 1_000
102
- val toleranceBytes = TARGET_SAMPLE_RATE * TARGET_CHANNELS * (TARGET_BIT_DEPTH / 8) / 2
103
- assertTrue(
104
- "final PCM byte length should be near requested target duration: expected=$expectedBytes actual=${decoded.data.size}",
105
- abs(decoded.data.size - expectedBytes) <= toleranceBytes
106
- )
107
- }
108
-
109
- private fun startRecordingSync(recordingOptions: Map<String, Any?>) {
110
- val latch = CountDownLatch(1)
111
- var rejected: String? = null
112
- audioRecorderManager.startRecording(recordingOptions, object : Promise {
113
- override fun resolve(value: Any?) {
114
- latch.countDown()
115
- }
116
-
117
- override fun reject(code: String, message: String?, cause: Throwable?) {
118
- rejected = "$code - $message"
119
- latch.countDown()
120
- }
121
- })
122
- assertTrue("Recording should start within 2 seconds", latch.await(2, TimeUnit.SECONDS))
123
- rejected?.let { throw AssertionError("Recording start failed: $it") }
124
- }
125
-
126
- private fun stopRecordingSync(): Map<String, Any?> {
127
- val latch = CountDownLatch(1)
128
- var result: Map<String, Any?>? = null
129
- var rejected: String? = null
130
- audioRecorderManager.stopRecording(object : Promise {
131
- override fun resolve(value: Any?) {
132
- result = when (value) {
133
- is android.os.Bundle -> bundleToMap(value)
134
- is Map<*, *> -> value.entries.associate { it.key.toString() to it.value }
135
- else -> throw AssertionError("Unexpected stop result type: ${value?.javaClass?.name}")
136
- }
137
- latch.countDown()
138
- }
139
-
140
- override fun reject(code: String, message: String?, cause: Throwable?) {
141
- rejected = "$code - $message"
142
- latch.countDown()
143
- }
144
- })
145
- assertTrue("Recording should stop within 2 seconds", latch.await(2, TimeUnit.SECONDS))
146
- rejected?.let { throw AssertionError("Recording stop failed: $it") }
147
- return result ?: throw AssertionError("Stop result should not be null")
148
- }
149
-
150
- private fun resolveCompressedFile(result: Map<String, Any?>): File {
151
- val compression = result["compression"]
152
- val compressionMap = when (compression) {
153
- is android.os.Bundle -> bundleToMap(compression)
154
- is Map<*, *> -> compression.entries.associate { it.key.toString() to it.value }
155
- else -> emptyMap()
156
- }
157
- val uri = compressionMap["compressedFileUri"] as? String
158
- ?: throw AssertionError("Compressed Opus URI should be present in stop result: $result")
159
- val file = when {
160
- uri.startsWith("file://") || uri.startsWith("file:") -> File(URI(uri))
161
- else -> File(uri)
162
- }
163
- assertTrue("Generated Opus file should exist: ${file.absolutePath}", file.exists())
164
- assertTrue("Generated file should be Opus: ${file.name}", file.name.endsWith(".opus"))
165
- return file
166
- }
167
-
168
- private fun bundleToMap(bundle: android.os.Bundle): Map<String, Any?> =
169
- bundle.keySet().associateWith { key -> bundle.get(key) }
170
-
171
- private fun cleanupGeneratedAudio() {
172
- filesDir.listFiles()?.forEach { file ->
173
- if (file.name.startsWith("recording_") && file.extension in setOf("opus", "wav", "m4a", "aac")) {
174
- file.delete()
175
- }
176
- }
177
- }
178
-
179
- companion object {
180
- private const val RECORDING_DURATION_MS = 2_000L
181
- private const val REQUESTED_RANGE_MS = 2_000L
182
- private const val TARGET_SAMPLE_RATE = 16_000
183
- private const val TARGET_CHANNELS = 1
184
- private const val TARGET_BIT_DEPTH = 16
185
- }
186
- }