8000 Implemented getDisplayMedia for Android. · CodeStrings/flutter-webrtc@65f4957 · GitHub
[go: up one dir, main page]

Skip to content

Commit 65f4957

Browse files
committed
Implemented getDisplayMedia for Android.
1 parent 66aaf91 commit 65f4957

File tree

8 files changed

+273
-124
lines changed

8 files changed

+273
-124
lines changed

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

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,11 @@ public void onMethodCall(MethodCall call, Result result) {
274274
double volume = call.argument("volume");
275275
mediaStreamTrackSetVolume(trackId, volume);
276276
result.success(null);
277-
} else {
277+
} else if(call.method.equals("getDisplayMedia")) {
278+
Map<String, Object> constraints = call.argument("constraints");
279+
ConstraintsMap constraintsMap = new ConstraintsMap(constraints);
280+
getDisplayMedia(constraintsMap, result);
281+
}else {
278282
result.notImplemented();
279283
}
280284
}
@@ -682,6 +686,24 @@ public void getUserMedia(ConstraintsMap constraints, Result result) {
682686
getUserMediaImpl.getUserMedia(constraints, result, mediaStream);
683687
}
684688

689+
public void getDisplayMedia(ConstraintsMap constraints, Result result) {
690+
String streamId = getNextStreamUUID();
691+
MediaStream mediaStream = mFactory.createLocalMediaStream(streamId);
692+
693+
if (mediaStream == null) {
694+
// XXX The following does not follow the getUserMedia() algorithm
695+
// specified by
696+
// https://www.w3.org/TR/mediacapture-streams/#dom-mediadevices-getusermedia
697+
// with respect to distinguishing the various causes of failure.
698+
result.error(
699+
/* type */ "getDisplayMedia",
700+
"Failed to create new media stream", null);
701+
return;
702+
}
703+
704+
getUserMediaImpl.getDisplayMedia(constraints, result, mediaStream);
705+
}
706+
685707
public void getSources(Result result) {
686708
ConstraintsArray array = new ConstraintsArray();
687709
String[] names = new String[Camera.getNumberOfCameras()];

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

Lines changed: 130 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ private void checkSelfPermissions(boolean requestPermissions) {
9696
if(resultCode != Activity.RESULT_OK) {
9797
Activity activity = this.getActivity();
9898
Bundle args = getArguments();
99-
resultReceiver = (ResultReceiver) args.getParcelable(RESULT_RECEIVER);
99+
resultReceiver = args.getParcelable(RESULT_RECEIVER);
100100
requestCode = args.getInt(REQUEST_CODE);
101101
requestStart(activity, requestCode);
102102
}
@@ -151,7 +151,6 @@ private void finish() {
151151
@Override
152152
public void onResume() {
153153
super.onResume();
154-
155154
checkSelfPermissions(/* requestPermissions */ true);
156155
}
157156
}
@@ -326,123 +325,8 @@ void getUserMedia(
326325
}
327326
}
328327

329-
boolean requestScreenCapturer = videoConstraintsMandatory != null &&
330-
videoConstraintsMandatory.hasKey("chromeMediaSource") &&
331-
videoConstraintsMandatory.getString("chromeMediaSource").equals("desktop");
332-
333328
final ArrayList<String> requestPermissions = new ArrayList<>();
334329

335-
if(requestScreenCapturer)
336-
{
337-
final ConstraintsMap videoConstraintsMandatory2 = videoConstraintsMandatory;
338-
screenRequestPremissions(new ResultReceiver(new Handler(Looper.getMainLooper())) {
339-
@Override
340-
protected void onReceiveResult(
341-
int requestCode,
342-
Bundle resultData) {
343-
344-
/*Create ScreenCapture*/
345-
int resultCode = resultData.getInt(GRANT_RESULTS);
346-
Intent mediaProjectionData = resultData.getParcelable(PROJECTION_DATA);
347-
348-
if (resultCode != Activity.RESULT_OK) {
349-
result.error( null,
350-
"User didn't give permission to capture the screen.", null);
351-
return;
352-
}
353-
354-
MediaStreamTrack[] tracks = new MediaStreamTrack[1];
355-
VideoCapturer videoCapturer = null;
356-
videoCapturer = new ScreenCapturerAndroid(
357-
mediaProjectionData, new MediaProjection.Callback() {
358-
@Override
359-
public void onStop() {
360-
Log.e(TAG, "User revoked permission to capture the screen.");
361-
result.error( null,
362-
"User revoked permission to capture the screen.", null);
363-
}
364-
});
365-
366-
if (videoCapturer != null) {
367-
368-
PeerConnectionFactory pcFactory = plugin.mFactory;
369-
VideoSource videoSource = pcFactory.createVideoSource(true);
370-
371-
// Fall back to defaults if keys are missing.
372-
int width
373-
= videoConstraintsMandatory2.hasKey("minWidth")
374-
? videoConstraintsMandatory2.getInt("minWidth")
375-
: DEFAULT_WIDTH;
376-
int height
377-
= videoConstraintsMandatory2.hasKey("minHeight")
378-
? videoConstraintsMandatory2.getInt("minHeight")
379-
: DEFAULT_HEIGHT;
380-
int fps
381-
= videoConstraintsMandatory2.hasKey("minFrameRate")
382-
? videoConstraintsMandatory2.getInt("minFrameRate")
383-
: DEFAULT_FPS;
384-
385-
videoCapturer.startCapture(width, height, fps);
386-
387-
String trackId = plugin.getNextTrackUUID();
388-
mVideoCapturers.put(trackId, videoCapturer);
389-
390-
Log.d(TAG, "changeCaptureFormat: " + width + "x" + height + "@" + fps);
391-
videoSource.adaptOutputFormat(width, height, fps);
392-
393-
tracks[0] = pcFactory.createVideoTrack(trackId, videoSource);
394-
395-
ConstraintsArray audioTracks = new ConstraintsArray();
396-
ConstraintsArray videoTracks = new ConstraintsArray();
397-
ConstraintsMap successResult = new ConstraintsMap();
398-
399-
for (MediaStreamTrack track : tracks) {
400-
if (track == null) {
401-
continue;
402-
}
403-
404-
String id = track.id();
405-
406-
if (track instanceof AudioTrack) {
407-
mediaStream.addTrack((AudioTrack) track);
408-
} else {
409-
mediaStream.addTrack((VideoTrack) track);
410-
}
411-
plugin.localTracks.put(id, track);
412-
413-
ConstraintsMap track_ = new ConstraintsMap();
414-
String kind = track.kind();
415-
416-
track_.putBoolean("enabled", track.enabled());
417-
track_.putString("id", id);
418-
track_.putString("kind", kind);
419-
track_.putString("label", kind);
420-
track_.putString("readyState", track.state().toString());
421-
track_.putBoolean("remote", false);
422-
423-
if (track instanceof AudioTrack) {
424-
audioTracks.pushMap(track_);
425-
} else {
426-
videoTracks.pushMap(track_);
427-
}
428-
}
429-
430-
String streamId = mediaStream.getId();
431-
432-
Log.d(TAG, "MediaStream id: " + streamId);
433-
plugin.localStreams.put(streamId, mediaStream);
434-
435-
successResult.putString("streamId", streamId);
436-
successResult.putArray("audioTracks", audioTracks.toArrayList());
437-
successResult.putArray("videoTracks", audioTracks.toArrayList());
438-
result.success(successResult.toMap());
439-
}
440-
441-
}
442-
});
443-
return;
444-
}
445-
446330
if (constraints.hasKey("audio")) {
447331
switch (constraints.getType("audio")) {
448332
case Boolean:
@@ -458,7 +342,7 @@ public void onStop() {
458342
}
459343
}
460344

461-
if (constraints.hasKey("video") && !requestScreenCapturer) {
345+
if (constraints.hasKey("video")) {
462346
switch (constraints.getType("video")) {
463347
case Boolean:
464348
if (constraints.getBoolean("video")) {
@@ -513,6 +397,134 @@ public void invoke(Object... args) {
513397
);
514398
}
515399

400+
void getDisplayMedia(
401+
final ConstraintsMap constraints,
402+
final Result result,
403+
final MediaStream mediaStream) {
404+
ConstraintsMap videoConstraintsMap = null;
405+
ConstraintsMap videoConstraintsMandatory = null;
406+
407+
if (constraints.getType("video") == ObjectType.Map) {
408+
videoConstraintsMap = constraints.getMap("video");
409+
if (videoConstraintsMap.hasKey("mandatory")
410+
&& videoConstraintsMap.getType("mandatory")
411+
== ObjectType.Map) {
412+
videoConstraintsMandatory
413+
= videoConstraintsMap.getMap("mandatory");
414+
}
415+
}
416+
417+
final ConstraintsMap videoConstraintsMandatory2 = videoConstraintsMandatory;
418+
screenRequestPremissions(new ResultReceiver(new Handler(Looper.getMainLooper())) {
419+
@Override
420+
protected void onReceiveResult(
421+
int requestCode,
422+
Bundle resultData) {
423+
424+
/* Create ScreenCapture */
425+
int resultCode = resultData.getInt(GRANT_RESULTS);
426+
Intent mediaProjectionData = resultData.getParcelable(PROJECTION_DATA);
427+
428+
if (resultCode != Activity.RESULT_OK) {
429+
result.error(null, "User didn't give permission to capture the screen.", null);
430+
return;
431+
}
432+
433+
MediaStreamTrack[] tracks = new MediaStreamTrack[1];
434+
VideoCapturer videoCapturer = null;
435+
videoCapturer = new ScreenCapturerAndroid(mediaProjectionData, new MediaProjection.Callback() {
436+
@Override
437+
public void onStop() {
438+
Log.e(TAG, "User revoked permission to capture the screen.");
439+
result.error(null, "User revoked permission to capture the screen.", null);
440+
}
441+
});
442+
if (videoCapturer != null) {
443+
PeerConnectionFactory pcFactory = plugin.mFactory;
444+
VideoSource videoSource = pcFactory.createVideoSource(true);
445+
446+
Context context = plugin.getContext();
447+
String threadName = Thread.currentThread().getName();
448+
SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.create(threadName, EglUtils.getRootEglBaseContext());
449+
videoCapturer.initialize(surfaceTextureHelper, context, videoSource.getCapturerObserver());
450+
451+
452+
// Fall back to defaults if keys are missing.
453+
int width
454+
= videoConstraintsMandatory2.hasKey("minWidth")
455+
? videoConstraintsMandatory2.getInt("minWidth")
456+
: DEFAULT_WIDTH;
457+
int height
458+
= videoConstraintsMandatory2.hasKey("minHeight")
459+
? videoConstraintsMandatory2.getInt("minHeight")
460+
: DEFAULT_HEIGHT;
461+
int fps
462+
= videoConstraintsMandatory2.hasKey("minFrameRate")
463+
? videoConstraintsMandatory2.getInt("minFrameRate")
464+
: DEFAULT_FPS;
465+
466+
videoCapturer.startCapture(width, height, fps);
467+
468+
String trackId = plugin.getNextTrackUUID();
469+
mVideoCapturers.put(trackId, videoCapturer);
470+
471+
Log.d(TAG, "changeCaptureFormat: " + width + "x" + height + "@" + fps);
472+
videoSource.adaptOutputFormat(width, height, fps);
473+
474+
tracks[0] = pcFactory.createVideoTrack(trackId, videoSource);
475+
476+
ConstraintsArray audioTracks = new ConstraintsArray();
477+
ConstraintsArray videoTracks = new ConstraintsArray();
478+
ConstraintsMap successResult = new ConstraintsMap();
479+
480+
for (MediaStreamTrack track : tracks) {
481+
if (track == null) {
482+
continue;
483+
}
484+
485+
String id = track.id();
486+
487+
if (track instanceof AudioTrack) {
488+
mediaStream.addTrack((AudioTrack) track);
489+
} else {
490+
mediaStream.addTrack((VideoTrack) track);
491+
}
492+
plugin.localTracks.put(id, track);
493+
494+
ConstraintsMap track_ = new ConstraintsMap();
495+
String kind = track.kind();
496+
497+
track_.putBoolean("enabled", track.enabled());
498+
track_.putString("id", id);
499+
track_.putString("kind", kind);
500+
track_.putString("label", kind);
501+
track_.putString("readyState", track.state().toString());
502+
track_.putBoolean("remote", false);
503+
504+
if (track instanceof AudioTrack) {
505+
audioTracks.pushMap(track_);
506+
} else {
507+
videoTracks.pushMap(track_);
508+
}
509+
}
510+
511+
String streamId = mediaStream.getId();
512+
513+
Log.d(TAG, "MediaStream id: " + streamId);
514+
plugin.localStreams.put(streamId, mediaStream);
515+
successResult.putString("streamId", streamId);
516+
successResult.putArray("audioTracks", audioTracks.toArrayList());
517+
successResult.putArray("videoTracks", audioTracks.toArrayList());
518+
result.success(successResult.toMap());
519+
}else{
520+
result.error(
521+
/* type */ "GetDisplayMediaFailed",
522+
"Failed to create new VideoCapturer!", null);
523+
}
524+
}
525+
});
526+
}
527+
516528
/**
517529
* Implements {@code getUserMedia} with the knowledge that the necessary
518530
* permissions have already been granted. If the necessary permissions have

android/src/main/java/com/cloudwebrtc/webrtc/utils/Callback.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22

33
public interface Callback {
44

5-
public void invoke(Object... args);
5+
void invoke(Object... args);
66
}

android/src/main/java/com/cloudwebrtc/webrtc/utils/PermissionUtils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ private void checkSelfPermissions(boolean requestPermissions) {
188188
// the user about the denied ones.
189189
finish();
190190
send(
191-
(ResultReceiver) args.getParcelable(RESULT_RECEIVER),
191+
args.getParcelable(RESULT_RECEIVER),
192192
requestCode,
193193
permissions,
194194
grantResults);

example/lib/main.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
22
import 'dart:core';
33
import 'src/loopback_sample.dart';
44
import 'src/get_user_media_sample.dart';
5+
import 'src/get_display_media_sample.dart';
56
import 'src/data_channel_sample.dart';
67
import 'src/route_item.dart';
78

@@ -65,6 +66,15 @@ class _MyAppState extends State<MyApp> {
6566
builder: (BuildContext context) =>
6667
new GetUserMediaSample()));
6768
}),
69+
RouteItem(
70+
title: 'GetDisplayMedia',
71+
push: (BuildContext context) {
72+
Navigator.push(
73+
context,
74+
new MaterialPageRoute(
75+
builder: (BuildContext context) =>
76+
new GetDisplayMediaSample()));
77+
}),
6878
RouteItem(
6979
title: 'LoopBack Sample',
7080
push: (BuildContext context) {

0 commit comments

Comments
 (0)
0