ios 11/12 webrtc video "invalid constraint"

according to 1 I tried several hours to get access the camera on Safari with WebRTC, record a video and save it to the server. But I failed with iOS and Safari. I always got the error "getUserMedia “invalid constraint”" However the script runs perfectly on Windows (Chrome, Firefos, Opera) and Android.

  • For example I tried to hardcode the camera-resolution -> error still appears
  • I tried to find the correct camera resolution with 2 -> video and audio appears but every single resolution test failed.

This is my script:

<script src="https://cdn.webrtc-experiment.com/RecordRTC.js"></script>
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>

const videoElement = document.querySelector('video');
const audioInputSelect = document.querySelector('select#audioSource');
const audioOutputSelect = document.querySelector('select#audioOutput');
const videoSelect = document.querySelector('select#videoSource');
const selectors = [audioInputSelect, audioOutputSelect, videoSelect];

audioOutputSelect.disabled = !('sinkId' in HTMLMediaElement.prototype);

function gotDevices(deviceInfos) {
    // Handles being called several times to update labels. Preserve values.
    const values = selectors.map(select => select.value);
    selectors.forEach(select => {
        while (select.firstChild) {
            select.removeChild(select.firstChild);
        }
    });
    for (let i = 0; i < deviceInfos.length; ++i) {
        const deviceInfo = deviceInfos[i];
        const option = document.createElement('option');
        option.value = deviceInfo.deviceId;
            if (deviceInfo.kind === 'audioinput') {
            option.text = deviceInfo.label || `microphone     ${audioInputSelect.length + 1}`;
            audioInputSelect.appendChild(option);
        } else if (deviceInfo.kind === 'audiooutput') {
            option.text = deviceInfo.label || `speaker     ${audioOutputSelect.length + 1}`;
            audioOutputSelect.appendChild(option);
        } else if (deviceInfo.kind === 'videoinput') {
            option.text = deviceInfo.label || `camera ${videoSelect.length + 1}`;
            videoSelect.appendChild(option);
        } else {
            console.log('Some other kind of source/device: ', deviceInfo);
        }
    }
    selectors.forEach((select, selectorIndex) => {
        if (Array.prototype.slice.call(select.childNodes).some(n => n.value === values[selectorIndex])) {
            select.value = values[selectorIndex];
        }
    });
}

// Store a reference of the preview video element and a global reference to the recorder instance
var video = document.getElementById('my-preview');
//          var videoHeight = 1280;
//          var videoWidth = 720;
//          var videoBPS = 1024000;


var recorder;
navigator.mediaDevices.enumerateDevices().then(gotDevices).catch(handleError);


navigator.mediaDevices.getUserMedia({
    audio: {deviceId: audioSource ? {exact: audioSource} : undefined},
    video: {deviceId: videoSource ? {exact: videoSource} : undefined,
            width: {max: videoWidth},    
            height: {max: videoHeight}   
           },
}).then(
    function(stream) {
        // Display a live preview on the video element of the page
        setSrcObject(stream, video);
        navigator.mediaDevices.enumerateDevices();
        video.srcObject = stream;
        // Start to display the preview on the video element
        // and mute the video to disable the echo issue !
        video.play();
        video.muted = true;
    });

// When the user clicks on start video recording
document.getElementById('btn-start-recording').addEventListener("click",         function(){
    // Disable start recording button
    this.disabled = true;

    const audioSource = audioInputSelect.value;
    const videoSource = videoSelect.value;

    // Request access to the media devices
    navigator.mediaDevices.getUserMedia({
        audio: {deviceId: audioSource ? {exact: audioSource} : undefined},
        video: {deviceId: videoSource ? {exact: videoSource} : undefined,
                width: {exact: videoWidth} ,    
                height: {max: videoHeight } 
               },
    }).then(
        function(stream) {
            // Display a live preview on the video element of the page
            setSrcObject(stream, video);
            navigator.mediaDevices.enumerateDevices();
            // Start to display the preview on the video element
            // and mute the video to disable the echo issue !
            video.play();
            video.muted = true;

            // Initialize the recorder
            recorder = new RecordRTCPromisesHandler(stream, {
                mimeType: 'video/webm',
                //              bitsPerSecond: 128000
                bitsPerSecond: videoBPS
            });

            // Start recording the video
            recorder.startRecording().then(function() {
                console.info('Recording video ...');
            }).catch(function(error) {
                console.error('Cannot start video recording: ', error);
            });

            // release stream on stopRecording
            recorder.stream = stream;

            // Enable stop recording button
            document.getElementById('btn-stop-recording').disabled = false;
        }).catch(handleError);

}, false);

// When the user clicks on Stop video recording
document.getElementById('btn-stop-recording').addEventListener("click",         function(){
    this.disabled = true;

    recorder.stopRecording().then(function() {
        console.info('stopRecording success');

        // Retrieve recorded video as blob and display in the preview element
        var videoBlob = recorder.getBlob();
        video.src = URL.createObjectURL(videoBlob);
        var url = URL.createObjectURL(videoBlob);
        //          video.play();

        // Unmute video on preview
        video.muted = false;

        // Stop the device streaming
        recorder.stream.stop();

        // Enable record button again !
        document.getElementById('btn-start-recording').disabled = false;

        var d = new Date();
        var n =     d.getFullYear()+"_"+d.getMonth()+"_"+d.getDay()+"____"+d.getHours()+"_"+d.getMinutes()+"_"+d.getSeconds();

        var formData = new FormData();
        formData.append('file', videoBlob);
        formData.append("VideoToken", VideoToken);
        formData.append("uniqid", guid());
        formData.append("fileName",VideoToken+".wav");

        // Execute the ajax request, in this case we have a very simple PHP script
            // that accepts and save the uploaded "video" file
            xhr('insert_video.php', formData, function (fName) {
            console.log("Video succesfully uploaded !" + fName);
            location.reload();
        });

    // Helper function to send 
    function xhr(url, data, callback) {
        var request = new XMLHttpRequest();
        request.onreadystatechange = function () {
            if (request.readyState == 4 && request.status == 200) {
                callback(location.href + request.responseText);
            }
        };
        request.open('POST', url);
        request.send(data);
    }

    }).catch(function(error) {
        console.error('stopRecording failure', error);
    });
    navigator.mediaDevices.enumerateDevices().then(gotDevices).catch(handleError);

}, false);

function guid() {
    return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
        s4() + '-' + s4() + s4() + s4();
}
function s4() {
    return Math.floor((1 + Math.random()) * 0x10000)
        .toString(16)
        .substring(1);
}



function handleError(error) {
    console.log('navigator.getUserMedia error: ', error);
    alert(error);
}

Can anybody tell me please, what's wrong in my script and how to fix it. Thank you very much in advance!