@abdurrahman-dev/react-native-ivs-broadcast 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +296 -0
- package/android/build.gradle +61 -0
- package/android/src/main/AndroidManifest.xml +13 -0
- package/android/src/main/java/com/reactnativeivsbroadcast/IVSBroadcastModule.kt +433 -0
- package/android/src/main/java/com/reactnativeivsbroadcast/IVSBroadcastPackage.kt +17 -0
- package/ios/IVSBroadcast.podspec +24 -0
- package/ios/IVSBroadcastModule.h +7 -0
- package/ios/IVSBroadcastModule.m +513 -0
- package/lib/index.d.ts +78 -0
- package/lib/index.js +234 -0
- package/lib/types.d.ts +55 -0
- package/lib/types.js +2 -0
- package/package.json +57 -0
- package/src/index.ts +273 -0
- package/src/types.ts +72 -0
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
package com.reactnativeivsbroadcast
|
|
2
|
+
|
|
3
|
+
import android.app.Activity
|
|
4
|
+
import android.content.Context
|
|
5
|
+
import android.view.View
|
|
6
|
+
import com.amazonaws.ivs.broadcast.BroadcastConfiguration
|
|
7
|
+
import com.amazonaws.ivs.broadcast.BroadcastSession
|
|
8
|
+
import com.amazonaws.ivs.broadcast.BroadcastState
|
|
9
|
+
import com.amazonaws.ivs.broadcast.Device
|
|
10
|
+
import com.amazonaws.ivs.broadcast.DeviceDescriptor
|
|
11
|
+
import com.amazonaws.ivs.broadcast.ImageDevice
|
|
12
|
+
import com.amazonaws.ivs.broadcast.MicrophoneDevice
|
|
13
|
+
import com.facebook.react.bridge.*
|
|
14
|
+
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
15
|
+
import java.net.URI
|
|
16
|
+
import java.util.concurrent.ConcurrentHashMap
|
|
17
|
+
|
|
18
|
+
class IVSBroadcastModule(reactContext: ReactApplicationContext) :
|
|
19
|
+
ReactContextBaseJavaModule(reactContext) {
|
|
20
|
+
|
|
21
|
+
private val sessions = ConcurrentHashMap<String, BroadcastSession>()
|
|
22
|
+
private val sessionUrls = ConcurrentHashMap<String, URI>()
|
|
23
|
+
private val reactContext = reactContext
|
|
24
|
+
|
|
25
|
+
override fun getName(): String {
|
|
26
|
+
return "IVSBroadcastModule"
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@ReactMethod
|
|
30
|
+
fun createSession(config: ReadableMap, promise: Promise) {
|
|
31
|
+
try {
|
|
32
|
+
val rtmpUrl = config.getString("rtmpUrl")
|
|
33
|
+
?: throw IllegalArgumentException("rtmpUrl is required")
|
|
34
|
+
|
|
35
|
+
val streamKey = config.getString("streamKey")
|
|
36
|
+
|
|
37
|
+
val fullUrl = if (streamKey != null) {
|
|
38
|
+
"$rtmpUrl/$streamKey"
|
|
39
|
+
} else {
|
|
40
|
+
rtmpUrl
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
val broadcastConfig = BroadcastConfiguration()
|
|
44
|
+
|
|
45
|
+
// Video config
|
|
46
|
+
val videoConfig = config.getMap("videoConfig")
|
|
47
|
+
if (videoConfig != null) {
|
|
48
|
+
broadcastConfig.videoConfig.apply {
|
|
49
|
+
videoConfig.getInt("width")?.let { width = it }
|
|
50
|
+
videoConfig.getInt("height")?.let { height = it }
|
|
51
|
+
videoConfig.getInt("bitrate")?.let { bitrate = it }
|
|
52
|
+
videoConfig.getInt("fps")?.let { targetFps = it }
|
|
53
|
+
videoConfig.getInt("targetFps")?.let { targetFps = it }
|
|
54
|
+
videoConfig.getInt("keyframeInterval")?.let { keyframeInterval = it }
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Audio config
|
|
59
|
+
val audioConfig = config.getMap("audioConfig")
|
|
60
|
+
if (audioConfig != null) {
|
|
61
|
+
broadcastConfig.audioConfig.apply {
|
|
62
|
+
audioConfig.getInt("bitrate")?.let { bitrate = it }
|
|
63
|
+
audioConfig.getInt("sampleRate")?.let { sampleRate = it }
|
|
64
|
+
audioConfig.getInt("channels")?.let { channels = it }
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
val sessionId = java.util.UUID.randomUUID().toString()
|
|
69
|
+
|
|
70
|
+
// Listener'ı sessionId ile birlikte oluştur
|
|
71
|
+
val listener = object : BroadcastSession.Listener() {
|
|
72
|
+
override fun onStateChanged(state: BroadcastState.State) {
|
|
73
|
+
val eventMap = createStateMap(state)
|
|
74
|
+
eventMap.putString("sessionId", sessionId)
|
|
75
|
+
sendEvent("onStateChanged", eventMap)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
override fun onError(error: Exception) {
|
|
79
|
+
val eventMap = createErrorMap(error)
|
|
80
|
+
eventMap.putString("sessionId", sessionId)
|
|
81
|
+
sendEvent("onError", eventMap)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
override fun onNetworkHealth(health: BroadcastSession.NetworkHealth) {
|
|
85
|
+
val eventMap = createNetworkHealthMap(health)
|
|
86
|
+
eventMap.putString("sessionId", sessionId)
|
|
87
|
+
sendEvent("onNetworkHealth", eventMap)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
override fun onAudioStats(stats: BroadcastSession.AudioStats) {
|
|
91
|
+
val eventMap = createAudioStatsMap(stats)
|
|
92
|
+
eventMap.putString("sessionId", sessionId)
|
|
93
|
+
sendEvent("onAudioStats", eventMap)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
override fun onVideoStats(stats: BroadcastSession.VideoStats) {
|
|
97
|
+
val eventMap = createVideoStatsMap(stats)
|
|
98
|
+
eventMap.putString("sessionId", sessionId)
|
|
99
|
+
sendEvent("onVideoStats", eventMap)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
val session = BroadcastSession(
|
|
104
|
+
reactContext.applicationContext,
|
|
105
|
+
broadcastConfig,
|
|
106
|
+
listener
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
sessions[sessionId] = session
|
|
110
|
+
sessionUrls[sessionId] = URI.create(fullUrl)
|
|
111
|
+
|
|
112
|
+
promise.resolve(sessionId)
|
|
113
|
+
} catch (e: Exception) {
|
|
114
|
+
promise.reject("CREATE_SESSION_ERROR", e.message, e)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
@ReactMethod
|
|
119
|
+
fun startBroadcast(sessionId: String, promise: Promise) {
|
|
120
|
+
try {
|
|
121
|
+
val session = sessions[sessionId]
|
|
122
|
+
?: throw IllegalArgumentException("Session not found: $sessionId")
|
|
123
|
+
|
|
124
|
+
val url = sessionUrls[sessionId]
|
|
125
|
+
?: throw IllegalArgumentException("Session URL not found: $sessionId")
|
|
126
|
+
|
|
127
|
+
val devices = getDevices(sessionId)
|
|
128
|
+
session.start(url, devices)
|
|
129
|
+
|
|
130
|
+
promise.resolve(null)
|
|
131
|
+
} catch (e: Exception) {
|
|
132
|
+
promise.reject("START_BROADCAST_ERROR", e.message, e)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
@ReactMethod
|
|
137
|
+
fun stopBroadcast(sessionId: String, promise: Promise) {
|
|
138
|
+
try {
|
|
139
|
+
val session = sessions[sessionId]
|
|
140
|
+
?: throw IllegalArgumentException("Session not found: $sessionId")
|
|
141
|
+
|
|
142
|
+
session.stop()
|
|
143
|
+
|
|
144
|
+
promise.resolve(null)
|
|
145
|
+
} catch (e: Exception) {
|
|
146
|
+
promise.reject("STOP_BROADCAST_ERROR", e.message, e)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
@ReactMethod
|
|
151
|
+
fun pauseBroadcast(sessionId: String, promise: Promise) {
|
|
152
|
+
try {
|
|
153
|
+
val session = sessions[sessionId]
|
|
154
|
+
?: throw IllegalArgumentException("Session not found: $sessionId")
|
|
155
|
+
|
|
156
|
+
session.pause()
|
|
157
|
+
|
|
158
|
+
promise.resolve(null)
|
|
159
|
+
} catch (e: Exception) {
|
|
160
|
+
promise.reject("PAUSE_BROADCAST_ERROR", e.message, e)
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
@ReactMethod
|
|
165
|
+
fun resumeBroadcast(sessionId: String, promise: Promise) {
|
|
166
|
+
try {
|
|
167
|
+
val session = sessions[sessionId]
|
|
168
|
+
?: throw IllegalArgumentException("Session not found: $sessionId")
|
|
169
|
+
|
|
170
|
+
session.resume()
|
|
171
|
+
|
|
172
|
+
promise.resolve(null)
|
|
173
|
+
} catch (e: Exception) {
|
|
174
|
+
promise.reject("RESUME_BROADCAST_ERROR", e.message, e)
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
@ReactMethod
|
|
179
|
+
fun destroySession(sessionId: String, promise: Promise) {
|
|
180
|
+
try {
|
|
181
|
+
val session = sessions.remove(sessionId)
|
|
182
|
+
?: throw IllegalArgumentException("Session not found: $sessionId")
|
|
183
|
+
|
|
184
|
+
sessionUrls.remove(sessionId)
|
|
185
|
+
session.stop()
|
|
186
|
+
session.release()
|
|
187
|
+
|
|
188
|
+
promise.resolve(null)
|
|
189
|
+
} catch (e: Exception) {
|
|
190
|
+
promise.reject("DESTROY_SESSION_ERROR", e.message, e)
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
@ReactMethod
|
|
195
|
+
fun getState(sessionId: String, promise: Promise) {
|
|
196
|
+
try {
|
|
197
|
+
val session = sessions[sessionId]
|
|
198
|
+
?: throw IllegalArgumentException("Session not found: $sessionId")
|
|
199
|
+
|
|
200
|
+
val state = session.state
|
|
201
|
+
promise.resolve(createStateMap(state))
|
|
202
|
+
} catch (e: Exception) {
|
|
203
|
+
promise.reject("GET_STATE_ERROR", e.message, e)
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
@ReactMethod
|
|
208
|
+
fun switchCamera(sessionId: String, promise: Promise) {
|
|
209
|
+
try {
|
|
210
|
+
val session = sessions[sessionId]
|
|
211
|
+
?: throw IllegalArgumentException("Session not found: $sessionId")
|
|
212
|
+
|
|
213
|
+
val availableCameras = session.listAvailableDevices(DeviceDescriptor.DeviceType.CAMERA)
|
|
214
|
+
if (availableCameras.isEmpty()) {
|
|
215
|
+
throw IllegalStateException("No camera devices available")
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
val activeDevices = session.listActiveDevices()
|
|
219
|
+
val currentCamera = activeDevices.firstOrNull {
|
|
220
|
+
it.descriptor.type == DeviceDescriptor.DeviceType.CAMERA
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
val newCamera = availableCameras.firstOrNull {
|
|
224
|
+
it.descriptor.uid != currentCamera?.descriptor?.uid
|
|
225
|
+
} ?: availableCameras.first()
|
|
226
|
+
|
|
227
|
+
if (currentCamera != null) {
|
|
228
|
+
session.replaceDevice(currentCamera, newCamera)
|
|
229
|
+
} else {
|
|
230
|
+
session.addDevice(newCamera)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
promise.resolve(null)
|
|
234
|
+
} catch (e: Exception) {
|
|
235
|
+
promise.reject("SWITCH_CAMERA_ERROR", e.message, e)
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
@ReactMethod
|
|
240
|
+
fun setCameraPosition(sessionId: String, position: String, promise: Promise) {
|
|
241
|
+
try {
|
|
242
|
+
val session = sessions[sessionId]
|
|
243
|
+
?: throw IllegalArgumentException("Session not found: $sessionId")
|
|
244
|
+
|
|
245
|
+
val cameraType = when (position) {
|
|
246
|
+
"front" -> DeviceDescriptor.DeviceType.CAMERA_FRONT
|
|
247
|
+
"back" -> DeviceDescriptor.DeviceType.CAMERA_BACK
|
|
248
|
+
else -> throw IllegalArgumentException("Invalid camera position: $position")
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
val cameraDevices = session.listAvailableDevices(cameraType)
|
|
252
|
+
if (cameraDevices.isEmpty()) {
|
|
253
|
+
throw IllegalStateException("Camera device not available: $position")
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
val currentCamera = session.listActiveDevices()
|
|
257
|
+
.firstOrNull { it.descriptor.type == DeviceDescriptor.DeviceType.CAMERA }
|
|
258
|
+
|
|
259
|
+
val newCamera = cameraDevices.first()
|
|
260
|
+
|
|
261
|
+
if (currentCamera != null) {
|
|
262
|
+
session.replaceDevice(currentCamera, newCamera)
|
|
263
|
+
} else {
|
|
264
|
+
session.addDevice(newCamera)
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
promise.resolve(null)
|
|
268
|
+
} catch (e: Exception) {
|
|
269
|
+
promise.reject("SET_CAMERA_POSITION_ERROR", e.message, e)
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
@ReactMethod
|
|
274
|
+
fun setMuted(sessionId: String, muted: Boolean, promise: Promise) {
|
|
275
|
+
try {
|
|
276
|
+
val session = sessions[sessionId]
|
|
277
|
+
?: throw IllegalArgumentException("Session not found: $sessionId")
|
|
278
|
+
|
|
279
|
+
val microphone = session.listActiveDevices()
|
|
280
|
+
.firstOrNull { it.descriptor.type == DeviceDescriptor.DeviceType.MICROPHONE }
|
|
281
|
+
as? MicrophoneDevice
|
|
282
|
+
|
|
283
|
+
microphone?.setMuted(muted)
|
|
284
|
+
|
|
285
|
+
promise.resolve(null)
|
|
286
|
+
} catch (e: Exception) {
|
|
287
|
+
promise.reject("SET_MUTED_ERROR", e.message, e)
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
@ReactMethod
|
|
292
|
+
fun isMuted(sessionId: String, promise: Promise) {
|
|
293
|
+
try {
|
|
294
|
+
val session = sessions[sessionId]
|
|
295
|
+
?: throw IllegalArgumentException("Session not found: $sessionId")
|
|
296
|
+
|
|
297
|
+
val microphone = session.listActiveDevices()
|
|
298
|
+
.firstOrNull { it.descriptor.type == DeviceDescriptor.DeviceType.MICROPHONE }
|
|
299
|
+
as? MicrophoneDevice
|
|
300
|
+
|
|
301
|
+
promise.resolve(microphone?.isMuted ?: false)
|
|
302
|
+
} catch (e: Exception) {
|
|
303
|
+
promise.reject("IS_MUTED_ERROR", e.message, e)
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
@ReactMethod
|
|
308
|
+
fun updateVideoConfig(sessionId: String, config: ReadableMap, promise: Promise) {
|
|
309
|
+
try {
|
|
310
|
+
val session = sessions[sessionId]
|
|
311
|
+
?: throw IllegalArgumentException("Session not found: $sessionId")
|
|
312
|
+
|
|
313
|
+
val videoConfig = session.configuration.videoConfig
|
|
314
|
+
config.getInt("width")?.let { videoConfig.width = it }
|
|
315
|
+
config.getInt("height")?.let { videoConfig.height = it }
|
|
316
|
+
config.getInt("bitrate")?.let { videoConfig.bitrate = it }
|
|
317
|
+
config.getInt("fps")?.let { videoConfig.targetFps = it }
|
|
318
|
+
config.getInt("targetFps")?.let { videoConfig.targetFps = it }
|
|
319
|
+
config.getInt("keyframeInterval")?.let { videoConfig.keyframeInterval = it }
|
|
320
|
+
|
|
321
|
+
promise.resolve(null)
|
|
322
|
+
} catch (e: Exception) {
|
|
323
|
+
promise.reject("UPDATE_VIDEO_CONFIG_ERROR", e.message, e)
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
@ReactMethod
|
|
328
|
+
fun updateAudioConfig(sessionId: String, config: ReadableMap, promise: Promise) {
|
|
329
|
+
try {
|
|
330
|
+
val session = sessions[sessionId]
|
|
331
|
+
?: throw IllegalArgumentException("Session not found: $sessionId")
|
|
332
|
+
|
|
333
|
+
val audioConfig = session.configuration.audioConfig
|
|
334
|
+
config.getInt("bitrate")?.let { audioConfig.bitrate = it }
|
|
335
|
+
config.getInt("sampleRate")?.let { audioConfig.sampleRate = it }
|
|
336
|
+
config.getInt("channels")?.let { audioConfig.channels = it }
|
|
337
|
+
|
|
338
|
+
promise.resolve(null)
|
|
339
|
+
} catch (e: Exception) {
|
|
340
|
+
promise.reject("UPDATE_AUDIO_CONFIG_ERROR", e.message, e)
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
private fun getDevices(sessionId: String): List<Device> {
|
|
345
|
+
val session = sessions[sessionId]
|
|
346
|
+
?: throw IllegalArgumentException("Session not found: $sessionId")
|
|
347
|
+
|
|
348
|
+
val devices = mutableListOf<Device>()
|
|
349
|
+
|
|
350
|
+
// Kamera ekle (öncelikle arka kamera)
|
|
351
|
+
val backCameraDescriptors = session.listAvailableDevices(DeviceDescriptor.DeviceType.CAMERA_BACK)
|
|
352
|
+
val frontCameraDescriptors = session.listAvailableDevices(DeviceDescriptor.DeviceType.CAMERA_FRONT)
|
|
353
|
+
val anyCameraDescriptors = session.listAvailableDevices(DeviceDescriptor.DeviceType.CAMERA)
|
|
354
|
+
|
|
355
|
+
val cameraDescriptor = when {
|
|
356
|
+
backCameraDescriptors.isNotEmpty() -> backCameraDescriptors.first()
|
|
357
|
+
frontCameraDescriptors.isNotEmpty() -> frontCameraDescriptors.first()
|
|
358
|
+
anyCameraDescriptors.isNotEmpty() -> anyCameraDescriptors.first()
|
|
359
|
+
else -> null
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
if (cameraDescriptor != null) {
|
|
363
|
+
val cameraDevice = session.addDevice(cameraDescriptor)
|
|
364
|
+
if (cameraDevice != null) {
|
|
365
|
+
devices.add(cameraDevice)
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Mikrofon ekle
|
|
370
|
+
val microphoneDescriptors = session.listAvailableDevices(DeviceDescriptor.DeviceType.MICROPHONE)
|
|
371
|
+
if (microphoneDescriptors.isNotEmpty()) {
|
|
372
|
+
val microphoneDevice = session.addDevice(microphoneDescriptors.first())
|
|
373
|
+
if (microphoneDevice != null) {
|
|
374
|
+
devices.add(microphoneDevice)
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
return devices
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
private fun sendEvent(eventName: String, params: WritableMap?) {
|
|
382
|
+
reactContext
|
|
383
|
+
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
384
|
+
.emit(eventName, params)
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
private fun createStateMap(state: BroadcastState.State): WritableMap {
|
|
388
|
+
val map = Arguments.createMap()
|
|
389
|
+
map.putBoolean("isBroadcasting", state == BroadcastState.State.CONNECTED)
|
|
390
|
+
map.putBoolean("isPaused", state == BroadcastState.State.PAUSED)
|
|
391
|
+
return map
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
private fun createErrorMap(error: Exception): WritableMap {
|
|
395
|
+
val map = Arguments.createMap()
|
|
396
|
+
map.putString("message", error.message ?: "Unknown error")
|
|
397
|
+
map.putString("code", error.javaClass.simpleName)
|
|
398
|
+
return map
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
private fun createNetworkHealthMap(health: BroadcastSession.NetworkHealth): WritableMap {
|
|
402
|
+
val map = Arguments.createMap()
|
|
403
|
+
val quality = when (health.networkQuality) {
|
|
404
|
+
BroadcastSession.NetworkHealth.Quality.EXCELLENT -> "excellent"
|
|
405
|
+
BroadcastSession.NetworkHealth.Quality.GOOD -> "good"
|
|
406
|
+
BroadcastSession.NetworkHealth.Quality.FAIR -> "fair"
|
|
407
|
+
BroadcastSession.NetworkHealth.Quality.POOR -> "poor"
|
|
408
|
+
else -> "unknown"
|
|
409
|
+
}
|
|
410
|
+
map.putString("networkQuality", quality)
|
|
411
|
+
map.putDouble("uplinkBandwidth", health.uplinkBandwidth.toDouble())
|
|
412
|
+
map.putDouble("rtt", health.rtt.toDouble())
|
|
413
|
+
return map
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
private fun createAudioStatsMap(stats: BroadcastSession.AudioStats): WritableMap {
|
|
417
|
+
val map = Arguments.createMap()
|
|
418
|
+
map.putDouble("bitrate", stats.bitrate.toDouble())
|
|
419
|
+
map.putDouble("sampleRate", stats.sampleRate.toDouble())
|
|
420
|
+
map.putInt("channels", stats.channels)
|
|
421
|
+
return map
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
private fun createVideoStatsMap(stats: BroadcastSession.VideoStats): WritableMap {
|
|
425
|
+
val map = Arguments.createMap()
|
|
426
|
+
map.putDouble("bitrate", stats.bitrate.toDouble())
|
|
427
|
+
map.putDouble("fps", stats.fps.toDouble())
|
|
428
|
+
map.putInt("width", stats.width)
|
|
429
|
+
map.putInt("height", stats.height)
|
|
430
|
+
return map
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
package com.reactnativeivsbroadcast
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.ReactPackage
|
|
4
|
+
import com.facebook.react.bridge.NativeModule
|
|
5
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
+
import com.facebook.react.uimanager.ViewManager
|
|
7
|
+
|
|
8
|
+
class IVSBroadcastPackage : ReactPackage {
|
|
9
|
+
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
|
|
10
|
+
return listOf(IVSBroadcastModule(reactContext))
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
|
|
14
|
+
return emptyList()
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, "../package.json")))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = "IVSBroadcast"
|
|
7
|
+
s.version = package["version"]
|
|
8
|
+
s.summary = package["description"]
|
|
9
|
+
s.description = <<-DESC
|
|
10
|
+
React Native bridge for Amazon IVS Broadcast SDK
|
|
11
|
+
DESC
|
|
12
|
+
s.homepage = "https://github.com/yourusername/react-native-ivs-broadcast"
|
|
13
|
+
s.license = "MIT"
|
|
14
|
+
s.author = { "author" => "author@example.com" }
|
|
15
|
+
s.platforms = { :ios => "11.0" }
|
|
16
|
+
s.source = { :git => "https://github.com/yourusername/react-native-ivs-broadcast.git", :tag => "#{s.version}" }
|
|
17
|
+
|
|
18
|
+
s.source_files = "ios/**/*.{h,m,mm,swift}"
|
|
19
|
+
s.requires_arc = true
|
|
20
|
+
|
|
21
|
+
s.dependency "React-Core"
|
|
22
|
+
s.dependency "AmazonIVSBroadcast", "1.37.0"
|
|
23
|
+
end
|
|
24
|
+
|