We are trying to use html5 getusermedia api to initialize webcamera in our android webview app. The code is perfectly working in the browsers, but when we deploy the page as webview in android app, it throws up error: "Could not access webcam:NotreadableError: could not start video source".
I do not understand as where i have gone wrong, based on other threads and documentation, i have followed everything from adding permissions to manifest file and importing libs, adding requestpermission function in mainactivity.java file.
Here is the MainActivity. Java / Android Manifest File and PHP file that we are using
MainActivity.Java
package com.example.mbracegate;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Build;
import android.graphics.Bitmap;
import java.util.*;
import android.view.View;
import android.webkit.PermissionRequest;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.Menu;
import android.webkit.CookieManager;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ProgressBar;
import android.content.pm.PackageManager;
public class MainActivity extends Activity {
private ProgressBar progressBar;
private WebView webView;
private class WebChromeClientDemo extends WebChromeClient {
private WebChromeClientDemo() {
}
public void onProgressChanged(WebView view, int progress) {
MainActivity.this.progressBar.setProgress(progress);
}
}
private class WebViewClientDemo extends WebViewClient {
private WebViewClientDemo() {
}
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
MainActivity.this.progressBar.setVisibility(8);
MainActivity.this.progressBar.setProgress(100);
}
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
MainActivity.this.progressBar.setVisibility(0);
MainActivity.this.progressBar.setProgress(0);
}
}
@SuppressLint({"SetJavaScriptEnabled"})
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.progressBar = (ProgressBar) findViewById(R.id.progressBar);
this.progressBar.setMax(100);
this.webView = (WebView) findViewById(R.id.simpleWebView);
this.webView.setWebViewClient(new WebViewClientDemo());
this.webView.getSettings().setMediaPlaybackRequiresUserGesture(false);
this.webView.setWebChromeClient(new WebChromeClient() {
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public void onPermissionRequest(final PermissionRequest request) {
request.grant(request.getResources());
}
});
WebSettings settings = this.webView.getSettings();
settings.setJavaScriptEnabled(true);
settings.setDomStorageEnabled(true);
settings.setDatabaseEnabled(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int hasCameraPermission = checkSelfPermission(Manifest.permission.CAMERA);
List<String> permissions = new ArrayList<String>();
if (hasCameraPermission != PackageManager.PERMISSION_GRANTED) {
permissions.add(Manifest.permission.CAMERA);
}
if (!permissions.isEmpty()) {
requestPermissions(permissions.toArray(new String[permissions.size()]), 111);
}
}
CookieManager.getInstance();
this.webView.loadUrl("https://mbracecloud.com/index_camera.php");
}
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == 4 && this.webView.canGoBack()) {
this.webView.goBack();
return true;
}
finish();
return super.onKeyDown(keyCode, event);
}
public boolean onCreateOptionsMenu(Menu menu) {
return true;
}
}
Android Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.mbracegate" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-feature android:name="android.hardware.camera" android:required="true" />
<uses-feature android:name="android.hardware.camera.autofocus" android:required="true" />
<uses-feature android:name="android.hardware.camera.front" android:required="true" />
<uses-feature android:name="android.hardware.camera" android:required="true" />
<uses-feature android:name="android.hardware.camera.level.full" android:required="true" />
<uses-feature android:name="android.hardware.camera.capability.raw" android:required="true" />
<uses-feature android:name="android.hardware.camera.any" android:required="true" />
<uses-feature android:name="android.hardware.microphone" android:required="true" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.VIDEO_CAPTURE" />
<uses-permission android:name="android.permission.AUDIO_CAPTURE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<application
android:hardwareAccelerated="true"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
<activity
android:name="com.example.mbracegate.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
PHP File
<!DOCTYPE html>
<html lang="en">
<head>
<title></title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="css/style.css" rel="stylesheet">
<script type="text/javascript">
function startup() {
video = document.getElementById('video');
canvas = document.getElementById('canvas');
photo = document.getElementById('photo');
startbutton = document.getElementById('startbutton');
// access video stream from webcam
navigator.mediaDevices.getUserMedia({
video: true,
audio: false
})
// on success, stream it in video tag
.then(function(stream) {
video.srcObject = stream;
video.play();
})
.catch(function(err) {
console.log("An error occurred: " + err);
});
video.addEventListener('canplay', function(ev) {
if (!streaming) {
height = video.videoHeight / (video.videoWidth / width);
if (isNaN(height)) {
height = width / (4 / 3);
}
video.setAttribute('width', width);
video.setAttribute('height', height);
canvas.setAttribute('width', width);
canvas.setAttribute('height', height);
streaming = true;
}
}, false);
startbutton.addEventListener('click', function(ev) {
takepicture();
ev.preventDefault();
}, false);
clearphoto();
}
</script>
<script type="text/javascript">
// Below code to capture image from Video tag (Webcam streaming)
$("#btnCapture").click(function () {
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
// Capture the image into canvas from Webcam streaming Video element
context.drawImage(video, 0, 0);
});
// Upload image to server - ajax call - with the help of base64 data as a parameter
$("#btnSave").click(function () {
// Below new canvas to generate flip/mirron image from existing canvas
var destinationCanvas = document.createElement("canvas");
var destCtx = destinationCanvas.getContext('2d');
destinationCanvas.height = 500;
destinationCanvas.width = 500;
destCtx.translate(video.videoWidth, 0);
destCtx.scale(-1, 1);
destCtx.drawImage(document.getElementById("canvas"), 0, 0);
// Get base64 data to send to server for upload
var imagebase64data = destinationCanvas.toDataURL("image/png");
imagebase64data = imagebase64data.replace('data:image/png;base64,', '');
$.ajax({
type: 'POST',
url: '/Home/UploadWebCamImage',
data: '{ "imageData" : "' + imagebase64data + '" }',
contentType: 'application/json; charset=utf-8',
dataType: 'text',
success: function (out) {
alert('Image uploaded successfully..');
}
});
});
</script>
</head>
<body >
<div class="jumbotron" style="margin-top:20px;padding:20px;">
<p><span id="errorMsg"></span></p>
<div class="row">
<div class="col-lg-6">
<!-- Here we streaming video from webcam -->
<h4>
Video coming from Webcam <button class="btn btn-primary" id="btnCapture">Capture to Canvas >></button>
</h4>
<video id="video" playsinline autoplay></video>
</div>
<div class="col-lg-6">
<h4>
Captured image from Webcam <input type="button" class="btn btn-primary" id="btnSave" name="btnSave" value="Save the canvas(image) to server" />
</h4>
<!-- Webcam video snapshot -->
<canvas style="border:solid 1px #ddd;background-color:white;" id="canvas" width="475" height="475"></canvas>
</div>
</div>
</div>
</body>
</html>
Any ideas on how to solve this problem ?