質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
AWS Lambda

AWS Lambdaは、クラウド上でアプリを実行できるコンピューティングサービス。サーバーのプロビジョニングや管理を要せず複数のイベントに対してコードを実行します。カスタムロジック用いた他AWSサービスの拡張やAWSの規模やパフォーマンスを用いたバックエンドサービスを作成できます。

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

Q&A

0回答

524閲覧

Node.js 16.xからNode.js 18.xにコード変更したら動作しない

akira777

総合スコア8

AWS Lambda

AWS Lambdaは、クラウド上でアプリを実行できるコンピューティングサービス。サーバーのプロビジョニングや管理を要せず複数のイベントに対してコードを実行します。カスタムロジック用いた他AWSサービスの拡張やAWSの規模やパフォーマンスを用いたバックエンドサービスを作成できます。

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

0グッド

0クリップ

投稿2024/03/28 08:35

編集2024/04/26 08:47

留守番電話を実装するため、下記参考サイトのWAV形式に変換してS3に保存するLambdaを利用して、問題なく動作しておりましたが、Node.js 16.xからNode.js 18.xにコード変更したところ、WAVファイルは作成されますが、中身が0バイトとなり、再生することができません。

参考サイト:https://qiita.com/echolimitless/items/af068e147e233c51d6a4

-------------------------Node.js 18.xコード---------------------------------------------------

import { GetObjectCommand, PutObjectCommand, S3Client } from "@aws-sdk/client-s3"; import { KinesisVideoClient, GetDataEndpointCommand } from "@aws-sdk/client-kinesis-video"; import { KinesisVideoMediaClient, GetMediaCommand } from "@aws-sdk/client-kinesis-video-media"; // リージョンやバケット名の設定 const region = 'ap-northeast-1'; const putKey = 'voice-message/wav/'; const bucketName = 'testname-pjcode'; // Lambda関数のエントリーポイント export const handler = async (event) => { // S3クライアントを作成 const s3Client = new S3Client({ region: region }); // イベントの各レコードに対して処理を実行 for (let record of event.Records) { // information/yyyymmdd_×××をgetKeyに格納 const getKey = record.s3.object.key; // '/'までの文字数10がindexに格納 let index = getKey.lastIndexOf('/'); let fileName = 'noname'; if (index >= 0) { // getKeyに対して、文字数11以降("/")の文字列を取得 fileName = getKey.substr(index + 1); } // S3から録音データに関する情報を取得 const s3GetCommand = new GetObjectCommand({ Bucket: bucketName, Key: getKey }); const s3GetRes = await s3Client.send(s3GetCommand); const info = await s3GetRes.Body.transformToString(); const infoStr = JSON.parse(info); const streamName = infoStr.streamARN.split('stream/')[1].split('/')[0]; const fragmentNumber = infoStr.startFragmentNumber; const streamARN = infoStr.streamARN; // Kinesis Video Media Clientを作成して、録音データを取得 const kvmClient = new KinesisVideoMediaClient({ region : region }); const kvmInput = { StreamName: streamName, StreamARN: streamARN, StartSelector: { StartSelectorType: 'FRAGMENT_NUMBER', AfterFragmentNumber: fragmentNumber, }, }; const kvmCommand = new GetMediaCommand(kvmInput); const data = await kvmClient.send(kvmCommand); // デコードされたデータをWAV形式に変換 const wav = Converter.createWav(data.Payload, 8000); // WAVファイルをS3に保存 let tagging = ''; // 付加情報をタグに追加する tagging += "customerEndpoint=" + infoStr.customerEndpoint + '&'; tagging += "systemEndpoint=" + infoStr.systemEndpoint + '&'; tagging += "startTimestamp=" + infoStr.startTimestamp; const wavInput = new PutObjectCommand({ Bucket: bucketName, Key: putKey + createKeyName() + fileName + '.wav', Body: Buffer.from(wav.buffer), Tagging: tagging }); const wavRes = await s3Client.send(wavInput); } }; // S3バケット保存時のオブジェクト名を生成 function createKeyName() { const date = new Date(); const year = date.getFullYear(); const mon = (date.getMonth() + 1); const day = date.getDate(); const hour = date.getHours(); const space = (n) => { return ('0' + (n)).slice(-2); }; let result = year + '/'; result += space(mon) + '/'; result += space(day) + '/'; result += space(hour) + '/'; return result; } // Decoderの初期化 let chunks = []; let decoder = function (data, fragmentNumber) {}; // デコーダー関数の宣言 decoderOn(); // decoderOn関数の呼び出し // デコーダー関数 decoder = function (data, fragmentNumber) { // ここでデコード処理を行う return data.Payload; // 今回はデータそのものを返す }; function decoderOn() { // デコーダーのオン/オフの設定 } class Converter { // WAVファイルの生成 static createWav(samples, sampleRate) { const len = samples.length; const view = new DataView(new ArrayBuffer(44 + len)); this._writeString(view, 0, 'RIFF'); view.setUint32(4, 36 + len, true); // RIFFのサイズを修正 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); for (let i = 0; i < len; i++) { view.setUint8(44 + i, samples[i]); } return view; } static _writeString(view, offset, string) { if (offset + string.length > view.byteLength) { throw new RangeError('Offset is outside the bounds of the DataView'); } for (let i = 0; i < string.length; i++) { if (offset + i < view.byteLength) { view.setUint8(offset + i, string.charCodeAt(i)); } else { throw new RangeError('Offset is outside the bounds of the DataView'); } } } }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mike2mike4

