Help us understand the problem. What is going on with this article?

【クラウド初心者向け】留守番電話3(kinesis Video StreamsデータをWAV形式に変換してS3に保存)

概要

使用ユーザー

  • IAMユーザー

手順

WAVデータを保存するS3の作成

  1. AWSにサインインします。

    1. アカウント、ユーザー名、パスワードを入力してサインインします。
      アカウント内(IAM)で作成したユーザーを使用してコンソールにサインインする
  2. 『AWSマネジメントコンソール』画面の右上にある《リージョン名》をクリックし、ドロップダウンます。
    image.png

  3. 『AWSマネジメントコンソール』画面にある「サービスを検索」にS3と入力し、検索結果から《S3》をクリックし、Amazon S3 コンソール(https://console.aws.amazon.com/s3/)を開きます。
    image.png

  4. S3のバケット一覧が表示されるので、営業時間の判断で作成したバケットをクリックします。
    image.png

  5. 先ほど作成したフォルダをクリックします。
    image.png

  6. 《フォルダの作成》をクリックします。
    image.png

  7. 以下の項目を選択、入力して《保存》をクリックします。
    image.png

    1. フォルダ名:フォルダの名前
    2. 暗号化:適宜必要な暗号化設定を選択

Lambdaでebmlを利用するための準備

  1. Node.jsをインストールする

    1. 詳細は、Windows 10へNode.jsをインストールするを参照してください。
  2. Windows PowerShellを起動します。
    image.png

  3. ebmlをダウンロードするため「nodejs」フォルダを作成するためコマンドを入力して実行します。
    image.png

    1. md nodejs
  4. nodejsフォルダに移動するためコマンドを入力して実行します。
    image.png

    1. cd nodejs
  5. ebmlをダウンロードするためコマンドを入力して実行します。
    image.png

    1. npm install ebml
  6. 作成したnodejsフォルダをZip形式で圧縮します。
    image.png

    1. 作成したnodejsフォルダの中身ではなくフォルダ自体を圧縮します。
  7. AWSにサインインします。

    1. アカウント、ユーザー名、パスワードを入力してサインインします。
      アカウント内(IAM)で作成したユーザーを使用してコンソールにサインインする
  8. 『AWSマネジメントコンソール』画面の右上にある《リージョン名》をクリックし、ドロップダウンます。
    image.png

  9. 『AWSマネジメントコンソール』画面にある「サービスを検索」にLambdaと入力し、検索結果から《Lambda》をクリックし、Amazon Lambda コンソール(https://console.aws.amazon.com/lambda/)を開きます。
    image.png

  10. Lambdaの関数一覧画面が表示されるので左側のメニューから《Layers》をクリックします。
    image.png

  11. 《レイヤーの作成》をクリックします。
    image.png

  12. 以下の項目を選択、入力して《作成》をクリックします。
    image.png

    1. 名前:ebml
    2. アップロード:先ほど作成したZipファイル
    3. ランタイム:Node.js 12.x

WAV形式に変換してS3に保存するLambdaの作成

  • 以下のコードで各自で変える部分
    • region変数:バケットを作成したリージョン名
    • bucketName変数:作成したバケット名
    • putKey変数:作成したフォルダ名(終わりに『/』を入れる)
voice-message-createwav
const AWS = require("aws-sdk");
const region = 'XXXXXXXXX';
const bucketName = 'my-baseXXXXXXXXX';
const putKey = 'my-voicemessageXXXXXXXXX/wav/';

exports.handler = async (event) => {
    console.log(JSON.stringify(event));

    const s3 = new S3(AWS, region);

    console.log(event.Records);

    for (let record of event.Records) {
        const getKey = record.s3.object.key;
        var index = getKey.lastIndexOf("/");
        var fileName = "noname";

        if (index >= 0) {
            fileName = getKey.substr(index + 1);
        };

        // S3から録音データに関する情報を取得
        const data = await s3.get(record.s3.bucket.name, getKey);
        const info = JSON.parse(data.Body);
        const streamName = info.streamARN.split('stream/')[1].split('/')[0];
        const fragmentNumber =  info.startFragmentNumber;

        console.log(info)
        // Kinesis Video Streamsから当該RAWデータの取得
        const raw = await getMedia(streamName, fragmentNumber);

        // RAWデータからWAVファイルを作成
        const wav = Converter.createWav(raw, 8000);

        // WAVファイルをS3に保存する
        let tagging = ''; // 付加情報をタグに追加する
        tagging += "customerEndpoint=" + info.customerEndpoint + '&';
        tagging += "systemEndpoint=" + info.systemEndpoint + '&';
        tagging += "startTimestamp=" + info.startTimestamp;
        await s3.put(bucketName, putKey + fileName + '.wav', Buffer.from(wav.buffer), tagging)

    }
    return {};
};

class S3 {
    constructor(AWS, region){
        this._s3 = new AWS.S3({region:region});
    }
    async get(bucketName, key){
        const params = {
            Bucket: bucketName,
            Key: key
        };
        return await this._s3.getObject(params).promise();
    }

    async put(bucketName, key, body, tagging) {
        const params = {
            Bucket: bucketName,
            Key: key,
            Body: body,
            Tagging: tagging
        };
        return  await this._s3.putObject(params).promise();
    }

}

const ebml = require('ebml');

async function getMedia(streamName, fragmentNumber) {
    // Endpointの取得
    const kinesisvideo = new AWS.KinesisVideo({region: region});
    var params = {
        APIName: "GET_MEDIA",
        StreamName: streamName
    };
    const end = await kinesisvideo.getDataEndpoint(params).promise();

    // RAWデータの取得
    const kinesisvideomedia = new AWS.KinesisVideoMedia({endpoint: end.DataEndpoint, region:region});
    var params = {
        StartSelector: { 
            StartSelectorType: "FRAGMENT_NUMBER",
            AfterFragmentNumber:fragmentNumber,
        },
        StreamName: streamName
    };
    const data = await kinesisvideomedia.getMedia(params).promise();
    const decoder = new ebml.Decoder();
    let chunks = [];
    decoder.on('data', chunk => {
        if(chunk[1].name == 'SimpleBlock'){
            chunks.push(chunk[1].data);
        }
    });
    decoder.write(data["Payload"]);

    // chunksの結合
    const margin = 4; // 各chunkの先頭4バイトを破棄する
    var sumLength = 0;
    chunks.forEach( chunk => {
        sumLength += chunk.byteLength - margin;
    })
    var sample = new Uint8Array(sumLength);
    var pos = 0;
    chunks.forEach(chunk => {
        let tmp = new Uint8Array(chunk.byteLength - margin);
        for(var e = 0; e < chunk.byteLength -  margin; e++){
            tmp[e] = chunk[e + margin];
        }
        sample.set(tmp, pos);
        pos += chunk.byteLength - margin;

    })
    return sample.buffer;
}

class Converter {
    // WAVファイルの生成
    static createWav(samples, sampleRate) {
        const len = samples.byteLength;
        const view = new DataView(new ArrayBuffer(44 + len));
        this._writeString(view, 0, 'RIFF');
        view.setUint32(4, 32 + len, true);
        this._writeString(view, 8, 'WAVE');
        this._writeString(view, 12, 'fmt ');
        view.setUint32(16, 16, true);
        view.setUint16(20, 1, true); // リニアPCM
        view.setUint16(22, 1, true); // モノラル
        view.setUint32(24, sampleRate, true); 
        view.setUint32(28, sampleRate * 2, true);
        view.setUint16(32, 2, true);
        view.setUint16(34, 16, true);
        this._writeString(view, 36, 'data');
        view.setUint32(40, len, true);
        let offset = 44;
        const srcView = new DataView(samples);
        for (var i = 0; i < len; i+=4, offset+=4) {
            view.setInt32(offset, srcView.getUint32(i));
        }
        return view;
    }

    static _writeString(view, offset, string) {
        for (var i = 0; i < string.length; i++) {
          view.setUint8(offset + i, string.charCodeAt(i));
        }
    }
}

  1. AWSにサインインします。

    1. アカウント、ユーザー名、パスワードを入力してサインインします。
      アカウント内(IAM)で作成したユーザーを使用してコンソールにサインインする
  2. 『AWSマネジメントコンソール』画面の右上にある《リージョン名》をクリックし、ドロップダウンます。
    image.png

  3. 『AWSマネジメントコンソール』画面にある「サービスを検索」にLambdaと入力し、検索結果から《Lambda》をクリックし、Amazon Lambda コンソール(https://console.aws.amazon.com/lambda/)を開きます。
    image.png

  4. Lambdaの関数一覧画面が表示されるので《関数の作成》をクリックします。
    image.png

  5. 「関数名」を入力して《関数の作成》をクリックします。
    image.png

    1. voice-message-createwav
  6. 関数のベースが作成されました。関数コードを入力するため下にスクロールして「関数コード」を表示します。
    image.png

  7. 「関数コード」に初期で登録されているコードを削除して、上記voice-message-createwavをコピー&ペーストします。
    image.png

  8. 日本時間に対応させるため、画面を下にスクロールして「環境変数」に以下の値を入力し《保存》ボタンをクリックします。
    image.png

    1. キー:TZ、値:Asia/Tokyo
  9. このLambdaは実行時間がかかるため、デフォルトの設定ではTimeOutエラー発生するためタイムアウトの設定を以下の内容に変更します。
    image.png

    1. タイムアウト:10秒
  10. Lambdaにサービスへのアクセス権を設定するため下にスクロールして「実行ロール」を表示し、《XXXXXXXXロールを表示》をクリックします。
    image.png

    1. Lambdaを作成する毎に自動的にLambda名の付いたロールが一つ作成されます。
    2. Lambdaで利用しているAPIのアクセス権を付与します。
      1. kinesis Video Streamsデータ取得用情報(voice-message-infomationで作成したもの)をS3から取得するための権限
        1. GetObject
      2. kinesis Video Streamsからデータを読み込むための権限
        1. GetMedia
        2. GetDataEndpoint
      3. kinesis Video StreamsデータをWAV形式に変換したものをS3に保存するための権限
        1. PutObjectTagging
        2. PutObject
  11. 選択したロールの概要が表示されるのでポリシー名の「▶」をクリックします。
    image.png

  12. 《ポリシーの編集》をクリックします。
    image.png

  13. ビジュアルエディタが表示されるので《さらにアクセス許可を追加する》をクリックします。
    image.png

    1. Lambdaの実行ログを記録するため、デフォルトでCloudWatch Logsの権限が付与されます。
  14. 《サービスの選択》をクリックします。
    image.png

  15. 「サービス」にS3と入力し、検索結果から《S3》をクリックします。
    image.png

  16. 「アクション」に今回利用するGetObjectを入力し、《GetObject》をクリックし、選択状態にします。
    image.png

  17. 《リソース》をクリックします。
    image.png

  18. 《ARNの追加》をクリックします。
    image.png

  19. 以下の項目を選択、入力して《追加》をクリックします。
    image.png

    1. Bucket name:kinesis Video Streamsデータ取得用情報が保存されているS3のバケット名+フォルダ名(バケット名とフォルダ名やフォルダ名とフォルダ名の間は『/』で連結する)
      1. Bucket name:my-baseXXXXXXXXX/my-voicemessageXXXXXXX/infomation
    2. Object name:すべてにチェックを付ける(テキストボックスには*が入力される)
  20. 《ポリシーの確認》をクリックします。
    image.png

  21. 内容を確認して、《変更の保存》をクリックします。
    image.png

  22. 再度、ポリシー名の「▶」をクリックします。
    image.png

  23. 《ポリシーの編集》をクリックします。
    image.png

  24. ビジュアルエディタが表示されるので《さらにアクセス許可を追加する》をクリックします。
    image.png

  25. 《サービスの選択》をクリックします。
    image.png

  26. 「サービス」にS3と入力し、検索結果から《S3》をクリックします。
    image.png

  27. 「アクション」に今回利用するPutObjectを入力し、《PutObject》をクリックし、選択状態にします。
    image.png

  28. 「アクション」に今回利用するPutObjectTaggingを上書き入力し、《PutObjectTagging》をクリックし、選択状態にします。
    image.png

  29. 《リソース》をクリックします。
    image.png

  30. 《ARNの追加》をクリックします。
    image.png

  31. 以下の項目を選択、入力して《追加》をクリックします。
    image.png

    1. Bucket name:kinesis Video StreamsデータをWAVに変換したデータを保存するS3のバケット名+フォルダ名(バケット名とフォルダ名やフォルダ名とフォルダ名の間は『/』で連結する)
      1. Bucket name:my-baseXXXXXXXXX/my-voicemessageXXXXXXX/wav
    2. Object name:すべてにチェックを付ける(テキストボックスには*が入力される)
  32. 《ポリシーの確認》をクリックします。
    image.png

  33. 内容を確認して、《変更の保存》をクリックします。
    image.png

  34. 再度、ポリシー名の「▶」をクリックします。
    image.png

  35. 《ポリシーの編集》をクリックします。
    image.png

  36. ビジュアルエディタが表示されるので《さらにアクセス許可を追加する》をクリックします。
    image.png

  37. 《サービスの選択》をクリックします。
    image.png

  38. 「サービス」にKinesis Video Streamsと入力し、検索結果から《Kinesis Video Streams》をクリックします。
    image.png

  39. 「アクション」に今回利用するGetDAtaEndpointを入力し、《GetDAtaEndpoint》をクリックし、選択状態にします。
    image.png

  40. 「アクション」に今回利用するGetMediaを上書き入力し、《GetMedia》をクリックし、選択状態にします。
    image.png

  41. 《リソース》をクリックします。
    image.png

  42. 《ARNの追加》をクリックします。
    image.png

  43. 以下の項目を選択、入力して《追加》をクリックします。
    image.png

    1. Reagion:kinesis Video Streamsを作成したリージョン名
      1. Reagion : aap-northeast-1(Kinesis Video Streamsを作成したリージョン)
    2. Account:自分のアカウント名(デフォルトで入力される)
    3. Stream name:すべて
    4. Creation time:すべて
  44. 《ポリシーの確認》をクリックします。
    image.png

  45. 内容を確認して、《変更の保存》をクリックします。
    image.png

  46. Lambdaでebmlを利用するため上にスクロールして《Layers》をクリックします。
    image.png

  47. 《レイヤーの追加》をクリックします。
    image.png

  48. 以下の項目を選択して《追加》をクリックします。
    image.png

    1. 名前:ebml
    2. バージョン:先ほど作成したebmlで利用するバージョン番号
  49. kinesis Video Streamsデータ取得用情報がS3に作成された場合に動かしたいので《トリガーを追加》をクリックします。
    image.png

  50. 「トリガー」にS3と入力し、検索結果から《S3》をクリックします。
    image.png

  51. 以下の項目を選択して《追加》をクリックします。
    image.png

    1. バケット:kinesis Video Streamsデータ取得用情報を作成したバケット
    2. イベントタイプ:PUT
    3. プレフィックス:kinesis Video Streamsデータ取得用情報を作成したフォルダ
  52. 《保存》をクリックします。
    image.png

参考サイト

目次に戻る

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした