expo-audio 0.3.4 → 0.3.5
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/CHANGELOG.md +6 -0
- package/android/build.gradle +2 -2
- package/android/src/main/java/expo/modules/audio/AudioModule.kt +27 -14
- package/android/src/main/java/expo/modules/audio/AudioPlayer.kt +44 -31
- package/android/src/main/java/expo/modules/audio/AudioRecorder.kt +44 -43
- package/android/src/main/java/expo/modules/audio/AudioRecords.kt +1 -1
- package/build/Audio.types.d.ts +19 -0
- package/build/Audio.types.d.ts.map +1 -1
- package/build/Audio.types.js.map +1 -1
- package/ios/AudioRecords.swift +2 -2
- package/package.json +3 -3
- package/src/Audio.types.ts +19 -0
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,10 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 0.3.5 — 2025-02-19
|
|
14
|
+
|
|
15
|
+
_This version does not introduce any user-facing changes._
|
|
16
|
+
|
|
13
17
|
## 0.3.4 — 2025-01-19
|
|
14
18
|
|
|
15
19
|
### 💡 Others
|
|
@@ -30,6 +34,8 @@
|
|
|
30
34
|
- On `Android`, allow player to accept a `null` audio source. ([#33854](https://github.com/expo/expo/pull/33854) by [@alanjhughes](https://github.com/alanjhughes))
|
|
31
35
|
- Override the `replace` method on the `AudioPlayer` so the source can be parsed correctly. ([#33708](https://github.com/expo/expo/pull/33708) by [@alanjhughes](https://github.com/alanjhughes))
|
|
32
36
|
- [Android] Remove unused `setAudioMode()` parameters. ([#34031](https://github.com/expo/expo/pull/34031) by [@alanjhughes](https://github.com/alanjhughes))
|
|
37
|
+
- [Android] Improvements in recording handling. ([#34841](https://github.com/expo/expo/pull/34841) by [@alanjhughes](https://github.com/alanjhughes))
|
|
38
|
+
- Fix `AudioMode` defaults. ([#34920](https://github.com/expo/expo/pull/34920) by [@alanjhughes](https://github.com/alanjhughes))
|
|
33
39
|
|
|
34
40
|
## 0.3.1 — 2024-12-16
|
|
35
41
|
|
package/android/build.gradle
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
apply plugin: 'com.android.library'
|
|
2
2
|
|
|
3
3
|
group = 'expo.modules.audio'
|
|
4
|
-
version = '0.3.
|
|
4
|
+
version = '0.3.5'
|
|
5
5
|
|
|
6
6
|
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
|
|
7
7
|
apply from: expoModulesCorePlugin
|
|
@@ -14,7 +14,7 @@ android {
|
|
|
14
14
|
namespace "expo.modules.audio"
|
|
15
15
|
defaultConfig {
|
|
16
16
|
versionCode 1
|
|
17
|
-
versionName "0.3.
|
|
17
|
+
versionName "0.3.5"
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
compileOptions {
|
|
@@ -33,6 +33,7 @@ import expo.modules.kotlin.modules.ModuleDefinition
|
|
|
33
33
|
import kotlinx.coroutines.launch
|
|
34
34
|
import kotlinx.coroutines.runBlocking
|
|
35
35
|
import okhttp3.OkHttpClient
|
|
36
|
+
import java.io.File
|
|
36
37
|
import kotlin.math.min
|
|
37
38
|
|
|
38
39
|
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
|
@@ -313,7 +314,7 @@ class AudioModule : Module() {
|
|
|
313
314
|
}
|
|
314
315
|
|
|
315
316
|
Property("uri") { ref ->
|
|
316
|
-
ref.
|
|
317
|
+
ref.filePath
|
|
317
318
|
}
|
|
318
319
|
|
|
319
320
|
Property("isRecording") { ref ->
|
|
@@ -321,7 +322,7 @@ class AudioModule : Module() {
|
|
|
321
322
|
}
|
|
322
323
|
|
|
323
324
|
Property("currentTime") { ref ->
|
|
324
|
-
ref.
|
|
325
|
+
ref.startTime
|
|
325
326
|
}
|
|
326
327
|
|
|
327
328
|
AsyncFunction("prepareToRecordAsync") { ref: AudioRecorder, options: RecordingOptions? ->
|
|
@@ -331,7 +332,9 @@ class AudioModule : Module() {
|
|
|
331
332
|
|
|
332
333
|
Function("record") { ref: AudioRecorder ->
|
|
333
334
|
checkRecordingPermission()
|
|
334
|
-
ref.
|
|
335
|
+
if (!ref.isPrepared) {
|
|
336
|
+
ref.record()
|
|
337
|
+
}
|
|
335
338
|
}
|
|
336
339
|
|
|
337
340
|
Function("pause") { ref: AudioRecorder ->
|
|
@@ -345,7 +348,11 @@ class AudioModule : Module() {
|
|
|
345
348
|
}
|
|
346
349
|
|
|
347
350
|
Function("getStatus") { ref: AudioRecorder ->
|
|
348
|
-
|
|
351
|
+
try {
|
|
352
|
+
return@Function ref.getAudioRecorderStatus()
|
|
353
|
+
} catch (e: Exception) {
|
|
354
|
+
throw e
|
|
355
|
+
}
|
|
349
356
|
}
|
|
350
357
|
|
|
351
358
|
AsyncFunction("getCurrentInput") { ref: AudioRecorder ->
|
|
@@ -362,16 +369,24 @@ class AudioModule : Module() {
|
|
|
362
369
|
}
|
|
363
370
|
}
|
|
364
371
|
|
|
365
|
-
private fun createMediaItem(source: AudioSource?): MediaSource? = source?.let {
|
|
366
|
-
val factory = createDataSourceFactory(
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
372
|
+
private fun createMediaItem(source: AudioSource?): MediaSource? = source?.uri?.let { uri ->
|
|
373
|
+
val factory = createDataSourceFactory(source)
|
|
374
|
+
val uri = if (Util.isLocalFileUri(Uri.parse(source.uri))) {
|
|
375
|
+
Uri.fromFile(File(source.uri))
|
|
376
|
+
} else {
|
|
377
|
+
Uri.parse(source.uri)
|
|
370
378
|
}
|
|
379
|
+
val item = MediaItem.fromUri(uri)
|
|
380
|
+
buildMediaSourceFactory(factory, item)
|
|
371
381
|
}
|
|
372
382
|
|
|
373
383
|
private fun createDataSourceFactory(audioSource: AudioSource): DataSource.Factory {
|
|
374
|
-
val
|
|
384
|
+
val uri = if (Util.isLocalFileUri(Uri.parse(audioSource.uri))) {
|
|
385
|
+
Uri.fromFile(File(audioSource.uri))
|
|
386
|
+
} else {
|
|
387
|
+
Uri.parse(audioSource.uri)
|
|
388
|
+
}
|
|
389
|
+
val isLocal = Util.isLocalFileUri(uri)
|
|
375
390
|
return if (isLocal) {
|
|
376
391
|
DefaultDataSource.Factory(context)
|
|
377
392
|
} else {
|
|
@@ -379,7 +394,6 @@ class AudioModule : Module() {
|
|
|
379
394
|
audioSource.headers?.let { headers ->
|
|
380
395
|
setDefaultRequestProperties(headers)
|
|
381
396
|
}
|
|
382
|
-
DefaultDataSource.Factory(context, this)
|
|
383
397
|
}
|
|
384
398
|
}
|
|
385
399
|
}
|
|
@@ -396,14 +410,13 @@ class AudioModule : Module() {
|
|
|
396
410
|
mediaItem: MediaItem
|
|
397
411
|
): MediaSource {
|
|
398
412
|
val uri = mediaItem.localConfiguration?.uri
|
|
399
|
-
|
|
413
|
+
return when (val type = uri?.let { retrieveStreamType(it) }) {
|
|
400
414
|
CONTENT_TYPE_SS -> SsMediaSource.Factory(factory)
|
|
401
415
|
CONTENT_TYPE_DASH -> DashMediaSource.Factory(factory)
|
|
402
416
|
CONTENT_TYPE_HLS -> HlsMediaSource.Factory(factory)
|
|
403
417
|
CONTENT_TYPE_OTHER -> ProgressiveMediaSource.Factory(factory)
|
|
404
418
|
else -> throw IllegalStateException("Unsupported type: $type")
|
|
405
|
-
}
|
|
406
|
-
return newFactory.createMediaSource(MediaItem.fromUri(uri))
|
|
419
|
+
}.createMediaSource(mediaItem)
|
|
407
420
|
}
|
|
408
421
|
|
|
409
422
|
private fun <T> runOnMain(block: () -> T): T =
|
|
@@ -10,7 +10,6 @@ import androidx.media3.common.AudioAttributes
|
|
|
10
10
|
import androidx.media3.common.C
|
|
11
11
|
import androidx.media3.common.MediaItem
|
|
12
12
|
import androidx.media3.common.Player
|
|
13
|
-
import androidx.media3.common.Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED
|
|
14
13
|
import androidx.media3.common.util.UnstableApi
|
|
15
14
|
import androidx.media3.exoplayer.ExoPlayer
|
|
16
15
|
import androidx.media3.exoplayer.source.MediaSource
|
|
@@ -18,9 +17,12 @@ import expo.modules.kotlin.AppContext
|
|
|
18
17
|
import expo.modules.kotlin.sharedobjects.SharedRef
|
|
19
18
|
import kotlinx.coroutines.CoroutineScope
|
|
20
19
|
import kotlinx.coroutines.Dispatchers
|
|
20
|
+
import kotlinx.coroutines.Job
|
|
21
21
|
import kotlinx.coroutines.cancel
|
|
22
22
|
import kotlinx.coroutines.delay
|
|
23
|
-
import kotlinx.coroutines.
|
|
23
|
+
import kotlinx.coroutines.flow.flow
|
|
24
|
+
import kotlinx.coroutines.flow.launchIn
|
|
25
|
+
import kotlinx.coroutines.flow.onEach
|
|
24
26
|
import kotlinx.coroutines.launch
|
|
25
27
|
import kotlinx.coroutines.withContext
|
|
26
28
|
import java.util.UUID
|
|
@@ -33,18 +35,11 @@ class AudioPlayer(
|
|
|
33
35
|
context: Context,
|
|
34
36
|
appContext: AppContext,
|
|
35
37
|
source: MediaSource?,
|
|
36
|
-
updateInterval: Double
|
|
38
|
+
private val updateInterval: Double
|
|
37
39
|
) : SharedRef<ExoPlayer>(
|
|
38
40
|
ExoPlayer.Builder(context)
|
|
39
41
|
.setLooper(context.mainLooper)
|
|
40
|
-
.build()
|
|
41
|
-
.apply {
|
|
42
|
-
source?.let {
|
|
43
|
-
setMediaSource(it)
|
|
44
|
-
}
|
|
45
|
-
setAudioAttributes(AudioAttributes.DEFAULT, true)
|
|
46
|
-
prepare()
|
|
47
|
-
},
|
|
42
|
+
.build(),
|
|
48
43
|
appContext
|
|
49
44
|
) {
|
|
50
45
|
val id = UUID.randomUUID().toString()
|
|
@@ -57,20 +52,34 @@ class AudioPlayer(
|
|
|
57
52
|
private var visualizer: Visualizer? = null
|
|
58
53
|
private var playing = false
|
|
59
54
|
|
|
60
|
-
|
|
61
|
-
|
|
55
|
+
private var updateJob: Job? = null
|
|
56
|
+
|
|
57
|
+
val currentTime get() = player.currentPosition / 1000f
|
|
58
|
+
val duration get() = if (player.duration != C.TIME_UNSET) player.duration / 1000f else 0f
|
|
62
59
|
|
|
63
60
|
init {
|
|
64
|
-
addPlayerListeners()
|
|
65
61
|
player.setAudioAttributes(AudioAttributes.DEFAULT, true)
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
62
|
+
addPlayerListeners()
|
|
63
|
+
source?.let {
|
|
64
|
+
setMediaSource(source)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private fun setMediaSource(source: MediaSource) {
|
|
69
|
+
player.setMediaSource(source)
|
|
70
|
+
player.prepare()
|
|
71
|
+
startUpdating()
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
private fun startUpdating() {
|
|
75
|
+
updateJob = flow {
|
|
76
|
+
while (true) {
|
|
77
|
+
emit(Unit)
|
|
71
78
|
delay(updateInterval.toLong())
|
|
72
79
|
}
|
|
73
80
|
}
|
|
81
|
+
.onEach { sendPlayerUpdate() }
|
|
82
|
+
.launchIn(playerScope)
|
|
74
83
|
}
|
|
75
84
|
|
|
76
85
|
private fun addPlayerListeners() = player.addListener(object : Player.Listener {
|
|
@@ -81,22 +90,33 @@ class AudioPlayer(
|
|
|
81
90
|
}
|
|
82
91
|
}
|
|
83
92
|
|
|
93
|
+
override fun onIsLoadingChanged(isLoading: Boolean) {
|
|
94
|
+
playerScope.launch {
|
|
95
|
+
sendPlayerUpdate(mapOf("isLoaded" to isLoading))
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
84
99
|
override fun onPlaybackStateChanged(playbackState: Int) {
|
|
85
100
|
playerScope.launch {
|
|
86
|
-
sendPlayerUpdate(mapOf("
|
|
101
|
+
sendPlayerUpdate(mapOf("playbackState" to playbackStateToString(playbackState)))
|
|
87
102
|
}
|
|
88
103
|
}
|
|
89
104
|
|
|
90
105
|
override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
sendPlayerUpdate()
|
|
94
|
-
}
|
|
106
|
+
playerScope.launch {
|
|
107
|
+
sendPlayerUpdate()
|
|
95
108
|
}
|
|
96
109
|
}
|
|
97
110
|
})
|
|
98
111
|
|
|
99
112
|
fun setSamplingEnabled(enabled: Boolean) {
|
|
113
|
+
appContext?.reactContext?.let {
|
|
114
|
+
if (ContextCompat.checkSelfPermission(it, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
|
|
115
|
+
Log.d(TAG, "\'android.permission.RECORD_AUDIO\' is required to use audio sampling. Please request this permission and try again.")
|
|
116
|
+
return
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
100
120
|
samplingEnabled = enabled
|
|
101
121
|
if (enabled) {
|
|
102
122
|
createVisualizer()
|
|
@@ -163,13 +183,6 @@ class AudioPlayer(
|
|
|
163
183
|
}
|
|
164
184
|
|
|
165
185
|
private fun createVisualizer() {
|
|
166
|
-
appContext?.reactContext?.let {
|
|
167
|
-
if (ContextCompat.checkSelfPermission(it, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
|
|
168
|
-
Log.d(TAG, "\'android.permission.RECORD_AUDIO\' is required to use audio sampling. Please request this permission and try again.")
|
|
169
|
-
return
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
186
|
// It must only be created once, otherwise the app will crash
|
|
174
187
|
if (visualizer == null) {
|
|
175
188
|
visualizer = Visualizer(player.audioSessionId).apply {
|
|
@@ -12,7 +12,6 @@ import android.media.MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED
|
|
|
12
12
|
import android.net.Uri
|
|
13
13
|
import android.os.Build
|
|
14
14
|
import android.os.Bundle
|
|
15
|
-
import android.os.SystemClock
|
|
16
15
|
import androidx.core.content.ContextCompat
|
|
17
16
|
import expo.modules.kotlin.AppContext
|
|
18
17
|
import expo.modules.kotlin.sharedobjects.SharedObject
|
|
@@ -30,24 +29,23 @@ class AudioRecorder(
|
|
|
30
29
|
) : SharedObject(appContext),
|
|
31
30
|
MediaRecorder.OnErrorListener,
|
|
32
31
|
MediaRecorder.OnInfoListener {
|
|
33
|
-
|
|
32
|
+
var filePath: String? = null
|
|
34
33
|
private var meteringEnabled = options.isMeteringEnabled
|
|
35
34
|
private var durationAlreadyRecorded = 0L
|
|
36
|
-
|
|
37
|
-
private var shouldCreateRecorder = false
|
|
35
|
+
var isPrepared = false
|
|
38
36
|
|
|
39
|
-
private var recorder =
|
|
37
|
+
private var recorder: MediaRecorder? = null
|
|
40
38
|
val id = UUID.randomUUID().toString()
|
|
41
|
-
var
|
|
42
|
-
var uptime = 0L
|
|
39
|
+
var startTime = 0L
|
|
43
40
|
var isRecording = false
|
|
44
41
|
var isPaused = false
|
|
45
42
|
|
|
46
|
-
private fun getAudioRecorderLevels(): Int {
|
|
47
|
-
if (!meteringEnabled) {
|
|
48
|
-
return
|
|
43
|
+
private fun getAudioRecorderLevels(): Int? {
|
|
44
|
+
if (!meteringEnabled || recorder == null || !isRecording) {
|
|
45
|
+
return null
|
|
49
46
|
}
|
|
50
|
-
|
|
47
|
+
|
|
48
|
+
val amplitude: Int = recorder?.maxAmplitude ?: 0
|
|
51
49
|
return if (amplitude == 0) {
|
|
52
50
|
-160
|
|
53
51
|
} else {
|
|
@@ -56,46 +54,51 @@ class AudioRecorder(
|
|
|
56
54
|
}
|
|
57
55
|
|
|
58
56
|
fun prepareRecording(options: RecordingOptions?) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
recorder
|
|
57
|
+
recorder = options?.let { createRecorder(it) } ?: createRecorder(this.options)
|
|
58
|
+
try {
|
|
59
|
+
recorder?.prepare()
|
|
60
|
+
isPrepared = true
|
|
61
|
+
} catch (_: Exception) {
|
|
62
|
+
recorder?.release()
|
|
63
|
+
recorder = null
|
|
64
|
+
isPrepared = false
|
|
65
65
|
}
|
|
66
|
-
recorder.prepare()
|
|
67
|
-
isPrepared = true
|
|
68
66
|
}
|
|
69
67
|
|
|
70
68
|
fun record() {
|
|
71
69
|
if (isPaused) {
|
|
72
|
-
recorder
|
|
70
|
+
recorder?.resume()
|
|
73
71
|
} else {
|
|
74
|
-
recorder
|
|
72
|
+
recorder?.start()
|
|
75
73
|
}
|
|
74
|
+
startTime = System.currentTimeMillis()
|
|
76
75
|
isRecording = true
|
|
77
76
|
isPaused = false
|
|
78
|
-
uptime = SystemClock.uptimeMillis()
|
|
79
77
|
}
|
|
80
78
|
|
|
81
79
|
fun pauseRecording() {
|
|
82
|
-
recorder
|
|
80
|
+
recorder?.pause()
|
|
83
81
|
durationAlreadyRecorded = getAudioRecorderDurationMillis()
|
|
84
82
|
isRecording = false
|
|
85
83
|
isPaused = true
|
|
86
84
|
}
|
|
87
85
|
|
|
88
86
|
fun stopRecording(): Bundle {
|
|
89
|
-
|
|
90
|
-
|
|
87
|
+
try {
|
|
88
|
+
recorder?.stop()
|
|
89
|
+
} finally {
|
|
90
|
+
reset()
|
|
91
|
+
}
|
|
91
92
|
return getAudioRecorderStatus()
|
|
92
93
|
}
|
|
93
94
|
|
|
94
95
|
private fun reset() {
|
|
96
|
+
recorder?.release()
|
|
97
|
+
recorder = null
|
|
95
98
|
isRecording = false
|
|
96
99
|
isPaused = false
|
|
97
100
|
durationAlreadyRecorded = 0
|
|
98
|
-
|
|
101
|
+
startTime = 0L
|
|
99
102
|
isPrepared = false
|
|
100
103
|
}
|
|
101
104
|
|
|
@@ -149,14 +152,13 @@ class AudioRecorder(
|
|
|
149
152
|
setOnErrorListener(this@AudioRecorder)
|
|
150
153
|
setOnInfoListener(this@AudioRecorder)
|
|
151
154
|
setOutputFile(filePath)
|
|
152
|
-
uri = filePath
|
|
153
155
|
isPrepared = false
|
|
154
156
|
}
|
|
155
157
|
}
|
|
156
158
|
|
|
157
159
|
override fun sharedObjectDidRelease() {
|
|
158
160
|
super.sharedObjectDidRelease()
|
|
159
|
-
|
|
161
|
+
reset()
|
|
160
162
|
}
|
|
161
163
|
|
|
162
164
|
fun getAudioRecorderStatus() = if (hasRecordingPermissions()) {
|
|
@@ -164,10 +166,10 @@ class AudioRecorder(
|
|
|
164
166
|
putBoolean("canRecord", isPrepared)
|
|
165
167
|
putBoolean("isRecording", isRecording)
|
|
166
168
|
putLong("durationMillis", getAudioRecorderDurationMillis())
|
|
167
|
-
|
|
168
|
-
putInt("metering",
|
|
169
|
+
getAudioRecorderLevels()?.let {
|
|
170
|
+
putInt("metering", it)
|
|
169
171
|
}
|
|
170
|
-
putString("url",
|
|
172
|
+
putString("url", filePath)
|
|
171
173
|
}
|
|
172
174
|
} else {
|
|
173
175
|
Bundle().apply {
|
|
@@ -180,8 +182,8 @@ class AudioRecorder(
|
|
|
180
182
|
|
|
181
183
|
private fun getAudioRecorderDurationMillis(): Long {
|
|
182
184
|
var duration = durationAlreadyRecorded
|
|
183
|
-
if (isRecording
|
|
184
|
-
duration +=
|
|
185
|
+
if (isRecording) {
|
|
186
|
+
duration += System.currentTimeMillis() - startTime
|
|
185
187
|
}
|
|
186
188
|
return duration
|
|
187
189
|
}
|
|
@@ -206,14 +208,14 @@ class AudioRecorder(
|
|
|
206
208
|
override fun onInfo(mr: MediaRecorder?, what: Int, extra: Int) {
|
|
207
209
|
when (what) {
|
|
208
210
|
MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED -> {
|
|
209
|
-
recorder
|
|
211
|
+
recorder?.stop()
|
|
210
212
|
emit(
|
|
211
|
-
|
|
213
|
+
RECORDING_STATUS_UPDATE,
|
|
212
214
|
mapOf(
|
|
213
215
|
"isFinished" to true,
|
|
214
216
|
"hasError" to true,
|
|
215
217
|
"error" to null,
|
|
216
|
-
"url" to Uri.
|
|
218
|
+
"url" to Uri.parse(filePath).toString()
|
|
217
219
|
)
|
|
218
220
|
)
|
|
219
221
|
}
|
|
@@ -231,14 +233,14 @@ class AudioRecorder(
|
|
|
231
233
|
// getRoutedDevice() is the most reliable way to return the actual mic input, however it
|
|
232
234
|
// only returns a valid device when actively recording, and may throw otherwise.
|
|
233
235
|
// https://developer.android.com/reference/android/media/MediaRecorder#getRoutedDevice()
|
|
234
|
-
deviceInfo = recorder
|
|
236
|
+
deviceInfo = recorder?.routedDevice
|
|
235
237
|
} catch (e: java.lang.Exception) {
|
|
236
238
|
// no-op
|
|
237
239
|
}
|
|
238
240
|
|
|
239
241
|
// If no routed device is found try preferred device
|
|
240
242
|
if (deviceInfo == null) {
|
|
241
|
-
deviceInfo = recorder
|
|
243
|
+
deviceInfo = recorder?.preferredDevice
|
|
242
244
|
}
|
|
243
245
|
|
|
244
246
|
if (deviceInfo == null) {
|
|
@@ -248,7 +250,7 @@ class AudioRecorder(
|
|
|
248
250
|
val type = availableDeviceInfo.type
|
|
249
251
|
if (type == AudioDeviceInfo.TYPE_BUILTIN_MIC) {
|
|
250
252
|
deviceInfo = availableDeviceInfo
|
|
251
|
-
recorder
|
|
253
|
+
recorder?.setPreferredDevice(deviceInfo)
|
|
252
254
|
break
|
|
253
255
|
}
|
|
254
256
|
}
|
|
@@ -295,8 +297,8 @@ class AudioRecorder(
|
|
|
295
297
|
}
|
|
296
298
|
}
|
|
297
299
|
|
|
298
|
-
val success = recorder
|
|
299
|
-
if (
|
|
300
|
+
val success = recorder?.setPreferredDevice(deviceInfo)
|
|
301
|
+
if (success == false) {
|
|
300
302
|
throw PreferredInputNotFoundException()
|
|
301
303
|
}
|
|
302
304
|
}
|
|
@@ -305,8 +307,7 @@ class AudioRecorder(
|
|
|
305
307
|
val id = uid.toInt()
|
|
306
308
|
val audioDevices: Array<AudioDeviceInfo> = audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)
|
|
307
309
|
for (device in audioDevices) {
|
|
308
|
-
|
|
309
|
-
if (deviceId == id) {
|
|
310
|
+
if (device.id == id) {
|
|
310
311
|
return device
|
|
311
312
|
}
|
|
312
313
|
}
|
package/build/Audio.types.d.ts
CHANGED
|
@@ -221,6 +221,11 @@ export type RecordingOptionsAndroid = {
|
|
|
221
221
|
maxFileSize?: number;
|
|
222
222
|
};
|
|
223
223
|
export type AudioMode = {
|
|
224
|
+
/**
|
|
225
|
+
* Determines if audio playback is allowed when the device is in silent mode.
|
|
226
|
+
*
|
|
227
|
+
* @platform ios
|
|
228
|
+
*/
|
|
224
229
|
playsInSilentMode: boolean;
|
|
225
230
|
/**
|
|
226
231
|
* Determines how the audio session interacts with other sessions.
|
|
@@ -228,8 +233,22 @@ export type AudioMode = {
|
|
|
228
233
|
* @platform ios
|
|
229
234
|
*/
|
|
230
235
|
interruptionMode: InterruptionMode;
|
|
236
|
+
/**
|
|
237
|
+
* Whether the audio session allows recording.
|
|
238
|
+
*
|
|
239
|
+
* @default false
|
|
240
|
+
* @platform ios
|
|
241
|
+
*/
|
|
231
242
|
allowsRecording: boolean;
|
|
243
|
+
/**
|
|
244
|
+
* Whether the audio session stays active when the app moves to the background.
|
|
245
|
+
* @default false
|
|
246
|
+
*/
|
|
232
247
|
shouldPlayInBackground: boolean;
|
|
248
|
+
/**
|
|
249
|
+
* Whether the audio should route through the earpiece.
|
|
250
|
+
* @platform android
|
|
251
|
+
*/
|
|
233
252
|
shouldRouteThroughEarpiece: boolean;
|
|
234
253
|
};
|
|
235
254
|
export type InterruptionMode = 'mixWithOthers' | 'doNotMix' | 'duckOthers';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Audio.types.d.ts","sourceRoot":"","sources":["../src/Audio.types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Audio.types.d.ts","sourceRoot":"","sources":["../src/Audio.types.ts"],"names":[],"mappings":"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"}
|
package/build/Audio.types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Audio.types.js","sourceRoot":"","sources":["../src/Audio.types.ts"],"names":[],"mappings":"AA4EA,MAAM,CAAN,IAAY,eAmCX;AAnCD,WAAY,eAAe;IACzB,qCAAkB,CAAA;IAClB,+BAAY,CAAA;IACZ,oCAAmB,CAAA;IACnB,qCAAkB,CAAA;IAClB,oCAAiB,CAAA;IACjB,qCAAkB,CAAA;IAClB,qCAAkB,CAAA;IAClB,uCAAoB,CAAA;IACpB,iCAAc,CAAA;IACd,iCAAc,CAAA;IACd,gCAAa,CAAA;IACb,gCAAa,CAAA;IACb,mCAAgB,CAAA;IAChB,oCAAiB,CAAA;IACjB,oCAAiB,CAAA;IACjB,sCAAmB,CAAA;IACnB,sCAAmB,CAAA;IACnB,sCAAmB,CAAA;IACnB,yCAAsB,CAAA;IACtB,uCAAoB,CAAA;IACpB,uCAAoB,CAAA;IACpB,wCAAqB,CAAA;IACrB,4CAAyB,CAAA;IACzB,2CAAwB,CAAA;IACxB,0CAAuB,CAAA;IACvB,4CAAyB,CAAA;IACzB,+BAAY,CAAA;IACZ,kCAAe,CAAA;IACf,mCAAgB,CAAA;IAChB,gCAAa,CAAA;IACb,4EAAwB,CAAA;IACxB,8EAAyB,CAAA;IACzB,gCAAa,CAAA;IACb,uCAAoB,CAAA;AACtB,CAAC,EAnCW,eAAe,KAAf,eAAe,QAmC1B;AAED,MAAM,CAAN,IAAY,YAMX;AAND,WAAY,YAAY;IACtB,6CAAO,CAAA;IACP,8CAAU,CAAA;IACV,oDAAa,CAAA;IACb,gDAAW,CAAA;IACX,+CAAU,CAAA;AACZ,CAAC,EANW,YAAY,KAAZ,YAAY,QAMvB","sourcesContent":["export type AudioSource =\n | string\n | number\n | null\n | {\n /**\n * A string representing the resource identifier for the audio,\n * which could be an HTTPS address, a local file path, or the name of a static audio file resource.\n */\n uri?: string;\n /**\n * The asset ID of a local audio asset, acquired with the `require` function.\n * This property is exclusive with the `uri` property. When both are present, the `assetId` will be ignored.\n */\n assetId?: number;\n /**\n * An object representing the HTTP headers to send along with the request for a remote audio source.\n * On web requires the `Access-Control-Allow-Origin` header returned by the server to include the current domain.\n */\n headers?: Record<string, string>;\n };\n\nexport type RecordingInput = {\n name: string;\n type: string;\n uid: string;\n};\n\nexport type PitchCorrectionQuality = 'low' | 'medium' | 'high';\n\nexport type AudioStatus = {\n id: number;\n currentTime: number;\n playbackState: string;\n timeControlStatus: string;\n reasonForWaitingToPlay: string;\n mute: boolean;\n duration: number;\n playing: boolean;\n loop: boolean;\n didJustFinish: boolean;\n isBuffering: boolean;\n isLoaded: boolean;\n playbackRate: number;\n shouldCorrectPitch: boolean;\n};\n\nexport type RecordingStatus = {\n id: number;\n isFinished: boolean;\n hasError: boolean;\n error: string | null;\n url: string | null;\n};\n\nexport type RecorderState = {\n canRecord: boolean;\n isRecording: boolean;\n durationMillis: number;\n mediaServicesDidReset: boolean;\n metering?: number;\n url: string | null;\n};\n\nexport type AndroidOutputFormat =\n | 'default'\n | '3gp'\n | 'mpeg4'\n | 'amrnb'\n | 'amrwb'\n | 'aac_adts'\n | 'mpeg2ts'\n | 'webm';\n\nexport type AndroidAudioEncoder = 'default' | 'amr_nb' | 'amr_wb' | 'aac' | 'he_aac' | 'aac_eld';\n\nexport enum IOSOutputFormat {\n LINEARPCM = 'lpcm',\n AC3 = 'ac-3',\n '60958AC3' = 'cac3',\n APPLEIMA4 = 'ima4',\n MPEG4AAC = 'aac ',\n MPEG4CELP = 'celp',\n MPEG4HVXC = 'hvxc',\n MPEG4TWINVQ = 'twvq',\n MACE3 = 'MAC3',\n MACE6 = 'MAC6',\n ULAW = 'ulaw',\n ALAW = 'alaw',\n QDESIGN = 'QDMC',\n QDESIGN2 = 'QDM2',\n QUALCOMM = 'Qclp',\n MPEGLAYER1 = '.mp1',\n MPEGLAYER2 = '.mp2',\n MPEGLAYER3 = '.mp3',\n APPLELOSSLESS = 'alac',\n MPEG4AAC_HE = 'aach',\n MPEG4AAC_LD = 'aacl',\n MPEG4AAC_ELD = 'aace',\n MPEG4AAC_ELD_SBR = 'aacf',\n MPEG4AAC_ELD_V2 = 'aacg',\n MPEG4AAC_HE_V2 = 'aacp',\n MPEG4AAC_SPATIAL = 'aacs',\n AMR = 'samr',\n AMR_WB = 'sawb',\n AUDIBLE = 'AUDB',\n ILBC = 'ilbc',\n DVIINTELIMA = 0x6d730011,\n MICROSOFTGSM = 0x6d730031,\n AES3 = 'aes3',\n ENHANCEDAC3 = 'ec-3',\n}\n\nexport enum AudioQuality {\n MIN = 0,\n LOW = 0x20,\n MEDIUM = 0x40,\n HIGH = 0x60,\n MAX = 0x7f,\n}\n\nexport type BitRateStrategy = 'constant' | 'longTermAverage' | 'variableConstrained' | 'variable';\n\nexport type RecordingOptions = {\n /**\n * A boolean that determines whether audio level information will be part of the status object under the \"metering\" key.\n */\n isMeteringEnabled?: boolean;\n /**\n * The desired file extension.\n *\n * @example .caf\n */\n extension: string;\n /**\n * The desired sample rate.\n *\n * @example 44100\n */\n sampleRate: number;\n /**\n * The desired number of channels.\n *\n * @example 2\n */\n numberOfChannels: number;\n /**\n * The desired bit rate.\n *\n * @example 128000\n */\n bitRate: number;\n /**\n * Recording options for the Android platform.\n */\n android: RecordingOptionsAndroid;\n /**\n * Recording options for the iOS platform.\n */\n ios: RecordingOptionsIos;\n /**\n * Recording options for the Web platform.\n */\n web?: RecordingOptionsWeb;\n};\n\nexport type RecordingOptionsWeb = {\n mimeType?: string;\n bitsPerSecond?: number;\n};\n\nexport type RecordingOptionsIos = {\n /**\n * The desired file extension.\n *\n * @example .caf\n */\n extension?: string;\n /**\n * The desired sample rate.\n *\n * @example 44100\n */\n sampleRate?: number;\n /**\n * The desired file format. See the [`IOSOutputFormat`](#iosoutputformat) enum for all valid values.\n */\n outputFormat?: string | IOSOutputFormat | number;\n /**\n * The desired audio quality. See the [`AudioQuality`](#audioquality) enum for all valid values.\n */\n audioQuality: AudioQuality | number;\n /**\n * The desired bit rate strategy. See the next section for an enumeration of all valid values of `bitRateStrategy`.\n */\n bitRateStrategy?: number;\n /**\n * The desired bit depth hint.\n *\n * @example 16\n */\n bitDepthHint?: number;\n /**\n * The desired PCM bit depth.\n *\n * @example 16\n */\n linearPCMBitDepth?: number;\n /**\n * A boolean describing if the PCM data should be formatted in big endian.\n */\n linearPCMIsBigEndian?: boolean;\n /**\n * A boolean describing if the PCM data should be encoded in floating point or integral values.\n */\n linearPCMIsFloat?: boolean;\n};\n\nexport type RecordingOptionsAndroid = {\n /**\n * The desired file extension.\n *\n * @example .caf\n */\n extension?: string;\n /**\n * The desired sample rate.\n *\n * @example 44100\n */\n sampleRate?: number;\n /**\n * The desired file format. See the [`AndroidOutputFormat`](#androidoutputformat) enum for all valid values.\n */\n outputFormat: AndroidOutputFormat;\n /**\n * The desired audio encoder. See the [`AndroidAudioEncoder`](#androidaudioencoder) enum for all valid values.\n */\n audioEncoder: AndroidAudioEncoder;\n /**\n * The desired maximum file size in bytes, after which the recording will stop (but `stopAndUnloadAsync()` must still\n * be called after this point).\n *\n * @example\n * `65536`\n */\n maxFileSize?: number;\n};\n\nexport type AudioMode = {\n playsInSilentMode: boolean;\n /**\n * Determines how the audio session interacts with other sessions.\n *\n * @platform ios\n */\n interruptionMode: InterruptionMode;\n allowsRecording: boolean;\n shouldPlayInBackground: boolean;\n shouldRouteThroughEarpiece: boolean;\n};\n\nexport type InterruptionMode = 'mixWithOthers' | 'doNotMix' | 'duckOthers';\n"]}
|
|
1
|
+
{"version":3,"file":"Audio.types.js","sourceRoot":"","sources":["../src/Audio.types.ts"],"names":[],"mappings":"AA4EA,MAAM,CAAN,IAAY,eAmCX;AAnCD,WAAY,eAAe;IACzB,qCAAkB,CAAA;IAClB,+BAAY,CAAA;IACZ,oCAAmB,CAAA;IACnB,qCAAkB,CAAA;IAClB,oCAAiB,CAAA;IACjB,qCAAkB,CAAA;IAClB,qCAAkB,CAAA;IAClB,uCAAoB,CAAA;IACpB,iCAAc,CAAA;IACd,iCAAc,CAAA;IACd,gCAAa,CAAA;IACb,gCAAa,CAAA;IACb,mCAAgB,CAAA;IAChB,oCAAiB,CAAA;IACjB,oCAAiB,CAAA;IACjB,sCAAmB,CAAA;IACnB,sCAAmB,CAAA;IACnB,sCAAmB,CAAA;IACnB,yCAAsB,CAAA;IACtB,uCAAoB,CAAA;IACpB,uCAAoB,CAAA;IACpB,wCAAqB,CAAA;IACrB,4CAAyB,CAAA;IACzB,2CAAwB,CAAA;IACxB,0CAAuB,CAAA;IACvB,4CAAyB,CAAA;IACzB,+BAAY,CAAA;IACZ,kCAAe,CAAA;IACf,mCAAgB,CAAA;IAChB,gCAAa,CAAA;IACb,4EAAwB,CAAA;IACxB,8EAAyB,CAAA;IACzB,gCAAa,CAAA;IACb,uCAAoB,CAAA;AACtB,CAAC,EAnCW,eAAe,KAAf,eAAe,QAmC1B;AAED,MAAM,CAAN,IAAY,YAMX;AAND,WAAY,YAAY;IACtB,6CAAO,CAAA;IACP,8CAAU,CAAA;IACV,oDAAa,CAAA;IACb,gDAAW,CAAA;IACX,+CAAU,CAAA;AACZ,CAAC,EANW,YAAY,KAAZ,YAAY,QAMvB","sourcesContent":["export type AudioSource =\n | string\n | number\n | null\n | {\n /**\n * A string representing the resource identifier for the audio,\n * which could be an HTTPS address, a local file path, or the name of a static audio file resource.\n */\n uri?: string;\n /**\n * The asset ID of a local audio asset, acquired with the `require` function.\n * This property is exclusive with the `uri` property. When both are present, the `assetId` will be ignored.\n */\n assetId?: number;\n /**\n * An object representing the HTTP headers to send along with the request for a remote audio source.\n * On web requires the `Access-Control-Allow-Origin` header returned by the server to include the current domain.\n */\n headers?: Record<string, string>;\n };\n\nexport type RecordingInput = {\n name: string;\n type: string;\n uid: string;\n};\n\nexport type PitchCorrectionQuality = 'low' | 'medium' | 'high';\n\nexport type AudioStatus = {\n id: number;\n currentTime: number;\n playbackState: string;\n timeControlStatus: string;\n reasonForWaitingToPlay: string;\n mute: boolean;\n duration: number;\n playing: boolean;\n loop: boolean;\n didJustFinish: boolean;\n isBuffering: boolean;\n isLoaded: boolean;\n playbackRate: number;\n shouldCorrectPitch: boolean;\n};\n\nexport type RecordingStatus = {\n id: number;\n isFinished: boolean;\n hasError: boolean;\n error: string | null;\n url: string | null;\n};\n\nexport type RecorderState = {\n canRecord: boolean;\n isRecording: boolean;\n durationMillis: number;\n mediaServicesDidReset: boolean;\n metering?: number;\n url: string | null;\n};\n\nexport type AndroidOutputFormat =\n | 'default'\n | '3gp'\n | 'mpeg4'\n | 'amrnb'\n | 'amrwb'\n | 'aac_adts'\n | 'mpeg2ts'\n | 'webm';\n\nexport type AndroidAudioEncoder = 'default' | 'amr_nb' | 'amr_wb' | 'aac' | 'he_aac' | 'aac_eld';\n\nexport enum IOSOutputFormat {\n LINEARPCM = 'lpcm',\n AC3 = 'ac-3',\n '60958AC3' = 'cac3',\n APPLEIMA4 = 'ima4',\n MPEG4AAC = 'aac ',\n MPEG4CELP = 'celp',\n MPEG4HVXC = 'hvxc',\n MPEG4TWINVQ = 'twvq',\n MACE3 = 'MAC3',\n MACE6 = 'MAC6',\n ULAW = 'ulaw',\n ALAW = 'alaw',\n QDESIGN = 'QDMC',\n QDESIGN2 = 'QDM2',\n QUALCOMM = 'Qclp',\n MPEGLAYER1 = '.mp1',\n MPEGLAYER2 = '.mp2',\n MPEGLAYER3 = '.mp3',\n APPLELOSSLESS = 'alac',\n MPEG4AAC_HE = 'aach',\n MPEG4AAC_LD = 'aacl',\n MPEG4AAC_ELD = 'aace',\n MPEG4AAC_ELD_SBR = 'aacf',\n MPEG4AAC_ELD_V2 = 'aacg',\n MPEG4AAC_HE_V2 = 'aacp',\n MPEG4AAC_SPATIAL = 'aacs',\n AMR = 'samr',\n AMR_WB = 'sawb',\n AUDIBLE = 'AUDB',\n ILBC = 'ilbc',\n DVIINTELIMA = 0x6d730011,\n MICROSOFTGSM = 0x6d730031,\n AES3 = 'aes3',\n ENHANCEDAC3 = 'ec-3',\n}\n\nexport enum AudioQuality {\n MIN = 0,\n LOW = 0x20,\n MEDIUM = 0x40,\n HIGH = 0x60,\n MAX = 0x7f,\n}\n\nexport type BitRateStrategy = 'constant' | 'longTermAverage' | 'variableConstrained' | 'variable';\n\nexport type RecordingOptions = {\n /**\n * A boolean that determines whether audio level information will be part of the status object under the \"metering\" key.\n */\n isMeteringEnabled?: boolean;\n /**\n * The desired file extension.\n *\n * @example .caf\n */\n extension: string;\n /**\n * The desired sample rate.\n *\n * @example 44100\n */\n sampleRate: number;\n /**\n * The desired number of channels.\n *\n * @example 2\n */\n numberOfChannels: number;\n /**\n * The desired bit rate.\n *\n * @example 128000\n */\n bitRate: number;\n /**\n * Recording options for the Android platform.\n */\n android: RecordingOptionsAndroid;\n /**\n * Recording options for the iOS platform.\n */\n ios: RecordingOptionsIos;\n /**\n * Recording options for the Web platform.\n */\n web?: RecordingOptionsWeb;\n};\n\nexport type RecordingOptionsWeb = {\n mimeType?: string;\n bitsPerSecond?: number;\n};\n\nexport type RecordingOptionsIos = {\n /**\n * The desired file extension.\n *\n * @example .caf\n */\n extension?: string;\n /**\n * The desired sample rate.\n *\n * @example 44100\n */\n sampleRate?: number;\n /**\n * The desired file format. See the [`IOSOutputFormat`](#iosoutputformat) enum for all valid values.\n */\n outputFormat?: string | IOSOutputFormat | number;\n /**\n * The desired audio quality. See the [`AudioQuality`](#audioquality) enum for all valid values.\n */\n audioQuality: AudioQuality | number;\n /**\n * The desired bit rate strategy. See the next section for an enumeration of all valid values of `bitRateStrategy`.\n */\n bitRateStrategy?: number;\n /**\n * The desired bit depth hint.\n *\n * @example 16\n */\n bitDepthHint?: number;\n /**\n * The desired PCM bit depth.\n *\n * @example 16\n */\n linearPCMBitDepth?: number;\n /**\n * A boolean describing if the PCM data should be formatted in big endian.\n */\n linearPCMIsBigEndian?: boolean;\n /**\n * A boolean describing if the PCM data should be encoded in floating point or integral values.\n */\n linearPCMIsFloat?: boolean;\n};\n\nexport type RecordingOptionsAndroid = {\n /**\n * The desired file extension.\n *\n * @example .caf\n */\n extension?: string;\n /**\n * The desired sample rate.\n *\n * @example 44100\n */\n sampleRate?: number;\n /**\n * The desired file format. See the [`AndroidOutputFormat`](#androidoutputformat) enum for all valid values.\n */\n outputFormat: AndroidOutputFormat;\n /**\n * The desired audio encoder. See the [`AndroidAudioEncoder`](#androidaudioencoder) enum for all valid values.\n */\n audioEncoder: AndroidAudioEncoder;\n /**\n * The desired maximum file size in bytes, after which the recording will stop (but `stopAndUnloadAsync()` must still\n * be called after this point).\n *\n * @example\n * `65536`\n */\n maxFileSize?: number;\n};\n\nexport type AudioMode = {\n /**\n * Determines if audio playback is allowed when the device is in silent mode.\n *\n * @platform ios\n */\n playsInSilentMode: boolean;\n /**\n * Determines how the audio session interacts with other sessions.\n *\n * @platform ios\n */\n interruptionMode: InterruptionMode;\n /**\n * Whether the audio session allows recording.\n *\n * @default false\n * @platform ios\n */\n allowsRecording: boolean;\n /**\n * Whether the audio session stays active when the app moves to the background.\n * @default false\n */\n shouldPlayInBackground: boolean;\n /**\n * Whether the audio should route through the earpiece.\n * @platform android\n */\n shouldRouteThroughEarpiece: boolean;\n};\n\nexport type InterruptionMode = 'mixWithOthers' | 'doNotMix' | 'duckOthers';\n"]}
|
package/ios/AudioRecords.swift
CHANGED
|
@@ -3,8 +3,8 @@ import ExpoModulesCore
|
|
|
3
3
|
struct AudioMode: Record {
|
|
4
4
|
@Field var playsInSilentMode: Bool = false
|
|
5
5
|
@Field var interruptionMode: InterruptionMode = .mixWithOthers
|
|
6
|
-
@Field var allowsRecording: Bool =
|
|
7
|
-
@Field var shouldPlayInBackground: Bool =
|
|
6
|
+
@Field var allowsRecording: Bool = false
|
|
7
|
+
@Field var shouldPlayInBackground: Bool = false
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
enum InterruptionMode: String, Enumerable {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-audio",
|
|
3
3
|
"title": "Expo Audio",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.5",
|
|
5
5
|
"description": "A cross-platform audio library for React Native and Expo apps.",
|
|
6
6
|
"main": "build/index.js",
|
|
7
7
|
"types": "build/index.d.ts",
|
|
@@ -33,12 +33,12 @@
|
|
|
33
33
|
"license": "MIT",
|
|
34
34
|
"dependencies": {},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"expo-module-scripts": "^4.0.
|
|
36
|
+
"expo-module-scripts": "^4.0.4"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"expo": "*",
|
|
40
40
|
"react": "*",
|
|
41
41
|
"react-native": "*"
|
|
42
42
|
},
|
|
43
|
-
"gitHead": "
|
|
43
|
+
"gitHead": "c01c449a1d6e6e8690bfcc88a778b46781a59674"
|
|
44
44
|
}
|
package/src/Audio.types.ts
CHANGED
|
@@ -248,6 +248,11 @@ export type RecordingOptionsAndroid = {
|
|
|
248
248
|
};
|
|
249
249
|
|
|
250
250
|
export type AudioMode = {
|
|
251
|
+
/**
|
|
252
|
+
* Determines if audio playback is allowed when the device is in silent mode.
|
|
253
|
+
*
|
|
254
|
+
* @platform ios
|
|
255
|
+
*/
|
|
251
256
|
playsInSilentMode: boolean;
|
|
252
257
|
/**
|
|
253
258
|
* Determines how the audio session interacts with other sessions.
|
|
@@ -255,8 +260,22 @@ export type AudioMode = {
|
|
|
255
260
|
* @platform ios
|
|
256
261
|
*/
|
|
257
262
|
interruptionMode: InterruptionMode;
|
|
263
|
+
/**
|
|
264
|
+
* Whether the audio session allows recording.
|
|
265
|
+
*
|
|
266
|
+
* @default false
|
|
267
|
+
* @platform ios
|
|
268
|
+
*/
|
|
258
269
|
allowsRecording: boolean;
|
|
270
|
+
/**
|
|
271
|
+
* Whether the audio session stays active when the app moves to the background.
|
|
272
|
+
* @default false
|
|
273
|
+
*/
|
|
259
274
|
shouldPlayInBackground: boolean;
|
|
275
|
+
/**
|
|
276
|
+
* Whether the audio should route through the earpiece.
|
|
277
|
+
* @platform android
|
|
278
|
+
*/
|
|
260
279
|
shouldRouteThroughEarpiece: boolean;
|
|
261
280
|
};
|
|
262
281
|
|