react-native-audio-api 0.6.0-rc.0 → 0.6.0-rc.2

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 (207) hide show
  1. package/README.md +35 -22
  2. package/android/CMakeLists.txt +6 -3
  3. package/android/build.gradle +1 -0
  4. package/android/src/main/cpp/audioapi/android/core/AndroidAudioRecorder.cpp +73 -0
  5. package/android/src/main/cpp/audioapi/android/core/AndroidAudioRecorder.h +37 -0
  6. package/android/src/main/cpp/audioapi/android/core/AudioPlayer.cpp +6 -10
  7. package/android/src/main/cpp/audioapi/android/core/AudioPlayer.h +2 -3
  8. package/android/src/main/java/com/swmansion/audioapi/AudioManagerModule.kt +19 -14
  9. package/android/src/main/java/com/swmansion/audioapi/system/AudioFocusListener.kt +60 -0
  10. package/android/src/main/java/com/swmansion/audioapi/system/LockScreenManager.kt +294 -0
  11. package/android/src/main/java/com/swmansion/audioapi/system/MediaNotificationManager.kt +279 -0
  12. package/android/src/main/java/com/swmansion/audioapi/system/MediaReceiver.kt +46 -0
  13. package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionCallback.kt +39 -0
  14. package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionEventEmitter.kt +88 -0
  15. package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionManager.kt +162 -0
  16. package/android/src/main/java/com/swmansion/audioapi/system/VolumeChangeListener.kt +27 -0
  17. package/android/src/main/res/drawable/next.xml +9 -0
  18. package/android/src/main/res/drawable/pause.xml +9 -0
  19. package/android/src/main/res/drawable/play.xml +9 -0
  20. package/android/src/main/res/drawable/previous.xml +9 -0
  21. package/android/src/main/res/drawable/skip_backward_5.xml +9 -0
  22. package/android/src/main/res/drawable/skip_forward_5.xml +9 -0
  23. package/android/src/main/res/drawable/stop.xml +9 -0
  24. package/app.plugin.js +1 -0
  25. package/common/cpp/audioapi/AudioAPIModuleInstaller.h +29 -5
  26. package/common/cpp/audioapi/HostObjects/AnalyserNodeHostObject.h +1 -0
  27. package/common/cpp/audioapi/HostObjects/AudioRecorderHostObject.h +149 -0
  28. package/common/cpp/audioapi/core/AudioContext.cpp +4 -3
  29. package/common/cpp/audioapi/core/BaseAudioContext.cpp +6 -6
  30. package/common/cpp/audioapi/core/inputs/AudioRecorder.h +38 -0
  31. package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp +1 -6
  32. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +8 -4
  33. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +6 -0
  34. package/common/cpp/audioapi/core/sources/OscillatorNode.cpp +1 -1
  35. package/common/cpp/audioapi/core/utils/AudioNodeDestructor.cpp +3 -3
  36. package/common/cpp/audioapi/core/utils/AudioNodeManager.cpp +45 -11
  37. package/common/cpp/audioapi/core/utils/AudioNodeManager.h +6 -2
  38. package/ios/audioapi/ios/AudioManagerModule.mm +16 -15
  39. package/ios/audioapi/ios/core/IOSAudioPlayer.h +11 -12
  40. package/ios/audioapi/ios/core/IOSAudioPlayer.mm +22 -16
  41. package/ios/audioapi/ios/core/IOSAudioRecorder.h +36 -0
  42. package/ios/audioapi/ios/core/IOSAudioRecorder.mm +62 -0
  43. package/ios/audioapi/ios/core/{AudioPlayer.h → NativeAudioPlayer.h} +1 -8
  44. package/ios/audioapi/ios/core/{AudioPlayer.m → NativeAudioPlayer.m} +4 -33
  45. package/ios/audioapi/ios/core/NativeAudioRecorder.h +25 -0
  46. package/ios/audioapi/ios/core/NativeAudioRecorder.m +47 -0
  47. package/ios/audioapi/ios/system/AudioEngine.h +7 -1
  48. package/ios/audioapi/ios/system/AudioEngine.mm +64 -20
  49. package/ios/audioapi/ios/system/AudioSessionManager.h +3 -1
  50. package/ios/audioapi/ios/system/AudioSessionManager.mm +37 -25
  51. package/ios/audioapi/ios/system/LockScreenManager.mm +4 -8
  52. package/ios/audioapi/ios/system/NotificationManager.h +13 -1
  53. package/ios/audioapi/ios/system/NotificationManager.mm +96 -44
  54. package/lib/commonjs/api.js +211 -0
  55. package/lib/commonjs/api.js.map +1 -0
  56. package/lib/commonjs/api.web.js +219 -0
  57. package/lib/commonjs/api.web.js.map +1 -0
  58. package/lib/commonjs/core/AnalyserNode.js +71 -0
  59. package/lib/commonjs/core/AnalyserNode.js.map +1 -0
  60. package/lib/commonjs/core/AudioBuffer.js +44 -0
  61. package/lib/commonjs/core/AudioBuffer.js.map +1 -0
  62. package/lib/commonjs/core/AudioBufferSourceNode.js +68 -0
  63. package/lib/commonjs/core/AudioBufferSourceNode.js.map +1 -0
  64. package/lib/commonjs/core/AudioContext.js +29 -0
  65. package/lib/commonjs/core/AudioContext.js.map +1 -0
  66. package/lib/commonjs/core/AudioDestinationNode.js +11 -0
  67. package/lib/commonjs/core/AudioDestinationNode.js.map +1 -0
  68. package/lib/commonjs/core/AudioNode.js +30 -0
  69. package/lib/commonjs/core/AudioNode.js.map +1 -0
  70. package/lib/commonjs/core/AudioParam.js +82 -0
  71. package/lib/commonjs/core/AudioParam.js.map +1 -0
  72. package/lib/commonjs/core/AudioRecorder.js +51 -0
  73. package/lib/commonjs/core/AudioRecorder.js.map +1 -0
  74. package/lib/commonjs/core/AudioScheduledSourceNode.js +38 -0
  75. package/lib/commonjs/core/AudioScheduledSourceNode.js.map +1 -0
  76. package/lib/commonjs/core/BaseAudioContext.js +80 -0
  77. package/lib/commonjs/core/BaseAudioContext.js.map +1 -0
  78. package/lib/commonjs/core/BiquadFilterNode.js +33 -0
  79. package/lib/commonjs/core/BiquadFilterNode.js.map +1 -0
  80. package/lib/commonjs/core/GainNode.js +17 -0
  81. package/lib/commonjs/core/GainNode.js.map +1 -0
  82. package/lib/commonjs/core/OfflineAudioContext.js +63 -0
  83. package/lib/commonjs/core/OfflineAudioContext.js.map +1 -0
  84. package/lib/commonjs/core/OscillatorNode.js +32 -0
  85. package/lib/commonjs/core/OscillatorNode.js.map +1 -0
  86. package/lib/commonjs/core/PeriodicWave.js +15 -0
  87. package/lib/commonjs/core/PeriodicWave.js.map +1 -0
  88. package/lib/commonjs/core/StereoPannerNode.js +17 -0
  89. package/lib/commonjs/core/StereoPannerNode.js.map +1 -0
  90. package/lib/commonjs/errors/IndexSizeError.js +14 -0
  91. package/lib/commonjs/errors/IndexSizeError.js.map +1 -0
  92. package/lib/commonjs/errors/InvalidAccessError.js +14 -0
  93. package/lib/commonjs/errors/InvalidAccessError.js.map +1 -0
  94. package/lib/commonjs/errors/InvalidStateError.js +14 -0
  95. package/lib/commonjs/errors/InvalidStateError.js.map +1 -0
  96. package/lib/commonjs/errors/NotSupportedError.js +14 -0
  97. package/lib/commonjs/errors/NotSupportedError.js.map +1 -0
  98. package/lib/commonjs/errors/RangeError.js +14 -0
  99. package/lib/commonjs/errors/RangeError.js.map +1 -0
  100. package/lib/commonjs/errors/index.js +42 -0
  101. package/lib/commonjs/errors/index.js.map +1 -0
  102. package/lib/commonjs/hooks/useSytemVolume.js +24 -0
  103. package/lib/commonjs/hooks/useSytemVolume.js.map +1 -0
  104. package/lib/commonjs/index.js +17 -0
  105. package/lib/commonjs/index.js.map +1 -0
  106. package/lib/commonjs/interfaces.js +6 -0
  107. package/lib/commonjs/interfaces.js.map +1 -0
  108. package/lib/commonjs/package.json +1 -0
  109. package/lib/commonjs/plugin/withAudioAPI.js +62 -0
  110. package/lib/commonjs/plugin/withAudioAPI.js.map +1 -0
  111. package/lib/commonjs/specs/NativeAudioAPIModule.js +9 -0
  112. package/lib/commonjs/specs/NativeAudioAPIModule.js.map +1 -0
  113. package/lib/commonjs/specs/NativeAudioManagerModule.js +36 -0
  114. package/lib/commonjs/specs/NativeAudioManagerModule.js.map +1 -0
  115. package/lib/commonjs/specs/index.js +27 -0
  116. package/lib/commonjs/specs/index.js.map +1 -0
  117. package/lib/commonjs/system/AudioManager.js +52 -0
  118. package/lib/commonjs/system/AudioManager.js.map +1 -0
  119. package/lib/commonjs/system/index.js +14 -0
  120. package/lib/commonjs/system/index.js.map +1 -0
  121. package/lib/commonjs/system/types.js +2 -0
  122. package/lib/commonjs/system/types.js.map +1 -0
  123. package/lib/commonjs/types.js +2 -0
  124. package/lib/commonjs/types.js.map +1 -0
  125. package/lib/commonjs/utils/index.js +10 -0
  126. package/lib/commonjs/utils/index.js.map +1 -0
  127. package/lib/commonjs/web-core/AnalyserNode.js +38 -0
  128. package/lib/commonjs/web-core/AnalyserNode.js.map +1 -0
  129. package/lib/commonjs/web-core/AudioBuffer.js +44 -0
  130. package/lib/commonjs/web-core/AudioBuffer.js.map +1 -0
  131. package/lib/commonjs/web-core/AudioBufferSourceNode.js +214 -0
  132. package/lib/commonjs/web-core/AudioBufferSourceNode.js.map +1 -0
  133. package/lib/commonjs/web-core/AudioContext.js +93 -0
  134. package/lib/commonjs/web-core/AudioContext.js.map +1 -0
  135. package/lib/commonjs/web-core/AudioDestinationNode.js +11 -0
  136. package/lib/commonjs/web-core/AudioDestinationNode.js.map +1 -0
  137. package/lib/commonjs/web-core/AudioNode.js +33 -0
  138. package/lib/commonjs/web-core/AudioNode.js.map +1 -0
  139. package/lib/commonjs/web-core/AudioParam.js +81 -0
  140. package/lib/commonjs/web-core/AudioParam.js.map +1 -0
  141. package/lib/commonjs/web-core/AudioScheduledSourceNode.js +41 -0
  142. package/lib/commonjs/web-core/AudioScheduledSourceNode.js.map +1 -0
  143. package/lib/commonjs/web-core/BaseAudioContext.js +2 -0
  144. package/lib/commonjs/web-core/BaseAudioContext.js.map +1 -0
  145. package/lib/commonjs/web-core/BiquadFilterNode.js +33 -0
  146. package/lib/commonjs/web-core/BiquadFilterNode.js.map +1 -0
  147. package/lib/commonjs/web-core/GainNode.js +17 -0
  148. package/lib/commonjs/web-core/GainNode.js.map +1 -0
  149. package/lib/commonjs/web-core/OfflineAudioContext.js +96 -0
  150. package/lib/commonjs/web-core/OfflineAudioContext.js.map +1 -0
  151. package/lib/commonjs/web-core/OscillatorNode.js +31 -0
  152. package/lib/commonjs/web-core/OscillatorNode.js.map +1 -0
  153. package/lib/commonjs/web-core/PeriodicWave.js +15 -0
  154. package/lib/commonjs/web-core/PeriodicWave.js.map +1 -0
  155. package/lib/commonjs/web-core/StereoPannerNode.js +17 -0
  156. package/lib/commonjs/web-core/StereoPannerNode.js.map +1 -0
  157. package/lib/commonjs/web-core/custom/LoadCustomWasm.js +37 -0
  158. package/lib/commonjs/web-core/custom/LoadCustomWasm.js.map +1 -0
  159. package/lib/commonjs/web-core/custom/index.js +14 -0
  160. package/lib/commonjs/web-core/custom/index.js.map +1 -0
  161. package/lib/commonjs/web-core/custom/signalsmithStretch/LICENSE.txt +21 -0
  162. package/lib/commonjs/web-core/custom/signalsmithStretch/README.md +46 -0
  163. package/lib/commonjs/web-core/custom/signalsmithStretch/SignalsmithStretch.mjs +826 -0
  164. package/lib/commonjs/web-core/custom/signalsmithStretch/SignalsmithStretch.mjs.map +1 -0
  165. package/lib/module/api.js +3 -1
  166. package/lib/module/api.js.map +1 -1
  167. package/lib/module/core/AudioRecorder.js +45 -0
  168. package/lib/module/core/AudioRecorder.js.map +1 -0
  169. package/lib/module/errors/NotSupportedError.js.map +1 -1
  170. package/lib/module/hooks/useSytemVolume.js +19 -0
  171. package/lib/module/hooks/useSytemVolume.js.map +1 -0
  172. package/lib/module/plugin/withAudioAPI.js +58 -0
  173. package/lib/module/plugin/withAudioAPI.js.map +1 -0
  174. package/lib/module/specs/NativeAudioManagerModule.js +10 -8
  175. package/lib/module/specs/NativeAudioManagerModule.js.map +1 -1
  176. package/lib/module/system/AudioManager.js +26 -44
  177. package/lib/module/system/AudioManager.js.map +1 -1
  178. package/lib/typescript/api.d.ts +5 -1
  179. package/lib/typescript/api.d.ts.map +1 -1
  180. package/lib/typescript/core/AudioRecorder.d.ts +22 -0
  181. package/lib/typescript/core/AudioRecorder.d.ts.map +1 -0
  182. package/lib/typescript/errors/NotSupportedError.d.ts.map +1 -1
  183. package/lib/typescript/hooks/useSytemVolume.d.ts +2 -0
  184. package/lib/typescript/hooks/useSytemVolume.d.ts.map +1 -0
  185. package/lib/typescript/interfaces.d.ts +11 -5
  186. package/lib/typescript/interfaces.d.ts.map +1 -1
  187. package/lib/typescript/plugin/withAudioAPI.d.ts +9 -0
  188. package/lib/typescript/plugin/withAudioAPI.d.ts.map +1 -0
  189. package/lib/typescript/specs/NativeAudioManagerModule.d.ts +4 -2
  190. package/lib/typescript/specs/NativeAudioManagerModule.d.ts.map +1 -1
  191. package/lib/typescript/system/AudioManager.d.ts +5 -2
  192. package/lib/typescript/system/AudioManager.d.ts.map +1 -1
  193. package/lib/typescript/system/types.d.ts +36 -5
  194. package/lib/typescript/system/types.d.ts.map +1 -1
  195. package/lib/typescript/types.d.ts +5 -0
  196. package/lib/typescript/types.d.ts.map +1 -1
  197. package/package.json +7 -3
  198. package/src/api.ts +13 -2
  199. package/src/core/AudioRecorder.ts +81 -0
  200. package/src/hooks/useSytemVolume.ts +19 -0
  201. package/src/interfaces.ts +25 -11
  202. package/src/plugin/withAudioAPI.ts +91 -0
  203. package/src/specs/NativeAudioManagerModule.ts +13 -19
  204. package/src/system/AudioManager.ts +37 -87
  205. package/src/system/types.ts +43 -17
  206. package/src/types.ts +13 -0
  207. /package/src/errors/{NotSupportedError.tsx → NotSupportedError.ts} +0 -0
