Add a new parameter |latency| to PPB_AudioInput_Callback.

This CL updates the version of PPB_AudioInput_Dev and PPB_AudioInput_Callback; it also adds a new type PP_TimeDelta.

BUG=240900
TEST=None

Review URL: https://chromiumcodereview.appspot.com/14619033

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@209965 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/content/renderer/pepper/pepper_platform_audio_input_impl.cc b/content/renderer/pepper/pepper_platform_audio_input_impl.cc
index b0800a7c..3aaa36a 100644
--- a/content/renderer/pepper/pepper_platform_audio_input_impl.cc
+++ b/content/renderer/pepper/pepper_platform_audio_input_impl.cc
@@ -14,6 +14,7 @@
 #include "content/renderer/render_thread_impl.h"
 #include "googleurl/src/gurl.h"
 #include "media/audio/audio_manager_base.h"
+#include "ppapi/shared_impl/ppb_audio_config_shared.h"
 
 namespace content {
 
@@ -152,8 +153,9 @@
   client_ = client;
 
   params_.Reset(media::AudioParameters::AUDIO_PCM_LINEAR,
-                media::CHANNEL_LAYOUT_MONO, 1, 0,
-                sample_rate, 16, frames_per_buffer);
+                media::CHANNEL_LAYOUT_MONO, ppapi::kAudioInputChannels, 0,
+                sample_rate, ppapi::kBitsPerAudioInputSample,
+                frames_per_buffer);
 
   // We need to open the device and obtain the label and session ID before
   // initializing.
diff --git a/ppapi/api/dev/ppb_audio_input_dev.idl b/ppapi/api/dev/ppb_audio_input_dev.idl
index 29c60cc..191c6d5cd8 100644
--- a/ppapi/api/dev/ppb_audio_input_dev.idl
+++ b/ppapi/api/dev/ppb_audio_input_dev.idl
@@ -8,20 +8,26 @@
  * provides realtime audio input capture.
  */
 
-[generate_thunk]
-
 label Chrome {
   M19 = 0.2,
-  M25 = 0.3
+  M25 = 0.3,
+  M29 = 0.4
 };
 
 /**
  * <code>PPB_AudioInput_Callback</code> defines the type of an audio callback
  * function used to provide the audio buffer with data. This callback will be
  * called on a separate thread from the creation thread.
+ *
+ * @param[in] sample_buffer A buffer providing audio input data.
+ * @param[in] buffer_size_in_bytes The size of the buffer in bytes.
+ * @param[in] latency The time that has elapsed since the data was recorded.
+ * @param[inout] user_data An opaque pointer that was passed into
+ * <code>PPB_AudioInput_Dev.Open()</code>.
  */
 typedef void PPB_AudioInput_Callback([in] mem_t sample_buffer,
                                      [in] uint32_t buffer_size_in_bytes,
+                                     [in, version=0.4] PP_TimeDelta latency,
                                      [inout] mem_t user_data);
 
 /**
diff --git a/ppapi/api/pp_time.idl b/ppapi/api/pp_time.idl
index 02de3ae..fdcac59 100644
--- a/ppapi/api/pp_time.idl
+++ b/ppapi/api/pp_time.idl
@@ -4,7 +4,7 @@
  */
 
 /**
- * This file defines time and time ticks types.
+ * This file defines time, time ticks and time delta types.
  */
 
 
@@ -29,3 +29,9 @@
 [assert_size(8)]
 typedef double_t PP_TimeTicks;
 
+/**
+ * A <code>PP_TimeDelta</code> value represents a duration of time which is
+ * measured in seconds.
+ */
+[assert_size(8)]
+typedef double_t PP_TimeDelta;
diff --git a/ppapi/c/dev/ppb_audio_input_dev.h b/ppapi/c/dev/ppb_audio_input_dev.h
index b47c7ea..2fd4d070 100644
--- a/ppapi/c/dev/ppb_audio_input_dev.h
+++ b/ppapi/c/dev/ppb_audio_input_dev.h
@@ -3,7 +3,7 @@
  * found in the LICENSE file.
  */
 
-/* From dev/ppb_audio_input_dev.idl modified Tue Dec 04 15:13:31 2012. */
+/* From dev/ppb_audio_input_dev.idl modified Fri May 10 16:06:35 2013. */
 
 #ifndef PPAPI_C_DEV_PPB_AUDIO_INPUT_DEV_H_
 #define PPAPI_C_DEV_PPB_AUDIO_INPUT_DEV_H_
@@ -16,10 +16,12 @@
 #include "ppapi/c/pp_macros.h"
 #include "ppapi/c/pp_resource.h"
 #include "ppapi/c/pp_stdint.h"
+#include "ppapi/c/pp_time.h"
 
 #define PPB_AUDIO_INPUT_DEV_INTERFACE_0_2 "PPB_AudioInput(Dev);0.2"
 #define PPB_AUDIO_INPUT_DEV_INTERFACE_0_3 "PPB_AudioInput(Dev);0.3"
-#define PPB_AUDIO_INPUT_DEV_INTERFACE PPB_AUDIO_INPUT_DEV_INTERFACE_0_3
+#define PPB_AUDIO_INPUT_DEV_INTERFACE_0_4 "PPB_AudioInput(Dev);0.4"
+#define PPB_AUDIO_INPUT_DEV_INTERFACE PPB_AUDIO_INPUT_DEV_INTERFACE_0_4
 
 /**
  * @file
@@ -36,10 +38,21 @@
  * <code>PPB_AudioInput_Callback</code> defines the type of an audio callback
  * function used to provide the audio buffer with data. This callback will be
  * called on a separate thread from the creation thread.
+ *
+ * @param[in] sample_buffer A buffer providing audio input data.
+ * @param[in] buffer_size_in_bytes The size of the buffer in bytes.
+ * @param[in] latency The time that has elapsed since the data was recorded.
+ * @param[inout] user_data An opaque pointer that was passed into
+ * <code>PPB_AudioInput_Dev.Open()</code>.
  */
 typedef void (*PPB_AudioInput_Callback)(const void* sample_buffer,
                                         uint32_t buffer_size_in_bytes,
+                                        PP_TimeDelta latency,
                                         void* user_data);
