@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.
Potentially problematic release.
This version of @abdurrahman-dev/react-native-ivs-broadcast might be problematic. Click here for more details.
- 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,513 @@
|
|
|
1
|
+
#import "IVSBroadcastModule.h"
|
|
2
|
+
#import <AmazonIVSBroadcast/AmazonIVSBroadcast.h>
|
|
3
|
+
|
|
4
|
+
@interface IVSBroadcastModule () <IVSBroadcastSessionDelegate>
|
|
5
|
+
@property (nonatomic, strong) NSMutableDictionary<NSString *, IVSBroadcastSession *> *sessions;
|
|
6
|
+
@property (nonatomic, strong) NSMutableDictionary<NSString *, NSURL *> *sessionUrls;
|
|
7
|
+
@end
|
|
8
|
+
|
|
9
|
+
@implementation IVSBroadcastModule
|
|
10
|
+
|
|
11
|
+
RCT_EXPORT_MODULE();
|
|
12
|
+
|
|
13
|
+
- (instancetype)init {
|
|
14
|
+
self = [super init];
|
|
15
|
+
if (self) {
|
|
16
|
+
_sessions = [NSMutableDictionary dictionary];
|
|
17
|
+
_sessionUrls = [NSMutableDictionary dictionary];
|
|
18
|
+
}
|
|
19
|
+
return self;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
+ (BOOL)requiresMainQueueSetup {
|
|
23
|
+
return YES;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
- (NSArray<NSString *> *)supportedEvents {
|
|
27
|
+
return @[
|
|
28
|
+
@"onStateChanged",
|
|
29
|
+
@"onError",
|
|
30
|
+
@"onNetworkHealth",
|
|
31
|
+
@"onAudioStats",
|
|
32
|
+
@"onVideoStats"
|
|
33
|
+
];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
RCT_EXPORT_METHOD(createSession:(NSDictionary *)config
|
|
37
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
38
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
39
|
+
@try {
|
|
40
|
+
NSString *rtmpUrl = config[@"rtmpUrl"];
|
|
41
|
+
if (!rtmpUrl) {
|
|
42
|
+
reject(@"CREATE_SESSION_ERROR", @"rtmpUrl is required", nil);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
NSString *streamKey = config[@"streamKey"];
|
|
47
|
+
NSString *fullUrl = streamKey ? [NSString stringWithFormat:@"%@/%@", rtmpUrl, streamKey] : rtmpUrl;
|
|
48
|
+
|
|
49
|
+
IVSBroadcastConfiguration *broadcastConfig = [[IVSBroadcastConfiguration alloc] init];
|
|
50
|
+
|
|
51
|
+
// Video config
|
|
52
|
+
NSDictionary *videoConfig = config[@"videoConfig"];
|
|
53
|
+
if (videoConfig) {
|
|
54
|
+
if (videoConfig[@"width"]) {
|
|
55
|
+
broadcastConfig.videoConfig.width = [videoConfig[@"width"] intValue];
|
|
56
|
+
}
|
|
57
|
+
if (videoConfig[@"height"]) {
|
|
58
|
+
broadcastConfig.videoConfig.height = [videoConfig[@"height"] intValue];
|
|
59
|
+
}
|
|
60
|
+
if (videoConfig[@"bitrate"]) {
|
|
61
|
+
broadcastConfig.videoConfig.bitrate = [videoConfig[@"bitrate"] intValue];
|
|
62
|
+
}
|
|
63
|
+
if (videoConfig[@"fps"]) {
|
|
64
|
+
broadcastConfig.videoConfig.targetFps = [videoConfig[@"fps"] intValue];
|
|
65
|
+
}
|
|
66
|
+
if (videoConfig[@"targetFps"]) {
|
|
67
|
+
broadcastConfig.videoConfig.targetFps = [videoConfig[@"targetFps"] intValue];
|
|
68
|
+
}
|
|
69
|
+
if (videoConfig[@"keyframeInterval"]) {
|
|
70
|
+
broadcastConfig.videoConfig.keyframeInterval = [videoConfig[@"keyframeInterval"] intValue];
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Audio config
|
|
75
|
+
NSDictionary *audioConfig = config[@"audioConfig"];
|
|
76
|
+
if (audioConfig) {
|
|
77
|
+
if (audioConfig[@"bitrate"]) {
|
|
78
|
+
broadcastConfig.audioConfig.bitrate = [audioConfig[@"bitrate"] intValue];
|
|
79
|
+
}
|
|
80
|
+
if (audioConfig[@"sampleRate"]) {
|
|
81
|
+
broadcastConfig.audioConfig.sampleRate = [audioConfig[@"sampleRate"] intValue];
|
|
82
|
+
}
|
|
83
|
+
if (audioConfig[@"channels"]) {
|
|
84
|
+
broadcastConfig.audioConfig.channels = [audioConfig[@"channels"] intValue];
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
IVSBroadcastSession *session = [[IVSBroadcastSession alloc] initWithConfiguration:broadcastConfig
|
|
89
|
+
delegate:self
|
|
90
|
+
error:nil];
|
|
91
|
+
|
|
92
|
+
if (!session) {
|
|
93
|
+
reject(@"CREATE_SESSION_ERROR", @"Failed to create broadcast session", nil);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
NSString *sessionId = [[NSUUID UUID] UUIDString];
|
|
98
|
+
self.sessions[sessionId] = session;
|
|
99
|
+
self.sessionUrls[sessionId] = [NSURL URLWithString:fullUrl];
|
|
100
|
+
|
|
101
|
+
resolve(sessionId);
|
|
102
|
+
} @catch (NSException *exception) {
|
|
103
|
+
reject(@"CREATE_SESSION_ERROR", exception.reason, nil);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
RCT_EXPORT_METHOD(startBroadcast:(NSString *)sessionId
|
|
108
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
109
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
110
|
+
@try {
|
|
111
|
+
IVSBroadcastSession *session = self.sessions[sessionId];
|
|
112
|
+
if (!session) {
|
|
113
|
+
reject(@"START_BROADCAST_ERROR", @"Session not found", nil);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
NSURL *url = self.sessionUrls[sessionId];
|
|
118
|
+
if (!url) {
|
|
119
|
+
reject(@"START_BROADCAST_ERROR", @"Session URL not found", nil);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
NSError *error = nil;
|
|
124
|
+
BOOL success = [session startWithURL:url error:&error];
|
|
125
|
+
|
|
126
|
+
if (!success) {
|
|
127
|
+
reject(@"START_BROADCAST_ERROR", error.localizedDescription, error);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
resolve(nil);
|
|
132
|
+
} @catch (NSException *exception) {
|
|
133
|
+
reject(@"START_BROADCAST_ERROR", exception.reason, nil);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
RCT_EXPORT_METHOD(stopBroadcast:(NSString *)sessionId
|
|
138
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
139
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
140
|
+
@try {
|
|
141
|
+
IVSBroadcastSession *session = self.sessions[sessionId];
|
|
142
|
+
if (!session) {
|
|
143
|
+
reject(@"STOP_BROADCAST_ERROR", @"Session not found", nil);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
[session stop];
|
|
148
|
+
resolve(nil);
|
|
149
|
+
} @catch (NSException *exception) {
|
|
150
|
+
reject(@"STOP_BROADCAST_ERROR", exception.reason, nil);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
RCT_EXPORT_METHOD(pauseBroadcast:(NSString *)sessionId
|
|
155
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
156
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
157
|
+
@try {
|
|
158
|
+
IVSBroadcastSession *session = self.sessions[sessionId];
|
|
159
|
+
if (!session) {
|
|
160
|
+
reject(@"PAUSE_BROADCAST_ERROR", @"Session not found", nil);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
[session pause];
|
|
165
|
+
resolve(nil);
|
|
166
|
+
} @catch (NSException *exception) {
|
|
167
|
+
reject(@"PAUSE_BROADCAST_ERROR", exception.reason, nil);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
RCT_EXPORT_METHOD(resumeBroadcast:(NSString *)sessionId
|
|
172
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
173
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
174
|
+
@try {
|
|
175
|
+
IVSBroadcastSession *session = self.sessions[sessionId];
|
|
176
|
+
if (!session) {
|
|
177
|
+
reject(@"RESUME_BROADCAST_ERROR", @"Session not found", nil);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
[session resume];
|
|
182
|
+
resolve(nil);
|
|
183
|
+
} @catch (NSException *exception) {
|
|
184
|
+
reject(@"RESUME_BROADCAST_ERROR", exception.reason, nil);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
RCT_EXPORT_METHOD(destroySession:(NSString *)sessionId
|
|
189
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
190
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
191
|
+
@try {
|
|
192
|
+
IVSBroadcastSession *session = self.sessions[sessionId];
|
|
193
|
+
if (!session) {
|
|
194
|
+
reject(@"DESTROY_SESSION_ERROR", @"Session not found", nil);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
[session stop];
|
|
199
|
+
[self.sessions removeObjectForKey:sessionId];
|
|
200
|
+
[self.sessionUrls removeObjectForKey:sessionId];
|
|
201
|
+
resolve(nil);
|
|
202
|
+
} @catch (NSException *exception) {
|
|
203
|
+
reject(@"DESTROY_SESSION_ERROR", exception.reason, nil);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
RCT_EXPORT_METHOD(getState:(NSString *)sessionId
|
|
208
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
209
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
210
|
+
@try {
|
|
211
|
+
IVSBroadcastSession *session = self.sessions[sessionId];
|
|
212
|
+
if (!session) {
|
|
213
|
+
reject(@"GET_STATE_ERROR", @"Session not found", nil);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
NSDictionary *state = @{
|
|
218
|
+
@"isBroadcasting": @(session.state == IVSBroadcastSessionStateConnected),
|
|
219
|
+
@"isPaused": @(session.state == IVSBroadcastSessionStatePaused)
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
resolve(state);
|
|
223
|
+
} @catch (NSException *exception) {
|
|
224
|
+
reject(@"GET_STATE_ERROR", exception.reason, nil);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
RCT_EXPORT_METHOD(switchCamera:(NSString *)sessionId
|
|
229
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
230
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
231
|
+
@try {
|
|
232
|
+
IVSBroadcastSession *session = self.sessions[sessionId];
|
|
233
|
+
if (!session) {
|
|
234
|
+
reject(@"SWITCH_CAMERA_ERROR", @"Session not found", nil);
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
NSArray<IVSDeviceDescriptor *> *cameras = [session listAvailableDevices:IVSDeviceTypeCamera];
|
|
239
|
+
if (cameras.count == 0) {
|
|
240
|
+
reject(@"SWITCH_CAMERA_ERROR", @"No camera devices available", nil);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
IVSDeviceDescriptor *currentCamera = [session listActiveDevices:IVSDeviceTypeCamera].firstObject;
|
|
245
|
+
IVSDeviceDescriptor *newCamera = cameras.firstObject;
|
|
246
|
+
|
|
247
|
+
for (IVSDeviceDescriptor *camera in cameras) {
|
|
248
|
+
if (![camera.uid isEqualToString:currentCamera.uid]) {
|
|
249
|
+
newCamera = camera;
|
|
250
|
+
break;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (currentCamera) {
|
|
255
|
+
[session replaceDevice:currentCamera withDevice:newCamera];
|
|
256
|
+
} else {
|
|
257
|
+
[session addDevice:newCamera];
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
resolve(nil);
|
|
261
|
+
} @catch (NSException *exception) {
|
|
262
|
+
reject(@"SWITCH_CAMERA_ERROR", exception.reason, nil);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
RCT_EXPORT_METHOD(setCameraPosition:(NSString *)sessionId
|
|
267
|
+
position:(NSString *)position
|
|
268
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
269
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
270
|
+
@try {
|
|
271
|
+
IVSBroadcastSession *session = self.sessions[sessionId];
|
|
272
|
+
if (!session) {
|
|
273
|
+
reject(@"SET_CAMERA_POSITION_ERROR", @"Session not found", nil);
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
IVSDeviceType deviceType = [position isEqualToString:@"front"]
|
|
278
|
+
? IVSDeviceTypeCameraFront
|
|
279
|
+
: IVSDeviceTypeCameraBack;
|
|
280
|
+
|
|
281
|
+
NSArray<IVSDeviceDescriptor *> *cameras = [session listAvailableDevices:deviceType];
|
|
282
|
+
if (cameras.count == 0) {
|
|
283
|
+
reject(@"SET_CAMERA_POSITION_ERROR",
|
|
284
|
+
[NSString stringWithFormat:@"Camera device not available: %@", position], nil);
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
IVSDeviceDescriptor *currentCamera = [session listActiveDevices:IVSDeviceTypeCamera].firstObject;
|
|
289
|
+
IVSDeviceDescriptor *newCamera = cameras.firstObject;
|
|
290
|
+
|
|
291
|
+
if (currentCamera) {
|
|
292
|
+
[session replaceDevice:currentCamera withDevice:newCamera];
|
|
293
|
+
} else {
|
|
294
|
+
[session addDevice:newCamera];
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
resolve(nil);
|
|
298
|
+
} @catch (NSException *exception) {
|
|
299
|
+
reject(@"SET_CAMERA_POSITION_ERROR", exception.reason, nil);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
RCT_EXPORT_METHOD(setMuted:(NSString *)sessionId
|
|
304
|
+
muted:(BOOL)muted
|
|
305
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
306
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
307
|
+
@try {
|
|
308
|
+
IVSBroadcastSession *session = self.sessions[sessionId];
|
|
309
|
+
if (!session) {
|
|
310
|
+
reject(@"SET_MUTED_ERROR", @"Session not found", nil);
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
IVSDeviceDescriptor *microphone = [session listActiveDevices:IVSDeviceTypeMicrophone].firstObject;
|
|
315
|
+
if (microphone) {
|
|
316
|
+
IVSMicrophoneDevice *micDevice = (IVSMicrophoneDevice *)[session deviceWithDescriptor:microphone];
|
|
317
|
+
[micDevice setMuted:muted];
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
resolve(nil);
|
|
321
|
+
} @catch (NSException *exception) {
|
|
322
|
+
reject(@"SET_MUTED_ERROR", exception.reason, nil);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
RCT_EXPORT_METHOD(isMuted:(NSString *)sessionId
|
|
327
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
328
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
329
|
+
@try {
|
|
330
|
+
IVSBroadcastSession *session = self.sessions[sessionId];
|
|
331
|
+
if (!session) {
|
|
332
|
+
reject(@"IS_MUTED_ERROR", @"Session not found", nil);
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
IVSDeviceDescriptor *microphone = [session listActiveDevices:IVSDeviceTypeMicrophone].firstObject;
|
|
337
|
+
BOOL muted = NO;
|
|
338
|
+
if (microphone) {
|
|
339
|
+
IVSMicrophoneDevice *micDevice = (IVSMicrophoneDevice *)[session deviceWithDescriptor:microphone];
|
|
340
|
+
muted = micDevice.isMuted;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
resolve(@(muted));
|
|
344
|
+
} @catch (NSException *exception) {
|
|
345
|
+
reject(@"IS_MUTED_ERROR", exception.reason, nil);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
RCT_EXPORT_METHOD(updateVideoConfig:(NSString *)sessionId
|
|
350
|
+
config:(NSDictionary *)config
|
|
351
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
352
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
353
|
+
@try {
|
|
354
|
+
IVSBroadcastSession *session = self.sessions[sessionId];
|
|
355
|
+
if (!session) {
|
|
356
|
+
reject(@"UPDATE_VIDEO_CONFIG_ERROR", @"Session not found", nil);
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
IVSBroadcastConfiguration *broadcastConfig = session.configuration;
|
|
361
|
+
if (config[@"width"]) {
|
|
362
|
+
broadcastConfig.videoConfig.width = [config[@"width"] intValue];
|
|
363
|
+
}
|
|
364
|
+
if (config[@"height"]) {
|
|
365
|
+
broadcastConfig.videoConfig.height = [config[@"height"] intValue];
|
|
366
|
+
}
|
|
367
|
+
if (config[@"bitrate"]) {
|
|
368
|
+
broadcastConfig.videoConfig.bitrate = [config[@"bitrate"] intValue];
|
|
369
|
+
}
|
|
370
|
+
if (config[@"fps"]) {
|
|
371
|
+
broadcastConfig.videoConfig.targetFps = [config[@"fps"] intValue];
|
|
372
|
+
}
|
|
373
|
+
if (config[@"targetFps"]) {
|
|
374
|
+
broadcastConfig.videoConfig.targetFps = [config[@"targetFps"] intValue];
|
|
375
|
+
}
|
|
376
|
+
if (config[@"keyframeInterval"]) {
|
|
377
|
+
broadcastConfig.videoConfig.keyframeInterval = [config[@"keyframeInterval"] intValue];
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
resolve(nil);
|
|
381
|
+
} @catch (NSException *exception) {
|
|
382
|
+
reject(@"UPDATE_VIDEO_CONFIG_ERROR", exception.reason, nil);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
RCT_EXPORT_METHOD(updateAudioConfig:(NSString *)sessionId
|
|
387
|
+
config:(NSDictionary *)config
|
|
388
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
389
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
390
|
+
@try {
|
|
391
|
+
IVSBroadcastSession *session = self.sessions[sessionId];
|
|
392
|
+
if (!session) {
|
|
393
|
+
reject(@"UPDATE_AUDIO_CONFIG_ERROR", @"Session not found", nil);
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
IVSBroadcastConfiguration *broadcastConfig = session.configuration;
|
|
398
|
+
if (config[@"bitrate"]) {
|
|
399
|
+
broadcastConfig.audioConfig.bitrate = [config[@"bitrate"] intValue];
|
|
400
|
+
}
|
|
401
|
+
if (config[@"sampleRate"]) {
|
|
402
|
+
broadcastConfig.audioConfig.sampleRate = [config[@"sampleRate"] intValue];
|
|
403
|
+
}
|
|
404
|
+
if (config[@"channels"]) {
|
|
405
|
+
broadcastConfig.audioConfig.channels = [config[@"channels"] intValue];
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
resolve(nil);
|
|
409
|
+
} @catch (NSException *exception) {
|
|
410
|
+
reject(@"UPDATE_AUDIO_CONFIG_ERROR", exception.reason, nil);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
#pragma mark - IVSBroadcastSessionDelegate
|
|
415
|
+
|
|
416
|
+
- (void)broadcastSession:(IVSBroadcastSession *)session didChangeState:(IVSBroadcastSessionState)state {
|
|
417
|
+
NSString *sessionId = [self sessionIdForSession:session];
|
|
418
|
+
if (!sessionId) return;
|
|
419
|
+
|
|
420
|
+
NSMutableDictionary *stateDict = [NSMutableDictionary dictionaryWithDictionary:@{
|
|
421
|
+
@"isBroadcasting": @(state == IVSBroadcastSessionStateConnected),
|
|
422
|
+
@"isPaused": @(state == IVSBroadcastSessionStatePaused)
|
|
423
|
+
}];
|
|
424
|
+
stateDict[@"sessionId"] = sessionId;
|
|
425
|
+
|
|
426
|
+
[self sendEventWithName:@"onStateChanged" body:stateDict];
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
- (void)broadcastSession:(IVSBroadcastSession *)session didEmitError:(NSError *)error {
|
|
430
|
+
NSString *sessionId = [self sessionIdForSession:session];
|
|
431
|
+
if (!sessionId) return;
|
|
432
|
+
|
|
433
|
+
NSMutableDictionary *errorDict = [NSMutableDictionary dictionaryWithDictionary:@{
|
|
434
|
+
@"message": error.localizedDescription ?: @"Unknown error",
|
|
435
|
+
@"code": @(error.code).stringValue
|
|
436
|
+
}];
|
|
437
|
+
errorDict[@"sessionId"] = sessionId;
|
|
438
|
+
|
|
439
|
+
[self sendEventWithName:@"onError" body:errorDict];
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
- (void)broadcastSession:(IVSBroadcastSession *)session didEmitNetworkHealth:(IVSNetworkHealth *)health {
|
|
443
|
+
NSString *sessionId = [self sessionIdForSession:session];
|
|
444
|
+
if (!sessionId) return;
|
|
445
|
+
|
|
446
|
+
NSString *quality = @"unknown";
|
|
447
|
+
switch (health.networkQuality) {
|
|
448
|
+
case IVSNetworkQualityExcellent:
|
|
449
|
+
quality = @"excellent";
|
|
450
|
+
break;
|
|
451
|
+
case IVSNetworkQualityGood:
|
|
452
|
+
quality = @"good";
|
|
453
|
+
break;
|
|
454
|
+
case IVSNetworkQualityFair:
|
|
455
|
+
quality = @"fair";
|
|
456
|
+
break;
|
|
457
|
+
case IVSNetworkQualityPoor:
|
|
458
|
+
quality = @"poor";
|
|
459
|
+
break;
|
|
460
|
+
default:
|
|
461
|
+
break;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
NSMutableDictionary *healthDict = [NSMutableDictionary dictionaryWithDictionary:@{
|
|
465
|
+
@"networkQuality": quality,
|
|
466
|
+
@"uplinkBandwidth": @(health.uplinkBandwidth),
|
|
467
|
+
@"rtt": @(health.rtt)
|
|
468
|
+
}];
|
|
469
|
+
healthDict[@"sessionId"] = sessionId;
|
|
470
|
+
|
|
471
|
+
[self sendEventWithName:@"onNetworkHealth" body:healthDict];
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
- (void)broadcastSession:(IVSBroadcastSession *)session didEmitAudioStats:(IVSAudioStats *)stats {
|
|
475
|
+
NSString *sessionId = [self sessionIdForSession:session];
|
|
476
|
+
if (!sessionId) return;
|
|
477
|
+
|
|
478
|
+
NSMutableDictionary *statsDict = [NSMutableDictionary dictionaryWithDictionary:@{
|
|
479
|
+
@"bitrate": @(stats.bitrate),
|
|
480
|
+
@"sampleRate": @(stats.sampleRate),
|
|
481
|
+
@"channels": @(stats.channels)
|
|
482
|
+
}];
|
|
483
|
+
statsDict[@"sessionId"] = sessionId;
|
|
484
|
+
|
|
485
|
+
[self sendEventWithName:@"onAudioStats" body:statsDict];
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
- (void)broadcastSession:(IVSBroadcastSession *)session didEmitVideoStats:(IVSVideoStats *)stats {
|
|
489
|
+
NSString *sessionId = [self sessionIdForSession:session];
|
|
490
|
+
if (!sessionId) return;
|
|
491
|
+
|
|
492
|
+
NSMutableDictionary *statsDict = [NSMutableDictionary dictionaryWithDictionary:@{
|
|
493
|
+
@"bitrate": @(stats.bitrate),
|
|
494
|
+
@"fps": @(stats.fps),
|
|
495
|
+
@"width": @(stats.width),
|
|
496
|
+
@"height": @(stats.height)
|
|
497
|
+
}];
|
|
498
|
+
statsDict[@"sessionId"] = sessionId;
|
|
499
|
+
|
|
500
|
+
[self sendEventWithName:@"onVideoStats" body:statsDict];
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
- (NSString *)sessionIdForSession:(IVSBroadcastSession *)session {
|
|
504
|
+
for (NSString *sessionId in self.sessions.allKeys) {
|
|
505
|
+
if (self.sessions[sessionId] == session) {
|
|
506
|
+
return sessionId;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
return nil;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
@end
|
|
513
|
+
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { IVSBroadcastConfig, IVSBroadcastSession, BroadcastState, NetworkHealth, AudioStats, VideoStats, VideoConfig, AudioConfig } from "./types";
|
|
2
|
+
declare class IVSBroadcast {
|
|
3
|
+
private listeners;
|
|
4
|
+
/**
|
|
5
|
+
* Yeni bir broadcast session oluşturur
|
|
6
|
+
*/
|
|
7
|
+
createSession(config: IVSBroadcastConfig): Promise<IVSBroadcastSession>;
|
|
8
|
+
/**
|
|
9
|
+
* Broadcast'i başlatır
|
|
10
|
+
*/
|
|
11
|
+
startBroadcast(sessionId: string): Promise<void>;
|
|
12
|
+
/**
|
|
13
|
+
* Broadcast'i durdurur
|
|
14
|
+
*/
|
|
15
|
+
stopBroadcast(sessionId: string): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Broadcast'i duraklatır
|
|
18
|
+
*/
|
|
19
|
+
pauseBroadcast(sessionId: string): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Duraklatılmış broadcast'i devam ettirir
|
|
22
|
+
*/
|
|
23
|
+
resumeBroadcast(sessionId: string): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Broadcast session'ı yok eder
|
|
26
|
+
*/
|
|
27
|
+
destroySession(sessionId: string): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Broadcast durumunu alır
|
|
30
|
+
*/
|
|
31
|
+
getState(sessionId: string): Promise<BroadcastState>;
|
|
32
|
+
/**
|
|
33
|
+
* Kamera pozisyonunu değiştirir
|
|
34
|
+
*/
|
|
35
|
+
switchCamera(sessionId: string): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Kamera pozisyonunu ayarlar
|
|
38
|
+
*/
|
|
39
|
+
setCameraPosition(sessionId: string, position: "front" | "back"): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* Mikrofonu açıp kapatır
|
|
42
|
+
*/
|
|
43
|
+
setMuted(sessionId: string, muted: boolean): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Mikrofon durumunu alır
|
|
46
|
+
*/
|
|
47
|
+
isMuted(sessionId: string): Promise<boolean>;
|
|
48
|
+
/**
|
|
49
|
+
* Video konfigürasyonunu günceller
|
|
50
|
+
*/
|
|
51
|
+
updateVideoConfig(sessionId: string, config: VideoConfig): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* Audio konfigürasyonunu günceller
|
|
54
|
+
*/
|
|
55
|
+
updateAudioConfig(sessionId: string, config: AudioConfig): Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* Event listener ekler
|
|
58
|
+
*/
|
|
59
|
+
addListener(eventType: "onStateChanged", callback: (state: BroadcastState) => void): void;
|
|
60
|
+
addListener(eventType: "onError", callback: (error: {
|
|
61
|
+
message: string;
|
|
62
|
+
code?: string;
|
|
63
|
+
}) => void): void;
|
|
64
|
+
addListener(eventType: "onNetworkHealth", callback: (health: NetworkHealth) => void): void;
|
|
65
|
+
addListener(eventType: "onAudioStats", callback: (stats: AudioStats) => void): void;
|
|
66
|
+
addListener(eventType: "onVideoStats", callback: (stats: VideoStats) => void): void;
|
|
67
|
+
/**
|
|
68
|
+
* Event listener'ı kaldırır
|
|
69
|
+
*/
|
|
70
|
+
removeListener(eventType: string, callback?: (data: any) => void): void;
|
|
71
|
+
/**
|
|
72
|
+
* Tüm listener'ları temizler
|
|
73
|
+
*/
|
|
74
|
+
removeAllListeners(eventType?: string): void;
|
|
75
|
+
}
|
|
76
|
+
declare const _default: IVSBroadcast;
|
|
77
|
+
export default _default;
|
|
78
|
+
export * from "./types";
|