@@ -0,0 +1,88 @@
1
+ package com.swmansion.audioapi.system
2
+
3
+ import android.content.Intent
4
+ import android.os.Build
5
+ import androidx.core.app.NotificationManagerCompat
6
+ import com.facebook.react.bridge.Arguments
7
+ import com.facebook.react.bridge.ReactApplicationContext
8
+ import com.facebook.react.modules.core.DeviceEventManagerModule
9
+
10
+ class MediaSessionEventEmitter(
11
+ val reactContext: ReactApplicationContext,
12
+ val notificationId: Int,
13
+ ) {
14
+ fun sendEvent(
15
+ name: String,
16
+ values: Map<String, Any>?,
17
+ ) {
18
+ val data = Arguments.createMap()
19
+
20
+ if (values != null) {
21
+ for (value in values) {
22
+ when (value.value) {
23
+ is Double, is Float -> {
24
+ data.putDouble(value.key, value.value as Double)
25
+ }
26
+
27
+ is Boolean -> {
28
+ data.putBoolean(value.key, value.value as Boolean)
29
+ }
30
+
31
+ is Int -> {
32
+ data.putInt(value.key, value.value as Int)
33
+ }
34
+ }
35
+ }
36
+ }
37
+
38
+ reactContext
39
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
40
+ .emit(name, data)
41
+ }
42
+
43
+ fun onPlay() {
44
+ sendEvent("onRemotePlay", null)
45
+ }
46
+
47
+ fun onPause() {
48
+ sendEvent("onRemotePause", null)
49
+ }
50
+
51
+ fun onStop() {
52
+ stopForegroundService()
53
+ sendEvent("onRemoteStop", null)
54
+ }
55
+
56
+ fun onSkipToNext() {
57
+ sendEvent("onRemoteNextTrack", null)
58
+ }
59
+
60
+ fun onSkipToPrevious() {
61
+ sendEvent("onRemotePreviousTrack", null)
62
+ }
63
+
64
+ fun onFastForward() {
65
+ sendEvent("onRemoteSkipForward", null)
66
+ }
67
+
68
+ fun onRewind() {
69
+ sendEvent("onRemoteSkipBackward", null)
70
+ }
71
+
72
+ fun onInterruption(values: Map<String, Any>) {
73
+ sendEvent("onInterruption", values)
74
+ }
75
+
76
+ fun onVolumeChange(values: Map<String, Number>) {
77
+ sendEvent("onVolumeChange", values)
78
+ }
79
+
80
+ private fun stopForegroundService() {
81
+ NotificationManagerCompat.from(reactContext).cancel(notificationId)
82
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
83
+ val myIntent =
84
+ Intent(reactContext, MediaNotificationManager.NotificationService::class.java)
85
+ reactContext.stopService(myIntent)
86
+ }
87
+ }
88
+ }
@@ -0,0 +1,162 @@
1
+ package com.swmansion.audioapi.system
2
+
3
+ import android.app.NotificationChannel
4
+ import android.app.NotificationManager
5
+ import android.content.ComponentName
6
+ import android.content.Context
7
+ import android.content.Intent
8
+ import android.content.IntentFilter
9
+ import android.content.ServiceConnection
10
+ import android.media.AudioManager
11
+ import android.os.Build
12
+ import android.os.IBinder
13
+ import android.support.v4.media.session.MediaSessionCompat
14
+ import android.util.Log
15
+ import androidx.annotation.RequiresApi
16
+ import androidx.core.app.NotificationCompat
17
+ import androidx.core.content.ContextCompat
18
+ import com.facebook.react.bridge.ReactApplicationContext
19
+ import com.facebook.react.bridge.ReadableMap
20
+
21
+ object MediaSessionManager {
22
+ lateinit var reactContext: ReactApplicationContext
23
+ val notificationId = 100
24
+ val channelId = "react-native-audio-api"
25
+
26
+ private lateinit var audioManager: AudioManager
27
+ lateinit var mediaSession: MediaSessionCompat
28
+ lateinit var mediaNotificationManager: MediaNotificationManager
29
+ private lateinit var lockScreenManager: LockScreenManager
30
+ lateinit var eventEmitter: MediaSessionEventEmitter
31
+ private lateinit var audioFocusListener: AudioFocusListener
32
+ private lateinit var volumeChangeListener: VolumeChangeListener
33
+ private lateinit var mediaReceiver: MediaReceiver
34
+
35
+ private val connection =
36
+ object : ServiceConnection {
37
+ override fun onServiceConnected(
38
+ name: ComponentName,
39
+ service: IBinder,
40
+ ) {
41
+ Log.w("MediaSessionManager", "onServiceConnected")
42
+ val binder = service as MediaNotificationManager.NotificationService.LocalBinder
43
+ val notificationService = binder.getService()
44
+ notificationService?.forceForeground()
45
+ reactContext.unbindService(this)
46
+ }
47
+
48
+ override fun onServiceDisconnected(name: ComponentName) {
49
+ Log.w("MediaSessionManager", "Service is disconnected.")
50
+ }
51
+
52
+ override fun onBindingDied(name: ComponentName) {
53
+ Log.w("MediaSessionManager", "Binding has died.")
54
+ }
55
+
56
+ override fun onNullBinding(name: ComponentName) {
57
+ Log.w("MediaSessionManager", "Bind was null.")
58
+ }
59
+ }
60
+
61
+ fun initialize(reactContext: ReactApplicationContext) {
62
+ this.reactContext = reactContext
63
+ this.audioManager = reactContext.getSystemService(Context.AUDIO_SERVICE) as AudioManager
64
+ this.mediaSession = MediaSessionCompat(reactContext, "MediaSessionManager")
65
+
66
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
67
+ createChannel()
68
+ }
69
+
70
+ this.mediaNotificationManager = MediaNotificationManager(reactContext, notificationId, channelId)
71
+ this.lockScreenManager = LockScreenManager(reactContext, mediaSession, mediaNotificationManager, channelId)
72
+ this.eventEmitter = MediaSessionEventEmitter(reactContext, notificationId)
73
+ this.mediaReceiver = MediaReceiver(reactContext, this)
74
+ this.mediaSession.setCallback(MediaSessionCallback(eventEmitter, lockScreenManager))
75
+
76
+ val filter = IntentFilter()
77
+ filter.addAction(MediaNotificationManager.REMOVE_NOTIFICATION)
78
+ filter.addAction(MediaNotificationManager.MEDIA_BUTTON)
79
+ filter.addAction(Intent.ACTION_MEDIA_BUTTON)
80
+ filter.addAction(AudioManager.ACTION_AUDIO_BECOMING_NOISY)
81
+
82
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
83
+ reactContext.registerReceiver(mediaReceiver, filter, Context.RECEIVER_EXPORTED)
84
+ } else {
85
+ ContextCompat.registerReceiver(
86
+ reactContext,
87
+ mediaReceiver,
88
+ filter,
89
+ ContextCompat.RECEIVER_NOT_EXPORTED,
90
+ )
91
+ }
92
+
93
+ this.audioFocusListener = AudioFocusListener(audioManager, eventEmitter, lockScreenManager)
94
+ this.volumeChangeListener = VolumeChangeListener(audioManager, eventEmitter)
95
+
96
+ val myIntent = Intent(reactContext, MediaNotificationManager.NotificationService::class.java)
97
+
98
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
99
+ try {
100
+ reactContext.bindService(myIntent, connection, Context.BIND_AUTO_CREATE)
101
+ } catch (ignored: Exception) {
102
+ ContextCompat.startForegroundService(reactContext, myIntent)
103
+ }
104
+ } else {
105
+ reactContext.startService(myIntent)
106
+ }
107
+ }
108
+
109
+ fun setLockScreenInfo(info: ReadableMap?) {
110
+ lockScreenManager.setLockScreenInfo(info)
111
+ }
112
+
113
+ fun resetLockScreenInfo() {
114
+ lockScreenManager.resetLockScreenInfo()
115
+ }
116
+
117
+ fun enableRemoteCommand(
118
+ name: String,
119
+ enabled: Boolean,
120
+ ) {
121
+ lockScreenManager.enableRemoteCommand(name, enabled)
122
+ }
123
+
124
+ fun getDevicePreferredSampleRate(): Double {
125
+ val sampleRate = this.audioManager.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE)
126
+ return sampleRate.toDouble()
127
+ }
128
+
129
+ fun observeAudioInterruptions(observe: Boolean) {
130
+ if (observe) {
131
+ audioFocusListener.requestAudioFocus()
132
+ } else {
133
+ audioFocusListener.abandonAudioFocus()
134
+ }
135
+ }
136
+
137
+ fun observeVolumeChanges(observe: Boolean) {
138
+ if (observe) {
139
+ ContextCompat.registerReceiver(
140
+ reactContext,
141
+ volumeChangeListener,
142
+ volumeChangeListener.getIntentFilter(),
143
+ ContextCompat.RECEIVER_NOT_EXPORTED,
144
+ )
145
+ } else {
146
+ reactContext.unregisterReceiver(volumeChangeListener)
147
+ }
148
+ }
149
+
150
+ @RequiresApi(Build.VERSION_CODES.O)
151
+ private fun createChannel() {
152
+ val notificationManager =
153
+ reactContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
154
+
155
+ val mChannel =
156
+ NotificationChannel(channelId, "Audio manager", NotificationManager.IMPORTANCE_LOW)
157
+ mChannel.description = "Audio manager"
158
+ mChannel.setShowBadge(false)
159
+ mChannel.lockscreenVisibility = NotificationCompat.VISIBILITY_PUBLIC
160
+ notificationManager.createNotificationChannel(mChannel)
161
+ }
162
+ }
@@ -0,0 +1,27 @@
1
+ package com.swmansion.audioapi.system
2
+
3
+ import android.content.BroadcastReceiver
4
+ import android.content.Context
5
+ import android.content.Intent
6
+ import android.content.IntentFilter
7
+ import android.media.AudioManager
8
+
9
+ class VolumeChangeListener(
10
+ private val audioManager: AudioManager,
11
+ private val eventEmitter: MediaSessionEventEmitter,
12
+ ) : BroadcastReceiver() {
13
+ override fun onReceive(
14
+ context: Context?,
15
+ intent: Intent?,
16
+ ) {
17
+ val currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC).toDouble()
18
+ val maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC).toDouble()
19
+ eventEmitter.onVolumeChange(mapOf("value" to currentVolume / maxVolume))
20
+ }
21
+
22
+ fun getIntentFilter(): IntentFilter {
23
+ val intentFilter = IntentFilter()
24
+ intentFilter.addAction("android.media.VOLUME_CHANGED_ACTION")
25
+ return intentFilter
26
+ }
27
+ }
@@ -0,0 +1,9 @@
1
+ <vector xmlns:android="http://schemas.android.com/apk/res/android"
2
+ android:width="24dp"
3
+ android:height="24dp"
4
+ android:viewportWidth="24.0"
5
+ android:viewportHeight="24.0">
6
+ <path
7
+ android:fillColor="#FFFFFFFF"
8
+ android:pathData="M6,18l8.5,-6L6,6v12zM16,6v12h2V6h-2z"/>
9
+ </vector>
@@ -0,0 +1,9 @@
1
+ <vector xmlns:android="http://schemas.android.com/apk/res/android"
2
+ android:width="24dp"
3
+ android:height="24dp"
4
+ android:viewportWidth="24.0"
5
+ android:viewportHeight="24.0">
6
+ <path
7
+ android:fillColor="#FFFFFFFF"
8
+ android:pathData="M6,19h4L10,5L6,5v14zM14,5v14h4L18,5h-4z"/>
9
+ </vector>
@@ -0,0 +1,9 @@
1
+ <vector xmlns:android="http://schemas.android.com/apk/res/android"
2
+ android:width="24dp"
3
+ android:height="24dp"
4
+ android:viewportWidth="24.0"
5
+ android:viewportHeight="24.0">
6
+ <path
7
+ android:fillColor="#FFFFFFFF"
8
+ android:pathData="M8,5v14l11,-7z"/>
9
+ </vector>
@@ -0,0 +1,9 @@
1
+ <vector xmlns:android="http://schemas.android.com/apk/res/android"
2
+ android:width="24dp"
3
+ android:height="24dp"
4
+ android:viewportWidth="24.0"
5
+ android:viewportHeight="24.0">
6
+ <path
7
+ android:fillColor="#FFFFFFFF"
8
+ android:pathData="M6,6h2v12L6,18zM9.5,12l8.5,6L18,6z"/>
9
+ </vector>
@@ -0,0 +1,9 @@
1
+ <vector xmlns:android="http://schemas.android.com/apk/res/android"
2
+ android:width="24dp"
3
+ android:height="24dp"
4
+ android:viewportWidth="24.0"
5
+ android:viewportHeight="24.0">
6
+ <path
7
+ android:fillColor="#FFFFFFFF"
8
+ android:pathData="M12,5L12,1L7,6l5,5L12,7c3.3,0 6,2.7 6,6s-2.7,6 -6,6 -6,-2.7 -6,-6L4,13c0,4.4 3.6,8 8,8s8,-3.6 8,-8 -3.6,-8 -8,-8zM10.7,13.9l0.2,-2.2h2.4v0.7h-1.7l-0.1,0.9s0.1,0 0.1,-0.1 0.1,0 0.1,-0.1 0.1,0 0.2,0h0.2c0.2,0 0.4,0 0.5,0.1s0.3,0.2 0.4,0.3 0.2,0.3 0.3,0.5 0.1,0.4 0.1,0.6c0,0.2 0,0.4 -0.1,0.5s-0.1,0.3 -0.3,0.5 -0.3,0.2 -0.4,0.3 -0.4,0.1 -0.6,0.1c-0.2,0 -0.4,0 -0.5,-0.1s-0.3,-0.1 -0.5,-0.2 -0.2,-0.2 -0.3,-0.4 -0.1,-0.3 -0.1,-0.5h0.8c0,0.2 0.1,0.3 0.2,0.4s0.2,0.1 0.4,0.1c0.1,0 0.2,0 0.3,-0.1l0.2,-0.2s0.1,-0.2 0.1,-0.3v-0.6l-0.1,-0.2 -0.2,-0.2s-0.2,-0.1 -0.3,-0.1h-0.2s-0.1,0 -0.2,0.1 -0.1,0 -0.1,0.1 -0.1,0.1 -0.1,0.1h-0.7z"/>
9
+ </vector>
@@ -0,0 +1,9 @@
1
+ <vector xmlns:android="http://schemas.android.com/apk/res/android"
2
+ android:width="24dp"
3
+ android:height="24dp"
4
+ android:viewportWidth="24.0"
5
+ android:viewportHeight="24.0">
6
+ <path
7
+ android:fillColor="#FFFFFFFF"
8
+ android:pathData="M4,13c0,4.4 3.6,8 8,8s8,-3.6 8,-8h-2c0,3.3 -2.7,6 -6,6s-6,-2.7 -6,-6 2.7,-6 6,-6v4l5,-5 -5,-5v4c-4.4,0 -8,3.6 -8,8zM10.7,13.9l0.2,-2.2h2.4v0.7h-1.7l-0.1,0.9s0.1,0 0.1,-0.1 0.1,0 0.1,-0.1 0.1,0 0.2,0h0.2c0.2,0 0.4,0 0.5,0.1s0.3,0.2 0.4,0.3 0.2,0.3 0.3,0.5 0.1,0.4 0.1,0.6c0,0.2 0,0.4 -0.1,0.5s-0.1,0.3 -0.3,0.5 -0.3,0.2 -0.5,0.3 -0.4,0.1 -0.6,0.1c-0.2,0 -0.4,0 -0.5,-0.1s-0.3,-0.1 -0.5,-0.2 -0.2,-0.2 -0.3,-0.4 -0.1,-0.3 -0.1,-0.5h0.8c0,0.2 0.1,0.3 0.2,0.4s0.2,0.1 0.4,0.1c0.1,0 0.2,0 0.3,-0.1l0.2,-0.2s0.1,-0.2 0.1,-0.3v-0.6l-0.1,-0.2 -0.2,-0.2s-0.2,-0.1 -0.3,-0.1h-0.2s-0.1,0 -0.2,0.1 -0.1,0 -0.1,0.1 -0.1,0.1 -0.1,0.1h-0.6z"/>
9
+ </vector>
@@ -0,0 +1,9 @@
1
+ <vector xmlns:android="http://schemas.android.com/apk/res/android"
2
+ android:width="24dp"
3
+ android:height="24dp"
4
+ android:viewportWidth="24.0"
5
+ android:viewportHeight="24.0">
6
+ <path
7
+ android:fillColor="#FFFFFFFF"
8
+ android:pathData="M6,6h12v12H6z"/>
9
+ </vector>
package/app.plugin.js ADDED
@@ -0,0 +1 @@
1
+ module.exports = require('./lib/commonjs/plugin/withAudioAPI');
@@ -3,8 +3,10 @@
3
3
  #include <audioapi/jsi/JsiPromise.h>