2024/03/28 09:28

すみません、コードが表示が変なことになってます。Lambdaのコードは</>のコードの挿入で纏めていただけないでしょうか?
akira777

2024/03/29 05:23

コメントありがとうございます。質問を修正したのでご確認よろしくお願いいたします。
mike2mike4

2024/03/29 06:53

Bufferの使用法: Node.jsでは、Bufferクラスはバイナリデータの取り扱いに用います。過去には、new Buffer()構文が推奨されていましたが、セキュリティの観点から非推奨となり、現在はBuffer.from()、Buffer.alloc()、Buffer.allocUnsafe()などのメソッドが推奨されています 。これらのメソッドが適切に使用されているか、特にNode.jsのバージョンアップに伴う変更点を踏まえて、コードを見直してください。 ChatGPTに聞いていくつかの指摘点のなかから上記が怪しいと思いました。 それよりも、CloudWatch Logのエラーを確認し、質問文に載せてください。 print文デバッグは割と有効です。
akira777

2024/03/29 07:54

ご返信、ありがとうございます。 CloudWatchも最初に確認したのですが、エラーはありませんでした。 WAVファイルも作成されておりますが、中身が空っぽで原因が特定できませんでした。 ファイルは作成されますが、ファイルの中身が無い場合、何が原因になるのでしょうか? よろしくお願いいたします。
mike2mike4

2024/03/29 09:21

stackoverflowにマルチポストされているようですが、私は気にしません。ただ、気にする人は居るので分かっても答えてくれない可能性はあります。 とりあえず、 ・Rawデータが取得できているか確認してください。 ・単純にV2からV3にバージョンアップしたいのであれば、codemodコマンドで上げられるようです。 https://docs.aws.amazon.com/ja_jp/sdk-for-javascript/v3/developer-guide/migrating.html ローカルに環境構築してcodemodコマンドで変換出来れば良し。ダメなら、どこまで出来ているか切り分けてください(Rawデータが出来ているか確認するのが一例です)
akira777

2024/04/12 07:16 編集

コードを修正してもダメでした。
mike2mike4

2024/04/12 07:37

