- 投稿日:2019-07-30T16:13:21+09:00
Lambdaでsoxを使用して音声を左右のチャンネルに分割する
AmazonConnectの録音ファイルが顧客とエージェントで左右のチャンネルに分割されている為、それを分割しようとした時のメモです。
Q: エージェントと顧客の音声は別々のステレオ音声チャネルに保存されるのですか?
はい。エージェントの音声は右チャネルに保存されます。エンドカスタマーやカンファレンスに参加した人など、すべての着信音声は左チャネルに保存されます。
AWSより引用ハマった事
lambdaのランタイムを
nodejs10.x
で検証していたのですが、soxが動作しませんでした。解決策
lambdaでsoxを動作させたい場合は、
nodejs8.10
をランタイムに設定しましょう。分割していく
AmazonConnectからS3に通話音声ファイル(.wav)が格納された際にLambdaが実行される前提となっています。
soxを使うために
lambda-audio
をインストール。npm i lambda-audiotypescriptで書いてます。
import {Handler} from 'aws-lambda'; import {S3} from "aws-sdk"; class S3Service { constructor(private s3: S3) { } async get(bucketName, key) { const params = { Bucket: bucketName, Key: key }; return await this.s3.getObject(params).promise(); } async put(bucketName, key, body) { const params = { Bucket: bucketName, Key: key, Body: body, }; return await this.s3.putObject(params).promise(); } } export const handler: Handler = async (event: any) => { const s3 = new S3Service(new S3()); const fs = require('fs'); const lambdaAudio = require('lambda-audio'); const nowTime = (new Date()).getTime(); const wavPath = '/tmp/' + nowTime + '.wav'; // S3に格納された.wavの情報を取得する for (let record of event.Records) { const key = record.s3.object.key; const bucketName = record.s3.bucket.name; const object = await s3.get(bucketName, decodeURIComponent(key)); await fs.writeFile(wavPath, object.Body, 'binary', err => { if (err) { console.error(err); return; } }); } // ここで左のチャンネルを抽出している const leftOutput = `/tmp/${nowTime}_output_l.wav`; await lambdaAudio.sox([wavPath, leftOutput, 'remix', '1']) .then(response => { console.log(`soxLeft: ${response}`); }) .catch(errorResponse => { console.log('Error from the sox command:', errorResponse) }); // ここで右のチャンネルを抽出している const rightOutput = `/tmp/${nowTime}_output_r.wav`; await lambdaAudio.sox([wavPath, rightOutput, 'remix', '2']) .then(response => { console.log(`soxRight: ${response}`); }) .catch(errorResponse => { console.log('Error from the sox command:', errorResponse) }); // S3へ格納(※1) await s3.put('BUCKET_NAME', `${nowTime}/l.wav`, fs.readFileSync(leftOutput)); await s3.put('BUCKET_NAME', `${nowTime}/r.wav`, fs.readFileSync(rightOutput)); return {} };※1
'BUCKET_NAME'
に保存先となるS3を指定まとめ
顧客、エージェントの音声を分割することにより、文字起こし等に使用する際に便利になると思います。
ファイルサイズが2倍になるため、利用料金は2倍になりますが、、、
- 投稿日:2019-07-30T14:37:15+09:00
【Webエンジニア目指している方向け・無料公開】HTML, CSS, JavaScriptが学べる解説動画129本をまとめました!
この2週間で撮ってきたHTML, CSS, JavaScript(基本文法, フロントエンド, バックエンド)の解説動画全てを以下の記事にまとめました^^
https://tsuyopon.xyz/learning-contents/web-dev-movie-list/
動画本数
動画リスト数と解説動画本数は以下のとおりです。
- 動画リスト : 21本
- 解説動画本数 : 129本
- 解説動画の合計時間 : 14時間20分45秒
一般公開している動画なので誰でも無料で観れます!
Webエンジニアを目指している方、参考にどうぞ!
- 投稿日:2019-07-30T14:37:15+09:00
【Webエンジニア目指している方向け】HTML, CSS, JavaScriptが学べる解説動画129本(14時間超え)をまとめました!
この2週間で撮ってきたHTML, CSS, JavaScript(基本文法, フロントエンド, バックエンド)の解説動画全てを以下の記事にまとめました^^
https://tsuyopon.xyz/learning-contents/web-dev-movie-list/
動画本数
動画リスト数と解説動画本数は以下のとおりです。
- 動画リスト : 21本
- 解説動画本数 : 129本
- 解説動画の合計時間 : 14時間20分45秒
一般公開している動画なので誰でも無料で観れます!
Webエンジニアを目指している方、参考にどうぞ!
- 投稿日:2019-07-30T12:44:39+09:00
AWS Lambdaのランタイムサポート
AWS LambdaのランタイムサポートはランタイムのEOLと同時に新規作成ができなくなり、その後1~2ヵ月で更新もできなくなる。
Node.jsはメジャーバージョンアップが1年ごとで、EOLもリリースから2年半と短いため、頻繁なEOL対応が必要となる。(Pythonはリリースから5年間サポートされる。)
ランタイム LTS開始 EOL 廃止 (作成) 廃止 (更新) Python 2.7 2010/07/03 2020/01/01 (未定) (未定) Python 3.5 2015/09/13 2020/09/13 (サポート対象外) (サポート対象外) Python 3.6 2016/12/23 2021/12/23 (未定) (未定) Python 3.7 2018/06/27 2023/06/27 (未定) (未定) Node.js 0.10 2013/03/11 2016/10/31 2016/10/31 2016/10/31 Node.js 4.3 2015/10/01 2018/04/30 2018/12/15 2019/4/30 Node.js 6.10 2016/10/18 2019/04/30 2019/04/30 2019/6/30 Node.js 8.10 2017/10/31 2019/12 (予定) ※ (未定) (未定) Node.js 10.x 2018/10/30 2021/04 (予定) (未定) (未定) Node.js 12.x 2019/10/22 2022/04 (予定) (未定) (未定) ※ OpenSSL-1.0.2と同時のEOLとするため、通常よりも早く設定されている。
参考
- 投稿日:2019-07-30T08:21:08+09:00
AWS EC2上でNode.jsを管理者ユーザーから実行した際のError: listen EACCES: permission denied 0.0.0.0:XXXXについて
はじめに
よく理解しないまま続けてしまい、ハマってしまったので書き残しておきます。
問題
前回まででローカル(VScode)からリモートサーバー(AWS EC2)の編集ができるようになりましたが、いざindex.jsファイルを追加し、実行しようとすると以下のようなエラーが出ます。
前回の記事:https://qiita.com/kobyta/items/510e638ba6693de12871
permission deniedとなっているので、安直にsudo権限からアクセスしたら、「sudo : node : コマンドが見つかりません」と出てくきます。
同じような問題にぶつかっていた人がいたので、自分もそれに習い下のようにシンボリックリンクを作成しましたが、下記画像のようにaddress already in useと出てきて断念、、(既に22番ポートをローカルとリモートサーバーのやりとりに使っていたせいか、、。そもそもシンボリックリンクを作る理由がわかっていない。管理者ユーザーとrootユーザーでPATHが同じならばエラーが解決するのか、、。)terminal$ sudo ln -s /home/ec2-user/.nvm/versions/node/v12.6.0/bin/node /usr/bin/node $ sudo ln -s /home/ec2-user/.nvm/versions/node/v12.6.0/bin/npm /usr/bin/npm $ sudo ln -s /usr/local/bin/node-waf /usr/bin/node-waf
- 一言メモ 「管理者ユーザーとrootユーザーと一般ユーザー」
ここまで「管理者」=「root」と思ってきましたが、そうでは無いようです。「root」は管理者より上位にいる神みたいな存在で、「管理者」だけが「sudo」コマンドを使って一時的に神の力を得るということらしいです。「一般」ユーザーはそもそも「sudo」コマンドが使えません。解決策
別のやり方を模索。以下の参考記事①で1024番以下のポート番号は管理者権限を持たないユーザーには実行できないことを知る。また参考記事②でnode.jeを管理者ユーザーから実行する際にポート番号3000を使っている人がいたので自分も同じようにやってみる。
参考記事①:http://dotnsf.blog.jp/archives/1066514800.html
参考記事②:https://qiita.com/oishihiroaki/items/bc663eb1282d87c46e97AWS EC2のセキュリティグループで以下のようにインバウンドに3000番のポートを増やす。
実行しようとしていた「index.js」のポート番号を3000に変更。ローカルからリモートサーバーに変更を送信。
「管理者」ユーザーで実行した後、「 http://パブリックIPアドレス:3000/ 」にアクセスすると実行できていました。
- 一言メモ「ブラウザのアクセス先について」
httpやhttpsなどではポート番号のデフォルトが80、443と決まっており「 http://パブリックIPアドレス/ 」とすればアクセスできる。今回のように別のポートを使いたい場合、「 http://パブリックIPアドレス:ポート番号/ 」というように指定しなければならない。なんとか実行できる環境まで行けたので、nodeでのアプリ制作を進めたいと思います。
- 投稿日:2019-07-30T01:13:24+09:00
書いて覚えるPromise
Promiseとは?
Promiseは非同期処理の完了or失敗を表すオブジェクト。
- 非同期処理の成功(resolve)、失敗(reject)を表すオブジェクト
then
やcatch
,finally
メソッドを使うことで非同期処理後に関数を実行することができるPromise.all
やPromise.race
を使えば、非同期処理を並列で実行することができるPromiseを使った処理を書いてみよう
resolve(成功)の例
- 非同期処理が成功した場合は、
resolve(結果の値)
を呼ぶ- 非同期処理成功後に行いたい処理は、
then()
メソッドに関数を渡すことで実現できるnew Promise((resolve, reject) => { setTimeout(() => { // 成功する例なので、resolveを返す resolve('非同期処理 成功!!'); }, 3000); }).then((value) => { console.log('=== thenメソッド内 ==='); console.log('resolveされた値: ' + value); }).catch((value) => { console.log('=== catchメソッド内 ==='); console.log('rejectされた値: ' + value); });
- 実行結果
$ node promise.js === thenメソッド内 === resolveされた値: 非同期処理 成功!!reject(失敗)の例
- 非同期処理が失敗した場合は、
reject(Errorオブジェクト)
を呼ぶ- 非同期処理失敗時に実行したい処理は、
catch()
メソッドに関数を渡すことで実現できるnew Promise((resolve, reject) => { setTimeout(() => { // 失敗する例なので、rejectを返す reject(new Error('非同期処理 失敗.....')); }, 3000); }).then((value) => { console.log('=== thenメソッド内 ==='); console.log('resolveされた値: ' + value); }).catch((value) => { console.log('=== catchメソッド内 ==='); console.log('rejectされた値: ' + value); });
- 実行結果
=== catchメソッド内 === rejectされた値: Error: 非同期処理 失敗.....finally 成功しても、失敗しても実行する処理の例
成功しても、失敗しても実行したい処理は、
finally()
に関数を渡すことで実現できる。new Promise((resolve, reject) => { setTimeout(() => { reject(new Error('非同期処理 失敗.....')); }, 3000); }).then((value) => { console.log('=== thenメソッド内 ==='); console.log('resolveされた値: ' + value); }).catch((value) => { console.log('=== catchメソッド内 ==='); console.log('rejectされた値: ' + value); }).finally(() => { console.log('=== finallyメソッド内 ==='); console.log('DONE!!') });
- 実行結果
=== catchメソッド内 === rejectされた値: Error: 非同期処理 失敗..... === finallyメソッド内 === DONE!!非同期処理の並列実行の例
Promise.all
Promise.all()
にPromiseオブジェクトの配列を渡す- 全てresolve(成功)した時に、
then()
が実行される- どれか1つでもreject(失敗)した時は、
catch()
が実行される例えば、2つのAPIを叩いて、2つとも成功したときに何か処理をするみたいなことをしたい場合は、
const postAPI1 = new Promise((resolve, reject) => { console.log('API1を叩く'); setTimeout(() => { resolve('API1成功'); }, 3000); }) const postAPI2 = new Promise((resolve, reject) => { console.log('API2を叩く'); setTimeout(() => { resolve('API2成功'); }, 200); }) Promise.all([postAPI1, postAPI2]).then((values) => { console.log('=== thenメソッド内 ===') console.log(values); });
- 実行結果
API1を叩く API2を叩く === thenメソッド内 === [ 'API1成功', 'API2成功' ]Promise.race
Promise.race()
にPromiseオブジェクトの配列を渡す- 1つでもresolve(成功), reject(失敗)が呼び出されたら、
then
もしくはcatch
が実行されるthen
やcatch
メソッドには最初に完了した処理の値が渡されるconst postAPI1 = new Promise((resolve, reject) => { console.log('API1を叩く'); setTimeout(() => { reject(new Error('API1失敗')); }, 3000); }) const postAPI2 = new Promise((resolve, reject) => { console.log('API2を叩く'); setTimeout(() => { resolve('API2成功'); }, 200); }) // postAPI2の方がsetTimeoutを短めに設定しているので、先に処理が完了する。 // そのためthenの処理が実行される。 Promise.race([postAPI1, postAPI2]) .then((value) => { console.log('=== thenメソッド内 ==='); console.log(value); }).catch((value) => { console.log('=== catchメソッド内 ==='); console.log(value); });
- 実行結果
API1を叩く API2を叩く === thenメソッド内 === API2成功参考
- 投稿日:2019-07-30T00:36:57+09:00
Node.js、Vue.js インストール(Windows)
Node.js インストール ~ 起動(node:v10.16.0, npm:v6.9.0)
- インストーラー取得 https://nodejs.org/en/download/
- インストーラー実行
画面に従い進める、許可などは確認して同意、はいを選択- インストール確認
コマンドプロンプトで以下を実行してバージョンが表示されればOK
node --version
npm --version
- プロジェクトフォルダを作成
コマンドプロンプトで以下を実行して${フォルダパス}に node_modules, package.json, package-lock.json あればOK
cd ${フォルダパス}
npm install express --save
※WARNでるが気にしない
npm init -y
※ -y を指定しない場合、対話形式で進む- 実行用のapp.js, index.html を作成
${フォルダパス}の直下に以下を作成、両方とも utf8
app.jsvar express = require('express'); var app = express(); app.use(express.static('./')); var port = 8080; app.listen(port,function(){ console.log("express server port %d", port) });index.html<!DOCTYPE html> <html> <head> <title>タイトル</title> </head> <body> こんにちは Nodejs </body> </html>
- server 実行
コマンドプロンプトで以下を実行して起動ログでればOK
node app.js
- server アクセス http://localhost:8080/
Vue.js (vue:v3.9.3)
- Node.js のインストーラー実行までやっておく
- Vue CLI をインストール
コマンドプロンプトで以下を実行
npm install -g @vue/cli
※-g を指定することでどこでも使えるようになる
npm install -g @vue/cli-service-global
※-g は上記同様
- インストール確認
コマンドプロンプトで以下を実行してバージョンが表示されればOK
vue --version
- プロジェクトフォルダを作成
コマンドプロンプトで以下を実行してプロジェクトフォルダができればOK
cd ${プロジェクトルートパス}
vue create -d ${プロジェクトフォルダ名}
※-d を指定しない場合、対話形式で設定- プロジェクトフォルダに移動して server 起動
コマンドプロンプトで以下を実行して npm のプロンプトあがればOK
cd ${プロジェクトルートパス}\${プロジェクトフォルダ名}
npm run serve
- server アクセス http://localhost:8080/