4
4
  #include <audioapi/core/AudioContext.h>
5
5
  #include <audioapi/core/OfflineAudioContext.h>
6
+ #include <audioapi/core/inputs/AudioRecorder.h>
6
7
  #include <audioapi/HostObjects/AudioContextHostObject.h>
7
8
  #include <audioapi/HostObjects/OfflineAudioContextHostObject.h>
9
+ #include <audioapi/HostObjects/AudioRecorderHostObject.h>
8
10
 
9
11
  #include <memory>
10
12
 
@@ -16,11 +18,12 @@ class AudioAPIModuleInstaller {
16
18
  public:
17
19
  static void injectJSIBindings(jsi::Runtime *jsiRuntime, const std::shared_ptr<react::CallInvoker> &jsCallInvoker) {
18
20
  auto createAudioContext = getCreateAudioContextFunction(jsiRuntime, jsCallInvoker);
21
+ auto createAudioRecorder = getCreateAudioRecorderFunction(jsiRuntime, jsCallInvoker);
19
22
  auto createOfflineAudioContext = getCreateOfflineAudioContextFunction(jsiRuntime, jsCallInvoker);
20
- jsiRuntime->global().setProperty(
21
- *jsiRuntime, "createAudioContext", createAudioContext);
22
- jsiRuntime->global().setProperty(
23
- *jsiRuntime, "createOfflineAudioContext", createOfflineAudioContext);
23
+
24
+ jsiRuntime->global().setProperty(*jsiRuntime, "createAudioContext", createAudioContext);
25
+ jsiRuntime->global().setProperty(*jsiRuntime, "createAudioRecorder", createAudioRecorder);
26
+ jsiRuntime->global().setProperty(*jsiRuntime, "createOfflineAudioContext", createOfflineAudioContext);
24
27
  }
25
28
 
26
29
  private:
@@ -60,7 +63,7 @@ class AudioAPIModuleInstaller {
60
63
  auto length = static_cast<size_t>(args[1].getNumber());
61
64
  auto sampleRate = static_cast<float>(args[2].getNumber());
62
65
 
63
- std::shared_ptr<OfflineAudioContext> offlineAudioContext = std::make_shared<OfflineAudioContext>(numberOfChannels, length, sampleRate);
66
+ auto offlineAudioContext = std::make_shared<OfflineAudioContext>(numberOfChannels, length, sampleRate);
64
67
  auto audioContextHostObject = std::make_shared<OfflineAudioContextHostObject>(
65
68
  offlineAudioContext, jsiRuntime, jsCallInvoker);
66
69
 
@@ -68,6 +71,27 @@ class AudioAPIModuleInstaller {
68
71
  runtime, audioContextHostObject);
69
72
  });
