/** * Copyright 2017 Google Inc. All Rights Reserved. * * 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. */'use strict';constfunctions=require('firebase-functions');constgcs=require('@google-cloud/storage')();constpath=require('path');constos=require('os');constfs=require('fs');constffmpeg=require('fluent-ffmpeg');constffmpeg_static=require('ffmpeg-static');// Makes an ffmpeg command return a promise.functionpromisifyCommand(command) {returnnewPromise((resolve, reject) => {command.on('end', resolve).on('error', reject).run(); });}/** * When an audio is uploaded in the Storage bucket We generate a mono channel audio automatically using * node-fluent-ffmpeg. */exports.generateMonoAudio =functions.storage.object().onFinalize(async (object) => {constfileBucket=object.bucket; // The Storage bucket that contains the file.constfilePath=object.name; // File path in the bucket.constcontentType=object.contentType; // File content type.// Exit if this is triggered on a file that is not an audio.if (!contentType.startsWith('audio/')) {console.log('This is not an audio.');returnnull; }// Get the file name.constfileName=path.basename(filePath);// Exit if the audio is already converted.if (fileName.endsWith('_output.flac')) {console.log('Already a converted audio.');returnnull; }// Download file from bucket.constbucket=gcs.bucket(fileBucket);consttempFilePath=path.join(os.tmpdir(), fileName);// We add a '_output.flac' suffix to target audio file name. That's where we'll upload the converted audio.consttargetTempFileName=fileName.replace(/\.[^/.]+$/,'') +'_output.flac';consttargetTempFilePath=path.join(os.tmpdir(), targetTempFileName);consttargetStorageFilePath=path.join(path.dirname(filePath), targetTempFileName);awaitbucket.file(filePath).download({destination: tempFilePath});console.log('Audio downloaded locally to', tempFilePath);// Convert the audio to mono channel using FFMPEG.let command =ffmpeg(tempFilePath).setFfmpegPath(ffmpeg_static.path).audioChannels(1).audioFrequency(16000).format('flac').output(targetTempFilePath);awaitpromisifyCommand(command);console.log('Output audio created at', targetTempFilePath);// Uploading the audio.awaitbucket.upload(targetTempFilePath, {destination: targetStorageFilePath});console.log('Output audio uploaded to', targetStorageFilePath);// Once the audio has been uploaded delete the local file to free up disk space.fs.unlinkSync(tempFilePath);fs.unlinkSync(targetTempFilePath);returnconsole.log('Temporary files removed.', targetTempFilePath);});
ffmpeg binary on cloud function
Seems like ffmpeg is availabe on cloud function by default.
We are also rebasing the underlying Cloud Functions operating system onto Ubuntu 18.04 LTS to broaden the scope of libraries available. In addition to imagemagick, available since beta launch, you now get access to additional system libraries such as ffmpeg and libcairo2, as well as everything required to run headless Chrome. For example, you can now process videos and take web page screenshots in Chrome from within Cloud Functions.
another option is to convert the file after a field is changed in firestore and/or a new document is created. eg see STT + Cloud Function + Google Task for more detailed examaple.
example of helper function to convert to audio that can be used in a firebase cloud function
constpath=require('path');constos=require('os');constfs=require('fs');constffmpeg=require('fluent-ffmpeg');/** * `convertToAudio` - converts video or audio file into audio feel that meets STT specs * Uses ffmpeg. ffmpeg binary is installed and available on cloud functions by default. * When done converting it uploads the audio to Google Cloud Storage * removes the converted file on the cloud function * returns `targetStorageFilePath` the path to the new converted file, saved in cloud storage * modified from https://github.com/firebase/functions-samples/blob/master/ffmpeg-convert-audio/functions/index.js * @param{*} storageRef * @param{*} downloadURLLink */exports.convertToAudio=async (admin, storageRef, downloadURLLink, AUDIO_EXTENSION, SAMPLE_RATE_HERTZ) => {returnnewPromise(async (resolve, reject) => {// Get the file name.constfileName=path.basename(storageRef);constfilePath= storageRef;// Exit if the audio is already converted.if (fileName.endsWith(`_output.${AUDIO_EXTENSION}`)) {console.error('Already a converted audio.');// return null;reject(newError()); }constbucket=admin.storage().bucket();// We add a '_output.flac' suffix to target audio file name. That's where we'll upload the converted audio.consttargetTempFileName=fileName.replace(/\.[^/.]+$/,'') +`_output.${AUDIO_EXTENSION}`;consttargetTempFilePath=path.join(os.tmpdir(), targetTempFileName);consttargetStorageFilePath=path.join(path.dirname(filePath), targetTempFileName);ffmpeg(downloadURLLink).noVideo().audioChannels(1).audioFrequency(SAMPLE_RATE_HERTZ).audioCodec('libopus').output(targetTempFilePath).on('end',async () => {// Uploading the audio Google Cloud Storageawaitbucket.upload(targetTempFilePath, { destination: targetStorageFilePath,// without resumable false, this seems to fail resumable:false, });// Once the audio has been uploaded delete the local file to free up disk space.fs.unlinkSync(targetTempFilePath);resolve(targetStorageFilePath); }).on('error', err => {reject(err); }).run(); });};