@siteed/expo-audio-stream 1.0.2 → 1.0.3

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 (113) hide show
  1. package/.size-limit.json +6 -0
  2. package/build/AudioAnalysis/AudioAnalysis.types.d.ts +76 -0
  3. package/build/AudioAnalysis/AudioAnalysis.types.d.ts.map +1 -0
  4. package/build/AudioAnalysis/AudioAnalysis.types.js +3 -0
  5. package/build/AudioAnalysis/AudioAnalysis.types.js.map +1 -0
  6. package/build/AudioAnalysis/extractAudioAnalysis.d.ts +4 -0
  7. package/build/AudioAnalysis/extractAudioAnalysis.d.ts.map +1 -0
  8. package/build/AudioAnalysis/extractAudioAnalysis.js +101 -0
  9. package/build/AudioAnalysis/extractAudioAnalysis.js.map +1 -0
  10. package/build/AudioAnalysis/extractWaveform.d.ts +8 -0
  11. package/build/AudioAnalysis/extractWaveform.d.ts.map +1 -0
  12. package/build/AudioAnalysis/extractWaveform.js +14 -0
  13. package/build/AudioAnalysis/extractWaveform.js.map +1 -0
  14. package/build/AudioRecorder.provider.d.ts +14 -1
  15. package/build/AudioRecorder.provider.d.ts.map +1 -1
  16. package/build/AudioRecorder.provider.js +17 -4
  17. package/build/AudioRecorder.provider.js.map +1 -1
  18. package/build/ExpoAudioStream.types.d.ts +26 -84
  19. package/build/ExpoAudioStream.types.d.ts.map +1 -1
  20. package/build/ExpoAudioStream.types.js.map +1 -1
  21. package/build/ExpoAudioStream.web.d.ts +6 -5
  22. package/build/ExpoAudioStream.web.d.ts.map +1 -1
  23. package/build/ExpoAudioStream.web.js +9 -8
  24. package/build/ExpoAudioStream.web.js.map +1 -1
  25. package/build/ExpoAudioStreamModule.d.ts.map +1 -1
  26. package/build/ExpoAudioStreamModule.js +5 -1
  27. package/build/ExpoAudioStreamModule.js.map +1 -1
  28. package/build/{WebRecorder.d.ts → WebRecorder.web.d.ts} +7 -3
  29. package/build/WebRecorder.web.d.ts.map +1 -0
  30. package/build/{WebRecorder.js → WebRecorder.web.js} +74 -29
  31. package/build/WebRecorder.web.js.map +1 -0
  32. package/build/constants.d.ts +11 -0
  33. package/build/constants.d.ts.map +1 -0
  34. package/build/constants.js +14 -0
  35. package/build/constants.js.map +1 -0
  36. package/build/events.d.ts +6 -0
  37. package/build/events.d.ts.map +1 -0
  38. package/build/events.js +15 -0
  39. package/build/events.js.map +1 -0
  40. package/build/index.d.ts +8 -16
  41. package/build/index.d.ts.map +1 -1
  42. package/build/index.js +6 -112
  43. package/build/index.js.map +1 -1
  44. package/build/logger.d.ts +9 -0
  45. package/build/logger.d.ts.map +1 -0
  46. package/build/logger.js +17 -0
  47. package/build/logger.js.map +1 -0
  48. package/build/{useAudioRecording.d.ts → useAudioRecorder.d.ts} +6 -7
  49. package/build/useAudioRecorder.d.ts.map +1 -0
  50. package/build/{useAudioRecording.js → useAudioRecorder.js} +69 -65
  51. package/build/useAudioRecorder.js.map +1 -0
  52. package/build/utils/convertPCMToFloat32.d.ts +11 -0
  53. package/build/utils/convertPCMToFloat32.d.ts.map +1 -0
  54. package/build/utils/convertPCMToFloat32.js +41 -0
  55. package/build/utils/convertPCMToFloat32.js.map +1 -0
  56. package/build/utils/encodingToBitDepth.d.ts +5 -0
  57. package/build/utils/encodingToBitDepth.d.ts.map +1 -0
  58. package/build/utils/encodingToBitDepth.js +13 -0
  59. package/build/utils/encodingToBitDepth.js.map +1 -0
  60. package/build/utils/getWavFileInfo.d.ts +25 -0
  61. package/build/utils/getWavFileInfo.d.ts.map +1 -0
  62. package/build/utils/getWavFileInfo.js +89 -0
  63. package/build/utils/getWavFileInfo.js.map +1 -0
  64. package/build/utils/writeWavHeader.d.ts +9 -0
  65. package/build/utils/writeWavHeader.d.ts.map +1 -0
  66. package/build/utils/writeWavHeader.js +41 -0
  67. package/build/utils/writeWavHeader.js.map +1 -0
  68. package/build/workers/InlineFeaturesExtractor.web.d.ts +2 -0
  69. package/build/workers/InlineFeaturesExtractor.web.d.ts.map +1 -0
  70. package/build/workers/InlineFeaturesExtractor.web.js +303 -0
  71. package/build/workers/InlineFeaturesExtractor.web.js.map +1 -0
  72. package/build/workers/inlineAudioWebWorker.web.d.ts +2 -0
  73. package/build/workers/inlineAudioWebWorker.web.d.ts.map +1 -0
  74. package/build/workers/inlineAudioWebWorker.web.js +243 -0
  75. package/build/workers/inlineAudioWebWorker.web.js.map +1 -0
  76. package/ios/AudioStreamManager.swift +39 -2
  77. package/ios/ExpoAudioStreamModule.swift +10 -0
  78. package/package.json +7 -6
  79. package/plugin/tsconfig.json +1 -1
  80. package/publish.sh +0 -0
  81. package/src/AudioAnalysis/AudioAnalysis.types.ts +85 -0
  82. package/src/AudioAnalysis/extractAudioAnalysis.ts +136 -0
  83. package/src/AudioAnalysis/extractWaveform.ts +25 -0
  84. package/src/AudioRecorder.provider.tsx +35 -7
  85. package/src/ExpoAudioStream.types.ts +33 -94
  86. package/src/ExpoAudioStream.web.ts +17 -16
  87. package/src/ExpoAudioStreamModule.ts +6 -1
  88. package/src/{WebRecorder.ts → WebRecorder.web.ts} +85 -33
  89. package/src/constants.ts +18 -0
  90. package/src/events.ts +25 -0
  91. package/src/index.ts +8 -169
  92. package/src/logger.ts +26 -0
  93. package/src/{useAudioRecording.tsx → useAudioRecorder.tsx} +141 -136
  94. package/src/utils/convertPCMToFloat32.ts +48 -0
  95. package/src/utils/encodingToBitDepth.ts +18 -0
  96. package/src/utils/getWavFileInfo.ts +125 -0
  97. package/src/utils/writeWavHeader.ts +56 -0
  98. package/src/workers/InlineFeaturesExtractor.web.tsx +302 -0
  99. package/src/workers/inlineAudioWebWorker.web.tsx +242 -0
  100. package/build/WebRecorder.d.ts.map +0 -1
  101. package/build/WebRecorder.js.map +0 -1
  102. package/build/inlineAudioWebWorker.d.ts +0 -3
  103. package/build/inlineAudioWebWorker.d.ts.map +0 -1
  104. package/build/inlineAudioWebWorker.js +0 -340
  105. package/build/inlineAudioWebWorker.js.map +0 -1
  106. package/build/useAudioRecording.d.ts.map +0 -1
  107. package/build/useAudioRecording.js.map +0 -1
  108. package/build/utils.d.ts +0 -31
  109. package/build/utils.d.ts.map +0 -1
  110. package/build/utils.js +0 -143
  111. package/build/utils.js.map +0 -1
  112. package/src/inlineAudioWebWorker.tsx +0 -340
  113. package/src/utils.ts +0 -189
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoAudioStream.web.js","sourceRoot":"","sources":["../src/ExpoAudioStream.web.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAUjD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAc7C,4DAA4D;AAC5D,MAAM,GAAG,GAAG,OAAO,CAAC;AACpB,MAAM,OAAO,kBAAmB,SAAQ,YAAY;IAClD,cAAc,CAAqB;IACnC,WAAW,CAAgB;IAC3B,WAAW,CAAU;IACrB,QAAQ,CAAU;IAClB,kBAAkB,CAAS;IAC3B,UAAU,CAAS;IACnB,iBAAiB,CAAS;IAC1B,WAAW,CAAS;IACpB,eAAe,CAAS;IACxB,eAAe,CAAS;IACxB,eAAe,CAAS;IACxB,UAAU,CAAgB;IAC1B,SAAS,GAAmB,KAAK,CAAC,CAAC,8BAA8B;IACjE,eAAe,CAAmB;IAClC,QAAQ,CAAS,CAAC,yBAAyB;IAC3C,eAAe,CAAS;IACxB,mBAAmB,CAAS;IAE5B,YAAY,EACV,eAAe,EACf,mBAAmB,GACK;QACxB,MAAM,gBAAgB,GAAG;YACvB,WAAW,EAAE,CAAC,SAAiB,EAAE,EAAE;gBACjC,kBAAkB;YACpB,CAAC;YACD,eAAe,EAAE,CAAC,KAAa,EAAE,EAAE;gBACjC,kBAAkB;YACpB,CAAC;SACF,CAAC;QACF,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,kDAAkD;QAE3E,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;QAC3B,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC;QACtB,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtB,IAAI,CAAC,kBAAkB,GAAG,CAAC,CAAC;QAC5B,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;QACpB,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAC;QAC3B,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC,CAAC,UAAU;QAC9B,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC,yBAAyB;QACtD,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,2CAA2C;QACnE,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;QACvC,IAAI,CAAC,mBAAmB,GAAG,mBAAmB,CAAC;IACjD,CAAC;IAED,sCAAsC;IACtC,KAAK,CAAC,cAAc;QAClB,IAAI,CAAC;YACH,OAAO,MAAM,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACpE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,KAAK,CAAC,CAAC;YACpD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,+BAA+B;IAC/B,KAAK,CAAC,cAAc,CAAC,kBAAmC,EAAE;QACxD,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;QACtD,CAAC;QAED,IAAI,CAAC,QAAQ,GAAG,kBAAkB,CAAC;YACjC,QAAQ,EAAE,eAAe,CAAC,QAAQ,IAAI,WAAW;SAClD,CAAC,CAAC;QAEH,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY;YAC3C,mDAAmD;YACnD,MAAM,CAAC,kBAAkB,CAAC,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;QAE3C,MAAM,MAAM,GAAG,YAAY,CAAC,uBAAuB,CAAC,MAAM,CAAC,CAAC;QAE5D,IAAI,CAAC,cAAc,GAAG,IAAI,WAAW,CAAC;YACpC,YAAY;YACZ,MAAM;YACN,eAAe;YACf,eAAe,EAAE,IAAI,CAAC,eAAe;YACrC,mBAAmB,EAAE,IAAI,CAAC,mBAAmB;YAC7C,sBAAsB,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAuB,EAAE,EAAE;gBAClE,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC5B,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,UAAU,CAAC;gBACpC,IAAI,CAAC,cAAc,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;gBACxC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBAClC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,WAAW,CAAC;YAC1C,CAAC;YACD,yBAAyB,EAAE,CAAC,iBAAoC,EAAE,EAAE;gBAClE,OAAO,CAAC,GAAG,CAAC,wBAAwB,EAAE,iBAAiB,CAAC,CAAC;gBACzD,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,iBAAiB,CAAC,CAAC;YAChD,CAAC;SACF,CAAC,CAAC;QACH,MAAM,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;QACjC,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC;QAE5B,mDAAmD;QACnD,qBAAqB;QACrB,4CAA4C;QAC5C,wCAAwC;QACxC,8BAA8B;QAC9B,YAAY;QAEZ,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;QACvC,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACrC,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;QACpB,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;QACxC,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACvD,MAAM,YAAY,GAA2B;YAC3C,OAAO;YACP,QAAQ,EAAE,SAAS,IAAI,CAAC,SAAS,EAAE;YACnC,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,QAAQ,EAAE,eAAe,CAAC,QAAQ,IAAI,CAAC;YACvC,UAAU,EAAE,eAAe,CAAC,UAAU,IAAI,KAAK;SAChD,CAAC;QACF,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,cAAc,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAuB;QACpD,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACvD,MAAM,iBAAiB,GAAsB;YAC3C,OAAO;YACP,QAAQ,EAAE,SAAS,IAAI,CAAC,SAAS,EAAE;YACnC,eAAe,EAAE,IAAI,CAAC,eAAe,EAAE,iEAAiE;YACxG,SAAS,EAAE,IAAI,CAAC,UAAU;YAC1B,QAAQ;YACR,SAAS,EAAE,IAAI,CAAC,WAAW;YAC3B,MAAM,EAAE,IAAI;YACZ,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,EAAE,EAAE,oDAAoD;SACxF,CAAC;QAEF,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC;IAC5C,CAAC;IAED,iBAAiB;IACjB,KAAK,CAAC,aAAa;QACjB,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;YACvD,GAAG,CAAC,KAAK,CAAC,mBAAmB,EAAE,aAAa,CAAC,CAAC;QAChD,CAAC;QACD,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,kBAAkB,CAAC;QAC9D,MAAM,MAAM,GAAsB;YAChC,OAAO,EAAE,GAAG,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,SAAS,EAAE;YAC/C,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,QAAQ,EAAE,IAAI,CAAC,eAAe,EAAE,QAAQ,IAAI,CAAC;YAC7C,UAAU,EAAE,IAAI,CAAC,eAAe,EAAE,UAAU,IAAI,KAAK;YACrD,UAAU,EAAE,IAAI,CAAC,iBAAiB;YAClC,IAAI,EAAE,IAAI,CAAC,WAAW;YACtB,QAAQ,EAAE,SAAS,IAAI,CAAC,SAAS,EAAE;SACpC,CAAC;QAEF,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,kBAAkB;IAClB,KAAK,CAAC,cAAc;QAClB,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACvC,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAC/D,CAAC;QAED,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;QAC7B,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC/B,CAAC;IAED,mBAAmB;IACnB,KAAK,CAAC,eAAe;QACnB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;QAC7C,CAAC;QAED,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC;QAC/B,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtB,IAAI,CAAC,kBAAkB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC;IAC1D,CAAC;IAED,qBAAqB;IACrB,MAAM;QACJ,MAAM,MAAM,GAAsB;YAChC,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,kBAAkB;YAChD,IAAI,EAAE,IAAI,CAAC,WAAW;YACtB,QAAQ,EAAE,IAAI,CAAC,eAAe;YAC9B,QAAQ,EAAE,SAAS,IAAI,CAAC,SAAS,EAAE;SACpC,CAAC;QACF,OAAO,MAAM,CAAC;IAChB,CAAC;CACF","sourcesContent":["// src/ExpoAudioStreamModule.web.ts\nimport debug from \"debug\";\nimport { EventEmitter } from \"expo-modules-core\";\n\nimport {\n AudioAnalysisData,\n AudioEventPayload,\n AudioStreamResult,\n AudioStreamStatus,\n RecordingConfig,\n StartAudioStreamResult,\n} from \"./ExpoAudioStream.types\";\nimport { WebRecorder } from \"./WebRecorder\";\nimport { encodingToBitDepth } from \"./utils\";\n\nexport interface EmitAudioEventProps {\n data: ArrayBuffer;\n position: number;\n}\nexport type EmitAudioEventFunction = (_: EmitAudioEventProps) => void;\nexport type EmitAudioAnalysisFunction = (_: AudioAnalysisData) => void;\n\nexport interface ExpoAudioStreamWebProps {\n audioWorkletUrl: string;\n featuresExtratorUrl: string;\n}\n\n// const log = debug(\"expo-audio-stream:useAudioRecording\");\nconst log = console;\nexport class ExpoAudioStreamWeb extends EventEmitter {\n customRecorder: WebRecorder | null;\n audioChunks: ArrayBuffer[];\n isRecording: boolean;\n isPaused: boolean;\n recordingStartTime: number;\n pausedTime: number;\n currentDurationMs: number;\n currentSize: number;\n currentInterval: number;\n lastEmittedSize: number;\n lastEmittedTime: number;\n streamUuid: string | null;\n extension: \"webm\" | \"wav\" = \"wav\"; // Default extension is 'webm'\n recordingConfig?: RecordingConfig;\n bitDepth: number; // Bit depth of the audio\n audioWorkletUrl: string;\n featuresExtratorUrl: string;\n\n constructor({\n audioWorkletUrl,\n featuresExtratorUrl,\n }: ExpoAudioStreamWebProps) {\n const mockNativeModule = {\n addListener: (eventName: string) => {\n // Not used on web\n },\n removeListeners: (count: number) => {\n // Not used on web\n },\n };\n super(mockNativeModule); // Pass the mock native module to the parent class\n\n this.customRecorder = null;\n this.audioChunks = [];\n this.isRecording = false;\n this.isPaused = false;\n this.recordingStartTime = 0;\n this.pausedTime = 0;\n this.currentDurationMs = 0;\n this.currentSize = 0;\n this.bitDepth = 32; // Default\n this.currentInterval = 1000; // Default interval in ms\n this.lastEmittedSize = 0;\n this.lastEmittedTime = 0;\n this.streamUuid = null; // Initialize UUID on first recording start\n this.audioWorkletUrl = audioWorkletUrl;\n this.featuresExtratorUrl = featuresExtratorUrl;\n }\n\n // Utility to handle user media stream\n async getMediaStream() {\n try {\n return await navigator.mediaDevices.getUserMedia({ audio: true });\n } catch (error) {\n console.error(\"Failed to get media stream:\", error);\n throw error;\n }\n }\n\n // Start recording with options\n async startRecording(recordingConfig: RecordingConfig = {}) {\n if (this.isRecording) {\n throw new Error(\"Recording is already in progress\");\n }\n\n this.bitDepth = encodingToBitDepth({\n encoding: recordingConfig.encoding ?? \"pcm_32bit\",\n });\n\n const audioContext = new (window.AudioContext ||\n // @ts-ignore - Allow webkitAudioContext for Safari\n window.webkitAudioContext)();\n const stream = await this.getMediaStream();\n\n const source = audioContext.createMediaStreamSource(stream);\n\n this.customRecorder = new WebRecorder({\n audioContext,\n source,\n recordingConfig,\n audioWorkletUrl: this.audioWorkletUrl,\n featuresExtratorUrl: this.featuresExtratorUrl,\n emitAudioEventCallback: ({ data, position }: EmitAudioEventProps) => {\n this.audioChunks.push(data);\n this.currentSize += data.byteLength;\n this.emitAudioEvent({ data, position });\n this.lastEmittedTime = Date.now();\n this.lastEmittedSize = this.currentSize;\n },\n emitAudioAnalysisCallback: (audioAnalysisData: AudioAnalysisData) => {\n console.log(`Emitted AudioAnalysis:`, audioAnalysisData);\n this.emit(\"AudioAnalysis\", audioAnalysisData);\n },\n });\n await this.customRecorder.init();\n this.customRecorder.start();\n\n // // Set a timer to stop recording after 5 seconds\n // setTimeout(() => {\n // console.log(\"AUTO Stopping recording\");\n // this.customRecorder?.stopAndPlay();\n // this.isRecording = false;\n // }, 3000);\n\n this.isRecording = true;\n this.recordingConfig = recordingConfig;\n this.recordingStartTime = Date.now();\n this.pausedTime = 0;\n this.lastEmittedSize = 0;\n this.lastEmittedTime = 0;\n this.streamUuid = Date.now().toString();\n const fileUri = `${this.streamUuid}.${this.extension}`;\n const streamConfig: StartAudioStreamResult = {\n fileUri,\n mimeType: `audio/${this.extension}`,\n bitDepth: this.bitDepth,\n channels: recordingConfig.channels ?? 1,\n sampleRate: recordingConfig.sampleRate ?? 44100,\n };\n return streamConfig;\n }\n\n emitAudioEvent({ data, position }: EmitAudioEventProps) {\n const fileUri = `${this.streamUuid}.${this.extension}`;\n const audioEventPayload: AudioEventPayload = {\n fileUri,\n mimeType: `audio/${this.extension}`,\n lastEmittedSize: this.lastEmittedSize, // Since this might be continuously streaming, adjust accordingly\n deltaSize: data.byteLength,\n position,\n totalSize: this.currentSize,\n buffer: data,\n streamUuid: this.streamUuid ?? \"\", // Generate or manage UUID for stream identification\n };\n\n this.emit(\"AudioData\", audioEventPayload);\n }\n\n // Stop recording\n async stopRecording(): Promise<AudioStreamResult | null> {\n if (this.customRecorder) {\n const fullPcmBuffer = await this.customRecorder.stop();\n log.debug(`Stopped recording`, fullPcmBuffer);\n }\n this.isRecording = false;\n this.currentDurationMs = Date.now() - this.recordingStartTime;\n const result: AudioStreamResult = {\n fileUri: `${this.streamUuid}.${this.extension}`,\n bitDepth: this.bitDepth,\n channels: this.recordingConfig?.channels ?? 1,\n sampleRate: this.recordingConfig?.sampleRate ?? 44100,\n durationMs: this.currentDurationMs,\n size: this.currentSize,\n mimeType: `audio/${this.extension}`,\n };\n\n return result;\n }\n\n // Pause recording\n async pauseRecording() {\n if (!this.isRecording || this.isPaused) {\n throw new Error(\"Recording is not active or already paused\");\n }\n\n if (this.customRecorder) {\n this.customRecorder.stop();\n }\n this.isPaused = true;\n this.pausedTime = Date.now();\n }\n\n // Resume recording\n async resumeRecording() {\n if (!this.isPaused) {\n throw new Error(\"Recording is not paused\");\n }\n\n if (this.customRecorder) {\n this.customRecorder.resume();\n }\n this.isPaused = false;\n this.recordingStartTime += Date.now() - this.pausedTime;\n }\n\n // Get current status\n status() {\n const status: AudioStreamStatus = {\n isRecording: this.isRecording,\n isPaused: this.isPaused,\n durationMs: Date.now() - this.recordingStartTime,\n size: this.currentSize,\n interval: this.currentInterval,\n mimeType: `audio/${this.extension}`,\n };\n return status;\n }\n}\n"]}
1
+ {"version":3,"file":"ExpoAudioStream.web.js","sourceRoot":"","sources":["../src/ExpoAudioStream.web.ts"],"names":[],"mappings":"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","sourcesContent":["// src/ExpoAudioStreamModule.web.ts\nimport { EventEmitter } from \"expo-modules-core\";\n\nimport { AudioAnalysisData } from \"./AudioAnalysis/AudioAnalysis.types\";\nimport {\n AudioEventPayload,\n AudioRecordingResult,\n AudioStreamStatus,\n BitDepth,\n RecordingConfig,\n StartRecordingResult,\n} from \"./ExpoAudioStream.types\";\nimport { WebRecorder } from \"./WebRecorder.web\";\nimport { getLogger } from \"./logger\";\nimport { encodingToBitDepth } from \"./utils/encodingToBitDepth\";\n\nexport interface EmitAudioEventProps {\n data: ArrayBuffer;\n position: number;\n}\nexport type EmitAudioEventFunction = (_: EmitAudioEventProps) => void;\nexport type EmitAudioAnalysisFunction = (_: AudioAnalysisData) => void;\n\nexport interface ExpoAudioStreamWebProps {\n audioWorkletUrl: string;\n featuresExtratorUrl: string;\n}\n\nconst logger = getLogger(\"ExpoAudioStreamWeb\");\n\nexport class ExpoAudioStreamWeb extends EventEmitter {\n customRecorder: WebRecorder | null;\n audioChunks: ArrayBuffer[];\n isRecording: boolean;\n isPaused: boolean;\n recordingStartTime: number;\n pausedTime: number;\n currentDurationMs: number;\n currentSize: number;\n currentInterval: number;\n lastEmittedSize: number;\n lastEmittedTime: number;\n streamUuid: string | null;\n extension: \"webm\" | \"wav\" = \"wav\"; // Default extension is 'webm'\n recordingConfig?: RecordingConfig;\n bitDepth: BitDepth; // Bit depth of the audio\n audioWorkletUrl: string;\n featuresExtratorUrl: string;\n\n constructor({\n audioWorkletUrl,\n featuresExtratorUrl,\n }: ExpoAudioStreamWebProps) {\n const mockNativeModule = {\n addListener: (eventName: string) => {\n // Not used on web\n },\n removeListeners: (count: number) => {\n // Not used on web\n },\n };\n super(mockNativeModule); // Pass the mock native module to the parent class\n\n this.customRecorder = null;\n this.audioChunks = [];\n this.isRecording = false;\n this.isPaused = false;\n this.recordingStartTime = 0;\n this.pausedTime = 0;\n this.currentDurationMs = 0;\n this.currentSize = 0;\n this.bitDepth = 32; // Default\n this.currentInterval = 1000; // Default interval in ms\n this.lastEmittedSize = 0;\n this.lastEmittedTime = 0;\n this.streamUuid = null; // Initialize UUID on first recording start\n this.audioWorkletUrl = audioWorkletUrl;\n this.featuresExtratorUrl = featuresExtratorUrl;\n }\n\n // Utility to handle user media stream\n async getMediaStream() {\n try {\n return await navigator.mediaDevices.getUserMedia({ audio: true });\n } catch (error) {\n console.error(\"Failed to get media stream:\", error);\n throw error;\n }\n }\n\n // Start recording with options\n async startRecording(recordingConfig: RecordingConfig = {}) {\n if (this.isRecording) {\n throw new Error(\"Recording is already in progress\");\n }\n\n this.bitDepth = encodingToBitDepth({\n encoding: recordingConfig.encoding ?? \"pcm_32bit\",\n });\n\n const audioContext = new (window.AudioContext ||\n // @ts-ignore - Allow webkitAudioContext for Safari\n window.webkitAudioContext)();\n const stream = await this.getMediaStream();\n\n const source = audioContext.createMediaStreamSource(stream);\n\n this.customRecorder = new WebRecorder({\n audioContext,\n source,\n recordingConfig,\n audioWorkletUrl: this.audioWorkletUrl,\n featuresExtratorUrl: this.featuresExtratorUrl,\n emitAudioEventCallback: ({ data, position }: EmitAudioEventProps) => {\n this.audioChunks.push(data);\n this.currentSize += data.byteLength;\n this.emitAudioEvent({ data, position });\n this.lastEmittedTime = Date.now();\n this.lastEmittedSize = this.currentSize;\n },\n emitAudioAnalysisCallback: (audioAnalysisData: AudioAnalysisData) => {\n logger.log(`Emitted AudioAnalysis:`, audioAnalysisData);\n this.emit(\"AudioAnalysis\", audioAnalysisData);\n },\n });\n await this.customRecorder.init();\n this.customRecorder.start();\n\n // // Set a timer to stop recording after 5 seconds\n // setTimeout(() => {\n // logger.log(\"AUTO Stopping recording\");\n // this.customRecorder?.stopAndPlay();\n // this.isRecording = false;\n // }, 3000);\n\n this.isRecording = true;\n this.recordingConfig = recordingConfig;\n this.recordingStartTime = Date.now();\n this.pausedTime = 0;\n this.lastEmittedSize = 0;\n this.lastEmittedTime = 0;\n this.streamUuid = Date.now().toString();\n const fileUri = `${this.streamUuid}.${this.extension}`;\n const streamConfig: StartRecordingResult = {\n fileUri,\n mimeType: `audio/${this.extension}`,\n bitDepth: this.bitDepth,\n channels: recordingConfig.channels ?? 1,\n sampleRate: recordingConfig.sampleRate ?? 44100,\n };\n return streamConfig;\n }\n\n emitAudioEvent({ data, position }: EmitAudioEventProps) {\n const fileUri = `${this.streamUuid}.${this.extension}`;\n const audioEventPayload: AudioEventPayload = {\n fileUri,\n mimeType: `audio/${this.extension}`,\n lastEmittedSize: this.lastEmittedSize, // Since this might be continuously streaming, adjust accordingly\n deltaSize: data.byteLength,\n position,\n totalSize: this.currentSize,\n buffer: data,\n streamUuid: this.streamUuid ?? \"\", // Generate or manage UUID for stream identification\n };\n\n this.emit(\"AudioData\", audioEventPayload);\n }\n\n // Stop recording\n async stopRecording(): Promise<AudioRecordingResult | null> {\n if (this.customRecorder) {\n const fullPcmBuffer = await this.customRecorder.stop();\n logger.debug(`Stopped recording`, fullPcmBuffer);\n }\n this.isRecording = false;\n this.currentDurationMs = Date.now() - this.recordingStartTime;\n const result: AudioRecordingResult = {\n fileUri: `${this.streamUuid}.${this.extension}`,\n bitDepth: this.bitDepth,\n channels: this.recordingConfig?.channels ?? 1,\n sampleRate: this.recordingConfig?.sampleRate ?? 44100,\n durationMs: this.currentDurationMs,\n size: this.currentSize,\n mimeType: `audio/${this.extension}`,\n };\n\n return result;\n }\n\n // Pause recording\n async pauseRecording() {\n if (!this.isRecording || this.isPaused) {\n throw new Error(\"Recording is not active or already paused\");\n }\n\n if (this.customRecorder) {\n this.customRecorder.pause();\n }\n this.isPaused = true;\n this.pausedTime = Date.now();\n }\n\n // Resume recording\n async resumeRecording() {\n if (!this.isPaused) {\n throw new Error(\"Recording is not paused\");\n }\n\n if (this.customRecorder) {\n this.customRecorder.resume();\n }\n this.isPaused = false;\n this.recordingStartTime += Date.now() - this.pausedTime;\n }\n\n // Get current status\n status() {\n const status: AudioStreamStatus = {\n isRecording: this.isRecording,\n isPaused: this.isPaused,\n durationMs: Date.now() - this.recordingStartTime,\n size: this.currentSize,\n interval: this.currentInterval,\n mimeType: `audio/${this.extension}`,\n };\n return status;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoAudioStreamModule.d.ts","sourceRoot":"","sources":["../src/ExpoAudioStreamModule.ts"],"names":[],"mappings":"AAQA,QAAA,IAAI,qBAAqB,EAAE,GAAG,CAAC;AAU/B,eAAe,qBAAqB,CAAC"}
1
+ {"version":3,"file":"ExpoAudioStreamModule.d.ts","sourceRoot":"","sources":["../src/ExpoAudioStreamModule.ts"],"names":[],"mappings":"AAQA,QAAA,IAAI,qBAAqB,EAAE,GAAG,CAAC;AAe/B,eAAe,qBAAqB,CAAC"}
@@ -3,8 +3,12 @@ import { Platform } from "react-native";
3
3
  import { ExpoAudioStreamWeb, } from "./ExpoAudioStream.web";
4
4
  let ExpoAudioStreamModule;
5
5
  if (Platform.OS === "web") {
6
+ let instance = null;
6
7
  ExpoAudioStreamModule = (webProps) => {
7
- return new ExpoAudioStreamWeb(webProps);
8
+ if (!instance) {
9
+ instance = new ExpoAudioStreamWeb(webProps);
10
+ }
11
+ return instance;
8
12
  };
9
13
  }
10
14
  else {
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoAudioStreamModule.js","sourceRoot":"","sources":["../src/ExpoAudioStreamModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,OAAO,EACL,kBAAkB,GAEnB,MAAM,uBAAuB,CAAC;AAE/B,IAAI,qBAA0B,CAAC;AAE/B,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;IAC1B,qBAAqB,GAAG,CAAC,QAAiC,EAAE,EAAE;QAC5D,OAAO,IAAI,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IAC1C,CAAC,CAAC;AACJ,CAAC;KAAM,CAAC;IACN,qBAAqB,GAAG,mBAAmB,CAAC,iBAAiB,CAAC,CAAC;AACjE,CAAC;AAED,eAAe,qBAAqB,CAAC","sourcesContent":["import { requireNativeModule } from \"expo-modules-core\";\nimport { Platform } from \"react-native\";\n\nimport {\n ExpoAudioStreamWeb,\n ExpoAudioStreamWebProps,\n} from \"./ExpoAudioStream.web\";\n\nlet ExpoAudioStreamModule: any;\n\nif (Platform.OS === \"web\") {\n ExpoAudioStreamModule = (webProps: ExpoAudioStreamWebProps) => {\n return new ExpoAudioStreamWeb(webProps);\n };\n} else {\n ExpoAudioStreamModule = requireNativeModule(\"ExpoAudioStream\");\n}\n\nexport default ExpoAudioStreamModule;\n"]}
1
+ {"version":3,"file":"ExpoAudioStreamModule.js","sourceRoot":"","sources":["../src/ExpoAudioStreamModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,OAAO,EACL,kBAAkB,GAEnB,MAAM,uBAAuB,CAAC;AAE/B,IAAI,qBAA0B,CAAC;AAE/B,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;IAC1B,IAAI,QAAQ,GAA8B,IAAI,CAAC;IAE/C,qBAAqB,GAAG,CAAC,QAAiC,EAAE,EAAE;QAC5D,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,QAAQ,GAAG,IAAI,kBAAkB,CAAC,QAAQ,CAAC,CAAC;QAC9C,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC,CAAC;AACJ,CAAC;KAAM,CAAC;IACN,qBAAqB,GAAG,mBAAmB,CAAC,iBAAiB,CAAC,CAAC;AACjE,CAAC;AAED,eAAe,qBAAqB,CAAC","sourcesContent":["import { requireNativeModule } from \"expo-modules-core\";\nimport { Platform } from \"react-native\";\n\nimport {\n ExpoAudioStreamWeb,\n ExpoAudioStreamWebProps,\n} from \"./ExpoAudioStream.web\";\n\nlet ExpoAudioStreamModule: any;\n\nif (Platform.OS === \"web\") {\n let instance: ExpoAudioStreamWeb | null = null;\n\n ExpoAudioStreamModule = (webProps: ExpoAudioStreamWebProps) => {\n if (!instance) {\n instance = new ExpoAudioStreamWeb(webProps);\n }\n return instance;\n };\n} else {\n ExpoAudioStreamModule = requireNativeModule(\"ExpoAudioStream\");\n}\n\nexport default ExpoAudioStreamModule;\n"]}
@@ -1,4 +1,5 @@
1
- import { AudioAnalysisData, RecordingConfig } from "./ExpoAudioStream.types";
1
+ import { AudioAnalysisData } from "./AudioAnalysis/AudioAnalysis.types";
2
+ import { RecordingConfig } from "./ExpoAudioStream.types";
2
3
  import { EmitAudioAnalysisFunction, EmitAudioEventFunction } from "./ExpoAudioStream.web";
3
4
  interface AudioFeaturesEvent {
4
5
  data: {
@@ -9,7 +10,7 @@ interface AudioFeaturesEvent {
9
10
  export declare class WebRecorder {
10
11
  private audioContext;
11
12
  private audioWorkletNode;
12
- private featureExtractorWorker;
13
+ private featureExtractorWorker?;
13
14
  private source;
14
15
  private audioWorkletUrl;
15
16
  private emitAudioEventCallback;
@@ -31,6 +32,9 @@ export declare class WebRecorder {
31
32
  emitAudioAnalysisCallback: EmitAudioAnalysisFunction;
32
33
  });
33
34
  init(): Promise<void>;
35
+ initFeatureExtractorWorker(featuresExtratorUrl?: string): void;
36
+ initFallbackWorker(): void;
37
+ handleWorkerError(error: ErrorEvent): void;
34
38
  handleFeatureExtractorMessage(event: AudioFeaturesEvent): void;
35
39
  start(): void;
36
40
  stop(): Promise<unknown>;
@@ -44,4 +48,4 @@ export declare class WebRecorder {
44
48
  resume(): void;
45
49
  }
46
50
  export {};
47
- //# sourceMappingURL=WebRecorder.d.ts.map
51
+ //# sourceMappingURL=WebRecorder.web.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebRecorder.web.d.ts","sourceRoot":"","sources":["../src/WebRecorder.web.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AACxE,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EACL,yBAAyB,EACzB,sBAAsB,EACvB,MAAM,uBAAuB,CAAC;AAc/B,UAAU,kBAAkB;IAC1B,IAAI,EAAE;QACJ,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,iBAAiB,CAAC;KAC3B,CAAC;CACH;AAUD,qBAAa,WAAW;IACtB,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,gBAAgB,CAAoB;IAC5C,OAAO,CAAC,sBAAsB,CAAC,CAAS;IACxC,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,sBAAsB,CAAyB;IACvD,OAAO,CAAC,yBAAyB,CAA4B;IAC7D,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,iBAAiB,CAAoB;gBAEjC,EACV,YAAY,EACZ,MAAM,EACN,eAAe,EACf,mBAAmB,EACnB,eAAe,EACf,sBAAsB,EACtB,yBAAyB,GAC1B,EAAE;QACD,YAAY,EAAE,YAAY,CAAC;QAC3B,MAAM,EAAE,0BAA0B,CAAC;QACnC,eAAe,EAAE,eAAe,CAAC;QACjC,mBAAmB,EAAE,MAAM,CAAC;QAC5B,eAAe,EAAE,MAAM,CAAC;QACxB,sBAAsB,EAAE,sBAAsB,CAAC;QAC/C,yBAAyB,EAAE,yBAAyB,CAAC;KACtD;IA+CK,IAAI;IA8FV,0BAA0B,CAAC,mBAAmB,CAAC,EAAE,MAAM;IAyBvD,kBAAkB;IAqBlB,iBAAiB,CAAC,KAAK,EAAE,UAAU;IAInC,6BAA6B,CAAC,KAAK,EAAE,kBAAkB;IA6BvD,KAAK;IAKL,IAAI;IA4DJ,KAAK;IAML,qBAAqB;IAMf,gBAAgB,CAAC,EACrB,YAAY,GACb,EAAE;QACD,YAAY,EAAE,WAAW,CAAC;QAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB;IAqBD,OAAO,CAAC,uBAAuB;IAoB/B,MAAM;CAKP"}
@@ -1,10 +1,13 @@
1
- import { encodingToBitDepth } from "./utils";
1
+ import { getLogger } from "./logger";
2
+ import { encodingToBitDepth } from "./utils/encodingToBitDepth";
3
+ import { InlineFeaturesExtractor } from "./workers/InlineFeaturesExtractor.web";
4
+ import { InlineAudioWebWorker } from "./workers/inlineAudioWebWorker.web";
2
5
  const DEFAULT_WEB_BITDEPTH = 32;
3
6
  const DEFAULT_WEB_POINTS_PER_SECOND = 10;
4
7
  const DEFAULT_WEB_INTERVAL = 500;
5
8
  const DEFAULT_WEB_NUMBER_OF_CHANNELS = 1;
6
- // const log = debug("expo-audio-stream:WebRecorder");
7
- const log = console.log;
9
+ const TAG = "WebRecorder";
10
+ const logger = getLogger(TAG);
8
11
  export class WebRecorder {
9
12
  audioContext;
10
13
  audioWorkletNode;
@@ -32,7 +35,7 @@ export class WebRecorder {
32
35
  const audioContextFormat = this.checkAudioContextFormat({
33
36
  sampleRate: this.audioContext.sampleRate,
34
37
  });
35
- log("Initialized WebRecorder with config:", {
38
+ logger.debug("Initialized WebRecorder with config:", {
36
39
  sampleRate: audioContextFormat.sampleRate,
37
40
  bitDepth: audioContextFormat.bitDepth,
38
41
  numberOfChannels: audioContextFormat.numberOfChannels,
@@ -57,22 +60,22 @@ export class WebRecorder {
57
60
  pointsPerSecond: this.config.pointsPerSecond || DEFAULT_WEB_POINTS_PER_SECOND,
58
61
  speakerChanges: [],
59
62
  };
60
- // Initialize the feature extractor worker
61
- //TODO: create audio feature extractor from a Blob instead of url since we cannot include the url directly in the library
62
- // We keep the url during dev and use the blob in production.
63
- this.featureExtractorWorker = new Worker(new URL(featuresExtratorUrl, window.location.href));
64
- this.featureExtractorWorker.onmessage =
65
- this.handleFeatureExtractorMessage.bind(this);
63
+ if (recordingConfig.enableProcessing) {
64
+ this.initFeatureExtractorWorker();
65
+ }
66
66
  }
67
67
  async init() {
68
68
  try {
69
- // TODO: Use the inline processor script for the audio worklet if the script is not available
70
- // const blob = new Blob([InlineProcessorScrippt], {
71
- // type: "application/javascript",
72
- // });
73
- // const url = URL.createObjectURL(blob);
74
- // await this.audioContext.audioWorklet.addModule(url);
75
- await this.audioContext.audioWorklet.addModule(this.audioWorkletUrl);
69
+ if (!this.audioWorkletUrl) {
70
+ const blob = new Blob([InlineAudioWebWorker], {
71
+ type: "application/javascript",
72
+ });
73
+ const url = URL.createObjectURL(blob);
74
+ await this.audioContext.audioWorklet.addModule(url);
75
+ }
76
+ else {
77
+ await this.audioContext.audioWorklet.addModule(this.audioWorkletUrl);
78
+ }
76
79
  this.audioWorkletNode = new AudioWorkletNode(this.audioContext, "recorder-processor");
77
80
  this.audioWorkletNode.port.onmessage = async (event) => {
78
81
  const command = event.data.command;
@@ -80,7 +83,7 @@ export class WebRecorder {
80
83
  return;
81
84
  }
82
85
  // Handle the audio blob (e.g., send it to the server or process it further)
83
- log("Received audio blob from processor", event);
86
+ logger.debug("Received audio blob from processor", event);
84
87
  const pcmBuffer = event.data.recordedData;
85
88
  if (!pcmBuffer) {
86
89
  return;
@@ -94,13 +97,13 @@ export class WebRecorder {
94
97
  const duration = channelData.length / sampleRate; // Calculate duration of the current buffer
95
98
  const otherDuration = pcmBuffer.byteLength /
96
99
  (otherSampleRate * (this.exportBitDepth / this.numberOfChannels)); // Calculate duration of the current buffer
97
- log(`sampleRate=${sampleRate} Duration: ${duration} -- otherSampleRate=${otherSampleRate} Other duration: ${otherDuration}`);
100
+ logger.debug(`sampleRate=${sampleRate} Duration: ${duration} -- otherSampleRate=${otherSampleRate} Other duration: ${otherDuration}`);
98
101
  this.emitAudioEventCallback({
99
102
  data: pcmBuffer,
100
103
  position: this.position,
101
104
  });
102
105
  this.position += duration; // Update position
103
- this.featureExtractorWorker.postMessage({
106
+ this.featureExtractorWorker?.postMessage({
104
107
  command: "process",
105
108
  channelData,
106
109
  sampleRate: this.audioContext.sampleRate,
@@ -112,7 +115,7 @@ export class WebRecorder {
112
115
  features: this.config.features,
113
116
  }, []);
114
117
  };
115
- log(`WebRecorder initialized -- recordSampleRate=${this.audioContext.sampleRate}`, this.config);
118
+ logger.debug(`WebRecorder initialized -- recordSampleRate=${this.audioContext.sampleRate}`, this.config);
116
119
  this.audioWorkletNode.port.postMessage({
117
120
  command: "init",
118
121
  recordSampleRate: this.audioContext.sampleRate, // Pass the original sample rate
@@ -127,9 +130,51 @@ export class WebRecorder {
127
130
  this.audioWorkletNode.connect(this.audioContext.destination);
128
131
  }
129
132
  catch (error) {
130
- console.error("Failed to initialize WebRecorder", error);
133
+ console.error(`[${TAG}] Failed to initialize WebRecorder`, error);
134
+ }
135
+ }
136
+ initFeatureExtractorWorker(featuresExtratorUrl) {
137
+ try {
138
+ if (featuresExtratorUrl) {
139
+ // Initialize the feature extractor worker
140
+ //TODO: create audio feature extractor from a Blob instead of url since we cannot include the url directly in the library
141
+ // We keep the url during dev and use the blob in production.
142
+ this.featureExtractorWorker = new Worker(new URL(featuresExtratorUrl, window.location.href));
143
+ this.featureExtractorWorker.onmessage =
144
+ this.handleFeatureExtractorMessage.bind(this);
145
+ this.featureExtractorWorker.onerror = this.handleWorkerError.bind(this);
146
+ }
147
+ else {
148
+ // Fallback to the inline worker if the URL is not provided
149
+ this.initFallbackWorker();
150
+ }
151
+ }
152
+ catch (error) {
153
+ console.error(`[${TAG}] Failed to initialize feature extractor worker`, error);
154
+ this.initFallbackWorker();
155
+ }
156
+ }
157
+ initFallbackWorker() {
158
+ try {
159
+ const blob = new Blob([InlineFeaturesExtractor], {
160
+ type: "application/javascript",
161
+ });
162
+ const url = URL.createObjectURL(blob);
163
+ this.featureExtractorWorker = new Worker(url);
164
+ this.featureExtractorWorker.onmessage =
165
+ this.handleFeatureExtractorMessage.bind(this);
166
+ this.featureExtractorWorker.onerror = (error) => {
167
+ console.error(`[${TAG}] Default Inline worker failed`, error);
168
+ };
169
+ logger.log("Inline worker initialized successfully");
170
+ }
171
+ catch (error) {
172
+ console.error(`[${TAG}] Failed to initialize Inline Feature Extractor worker`, error);
131
173
  }
132
174
  }
175
+ handleWorkerError(error) {
176
+ console.error(`[${TAG}] Feature extractor worker error:`, error);
177
+ }
133
178
  handleFeatureExtractorMessage(event) {
134
179
  if (event.data.command === "features") {
135
180
  const segmentResult = event.data.result;
@@ -144,8 +189,8 @@ export class WebRecorder {
144
189
  };
145
190
  }
146
191
  // Handle the extracted features (e.g., emit an event or log them)
147
- log("features event segmentResult", segmentResult);
148
- log("features event audioAnalysisData", this.audioAnalysisData);
192
+ logger.debug("features event segmentResult", segmentResult);
193
+ logger.debug("features event audioAnalysisData", this.audioAnalysisData);
149
194
  this.emitAudioAnalysisCallback(segmentResult);
150
195
  }
151
196
  }
@@ -175,8 +220,8 @@ export class WebRecorder {
175
220
  const duration = rawPCMDataFull.byteLength /
176
221
  (this.audioContext.sampleRate *
177
222
  (this.exportBitDepth / this.numberOfChannels));
178
- log(`Received recorded data -- Duration: ${duration} vs ${rawPCMDataFull.byteLength / this.audioContext.sampleRate} seconds`);
179
- log(`recordedData.length=${rawPCMDataFull.byteLength} vs transmittedData.length=${this.buffers[0].byteLength}`);
223
+ logger.debug(`Received recorded data -- Duration: ${duration} vs ${rawPCMDataFull.byteLength / this.audioContext.sampleRate} seconds`);
224
+ logger.debug(`recordedData.length=${rawPCMDataFull.byteLength} vs transmittedData.length=${this.buffers[0].byteLength}`);
180
225
  // Remove the event listener after receiving the final data
181
226
  this.audioWorkletNode.port.removeEventListener("message", onMessage);
182
227
  resolve(this.buffers); // Resolve the promise with the collected buffers
@@ -215,10 +260,10 @@ export class WebRecorder {
215
260
  bufferSource.buffer = audioBuffer;
216
261
  bufferSource.connect(this.audioContext.destination);
217
262
  bufferSource.start();
218
- log("Playing recorded data", recordedData);
263
+ logger.debug("Playing recorded data", recordedData);
219
264
  }
220
265
  catch (error) {
221
- console.error(`Failed to play recorded data:`, error);
266
+ console.error(`[${TAG}] Failed to play recorded data:`, error);
222
267
  }
223
268
  }
224
269
  checkAudioContextFormat({ sampleRate }) {
@@ -240,4 +285,4 @@ export class WebRecorder {
240
285
  this.audioWorkletNode.port.postMessage({ command: "resume" });
241
286
  }
242
287
  }
243
- //# sourceMappingURL=WebRecorder.js.map
288
+ //# sourceMappingURL=WebRecorder.web.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebRecorder.web.js","sourceRoot":"","sources":["../src/WebRecorder.web.ts"],"names":[],"mappings":"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","sourcesContent":["// src/WebRecorder.ts\nimport { AudioAnalysisData } from \"./AudioAnalysis/AudioAnalysis.types\";\nimport { RecordingConfig } from \"./ExpoAudioStream.types\";\nimport {\n EmitAudioAnalysisFunction,\n EmitAudioEventFunction,\n} from \"./ExpoAudioStream.web\";\nimport { getLogger } from \"./logger\";\nimport { encodingToBitDepth } from \"./utils/encodingToBitDepth\";\nimport { InlineFeaturesExtractor } from \"./workers/InlineFeaturesExtractor.web\";\nimport { InlineAudioWebWorker } from \"./workers/inlineAudioWebWorker.web\";\n\ninterface AudioWorkletEvent {\n data: {\n command: string;\n recordedData?: ArrayBuffer;\n sampleRate?: number;\n };\n}\n\ninterface AudioFeaturesEvent {\n data: {\n command: string;\n result: AudioAnalysisData;\n };\n}\n\nconst DEFAULT_WEB_BITDEPTH = 32;\nconst DEFAULT_WEB_POINTS_PER_SECOND = 10;\nconst DEFAULT_WEB_INTERVAL = 500;\nconst DEFAULT_WEB_NUMBER_OF_CHANNELS = 1;\n\nconst TAG = \"WebRecorder\";\nconst logger = getLogger(TAG);\n\nexport class WebRecorder {\n private audioContext: AudioContext;\n private audioWorkletNode!: AudioWorkletNode;\n private featureExtractorWorker?: Worker;\n private source: MediaStreamAudioSourceNode;\n private audioWorkletUrl: string;\n private emitAudioEventCallback: EmitAudioEventFunction;\n private emitAudioAnalysisCallback: EmitAudioAnalysisFunction;\n private config: RecordingConfig;\n private position: number; // Track the cumulative position\n private numberOfChannels: number; // Number of audio channels\n private bitDepth: number; // Bit depth of the audio\n private exportBitDepth: number; // Bit depth of the audio\n private buffers: ArrayBuffer[]; // Array to store the buffers\n private audioAnalysisData: AudioAnalysisData; // Keep updating the full audio analysis data with latest events\n\n constructor({\n audioContext,\n source,\n recordingConfig,\n featuresExtratorUrl,\n audioWorkletUrl,\n emitAudioEventCallback,\n emitAudioAnalysisCallback,\n }: {\n audioContext: AudioContext;\n source: MediaStreamAudioSourceNode;\n recordingConfig: RecordingConfig;\n featuresExtratorUrl: string;\n audioWorkletUrl: string;\n emitAudioEventCallback: EmitAudioEventFunction;\n emitAudioAnalysisCallback: EmitAudioAnalysisFunction;\n }) {\n this.audioContext = audioContext;\n this.source = source;\n this.audioWorkletUrl = audioWorkletUrl;\n this.emitAudioEventCallback = emitAudioEventCallback;\n this.emitAudioAnalysisCallback = emitAudioAnalysisCallback;\n this.config = recordingConfig;\n this.position = 0;\n this.buffers = []; // Initialize the buffers array\n\n const audioContextFormat = this.checkAudioContextFormat({\n sampleRate: this.audioContext.sampleRate,\n });\n logger.debug(\"Initialized WebRecorder with config:\", {\n sampleRate: audioContextFormat.sampleRate,\n bitDepth: audioContextFormat.bitDepth,\n numberOfChannels: audioContextFormat.numberOfChannels,\n });\n\n this.bitDepth = audioContextFormat.bitDepth;\n this.numberOfChannels =\n audioContextFormat.numberOfChannels || DEFAULT_WEB_NUMBER_OF_CHANNELS; // Default to 1 if not available\n this.exportBitDepth =\n encodingToBitDepth({\n encoding: recordingConfig.encoding ?? \"pcm_32bit\",\n }) ||\n audioContextFormat.bitDepth ||\n DEFAULT_WEB_BITDEPTH;\n\n this.audioAnalysisData = {\n amplitudeRange: { min: 0, max: 0 },\n dataPoints: [],\n durationMs: 0,\n samples: 0,\n bitDepth: this.bitDepth,\n numberOfChannels: this.numberOfChannels,\n sampleRate: this.config.sampleRate || this.audioContext.sampleRate,\n pointsPerSecond:\n this.config.pointsPerSecond || DEFAULT_WEB_POINTS_PER_SECOND,\n speakerChanges: [],\n };\n\n if (recordingConfig.enableProcessing) {\n this.initFeatureExtractorWorker();\n }\n }\n\n async init() {\n try {\n if (!this.audioWorkletUrl) {\n const blob = new Blob([InlineAudioWebWorker], {\n type: \"application/javascript\",\n });\n const url = URL.createObjectURL(blob);\n await this.audioContext.audioWorklet.addModule(url);\n } else {\n await this.audioContext.audioWorklet.addModule(this.audioWorkletUrl);\n }\n this.audioWorkletNode = new AudioWorkletNode(\n this.audioContext,\n \"recorder-processor\",\n );\n\n this.audioWorkletNode.port.onmessage = async (\n event: AudioWorkletEvent,\n ) => {\n const command = event.data.command;\n if (command !== \"newData\") {\n return;\n }\n // Handle the audio blob (e.g., send it to the server or process it further)\n logger.debug(\"Received audio blob from processor\", event);\n const pcmBuffer = event.data.recordedData;\n\n if (!pcmBuffer) {\n return;\n }\n\n this.buffers.push(pcmBuffer); // Store the buffer\n const sampleRate =\n event.data.sampleRate ?? this.audioContext.sampleRate;\n const otherSampleRate = this.audioContext.sampleRate;\n\n // Pass the intermediary buffer to the feature extractor worker\n const pcmBufferCopy = pcmBuffer.slice(0);\n const channelData = new Float32Array(pcmBufferCopy);\n\n const duration = channelData.length / sampleRate; // Calculate duration of the current buffer\n const otherDuration =\n pcmBuffer.byteLength /\n (otherSampleRate * (this.exportBitDepth / this.numberOfChannels)); // Calculate duration of the current buffer\n logger.debug(\n `sampleRate=${sampleRate} Duration: ${duration} -- otherSampleRate=${otherSampleRate} Other duration: ${otherDuration}`,\n );\n\n this.emitAudioEventCallback({\n data: pcmBuffer,\n position: this.position,\n });\n this.position += duration; // Update position\n\n this.featureExtractorWorker?.postMessage(\n {\n command: \"process\",\n channelData,\n sampleRate: this.audioContext.sampleRate,\n pointsPerSecond:\n this.config.pointsPerSecond || DEFAULT_WEB_POINTS_PER_SECOND,\n algorithm: this.config.algorithm || \"rms\",\n bitDepth: this.bitDepth,\n fullAudioDurationMs: this.position * 1000,\n numberOfChannels: this.numberOfChannels,\n features: this.config.features,\n },\n [],\n );\n };\n\n logger.debug(\n `WebRecorder initialized -- recordSampleRate=${this.audioContext.sampleRate}`,\n this.config,\n );\n this.audioWorkletNode.port.postMessage({\n command: \"init\",\n recordSampleRate: this.audioContext.sampleRate, // Pass the original sample rate\n exportSampleRate:\n this.config.sampleRate ?? this.audioContext.sampleRate,\n bitDepth: this.bitDepth,\n exportBitDepth: this.exportBitDepth,\n channels: this.numberOfChannels,\n interval: this.config.interval ?? DEFAULT_WEB_INTERVAL,\n });\n\n // Connect the source to the AudioWorkletNode and start recording\n this.source.connect(this.audioWorkletNode);\n this.audioWorkletNode.connect(this.audioContext.destination);\n } catch (error) {\n console.error(`[${TAG}] Failed to initialize WebRecorder`, error);\n }\n }\n\n initFeatureExtractorWorker(featuresExtratorUrl?: string) {\n try {\n if (featuresExtratorUrl) {\n // Initialize the feature extractor worker\n //TODO: create audio feature extractor from a Blob instead of url since we cannot include the url directly in the library\n // We keep the url during dev and use the blob in production.\n this.featureExtractorWorker = new Worker(\n new URL(featuresExtratorUrl, window.location.href),\n );\n this.featureExtractorWorker.onmessage =\n this.handleFeatureExtractorMessage.bind(this);\n this.featureExtractorWorker.onerror = this.handleWorkerError.bind(this);\n } else {\n // Fallback to the inline worker if the URL is not provided\n this.initFallbackWorker();\n }\n } catch (error) {\n console.error(\n `[${TAG}] Failed to initialize feature extractor worker`,\n error,\n );\n this.initFallbackWorker();\n }\n }\n\n initFallbackWorker() {\n try {\n const blob = new Blob([InlineFeaturesExtractor], {\n type: \"application/javascript\",\n });\n const url = URL.createObjectURL(blob);\n this.featureExtractorWorker = new Worker(url);\n this.featureExtractorWorker.onmessage =\n this.handleFeatureExtractorMessage.bind(this);\n this.featureExtractorWorker.onerror = (error) => {\n console.error(`[${TAG}] Default Inline worker failed`, error);\n };\n logger.log(\"Inline worker initialized successfully\");\n } catch (error) {\n console.error(\n `[${TAG}] Failed to initialize Inline Feature Extractor worker`,\n error,\n );\n }\n }\n\n handleWorkerError(error: ErrorEvent) {\n console.error(`[${TAG}] Feature extractor worker error:`, error);\n }\n\n handleFeatureExtractorMessage(event: AudioFeaturesEvent) {\n if (event.data.command === \"features\") {\n const segmentResult = event.data.result;\n\n // Merge the segment result with the full audio analysis data\n this.audioAnalysisData.dataPoints.push(...segmentResult.dataPoints);\n this.audioAnalysisData.speakerChanges?.push(\n ...(segmentResult.speakerChanges ?? []),\n );\n this.audioAnalysisData.durationMs = segmentResult.durationMs;\n if (segmentResult.amplitudeRange) {\n this.audioAnalysisData.amplitudeRange = {\n min: Math.min(\n this.audioAnalysisData.amplitudeRange.min,\n segmentResult.amplitudeRange.min,\n ),\n max: Math.max(\n this.audioAnalysisData.amplitudeRange.max,\n segmentResult.amplitudeRange.max,\n ),\n };\n }\n // Handle the extracted features (e.g., emit an event or log them)\n logger.debug(\"features event segmentResult\", segmentResult);\n logger.debug(\"features event audioAnalysisData\", this.audioAnalysisData);\n this.emitAudioAnalysisCallback(segmentResult);\n }\n }\n\n start() {\n this.source.connect(this.audioWorkletNode);\n this.audioWorkletNode.connect(this.audioContext.destination);\n }\n\n stop() {\n return new Promise((resolve, reject) => {\n try {\n if (this.audioWorkletNode) {\n // this.source.disconnect(this.audioWorkletNode);\n // this.audioWorkletNode.disconnect(this.audioContext.destination);\n this.audioWorkletNode.port.postMessage({ command: \"stop\" });\n\n // Set a timeout to reject the promise if no message is received within 5 seconds\n const timeout = setTimeout(() => {\n this.audioWorkletNode.port.removeEventListener(\n \"message\",\n onMessage,\n );\n reject(\n new Error(\"Timeout error, audioWorkletNode didn't complete.\"),\n );\n }, 5000);\n\n // Listen for the recordedData message to confirm stopping\n const onMessage = async (event: AudioWorkletEvent) => {\n const command = event.data.command;\n if (command === \"recordedData\") {\n clearTimeout(timeout); // Clear the timeout\n\n const rawPCMDataFull = event.data.recordedData?.slice(\n 0,\n ) as ArrayBuffer;\n\n // Compute duration of the recorded data\n const duration =\n rawPCMDataFull.byteLength /\n (this.audioContext.sampleRate *\n (this.exportBitDepth / this.numberOfChannels));\n logger.debug(\n `Received recorded data -- Duration: ${duration} vs ${rawPCMDataFull.byteLength / this.audioContext.sampleRate} seconds`,\n );\n logger.debug(\n `recordedData.length=${rawPCMDataFull.byteLength} vs transmittedData.length=${this.buffers[0].byteLength}`,\n );\n\n // Remove the event listener after receiving the final data\n this.audioWorkletNode.port.removeEventListener(\n \"message\",\n onMessage,\n );\n resolve(this.buffers); // Resolve the promise with the collected buffers\n }\n };\n this.audioWorkletNode.port.addEventListener(\"message\", onMessage);\n }\n\n // Stop all media stream tracks to stop the browser recording\n this.stopMediaStreamTracks();\n } catch (error) {\n reject(error);\n }\n });\n }\n\n pause() {\n this.source.disconnect(this.audioWorkletNode); // Disconnect the source from the AudioWorkletNode\n this.audioWorkletNode.disconnect(this.audioContext.destination); // Disconnect the AudioWorkletNode from the destination\n this.audioWorkletNode.port.postMessage({ command: \"pause\" });\n }\n\n stopMediaStreamTracks() {\n // Stop all audio tracks to stop the recording icon\n const tracks = this.source.mediaStream.getTracks();\n tracks.forEach((track) => track.stop());\n }\n\n async playRecordedData({\n recordedData,\n }: {\n recordedData: ArrayBuffer;\n mimeType?: string;\n }) {\n try {\n const blob = new Blob([recordedData]);\n const url = URL.createObjectURL(blob);\n const response = await fetch(url);\n const arrayBuffer = await response.arrayBuffer();\n\n // Decode the audio data\n const audioBuffer = await this.audioContext.decodeAudioData(arrayBuffer);\n\n // Create a buffer source node and play the audio\n const bufferSource = this.audioContext.createBufferSource();\n bufferSource.buffer = audioBuffer;\n bufferSource.connect(this.audioContext.destination);\n bufferSource.start();\n logger.debug(\"Playing recorded data\", recordedData);\n } catch (error) {\n console.error(`[${TAG}] Failed to play recorded data:`, error);\n }\n }\n\n private checkAudioContextFormat({ sampleRate }: { sampleRate: number }) {\n // Create a silent AudioBuffer\n const frameCount = sampleRate * 1.0; // 1 second buffer\n const audioBuffer = this.audioContext.createBuffer(\n 1,\n frameCount,\n sampleRate,\n );\n\n // Check the format\n const channelData = audioBuffer.getChannelData(0);\n const bitDepth = channelData.BYTES_PER_ELEMENT * 8; // 4 bytes per element means 32-bit\n\n return {\n sampleRate: audioBuffer.sampleRate,\n bitDepth,\n numberOfChannels: audioBuffer.numberOfChannels,\n };\n }\n\n resume() {\n this.source.connect(this.audioWorkletNode);\n this.audioWorkletNode.connect(this.audioContext.destination);\n this.audioWorkletNode.port.postMessage({ command: \"resume\" });\n }\n}\n"]}
@@ -0,0 +1,11 @@
1
+ import { BitDepth, SampleRate } from "./ExpoAudioStream.types";
2
+ export declare const isWeb: boolean;
3
+ export declare const DEBUG_NAMESPACE = "expo-audio-stream";
4
+ export declare const RIFF_HEADER = 1380533830;
5
+ export declare const WAVE_HEADER = 1463899717;
6
+ export declare const FMT_CHUNK_ID = 1718449184;
7
+ export declare const DATA_CHUNK_ID = 1684108385;
8
+ export declare const INFO_CHUNK_ID = 1229866575;
9
+ export declare const DEFAULT_SAMPLE_RATE: SampleRate;
10
+ export declare const DEFAULT_BIT_DEPTH: BitDepth;
11
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE/D,eAAO,MAAM,KAAK,SAAwB,CAAC;AAC3C,eAAO,MAAM,eAAe,sBAAsB,CAAC;AAGnD,eAAO,MAAM,WAAW,aAAa,CAAC;AACtC,eAAO,MAAM,WAAW,aAAa,CAAC;AACtC,eAAO,MAAM,YAAY,aAAa,CAAC;AACvC,eAAO,MAAM,aAAa,aAAa,CAAC;AACxC,eAAO,MAAM,aAAa,aAAa,CAAC;AAGxC,eAAO,MAAM,mBAAmB,EAAE,UAAkB,CAAC;AACrD,eAAO,MAAM,iBAAiB,EAAE,QAAa,CAAC"}
@@ -0,0 +1,14 @@
1
+ // packages/expo-audio-stream/src/constants.ts
2
+ import { Platform } from "react-native";
3
+ export const isWeb = Platform.OS === "web";
4
+ export const DEBUG_NAMESPACE = "expo-audio-stream";
5
+ // Constants for identifying chunks in a WAV file
6
+ export const RIFF_HEADER = 0x52494646; // "RIFF"
7
+ export const WAVE_HEADER = 0x57415645; // "WAVE"
8
+ export const FMT_CHUNK_ID = 0x666d7420; // "fmt "
9
+ export const DATA_CHUNK_ID = 0x64617461; // "data"
10
+ export const INFO_CHUNK_ID = 0x494e464f; // "INFO"
11
+ // Default values
12
+ export const DEFAULT_SAMPLE_RATE = 16000;
13
+ export const DEFAULT_BIT_DEPTH = 32;
14
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAIxC,MAAM,CAAC,MAAM,KAAK,GAAG,QAAQ,CAAC,EAAE,KAAK,KAAK,CAAC;AAC3C,MAAM,CAAC,MAAM,eAAe,GAAG,mBAAmB,CAAC;AAEnD,iDAAiD;AACjD,MAAM,CAAC,MAAM,WAAW,GAAG,UAAU,CAAC,CAAC,SAAS;AAChD,MAAM,CAAC,MAAM,WAAW,GAAG,UAAU,CAAC,CAAC,SAAS;AAChD,MAAM,CAAC,MAAM,YAAY,GAAG,UAAU,CAAC,CAAC,SAAS;AACjD,MAAM,CAAC,MAAM,aAAa,GAAG,UAAU,CAAC,CAAC,SAAS;AAClD,MAAM,CAAC,MAAM,aAAa,GAAG,UAAU,CAAC,CAAC,SAAS;AAElD,iBAAiB;AACjB,MAAM,CAAC,MAAM,mBAAmB,GAAe,KAAK,CAAC;AACrD,MAAM,CAAC,MAAM,iBAAiB,GAAa,EAAE,CAAC","sourcesContent":["// packages/expo-audio-stream/src/constants.ts\nimport { Platform } from \"react-native\";\n\nimport { BitDepth, SampleRate } from \"./ExpoAudioStream.types\";\n\nexport const isWeb = Platform.OS === \"web\";\nexport const DEBUG_NAMESPACE = \"expo-audio-stream\";\n\n// Constants for identifying chunks in a WAV file\nexport const RIFF_HEADER = 0x52494646; // \"RIFF\"\nexport const WAVE_HEADER = 0x57415645; // \"WAVE\"\nexport const FMT_CHUNK_ID = 0x666d7420; // \"fmt \"\nexport const DATA_CHUNK_ID = 0x64617461; // \"data\"\nexport const INFO_CHUNK_ID = 0x494e464f; // \"INFO\"\n\n// Default values\nexport const DEFAULT_SAMPLE_RATE: SampleRate = 16000;\nexport const DEFAULT_BIT_DEPTH: BitDepth = 32;\n"]}
@@ -0,0 +1,6 @@
1
+ import { type Subscription } from "expo-modules-core";
2
+ import { AudioAnalysisData } from "./AudioAnalysis/AudioAnalysis.types";
3
+ import { AudioEventPayload } from "./ExpoAudioStream.types";
4
+ export declare function addAudioEventListener(listener: (event: AudioEventPayload) => Promise<void>): Subscription;
5
+ export declare function addAudioAnalysisListener(listener: (event: AudioAnalysisData) => Promise<void>): Subscription;
6
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgB,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAO5D,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,GACpD,YAAY,CAGd;AAED,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,GACpD,YAAY,CAGd"}
@@ -0,0 +1,15 @@
1
+ // packages/expo-audio-stream/src/events.ts
2
+ import { EventEmitter } from "expo-modules-core";
3
+ import ExpoAudioStreamModule from "./ExpoAudioStreamModule";
4
+ import { getLogger } from "./logger";
5
+ const emitter = new EventEmitter(ExpoAudioStreamModule);
6
+ const logger = getLogger("events");
7
+ export function addAudioEventListener(listener) {
8
+ logger.log("Adding listener for AudioData event");
9
+ return emitter.addListener("AudioData", listener);
10
+ }
11
+ export function addAudioAnalysisListener(listener) {
12
+ logger.log("Adding listener for AudioAnalysis event");
13
+ return emitter.addListener("AudioAnalysis", listener);
14
+ }
15
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAE3C,OAAO,EAAE,YAAY,EAAqB,MAAM,mBAAmB,CAAC;AAIpE,OAAO,qBAAqB,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAErC,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC,qBAAqB,CAAC,CAAC;AACxD,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAEnC,MAAM,UAAU,qBAAqB,CACnC,QAAqD;IAErD,MAAM,CAAC,GAAG,CAAC,qCAAqC,CAAC,CAAC;IAClD,OAAO,OAAO,CAAC,WAAW,CAAoB,WAAW,EAAE,QAAQ,CAAC,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,wBAAwB,CACtC,QAAqD;IAErD,MAAM,CAAC,GAAG,CAAC,yCAAyC,CAAC,CAAC;IACtD,OAAO,OAAO,CAAC,WAAW,CAAoB,eAAe,EAAE,QAAQ,CAAC,CAAC;AAC3E,CAAC","sourcesContent":["// packages/expo-audio-stream/src/events.ts\n\nimport { EventEmitter, type Subscription } from \"expo-modules-core\";\n\nimport { AudioAnalysisData } from \"./AudioAnalysis/AudioAnalysis.types\";\nimport { AudioEventPayload } from \"./ExpoAudioStream.types\";\nimport ExpoAudioStreamModule from \"./ExpoAudioStreamModule\";\nimport { getLogger } from \"./logger\";\n\nconst emitter = new EventEmitter(ExpoAudioStreamModule);\nconst logger = getLogger(\"events\");\n\nexport function addAudioEventListener(\n listener: (event: AudioEventPayload) => Promise<void>,\n): Subscription {\n logger.log(\"Adding listener for AudioData event\");\n return emitter.addListener<AudioEventPayload>(\"AudioData\", listener);\n}\n\nexport function addAudioAnalysisListener(\n listener: (event: AudioAnalysisData) => Promise<void>,\n): Subscription {\n logger.log(\"Adding listener for AudioAnalysis event\");\n return emitter.addListener<AudioAnalysisData>(\"AudioAnalysis\", listener);\n}\n"]}
package/build/index.d.ts CHANGED
@@ -1,18 +1,10 @@
1
- import { type Subscription } from "expo-modules-core";
1
+ import { extractAudioAnalysis } from "./AudioAnalysis/extractAudioAnalysis";
2
2
  import { AudioRecorderProvider, useSharedAudioRecorder } from "./AudioRecorder.provider";
3
- import { AudioAnalysisData, AudioEventPayload } from "./ExpoAudioStream.types";
4
- import { ExtractMetadataProps, useAudioRecorder } from "./useAudioRecording";
5
- import { convertPCMToFloat32, getWavFileInfo, writeWavHeader } from "./utils";
6
- export declare function addAudioEventListener(listener: (event: AudioEventPayload) => Promise<void>): Subscription;
7
- export declare function addAudioAnalysisListener(listener: (event: AudioAnalysisData) => Promise<void>): Subscription;
8
- export declare const extractAudioAnalysis: ({ fileUri, pointsPerSecond, arrayBuffer, bitDepth, skipWavHeader, durationMs, sampleRate, numberOfChannels, algorithm, features, featuresExtratorUrl, }: ExtractMetadataProps) => Promise<AudioAnalysisData>;
9
- export interface ExtractWaveformProps {
10
- fileUri: string;
11
- numberOfSamples: number;
12
- offset?: number;
13
- length?: number;
14
- }
15
- export declare const extractWaveform: ({ fileUri, numberOfSamples, offset, length, }: ExtractWaveformProps) => Promise<unknown>;
16
- export { AudioRecorderProvider, convertPCMToFloat32, getWavFileInfo, useAudioRecorder, useSharedAudioRecorder, writeWavHeader as writeWaveHeader, };
17
- export * from "./ExpoAudioStream.types";
3
+ import { useAudioRecorder } from "./useAudioRecorder";
4
+ export * from "./utils/getWavFileInfo";
5
+ export * from "./utils/convertPCMToFloat32";
6
+ export * from "./utils/writeWavHeader";
7
+ export { AudioRecorderProvider, extractAudioAnalysis, useAudioRecorder, useSharedAudioRecorder, };
8
+ export type * from "./AudioAnalysis/AudioAnalysis.types";
9
+ export type * from "./ExpoAudioStream.types";
18
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAKpE,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACvB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE/E,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC7E,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAI9E,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,GACpD,YAAY,CAGd;AAED,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,GACpD,YAAY,CAGd;AAID,eAAO,MAAM,oBAAoB,4JAY9B,oBAAoB,KAAG,OAAO,CAAC,iBAAiB,CAwGlD,CAAC;AAEF,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AACD,eAAO,MAAM,eAAe,kDAKzB,oBAAoB,KAAG,OAAO,CAAC,OAAO,CASxC,CAAC;AAEF,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACtB,cAAc,IAAI,eAAe,GAClC,CAAC;AAEF,cAAc,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAC5E,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACvB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AAEvC,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,gBAAgB,EAChB,sBAAsB,GACvB,CAAC;AAEF,mBAAmB,qCAAqC,CAAC;AACzD,mBAAmB,yBAAyB,CAAC"}
package/build/index.js CHANGED
@@ -1,115 +1,9 @@
1
1
  // src/index.ts
2
- import { EventEmitter } from "expo-modules-core";
3
- import { Platform } from "react-native";
4
- // Import the native module. On web, it will be resolved to ExpoAudioStream.web.ts
5
- // and on native platforms to ExpoAudioStream.ts
2
+ import { extractAudioAnalysis } from "./AudioAnalysis/extractAudioAnalysis";
6
3
  import { AudioRecorderProvider, useSharedAudioRecorder, } from "./AudioRecorder.provider";
7
- import ExpoAudioStreamModule from "./ExpoAudioStreamModule";
8
- import { useAudioRecorder } from "./useAudioRecording";
9
- import { convertPCMToFloat32, getWavFileInfo, writeWavHeader } from "./utils";
10
- const emitter = new EventEmitter(ExpoAudioStreamModule);
11
- export function addAudioEventListener(listener) {
12
- console.log(`addAudioEventListener`, listener);
13
- return emitter.addListener("AudioData", listener);
14
- }
15
- export function addAudioAnalysisListener(listener) {
16
- console.log(`addAudioAnalysisListener`, listener);
17
- return emitter.addListener("AudioAnalysis", listener);
18
- }
19
- const isWeb = Platform.OS === "web";
20
- export const extractAudioAnalysis = async ({ fileUri, pointsPerSecond = 20, arrayBuffer, bitDepth, skipWavHeader, durationMs, sampleRate, numberOfChannels, algorithm = "rms", features, featuresExtratorUrl = "/audio-features-extractor.js", }) => {
21
- if (isWeb) {
22
- if (!arrayBuffer && !fileUri) {
23
- throw new Error("Either arrayBuffer or fileUri must be provided");
24
- }
25
- if (!arrayBuffer) {
26
- console.log(`fetching fileUri`, fileUri);
27
- const response = await fetch(fileUri);
28
- if (!response.ok) {
29
- throw new Error(`Failed to fetch fileUri: ${response.statusText}`);
30
- }
31
- arrayBuffer = (await response.arrayBuffer()).slice(0);
32
- console.log(`fetched fileUri`, arrayBuffer.byteLength, arrayBuffer);
33
- }
34
- // Create a new copy of the ArrayBuffer to avoid detachment issues
35
- const bufferCopy = arrayBuffer.slice(0);
36
- console.log(`extractAudioAnalysis skipWavHeader=${skipWavHeader} bitDepth=${bitDepth} len=${bufferCopy.byteLength}`, bufferCopy.slice(0, 100));
37
- let actualBitDepth = bitDepth;
38
- if (!actualBitDepth) {
39
- console.log(`extractAudioAnalysis bitDepth not provided -- getting wav file info`);
40
- const fileInfo = await getWavFileInfo(bufferCopy);
41
- actualBitDepth = fileInfo.bitDepth;
42
- }
43
- console.log(`extractAudioAnalysis actualBitDepth=${actualBitDepth}`);
44
- // let copyChannelData: Float32Array;
45
- // try {
46
- // const audioContext = new (window.AudioContext ||
47
- // // @ts-ignore
48
- // window.webkitAudioContext)();
49
- // const audioBuffer = await audioContext.decodeAudioData(bufferCopy);
50
- // const channelData = audioBuffer.getChannelData(0); // Use only the first channel
51
- // copyChannelData = new Float32Array(channelData); // Create a new Float32Array
52
- // } catch (error) {
53
- // console.warn("Failed to decode audio data:", error);
54
- // // Fall back to creating a new Float32Array from the ArrayBuffer if decoding fails
55
- // copyChannelData = new Float32Array(arrayBuffer);
56
- // }
57
- const { pcmValues: channelData, min, max, } = convertPCMToFloat32({
58
- buffer: arrayBuffer,
59
- bitDepth: actualBitDepth,
60
- skipWavHeader,
61
- });
62
- console.log(`extractAudioAnalysis skipWaveHeader=${skipWavHeader} convertPCMToFloat32 length=${channelData.length} range: [ ${min} :: ${max} ]`);
63
- return new Promise((resolve, reject) => {
64
- const worker = new Worker(new URL(featuresExtratorUrl, window.location.href));
65
- worker.onmessage = (event) => {
66
- resolve(event.data.result);
67
- };
68
- worker.onerror = (error) => {
69
- reject(error);
70
- };
71
- worker.postMessage({
72
- command: "process",
73
- channelData,
74
- sampleRate,
75
- pointsPerSecond,
76
- algorithm,
77
- bitDepth,
78
- fullAudioDurationMs: durationMs,
79
- numberOfChannels,
80
- });
81
- });
82
- }
83
- else {
84
- if (!fileUri) {
85
- throw new Error("fileUri is required");
86
- }
87
- console.log(`extractAudioAnalysis`, {
88
- fileUri,
89
- pointsPerSecond,
90
- algorithm,
91
- });
92
- const res = await ExpoAudioStreamModule.extractAudioAnalysis({
93
- fileUri,
94
- pointsPerSecond,
95
- skipWavHeader,
96
- algorithm,
97
- features,
98
- });
99
- console.log(`extractAudioAnalysis`, res);
100
- return res;
101
- }
102
- };
103
- export const extractWaveform = async ({ fileUri, numberOfSamples, offset = 0, length, }) => {
104
- const res = await ExpoAudioStreamModule.extractAudioAnalysis({
105
- fileUri,
106
- numberOfSamples,
107
- offset,
108
- length,
109
- });
110
- console.log(`extractWaveform`, res);
111
- return res;
112
- };
113
- export { AudioRecorderProvider, convertPCMToFloat32, getWavFileInfo, useAudioRecorder, useSharedAudioRecorder, writeWavHeader as writeWaveHeader, };
114
- export * from "./ExpoAudioStream.types";
4
+ import { useAudioRecorder } from "./useAudioRecorder";
5
+ export * from "./utils/getWavFileInfo";
6
+ export * from "./utils/convertPCMToFloat32";
7
+ export * from "./utils/writeWavHeader";
8
+ export { AudioRecorderProvider, extractAudioAnalysis, useAudioRecorder, useSharedAudioRecorder, };
115
9
  //# sourceMappingURL=index.js.map