+
+typedef void (*PPB_AudioInput_Callback_0_2)(const void* sample_buffer,
+                                            uint32_t buffer_size_in_bytes,
+                                            void* user_data);
 /**
  * @}
  */
@@ -65,7 +78,7 @@
  * device. We may want to move the "recommend" functions to the input or output
  * classes rather than the config.
  */
-struct PPB_AudioInput_Dev_0_3 {
+struct PPB_AudioInput_Dev_0_4 {
   /**
    * Creates an audio input resource.
    *
@@ -196,7 +209,7 @@
   void (*Close)(PP_Resource audio_input);
 };
 
-typedef struct PPB_AudioInput_Dev_0_3 PPB_AudioInput_Dev;
+typedef struct PPB_AudioInput_Dev_0_4 PPB_AudioInput_Dev;
 
 struct PPB_AudioInput_Dev_0_2 {
   PP_Resource (*Create)(PP_Instance instance);
@@ -207,7 +220,28 @@
   int32_t (*Open)(PP_Resource audio_input,
                   PP_Resource device_ref,
                   PP_Resource config,
-                  PPB_AudioInput_Callback audio_input_callback,
+                  PPB_AudioInput_Callback_0_2 audio_input_callback,
+                  void* user_data,
+                  struct PP_CompletionCallback callback);
+  PP_Resource (*GetCurrentConfig)(PP_Resource audio_input);
+  PP_Bool (*StartCapture)(PP_Resource audio_input);
+  PP_Bool (*StopCapture)(PP_Resource audio_input);
+  void (*Close)(PP_Resource audio_input);
+};
+
+struct PPB_AudioInput_Dev_0_3 {
+  PP_Resource (*Create)(PP_Instance instance);
+  PP_Bool (*IsAudioInput)(PP_Resource resource);
+  int32_t (*EnumerateDevices)(PP_Resource audio_input,
+                              struct PP_ArrayOutput output,
+                              struct PP_CompletionCallback callback);
+  int32_t (*MonitorDeviceChange)(PP_Resource audio_input,
+                                 PP_MonitorDeviceChangeCallback callback,
+                                 void* user_data);
+  int32_t (*Open)(PP_Resource audio_input,
+                  PP_Resource device_ref,
+                  PP_Resource config,
+                  PPB_AudioInput_Callback_0_2 audio_input_callback,
                   void* user_data,
                   struct PP_CompletionCallback callback);
   PP_Resource (*GetCurrentConfig)(PP_Resource audio_input);
diff --git a/ppapi/c/pp_time.h b/ppapi/c/pp_time.h
index 103e405..145ca46d 100644
--- a/ppapi/c/pp_time.h
+++ b/ppapi/c/pp_time.h
@@ -1,9 +1,9 @@
-/* Copyright (c) 2011 The Chromium Authors. All rights reserved.
+/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
 
-/* From pp_time.idl modified Tue Jul  5 16:02:03 2011. */
+/* From pp_time.idl modified Fri May 10 15:48:42 2013. */
 
 #ifndef PPAPI_C_PP_TIME_H_
 #define PPAPI_C_PP_TIME_H_
@@ -13,7 +13,7 @@
 
 /**
  * @file
- * This file defines time and time ticks types.
+ * This file defines time, time ticks and time delta types.
  */
 
 
@@ -41,6 +41,13 @@
  */
 typedef double PP_TimeTicks;
 PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_TimeTicks, 8);
+
+/**
+ * A <code>PP_TimeDelta</code> value represents a duration of time which is
+ * measured in seconds.
+ */
+typedef double PP_TimeDelta;
+PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_TimeDelta, 8);
 /**
  * @}
  */
diff --git a/ppapi/cpp/dev/audio_input_dev.cc b/ppapi/cpp/dev/audio_input_dev.cc
index cc0f08b..0c2f3778 100644
--- a/ppapi/cpp/dev/audio_input_dev.cc
+++ b/ppapi/cpp/dev/audio_input_dev.cc
@@ -22,13 +22,20 @@
   return PPB_AUDIO_INPUT_DEV_INTERFACE_0_3;
 }
 
