react-native-audio-api 0.6.0-rc.0 → 0.6.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/CMakeLists.txt +6 -3
- package/android/build.gradle +1 -0
- package/android/src/main/java/com/swmansion/audioapi/AudioManagerModule.kt +15 -12
- package/android/src/main/java/com/swmansion/audioapi/system/AudioFocusListener.kt +60 -0
- package/android/src/main/java/com/swmansion/audioapi/system/LockScreenManager.kt +294 -0
- package/android/src/main/java/com/swmansion/audioapi/system/MediaNotificationManager.kt +279 -0
- package/android/src/main/java/com/swmansion/audioapi/system/MediaReceiver.kt +46 -0
- package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionCallback.kt +39 -0
- package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionEventEmitter.kt +84 -0
- package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionManager.kt +144 -0
- package/android/src/main/res/drawable/next.xml +9 -0
- package/android/src/main/res/drawable/pause.xml +9 -0
- package/android/src/main/res/drawable/play.xml +9 -0
- package/android/src/main/res/drawable/previous.xml +9 -0
- package/android/src/main/res/drawable/skip_backward_5.xml +9 -0
- package/android/src/main/res/drawable/skip_forward_5.xml +9 -0
- package/android/src/main/res/drawable/stop.xml +9 -0
- package/app.plugin.js +1 -0
- package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp +1 -6
- package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +8 -4
- package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +1 -0
- package/common/cpp/audioapi/core/utils/AudioNodeDestructor.cpp +3 -3
- package/ios/audioapi/ios/AudioManagerModule.mm +9 -7
- package/ios/audioapi/ios/system/LockScreenManager.mm +4 -8
- package/ios/audioapi/ios/system/NotificationManager.h +7 -1
- package/ios/audioapi/ios/system/NotificationManager.mm +66 -44
- package/lib/commonjs/api.js +197 -0
- package/lib/commonjs/api.js.map +1 -0
- package/lib/commonjs/api.web.js +219 -0
- package/lib/commonjs/api.web.js.map +1 -0
- package/lib/commonjs/core/AnalyserNode.js +71 -0
- package/lib/commonjs/core/AnalyserNode.js.map +1 -0
- package/lib/commonjs/core/AudioBuffer.js +44 -0
- package/lib/commonjs/core/AudioBuffer.js.map +1 -0
- package/lib/commonjs/core/AudioBufferSourceNode.js +68 -0
- package/lib/commonjs/core/AudioBufferSourceNode.js.map +1 -0
- package/lib/commonjs/core/AudioContext.js +29 -0
- package/lib/commonjs/core/AudioContext.js.map +1 -0
- package/lib/commonjs/core/AudioDestinationNode.js +11 -0
- package/lib/commonjs/core/AudioDestinationNode.js.map +1 -0
- package/lib/commonjs/core/AudioNode.js +30 -0
- package/lib/commonjs/core/AudioNode.js.map +1 -0
- package/lib/commonjs/core/AudioParam.js +82 -0
- package/lib/commonjs/core/AudioParam.js.map +1 -0
- package/lib/commonjs/core/AudioScheduledSourceNode.js +38 -0
- package/lib/commonjs/core/AudioScheduledSourceNode.js.map +1 -0
- package/lib/commonjs/core/BaseAudioContext.js +80 -0
- package/lib/commonjs/core/BaseAudioContext.js.map +1 -0
- package/lib/commonjs/core/BiquadFilterNode.js +33 -0
- package/lib/commonjs/core/BiquadFilterNode.js.map +1 -0
- package/lib/commonjs/core/GainNode.js +17 -0
- package/lib/commonjs/core/GainNode.js.map +1 -0
- package/lib/commonjs/core/OfflineAudioContext.js +63 -0
- package/lib/commonjs/core/OfflineAudioContext.js.map +1 -0
- package/lib/commonjs/core/OscillatorNode.js +32 -0
- package/lib/commonjs/core/OscillatorNode.js.map +1 -0
- package/lib/commonjs/core/PeriodicWave.js +15 -0
- package/lib/commonjs/core/PeriodicWave.js.map +1 -0
- package/lib/commonjs/core/StereoPannerNode.js +17 -0
- package/lib/commonjs/core/StereoPannerNode.js.map +1 -0
- package/lib/commonjs/errors/IndexSizeError.js +14 -0
- package/lib/commonjs/errors/IndexSizeError.js.map +1 -0
- package/lib/commonjs/errors/InvalidAccessError.js +14 -0
- package/lib/commonjs/errors/InvalidAccessError.js.map +1 -0
- package/lib/commonjs/errors/InvalidStateError.js +14 -0
- package/lib/commonjs/errors/InvalidStateError.js.map +1 -0
- package/lib/commonjs/errors/NotSupportedError.js +14 -0
- package/lib/commonjs/errors/NotSupportedError.js.map +1 -0
- package/lib/commonjs/errors/RangeError.js +14 -0
- package/lib/commonjs/errors/RangeError.js.map +1 -0
- package/lib/commonjs/errors/index.js +42 -0
- package/lib/commonjs/errors/index.js.map +1 -0
- package/lib/commonjs/index.js +17 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/interfaces.js +6 -0
- package/lib/commonjs/interfaces.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/plugin/withAudioAPI.js +62 -0
- package/lib/commonjs/plugin/withAudioAPI.js.map +1 -0
- package/lib/commonjs/specs/NativeAudioAPIModule.js +9 -0
- package/lib/commonjs/specs/NativeAudioAPIModule.js.map +1 -0
- package/lib/commonjs/specs/NativeAudioManagerModule.js +33 -0
- package/lib/commonjs/specs/NativeAudioManagerModule.js.map +1 -0
- package/lib/commonjs/specs/index.js +27 -0
- package/lib/commonjs/specs/index.js.map +1 -0
- package/lib/commonjs/system/AudioManager.js +79 -0
- package/lib/commonjs/system/AudioManager.js.map +1 -0
- package/lib/commonjs/system/index.js +14 -0
- package/lib/commonjs/system/index.js.map +1 -0
- package/lib/commonjs/system/types.js +2 -0
- package/lib/commonjs/system/types.js.map +1 -0
- package/lib/commonjs/types.js +2 -0
- package/lib/commonjs/types.js.map +1 -0
- package/lib/commonjs/utils/index.js +10 -0
- package/lib/commonjs/utils/index.js.map +1 -0
- package/lib/commonjs/web-core/AnalyserNode.js +38 -0
- package/lib/commonjs/web-core/AnalyserNode.js.map +1 -0
- package/lib/commonjs/web-core/AudioBuffer.js +44 -0
- package/lib/commonjs/web-core/AudioBuffer.js.map +1 -0
- package/lib/commonjs/web-core/AudioBufferSourceNode.js +214 -0
- package/lib/commonjs/web-core/AudioBufferSourceNode.js.map +1 -0
- package/lib/commonjs/web-core/AudioContext.js +93 -0
- package/lib/commonjs/web-core/AudioContext.js.map +1 -0
- package/lib/commonjs/web-core/AudioDestinationNode.js +11 -0
- package/lib/commonjs/web-core/AudioDestinationNode.js.map +1 -0
- package/lib/commonjs/web-core/AudioNode.js +33 -0
- package/lib/commonjs/web-core/AudioNode.js.map +1 -0
- package/lib/commonjs/web-core/AudioParam.js +81 -0
- package/lib/commonjs/web-core/AudioParam.js.map +1 -0
- package/lib/commonjs/web-core/AudioScheduledSourceNode.js +41 -0
- package/lib/commonjs/web-core/AudioScheduledSourceNode.js.map +1 -0
- package/lib/commonjs/web-core/BaseAudioContext.js +2 -0
- package/lib/commonjs/web-core/BaseAudioContext.js.map +1 -0
- package/lib/commonjs/web-core/BiquadFilterNode.js +33 -0
- package/lib/commonjs/web-core/BiquadFilterNode.js.map +1 -0
- package/lib/commonjs/web-core/GainNode.js +17 -0
- package/lib/commonjs/web-core/GainNode.js.map +1 -0
- package/lib/commonjs/web-core/OfflineAudioContext.js +96 -0
- package/lib/commonjs/web-core/OfflineAudioContext.js.map +1 -0
- package/lib/commonjs/web-core/OscillatorNode.js +31 -0
- package/lib/commonjs/web-core/OscillatorNode.js.map +1 -0
- package/lib/commonjs/web-core/PeriodicWave.js +15 -0
- package/lib/commonjs/web-core/PeriodicWave.js.map +1 -0
- package/lib/commonjs/web-core/StereoPannerNode.js +17 -0
- package/lib/commonjs/web-core/StereoPannerNode.js.map +1 -0
- package/lib/commonjs/web-core/custom/LoadCustomWasm.js +37 -0
- package/lib/commonjs/web-core/custom/LoadCustomWasm.js.map +1 -0
- package/lib/commonjs/web-core/custom/index.js +14 -0
- package/lib/commonjs/web-core/custom/index.js.map +1 -0
- package/lib/commonjs/web-core/custom/signalsmithStretch/LICENSE.txt +21 -0
- package/lib/commonjs/web-core/custom/signalsmithStretch/README.md +46 -0
- package/lib/commonjs/web-core/custom/signalsmithStretch/SignalsmithStretch.mjs +826 -0
- package/lib/commonjs/web-core/custom/signalsmithStretch/SignalsmithStretch.mjs.map +1 -0
- package/lib/module/plugin/withAudioAPI.js +58 -0
- package/lib/module/plugin/withAudioAPI.js.map +1 -0
- package/lib/module/specs/NativeAudioManagerModule.js +5 -6
- package/lib/module/specs/NativeAudioManagerModule.js.map +1 -1
- package/lib/module/system/AudioManager.js +9 -0
- package/lib/module/system/AudioManager.js.map +1 -1
- package/lib/typescript/plugin/withAudioAPI.d.ts +9 -0
- package/lib/typescript/plugin/withAudioAPI.d.ts.map +1 -0
- package/lib/typescript/specs/NativeAudioManagerModule.d.ts +2 -1
- package/lib/typescript/specs/NativeAudioManagerModule.d.ts.map +1 -1
- package/lib/typescript/system/AudioManager.d.ts +4 -2
- package/lib/typescript/system/AudioManager.d.ts.map +1 -1
- package/lib/typescript/system/types.d.ts +16 -4
- package/lib/typescript/system/types.d.ts.map +1 -1
- package/package.json +6 -3
- package/src/plugin/withAudioAPI.ts +90 -0
- package/src/specs/NativeAudioManagerModule.ts +8 -11
- package/src/system/AudioManager.ts +42 -15
- package/src/system/types.ts +20 -4
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
package com.swmansion.audioapi.system
|
|
2
|
+
|
|
3
|
+
import android.annotation.SuppressLint
|
|
4
|
+
import android.app.Notification
|
|
5
|
+
import android.app.PendingIntent
|
|
6
|
+
import android.app.Service
|
|
7
|
+
import android.content.Intent
|
|
8
|
+
import android.content.res.Resources
|
|
9
|
+
import android.os.Binder
|
|
10
|
+
import android.os.Build
|
|
11
|
+
import android.os.IBinder
|
|
12
|
+
import android.provider.ContactsContract
|
|
13
|
+
import android.support.v4.media.session.PlaybackStateCompat
|
|
14
|
+
import android.util.Log
|
|
15
|
+
import android.view.KeyEvent
|
|
16
|
+
import androidx.core.app.NotificationCompat
|
|
17
|
+
import androidx.core.app.NotificationManagerCompat
|
|
18
|
+
import androidx.core.content.ContextCompat
|
|
19
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
20
|
+
import com.swmansion.audioapi.R
|
|
21
|
+
import java.lang.ref.WeakReference
|
|
22
|
+
|
|
23
|
+
class MediaNotificationManager(
|
|
24
|
+
val reactContext: ReactApplicationContext,
|
|
25
|
+
val notificationId: Int,
|
|
26
|
+
val channelId: String,
|
|
27
|
+
) {
|
|
28
|
+
private var smallIcon: Int = R.drawable.play
|
|
29
|
+
private var customIcon: Int = 0
|
|
30
|
+
|
|
31
|
+
private var play: NotificationCompat.Action? = null
|
|
32
|
+
private var pause: NotificationCompat.Action? = null
|
|
33
|
+
private var stop: NotificationCompat.Action? = null
|
|
34
|
+
private var next: NotificationCompat.Action? = null
|
|
35
|
+
private var previous: NotificationCompat.Action? = null
|
|
36
|
+
private var skipForward: NotificationCompat.Action? = null
|
|
37
|
+
private var skipBackward: NotificationCompat.Action? = null
|
|
38
|
+
|
|
39
|
+
companion object {
|
|
40
|
+
const val REMOVE_NOTIFICATION: String = "audio_manager_remove_notification"
|
|
41
|
+
const val PACKAGE_NAME: String = "com.swmansion.audioapi.system"
|
|
42
|
+
const val MEDIA_BUTTON: String = "audio_manager_media_button"
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@SuppressLint("RestrictedApi")
|
|
46
|
+
@Synchronized
|
|
47
|
+
fun prepareNotification(
|
|
48
|
+
builder: NotificationCompat.Builder,
|
|
49
|
+
isPlaying: Boolean,
|
|
50
|
+
): Notification {
|
|
51
|
+
builder.mActions.clear()
|
|
52
|
+
|
|
53
|
+
if (previous != null) {
|
|
54
|
+
builder.addAction(previous)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (skipBackward != null) {
|
|
58
|
+
builder.addAction(skipBackward)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (play != null && !isPlaying) {
|
|
62
|
+
builder.addAction(play)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (pause != null && isPlaying) {
|
|
66
|
+
builder.addAction(pause)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (stop != null) {
|
|
70
|
+
builder.addAction(stop)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (next != null) {
|
|
74
|
+
builder.addAction(next)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (skipForward != null) {
|
|
78
|
+
builder.addAction(skipForward)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
builder.setSmallIcon(if (customIcon != 0) customIcon else smallIcon)
|
|
82
|
+
|
|
83
|
+
val packageName: String = reactContext.packageName
|
|
84
|
+
val openApp: Intent? = reactContext.packageManager.getLaunchIntentForPackage(packageName)
|
|
85
|
+
try {
|
|
86
|
+
builder.setContentIntent(
|
|
87
|
+
PendingIntent.getActivity(
|
|
88
|
+
reactContext,
|
|
89
|
+
0,
|
|
90
|
+
openApp,
|
|
91
|
+
PendingIntent.FLAG_IMMUTABLE,
|
|
92
|
+
),
|
|
93
|
+
)
|
|
94
|
+
} catch (e: Exception) {
|
|
95
|
+
Log.w("AudioManagerModule", "Error creating content intent: ${e.message}")
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
val remove = Intent(REMOVE_NOTIFICATION)
|
|
99
|
+
remove.putExtra(PACKAGE_NAME, reactContext.applicationInfo.packageName)
|
|
100
|
+
builder.setDeleteIntent(
|
|
101
|
+
PendingIntent.getBroadcast(
|
|
102
|
+
reactContext,
|
|
103
|
+
0,
|
|
104
|
+
remove,
|
|
105
|
+
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT,
|
|
106
|
+
),
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
return builder.build()
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
@SuppressLint("MissingPermission")
|
|
113
|
+
@Synchronized
|
|
114
|
+
fun show(
|
|
115
|
+
builder: NotificationCompat.Builder?,
|
|
116
|
+
isPlaying: Boolean,
|
|
117
|
+
) {
|
|
118
|
+
NotificationManagerCompat.from(reactContext).notify(
|
|
119
|
+
notificationId,
|
|
120
|
+
prepareNotification(
|
|
121
|
+
builder!!,
|
|
122
|
+
isPlaying,
|
|
123
|
+
),
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
fun hide() {
|
|
128
|
+
NotificationManagerCompat.from(reactContext).cancel(notificationId)
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
val myIntent =
|
|
132
|
+
Intent(
|
|
133
|
+
reactContext,
|
|
134
|
+
NotificationService::class.java,
|
|
135
|
+
)
|
|
136
|
+
reactContext.stopService(myIntent)
|
|
137
|
+
} catch (e: java.lang.Exception) {
|
|
138
|
+
Log.w("AudioManagerModule", "Error stopping service: ${e.message}")
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
@Synchronized
|
|
143
|
+
fun updateActions(mask: Long) {
|
|
144
|
+
play = createAction("play", "Play", mask, PlaybackStateCompat.ACTION_PLAY, play)
|
|
145
|
+
pause = createAction("pause", "Pause", mask, PlaybackStateCompat.ACTION_PAUSE, pause)
|
|
146
|
+
stop = createAction("stop", "Stop", mask, PlaybackStateCompat.ACTION_STOP, stop)
|
|
147
|
+
next = createAction("next", "Next", mask, PlaybackStateCompat.ACTION_SKIP_TO_NEXT, next)
|
|
148
|
+
previous =
|
|
149
|
+
createAction(
|
|
150
|
+
"previous",
|
|
151
|
+
"Previous",
|
|
152
|
+
mask,
|
|
153
|
+
PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS,
|
|
154
|
+
previous,
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
skipForward =
|
|
158
|
+
createAction(
|
|
159
|
+
"skip_forward_5",
|
|
160
|
+
"Skip Forward",
|
|
161
|
+
mask,
|
|
162
|
+
PlaybackStateCompat.ACTION_FAST_FORWARD,
|
|
163
|
+
skipForward,
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
skipBackward =
|
|
167
|
+
createAction(
|
|
168
|
+
"skip_backward_5",
|
|
169
|
+
"Skip Backward",
|
|
170
|
+
mask,
|
|
171
|
+
PlaybackStateCompat.ACTION_REWIND,
|
|
172
|
+
skipBackward,
|
|
173
|
+
)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
private fun createAction(
|
|
177
|
+
iconName: String,
|
|
178
|
+
title: String,
|
|
179
|
+
mask: Long,
|
|
180
|
+
action: Long,
|
|
181
|
+
oldAction: NotificationCompat.Action?,
|
|
182
|
+
): NotificationCompat.Action? {
|
|
183
|
+
if ((mask and action) == 0L) {
|
|
184
|
+
return null
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (oldAction != null) {
|
|
188
|
+
return oldAction
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
val r: Resources = reactContext.resources
|
|
192
|
+
val packageName: String = reactContext.packageName
|
|
193
|
+
val icon = r.getIdentifier(iconName, "drawable", packageName)
|
|
194
|
+
|
|
195
|
+
val keyCode = PlaybackStateCompat.toKeyCode(action)
|
|
196
|
+
val intent = Intent(MEDIA_BUTTON)
|
|
197
|
+
intent.putExtra(Intent.EXTRA_KEY_EVENT, KeyEvent(KeyEvent.ACTION_DOWN, keyCode))
|
|
198
|
+
intent.putExtra(ContactsContract.Directory.PACKAGE_NAME, packageName)
|
|
199
|
+
val i =
|
|
200
|
+
PendingIntent.getBroadcast(
|
|
201
|
+
reactContext,
|
|
202
|
+
keyCode,
|
|
203
|
+
intent,
|
|
204
|
+
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT,
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
return NotificationCompat.Action(icon, title, i)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
inner class NotificationService : Service() {
|
|
211
|
+
private val binder = LocalBinder()
|
|
212
|
+
private var notification: Notification? = null
|
|
213
|
+
|
|
214
|
+
inner class LocalBinder : Binder() {
|
|
215
|
+
private var weakService: WeakReference<NotificationService>? = null
|
|
216
|
+
|
|
217
|
+
fun onBind(service: NotificationService) {
|
|
218
|
+
weakService = WeakReference(service)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
fun getService(): NotificationService? = weakService?.get()
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
override fun onBind(intent: Intent): IBinder {
|
|
225
|
+
binder.onBind(this)
|
|
226
|
+
return binder
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
fun forceForeground() {
|
|
230
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
231
|
+
val intent = Intent(this, NotificationService::class.java)
|
|
232
|
+
ContextCompat.startForegroundService(this, intent)
|
|
233
|
+
notification =
|
|
234
|
+
MediaNotificationManager(reactContext, notificationId, channelId)
|
|
235
|
+
.prepareNotification(NotificationCompat.Builder(this, channelId), false)
|
|
236
|
+
startForeground(notificationId, notification)
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
override fun onCreate() {
|
|
241
|
+
super.onCreate()
|
|
242
|
+
try {
|
|
243
|
+
notification =
|
|
244
|
+
MediaNotificationManager(reactContext, notificationId, channelId)
|
|
245
|
+
.prepareNotification(NotificationCompat.Builder(this, channelId), false)
|
|
246
|
+
startForeground(notificationId, notification)
|
|
247
|
+
} catch (ex: Exception) {
|
|
248
|
+
Log.w("AudioManagerModule", "Error starting service: ${ex.message}")
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
override fun onStartCommand(
|
|
253
|
+
intent: Intent?,
|
|
254
|
+
flags: Int,
|
|
255
|
+
startId: Int,
|
|
256
|
+
): Int {
|
|
257
|
+
onCreate()
|
|
258
|
+
return START_NOT_STICKY
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
override fun onTaskRemoved(rootIntent: Intent?) {
|
|
262
|
+
super.onTaskRemoved(rootIntent)
|
|
263
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
264
|
+
stopForeground(STOP_FOREGROUND_REMOVE)
|
|
265
|
+
}
|
|
266
|
+
stopSelf()
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
override fun onDestroy() {
|
|
270
|
+
super.onDestroy()
|
|
271
|
+
|
|
272
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
273
|
+
stopForeground(STOP_FOREGROUND_REMOVE)
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
stopSelf()
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
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.media.AudioManager
|
|
7
|
+
import android.view.KeyEvent
|
|
8
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
9
|
+
|
|
10
|
+
class MediaReceiver(
|
|
11
|
+
val reactContext: ReactApplicationContext,
|
|
12
|
+
private val mediaSessionManager: MediaSessionManager,
|
|
13
|
+
) : BroadcastReceiver() {
|
|
14
|
+
override fun onReceive(
|
|
15
|
+
context: Context?,
|
|
16
|
+
intent: Intent?,
|
|
17
|
+
) {
|
|
18
|
+
val action = intent!!.action
|
|
19
|
+
|
|
20
|
+
if (MediaNotificationManager.REMOVE_NOTIFICATION == action) {
|
|
21
|
+
if (!checkApp(intent)) return
|
|
22
|
+
|
|
23
|
+
mediaSessionManager.mediaNotificationManager.hide()
|
|
24
|
+
mediaSessionManager.mediaSession.isActive = false
|
|
25
|
+
|
|
26
|
+
mediaSessionManager.eventEmitter.sendEvent("onCloseNotification", null)
|
|
27
|
+
} else if (MediaNotificationManager.MEDIA_BUTTON == action || Intent.ACTION_MEDIA_BUTTON == action) {
|
|
28
|
+
if (!intent.hasExtra(Intent.EXTRA_KEY_EVENT)) return
|
|
29
|
+
if (!checkApp(intent)) return
|
|
30
|
+
|
|
31
|
+
val keyEvent = intent.getParcelableExtra<KeyEvent>(Intent.EXTRA_KEY_EVENT)
|
|
32
|
+
mediaSessionManager.mediaSession.controller.dispatchMediaButtonEvent(keyEvent)
|
|
33
|
+
} else if (AudioManager.ACTION_AUDIO_BECOMING_NOISY == action) {
|
|
34
|
+
mediaSessionManager.mediaSession.controller.transportControls
|
|
35
|
+
.pause()
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private fun checkApp(intent: Intent): Boolean {
|
|
40
|
+
if (intent.hasExtra(MediaNotificationManager.PACKAGE_NAME)) {
|
|
41
|
+
val name = intent.getStringExtra(MediaNotificationManager.PACKAGE_NAME)
|
|
42
|
+
if (!reactContext.packageName.equals(name)) return false
|
|
43
|
+
}
|
|
44
|
+
return true
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
package com.swmansion.audioapi.system
|
|
2
|
+
|
|
3
|
+
import android.support.v4.media.session.MediaSessionCompat
|
|
4
|
+
import android.support.v4.media.session.PlaybackStateCompat
|
|
5
|
+
|
|
6
|
+
class MediaSessionCallback(
|
|
7
|
+
val eventEmitter: MediaSessionEventEmitter,
|
|
8
|
+
private val lockScreenManager: LockScreenManager,
|
|
9
|
+
) : MediaSessionCompat.Callback() {
|
|
10
|
+
override fun onPlay() {
|
|
11
|
+
lockScreenManager.updatePlaybackState(PlaybackStateCompat.STATE_PLAYING)
|
|
12
|
+
eventEmitter.onPlay()
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
override fun onPause() {
|
|
16
|
+
lockScreenManager.updatePlaybackState(PlaybackStateCompat.STATE_PAUSED)
|
|
17
|
+
eventEmitter.onPause()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
override fun onStop() {
|
|
21
|
+
eventEmitter.onStop()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
override fun onSkipToNext() {
|
|
25
|
+
eventEmitter.onSkipToNext()
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
override fun onSkipToPrevious() {
|
|
29
|
+
eventEmitter.onSkipToPrevious()
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
override fun onFastForward() {
|
|
33
|
+
eventEmitter.onFastForward()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
override fun onRewind() {
|
|
37
|
+
eventEmitter.onRewind()
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
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
|
+
private fun stopForegroundService() {
|
|
77
|
+
NotificationManagerCompat.from(reactContext).cancel(notificationId)
|
|
78
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
79
|
+
val myIntent =
|
|
80
|
+
Intent(reactContext, MediaNotificationManager.NotificationService::class.java)
|
|
81
|
+
reactContext.stopService(myIntent)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
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
|
+
class MediaSessionManager(
|
|
22
|
+
val reactContext: ReactApplicationContext,
|
|
23
|
+
) {
|
|
24
|
+
val notificationId = 100
|
|
25
|
+
val channelId = "react-native-audio-api"
|
|
26
|
+
|
|
27
|
+
private val audioManager: AudioManager = reactContext.getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
|
28
|
+
val mediaSession: MediaSessionCompat = MediaSessionCompat(reactContext, "MediaSessionManager")
|
|
29
|
+
val mediaNotificationManager: MediaNotificationManager
|
|
30
|
+
private val lockScreenManager: LockScreenManager
|
|
31
|
+
val eventEmitter: MediaSessionEventEmitter =
|
|
32
|
+
MediaSessionEventEmitter(reactContext, notificationId)
|
|
33
|
+
private val audioFocusListener: AudioFocusListener
|
|
34
|
+
private val mediaReceiver: MediaReceiver =
|
|
35
|
+
MediaReceiver(reactContext, this)
|
|
36
|
+
|
|
37
|
+
private val connection =
|
|
38
|
+
object : ServiceConnection {
|
|
39
|
+
override fun onServiceConnected(
|
|
40
|
+
name: ComponentName,
|
|
41
|
+
service: IBinder,
|
|
42
|
+
) {
|
|
43
|
+
Log.w("MediaSessionManager", "onServiceConnected")
|
|
44
|
+
val binder = service as MediaNotificationManager.NotificationService.LocalBinder
|
|
45
|
+
val notificationService = binder.getService()
|
|
46
|
+
notificationService?.forceForeground()
|
|
47
|
+
reactContext.unbindService(this)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
override fun onServiceDisconnected(name: ComponentName) {
|
|
51
|
+
Log.w("MediaSessionManager", "Service is disconnected.")
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
override fun onBindingDied(name: ComponentName) {
|
|
55
|
+
Log.w("MediaSessionManager", "Binding has died.")
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
override fun onNullBinding(name: ComponentName) {
|
|
59
|
+
Log.w("MediaSessionManager", "Bind was null.")
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
init {
|
|
64
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
65
|
+
createChannel()
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
this.mediaNotificationManager = MediaNotificationManager(reactContext, notificationId, channelId)
|
|
69
|
+
this.lockScreenManager = LockScreenManager(reactContext, mediaSession, mediaNotificationManager, channelId)
|
|
70
|
+
this.mediaSession.setCallback(MediaSessionCallback(eventEmitter, lockScreenManager))
|
|
71
|
+
|
|
72
|
+
val filter = IntentFilter()
|
|
73
|
+
filter.addAction(MediaNotificationManager.REMOVE_NOTIFICATION)
|
|
74
|
+
filter.addAction(MediaNotificationManager.MEDIA_BUTTON)
|
|
75
|
+
filter.addAction(Intent.ACTION_MEDIA_BUTTON)
|
|
76
|
+
filter.addAction(AudioManager.ACTION_AUDIO_BECOMING_NOISY)
|
|
77
|
+
|
|
78
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
79
|
+
reactContext.registerReceiver(mediaReceiver, filter, Context.RECEIVER_EXPORTED)
|
|
80
|
+
} else {
|
|
81
|
+
ContextCompat.registerReceiver(
|
|
82
|
+
reactContext,
|
|
83
|
+
mediaReceiver,
|
|
84
|
+
filter,
|
|
85
|
+
ContextCompat.RECEIVER_NOT_EXPORTED,
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
this.audioFocusListener = AudioFocusListener(audioManager, eventEmitter, lockScreenManager)
|
|
90
|
+
|
|
91
|
+
val myIntent = Intent(reactContext, MediaNotificationManager.NotificationService::class.java)
|
|
92
|
+
|
|
93
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
94
|
+
try {
|
|
95
|
+
reactContext.bindService(myIntent, connection, Context.BIND_AUTO_CREATE)
|
|
96
|
+
} catch (ignored: Exception) {
|
|
97
|
+
ContextCompat.startForegroundService(reactContext, myIntent)
|
|
98
|
+
}
|
|
99
|
+
} else {
|
|
100
|
+
reactContext.startService(myIntent)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
fun setLockScreenInfo(info: ReadableMap?) {
|
|
105
|
+
lockScreenManager.setLockScreenInfo(info)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
fun resetLockScreenInfo() {
|
|
109
|
+
lockScreenManager.resetLockScreenInfo()
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
fun enableRemoteCommand(
|
|
113
|
+
name: String,
|
|
114
|
+
enabled: Boolean,
|
|
115
|
+
) {
|
|
116
|
+
lockScreenManager.enableRemoteCommand(name, enabled)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
fun getDevicePreferredSampleRate(): Double {
|
|
120
|
+
val sampleRate = this.audioManager.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE)
|
|
121
|
+
return sampleRate.toDouble()
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
fun observeAudioInterruptions(observe: Boolean) {
|
|
125
|
+
if (observe) {
|
|
126
|
+
audioFocusListener.requestAudioFocus()
|
|
127
|
+
} else {
|
|
128
|
+
audioFocusListener.abandonAudioFocus()
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
@RequiresApi(Build.VERSION_CODES.O)
|
|
133
|
+
private fun createChannel() {
|
|
134
|
+
val notificationManager =
|
|
135
|
+
reactContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
|
136
|
+
|
|
137
|
+
val mChannel =
|
|
138
|
+
NotificationChannel(channelId, "Audio manager", NotificationManager.IMPORTANCE_LOW)
|
|
139
|
+
mChannel.description = "Audio manager"
|
|
140
|
+
mChannel.setShowBadge(false)
|
|
141
|
+
mChannel.lockscreenVisibility = NotificationCompat.VISIBILITY_PUBLIC
|
|
142
|
+
notificationManager.createNotificationChannel(mChannel)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -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');
|
|
@@ -128,12 +128,7 @@ void AudioBufferSourceNode::start(double when, double offset, double duration) {
|
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
void AudioBufferSourceNode::disable() {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
if (onendedCallback_) {
|
|
134
|
-
onendedCallback_(getStopTime());
|
|
135
|
-
}
|
|
136
|
-
|
|
131
|
+
AudioScheduledSourceNode::disable();
|
|
137
132
|
alignedBus_.reset();
|
|
138
133
|
}
|
|
139
134
|
|