8000 Fixed critical error when opening/closing camera. (#1633) · flutter-webrtc/flutter-webrtc@4637d53 · GitHub
[go: up one dir, main page]

Skip to content

Commit 4637d53

Browse files
authored
Fixed critical error when opening/closing camera. (#1633)
* Fixed critical error when opening/closing camera. * replace describeEnum to .name. * fixed analyzing issues. * bump version for dart-webrtc. * update.
1 parent bfb64e2 commit 4637d53

File tree

6 files changed

+90
-96
lines changed

6 files changed

+90
-96
lines changed

android/src/main/java/com/cloudwebrtc/webrtc/CameraEventsHandler.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,42 +5,80 @@
55
import org.webrtc.CameraVideoCapturer;
66

77
class CameraEventsHandler implements CameraVideoCapturer.CameraEventsHandler {
8+
public enum CameraState {
9+
NEW,
10+
OPENING,
11+
OPENED,
12+
CLOSED,
13+
DISCONNECTED,
14+
ERROR,
15+
FREEZED
16+
}
817
private final static String TAG = FlutterWebRTCPlugin.TAG;
18+
private CameraState state = CameraState.NEW;
19+
20+
public void waitForCameraOpen() {
21+
Log.d(TAG, "CameraEventsHandler.waitForCameraOpen");
22+
while (state != CameraState.OPENED && state != CameraState.ERROR) {
23+
try {
24+
Thread.sleep(1);
25+
} catch (InterruptedException e) {
26+
e.printStackTrace();
27+
}
28+
}
29+
}
30+
31+
public void waitForCameraClosed() {
32+
Log.d(TAG, "CameraEventsHandler.waitForCameraClosed");
33+
while (state != CameraState.CLOSED && state != CameraState.ERROR) {
34+
try {
35+
Thread.sleep(1);
36+
} catch (InterruptedException e) {
37+
e.printStackTrace();
38+
}
39+
}
40+
}
941

1042
// Camera error handler - invoked when camera can not be opened
1143
// or any camera exception happens on camera thread.
1244
@Override
1345
public void onCameraError(String errorDescription) {
1446
Log.d(TAG, String.format("CameraEventsHandler.onCameraError: errorDescription=%s", errorDescription));
47+
state = CameraState.ERROR;
1548
}
1649

1750
// Called when camera is disconnected.
1851
@Override
1952
public void onCameraDisconnected() {
2053
Log.d(TAG, "CameraEventsHandler.onCameraDisconnected");
54+
state = CameraState.DISCONNECTED;
2155
}
2256

2357
// Invoked when camera stops receiving frames
2458
@Override
2559
public void onCameraFreezed(String errorDescription) {
2660
Log.d(TAG, String.format("CameraEventsHandler.onCameraFreezed: errorDescription=%s", errorDescription));
61+
state = CameraState.FREEZED;
2762
}
2863

2964
// Callback invoked when camera is opening.
3065
@Override
3166
public void onCameraOpening(String cameraName) {
3267
Log.d(TAG, String.format("CameraEventsHandler.onCameraOpening: cameraName=%s", cameraName));
68+
state = CameraState.OPENING;
3369
}
3470

3571
// Callback invoked when first camera frame is available after camera is opened.
3672
@Override
3773
public void onFirstFrameAvailable() {
3874
Log.d(TAG, "CameraEventsHandler.onFirstFrameAvailable");
75+
state = CameraState.OPENED;
3976
}
4077

4178
// Callback invoked when camera closed.
4279
@Override
4380
public void onCameraClosed() {
4481
Log.d(TAG, "CameraEventsHandler.onFirstFrameAvailable");
82+
state = CameraState.CLOSED;
4583
}
4684
}

android/src/main/java/com/cloudwebrtc/webrtc/GetUserMediaImpl.java

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -270,15 +270,15 @@ private void addDefaultAudioConstraints(MediaConstraints audioConstraints) {
270270
* if not matched camera with specified facing mode.
271271
*/
272272
private Map<String, VideoCapturer> createVideoCapturer(
273-
CameraEnumerator enumerator, boolean isFacing, String sourceId) {
273+
CameraEnumerator enumerator, boolean isFacing, String sourceId, CameraEventsHandler cameraEventsHandler) {
274274
VideoCapturer videoCapturer = null;
275275
Map<String, VideoCapturer> result = new HashMap<String, VideoCapturer>();
276276
// if sourceId given, use specified sourceId first
277277
final String[] deviceNames = enumerator.getDeviceNames();
278278
if (sourceId != null && !sourceId.equals("")) {
279279
for (String name : deviceNames) {
280280
if (name.equals(sourceId)) {
281-
videoCapturer = enumerator.createCapturer(name, new CameraEventsHandler());
281+
videoCapturer = enumerator.createCapturer(name, cameraEventsHandler);
282282
if (videoCapturer != null) {
283283
Log.d(TAG, "create user specified camera " + name + " succeeded");
284284
result.put(name, videoCapturer);
@@ -295,10 +295,9 @@ private Map<String, VideoCapturer> createVideoCapturer(
295295
String facingStr = isFacing ? "front" : "back";
296296
for (String name : deviceNames) {
297297
if (enumerator.isFrontFacing(name) == isFacing) {
298-
videoCapturer = enumerator.createCapturer(name, new CameraEventsHandler());
298+
videoCapturer = enumerator.createCapturer(name, cameraEventsHandler);
299299
if (videoCapturer != null) {
300300
Log.d(TAG, "Create " + facingStr + " camera " + name + " succeeded");
301-
302301
result.put(name, videoCapturer);
303302
return result;
304303
} else {
@@ -309,7 +308,7 @@ private Map<String, VideoCapturer> createVideoCapturer(
309308

310309
// falling back to the first available camera
311310
if (videoCapturer == null && deviceNames.length > 0) {
312-
videoCapturer = enumerator.createCapturer(deviceNames[0], new CameraEventsHandler());
311+
videoCapturer = enumerator.createCapturer(deviceNames[0], cameraEventsHandler);
313312
Log.d(TAG, "Falling back to the first available camera");
314313
result.put(deviceNames[0], videoCapturer);
315314
}
@@ -741,15 +740,19 @@ private ConstraintsMap getUserVideo(ConstraintsMap constraints, MediaStream medi
741740
String facingMode = getFacingMode(videoConstraintsMap);
742741
isFacing = facingMode == null || !facingMode.equals("environment");
743742
String deviceId = getSourceIdConstraint(videoConstraintsMap);
744-
745-
Map<String, VideoCapturer> result = createVideoCapturer(cameraEnumerator, isFacing, deviceId);
743+
CameraEventsHandler cameraEventsHandler = new CameraEventsHandler();
744+
Map<String, VideoCapturer> result = createVideoCapturer(cameraEnumerator, isFacing, deviceId, cameraEventsHandler);
746745

747746
if (result == null) {
748747
return null;
749748
}
750749

751750
if (deviceId == null) {
752-
deviceId = result.keySet().iterator().next();
751+
if(!result.keySet().isEmpty()) {
752+
deviceId = result.keySet().iterator().next();
753+
} else {
754+
return null;
755+
}
753756
}
754757

755758
VideoCapturer videoCapturer = result.get(deviceId);
@@ -785,8 +788,11 @@ private ConstraintsMap getUserVideo(ConstraintsMap constraints, MediaStream medi
785788
? videoConstraintsMandatory.getInt("minFrameRate")
786789
: DEFAULT_FPS;
787790
info.capturer = videoCapturer;
791+
info.cameraEventsHandler = cameraEventsHandler;
788792
videoCapturer.startCapture(info.width, info.height, info.fps);
789793

794+
cameraEventsHandler.waitForCameraOpen();
795+
790796
String trackId = stateProvider.getNextTrackUUID();
791797
mVideoCapturers.put(trackId, info);
792798
mSurfaceTextureHelpers.put(trackId, surfaceTextureHelper);
@@ -819,34 +825,29 @@ private ConstraintsMap getUserVideo(ConstraintsMap constraints, MediaStream medi
819825
return trackParams;
820826
}
821827

822-
void removeVideoCapturerSync(String id) {
823-
synchronized (mVideoCapturers) {
824-
VideoCapturerInfo info = mVideoCapturers.get(id);
825-
if (info != null) {
826-
try {
827-
info.capturer.stopCapture();
828-
} catch (InterruptedException e) {
829-
Log.e(TAG, "removeVideoCapturer() Failed to stop video capturer");
830-
} finally {
831-
info.capturer.dispose();
832-
mVideoCapturers.remove(id);
833-
SurfaceTextureHelper helper = mSurfaceTextureHelpers.get(id);
834-
if (helper != null) {
835-
helper.stopListening();
836-
helper.dispose();
837-
mSurfaceTextureHelpers.remove(id);
838-
}
828+
void removeVideoCapturer(String id) {
829+
VideoCapturerInfo info = mVideoCapturers.get(id);
830+
if (info != null) {
831+
try {
832+
info.capturer.stopCapture();
833+
if (info.cameraEventsHandler != null) {
834+
info.cameraEventsHandler.waitForCameraClosed();
835+
}
836+
} catch (InterruptedException e) {
837+
Log.e(TAG, "removeVideoCapturer() Failed to stop video capturer");
838+
} finally {
839+
info.capturer.dispose();
840+
mVideoCapturers.remove(id);
841+
SurfaceTextureHelper helper = mSurfaceTextureHelpers.get(id);
842+
if (helper != null) {
843+
helper.stopListening();
844+
helper.dispose();
845+
mSurfaceTextureHelpers.remove(id);
839846
}
840847
}
841848
}
842849
}
843850

844-
void removeVideoCapturer(String id) {
845-
new Thread(() -> {
846-
removeVideoCapturerSync(id);
847-
}).start();
848-
}
849-
850851
@RequiresApi(api = VERSION_CODES.M)
851852
private void requestPermissions(
852853
final ArrayList<String> permissions,
@@ -1289,6 +1290,7 @@ public class VideoCapturerInfo {
12891290
int height;
12901291
int fps;
12911292
boolean isScreenCapture = false;
1293+
CameraEventsHandler cameraEventsHandler;
12921294
}
12931295

12941296
@RequiresApi(api = VERSION_CODES.M)

lib/src/native/adapter_type.dart

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import 'package:flutter/foundation.dart';
2-
31
enum AdapterType {
42
adapterTypeUnknown,
53
adapterTypeEthernet,
@@ -9,7 +7,3 @@ enum AdapterType {
97
adapterTypeLoopback,
108
adapterTypeAny
119
}
12-
13-
extension AdapterTypeExt on AdapterType {
14-
String get value => describeEnum(this);
15-
}

lib/src/native/android/audio_configuration.dart

Lines changed: 11 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import 'package:flutter/foundation.dart';
2-
31
import '../utils.dart';
42

53
enum AndroidAudioMode {
@@ -10,13 +8,9 @@ enum AndroidAudioMode {
108
ringtone,
119
}
1210

13-
extension AndroidAudioModeExt on AndroidAudioMode {
14-
String get value => describeEnum(this);
15-
}
16-
1711
extension AndroidAudioModeEnumEx on String {
18-
AndroidAudioMode toAndroidAudioMode() => AndroidAudioMode.values
19-
.firstWhere((d) => describeEnum(d) == toLowerCase());
12+
AndroidAudioMode toAndroidAudioMode() =>
13+
AndroidAudioMode.values.firstWhere((d) => d.name == toLowerCase());
2014
}
2115

2216
enum AndroidAudioFocusMode {
@@ -26,14 +20,9 @@ enum AndroidAudioFocusMode {
2620
gainTransientMayDuck
2721
}
2822

29-
extension AndroidAudioFocusModeExt on AndroidAudioFocusMode {
30-
String get value => describeEnum(this);
31-
}
32-
3323
extension AndroidAudioFocusModeEnumEx on String {
3424
AndroidAudioFocusMode toAndroidAudioFocusMode() =>
35-
AndroidAudioFocusMode.values
36-
.firstWhere((d) => describeEnum(d) == toLowerCase());
25+
AndroidAudioFocusMode.values.firstWhere((d) => d.name == toLowerCase());
3726
}
3827

3928
enum AndroidAudioStreamType {
@@ -47,14 +36,9 @@ enum AndroidAudioStreamType {
4736
voiceCall
4837
}
4938

50-
extension AndroidAudioStreamTypeExt on AndroidAudioStreamType {
51-
String get value => describeEnum(this);
52-
}
53-
5439
extension AndroidAudioStreamTypeEnumEx on String {
5540
AndroidAudioStreamType toAndroidAudioStreamType() =>
56-
AndroidAudioStreamType.values
57-
.firstWhere((d) => describeEnum(d) == toLowerCase());
41+
AndroidAudioStreamType.values.firstWhere((d) => d.name == toLowerCase());
5842
}
5943

6044
enum AndroidAudioAttributesUsageType {
@@ -73,15 +57,10 @@ enum AndroidAudioAttributesUsageType {
7357
voiceCommunicationSignalling
7458
}
7559

76-
extension AndroidAudioAttributesUsageTypeExt
77-
on AndroidAudioAttributesUsageType {
78-
String get value => describeEnum(this);
79-
}
80-
8160
extension AndroidAudioAttributesUsageTypeEnumEx on String {
8261
AndroidAudioAttributesUsageType toAndroidAudioAttributesUsageType() =>
8362
AndroidAudioAttributesUsageType.values
84-
.firstWhere((d) => describeEnum(d) == toLowerCase());
63+
.firstWhere((d) => d.name == toLowerCase());
8564
}
8665

8766
enum AndroidAudioAttributesContentType {
@@ -92,15 +71,10 @@ enum AndroidAudioAttributesContentType {
9271
unknown
9372
}
9473

95-
extension AndroidAudioAttributesContentTypeExt
96-
on AndroidAudioAttributesContentType {
97-
String get value => describeEnum(this);
98-
}
99-
10074
extension AndroidAudioAttributesContentTypeEnumEx on String {
10175
AndroidAudioAttributesContentType toAndroidAudioAttributesContentType() =>
10276
AndroidAudioAttributesContentType.values
103-
.firstWhere((d) => describeEnum(d) == toLowerCase());
77+
.firstWhere((d) => d.name == toLowerCase());
10478
}
10579

10680
class AndroidAudioConfiguration {
@@ -133,17 +107,17 @@ class AndroidAudioConfiguration {
133107
Map<String, dynamic> toMap() => <String, dynamic>{
134108
if (manageAudioFocus != null) 'manageAudioFocus': manageAudioFocus!,
135109
if (androidAudioMode != null)
136-
'androidAudioMode': androidAudioMode!.value,
110+
'androidAudioMode': androidAudioMode!.name,
137111
if (androidAudioFocusMode != null)
138-
'androidAudioFocusMode': androidAudioFocusMode!.value,
112+
'androidAudioFocusMode': androidAudioFocusMode!.name,
139113
if (androidAudioStreamType != null)
140-
'androidAudioStreamType': androidAudioStreamType!.value,
114+
'androidAudioStreamType': androidAudioStreamType!.name,
141115
if (androidAudioAttributesUsageType != null)
142116
'androidAudioAttributesUsageType':
143-
androidAudioAttributesUsageType!.value,
117+
androidAudioAttributesUsageType!.name,
144118
if (androidAudioAttributesContentType != null)
145119
'androidAudioAttributesContentType':
146-
androidAudioAttributesContentType!.value,
120+
androidAudioAttributesContentType!.name,
147121
if (forceHandleAudioRouting != null)
148122
'forceHandleAudioRouting': forceHandleAudioRouting!,
149123
};

0 commit comments

Comments
 (0)
0