70
73
  }
74
+
75
+ static jsi::Function getCreateAudioRecorderFunction(jsi::Runtime *jsiRuntime, const std::shared_ptr<react::CallInvoker> &jsCallInvoker) {
76
+ return jsi::Function::createFromHostFunction(
77
+ *jsiRuntime,
78
+ jsi::PropNameID::forAscii(*jsiRuntime, "createAudioRecorder"),
79
+ 0,
80
+ [jsCallInvoker](
81
+ jsi::Runtime &runtime,
82
+ const jsi::Value &thisValue,
83
+ const jsi::Value *args,
84
+ size_t count) -> jsi::Value {
85
+ auto options = args[0].getObject(runtime);
86
+
87
+ auto sampleRate = static_cast<float>(options.getProperty(runtime, "sampleRate").getNumber());
88
+ auto bufferLength = static_cast<int>(options.getProperty(runtime, "bufferLengthInSamples").getNumber());
89
+
90
+ auto audioRecorderHostObject = std::make_shared<AudioRecorderHostObject>(&runtime, jsCallInvoker, sampleRate, bufferLength);
91
+
92
+ return jsi::Object::createFromHostObject(runtime, audioRecorderHostObject);
93
+ });
94
+ }
71
95
  };
72
96
 
73
97
  } // namespace audioapi
