@siteed/expo-audio-stream 2.0.1 → 2.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.
- package/README.md +46 -27
- package/build/index.d.ts +11 -12
- package/build/index.js +44 -10
- package/package.json +49 -110
- package/src/index.ts +18 -33
- package/CHANGELOG.md +0 -195
- package/android/build.gradle +0 -105
- package/android/src/main/AndroidManifest.xml +0 -27
- package/android/src/main/java/net/siteed/audiostream/AudioAnalysisData.kt +0 -166
- package/android/src/main/java/net/siteed/audiostream/AudioDataEncoder.kt +0 -9
- package/android/src/main/java/net/siteed/audiostream/AudioFileHandler.kt +0 -131
- package/android/src/main/java/net/siteed/audiostream/AudioFormatUtils.kt +0 -103
- package/android/src/main/java/net/siteed/audiostream/AudioNotificationsManager.kt +0 -435
- package/android/src/main/java/net/siteed/audiostream/AudioProcessor.kt +0 -1936
- package/android/src/main/java/net/siteed/audiostream/AudioRecorderManager.kt +0 -1437
- package/android/src/main/java/net/siteed/audiostream/AudioRecordingService.kt +0 -138
- package/android/src/main/java/net/siteed/audiostream/Constants.kt +0 -20
- package/android/src/main/java/net/siteed/audiostream/EventSender.kt +0 -7
- package/android/src/main/java/net/siteed/audiostream/ExpoAudioStreamModule.kt +0 -509
- package/android/src/main/java/net/siteed/audiostream/FFT.kt +0 -99
- package/android/src/main/java/net/siteed/audiostream/Features.kt +0 -98
- package/android/src/main/java/net/siteed/audiostream/NotificationConfig.kt +0 -70
- package/android/src/main/java/net/siteed/audiostream/PermissionUtils.kt +0 -59
- package/android/src/main/java/net/siteed/audiostream/RecordingActionReceiver.kt +0 -59
- package/android/src/main/java/net/siteed/audiostream/RecordingConfig.kt +0 -205
- package/android/src/main/java/net/siteed/audiostream/WaveformConfig.kt +0 -19
- package/android/src/main/java/net/siteed/audiostream/WaveformRenderer.kt +0 -159
- package/android/src/main/res/drawable/ic_default_action_icon.xml +0 -16
- package/android/src/main/res/drawable/ic_microphone.xml +0 -13
- package/android/src/main/res/drawable/ic_pause.xml +0 -10
- package/android/src/main/res/drawable/ic_play.xml +0 -10
- package/android/src/main/res/drawable/ic_stop.xml +0 -10
- package/android/src/main/res/layout/notification_recording.xml +0 -37
- package/android/src/main/test/java/net/siteed/audiostream/AudioProcessorTest.kt +0 -56
- package/app.plugin.js +0 -1
- package/build/AudioAnalysis/AudioAnalysis.types.d.ts +0 -144
- package/build/AudioAnalysis/AudioAnalysis.types.d.ts.map +0 -1
- package/build/AudioAnalysis/AudioAnalysis.types.js +0 -3
- package/build/AudioAnalysis/AudioAnalysis.types.js.map +0 -1
- package/build/AudioAnalysis/extractAudioAnalysis.d.ts +0 -78
- package/build/AudioAnalysis/extractAudioAnalysis.d.ts.map +0 -1
- package/build/AudioAnalysis/extractAudioAnalysis.js +0 -229
- package/build/AudioAnalysis/extractAudioAnalysis.js.map +0 -1
- package/build/AudioAnalysis/extractWaveform.d.ts +0 -8
- package/build/AudioAnalysis/extractWaveform.d.ts.map +0 -1
- package/build/AudioAnalysis/extractWaveform.js +0 -11
- package/build/AudioAnalysis/extractWaveform.js.map +0 -1
- package/build/AudioRecorder.provider.d.ts +0 -11
- package/build/AudioRecorder.provider.d.ts.map +0 -1
- package/build/AudioRecorder.provider.js +0 -37
- package/build/AudioRecorder.provider.js.map +0 -1
- package/build/ExpoAudioStream.native.d.ts +0 -3
- package/build/ExpoAudioStream.native.d.ts.map +0 -1
- package/build/ExpoAudioStream.native.js +0 -6
- package/build/ExpoAudioStream.native.js.map +0 -1
- package/build/ExpoAudioStream.types.d.ts +0 -206
- package/build/ExpoAudioStream.types.d.ts.map +0 -1
- package/build/ExpoAudioStream.types.js +0 -2
- package/build/ExpoAudioStream.types.js.map +0 -1
- package/build/ExpoAudioStream.web.d.ts +0 -59
- package/build/ExpoAudioStream.web.d.ts.map +0 -1
- package/build/ExpoAudioStream.web.js +0 -285
- package/build/ExpoAudioStream.web.js.map +0 -1
- package/build/ExpoAudioStreamModule.d.ts +0 -3
- package/build/ExpoAudioStreamModule.d.ts.map +0 -1
- package/build/ExpoAudioStreamModule.js +0 -239
- package/build/ExpoAudioStreamModule.js.map +0 -1
- package/build/WebRecorder.web.d.ts +0 -119
- package/build/WebRecorder.web.d.ts.map +0 -1
- package/build/WebRecorder.web.js +0 -436
- package/build/WebRecorder.web.js.map +0 -1
- package/build/constants.d.ts +0 -11
- package/build/constants.d.ts.map +0 -1
- package/build/constants.js +0 -14
- package/build/constants.js.map +0 -1
- package/build/events.d.ts +0 -26
- package/build/events.d.ts.map +0 -1
- package/build/events.js +0 -21
- package/build/events.js.map +0 -1
- package/build/index.d.ts.map +0 -1
- package/build/index.js.map +0 -1
- package/build/useAudioRecorder.d.ts +0 -21
- package/build/useAudioRecorder.d.ts.map +0 -1
- package/build/useAudioRecorder.js +0 -427
- package/build/useAudioRecorder.js.map +0 -1
- package/build/utils/BlobFix.d.ts +0 -9
- package/build/utils/BlobFix.d.ts.map +0 -1
- package/build/utils/BlobFix.js +0 -498
- package/build/utils/BlobFix.js.map +0 -1
- package/build/utils/audioProcessing.d.ts +0 -24
- package/build/utils/audioProcessing.d.ts.map +0 -1
- package/build/utils/audioProcessing.js +0 -133
- package/build/utils/audioProcessing.js.map +0 -1
- package/build/utils/concatenateBuffers.d.ts +0 -8
- package/build/utils/concatenateBuffers.d.ts.map +0 -1
- package/build/utils/concatenateBuffers.js +0 -21
- package/build/utils/concatenateBuffers.js.map +0 -1
- package/build/utils/convertPCMToFloat32.d.ts +0 -13
- package/build/utils/convertPCMToFloat32.d.ts.map +0 -1
- package/build/utils/convertPCMToFloat32.js +0 -120
- package/build/utils/convertPCMToFloat32.js.map +0 -1
- package/build/utils/encodingToBitDepth.d.ts +0 -5
- package/build/utils/encodingToBitDepth.d.ts.map +0 -1
- package/build/utils/encodingToBitDepth.js +0 -13
- package/build/utils/encodingToBitDepth.js.map +0 -1
- package/build/utils/getWavFileInfo.d.ts +0 -26
- package/build/utils/getWavFileInfo.d.ts.map +0 -1
- package/build/utils/getWavFileInfo.js +0 -92
- package/build/utils/getWavFileInfo.js.map +0 -1
- package/build/utils/writeWavHeader.d.ts +0 -49
- package/build/utils/writeWavHeader.d.ts.map +0 -1
- package/build/utils/writeWavHeader.js +0 -91
- package/build/utils/writeWavHeader.js.map +0 -1
- package/build/workers/InlineFeaturesExtractor.web.d.ts +0 -2
- package/build/workers/InlineFeaturesExtractor.web.d.ts.map +0 -1
- package/build/workers/InlineFeaturesExtractor.web.js +0 -828
- package/build/workers/InlineFeaturesExtractor.web.js.map +0 -1
- package/build/workers/inlineAudioWebWorker.web.d.ts +0 -2
- package/build/workers/inlineAudioWebWorker.web.d.ts.map +0 -1
- package/build/workers/inlineAudioWebWorker.web.js +0 -157
- package/build/workers/inlineAudioWebWorker.web.js.map +0 -1
- package/expo-module.config.json +0 -9
- package/ios/AudioAnalysisData.swift +0 -74
- package/ios/AudioNotificationManager.swift +0 -135
- package/ios/AudioProcessingHelpers.swift +0 -743
- package/ios/AudioProcessor.swift +0 -858
- package/ios/AudioStreamError.swift +0 -7
- package/ios/AudioStreamManager.swift +0 -1708
- package/ios/AudioStreamManagerDelegate.swift +0 -16
- package/ios/DataPoint.swift +0 -54
- package/ios/DecodingConfig.swift +0 -47
- package/ios/ExpoAudioStream.podspec +0 -27
- package/ios/ExpoAudioStreamModule.swift +0 -698
- package/ios/FFT.swift +0 -62
- package/ios/Features.swift +0 -95
- package/ios/Logger.swift +0 -7
- package/ios/NotificationExtension.swift +0 -15
- package/ios/RecordingResult.swift +0 -22
- package/ios/RecordingSettings.swift +0 -265
- package/ios/WaveformExtractor.swift +0 -105
- package/plugin/build/index.d.ts +0 -21
- package/plugin/build/index.js +0 -191
- package/plugin/src/index.ts +0 -278
- package/plugin/tsconfig.json +0 -10
- package/plugin/tsconfig.tsbuildinfo +0 -1
- package/src/AudioAnalysis/AudioAnalysis.types.ts +0 -165
- package/src/AudioAnalysis/extractAudioAnalysis.ts +0 -370
- package/src/AudioAnalysis/extractWaveform.ts +0 -22
- package/src/AudioRecorder.provider.tsx +0 -54
- package/src/ExpoAudioStream.native.ts +0 -6
- package/src/ExpoAudioStream.types.ts +0 -329
- package/src/ExpoAudioStream.web.ts +0 -359
- package/src/ExpoAudioStreamModule.ts +0 -286
- package/src/WebRecorder.web.ts +0 -580
- package/src/constants.ts +0 -18
- package/src/events.ts +0 -60
- package/src/useAudioRecorder.tsx +0 -620
- package/src/utils/BlobFix.ts +0 -559
- package/src/utils/audioProcessing.ts +0 -205
- package/src/utils/concatenateBuffers.ts +0 -24
- package/src/utils/convertPCMToFloat32.ts +0 -170
- package/src/utils/encodingToBitDepth.ts +0 -18
- package/src/utils/getWavFileInfo.ts +0 -132
- package/src/utils/writeWavHeader.ts +0 -114
- package/src/workers/InlineFeaturesExtractor.web.tsx +0 -827
- package/src/workers/inlineAudioWebWorker.web.tsx +0 -156
package/android/build.gradle
DELETED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
apply plugin: 'com.android.library'
|
|
2
|
-
apply plugin: 'kotlin-android'
|
|
3
|
-
apply plugin: 'maven-publish'
|
|
4
|
-
|
|
5
|
-
group = 'net.siteed.audiostream'
|
|
6
|
-
version = '0.1.0'
|
|
7
|
-
|
|
8
|
-
buildscript {
|
|
9
|
-
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
|
|
10
|
-
if (expoModulesCorePlugin.exists()) {
|
|
11
|
-
apply from: expoModulesCorePlugin
|
|
12
|
-
applyKotlinExpoModulesCorePlugin()
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// Simple helper that allows the root project to override versions declared by this library.
|
|
16
|
-
ext.safeExtGet = { prop, fallback ->
|
|
17
|
-
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// Ensures backward compatibility
|
|
21
|
-
ext.getKotlinVersion = {
|
|
22
|
-
if (ext.has("kotlinVersion")) {
|
|
23
|
-
ext.kotlinVersion()
|
|
24
|
-
} else {
|
|
25
|
-
ext.safeExtGet("kotlinVersion", "1.8.10")
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
repositories {
|
|
30
|
-
mavenCentral()
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
dependencies {
|
|
34
|
-
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${getKotlinVersion()}")
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
afterEvaluate {
|
|
39
|
-
publishing {
|
|
40
|
-
publications {
|
|
41
|
-
release(MavenPublication) {
|
|
42
|
-
from components.release
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
repositories {
|
|
46
|
-
maven {
|
|
47
|
-
url = mavenLocal().url
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
android {
|
|
54
|
-
compileSdkVersion safeExtGet("compileSdkVersion", 34)
|
|
55
|
-
|
|
56
|
-
def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION
|
|
57
|
-
if (agpVersion.tokenize('.')[0].toInteger() < 8) {
|
|
58
|
-
compileOptions {
|
|
59
|
-
sourceCompatibility JavaVersion.VERSION_17
|
|
60
|
-
targetCompatibility JavaVersion.VERSION_17
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
|
|
64
|
-
kotlinOptions {
|
|
65
|
-
jvmTarget = '17'
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
namespace "net.siteed.audiostream"
|
|
71
|
-
defaultConfig {
|
|
72
|
-
minSdkVersion safeExtGet("minSdkVersion", 21)
|
|
73
|
-
targetSdkVersion safeExtGet("targetSdkVersion", 34)
|
|
74
|
-
versionCode 1
|
|
75
|
-
versionName "0.1.0"
|
|
76
|
-
}
|
|
77
|
-
lintOptions {
|
|
78
|
-
abortOnError false
|
|
79
|
-
}
|
|
80
|
-
publishing {
|
|
81
|
-
singleVariant("release") {
|
|
82
|
-
withSourcesJar()
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
repositories {
|
|
88
|
-
mavenCentral()
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
dependencies {
|
|
92
|
-
implementation project(':expo-modules-core')
|
|
93
|
-
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${getKotlinVersion()}"
|
|
94
|
-
|
|
95
|
-
// Add testing dependencies
|
|
96
|
-
testImplementation 'junit:junit:4.13.2'
|
|
97
|
-
testImplementation 'org.jetbrains.kotlin:kotlin-test:1.8.10'
|
|
98
|
-
testImplementation 'org.jetbrains.kotlin:kotlin-test-junit:1.8.10'
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
kotlin {
|
|
102
|
-
jvmToolchain {
|
|
103
|
-
languageVersion.set(JavaLanguageVersion.of(17))
|
|
104
|
-
}
|
|
105
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
2
|
-
<!-- Permissions will be merged into the app's manifest -->
|
|
3
|
-
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
|
4
|
-
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
|
5
|
-
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
|
6
|
-
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE"/>
|
|
7
|
-
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
|
8
|
-
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
|
9
|
-
|
|
10
|
-
<application>
|
|
11
|
-
<receiver
|
|
12
|
-
android:name=".RecordingActionReceiver"
|
|
13
|
-
android:exported="false">
|
|
14
|
-
<intent-filter>
|
|
15
|
-
<action android:name="PAUSE_RECORDING" />
|
|
16
|
-
<action android:name="RESUME_RECORDING" />
|
|
17
|
-
<action android:name="STOP_RECORDING" />
|
|
18
|
-
</intent-filter>
|
|
19
|
-
</receiver>
|
|
20
|
-
|
|
21
|
-
<service
|
|
22
|
-
android:name=".AudioRecordingService"
|
|
23
|
-
android:enabled="true"
|
|
24
|
-
android:exported="false"
|
|
25
|
-
android:foregroundServiceType="microphone" />
|
|
26
|
-
</application>
|
|
27
|
-
</manifest>
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
// net/siteed/audiostream/AudioAnalysisData.kt
|
|
2
|
-
package net.siteed.audiostream
|
|
3
|
-
|
|
4
|
-
import android.os.Bundle
|
|
5
|
-
import androidx.core.os.bundleOf
|
|
6
|
-
|
|
7
|
-
data class SpeechFeatures(
|
|
8
|
-
val isActive: Boolean,
|
|
9
|
-
val speakerId: Int? = null
|
|
10
|
-
) {
|
|
11
|
-
fun toDictionary(): Map<String, Any?> {
|
|
12
|
-
return mapOf(
|
|
13
|
-
"isActive" to isActive,
|
|
14
|
-
"speakerId" to speakerId
|
|
15
|
-
)
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
fun toBundle(): Bundle {
|
|
19
|
-
return bundleOf(
|
|
20
|
-
"isActive" to isActive,
|
|
21
|
-
"speakerId" to speakerId
|
|
22
|
-
)
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
data class DataPoint(
|
|
27
|
-
val id: Long,
|
|
28
|
-
val amplitude: Float,
|
|
29
|
-
val rms: Float,
|
|
30
|
-
val dB: Float,
|
|
31
|
-
val silent: Boolean,
|
|
32
|
-
val features: Features? = null,
|
|
33
|
-
val speech: SpeechFeatures? = null,
|
|
34
|
-
val startTime: Float? = null,
|
|
35
|
-
val endTime: Float? = null,
|
|
36
|
-
val startPosition: Int? = null,
|
|
37
|
-
val endPosition: Int? = null,
|
|
38
|
-
val samples: Int = 0
|
|
39
|
-
) {
|
|
40
|
-
fun toDictionary(): Map<String, Any?> {
|
|
41
|
-
return mapOf(
|
|
42
|
-
"id" to id,
|
|
43
|
-
"amplitude" to amplitude,
|
|
44
|
-
"rms" to rms,
|
|
45
|
-
"dB" to dB,
|
|
46
|
-
"silent" to silent,
|
|
47
|
-
"features" to features?.toDictionary(),
|
|
48
|
-
"speech" to speech?.toDictionary(),
|
|
49
|
-
"startTime" to startTime,
|
|
50
|
-
"endTime" to endTime,
|
|
51
|
-
"startPosition" to startPosition,
|
|
52
|
-
"endPosition" to endPosition,
|
|
53
|
-
"samples" to samples
|
|
54
|
-
)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
fun toBundle(): Bundle {
|
|
58
|
-
return bundleOf(
|
|
59
|
-
"id" to id,
|
|
60
|
-
"amplitude" to amplitude,
|
|
61
|
-
"rms" to rms,
|
|
62
|
-
"dB" to dB,
|
|
63
|
-
"silent" to silent,
|
|
64
|
-
"features" to features?.toBundle(),
|
|
65
|
-
"speech" to speech?.toBundle(),
|
|
66
|
-
"startTime" to startTime,
|
|
67
|
-
"endTime" to endTime,
|
|
68
|
-
"startPosition" to startPosition,
|
|
69
|
-
"endPosition" to endPosition,
|
|
70
|
-
"samples" to samples
|
|
71
|
-
)
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
data class AudioAnalysisData(
|
|
76
|
-
val segmentDurationMs: Int,
|
|
77
|
-
val durationMs: Int,
|
|
78
|
-
val bitDepth: Int,
|
|
79
|
-
val numberOfChannels: Int,
|
|
80
|
-
val sampleRate: Int,
|
|
81
|
-
val samples: Int,
|
|
82
|
-
val dataPoints: List<DataPoint>,
|
|
83
|
-
val amplitudeRange: AmplitudeRange,
|
|
84
|
-
val rmsRange: AmplitudeRange,
|
|
85
|
-
val speechAnalysis: SpeechAnalysis? = null,
|
|
86
|
-
val extractionTimeMs: Float
|
|
87
|
-
) {
|
|
88
|
-
data class AmplitudeRange(val min: Float, val max: Float) {
|
|
89
|
-
fun toDictionary(): Map<String, Float> {
|
|
90
|
-
return mapOf("min" to min, "max" to max)
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
fun toBundle(): Bundle {
|
|
94
|
-
return bundleOf("min" to min, "max" to max)
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
data class SpeechAnalysis(
|
|
99
|
-
val speakerChanges: List<SpeakerChange>
|
|
100
|
-
) {
|
|
101
|
-
fun toDictionary(): Map<String, Any> {
|
|
102
|
-
return mapOf(
|
|
103
|
-
"speakerChanges" to speakerChanges.map { it.toDictionary() }
|
|
104
|
-
)
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
fun toBundle(): Bundle {
|
|
108
|
-
return bundleOf(
|
|
109
|
-
"speakerChanges" to speakerChanges.map { it.toBundle() }.toTypedArray()
|
|
110
|
-
)
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
data class SpeakerChange(
|
|
115
|
-
val timestamp: Long,
|
|
116
|
-
val speakerId: Int
|
|
117
|
-
) {
|
|
118
|
-
fun toDictionary(): Map<String, Any> {
|
|
119
|
-
return mapOf(
|
|
120
|
-
"timestamp" to timestamp,
|
|
121
|
-
"speakerId" to speakerId
|
|
122
|
-
)
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
fun toBundle(): Bundle {
|
|
126
|
-
return bundleOf(
|
|
127
|
-
"timestamp" to timestamp,
|
|
128
|
-
"speakerId" to speakerId
|
|
129
|
-
)
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
fun toDictionary(): Map<String, Any?> {
|
|
134
|
-
return mapOf(
|
|
135
|
-
"segmentDurationMs" to segmentDurationMs,
|
|
136
|
-
"durationMs" to durationMs,
|
|
137
|
-
"bitDepth" to bitDepth,
|
|
138
|
-
"numberOfChannels" to numberOfChannels,
|
|
139
|
-
"sampleRate" to sampleRate,
|
|
140
|
-
"samples" to samples,
|
|
141
|
-
"dataPoints" to dataPoints.map { it.toDictionary() },
|
|
142
|
-
"amplitudeRange" to amplitudeRange.toDictionary(),
|
|
143
|
-
"rmsRange" to rmsRange.toDictionary(),
|
|
144
|
-
"speechAnalysis" to speechAnalysis?.toDictionary(),
|
|
145
|
-
"extractionTimeMs" to extractionTimeMs
|
|
146
|
-
)
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
fun toBundle(): Bundle {
|
|
150
|
-
val dataPointsBundleArray = dataPoints.map { it.toBundle() }.toTypedArray()
|
|
151
|
-
|
|
152
|
-
return bundleOf(
|
|
153
|
-
"segmentDurationMs" to segmentDurationMs,
|
|
154
|
-
"durationMs" to durationMs,
|
|
155
|
-
"bitDepth" to bitDepth,
|
|
156
|
-
"numberOfChannels" to numberOfChannels,
|
|
157
|
-
"sampleRate" to sampleRate,
|
|
158
|
-
"samples" to samples,
|
|
159
|
-
"dataPoints" to dataPointsBundleArray,
|
|
160
|
-
"amplitudeRange" to amplitudeRange.toBundle(),
|
|
161
|
-
"rmsRange" to rmsRange.toBundle(),
|
|
162
|
-
"speechAnalysis" to speechAnalysis?.toBundle(),
|
|
163
|
-
"extractionTimeMs" to extractionTimeMs
|
|
164
|
-
)
|
|
165
|
-
}
|
|
166
|
-
}
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
package net.siteed.audiostream
|
|
2
|
-
|
|
3
|
-
import android.util.Log
|
|
4
|
-
import java.io.File
|
|
5
|
-
import java.io.IOException
|
|
6
|
-
import java.io.OutputStream
|
|
7
|
-
import java.io.RandomAccessFile
|
|
8
|
-
import java.util.UUID
|
|
9
|
-
|
|
10
|
-
class AudioFileHandler(private val filesDir: File) {
|
|
11
|
-
// Method to write WAV file header
|
|
12
|
-
fun writeWavHeader(out: OutputStream, sampleRateInHz: Int, channels: Int, bitDepth: Int) {
|
|
13
|
-
val header = ByteArray(44)
|
|
14
|
-
val byteRate = sampleRateInHz * channels * bitDepth / 8
|
|
15
|
-
val blockAlign = channels * bitDepth / 8
|
|
16
|
-
|
|
17
|
-
// RIFF/WAVE header
|
|
18
|
-
"RIFF".toByteArray().copyInto(header, 0)
|
|
19
|
-
// (file size - 8) to be updated later
|
|
20
|
-
header[4] = 0 // Placeholder
|
|
21
|
-
header[5] = 0 // Placeholder
|
|
22
|
-
header[6] = 0 // Placeholder
|
|
23
|
-
header[7] = 0 // Placeholder
|
|
24
|
-
"WAVE".toByteArray().copyInto(header, 8)
|
|
25
|
-
"fmt ".toByteArray().copyInto(header, 12)
|
|
26
|
-
|
|
27
|
-
// 16 for PCM
|
|
28
|
-
header[16] = 16
|
|
29
|
-
header[17] = 0
|
|
30
|
-
header[18] = 0
|
|
31
|
-
header[19] = 0
|
|
32
|
-
|
|
33
|
-
// PCM format ID
|
|
34
|
-
header[20] = 1 // Audio format 1 for PCM (not compressed)
|
|
35
|
-
header[21] = 0
|
|
36
|
-
|
|
37
|
-
// Number of channels
|
|
38
|
-
header[22] = (channels and 0xff).toByte()
|
|
39
|
-
header[23] = (channels shr 8 and 0xff).toByte()
|
|
40
|
-
|
|
41
|
-
// Sample rate
|
|
42
|
-
header[24] = (sampleRateInHz and 0xff).toByte()
|
|
43
|
-
header[25] = (sampleRateInHz shr 8 and 0xff).toByte()
|
|
44
|
-
header[26] = (sampleRateInHz shr 16 and 0xff).toByte()
|
|
45
|
-
header[27] = (sampleRateInHz shr 24 and 0xff).toByte()
|
|
46
|
-
|
|
47
|
-
// Byte rate
|
|
48
|
-
header[28] = (byteRate and 0xff).toByte()
|
|
49
|
-
header[29] = (byteRate shr 8 and 0xff).toByte()
|
|
50
|
-
header[30] = (byteRate shr 16 and 0xff).toByte()
|
|
51
|
-
header[31] = (byteRate shr 24 and 0xff).toByte()
|
|
52
|
-
|
|
53
|
-
// Block align
|
|
54
|
-
header[32] = (blockAlign and 0xff).toByte()
|
|
55
|
-
header[33] = (blockAlign shr 8 and 0xff).toByte()
|
|
56
|
-
|
|
57
|
-
// Bits per sample
|
|
58
|
-
header[34] = (bitDepth and 0xff).toByte()
|
|
59
|
-
header[35] = (bitDepth shr 8 and 0xff).toByte()
|
|
60
|
-
|
|
61
|
-
// Data chunk
|
|
62
|
-
"data".toByteArray().copyInto(header, 36)
|
|
63
|
-
// Data size to be updated later
|
|
64
|
-
header[40] = 0 // Placeholder
|
|
65
|
-
header[41] = 0 // Placeholder
|
|
66
|
-
header[42] = 0 // Placeholder
|
|
67
|
-
header[43] = 0 // Placeholder
|
|
68
|
-
|
|
69
|
-
out.write(header, 0, 44)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
fun updateWavHeader(file: File) {
|
|
73
|
-
try {
|
|
74
|
-
RandomAccessFile(file, "rw").use { raf ->
|
|
75
|
-
val fileSize = raf.length()
|
|
76
|
-
val dataSize = fileSize - 44 // Subtract the header size
|
|
77
|
-
|
|
78
|
-
raf.seek(4) // Write correct file size, excluding the first 8 bytes of the RIFF header
|
|
79
|
-
raf.writeInt(Integer.reverseBytes((dataSize + 36).toInt()))
|
|
80
|
-
|
|
81
|
-
raf.seek(40) // Go to the data size position
|
|
82
|
-
raf.writeInt(Integer.reverseBytes(dataSize.toInt())) // Write the size of the data segment
|
|
83
|
-
}
|
|
84
|
-
} catch (e: IOException) {
|
|
85
|
-
println("Could not update WAV header: ${e.message}")
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
fun clearAudioStorage() {
|
|
90
|
-
filesDir.listFiles()?.forEach {
|
|
91
|
-
it.delete()
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
fun createAudioFile(extension: String): File {
|
|
96
|
-
val timestamp = System.currentTimeMillis()
|
|
97
|
-
val uuid = UUID.randomUUID().toString()
|
|
98
|
-
val filename = "recording_${timestamp}_${uuid}.${extension}"
|
|
99
|
-
|
|
100
|
-
return try {
|
|
101
|
-
File(filesDir, filename).apply {
|
|
102
|
-
parentFile?.mkdirs() // Create directories if they don't exist
|
|
103
|
-
createNewFile() // Create the file
|
|
104
|
-
}
|
|
105
|
-
} catch (e: Exception) {
|
|
106
|
-
Log.e(Constants.TAG, "Failed to create audio file", e)
|
|
107
|
-
throw e
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
fun deleteFile(file: File?): Boolean {
|
|
112
|
-
return try {
|
|
113
|
-
if (file == null) {
|
|
114
|
-
Log.w(Constants.TAG, "Attempted to delete null file")
|
|
115
|
-
false
|
|
116
|
-
} else if (!file.exists()) {
|
|
117
|
-
Log.w(Constants.TAG, "File does not exist: ${file.absolutePath}")
|
|
118
|
-
false
|
|
119
|
-
} else {
|
|
120
|
-
val wasDeleted = file.delete()
|
|
121
|
-
if (!wasDeleted) {
|
|
122
|
-
Log.w(Constants.TAG, "Failed to delete file: ${file.absolutePath}")
|
|
123
|
-
}
|
|
124
|
-
wasDeleted
|
|
125
|
-
}
|
|
126
|
-
} catch (e: Exception) {
|
|
127
|
-
Log.e(Constants.TAG, "Error deleting file: ${file?.absolutePath}", e)
|
|
128
|
-
false
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
package net.siteed.audiostream
|
|
2
|
-
|
|
3
|
-
import android.media.AudioFormat
|
|
4
|
-
import java.nio.ByteBuffer
|
|
5
|
-
import java.nio.ByteOrder
|
|
6
|
-
|
|
7
|
-
object AudioFormatUtils {
|
|
8
|
-
/**
|
|
9
|
-
* Converts a byte array of audio data to a float array based on the given encoding.
|
|
10
|
-
* @param audioData The raw audio data in bytes.
|
|
11
|
-
* @param encoding The encoding format (e.g., "pcm_8bit", "pcm_16bit", "pcm_32bit").
|
|
12
|
-
* @return A float array with normalized audio samples in the range [-1.0, 1.0].
|
|
13
|
-
*/
|
|
14
|
-
fun convertByteArrayToFloatArray(audioData: ByteArray, encoding: String): FloatArray {
|
|
15
|
-
return when (encoding) {
|
|
16
|
-
"pcm_8bit" -> {
|
|
17
|
-
val floatArray = FloatArray(audioData.size)
|
|
18
|
-
for (i in audioData.indices) {
|
|
19
|
-
// Convert unsigned 8-bit to float in range [-1.0, 1.0]
|
|
20
|
-
floatArray[i] = ((audioData[i].toInt() and 0xFF) - 128) / 128.0f
|
|
21
|
-
}
|
|
22
|
-
floatArray
|
|
23
|
-
}
|
|
24
|
-
"pcm_16bit" -> {
|
|
25
|
-
val floatArray = FloatArray(audioData.size / 2)
|
|
26
|
-
val buffer = ByteBuffer.wrap(audioData).order(ByteOrder.LITTLE_ENDIAN)
|
|
27
|
-
for (i in floatArray.indices) {
|
|
28
|
-
floatArray[i] = buffer.short / 32768.0f // Normalize to [-1.0, 1.0]
|
|
29
|
-
}
|
|
30
|
-
floatArray
|
|
31
|
-
}
|
|
32
|
-
"pcm_32bit" -> {
|
|
33
|
-
val floatArray = FloatArray(audioData.size / 4)
|
|
34
|
-
val buffer = ByteBuffer.wrap(audioData).order(ByteOrder.LITTLE_ENDIAN)
|
|
35
|
-
for (i in floatArray.indices) {
|
|
36
|
-
floatArray[i] = buffer.int / 2_147_483_648.0f // Normalize to [-1.0, 1.0]
|
|
37
|
-
}
|
|
38
|
-
floatArray
|
|
39
|
-
}
|
|
40
|
-
else -> {
|
|
41
|
-
// Default to 16-bit PCM if encoding is not recognized
|
|
42
|
-
val floatArray = FloatArray(audioData.size / 2)
|
|
43
|
-
val buffer = ByteBuffer.wrap(audioData).order(ByteOrder.LITTLE_ENDIAN)
|
|
44
|
-
for (i in floatArray.indices) {
|
|
45
|
-
floatArray[i] = buffer.short / 32768.0f
|
|
46
|
-
}
|
|
47
|
-
floatArray
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Calculates the bit depth (number of bits per sample) based on the encoding string.
|
|
54
|
-
* @param encoding The encoding format (e.g., "pcm_8bit", "pcm_16bit", "pcm_32bit").
|
|
55
|
-
* @return The bit depth as an integer.
|
|
56
|
-
*/
|
|
57
|
-
fun getBitDepth(encoding: String): Int {
|
|
58
|
-
return when (encoding) {
|
|
59
|
-
"pcm_8bit" -> 8
|
|
60
|
-
"pcm_16bit" -> 16
|
|
61
|
-
"pcm_32bit" -> 32
|
|
62
|
-
else -> 16 // Default to 16-bit if not recognized
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Determines the AudioFormat encoding constant based on the encoding string.
|
|
68
|
-
* @param encoding The encoding format (e.g., "pcm_8bit", "pcm_16bit", "pcm_32bit").
|
|
69
|
-
* @return The corresponding AudioFormat constant.
|
|
70
|
-
*/
|
|
71
|
-
fun getAudioFormat(encoding: String): Int {
|
|
72
|
-
return when (encoding) {
|
|
73
|
-
"pcm_8bit" -> AudioFormat.ENCODING_PCM_8BIT
|
|
74
|
-
"pcm_16bit" -> AudioFormat.ENCODING_PCM_16BIT
|
|
75
|
-
"pcm_32bit" -> AudioFormat.ENCODING_PCM_FLOAT
|
|
76
|
-
else -> AudioFormat.ENCODING_PCM_16BIT // Default to 16-bit PCM
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Converts audio data between different bit depths
|
|
82
|
-
* @param audioData The raw audio data
|
|
83
|
-
* @param sourceBitDepth The original bit depth
|
|
84
|
-
* @param targetBitDepth The desired bit depth
|
|
85
|
-
* @return The converted audio data
|
|
86
|
-
*/
|
|
87
|
-
fun convertBitDepth(audioData: ByteArray, sourceBitDepth: Int, targetBitDepth: Int): ByteArray {
|
|
88
|
-
// First convert to float array for normalization
|
|
89
|
-
val floatArray = convertByteArrayToFloatArray(audioData, "pcm_${sourceBitDepth}bit")
|
|
90
|
-
|
|
91
|
-
// Convert back to bytes with new bit depth
|
|
92
|
-
return when (targetBitDepth) {
|
|
93
|
-
8 -> floatArray.map { ((it + 1.0f) * 127.5f).toInt().toByte() }.toByteArray()
|
|
94
|
-
16 -> ByteBuffer.allocate(floatArray.size * 2).order(ByteOrder.LITTLE_ENDIAN).apply {
|
|
95
|
-
floatArray.forEach { asShortBuffer().put((it * 32767f).toInt().toShort()) }
|
|
96
|
-
}.array()
|
|
97
|
-
32 -> ByteBuffer.allocate(floatArray.size * 4).order(ByteOrder.LITTLE_ENDIAN).apply {
|
|
98
|
-
floatArray.forEach { putFloat(it) }
|
|
99
|
-
}.array()
|
|
100
|
-
else -> throw IllegalArgumentException("Unsupported target bit depth: $targetBitDepth")
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|