// (C) Copyright 2015 Martin Dougiamas // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import { Injectable } from '@angular/core'; import { ModalController, Modal } from 'ionic-angular'; import { CoreMimetypeUtilsProvider } from '../../../providers/utils/mimetype'; import { CoreUtilsProvider } from '../../../providers/utils/utils'; /** * Helper service with some features to capture media (image, audio, video). */ @Injectable() export class CoreEmulatorCaptureHelperProvider { protected possibleAudioMimeTypes = { 'audio/webm': 'weba', 'audio/ogg': 'ogg' }; protected possibleVideoMimeTypes = { 'video/webm;codecs=vp9': 'webm', 'video/webm;codecs=vp8': 'webm', 'video/ogg': 'ogv' }; protected win: any; videoMimeType: string; audioMimeType: string; constructor(private utils: CoreUtilsProvider, private mimeUtils: CoreMimetypeUtilsProvider, private modalCtrl: ModalController) { // Convert the window to "any" type because some of the variables used (like MediaRecorder) aren't in the window spec. this.win = window; } /** * Capture media (image, audio, video). * * @param {String} type Type of media: image, audio, video. * @param {Function} successCallback Function called when media taken. * @param {Function} errorCallback Function called when error or cancel. * @param {Object} [options] Optional options. * @return {Void} */ captureMedia(type: string, options: any) : Promise { options = options || {}; try { // Build the params to send to the modal. let deferred = this.utils.promiseDefer(), params: any = { type: type }, mimeAndExt, modal: Modal; // Initialize some data based on the type of media to capture. if (type == 'video') { mimeAndExt = this.getMimeTypeAndExtension(type, options.mimetypes); params.mimetype = mimeAndExt.mimetype; params.extension = mimeAndExt.extension; } else if (type == 'audio') { mimeAndExt = this.getMimeTypeAndExtension(type, options.mimetypes); params.mimetype = mimeAndExt.mimetype; params.extension = mimeAndExt.extension; } else if (type == 'image') { if (typeof options.sourceType != 'undefined' && options.sourceType != 1) { return Promise.reject('This source type is not supported in desktop.'); } if (options.cameraDirection == 1) { params.facingMode = 'user'; } if (options.encodingType == 1) { params.mimetype = 'image/png'; params.extension = 'png'; } else { params.mimetype = 'image/jpeg'; params.extension = 'jpeg'; } if (options.quality >= 0 && options.quality <= 100) { params.quality = options.quality / 100; } if (options.destinationType == 0) { params.returnDataUrl = true; } } if (options.duration) { params.maxTime = options.duration * 1000; } modal = this.modalCtrl.create('CoreEmulatorCaptureMediaPage', params); modal.present(); modal.onDidDismiss((data: any, role: string) => { if (role == 'success') { deferred.resolve(data); } else { deferred.reject(data); } }); return deferred.promise; } catch(ex) { return Promise.reject(ex.toString()); } } /** * Get the mimetype and extension to capture media. * * @param {string} type Type of media: image, audio, video. * @param {string[]} [mimetypes] List of supported mimetypes. If undefined, all mimetypes supported. * @return {{extension: string, mimetype: string}} An object with mimetype and extension to use. */ protected getMimeTypeAndExtension(type: string, mimetypes) : {extension: string, mimetype: string} { var result: any = {}; if (mimetypes && mimetypes.length) { // Search for a supported mimetype. for (let i = 0; i < mimetypes.length; i++) { let mimetype = mimetypes[i], matches = mimetype.match(new RegExp('^' + type + '/')); if (matches && matches.length && this.win.MediaRecorder.isTypeSupported(mimetype)) { result.mimetype = mimetype; break; } } } if (result.mimetype) { // Found a supported mimetype in the mimetypes array, get the extension. result.extension = this.mimeUtils.getExtension(result.mimetype); } else if (type == 'video') { // No mimetype found, use default extension. result.mimetype = this.videoMimeType; result.extension = this.possibleVideoMimeTypes[result.mimetype]; } else if (type == 'audio') { // No mimetype found, use default extension. result.mimetype = this.audioMimeType; result.extension = this.possibleAudioMimeTypes[result.mimetype]; } return result; } /** * Init the getUserMedia function, using a deprecated function as fallback if the new one doesn't exist. * * @return {boolean} Whether the function is supported. */ protected initGetUserMedia() : boolean { let nav = navigator; // Check if there is a function to get user media. if (typeof nav.mediaDevices == 'undefined') { nav.mediaDevices = {}; } if (!nav.mediaDevices.getUserMedia) { // New function doesn't exist, check if the deprecated function is supported. nav.getUserMedia = nav.getUserMedia || nav.webkitGetUserMedia || nav.mozGetUserMedia || nav.msGetUserMedia; if (nav.getUserMedia) { // Deprecated function exists, support the new function using the deprecated one. navigator.mediaDevices.getUserMedia = (constraints) => { let deferred = this.utils.promiseDefer(); nav.getUserMedia(constraints, deferred.resolve, deferred.reject); return deferred.promise; }; } else { return false; } } return true; } /** * Initialize the mimetypes to use when capturing. */ protected initMimeTypes() : void { // Determine video and audio mimetype to use. for (let mimeType in this.possibleVideoMimeTypes) { if (this.win.MediaRecorder.isTypeSupported(mimeType)) { this.videoMimeType = mimeType; break; } } for (let mimeType in this.possibleAudioMimeTypes) { if (this.win.MediaRecorder.isTypeSupported(mimeType)) { this.audioMimeType = mimeType; break; } } } /** * Load the Mocks that need it. * * @return {Promise} Promise resolved when loaded. */ load() : Promise { if (typeof this.win.MediaRecorder != 'undefined' && this.initGetUserMedia()) { this.initMimeTypes(); } return Promise.resolve(); } }