Rawデータが入っていることは確認できましたでしょうか? 以下の、console.logを入れて確認してみてください。 async function getMedia(streamName, fragmentNumber) { let kvInput = { APIName: "GET_MEDIA", StreamName: streamName }; // Kinesis Video Clientでエンドポイントを取得 const kvClient = new KinesisVideoClient({ region: region }); const kvCommand = new GetDataEndpointCommand(kvInput); const endpointResponse = await kvClient.send(kvCommand); // Kinesis Video Media Clientを使用してRAWデータを取得 let kvmInput = { StartSelector: { StartSelectorType: "FRAGMENT_NUMBER", AfterFragmentNumber: fragmentNumber, }, StreamName: streamName }; const kvmClient = new KinesisVideoMediaClient({ endpoint: endpointResponse.DataEndpoint, region: region }); const kvmCommand = new GetMediaCommand(kvmInput); const mediaResponse = await kvmClient.send(kvmCommand); // RAWデータのバイト長と内容の一部をログ出力 console.log("RAWデータのバイト長: ", mediaResponse.Payload.length); console.log("RAWデータの内容の先頭部分: ", mediaResponse.Payload.slice(0, 100)); return mediaResponse.Payload; }
akira777

2024/04/25 01:15 編集

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, 36 + len, true); // RIFFのサイズを修正 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); const srcView = new DataView(samples); let offset = 44; for (let i = 0; i < len; i++) { if (offset + i >= view.byteLength) { throw new RangeError('Offset is outside the bounds of the DataView'); } view.setUint8(offset + i, srcView.getUint8(i)); } return view; } static _writeString(view, offset, string) { if (offset + string.length > view.byteLength) { throw new RangeError('Offset is outside the bounds of the DataView'); } for (let i = 0; i < string.length; i++) { view.setUint8(offset + i, string.charCodeAt(i)); } } }
akira777

2024/04/26 08:25 編集

2024-04-26T08:24:14.597Z undefined ERROR Uncaught Exception { "errorType": "Runtime.UserCodeSyntaxError", "errorMessage": "SyntaxError: Identifier 'decoder' has already been declared", "stack": [ "Runtime.UserCodeSyntaxError: SyntaxError: Identifier 'decoder' has already been declared", " at _loadUserApp (file:///var/runtime/index.mjs:1084:17)", " at async UserFunction.js.module.exports.load (file:///var/runtime/index.mjs:1119:21)", " at async start (file:///var/runtime/index.mjs:1282:23)", " at async file:///var/runtime/index.mjs:1288:1" ] }
mike2mike4

2024/04/26 08:08

通知が来るので見ることは見ているのですが、コードとエラーメッセージだけで何をして、どういう結果を期待し、どこでエラーが出たのか書いてないので私はコメントのしようがありません。同一環境を用意できないのでこちらで試すこともできません。エラーメッセージが分からないときはAIチャット(ChatGPTやClaude)に聞いてみるといいですよ。
akira777

2024/04/26 08:49

ありがとうございます。 いろいろと試行錯誤しているのですが、当初はCloudWatchではエラーが発生しなかったのですが、コードを変更すると下記のエラーが発生してしまい、解消されません。 2024-04-26T08:44:12.504Z 0f00a54c-a362-4be7-aff3-10f97307eeef ERROR Invoke Error { "errorType": "RangeError", "errorMessage": "Offset is outside the bounds of the DataView", "stack": [ "RangeError: Offset is outside the bounds of the DataView", " at Converter._writeString (file:///var/task/index.mjs:138:19)", " at Converter.createWav (file:///var/task/index.mjs:115:14)", " at Runtime.handler (file:///var/task/index.mjs:56:31)", " at process.processTicksAndRejections (node:internal/process/task_queues:95:5)" ] }
mike2mike4

2024/04/26 09:03

エラーを見ると、DataViewのバッファからデータが溢れているようです。初期値とか変更しなかったでしょうか? 大きめに設定し直すか、console.logで大きさを測って再設定してください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問