{
    "componentChunkName": "component---src-templates-blog-post-jsx",
    "path": "/post/rn-audio-record/",
    "result": {"data":{"site":{"siteMetadata":{"title":"WEB EGG","author":"Leko - CTO at Yuimedi"}},"markdownRemark":{"id":"09daeeda-cfa4-5354-8a09-9d58f73e1f3b","excerpt":"こんにちは。 React Nativeで音声の録音機能を実装した時のメモです。 使用するライブラリはAndroidにも対応しているので、iOS/Android両方対応してみます。 つくったもの — Leko/ReactNative-KitchenSink: Kitchen sink of react-native…","html":"<p>こんにちは。<br>\nReact Nativeで音声の録音機能を実装した時のメモです。</p>\n<p>使用するライブラリはAndroidにも対応しているので、iOS/Android両方対応してみます。</p>\n<!--more-->\n<h2 id=\"つくったもの\" style=\"position:relative;\"><a href=\"#%E3%81%A4%E3%81%8F%E3%81%A3%E3%81%9F%E3%82%82%E3%81%AE\" aria-label=\"つくったもの permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>つくったもの</h2>\n<blockquote>\n<p>— <a href=\"https://github.com/Leko/ReactNative-KitchenSink\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Leko/ReactNative-KitchenSink: Kitchen sink of react-native</a></p>\n</blockquote>\n<p>ここにおいてあります。<br>\nこの記事に関係する差分は<a href=\"https://github.com/Leko/ReactNative-KitchenSink/pull/1\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">このPR</a>になります。</p>\n<p>先の話ですが、今後React Nativeの実験的な記事を書いていくときにここにコードを置いていこうと思います。</p>\n<h2 id=\"react-native-audioを導入\" style=\"position:relative;\"><a href=\"#react-native-audio%E3%82%92%E5%B0%8E%E5%85%A5\" aria-label=\"react native audioを導入 permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>react-native-audioを導入</h2>\n<p><a href=\"https://github.com/jsierles/react-native-audio\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">jsierles/react-native-audio</a>というライブラリを使ってみました。<br>\n他にも選択肢はあったんですが、Starが結構（執筆時点で417）ついていて、LicenseもMITなので採用しました。</p>\n<div class=\"gatsby-highlight\" data-language=\"shell\"><pre class=\"language-shell\"><code class=\"language-shell\"><span class=\"token function\">npm</span> <span class=\"token function\">install</span> react-native-audio --save\nreact-native <span class=\"token function\">link</span> react-native-audio</code></pre></div>\n<p>差分は<a href=\"https://github.com/Leko/ReactNative-KitchenSink/compare/94c16d2...47a5089\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">こちら</a>を確認して下さい</p>\n<h2 id=\"infoplistを編集\" style=\"position:relative;\"><a href=\"#infoplist%E3%82%92%E7%B7%A8%E9%9B%86\" aria-label=\"infoplistを編集 permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Info.plistを編集</h2>\n<p>マイクを扱うには、ユーザに許可を求めるために設定を書き換える必要があります。</p>\n<p>差分は<a href=\"https://github.com/Leko/ReactNative-KitchenSink/compare/47a5089...867ca77\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">こちら</a>を確認して下さい</p>\n<h3 id=\"ios\" style=\"position:relative;\"><a href=\"#ios\" aria-label=\"ios permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>iOS</h3>\n<p><code>ios/ReactNativeKitchenSink/Info.plist</code>に追加</p>\n<div class=\"gatsby-highlight\" data-language=\"xml\"><pre class=\"language-xml\"><code class=\"language-xml\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>key</span><span class=\"token punctuation\">></span></span>NSMicrophoneUsageDescription<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>key</span><span class=\"token punctuation\">></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>string</span><span class=\"token punctuation\">></span></span>This sample uses the microphone to record your speech and convert it to text.<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>string</span><span class=\"token punctuation\">></span></span></code></pre></div>\n<p><code>&#x3C;string>...&#x3C;/string></code>のところはなぜマイクを使う必要があるのかを記入します。</p>\n<blockquote>\n<p>— <a href=\"http://dev.classmethod.jp/smartphone/iphone/ios10-privacy-data-purpose-description/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">[iOS 10] 各種ユーザーデータへアクセスする目的を記述することが必須になるようです ｜ Developers.IO</a></p>\n</blockquote>\n<h3 id=\"android\" style=\"position:relative;\"><a href=\"#android\" aria-label=\"android permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Android</h3>\n<p><code>android/app/src/main/AndroidManifest.xml</code>に追加</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&lt;uses-permission android:name=\"android.permission.RECORD_AUDIO\" /></code></pre></div>\n<h2 id=\"音声の仕様を決定する\" style=\"position:relative;\"><a href=\"#%E9%9F%B3%E5%A3%B0%E3%81%AE%E4%BB%95%E6%A7%98%E3%82%92%E6%B1%BA%E5%AE%9A%E3%81%99%E3%82%8B\" aria-label=\"音声の仕様を決定する permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>音声の仕様を決定する</h2>\n<p><a href=\"https://github.com/jsierles/react-native-audio#cross-platform-options\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">公式のCross-platform options</a>を見てみると、<br>\niOS, Androidの共通項となるオーディオフォーマットは<code>aac</code>だけです。<br>\nということで、今回は<code>.aac</code>ファイルとして録音した音声を保存することにします。</p>\n<p>ひとまず音になっていればいいので、サンプリングレートやチャンネル数は適当にしておきます。</p>\n<h2 id=\"録音処理\" style=\"position:relative;\"><a href=\"#%E9%8C%B2%E9%9F%B3%E5%87%A6%E7%90%86\" aria-label=\"録音処理 permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>録音処理</h2>\n<p><a href=\"https://github.com/jsierles/react-native-audio#usage\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">公式のUsage</a>がやや複雑なので、もう少し簡素なものを実装しました。\nまるごと貼ると長くなってしまうので、全差分は<a href=\"https://github.com/Leko/ReactNative-KitchenSink/blob/master/src/scenes/AudioRecord.js\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">こちら</a>を確認して下さい。</p>\n<h3 id=\"録音するための準備\" style=\"position:relative;\"><a href=\"#%E9%8C%B2%E9%9F%B3%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AE%E6%BA%96%E5%82%99\" aria-label=\"録音するための準備 permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>録音するための準備</h3>\n<p>録音を開始する前に、ファイルパスやフォーマット、メタ情報などを与えておく必要があります。</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\">  <span class=\"token keyword\">async</span> <span class=\"token function\">setUp</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> options <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n      SampleRate<span class=\"token operator\">:</span> <span class=\"token number\">22050</span><span class=\"token punctuation\">,</span>    <span class=\"token comment\">// CDと同じ</span>\n      Channels<span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>          <span class=\"token comment\">// モノラル</span>\n      AudioQuality<span class=\"token operator\">:</span> <span class=\"token string\">'Low'</span><span class=\"token punctuation\">,</span>  <span class=\"token comment\">// </span>\n      AudioEncoding<span class=\"token operator\">:</span> <span class=\"token string\">'aac'</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// iOS/Android両対応のフォーマット</span>\n    <span class=\"token punctuation\">}</span>\n\n    <span class=\"token keyword\">return</span> AudioRecorder<span class=\"token punctuation\">.</span><span class=\"token function\">prepareRecordingAtPath</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>props<span class=\"token punctuation\">.</span>audioPath<span class=\"token punctuation\">,</span> options<span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span></code></pre></div>\n<h3 id=\"録音する\" style=\"position:relative;\"><a href=\"#%E9%8C%B2%E9%9F%B3%E3%81%99%E3%82%8B\" aria-label=\"録音する permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>録音する</h3>\n<p>準備が整っていれば、<code>AudioRecorder.startRecording</code>を呼ぶだけです。</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\">  <span class=\"token keyword\">async</span> <span class=\"token function\">record</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> <span class=\"token keyword\">await</span> AudioRecorder<span class=\"token punctuation\">.</span><span class=\"token function\">startRecording</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span></code></pre></div>\n<h3 id=\"録音中の経過時間を取得する\" style=\"position:relative;\"><a href=\"#%E9%8C%B2%E9%9F%B3%E4%B8%AD%E3%81%AE%E7%B5%8C%E9%81%8E%E6%99%82%E9%96%93%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B\" aria-label=\"録音中の経過時間を取得する permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>録音中の経過時間を取得する</h3>\n<p>iOS/Androidともに<code>AudioRecorder.onProgress</code>というイベントハンドラが設定できます。<br>\nこれをstateやactionに渡してあげることで、何秒間録音しているかを表示したり、録音可能な秒数を制限する機能の実装などができると思います。</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\">  <span class=\"token function\">componentDidMount</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// ...</span>\n    AudioRecorder<span class=\"token punctuation\">.</span><span class=\"token function-variable function\">onProgress</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> currentTime <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">setState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> recordingTime<span class=\"token operator\">:</span> Math<span class=\"token punctuation\">.</span><span class=\"token function\">floor</span><span class=\"token punctuation\">(</span>currentTime<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span></code></pre></div>\n<h3 id=\"録音終了するandroid\" style=\"position:relative;\"><a href=\"#%E9%8C%B2%E9%9F%B3%E7%B5%82%E4%BA%86%E3%81%99%E3%82%8Bandroid\" aria-label=\"録音終了するandroid permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>録音終了する（Android）</h3>\n<p>Androidの場合は<code>AudioRecorder.stopRecording</code>を呼ぶだけです。<br>\nなぜここが揃ってないのかわからないのですが、iOSは別の方法で完了をハンドリングします</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\">  <span class=\"token keyword\">async</span> <span class=\"token function\">tearDown</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">success</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">setState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> recording<span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span> recorded<span class=\"token operator\">:</span> success<span class=\"token punctuation\">,</span> recordingTime<span class=\"token operator\">:</span> <span class=\"token number\">0</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">async</span> <span class=\"token function\">handleStop</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>state<span class=\"token punctuation\">.</span>recording<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">return</span>\n    <span class=\"token punctuation\">}</span>\n\n    <span class=\"token keyword\">const</span> filePath <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> AudioRecorder<span class=\"token punctuation\">.</span><span class=\"token function\">stopRecording</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>Platform<span class=\"token punctuation\">.</span><span class=\"token constant\">OS</span> <span class=\"token operator\">===</span> <span class=\"token string\">'android'</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">await</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">tearDown</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span> filePath<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span></code></pre></div>\n<h3 id=\"録音終了するios\" style=\"position:relative;\"><a href=\"#%E9%8C%B2%E9%9F%B3%E7%B5%82%E4%BA%86%E3%81%99%E3%82%8Bios\" aria-label=\"録音終了するios permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>録音終了する（iOS）</h3>\n<p>iOS用の録音を終了する処理は<code>AudioRecorder.onFinished</code>イベントハンドラから行います<br>\nこれは、Androidのほうで出てきた<code>AudioRecorder.stopRecording</code>から内部的にコールされます<br>\n<code>tearDown</code>は先ほど貼ったコードと同じなので割愛します</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\">  <span class=\"token function\">componentDidMount</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> isOK <span class=\"token operator\">=</span> <span class=\"token function\">flow</span><span class=\"token punctuation\">(</span><span class=\"token function\">digger</span><span class=\"token punctuation\">(</span><span class=\"token string\">'status'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token function\">is</span><span class=\"token punctuation\">(</span><span class=\"token string\">'OK'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n    AudioRecorder<span class=\"token punctuation\">.</span><span class=\"token function-variable function\">onFinished</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">data</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>Platform<span class=\"token punctuation\">.</span><span class=\"token constant\">OS</span> <span class=\"token operator\">!==</span> <span class=\"token string\">'ios'</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">return</span>\n      <span class=\"token punctuation\">}</span>\n      <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">tearDown</span><span class=\"token punctuation\">(</span><span class=\"token function\">isOK</span><span class=\"token punctuation\">(</span>data<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token comment\">// ...</span>\n  <span class=\"token punctuation\">}</span></code></pre></div>\n<h2 id=\"録音中のstate変更とui\" style=\"position:relative;\"><a href=\"#%E9%8C%B2%E9%9F%B3%E4%B8%AD%E3%81%AEstate%E5%A4%89%E6%9B%B4%E3%81%A8ui\" aria-label=\"録音中のstate変更とui permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>録音中のstate変更とUI</h2>\n<p>上記コードの中ですでにsetStateが出ていることからもお察しの通り、<br>\nreact-native-audioは録音していることをあらわすUIは提供してくれません。自前で実装する必要があります。</p>\n<p>べた書きコンポーネントなのでやや読みづらいかもしれませんが、<br>\nコードを読めばどこが状態を書き換えるべきポイントかは分かるかと思います。<br>\nもしReduxな方ならactionに変えればいいし、他のFluxでも同様に、フックポイントにあたる部分を好みの通りに改変してもらえればと思います。</p>\n<h2 id=\"録音した音声を再生する\" style=\"position:relative;\"><a href=\"#%E9%8C%B2%E9%9F%B3%E3%81%97%E3%81%9F%E9%9F%B3%E5%A3%B0%E3%82%92%E5%86%8D%E7%94%9F%E3%81%99%E3%82%8B\" aria-label=\"録音した音声を再生する permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>録音した音声を再生する</h2>\n<p>「あ、その機能はないんだ」感がややありますが、録音した音声を再生する手段が提供されていません。<br>\nですが、公式のデモにもある通り、<a href=\"https://github.com/zmxv/react-native-sound\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">react-native-sound</a>を利用すれば簡単に再生できます。<br>\n名前がややこしいですが、<code>audio</code>は録音、<code>sound</code>は再生、覚えゲーです。混同しないようにご注意下さい。</p>\n<p><a href=\"https://github.com/zmxv/react-native-sound#notes\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">AAC形式の音声はiOS/Androidどちらでも再生可能</a>なので、録音形式をAACにしておけば、互換性にさほど悩まずに済むと思います。</p>\n<h2 id=\"あとがき\" style=\"position:relative;\"><a href=\"#%E3%81%82%E3%81%A8%E3%81%8C%E3%81%8D\" aria-label=\"あとがき permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>あとがき</h2>\n<p>公式のREADME見るだけではやはりハマるポイントがあり、まとめておきたいと思いました。<br>\n一度写経した上で削って最小構成にして理解していく、という方法が私が理解しやすいかなと思っています。</p>\n<p>次回以降の記事で、</p>\n<ul>\n<li>音声メディアで出てくる用語</li>\n<li>音声メディアで出てくるファイルの形式・オーディオコーデック</li>\n<li>この録音した音声をS3にアップロードしたり、といった音声メディアの取扱い</li>\n</ul>\n<p>などについてものんびりと書き留めていこうと思っていますので、ぜひ今後の続編も読んでいただけると幸いです。</p>","timeToRead":7,"frontmatter":{"title":"React nativeで音声を録音する","tags":["JavaScript","React","React Native","iOS","Android"],"date":"July 25, 2017","featuredImage":{"childImageSharp":{"fluid":{"tracedSVG":"data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='400'%20height='165'%20viewBox='0%200%20400%20165'%20preserveAspectRatio='none'%3e%3cpath%20d='M206%206v6h194V0H206v6M95%2020c0%201-1%202-2%201-3%200-3%200-3%202s3%204%204%202h17c2%201%206%201%206-1%200-3%202-2%202%200%201%204%205%203%205-1s-1-5-2-3l-8%201-8%201h-1l-3-1c-1%201-2%200-2-1h-5M48%20145c0%202%200%202-1%201%200-2-1-2-1-1l-1-1c-1-1-1-1-1%201s-1%203-4%201c-1-2-3-2-3-1l-2-1c-3-1-3-1-4%201h-7l-1-2-1%201h-7l2%201%201%203c0%202%200%202%201%201l5-1h5l2-1%201-1c0%202%202%202%209%202h5c3%200%203-1%203-3%200-4-1-4-1%200'%20fill='%23d3d3d3'%20fill-rule='evenodd'/%3e%3c/svg%3e","aspectRatio":2.420289855072464,"src":"/static/1d908d149b3ad712f8636d800bf063bf/8eab8/featured-image.png","srcSet":"/static/1d908d149b3ad712f8636d800bf063bf/1ec58/featured-image.png 334w,\n/static/1d908d149b3ad712f8636d800bf063bf/ccb4a/featured-image.png 668w,\n/static/1d908d149b3ad712f8636d800bf063bf/8eab8/featured-image.png 1336w,\n/static/1d908d149b3ad712f8636d800bf063bf/85e22/featured-image.png 2004w,\n/static/1d908d149b3ad712f8636d800bf063bf/ebefb/featured-image.png 2058w","srcWebp":"/static/1d908d149b3ad712f8636d800bf063bf/f7e47/featured-image.webp","srcSetWebp":"/static/1d908d149b3ad712f8636d800bf063bf/cd98f/featured-image.webp 334w,\n/static/1d908d149b3ad712f8636d800bf063bf/7535d/featured-image.webp 668w,\n/static/1d908d149b3ad712f8636d800bf063bf/f7e47/featured-image.webp 1336w,\n/static/1d908d149b3ad712f8636d800bf063bf/f6b67/featured-image.webp 2004w,\n/static/1d908d149b3ad712f8636d800bf063bf/8aa9d/featured-image.webp 2058w","sizes":"(max-width: 1336px) 100vw, 1336px"}}}}}},"pageContext":{"slug":"/rn-audio-record/","previous":{"fields":{"slug":"/benefits-of-node-bluebird/"},"frontmatter":{"title":"ネイティブのPromiseより早いbluebirdのPromiseの便利機能をまとめてみた","tags":["Nodejs","JavaScript"]}},"next":{"fields":{"slug":"/special-chars-for-cli/"},"frontmatter":{"title":"CLIアプリに使えそうな特殊文字たちで遊んでみた","tags":["Nodejs","JavaScript","CLI"]}}}},
    "staticQueryHashes": ["2585454260","2954598359"]}