-
Notifications
You must be signed in to change notification settings - Fork 169
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
12d76d8
commit 93b5f5d
Showing
28 changed files
with
1,179 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# intellij | ||
*.iml | ||
|
||
.gradle | ||
/local.properties | ||
/.idea/workspace.xml | ||
/.idea/libraries | ||
.DS_Store | ||
/build | ||
/captures | ||
.externalNativeBuild | ||
app/build | ||
|
||
.settings/ | ||
app/jniLibs/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
# Screen Sharing | ||
|
||
This app shows how to use `WebView` as the source for screen-sharing video. | ||
|
||
> Check [Basic-Video-Capturer-Camera-2](../Basic-Video-Capturer-Camera-2) project to see how a device camera can be used as the video source for the custom `Capturer`. | ||
## Screen sharing | ||
|
||
Custom video capturer is using `WebView` from the Android application as the source of | ||
a published stream. | ||
|
||
When the app starts up, the `onCreate` method instantiates a `WebView` object: | ||
|
||
```java | ||
webViewContainer = findViewById(R.id.webview); | ||
``` | ||
|
||
Upon connecting to the OpenTok session, the app instantiates a `Publisher` object, and calls its | ||
`setCapturer` method to use a custom video capturer, defined by the `ScreenSharingCapturer` | ||
class: | ||
|
||
```java | ||
@Override | ||
public void onConnected(Session session) { | ||
ScreenSharingCapturer screenSharingCapturer = new ScreenSharingCapturer(MainActivity.this, webViewContainer); | ||
|
||
publisher = new Publisher.Builder(MainActivity.this) | ||
.capturer(screenSharingCapturer) | ||
.build(); | ||
|
||
publisher.setPublisherListener(publisherListener); | ||
publisher.setPublisherVideoType(PublisherKit.PublisherKitVideoType.PublisherKitVideoTypeScreen); | ||
publisher.setAudioFallbackEnabled(false); | ||
|
||
webViewContainer.setWebViewClient(new WebViewClient()); | ||
WebSettings webSettings = webViewContainer.getSettings(); | ||
webSettings.setJavaScriptEnabled(true); | ||
webViewContainer.setLayerType(View.LAYER_TYPE_SOFTWARE, null); | ||
webViewContainer.loadUrl("https://www.tokbox.com"); | ||
|
||
publisher.setStyle(BaseVideoRenderer.STYLE_VIDEO_SCALE, BaseVideoRenderer.STYLE_VIDEO_FILL); | ||
publisherViewContainer.addView(publisher.getView()); | ||
|
||
session.publish(publisher); | ||
} | ||
``` | ||
|
||
> Note: that the call to the `setPublisherVideoType` method sets the video type of the published | ||
stream to `PublisherKitVideoType.PublisherKitVideoTypeScreen`. This optimizes the video encoding for | ||
screen sharing. It is recommended to use a low frame rate (15 frames per second or lower) with this | ||
video type. When using the screen video type in a session that uses the [OpenTok Media | ||
Server](https://tokbox.com/opentok/tutorials/create-session/#media-mode), the | ||
audio-only fallback feature is disabled, so that the video does not drop out in subscribers. | ||
|
||
The `onConnected` method also calls the `loadScreenWebView` method. This method | ||
configures the WebView object, loading the TokBox URL. | ||
|
||
Note that the `webViewContainer` object is passed into the `ScreenSharingCapturer` constructor, | ||
which assigns it to the `contentView` property. | ||
|
||
The `getCaptureSettings` method initializes capture settings to be used by the custom | ||
video capturer: | ||
|
||
```java | ||
@Override | ||
public CaptureSettings getCaptureSettings() { | ||
|
||
CaptureSettings captureSettings = new CaptureSettings(); | ||
captureSettings.fps = fps; | ||
captureSettings.width = width; | ||
captureSettings.height = height; | ||
captureSettings.format = ARGB; | ||
return captureSettings; | ||
} | ||
``` | ||
|
||
The `startCapture` method starts the `frameProducer` thread after 1/15 second: | ||
|
||
```java | ||
@Override | ||
public int startCapture() { | ||
capturing = true; | ||
|
||
handler.postDelayed(newFrame, 1000 / fps); | ||
return 0; | ||
} | ||
``` | ||
|
||
The `frameProducer` thread gets a `Bitmap` representation of the `contentView` object | ||
(the `WebView`), writes its pixels to a buffer, and then calls the `provideIntArrayFrame()` | ||
method, passing in that buffer as a parameter: | ||
|
||
```java | ||
private Runnable newFrame = new Runnable() { | ||
@Override | ||
public void run() { | ||
if (capturing) { | ||
int width = contentView.getWidth(); | ||
int height = contentView.getHeight(); | ||
|
||
if (frame == null || | ||
ScreenSharingCapturer.this.width != width || | ||
ScreenSharingCapturer.this.height != height) { | ||
|
||
ScreenSharingCapturer.this.width = width; | ||
ScreenSharingCapturer.this.height = height; | ||
|
||
if (bmp != null) { | ||
bmp.recycle(); | ||
bmp = null; | ||
} | ||
|
||
bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); | ||
|
||
canvas = new Canvas(bmp); | ||
frame = new int[width * height]; | ||
} | ||
canvas.saveLayer(0, 0, width, height, null); | ||
canvas.translate(-contentView.getScrollX(), - contentView.getScrollY()); | ||
contentView.draw(canvas); | ||
|
||
bmp.getPixels(frame, 0, width, 0, 0, width, height); | ||
|
||
provideIntArrayFrame(frame, ARGB, width, height, 0, false); | ||
|
||
canvas.restore(); | ||
|
||
handler.postDelayed(newFrame, 1000 / fps); | ||
|
||
} | ||
} | ||
}; | ||
``` | ||
|
||
The `provideIntArrayFrame` method, defined by the `BaseVideoCapturer` class sends an integer array of data to the publisher, to be used for the next video frame published. | ||
|
||
If the publisher is still capturing video, the thread starts again after another 1/15 of a | ||
second, so that the capturer continues to supply the publisher with new video frames to publish. | ||
``` | ||
## Further Reading | ||
* Review [other sample projects](../) | ||
* Read more about [OpenTok Android SDK](https://tokbox.com/developer/sdks/android/) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/build |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
plugins { | ||
id 'com.android.application' | ||
} | ||
|
||
apply { | ||
from '../../commons.gradle' | ||
} | ||
|
||
android { | ||
compileSdkVersion extCompileSdkVersion | ||
|
||
defaultConfig { | ||
applicationId "com.tokbox.sample.screensharing" | ||
minSdkVersion extMinSdkVersion | ||
targetSdkVersion extTargetSdkVersion | ||
versionCode extVersionCode | ||
versionName extVersionName | ||
} | ||
|
||
buildTypes { | ||
release { | ||
minifyEnabled extMinifyEnabled | ||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' | ||
} | ||
} | ||
|
||
compileOptions { | ||
sourceCompatibility JavaVersion.VERSION_1_8 | ||
targetCompatibility JavaVersion.VERSION_1_8 | ||
} | ||
} | ||
|
||
dependencies { | ||
// Dependency versions are defined in the ../../commons.gradle file | ||
implementation "com.opentok.android:opentok-android-sdk:${extOpentokSdkVersion}" | ||
implementation "androidx.appcompat:appcompat:${extAppCompatVersion}" | ||
implementation "pub.devrel:easypermissions:${extEasyPermissionsVersion}" | ||
} |
29 changes: 29 additions & 0 deletions
29
Device-Screen-Sharing-Java/app/src/main/AndroidManifest.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||
package="com.tokbox.sample.screensharing"> | ||
|
||
<uses-permission android:name="android.permission.INTERNET" /> | ||
<uses-permission android:name="android.permission.CAMERA" /> | ||
<uses-permission android:name="android.permission.RECORD_AUDIO" /> | ||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> | ||
|
||
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" | ||
android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> | ||
<activity | ||
android:name=".MainActivity" | ||
android:screenOrientation="portrait" | ||
android:exported="true"> | ||
<intent-filter> | ||
<action android:name="android.intent.action.MAIN" /> | ||
|
||
<category android:name="android.intent.category.LAUNCHER" /> | ||
</intent-filter> | ||
</activity> | ||
<service | ||
android:enabled="true" | ||
android:name=".ScreenSharingService" | ||
android:foregroundServiceType="mediaProjection"> | ||
</service> | ||
</application> | ||
|
||
</manifest> |
Oops, something went wrong.