NotReadableError: Could not start source

I wanted to add the solution to my saga of fighting this particular error. I am using Ionic to build a WebRTC chat app, and have got this error with my native Android build. Here are the things that made all the difference.

Install Ionic's AndroidPermissions plugin...

$ ionic cordova plugin add cordova-plugin-android-permissions
$ npm install --save @ionic-native/android-permissions

Don't forget to add it to app.module.ts as a provider

In your component's .ts file...

import { AndroidPermissions } from '@ionic-native/android-permissions';

...

iosCordova = false; // I use these for easy if-else logic later
androidCordova = false; // but I want you to see how I handle the logic

constructor(private platform:Platform, private androidPermissions: AndroidPermissions, etc...) {
        navigator.getUserMedia = ((<any>navigator).getUserMedia || (<any>navigator).webkitGetUserMedia || (<any>navigator).mozGetUserMedia || (<any>navigator).msGetUserMedia);
        this.iosCordova = this.platform.is('ios') && typeof cordova !== 'undefined';
        this.androidCordova = this.platform.is('android') && typeof cordova !== 'undefined';
        platform.ready().then(() => {
            if( this.androidCordova ){ // is Android Native App
                // alert("Android Native")
                androidPermissions.requestPermissions(
                [
                    androidPermissions.PERMISSION.CAMERA, 
                    androidPermissions.PERMISSION.MODIFY_AUDIO_SETTINGS,
                    androidPermissions.PERMISSION.RECORD_AUDIO
                ]
                ).then(()=>{
//getDevices uses Enumerate Devices and initWebRTC starts the chat connections, etc...
                    this.getDevices().then(() => this.initWebRTC())
                })
            }
       }) 
    }


ngOnInit() {
        if( !this.androidCordova ){ // is NOT Android Native App
            // alert("NOT Android Native")
            try {
                this.getDevices().then(() => this.initWebRTC())     
            } catch(e) {
                alert(e);
            }
        }
    }
...

Inspect your config.xml at myAppName/config.xml and add xmlns:android="http://schemas.android.com/apk/res/android" to your widget tag and add the permissions request. I had issues trying to include them in the previously existing tags, and just add these permissions requests right under the closing tags (creating my own second set)

<widget id="your.app" version="1.2.3" xmlns="http://www.w3.org/ns/widgets" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:cdv="http://cordova.apache.org/ns/1.0">
...
</platform> // previously existing platform name="android" closing tag
<platform name="android">
    <custom-config-file parent="/manifest" target="AndroidManifest.xml">
        <uses-permission android:name="android.permission.CAMERA" />
        <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
        <uses-permission android:name="android.permission.RECORD_AUDIO" />
    </custom-config-file>
</platform>
<platform name="ios"> // previously existing platform name="ios" opening tag

Now, you need to inspect your AndroidManifest.xml file at myAppName/platforms/android/app/src/main/AndroidManifest.xml and look for these permissions. If they are not there, add them

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />

Having these permissions declared in the manifest is critical to not being ignored. Apparently Android 26 is getting strict on permissions, and you can't just ask willy-nilly for them. According to the documentation I've been reading, if you are not actually using the permission from within the code you are calling it from, your request will be dropped by the OS and the user will never see it.

Anyway, I'm very junior to all this Ionic and native device development, so if anyone has anything enlightening to add, please do so! Thanks everyone!


Update - 19/11/2020

WKWebView can use getUserMedia in iOS 14.3 beta 1.

  • https://bugs.webkit.org/show_bug.cgi?id=208667
  • https://bugs.chromium.org/p/chromium/issues/detail?id=752458

Update - 04/06/2020

Another bug ticket has been filed specifically for WKWebView. No support. https://bugs.webkit.org/show_bug.cgi?id=208667

Updates to standalone mode gaining getUserMedia access in iOS 13.4 https://bugs.webkit.org/show_bug.cgi?id=185448#c6

Update - 14/09/2019

There are changes to Safari on iOS 13 & Safari 13: https://developer.apple.com/documentation/safari_release_notes/safari_13_release_notes

SFSafariViewController has gained getUserMedia functionality (!!!, however I need to confirm this, please see below for reports of it working)

https://bugs.webkit.org/show_bug.cgi?id=183201

However WKWebView does not seem to gain getUserMedia functionality:

https://bugs.chromium.org/p/chromium/issues/detail?id=752458 https://bugs.webkit.org/show_bug.cgi?id=185448

iOS 13 and Safari 13 release notes:

https://developer.apple.com/documentation/ios_ipados_release_notes/ios_13_release_notes https://developer.apple.com/documentation/safari_release_notes/safari_13_release_notes

Update - 04/11/2018 - Links to working Ionic, Cordova and Native android examples with instructions

GitHub link to working Cordova example

GitHub link to working Android example

GitHub link to a working Ionic example

Steps to achieve getUserMedia access on Android via the Cordova framework are:

  • Follow Cordova Android install instructions (link)
  • Add Permissions to AndroidManifiest.xml (link)
  • Save WebRTC Adapter.js file to ./www/js/adapter.js and include in ./www/index.html
  • Add cordova plugin add cordova-plugin-android-permissions
  • Add plugin permission code, and the necessary getUserMedia code inside of the ./www/js/index.js file. Make sure you use getUserMedia adapter. Please see this file as an example (link).

Please see the full line by line instructions with a success and error image inside the GitHub project.


I am not sure how much of this relates to Cordova... However I had this error when I made my own Android getUserMedia test app (link). It is dependant mainly on the native app user permissions, then how the parent app creates the webviews, which version of webrtc is packaged within your app, and how you call getUserMedia.

JavaScript side of the application: Rather than doing browser shim code yourself make sure you use the WebRTC adapter (link). This removes a lot of common problems. You can see an example here (link). I also recommend looking at the WebRTC Samples here (link).

Native side of the application: You will need Mic and Camera user permissions for Video and Audio. This is the main culprit. You need to make sure they have been accepted before the creation of the WebView. Thus all permission checking, popups, etc, need to happen before the creation of the WebView. If permissions are granted after you most likely need to reboot the App, etc.

When you build and deploy your application go to App Settings and manually turn on the permissions if you haven't been prompted already. Then it should work.

I wasn't able to get Video/Audio emulation working in the emulator only on the actual device. I also only encountered the NotReadableError on Android utilising a WebChromeView before permissions have been accepted. Lastly The min API version for Android is 21 (Lollipop) for this functionality as the parent application needs to allow run-time permissions via WebView onPermissionRequest (link).

As numerous in-app browsers (Facebook, Pinterest, etc) do not handle onPermissionRequest on Android WebRTC via a website typically doesn't work. On iOS it is guaranteed (as of April 2018) not to work as Apple have only allowed WebRTC access through the Safari only. Thus Cordova is limited to Android API 21 if it handles the permissions correctly.