@@ -145,4 +145,5 @@ class AnalyserNodeHostObject : public AudioNodeHostObject {
145
145
  analyserNode->setWindowType(value.getString(runtime).utf8(runtime));
146
146
  }
147
147
  };
148
+
148
149
  } // namespace audioapi
@@ -0,0 +1,149 @@
1
+ #pragma once
2
+
3
+ #include <jsi/jsi.h>
4
+
5
+ #include <audioapi/core/sources/AudioBuffer.h>
6
+ #include <audioapi/HostObjects/AudioBufferHostObject.h>
7
+ #include <audioapi/core/inputs/AudioRecorder.h>
8
+
9
+ #ifdef ANDROID
10
+ #include <audioapi/android/core/AndroidAudioRecorder.h>
11
+ #else
12
+ #include <audioapi/ios/core/IOSAudioRecorder.h>
13
+ #endif
14
+
15
+ #include <memory>
16
+ #include <utility>
17
+ #include <vector>
18
+ #include <cstdio>
19
+
20
+ namespace audioapi {
21
+ using namespace facebook;
22
+
23
+ class AudioRecorderHostObject : public JsiHostObject {
24
+ public:
25
+ explicit AudioRecorderHostObject(
26
+ jsi::Runtime *runtime,
27
+ const std::shared_ptr<react::CallInvoker> &callInvoker,
28
+ float sampleRate,
29
+ int bufferLength)
30
+ : callInvoker_(callInvoker) {
31
+ promiseVendor_ = std::make_shared<PromiseVendor>(runtime, callInvoker);
32
+
33
+ #ifdef ANDROID
34
+ audioRecorder_ = std::make_shared<AndroidAudioRecorder>(
35
+ sampleRate,
36
+ bufferLength,
37
+ this->getOnError(),
38
+ this->getOnStatusChange(),
39
+ this->getOnAudioReady()
40
+ );
41
+ #else
42
+ audioRecorder_ = std::make_shared<IOSAudioRecorder>(
43
+ sampleRate,
44
+ bufferLength,
45
+ this->getOnError(),
46
+ this->getOnStatusChange(),
47
+ this->getOnAudioReady()
48
+ );
49
+ #endif
50
+
51
+ addFunctions(
52
+ JSI_EXPORT_FUNCTION(AudioRecorderHostObject, start),
53
+ JSI_EXPORT_FUNCTION(AudioRecorderHostObject, stop),
54
+ JSI_EXPORT_FUNCTION(AudioRecorderHostObject, onAudioReady),
55
+ JSI_EXPORT_FUNCTION(AudioRecorderHostObject, onError),
56
+ JSI_EXPORT_FUNCTION(AudioRecorderHostObject, onStatusChange));
57
+ }
58
+
59
+ ~AudioRecorderHostObject() override {
60
+ errorCallback_ = nullptr;
61
+ audioReadyCallback_ = nullptr;
62
+ statusChangeCallback_ = nullptr;
63
+ }
64
+
65
+ JSI_HOST_FUNCTION(start) {
66
+ audioRecorder_->start();
67
+
68
+ return jsi::Value::undefined();
69
+ }
70
+
71
+ JSI_HOST_FUNCTION(stop) {
72
+ audioRecorder_->stop();
73
+
74
+ return jsi::Value::undefined();
75
+ }
76
+
77
+ JSI_HOST_FUNCTION(onAudioReady) {
78
+ audioReadyCallback_ = std::make_unique<jsi::Function>(args[0].getObject(runtime).getFunction(runtime));
79
+
80
+ return jsi::Value::undefined();
81
+ }
82
+
83
+ JSI_HOST_FUNCTION(onError) {
84
+ errorCallback_ = std::make_unique<jsi::Function>(args[0].getObject(runtime).getFunction(runtime));
85
+
86
+ return jsi::Value::undefined();
87
+ }
88
+
89
+ JSI_HOST_FUNCTION(onStatusChange) {
90
+ statusChangeCallback_ = std::make_unique<jsi::Function>(args[0].getObject(runtime).getFunction(runtime));
91
+
92
+ return jsi::Value::undefined();
93
+ }
94
+
95
+ protected:
96
+ std::shared_ptr<AudioRecorder> audioRecorder_;
97
+ std::shared_ptr<PromiseVendor> promiseVendor_;
98
+ std::shared_ptr<react::CallInvoker> callInvoker_;
99
+
100
+ std::unique_ptr<jsi::Function> errorCallback_;
101
+ std::unique_ptr<jsi::Function> audioReadyCallback_;
102
+ std::unique_ptr<jsi::Function> statusChangeCallback_;
103
+
104
+ std::function<void(std::shared_ptr<AudioBus>, int, double)> getOnAudioReady() {
105
+ return [this](const std::shared_ptr<AudioBus> &bus, int numFrames, double when) {
106
+ if (audioReadyCallback_ == nullptr) {
107
+ return;
108
+ }
109
+
110
+ callInvoker_->invokeAsync([this, bus = bus, numFrames, when](jsi::Runtime &runtime) {
111
+ auto buffer = std::make_shared<AudioBuffer>(bus);
112
+ auto bufferHostObject = std::make_shared<AudioBufferHostObject>(buffer);
113
+
114
+ audioReadyCallback_->call(
115
+ runtime,
116
+ jsi::Object::createFromHostObject(runtime, bufferHostObject),
117
+ jsi::Value(numFrames),
118
+ jsi::Value(when)
119
+ );
120
+ });
121
+ };
122
+ }
123
+
124
+ std::function<void(void)> getOnError() {
125
+ return [this]() {
126
+ if (errorCallback_ == nullptr) {
127
+ return;
128
+ }
129
+
130
+ callInvoker_->invokeAsync([this](jsi::Runtime &runtime) {
131
+ errorCallback_->call(runtime);
132
+ });
133
+ };
134
+ }
135
+
136
+ std::function<void(void)> getOnStatusChange() {
137
+ return [this]() {
138
+ if (statusChangeCallback_ == nullptr) {
139
+ return;
140
+ }
141
+
142
+ callInvoker_->invokeAsync([this](jsi::Runtime &runtime) {
143
+ statusChangeCallback_->call(runtime);
144
+ });
145
+ };
146
+ }
147
+ };
148
+
149
+ } // namespace audioapi
@@ -18,9 +18,10 @@ AudioContext::AudioContext(float sampleRate) : BaseAudioContext() {
18
18
  std::make_shared<IOSAudioPlayer>(this->renderAudio(), sampleRate);
19
19
  #endif
20
20
 
21
- sampleRate_ = audioPlayer_->getSampleRate();
22
- audioDecoder_ = std::make_shared<AudioDecoder>(sampleRate_);
21
+ sampleRate_ = sampleRate;
22
+ audioDecoder_ = std::make_shared<AudioDecoder>(sampleRate);
23
23
 
24
+ state_ = ContextState::RUNNING;
24
25
  audioPlayer_->start();
25
26
  }