+template <> const char* interface_name<PPB_AudioInput_Dev_0_4>() {
+  return PPB_AUDIO_INPUT_DEV_INTERFACE_0_4;
+}
+
 }  // namespace
 
 AudioInput_Dev::AudioInput_Dev() {
 }
 
 AudioInput_Dev::AudioInput_Dev(const InstanceHandle& instance) {
-  if (has_interface<PPB_AudioInput_Dev_0_3>()) {
+  if (has_interface<PPB_AudioInput_Dev_0_4>()) {
+    PassRefFromConstructor(get_interface<PPB_AudioInput_Dev_0_4>()->Create(
+        instance.pp_instance()));
+  } else if (has_interface<PPB_AudioInput_Dev_0_3>()) {
     PassRefFromConstructor(get_interface<PPB_AudioInput_Dev_0_3>()->Create(
         instance.pp_instance()));
   } else if (has_interface<PPB_AudioInput_Dev_0_2>()) {
@@ -42,12 +49,17 @@
 
 // static
 bool AudioInput_Dev::IsAvailable() {
-  return has_interface<PPB_AudioInput_Dev_0_3>() ||
+  return has_interface<PPB_AudioInput_Dev_0_4>() ||
+         has_interface<PPB_AudioInput_Dev_0_3>() ||
          has_interface<PPB_AudioInput_Dev_0_2>();
 }
 
 int32_t AudioInput_Dev::EnumerateDevices(
     const CompletionCallbackWithOutput<std::vector<DeviceRef_Dev> >& callback) {
+  if (has_interface<PPB_AudioInput_Dev_0_4>()) {
+    return get_interface<PPB_AudioInput_Dev_0_4>()->EnumerateDevices(
+        pp_resource(), callback.output(), callback.pp_completion_callback());
+  }
   if (has_interface<PPB_AudioInput_Dev_0_3>()) {
     return get_interface<PPB_AudioInput_Dev_0_3>()->EnumerateDevices(
         pp_resource(), callback.output(), callback.pp_completion_callback());
@@ -72,6 +84,10 @@
 int32_t AudioInput_Dev::MonitorDeviceChange(
     PP_MonitorDeviceChangeCallback callback,
     void* user_data) {
+  if (has_interface<PPB_AudioInput_Dev_0_4>()) {
+    return get_interface<PPB_AudioInput_Dev_0_4>()->MonitorDeviceChange(
+        pp_resource(), callback, user_data);
+  }
   if (has_interface<PPB_AudioInput_Dev_0_3>()) {
     return get_interface<PPB_AudioInput_Dev_0_3>()->MonitorDeviceChange(
         pp_resource(), callback, user_data);
@@ -85,13 +101,8 @@
                              PPB_AudioInput_Callback audio_input_callback,
                              void* user_data,
                              const CompletionCallback& callback) {
-  if (has_interface<PPB_AudioInput_Dev_0_3>()) {
-    return get_interface<PPB_AudioInput_Dev_0_3>()->Open(
-        pp_resource(), device_ref.pp_resource(), config.pp_resource(),
-        audio_input_callback, user_data, callback.pp_completion_callback());
-  }
-  if (has_interface<PPB_AudioInput_Dev_0_2>()) {
-    return get_interface<PPB_AudioInput_Dev_0_2>()->Open(
+  if (has_interface<PPB_AudioInput_Dev_0_4>()) {
+    return get_interface<PPB_AudioInput_Dev_0_4>()->Open(
         pp_resource(), device_ref.pp_resource(), config.pp_resource(),
         audio_input_callback, user_data, callback.pp_completion_callback());
   }
@@ -99,7 +110,31 @@
   return callback.MayForce(PP_ERROR_NOINTERFACE);
 }
 
+int32_t AudioInput_Dev::Open(
+    const DeviceRef_Dev& device_ref,
+    const AudioConfig& config,
+    PPB_AudioInput_Callback_0_2 audio_input_callback_0_2,
+    void* user_data,
+    const CompletionCallback& callback) {
+  if (has_interface<PPB_AudioInput_Dev_0_3>()) {
+    return get_interface<PPB_AudioInput_Dev_0_3>()->Open(
+        pp_resource(), device_ref.pp_resource(), config.pp_resource(),
+        audio_input_callback_0_2, user_data, callback.pp_completion_callback());
+  }
+  if (has_interface<PPB_AudioInput_Dev_0_2>()) {
+    return get_interface<PPB_AudioInput_Dev_0_2>()->Open(
+        pp_resource(), device_ref.pp_resource(), config.pp_resource(),
+        audio_input_callback_0_2, user_data, callback.pp_completion_callback());
+  }
+
+  return callback.MayForce(PP_ERROR_NOINTERFACE);
+}
+
 bool AudioInput_Dev::StartCapture() {
+  if (has_interface<PPB_AudioInput_Dev_0_4>()) {
+    return PP_ToBool(get_interface<PPB_AudioInput_Dev_0_4>()->StartCapture(
+        pp_resource()));
+  }
   if (has_interface<PPB_AudioInput_Dev_0_3>()) {
     return PP_ToBool(get_interface<PPB_AudioInput_Dev_0_3>()->StartCapture(
         pp_resource()));
@@ -113,6 +148,10 @@
 }
 
 bool AudioInput_Dev::StopCapture() {
+  if (has_interface<PPB_AudioInput_Dev_0_4>()) {
+    return PP_ToBool(get_interface<PPB_AudioInput_Dev_0_4>()->StopCapture(
+        pp_resource()));
+  }
   if (has_interface<PPB_AudioInput_Dev_0_3>()) {
     return PP_ToBool(get_interface<PPB_AudioInput_Dev_0_3>()->StopCapture(
         pp_resource()));
@@ -126,7 +165,9 @@
 }
 
 void AudioInput_Dev::Close() {
-  if (has_interface<PPB_AudioInput_Dev_0_3>()) {
+  if (has_interface<PPB_AudioInput_Dev_0_4>()) {
+    get_interface<PPB_AudioInput_Dev_0_4>()->Close(pp_resource());
+  } else if (has_interface<PPB_AudioInput_Dev_0_3>()) {
     get_interface<PPB_AudioInput_Dev_0_3>()->Close(pp_resource());
   } else if (has_interface<PPB_AudioInput_Dev_0_2>()) {
     get_interface<PPB_AudioInput_Dev_0_2>()->Close(pp_resource());
diff --git a/ppapi/cpp/dev/audio_input_dev.h b/ppapi/cpp/dev/audio_input_dev.h
index 22408cdf..cb1f4ef 100644
--- a/ppapi/cpp/dev/audio_input_dev.h
+++ b/ppapi/cpp/dev/audio_input_dev.h
@@ -42,12 +42,21 @@
 
   /// If |device_ref| is null (i.e., is_null() returns true), the default device
   /// will be used.
+  ///
+  /// Requires <code>PPB_AudioInput_Dev</code> version 0.4 or up.
   int32_t Open(const DeviceRef_Dev& device_ref,
                const AudioConfig& config,
                PPB_AudioInput_Callback audio_input_callback,
                void* user_data,
                const CompletionCallback& callback);
 
+  /// Requires <code>PPB_AudioInput_Dev</code> version 0.2 or 0.3.
+  int32_t Open(const DeviceRef_Dev& device_ref,
+               const AudioConfig& config,
+               PPB_AudioInput_Callback_0_2 audio_input_callback_0_2,
+               void* user_data,
+               const CompletionCallback& callback);
+
   bool StartCapture();
   bool StopCapture();
   void Close();
diff --git a/ppapi/examples/audio_input/audio_input.cc b/ppapi/examples/audio_input/audio_input.cc
index e2df2b8..06cea43 100644
--- a/ppapi/examples/audio_input/audio_input.cc
+++ b/ppapi/examples/audio_input/audio_input.cc
@@ -20,6 +20,7 @@
 #include "ppapi/cpp/rect.h"
 #include "ppapi/cpp/size.h"
 #include "ppapi/utility/completion_callback_factory.h"
+#include "ppapi/utility/threading/lock.h"
 
 // When compiling natively on Windows, PostMessage can be #define-d to
 // something else.
@@ -45,6 +46,7 @@
         sample_count_(0),
         channel_count_(0),
         samples_(NULL),
+        latency_(0),
         timer_interval_(0),
         pending_paint_(false),
         waiting_for_flush_completion_(false) {
@@ -53,6 +55,8 @@
     device_detector_.MonitorDeviceChange(NULL, NULL);
     audio_input_.Close();
 
+    // The audio input thread has exited before the previous call returned, so
+    // it is safe to do so now.
     delete[] samples_;
   }
 
@@ -187,13 +191,25 @@
       *image.GetAddr32(pp::Point(x, mid_height - max_amplitude)) = 0xff404040;
     }
 
-    // Draw our samples.
-    for (int x = 0, i = 0;
-         x < std::min(size.width(), static_cast<int>(sample_count_));
-         x++, i += channel_count_) {
-      int y = samples_[i] * max_amplitude /
-              (std::numeric_limits<int16_t>::max() + 1) + mid_height;
-      *image.GetAddr32(pp::Point(x, y)) = 0xffffffff;
+    {
+      pp::AutoLock auto_lock(lock_);
+
+      // Draw the latency as a red bar at the bottom.
+      PP_DCHECK(latency_ >= 0);
+      int latency_bar_length =
+          latency_ < 1 ? size.width() * latency_ : size.width();
+      for (int x = 0; x < latency_bar_length; ++x) {
+        *image.GetAddr32(pp::Point(x, mid_height + max_amplitude)) = 0xffff0000;
+      }
+
+      // Draw our samples.
+      for (int x = 0, i = 0;
+           x < std::min(size.width(), static_cast<int>(sample_count_));
+           x++, i += channel_count_) {
+        int y = samples_[i] * max_amplitude /
+                (std::numeric_limits<int16_t>::max() + 1) + mid_height;
+        *image.GetAddr32(pp::Point(x, y)) = 0xffffffff;
+      }
     }
 
     return image;
@@ -252,14 +268,13 @@
     }
   }
 
-  // TODO(viettrungluu): Danger! We really should lock, but which thread
-  // primitives to use? In any case, the |StopCapture()| in the destructor
-  // shouldn't return until this callback is done, so at least we should be
-  // writing to a valid region of memory.
   static void CaptureCallback(const void* samples,
                               uint32_t num_bytes,
+                              PP_TimeDelta latency,
                               void* ctx) {
     MyInstance* thiz = static_cast<MyInstance*>(ctx);
+    pp::AutoLock auto_lock(thiz->lock_);
+    thiz->latency_ = latency;
     uint32_t buffer_size =
         thiz->sample_count_ * thiz->channel_count_ * sizeof(int16_t);
     PP_DCHECK(num_bytes <= buffer_size);
@@ -295,6 +310,8 @@
   uint32_t channel_count_;
   int16_t* samples_;
 
+  PP_TimeDelta latency_;
+
   int32_t timer_interval_;
 
   // Painting stuff.
@@ -311,6 +328,9 @@
 
   std::vector<pp::DeviceRef_Dev> enumerate_devices_;
   std::vector<pp::DeviceRef_Dev> monitor_devices_;
+
+  // Protects |samples_| and |latency_|.
+  pp::Lock lock_;
 };
 
 class MyModule : public pp::Module {
diff --git a/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c b/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c
index 6f1d876..d85099d 100644
--- a/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c
+++ b/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c
@@ -168,6 +168,7 @@
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPP_Messaging_1_0;
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_AudioInput_Dev_0_2;
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_AudioInput_Dev_0_3;
+static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_AudioInput_Dev_0_4;
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_DeviceRef_Dev_0_1;
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_FileChooser_Dev_0_5;
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_FileChooser_Dev_0_6;
@@ -1435,7 +1436,7 @@
   return iface->EnumerateDevices(audio_input, devices, *callback);
 }
 
-static int32_t Pnacl_M19_PPB_AudioInput_Dev_Open(PP_Resource audio_input, PP_Resource device_ref, PP_Resource config, PPB_AudioInput_Callback audio_input_callback, void* user_data, struct PP_CompletionCallback* callback) {
+static int32_t Pnacl_M19_PPB_AudioInput_Dev_Open(PP_Resource audio_input, PP_Resource device_ref, PP_Resource config, PPB_AudioInput_Callback_0_2 audio_input_callback, void* user_data, struct PP_CompletionCallback* callback) {
   const struct PPB_AudioInput_Dev_0_2 *iface = Pnacl_WrapperInfo_PPB_AudioInput_Dev_0_2.real_iface;
   return iface->Open(audio_input, device_ref, config, audio_input_callback, user_data, *callback);
 }
@@ -1484,7 +1485,7 @@
   return iface->MonitorDeviceChange(audio_input, callback, user_data);
 }
 
-static int32_t Pnacl_M25_PPB_AudioInput_Dev_Open(PP_Resource audio_input, PP_Resource device_ref, PP_Resource config, PPB_AudioInput_Callback audio_input_callback, void* user_data, struct PP_CompletionCallback* callback) {
+static int32_t Pnacl_M25_PPB_AudioInput_Dev_Open(PP_Resource audio_input, PP_Resource device_ref, PP_Resource config, PPB_AudioInput_Callback_0_2 audio_input_callback, void* user_data, struct PP_CompletionCallback* callback) {
   const struct PPB_AudioInput_Dev_0_3 *iface = Pnacl_WrapperInfo_PPB_AudioInput_Dev_0_3.real_iface;
   return iface->Open(audio_input, device_ref, config, audio_input_callback, user_data, *callback);
 }
@@ -1511,6 +1512,55 @@
 
 /* End wrapper methods for PPB_AudioInput_Dev_0_3 */
 
+/* Begin wrapper methods for PPB_AudioInput_Dev_0_4 */
+
+static PP_Resource Pnacl_M29_PPB_AudioInput_Dev_Create(PP_Instance instance) {
+  const struct PPB_AudioInput_Dev_0_4 *iface = Pnacl_WrapperInfo_PPB_AudioInput_Dev_0_4.real_iface;
+  return iface->Create(instance);
+}
+
+static PP_Bool Pnacl_M29_PPB_AudioInput_Dev_IsAudioInput(PP_Resource resource) {
+  const struct PPB_AudioInput_Dev_0_4 *iface = Pnacl_WrapperInfo_PPB_AudioInput_Dev_0_4.real_iface;
+  return iface->IsAudioInput(resource);
+}
+
+static int32_t Pnacl_M29_PPB_AudioInput_Dev_EnumerateDevices(PP_Resource audio_input, struct PP_ArrayOutput* output, struct PP_CompletionCallback* callback) {
+  const struct PPB_AudioInput_Dev_0_4 *iface = Pnacl_WrapperInfo_PPB_AudioInput_Dev_0_4.real_iface;
+  return iface->EnumerateDevices(audio_input, *output, *callback);
+}
+
+static int32_t Pnacl_M29_PPB_AudioInput_Dev_MonitorDeviceChange(PP_Resource audio_input, PP_MonitorDeviceChangeCallback callback, void* user_data) {
+  const struct PPB_AudioInput_Dev_0_4 *iface = Pnacl_WrapperInfo_PPB_AudioInput_Dev_0_4.real_iface;
+  return iface->MonitorDeviceChange(audio_input, callback, user_data);
+}
+
+static int32_t Pnacl_M29_PPB_AudioInput_Dev_Open(PP_Resource audio_input, PP_Resource device_ref, PP_Resource config, PPB_AudioInput_Callback audio_input_callback, void* user_data, struct PP_CompletionCallback* callback) {
+  const struct PPB_AudioInput_Dev_0_4 *iface = Pnacl_WrapperInfo_PPB_AudioInput_Dev_0_4.real_iface;
+  return iface->Open(audio_input, device_ref, config, audio_input_callback, user_data, *callback);
+}
+
+static PP_Resource Pnacl_M29_PPB_AudioInput_Dev_GetCurrentConfig(PP_Resource audio_input) {
+  const struct PPB_AudioInput_Dev_0_4 *iface = Pnacl_WrapperInfo_PPB_AudioInput_Dev_0_4.real_iface;
+  return iface->GetCurrentConfig(audio_input);
+}
+
+static PP_Bool Pnacl_M29_PPB_AudioInput_Dev_StartCapture(PP_Resource audio_input) {
+  const struct PPB_AudioInput_Dev_0_4 *iface = Pnacl_WrapperInfo_PPB_AudioInput_Dev_0_4.real_iface;
+  return iface->StartCapture(audio_input);
+}
+
+static PP_Bool Pnacl_M29_PPB_AudioInput_Dev_StopCapture(PP_Resource audio_input) {
+  const struct PPB_AudioInput_Dev_0_4 *iface = Pnacl_WrapperInfo_PPB_AudioInput_Dev_0_4.real_iface;
+  return iface->StopCapture(audio_input);
+}
+
+static void Pnacl_M29_PPB_AudioInput_Dev_Close(PP_Resource audio_input) {
+  const struct PPB_AudioInput_Dev_0_4 *iface = Pnacl_WrapperInfo_PPB_AudioInput_Dev_0_4.real_iface;
+  iface->Close(audio_input);
+}
+
+/* End wrapper methods for PPB_AudioInput_Dev_0_4 */
+
 /* Not generating wrapper methods for PPB_Buffer_Dev_0_4 */
 
 /* Not generating wrapper methods for PPB_Crypto_Dev_0_1 */
@@ -4129,7 +4179,7 @@
     .Create = (PP_Resource (*)(PP_Instance instance))&Pnacl_M19_PPB_AudioInput_Dev_Create,
     .IsAudioInput = (PP_Bool (*)(PP_Resource resource))&Pnacl_M19_PPB_AudioInput_Dev_IsAudioInput,
     .EnumerateDevices = (int32_t (*)(PP_Resource audio_input, PP_Resource* devices, struct PP_CompletionCallback callback))&Pnacl_M19_PPB_AudioInput_Dev_EnumerateDevices,
-    .Open = (int32_t (*)(PP_Resource audio_input, PP_Resource device_ref, PP_Resource config, PPB_AudioInput_Callback audio_input_callback, void* user_data, struct PP_CompletionCallback callback))&Pnacl_M19_PPB_AudioInput_Dev_Open,
+    .Open = (int32_t (*)(PP_Resource audio_input, PP_Resource device_ref, PP_Resource config, PPB_AudioInput_Callback_0_2 audio_input_callback, void* user_data, struct PP_CompletionCallback callback))&Pnacl_M19_PPB_AudioInput_Dev_Open,
     .GetCurrentConfig = (PP_Resource (*)(PP_Resource audio_input))&Pnacl_M19_PPB_AudioInput_Dev_GetCurrentConfig,
     .StartCapture = (PP_Bool (*)(PP_Resource audio_input))&Pnacl_M19_PPB_AudioInput_Dev_StartCapture,
     .StopCapture = (PP_Bool (*)(PP_Resource audio_input))&Pnacl_M19_PPB_AudioInput_Dev_StopCapture,
@@ -4141,13 +4191,25 @@
     .IsAudioInput = (PP_Bool (*)(PP_Resource resource))&Pnacl_M25_PPB_AudioInput_Dev_IsAudioInput,
     .EnumerateDevices = (int32_t (*)(PP_Resource audio_input, struct PP_ArrayOutput output, struct PP_CompletionCallback callback))&Pnacl_M25_PPB_AudioInput_Dev_EnumerateDevices,
     .MonitorDeviceChange = (int32_t (*)(PP_Resource audio_input, PP_MonitorDeviceChangeCallback callback, void* user_data))&Pnacl_M25_PPB_AudioInput_Dev_MonitorDeviceChange,
-    .Open = (int32_t (*)(PP_Resource audio_input, PP_Resource device_ref, PP_Resource config, PPB_AudioInput_Callback audio_input_callback, void* user_data, struct PP_CompletionCallback callback))&Pnacl_M25_PPB_AudioInput_Dev_Open,
+    .Open = (int32_t (*)(PP_Resource audio_input, PP_Resource device_ref, PP_Resource config, PPB_AudioInput_Callback_0_2 audio_input_callback, void* user_data, struct PP_CompletionCallback callback))&Pnacl_M25_PPB_AudioInput_Dev_Open,
     .GetCurrentConfig = (PP_Resource (*)(PP_Resource audio_input))&Pnacl_M25_PPB_AudioInput_Dev_GetCurrentConfig,
     .StartCapture = (PP_Bool (*)(PP_Resource audio_input))&Pnacl_M25_PPB_AudioInput_Dev_StartCapture,
     .StopCapture = (PP_Bool (*)(PP_Resource audio_input))&Pnacl_M25_PPB_AudioInput_Dev_StopCapture,
     .Close = (void (*)(PP_Resource audio_input))&Pnacl_M25_PPB_AudioInput_Dev_Close
 };
 
+struct PPB_AudioInput_Dev_0_4 Pnacl_Wrappers_PPB_AudioInput_Dev_0_4 = {
+    .Create = (PP_Resource (*)(PP_Instance instance))&Pnacl_M29_PPB_AudioInput_Dev_Create,
+    .IsAudioInput = (PP_Bool (*)(PP_Resource resource))&Pnacl_M29_PPB_AudioInput_Dev_IsAudioInput,
+    .EnumerateDevices = (int32_t (*)(PP_Resource audio_input, struct PP_ArrayOutput output, struct PP_CompletionCallback callback))&Pnacl_M29_PPB_AudioInput_Dev_EnumerateDevices,
+    .MonitorDeviceChange = (int32_t (*)(PP_Resource audio_input, PP_MonitorDeviceChangeCallback callback, void* user_data))&Pnacl_M29_PPB_AudioInput_Dev_MonitorDeviceChange,
+    .Open = (int32_t (*)(PP_Resource audio_input, PP_Resource device_ref, PP_Resource config, PPB_AudioInput_Callback audio_input_callback, void* user_data, struct PP_CompletionCallback callback))&Pnacl_M29_PPB_AudioInput_Dev_Open,
+    .GetCurrentConfig = (PP_Resource (*)(PP_Resource audio_input))&Pnacl_M29_PPB_AudioInput_Dev_GetCurrentConfig,
+    .StartCapture = (PP_Bool (*)(PP_Resource audio_input))&Pnacl_M29_PPB_AudioInput_Dev_StartCapture,
+    .StopCapture = (PP_Bool (*)(PP_Resource audio_input))&Pnacl_M29_PPB_AudioInput_Dev_StopCapture,
+    .Close = (void (*)(PP_Resource audio_input))&Pnacl_M29_PPB_AudioInput_Dev_Close
+};
+
 /* Not generating wrapper interface for PPB_Buffer_Dev_0_4 */
 
 /* Not generating wrapper interface for PPB_Crypto_Dev_0_1 */
@@ -4993,6 +5055,12 @@
   .real_iface = NULL
 };
 
+static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_AudioInput_Dev_0_4 = {
+  .iface_macro = PPB_AUDIO_INPUT_DEV_INTERFACE_0_4,
+  .wrapped_iface = (void *) &Pnacl_Wrappers_PPB_AudioInput_Dev_0_4,
+  .real_iface = NULL
+};
+
 static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_DeviceRef_Dev_0_1 = {
   .iface_macro = PPB_DEVICEREF_DEV_INTERFACE_0_1,
   .wrapped_iface = (void *) &Pnacl_Wrappers_PPB_DeviceRef_Dev_0_1,
@@ -5364,6 +5432,7 @@
   &Pnacl_WrapperInfo_PPB_WebSocket_1_0,
   &Pnacl_WrapperInfo_PPB_AudioInput_Dev_0_2,
   &Pnacl_WrapperInfo_PPB_AudioInput_Dev_0_3,
+  &Pnacl_WrapperInfo_PPB_AudioInput_Dev_0_4,
   &Pnacl_WrapperInfo_PPB_DeviceRef_Dev_0_1,
   &Pnacl_WrapperInfo_PPB_FileChooser_Dev_0_5,
   &Pnacl_WrapperInfo_PPB_FileChooser_Dev_0_6,
diff --git a/ppapi/proxy/audio_input_resource.cc b/ppapi/proxy/audio_input_resource.cc
index 487df296..4a7afff 100644
--- a/ppapi/proxy/audio_input_resource.cc
+++ b/ppapi/proxy/audio_input_resource.cc
@@ -14,6 +14,7 @@
 #include "ppapi/proxy/resource_message_params.h"
 #include "ppapi/proxy/serialized_handle.h"
 #include "ppapi/shared_impl/ppapi_globals.h"
+#include "ppapi/shared_impl/ppb_audio_config_shared.h"
 #include "ppapi/shared_impl/resource_tracker.h"
 #include "ppapi/shared_impl/tracked_callback.h"
 #include "ppapi/thunk/enter.h"
@@ -29,9 +30,11 @@
       open_state_(BEFORE_OPEN),
       capturing_(false),
       shared_memory_size_(0),
+      audio_input_callback_0_2_(NULL),
       audio_input_callback_(NULL),
       user_data_(NULL),
-      enumeration_helper_(this) {
+      enumeration_helper_(this),
+      bytes_per_second_(0) {
   SendCreate(RENDERER, PpapiHostMsg_AudioInput_Create());
 }
 
@@ -68,47 +71,23 @@
   return enumeration_helper_.MonitorDeviceChange(callback, user_data);
 }
 
+int32_t AudioInputResource::Open0_2(
+    PP_Resource device_ref,
+    PP_Resource config,
+    PPB_AudioInput_Callback_0_2 audio_input_callback_0_2,
+    void* user_data,
+    scoped_refptr<TrackedCallback> callback) {
+  return CommonOpen(device_ref, config, audio_input_callback_0_2, NULL,
+                    user_data, callback);
+}
+
 int32_t AudioInputResource::Open(PP_Resource device_ref,
                                  PP_Resource config,
                                  PPB_AudioInput_Callback audio_input_callback,
                                  void* user_data,
                                  scoped_refptr<TrackedCallback> callback) {
-  std::string device_id;
-  // |device_id| remains empty if |device_ref| is 0, which means the default
-  // device.
-  if (device_ref != 0) {
-    thunk::EnterResourceNoLock<thunk::PPB_DeviceRef_API> enter_device_ref(
-        device_ref, true);
-    if (enter_device_ref.failed())
-      return PP_ERROR_BADRESOURCE;
-    device_id = enter_device_ref.object()->GetDeviceRefData().id;
-  }
-
-  if (TrackedCallback::IsPending(open_callback_))
-    return PP_ERROR_INPROGRESS;
-  if (open_state_ != BEFORE_OPEN)
-    return PP_ERROR_FAILED;
-
-  if (!audio_input_callback)
-    return PP_ERROR_BADARGUMENT;
-  thunk::EnterResourceNoLock<thunk::PPB_AudioConfig_API> enter_config(config,
-                                                                      true);
-  if (enter_config.failed())
-    return PP_ERROR_BADARGUMENT;
-
-  config_ = config;
-  audio_input_callback_ = audio_input_callback;
-  user_data_ = user_data;
-  open_callback_ = callback;
-
-  PpapiHostMsg_AudioInput_Open msg(
-      device_id, enter_config.object()->GetSampleRate(),
-      enter_config.object()->GetSampleFrameCount());
-  Call<PpapiPluginMsg_AudioInput_OpenReply>(
-      RENDERER, msg,
-      base::Bind(&AudioInputResource::OnPluginMsgOpenReply,
-                 base::Unretained(this)));
-  return PP_OK_COMPLETIONPENDING;
+  return CommonOpen(device_ref, config, NULL, audio_input_callback, user_data,
+                    callback);
 }
 
 PP_Resource AudioInputResource::GetCurrentConfig() {
@@ -235,8 +214,8 @@
 
 void AudioInputResource::StartThread() {
   // Don't start the thread unless all our state is set up correctly.
-  if (!audio_input_callback_ || !socket_.get() || !capturing_ ||
-      !shared_memory_->memory()) {
+  if ((!audio_input_callback_0_2_ && !audio_input_callback_) ||
+      !socket_.get() || !capturing_ || !shared_memory_->memory()) {
     return;
   }
   DCHECK(!audio_input_thread_.get());
@@ -270,10 +249,66 @@
     // While closing the stream, we may receive buffers whose size is different
     // from |data_buffer_size|.
     CHECK_LE(buffer->params.size, data_buffer_size);
-    if (buffer->params.size > 0)
-      audio_input_callback_(&buffer->audio[0], buffer->params.size, user_data_);
+    if (buffer->params.size > 0) {
+      if (audio_input_callback_) {
+        PP_TimeDelta latency =
+            static_cast<double>(pending_data) / bytes_per_second_;
+        audio_input_callback_(&buffer->audio[0], buffer->params.size, latency,
+                              user_data_);
+      } else {
+        audio_input_callback_0_2_(&buffer->audio[0], buffer->params.size,
+                                  user_data_);
+      }
+    }
   }
 }
 
+int32_t AudioInputResource::CommonOpen(
+    PP_Resource device_ref,
+    PP_Resource config,
+    PPB_AudioInput_Callback_0_2 audio_input_callback_0_2,
+    PPB_AudioInput_Callback audio_input_callback,
+    void* user_data,
+    scoped_refptr<TrackedCallback> callback) {
+  std::string device_id;
+  // |device_id| remains empty if |device_ref| is 0, which means the default
+  // device.
+  if (device_ref != 0) {
+    thunk::EnterResourceNoLock<thunk::PPB_DeviceRef_API> enter_device_ref(
+        device_ref, true);
+    if (enter_device_ref.failed())
+      return PP_ERROR_BADRESOURCE;
+    device_id = enter_device_ref.object()->GetDeviceRefData().id;
+  }
+
+  if (TrackedCallback::IsPending(open_callback_))
+    return PP_ERROR_INPROGRESS;
+  if (open_state_ != BEFORE_OPEN)
+    return PP_ERROR_FAILED;
+
+  if (!audio_input_callback_0_2 && !audio_input_callback)
+    return PP_ERROR_BADARGUMENT;
+  thunk::EnterResourceNoLock<thunk::PPB_AudioConfig_API> enter_config(config,
+                                                                      true);
+  if (enter_config.failed())
+    return PP_ERROR_BADARGUMENT;
+
+  config_ = config;
+  audio_input_callback_0_2_ = audio_input_callback_0_2;
+  audio_input_callback_ = audio_input_callback;
+  user_data_ = user_data;
+  open_callback_ = callback;
+  bytes_per_second_ = kAudioInputChannels * (kBitsPerAudioInputSample / 8) *
+                      enter_config.object()->GetSampleRate();
+
+  PpapiHostMsg_AudioInput_Open msg(
+      device_id, enter_config.object()->GetSampleRate(),
+      enter_config.object()->GetSampleFrameCount());
+  Call<PpapiPluginMsg_AudioInput_OpenReply>(
+      RENDERER, msg,
+      base::Bind(&AudioInputResource::OnPluginMsgOpenReply,
+                 base::Unretained(this)));
+  return PP_OK_COMPLETIONPENDING;
+}
 }  // namespace proxy
 }  // namespace ppapi
diff --git a/ppapi/proxy/audio_input_resource.h b/ppapi/proxy/audio_input_resource.h
index abe18db2..d2e4890 100644
--- a/ppapi/proxy/audio_input_resource.h
+++ b/ppapi/proxy/audio_input_resource.h
@@ -44,6 +44,11 @@
   virtual int32_t MonitorDeviceChange(
       PP_MonitorDeviceChangeCallback callback,
       void* user_data) OVERRIDE;
+  virtual int32_t Open0_2(PP_Resource device_ref,
+                          PP_Resource config,
+                          PPB_AudioInput_Callback_0_2 audio_input_callback_0_2,
+                          void* user_data,
+                          scoped_refptr<TrackedCallback> callback) OVERRIDE;
   virtual int32_t Open(PP_Resource device_ref,
                        PP_Resource config,
                        PPB_AudioInput_Callback audio_input_callback,
@@ -83,6 +88,13 @@
   // Run on the audio input thread.
   virtual void Run() OVERRIDE;
 
+  int32_t CommonOpen(PP_Resource device_ref,
+                     PP_Resource config,
+                     PPB_AudioInput_Callback_0_2 audio_input_callback_0_2,
+                     PPB_AudioInput_Callback audio_input_callback,
+                     void* user_data,
+                     scoped_refptr<TrackedCallback> callback);
+
   OpenState open_state_;
 
   // True if capturing the stream.
@@ -104,6 +116,7 @@
   scoped_ptr<base::DelegateSimpleThread> audio_input_thread_;
 
   // Callback to call when new samples are available.
+  PPB_AudioInput_Callback_0_2 audio_input_callback_0_2_;
   PPB_AudioInput_Callback audio_input_callback_;
 
   // User data pointer passed verbatim to the callback function.
@@ -119,6 +132,10 @@
 
   DeviceEnumerationResourceHelper enumeration_helper_;
 
+  // The data size (in bytes) of one second of audio input. Used to calculate
+  // latency.
+  size_t bytes_per_second_;
+
   DISALLOW_COPY_AND_ASSIGN(AudioInputResource);
 };
 
diff --git a/ppapi/shared_impl/ppb_audio_config_shared.h b/ppapi/shared_impl/ppb_audio_config_shared.h
index 77826be..b77a1124 100644
--- a/ppapi/shared_impl/ppb_audio_config_shared.h
+++ b/ppapi/shared_impl/ppb_audio_config_shared.h
@@ -12,6 +12,12 @@
 
 namespace ppapi {
 
+const int kBitsPerAudioInputSample = 16;
+const int kAudioInputChannels = 1;
+
+const int kBitsPerAudioOutputSample = 16;
+const int kAudioOutputChannels = 2;
+
 class PPAPI_SHARED_EXPORT PPB_AudioConfig_Shared
     : public Resource,
       public thunk::PPB_AudioConfig_API {
diff --git a/ppapi/thunk/interfaces_ppb_public_dev.h b/ppapi/thunk/interfaces_ppb_public_dev.h
index 8fa7a93..ca487aa 100644
--- a/ppapi/thunk/interfaces_ppb_public_dev.h
+++ b/ppapi/thunk/interfaces_ppb_public_dev.h
@@ -54,6 +54,8 @@
               PPB_AudioInput_Dev_0_2)
 PROXIED_IFACE(NoAPIName, PPB_AUDIO_INPUT_DEV_INTERFACE_0_3,
               PPB_AudioInput_Dev_0_3)
+PROXIED_IFACE(NoAPIName, PPB_AUDIO_INPUT_DEV_INTERFACE_0_4,
+              PPB_AudioInput_Dev_0_4)
 PROXIED_IFACE(NoAPIName, PPB_IME_INPUT_EVENT_DEV_INTERFACE_0_1,
               PPB_IMEInputEvent_Dev_0_1)
 PROXIED_IFACE(PPB_Buffer, PPB_BUFFER_DEV_INTERFACE_0_4, PPB_Buffer_Dev_0_4)
diff --git a/ppapi/thunk/ppb_audio_input_api.h b/ppapi/thunk/ppb_audio_input_api.h
index ebae557..60fc881 100644
--- a/ppapi/thunk/ppb_audio_input_api.h
+++ b/ppapi/thunk/ppb_audio_input_api.h
@@ -27,6 +27,11 @@
                                    scoped_refptr<TrackedCallback> callback) = 0;
   virtual int32_t MonitorDeviceChange(PP_MonitorDeviceChangeCallback callback,
                                       void* user_data) = 0;
+  virtual int32_t Open0_2(PP_Resource device_ref,
+                          PP_Resource config,
+                          PPB_AudioInput_Callback_0_2 audio_input_callback_0_2,
+                          void* user_data,
+                          scoped_refptr<TrackedCallback> callback) = 0;
   virtual int32_t Open(PP_Resource device_ref,
                        PP_Resource config,
                        PPB_AudioInput_Callback audio_input_callback,
diff --git a/ppapi/thunk/ppb_audio_input_dev_thunk.cc b/ppapi/thunk/ppb_audio_input_dev_thunk.cc
index 2a78737..ee38c7ad 100644
--- a/ppapi/thunk/ppb_audio_input_dev_thunk.cc
+++ b/ppapi/thunk/ppb_audio_input_dev_thunk.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// From dev/ppb_audio_input_dev.idl modified Tue Apr 16 11:25:44 2013.
-
 #include "ppapi/c/dev/ppb_audio_input_dev.h"
 #include "ppapi/c/pp_completion_callback.h"
 #include "ppapi/c/pp_errors.h"
@@ -66,6 +64,23 @@
   return enter.object()->MonitorDeviceChange(callback, user_data);
 }
 
+int32_t Open_0_2(PP_Resource audio_input,
+                 PP_Resource device_ref,
+                 PP_Resource config,
+                 PPB_AudioInput_Callback_0_2 audio_input_callback,
+                 void* user_data,
+                 struct PP_CompletionCallback callback) {
+  VLOG(4) << "PPB_AudioInput_Dev::Open()";
+  EnterResource<PPB_AudioInput_API> enter(audio_input, callback, true);
+  if (enter.failed())
+    return enter.retval();
+  return enter.SetResult(enter.object()->Open0_2(device_ref,
+                                                 config,
+                                                 audio_input_callback,
+                                                 user_data,
+                                                 enter.callback()));
+}
+
 int32_t Open(PP_Resource audio_input,
              PP_Resource device_ref,
              PP_Resource config,
@@ -119,7 +134,7 @@
   &Create,
   &IsAudioInput,
   &EnumerateDevices_0_2,
-  &Open,
+  &Open_0_2,
   &GetCurrentConfig,
   &StartCapture,
   &StopCapture,
@@ -131,6 +146,18 @@
   &IsAudioInput,
   &EnumerateDevices,
   &MonitorDeviceChange,
+  &Open_0_2,
+  &GetCurrentConfig,
+  &StartCapture,
+  &StopCapture,
+  &Close
+};
+
+const PPB_AudioInput_Dev_0_4 g_ppb_audioinput_dev_thunk_0_4 = {
+  &Create,
+  &IsAudioInput,
+  &EnumerateDevices,
+  &MonitorDeviceChange,
   &Open,
   &GetCurrentConfig,
   &StartCapture,
@@ -148,5 +175,9 @@
   return &g_ppb_audioinput_dev_thunk_0_3;
 }
 
+const PPB_AudioInput_Dev_0_4* GetPPB_AudioInput_Dev_0_4_Thunk() {
+  return &g_ppb_audioinput_dev_thunk_0_4;
+}
+
 }  // namespace thunk
 }  // namespace ppapi