26
27
 
@@ -53,7 +54,7 @@ bool AudioContext::suspend() {
53
54
  }
54
55
 
55
56
  state_ = ContextState::SUSPENDED;
56
- audioPlayer_->suspend();
57
+ audioPlayer_->pause();
57
58
  return true;
58
59
  }
59
60
 
@@ -43,25 +43,25 @@ std::shared_ptr<AudioDestinationNode> BaseAudioContext::getDestination() {
43
43
 
44
44
  std::shared_ptr<OscillatorNode> BaseAudioContext::createOscillator() {
45
45
  auto oscillator = std::make_shared<OscillatorNode>(this);
46
- nodeManager_->addNode(oscillator);
46
+ nodeManager_->addSourceNode(oscillator);
47
47
  return oscillator;
48
48
  }
49
49
 
50
50
  std::shared_ptr<GainNode> BaseAudioContext::createGain() {
51
51
  auto gain = std::make_shared<GainNode>(this);
52
- nodeManager_->addNode(gain);
52
+ nodeManager_->addProcessingNode(gain);
53
53
  return gain;
54
54
  }
55
55
 
56
56
  std::shared_ptr<StereoPannerNode> BaseAudioContext::createStereoPanner() {
57
57
  auto stereoPanner = std::make_shared<StereoPannerNode>(this);
58
- nodeManager_->addNode(stereoPanner);
58
+ nodeManager_->addProcessingNode(stereoPanner);
59
59
  return stereoPanner;
60
60
  }
61
61
 
62
62
  std::shared_ptr<BiquadFilterNode> BaseAudioContext::createBiquadFilter() {
63
63
  auto biquadFilter = std::make_shared<BiquadFilterNode>(this);
64
- nodeManager_->addNode(biquadFilter);
64
+ nodeManager_->addProcessingNode(biquadFilter);
65
65
  return biquadFilter;
66
66
  }
67
67
 
@@ -69,7 +69,7 @@ std::shared_ptr<AudioBufferSourceNode> BaseAudioContext::createBufferSource(
69
69
  bool pitchCorrection) {
70
70
  auto bufferSource =
71
71
  std::make_shared<AudioBufferSourceNode>(this, pitchCorrection);
72
- nodeManager_->addNode(bufferSource);
72
+ nodeManager_->addSourceNode(bufferSource);
73
73
  return bufferSource;
74
74
  }
75
75
 
@@ -90,7 +90,7 @@ std::shared_ptr<PeriodicWave> BaseAudioContext::createPeriodicWave(
90
90
 
91
91
  std::shared_ptr<AnalyserNode> BaseAudioContext::createAnalyser() {
92
92
  auto analyser = std::make_shared<AnalyserNode>(this);
93
- nodeManager_->addNode(analyser);
93
+ nodeManager_->addProcessingNode(analyser);
94
94
  return analyser;
95
95
  }
96
96